blob: 4c94b83d5d804d570f73491a8bd501d3eddd96e0 [file] [log] [blame]
Matt Wagantall292aace2012-01-26 19:12:34 -08001/*
2 * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/kernel.h>
15#include <linux/err.h>
16#include <linux/io.h>
17#include <linux/elf.h>
18#include <linux/delay.h>
19#include <linux/module.h>
20#include <linux/slab.h>
21#include <linux/platform_device.h>
22#include <linux/workqueue.h>
23#include <linux/clk.h>
24
25#include <mach/msm_iomap.h>
26#include <mach/msm_xo.h>
27
28#include "peripheral-loader.h"
29#include "scm-pas.h"
30
31#define GSS_CSR_AHB_CLK_SEL 0x0
32#define GSS_CSR_RESET 0x4
33#define GSS_CSR_CLK_BLK_CONFIG 0x8
34#define GSS_CSR_CLK_ENABLE 0xC
35#define GSS_CSR_BOOT_REMAP 0x14
36#define GSS_CSR_POWER_UP_DOWN 0x18
37
38#define GSS_SLP_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C60)
39#define GSS_RESET (MSM_CLK_CTL_BASE + 0x2C64)
40#define GSS_CLAMP_ENA (MSM_CLK_CTL_BASE + 0x2C68)
41#define GSS_CXO_SRC_CTL (MSM_CLK_CTL_BASE + 0x2C74)
42
43#define PLL5_MODE (MSM_CLK_CTL_BASE + 0x30E0)
44#define PLL5_L_VAL (MSM_CLK_CTL_BASE + 0x30E4)
45#define PLL5_M_VAL (MSM_CLK_CTL_BASE + 0x30E8)
46#define PLL5_N_VAL (MSM_CLK_CTL_BASE + 0x30EC)
47#define PLL5_CONFIG (MSM_CLK_CTL_BASE + 0x30F4)
48#define PLL5_STATUS (MSM_CLK_CTL_BASE + 0x30F8)
49#define PLL_ENA_GSS (MSM_CLK_CTL_BASE + 0x3480)
50#define PLL_ENA_RPM (MSM_CLK_CTL_BASE + 0x34A0)
51
52#define PLL5_VOTE BIT(5)
53#define PLL_STATUS BIT(16)
54#define REMAP_ENABLE BIT(16)
55#define A5_POWER_STATUS BIT(4)
56#define A5_POWER_ENA BIT(0)
57#define NAV_POWER_ENA BIT(1)
58#define XO_CLK_BRANCH_ENA BIT(0)
59#define SLP_CLK_BRANCH_ENA BIT(4)
60#define A5_RESET BIT(0)
61
62#define PROXY_VOTE_TIMEOUT 10000
63
64struct gss_data {
65 void __iomem *base;
66 unsigned long start_addr;
67 struct delayed_work work;
68 struct clk *xo;
69};
70
71static int nop_verify_blob(struct pil_desc *pil, u32 phy_addr, size_t size)
72{
73 return 0;
74}
75
76static int pil_gss_init_image(struct pil_desc *pil, const u8 *metadata,
77 size_t size)
78{
79 const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
80 struct gss_data *drv = dev_get_drvdata(pil->dev);
81 drv->start_addr = ehdr->e_entry;
82 return 0;
83}
84
85static int make_gss_proxy_votes(struct device *dev)
86{
87 int ret;
88 struct gss_data *drv = dev_get_drvdata(dev);
89
90 ret = clk_prepare_enable(drv->xo);
91 if (ret) {
92 dev_err(dev, "Failed to enable XO\n");
93 return ret;
94 }
95 schedule_delayed_work(&drv->work, msecs_to_jiffies(PROXY_VOTE_TIMEOUT));
96 return 0;
97}
98
99static void remove_gss_proxy_votes(struct work_struct *work)
100{
101 struct gss_data *drv = container_of(work, struct gss_data, work.work);
102 clk_disable_unprepare(drv->xo);
103}
104
105static void remove_gss_proxy_votes_now(struct gss_data *drv)
106{
107 flush_delayed_work(&drv->work);
108}
109
110static void gss_init(struct gss_data *drv)
111{
112 void __iomem *base = drv->base;
113
114 /* Supply clocks to GSS. */
115 writel_relaxed(XO_CLK_BRANCH_ENA, GSS_CXO_SRC_CTL);
116 writel_relaxed(SLP_CLK_BRANCH_ENA, GSS_SLP_CLK_CTL);
117
118 /* Deassert GSS reset and clamps. */
119 writel_relaxed(0x0, GSS_RESET);
120 writel_relaxed(0x0, GSS_CLAMP_ENA);
121 mb();
122
123 /*
124 * Configure clock source and dividers for 288MHz core, 144MHz AXI and
125 * 72MHz AHB, all derived from the 288MHz PLL.
126 */
127 writel_relaxed(0x341, base + GSS_CSR_CLK_BLK_CONFIG);
128 writel_relaxed(0x1, base + GSS_CSR_AHB_CLK_SEL);
129
130 /* Assert all GSS resets. */
131 writel_relaxed(0x7F, base + GSS_CSR_RESET);
132
133 /* Enable all bus clocks and wait for resets to propagate. */
134 writel_relaxed(0x1F, base + GSS_CSR_CLK_ENABLE);
135 mb();
136 udelay(1);
137
138 /* Release subsystem from reset, but leave A5 in reset. */
139 writel_relaxed(A5_RESET, base + GSS_CSR_RESET);
140}
141
142static int pil_gss_reset(struct pil_desc *pil)
143{
144 struct gss_data *drv = dev_get_drvdata(pil->dev);
145 void __iomem *base = drv->base;
146 unsigned long start_addr = drv->start_addr;
147 int ret;
148
149 ret = make_gss_proxy_votes(pil->dev);
150 if (ret)
151 return ret;
152
153 /* Vote PLL on in GSS's voting register and wait for it to enable. */
154 writel_relaxed(PLL5_VOTE, PLL_ENA_GSS);
155 while ((readl_relaxed(PLL5_STATUS) & PLL_STATUS) == 0)
156 cpu_relax();
157
158 /* Perform GSS initialization. */
159 gss_init(drv);
160
161 /* Configure boot address and enable remap. */
162 writel_relaxed(REMAP_ENABLE | (start_addr >> 16),
163 base + GSS_CSR_BOOT_REMAP);
164
165 /* Power up A5 core. */
166 writel_relaxed(A5_POWER_ENA, base + GSS_CSR_POWER_UP_DOWN);
167 while (!(readl_relaxed(base + GSS_CSR_POWER_UP_DOWN) & A5_POWER_STATUS))
168 cpu_relax();
169
170 /* Release A5 from reset. */
171 writel_relaxed(0x0, base + GSS_CSR_RESET);
172
173 return 0;
174}
175
176static int pil_gss_shutdown(struct pil_desc *pil)
177{
178 struct gss_data *drv = dev_get_drvdata(pil->dev);
179 void __iomem *base = drv->base;
180 u32 regval;
181 int ret;
182
183 ret = clk_prepare_enable(drv->xo);
184 if (ret) {
185 dev_err(pil->dev, "Failed to enable XO\n");
186 return ret;
187 }
188
189 /*
190 * Vote PLL on in GSS's voting register and wait for it to enable.
191 * The PLL must be enable to switch the GFMUX to a low-power source.
192 */
193 writel_relaxed(PLL5_VOTE, PLL_ENA_GSS);
194 while ((readl_relaxed(PLL5_STATUS) & PLL_STATUS) == 0)
195 cpu_relax();
196
197 /* Perform one-time GSS initialization. */
198 gss_init(drv);
199
200 /* Assert A5 reset. */
201 regval = readl_relaxed(base + GSS_CSR_RESET);
202 regval |= A5_RESET;
203 writel_relaxed(regval, base + GSS_CSR_RESET);
204
205 /* Power down A5 and NAV. */
206 regval = readl_relaxed(base + GSS_CSR_POWER_UP_DOWN);
207 regval &= ~(A5_POWER_ENA|NAV_POWER_ENA);
208 writel_relaxed(regval, base + GSS_CSR_POWER_UP_DOWN);
209
210 /* Select XO clock source and increase dividers to save power. */
211 regval = readl_relaxed(base + GSS_CSR_CLK_BLK_CONFIG);
212 regval |= 0x3FF;
213 writel_relaxed(regval, base + GSS_CSR_CLK_BLK_CONFIG);
214
215 /* Disable bus clocks. */
216 writel_relaxed(0x1F, base + GSS_CSR_CLK_ENABLE);
217
218 /* Clear GSS PLL votes. */
219 writel_relaxed(0, PLL_ENA_GSS);
220 mb();
221
222 clk_disable_unprepare(drv->xo);
223 remove_gss_proxy_votes_now(drv);
224
225 return 0;
226}
227
228static struct pil_reset_ops pil_gss_ops = {
229 .init_image = pil_gss_init_image,
230 .verify_blob = nop_verify_blob,
231 .auth_and_reset = pil_gss_reset,
232 .shutdown = pil_gss_shutdown,
233};
234
235static void configure_gss_pll(struct gss_data *drv)
236{
237 u32 regval, is_pll_enabled;
238
239 /* Check if PLL5 is enabled by FSM. */
240 is_pll_enabled = readl_relaxed(PLL5_STATUS) & PLL_STATUS;
241 if (!is_pll_enabled) {
242 /* Enable XO reference for PLL5 */
243 clk_prepare_enable(drv->xo);
244
245 /*
246 * Assert a vote to hold PLL5 on in RPM register until other
247 * voters are in place.
248 */
249 regval = readl_relaxed(PLL_ENA_RPM);
250 regval |= PLL5_VOTE;
251 writel_relaxed(regval, PLL_ENA_RPM);
252
253 /* Ref clk = 27MHz and program pll5 to 288MHz */
254 writel_relaxed(0xF, PLL5_L_VAL);
255 writel_relaxed(0x0, PLL5_M_VAL);
256 writel_relaxed(0x1, PLL5_N_VAL);
257
258 regval = readl_relaxed(PLL5_CONFIG);
259 /* Disable the MN accumulator and enable the main output. */
260 regval &= ~BIT(22);
261 regval |= BIT(23);
262
263 /* Set pre-divider and post-divider values to 1 and 1 */
264 regval &= ~BIT(19);
265 regval &= ~(BIT(21)|BIT(20));
266
267 /* Set VCO frequency */
268 regval &= ~(BIT(17)|BIT(16));
269 writel_relaxed(regval, PLL5_CONFIG);
270
271 regval = readl_relaxed(PLL5_MODE);
272 /* De-assert reset to FSM */
273 regval &= ~BIT(21);
274 writel_relaxed(regval, PLL5_MODE);
275
276 /* Program bias count */
277 regval &= ~(0x3F << 14);
278 regval |= (0x1 << 14);
279 writel_relaxed(regval, PLL5_MODE);
280
281 /* Program lock count */
282 regval &= ~(0x3F << 8);
283 regval |= (0x8 << 8);
284 writel_relaxed(regval, PLL5_MODE);
285
286 /* Enable PLL FSM voting */
287 regval |= BIT(20);
288 writel_relaxed(regval, PLL5_MODE);
289 }
290}
291
292static int __devinit pil_gss_probe(struct platform_device *pdev)
293{
294 struct gss_data *drv;
295 struct resource *res;
296 struct pil_desc *desc;
297 int ret;
298
299 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
300 if (!res)
301 return -EINVAL;
302
303 drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
304 if (!drv)
305 return -ENOMEM;
306 platform_set_drvdata(pdev, drv);
307
308 drv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
309 if (!drv->base)
310 return -ENOMEM;
311
312 desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
313 if (!desc)
314 return -ENOMEM;
315
316 drv->xo = clk_get(&pdev->dev, "xo");
317 if (IS_ERR(drv->xo))
318 return PTR_ERR(drv->xo);
319
320 desc->name = "gss";
321 desc->dev = &pdev->dev;
322
323 desc->ops = &pil_gss_ops;
324 dev_info(&pdev->dev, "using non-secure boot\n");
325
326 INIT_DELAYED_WORK(&drv->work, remove_gss_proxy_votes);
327
328 /* FIXME: Remove when PLL is configured by bootloaders. */
329 configure_gss_pll(drv);
330
331 ret = msm_pil_register(desc);
332 if (ret) {
333 flush_delayed_work_sync(&drv->work);
334 clk_put(drv->xo);
335 }
336 return ret;
337}
338
339static int __devexit pil_gss_remove(struct platform_device *pdev)
340{
341 struct gss_data *drv = platform_get_drvdata(pdev);
342 flush_delayed_work_sync(&drv->work);
343 clk_put(drv->xo);
344 return 0;
345}
346
347static struct platform_driver pil_gss_driver = {
348 .probe = pil_gss_probe,
349 .remove = __devexit_p(pil_gss_remove),
350 .driver = {
351 .name = "pil_gss",
352 .owner = THIS_MODULE,
353 },
354};
355
356static int __init pil_gss_init(void)
357{
358 return platform_driver_register(&pil_gss_driver);
359}
360module_init(pil_gss_init);
361
362static void __exit pil_gss_exit(void)
363{
364 platform_driver_unregister(&pil_gss_driver);
365}
366module_exit(pil_gss_exit);
367
368MODULE_DESCRIPTION("Support for booting the GSS processor");
369MODULE_LICENSE("GPL v2");