| 
									
										
										
										
											2008-09-09 09:36:50 -07:00
										 |  |  | /* arch/arm/mach-msm/proc_comm.c
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (C) 2007-2008 Google, Inc. | 
					
						
							|  |  |  |  * Author: Brian Swetland <swetland@google.com> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This software is licensed under the terms of the GNU General Public | 
					
						
							|  |  |  |  * License version 2, as published by the Free Software Foundation, and | 
					
						
							|  |  |  |  * may be copied, distributed, and modified under those terms. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |  * GNU General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <linux/delay.h>
 | 
					
						
							|  |  |  | #include <linux/errno.h>
 | 
					
						
							|  |  |  | #include <linux/io.h>
 | 
					
						
							|  |  |  | #include <linux/spinlock.h>
 | 
					
						
							|  |  |  | #include <mach/msm_iomap.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "proc_comm.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-29 11:43:42 -08:00
										 |  |  | static inline void msm_a2m_int(uint32_t irq) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | #if defined(CONFIG_ARCH_MSM7X30)
 | 
					
						
							|  |  |  | 	writel(1 << irq, MSM_GCC_BASE + 0x8); | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | 	writel(1, MSM_CSR_BASE + 0x400 + (irq * 4)); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2008-09-09 09:36:50 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | static inline void notify_other_proc_comm(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-01-29 11:43:42 -08:00
										 |  |  | 	msm_a2m_int(6); | 
					
						
							| 
									
										
										
										
											2008-09-09 09:36:50 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define APP_COMMAND 0x00
 | 
					
						
							|  |  |  | #define APP_STATUS  0x04
 | 
					
						
							|  |  |  | #define APP_DATA1   0x08
 | 
					
						
							|  |  |  | #define APP_DATA2   0x0C
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define MDM_COMMAND 0x10
 | 
					
						
							|  |  |  | #define MDM_STATUS  0x14
 | 
					
						
							|  |  |  | #define MDM_DATA1   0x18
 | 
					
						
							|  |  |  | #define MDM_DATA2   0x1C
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static DEFINE_SPINLOCK(proc_comm_lock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* The higher level SMD support will install this to
 | 
					
						
							|  |  |  |  * provide a way to check for and handle modem restart. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | int (*msm_check_for_modem_crash)(void); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Poll for a state change, checking for possible
 | 
					
						
							|  |  |  |  * modem crashes along the way (so we don't wait | 
					
						
							|  |  |  |  * forever while the ARM9 is blowing up). | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Return an error in the event of a modem crash and | 
					
						
							|  |  |  |  * restart so the msm_proc_comm() routine can restart | 
					
						
							|  |  |  |  * the operation from the beginning. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int proc_comm_wait_for(void __iomem *addr, unsigned value) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	for (;;) { | 
					
						
							|  |  |  | 		if (readl(addr) == value) | 
					
						
							|  |  |  | 			return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (msm_check_for_modem_crash) | 
					
						
							|  |  |  | 			if (msm_check_for_modem_crash()) | 
					
						
							|  |  |  | 				return -EAGAIN; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int msm_proc_comm(unsigned cmd, unsigned *data1, unsigned *data2) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	void __iomem *base = MSM_SHARED_RAM_BASE; | 
					
						
							|  |  |  | 	unsigned long flags; | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	spin_lock_irqsave(&proc_comm_lock, flags); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (;;) { | 
					
						
							|  |  |  | 		if (proc_comm_wait_for(base + MDM_STATUS, PCOM_READY)) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		writel(cmd, base + APP_COMMAND); | 
					
						
							|  |  |  | 		writel(data1 ? *data1 : 0, base + APP_DATA1); | 
					
						
							|  |  |  | 		writel(data2 ? *data2 : 0, base + APP_DATA2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		notify_other_proc_comm(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (proc_comm_wait_for(base + APP_COMMAND, PCOM_CMD_DONE)) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (readl(base + APP_STATUS) != PCOM_CMD_FAIL) { | 
					
						
							|  |  |  | 			if (data1) | 
					
						
							|  |  |  | 				*data1 = readl(base + APP_DATA1); | 
					
						
							|  |  |  | 			if (data2) | 
					
						
							|  |  |  | 				*data2 = readl(base + APP_DATA2); | 
					
						
							|  |  |  | 			ret = 0; | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			ret = -EIO; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	writel(PCOM_CMD_IDLE, base + APP_COMMAND); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	spin_unlock_irqrestore(&proc_comm_lock, flags); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-18 12:31:08 -07:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * We need to wait for the ARM9 to at least partially boot | 
					
						
							|  |  |  |  * up before we can continue. Since the ARM9 does resource | 
					
						
							|  |  |  |  * allocation, if we dont' wait we could end up crashing or in | 
					
						
							|  |  |  |  * and unknown state. This function should be called early to | 
					
						
							|  |  |  |  * wait on the ARM9. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2012-12-21 14:02:24 -08:00
										 |  |  | void proc_comm_boot_wait(void) | 
					
						
							| 
									
										
										
										
											2010-03-18 12:31:08 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	void __iomem *base = MSM_SHARED_RAM_BASE; | 
					
						
							|  |  |  |   | 
					
						
							|  |  |  | 	proc_comm_wait_for(base + MDM_STATUS, PCOM_READY); | 
					
						
							|  |  |  |   | 
					
						
							|  |  |  | } |