1/* linux/arch/arm/mach-s5pv310/clock.c 2 * 3 * Copyright (c) 2010 Samsung Electronics Co., Ltd. 4 * http://www.samsung.com/ 5 * 6 * S5PV310 - Clock support 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License version 2 as 10 * published by the Free Software Foundation. 11*/ 12 13#include <linux/kernel.h> 14#include <linux/err.h> 15#include <linux/io.h> 16 17#include <plat/cpu-freq.h> 18#include <plat/clock.h> 19#include <plat/cpu.h> 20#include <plat/pll.h> 21#include <plat/s5p-clock.h> 22#include <plat/clock-clksrc.h> 23 24#include <mach/map.h> 25#include <mach/regs-clock.h> 26 27static struct clk clk_sclk_hdmi27m = { 28 .name = "sclk_hdmi27m", 29 .id = -1, 30 .rate = 27000000, 31}; 32 33static int s5pv310_clksrc_mask_peril0_ctrl(struct clk *clk, int enable) 34{ 35 return s5p_gatectrl(S5P_CLKSRC_MASK_PERIL0, clk, enable); 36} 37 38static int s5pv310_clk_ip_peril_ctrl(struct clk *clk, int enable) 39{ 40 return s5p_gatectrl(S5P_CLKGATE_IP_PERIL, clk, enable); 41} 42 43/* Core list of CMU_CPU side */ 44 45static struct clksrc_clk clk_mout_apll = { 46 .clk = { 47 .name = "mout_apll", 48 .id = -1, 49 }, 50 .sources = &clk_src_apll, 51 .reg_src = { .reg = S5P_CLKSRC_CPU, .shift = 0, .size = 1 }, 52}; 53 54static struct clksrc_clk clk_sclk_apll = { 55 .clk = { 56 .name = "sclk_apll", 57 .id = -1, 58 .parent = &clk_mout_apll.clk, 59 }, 60 .reg_div = { .reg = S5P_CLKDIV_CPU, .shift = 24, .size = 3 }, 61}; 62 63static struct clksrc_clk clk_mout_epll = { 64 .clk = { 65 .name = "mout_epll", 66 .id = -1, 67 }, 68 .sources = &clk_src_epll, 69 .reg_src = { .reg = S5P_CLKSRC_TOP0, .shift = 4, .size = 1 }, 70}; 71 72static struct clksrc_clk clk_mout_mpll = { 73 .clk = { 74 .name = "mout_mpll", 75 .id = -1, 76 }, 77 .sources = &clk_src_mpll, 78 .reg_src = { .reg = S5P_CLKSRC_CPU, .shift = 8, .size = 1 }, 79}; 80 81static struct clk *clkset_moutcore_list[] = { 82 [0] = &clk_sclk_apll.clk, 83 [1] = &clk_mout_mpll.clk, 84}; 85 86static struct clksrc_sources clkset_moutcore = { 87 .sources = clkset_moutcore_list, 88 .nr_sources = ARRAY_SIZE(clkset_moutcore_list), 89}; 90 91static struct clksrc_clk clk_moutcore = { 92 .clk = { 93 .name = "moutcore", 94 .id = -1, 95 }, 96 .sources = &clkset_moutcore, 97 .reg_src = { .reg = S5P_CLKSRC_CPU, .shift = 16, .size = 1 }, 98}; 99 100static struct clksrc_clk clk_coreclk = { 101 .clk = { 102 .name = "core_clk", 103 .id = -1, 104 .parent = &clk_moutcore.clk, 105 }, 106 .reg_div = { .reg = S5P_CLKDIV_CPU, .shift = 0, .size = 3 }, 107}; 108 109static struct clksrc_clk clk_armclk = { 110 .clk = { 111 .name = "armclk", 112 .id = -1, 113 .parent = &clk_coreclk.clk, 114 }, 115}; 116 117static struct clksrc_clk clk_aclk_corem0 = { 118 .clk = { 119 .name = "aclk_corem0", 120 .id = -1, 121 .parent = &clk_coreclk.clk, 122 }, 123 .reg_div = { .reg = S5P_CLKDIV_CPU, .shift = 4, .size = 3 }, 124}; 125 126static struct clksrc_clk clk_aclk_cores = { 127 .clk = { 128 .name = "aclk_cores", 129 .id = -1, 130 .parent = &clk_coreclk.clk, 131 }, 132 .reg_div = { .reg = S5P_CLKDIV_CPU, .shift = 4, .size = 3 }, 133}; 134 135static struct clksrc_clk clk_aclk_corem1 = { 136 .clk = { 137 .name = "aclk_corem1", 138 .id = -1, 139 .parent = &clk_coreclk.clk, 140 }, 141 .reg_div = { .reg = S5P_CLKDIV_CPU, .shift = 8, .size = 3 }, 142}; 143 144static struct clksrc_clk clk_periphclk = { 145 .clk = { 146 .name = "periphclk", 147 .id = -1, 148 .parent = &clk_coreclk.clk, 149 }, 150 .reg_div = { .reg = S5P_CLKDIV_CPU, .shift = 12, .size = 3 }, 151}; 152 153static struct clksrc_clk clk_atclk = { 154 .clk = { 155 .name = "atclk", 156 .id = -1, 157 .parent = &clk_moutcore.clk, 158 }, 159 .reg_div = { .reg = S5P_CLKDIV_CPU, .shift = 16, .size = 3 }, 160}; 161 162static struct clksrc_clk clk_pclk_dbg = { 163 .clk = { 164 .name = "pclk_dbg", 165 .id = -1, 166 .parent = &clk_atclk.clk, 167 }, 168 .reg_div = { .reg = S5P_CLKDIV_CPU, .shift = 20, .size = 3 }, 169}; 170 171/* Core list of CMU_CORE side */ 172 173static struct clk *clkset_corebus_list[] = { 174 [0] = &clk_mout_mpll.clk, 175 [1] = &clk_sclk_apll.clk, 176}; 177 178static struct clksrc_sources clkset_mout_corebus = { 179 .sources = clkset_corebus_list, 180 .nr_sources = ARRAY_SIZE(clkset_corebus_list), 181}; 182 183static struct clksrc_clk clk_mout_corebus = { 184 .clk = { 185 .name = "mout_corebus", 186 .id = -1, 187 }, 188 .sources = &clkset_mout_corebus, 189 .reg_src = { .reg = S5P_CLKSRC_CORE, .shift = 4, .size = 1 }, 190}; 191 192static struct clksrc_clk clk_sclk_dmc = { 193 .clk = { 194 .name = "sclk_dmc", 195 .id = -1, 196 .parent = &clk_mout_corebus.clk, 197 }, 198 .reg_div = { .reg = S5P_CLKDIV_CORE0, .shift = 12, .size = 3 }, 199}; 200 201static struct clksrc_clk clk_aclk_cored = { 202 .clk = { 203 .name = "aclk_cored", 204 .id = -1, 205 .parent = &clk_sclk_dmc.clk, 206 }, 207 .reg_div = { .reg = S5P_CLKDIV_CORE0, .shift = 16, .size = 3 }, 208}; 209 210static struct clksrc_clk clk_aclk_corep = { 211 .clk = { 212 .name = "aclk_corep", 213 .id = -1, 214 .parent = &clk_aclk_cored.clk, 215 }, 216 .reg_div = { .reg = S5P_CLKDIV_CORE0, .shift = 20, .size = 3 }, 217}; 218 219static struct clksrc_clk clk_aclk_acp = { 220 .clk = { 221 .name = "aclk_acp", 222 .id = -1, 223 .parent = &clk_mout_corebus.clk, 224 }, 225 .reg_div = { .reg = S5P_CLKDIV_CORE0, .shift = 0, .size = 3 }, 226}; 227 228static struct clksrc_clk clk_pclk_acp = { 229 .clk = { 230 .name = "pclk_acp", 231 .id = -1, 232 .parent = &clk_aclk_acp.clk, 233 }, 234 .reg_div = { .reg = S5P_CLKDIV_CORE0, .shift = 4, .size = 3 }, 235}; 236 237/* Core list of CMU_TOP side */ 238 239static struct clk *clkset_aclk_top_list[] = { 240 [0] = &clk_mout_mpll.clk, 241 [1] = &clk_sclk_apll.clk, 242}; 243 244static struct clksrc_sources clkset_aclk_200 = { 245 .sources = clkset_aclk_top_list, 246 .nr_sources = ARRAY_SIZE(clkset_aclk_top_list), 247}; 248 249static struct clksrc_clk clk_aclk_200 = { 250 .clk = { 251 .name = "aclk_200", 252 .id = -1, 253 }, 254 .sources = &clkset_aclk_200, 255 .reg_src = { .reg = S5P_CLKSRC_TOP0, .shift = 12, .size = 1 }, 256 .reg_div = { .reg = S5P_CLKDIV_TOP, .shift = 0, .size = 3 }, 257}; 258 259static struct clksrc_sources clkset_aclk_100 = { 260 .sources = clkset_aclk_top_list, 261 .nr_sources = ARRAY_SIZE(clkset_aclk_top_list), 262}; 263 264static struct clksrc_clk clk_aclk_100 = { 265 .clk = { 266 .name = "aclk_100", 267 .id = -1, 268 }, 269 .sources = &clkset_aclk_100, 270 .reg_src = { .reg = S5P_CLKSRC_TOP0, .shift = 16, .size = 1 }, 271 .reg_div = { .reg = S5P_CLKDIV_TOP, .shift = 4, .size = 4 }, 272}; 273 274static struct clksrc_sources clkset_aclk_160 = { 275 .sources = clkset_aclk_top_list, 276 .nr_sources = ARRAY_SIZE(clkset_aclk_top_list), 277}; 278 279static struct clksrc_clk clk_aclk_160 = { 280 .clk = { 281 .name = "aclk_160", 282 .id = -1, 283 }, 284 .sources = &clkset_aclk_160, 285 .reg_src = { .reg = S5P_CLKSRC_TOP0, .shift = 20, .size = 1 }, 286 .reg_div = { .reg = S5P_CLKDIV_TOP, .shift = 8, .size = 3 }, 287}; 288 289static struct clksrc_sources clkset_aclk_133 = { 290 .sources = clkset_aclk_top_list, 291 .nr_sources = ARRAY_SIZE(clkset_aclk_top_list), 292}; 293 294static struct clksrc_clk clk_aclk_133 = { 295 .clk = { 296 .name = "aclk_133", 297 .id = -1, 298 }, 299 .sources = &clkset_aclk_133, 300 .reg_src = { .reg = S5P_CLKSRC_TOP0, .shift = 24, .size = 1 }, 301 .reg_div = { .reg = S5P_CLKDIV_TOP, .shift = 12, .size = 3 }, 302}; 303 304static struct clk *clkset_vpllsrc_list[] = { 305 [0] = &clk_fin_vpll, 306 [1] = &clk_sclk_hdmi27m, 307}; 308 309static struct clksrc_sources clkset_vpllsrc = { 310 .sources = clkset_vpllsrc_list, 311 .nr_sources = ARRAY_SIZE(clkset_vpllsrc_list), 312}; 313 314static struct clksrc_clk clk_vpllsrc = { 315 .clk = { 316 .name = "vpll_src", 317 .id = -1, 318 }, 319 .sources = &clkset_vpllsrc, 320 .reg_src = { .reg = S5P_CLKSRC_TOP1, .shift = 0, .size = 1 }, 321}; 322 323static struct clk *clkset_sclk_vpll_list[] = { 324 [0] = &clk_vpllsrc.clk, 325 [1] = &clk_fout_vpll, 326}; 327 328static struct clksrc_sources clkset_sclk_vpll = { 329 .sources = clkset_sclk_vpll_list, 330 .nr_sources = ARRAY_SIZE(clkset_sclk_vpll_list), 331}; 332 333static struct clksrc_clk clk_sclk_vpll = { 334 .clk = { 335 .name = "sclk_vpll", 336 .id = -1, 337 }, 338 .sources = &clkset_sclk_vpll, 339 .reg_src = { .reg = S5P_CLKSRC_TOP0, .shift = 8, .size = 1 }, 340}; 341 342static struct clk init_clocks_disable[] = { 343 { 344 .name = "timers", 345 .id = -1, 346 .parent = &clk_aclk_100.clk, 347 .enable = s5pv310_clk_ip_peril_ctrl, 348 .ctrlbit = (1<<24), 349 } 350}; 351 352static struct clk init_clocks[] = { 353 { 354 .name = "uart", 355 .id = 0, 356 .enable = s5pv310_clk_ip_peril_ctrl, 357 .ctrlbit = (1 << 0), 358 }, { 359 .name = "uart", 360 .id = 1, 361 .enable = s5pv310_clk_ip_peril_ctrl, 362 .ctrlbit = (1 << 1), 363 }, { 364 .name = "uart", 365 .id = 2, 366 .enable = s5pv310_clk_ip_peril_ctrl, 367 .ctrlbit = (1 << 2), 368 }, { 369 .name = "uart", 370 .id = 3, 371 .enable = s5pv310_clk_ip_peril_ctrl, 372 .ctrlbit = (1 << 3), 373 }, { 374 .name = "uart", 375 .id = 4, 376 .enable = s5pv310_clk_ip_peril_ctrl, 377 .ctrlbit = (1 << 4), 378 }, { 379 .name = "uart", 380 .id = 5, 381 .enable = s5pv310_clk_ip_peril_ctrl, 382 .ctrlbit = (1 << 5), 383 } 384}; 385 386static struct clk *clkset_group_list[] = { 387 [0] = &clk_ext_xtal_mux, 388 [1] = &clk_xusbxti, 389 [2] = &clk_sclk_hdmi27m, 390 [6] = &clk_mout_mpll.clk, 391 [7] = &clk_mout_epll.clk, 392 [8] = &clk_sclk_vpll.clk, 393}; 394 395static struct clksrc_sources clkset_group = { 396 .sources = clkset_group_list, 397 .nr_sources = ARRAY_SIZE(clkset_group_list), 398}; 399 400static struct clksrc_clk clksrcs[] = { 401 { 402 .clk = { 403 .name = "uclk1", 404 .id = 0, 405 .enable = s5pv310_clksrc_mask_peril0_ctrl, 406 .ctrlbit = (1 << 0), 407 }, 408 .sources = &clkset_group, 409 .reg_src = { .reg = S5P_CLKSRC_PERIL0, .shift = 0, .size = 4 }, 410 .reg_div = { .reg = S5P_CLKDIV_PERIL0, .shift = 0, .size = 4 }, 411 }, { 412 .clk = { 413 .name = "uclk1", 414 .id = 1, 415 .enable = s5pv310_clksrc_mask_peril0_ctrl, 416 .ctrlbit = (1 << 4), 417 }, 418 .sources = &clkset_group, 419 .reg_src = { .reg = S5P_CLKSRC_PERIL0, .shift = 4, .size = 4 }, 420 .reg_div = { .reg = S5P_CLKDIV_PERIL0, .shift = 4, .size = 4 }, 421 }, { 422 .clk = { 423 .name = "uclk1", 424 .id = 2, 425 .enable = s5pv310_clksrc_mask_peril0_ctrl, 426 .ctrlbit = (1 << 8), 427 }, 428 .sources = &clkset_group, 429 .reg_src = { .reg = S5P_CLKSRC_PERIL0, .shift = 8, .size = 4 }, 430 .reg_div = { .reg = S5P_CLKDIV_PERIL0, .shift = 8, .size = 4 }, 431 }, { 432 .clk = { 433 .name = "uclk1", 434 .id = 3, 435 .enable = s5pv310_clksrc_mask_peril0_ctrl, 436 .ctrlbit = (1 << 12), 437 }, 438 .sources = &clkset_group, 439 .reg_src = { .reg = S5P_CLKSRC_PERIL0, .shift = 12, .size = 4 }, 440 .reg_div = { .reg = S5P_CLKDIV_PERIL0, .shift = 12, .size = 4 }, 441 }, { 442 .clk = { 443 .name = "sclk_pwm", 444 .id = -1, 445 .enable = s5pv310_clksrc_mask_peril0_ctrl, 446 .ctrlbit = (1 << 24), 447 }, 448 .sources = &clkset_group, 449 .reg_src = { .reg = S5P_CLKSRC_PERIL0, .shift = 24, .size = 4 }, 450 .reg_div = { .reg = S5P_CLKDIV_PERIL3, .shift = 0, .size = 4 }, 451 }, 452}; 453 454/* Clock initialization code */ 455static struct clksrc_clk *sysclks[] = { 456 &clk_mout_apll, 457 &clk_sclk_apll, 458 &clk_mout_epll, 459 &clk_mout_mpll, 460 &clk_moutcore, 461 &clk_coreclk, 462 &clk_armclk, 463 &clk_aclk_corem0, 464 &clk_aclk_cores, 465 &clk_aclk_corem1, 466 &clk_periphclk, 467 &clk_atclk, 468 &clk_pclk_dbg, 469 &clk_mout_corebus, 470 &clk_sclk_dmc, 471 &clk_aclk_cored, 472 &clk_aclk_corep, 473 &clk_aclk_acp, 474 &clk_pclk_acp, 475 &clk_vpllsrc, 476 &clk_sclk_vpll, 477 &clk_aclk_200, 478 &clk_aclk_100, 479 &clk_aclk_160, 480 &clk_aclk_133, 481}; 482 483void __init_or_cpufreq s5pv310_setup_clocks(void) 484{ 485 struct clk *xtal_clk; 486 unsigned long apll; 487 unsigned long mpll; 488 unsigned long epll; 489 unsigned long vpll; 490 unsigned long vpllsrc; 491 unsigned long xtal; 492 unsigned long armclk; 493 unsigned long aclk_corem0; 494 unsigned long aclk_cores; 495 unsigned long aclk_corem1; 496 unsigned long periphclk; 497 unsigned long sclk_dmc; 498 unsigned long aclk_cored; 499 unsigned long aclk_corep; 500 unsigned long aclk_acp; 501 unsigned long pclk_acp; 502 unsigned int ptr; 503 504 printk(KERN_DEBUG "%s: registering clocks\n", __func__); 505 506 xtal_clk = clk_get(NULL, "xtal"); 507 BUG_ON(IS_ERR(xtal_clk)); 508 509 xtal = clk_get_rate(xtal_clk); 510 clk_put(xtal_clk); 511 512 printk(KERN_DEBUG "%s: xtal is %ld\n", __func__, xtal); 513 514 apll = s5p_get_pll45xx(xtal, __raw_readl(S5P_APLL_CON0), pll_4508); 515 mpll = s5p_get_pll45xx(xtal, __raw_readl(S5P_MPLL_CON0), pll_4508); 516 epll = s5p_get_pll46xx(xtal, __raw_readl(S5P_EPLL_CON0), 517 __raw_readl(S5P_EPLL_CON1), pll_4600); 518 519 vpllsrc = clk_get_rate(&clk_vpllsrc.clk); 520 vpll = s5p_get_pll46xx(vpllsrc, __raw_readl(S5P_VPLL_CON0), 521 __raw_readl(S5P_VPLL_CON1), pll_4650); 522 523 clk_fout_apll.rate = apll; 524 clk_fout_mpll.rate = mpll; 525 clk_fout_epll.rate = epll; 526 clk_fout_vpll.rate = vpll; 527 528 printk(KERN_INFO "S5PV310: PLL settings, A=%ld, M=%ld, E=%ld V=%ld", 529 apll, mpll, epll, vpll); 530 531 armclk = clk_get_rate(&clk_armclk.clk); 532 aclk_corem0 = clk_get_rate(&clk_aclk_corem0.clk); 533 aclk_cores = clk_get_rate(&clk_aclk_cores.clk); 534 aclk_corem1 = clk_get_rate(&clk_aclk_corem1.clk); 535 periphclk = clk_get_rate(&clk_periphclk.clk); 536 sclk_dmc = clk_get_rate(&clk_sclk_dmc.clk); 537 aclk_cored = clk_get_rate(&clk_aclk_cored.clk); 538 aclk_corep = clk_get_rate(&clk_aclk_corep.clk); 539 aclk_acp = clk_get_rate(&clk_aclk_acp.clk); 540 pclk_acp = clk_get_rate(&clk_pclk_acp.clk); 541 542 printk(KERN_INFO "S5PV310: ARMCLK=%ld, COREM0=%ld, CORES=%ld\n" 543 "COREM1=%ld, PERI=%ld, DMC=%ld, CORED=%ld\n" 544 "COREP=%ld, ACLK_ACP=%ld, PCLK_ACP=%ld", 545 armclk, aclk_corem0, aclk_cores, aclk_corem1, 546 periphclk, sclk_dmc, aclk_cored, aclk_corep, 547 aclk_acp, pclk_acp); 548 549 clk_f.rate = armclk; 550 clk_h.rate = sclk_dmc; 551 clk_p.rate = periphclk; 552 553 for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++) 554 s3c_set_clksrc(&clksrcs[ptr], true); 555} 556 557static struct clk *clks[] __initdata = { 558 /* Nothing here yet */ 559}; 560 561void __init s5pv310_register_clocks(void) 562{ 563 struct clk *clkp; 564 int ret; 565 int ptr; 566 567 ret = s3c24xx_register_clocks(clks, ARRAY_SIZE(clks)); 568 if (ret > 0) 569 printk(KERN_ERR "Failed to register %u clocks\n", ret); 570 571 for (ptr = 0; ptr < ARRAY_SIZE(sysclks); ptr++) 572 s3c_register_clksrc(sysclks[ptr], 1); 573 574 s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs)); 575 s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks)); 576 577 clkp = init_clocks_disable; 578 for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) { 579 ret = s3c24xx_register_clock(clkp); 580 if (ret < 0) { 581 printk(KERN_ERR "Failed to register clock %s (%d)\n", 582 clkp->name, ret); 583 } 584 (clkp->enable)(clkp, 0); 585 } 586 587 s3c_pwmclk_init(); 588} 589