blob: c7705e786934a94573134e2dcbe8032b3b392bd7 [file] [log] [blame]
Brian Swetlandb8a16e12008-09-09 09:36:50 -07001/* arch/arm/mach-msm/proc_comm.c
2 *
3 * Copyright (C) 2007-2008 Google, Inc.
Duy Truong790f06d2013-02-13 16:38:12 -08004 * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
Brian Swetlandb8a16e12008-09-09 09:36:50 -07005 * 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 Huntsman3f2bc4d2011-08-16 17:27:22 -070022#include <linux/module.h>
Brian Swetlandb8a16e12008-09-09 09:36:50 -070023#include <mach/msm_iomap.h>
24#include <mach/system.h>
Steve Mucklef132c6c2012-06-06 18:30:57 -070025#include <mach/proc_comm.h>
Brian Swetlandb8a16e12008-09-09 09:36:50 -070026
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070027#include "smd_private.h"
Brian Swetlandb8a16e12008-09-09 09:36:50 -070028
29static inline void notify_other_proc_comm(void)
30{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070031 /* Make sure the write completes before interrupt */
32 wmb();
33#if defined(CONFIG_ARCH_MSM7X30)
Taniya Das298de8c2012-02-16 11:45:31 +053034 __raw_writel(1 << 6, MSM_APCS_GCC_BASE + 0x8);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070035#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 Swetlandb8a16e12008-09-09 09:36:50 -070040}
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
52static DEFINE_SPINLOCK(proc_comm_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070053static int msm_proc_comm_disable;
Brian Swetlandb8a16e12008-09-09 09:36:50 -070054
55/* Poll for a state change, checking for possible
56 * modem crashes along the way (so we don't wait
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070057 * forever while the ARM9 is blowing up.
Brian Swetlandb8a16e12008-09-09 09:36:50 -070058 *
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 Huntsman3f2bc4d2011-08-16 17:27:22 -070063static int proc_comm_wait_for(unsigned addr, unsigned value)
Brian Swetlandb8a16e12008-09-09 09:36:50 -070064{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070065 while (1) {
66 /* Barrier here prevents excessive spinning */
67 mb();
68 if (readl_relaxed(addr) == value)
Brian Swetlandb8a16e12008-09-09 09:36:50 -070069 return 0;
70
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070071 if (smsm_check_for_modem_crash())
72 return -EAGAIN;
73
74 udelay(5);
Brian Swetlandb8a16e12008-09-09 09:36:50 -070075 }
76}
77
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070078void 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
85again:
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}
101EXPORT_SYMBOL(msm_proc_comm_reset_modem_now);
102
Brian Swetlandb8a16e12008-09-09 09:36:50 -0700103int msm_proc_comm(unsigned cmd, unsigned *data1, unsigned *data2)
104{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700105 unsigned base = (unsigned)MSM_SHARED_RAM_BASE;
Brian Swetlandb8a16e12008-09-09 09:36:50 -0700106 unsigned long flags;
107 int ret;
108
109 spin_lock_irqsave(&proc_comm_lock, flags);
110
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700111 if (msm_proc_comm_disable) {
112 ret = -EIO;
113 goto end;
Brian Swetlandb8a16e12008-09-09 09:36:50 -0700114 }
115
Brian Swetlandb8a16e12008-09-09 09:36:50 -0700116
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700117again:
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 }
152end:
153 /* Make sure the writes complete before returning */
154 wmb();
Brian Swetlandb8a16e12008-09-09 09:36:50 -0700155 spin_unlock_irqrestore(&proc_comm_lock, flags);
Brian Swetlandb8a16e12008-09-09 09:36:50 -0700156 return ret;
157}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700158EXPORT_SYMBOL(msm_proc_comm);