blob: 2d60a7e5ee133f9a2daf4b31d25e51ff4b631e66 [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>
Stephen Boyd3f4da322011-08-30 01:03:23 -070023#include <linux/platform_device.h>
24
25#include <asm/mach-types.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070026
27#include <mach/scm.h>
28#include <mach/msm_iomap.h>
29#include <mach/msm_xo.h>
30
31#include "peripheral-loader.h"
Stephen Boyde44ec392011-08-29 12:03:24 -070032#include "scm-pas.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070033
34#define PROXY_VOTE_TIMEOUT 10000
35
36#define MSM_MMS_REGS_BASE 0x10200000
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070037
38#define MARM_RESET (MSM_CLK_CTL_BASE + 0x2BD4)
39#define MARM_BOOT_CONTROL (msm_mms_regs_base + 0x0010)
40#define MAHB0_SFAB_PORT_RESET (MSM_CLK_CTL_BASE + 0x2304)
41#define MARM_CLK_BRANCH_ENA_VOTE (MSM_CLK_CTL_BASE + 0x3000)
42#define MARM_CLK_SRC0_NS (MSM_CLK_CTL_BASE + 0x2BC0)
43#define MARM_CLK_SRC1_NS (MSM_CLK_CTL_BASE + 0x2BC4)
44#define MARM_CLK_SRC_CTL (MSM_CLK_CTL_BASE + 0x2BC8)
45#define MARM_CLK_CTL (MSM_CLK_CTL_BASE + 0x2BCC)
46#define SFAB_MSS_S_HCLK_CTL (MSM_CLK_CTL_BASE + 0x2C00)
47#define MSS_MODEM_CXO_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C44)
48#define MSS_SLP_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C60)
49#define MSS_MARM_SYS_REF_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C64)
50#define MAHB0_CLK_CTL (MSM_CLK_CTL_BASE + 0x2300)
51#define MAHB1_CLK_CTL (MSM_CLK_CTL_BASE + 0x2BE4)
52#define MAHB2_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C20)
53#define MAHB1_NS (MSM_CLK_CTL_BASE + 0x2BE0)
54#define MARM_CLK_FS (MSM_CLK_CTL_BASE + 0x2BD0)
55#define MAHB2_CLK_FS (MSM_CLK_CTL_BASE + 0x2C24)
56#define PLL_ENA_MARM (MSM_CLK_CTL_BASE + 0x3500)
57#define PLL8_STATUS (MSM_CLK_CTL_BASE + 0x3158)
58#define CLK_HALT_MSS_SMPSS_MISC_STATE (MSM_CLK_CTL_BASE + 0x2FDC)
59
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070060#define PPSS_RESET (MSM_CLK_CTL_BASE + 0x2594)
61#define PPSS_PROC_CLK_CTL (MSM_CLK_CTL_BASE + 0x2588)
62#define CLK_HALT_DFAB_STATE (MSM_CLK_CTL_BASE + 0x2FC8)
63
Stephen Boyd3acc9e42011-09-28 16:46:40 -070064static int modem_start, dsps_start;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070065static void __iomem *msm_mms_regs_base;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070066
Stephen Boyd3f4da322011-08-30 01:03:23 -070067static int init_image_modem_trusted(struct pil_desc *pil, const u8 *metadata,
Stephen Boyd5bd999a2011-08-02 18:50:57 -070068 size_t size)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070069{
Stephen Boyde44ec392011-08-29 12:03:24 -070070 return pas_init_image(PAS_MODEM, metadata, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070071}
72
Stephen Boyd3f4da322011-08-30 01:03:23 -070073static int init_image_modem_untrusted(struct pil_desc *pil,
Stephen Boyd5bd999a2011-08-02 18:50:57 -070074 const u8 *metadata, size_t size)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070075{
76 struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
77 modem_start = ehdr->e_entry;
78 return 0;
79}
80
Stephen Boyd3f4da322011-08-30 01:03:23 -070081static int init_image_dsps_trusted(struct pil_desc *pil, const u8 *metadata,
Stephen Boyd5bd999a2011-08-02 18:50:57 -070082 size_t size)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070083{
Stephen Boyde44ec392011-08-29 12:03:24 -070084 return pas_init_image(PAS_DSPS, metadata, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070085}
86
Stephen Boyd3f4da322011-08-30 01:03:23 -070087static int init_image_dsps_untrusted(struct pil_desc *pil, const u8 *metadata,
Stephen Boyd5bd999a2011-08-02 18:50:57 -070088 size_t size)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070089{
90 struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
91 dsps_start = ehdr->e_entry;
92 /* Bring memory and bus interface out of reset */
93 __raw_writel(0x2, PPSS_RESET);
94 mb();
95 return 0;
96}
97
Stephen Boyd3f4da322011-08-30 01:03:23 -070098static int verify_blob(struct pil_desc *pil, u32 phy_addr, size_t size)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070099{
100 return 0;
101}
102
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700103static struct msm_xo_voter *pxo;
104static void remove_modem_proxy_votes(unsigned long data)
105{
106 msm_xo_mode_vote(pxo, MSM_XO_MODE_OFF);
107}
108static DEFINE_TIMER(modem_timer, remove_modem_proxy_votes, 0, 0);
109
110static void make_modem_proxy_votes(void)
111{
112 /* Make proxy votes for modem and set up timer to disable it. */
113 msm_xo_mode_vote(pxo, MSM_XO_MODE_ON);
114 mod_timer(&modem_timer, jiffies + msecs_to_jiffies(PROXY_VOTE_TIMEOUT));
115}
116
117static void remove_modem_proxy_votes_now(void)
118{
119 /*
120 * If the modem proxy vote hasn't been removed yet, them remove the
121 * votes immediately.
122 */
123 if (del_timer(&modem_timer))
124 remove_modem_proxy_votes(0);
125}
126
Stephen Boyd3f4da322011-08-30 01:03:23 -0700127static int reset_modem_untrusted(struct pil_desc *pil)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700128{
129 u32 reg;
130
131 make_modem_proxy_votes();
132
133 /* Put modem AHB0,1,2 clocks into reset */
134 __raw_writel(BIT(0) | BIT(1), MAHB0_SFAB_PORT_RESET);
135 __raw_writel(BIT(7), MAHB1_CLK_CTL);
136 __raw_writel(BIT(7), MAHB2_CLK_CTL);
137
138 /* Vote for pll8 on behalf of the modem */
139 reg = __raw_readl(PLL_ENA_MARM);
140 reg |= BIT(8);
141 __raw_writel(reg, PLL_ENA_MARM);
142
143 /* Wait for PLL8 to enable */
144 while (!(__raw_readl(PLL8_STATUS) & BIT(16)))
145 cpu_relax();
146
147 /* Set MAHB1 divider to Div-5 to run MAHB1,2 and sfab at 79.8 Mhz*/
148 __raw_writel(0x4, MAHB1_NS);
149
150 /* Vote for modem AHB1 and 2 clocks to be on on behalf of the modem */
151 reg = __raw_readl(MARM_CLK_BRANCH_ENA_VOTE);
152 reg |= BIT(0) | BIT(1);
153 __raw_writel(reg, MARM_CLK_BRANCH_ENA_VOTE);
154
155 /* Source marm_clk off of PLL8 */
156 reg = __raw_readl(MARM_CLK_SRC_CTL);
157 if ((reg & 0x1) == 0) {
158 __raw_writel(0x3, MARM_CLK_SRC1_NS);
159 reg |= 0x1;
160 } else {
161 __raw_writel(0x3, MARM_CLK_SRC0_NS);
162 reg &= ~0x1;
163 }
164 __raw_writel(reg | 0x2, MARM_CLK_SRC_CTL);
165
166 /*
167 * Force core on and periph on signals to remain active during halt
168 * for marm_clk and mahb2_clk
169 */
170 __raw_writel(0x6F, MARM_CLK_FS);
171 __raw_writel(0x6F, MAHB2_CLK_FS);
172
173 /*
174 * Enable all of the marm_clk branches, cxo sourced marm branches,
175 * and sleep clock branches
176 */
177 __raw_writel(0x10, MARM_CLK_CTL);
178 __raw_writel(0x10, MAHB0_CLK_CTL);
179 __raw_writel(0x10, SFAB_MSS_S_HCLK_CTL);
180 __raw_writel(0x10, MSS_MODEM_CXO_CLK_CTL);
181 __raw_writel(0x10, MSS_SLP_CLK_CTL);
182 __raw_writel(0x10, MSS_MARM_SYS_REF_CLK_CTL);
183
184 /* Wait for above clocks to be turned on */
185 while (__raw_readl(CLK_HALT_MSS_SMPSS_MISC_STATE) & (BIT(7) | BIT(8) |
186 BIT(9) | BIT(10) | BIT(4) | BIT(6)))
187 cpu_relax();
188
189 /* Take MAHB0,1,2 clocks out of reset */
190 __raw_writel(0x0, MAHB2_CLK_CTL);
191 __raw_writel(0x0, MAHB1_CLK_CTL);
192 __raw_writel(0x0, MAHB0_SFAB_PORT_RESET);
193
194 /* Setup exception vector table base address */
195 __raw_writel(modem_start | 0x1, MARM_BOOT_CONTROL);
196
197 /* Wait for vector table to be setup */
198 mb();
199
200 /* Bring modem out of reset */
201 __raw_writel(0x0, MARM_RESET);
202
203 return 0;
204}
205
Stephen Boyd3f4da322011-08-30 01:03:23 -0700206static int reset_modem_trusted(struct pil_desc *pil)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700207{
208 int ret;
209
210 make_modem_proxy_votes();
211
Stephen Boyde44ec392011-08-29 12:03:24 -0700212 ret = pas_auth_and_reset(PAS_MODEM);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700213 if (ret)
214 remove_modem_proxy_votes_now();
215
216 return ret;
217}
218
Stephen Boyd3f4da322011-08-30 01:03:23 -0700219static int shutdown_modem_untrusted(struct pil_desc *pil)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700220{
221 u32 reg;
222
223 /* Put modem into reset */
224 __raw_writel(0x1, MARM_RESET);
225 mb();
226
227 /* Put modem AHB0,1,2 clocks into reset */
228 __raw_writel(BIT(0) | BIT(1), MAHB0_SFAB_PORT_RESET);
229 __raw_writel(BIT(7), MAHB1_CLK_CTL);
230 __raw_writel(BIT(7), MAHB2_CLK_CTL);
231 mb();
232
233 /*
234 * Disable all of the marm_clk branches, cxo sourced marm branches,
235 * and sleep clock branches
236 */
237 __raw_writel(0x0, MARM_CLK_CTL);
238 __raw_writel(0x0, MAHB0_CLK_CTL);
239 __raw_writel(0x0, SFAB_MSS_S_HCLK_CTL);
240 __raw_writel(0x0, MSS_MODEM_CXO_CLK_CTL);
241 __raw_writel(0x0, MSS_SLP_CLK_CTL);
242 __raw_writel(0x0, MSS_MARM_SYS_REF_CLK_CTL);
243
244 /* Disable marm_clk */
245 reg = __raw_readl(MARM_CLK_SRC_CTL);
246 reg &= ~0x2;
247 __raw_writel(reg, MARM_CLK_SRC_CTL);
248
249 /* Clear modem's votes for ahb clocks */
250 __raw_writel(0x0, MARM_CLK_BRANCH_ENA_VOTE);
251
252 /* Clear modem's votes for PLLs */
253 __raw_writel(0x0, PLL_ENA_MARM);
254
255 remove_modem_proxy_votes_now();
256
257 return 0;
258}
259
Stephen Boyd3f4da322011-08-30 01:03:23 -0700260static int shutdown_modem_trusted(struct pil_desc *pil)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700261{
262 int ret;
263
Stephen Boyde44ec392011-08-29 12:03:24 -0700264 ret = pas_shutdown(PAS_MODEM);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700265 if (ret)
266 return ret;
267
268 remove_modem_proxy_votes_now();
269
270 return 0;
271}
272
Stephen Boyd3f4da322011-08-30 01:03:23 -0700273static int reset_dsps_untrusted(struct pil_desc *pil)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700274{
275 __raw_writel(0x10, PPSS_PROC_CLK_CTL);
276 while (__raw_readl(CLK_HALT_DFAB_STATE) & BIT(18))
277 cpu_relax();
278
279 /* Bring DSPS out of reset */
280 __raw_writel(0x0, PPSS_RESET);
281 return 0;
282}
283
Stephen Boyd3f4da322011-08-30 01:03:23 -0700284static int reset_dsps_trusted(struct pil_desc *pil)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700285{
Stephen Boyde44ec392011-08-29 12:03:24 -0700286 return pas_auth_and_reset(PAS_DSPS);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700287}
288
Stephen Boyd3f4da322011-08-30 01:03:23 -0700289static int shutdown_dsps_trusted(struct pil_desc *pil)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700290{
Stephen Boyde44ec392011-08-29 12:03:24 -0700291 return pas_shutdown(PAS_DSPS);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700292}
293
Stephen Boyd3f4da322011-08-30 01:03:23 -0700294static int shutdown_dsps_untrusted(struct pil_desc *pil)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700295{
296 __raw_writel(0x2, PPSS_RESET);
297 __raw_writel(0x0, PPSS_PROC_CLK_CTL);
298 return 0;
299}
300
Stephen Boyd3f4da322011-08-30 01:03:23 -0700301static int init_image_playready(struct pil_desc *pil, const u8 *metadata,
Stephen Boyd5bd999a2011-08-02 18:50:57 -0700302 size_t size)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700303{
Stephen Boyde44ec392011-08-29 12:03:24 -0700304 return pas_init_image(PAS_PLAYREADY, metadata, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700305}
306
Stephen Boyd3f4da322011-08-30 01:03:23 -0700307static int reset_playready(struct pil_desc *pil)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700308{
Stephen Boyde44ec392011-08-29 12:03:24 -0700309 return pas_auth_and_reset(PAS_PLAYREADY);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700310}
311
Stephen Boyd3f4da322011-08-30 01:03:23 -0700312static int shutdown_playready(struct pil_desc *pil)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700313{
Stephen Boyde44ec392011-08-29 12:03:24 -0700314 return pas_shutdown(PAS_PLAYREADY);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700315}
316
317struct pil_reset_ops pil_modem_ops = {
318 .init_image = init_image_modem_untrusted,
319 .verify_blob = verify_blob,
320 .auth_and_reset = reset_modem_untrusted,
321 .shutdown = shutdown_modem_untrusted,
322};
323
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700324struct pil_reset_ops pil_dsps_ops = {
325 .init_image = init_image_dsps_untrusted,
326 .verify_blob = verify_blob,
327 .auth_and_reset = reset_dsps_untrusted,
328 .shutdown = shutdown_dsps_untrusted,
329};
330
331struct pil_reset_ops pil_playready_ops = {
332 .init_image = init_image_playready,
333 .verify_blob = verify_blob,
334 .auth_and_reset = reset_playready,
335 .shutdown = shutdown_playready,
336};
337
Stephen Boyd3f4da322011-08-30 01:03:23 -0700338static struct platform_device pil_modem = {
339 .name = "pil_modem",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700340};
341
Stephen Boyd3f4da322011-08-30 01:03:23 -0700342static struct pil_desc pil_modem_desc = {
343 .name = "modem",
344 .depends_on = "q6",
345 .dev = &pil_modem.dev,
346 .ops = &pil_modem_ops,
347};
348
Stephen Boyd3f4da322011-08-30 01:03:23 -0700349static struct platform_device pil_playready = {
350 .name = "pil_playready",
351};
352
353static struct pil_desc pil_playready_desc = {
354 .name = "tzapps",
355 .dev = &pil_playready.dev,
356 .ops = &pil_playready_ops,
357};
358
359static struct platform_device pil_dsps = {
360 .name = "pil_dsps",
361};
362
363static struct pil_desc pil_dsps_desc = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700364 .name = "dsps",
Stephen Boyd3f4da322011-08-30 01:03:23 -0700365 .dev = &pil_dsps.dev,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700366 .ops = &pil_dsps_ops,
367};
368
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700369static int __init msm_peripheral_reset_init(void)
370{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700371 msm_mms_regs_base = ioremap(MSM_MMS_REGS_BASE, SZ_256);
372 if (!msm_mms_regs_base)
373 goto err;
374
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700375 pxo = msm_xo_get(MSM_XO_PXO, "pil");
376 if (IS_ERR(pxo))
377 goto err_pxo;
378
Stephen Boyde44ec392011-08-29 12:03:24 -0700379 if (pas_supported(PAS_MODEM) > 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700380 pil_modem_ops.init_image = init_image_modem_trusted;
381 pil_modem_ops.auth_and_reset = reset_modem_trusted;
382 pil_modem_ops.shutdown = shutdown_modem_trusted;
Stephen Boyde44ec392011-08-29 12:03:24 -0700383 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700384
Stephen Boyde44ec392011-08-29 12:03:24 -0700385 if (pas_supported(PAS_DSPS) > 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700386 pil_dsps_ops.init_image = init_image_dsps_trusted;
387 pil_dsps_ops.auth_and_reset = reset_dsps_trusted;
388 pil_dsps_ops.shutdown = shutdown_dsps_trusted;
389 }
390
Stephen Boyd3f4da322011-08-30 01:03:23 -0700391 BUG_ON(platform_device_register(&pil_modem));
392 BUG_ON(msm_pil_register(&pil_modem_desc));
393 BUG_ON(platform_device_register(&pil_playready));
394 BUG_ON(msm_pil_register(&pil_playready_desc));
395
396 if (machine_is_msm8x60_fluid())
397 pil_dsps_desc.name = "dsps_fluid";
398 BUG_ON(platform_device_register(&pil_dsps));
399 BUG_ON(msm_pil_register(&pil_dsps_desc));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700400
401 return 0;
402
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700403err_pxo:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700404 iounmap(msm_mms_regs_base);
405err:
406 return -ENOMEM;
407}
408
409static void __exit msm_peripheral_reset_exit(void)
410{
411 iounmap(msm_mms_regs_base);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700412}
413
414arch_initcall(msm_peripheral_reset_init);
415module_exit(msm_peripheral_reset_exit);
416
417MODULE_LICENSE("GPL v2");
418MODULE_DESCRIPTION("Validate and bring peripherals out of reset");