blob: 6c15e3316137b87177753f3bd2b04d154d2f3f7a [file] [log] [blame]
Binghua Duan02c981c2011-07-08 17:40:12 +08001/*
2 * Clock tree for CSR SiRFprimaII
3 *
4 * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
5 *
6 * Licensed under GPLv2 or later.
7 */
8
9#include <linux/module.h>
10#include <linux/bitops.h>
Binghua Duan02c981c2011-07-08 17:40:12 +080011#include <linux/io.h>
Binghua Duan02c981c2011-07-08 17:40:12 +080012#include <linux/clk.h>
Binghua Duan198678b2012-08-20 06:42:36 +000013#include <linux/clkdev.h>
14#include <linux/clk-provider.h>
Binghua Duan02c981c2011-07-08 17:40:12 +080015#include <linux/of_address.h>
Binghua Duan198678b2012-08-20 06:42:36 +000016#include <linux/syscore_ops.h>
Binghua Duan02c981c2011-07-08 17:40:12 +080017
18#define SIRFSOC_CLKC_CLK_EN0 0x0000
19#define SIRFSOC_CLKC_CLK_EN1 0x0004
20#define SIRFSOC_CLKC_REF_CFG 0x0014
21#define SIRFSOC_CLKC_CPU_CFG 0x0018
22#define SIRFSOC_CLKC_MEM_CFG 0x001c
23#define SIRFSOC_CLKC_SYS_CFG 0x0020
24#define SIRFSOC_CLKC_IO_CFG 0x0024
25#define SIRFSOC_CLKC_DSP_CFG 0x0028
26#define SIRFSOC_CLKC_GFX_CFG 0x002c
27#define SIRFSOC_CLKC_MM_CFG 0x0030
Binghua Duan198678b2012-08-20 06:42:36 +000028#define SIRFSOC_CLKC_LCD_CFG 0x0034
Binghua Duan02c981c2011-07-08 17:40:12 +080029#define SIRFSOC_CLKC_MMC_CFG 0x0038
30#define SIRFSOC_CLKC_PLL1_CFG0 0x0040
31#define SIRFSOC_CLKC_PLL2_CFG0 0x0044
32#define SIRFSOC_CLKC_PLL3_CFG0 0x0048
33#define SIRFSOC_CLKC_PLL1_CFG1 0x004c
34#define SIRFSOC_CLKC_PLL2_CFG1 0x0050
35#define SIRFSOC_CLKC_PLL3_CFG1 0x0054
36#define SIRFSOC_CLKC_PLL1_CFG2 0x0058
37#define SIRFSOC_CLKC_PLL2_CFG2 0x005c
38#define SIRFSOC_CLKC_PLL3_CFG2 0x0060
Binghua Duan198678b2012-08-20 06:42:36 +000039#define SIRFSOC_USBPHY_PLL_CTRL 0x0008
40#define SIRFSOC_USBPHY_PLL_POWERDOWN BIT(1)
41#define SIRFSOC_USBPHY_PLL_BYPASS BIT(2)
42#define SIRFSOC_USBPHY_PLL_LOCK BIT(3)
Binghua Duan02c981c2011-07-08 17:40:12 +080043
Binghua Duan198678b2012-08-20 06:42:36 +000044static void *sirfsoc_clk_vbase, *sirfsoc_rsc_vbase;
Binghua Duan02c981c2011-07-08 17:40:12 +080045
46#define KHZ 1000
47#define MHZ (KHZ * KHZ)
48
Binghua Duan198678b2012-08-20 06:42:36 +000049/*
50 * SiRFprimaII clock controller
51 * - 2 oscillators: osc-26MHz, rtc-32.768KHz
52 * - 3 standard configurable plls: pll1, pll2 & pll3
53 * - 2 exclusive plls: usb phy pll and sata phy pll
54 * - 8 clock domains: cpu/cpudiv, mem/memdiv, sys/io, dsp, graphic, multimedia,
55 * display and sdphy.
56 * Each clock domain can select its own clock source from five clock sources,
57 * X_XIN, X_XINW, PLL1, PLL2 and PLL3. The domain clock is used as the source
58 * clock of the group clock.
59 * - dsp domain: gps, mf
60 * - io domain: dmac, nand, audio, uart, i2c, spi, usp, pwm, pulse
61 * - sys domain: security
62 */
63
64struct clk_pll {
65 struct clk_hw hw;
66 unsigned short regofs; /* register offset */
Binghua Duan02c981c2011-07-08 17:40:12 +080067};
68
Binghua Duan198678b2012-08-20 06:42:36 +000069#define to_pllclk(_hw) container_of(_hw, struct clk_pll, hw)
70
71struct clk_dmn {
72 struct clk_hw hw;
Binghua Duan02c981c2011-07-08 17:40:12 +080073 signed char enable_bit; /* enable bit: 0 ~ 63 */
74 unsigned short regofs; /* register offset */
Binghua Duan02c981c2011-07-08 17:40:12 +080075};
76
Binghua Duan198678b2012-08-20 06:42:36 +000077#define to_dmnclk(_hw) container_of(_hw, struct clk_dmn, hw)
78
79struct clk_std {
80 struct clk_hw hw;
81 signed char enable_bit; /* enable bit: 0 ~ 63 */
82};
83
84#define to_stdclk(_hw) container_of(_hw, struct clk_std, hw)
85
86static int std_clk_is_enabled(struct clk_hw *hw);
87static int std_clk_enable(struct clk_hw *hw);
88static void std_clk_disable(struct clk_hw *hw);
Binghua Duan02c981c2011-07-08 17:40:12 +080089
90static inline unsigned long clkc_readl(unsigned reg)
91{
Binghua Duan198678b2012-08-20 06:42:36 +000092 return readl(sirfsoc_clk_vbase + reg);
Binghua Duan02c981c2011-07-08 17:40:12 +080093}
94
95static inline void clkc_writel(u32 val, unsigned reg)
96{
Binghua Duan198678b2012-08-20 06:42:36 +000097 writel(val, sirfsoc_clk_vbase + reg);
Binghua Duan02c981c2011-07-08 17:40:12 +080098}
99
100/*
Binghua Duan02c981c2011-07-08 17:40:12 +0800101 * std pll
102 */
Binghua Duan198678b2012-08-20 06:42:36 +0000103
104static unsigned long pll_clk_recalc_rate(struct clk_hw *hw,
105 unsigned long parent_rate)
Binghua Duan02c981c2011-07-08 17:40:12 +0800106{
Binghua Duan198678b2012-08-20 06:42:36 +0000107 unsigned long fin = parent_rate;
108 struct clk_pll *clk = to_pllclk(hw);
Binghua Duan02c981c2011-07-08 17:40:12 +0800109 u32 regcfg2 = clk->regofs + SIRFSOC_CLKC_PLL1_CFG2 -
110 SIRFSOC_CLKC_PLL1_CFG0;
111
112 if (clkc_readl(regcfg2) & BIT(2)) {
113 /* pll bypass mode */
Binghua Duan198678b2012-08-20 06:42:36 +0000114 return fin;
Binghua Duan02c981c2011-07-08 17:40:12 +0800115 } else {
116 /* fout = fin * nf / nr / od */
117 u32 cfg0 = clkc_readl(clk->regofs);
118 u32 nf = (cfg0 & (BIT(13) - 1)) + 1;
119 u32 nr = ((cfg0 >> 13) & (BIT(6) - 1)) + 1;
120 u32 od = ((cfg0 >> 19) & (BIT(4) - 1)) + 1;
121 WARN_ON(fin % MHZ);
Binghua Duan198678b2012-08-20 06:42:36 +0000122 return fin / MHZ * nf / nr / od * MHZ;
Binghua Duan02c981c2011-07-08 17:40:12 +0800123 }
Binghua Duan02c981c2011-07-08 17:40:12 +0800124}
125
Binghua Duan198678b2012-08-20 06:42:36 +0000126static long pll_clk_round_rate(struct clk_hw *hw, unsigned long rate,
127 unsigned long *parent_rate)
Binghua Duan02c981c2011-07-08 17:40:12 +0800128{
Binghua Duan198678b2012-08-20 06:42:36 +0000129 unsigned long fin, nf, nr, od;
130
131 /*
132 * fout = fin * nf / (nr * od);
133 * set od = 1, nr = fin/MHz, so fout = nf * MHz
134 */
135 rate = rate - rate % MHZ;
136
137 nf = rate / MHZ;
138 if (nf > BIT(13))
139 nf = BIT(13);
140 if (nf < 1)
141 nf = 1;
142
143 fin = *parent_rate;
144
145 nr = fin / MHZ;
146 if (nr > BIT(6))
147 nr = BIT(6);
148 od = 1;
149
150 return fin * nf / (nr * od);
151}
152
153static int pll_clk_set_rate(struct clk_hw *hw, unsigned long rate,
154 unsigned long parent_rate)
155{
156 struct clk_pll *clk = to_pllclk(hw);
Binghua Duan02c981c2011-07-08 17:40:12 +0800157 unsigned long fin, nf, nr, od, reg;
158
159 /*
160 * fout = fin * nf / (nr * od);
161 * set od = 1, nr = fin/MHz, so fout = nf * MHz
162 */
163
164 nf = rate / MHZ;
165 if (unlikely((rate % MHZ) || nf > BIT(13) || nf < 1))
166 return -EINVAL;
167
Binghua Duan198678b2012-08-20 06:42:36 +0000168 fin = parent_rate;
Binghua Duan02c981c2011-07-08 17:40:12 +0800169 BUG_ON(fin < MHZ);
170
171 nr = fin / MHZ;
172 BUG_ON((fin % MHZ) || nr > BIT(6));
173
174 od = 1;
175
176 reg = (nf - 1) | ((nr - 1) << 13) | ((od - 1) << 19);
177 clkc_writel(reg, clk->regofs);
178
179 reg = clk->regofs + SIRFSOC_CLKC_PLL1_CFG1 - SIRFSOC_CLKC_PLL1_CFG0;
180 clkc_writel((nf >> 1) - 1, reg);
181
182 reg = clk->regofs + SIRFSOC_CLKC_PLL1_CFG2 - SIRFSOC_CLKC_PLL1_CFG0;
183 while (!(clkc_readl(reg) & BIT(6)))
184 cpu_relax();
185
Binghua Duan02c981c2011-07-08 17:40:12 +0800186 return 0;
187}
188
189static struct clk_ops std_pll_ops = {
Binghua Duan198678b2012-08-20 06:42:36 +0000190 .recalc_rate = pll_clk_recalc_rate,
191 .round_rate = pll_clk_round_rate,
192 .set_rate = pll_clk_set_rate,
Binghua Duan02c981c2011-07-08 17:40:12 +0800193};
194
Binghua Duan198678b2012-08-20 06:42:36 +0000195static const char *pll_clk_parents[] = {
196 "osc",
197};
198
199static struct clk_init_data clk_pll1_init = {
200 .name = "pll1",
201 .ops = &std_pll_ops,
202 .parent_names = pll_clk_parents,
203 .num_parents = ARRAY_SIZE(pll_clk_parents),
204};
205
206static struct clk_init_data clk_pll2_init = {
207 .name = "pll2",
208 .ops = &std_pll_ops,
209 .parent_names = pll_clk_parents,
210 .num_parents = ARRAY_SIZE(pll_clk_parents),
211};
212
213static struct clk_init_data clk_pll3_init = {
214 .name = "pll3",
215 .ops = &std_pll_ops,
216 .parent_names = pll_clk_parents,
217 .num_parents = ARRAY_SIZE(pll_clk_parents),
218};
219
220static struct clk_pll clk_pll1 = {
Binghua Duan02c981c2011-07-08 17:40:12 +0800221 .regofs = SIRFSOC_CLKC_PLL1_CFG0,
Binghua Duan198678b2012-08-20 06:42:36 +0000222 .hw = {
223 .init = &clk_pll1_init,
224 },
Binghua Duan02c981c2011-07-08 17:40:12 +0800225};
226
Binghua Duan198678b2012-08-20 06:42:36 +0000227static struct clk_pll clk_pll2 = {
Binghua Duan02c981c2011-07-08 17:40:12 +0800228 .regofs = SIRFSOC_CLKC_PLL2_CFG0,
Binghua Duan198678b2012-08-20 06:42:36 +0000229 .hw = {
230 .init = &clk_pll2_init,
231 },
Binghua Duan02c981c2011-07-08 17:40:12 +0800232};
233
Binghua Duan198678b2012-08-20 06:42:36 +0000234static struct clk_pll clk_pll3 = {
Binghua Duan02c981c2011-07-08 17:40:12 +0800235 .regofs = SIRFSOC_CLKC_PLL3_CFG0,
Binghua Duan198678b2012-08-20 06:42:36 +0000236 .hw = {
237 .init = &clk_pll3_init,
238 },
Binghua Duan02c981c2011-07-08 17:40:12 +0800239};
240
241/*
Binghua Duan198678b2012-08-20 06:42:36 +0000242 * usb uses specified pll
Binghua Duan02c981c2011-07-08 17:40:12 +0800243 */
244
Binghua Duan198678b2012-08-20 06:42:36 +0000245static int usb_pll_clk_enable(struct clk_hw *hw)
Binghua Duan02c981c2011-07-08 17:40:12 +0800246{
Binghua Duan198678b2012-08-20 06:42:36 +0000247 u32 reg = readl(sirfsoc_rsc_vbase + SIRFSOC_USBPHY_PLL_CTRL);
248 reg &= ~(SIRFSOC_USBPHY_PLL_POWERDOWN | SIRFSOC_USBPHY_PLL_BYPASS);
249 writel(reg, sirfsoc_rsc_vbase + SIRFSOC_USBPHY_PLL_CTRL);
250 while (!(readl(sirfsoc_rsc_vbase + SIRFSOC_USBPHY_PLL_CTRL) &
251 SIRFSOC_USBPHY_PLL_LOCK))
252 cpu_relax();
253
254 return 0;
255}
256
257static void usb_pll_clk_disable(struct clk_hw *clk)
258{
259 u32 reg = readl(sirfsoc_rsc_vbase + SIRFSOC_USBPHY_PLL_CTRL);
260 reg |= (SIRFSOC_USBPHY_PLL_POWERDOWN | SIRFSOC_USBPHY_PLL_BYPASS);
261 writel(reg, sirfsoc_rsc_vbase + SIRFSOC_USBPHY_PLL_CTRL);
262}
263
264static unsigned long usb_pll_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
265{
266 u32 reg = readl(sirfsoc_rsc_vbase + SIRFSOC_USBPHY_PLL_CTRL);
267 return (reg & SIRFSOC_USBPHY_PLL_BYPASS) ? parent_rate : 48*MHZ;
268}
269
270static struct clk_ops usb_pll_ops = {
271 .enable = usb_pll_clk_enable,
272 .disable = usb_pll_clk_disable,
273 .recalc_rate = usb_pll_clk_recalc_rate,
274};
275
276static struct clk_init_data clk_usb_pll_init = {
277 .name = "usb_pll",
278 .ops = &usb_pll_ops,
279 .parent_names = pll_clk_parents,
280 .num_parents = ARRAY_SIZE(pll_clk_parents),
281};
282
283static struct clk_hw usb_pll_clk_hw = {
284 .init = &clk_usb_pll_init,
285};
286
287/*
288 * clock domains - cpu, mem, sys/io, dsp, gfx
289 */
290
291static const char *dmn_clk_parents[] = {
292 "rtc",
293 "osc",
294 "pll1",
295 "pll2",
296 "pll3",
297};
298
299static u8 dmn_clk_get_parent(struct clk_hw *hw)
300{
301 struct clk_dmn *clk = to_dmnclk(hw);
Binghua Duan02c981c2011-07-08 17:40:12 +0800302 u32 cfg = clkc_readl(clk->regofs);
Binghua Duan198678b2012-08-20 06:42:36 +0000303
304 /* parent of io domain can only be pll3 */
305 if (strcmp(hw->init->name, "io") == 0)
306 return 4;
307
Binghua Duan02c981c2011-07-08 17:40:12 +0800308 WARN_ON((cfg & (BIT(3) - 1)) > 4);
Binghua Duan198678b2012-08-20 06:42:36 +0000309
310 return cfg & (BIT(3) - 1);
Binghua Duan02c981c2011-07-08 17:40:12 +0800311}
312
Binghua Duan198678b2012-08-20 06:42:36 +0000313static int dmn_clk_set_parent(struct clk_hw *hw, u8 parent)
Binghua Duan02c981c2011-07-08 17:40:12 +0800314{
Binghua Duan198678b2012-08-20 06:42:36 +0000315 struct clk_dmn *clk = to_dmnclk(hw);
Binghua Duan02c981c2011-07-08 17:40:12 +0800316 u32 cfg = clkc_readl(clk->regofs);
Binghua Duan198678b2012-08-20 06:42:36 +0000317
318 /* parent of io domain can only be pll3 */
319 if (strcmp(hw->init->name, "io") == 0)
320 return -EINVAL;
321
322 cfg &= ~(BIT(3) - 1);
323 clkc_writel(cfg | parent, clk->regofs);
324 /* BIT(3) - switching status: 1 - busy, 0 - done */
325 while (clkc_readl(clk->regofs) & BIT(3))
326 cpu_relax();
327
328 return 0;
Binghua Duan02c981c2011-07-08 17:40:12 +0800329}
330
Binghua Duan198678b2012-08-20 06:42:36 +0000331static unsigned long dmn_clk_recalc_rate(struct clk_hw *hw,
332 unsigned long parent_rate)
333
Binghua Duan02c981c2011-07-08 17:40:12 +0800334{
Binghua Duan198678b2012-08-20 06:42:36 +0000335 unsigned long fin = parent_rate;
336 struct clk_dmn *clk = to_dmnclk(hw);
337
Binghua Duan02c981c2011-07-08 17:40:12 +0800338 u32 cfg = clkc_readl(clk->regofs);
Binghua Duan198678b2012-08-20 06:42:36 +0000339
Binghua Duan02c981c2011-07-08 17:40:12 +0800340 if (cfg & BIT(24)) {
341 /* fcd bypass mode */
Binghua Duan198678b2012-08-20 06:42:36 +0000342 return fin;
Binghua Duan02c981c2011-07-08 17:40:12 +0800343 } else {
344 /*
345 * wait count: bit[19:16], hold count: bit[23:20]
346 */
347 u32 wait = (cfg >> 16) & (BIT(4) - 1);
348 u32 hold = (cfg >> 20) & (BIT(4) - 1);
349
Binghua Duan198678b2012-08-20 06:42:36 +0000350 return fin / (wait + hold + 2);
Binghua Duan02c981c2011-07-08 17:40:12 +0800351 }
Binghua Duan02c981c2011-07-08 17:40:12 +0800352}
353
Binghua Duan198678b2012-08-20 06:42:36 +0000354static long dmn_clk_round_rate(struct clk_hw *hw, unsigned long rate,
355 unsigned long *parent_rate)
Binghua Duan02c981c2011-07-08 17:40:12 +0800356{
357 unsigned long fin;
Binghua Duan198678b2012-08-20 06:42:36 +0000358 unsigned ratio, wait, hold;
359 unsigned bits = (strcmp(hw->init->name, "mem") == 0) ? 3 : 4;
Binghua Duan02c981c2011-07-08 17:40:12 +0800360
Binghua Duan198678b2012-08-20 06:42:36 +0000361 fin = *parent_rate;
362 ratio = fin / rate;
363
364 if (ratio < 2)
365 ratio = 2;
366 if (ratio > BIT(bits + 1))
367 ratio = BIT(bits + 1);
368
369 wait = (ratio >> 1) - 1;
370 hold = ratio - wait - 2;
371
372 return fin / (wait + hold + 2);
373}
374
375static int dmn_clk_set_rate(struct clk_hw *hw, unsigned long rate,
376 unsigned long parent_rate)
377{
378 struct clk_dmn *clk = to_dmnclk(hw);
379 unsigned long fin;
380 unsigned ratio, wait, hold, reg;
381 unsigned bits = (strcmp(hw->init->name, "mem") == 0) ? 3 : 4;
382
383 fin = parent_rate;
Binghua Duan02c981c2011-07-08 17:40:12 +0800384 ratio = fin / rate;
385
386 if (unlikely(ratio < 2 || ratio > BIT(bits + 1)))
387 return -EINVAL;
388
389 WARN_ON(fin % rate);
390
391 wait = (ratio >> 1) - 1;
392 hold = ratio - wait - 2;
393
394 reg = clkc_readl(clk->regofs);
395 reg &= ~(((BIT(bits) - 1) << 16) | ((BIT(bits) - 1) << 20));
396 reg |= (wait << 16) | (hold << 20) | BIT(25);
397 clkc_writel(reg, clk->regofs);
398
399 /* waiting FCD been effective */
400 while (clkc_readl(clk->regofs) & BIT(25))
401 cpu_relax();
402
Binghua Duan02c981c2011-07-08 17:40:12 +0800403 return 0;
404}
405
Binghua Duan02c981c2011-07-08 17:40:12 +0800406static struct clk_ops msi_ops = {
Binghua Duan198678b2012-08-20 06:42:36 +0000407 .set_rate = dmn_clk_set_rate,
408 .round_rate = dmn_clk_round_rate,
409 .recalc_rate = dmn_clk_recalc_rate,
410 .set_parent = dmn_clk_set_parent,
411 .get_parent = dmn_clk_get_parent,
Binghua Duan02c981c2011-07-08 17:40:12 +0800412};
413
Binghua Duan198678b2012-08-20 06:42:36 +0000414static struct clk_init_data clk_mem_init = {
415 .name = "mem",
416 .ops = &msi_ops,
417 .parent_names = dmn_clk_parents,
418 .num_parents = ARRAY_SIZE(dmn_clk_parents),
419};
420
421static struct clk_dmn clk_mem = {
Binghua Duan02c981c2011-07-08 17:40:12 +0800422 .regofs = SIRFSOC_CLKC_MEM_CFG,
Binghua Duan198678b2012-08-20 06:42:36 +0000423 .hw = {
424 .init = &clk_mem_init,
Binghua Duan02c981c2011-07-08 17:40:12 +0800425 },
426};
427
Binghua Duan198678b2012-08-20 06:42:36 +0000428static struct clk_init_data clk_sys_init = {
429 .name = "sys",
430 .ops = &msi_ops,
431 .parent_names = dmn_clk_parents,
432 .num_parents = ARRAY_SIZE(dmn_clk_parents),
433 .flags = CLK_SET_RATE_GATE,
434};
435
436static struct clk_dmn clk_sys = {
437 .regofs = SIRFSOC_CLKC_SYS_CFG,
438 .hw = {
439 .init = &clk_sys_init,
440 },
441};
442
443static struct clk_init_data clk_io_init = {
444 .name = "io",
445 .ops = &msi_ops,
446 .parent_names = dmn_clk_parents,
447 .num_parents = ARRAY_SIZE(dmn_clk_parents),
448};
449
450static struct clk_dmn clk_io = {
451 .regofs = SIRFSOC_CLKC_IO_CFG,
452 .hw = {
453 .init = &clk_io_init,
454 },
455};
456
457static struct clk_ops cpu_ops = {
458 .set_parent = dmn_clk_set_parent,
459 .get_parent = dmn_clk_get_parent,
460};
461
462static struct clk_init_data clk_cpu_init = {
463 .name = "cpu",
464 .ops = &cpu_ops,
465 .parent_names = dmn_clk_parents,
466 .num_parents = ARRAY_SIZE(dmn_clk_parents),
467 .flags = CLK_SET_RATE_PARENT,
468};
469
470static struct clk_dmn clk_cpu = {
471 .regofs = SIRFSOC_CLKC_CPU_CFG,
472 .hw = {
473 .init = &clk_cpu_init,
474 },
475};
476
477static struct clk_ops dmn_ops = {
478 .is_enabled = std_clk_is_enabled,
479 .enable = std_clk_enable,
480 .disable = std_clk_disable,
481 .set_rate = dmn_clk_set_rate,
482 .round_rate = dmn_clk_round_rate,
483 .recalc_rate = dmn_clk_recalc_rate,
484 .set_parent = dmn_clk_set_parent,
485 .get_parent = dmn_clk_get_parent,
486};
487
488/* dsp, gfx, mm, lcd and vpp domain */
489
490static struct clk_init_data clk_dsp_init = {
491 .name = "dsp",
492 .ops = &dmn_ops,
493 .parent_names = dmn_clk_parents,
494 .num_parents = ARRAY_SIZE(dmn_clk_parents),
495};
496
497static struct clk_dmn clk_dsp = {
498 .regofs = SIRFSOC_CLKC_DSP_CFG,
499 .enable_bit = 0,
500 .hw = {
501 .init = &clk_dsp_init,
502 },
503};
504
505static struct clk_init_data clk_gfx_init = {
506 .name = "gfx",
507 .ops = &dmn_ops,
508 .parent_names = dmn_clk_parents,
509 .num_parents = ARRAY_SIZE(dmn_clk_parents),
510};
511
512static struct clk_dmn clk_gfx = {
513 .regofs = SIRFSOC_CLKC_GFX_CFG,
514 .enable_bit = 8,
515 .hw = {
516 .init = &clk_gfx_init,
517 },
518};
519
520static struct clk_init_data clk_mm_init = {
521 .name = "mm",
522 .ops = &dmn_ops,
523 .parent_names = dmn_clk_parents,
524 .num_parents = ARRAY_SIZE(dmn_clk_parents),
525};
526
527static struct clk_dmn clk_mm = {
528 .regofs = SIRFSOC_CLKC_MM_CFG,
529 .enable_bit = 9,
530 .hw = {
531 .init = &clk_mm_init,
532 },
533};
534
535static struct clk_init_data clk_lcd_init = {
536 .name = "lcd",
537 .ops = &dmn_ops,
538 .parent_names = dmn_clk_parents,
539 .num_parents = ARRAY_SIZE(dmn_clk_parents),
540};
541
542static struct clk_dmn clk_lcd = {
543 .regofs = SIRFSOC_CLKC_LCD_CFG,
544 .enable_bit = 10,
545 .hw = {
546 .init = &clk_lcd_init,
547 },
548};
549
550static struct clk_init_data clk_vpp_init = {
551 .name = "vpp",
552 .ops = &dmn_ops,
553 .parent_names = dmn_clk_parents,
554 .num_parents = ARRAY_SIZE(dmn_clk_parents),
555};
556
557static struct clk_dmn clk_vpp = {
558 .regofs = SIRFSOC_CLKC_LCD_CFG,
559 .enable_bit = 11,
560 .hw = {
561 .init = &clk_vpp_init,
562 },
563};
564
565static struct clk_init_data clk_mmc01_init = {
566 .name = "mmc01",
567 .ops = &dmn_ops,
568 .parent_names = dmn_clk_parents,
569 .num_parents = ARRAY_SIZE(dmn_clk_parents),
570};
571
572static struct clk_dmn clk_mmc01 = {
573 .regofs = SIRFSOC_CLKC_MMC_CFG,
574 .enable_bit = 59,
575 .hw = {
576 .init = &clk_mmc01_init,
577 },
578};
579
580static struct clk_init_data clk_mmc23_init = {
581 .name = "mmc23",
582 .ops = &dmn_ops,
583 .parent_names = dmn_clk_parents,
584 .num_parents = ARRAY_SIZE(dmn_clk_parents),
585};
586
587static struct clk_dmn clk_mmc23 = {
588 .regofs = SIRFSOC_CLKC_MMC_CFG,
589 .enable_bit = 60,
590 .hw = {
591 .init = &clk_mmc23_init,
592 },
593};
594
595static struct clk_init_data clk_mmc45_init = {
596 .name = "mmc45",
597 .ops = &dmn_ops,
598 .parent_names = dmn_clk_parents,
599 .num_parents = ARRAY_SIZE(dmn_clk_parents),
600};
601
602static struct clk_dmn clk_mmc45 = {
603 .regofs = SIRFSOC_CLKC_MMC_CFG,
604 .enable_bit = 61,
605 .hw = {
606 .init = &clk_mmc45_init,
607 },
608};
609
610/*
611 * peripheral controllers in io domain
612 */
613
614static int std_clk_is_enabled(struct clk_hw *hw)
Binghua Duan02c981c2011-07-08 17:40:12 +0800615{
Binghua Duan198678b2012-08-20 06:42:36 +0000616 u32 reg;
617 int bit;
618 struct clk_std *clk = to_stdclk(hw);
Binghua Duan02c981c2011-07-08 17:40:12 +0800619
Binghua Duan198678b2012-08-20 06:42:36 +0000620 bit = clk->enable_bit % 32;
621 reg = clk->enable_bit / 32;
622 reg = SIRFSOC_CLKC_CLK_EN0 + reg * sizeof(reg);
Binghua Duan02c981c2011-07-08 17:40:12 +0800623
Binghua Duan198678b2012-08-20 06:42:36 +0000624 return !!(clkc_readl(reg) & BIT(bit));
625}
Binghua Duan02c981c2011-07-08 17:40:12 +0800626
Binghua Duan198678b2012-08-20 06:42:36 +0000627static int std_clk_enable(struct clk_hw *hw)
628{
629 u32 val, reg;
630 int bit;
631 struct clk_std *clk = to_stdclk(hw);
632
633 BUG_ON(clk->enable_bit < 0 || clk->enable_bit > 63);
634
635 bit = clk->enable_bit % 32;
636 reg = clk->enable_bit / 32;
637 reg = SIRFSOC_CLKC_CLK_EN0 + reg * sizeof(reg);
638
639 val = clkc_readl(reg) | BIT(bit);
640 clkc_writel(val, reg);
Binghua Duan02c981c2011-07-08 17:40:12 +0800641 return 0;
642}
Binghua Duan02c981c2011-07-08 17:40:12 +0800643
Binghua Duan198678b2012-08-20 06:42:36 +0000644static void std_clk_disable(struct clk_hw *hw)
Binghua Duan02c981c2011-07-08 17:40:12 +0800645{
Binghua Duan198678b2012-08-20 06:42:36 +0000646 u32 val, reg;
647 int bit;
648 struct clk_std *clk = to_stdclk(hw);
Binghua Duan02c981c2011-07-08 17:40:12 +0800649
Binghua Duan198678b2012-08-20 06:42:36 +0000650 BUG_ON(clk->enable_bit < 0 || clk->enable_bit > 63);
Binghua Duan02c981c2011-07-08 17:40:12 +0800651
Binghua Duan198678b2012-08-20 06:42:36 +0000652 bit = clk->enable_bit % 32;
653 reg = clk->enable_bit / 32;
654 reg = SIRFSOC_CLKC_CLK_EN0 + reg * sizeof(reg);
Binghua Duan02c981c2011-07-08 17:40:12 +0800655
Binghua Duan198678b2012-08-20 06:42:36 +0000656 val = clkc_readl(reg) & ~BIT(bit);
657 clkc_writel(val, reg);
Binghua Duan02c981c2011-07-08 17:40:12 +0800658}
Binghua Duan02c981c2011-07-08 17:40:12 +0800659
Binghua Duan198678b2012-08-20 06:42:36 +0000660static const char *std_clk_io_parents[] = {
661 "io",
662};
Binghua Duan02c981c2011-07-08 17:40:12 +0800663
Binghua Duan198678b2012-08-20 06:42:36 +0000664static struct clk_ops ios_ops = {
665 .is_enabled = std_clk_is_enabled,
666 .enable = std_clk_enable,
667 .disable = std_clk_disable,
668};
Binghua Duan02c981c2011-07-08 17:40:12 +0800669
Binghua Duan198678b2012-08-20 06:42:36 +0000670static struct clk_init_data clk_dmac0_init = {
671 .name = "dmac0",
672 .ops = &ios_ops,
673 .parent_names = std_clk_io_parents,
674 .num_parents = ARRAY_SIZE(std_clk_io_parents),
675};
Binghua Duan02c981c2011-07-08 17:40:12 +0800676
Binghua Duan198678b2012-08-20 06:42:36 +0000677static struct clk_std clk_dmac0 = {
678 .enable_bit = 32,
679 .hw = {
680 .init = &clk_dmac0_init,
681 },
682};
Binghua Duan02c981c2011-07-08 17:40:12 +0800683
Binghua Duan198678b2012-08-20 06:42:36 +0000684static struct clk_init_data clk_dmac1_init = {
685 .name = "dmac1",
686 .ops = &ios_ops,
687 .parent_names = std_clk_io_parents,
688 .num_parents = ARRAY_SIZE(std_clk_io_parents),
689};
Binghua Duan02c981c2011-07-08 17:40:12 +0800690
Binghua Duan198678b2012-08-20 06:42:36 +0000691static struct clk_std clk_dmac1 = {
692 .enable_bit = 33,
693 .hw = {
694 .init = &clk_dmac1_init,
695 },
696};
Binghua Duan02c981c2011-07-08 17:40:12 +0800697
Binghua Duan198678b2012-08-20 06:42:36 +0000698static struct clk_init_data clk_nand_init = {
699 .name = "nand",
700 .ops = &ios_ops,
701 .parent_names = std_clk_io_parents,
702 .num_parents = ARRAY_SIZE(std_clk_io_parents),
703};
Binghua Duan02c981c2011-07-08 17:40:12 +0800704
Binghua Duan198678b2012-08-20 06:42:36 +0000705static struct clk_std clk_nand = {
706 .enable_bit = 34,
707 .hw = {
708 .init = &clk_nand_init,
709 },
710};
Binghua Duan02c981c2011-07-08 17:40:12 +0800711
Binghua Duan198678b2012-08-20 06:42:36 +0000712static struct clk_init_data clk_audio_init = {
713 .name = "audio",
714 .ops = &ios_ops,
715 .parent_names = std_clk_io_parents,
716 .num_parents = ARRAY_SIZE(std_clk_io_parents),
717};
Binghua Duan02c981c2011-07-08 17:40:12 +0800718
Binghua Duan198678b2012-08-20 06:42:36 +0000719static struct clk_std clk_audio = {
720 .enable_bit = 35,
721 .hw = {
722 .init = &clk_audio_init,
723 },
724};
Binghua Duan02c981c2011-07-08 17:40:12 +0800725
Binghua Duan198678b2012-08-20 06:42:36 +0000726static struct clk_init_data clk_uart0_init = {
727 .name = "uart0",
728 .ops = &ios_ops,
729 .parent_names = std_clk_io_parents,
730 .num_parents = ARRAY_SIZE(std_clk_io_parents),
731};
Binghua Duan02c981c2011-07-08 17:40:12 +0800732
Binghua Duan198678b2012-08-20 06:42:36 +0000733static struct clk_std clk_uart0 = {
734 .enable_bit = 36,
735 .hw = {
736 .init = &clk_uart0_init,
737 },
738};
Binghua Duan02c981c2011-07-08 17:40:12 +0800739
Binghua Duan198678b2012-08-20 06:42:36 +0000740static struct clk_init_data clk_uart1_init = {
741 .name = "uart1",
742 .ops = &ios_ops,
743 .parent_names = std_clk_io_parents,
744 .num_parents = ARRAY_SIZE(std_clk_io_parents),
745};
Binghua Duan02c981c2011-07-08 17:40:12 +0800746
Binghua Duan198678b2012-08-20 06:42:36 +0000747static struct clk_std clk_uart1 = {
748 .enable_bit = 37,
749 .hw = {
750 .init = &clk_uart1_init,
751 },
752};
Binghua Duan02c981c2011-07-08 17:40:12 +0800753
Binghua Duan198678b2012-08-20 06:42:36 +0000754static struct clk_init_data clk_uart2_init = {
755 .name = "uart2",
756 .ops = &ios_ops,
757 .parent_names = std_clk_io_parents,
758 .num_parents = ARRAY_SIZE(std_clk_io_parents),
759};
Binghua Duan02c981c2011-07-08 17:40:12 +0800760
Binghua Duan198678b2012-08-20 06:42:36 +0000761static struct clk_std clk_uart2 = {
762 .enable_bit = 38,
763 .hw = {
764 .init = &clk_uart2_init,
765 },
766};
Binghua Duan02c981c2011-07-08 17:40:12 +0800767
Binghua Duan198678b2012-08-20 06:42:36 +0000768static struct clk_init_data clk_usp0_init = {
769 .name = "usp0",
770 .ops = &ios_ops,
771 .parent_names = std_clk_io_parents,
772 .num_parents = ARRAY_SIZE(std_clk_io_parents),
773};
Binghua Duan02c981c2011-07-08 17:40:12 +0800774
Binghua Duan198678b2012-08-20 06:42:36 +0000775static struct clk_std clk_usp0 = {
776 .enable_bit = 39,
777 .hw = {
778 .init = &clk_usp0_init,
779 },
780};
Binghua Duan02c981c2011-07-08 17:40:12 +0800781
Binghua Duan198678b2012-08-20 06:42:36 +0000782static struct clk_init_data clk_usp1_init = {
783 .name = "usp1",
784 .ops = &ios_ops,
785 .parent_names = std_clk_io_parents,
786 .num_parents = ARRAY_SIZE(std_clk_io_parents),
787};
788
789static struct clk_std clk_usp1 = {
790 .enable_bit = 40,
791 .hw = {
792 .init = &clk_usp1_init,
793 },
794};
795
796static struct clk_init_data clk_usp2_init = {
797 .name = "usp2",
798 .ops = &ios_ops,
799 .parent_names = std_clk_io_parents,
800 .num_parents = ARRAY_SIZE(std_clk_io_parents),
801};
802
803static struct clk_std clk_usp2 = {
804 .enable_bit = 41,
805 .hw = {
806 .init = &clk_usp2_init,
807 },
808};
809
810static struct clk_init_data clk_vip_init = {
811 .name = "vip",
812 .ops = &ios_ops,
813 .parent_names = std_clk_io_parents,
814 .num_parents = ARRAY_SIZE(std_clk_io_parents),
815};
816
817static struct clk_std clk_vip = {
818 .enable_bit = 42,
819 .hw = {
820 .init = &clk_vip_init,
821 },
822};
823
824static struct clk_init_data clk_spi0_init = {
825 .name = "spi0",
826 .ops = &ios_ops,
827 .parent_names = std_clk_io_parents,
828 .num_parents = ARRAY_SIZE(std_clk_io_parents),
829};
830
831static struct clk_std clk_spi0 = {
832 .enable_bit = 43,
833 .hw = {
834 .init = &clk_spi0_init,
835 },
836};
837
838static struct clk_init_data clk_spi1_init = {
839 .name = "spi1",
840 .ops = &ios_ops,
841 .parent_names = std_clk_io_parents,
842 .num_parents = ARRAY_SIZE(std_clk_io_parents),
843};
844
845static struct clk_std clk_spi1 = {
846 .enable_bit = 44,
847 .hw = {
848 .init = &clk_spi1_init,
849 },
850};
851
852static struct clk_init_data clk_tsc_init = {
853 .name = "tsc",
854 .ops = &ios_ops,
855 .parent_names = std_clk_io_parents,
856 .num_parents = ARRAY_SIZE(std_clk_io_parents),
857};
858
859static struct clk_std clk_tsc = {
860 .enable_bit = 45,
861 .hw = {
862 .init = &clk_tsc_init,
863 },
864};
865
866static struct clk_init_data clk_i2c0_init = {
867 .name = "i2c0",
868 .ops = &ios_ops,
869 .parent_names = std_clk_io_parents,
870 .num_parents = ARRAY_SIZE(std_clk_io_parents),
871};
872
873static struct clk_std clk_i2c0 = {
874 .enable_bit = 46,
875 .hw = {
876 .init = &clk_i2c0_init,
877 },
878};
879
880static struct clk_init_data clk_i2c1_init = {
881 .name = "i2c1",
882 .ops = &ios_ops,
883 .parent_names = std_clk_io_parents,
884 .num_parents = ARRAY_SIZE(std_clk_io_parents),
885};
886
887static struct clk_std clk_i2c1 = {
888 .enable_bit = 47,
889 .hw = {
890 .init = &clk_i2c1_init,
891 },
892};
893
894static struct clk_init_data clk_pwmc_init = {
895 .name = "pwmc",
896 .ops = &ios_ops,
897 .parent_names = std_clk_io_parents,
898 .num_parents = ARRAY_SIZE(std_clk_io_parents),
899};
900
901static struct clk_std clk_pwmc = {
902 .enable_bit = 48,
903 .hw = {
904 .init = &clk_pwmc_init,
905 },
906};
907
908static struct clk_init_data clk_efuse_init = {
909 .name = "efuse",
910 .ops = &ios_ops,
911 .parent_names = std_clk_io_parents,
912 .num_parents = ARRAY_SIZE(std_clk_io_parents),
913};
914
915static struct clk_std clk_efuse = {
916 .enable_bit = 49,
917 .hw = {
918 .init = &clk_efuse_init,
919 },
920};
921
922static struct clk_init_data clk_pulse_init = {
923 .name = "pulse",
924 .ops = &ios_ops,
925 .parent_names = std_clk_io_parents,
926 .num_parents = ARRAY_SIZE(std_clk_io_parents),
927};
928
929static struct clk_std clk_pulse = {
930 .enable_bit = 50,
931 .hw = {
932 .init = &clk_pulse_init,
933 },
934};
935
936static const char *std_clk_dsp_parents[] = {
937 "dsp",
938};
939
940static struct clk_init_data clk_gps_init = {
941 .name = "gps",
942 .ops = &ios_ops,
943 .parent_names = std_clk_dsp_parents,
944 .num_parents = ARRAY_SIZE(std_clk_dsp_parents),
945};
946
947static struct clk_std clk_gps = {
948 .enable_bit = 1,
949 .hw = {
950 .init = &clk_gps_init,
951 },
952};
953
954static struct clk_init_data clk_mf_init = {
955 .name = "mf",
956 .ops = &ios_ops,
957 .parent_names = std_clk_io_parents,
958 .num_parents = ARRAY_SIZE(std_clk_io_parents),
959};
960
961static struct clk_std clk_mf = {
962 .enable_bit = 2,
963 .hw = {
964 .init = &clk_mf_init,
965 },
966};
967
968static const char *std_clk_sys_parents[] = {
969 "sys",
970};
971
972static struct clk_init_data clk_security_init = {
973 .name = "mf",
974 .ops = &ios_ops,
975 .parent_names = std_clk_sys_parents,
976 .num_parents = ARRAY_SIZE(std_clk_sys_parents),
977};
978
979static struct clk_std clk_security = {
980 .enable_bit = 19,
981 .hw = {
982 .init = &clk_security_init,
983 },
984};
985
986static const char *std_clk_usb_parents[] = {
987 "usb_pll",
988};
989
990static struct clk_init_data clk_usb0_init = {
991 .name = "usb0",
992 .ops = &ios_ops,
993 .parent_names = std_clk_usb_parents,
994 .num_parents = ARRAY_SIZE(std_clk_usb_parents),
995};
996
997static struct clk_std clk_usb0 = {
998 .enable_bit = 16,
999 .hw = {
1000 .init = &clk_usb0_init,
1001 },
1002};
1003
1004static struct clk_init_data clk_usb1_init = {
1005 .name = "usb1",
1006 .ops = &ios_ops,
1007 .parent_names = std_clk_usb_parents,
1008 .num_parents = ARRAY_SIZE(std_clk_usb_parents),
1009};
1010
1011static struct clk_std clk_usb1 = {
1012 .enable_bit = 17,
1013 .hw = {
1014 .init = &clk_usb1_init,
1015 },
1016};
Binghua Duan02c981c2011-07-08 17:40:12 +08001017
Barry Songeb8b8f22012-12-20 16:51:31 +08001018enum prima2_clk_index {
1019 /* 0 1 2 3 4 5 6 7 8 9 */
1020 rtc, osc, pll1, pll2, pll3, mem, sys, security, dsp, gps,
1021 mf, io, cpu, uart0, uart1, uart2, tsc, i2c0, i2c1, spi0,
1022 spi1, pwmc, efuse, pulse, dmac0, dmac1, nand, audio, usp0, usp1,
1023 usp2, vip, gfx, mm, lcd, vpp, mmc01, mmc23, mmc45, usbpll,
1024 usb0, usb1, maxclk,
1025};
1026
Sachin Kamat18f58632013-08-08 10:01:26 +05301027static struct clk_hw *prima2_clk_hw_array[maxclk] __initdata = {
Barry Songeb8b8f22012-12-20 16:51:31 +08001028 NULL, /* dummy */
1029 NULL,
1030 &clk_pll1.hw,
1031 &clk_pll2.hw,
1032 &clk_pll3.hw,
1033 &clk_mem.hw,
1034 &clk_sys.hw,
1035 &clk_security.hw,
1036 &clk_dsp.hw,
1037 &clk_gps.hw,
1038 &clk_mf.hw,
1039 &clk_io.hw,
1040 &clk_cpu.hw,
1041 &clk_uart0.hw,
1042 &clk_uart1.hw,
1043 &clk_uart2.hw,
1044 &clk_tsc.hw,
1045 &clk_i2c0.hw,
1046 &clk_i2c1.hw,
1047 &clk_spi0.hw,
1048 &clk_spi1.hw,
1049 &clk_pwmc.hw,
1050 &clk_efuse.hw,
1051 &clk_pulse.hw,
1052 &clk_dmac0.hw,
1053 &clk_dmac1.hw,
1054 &clk_nand.hw,
1055 &clk_audio.hw,
1056 &clk_usp0.hw,
1057 &clk_usp1.hw,
1058 &clk_usp2.hw,
1059 &clk_vip.hw,
1060 &clk_gfx.hw,
1061 &clk_mm.hw,
1062 &clk_lcd.hw,
1063 &clk_vpp.hw,
1064 &clk_mmc01.hw,
1065 &clk_mmc23.hw,
1066 &clk_mmc45.hw,
1067 &usb_pll_clk_hw,
1068 &clk_usb0.hw,
1069 &clk_usb1.hw,
1070};
1071
1072static struct clk *prima2_clks[maxclk];
1073static struct clk_onecell_data clk_data;
1074
Sebastian Hesselbarth27966ff2013-09-04 14:21:18 +02001075static void __init sirfsoc_clk_init(struct device_node *np)
Binghua Duan02c981c2011-07-08 17:40:12 +08001076{
Sebastian Hesselbarth27966ff2013-09-04 14:21:18 +02001077 struct device_node *rscnp;
Barry Songeb8b8f22012-12-20 16:51:31 +08001078 int i;
Binghua Duan02c981c2011-07-08 17:40:12 +08001079
Sebastian Hesselbarth27966ff2013-09-04 14:21:18 +02001080 rscnp = of_find_compatible_node(NULL, NULL, "sirf,prima2-rsc");
1081 sirfsoc_rsc_vbase = of_iomap(rscnp, 0);
Binghua Duan198678b2012-08-20 06:42:36 +00001082 if (!sirfsoc_rsc_vbase)
1083 panic("unable to map rsc registers\n");
Sebastian Hesselbarth27966ff2013-09-04 14:21:18 +02001084 of_node_put(rscnp);
Barry Songeb8b8f22012-12-20 16:51:31 +08001085
1086 sirfsoc_clk_vbase = of_iomap(np, 0);
1087 if (!sirfsoc_clk_vbase)
1088 panic("unable to map clkc registers\n");
Binghua Duan198678b2012-08-20 06:42:36 +00001089
1090 /* These are always available (RTC and 26MHz OSC)*/
Barry Songeb8b8f22012-12-20 16:51:31 +08001091 prima2_clks[rtc] = clk_register_fixed_rate(NULL, "rtc", NULL,
Binghua Duan198678b2012-08-20 06:42:36 +00001092 CLK_IS_ROOT, 32768);
Barry Songeb8b8f22012-12-20 16:51:31 +08001093 prima2_clks[osc]= clk_register_fixed_rate(NULL, "osc", NULL,
Binghua Duan198678b2012-08-20 06:42:36 +00001094 CLK_IS_ROOT, 26000000);
Binghua Duan198678b2012-08-20 06:42:36 +00001095
Barry Songeb8b8f22012-12-20 16:51:31 +08001096 for (i = pll1; i < maxclk; i++) {
1097 prima2_clks[i] = clk_register(NULL, prima2_clk_hw_array[i]);
Wei Yongjunf15ea6c2013-03-11 23:55:18 +08001098 BUG_ON(IS_ERR(prima2_clks[i]));
Barry Songeb8b8f22012-12-20 16:51:31 +08001099 }
1100 clk_register_clkdev(prima2_clks[cpu], NULL, "cpu");
1101 clk_register_clkdev(prima2_clks[io], NULL, "io");
1102 clk_register_clkdev(prima2_clks[mem], NULL, "mem");
1103
1104 clk_data.clks = prima2_clks;
1105 clk_data.clk_num = maxclk;
1106
1107 of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
Binghua Duan02c981c2011-07-08 17:40:12 +08001108}
Sebastian Hesselbarth27966ff2013-09-04 14:21:18 +02001109CLK_OF_DECLARE(sirfsoc_clk, "sirf,prima2-clkc", sirfsoc_clk_init);