blob: 07a924119a8f1462832376ceb2b3f1e6d8faa6ab [file] [log] [blame]
Ankur Nandwanie258cf02011-08-19 10:16:38 -07001/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
2 *
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
38static void *riva_ramdump_dev;
39static int riva_crash;
40static int ss_restart_inprogress;
Sameer Thalappil74743382011-11-10 16:38:58 -080041static int enable_riva_ssr;
Ankur Nandwanie258cf02011-08-19 10:16:38 -070042
43static void riva_smsm_cb_fn(struct work_struct *work)
44{
Sameer Thalappil74743382011-11-10 16:38:58 -080045 if (!enable_riva_ssr)
46 panic(MODULE_NAME ": SMSM reset request received from Riva");
47 else
48 subsystem_restart("riva");
Ankur Nandwanie258cf02011-08-19 10:16:38 -070049}
50
51static void smsm_state_cb_hdlr(void *data, uint32_t old_state,
52 uint32_t new_state)
53{
54 riva_crash = true;
55 pr_err("%s: smsm state changed to smsm reset\n", MODULE_NAME);
56
57 if (ss_restart_inprogress) {
58 pr_err("%s: Ignoring smsm reset req, restart in progress\n",
59 MODULE_NAME);
60 return;
61 }
Sameer Thalappild87cf662011-12-12 13:37:31 -080062 if (new_state & SMSM_RESET) {
63 ss_restart_inprogress = true;
Ankur Nandwanie258cf02011-08-19 10:16:38 -070064 schedule_work(&riva_smsm_cb_work);
Sameer Thalappild87cf662011-12-12 13:37:31 -080065 }
Ankur Nandwanie258cf02011-08-19 10:16:38 -070066}
67
68static void riva_fatal_fn(struct work_struct *work)
69{
Sameer Thalappild87cf662011-12-12 13:37:31 -080070 if (!enable_riva_ssr)
Sameer Thalappil1806ae12011-10-20 12:45:41 -070071 panic(MODULE_NAME ": Watchdog bite received from Riva");
Sameer Thalappild87cf662011-12-12 13:37:31 -080072 else
73 subsystem_restart("riva");
74}
75
76static irqreturn_t riva_wdog_bite_irq_hdlr(int irq, void *dev_id)
77{
78 int ret;
79
80 if (ss_restart_inprogress) {
81 pr_err("%s: Ignoring riva bite irq, restart in progress\n",
82 MODULE_NAME);
83 return IRQ_HANDLED;
84 }
85 disable_irq_nosync(RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ);
86 ss_restart_inprogress = true;
87 ret = schedule_work(&riva_fatal_work);
88 return IRQ_HANDLED;
Ankur Nandwanie258cf02011-08-19 10:16:38 -070089}
90
Ankur Nandwanie258cf02011-08-19 10:16:38 -070091/* SMSM reset Riva */
92static void smsm_riva_reset(void)
93{
94 /* per SS reset request bit is not available now,
95 * all SS host modules are setting this bit
96 * This is still under discussion*/
97 smsm_change_state(SMSM_APPS_STATE, SMSM_RESET, SMSM_RESET);
98}
99
100/* Subsystem handlers */
101static int riva_shutdown(const struct subsys_data *subsys)
102{
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();
105 int ret = -1;
106
Sameer Thalappil74743382011-11-10 16:38:58 -0800107 pil_force_shutdown("wcnss");
Sameer Thalappil409ed352011-12-07 10:53:31 -0800108
109 /* proxy vote on behalf of Riva */
110 if (pdev && pwlanconfig)
111 ret = wcnss_wlan_power(&pdev->dev, pwlanconfig,
112 WCNSS_WLAN_SWITCH_OFF);
113 return ret;
Ankur Nandwanie258cf02011-08-19 10:16:38 -0700114}
115
116static int riva_powerup(const struct subsys_data *subsys)
117{
Sameer Thalappil409ed352011-12-07 10:53:31 -0800118 struct platform_device *pdev = wcnss_get_platform_device();
119 struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
120 int ret = -1;
121
122 if (pdev && pwlanconfig)
123 ret = wcnss_wlan_power(&pdev->dev, pwlanconfig,
124 WCNSS_WLAN_SWITCH_ON);
125 if (!ret)
126 pil_force_boot("wcnss");
127
Sameer Thalappild87cf662011-12-12 13:37:31 -0800128 ss_restart_inprogress = false;
129 enable_irq(RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ);
130
Sameer Thalappil409ed352011-12-07 10:53:31 -0800131 return ret;
Ankur Nandwanie258cf02011-08-19 10:16:38 -0700132}
133
134/* RAM segments for Riva SS;
135 * We don't specify the full 5MB allocated for Riva. Only 3MB is specified */
136static struct ramdump_segment riva_segments[] = {{0x8f200000,
137 0x8f500000 - 0x8f200000} };
138
139static int riva_ramdump(int enable, const struct subsys_data *subsys)
140{
141 pr_debug("%s: enable[%d]\n", MODULE_NAME, enable);
142 if (enable)
143 return do_ramdump(riva_ramdump_dev,
144 riva_segments,
145 ARRAY_SIZE(riva_segments));
146 else
147 return 0;
148}
149
150/* Riva crash handler */
151static void riva_crash_shutdown(const struct subsys_data *subsys)
152{
Ankur Nandwanie258cf02011-08-19 10:16:38 -0700153 pr_err("%s: crash shutdown : %d\n", MODULE_NAME, riva_crash);
154 if (riva_crash != true)
155 smsm_riva_reset();
156}
157
158static struct subsys_data riva_8960 = {
159 .name = "riva",
160 .shutdown = riva_shutdown,
161 .powerup = riva_powerup,
162 .ramdump = riva_ramdump,
163 .crash_shutdown = riva_crash_shutdown
164};
165
Sameer Thalappil74743382011-11-10 16:38:58 -0800166static int enable_riva_ssr_set(const char *val, struct kernel_param *kp)
167{
168 int ret;
169
170 ret = param_set_int(val, kp);
171 if (ret)
172 return ret;
173
174 if (enable_riva_ssr)
175 pr_info(MODULE_NAME ": Subsystem restart activated for riva.\n");
176
177 return 0;
178}
179
180module_param_call(enable_riva_ssr, enable_riva_ssr_set, param_get_int,
181 &enable_riva_ssr, S_IRUGO | S_IWUSR);
182
Ankur Nandwanie258cf02011-08-19 10:16:38 -0700183static int __init riva_restart_init(void)
184{
185 return ssr_register_subsystem(&riva_8960);
186}
187
188static int __init riva_ssr_module_init(void)
189{
190 int ret;
191
192 ret = smsm_state_cb_register(SMSM_WCNSS_STATE, SMSM_RESET,
193 smsm_state_cb_hdlr, 0);
194 if (ret < 0) {
195 pr_err("%s: Unable to register smsm callback for Riva Reset!"
196 " (%d)\n", MODULE_NAME, ret);
197 goto out;
198 }
Sameer Thalappild87cf662011-12-12 13:37:31 -0800199 ret = request_irq(RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ,
200 riva_wdog_bite_irq_hdlr, IRQF_TRIGGER_HIGH,
201 "riva_wdog", NULL);
202
203 if (ret < 0) {
204 pr_err("%s: Unable to register for Riva bite interrupt"
205 " (%d)\n", MODULE_NAME, ret);
206 goto out;
207 }
Ankur Nandwanie258cf02011-08-19 10:16:38 -0700208 ret = riva_restart_init();
209 if (ret < 0) {
210 pr_err("%s: Unable to register with ssr. (%d)\n",
211 MODULE_NAME, ret);
212 goto out;
213 }
214 riva_ramdump_dev = create_ramdump_device("riva");
215 if (!riva_ramdump_dev) {
216 pr_err("%s: Unable to create ramdump device.\n",
217 MODULE_NAME);
218 ret = -ENOMEM;
219 goto out;
220 }
221 pr_info("%s: module initialized\n", MODULE_NAME);
222out:
223 return ret;
224}
225
226static void __exit riva_ssr_module_exit(void)
227{
228 free_irq(RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ, NULL);
229}
230
231module_init(riva_ssr_module_init);
232module_exit(riva_ssr_module_exit);
233
234MODULE_LICENSE("GPL v2");