1/* 2 * Common code for SoCs starting with the S3C2443 3 * 4 * Copyright (c) 2007, 2010 Simtec Electronics 5 * Ben Dooks <ben@simtec.co.uk> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 */ 17 18#include <linux/init.h> 19#include <linux/clk.h> 20#include <linux/io.h> 21 22#include <mach/regs-s3c2443-clock.h> 23 24#include <plat/clock.h> 25#include <plat/clock-clksrc.h> 26#include <plat/cpu.h> 27 28#include <plat/cpu-freq.h> 29 30 31static int s3c2443_gate(void __iomem *reg, struct clk *clk, int enable) 32{ 33 u32 ctrlbit = clk->ctrlbit; 34 u32 con = __raw_readl(reg); 35 36 if (enable) 37 con |= ctrlbit; 38 else 39 con &= ~ctrlbit; 40 41 __raw_writel(con, reg); 42 return 0; 43} 44 45int s3c2443_clkcon_enable_h(struct clk *clk, int enable) 46{ 47 return s3c2443_gate(S3C2443_HCLKCON, clk, enable); 48} 49 50int s3c2443_clkcon_enable_p(struct clk *clk, int enable) 51{ 52 return s3c2443_gate(S3C2443_PCLKCON, clk, enable); 53} 54 55int s3c2443_clkcon_enable_s(struct clk *clk, int enable) 56{ 57 return s3c2443_gate(S3C2443_SCLKCON, clk, enable); 58} 59 60/* mpllref is a direct descendant of clk_xtal by default, but it is not 61 * elided as the EPLL can be either sourced by the XTAL or EXTCLK and as 62 * such directly equating the two source clocks is impossible. 63 */ 64static struct clk clk_mpllref = { 65 .name = "mpllref", 66 .parent = &clk_xtal, 67}; 68 69static struct clk *clk_epllref_sources[] = { 70 [0] = &clk_mpllref, 71 [1] = &clk_mpllref, 72 [2] = &clk_xtal, 73 [3] = &clk_ext, 74}; 75 76struct clksrc_clk clk_epllref = { 77 .clk = { 78 .name = "epllref", 79 }, 80 .sources = &(struct clksrc_sources) { 81 .sources = clk_epllref_sources, 82 .nr_sources = ARRAY_SIZE(clk_epllref_sources), 83 }, 84 .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 7 }, 85}; 86 87/* esysclk 88 * 89 * this is sourced from either the EPLL or the EPLLref clock 90*/ 91 92static struct clk *clk_sysclk_sources[] = { 93 [0] = &clk_epllref.clk, 94 [1] = &clk_epll, 95}; 96 97struct clksrc_clk clk_esysclk = { 98 .clk = { 99 .name = "esysclk", 100 .parent = &clk_epll, 101 }, 102 .sources = &(struct clksrc_sources) { 103 .sources = clk_sysclk_sources, 104 .nr_sources = ARRAY_SIZE(clk_sysclk_sources), 105 }, 106 .reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 6 }, 107}; 108 109static unsigned long s3c2443_getrate_mdivclk(struct clk *clk) 110{ 111 unsigned long parent_rate = clk_get_rate(clk->parent); 112 unsigned long div = __raw_readl(S3C2443_CLKDIV0); 113 114 div &= S3C2443_CLKDIV0_EXTDIV_MASK; 115 div >>= (S3C2443_CLKDIV0_EXTDIV_SHIFT-1); /* x2 */ 116 117 return parent_rate / (div + 1); 118} 119 120static struct clk clk_mdivclk = { 121 .name = "mdivclk", 122 .parent = &clk_mpllref, 123 .ops = &(struct clk_ops) { 124 .get_rate = s3c2443_getrate_mdivclk, 125 }, 126}; 127 128static struct clk *clk_msysclk_sources[] = { 129 [0] = &clk_mpllref, 130 [1] = &clk_mpll, 131 [2] = &clk_mdivclk, 132 [3] = &clk_mpllref, 133}; 134 135struct clksrc_clk clk_msysclk = { 136 .clk = { 137 .name = "msysclk", 138 .parent = &clk_xtal, 139 }, 140 .sources = &(struct clksrc_sources) { 141 .sources = clk_msysclk_sources, 142 .nr_sources = ARRAY_SIZE(clk_msysclk_sources), 143 }, 144 .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 3 }, 145}; 146 147/* prediv 148 * 149 * this divides the msysclk down to pass to h/p/etc. 150 */ 151 152static unsigned long s3c2443_prediv_getrate(struct clk *clk) 153{ 154 unsigned long rate = clk_get_rate(clk->parent); 155 unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0); 156 157 clkdiv0 &= S3C2443_CLKDIV0_PREDIV_MASK; 158 clkdiv0 >>= S3C2443_CLKDIV0_PREDIV_SHIFT; 159 160 return rate / (clkdiv0 + 1); 161} 162 163static struct clk clk_prediv = { 164 .name = "prediv", 165 .parent = &clk_msysclk.clk, 166 .ops = &(struct clk_ops) { 167 .get_rate = s3c2443_prediv_getrate, 168 }, 169}; 170 171/* hclk divider 172 * 173 * divides the prediv and provides the hclk. 174 */ 175 176static unsigned long s3c2443_hclkdiv_getrate(struct clk *clk) 177{ 178 unsigned long rate = clk_get_rate(clk->parent); 179 unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0); 180 181 clkdiv0 &= S3C2443_CLKDIV0_HCLKDIV_MASK; 182 183 return rate / (clkdiv0 + 1); 184} 185 186static struct clk_ops clk_h_ops = { 187 .get_rate = s3c2443_hclkdiv_getrate, 188}; 189 190/* pclk divider 191 * 192 * divides the hclk and provides the pclk. 193 */ 194 195static unsigned long s3c2443_pclkdiv_getrate(struct clk *clk) 196{ 197 unsigned long rate = clk_get_rate(clk->parent); 198 unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0); 199 200 clkdiv0 = ((clkdiv0 & S3C2443_CLKDIV0_HALF_PCLK) ? 1 : 0); 201 202 return rate / (clkdiv0 + 1); 203} 204 205static struct clk_ops clk_p_ops = { 206 .get_rate = s3c2443_pclkdiv_getrate, 207}; 208 209/* armdiv 210 * 211 * this clock is sourced from msysclk and can have a number of 212 * divider values applied to it to then be fed into armclk. 213*/ 214 215static unsigned int *armdiv; 216static int nr_armdiv; 217static int armdivmask; 218 219static unsigned long s3c2443_armclk_roundrate(struct clk *clk, 220 unsigned long rate) 221{ 222 unsigned long parent = clk_get_rate(clk->parent); 223 unsigned long calc; 224 unsigned best = 256; /* bigger than any value */ 225 unsigned div; 226 int ptr; 227 228 if (!nr_armdiv) 229 return -EINVAL; 230 231 for (ptr = 0; ptr < nr_armdiv; ptr++) { 232 div = armdiv[ptr]; 233 if (div) { 234 /* cpufreq provides 266mhz as 266666000 not 266666666 */ 235 calc = (parent / div / 1000) * 1000; 236 if (calc <= rate && div < best) 237 best = div; 238 } 239 } 240 241 return parent / best; 242} 243 244static unsigned long s3c2443_armclk_getrate(struct clk *clk) 245{ 246 unsigned long rate = clk_get_rate(clk->parent); 247 unsigned long clkcon0; 248 int val; 249 250 if (!nr_armdiv || !armdivmask) 251 return -EINVAL; 252 253 clkcon0 = __raw_readl(S3C2443_CLKDIV0); 254 clkcon0 &= armdivmask; 255 val = clkcon0 >> S3C2443_CLKDIV0_ARMDIV_SHIFT; 256 257 return rate / armdiv[val]; 258} 259 260static int s3c2443_armclk_setrate(struct clk *clk, unsigned long rate) 261{ 262 unsigned long parent = clk_get_rate(clk->parent); 263 unsigned long calc; 264 unsigned div; 265 unsigned best = 256; /* bigger than any value */ 266 int ptr; 267 int val = -1; 268 269 if (!nr_armdiv || !armdivmask) 270 return -EINVAL; 271 272 for (ptr = 0; ptr < nr_armdiv; ptr++) { 273 div = armdiv[ptr]; 274 if (div) { 275 /* cpufreq provides 266mhz as 266666000 not 266666666 */ 276 calc = (parent / div / 1000) * 1000; 277 if (calc <= rate && div < best) { 278 best = div; 279 val = ptr; 280 } 281 } 282 } 283 284 if (val >= 0) { 285 unsigned long clkcon0; 286 287 clkcon0 = __raw_readl(S3C2443_CLKDIV0); 288 clkcon0 &= ~armdivmask; 289 clkcon0 |= val << S3C2443_CLKDIV0_ARMDIV_SHIFT; 290 __raw_writel(clkcon0, S3C2443_CLKDIV0); 291 } 292 293 return (val == -1) ? -EINVAL : 0; 294} 295 296static struct clk clk_armdiv = { 297 .name = "armdiv", 298 .parent = &clk_msysclk.clk, 299 .ops = &(struct clk_ops) { 300 .round_rate = s3c2443_armclk_roundrate, 301 .get_rate = s3c2443_armclk_getrate, 302 .set_rate = s3c2443_armclk_setrate, 303 }, 304}; 305 306/* armclk 307 * 308 * this is the clock fed into the ARM core itself, from armdiv or from hclk. 309 */ 310 311static struct clk *clk_arm_sources[] = { 312 [0] = &clk_armdiv, 313 [1] = &clk_h, 314}; 315 316static struct clksrc_clk clk_arm = { 317 .clk = { 318 .name = "armclk", 319 }, 320 .sources = &(struct clksrc_sources) { 321 .sources = clk_arm_sources, 322 .nr_sources = ARRAY_SIZE(clk_arm_sources), 323 }, 324 .reg_src = { .reg = S3C2443_CLKDIV0, .size = 1, .shift = 13 }, 325}; 326 327/* usbhost 328 * 329 * usb host bus-clock, usually 48MHz to provide USB bus clock timing 330*/ 331 332static struct clksrc_clk clk_usb_bus_host = { 333 .clk = { 334 .name = "usb-bus-host-parent", 335 .parent = &clk_esysclk.clk, 336 .ctrlbit = S3C2443_SCLKCON_USBHOST, 337 .enable = s3c2443_clkcon_enable_s, 338 }, 339 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 }, 340}; 341 342/* common clksrc clocks */ 343 344static struct clksrc_clk clksrc_clks[] = { 345 { 346 /* camera interface bus-clock, divided down from esysclk */ 347 .clk = { 348 .name = "camif-upll", /* same as 2440 name */ 349 .parent = &clk_esysclk.clk, 350 .ctrlbit = S3C2443_SCLKCON_CAMCLK, 351 .enable = s3c2443_clkcon_enable_s, 352 }, 353 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 26 }, 354 }, { 355 .clk = { 356 .name = "display-if", 357 .parent = &clk_esysclk.clk, 358 .ctrlbit = S3C2443_SCLKCON_DISPCLK, 359 .enable = s3c2443_clkcon_enable_s, 360 }, 361 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 8, .shift = 16 }, 362 }, 363}; 364 365static struct clksrc_clk clk_esys_uart = { 366 /* ART baud-rate clock sourced from esysclk via a divisor */ 367 .clk = { 368 .name = "uartclk", 369 .parent = &clk_esysclk.clk, 370 }, 371 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 8 }, 372}; 373 374static struct clk clk_i2s_ext = { 375 .name = "i2s-ext", 376}; 377 378/* i2s_eplldiv 379 * 380 * This clock is the output from the I2S divisor of ESYSCLK, and is separate 381 * from the mux that comes after it (cannot merge into one single clock) 382*/ 383 384static struct clksrc_clk clk_i2s_eplldiv = { 385 .clk = { 386 .name = "i2s-eplldiv", 387 .parent = &clk_esysclk.clk, 388 }, 389 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 12, }, 390}; 391 392/* i2s-ref 393 * 394 * i2s bus reference clock, selectable from external, esysclk or epllref 395 * 396 * Note, this used to be two clocks, but was compressed into one. 397*/ 398 399static struct clk *clk_i2s_srclist[] = { 400 [0] = &clk_i2s_eplldiv.clk, 401 [1] = &clk_i2s_ext, 402 [2] = &clk_epllref.clk, 403 [3] = &clk_epllref.clk, 404}; 405 406static struct clksrc_clk clk_i2s = { 407 .clk = { 408 .name = "i2s-if", 409 .ctrlbit = S3C2443_SCLKCON_I2SCLK, 410 .enable = s3c2443_clkcon_enable_s, 411 412 }, 413 .sources = &(struct clksrc_sources) { 414 .sources = clk_i2s_srclist, 415 .nr_sources = ARRAY_SIZE(clk_i2s_srclist), 416 }, 417 .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 14 }, 418}; 419 420static struct clk init_clocks_off[] = { 421 { 422 .name = "iis", 423 .parent = &clk_p, 424 .enable = s3c2443_clkcon_enable_p, 425 .ctrlbit = S3C2443_PCLKCON_IIS, 426 }, { 427 .name = "hsspi", 428 .parent = &clk_p, 429 .enable = s3c2443_clkcon_enable_p, 430 .ctrlbit = S3C2443_PCLKCON_HSSPI, 431 }, { 432 .name = "adc", 433 .parent = &clk_p, 434 .enable = s3c2443_clkcon_enable_p, 435 .ctrlbit = S3C2443_PCLKCON_ADC, 436 }, { 437 .name = "i2c", 438 .parent = &clk_p, 439 .enable = s3c2443_clkcon_enable_p, 440 .ctrlbit = S3C2443_PCLKCON_IIC, 441 } 442}; 443 444static struct clk init_clocks[] = { 445 { 446 .name = "dma", 447 .parent = &clk_h, 448 .enable = s3c2443_clkcon_enable_h, 449 .ctrlbit = S3C2443_HCLKCON_DMA0, 450 }, { 451 .name = "dma", 452 .parent = &clk_h, 453 .enable = s3c2443_clkcon_enable_h, 454 .ctrlbit = S3C2443_HCLKCON_DMA1, 455 }, { 456 .name = "dma", 457 .parent = &clk_h, 458 .enable = s3c2443_clkcon_enable_h, 459 .ctrlbit = S3C2443_HCLKCON_DMA2, 460 }, { 461 .name = "dma", 462 .parent = &clk_h, 463 .enable = s3c2443_clkcon_enable_h, 464 .ctrlbit = S3C2443_HCLKCON_DMA3, 465 }, { 466 .name = "dma", 467 .parent = &clk_h, 468 .enable = s3c2443_clkcon_enable_h, 469 .ctrlbit = S3C2443_HCLKCON_DMA4, 470 }, { 471 .name = "dma", 472 .parent = &clk_h, 473 .enable = s3c2443_clkcon_enable_h, 474 .ctrlbit = S3C2443_HCLKCON_DMA5, 475 }, { 476 .name = "gpio", 477 .parent = &clk_p, 478 .enable = s3c2443_clkcon_enable_p, 479 .ctrlbit = S3C2443_PCLKCON_GPIO, 480 }, { 481 .name = "usb-host", 482 .parent = &clk_h, 483 .enable = s3c2443_clkcon_enable_h, 484 .ctrlbit = S3C2443_HCLKCON_USBH, 485 }, { 486 .name = "usb-device", 487 .parent = &clk_h, 488 .enable = s3c2443_clkcon_enable_h, 489 .ctrlbit = S3C2443_HCLKCON_USBD, 490 }, { 491 .name = "lcd", 492 .parent = &clk_h, 493 .enable = s3c2443_clkcon_enable_h, 494 .ctrlbit = S3C2443_HCLKCON_LCDC, 495 496 }, { 497 .name = "timers", 498 .parent = &clk_p, 499 .enable = s3c2443_clkcon_enable_p, 500 .ctrlbit = S3C2443_PCLKCON_PWMT, 501 }, { 502 .name = "cfc", 503 .parent = &clk_h, 504 .enable = s3c2443_clkcon_enable_h, 505 .ctrlbit = S3C2443_HCLKCON_CFC, 506 }, { 507 .name = "ssmc", 508 .parent = &clk_h, 509 .enable = s3c2443_clkcon_enable_h, 510 .ctrlbit = S3C2443_HCLKCON_SSMC, 511 }, { 512 .name = "uart", 513 .devname = "s3c2440-uart.0", 514 .parent = &clk_p, 515 .enable = s3c2443_clkcon_enable_p, 516 .ctrlbit = S3C2443_PCLKCON_UART0, 517 }, { 518 .name = "uart", 519 .devname = "s3c2440-uart.1", 520 .parent = &clk_p, 521 .enable = s3c2443_clkcon_enable_p, 522 .ctrlbit = S3C2443_PCLKCON_UART1, 523 }, { 524 .name = "uart", 525 .devname = "s3c2440-uart.2", 526 .parent = &clk_p, 527 .enable = s3c2443_clkcon_enable_p, 528 .ctrlbit = S3C2443_PCLKCON_UART2, 529 }, { 530 .name = "uart", 531 .devname = "s3c2440-uart.3", 532 .parent = &clk_p, 533 .enable = s3c2443_clkcon_enable_p, 534 .ctrlbit = S3C2443_PCLKCON_UART3, 535 }, { 536 .name = "rtc", 537 .parent = &clk_p, 538 .enable = s3c2443_clkcon_enable_p, 539 .ctrlbit = S3C2443_PCLKCON_RTC, 540 }, { 541 .name = "watchdog", 542 .parent = &clk_p, 543 .ctrlbit = S3C2443_PCLKCON_WDT, 544 }, { 545 .name = "ac97", 546 .parent = &clk_p, 547 .ctrlbit = S3C2443_PCLKCON_AC97, 548 }, { 549 .name = "nand", 550 .parent = &clk_h, 551 }, { 552 .name = "usb-bus-host", 553 .parent = &clk_usb_bus_host.clk, 554 } 555}; 556 557static struct clk hsmmc1_clk = { 558 .name = "hsmmc", 559 .devname = "s3c-sdhci.1", 560 .parent = &clk_h, 561 .enable = s3c2443_clkcon_enable_h, 562 .ctrlbit = S3C2443_HCLKCON_HSMMC, 563}; 564 565/* EPLLCON compatible enough to get on/off information */ 566 567void __init_or_cpufreq s3c2443_common_setup_clocks(pll_fn get_mpll) 568{ 569 unsigned long epllcon = __raw_readl(S3C2443_EPLLCON); 570 unsigned long mpllcon = __raw_readl(S3C2443_MPLLCON); 571 struct clk *xtal_clk; 572 unsigned long xtal; 573 unsigned long pll; 574 int ptr; 575 576 xtal_clk = clk_get(NULL, "xtal"); 577 xtal = clk_get_rate(xtal_clk); 578 clk_put(xtal_clk); 579 580 pll = get_mpll(mpllcon, xtal); 581 clk_msysclk.clk.rate = pll; 582 clk_mpll.rate = pll; 583 584 printk("CPU: MPLL %s %ld.%03ld MHz, cpu %ld.%03ld MHz, mem %ld.%03ld MHz, pclk %ld.%03ld MHz\n", 585 (mpllcon & S3C2443_PLLCON_OFF) ? "off" : "on", 586 print_mhz(pll), print_mhz(clk_get_rate(&clk_armdiv)), 587 print_mhz(clk_get_rate(&clk_h)), 588 print_mhz(clk_get_rate(&clk_p))); 589 590 for (ptr = 0; ptr < ARRAY_SIZE(clksrc_clks); ptr++) 591 s3c_set_clksrc(&clksrc_clks[ptr], true); 592 593 /* ensure usb bus clock is within correct rate of 48MHz */ 594 595 if (clk_get_rate(&clk_usb_bus_host.clk) != (48 * 1000 * 1000)) { 596 printk(KERN_INFO "Warning: USB host bus not at 48MHz\n"); 597 clk_set_rate(&clk_usb_bus_host.clk, 48*1000*1000); 598 } 599 600 printk("CPU: EPLL %s %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n", 601 (epllcon & S3C2443_PLLCON_OFF) ? "off" : "on", 602 print_mhz(clk_get_rate(&clk_epll)), 603 print_mhz(clk_get_rate(&clk_usb_bus))); 604} 605 606static struct clk *clks[] __initdata = { 607 &clk_prediv, 608 &clk_mpllref, 609 &clk_mdivclk, 610 &clk_ext, 611 &clk_epll, 612 &clk_usb_bus, 613 &clk_armdiv, 614 &hsmmc1_clk, 615}; 616 617static struct clksrc_clk *clksrcs[] __initdata = { 618 &clk_i2s_eplldiv, 619 &clk_i2s, 620 &clk_usb_bus_host, 621 &clk_epllref, 622 &clk_esysclk, 623 &clk_msysclk, 624 &clk_arm, 625}; 626 627static struct clk_lookup s3c2443_clk_lookup[] = { 628 CLKDEV_INIT(NULL, "clk_uart_baud1", &s3c24xx_uclk), 629 CLKDEV_INIT(NULL, "clk_uart_baud2", &clk_p), 630 CLKDEV_INIT(NULL, "clk_uart_baud3", &clk_esys_uart.clk), 631 CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.0", &hsmmc1_clk), 632}; 633 634void __init s3c2443_common_init_clocks(int xtal, pll_fn get_mpll, 635 unsigned int *divs, int nr_divs, 636 int divmask) 637{ 638 int ptr; 639 640 armdiv = divs; 641 nr_armdiv = nr_divs; 642 armdivmask = divmask; 643 644 /* s3c2443 parents h clock from prediv */ 645 clk_h.parent = &clk_prediv; 646 clk_h.ops = &clk_h_ops; 647 648 /* and p clock from h clock */ 649 clk_p.parent = &clk_h; 650 clk_p.ops = &clk_p_ops; 651 652 clk_usb_bus.parent = &clk_usb_bus_host.clk; 653 clk_epll.parent = &clk_epllref.clk; 654 655 s3c24xx_register_baseclocks(xtal); 656 s3c24xx_register_clocks(clks, ARRAY_SIZE(clks)); 657 658 for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++) 659 s3c_register_clksrc(clksrcs[ptr], 1); 660 661 s3c_register_clksrc(clksrc_clks, ARRAY_SIZE(clksrc_clks)); 662 s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks)); 663 664 /* See s3c2443/etc notes on disabling clocks at init time */ 665 s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); 666 s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); 667 clkdev_add_table(s3c2443_clk_lookup, ARRAY_SIZE(s3c2443_clk_lookup)); 668 669 s3c2443_common_setup_clocks(get_mpll); 670} 671