blob: 7089772a92a18c7b649513c314bab90044738bc1 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2010-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/err.h>
15#include <linux/io.h>
16#include <linux/elf.h>
17#include <linux/delay.h>
18#include <linux/module.h>
19#include <linux/slab.h>
20#include <linux/clk.h>
21#include <linux/timer.h>
22#include <linux/jiffies.h>
23
24#include <mach/scm.h>
25#include <mach/msm_iomap.h>
26#include <mach/msm_xo.h>
27
28#include "peripheral-loader.h"
29
30#define PROXY_VOTE_TIMEOUT 10000
31
32#define MSM_MMS_REGS_BASE 0x10200000
33#define MSM_LPASS_QDSP6SS_BASE 0x28800000
34
35#define MARM_RESET (MSM_CLK_CTL_BASE + 0x2BD4)
36#define MARM_BOOT_CONTROL (msm_mms_regs_base + 0x0010)
37#define MAHB0_SFAB_PORT_RESET (MSM_CLK_CTL_BASE + 0x2304)
38#define MARM_CLK_BRANCH_ENA_VOTE (MSM_CLK_CTL_BASE + 0x3000)
39#define MARM_CLK_SRC0_NS (MSM_CLK_CTL_BASE + 0x2BC0)
40#define MARM_CLK_SRC1_NS (MSM_CLK_CTL_BASE + 0x2BC4)
41#define MARM_CLK_SRC_CTL (MSM_CLK_CTL_BASE + 0x2BC8)
42#define MARM_CLK_CTL (MSM_CLK_CTL_BASE + 0x2BCC)
43#define SFAB_MSS_S_HCLK_CTL (MSM_CLK_CTL_BASE + 0x2C00)
44#define MSS_MODEM_CXO_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C44)
45#define MSS_SLP_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C60)
46#define MSS_MARM_SYS_REF_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C64)
47#define MAHB0_CLK_CTL (MSM_CLK_CTL_BASE + 0x2300)
48#define MAHB1_CLK_CTL (MSM_CLK_CTL_BASE + 0x2BE4)
49#define MAHB2_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C20)
50#define MAHB1_NS (MSM_CLK_CTL_BASE + 0x2BE0)
51#define MARM_CLK_FS (MSM_CLK_CTL_BASE + 0x2BD0)
52#define MAHB2_CLK_FS (MSM_CLK_CTL_BASE + 0x2C24)
53#define PLL_ENA_MARM (MSM_CLK_CTL_BASE + 0x3500)
54#define PLL8_STATUS (MSM_CLK_CTL_BASE + 0x3158)
55#define CLK_HALT_MSS_SMPSS_MISC_STATE (MSM_CLK_CTL_BASE + 0x2FDC)
56
57#define LCC_Q6_FUNC (MSM_LPASS_CLK_CTL_BASE + 0x001C)
58#define QDSP6SS_RST_EVB (msm_lpass_qdsp6ss_base + 0x0000)
59#define QDSP6SS_STRAP_TCM (msm_lpass_qdsp6ss_base + 0x001C)
60#define QDSP6SS_STRAP_AHB (msm_lpass_qdsp6ss_base + 0x0020)
61
62#define PPSS_RESET (MSM_CLK_CTL_BASE + 0x2594)
63#define PPSS_PROC_CLK_CTL (MSM_CLK_CTL_BASE + 0x2588)
64#define CLK_HALT_DFAB_STATE (MSM_CLK_CTL_BASE + 0x2FC8)
65
66#define PAS_MODEM 0
67#define PAS_Q6 1
68#define PAS_DSPS 2
69#define PAS_PLAYREADY 3
70
71#define PAS_INIT_IMAGE_CMD 1
72#define PAS_MEM_CMD 2
73#define PAS_AUTH_AND_RESET_CMD 5
74#define PAS_SHUTDOWN_CMD 6
75
76struct pas_init_image_req {
77 u32 proc;
78 u32 image_addr;
79};
80
81struct pas_init_image_resp {
82 u32 image_valid;
83};
84
85struct pas_auth_image_req {
86 u32 proc;
87};
88
89struct pas_auth_image_resp {
90 u32 reset_initiated;
91};
92
93struct pas_shutdown_req {
94 u32 proc;
95};
96
97struct pas_shutdown_resp {
98 u32 success;
99};
100
101static int modem_start, q6_start, dsps_start;
102static void __iomem *msm_mms_regs_base;
103static void __iomem *msm_lpass_qdsp6ss_base;
104
105static int init_image_trusted(int id, const u8 *metadata, size_t size)
106{
107 int ret;
108 struct pas_init_image_req request;
109 struct pas_init_image_resp resp = {0};
110 void *mdata_buf;
111
112 /* Make memory physically contiguous */
113 mdata_buf = kmemdup(metadata, size, GFP_KERNEL);
114 if (!mdata_buf)
115 return -ENOMEM;
116
117 request.proc = id;
118 request.image_addr = virt_to_phys(mdata_buf);
119
120 ret = scm_call(SCM_SVC_PIL, PAS_INIT_IMAGE_CMD, &request,
121 sizeof(request), &resp, sizeof(resp));
122 kfree(mdata_buf);
123
124 if (ret)
125 return ret;
126 return resp.image_valid;
127}
128
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700129static int init_image_modem_trusted(struct pil_device *pil, const u8 *metadata,
130 size_t size)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700131{
132 return init_image_trusted(PAS_MODEM, metadata, size);
133}
134
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700135static int init_image_modem_untrusted(struct pil_device *pil,
136 const u8 *metadata, size_t size)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700137{
138 struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
139 modem_start = ehdr->e_entry;
140 return 0;
141}
142
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700143static int init_image_q6_trusted(struct pil_device *pil,
144 const u8 *metadata, size_t size)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700145{
146 return init_image_trusted(PAS_Q6, metadata, size);
147}
148
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700149static int init_image_q6_untrusted(struct pil_device *pil, const u8 *metadata,
150 size_t size)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700151{
152 struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
153 q6_start = ehdr->e_entry;
154 return 0;
155}
156
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700157static int init_image_dsps_trusted(struct pil_device *pil, const u8 *metadata,
158 size_t size)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700159{
160 return init_image_trusted(PAS_DSPS, metadata, size);
161}
162
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700163static int init_image_dsps_untrusted(struct pil_device *pil, const u8 *metadata,
164 size_t size)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700165{
166 struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
167 dsps_start = ehdr->e_entry;
168 /* Bring memory and bus interface out of reset */
169 __raw_writel(0x2, PPSS_RESET);
170 mb();
171 return 0;
172}
173
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700174static int verify_blob(struct pil_device *pil, u32 phy_addr, size_t size)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700175{
176 return 0;
177}
178
179static int auth_and_reset_trusted(int id)
180{
181 int ret;
182 struct pas_auth_image_req request;
183 struct pas_auth_image_resp resp = {0};
184
185 request.proc = id;
186 ret = scm_call(SCM_SVC_PIL, PAS_AUTH_AND_RESET_CMD, &request,
187 sizeof(request), &resp, sizeof(resp));
188 if (ret)
189 return ret;
190
191 return resp.reset_initiated;
192}
193
194static struct msm_xo_voter *pxo;
195static void remove_modem_proxy_votes(unsigned long data)
196{
197 msm_xo_mode_vote(pxo, MSM_XO_MODE_OFF);
198}
199static DEFINE_TIMER(modem_timer, remove_modem_proxy_votes, 0, 0);
200
201static void make_modem_proxy_votes(void)
202{
203 /* Make proxy votes for modem and set up timer to disable it. */
204 msm_xo_mode_vote(pxo, MSM_XO_MODE_ON);
205 mod_timer(&modem_timer, jiffies + msecs_to_jiffies(PROXY_VOTE_TIMEOUT));
206}
207
208static void remove_modem_proxy_votes_now(void)
209{
210 /*
211 * If the modem proxy vote hasn't been removed yet, them remove the
212 * votes immediately.
213 */
214 if (del_timer(&modem_timer))
215 remove_modem_proxy_votes(0);
216}
217
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700218static int reset_modem_untrusted(struct pil_device *pil)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700219{
220 u32 reg;
221
222 make_modem_proxy_votes();
223
224 /* Put modem AHB0,1,2 clocks into reset */
225 __raw_writel(BIT(0) | BIT(1), MAHB0_SFAB_PORT_RESET);
226 __raw_writel(BIT(7), MAHB1_CLK_CTL);
227 __raw_writel(BIT(7), MAHB2_CLK_CTL);
228
229 /* Vote for pll8 on behalf of the modem */
230 reg = __raw_readl(PLL_ENA_MARM);
231 reg |= BIT(8);
232 __raw_writel(reg, PLL_ENA_MARM);
233
234 /* Wait for PLL8 to enable */
235 while (!(__raw_readl(PLL8_STATUS) & BIT(16)))
236 cpu_relax();
237
238 /* Set MAHB1 divider to Div-5 to run MAHB1,2 and sfab at 79.8 Mhz*/
239 __raw_writel(0x4, MAHB1_NS);
240
241 /* Vote for modem AHB1 and 2 clocks to be on on behalf of the modem */
242 reg = __raw_readl(MARM_CLK_BRANCH_ENA_VOTE);
243 reg |= BIT(0) | BIT(1);
244 __raw_writel(reg, MARM_CLK_BRANCH_ENA_VOTE);
245
246 /* Source marm_clk off of PLL8 */
247 reg = __raw_readl(MARM_CLK_SRC_CTL);
248 if ((reg & 0x1) == 0) {
249 __raw_writel(0x3, MARM_CLK_SRC1_NS);
250 reg |= 0x1;
251 } else {
252 __raw_writel(0x3, MARM_CLK_SRC0_NS);
253 reg &= ~0x1;
254 }
255 __raw_writel(reg | 0x2, MARM_CLK_SRC_CTL);
256
257 /*
258 * Force core on and periph on signals to remain active during halt
259 * for marm_clk and mahb2_clk
260 */
261 __raw_writel(0x6F, MARM_CLK_FS);
262 __raw_writel(0x6F, MAHB2_CLK_FS);
263
264 /*
265 * Enable all of the marm_clk branches, cxo sourced marm branches,
266 * and sleep clock branches
267 */
268 __raw_writel(0x10, MARM_CLK_CTL);
269 __raw_writel(0x10, MAHB0_CLK_CTL);
270 __raw_writel(0x10, SFAB_MSS_S_HCLK_CTL);
271 __raw_writel(0x10, MSS_MODEM_CXO_CLK_CTL);
272 __raw_writel(0x10, MSS_SLP_CLK_CTL);
273 __raw_writel(0x10, MSS_MARM_SYS_REF_CLK_CTL);
274
275 /* Wait for above clocks to be turned on */
276 while (__raw_readl(CLK_HALT_MSS_SMPSS_MISC_STATE) & (BIT(7) | BIT(8) |
277 BIT(9) | BIT(10) | BIT(4) | BIT(6)))
278 cpu_relax();
279
280 /* Take MAHB0,1,2 clocks out of reset */
281 __raw_writel(0x0, MAHB2_CLK_CTL);
282 __raw_writel(0x0, MAHB1_CLK_CTL);
283 __raw_writel(0x0, MAHB0_SFAB_PORT_RESET);
284
285 /* Setup exception vector table base address */
286 __raw_writel(modem_start | 0x1, MARM_BOOT_CONTROL);
287
288 /* Wait for vector table to be setup */
289 mb();
290
291 /* Bring modem out of reset */
292 __raw_writel(0x0, MARM_RESET);
293
294 return 0;
295}
296
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700297static int reset_modem_trusted(struct pil_device *pil)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700298{
299 int ret;
300
301 make_modem_proxy_votes();
302
303 ret = auth_and_reset_trusted(PAS_MODEM);
304 if (ret)
305 remove_modem_proxy_votes_now();
306
307 return ret;
308}
309
310static int shutdown_trusted(int id)
311{
312 int ret;
313 struct pas_shutdown_req request;
314 struct pas_shutdown_resp resp = {0};
315
316 request.proc = id;
317 ret = scm_call(SCM_SVC_PIL, PAS_SHUTDOWN_CMD, &request, sizeof(request),
318 &resp, sizeof(resp));
319 if (ret)
320 return ret;
321
322 return resp.success;
323}
324
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700325static int shutdown_modem_untrusted(struct pil_device *pil)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700326{
327 u32 reg;
328
329 /* Put modem into reset */
330 __raw_writel(0x1, MARM_RESET);
331 mb();
332
333 /* Put modem AHB0,1,2 clocks into reset */
334 __raw_writel(BIT(0) | BIT(1), MAHB0_SFAB_PORT_RESET);
335 __raw_writel(BIT(7), MAHB1_CLK_CTL);
336 __raw_writel(BIT(7), MAHB2_CLK_CTL);
337 mb();
338
339 /*
340 * Disable all of the marm_clk branches, cxo sourced marm branches,
341 * and sleep clock branches
342 */
343 __raw_writel(0x0, MARM_CLK_CTL);
344 __raw_writel(0x0, MAHB0_CLK_CTL);
345 __raw_writel(0x0, SFAB_MSS_S_HCLK_CTL);
346 __raw_writel(0x0, MSS_MODEM_CXO_CLK_CTL);
347 __raw_writel(0x0, MSS_SLP_CLK_CTL);
348 __raw_writel(0x0, MSS_MARM_SYS_REF_CLK_CTL);
349
350 /* Disable marm_clk */
351 reg = __raw_readl(MARM_CLK_SRC_CTL);
352 reg &= ~0x2;
353 __raw_writel(reg, MARM_CLK_SRC_CTL);
354
355 /* Clear modem's votes for ahb clocks */
356 __raw_writel(0x0, MARM_CLK_BRANCH_ENA_VOTE);
357
358 /* Clear modem's votes for PLLs */
359 __raw_writel(0x0, PLL_ENA_MARM);
360
361 remove_modem_proxy_votes_now();
362
363 return 0;
364}
365
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700366static int shutdown_modem_trusted(struct pil_device *pil)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700367{
368 int ret;
369
370 ret = shutdown_trusted(PAS_MODEM);
371 if (ret)
372 return ret;
373
374 remove_modem_proxy_votes_now();
375
376 return 0;
377}
378
379#define LV_EN BIT(27)
380#define STOP_CORE BIT(26)
381#define CLAMP_IO BIT(25)
382#define Q6SS_PRIV_ARES BIT(24)
383#define Q6SS_SS_ARES BIT(23)
384#define Q6SS_ISDB_ARES BIT(22)
385#define Q6SS_ETM_ARES BIT(21)
386#define Q6_JTAG_CRC_EN BIT(20)
387#define Q6_JTAG_INV_EN BIT(19)
388#define Q6_JTAG_CXC_EN BIT(18)
389#define Q6_PXO_CRC_EN BIT(17)
390#define Q6_PXO_INV_EN BIT(16)
391#define Q6_PXO_CXC_EN BIT(15)
392#define Q6_PXO_SLEEP_EN BIT(14)
393#define Q6_SLP_CRC_EN BIT(13)
394#define Q6_SLP_INV_EN BIT(12)
395#define Q6_SLP_CXC_EN BIT(11)
396#define CORE_ARES BIT(10)
397#define CORE_L1_MEM_CORE_EN BIT(9)
398#define CORE_TCM_MEM_CORE_EN BIT(8)
399#define CORE_TCM_MEM_PERPH_EN BIT(7)
400#define CORE_GFM4_CLK_EN BIT(2)
401#define CORE_GFM4_RES BIT(1)
402#define RAMP_PLL_SRC_SEL BIT(0)
403
404#define Q6_STRAP_AHB_UPPER (0x290 << 12)
405#define Q6_STRAP_AHB_LOWER 0x280
406#define Q6_STRAP_TCM_BASE (0x28C << 15)
407#define Q6_STRAP_TCM_CONFIG 0x28B
408
409static struct clk *pll4;
410
411static void remove_q6_proxy_votes(unsigned long data)
412{
413 clk_disable(pll4);
414}
415static DEFINE_TIMER(q6_timer, remove_q6_proxy_votes, 0, 0);
416
417static void make_q6_proxy_votes(void)
418{
419 /* Make proxy votes for Q6 and set up timer to disable it. */
420 clk_enable(pll4);
421 mod_timer(&q6_timer, jiffies + msecs_to_jiffies(PROXY_VOTE_TIMEOUT));
422}
423
424static void remove_q6_proxy_votes_now(void)
425{
426 /*
427 * If the Q6 proxy vote hasn't been removed yet, them remove the
428 * votes immediately.
429 */
430 if (del_timer(&q6_timer))
431 remove_q6_proxy_votes(0);
432}
433
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700434static int reset_q6_untrusted(struct pil_device *pil)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700435{
436 u32 reg;
437
438 make_q6_proxy_votes();
439
440 /* Put Q6 into reset */
441 reg = __raw_readl(LCC_Q6_FUNC);
442 reg |= Q6SS_SS_ARES | Q6SS_ISDB_ARES | Q6SS_ETM_ARES | STOP_CORE |
443 CORE_ARES;
444 reg &= ~CORE_GFM4_CLK_EN;
445 __raw_writel(reg, LCC_Q6_FUNC);
446
447 /* Wait 8 AHB cycles for Q6 to be fully reset (AHB = 1.5Mhz) */
448 usleep_range(20, 30);
449
450 /* Turn on Q6 memory */
451 reg |= CORE_GFM4_CLK_EN | CORE_L1_MEM_CORE_EN | CORE_TCM_MEM_CORE_EN |
452 CORE_TCM_MEM_PERPH_EN;
453 __raw_writel(reg, LCC_Q6_FUNC);
454
455 /* Turn on Q6 core clocks and take core out of reset */
456 reg &= ~(CLAMP_IO | Q6SS_SS_ARES | Q6SS_ISDB_ARES | Q6SS_ETM_ARES |
457 CORE_ARES);
458 __raw_writel(reg, LCC_Q6_FUNC);
459
460 /* Wait for clocks to be enabled */
461 mb();
462 /* Program boot address */
463 __raw_writel((q6_start >> 12) & 0xFFFFF, QDSP6SS_RST_EVB);
464
465 __raw_writel(Q6_STRAP_TCM_CONFIG | Q6_STRAP_TCM_BASE,
466 QDSP6SS_STRAP_TCM);
467 __raw_writel(Q6_STRAP_AHB_UPPER | Q6_STRAP_AHB_LOWER,
468 QDSP6SS_STRAP_AHB);
469
470 /* Wait for addresses to be programmed before starting Q6 */
471 mb();
472
473 /* Start Q6 instruction execution */
474 reg &= ~STOP_CORE;
475 __raw_writel(reg, LCC_Q6_FUNC);
476
477 return 0;
478}
479
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700480static int reset_q6_trusted(struct pil_device *pil)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700481{
482 make_q6_proxy_votes();
483
484 return auth_and_reset_trusted(PAS_Q6);
485}
486
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700487static int shutdown_q6_untrusted(struct pil_device *pil)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700488{
489 u32 reg;
490
491 /* Put Q6 into reset */
492 reg = __raw_readl(LCC_Q6_FUNC);
493 reg |= Q6SS_SS_ARES | Q6SS_ISDB_ARES | Q6SS_ETM_ARES | STOP_CORE |
494 CORE_ARES;
495 reg &= ~CORE_GFM4_CLK_EN;
496 __raw_writel(reg, LCC_Q6_FUNC);
497
498 /* Wait 8 AHB cycles for Q6 to be fully reset (AHB = 1.5Mhz) */
499 usleep_range(20, 30);
500
501 /* Turn off Q6 memory */
502 reg &= ~(CORE_L1_MEM_CORE_EN | CORE_TCM_MEM_CORE_EN |
503 CORE_TCM_MEM_PERPH_EN);
504 __raw_writel(reg, LCC_Q6_FUNC);
505
506 reg |= CLAMP_IO;
507 __raw_writel(reg, LCC_Q6_FUNC);
508
509 remove_q6_proxy_votes_now();
510
511 return 0;
512}
513
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700514static int shutdown_q6_trusted(struct pil_device *pil)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700515{
516 int ret;
517
518 ret = shutdown_trusted(PAS_Q6);
519 if (ret)
520 return ret;
521
522 remove_q6_proxy_votes_now();
523
524 return 0;
525}
526
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700527static int reset_dsps_untrusted(struct pil_device *pil)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700528{
529 __raw_writel(0x10, PPSS_PROC_CLK_CTL);
530 while (__raw_readl(CLK_HALT_DFAB_STATE) & BIT(18))
531 cpu_relax();
532
533 /* Bring DSPS out of reset */
534 __raw_writel(0x0, PPSS_RESET);
535 return 0;
536}
537
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700538static int reset_dsps_trusted(struct pil_device *pil)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700539{
540 return auth_and_reset_trusted(PAS_DSPS);
541}
542
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700543static int shutdown_dsps_trusted(struct pil_device *pil)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700544{
545 return shutdown_trusted(PAS_DSPS);
546}
547
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700548static int shutdown_dsps_untrusted(struct pil_device *pil)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700549{
550 __raw_writel(0x2, PPSS_RESET);
551 __raw_writel(0x0, PPSS_PROC_CLK_CTL);
552 return 0;
553}
554
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700555static int init_image_playready(struct pil_device *pil, const u8 *metadata,
556 size_t size)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700557{
558 return init_image_trusted(PAS_PLAYREADY, metadata, size);
559}
560
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700561static int reset_playready(struct pil_device *pil)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700562{
563 return auth_and_reset_trusted(PAS_PLAYREADY);
564}
565
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700566static int shutdown_playready(struct pil_device *pil)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700567{
568 return shutdown_trusted(PAS_PLAYREADY);
569}
570
571struct pil_reset_ops pil_modem_ops = {
572 .init_image = init_image_modem_untrusted,
573 .verify_blob = verify_blob,
574 .auth_and_reset = reset_modem_untrusted,
575 .shutdown = shutdown_modem_untrusted,
576};
577
578struct pil_reset_ops pil_q6_ops = {
579 .init_image = init_image_q6_untrusted,
580 .verify_blob = verify_blob,
581 .auth_and_reset = reset_q6_untrusted,
582 .shutdown = shutdown_q6_untrusted,
583};
584
585struct pil_reset_ops pil_dsps_ops = {
586 .init_image = init_image_dsps_untrusted,
587 .verify_blob = verify_blob,
588 .auth_and_reset = reset_dsps_untrusted,
589 .shutdown = shutdown_dsps_untrusted,
590};
591
592struct pil_reset_ops pil_playready_ops = {
593 .init_image = init_image_playready,
594 .verify_blob = verify_blob,
595 .auth_and_reset = reset_playready,
596 .shutdown = shutdown_playready,
597};
598
599static struct pil_device peripherals[] = {
600 {
601 .name = "modem",
602 .depends_on = "q6",
603 .pdev = {
604 .name = "pil_modem",
605 .id = -1,
606 },
607 .ops = &pil_modem_ops,
608 },
609 {
610 .name = "q6",
611 .pdev = {
612 .name = "pil_q6",
613 .id = -1,
614 },
615 .ops = &pil_q6_ops,
616 },
617 {
618 .name = "playrdy",
619 .pdev = {
620 .name = "pil_playready",
621 .id = -1,
622 },
623 .ops = &pil_playready_ops,
624 },
625};
626
627struct pil_device peripheral_dsps = {
628 .name = "dsps",
629 .pdev = {
630 .name = "pil_dsps",
631 .id = -1,
632 },
633 .ops = &pil_dsps_ops,
634};
635
636#ifdef CONFIG_MSM_SECURE_PIL
637#define SECURE_PIL 1
638#else
639#define SECURE_PIL 0
640#endif
641
642static int __init msm_peripheral_reset_init(void)
643{
644 unsigned i;
645
646 msm_mms_regs_base = ioremap(MSM_MMS_REGS_BASE, SZ_256);
647 if (!msm_mms_regs_base)
648 goto err;
649
650 msm_lpass_qdsp6ss_base = ioremap(MSM_LPASS_QDSP6SS_BASE, SZ_256);
651 if (!msm_lpass_qdsp6ss_base)
652 goto err_lpass;
653
654 pxo = msm_xo_get(MSM_XO_PXO, "pil");
655 if (IS_ERR(pxo))
656 goto err_pxo;
657
658 pll4 = clk_get_sys("peripheral-reset", "pll4");
659 if (IS_ERR(pll4))
660 goto err_clk;
661
662 if (SECURE_PIL) {
663 pil_modem_ops.init_image = init_image_modem_trusted;
664 pil_modem_ops.auth_and_reset = reset_modem_trusted;
665 pil_modem_ops.shutdown = shutdown_modem_trusted;
666
667 pil_q6_ops.init_image = init_image_q6_trusted;
668 pil_q6_ops.auth_and_reset = reset_q6_trusted;
669 pil_q6_ops.shutdown = shutdown_q6_trusted;
670
671 pil_dsps_ops.init_image = init_image_dsps_trusted;
672 pil_dsps_ops.auth_and_reset = reset_dsps_trusted;
673 pil_dsps_ops.shutdown = shutdown_dsps_trusted;
674 }
675
676 for (i = 0; i < ARRAY_SIZE(peripherals); i++)
677 msm_pil_add_device(&peripherals[i]);
678
679 return 0;
680
681err_clk:
682 msm_xo_put(pxo);
683err_pxo:
684 iounmap(msm_lpass_qdsp6ss_base);
685err_lpass:
686 iounmap(msm_mms_regs_base);
687err:
688 return -ENOMEM;
689}
690
691static void __exit msm_peripheral_reset_exit(void)
692{
693 iounmap(msm_mms_regs_base);
694 iounmap(msm_lpass_qdsp6ss_base);
695}
696
697arch_initcall(msm_peripheral_reset_init);
698module_exit(msm_peripheral_reset_exit);
699
700MODULE_LICENSE("GPL v2");
701MODULE_DESCRIPTION("Validate and bring peripherals out of reset");