2 * linux/arch/unicore32/kernel/clock.c
4 * Code specific to PKUnity SoC and UniCore ISA
6 * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
7 * Copyright (C) 2001-2010 Guan Xuetao
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
13 #include <linux/module.h>
14 #include <linux/kernel.h>
15 #include <linux/device.h>
16 #include <linux/list.h>
17 #include <linux/errno.h>
18 #include <linux/err.h>
19 #include <linux/string.h>
20 #include <linux/clk.h>
21 #include <linux/mutex.h>
22 #include <linux/delay.h>
25 #include <mach/hardware.h>
28 * Very simple clock implementation
31 struct list_head node
;
36 static struct clk clk_ost_clk
= {
38 .rate
= CLOCK_TICK_RATE
,
41 static struct clk clk_mclk_clk
= {
45 static struct clk clk_bclk32_clk
= {
49 static struct clk clk_ddr_clk
= {
53 static struct clk clk_vga_clk
= {
57 static LIST_HEAD(clocks
);
58 static DEFINE_MUTEX(clocks_mutex
);
60 struct clk
*clk_get(struct device
*dev
, const char *id
)
62 struct clk
*p
, *clk
= ERR_PTR(-ENOENT
);
64 mutex_lock(&clocks_mutex
);
65 list_for_each_entry(p
, &clocks
, node
) {
66 if (strcmp(id
, p
->name
) == 0) {
71 mutex_unlock(&clocks_mutex
);
75 EXPORT_SYMBOL(clk_get
);
77 void clk_put(struct clk
*clk
)
80 EXPORT_SYMBOL(clk_put
);
82 int clk_enable(struct clk
*clk
)
86 EXPORT_SYMBOL(clk_enable
);
88 void clk_disable(struct clk
*clk
)
91 EXPORT_SYMBOL(clk_disable
);
93 unsigned long clk_get_rate(struct clk
*clk
)
97 EXPORT_SYMBOL(clk_get_rate
);
103 } vga_clk_table
[] = {
104 {.rate
= 25175000, .cfg
= 0x00002001, .div
= 0x9},
105 {.rate
= 31500000, .cfg
= 0x00002001, .div
= 0x7},
106 {.rate
= 40000000, .cfg
= 0x00003801, .div
= 0x9},
107 {.rate
= 49500000, .cfg
= 0x00003801, .div
= 0x7},
108 {.rate
= 65000000, .cfg
= 0x00002c01, .div
= 0x4},
109 {.rate
= 78750000, .cfg
= 0x00002400, .div
= 0x7},
110 {.rate
= 108000000, .cfg
= 0x00002c01, .div
= 0x2},
111 {.rate
= 106500000, .cfg
= 0x00003c01, .div
= 0x3},
112 {.rate
= 50650000, .cfg
= 0x00106400, .div
= 0x9},
113 {.rate
= 61500000, .cfg
= 0x00106400, .div
= 0xa},
114 {.rate
= 85500000, .cfg
= 0x00002800, .div
= 0x6},
120 } mclk_clk_table
[] = {
121 {.mrate
= 500000000, .prate
= 0x00109801},
122 {.mrate
= 525000000, .prate
= 0x00104C00},
123 {.mrate
= 550000000, .prate
= 0x00105000},
124 {.mrate
= 575000000, .prate
= 0x00105400},
125 {.mrate
= 600000000, .prate
= 0x00105800},
126 {.mrate
= 625000000, .prate
= 0x00105C00},
127 {.mrate
= 650000000, .prate
= 0x00106000},
128 {.mrate
= 675000000, .prate
= 0x00106400},
129 {.mrate
= 700000000, .prate
= 0x00106800},
130 {.mrate
= 725000000, .prate
= 0x00106C00},
131 {.mrate
= 750000000, .prate
= 0x00107000},
132 {.mrate
= 775000000, .prate
= 0x00107400},
133 {.mrate
= 800000000, .prate
= 0x00107800},
136 int clk_set_rate(struct clk
*clk
, unsigned long rate
)
138 if (clk
== &clk_vga_clk
) {
139 unsigned long pll_vgacfg
, pll_vgadiv
;
142 /* lookup vga_clk_table */
144 for (i
= 0; i
< ARRAY_SIZE(vga_clk_table
); i
++) {
145 if (rate
== vga_clk_table
[i
].rate
) {
146 pll_vgacfg
= vga_clk_table
[i
].cfg
;
147 pll_vgadiv
= vga_clk_table
[i
].div
;
156 if (readl(PM_PLLVGACFG
) == pll_vgacfg
)
159 /* set pll vga cfg reg. */
160 writel(pll_vgacfg
, PM_PLLVGACFG
);
162 writel(PM_PMCR_CFBVGA
, PM_PMCR
);
163 while ((readl(PM_PLLDFCDONE
) & PM_PLLDFCDONE_VGADFC
)
164 != PM_PLLDFCDONE_VGADFC
)
165 udelay(100); /* about 1ms */
167 /* set div cfg reg. */
168 writel(readl(PM_PCGR
) | PM_PCGR_VGACLK
, PM_PCGR
);
170 writel((readl(PM_DIVCFG
) & ~PM_DIVCFG_VGACLK_MASK
)
171 | PM_DIVCFG_VGACLK(pll_vgadiv
), PM_DIVCFG
);
173 writel(readl(PM_SWRESET
) | PM_SWRESET_VGADIV
, PM_SWRESET
);
174 while ((readl(PM_SWRESET
) & PM_SWRESET_VGADIV
)
175 == PM_SWRESET_VGADIV
)
176 udelay(100); /* 65536 bclk32, about 320us */
178 writel(readl(PM_PCGR
) & ~PM_PCGR_VGACLK
, PM_PCGR
);
180 #ifdef CONFIG_CPU_FREQ
181 if (clk
== &clk_mclk_clk
) {
182 u32 pll_rate
, divstatus
= PM_DIVSTATUS
;
185 /* lookup mclk_clk_table */
187 for (i
= 0; i
< ARRAY_SIZE(mclk_clk_table
); i
++) {
188 if (rate
== mclk_clk_table
[i
].mrate
) {
189 pll_rate
= mclk_clk_table
[i
].prate
;
190 clk_mclk_clk
.rate
= mclk_clk_table
[i
].mrate
;
199 if (clk_mclk_clk
.rate
)
200 clk_bclk32_clk
.rate
= clk_mclk_clk
.rate
201 / (((divstatus
& 0x0000f000) >> 12) + 1);
203 /* set pll sys cfg reg. */
204 PM_PLLSYSCFG
= pll_rate
;
206 PM_PMCR
= PM_PMCR_CFBSYS
;
207 while ((PM_PLLDFCDONE
& PM_PLLDFCDONE_SYSDFC
)
208 != PM_PLLDFCDONE_SYSDFC
)
215 EXPORT_SYMBOL(clk_set_rate
);
217 int clk_register(struct clk
*clk
)
219 mutex_lock(&clocks_mutex
);
220 list_add(&clk
->node
, &clocks
);
221 mutex_unlock(&clocks_mutex
);
222 printk(KERN_DEFAULT
"PKUnity PM: %s %lu.%02luM\n", clk
->name
,
223 (clk
->rate
)/1000000, (clk
->rate
)/10000 % 100);
226 EXPORT_SYMBOL(clk_register
);
228 void clk_unregister(struct clk
*clk
)
230 mutex_lock(&clocks_mutex
);
231 list_del(&clk
->node
);
232 mutex_unlock(&clocks_mutex
);
234 EXPORT_SYMBOL(clk_unregister
);
239 } pllrate_table
[] = {
240 {.prate
= 0x00002001, .rate
= 250000000},
241 {.prate
= 0x00104801, .rate
= 250000000},
242 {.prate
= 0x00104C01, .rate
= 262500000},
243 {.prate
= 0x00002401, .rate
= 275000000},
244 {.prate
= 0x00105001, .rate
= 275000000},
245 {.prate
= 0x00105401, .rate
= 287500000},
246 {.prate
= 0x00002801, .rate
= 300000000},
247 {.prate
= 0x00105801, .rate
= 300000000},
248 {.prate
= 0x00105C01, .rate
= 312500000},
249 {.prate
= 0x00002C01, .rate
= 325000000},
250 {.prate
= 0x00106001, .rate
= 325000000},
251 {.prate
= 0x00106401, .rate
= 337500000},
252 {.prate
= 0x00003001, .rate
= 350000000},
253 {.prate
= 0x00106801, .rate
= 350000000},
254 {.prate
= 0x00106C01, .rate
= 362500000},
255 {.prate
= 0x00003401, .rate
= 375000000},
256 {.prate
= 0x00107001, .rate
= 375000000},
257 {.prate
= 0x00107401, .rate
= 387500000},
258 {.prate
= 0x00003801, .rate
= 400000000},
259 {.prate
= 0x00107801, .rate
= 400000000},
260 {.prate
= 0x00107C01, .rate
= 412500000},
261 {.prate
= 0x00003C01, .rate
= 425000000},
262 {.prate
= 0x00108001, .rate
= 425000000},
263 {.prate
= 0x00108401, .rate
= 437500000},
264 {.prate
= 0x00004001, .rate
= 450000000},
265 {.prate
= 0x00108801, .rate
= 450000000},
266 {.prate
= 0x00108C01, .rate
= 462500000},
267 {.prate
= 0x00004401, .rate
= 475000000},
268 {.prate
= 0x00109001, .rate
= 475000000},
269 {.prate
= 0x00109401, .rate
= 487500000},
270 {.prate
= 0x00004801, .rate
= 500000000},
271 {.prate
= 0x00109801, .rate
= 500000000},
272 {.prate
= 0x00104C00, .rate
= 525000000},
273 {.prate
= 0x00002400, .rate
= 550000000},
274 {.prate
= 0x00105000, .rate
= 550000000},
275 {.prate
= 0x00105400, .rate
= 575000000},
276 {.prate
= 0x00002800, .rate
= 600000000},
277 {.prate
= 0x00105800, .rate
= 600000000},
278 {.prate
= 0x00105C00, .rate
= 625000000},
279 {.prate
= 0x00002C00, .rate
= 650000000},
280 {.prate
= 0x00106000, .rate
= 650000000},
281 {.prate
= 0x00106400, .rate
= 675000000},
282 {.prate
= 0x00003000, .rate
= 700000000},
283 {.prate
= 0x00106800, .rate
= 700000000},
284 {.prate
= 0x00106C00, .rate
= 725000000},
285 {.prate
= 0x00003400, .rate
= 750000000},
286 {.prate
= 0x00107000, .rate
= 750000000},
287 {.prate
= 0x00107400, .rate
= 775000000},
288 {.prate
= 0x00003800, .rate
= 800000000},
289 {.prate
= 0x00107800, .rate
= 800000000},
290 {.prate
= 0x00107C00, .rate
= 825000000},
291 {.prate
= 0x00003C00, .rate
= 850000000},
292 {.prate
= 0x00108000, .rate
= 850000000},
293 {.prate
= 0x00108400, .rate
= 875000000},
294 {.prate
= 0x00004000, .rate
= 900000000},
295 {.prate
= 0x00108800, .rate
= 900000000},
296 {.prate
= 0x00108C00, .rate
= 925000000},
297 {.prate
= 0x00004400, .rate
= 950000000},
298 {.prate
= 0x00109000, .rate
= 950000000},
299 {.prate
= 0x00109400, .rate
= 975000000},
300 {.prate
= 0x00004800, .rate
= 1000000000},
301 {.prate
= 0x00109800, .rate
= 1000000000},
308 {.prate
= 0x00100800, .drate
= 44236800},
309 {.prate
= 0x00100C00, .drate
= 66355200},
310 {.prate
= 0x00101000, .drate
= 88473600},
311 {.prate
= 0x00101400, .drate
= 110592000},
312 {.prate
= 0x00101800, .drate
= 132710400},
313 {.prate
= 0x00101C01, .drate
= 154828800},
314 {.prate
= 0x00102001, .drate
= 176947200},
315 {.prate
= 0x00102401, .drate
= 199065600},
316 {.prate
= 0x00102801, .drate
= 221184000},
317 {.prate
= 0x00102C01, .drate
= 243302400},
318 {.prate
= 0x00103001, .drate
= 265420800},
319 {.prate
= 0x00103401, .drate
= 287539200},
320 {.prate
= 0x00103801, .drate
= 309657600},
321 {.prate
= 0x00103C01, .drate
= 331776000},
322 {.prate
= 0x00104001, .drate
= 353894400},
325 static int __init
clk_init(void)
327 #ifdef CONFIG_PUV3_PM
328 u32 pllrate
, divstatus
= readl(PM_DIVSTATUS
);
329 u32 pcgr_val
= readl(PM_PCGR
);
332 pcgr_val
|= PM_PCGR_BCLKMME
| PM_PCGR_BCLKH264E
| PM_PCGR_BCLKH264D
333 | PM_PCGR_HECLK
| PM_PCGR_HDCLK
;
334 writel(pcgr_val
, PM_PCGR
);
336 pllrate
= readl(PM_PLLSYSSTATUS
);
338 /* lookup pmclk_table */
339 clk_mclk_clk
.rate
= 0;
340 for (i
= 0; i
< ARRAY_SIZE(pllrate_table
); i
++) {
341 if (pllrate
== pllrate_table
[i
].prate
) {
342 clk_mclk_clk
.rate
= pllrate_table
[i
].rate
;
347 if (clk_mclk_clk
.rate
)
348 clk_bclk32_clk
.rate
= clk_mclk_clk
.rate
/
349 (((divstatus
& 0x0000f000) >> 12) + 1);
351 pllrate
= readl(PM_PLLDDRSTATUS
);
353 /* lookup pddr_table */
354 clk_ddr_clk
.rate
= 0;
355 for (i
= 0; i
< ARRAY_SIZE(pddr_table
); i
++) {
356 if (pllrate
== pddr_table
[i
].prate
) {
357 clk_ddr_clk
.rate
= pddr_table
[i
].drate
;
362 pllrate
= readl(PM_PLLVGASTATUS
);
364 /* lookup pvga_table */
365 clk_vga_clk
.rate
= 0;
366 for (i
= 0; i
< ARRAY_SIZE(pllrate_table
); i
++) {
367 if (pllrate
== pllrate_table
[i
].prate
) {
368 clk_vga_clk
.rate
= pllrate_table
[i
].rate
;
373 if (clk_vga_clk
.rate
)
374 clk_vga_clk
.rate
= clk_vga_clk
.rate
/
375 (((divstatus
& 0x00f00000) >> 20) + 1);
377 clk_register(&clk_vga_clk
);
379 #ifdef CONFIG_ARCH_FPGA
380 clk_ddr_clk
.rate
= 33000000;
381 clk_mclk_clk
.rate
= 33000000;
382 clk_bclk32_clk
.rate
= 33000000;
384 clk_register(&clk_ddr_clk
);
385 clk_register(&clk_mclk_clk
);
386 clk_register(&clk_bclk32_clk
);
387 clk_register(&clk_ost_clk
);
390 core_initcall(clk_init
);