| Brian Swetland | b8a16e1 | 2008-09-09 09:36:50 -0700 | [diff] [blame] | 1 | /* arch/arm/mach-msm/proc_comm.c | 
 | 2 |  * | 
 | 3 |  * Copyright (C) 2007-2008 Google, Inc. | 
| Duy Truong | e833aca | 2013-02-12 13:35:08 -0800 | [diff] [blame] | 4 |  * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved. | 
| Brian Swetland | b8a16e1 | 2008-09-09 09:36:50 -0700 | [diff] [blame] | 5 |  * Author: Brian Swetland <swetland@google.com> | 
 | 6 |  * | 
 | 7 |  * This software is licensed under the terms of the GNU General Public | 
 | 8 |  * License version 2, as published by the Free Software Foundation, and | 
 | 9 |  * may be copied, distributed, and modified under those terms. | 
 | 10 |  * | 
 | 11 |  * This program is distributed in the hope that it will be useful, | 
 | 12 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | 13 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 | 14 |  * GNU General Public License for more details. | 
 | 15 |  * | 
 | 16 |  */ | 
 | 17 |  | 
 | 18 | #include <linux/delay.h> | 
 | 19 | #include <linux/errno.h> | 
 | 20 | #include <linux/io.h> | 
 | 21 | #include <linux/spinlock.h> | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 22 | #include <linux/module.h> | 
| Brian Swetland | b8a16e1 | 2008-09-09 09:36:50 -0700 | [diff] [blame] | 23 | #include <mach/msm_iomap.h> | 
 | 24 | #include <mach/system.h> | 
| Steve Muckle | f132c6c | 2012-06-06 18:30:57 -0700 | [diff] [blame] | 25 | #include <mach/proc_comm.h> | 
| Brian Swetland | b8a16e1 | 2008-09-09 09:36:50 -0700 | [diff] [blame] | 26 |  | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 27 | #include "smd_private.h" | 
| Brian Swetland | b8a16e1 | 2008-09-09 09:36:50 -0700 | [diff] [blame] | 28 |  | 
 | 29 | static inline void notify_other_proc_comm(void) | 
 | 30 | { | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 31 | 	/* Make sure the write completes before interrupt */ | 
 | 32 | 	wmb(); | 
 | 33 | #if defined(CONFIG_ARCH_MSM7X30) | 
| Taniya Das | 298de8c | 2012-02-16 11:45:31 +0530 | [diff] [blame] | 34 | 	__raw_writel(1 << 6, MSM_APCS_GCC_BASE + 0x8); | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 35 | #elif defined(CONFIG_ARCH_MSM8X60) | 
 | 36 | 	__raw_writel(1 << 5, MSM_GCC_BASE + 0x8); | 
 | 37 | #else | 
 | 38 | 	__raw_writel(1, MSM_CSR_BASE + 0x400 + (6) * 4); | 
 | 39 | #endif | 
| Brian Swetland | b8a16e1 | 2008-09-09 09:36:50 -0700 | [diff] [blame] | 40 | } | 
 | 41 |  | 
 | 42 | #define APP_COMMAND 0x00 | 
 | 43 | #define APP_STATUS  0x04 | 
 | 44 | #define APP_DATA1   0x08 | 
 | 45 | #define APP_DATA2   0x0C | 
 | 46 |  | 
 | 47 | #define MDM_COMMAND 0x10 | 
 | 48 | #define MDM_STATUS  0x14 | 
 | 49 | #define MDM_DATA1   0x18 | 
 | 50 | #define MDM_DATA2   0x1C | 
 | 51 |  | 
 | 52 | static DEFINE_SPINLOCK(proc_comm_lock); | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 53 | static int msm_proc_comm_disable; | 
| Brian Swetland | b8a16e1 | 2008-09-09 09:36:50 -0700 | [diff] [blame] | 54 |  | 
 | 55 | /* Poll for a state change, checking for possible | 
 | 56 |  * modem crashes along the way (so we don't wait | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 57 |  * forever while the ARM9 is blowing up. | 
| Brian Swetland | b8a16e1 | 2008-09-09 09:36:50 -0700 | [diff] [blame] | 58 |  * | 
 | 59 |  * Return an error in the event of a modem crash and | 
 | 60 |  * restart so the msm_proc_comm() routine can restart | 
 | 61 |  * the operation from the beginning. | 
 | 62 |  */ | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 63 | static int proc_comm_wait_for(unsigned addr, unsigned value) | 
