blob: 5456e14ad69b2eff913a7901aa3df54112e85c9c [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"
Stephen Boyde44ec392011-08-29 12:03:24 -070029#include "scm-pas.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070030
31#define PROXY_VOTE_TIMEOUT 10000
32
33#define MSM_MMS_REGS_BASE 0x10200000
34#define MSM_LPASS_QDSP6SS_BASE 0x28800000
35
36#define MARM_RESET (MSM_CLK_CTL_BASE + 0x2BD4)
37#define MARM_BOOT_CONTROL (msm_mms_regs_base + 0x0010)
38#define MAHB0_SFAB_PORT_RESET (MSM_CLK_CTL_BASE + 0x2304)
39#define MARM_CLK_BRANCH_ENA_VOTE (MSM_CLK_CTL_BASE + 0x3000)
40#define MARM_CLK_SRC0_NS (MSM_CLK_CTL_BASE + 0x2BC0)
41#define MARM_CLK_SRC1_NS (MSM_CLK_CTL_BASE + 0x2BC4)
42#define MARM_CLK_SRC_CTL (MSM_CLK_CTL_BASE + 0x2BC8)
43#define MARM_CLK_CTL (MSM_CLK_CTL_BASE + 0x2BCC)
44#define SFAB_MSS_S_HCLK_CTL (MSM_CLK_CTL_BASE + 0x2C00)
45#define MSS_MODEM_CXO_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C44)
46#define MSS_SLP_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C60)
47#define MSS_MARM_SYS_REF_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C64)
48#define MAHB0_CLK_CTL (MSM_CLK_CTL_BASE + 0x2300)
49#define MAHB1_CLK_CTL (MSM_CLK_CTL_BASE + 0x2BE4)
50#define MAHB2_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C20)
51#define MAHB1_NS (MSM_CLK_CTL_BASE + 0x2BE0)
52#define MARM_CLK_FS (MSM_CLK_CTL_BASE + 0x2BD0)
53#define MAHB2_CLK_FS (MSM_CLK_CTL_BASE + 0x2C24)
54#define PLL_ENA_MARM (MSM_CLK_CTL_BASE + 0x3500)
55#define PLL8_STATUS (MSM_CLK_CTL_BASE + 0x3158)
56#define CLK_HALT_MSS_SMPSS_MISC_STATE (MSM_CLK_CTL_BASE + 0x2FDC)
57
58#define LCC_Q6_FUNC (MSM_LPASS_CLK_CTL_BASE + 0x001C)
59#define QDSP6SS_RST_EVB (msm_lpass_qdsp6ss_base + 0x0000)
60#define QDSP6SS_STRAP_TCM (msm_lpass_qdsp6ss_base + 0x001C)
61#define QDSP6SS_STRAP_AHB (msm_lpass_qdsp6ss_base + 0x0020)
62
63#define PPSS_RESET (MSM_CLK_CTL_BASE + 0x2594)
64#define PPSS_PROC_CLK_CTL (MSM_CLK_CTL_BASE + 0x2588)
65#define CLK_HALT_DFAB_STATE (MSM_CLK_CTL_BASE + 0x2FC8)
66
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070067static int modem_start, q6_start, dsps_start;
68static void __iomem *msm_mms_regs_base;
69static void __iomem *msm_lpass_qdsp6ss_base;
70
Stephen Boyd5bd999a2011-08-02 18:50:57 -070071static int init_image_modem_trusted(struct pil_device *pil, const u8 *metadata,
72 size_t size)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070073{
Stephen Boyde44ec392011-08-29 12:03:24 -070074 return pas_init_image(PAS_MODEM, metadata, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070075}
76
Stephen Boyd5bd999a2011-08-02 18:50:57 -070077static int init_image_modem_untrusted(struct pil_device *pil,
78 const u8 *metadata, size_t size)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070079{
80 struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
81 modem_start = ehdr->e_entry;
82 return 0;
83}
84
Stephen Boyd5bd999a2011-08-02 18:50:57 -070085static int init_image_q6_trusted(struct pil_device *pil,
86 const u8 *metadata, size_t size)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070087{
Stephen Boyde44ec392011-08-29 12:03:24 -070088 return pas_init_image(PAS_Q6, metadata, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070089}
90
Stephen Boyd5bd999a2011-08-02 18:50:57 -070091static int init_image_q6_untrusted(struct pil_device *pil, const u8 *metadata,
92 size_t size)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070093{
94 struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
95 q6_start = ehdr->e_entry;
96 return 0;
97}
98
Stephen Boyd5bd999a2011-08-02 18:50:57 -070099static int init_image_dsps_trusted(struct pil_device *pil, const u8 *metadata,
100 size_t size)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700101{
Stephen Boyde44ec392011-08-29 12:03:24 -0700102 return pas_init_image(PAS_DSPS, metadata, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700103}
104
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700105static int init_image_dsps_untrusted(struct pil_device *pil, const u8 *metadata,
106 size_t size)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700107{
108 struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
109 dsps_start = ehdr->e_entry;
110 /* Bring memory and bus interface out of reset */
111 __raw_writel(0x2, PPSS_RESET);
112 mb();
113 return 0;
114}
115
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700116static int verify_blob(struct pil_device *pil, u32 phy_addr, size_t size)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700117{
118 return 0;
119}
120
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700121static struct msm_xo_voter *pxo;
122static void remove_modem_proxy_votes(unsigned long data)
123{
124 msm_xo_mode_vote(pxo, MSM_XO_MODE_OFF);
125}
126static DEFINE_TIMER(modem_timer, remove_modem_proxy_votes, 0, 0);
127
128static void make_modem_proxy_votes(void)
129{
130 /* Make proxy votes for modem and set up timer to disable it. */
131 msm_xo_mode_vote(pxo, MSM_XO_MODE_ON);
132 mod_timer(&modem_timer, jiffies + msecs_to_jiffies(PROXY_VOTE_TIMEOUT));
133}
134
135static void remove_modem_proxy_votes_now(void)
136{
137 /*
138 * If the modem proxy vote hasn't been removed yet, them remove the
139 * votes immediately.
140 */
141 if (del_timer(&modem_timer))
142 remove_modem_proxy_votes(0);
143}
144
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700145static int reset_modem_untrusted(struct pil_device *pil)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700146{
147 u32 reg;
148
149 make_modem_proxy_votes();
150
151 /* Put modem AHB0,1,2 clocks into reset */
152 __raw_writel(BIT(0) | BIT(1), MAHB0_SFAB_PORT_RESET);
153 __raw_writel(BIT(7), MAHB1_CLK_CTL);
154 __raw_writel(BIT(7), MAHB2_CLK_CTL);
155
156 /* Vote for pll8 on behalf of the modem */
157 reg = __raw_readl(PLL_ENA_MARM);
158 reg |= BIT(8);
159 __raw_writel(reg, PLL_ENA_MARM);
160
161 /* Wait for PLL8 to enable */
162 while (!(__raw_readl(PLL8_STATUS) & BIT(16)))
163 cpu_relax();
164
165 /* Set MAHB1 divider to Div-5 to run MAHB1,2 and sfab at 79.8 Mhz*/
166 __raw_writel(0x4, MAHB1_NS);
167
168 /* Vote for modem AHB1 and 2 clocks to be on on behalf of the modem */
169 reg = __raw_readl(MARM_CLK_BRANCH_ENA_VOTE);
170 reg |= BIT(0) | BIT(1);
171 __raw_writel(reg, MARM_CLK_BRANCH_ENA_VOTE);
172
173 /* Source marm_clk off of PLL8 */
174 reg = __raw_readl(MARM_CLK_SRC_CTL);
175 if ((reg & 0x1) == 0) {
176 __raw_writel(0x3, MARM_CLK_SRC1_NS);
177 reg |= 0x1;
178 } else {
179 __raw_writel(0x3, MARM_CLK_SRC0_NS);
180 reg &= ~0x1;
181 }
182 __raw_writel(reg | 0x2, MARM_CLK_SRC_CTL);
183
184 /*
185 * Force core on and periph on signals to remain active during halt
186 * for marm_clk and mahb2_clk
187 */
188 __raw_writel(0x6F, MARM_CLK_FS);
189 __raw_writel(0x6F, MAHB2_CLK_FS);
190
191 /*
192 * Enable all of the marm_clk branches, cxo sourced marm branches,
193 * and sleep clock branches
194 */
195 __raw_writel(0x10, MARM_CLK_CTL);
196 __raw_writel(0x10, MAHB0_CLK_CTL);
197 __raw_writel(0x10, SFAB_MSS_S_HCLK_CTL);
198 __raw_writel(0x10, MSS_MODEM_CXO_CLK_CTL);
199 __raw_writel(0x10, MSS_SLP_CLK_CTL);
200 __raw_writel(0x10, MSS_MARM_SYS_REF_CLK_CTL);
201
202 /* Wait for above clocks to be turned on */
203 while (__raw_readl(CLK_HALT_MSS_SMPSS_MISC_STATE) & (BIT(7) | BIT(8) |
204 BIT(9) | BIT(10) | BIT(4) | BIT(6)))
205 cpu_relax();
206
207 /* Take MAHB0,1,2 clocks out of reset */
208 __raw_writel(0x0, MAHB2_CLK_CTL);
209 __raw_writel(0x0, MAHB1_CLK_CTL);
210 __raw_writel(0x0, MAHB0_SFAB_PORT_RESET);
211
212 /* Setup exception vector table base address */
213 __raw_writel(modem_start | 0x1, MARM_BOOT_CONTROL);
214
215 /* Wait for vector table to be setup */
216 mb();
217
218 /* Bring modem out of reset */
219 __raw_writel(0x0, MARM_RESET);
220
221 return 0;
222}
223
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700224static int reset_modem_trusted(struct pil_device *pil)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700225{
226 int ret;
227
228 make_modem_proxy_votes();
229
Stephen Boyde44ec392011-08-29 12:03:24 -0700230 ret = pas_auth_and_reset(PAS_MODEM);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700231 if (ret)
232 remove_modem_proxy_votes_now();
233
234 return ret;
235}
236
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700237static int shutdown_modem_untrusted(struct pil_device *pil)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700238{
239 u32 reg;
240
241 /* Put modem into reset */
242 __raw_writel(0x1, MARM_RESET);
243 mb();
244
245 /* Put modem AHB0,1,2 clocks into reset */
246 __raw_writel(BIT(0) | BIT(1), MAHB0_SFAB_PORT_RESET);
247 __raw_writel(BIT(7), MAHB1_CLK_CTL);
248 __raw_writel(BIT(7), MAHB2_CLK_CTL);
249 mb();
250
251 /*
252 * Disable all of the marm_clk branches, cxo sourced marm branches,
253 * and sleep clock branches
254 */
255 __raw_writel(0x0, MARM_CLK_CTL);
256 __raw_writel(0x0, MAHB0_CLK_CTL);
257 __raw_writel(0x0, SFAB_MSS_S_HCLK_CTL);
258 __raw_writel(0x0, MSS_MODEM_CXO_CLK_CTL);
259 __raw_writel(0x0, MSS_SLP_CLK_CTL);
260 __raw_writel(0x0, MSS_MARM_SYS_REF_CLK_CTL);
261
262 /* Disable marm_clk */
263 reg = __raw_readl(MARM_CLK_SRC_CTL);
264 reg &= ~0x2;
265 __raw_writel(reg, MARM_CLK_SRC_CTL);
266
267 /* Clear modem's votes for ahb clocks */
268 __raw_writel(0x0, MARM_CLK_BRANCH_ENA_VOTE);
269
270 /* Clear modem's votes for PLLs */
271 __raw_writel(0x0, PLL_ENA_MARM);
272
273 remove_modem_proxy_votes_now();
274
275 return 0;
276}
277
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700278static int shutdown_modem_trusted(struct pil_device *pil)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700279{
280 int ret;
281
Stephen Boyde44ec392011-08-29 12:03:24 -0700282 ret = pas_shutdown(PAS_MODEM);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700283 if (ret)
284 return ret;
285
286 remove_modem_proxy_votes_now();
287
288 return 0;
289}
290
291#define LV_EN BIT(27)
292#define STOP_CORE BIT(26)
293#define CLAMP_IO BIT(25)
294#define Q6SS_PRIV_ARES BIT(24)
295#define Q6SS_SS_ARES BIT(23)
296#define Q6SS_ISDB_ARES BIT(22)
297#define Q6SS_ETM_ARES BIT(21)
298#define Q6_JTAG_CRC_EN BIT(20)
299#define Q6_JTAG_INV_EN BIT(19)
300#define Q6_JTAG_CXC_EN BIT(18)
301#define Q6_PXO_CRC_EN BIT(17)
302#define Q6_PXO_INV_EN BIT(16)
303#define Q6_PXO_CXC_EN BIT(15)
304#define Q6_PXO_SLEEP_EN BIT(14)
305#define Q6_SLP_CRC_EN BIT(13)
306#define Q6_SLP_INV_EN BIT(12)
307#define Q6_SLP_CXC_EN BIT(11)
308#define CORE_ARES BIT(10)
309#define CORE_L1_MEM_CORE_EN BIT(9)
310#define CORE_TCM_MEM_CORE_EN BIT(8)
311#define CORE_TCM_MEM_PERPH_EN BIT(7)
312#define CORE_GFM4_CLK_EN BIT(2)
313#define CORE_GFM4_RES BIT(1)
314#define RAMP_PLL_SRC_SEL BIT(0)
315
316#define Q6_STRAP_AHB_UPPER (0x290 << 12)
317#define Q6_STRAP_AHB_LOWER 0x280
318#define Q6_STRAP_TCM_BASE (0x28C << 15)
319#define Q6_STRAP_TCM_CONFIG 0x28B
320
321static struct clk *pll4;
322
323static void remove_q6_proxy_votes(unsigned long data)
324{
325 clk_disable(pll4);
326}
327static DEFINE_TIMER(q6_timer, remove_q6_proxy_votes, 0, 0);
328
329static void make_q6_proxy_votes(void)
330{
331 /* Make proxy votes for Q6 and set up timer to disable it. */
332 clk_enable(pll4);
333 mod_timer(&q6_timer, jiffies + msecs_to_jiffies(PROXY_VOTE_TIMEOUT));
334}
335
336static void remove_q6_proxy_votes_now(void)
337{
338 /*
339 * If the Q6 proxy vote hasn't been removed yet, them remove the
340 * votes immediately.
341 */
342 if (del_timer(&q6_timer))
343 remove_q6_proxy_votes(0);
344}
345
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700346static int reset_q6_untrusted(struct pil_device *pil)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700347{
348 u32 reg;
349
350 make_q6_proxy_votes();
351
352 /* Put Q6 into reset */
353 reg = __raw_readl(LCC_Q6_FUNC);
354 reg |= Q6SS_SS_ARES | Q6SS_ISDB_ARES | Q6SS_ETM_ARES | STOP_CORE |
355 CORE_ARES;
356 reg &= ~CORE_GFM4_CLK_EN;
357 __raw_writel(reg, LCC_Q6_FUNC);
358
359 /* Wait 8 AHB cycles for Q6 to be fully reset (AHB = 1.5Mhz) */
360 usleep_range(20, 30);
361
362 /* Turn on Q6 memory */
363 reg |= CORE_GFM4_CLK_EN | CORE_L1_MEM_CORE_EN | CORE_TCM_MEM_CORE_EN |
364 CORE_TCM_MEM_PERPH_EN;
365 __raw_writel(reg, LCC_Q6_FUNC);
366
367 /* Turn on Q6 core clocks and take core out of reset */
368 reg &= ~(CLAMP_IO | Q6SS_SS_ARES | Q6SS_ISDB_ARES | Q6SS_ETM_ARES |
369 CORE_ARES);
370 __raw_writel(reg, LCC_Q6_FUNC);
371
372 /* Wait for clocks to be enabled */
373 mb();
374 /* Program boot address */
375 __raw_writel((q6_start >> 12) & 0xFFFFF, QDSP6SS_RST_EVB);
376
377 __raw_writel(Q6_STRAP_TCM_CONFIG | Q6_STRAP_TCM_BASE,
378 QDSP6SS_STRAP_TCM);
379 __raw_writel(Q6_STRAP_AHB_UPPER | Q6_STRAP_AHB_LOWER,
380 QDSP6SS_STRAP_AHB);
381
382 /* Wait for addresses to be programmed before starting Q6 */
383 mb();
384
385 /* Start Q6 instruction execution */
386 reg &= ~STOP_CORE;
387 __raw_writel(reg, LCC_Q6_FUNC);
388
389 return 0;
390}
391
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700392static int reset_q6_trusted(struct pil_device *pil)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700393{
394 make_q6_proxy_votes();
395
Stephen Boyde44ec392011-08-29 12:03:24 -0700396 return pas_auth_and_reset(PAS_Q6);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700397}
398
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700399static int shutdown_q6_untrusted(struct pil_device *pil)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700400{
401 u32 reg;
402
403 /* Put Q6 into reset */
404 reg = __raw_readl(LCC_Q6_FUNC);
405 reg |= Q6SS_SS_ARES | Q6SS_ISDB_ARES | Q6SS_ETM_ARES | STOP_CORE |
406 CORE_ARES;
407 reg &= ~CORE_GFM4_CLK_EN;
408 __raw_writel(reg, LCC_Q6_FUNC);
409
410 /* Wait 8 AHB cycles for Q6 to be fully reset (AHB = 1.5Mhz) */
411 usleep_range(20, 30);
412
413 /* Turn off Q6 memory */
414 reg &= ~(CORE_L1_MEM_CORE_EN | CORE_TCM_MEM_CORE_EN |
415 CORE_TCM_MEM_PERPH_EN);
416 __raw_writel(reg, LCC_Q6_FUNC);
417
418 reg |= CLAMP_IO;
419 __raw_writel(reg, LCC_Q6_FUNC);
420
421 remove_q6_proxy_votes_now();
422
423 return 0;
424}
425
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700426static int shutdown_q6_trusted(struct pil_device *pil)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700427{
428 int ret;
429
Stephen Boyde44ec392011-08-29 12:03:24 -0700430 ret = pas_shutdown(PAS_Q6);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700431 if (ret)
432 return ret;
433
434 remove_q6_proxy_votes_now();
435
436 return 0;
437}
438
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700439static int reset_dsps_untrusted(struct pil_device *pil)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700440{
441 __raw_writel(0x10, PPSS_PROC_CLK_CTL);
442 while (__raw_readl(CLK_HALT_DFAB_STATE) & BIT(18))
443 cpu_relax();
444
445 /* Bring DSPS out of reset */
446 __raw_writel(0x0, PPSS_RESET);
447 return 0;
448}
449
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700450static int reset_dsps_trusted(struct pil_device *pil)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700451{
Stephen Boyde44ec392011-08-29 12:03:24 -0700452 return pas_auth_and_reset(PAS_DSPS);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700453}
454
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700455static int shutdown_dsps_trusted(struct pil_device *pil)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700456{
Stephen Boyde44ec392011-08-29 12:03:24 -0700457 return pas_shutdown(PAS_DSPS);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700458}
459
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700460static int shutdown_dsps_untrusted(struct pil_device *pil)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700461{
462 __raw_writel(0x2, PPSS_RESET);
463 __raw_writel(0x0, PPSS_PROC_CLK_CTL);
464 return 0;
465}
466
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700467static int init_image_playready(struct pil_device *pil, const u8 *metadata,
468 size_t size)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700469{
Stephen Boyde44ec392011-08-29 12:03:24 -0700470 return pas_init_image(PAS_PLAYREADY, metadata, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700471}
472
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700473static int reset_playready(struct pil_device *pil)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700474{
Stephen Boyde44ec392011-08-29 12:03:24 -0700475 return pas_auth_and_reset(PAS_PLAYREADY);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700476}
477
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700478static int shutdown_playready(struct pil_device *pil)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700479{
Stephen Boyde44ec392011-08-29 12:03:24 -0700480 return pas_shutdown(PAS_PLAYREADY);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700481}
482
483struct pil_reset_ops pil_modem_ops = {
484 .init_image = init_image_modem_untrusted,
485 .verify_blob = verify_blob,
486 .auth_and_reset = reset_modem_untrusted,
487 .shutdown = shutdown_modem_untrusted,
488};
489
490struct pil_reset_ops pil_q6_ops = {
491 .init_image = init_image_q6_untrusted,
492 .verify_blob = verify_blob,
493 .auth_and_reset = reset_q6_untrusted,
494 .shutdown = shutdown_q6_untrusted,
495};
496
497struct pil_reset_ops pil_dsps_ops = {
498 .init_image = init_image_dsps_untrusted,
499 .verify_blob = verify_blob,
500 .auth_and_reset = reset_dsps_untrusted,
501 .shutdown = shutdown_dsps_untrusted,
502};
503
504struct pil_reset_ops pil_playready_ops = {
505 .init_image = init_image_playready,
506 .verify_blob = verify_blob,
507 .auth_and_reset = reset_playready,
508 .shutdown = shutdown_playready,
509};
510
511static struct pil_device peripherals[] = {
512 {
513 .name = "modem",
514 .depends_on = "q6",
515 .pdev = {
516 .name = "pil_modem",
517 .id = -1,
518 },
519 .ops = &pil_modem_ops,
520 },
521 {
522 .name = "q6",
523 .pdev = {
524 .name = "pil_q6",
525 .id = -1,
526 },
527 .ops = &pil_q6_ops,
528 },
529 {
Stephen Boyd700819d2011-09-30 17:14:13 -0700530 .name = "tzapps",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700531 .pdev = {
532 .name = "pil_playready",
533 .id = -1,
534 },
535 .ops = &pil_playready_ops,
536 },
537};
538
539struct pil_device peripheral_dsps = {
540 .name = "dsps",
541 .pdev = {
542 .name = "pil_dsps",
543 .id = -1,
544 },
545 .ops = &pil_dsps_ops,
546};
547
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700548static int __init msm_peripheral_reset_init(void)
549{
550 unsigned i;
551
552 msm_mms_regs_base = ioremap(MSM_MMS_REGS_BASE, SZ_256);
553 if (!msm_mms_regs_base)
554 goto err;
555
556 msm_lpass_qdsp6ss_base = ioremap(MSM_LPASS_QDSP6SS_BASE, SZ_256);
557 if (!msm_lpass_qdsp6ss_base)
558 goto err_lpass;
559
560 pxo = msm_xo_get(MSM_XO_PXO, "pil");
561 if (IS_ERR(pxo))
562 goto err_pxo;
563
564 pll4 = clk_get_sys("peripheral-reset", "pll4");
565 if (IS_ERR(pll4))
566 goto err_clk;
567
Stephen Boyde44ec392011-08-29 12:03:24 -0700568 if (pas_supported(PAS_MODEM) > 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700569 pil_modem_ops.init_image = init_image_modem_trusted;
570 pil_modem_ops.auth_and_reset = reset_modem_trusted;
571 pil_modem_ops.shutdown = shutdown_modem_trusted;
Stephen Boyde44ec392011-08-29 12:03:24 -0700572 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700573
Stephen Boyde44ec392011-08-29 12:03:24 -0700574 if (pas_supported(PAS_Q6) > 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700575 pil_q6_ops.init_image = init_image_q6_trusted;
576 pil_q6_ops.auth_and_reset = reset_q6_trusted;
577 pil_q6_ops.shutdown = shutdown_q6_trusted;
Stephen Boyde44ec392011-08-29 12:03:24 -0700578 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700579
Stephen Boyde44ec392011-08-29 12:03:24 -0700580 if (pas_supported(PAS_DSPS) > 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700581 pil_dsps_ops.init_image = init_image_dsps_trusted;
582 pil_dsps_ops.auth_and_reset = reset_dsps_trusted;
583 pil_dsps_ops.shutdown = shutdown_dsps_trusted;
584 }
585
586 for (i = 0; i < ARRAY_SIZE(peripherals); i++)
587 msm_pil_add_device(&peripherals[i]);
588
589 return 0;
590
591err_clk:
592 msm_xo_put(pxo);
593err_pxo:
594 iounmap(msm_lpass_qdsp6ss_base);
595err_lpass:
596 iounmap(msm_mms_regs_base);
597err:
598 return -ENOMEM;
599}
600
601static void __exit msm_peripheral_reset_exit(void)
602{
603 iounmap(msm_mms_regs_base);
604 iounmap(msm_lpass_qdsp6ss_base);
605}
606
607arch_initcall(msm_peripheral_reset_init);
608module_exit(msm_peripheral_reset_exit);
609
610MODULE_LICENSE("GPL v2");
611MODULE_DESCRIPTION("Validate and bring peripherals out of reset");