blob: 7e4bdb9827a5ec3f5191cecb2d3644ccee40943d [file] [log] [blame]
Sameer Thalappil74ce6d02012-02-22 07:24:51 -08001/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Ankur Nandwanie258cf02011-08-19 10:16:38 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/kernel.h>
14#include <linux/interrupt.h>
15#include <linux/reboot.h>
16#include <linux/workqueue.h>
17#include <linux/io.h>
18#include <linux/delay.h>
19#include <linux/module.h>
Sameer Thalappil409ed352011-12-07 10:53:31 -080020#include <linux/platform_device.h>
21#include <linux/wcnss_wlan.h>
Stephen Boyd0ebf7212012-04-30 20:42:35 -070022#include <linux/err.h>
Ankur Nandwanie258cf02011-08-19 10:16:38 -070023#include <mach/irqs.h>
24#include <mach/scm.h>
25#include <mach/subsystem_restart.h>
26#include <mach/subsystem_notif.h>
Sameer Thalappil74743382011-11-10 16:38:58 -080027#include <mach/peripheral-loader.h>
Ankur Nandwanie258cf02011-08-19 10:16:38 -070028#include "smd_private.h"
29#include "ramdump.h"
30
31#define MODULE_NAME "wcnss_8960"
Sunny Kapdic6e42882012-05-30 12:24:48 -070032#define MAX_BUF_SIZE 0x51
Ankur Nandwanie258cf02011-08-19 10:16:38 -070033
Mekala Natarajanf3d7cba2012-09-27 22:18:55 -070034static void __iomem *msm_riva_base;
35#define MSM_RIVA_PHYS 0x03204000
36#define RIVA_SSR_OUT (msm_riva_base + 0x0b4)
37#define RIVA_SSR_BIT BIT(23)
Ankur Nandwanie258cf02011-08-19 10:16:38 -070038
Ankur Nandwanie258cf02011-08-19 10:16:38 -070039
Sameer Thalappil74ce6d02012-02-22 07:24:51 -080040static struct delayed_work cancel_vote_work;
Ankur Nandwanie258cf02011-08-19 10:16:38 -070041static void *riva_ramdump_dev;
42static int riva_crash;
43static int ss_restart_inprogress;
Sameer Thalappil74743382011-11-10 16:38:58 -080044static int enable_riva_ssr;
Stephen Boyd0ebf7212012-04-30 20:42:35 -070045static struct subsys_device *riva_8960_dev;
Ankur Nandwanie258cf02011-08-19 10:16:38 -070046
Ankur Nandwanie258cf02011-08-19 10:16:38 -070047static void smsm_state_cb_hdlr(void *data, uint32_t old_state,
48 uint32_t new_state)
49{
Sunny Kapdic6e42882012-05-30 12:24:48 -070050 char *smem_reset_reason;
51 char buffer[MAX_BUF_SIZE];
52 unsigned smem_reset_size;
53 unsigned size;
54
Sameer Thalappil50d62902012-06-15 16:05:51 -070055 riva_crash = true;
56
57 pr_err("%s: smsm state changed\n", MODULE_NAME);
58
Eric Holmberg6866cb72012-03-05 15:29:44 -070059 if (!(new_state & SMSM_RESET))
60 return;
61
Ankur Nandwanie258cf02011-08-19 10:16:38 -070062 if (ss_restart_inprogress) {
63 pr_err("%s: Ignoring smsm reset req, restart in progress\n",
64 MODULE_NAME);
65 return;
66 }
Ankur Nandwanie258cf02011-08-19 10:16:38 -070067
Sameer Thalappild87cf662011-12-12 13:37:31 -080068 if (!enable_riva_ssr)
Sameer Thalappil50d62902012-06-15 16:05:51 -070069 panic(MODULE_NAME ": SMSM reset request received from Riva");
70
71 smem_reset_reason = smem_get_entry(SMEM_SSR_REASON_WCNSS0,
72 &smem_reset_size);
73
74 if (!smem_reset_reason || !smem_reset_size) {
75 pr_err("%s: wcnss subsystem failure reason: %s\n",
76 __func__, "(unknown, smem_get_entry failed)");
77 } else if (!smem_reset_reason[0]) {
78 pr_err("%s: wcnss subsystem failure reason: %s\n",
79 __func__, "(unknown, init string found)");
80 } else {
81 size = smem_reset_size < MAX_BUF_SIZE ? smem_reset_size :
82 (MAX_BUF_SIZE - 1);
83 memcpy(buffer, smem_reset_reason, size);
84 buffer[size] = '\0';
85 pr_err("%s: wcnss subsystem failure reason: %s\n",
86 __func__, buffer);
87 memset(smem_reset_reason, 0, smem_reset_size);
88 wmb();
89 }
90
91 ss_restart_inprogress = true;
Stephen Boyd0ebf7212012-04-30 20:42:35 -070092 subsystem_restart_dev(riva_8960_dev);
Sameer Thalappild87cf662011-12-12 13:37:31 -080093}
94
95static irqreturn_t riva_wdog_bite_irq_hdlr(int irq, void *dev_id)
96{
Sameer Thalappil50d62902012-06-15 16:05:51 -070097 riva_crash = true;
Sameer Thalappild87cf662011-12-12 13:37:31 -080098
99 if (ss_restart_inprogress) {
100 pr_err("%s: Ignoring riva bite irq, restart in progress\n",
101 MODULE_NAME);
102 return IRQ_HANDLED;
103 }
Sameer Thalappil50d62902012-06-15 16:05:51 -0700104
105 if (!enable_riva_ssr)
106 panic(MODULE_NAME ": Watchdog bite received from Riva");
107
Sameer Thalappild87cf662011-12-12 13:37:31 -0800108 ss_restart_inprogress = true;
Stephen Boyd0ebf7212012-04-30 20:42:35 -0700109 subsystem_restart_dev(riva_8960_dev);
Sameer Thalappil50d62902012-06-15 16:05:51 -0700110
Sameer Thalappild87cf662011-12-12 13:37:31 -0800111 return IRQ_HANDLED;
Ankur Nandwanie258cf02011-08-19 10:16:38 -0700112}
113
Ankur Nandwanie258cf02011-08-19 10:16:38 -0700114/* SMSM reset Riva */
115static void smsm_riva_reset(void)
116{
117 /* per SS reset request bit is not available now,
118 * all SS host modules are setting this bit
119 * This is still under discussion*/
120 smsm_change_state(SMSM_APPS_STATE, SMSM_RESET, SMSM_RESET);
121}
122
Sameer Thalappil74ce6d02012-02-22 07:24:51 -0800123static void riva_post_bootup(struct work_struct *work)
Ankur Nandwanie258cf02011-08-19 10:16:38 -0700124{
Sameer Thalappil409ed352011-12-07 10:53:31 -0800125 struct platform_device *pdev = wcnss_get_platform_device();
126 struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
Sameer Thalappil409ed352011-12-07 10:53:31 -0800127
Sameer Thalappil74ce6d02012-02-22 07:24:51 -0800128 pr_debug(MODULE_NAME ": Cancel APPS vote for Iris & Riva\n");
129
130 wcnss_wlan_power(&pdev->dev, pwlanconfig,
131 WCNSS_WLAN_SWITCH_OFF);
132}
133
134/* Subsystem handlers */
Stephen Boyd0ebf7212012-04-30 20:42:35 -0700135static int riva_shutdown(const struct subsys_desc *subsys)
Sameer Thalappil74ce6d02012-02-22 07:24:51 -0800136{
Sameer Thalappil74743382011-11-10 16:38:58 -0800137 pil_force_shutdown("wcnss");
Sameer Thalappil74ce6d02012-02-22 07:24:51 -0800138 flush_delayed_work(&cancel_vote_work);
Sameer Thalappil13f45182012-07-23 18:02:45 -0700139 wcnss_flush_delayed_boot_votes();
Sameer Thalappil27d3f532012-03-21 15:02:17 -0700140 disable_irq_nosync(RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ);
Sameer Thalappil409ed352011-12-07 10:53:31 -0800141
Sameer Thalappil74ce6d02012-02-22 07:24:51 -0800142 return 0;
Ankur Nandwanie258cf02011-08-19 10:16:38 -0700143}
144
Stephen Boyd0ebf7212012-04-30 20:42:35 -0700145static int riva_powerup(const struct subsys_desc *subsys)
Ankur Nandwanie258cf02011-08-19 10:16:38 -0700146{
Sameer Thalappil409ed352011-12-07 10:53:31 -0800147 struct platform_device *pdev = wcnss_get_platform_device();
148 struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
149 int ret = -1;
Mekala Natarajanf3d7cba2012-09-27 22:18:55 -0700150 u32 reg = 0;
Sameer Thalappil409ed352011-12-07 10:53:31 -0800151
Mekala Natarajanf3d7cba2012-09-27 22:18:55 -0700152 msm_riva_base = ioremap(MSM_RIVA_PHYS, SZ_256);
153 if (!msm_riva_base) {
154 pr_err("ioremap MSM_RIVA_PHYS failed\n");
155 goto poweron;
156 }
157
158 reg = readl_relaxed(RIVA_SSR_OUT);
159 reg |= RIVA_SSR_BIT;
160 writel_relaxed(reg, RIVA_SSR_OUT);
161 iounmap(msm_riva_base);
162
163poweron:
Sameer Thalappil409ed352011-12-07 10:53:31 -0800164 if (pdev && pwlanconfig)
165 ret = wcnss_wlan_power(&pdev->dev, pwlanconfig,
166 WCNSS_WLAN_SWITCH_ON);
Sameer Thalappil6e727d22012-02-14 19:37:54 -0800167 /* delay PIL operation, this SSR may be happening soon after kernel
168 * resumes because of a SMSM RESET by Riva when APPS was suspended.
169 * PIL fails to locate the images without this delay */
170 if (!ret) {
171 msleep(1000);
Sameer Thalappil409ed352011-12-07 10:53:31 -0800172 pil_force_boot("wcnss");
Sameer Thalappil6e727d22012-02-14 19:37:54 -0800173 }
Sameer Thalappild87cf662011-12-12 13:37:31 -0800174 ss_restart_inprogress = false;
175 enable_irq(RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ);
Sameer Thalappil74ce6d02012-02-22 07:24:51 -0800176 schedule_delayed_work(&cancel_vote_work, msecs_to_jiffies(5000));
Sameer Thalappild87cf662011-12-12 13:37:31 -0800177
Sameer Thalappil409ed352011-12-07 10:53:31 -0800178 return ret;
Ankur Nandwanie258cf02011-08-19 10:16:38 -0700179}
180
Jeff Johnson5398d2b2012-10-11 12:09:12 -0700181/* 7MB RAM segments for Riva SS;
182 * Riva 1.1 0x8f000000 - 0x8f700000
183 * Riva 1.0 0x8f200000 - 0x8f700000
184 */
185static struct ramdump_segment riva_segments[] = {{0x8f000000,
186 0x8f700000 - 0x8f000000} };
Ankur Nandwanie258cf02011-08-19 10:16:38 -0700187
Stephen Boyd0ebf7212012-04-30 20:42:35 -0700188static int riva_ramdump(int enable, const struct subsys_desc *subsys)
Ankur Nandwanie258cf02011-08-19 10:16:38 -0700189{
190 pr_debug("%s: enable[%d]\n", MODULE_NAME, enable);
191 if (enable)
192 return do_ramdump(riva_ramdump_dev,
193 riva_segments,
194 ARRAY_SIZE(riva_segments));
195 else
196 return 0;
197}
198
199/* Riva crash handler */
Stephen Boyd0ebf7212012-04-30 20:42:35 -0700200static void riva_crash_shutdown(const struct subsys_desc *subsys)
Ankur Nandwanie258cf02011-08-19 10:16:38 -0700201{
Ankur Nandwanie258cf02011-08-19 10:16:38 -0700202 pr_err("%s: crash shutdown : %d\n", MODULE_NAME, riva_crash);
Sameer Thalappila0c30ae2012-08-13 11:13:06 -0700203 if (riva_crash != true) {
Ankur Nandwanie258cf02011-08-19 10:16:38 -0700204 smsm_riva_reset();
Sameer Thalappila0c30ae2012-08-13 11:13:06 -0700205 /* give sufficient time for wcnss to finish it's error
206 * fatal routine */
Jaeseong GIM393bd8e2012-09-17 17:24:15 +0900207 mdelay(3000);
Sameer Thalappila0c30ae2012-08-13 11:13:06 -0700208 }
209
Ankur Nandwanie258cf02011-08-19 10:16:38 -0700210}
211
Stephen Boyd0ebf7212012-04-30 20:42:35 -0700212static struct subsys_desc riva_8960 = {
Ankur Nandwanie258cf02011-08-19 10:16:38 -0700213 .name = "riva",
214 .shutdown = riva_shutdown,
215 .powerup = riva_powerup,
216 .ramdump = riva_ramdump,
217 .crash_shutdown = riva_crash_shutdown
218};
219
Sameer Thalappil74743382011-11-10 16:38:58 -0800220static int enable_riva_ssr_set(const char *val, struct kernel_param *kp)
221{
222 int ret;
223
224 ret = param_set_int(val, kp);
225 if (ret)
226 return ret;
227
228 if (enable_riva_ssr)
229 pr_info(MODULE_NAME ": Subsystem restart activated for riva.\n");
230
231 return 0;
232}
233
234module_param_call(enable_riva_ssr, enable_riva_ssr_set, param_get_int,
235 &enable_riva_ssr, S_IRUGO | S_IWUSR);
236
Ankur Nandwanie258cf02011-08-19 10:16:38 -0700237static int __init riva_restart_init(void)
238{
Stephen Boyd0ebf7212012-04-30 20:42:35 -0700239 riva_8960_dev = subsys_register(&riva_8960);
240 if (IS_ERR(riva_8960_dev))
241 return PTR_ERR(riva_8960_dev);
242 return 0;
Ankur Nandwanie258cf02011-08-19 10:16:38 -0700243}
244
245static int __init riva_ssr_module_init(void)
246{
247 int ret;
248
249 ret = smsm_state_cb_register(SMSM_WCNSS_STATE, SMSM_RESET,
250 smsm_state_cb_hdlr, 0);
251 if (ret < 0) {
Sameer Thalappil50d62902012-06-15 16:05:51 -0700252 pr_err("%s: Unable to register smsm callback for Riva Reset! %d\n",
253 MODULE_NAME, ret);
Ankur Nandwanie258cf02011-08-19 10:16:38 -0700254 goto out;
255 }
Sameer Thalappild87cf662011-12-12 13:37:31 -0800256 ret = request_irq(RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ,
257 riva_wdog_bite_irq_hdlr, IRQF_TRIGGER_HIGH,
258 "riva_wdog", NULL);
259
260 if (ret < 0) {
Sameer Thalappil50d62902012-06-15 16:05:51 -0700261 pr_err("%s: Unable to register for Riva bite interrupt (%d)\n",
262 MODULE_NAME, ret);
Sameer Thalappild87cf662011-12-12 13:37:31 -0800263 goto out;
264 }
Ankur Nandwanie258cf02011-08-19 10:16:38 -0700265 ret = riva_restart_init();
266 if (ret < 0) {
267 pr_err("%s: Unable to register with ssr. (%d)\n",
268 MODULE_NAME, ret);
269 goto out;
270 }
271 riva_ramdump_dev = create_ramdump_device("riva");
272 if (!riva_ramdump_dev) {
273 pr_err("%s: Unable to create ramdump device.\n",
274 MODULE_NAME);
275 ret = -ENOMEM;
276 goto out;
277 }
Sameer Thalappil74ce6d02012-02-22 07:24:51 -0800278 INIT_DELAYED_WORK(&cancel_vote_work, riva_post_bootup);
279
Ankur Nandwanie258cf02011-08-19 10:16:38 -0700280 pr_info("%s: module initialized\n", MODULE_NAME);
281out:
282 return ret;
283}
284
285static void __exit riva_ssr_module_exit(void)
286{
Stephen Boyd0ebf7212012-04-30 20:42:35 -0700287 subsys_unregister(riva_8960_dev);
Ankur Nandwanie258cf02011-08-19 10:16:38 -0700288 free_irq(RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ, NULL);
289}
290
291module_init(riva_ssr_module_init);
292module_exit(riva_ssr_module_exit);
293
294MODULE_LICENSE("GPL v2");