| Brian Swetland | b8a16e1 | 2008-09-09 09:36:50 -0700 | [diff] [blame] | 64 | { | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 65 | 	while (1) { | 
 | 66 | 		/* Barrier here prevents excessive spinning */ | 
 | 67 | 		mb(); | 
 | 68 | 		if (readl_relaxed(addr) == value) | 
| Brian Swetland | b8a16e1 | 2008-09-09 09:36:50 -0700 | [diff] [blame] | 69 | 			return 0; | 
 | 70 |  | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 71 | 		if (smsm_check_for_modem_crash()) | 
 | 72 | 			return -EAGAIN; | 
 | 73 |  | 
 | 74 | 		udelay(5); | 
| Brian Swetland | b8a16e1 | 2008-09-09 09:36:50 -0700 | [diff] [blame] | 75 | 	} | 
 | 76 | } | 
 | 77 |  | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 78 | void msm_proc_comm_reset_modem_now(void) | 
 | 79 | { | 
 | 80 | 	unsigned base = (unsigned)MSM_SHARED_RAM_BASE; | 
 | 81 | 	unsigned long flags; | 
 | 82 |  | 
 | 83 | 	spin_lock_irqsave(&proc_comm_lock, flags); | 
 | 84 |  | 
 | 85 | again: | 
 | 86 | 	if (proc_comm_wait_for(base + MDM_STATUS, PCOM_READY)) | 
 | 87 | 		goto again; | 
 | 88 |  | 
 | 89 | 	writel_relaxed(PCOM_RESET_MODEM, base + APP_COMMAND); | 
 | 90 | 	writel_relaxed(0, base + APP_DATA1); | 
 | 91 | 	writel_relaxed(0, base + APP_DATA2); | 
 | 92 |  | 
 | 93 | 	spin_unlock_irqrestore(&proc_comm_lock, flags); | 
 | 94 |  | 
 | 95 | 	/* Make sure the writes complete before notifying the other side */ | 
 | 96 | 	wmb(); | 
 | 97 | 	notify_other_proc_comm(); | 
 | 98 |  | 
 | 99 | 	return; | 
 | 100 | } | 
 | 101 | EXPORT_SYMBOL(msm_proc_comm_reset_modem_now); | 
 | 102 |  | 
| Brian Swetland | b8a16e1 | 2008-09-09 09:36:50 -0700 | [diff] [blame] | 103 | int msm_proc_comm(unsigned cmd, unsigned *data1, unsigned *data2) | 
 | 104 | { | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 105 | 	unsigned base = (unsigned)MSM_SHARED_RAM_BASE; | 
| Brian Swetland | b8a16e1 | 2008-09-09 09:36:50 -0700 | [diff] [blame] | 106 | 	unsigned long flags; | 
 | 107 | 	int ret; | 
 | 108 |  | 
 | 109 | 	spin_lock_irqsave(&proc_comm_lock, flags); | 
 | 110 |  | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 111 | 	if (msm_proc_comm_disable) { | 
 | 112 | 		ret = -EIO; | 
 | 113 | 		goto end; | 
| Brian Swetland | b8a16e1 | 2008-09-09 09:36:50 -0700 | [diff] [blame] | 114 | 	} | 
 | 115 |  | 
| Brian Swetland | b8a16e1 | 2008-09-09 09:36:50 -0700 | [diff] [blame] | 116 |  | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 117 | again: | 
 | 118 | 	if (proc_comm_wait_for(base + MDM_STATUS, PCOM_READY)) | 
 | 119 | 		goto again; | 
 | 120 |  | 
 | 121 | 	writel_relaxed(cmd, base + APP_COMMAND); | 
 | 122 | 	writel_relaxed(data1 ? *data1 : 0, base + APP_DATA1); | 
 | 123 | 	writel_relaxed(data2 ? *data2 : 0, base + APP_DATA2); | 
 | 124 |  | 
 | 125 | 	/* Make sure the writes complete before notifying the other side */ | 
 | 126 | 	wmb(); | 
 | 127 | 	notify_other_proc_comm(); | 
 | 128 |  | 
 | 129 | 	if (proc_comm_wait_for(base + APP_COMMAND, PCOM_CMD_DONE)) | 
 | 130 | 		goto again; | 
 | 131 |  | 
 | 132 | 	if (readl_relaxed(base + APP_STATUS) == PCOM_CMD_SUCCESS) { | 
 | 133 | 		if (data1) | 
 | 134 | 			*data1 = readl_relaxed(base + APP_DATA1); | 
 | 135 | 		if (data2) | 
 | 136 | 			*data2 = readl_relaxed(base + APP_DATA2); | 
 | 137 | 		ret = 0; | 
 | 138 | 	} else { | 
 | 139 | 		ret = -EIO; | 
 | 140 | 	} | 
 | 141 |  | 
 | 142 | 	writel_relaxed(PCOM_CMD_IDLE, base + APP_COMMAND); | 
 | 143 |  | 
 | 144 | 	switch (cmd) { | 
 | 145 | 	case PCOM_RESET_CHIP: | 
 | 146 | 	case PCOM_RESET_CHIP_IMM: | 
 | 147 | 	case PCOM_RESET_APPS: | 
 | 148 | 		msm_proc_comm_disable = 1; | 
 | 149 | 		printk(KERN_ERR "msm: proc_comm: proc comm disabled\n"); | 
 | 150 | 		break; | 
 | 151 | 	} | 
 | 152 | end: | 
 | 153 | 	/* Make sure the writes complete before returning */ | 
 | 154 | 	wmb(); | 
| Brian Swetland | b8a16e1 | 2008-09-09 09:36:50 -0700 | [diff] [blame] | 155 | 	spin_unlock_irqrestore(&proc_comm_lock, flags); | 
| Brian Swetland | b8a16e1 | 2008-09-09 09:36:50 -0700 | [diff] [blame] | 156 | 	return ret; | 
 | 157 | } | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 158 | EXPORT_SYMBOL(msm_proc_comm); |