blob: d72b848a3fe5d94b4618aa42c855f01070120ea5 [file] [log] [blame]
Seemanta Dutta4e2d49c2013-04-05 16:28:11 -07001/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
Stephen Boyd322a9922011-09-20 01:05:54 -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/err.h>
15#include <linux/io.h>
Stephen Boyd322a9922011-09-20 01:05:54 -070016#include <linux/delay.h>
17#include <linux/module.h>
18#include <linux/slab.h>
19#include <linux/platform_device.h>
Stephen Boyd3bbdf6c2011-12-21 16:02:26 -080020#include <linux/regulator/consumer.h>
Stephen Boyd86f2e652012-01-11 18:25:44 -080021#include <linux/clk.h>
Stephen Boydfdec00d2012-05-10 17:04:49 -070022#include <linux/interrupt.h>
23#include <linux/wcnss_wlan.h>
Stephen Boyd322a9922011-09-20 01:05:54 -070024
Stephen Boydfdec00d2012-05-10 17:04:49 -070025#include <mach/subsystem_restart.h>
Seemanta Dutta4e2d49c2013-04-05 16:28:11 -070026#include <mach/ramdump.h>
Stephen Boyd322a9922011-09-20 01:05:54 -070027
28#include "peripheral-loader.h"
29#include "scm-pas.h"
Stephen Boydfdec00d2012-05-10 17:04:49 -070030#include "smd_private.h"
Stephen Boyd322a9922011-09-20 01:05:54 -070031
32#define RIVA_PMU_A2XB_CFG 0xB8
33#define RIVA_PMU_A2XB_CFG_EN BIT(0)
34
35#define RIVA_PMU_CFG 0x28
36#define RIVA_PMU_CFG_WARM_BOOT BIT(0)
37#define RIVA_PMU_CFG_IRIS_XO_MODE 0x6
38#define RIVA_PMU_CFG_IRIS_XO_MODE_48 (3 << 1)
39
Stephen Boyd12332572011-12-06 16:00:51 -080040#define RIVA_PMU_OVRD_EN 0x2C
41#define RIVA_PMU_OVRD_EN_CCPU_RESET BIT(0)
42#define RIVA_PMU_OVRD_EN_CCPU_CLK BIT(1)
43
Stephen Boyd322a9922011-09-20 01:05:54 -070044#define RIVA_PMU_OVRD_VAL 0x30
45#define RIVA_PMU_OVRD_VAL_CCPU_RESET BIT(0)
46#define RIVA_PMU_OVRD_VAL_CCPU_CLK BIT(1)
47
48#define RIVA_PMU_CCPU_CTL 0x9C
49#define RIVA_PMU_CCPU_CTL_HIGH_IVT BIT(0)
50#define RIVA_PMU_CCPU_CTL_REMAP_EN BIT(2)
51
52#define RIVA_PMU_CCPU_BOOT_REMAP_ADDR 0xA0
53
Stephen Boyde24edf52012-07-12 17:46:19 -070054#define RIVA_PLL_MODE 0x31A0
Stephen Boyd322a9922011-09-20 01:05:54 -070055#define PLL_MODE_OUTCTRL BIT(0)
56#define PLL_MODE_BYPASSNL BIT(1)
57#define PLL_MODE_RESET_N BIT(2)
58#define PLL_MODE_REF_XO_SEL 0x30
59#define PLL_MODE_REF_XO_SEL_CXO (2 << 4)
60#define PLL_MODE_REF_XO_SEL_RF (3 << 4)
Stephen Boyde24edf52012-07-12 17:46:19 -070061#define RIVA_PLL_L_VAL 0x31A4
62#define RIVA_PLL_M_VAL 0x31A8
63#define RIVA_PLL_N_VAL 0x31Ac
64#define RIVA_PLL_CONFIG 0x31B4
65#define RIVA_RESET 0x35E0
Stephen Boyd322a9922011-09-20 01:05:54 -070066
67#define RIVA_PMU_ROOT_CLK_SEL 0xC8
68#define RIVA_PMU_ROOT_CLK_SEL_3 BIT(2)
69
70#define RIVA_PMU_CLK_ROOT3 0x78
71#define RIVA_PMU_CLK_ROOT3_ENA BIT(0)
72#define RIVA_PMU_CLK_ROOT3_SRC0_DIV 0x3C
73#define RIVA_PMU_CLK_ROOT3_SRC0_DIV_2 (1 << 2)
74#define RIVA_PMU_CLK_ROOT3_SRC0_SEL 0x1C0
75#define RIVA_PMU_CLK_ROOT3_SRC0_SEL_RIVA (1 << 6)
76#define RIVA_PMU_CLK_ROOT3_SRC1_DIV 0x1E00
77#define RIVA_PMU_CLK_ROOT3_SRC1_DIV_2 (1 << 9)
78#define RIVA_PMU_CLK_ROOT3_SRC1_SEL 0xE000
79#define RIVA_PMU_CLK_ROOT3_SRC1_SEL_RIVA (1 << 13)
80
81struct riva_data {
82 void __iomem *base;
Stephen Boyde24edf52012-07-12 17:46:19 -070083 void __iomem *cbase;
Stephen Boyd86f2e652012-01-11 18:25:44 -080084 struct clk *xo;
Stephen Boyd3bbdf6c2011-12-21 16:02:26 -080085 struct regulator *pll_supply;
Stephen Boyde83a0a22012-06-29 13:51:27 -070086 struct pil_desc pil_desc;
Stephen Boydfdec00d2012-05-10 17:04:49 -070087 int irq;
88 int crash;
89 int rst_in_progress;
90 struct subsys_device *subsys;
91 struct subsys_desc subsys_desc;
92 struct delayed_work cancel_work;
93 struct ramdump_device *ramdump_dev;
Stephen Boyd322a9922011-09-20 01:05:54 -070094};
95
Stephen Boyd86f4a092012-03-22 10:59:22 -070096static bool cxo_is_needed(struct riva_data *drv)
Matt Wagantall04b7cc72011-12-09 18:52:26 -080097{
Stephen Boyd86f4a092012-03-22 10:59:22 -070098 u32 reg = readl_relaxed(drv->base + RIVA_PMU_CFG);
99 return (reg & RIVA_PMU_CFG_IRIS_XO_MODE)
100 != RIVA_PMU_CFG_IRIS_XO_MODE_48;
101}
102
103static int pil_riva_make_proxy_vote(struct pil_desc *pil)
104{
105 struct riva_data *drv = dev_get_drvdata(pil->dev);
Stephen Boyd3bbdf6c2011-12-21 16:02:26 -0800106 int ret;
Matt Wagantall04b7cc72011-12-09 18:52:26 -0800107
Stephen Boydd0b993a2012-01-30 11:59:31 -0800108 ret = regulator_enable(drv->pll_supply);
109 if (ret) {
Stephen Boyd86f4a092012-03-22 10:59:22 -0700110 dev_err(pil->dev, "failed to enable pll supply\n");
Stephen Boydd0b993a2012-01-30 11:59:31 -0800111 goto err;
112 }
Stephen Boyda74acd62012-04-03 17:41:33 -0700113 ret = clk_prepare_enable(drv->xo);
114 if (ret) {
115 dev_err(pil->dev, "failed to enable xo\n");
116 goto err_clk;
Stephen Boyd86f2e652012-01-11 18:25:44 -0800117 }
Stephen Boydd0b993a2012-01-30 11:59:31 -0800118 return 0;
119err_clk:
120 regulator_disable(drv->pll_supply);
121err:
122 return ret;
Matt Wagantall04b7cc72011-12-09 18:52:26 -0800123}
124
Stephen Boyd86f4a092012-03-22 10:59:22 -0700125static void pil_riva_remove_proxy_vote(struct pil_desc *pil)
Matt Wagantall04b7cc72011-12-09 18:52:26 -0800126{
Stephen Boyd86f4a092012-03-22 10:59:22 -0700127 struct riva_data *drv = dev_get_drvdata(pil->dev);
Stephen Boyd3bbdf6c2011-12-21 16:02:26 -0800128 regulator_disable(drv->pll_supply);
Stephen Boyda74acd62012-04-03 17:41:33 -0700129 clk_disable_unprepare(drv->xo);
Matt Wagantall04b7cc72011-12-09 18:52:26 -0800130}
131
Stephen Boyd322a9922011-09-20 01:05:54 -0700132static int pil_riva_reset(struct pil_desc *pil)
133{
134 u32 reg, sel;
Stephen Boyd322a9922011-09-20 01:05:54 -0700135 struct riva_data *drv = dev_get_drvdata(pil->dev);
136 void __iomem *base = drv->base;
Tianyi Gou819851e2013-04-16 16:05:56 -0700137 phys_addr_t start_addr = pil_get_entry_addr(pil);
Stephen Boyde24edf52012-07-12 17:46:19 -0700138 void __iomem *cbase = drv->cbase;
Stephen Boyda74acd62012-04-03 17:41:33 -0700139 bool use_cxo = cxo_is_needed(drv);
Stephen Boyd322a9922011-09-20 01:05:54 -0700140
141 /* Enable A2XB bridge */
142 reg = readl_relaxed(base + RIVA_PMU_A2XB_CFG);
143 reg |= RIVA_PMU_A2XB_CFG_EN;
144 writel_relaxed(reg, base + RIVA_PMU_A2XB_CFG);
145
Stephen Boyd322a9922011-09-20 01:05:54 -0700146 /* Program PLL 13 to 960 MHz */
Stephen Boyde24edf52012-07-12 17:46:19 -0700147 reg = readl_relaxed(cbase + RIVA_PLL_MODE);
Stephen Boyd322a9922011-09-20 01:05:54 -0700148 reg &= ~(PLL_MODE_BYPASSNL | PLL_MODE_OUTCTRL | PLL_MODE_RESET_N);
Stephen Boyde24edf52012-07-12 17:46:19 -0700149 writel_relaxed(reg, cbase + RIVA_PLL_MODE);
Stephen Boyd322a9922011-09-20 01:05:54 -0700150
Stephen Boyda74acd62012-04-03 17:41:33 -0700151 if (use_cxo)
Stephen Boyde24edf52012-07-12 17:46:19 -0700152 writel_relaxed(0x40000C00 | 50, cbase + RIVA_PLL_L_VAL);
Matt Wagantall04b7cc72011-12-09 18:52:26 -0800153 else
Stephen Boyde24edf52012-07-12 17:46:19 -0700154 writel_relaxed(0x40000C00 | 40, cbase + RIVA_PLL_L_VAL);
155 writel_relaxed(0, cbase + RIVA_PLL_M_VAL);
156 writel_relaxed(1, cbase + RIVA_PLL_N_VAL);
157 writel_relaxed(0x01495227, cbase + RIVA_PLL_CONFIG);
Stephen Boyd322a9922011-09-20 01:05:54 -0700158
Stephen Boyde24edf52012-07-12 17:46:19 -0700159 reg = readl_relaxed(cbase + RIVA_PLL_MODE);
Stephen Boyd322a9922011-09-20 01:05:54 -0700160 reg &= ~(PLL_MODE_REF_XO_SEL);
Stephen Boyda74acd62012-04-03 17:41:33 -0700161 reg |= use_cxo ? PLL_MODE_REF_XO_SEL_CXO : PLL_MODE_REF_XO_SEL_RF;
Stephen Boyde24edf52012-07-12 17:46:19 -0700162 writel_relaxed(reg, cbase + RIVA_PLL_MODE);
Stephen Boyd322a9922011-09-20 01:05:54 -0700163
164 /* Enable PLL 13 */
165 reg |= PLL_MODE_BYPASSNL;
Stephen Boyde24edf52012-07-12 17:46:19 -0700166 writel_relaxed(reg, cbase + RIVA_PLL_MODE);
Stephen Boyd322a9922011-09-20 01:05:54 -0700167
168 /*
169 * H/W requires a 5us delay between disabling the bypass and
170 * de-asserting the reset. Delay 10us just to be safe.
171 */
172 mb();
173 usleep_range(10, 20);
174
175 reg |= PLL_MODE_RESET_N;
Stephen Boyde24edf52012-07-12 17:46:19 -0700176 writel_relaxed(reg, cbase + RIVA_PLL_MODE);
Stephen Boyd322a9922011-09-20 01:05:54 -0700177 reg |= PLL_MODE_OUTCTRL;
Stephen Boyde24edf52012-07-12 17:46:19 -0700178 writel_relaxed(reg, cbase + RIVA_PLL_MODE);
Stephen Boyd322a9922011-09-20 01:05:54 -0700179
180 /* Wait for PLL to settle */
181 mb();
182 usleep_range(50, 100);
183
184 /* Configure cCPU for 240 MHz */
185 sel = readl_relaxed(base + RIVA_PMU_ROOT_CLK_SEL);
186 reg = readl_relaxed(base + RIVA_PMU_CLK_ROOT3);
187 if (sel & RIVA_PMU_ROOT_CLK_SEL_3) {
188 reg &= ~(RIVA_PMU_CLK_ROOT3_SRC0_SEL |
189 RIVA_PMU_CLK_ROOT3_SRC0_DIV);
190 reg |= RIVA_PMU_CLK_ROOT3_SRC0_SEL_RIVA |
191 RIVA_PMU_CLK_ROOT3_SRC0_DIV_2;
192 } else {
193 reg &= ~(RIVA_PMU_CLK_ROOT3_SRC1_SEL |
194 RIVA_PMU_CLK_ROOT3_SRC1_DIV);
195 reg |= RIVA_PMU_CLK_ROOT3_SRC1_SEL_RIVA |
196 RIVA_PMU_CLK_ROOT3_SRC1_DIV_2;
197 }
198 writel_relaxed(reg, base + RIVA_PMU_CLK_ROOT3);
199 reg |= RIVA_PMU_CLK_ROOT3_ENA;
200 writel_relaxed(reg, base + RIVA_PMU_CLK_ROOT3);
201 reg = readl_relaxed(base + RIVA_PMU_ROOT_CLK_SEL);
202 reg ^= RIVA_PMU_ROOT_CLK_SEL_3;
203 writel_relaxed(reg, base + RIVA_PMU_ROOT_CLK_SEL);
204
205 /* Use the high vector table */
206 reg = readl_relaxed(base + RIVA_PMU_CCPU_CTL);
207 reg |= RIVA_PMU_CCPU_CTL_HIGH_IVT | RIVA_PMU_CCPU_CTL_REMAP_EN;
208 writel_relaxed(reg, base + RIVA_PMU_CCPU_CTL);
209
210 /* Set base memory address */
211 writel_relaxed(start_addr >> 16, base + RIVA_PMU_CCPU_BOOT_REMAP_ADDR);
212
213 /* Clear warmboot bit indicating this is a cold boot */
214 reg = readl_relaxed(base + RIVA_PMU_CFG);
215 reg &= ~(RIVA_PMU_CFG_WARM_BOOT);
216 writel_relaxed(reg, base + RIVA_PMU_CFG);
217
218 /* Enable the cCPU clock */
219 reg = readl_relaxed(base + RIVA_PMU_OVRD_VAL);
220 reg |= RIVA_PMU_OVRD_VAL_CCPU_CLK;
221 writel_relaxed(reg, base + RIVA_PMU_OVRD_VAL);
222
223 /* Take cCPU out of reset */
224 reg |= RIVA_PMU_OVRD_VAL_CCPU_RESET;
225 writel_relaxed(reg, base + RIVA_PMU_OVRD_VAL);
226
227 return 0;
228}
229
230static int pil_riva_shutdown(struct pil_desc *pil)
231{
Stephen Boyde24edf52012-07-12 17:46:19 -0700232 struct riva_data *drv = dev_get_drvdata(pil->dev);
233 void __iomem *cbase = drv->cbase;
234
Stephen Boyd12332572011-12-06 16:00:51 -0800235 /* Assert reset to Riva */
Stephen Boyde24edf52012-07-12 17:46:19 -0700236 writel_relaxed(1, cbase + RIVA_RESET);
Stephen Boyd12332572011-12-06 16:00:51 -0800237 mb();
238 usleep_range(1000, 2000);
239
240 /* Deassert reset to Riva */
Stephen Boyde24edf52012-07-12 17:46:19 -0700241 writel_relaxed(0, cbase + RIVA_RESET);
Stephen Boyd12332572011-12-06 16:00:51 -0800242 mb();
Stephen Boyd322a9922011-09-20 01:05:54 -0700243
244 return 0;
245}
246
247static struct pil_reset_ops pil_riva_ops = {
Stephen Boyd322a9922011-09-20 01:05:54 -0700248 .auth_and_reset = pil_riva_reset,
249 .shutdown = pil_riva_shutdown,
Stephen Boyd86f4a092012-03-22 10:59:22 -0700250 .proxy_vote = pil_riva_make_proxy_vote,
251 .proxy_unvote = pil_riva_remove_proxy_vote,
Stephen Boyd322a9922011-09-20 01:05:54 -0700252};
253
254static int pil_riva_init_image_trusted(struct pil_desc *pil,
255 const u8 *metadata, size_t size)
256{
Tianyi Gouca0aaac2012-07-27 14:13:29 -0700257 return pas_init_image(PAS_WCNSS, metadata, size);
Stephen Boyd322a9922011-09-20 01:05:54 -0700258}
259
260static int pil_riva_reset_trusted(struct pil_desc *pil)
261{
Tianyi Gouca0aaac2012-07-27 14:13:29 -0700262 return pas_auth_and_reset(PAS_WCNSS);
Stephen Boyd322a9922011-09-20 01:05:54 -0700263}
264
265static int pil_riva_shutdown_trusted(struct pil_desc *pil)
266{
Tianyi Gouca0aaac2012-07-27 14:13:29 -0700267 return pas_shutdown(PAS_WCNSS);
Stephen Boyd322a9922011-09-20 01:05:54 -0700268}
269
270static struct pil_reset_ops pil_riva_ops_trusted = {
271 .init_image = pil_riva_init_image_trusted,
Stephen Boyd322a9922011-09-20 01:05:54 -0700272 .auth_and_reset = pil_riva_reset_trusted,
273 .shutdown = pil_riva_shutdown_trusted,
Stephen Boyd86f4a092012-03-22 10:59:22 -0700274 .proxy_vote = pil_riva_make_proxy_vote,
275 .proxy_unvote = pil_riva_remove_proxy_vote,
Stephen Boyd322a9922011-09-20 01:05:54 -0700276};
277
Stephen Boydfdec00d2012-05-10 17:04:49 -0700278static int enable_riva_ssr;
279
280static int enable_riva_ssr_set(const char *val, struct kernel_param *kp)
281{
282 int ret;
283
284 ret = param_set_int(val, kp);
285 if (ret)
286 return ret;
287
288 if (enable_riva_ssr)
289 pr_info("Subsystem restart activated for riva.\n");
290
291 return 0;
292}
293module_param_call(enable_riva_ssr, enable_riva_ssr_set, param_get_int,
294 &enable_riva_ssr, S_IRUGO | S_IWUSR);
295
296static void smsm_state_cb_hdlr(void *data, uint32_t old_state,
297 uint32_t new_state)
298{
299 struct riva_data *drv = data;
300 char *smem_reset_reason;
301 char buffer[81];
302 unsigned smem_reset_size;
303 unsigned size;
304
305 drv->crash = true;
306 if (!(new_state & SMSM_RESET))
307 return;
308
309 if (drv->rst_in_progress) {
310 pr_err("riva: Ignoring smsm reset req, restart in progress\n");
311 return;
312 }
313
314 pr_err("riva: smsm state changed to smsm reset\n");
315
316 smem_reset_reason = smem_get_entry(SMEM_SSR_REASON_WCNSS0,
317 &smem_reset_size);
318
319 if (!smem_reset_reason || !smem_reset_size) {
320 pr_err("wcnss subsystem failure reason:\n"
321 "(unknown, smem_get_entry failed)");
322 } else if (!smem_reset_reason[0]) {
323 pr_err("wcnss subsystem failure reason:\n"
324 "(unknown, init string found)");
325 } else {
326 size = smem_reset_size < sizeof(buffer) ? smem_reset_size :
327 (sizeof(buffer) - 1);
328 memcpy(buffer, smem_reset_reason, size);
329 buffer[size] = '\0';
330 pr_err("wcnss subsystem failure reason: %s\n", buffer);
331 memset(smem_reset_reason, 0, smem_reset_size);
332 wmb();
333 }
334
335 drv->rst_in_progress = 1;
336 subsystem_restart_dev(drv->subsys);
337}
338
339static irqreturn_t riva_wdog_bite_irq_hdlr(int irq, void *dev_id)
340{
341 struct riva_data *drv = dev_id;
342
343 drv->crash = true;
344 if (drv->rst_in_progress) {
345 pr_err("Ignoring riva bite irq, restart in progress\n");
346 return IRQ_HANDLED;
347 }
348 if (!enable_riva_ssr)
349 panic("Watchdog bite received from Riva");
350
351 drv->rst_in_progress = 1;
Sameer Thalappil1b3e6112012-12-14 15:16:07 -0800352 wcnss_riva_log_debug_regs();
Stephen Boydfdec00d2012-05-10 17:04:49 -0700353 subsystem_restart_dev(drv->subsys);
354
355 return IRQ_HANDLED;
356}
357
358static void riva_post_bootup(struct work_struct *work)
359{
360 struct platform_device *pdev = wcnss_get_platform_device();
361 struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
362
363 wcnss_wlan_power(&pdev->dev, pwlanconfig, WCNSS_WLAN_SWITCH_OFF);
364}
365
Stephen Boyd3e4e9752012-06-27 12:46:32 -0700366static int riva_start(const struct subsys_desc *desc)
367{
Stephen Boyd3e4e9752012-06-27 12:46:32 -0700368 struct riva_data *drv;
369
370 drv = container_of(desc, struct riva_data, subsys_desc);
Stephen Boyde83a0a22012-06-29 13:51:27 -0700371 return pil_boot(&drv->pil_desc);
Stephen Boyd3e4e9752012-06-27 12:46:32 -0700372}
373
374static void riva_stop(const struct subsys_desc *desc)
375{
376 struct riva_data *drv;
377
378 drv = container_of(desc, struct riva_data, subsys_desc);
Stephen Boyde83a0a22012-06-29 13:51:27 -0700379 pil_shutdown(&drv->pil_desc);
Stephen Boyd3e4e9752012-06-27 12:46:32 -0700380}
381
Stephen Boydfdec00d2012-05-10 17:04:49 -0700382static int riva_shutdown(const struct subsys_desc *desc)
383{
384 struct riva_data *drv;
385
386 drv = container_of(desc, struct riva_data, subsys_desc);
Stephen Boyde83a0a22012-06-29 13:51:27 -0700387 pil_shutdown(&drv->pil_desc);
Stephen Boydfdec00d2012-05-10 17:04:49 -0700388 flush_delayed_work(&drv->cancel_work);
389 wcnss_flush_delayed_boot_votes();
390 disable_irq_nosync(drv->irq);
391
392 return 0;
393}
394
395static int riva_powerup(const struct subsys_desc *desc)
396{
397 struct riva_data *drv;
398 struct platform_device *pdev = wcnss_get_platform_device();
399 struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
400 int ret = 0;
401
402 drv = container_of(desc, struct riva_data, subsys_desc);
403 if (pdev && pwlanconfig) {
404 ret = wcnss_wlan_power(&pdev->dev, pwlanconfig,
405 WCNSS_WLAN_SWITCH_ON);
406 if (!ret)
Stephen Boyde83a0a22012-06-29 13:51:27 -0700407 pil_boot(&drv->pil_desc);
Stephen Boydfdec00d2012-05-10 17:04:49 -0700408 }
409 drv->rst_in_progress = 0;
410 enable_irq(drv->irq);
411 schedule_delayed_work(&drv->cancel_work, msecs_to_jiffies(5000));
412
413 return ret;
414}
415
Stephen Boydfdec00d2012-05-10 17:04:49 -0700416static int riva_ramdump(int enable, const struct subsys_desc *desc)
417{
418 struct riva_data *drv;
419
420 drv = container_of(desc, struct riva_data, subsys_desc);
421
Stephen Boyd5eb17ce2012-11-29 15:34:21 -0800422 if (!enable)
Stephen Boydfdec00d2012-05-10 17:04:49 -0700423 return 0;
Stephen Boyd5eb17ce2012-11-29 15:34:21 -0800424
425 return pil_do_ramdump(&drv->pil_desc, drv->ramdump_dev);
Stephen Boydfdec00d2012-05-10 17:04:49 -0700426}
427
428/* Riva crash handler */
429static void riva_crash_shutdown(const struct subsys_desc *desc)
430{
431 struct riva_data *drv;
432
433 drv = container_of(desc, struct riva_data, subsys_desc);
434 pr_err("riva crash shutdown %d\n", drv->crash);
435 if (drv->crash != true)
436 smsm_change_state(SMSM_APPS_STATE, SMSM_RESET, SMSM_RESET);
437}
438
Stephen Boyd322a9922011-09-20 01:05:54 -0700439static int __devinit pil_riva_probe(struct platform_device *pdev)
440{
441 struct riva_data *drv;
442 struct resource *res;
443 struct pil_desc *desc;
Stephen Boyd3bbdf6c2011-12-21 16:02:26 -0800444 int ret;
Stephen Boyd322a9922011-09-20 01:05:54 -0700445
Stephen Boyd322a9922011-09-20 01:05:54 -0700446 drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
447 if (!drv)
448 return -ENOMEM;
449 platform_set_drvdata(pdev, drv);
450
Stephen Boydf8f89282012-07-16 18:05:48 -0700451
452 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
453 drv->base = devm_request_and_ioremap(&pdev->dev, res);
Stephen Boyd322a9922011-09-20 01:05:54 -0700454 if (!drv->base)
455 return -ENOMEM;
456
Stephen Boyde24edf52012-07-12 17:46:19 -0700457 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
Stephen Boydf8f89282012-07-16 18:05:48 -0700458 drv->cbase = devm_request_and_ioremap(&pdev->dev, res);
Stephen Boyde24edf52012-07-12 17:46:19 -0700459 if (!drv->cbase)
460 return -ENOMEM;
461
Stephen Boyd83e5eae2012-03-23 15:04:46 -0700462 drv->pll_supply = devm_regulator_get(&pdev->dev, "pll_vdd");
Stephen Boyd3bbdf6c2011-12-21 16:02:26 -0800463 if (IS_ERR(drv->pll_supply)) {
464 dev_err(&pdev->dev, "failed to get pll supply\n");
465 return PTR_ERR(drv->pll_supply);
466 }
Matt Wagantall52dd0622012-02-02 18:26:16 -0800467 if (regulator_count_voltages(drv->pll_supply) > 0) {
468 ret = regulator_set_voltage(drv->pll_supply, 1800000, 1800000);
469 if (ret) {
470 dev_err(&pdev->dev,
471 "failed to set pll supply voltage\n");
Stephen Boyd93528ea2012-03-23 15:23:10 -0700472 return ret;
Matt Wagantall52dd0622012-02-02 18:26:16 -0800473 }
Stephen Boyd3bbdf6c2011-12-21 16:02:26 -0800474
Matt Wagantall52dd0622012-02-02 18:26:16 -0800475 ret = regulator_set_optimum_mode(drv->pll_supply, 100000);
476 if (ret < 0) {
477 dev_err(&pdev->dev,
478 "failed to set pll supply optimum mode\n");
Stephen Boyd93528ea2012-03-23 15:23:10 -0700479 return ret;
Matt Wagantall52dd0622012-02-02 18:26:16 -0800480 }
Stephen Boyd3bbdf6c2011-12-21 16:02:26 -0800481 }
482
Stephen Boydfdec00d2012-05-10 17:04:49 -0700483 drv->irq = platform_get_irq(pdev, 0);
484 if (drv->irq < 0)
485 return drv->irq;
486
Stephen Boyde83a0a22012-06-29 13:51:27 -0700487 drv->xo = devm_clk_get(&pdev->dev, "cxo");
488 if (IS_ERR(drv->xo))
489 return PTR_ERR(drv->xo);
490
491 desc = &drv->pil_desc;
Stephen Boyd322a9922011-09-20 01:05:54 -0700492 desc->name = "wcnss";
493 desc->dev = &pdev->dev;
Stephen Boyd6d67d252011-09-27 11:50:05 -0700494 desc->owner = THIS_MODULE;
Stephen Boyd86f4a092012-03-22 10:59:22 -0700495 desc->proxy_timeout = 10000;
Stephen Boyd322a9922011-09-20 01:05:54 -0700496
Tianyi Gouca0aaac2012-07-27 14:13:29 -0700497 if (pas_supported(PAS_WCNSS) > 0) {
Stephen Boyd322a9922011-09-20 01:05:54 -0700498 desc->ops = &pil_riva_ops_trusted;
499 dev_info(&pdev->dev, "using secure boot\n");
500 } else {
501 desc->ops = &pil_riva_ops;
502 dev_info(&pdev->dev, "using non-secure boot\n");
503 }
Stephen Boyde83a0a22012-06-29 13:51:27 -0700504 ret = pil_desc_init(desc);
Stephen Boydfdec00d2012-05-10 17:04:49 -0700505
506 ret = smsm_state_cb_register(SMSM_WCNSS_STATE, SMSM_RESET,
507 smsm_state_cb_hdlr, drv);
508 if (ret < 0)
509 goto err_smsm;
510
511 drv->subsys_desc.name = "wcnss";
Stephen Boyd3e4e9752012-06-27 12:46:32 -0700512 drv->subsys_desc.dev = &pdev->dev;
513 drv->subsys_desc.owner = THIS_MODULE;
514 drv->subsys_desc.start = riva_start;
515 drv->subsys_desc.stop = riva_stop;
Stephen Boydfdec00d2012-05-10 17:04:49 -0700516 drv->subsys_desc.shutdown = riva_shutdown;
517 drv->subsys_desc.powerup = riva_powerup;
518 drv->subsys_desc.ramdump = riva_ramdump;
519 drv->subsys_desc.crash_shutdown = riva_crash_shutdown;
520
521 INIT_DELAYED_WORK(&drv->cancel_work, riva_post_bootup);
522
Stephen Boydc1a72612012-07-05 14:07:35 -0700523 drv->ramdump_dev = create_ramdump_device("riva", &pdev->dev);
Stephen Boydfdec00d2012-05-10 17:04:49 -0700524 if (!drv->ramdump_dev) {
525 ret = -ENOMEM;
526 goto err_ramdump;
527 }
528
529 drv->subsys = subsys_register(&drv->subsys_desc);
530 if (IS_ERR(drv->subsys)) {
531 ret = PTR_ERR(drv->subsys);
532 goto err_subsys;
533 }
534
535 ret = devm_request_irq(&pdev->dev, drv->irq, riva_wdog_bite_irq_hdlr,
Sameer Thalappildb8604c2012-11-29 14:10:48 -0800536 IRQF_TRIGGER_RISING, "riva_wdog", drv);
Stephen Boydfdec00d2012-05-10 17:04:49 -0700537 if (ret < 0)
538 goto err;
539
Stephen Boyd3bbdf6c2011-12-21 16:02:26 -0800540 return 0;
Stephen Boydfdec00d2012-05-10 17:04:49 -0700541err:
542 subsys_unregister(drv->subsys);
543err_subsys:
544 destroy_ramdump_device(drv->ramdump_dev);
545err_ramdump:
546 smsm_state_cb_deregister(SMSM_WCNSS_STATE, SMSM_RESET,
547 smsm_state_cb_hdlr, drv);
548err_smsm:
Stephen Boyde83a0a22012-06-29 13:51:27 -0700549 pil_desc_release(desc);
Stephen Boydfdec00d2012-05-10 17:04:49 -0700550 return ret;
Stephen Boyd322a9922011-09-20 01:05:54 -0700551}
552
553static int __devexit pil_riva_remove(struct platform_device *pdev)
554{
Stephen Boyd3bbdf6c2011-12-21 16:02:26 -0800555 struct riva_data *drv = platform_get_drvdata(pdev);
Stephen Boydfdec00d2012-05-10 17:04:49 -0700556
557 subsys_unregister(drv->subsys);
558 destroy_ramdump_device(drv->ramdump_dev);
559 smsm_state_cb_deregister(SMSM_WCNSS_STATE, SMSM_RESET,
560 smsm_state_cb_hdlr, drv);
Stephen Boyde83a0a22012-06-29 13:51:27 -0700561 pil_desc_release(&drv->pil_desc);
Stephen Boydfdec00d2012-05-10 17:04:49 -0700562
Stephen Boyd322a9922011-09-20 01:05:54 -0700563 return 0;
564}
565
566static struct platform_driver pil_riva_driver = {
567 .probe = pil_riva_probe,
568 .remove = __devexit_p(pil_riva_remove),
569 .driver = {
570 .name = "pil_riva",
571 .owner = THIS_MODULE,
572 },
573};
574
575static int __init pil_riva_init(void)
576{
577 return platform_driver_register(&pil_riva_driver);
578}
579module_init(pil_riva_init);
580
581static void __exit pil_riva_exit(void)
582{
Stephen Boyd322a9922011-09-20 01:05:54 -0700583 platform_driver_unregister(&pil_riva_driver);
584}
585module_exit(pil_riva_exit);
586
587MODULE_DESCRIPTION("Support for booting RIVA (WCNSS) processors");
588MODULE_LICENSE("GPL v2");