uboot/arch/arm/cpu/armv7/exynos/clock.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2010 Samsung Electronics
   3 * Minkyu Kang <mk7.kang@samsung.com>
   4 *
   5 * See file CREDITS for list of people who contributed to this
   6 * project.
   7 *
   8 * This program is free software; you can redistribute it and/or
   9 * modify it under the terms of the GNU General Public License as
  10 * published by the Free Software Foundation; either version 2 of
  11 * the License, or (at your option) any later version.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 *
  18 * You should have received a copy of the GNU General Public License
  19 * along with this program; if not, write to the Free Software
  20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  21 * MA 02111-1307 USA
  22 */
  23
  24#include <common.h>
  25#include <asm/io.h>
  26#include <asm/arch/clock.h>
  27#include <asm/arch/clk.h>
  28
  29/* exynos4: return pll clock frequency */
  30static unsigned long exynos4_get_pll_clk(int pllreg)
  31{
  32        struct exynos4_clock *clk =
  33                (struct exynos4_clock *)samsung_get_base_clock();
  34        unsigned long r, m, p, s, k = 0, mask, fout;
  35        unsigned int freq;
  36
  37        switch (pllreg) {
  38        case APLL:
  39                r = readl(&clk->apll_con0);
  40                break;
  41        case MPLL:
  42                r = readl(&clk->mpll_con0);
  43                break;
  44        case EPLL:
  45                r = readl(&clk->epll_con0);
  46                k = readl(&clk->epll_con1);
  47                break;
  48        case VPLL:
  49                r = readl(&clk->vpll_con0);
  50                k = readl(&clk->vpll_con1);
  51                break;
  52        default:
  53                printf("Unsupported PLL (%d)\n", pllreg);
  54                return 0;
  55        }
  56
  57        /*
  58         * APLL_CON: MIDV [25:16]
  59         * MPLL_CON: MIDV [25:16]
  60         * EPLL_CON: MIDV [24:16]
  61         * VPLL_CON: MIDV [24:16]
  62         */
  63        if (pllreg == APLL || pllreg == MPLL)
  64                mask = 0x3ff;
  65        else
  66                mask = 0x1ff;
  67
  68        m = (r >> 16) & mask;
  69
  70        /* PDIV [13:8] */
  71        p = (r >> 8) & 0x3f;
  72        /* SDIV [2:0] */
  73        s = r & 0x7;
  74
  75        freq = CONFIG_SYS_CLK_FREQ;
  76
  77        if (pllreg == EPLL) {
  78                k = k & 0xffff;
  79                /* FOUT = (MDIV + K / 65536) * FIN / (PDIV * 2^SDIV) */
  80                fout = (m + k / 65536) * (freq / (p * (1 << s)));
  81        } else if (pllreg == VPLL) {
  82                k = k & 0xfff;
  83                /* FOUT = (MDIV + K / 1024) * FIN / (PDIV * 2^SDIV) */
  84                fout = (m + k / 1024) * (freq / (p * (1 << s)));
  85        } else {
  86                if (s < 1)
  87                        s = 1;
  88                /* FOUT = MDIV * FIN / (PDIV * 2^(SDIV - 1)) */
  89                fout = m * (freq / (p * (1 << (s - 1))));
  90        }
  91
  92        return fout;
  93}
  94
  95/* exynos5: return pll clock frequency */
  96static unsigned long exynos5_get_pll_clk(int pllreg)
  97{
  98        struct exynos5_clock *clk =
  99                (struct exynos5_clock *)samsung_get_base_clock();
 100        unsigned long r, m, p, s, k = 0, mask, fout;
 101        unsigned int freq;
 102
 103        switch (pllreg) {
 104        case APLL:
 105                r = readl(&clk->apll_con0);
 106                break;
 107        case MPLL:
 108                r = readl(&clk->mpll_con0);
 109                break;
 110        case EPLL:
 111                r = readl(&clk->epll_con0);
 112                k = readl(&clk->epll_con1);
 113                break;
 114        case VPLL:
 115                r = readl(&clk->vpll_con0);
 116                k = readl(&clk->vpll_con1);
 117                break;
 118        default:
 119                printf("Unsupported PLL (%d)\n", pllreg);
 120                return 0;
 121        }
 122
 123        /*
 124         * APLL_CON: MIDV [25:16]
 125         * MPLL_CON: MIDV [25:16]
 126         * EPLL_CON: MIDV [24:16]
 127         * VPLL_CON: MIDV [24:16]
 128         */
 129        if (pllreg == APLL || pllreg == MPLL)
 130                mask = 0x3ff;
 131        else
 132                mask = 0x1ff;
 133
 134        m = (r >> 16) & mask;
 135
 136        /* PDIV [13:8] */
 137        p = (r >> 8) & 0x3f;
 138        /* SDIV [2:0] */
 139        s = r & 0x7;
 140
 141        freq = CONFIG_SYS_CLK_FREQ;
 142
 143        if (pllreg == EPLL) {
 144                k = k & 0xffff;
 145                /* FOUT = (MDIV + K / 65536) * FIN / (PDIV * 2^SDIV) */
 146                fout = (m + k / 65536) * (freq / (p * (1 << s)));
 147        } else if (pllreg == VPLL) {
 148                k = k & 0xfff;
 149                /* FOUT = (MDIV + K / 1024) * FIN / (PDIV * 2^SDIV) */
 150                fout = (m + k / 1024) * (freq / (p * (1 << s)));
 151        } else {
 152                if (s < 1)
 153                        s = 1;
 154                /* FOUT = MDIV * FIN / (PDIV * 2^(SDIV - 1)) */
 155                fout = m * (freq / (p * (1 << (s - 1))));
 156        }
 157
 158        return fout;
 159}
 160
 161/* exynos4: return ARM clock frequency */
 162static unsigned long exynos4_get_arm_clk(void)
 163{
 164        struct exynos4_clock *clk =
 165                (struct exynos4_clock *)samsung_get_base_clock();
 166        unsigned long div;
 167        unsigned long armclk;
 168        unsigned int core_ratio;
 169        unsigned int core2_ratio;
 170
 171        div = readl(&clk->div_cpu0);
 172
 173        /* CORE_RATIO: [2:0], CORE2_RATIO: [30:28] */
 174        core_ratio = (div >> 0) & 0x7;
 175        core2_ratio = (div >> 28) & 0x7;
 176
 177        armclk = get_pll_clk(APLL) / (core_ratio + 1);
 178        armclk /= (core2_ratio + 1);
 179
 180        return armclk;
 181}
 182
 183/* exynos5: return ARM clock frequency */
 184static unsigned long exynos5_get_arm_clk(void)
 185{
 186        struct exynos5_clock *clk =
 187                (struct exynos5_clock *)samsung_get_base_clock();
 188        unsigned long div;
 189        unsigned long armclk;
 190        unsigned int arm_ratio;
 191        unsigned int arm2_ratio;
 192
 193        div = readl(&clk->div_cpu0);
 194
 195        /* ARM_RATIO: [2:0], ARM2_RATIO: [30:28] */
 196        arm_ratio = (div >> 0) & 0x7;
 197        arm2_ratio = (div >> 28) & 0x7;
 198
 199        armclk = get_pll_clk(APLL) / (arm_ratio + 1);
 200        armclk /= (arm2_ratio + 1);
 201
 202        return armclk;
 203}
 204
 205/* exynos4: return pwm clock frequency */
 206static unsigned long exynos4_get_pwm_clk(void)
 207{
 208        struct exynos4_clock *clk =
 209                (struct exynos4_clock *)samsung_get_base_clock();
 210        unsigned long pclk, sclk;
 211        unsigned int sel;
 212        unsigned int ratio;
 213
 214        if (s5p_get_cpu_rev() == 0) {
 215                /*
 216                 * CLK_SRC_PERIL0
 217                 * PWM_SEL [27:24]
 218                 */
 219                sel = readl(&clk->src_peril0);
 220                sel = (sel >> 24) & 0xf;
 221
 222                if (sel == 0x6)
 223                        sclk = get_pll_clk(MPLL);
 224                else if (sel == 0x7)
 225                        sclk = get_pll_clk(EPLL);
 226                else if (sel == 0x8)
 227                        sclk = get_pll_clk(VPLL);
 228                else
 229                        return 0;
 230
 231                /*
 232                 * CLK_DIV_PERIL3
 233                 * PWM_RATIO [3:0]
 234                 */
 235                ratio = readl(&clk->div_peril3);
 236                ratio = ratio & 0xf;
 237        } else if (s5p_get_cpu_rev() == 1) {
 238                sclk = get_pll_clk(MPLL);
 239                ratio = 8;
 240        } else
 241                return 0;
 242
 243        pclk = sclk / (ratio + 1);
 244
 245        return pclk;
 246}
 247
 248/* exynos5: return pwm clock frequency */
 249static unsigned long exynos5_get_pwm_clk(void)
 250{
 251        struct exynos5_clock *clk =
 252                (struct exynos5_clock *)samsung_get_base_clock();
 253        unsigned long pclk, sclk;
 254        unsigned int ratio;
 255
 256        /*
 257         * CLK_DIV_PERIC3
 258         * PWM_RATIO [3:0]
 259         */
 260        ratio = readl(&clk->div_peric3);
 261        ratio = ratio & 0xf;
 262        sclk = get_pll_clk(MPLL);
 263
 264        pclk = sclk / (ratio + 1);
 265
 266        return pclk;
 267}
 268
 269/* exynos4: return uart clock frequency */
 270static unsigned long exynos4_get_uart_clk(int dev_index)
 271{
 272        struct exynos4_clock *clk =
 273                (struct exynos4_clock *)samsung_get_base_clock();
 274        unsigned long uclk, sclk;
 275        unsigned int sel;
 276        unsigned int ratio;
 277
 278        /*
 279         * CLK_SRC_PERIL0
 280         * UART0_SEL [3:0]
 281         * UART1_SEL [7:4]
 282         * UART2_SEL [8:11]
 283         * UART3_SEL [12:15]
 284         * UART4_SEL [16:19]
 285         * UART5_SEL [23:20]
 286         */
 287        sel = readl(&clk->src_peril0);
 288        sel = (sel >> (dev_index << 2)) & 0xf;
 289
 290        if (sel == 0x6)
 291                sclk = get_pll_clk(MPLL);
 292        else if (sel == 0x7)
 293                sclk = get_pll_clk(EPLL);
 294        else if (sel == 0x8)
 295                sclk = get_pll_clk(VPLL);
 296        else
 297                return 0;
 298
 299        /*
 300         * CLK_DIV_PERIL0
 301         * UART0_RATIO [3:0]
 302         * UART1_RATIO [7:4]
 303         * UART2_RATIO [8:11]
 304         * UART3_RATIO [12:15]
 305         * UART4_RATIO [16:19]
 306         * UART5_RATIO [23:20]
 307         */
 308        ratio = readl(&clk->div_peril0);
 309        ratio = (ratio >> (dev_index << 2)) & 0xf;
 310
 311        uclk = sclk / (ratio + 1);
 312
 313        return uclk;
 314}
 315
 316/* exynos5: return uart clock frequency */
 317static unsigned long exynos5_get_uart_clk(int dev_index)
 318{
 319        struct exynos5_clock *clk =
 320                (struct exynos5_clock *)samsung_get_base_clock();
 321        unsigned long uclk, sclk;
 322        unsigned int sel;
 323        unsigned int ratio;
 324
 325        /*
 326         * CLK_SRC_PERIC0
 327         * UART0_SEL [3:0]
 328         * UART1_SEL [7:4]
 329         * UART2_SEL [8:11]
 330         * UART3_SEL [12:15]
 331         * UART4_SEL [16:19]
 332         * UART5_SEL [23:20]
 333         */
 334        sel = readl(&clk->src_peric0);
 335        sel = (sel >> (dev_index << 2)) & 0xf;
 336
 337        if (sel == 0x6)
 338                sclk = get_pll_clk(MPLL);
 339        else if (sel == 0x7)
 340                sclk = get_pll_clk(EPLL);
 341        else if (sel == 0x8)
 342                sclk = get_pll_clk(VPLL);
 343        else
 344                return 0;
 345
 346        /*
 347         * CLK_DIV_PERIC0
 348         * UART0_RATIO [3:0]
 349         * UART1_RATIO [7:4]
 350         * UART2_RATIO [8:11]
 351         * UART3_RATIO [12:15]
 352         * UART4_RATIO [16:19]
 353         * UART5_RATIO [23:20]
 354         */
 355        ratio = readl(&clk->div_peric0);
 356        ratio = (ratio >> (dev_index << 2)) & 0xf;
 357
 358        uclk = sclk / (ratio + 1);
 359
 360        return uclk;
 361}
 362
 363/* exynos4: set the mmc clock */
 364static void exynos4_set_mmc_clk(int dev_index, unsigned int div)
 365{
 366        struct exynos4_clock *clk =
 367                (struct exynos4_clock *)samsung_get_base_clock();
 368        unsigned int addr;
 369        unsigned int val;
 370
 371        /*
 372         * CLK_DIV_FSYS1
 373         * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24]
 374         * CLK_DIV_FSYS2
 375         * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24]
 376         */
 377        if (dev_index < 2) {
 378                addr = (unsigned int)&clk->div_fsys1;
 379        } else {
 380                addr = (unsigned int)&clk->div_fsys2;
 381                dev_index -= 2;
 382        }
 383
 384        val = readl(addr);
 385        val &= ~(0xff << ((dev_index << 4) + 8));
 386        val |= (div & 0xff) << ((dev_index << 4) + 8);
 387        writel(val, addr);
 388}
 389
 390/* exynos5: set the mmc clock */
 391static void exynos5_set_mmc_clk(int dev_index, unsigned int div)
 392{
 393        struct exynos5_clock *clk =
 394                (struct exynos5_clock *)samsung_get_base_clock();
 395        unsigned int addr;
 396        unsigned int val;
 397
 398        /*
 399         * CLK_DIV_FSYS1
 400         * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24]
 401         * CLK_DIV_FSYS2
 402         * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24]
 403         */
 404        if (dev_index < 2) {
 405                addr = (unsigned int)&clk->div_fsys1;
 406        } else {
 407                addr = (unsigned int)&clk->div_fsys2;
 408                dev_index -= 2;
 409        }
 410
 411        val = readl(addr);
 412        val &= ~(0xff << ((dev_index << 4) + 8));
 413        val |= (div & 0xff) << ((dev_index << 4) + 8);
 414        writel(val, addr);
 415}
 416
 417/* get_lcd_clk: return lcd clock frequency */
 418static unsigned long exynos4_get_lcd_clk(void)
 419{
 420        struct exynos4_clock *clk =
 421                (struct exynos4_clock *)samsung_get_base_clock();
 422        unsigned long pclk, sclk;
 423        unsigned int sel;
 424        unsigned int ratio;
 425
 426        /*
 427         * CLK_SRC_LCD0
 428         * FIMD0_SEL [3:0]
 429         */
 430        sel = readl(&clk->src_lcd0);
 431        sel = sel & 0xf;
 432
 433        /*
 434         * 0x6: SCLK_MPLL
 435         * 0x7: SCLK_EPLL
 436         * 0x8: SCLK_VPLL
 437         */
 438        if (sel == 0x6)
 439                sclk = get_pll_clk(MPLL);
 440        else if (sel == 0x7)
 441                sclk = get_pll_clk(EPLL);
 442        else if (sel == 0x8)
 443                sclk = get_pll_clk(VPLL);
 444        else
 445                return 0;
 446
 447        /*
 448         * CLK_DIV_LCD0
 449         * FIMD0_RATIO [3:0]
 450         */
 451        ratio = readl(&clk->div_lcd0);
 452        ratio = ratio & 0xf;
 453
 454        pclk = sclk / (ratio + 1);
 455
 456        return pclk;
 457}
 458
 459void exynos4_set_lcd_clk(void)
 460{
 461        struct exynos4_clock *clk =
 462            (struct exynos4_clock *)samsung_get_base_clock();
 463        unsigned int cfg = 0;
 464
 465        /*
 466         * CLK_GATE_BLOCK
 467         * CLK_CAM      [0]
 468         * CLK_TV       [1]
 469         * CLK_MFC      [2]
 470         * CLK_G3D      [3]
 471         * CLK_LCD0     [4]
 472         * CLK_LCD1     [5]
 473         * CLK_GPS      [7]
 474         */
 475        cfg = readl(&clk->gate_block);
 476        cfg |= 1 << 4;
 477        writel(cfg, &clk->gate_block);
 478
 479        /*
 480         * CLK_SRC_LCD0
 481         * FIMD0_SEL            [3:0]
 482         * MDNIE0_SEL           [7:4]
 483         * MDNIE_PWM0_SEL       [8:11]
 484         * MIPI0_SEL            [12:15]
 485         * set lcd0 src clock 0x6: SCLK_MPLL
 486         */
 487        cfg = readl(&clk->src_lcd0);
 488        cfg &= ~(0xf);
 489        cfg |= 0x6;
 490        writel(cfg, &clk->src_lcd0);
 491
 492        /*
 493         * CLK_GATE_IP_LCD0
 494         * CLK_FIMD0            [0]
 495         * CLK_MIE0             [1]
 496         * CLK_MDNIE0           [2]
 497         * CLK_DSIM0            [3]
 498         * CLK_SMMUFIMD0        [4]
 499         * CLK_PPMULCD0         [5]
 500         * Gating all clocks for FIMD0
 501         */
 502        cfg = readl(&clk->gate_ip_lcd0);
 503        cfg |= 1 << 0;
 504        writel(cfg, &clk->gate_ip_lcd0);
 505
 506        /*
 507         * CLK_DIV_LCD0
 508         * FIMD0_RATIO          [3:0]
 509         * MDNIE0_RATIO         [7:4]
 510         * MDNIE_PWM0_RATIO     [11:8]
 511         * MDNIE_PWM_PRE_RATIO  [15:12]
 512         * MIPI0_RATIO          [19:16]
 513         * MIPI0_PRE_RATIO      [23:20]
 514         * set fimd ratio
 515         */
 516        cfg &= ~(0xf);
 517        cfg |= 0x1;
 518        writel(cfg, &clk->div_lcd0);
 519}
 520
 521void exynos4_set_mipi_clk(void)
 522{
 523        struct exynos4_clock *clk =
 524            (struct exynos4_clock *)samsung_get_base_clock();
 525        unsigned int cfg = 0;
 526
 527        /*
 528         * CLK_SRC_LCD0
 529         * FIMD0_SEL            [3:0]
 530         * MDNIE0_SEL           [7:4]
 531         * MDNIE_PWM0_SEL       [8:11]
 532         * MIPI0_SEL            [12:15]
 533         * set mipi0 src clock 0x6: SCLK_MPLL
 534         */
 535        cfg = readl(&clk->src_lcd0);
 536        cfg &= ~(0xf << 12);
 537        cfg |= (0x6 << 12);
 538        writel(cfg, &clk->src_lcd0);
 539
 540        /*
 541         * CLK_SRC_MASK_LCD0
 542         * FIMD0_MASK           [0]
 543         * MDNIE0_MASK          [4]
 544         * MDNIE_PWM0_MASK      [8]
 545         * MIPI0_MASK           [12]
 546         * set src mask mipi0 0x1: Unmask
 547         */
 548        cfg = readl(&clk->src_mask_lcd0);
 549        cfg |= (0x1 << 12);
 550        writel(cfg, &clk->src_mask_lcd0);
 551
 552        /*
 553         * CLK_GATE_IP_LCD0
 554         * CLK_FIMD0            [0]
 555         * CLK_MIE0             [1]
 556         * CLK_MDNIE0           [2]
 557         * CLK_DSIM0            [3]
 558         * CLK_SMMUFIMD0        [4]
 559         * CLK_PPMULCD0         [5]
 560         * Gating all clocks for MIPI0
 561         */
 562        cfg = readl(&clk->gate_ip_lcd0);
 563        cfg |= 1 << 3;
 564        writel(cfg, &clk->gate_ip_lcd0);
 565
 566        /*
 567         * CLK_DIV_LCD0
 568         * FIMD0_RATIO          [3:0]
 569         * MDNIE0_RATIO         [7:4]
 570         * MDNIE_PWM0_RATIO     [11:8]
 571         * MDNIE_PWM_PRE_RATIO  [15:12]
 572         * MIPI0_RATIO          [19:16]
 573         * MIPI0_PRE_RATIO      [23:20]
 574         * set mipi ratio
 575         */
 576        cfg &= ~(0xf << 16);
 577        cfg |= (0x1 << 16);
 578        writel(cfg, &clk->div_lcd0);
 579}
 580
 581unsigned long get_pll_clk(int pllreg)
 582{
 583        if (cpu_is_exynos5())
 584                return exynos5_get_pll_clk(pllreg);
 585        else
 586                return exynos4_get_pll_clk(pllreg);
 587}
 588
 589unsigned long get_arm_clk(void)
 590{
 591        if (cpu_is_exynos5())
 592                return exynos5_get_arm_clk();
 593        else
 594                return exynos4_get_arm_clk();
 595}
 596
 597unsigned long get_pwm_clk(void)
 598{
 599        if (cpu_is_exynos5())
 600                return exynos5_get_pwm_clk();
 601        else
 602                return exynos4_get_pwm_clk();
 603}
 604
 605unsigned long get_uart_clk(int dev_index)
 606{
 607        if (cpu_is_exynos5())
 608                return exynos5_get_uart_clk(dev_index);
 609        else
 610                return exynos4_get_uart_clk(dev_index);
 611}
 612
 613void set_mmc_clk(int dev_index, unsigned int div)
 614{
 615        if (cpu_is_exynos5())
 616                exynos5_set_mmc_clk(dev_index, div);
 617        else
 618                exynos4_set_mmc_clk(dev_index, div);
 619}
 620
 621unsigned long get_lcd_clk(void)
 622{
 623        if (cpu_is_exynos4())
 624                return exynos4_get_lcd_clk();
 625        else
 626                return 0;
 627}
 628
 629void set_lcd_clk(void)
 630{
 631        if (cpu_is_exynos4())
 632                exynos4_set_lcd_clk();
 633}
 634
 635void set_mipi_clk(void)
 636{
 637        if (cpu_is_exynos4())
 638                exynos4_set_mipi_clk();
 639}
 640