1/* 2 * linux/arch/unicore32/kernel/clock.c 3 * 4 * Code specific to PKUnity SoC and UniCore ISA 5 * 6 * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn> 7 * Copyright (C) 2001-2010 Guan Xuetao 8 * 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. 12 */ 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> 23#include <linux/io.h> 24 25#include <mach/hardware.h> 26 27/* 28 * Very simple clock implementation 29 */ 30struct clk { 31 struct list_head node; 32 unsigned long rate; 33 const char *name; 34}; 35 36static struct clk clk_ost_clk = { 37 .name = "OST_CLK", 38 .rate = CLOCK_TICK_RATE, 39}; 40 41static struct clk clk_mclk_clk = { 42 .name = "MAIN_CLK", 43}; 44 45static struct clk clk_bclk32_clk = { 46 .name = "BUS32_CLK", 47}; 48 49static struct clk clk_ddr_clk = { 50 .name = "DDR_CLK", 51}; 52 53static struct clk clk_vga_clk = { 54 .name = "VGA_CLK", 55}; 56 57static LIST_HEAD(clocks); 58static DEFINE_MUTEX(clocks_mutex); 59 60struct clk *clk_get(struct device *dev, const char *id) 61{ 62 struct clk *p, *clk = ERR_PTR(-ENOENT); 63 64 mutex_lock(&clocks_mutex); 65 list_for_each_entry(p, &clocks, node) { 66 if (strcmp(id, p->name) == 0) { 67 clk = p; 68 break; 69 } 70 } 71 mutex_unlock(&clocks_mutex); 72 73 return clk; 74} 75EXPORT_SYMBOL(clk_get); 76 77void clk_put(struct clk *clk) 78{ 79} 80EXPORT_SYMBOL(clk_put); 81 82int clk_enable(struct clk *clk) 83{ 84 return 0; 85} 86EXPORT_SYMBOL(clk_enable); 87 88void clk_disable(struct clk *clk) 89{ 90} 91EXPORT_SYMBOL(clk_disable); 92 93unsigned long clk_get_rate(struct clk *clk) 94{ 95 return clk->rate; 96} 97EXPORT_SYMBOL(clk_get_rate); 98 99struct { 100 unsigned long rate; 101 unsigned long cfg; 102 unsigned long div; 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}, 115}; 116 117struct { 118 unsigned long mrate; 119 unsigned long prate; 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}, 134}; 135 136int clk_set_rate(struct clk *clk, unsigned long rate) 137{ 138 if (clk == &clk_vga_clk) { 139 unsigned long pll_vgacfg, pll_vgadiv; 140 int ret, i; 141 142 /* lookup vga_clk_table */ 143 ret = -EINVAL; 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; 148 ret = 0; 149 break; 150 } 151 } 152 153 if (ret) 154 return ret; 155 156 if (readl(PM_PLLVGACFG) == pll_vgacfg) 157 return 0; 158 159 /* set pll vga cfg reg. */ 160 writel(pll_vgacfg, PM_PLLVGACFG); 161 162 writel(PM_PMCR_CFBVGA, PM_PMCR); 163 while ((readl(PM_PLLDFCDONE) & PM_PLLDFCDONE_VGADFC) 164 != PM_PLLDFCDONE_VGADFC) 165 udelay(100); /* about 1ms */ 166 167 /* set div cfg reg. */ 168 writel(readl(PM_PCGR) | PM_PCGR_VGACLK, PM_PCGR); 169 170 writel((readl(PM_DIVCFG) & ~PM_DIVCFG_VGACLK_MASK) 171 | PM_DIVCFG_VGACLK(pll_vgadiv), PM_DIVCFG); 172 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 */ 177 178 writel(readl(PM_PCGR) & ~PM_PCGR_VGACLK, PM_PCGR); 179 } 180#ifdef CONFIG_CPU_FREQ 181 if (clk == &clk_mclk_clk) { 182 u32 pll_rate, divstatus = readl(PM_DIVSTATUS); 183 int ret, i; 184 185 /* lookup mclk_clk_table */ 186 ret = -EINVAL; 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; 191 ret = 0; 192 break; 193 } 194 } 195 196 if (ret) 197 return ret; 198 199 if (clk_mclk_clk.rate) 200 clk_bclk32_clk.rate = clk_mclk_clk.rate 201 / (((divstatus & 0x0000f000) >> 12) + 1); 202 203 /* set pll sys cfg reg. */ 204 writel(pll_rate, PM_PLLSYSCFG); 205 206 writel(PM_PMCR_CFBSYS, PM_PMCR); 207 while ((readl(PM_PLLDFCDONE) & PM_PLLDFCDONE_SYSDFC) 208 != PM_PLLDFCDONE_SYSDFC) 209 udelay(100); 210 /* about 1ms */ 211 } 212#endif 213 return 0; 214} 215EXPORT_SYMBOL(clk_set_rate); 216 217int clk_register(struct clk *clk) 218{ 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); 224 return 0; 225} 226EXPORT_SYMBOL(clk_register); 227 228void clk_unregister(struct clk *clk) 229{ 230 mutex_lock(&clocks_mutex); 231 list_del(&clk->node); 232 mutex_unlock(&clocks_mutex); 233} 234EXPORT_SYMBOL(clk_unregister); 235 236struct { 237 unsigned long prate; 238 unsigned long rate; 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}, 302}; 303 304struct { 305 unsigned long prate; 306 unsigned long drate; 307} pddr_table[] = { 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}, 323}; 324 325static int __init clk_init(void) 326{ 327#ifdef CONFIG_PUV3_PM 328 u32 pllrate, divstatus = readl(PM_DIVSTATUS); 329 u32 pcgr_val = readl(PM_PCGR); 330 int i; 331 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); 335 336 pllrate = readl(PM_PLLSYSSTATUS); 337 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; 343 break; 344 } 345 } 346 347 if (clk_mclk_clk.rate) 348 clk_bclk32_clk.rate = clk_mclk_clk.rate / 349 (((divstatus & 0x0000f000) >> 12) + 1); 350 351 pllrate = readl(PM_PLLDDRSTATUS); 352 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; 358 break; 359 } 360 } 361 362 pllrate = readl(PM_PLLVGASTATUS); 363 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; 369 break; 370 } 371 } 372 373 if (clk_vga_clk.rate) 374 clk_vga_clk.rate = clk_vga_clk.rate / 375 (((divstatus & 0x00f00000) >> 20) + 1); 376 377 clk_register(&clk_vga_clk); 378#endif 379#ifdef CONFIG_ARCH_FPGA 380 clk_ddr_clk.rate = 33000000; 381 clk_mclk_clk.rate = 33000000; 382 clk_bclk32_clk.rate = 33000000; 383#endif 384 clk_register(&clk_ddr_clk); 385 clk_register(&clk_mclk_clk); 386 clk_register(&clk_bclk32_clk); 387 clk_register(&clk_ost_clk); 388 return 0; 389} 390core_initcall(clk_init); 391