blob: 90948ea9f0b3939ba0019ee6402c61fe2d062299 [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>
Ankur Nandwanie258cf02011-08-19 10:16:38 -070022#include <mach/irqs.h>
23#include <mach/scm.h>
24#include <mach/subsystem_restart.h>
25#include <mach/subsystem_notif.h>
Sameer Thalappil74743382011-11-10 16:38:58 -080026#include <mach/peripheral-loader.h>
Ankur Nandwanie258cf02011-08-19 10:16:38 -070027#include "smd_private.h"
28#include "ramdump.h"
29
30#define MODULE_NAME "wcnss_8960"
31
32static void riva_smsm_cb_fn(struct work_struct *);
33static DECLARE_WORK(riva_smsm_cb_work, riva_smsm_cb_fn);
34
35static void riva_fatal_fn(struct work_struct *);
36static DECLARE_WORK(riva_fatal_work, riva_fatal_fn);
37
Sameer Thalappil74ce6d02012-02-22 07:24:51 -080038static struct delayed_work cancel_vote_work;
Ankur Nandwanie258cf02011-08-19 10:16:38 -070039static void *riva_ramdump_dev;
40static int riva_crash;
41static int ss_restart_inprogress;
Sameer Thalappil74743382011-11-10 16:38:58 -080042static int enable_riva_ssr;
Ankur Nandwanie258cf02011-08-19 10:16:38 -070043
44static void riva_smsm_cb_fn(struct work_struct *work)
45{
Sameer Thalappil74743382011-11-10 16:38:58 -080046 if (!enable_riva_ssr)
47 panic(MODULE_NAME ": SMSM reset request received from Riva");
48 else
49 subsystem_restart("riva");
Ankur Nandwanie258cf02011-08-19 10:16:38 -070050}
51
52static void smsm_state_cb_hdlr(void *data, uint32_t old_state,
53 uint32_t new_state)
54{
Eric Holmberg6866cb72012-03-05 15:29:44 -070055 if (!(new_state & SMSM_RESET))
56 return;
57
Ankur Nandwanie258cf02011-08-19 10:16:38 -070058 riva_crash = true;
59 pr_err("%s: smsm state changed to smsm reset\n", MODULE_NAME);
60
61 if (ss_restart_inprogress) {
62 pr_err("%s: Ignoring smsm reset req, restart in progress\n",
63 MODULE_NAME);
64 return;
65 }
Eric Holmberg6866cb72012-03-05 15:29:44 -070066 ss_restart_inprogress = true;
67 schedule_work(&riva_smsm_cb_work);
Ankur Nandwanie258cf02011-08-19 10:16:38 -070068}
69
70static void riva_fatal_fn(struct work_struct *work)
71{
Sameer Thalappild87cf662011-12-12 13:37:31 -080072 if (!enable_riva_ssr)
Sameer Thalappil1806ae12011-10-20 12:45:41 -070073 panic(MODULE_NAME ": Watchdog bite received from Riva");
Sameer Thalappild87cf662011-12-12 13:37:31 -080074 else
75 subsystem_restart("riva");
76}
77
78static irqreturn_t riva_wdog_bite_irq_hdlr(int irq, void *dev_id)
79{
80 int ret;
81
82 if (ss_restart_inprogress) {
83 pr_err("%s: Ignoring riva bite irq, restart in progress\n",
84 MODULE_NAME);
85 return IRQ_HANDLED;
86 }
Sameer Thalappild87cf662011-12-12 13:37:31 -080087 ss_restart_inprogress = true;
88 ret = schedule_work(&riva_fatal_work);
89 return IRQ_HANDLED;
Ankur Nandwanie258cf02011-08-19 10:16:38 -070090}
91
Ankur Nandwanie258cf02011-08-19 10:16:38 -070092/* SMSM reset Riva */
93static void smsm_riva_reset(void)
94{
95 /* per SS reset request bit is not available now,
96 * all SS host modules are setting this bit
97 * This is still under discussion*/
98 smsm_change_state(SMSM_APPS_STATE, SMSM_RESET, SMSM_RESET);
99}
100
Sameer Thalappil74ce6d02012-02-22 07:24:51 -0800101static void riva_post_bootup(struct work_struct *work)
Ankur Nandwanie258cf02011-08-19 10:16:38 -0700102{
Sameer Thalappil409ed352011-12-07 10:53:31 -0800103 struct platform_device *pdev = wcnss_get_platform_device();
104 struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
Sameer Thalappil409ed352011-12-07 10:53:31 -0800105
Sameer Thalappil74ce6d02012-02-22 07:24:51 -0800106 pr_debug(MODULE_NAME ": Cancel APPS vote for Iris & Riva\n");
107
108 wcnss_wlan_power(&pdev->dev, pwlanconfig,
109 WCNSS_WLAN_SWITCH_OFF);
110}
111
112/* Subsystem handlers */
113static int riva_shutdown(const struct subsys_data *subsys)
114{
Sameer Thalappil74743382011-11-10 16:38:58 -0800115 pil_force_shutdown("wcnss");
Sameer Thalappil74ce6d02012-02-22 07:24:51 -0800116 flush_delayed_work(&cancel_vote_work);
Sameer Thalappil27d3f532012-03-21 15:02:17 -0700117 disable_irq_nosync(RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ);
Sameer Thalappil409ed352011-12-07 10:53:31 -0800118
Sameer Thalappil74ce6d02012-02-22 07:24:51 -0800119 return 0;
Ankur Nandwanie258cf02011-08-19 10:16:38 -0700120}
121
122static int riva_powerup(const struct subsys_data *subsys)
123{
Sameer Thalappil409ed352011-12-07 10:53:31 -0800124 struct platform_device *pdev = wcnss_get_platform_device();
125 struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
126 int ret = -1;
127
128 if (pdev && pwlanconfig)
129 ret = wcnss_wlan_power(&pdev->dev, pwlanconfig,
130 WCNSS_WLAN_SWITCH_ON);
Sameer Thalappil6e727d22012-02-14 19:37:54 -0800131 /* delay PIL operation, this SSR may be happening soon after kernel
132 * resumes because of a SMSM RESET by Riva when APPS was suspended.
133 * PIL fails to locate the images without this delay */
134 if (!ret) {
135 msleep(1000);
Sameer Thalappil409ed352011-12-07 10:53:31 -0800136 pil_force_boot("wcnss");
Sameer Thalappil6e727d22012-02-14 19:37:54 -0800137 }
Sameer Thalappild87cf662011-12-12 13:37:31 -0800138 ss_restart_inprogress = false;
139 enable_irq(RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ);
Sameer Thalappil74ce6d02012-02-22 07:24:51 -0800140 schedule_delayed_work(&cancel_vote_work, msecs_to_jiffies(5000));
Sameer Thalappild87cf662011-12-12 13:37:31 -0800141
Sameer Thalappil409ed352011-12-07 10:53:31 -0800142 return ret;
Ankur Nandwanie258cf02011-08-19 10:16:38 -0700143}
144
145/* RAM segments for Riva SS;
146 * We don't specify the full 5MB allocated for Riva. Only 3MB is specified */
147static struct ramdump_segment riva_segments[] = {{0x8f200000,
148 0x8f500000 - 0x8f200000} };
149
150static int riva_ramdump(int enable, const struct subsys_data *subsys)
151{
152 pr_debug("%s: enable[%d]\n", MODULE_NAME, enable);
153 if (enable)
154 return do_ramdump(riva_ramdump_dev,
155 riva_segments,
156 ARRAY_SIZE(riva_segments));
157 else
158 return 0;
159}
160
161/* Riva crash handler */
162static void riva_crash_shutdown(const struct subsys_data *subsys)
163{
Ankur Nandwanie258cf02011-08-19 10:16:38 -0700164 pr_err("%s: crash shutdown : %d\n", MODULE_NAME, riva_crash);
165 if (riva_crash != true)
166 smsm_riva_reset();
167}
168
169static struct subsys_data riva_8960 = {
170 .name = "riva",
171 .shutdown = riva_shutdown,
172 .powerup = riva_powerup,
173 .ramdump = riva_ramdump,
174 .crash_shutdown = riva_crash_shutdown
175};
176
Sameer Thalappil74743382011-11-10 16:38:58 -0800177static int enable_riva_ssr_set(const char *val, struct kernel_param *kp)
178{
179 int ret;
180
181 ret = param_set_int(val, kp);
182 if (ret)
183 return ret;
184
185 if (enable_riva_ssr)
186 pr_info(MODULE_NAME ": Subsystem restart activated for riva.\n");
187
188 return 0;
189}
190
191module_param_call(enable_riva_ssr, enable_riva_ssr_set, param_get_int,
192 &enable_riva_ssr, S_IRUGO | S_IWUSR);
193
Ankur Nandwanie258cf02011-08-19 10:16:38 -0700194static int __init riva_restart_init(void)
195{
196 return ssr_register_subsystem(&riva_8960);
197}
198
199static int __init riva_ssr_module_init(void)
200{
201 int ret;
202
203 ret = smsm_state_cb_register(SMSM_WCNSS_STATE, SMSM_RESET,
204 smsm_state_cb_hdlr, 0);
205 if (ret < 0) {
206 pr_err("%s: Unable to register smsm callback for Riva Reset!"
207 " (%d)\n", MODULE_NAME, ret);
208 goto out;
209 }
Sameer Thalappild87cf662011-12-12 13:37:31 -0800210 ret = request_irq(RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ,
211 riva_wdog_bite_irq_hdlr, IRQF_TRIGGER_HIGH,
212 "riva_wdog", NULL);
213
214 if (ret < 0) {
215 pr_err("%s: Unable to register for Riva bite interrupt"
216 " (%d)\n", MODULE_NAME, ret);
217 goto out;
218 }
Ankur Nandwanie258cf02011-08-19 10:16:38 -0700219 ret = riva_restart_init();
220 if (ret < 0) {
221 pr_err("%s: Unable to register with ssr. (%d)\n",
222 MODULE_NAME, ret);
223 goto out;
224 }
225 riva_ramdump_dev = create_ramdump_device("riva");
226 if (!riva_ramdump_dev) {
227 pr_err("%s: Unable to create ramdump device.\n",
228 MODULE_NAME);
229 ret = -ENOMEM;
230 goto out;
231 }
Sameer Thalappil74ce6d02012-02-22 07:24:51 -0800232 INIT_DELAYED_WORK(&cancel_vote_work, riva_post_bootup);
233
Ankur Nandwanie258cf02011-08-19 10:16:38 -0700234 pr_info("%s: module initialized\n", MODULE_NAME);
235out:
236 return ret;
237}
238
239static void __exit riva_ssr_module_exit(void)
240{
241 free_irq(RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ, NULL);
242}
243
244module_init(riva_ssr_module_init);
245module_exit(riva_ssr_module_exit);
246
247MODULE_LICENSE("GPL v2");