blob: fd7753c9c07d517dfbbbf23a59777aa60333688e [file] [log] [blame]
Stephen Boydeb819882011-08-29 14:46:30 -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/init.h>
14#include <linux/module.h>
15#include <linux/platform_device.h>
16#include <linux/io.h>
17#include <linux/ioport.h>
18#include <linux/regulator/consumer.h>
19#include <linux/elf.h>
20#include <linux/delay.h>
21#include <linux/err.h>
22
23#include <mach/msm_iomap.h>
24
25#include "peripheral-loader.h"
26#include "pil-q6v4.h"
27#include "scm-pas.h"
28
29#define QDSP6SS_RST_EVB 0x0
30#define QDSP6SS_RESET 0x04
31#define QDSP6SS_CGC_OVERRIDE 0x18
32#define QDSP6SS_STRAP_TCM 0x1C
33#define QDSP6SS_STRAP_AHB 0x20
34#define QDSP6SS_GFMUX_CTL 0x30
35#define QDSP6SS_PWR_CTL 0x38
36
37#define MSS_S_HCLK_CTL (MSM_CLK_CTL_BASE + 0x2C70)
38#define MSS_SLP_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C60)
39#define SFAB_MSS_M_ACLK_CTL (MSM_CLK_CTL_BASE + 0x2340)
40#define SFAB_MSS_S_HCLK_CTL (MSM_CLK_CTL_BASE + 0x2C00)
41#define MSS_RESET (MSM_CLK_CTL_BASE + 0x2C64)
42
43#define Q6SS_SS_ARES BIT(0)
44#define Q6SS_CORE_ARES BIT(1)
45#define Q6SS_ISDB_ARES BIT(2)
46#define Q6SS_ETM_ARES BIT(3)
47#define Q6SS_STOP_CORE_ARES BIT(4)
48#define Q6SS_PRIV_ARES BIT(5)
49
50#define Q6SS_L2DATA_SLP_NRET_N BIT(0)
51#define Q6SS_SLP_RET_N BIT(1)
52#define Q6SS_L1TCM_SLP_NRET_N BIT(2)
53#define Q6SS_L2TAG_SLP_NRET_N BIT(3)
54#define Q6SS_ETB_SLEEP_NRET_N BIT(4)
55#define Q6SS_ARR_STBY_N BIT(5)
56#define Q6SS_CLAMP_IO BIT(6)
57
58#define Q6SS_CLK_ENA BIT(1)
59#define Q6SS_SRC_SWITCH_CLK_OVR BIT(8)
60#define Q6SS_AXIS_ACLK_EN BIT(9)
61
62struct q6v4_data {
63 void __iomem *base;
64 void __iomem *modem_base;
65 unsigned long start_addr;
66 struct regulator *vreg;
67 bool vreg_enabled;
68};
69
70static int pil_q6v4_init_image(struct pil_desc *pil, const u8 *metadata,
71 size_t size)
72{
73 const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
74 struct q6v4_data *drv = dev_get_drvdata(pil->dev);
75 drv->start_addr = ehdr->e_entry;
76 return 0;
77}
78
79static int nop_verify_blob(struct pil_desc *pil, u32 phy_addr, size_t size)
80{
81 return 0;
82}
83
84static int pil_q6v4_power_up(struct device *dev)
85{
86 int err;
87 struct q6v4_data *drv = dev_get_drvdata(dev);
88
89 err = regulator_set_voltage(drv->vreg, 1050000, 1050000);
90 if (err) {
91 dev_err(dev, "Failed to set regulator's voltage.\n");
92 return err;
93 }
94 err = regulator_set_optimum_mode(drv->vreg, 100000);
95 if (err < 0) {
96 dev_err(dev, "Failed to set regulator's mode.\n");
97 return err;
98 }
99 err = regulator_enable(drv->vreg);
100 if (err) {
101 dev_err(dev, "Failed to enable regulator.\n");
102 return err;
103 }
104 drv->vreg_enabled = true;
105 return 0;
106}
107
108static DEFINE_MUTEX(pil_q6v4_modem_lock);
109static unsigned pil_q6v4_modem_count;
110
111/* Bring modem subsystem out of reset */
112static void pil_q6v4_init_modem(void __iomem *base, void __iomem *jtag_clk)
113{
114 mutex_lock(&pil_q6v4_modem_lock);
115 if (!pil_q6v4_modem_count) {
116 /* Enable MSS clocks */
117 writel_relaxed(0x10, SFAB_MSS_M_ACLK_CTL);
118 writel_relaxed(0x10, SFAB_MSS_S_HCLK_CTL);
119 writel_relaxed(0x10, MSS_S_HCLK_CTL);
120 writel_relaxed(0x10, MSS_SLP_CLK_CTL);
121 /* Wait for clocks to enable */
122 mb();
123 udelay(10);
124
125 /* De-assert MSS reset */
126 writel_relaxed(0x0, MSS_RESET);
127 mb();
128 udelay(10);
129 /* Enable MSS */
130 writel_relaxed(0x7, base);
131 }
132
133 /* Enable JTAG clocks */
134 /* TODO: Remove if/when Q6 software enables them? */
135 writel_relaxed(0x10, jtag_clk);
136
137 pil_q6v4_modem_count++;
138 mutex_unlock(&pil_q6v4_modem_lock);
139}
140
141/* Put modem subsystem back into reset */
142static void pil_q6v4_shutdown_modem(void)
143{
144 mutex_lock(&pil_q6v4_modem_lock);
145 if (pil_q6v4_modem_count)
146 pil_q6v4_modem_count--;
147 if (pil_q6v4_modem_count == 0)
148 writel_relaxed(0x1, MSS_RESET);
149 mutex_unlock(&pil_q6v4_modem_lock);
150}
151
152static int pil_q6v4_reset(struct pil_desc *pil)
153{
154 u32 reg, err = 0;
155 const struct q6v4_data *drv = dev_get_drvdata(pil->dev);
156 const struct pil_q6v4_pdata *pdata = pil->dev->platform_data;
157
158 err = pil_q6v4_power_up(pil->dev);
159 if (err)
160 return err;
161 /* Enable Q6 ACLK */
162 writel_relaxed(0x10, pdata->aclk_reg);
163
164 if (drv->modem_base)
165 pil_q6v4_init_modem(drv->modem_base, pdata->jtag_clk_reg);
166
167 /*
168 * Assert AXIS_ACLK_EN override to allow for correct updating of the
169 * QDSP6_CORE_STATE status bit. This is mandatory only for the SW Q6
170 * in 8960v1 and optional elsewhere.
171 */
172 reg = readl_relaxed(drv->base + QDSP6SS_CGC_OVERRIDE);
173 reg |= Q6SS_AXIS_ACLK_EN;
174 writel_relaxed(reg, drv->base + QDSP6SS_CGC_OVERRIDE);
175
176 /* Deassert Q6SS_SS_ARES */
177 reg = readl_relaxed(drv->base + QDSP6SS_RESET);
178 reg &= ~(Q6SS_SS_ARES);
179 writel_relaxed(reg, drv->base + QDSP6SS_RESET);
180
181 /* Program boot address */
182 writel_relaxed((drv->start_addr >> 8) & 0xFFFFFF,
183 drv->base + QDSP6SS_RST_EVB);
184
185 /* Program TCM and AHB address ranges */
186 writel_relaxed(pdata->strap_tcm_base, drv->base + QDSP6SS_STRAP_TCM);
187 writel_relaxed(pdata->strap_ahb_upper | pdata->strap_ahb_lower,
188 drv->base + QDSP6SS_STRAP_AHB);
189
190 /* Turn off Q6 core clock */
191 writel_relaxed(Q6SS_SRC_SWITCH_CLK_OVR,
192 drv->base + QDSP6SS_GFMUX_CTL);
193
194 /* Put memories to sleep */
195 writel_relaxed(Q6SS_CLAMP_IO, drv->base + QDSP6SS_PWR_CTL);
196
197 /* Assert resets */
198 reg = readl_relaxed(drv->base + QDSP6SS_RESET);
199 reg |= (Q6SS_CORE_ARES | Q6SS_ISDB_ARES | Q6SS_ETM_ARES
200 | Q6SS_STOP_CORE_ARES);
201 writel_relaxed(reg, drv->base + QDSP6SS_RESET);
202
203 /* Wait 8 AHB cycles for Q6 to be fully reset (AHB = 1.5Mhz) */
204 mb();
205 usleep_range(20, 30);
206
207 /* Turn on Q6 memories */
208 reg = Q6SS_L2DATA_SLP_NRET_N | Q6SS_SLP_RET_N | Q6SS_L1TCM_SLP_NRET_N
209 | Q6SS_L2TAG_SLP_NRET_N | Q6SS_ETB_SLEEP_NRET_N | Q6SS_ARR_STBY_N
210 | Q6SS_CLAMP_IO;
211 writel_relaxed(reg, drv->base + QDSP6SS_PWR_CTL);
212
213 /* Turn on Q6 core clock */
214 reg = Q6SS_CLK_ENA | Q6SS_SRC_SWITCH_CLK_OVR;
215 writel_relaxed(reg, drv->base + QDSP6SS_GFMUX_CTL);
216
217 /* Remove Q6SS_CLAMP_IO */
218 reg = readl_relaxed(drv->base + QDSP6SS_PWR_CTL);
219 reg &= ~Q6SS_CLAMP_IO;
220 writel_relaxed(reg, drv->base + QDSP6SS_PWR_CTL);
221
222 /* Bring Q6 core out of reset and start execution. */
223 writel_relaxed(0x0, drv->base + QDSP6SS_RESET);
224
225 /*
226 * Re-enable auto-gating of AXIS_ACLK at lease one AXI clock cycle
227 * after resets are de-asserted.
228 */
229 mb();
230 usleep_range(1, 10);
231 reg = readl_relaxed(drv->base + QDSP6SS_CGC_OVERRIDE);
232 reg &= ~Q6SS_AXIS_ACLK_EN;
233 writel_relaxed(reg, drv->base + QDSP6SS_CGC_OVERRIDE);
234
235 return 0;
236}
237
238static int pil_q6v4_shutdown(struct pil_desc *pil)
239{
240 u32 reg;
241 struct q6v4_data *drv = dev_get_drvdata(pil->dev);
242
243 /* Turn off Q6 core clock */
244 writel_relaxed(Q6SS_SRC_SWITCH_CLK_OVR,
245 drv->base + QDSP6SS_GFMUX_CTL);
246
247 /* Assert resets */
248 reg = (Q6SS_SS_ARES | Q6SS_CORE_ARES | Q6SS_ISDB_ARES
249 | Q6SS_ETM_ARES | Q6SS_STOP_CORE_ARES | Q6SS_PRIV_ARES);
250 writel_relaxed(reg, drv->base + QDSP6SS_RESET);
251
252 /* Turn off Q6 memories */
253 writel_relaxed(Q6SS_CLAMP_IO, drv->base + QDSP6SS_PWR_CTL);
254
255 if (drv->modem_base)
256 pil_q6v4_shutdown_modem();
257
258 if (drv->vreg_enabled) {
259 regulator_disable(drv->vreg);
260 drv->vreg_enabled = false;
261 }
262
263 return 0;
264}
265
266static struct pil_reset_ops pil_q6v4_ops = {
267 .init_image = pil_q6v4_init_image,
268 .verify_blob = nop_verify_blob,
269 .auth_and_reset = pil_q6v4_reset,
270 .shutdown = pil_q6v4_shutdown,
271};
272
273static int pil_q6v4_init_image_trusted(struct pil_desc *pil,
274 const u8 *metadata, size_t size)
275{
276 const struct pil_q6v4_pdata *pdata = pil->dev->platform_data;
277 return pas_init_image(pdata->pas_id, metadata, size);
278}
279
280static int pil_q6v4_reset_trusted(struct pil_desc *pil)
281{
282 const struct pil_q6v4_pdata *pdata = pil->dev->platform_data;
283 int err;
284
285 err = pil_q6v4_power_up(pil->dev);
286 if (err)
287 return err;
288 return pas_auth_and_reset(pdata->pas_id);
289}
290
291static int pil_q6v4_shutdown_trusted(struct pil_desc *pil)
292{
293 int ret;
294 struct q6v4_data *drv = dev_get_drvdata(pil->dev);
295 struct pil_q6v4_pdata *pdata = pil->dev->platform_data;
296
297 ret = pas_shutdown(pdata->pas_id);
298 if (ret)
299 return ret;
300
301 if (drv->vreg_enabled) {
302 regulator_disable(drv->vreg);
303 drv->vreg_enabled = false;
304 }
305
306 return ret;
307}
308
309static struct pil_reset_ops pil_q6v4_ops_trusted = {
310 .init_image = pil_q6v4_init_image_trusted,
311 .verify_blob = nop_verify_blob,
312 .auth_and_reset = pil_q6v4_reset_trusted,
313 .shutdown = pil_q6v4_shutdown_trusted,
314};
315
316static int __devinit pil_q6v4_driver_probe(struct platform_device *pdev)
317{
318 const struct pil_q6v4_pdata *pdata = pdev->dev.platform_data;
319 struct q6v4_data *drv;
320 struct resource *res;
321 struct pil_desc *desc;
322
323 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
324 if (!res)
325 return -EINVAL;
326
327 drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
328 if (!drv)
329 return -ENOMEM;
330 platform_set_drvdata(pdev, drv);
331
332 drv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
333 if (!drv->base)
334 return -ENOMEM;
335
336 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
337 if (res) {
338 drv->modem_base = devm_ioremap(&pdev->dev, res->start,
339 resource_size(res));
340 if (!drv->modem_base)
341 return -ENOMEM;
342 }
343
344 desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
345 if (!drv)
346 return -ENOMEM;
347
348 desc->name = pdata->name;
349 desc->depends_on = pdata->depends;
350 desc->dev = &pdev->dev;
351
352 if (pas_supported(pdata->pas_id) > 0) {
353 desc->ops = &pil_q6v4_ops_trusted;
354 dev_info(&pdev->dev, "using secure boot\n");
355 } else {
356 desc->ops = &pil_q6v4_ops;
357 dev_info(&pdev->dev, "using non-secure boot\n");
358 }
359
360 drv->vreg = regulator_get(&pdev->dev, "core_vdd");
361 if (IS_ERR(drv->vreg))
362 return PTR_ERR(drv->vreg);
363
364 if (msm_pil_register(desc)) {
365 regulator_put(drv->vreg);
366 return -EINVAL;
367 }
368 return 0;
369}
370
371static int __devexit pil_q6v4_driver_exit(struct platform_device *pdev)
372{
373 struct q6v4_data *drv = platform_get_drvdata(pdev);
374 regulator_put(drv->vreg);
375 return 0;
376}
377
378static struct platform_driver pil_q6v4_driver = {
379 .probe = pil_q6v4_driver_probe,
380 .remove = __devexit_p(pil_q6v4_driver_exit),
381 .driver = {
382 .name = "pil_qdsp6v4",
383 .owner = THIS_MODULE,
384 },
385};
386
387static int __init pil_q6v4_init(void)
388{
389 return platform_driver_register(&pil_q6v4_driver);
390}
391module_init(pil_q6v4_init);
392
393static void __exit pil_q6v4_exit(void)
394{
395 platform_driver_unregister(&pil_q6v4_driver);
396}
397module_exit(pil_q6v4_exit);
398
399MODULE_DESCRIPTION("Support for booting QDSP6v4 (Hexagon) processors");
400MODULE_LICENSE("GPL v2");