blob: 7cf2388d9cd08f7418cb33ff0ae508f7d67c7e2b [file] [log] [blame]
Stephen Boyd12332572011-12-06 16:00:51 -08001/* Copyright (c) 2011-2012, Code Aurora Forum. 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>
Stephen Boyd322a9922011-09-20 01:05:54 -070026
27#include "peripheral-loader.h"
28#include "scm-pas.h"
Stephen Boydfdec00d2012-05-10 17:04:49 -070029#include "ramdump.h"
30#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;
Stephen Boyd3030c252012-08-08 17:24:05 -0700137 unsigned long 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;
352 subsystem_restart_dev(drv->subsys);
353
354 return IRQ_HANDLED;
355}
356
357static void riva_post_bootup(struct work_struct *work)
358{
359 struct platform_device *pdev = wcnss_get_platform_device();
360 struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
361
362 wcnss_wlan_power(&pdev->dev, pwlanconfig, WCNSS_WLAN_SWITCH_OFF);
363}
364
Stephen Boyd3e4e9752012-06-27 12:46:32 -0700365static int riva_start(const struct subsys_desc *desc)
366{
Stephen Boyd3e4e9752012-06-27 12:46:32 -0700367 struct riva_data *drv;
368
369 drv = container_of(desc, struct riva_data, subsys_desc);
Stephen Boyde83a0a22012-06-29 13:51:27 -0700370 return pil_boot(&drv->pil_desc);
Stephen Boyd3e4e9752012-06-27 12:46:32 -0700371}
372
373static void riva_stop(const struct subsys_desc *desc)
374{
375 struct riva_data *drv;
376
377 drv = container_of(desc, struct riva_data, subsys_desc);
Stephen Boyde83a0a22012-06-29 13:51:27 -0700378 pil_shutdown(&drv->pil_desc);
Stephen Boyd3e4e9752012-06-27 12:46:32 -0700379}
380
Stephen Boydfdec00d2012-05-10 17:04:49 -0700381static int riva_shutdown(const struct subsys_desc *desc)
382{
383 struct riva_data *drv;
384
385 drv = container_of(desc, struct riva_data, subsys_desc);
Stephen Boyde83a0a22012-06-29 13:51:27 -0700386 pil_shutdown(&drv->pil_desc);
Stephen Boydfdec00d2012-05-10 17:04:49 -0700387 flush_delayed_work(&drv->cancel_work);
388 wcnss_flush_delayed_boot_votes();
389 disable_irq_nosync(drv->irq);
390
391 return 0;
392}
393
394static int riva_powerup(const struct subsys_desc *desc)
395{
396 struct riva_data *drv;
397 struct platform_device *pdev = wcnss_get_platform_device();
398 struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
399 int ret = 0;
400
401 drv = container_of(desc, struct riva_data, subsys_desc);
402 if (pdev && pwlanconfig) {
403 ret = wcnss_wlan_power(&pdev->dev, pwlanconfig,
404 WCNSS_WLAN_SWITCH_ON);
405 if (!ret)
Stephen Boyde83a0a22012-06-29 13:51:27 -0700406 pil_boot(&drv->pil_desc);
Stephen Boydfdec00d2012-05-10 17:04:49 -0700407 }
408 drv->rst_in_progress = 0;
409 enable_irq(drv->irq);
410 schedule_delayed_work(&drv->cancel_work, msecs_to_jiffies(5000));
411
412 return ret;
413}
414
415/*
416 * 7MB RAM segments for Riva SS;
417 * Riva 1.1 0x8f000000 - 0x8f700000
418 * Riva 1.0 0x8f200000 - 0x8f700000
419 */
420static struct ramdump_segment riva_segments[] = {
421 {0x8f000000, 0x8f700000 - 0x8f000000}
422};
423
424static int riva_ramdump(int enable, const struct subsys_desc *desc)
425{
426 struct riva_data *drv;
427
428 drv = container_of(desc, struct riva_data, subsys_desc);
429
430 if (enable)
431 return do_ramdump(drv->ramdump_dev, riva_segments,
432 ARRAY_SIZE(riva_segments));
433 else
434 return 0;
435}
436
437/* Riva crash handler */
438static void riva_crash_shutdown(const struct subsys_desc *desc)
439{
440 struct riva_data *drv;
441
442 drv = container_of(desc, struct riva_data, subsys_desc);
443 pr_err("riva crash shutdown %d\n", drv->crash);
444 if (drv->crash != true)
445 smsm_change_state(SMSM_APPS_STATE, SMSM_RESET, SMSM_RESET);
446}
447
Stephen Boyd322a9922011-09-20 01:05:54 -0700448static int __devinit pil_riva_probe(struct platform_device *pdev)
449{
450 struct riva_data *drv;
451 struct resource *res;
452 struct pil_desc *desc;
Stephen Boyd3bbdf6c2011-12-21 16:02:26 -0800453 int ret;
Stephen Boyd322a9922011-09-20 01:05:54 -0700454
455 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
456 if (!res)
457 return -EINVAL;
458
459 drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
460 if (!drv)
461 return -ENOMEM;
462 platform_set_drvdata(pdev, drv);
463
464 drv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
465 if (!drv->base)
466 return -ENOMEM;
467
Stephen Boyde24edf52012-07-12 17:46:19 -0700468 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
469 if (!res)
470 return -EINVAL;
471 drv->cbase = devm_ioremap(&pdev->dev, res->start, resource_size(res));
472 if (!drv->cbase)
473 return -ENOMEM;
474
Stephen Boyd83e5eae2012-03-23 15:04:46 -0700475 drv->pll_supply = devm_regulator_get(&pdev->dev, "pll_vdd");
Stephen Boyd3bbdf6c2011-12-21 16:02:26 -0800476 if (IS_ERR(drv->pll_supply)) {
477 dev_err(&pdev->dev, "failed to get pll supply\n");
478 return PTR_ERR(drv->pll_supply);
479 }
Matt Wagantall52dd0622012-02-02 18:26:16 -0800480 if (regulator_count_voltages(drv->pll_supply) > 0) {
481 ret = regulator_set_voltage(drv->pll_supply, 1800000, 1800000);
482 if (ret) {
483 dev_err(&pdev->dev,
484 "failed to set pll supply voltage\n");
Stephen Boyd93528ea2012-03-23 15:23:10 -0700485 return ret;
Matt Wagantall52dd0622012-02-02 18:26:16 -0800486 }
Stephen Boyd3bbdf6c2011-12-21 16:02:26 -0800487
Matt Wagantall52dd0622012-02-02 18:26:16 -0800488 ret = regulator_set_optimum_mode(drv->pll_supply, 100000);
489 if (ret < 0) {
490 dev_err(&pdev->dev,
491 "failed to set pll supply optimum mode\n");
Stephen Boyd93528ea2012-03-23 15:23:10 -0700492 return ret;
Matt Wagantall52dd0622012-02-02 18:26:16 -0800493 }
Stephen Boyd3bbdf6c2011-12-21 16:02:26 -0800494 }
495
Stephen Boydfdec00d2012-05-10 17:04:49 -0700496 drv->irq = platform_get_irq(pdev, 0);
497 if (drv->irq < 0)
498 return drv->irq;
499
Stephen Boyde83a0a22012-06-29 13:51:27 -0700500 drv->xo = devm_clk_get(&pdev->dev, "cxo");
501 if (IS_ERR(drv->xo))
502 return PTR_ERR(drv->xo);
503
504 desc = &drv->pil_desc;
Stephen Boyd322a9922011-09-20 01:05:54 -0700505 desc->name = "wcnss";
506 desc->dev = &pdev->dev;
Stephen Boyd6d67d252011-09-27 11:50:05 -0700507 desc->owner = THIS_MODULE;
Stephen Boyd86f4a092012-03-22 10:59:22 -0700508 desc->proxy_timeout = 10000;
Stephen Boyd322a9922011-09-20 01:05:54 -0700509
Tianyi Gouca0aaac2012-07-27 14:13:29 -0700510 if (pas_supported(PAS_WCNSS) > 0) {
Stephen Boyd322a9922011-09-20 01:05:54 -0700511 desc->ops = &pil_riva_ops_trusted;
512 dev_info(&pdev->dev, "using secure boot\n");
513 } else {
514 desc->ops = &pil_riva_ops;
515 dev_info(&pdev->dev, "using non-secure boot\n");
516 }
Stephen Boyde83a0a22012-06-29 13:51:27 -0700517 ret = pil_desc_init(desc);
Stephen Boydfdec00d2012-05-10 17:04:49 -0700518
519 ret = smsm_state_cb_register(SMSM_WCNSS_STATE, SMSM_RESET,
520 smsm_state_cb_hdlr, drv);
521 if (ret < 0)
522 goto err_smsm;
523
524 drv->subsys_desc.name = "wcnss";
Stephen Boyd3e4e9752012-06-27 12:46:32 -0700525 drv->subsys_desc.dev = &pdev->dev;
526 drv->subsys_desc.owner = THIS_MODULE;
527 drv->subsys_desc.start = riva_start;
528 drv->subsys_desc.stop = riva_stop;
Stephen Boydfdec00d2012-05-10 17:04:49 -0700529 drv->subsys_desc.shutdown = riva_shutdown;
530 drv->subsys_desc.powerup = riva_powerup;
531 drv->subsys_desc.ramdump = riva_ramdump;
532 drv->subsys_desc.crash_shutdown = riva_crash_shutdown;
533
534 INIT_DELAYED_WORK(&drv->cancel_work, riva_post_bootup);
535
Stephen Boydc1a72612012-07-05 14:07:35 -0700536 drv->ramdump_dev = create_ramdump_device("riva", &pdev->dev);
Stephen Boydfdec00d2012-05-10 17:04:49 -0700537 if (!drv->ramdump_dev) {
538 ret = -ENOMEM;
539 goto err_ramdump;
540 }
541
542 drv->subsys = subsys_register(&drv->subsys_desc);
543 if (IS_ERR(drv->subsys)) {
544 ret = PTR_ERR(drv->subsys);
545 goto err_subsys;
546 }
547
548 ret = devm_request_irq(&pdev->dev, drv->irq, riva_wdog_bite_irq_hdlr,
549 IRQF_TRIGGER_HIGH, "riva_wdog", drv);
550 if (ret < 0)
551 goto err;
552
Stephen Boyd3bbdf6c2011-12-21 16:02:26 -0800553 return 0;
Stephen Boydfdec00d2012-05-10 17:04:49 -0700554err:
555 subsys_unregister(drv->subsys);
556err_subsys:
557 destroy_ramdump_device(drv->ramdump_dev);
558err_ramdump:
559 smsm_state_cb_deregister(SMSM_WCNSS_STATE, SMSM_RESET,
560 smsm_state_cb_hdlr, drv);
561err_smsm:
Stephen Boyde83a0a22012-06-29 13:51:27 -0700562 pil_desc_release(desc);
Stephen Boydfdec00d2012-05-10 17:04:49 -0700563 return ret;
Stephen Boyd322a9922011-09-20 01:05:54 -0700564}
565
566static int __devexit pil_riva_remove(struct platform_device *pdev)
567{
Stephen Boyd3bbdf6c2011-12-21 16:02:26 -0800568 struct riva_data *drv = platform_get_drvdata(pdev);
Stephen Boydfdec00d2012-05-10 17:04:49 -0700569
570 subsys_unregister(drv->subsys);
571 destroy_ramdump_device(drv->ramdump_dev);
572 smsm_state_cb_deregister(SMSM_WCNSS_STATE, SMSM_RESET,
573 smsm_state_cb_hdlr, drv);
Stephen Boyde83a0a22012-06-29 13:51:27 -0700574 pil_desc_release(&drv->pil_desc);
Stephen Boydfdec00d2012-05-10 17:04:49 -0700575
Stephen Boyd322a9922011-09-20 01:05:54 -0700576 return 0;
577}
578
579static struct platform_driver pil_riva_driver = {
580 .probe = pil_riva_probe,
581 .remove = __devexit_p(pil_riva_remove),
582 .driver = {
583 .name = "pil_riva",
584 .owner = THIS_MODULE,
585 },
586};
587
588static int __init pil_riva_init(void)
589{
590 return platform_driver_register(&pil_riva_driver);
591}
592module_init(pil_riva_init);
593
594static void __exit pil_riva_exit(void)
595{
Stephen Boyd322a9922011-09-20 01:05:54 -0700596 platform_driver_unregister(&pil_riva_driver);
597}
598module_exit(pil_riva_exit);
599
600MODULE_DESCRIPTION("Support for booting RIVA (WCNSS) processors");
601MODULE_LICENSE("GPL v2");