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#include <asm/arch/periph.h>
  29
  30/* Epll Clock division values to achive different frequency output */
  31static struct set_epll_con_val exynos5_epll_div[] = {
  32        { 192000000, 0, 48, 3, 1, 0 },
  33        { 180000000, 0, 45, 3, 1, 0 },
  34        {  73728000, 1, 73, 3, 3, 47710 },
  35        {  67737600, 1, 90, 4, 3, 20762 },
  36        {  49152000, 0, 49, 3, 3, 9961 },
  37        {  45158400, 0, 45, 3, 3, 10381 },
  38        { 180633600, 0, 45, 3, 1, 10381 }
  39};
  40
  41/* exynos: return pll clock frequency */
  42static int exynos_get_pll_clk(int pllreg, unsigned int r, unsigned int k)
  43{
  44        unsigned long m, p, s = 0, mask, fout;
  45        unsigned int freq;
  46        /*
  47         * APLL_CON: MIDV [25:16]
  48         * MPLL_CON: MIDV [25:16]
  49         * EPLL_CON: MIDV [24:16]
  50         * VPLL_CON: MIDV [24:16]
  51         * BPLL_CON: MIDV [25:16]: Exynos5
  52         */
  53        if (pllreg == APLL || pllreg == MPLL || pllreg == BPLL)
  54                mask = 0x3ff;
  55        else
  56                mask = 0x1ff;
  57
  58        m = (r >> 16) & mask;
  59
  60        /* PDIV [13:8] */
  61        p = (r >> 8) & 0x3f;
  62        /* SDIV [2:0] */
  63        s = r & 0x7;
  64
  65        freq = CONFIG_SYS_CLK_FREQ;
  66
  67        if (pllreg == EPLL) {
  68                k = k & 0xffff;
  69                /* FOUT = (MDIV + K / 65536) * FIN / (PDIV * 2^SDIV) */
  70                fout = (m + k / 65536) * (freq / (p * (1 << s)));
  71        } else if (pllreg == VPLL) {
  72                k = k & 0xfff;
  73                /* FOUT = (MDIV + K / 1024) * FIN / (PDIV * 2^SDIV) */
  74                fout = (m + k / 1024) * (freq / (p * (1 << s)));
  75        } else {
  76                if (s < 1)
  77                        s = 1;
  78                /* FOUT = MDIV * FIN / (PDIV * 2^(SDIV - 1)) */
  79                fout = m * (freq / (p * (1 << (s - 1))));
  80        }
  81
  82        return fout;
  83}
  84
  85/* exynos4: return pll clock frequency */
  86static unsigned long exynos4_get_pll_clk(int pllreg)
  87{
  88        struct exynos4_clock *clk =
  89                (struct exynos4_clock *)samsung_get_base_clock();
  90        unsigned long r, k = 0;
  91
  92        switch (pllreg) {
  93        case APLL:
  94                r = readl(&clk->apll_con0);
  95                break;
  96        case MPLL:
  97                r = readl(&clk->mpll_con0);
  98                break;
  99        case EPLL:
 100                r = readl(&clk->epll_con0);
 101                k = readl(&clk->epll_con1);
 102                break;
 103        case VPLL:
 104                r = readl(&clk->vpll_con0);
 105                k = readl(&clk->vpll_con1);
 106                break;
 107        default:
 108                printf("Unsupported PLL (%d)\n", pllreg);
 109                return 0;
 110        }
 111
 112        return exynos_get_pll_clk(pllreg, r, k);
 113}
 114
 115/* exynos4x12: return pll clock frequency */
 116static unsigned long exynos4x12_get_pll_clk(int pllreg)
 117{
 118        struct exynos4x12_clock *clk =
 119                (struct exynos4x12_clock *)samsung_get_base_clock();
 120        unsigned long r, k = 0;
 121
 122        switch (pllreg) {
 123        case APLL:
 124                r = readl(&clk->apll_con0);
 125                break;
 126        case MPLL:
 127                r = readl(&clk->mpll_con0);
 128                break;
 129        case EPLL:
 130                r = readl(&clk->epll_con0);
 131                k = readl(&clk->epll_con1);
 132                break;
 133        case VPLL:
 134                r = readl(&clk->vpll_con0);
 135                k = readl(&clk->vpll_con1);
 136                break;
 137        default:
 138                printf("Unsupported PLL (%d)\n", pllreg);
 139                return 0;
 140        }
 141
 142        return exynos_get_pll_clk(pllreg, r, k);
 143}
 144
 145/* exynos5: return pll clock frequency */
 146static unsigned long exynos5_get_pll_clk(int pllreg)
 147{
 148        struct exynos5_clock *clk =
 149                (struct exynos5_clock *)samsung_get_base_clock();
 150        unsigned long r, k = 0, fout;
 151        unsigned int pll_div2_sel, fout_sel;
 152
 153        switch (pllreg) {
 154        case APLL:
 155                r = readl(&clk->apll_con0);
 156                break;
 157        case MPLL:
 158                r = readl(&clk->mpll_con0);
 159                break;
 160        case EPLL:
 161                r = readl(&clk->epll_con0);
 162                k = readl(&clk->epll_con1);
 163                break;
 164        case VPLL:
 165                r = readl(&clk->vpll_con0);
 166                k = readl(&clk->vpll_con1);
 167                break;
 168        case BPLL:
 169                r = readl(&clk->bpll_con0);
 170                break;
 171        default:
 172                printf("Unsupported PLL (%d)\n", pllreg);
 173                return 0;
 174        }
 175
 176        fout = exynos_get_pll_clk(pllreg, r, k);
 177
 178        /* According to the user manual, in EVT1 MPLL and BPLL always gives
 179         * 1.6GHz clock, so divide by 2 to get 800MHz MPLL clock.*/
 180        if (pllreg == MPLL || pllreg == BPLL) {
 181                pll_div2_sel = readl(&clk->pll_div2_sel);
 182
 183                switch (pllreg) {
 184                case MPLL:
 185                        fout_sel = (pll_div2_sel >> MPLL_FOUT_SEL_SHIFT)
 186                                        & MPLL_FOUT_SEL_MASK;
 187                        break;
 188                case BPLL:
 189                        fout_sel = (pll_div2_sel >> BPLL_FOUT_SEL_SHIFT)
 190                                        & BPLL_FOUT_SEL_MASK;
 191                        break;
 192                default:
 193                        fout_sel = -1;
 194                        break;
 195                }
 196
 197                if (fout_sel == 0)
 198                        fout /= 2;
 199        }
 200
 201        return fout;
 202}
 203
 204/* exynos4: return ARM clock frequency */
 205static unsigned long exynos4_get_arm_clk(void)
 206{
 207        struct exynos4_clock *clk =
 208                (struct exynos4_clock *)samsung_get_base_clock();
 209        unsigned long div;
 210        unsigned long armclk;
 211        unsigned int core_ratio;
 212        unsigned int core2_ratio;
 213
 214        div = readl(&clk->div_cpu0);
 215
 216        /* CORE_RATIO: [2:0], CORE2_RATIO: [30:28] */
 217        core_ratio = (div >> 0) & 0x7;
 218        core2_ratio = (div >> 28) & 0x7;
 219
 220        armclk = get_pll_clk(APLL) / (core_ratio + 1);
 221        armclk /= (core2_ratio + 1);
 222
 223        return armclk;
 224}
 225
 226/* exynos4x12: return ARM clock frequency */
 227static unsigned long exynos4x12_get_arm_clk(void)
 228{
 229        struct exynos4x12_clock *clk =
 230                (struct exynos4x12_clock *)samsung_get_base_clock();
 231        unsigned long div;
 232        unsigned long armclk;
 233        unsigned int core_ratio;
 234        unsigned int core2_ratio;
 235
 236        div = readl(&clk->div_cpu0);
 237
 238        /* CORE_RATIO: [2:0], CORE2_RATIO: [30:28] */
 239        core_ratio = (div >> 0) & 0x7;
 240        core2_ratio = (div >> 28) & 0x7;
 241
 242        armclk = get_pll_clk(APLL) / (core_ratio + 1);
 243        armclk /= (core2_ratio + 1);
 244
 245        return armclk;
 246}
 247
 248/* exynos5: return ARM clock frequency */
 249static unsigned long exynos5_get_arm_clk(void)
 250{
 251        struct exynos5_clock *clk =
 252                (struct exynos5_clock *)samsung_get_base_clock();
 253        unsigned long div;
 254        unsigned long armclk;
 255        unsigned int arm_ratio;
 256        unsigned int arm2_ratio;
 257
 258        div = readl(&clk->div_cpu0);
 259
 260        /* ARM_RATIO: [2:0], ARM2_RATIO: [30:28] */
 261        arm_ratio = (div >> 0) & 0x7;
 262        arm2_ratio = (div >> 28) & 0x7;
 263
 264        armclk = get_pll_clk(APLL) / (arm_ratio + 1);
 265        armclk /= (arm2_ratio + 1);
 266
 267        return armclk;
 268}
 269
 270/* exynos4: return pwm clock frequency */
 271static unsigned long exynos4_get_pwm_clk(void)
 272{
 273        struct exynos4_clock *clk =
 274                (struct exynos4_clock *)samsung_get_base_clock();
 275        unsigned long pclk, sclk;
 276        unsigned int sel;
 277        unsigned int ratio;
 278
 279        if (s5p_get_cpu_rev() == 0) {
 280                /*
 281                 * CLK_SRC_PERIL0
 282                 * PWM_SEL [27:24]
 283                 */
 284                sel = readl(&clk->src_peril0);
 285                sel = (sel >> 24) & 0xf;
 286
 287                if (sel == 0x6)
 288                        sclk = get_pll_clk(MPLL);
 289                else if (sel == 0x7)
 290                        sclk = get_pll_clk(EPLL);
 291                else if (sel == 0x8)
 292                        sclk = get_pll_clk(VPLL);
 293                else
 294                        return 0;
 295
 296                /*
 297                 * CLK_DIV_PERIL3
 298                 * PWM_RATIO [3:0]
 299                 */
 300                ratio = readl(&clk->div_peril3);
 301                ratio = ratio & 0xf;
 302        } else if (s5p_get_cpu_rev() == 1) {
 303                sclk = get_pll_clk(MPLL);
 304                ratio = 8;
 305        } else
 306                return 0;
 307
 308        pclk = sclk / (ratio + 1);
 309
 310        return pclk;
 311}
 312
 313/* exynos4x12: return pwm clock frequency */
 314static unsigned long exynos4x12_get_pwm_clk(void)
 315{
 316        unsigned long pclk, sclk;
 317        unsigned int ratio;
 318
 319        sclk = get_pll_clk(MPLL);
 320        ratio = 8;
 321
 322        pclk = sclk / (ratio + 1);
 323
 324        return pclk;
 325}
 326
 327/* exynos5: return pwm clock frequency */
 328static unsigned long exynos5_get_pwm_clk(void)
 329{
 330        struct exynos5_clock *clk =
 331                (struct exynos5_clock *)samsung_get_base_clock();
 332        unsigned long pclk, sclk;
 333        unsigned int ratio;
 334
 335        /*
 336         * CLK_DIV_PERIC3
 337         * PWM_RATIO [3:0]
 338         */
 339        ratio = readl(&clk->div_peric3);
 340        ratio = ratio & 0xf;
 341        sclk = get_pll_clk(MPLL);
 342
 343        pclk = sclk / (ratio + 1);
 344
 345        return pclk;
 346}
 347
 348/* exynos4: return uart clock frequency */
 349static unsigned long exynos4_get_uart_clk(int dev_index)
 350{
 351        struct exynos4_clock *clk =
 352                (struct exynos4_clock *)samsung_get_base_clock();
 353        unsigned long uclk, sclk;
 354        unsigned int sel;
 355        unsigned int ratio;
 356
 357        /*
 358         * CLK_SRC_PERIL0
 359         * UART0_SEL [3:0]
 360         * UART1_SEL [7:4]
 361         * UART2_SEL [8:11]
 362         * UART3_SEL [12:15]
 363         * UART4_SEL [16:19]
 364         * UART5_SEL [23:20]
 365         */
 366        sel = readl(&clk->src_peril0);
 367        sel = (sel >> (dev_index << 2)) & 0xf;
 368
 369        if (sel == 0x6)
 370                sclk = get_pll_clk(MPLL);
 371        else if (sel == 0x7)
 372                sclk = get_pll_clk(EPLL);
 373        else if (sel == 0x8)
 374                sclk = get_pll_clk(VPLL);
 375        else
 376                return 0;
 377
 378        /*
 379         * CLK_DIV_PERIL0
 380         * UART0_RATIO [3:0]
 381         * UART1_RATIO [7:4]
 382         * UART2_RATIO [8:11]
 383         * UART3_RATIO [12:15]
 384         * UART4_RATIO [16:19]
 385         * UART5_RATIO [23:20]
 386         */
 387        ratio = readl(&clk->div_peril0);
 388        ratio = (ratio >> (dev_index << 2)) & 0xf;
 389
 390        uclk = sclk / (ratio + 1);
 391
 392        return uclk;
 393}
 394
 395/* exynos4x12: return uart clock frequency */
 396static unsigned long exynos4x12_get_uart_clk(int dev_index)
 397{
 398        struct exynos4x12_clock *clk =
 399                (struct exynos4x12_clock *)samsung_get_base_clock();
 400        unsigned long uclk, sclk;
 401        unsigned int sel;
 402        unsigned int ratio;
 403
 404        /*
 405         * CLK_SRC_PERIL0
 406         * UART0_SEL [3:0]
 407         * UART1_SEL [7:4]
 408         * UART2_SEL [8:11]
 409         * UART3_SEL [12:15]
 410         * UART4_SEL [16:19]
 411         */
 412        sel = readl(&clk->src_peril0);
 413        sel = (sel >> (dev_index << 2)) & 0xf;
 414
 415        if (sel == 0x6)
 416                sclk = get_pll_clk(MPLL);
 417        else if (sel == 0x7)
 418                sclk = get_pll_clk(EPLL);
 419        else if (sel == 0x8)
 420                sclk = get_pll_clk(VPLL);
 421        else
 422                return 0;
 423
 424        /*
 425         * CLK_DIV_PERIL0
 426         * UART0_RATIO [3:0]
 427         * UART1_RATIO [7:4]
 428         * UART2_RATIO [8:11]
 429         * UART3_RATIO [12:15]
 430         * UART4_RATIO [16:19]
 431         */
 432        ratio = readl(&clk->div_peril0);
 433        ratio = (ratio >> (dev_index << 2)) & 0xf;
 434
 435        uclk = sclk / (ratio + 1);
 436
 437        return uclk;
 438}
 439
 440/* exynos5: return uart clock frequency */
 441static unsigned long exynos5_get_uart_clk(int dev_index)
 442{
 443        struct exynos5_clock *clk =
 444                (struct exynos5_clock *)samsung_get_base_clock();
 445        unsigned long uclk, sclk;
 446        unsigned int sel;
 447        unsigned int ratio;
 448
 449        /*
 450         * CLK_SRC_PERIC0
 451         * UART0_SEL [3:0]
 452         * UART1_SEL [7:4]
 453         * UART2_SEL [8:11]
 454         * UART3_SEL [12:15]
 455         * UART4_SEL [16:19]
 456         * UART5_SEL [23:20]
 457         */
 458        sel = readl(&clk->src_peric0);
 459        sel = (sel >> (dev_index << 2)) & 0xf;
 460
 461        if (sel == 0x6)
 462                sclk = get_pll_clk(MPLL);
 463        else if (sel == 0x7)
 464                sclk = get_pll_clk(EPLL);
 465        else if (sel == 0x8)
 466                sclk = get_pll_clk(VPLL);
 467        else
 468                return 0;
 469
 470        /*
 471         * CLK_DIV_PERIC0
 472         * UART0_RATIO [3:0]
 473         * UART1_RATIO [7:4]
 474         * UART2_RATIO [8:11]
 475         * UART3_RATIO [12:15]
 476         * UART4_RATIO [16:19]
 477         * UART5_RATIO [23:20]
 478         */
 479        ratio = readl(&clk->div_peric0);
 480        ratio = (ratio >> (dev_index << 2)) & 0xf;
 481
 482        uclk = sclk / (ratio + 1);
 483
 484        return uclk;
 485}
 486
 487static unsigned long exynos4_get_mmc_clk(int dev_index)
 488{
 489        struct exynos4_clock *clk =
 490                (struct exynos4_clock *)samsung_get_base_clock();
 491        unsigned long uclk, sclk;
 492        unsigned int sel, ratio, pre_ratio;
 493        int shift;
 494
 495        sel = readl(&clk->src_fsys);
 496        sel = (sel >> (dev_index << 2)) & 0xf;
 497
 498        if (sel == 0x6)
 499                sclk = get_pll_clk(MPLL);
 500        else if (sel == 0x7)
 501                sclk = get_pll_clk(EPLL);
 502        else if (sel == 0x8)
 503                sclk = get_pll_clk(VPLL);
 504        else
 505                return 0;
 506
 507        switch (dev_index) {
 508        case 0:
 509        case 1:
 510                ratio = readl(&clk->div_fsys1);
 511                pre_ratio = readl(&clk->div_fsys1);
 512                break;
 513        case 2:
 514        case 3:
 515                ratio = readl(&clk->div_fsys2);
 516                pre_ratio = readl(&clk->div_fsys2);
 517                break;
 518        case 4:
 519                ratio = readl(&clk->div_fsys3);
 520                pre_ratio = readl(&clk->div_fsys3);
 521                break;
 522        default:
 523                return 0;
 524        }
 525
 526        if (dev_index == 1 || dev_index == 3)
 527                shift = 16;
 528
 529        ratio = (ratio >> shift) & 0xf;
 530        pre_ratio = (pre_ratio >> (shift + 8)) & 0xff;
 531        uclk = (sclk / (ratio + 1)) / (pre_ratio + 1);
 532
 533        return uclk;
 534}
 535
 536static unsigned long exynos5_get_mmc_clk(int dev_index)
 537{
 538        struct exynos5_clock *clk =
 539                (struct exynos5_clock *)samsung_get_base_clock();
 540        unsigned long uclk, sclk;
 541        unsigned int sel, ratio, pre_ratio;
 542        int shift;
 543
 544        sel = readl(&clk->src_fsys);
 545        sel = (sel >> (dev_index << 2)) & 0xf;
 546
 547        if (sel == 0x6)
 548                sclk = get_pll_clk(MPLL);
 549        else if (sel == 0x7)
 550                sclk = get_pll_clk(EPLL);
 551        else if (sel == 0x8)
 552                sclk = get_pll_clk(VPLL);
 553        else
 554                return 0;
 555
 556        switch (dev_index) {
 557        case 0:
 558        case 1:
 559                ratio = readl(&clk->div_fsys1);
 560                pre_ratio = readl(&clk->div_fsys1);
 561                break;
 562        case 2:
 563        case 3:
 564                ratio = readl(&clk->div_fsys2);
 565                pre_ratio = readl(&clk->div_fsys2);
 566                break;
 567        default:
 568                return 0;
 569        }
 570
 571        if (dev_index == 1 || dev_index == 3)
 572                shift = 16;
 573
 574        ratio = (ratio >> shift) & 0xf;
 575        pre_ratio = (pre_ratio >> (shift + 8)) & 0xff;
 576        uclk = (sclk / (ratio + 1)) / (pre_ratio + 1);
 577
 578        return uclk;
 579}
 580
 581/* exynos4: set the mmc clock */
 582static void exynos4_set_mmc_clk(int dev_index, unsigned int div)
 583{
 584        struct exynos4_clock *clk =
 585                (struct exynos4_clock *)samsung_get_base_clock();
 586        unsigned int addr;
 587        unsigned int val;
 588
 589        /*
 590         * CLK_DIV_FSYS1
 591         * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24]
 592         * CLK_DIV_FSYS2
 593         * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24]
 594         * CLK_DIV_FSYS3
 595         * MMC4_PRE_RATIO [15:8]
 596         */
 597        if (dev_index < 2) {
 598                addr = (unsigned int)&clk->div_fsys1;
 599        }  else if (dev_index == 4) {
 600                addr = (unsigned int)&clk->div_fsys3;
 601                dev_index -= 4;
 602        } else {
 603                addr = (unsigned int)&clk->div_fsys2;
 604                dev_index -= 2;
 605        }
 606
 607        val = readl(addr);
 608        val &= ~(0xff << ((dev_index << 4) + 8));
 609        val |= (div & 0xff) << ((dev_index << 4) + 8);
 610        writel(val, addr);
 611}
 612
 613/* exynos4x12: set the mmc clock */
 614static void exynos4x12_set_mmc_clk(int dev_index, unsigned int div)
 615{
 616        struct exynos4x12_clock *clk =
 617                (struct exynos4x12_clock *)samsung_get_base_clock();
 618        unsigned int addr;
 619        unsigned int val;
 620
 621        /*
 622         * CLK_DIV_FSYS1
 623         * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24]
 624         * CLK_DIV_FSYS2
 625         * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24]
 626         */
 627        if (dev_index < 2) {
 628                addr = (unsigned int)&clk->div_fsys1;
 629        } else {
 630                addr = (unsigned int)&clk->div_fsys2;
 631                dev_index -= 2;
 632        }
 633
 634        val = readl(addr);
 635        val &= ~(0xff << ((dev_index << 4) + 8));
 636        val |= (div & 0xff) << ((dev_index << 4) + 8);
 637        writel(val, addr);
 638}
 639
 640/* exynos5: set the mmc clock */
 641static void exynos5_set_mmc_clk(int dev_index, unsigned int div)
 642{
 643        struct exynos5_clock *clk =
 644                (struct exynos5_clock *)samsung_get_base_clock();
 645        unsigned int addr;
 646        unsigned int val;
 647
 648        /*
 649         * CLK_DIV_FSYS1
 650         * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24]
 651         * CLK_DIV_FSYS2
 652         * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24]
 653         */
 654        if (dev_index < 2) {
 655                addr = (unsigned int)&clk->div_fsys1;
 656        } else {
 657                addr = (unsigned int)&clk->div_fsys2;
 658                dev_index -= 2;
 659        }
 660
 661        val = readl(addr);
 662        val &= ~(0xff << ((dev_index << 4) + 8));
 663        val |= (div & 0xff) << ((dev_index << 4) + 8);
 664        writel(val, addr);
 665}
 666
 667/* get_lcd_clk: return lcd clock frequency */
 668static unsigned long exynos4_get_lcd_clk(void)
 669{
 670        struct exynos4_clock *clk =
 671                (struct exynos4_clock *)samsung_get_base_clock();
 672        unsigned long pclk, sclk;
 673        unsigned int sel;
 674        unsigned int ratio;
 675
 676        /*
 677         * CLK_SRC_LCD0
 678         * FIMD0_SEL [3:0]
 679         */
 680        sel = readl(&clk->src_lcd0);
 681        sel = sel & 0xf;
 682
 683        /*
 684         * 0x6: SCLK_MPLL
 685         * 0x7: SCLK_EPLL
 686         * 0x8: SCLK_VPLL
 687         */
 688        if (sel == 0x6)
 689                sclk = get_pll_clk(MPLL);
 690        else if (sel == 0x7)
 691                sclk = get_pll_clk(EPLL);
 692        else if (sel == 0x8)
 693                sclk = get_pll_clk(VPLL);
 694        else
 695                return 0;
 696
 697        /*
 698         * CLK_DIV_LCD0
 699         * FIMD0_RATIO [3:0]
 700         */
 701        ratio = readl(&clk->div_lcd0);
 702        ratio = ratio & 0xf;
 703
 704        pclk = sclk / (ratio + 1);
 705
 706        return pclk;
 707}
 708
 709/* get_lcd_clk: return lcd clock frequency */
 710static unsigned long exynos5_get_lcd_clk(void)
 711{
 712        struct exynos5_clock *clk =
 713                (struct exynos5_clock *)samsung_get_base_clock();
 714        unsigned long pclk, sclk;
 715        unsigned int sel;
 716        unsigned int ratio;
 717
 718        /*
 719         * CLK_SRC_LCD0
 720         * FIMD0_SEL [3:0]
 721         */
 722        sel = readl(&clk->src_disp1_0);
 723        sel = sel & 0xf;
 724
 725        /*
 726         * 0x6: SCLK_MPLL
 727         * 0x7: SCLK_EPLL
 728         * 0x8: SCLK_VPLL
 729         */
 730        if (sel == 0x6)
 731                sclk = get_pll_clk(MPLL);
 732        else if (sel == 0x7)
 733                sclk = get_pll_clk(EPLL);
 734        else if (sel == 0x8)
 735                sclk = get_pll_clk(VPLL);
 736        else
 737                return 0;
 738
 739        /*
 740         * CLK_DIV_LCD0
 741         * FIMD0_RATIO [3:0]
 742         */
 743        ratio = readl(&clk->div_disp1_0);
 744        ratio = ratio & 0xf;
 745
 746        pclk = sclk / (ratio + 1);
 747
 748        return pclk;
 749}
 750
 751void exynos4_set_lcd_clk(void)
 752{
 753        struct exynos4_clock *clk =
 754            (struct exynos4_clock *)samsung_get_base_clock();
 755        unsigned int cfg = 0;
 756
 757        /*
 758         * CLK_GATE_BLOCK
 759         * CLK_CAM      [0]
 760         * CLK_TV       [1]
 761         * CLK_MFC      [2]
 762         * CLK_G3D      [3]
 763         * CLK_LCD0     [4]
 764         * CLK_LCD1     [5]
 765         * CLK_GPS      [7]
 766         */
 767        cfg = readl(&clk->gate_block);
 768        cfg |= 1 << 4;
 769        writel(cfg, &clk->gate_block);
 770
 771        /*
 772         * CLK_SRC_LCD0
 773         * FIMD0_SEL            [3:0]
 774         * MDNIE0_SEL           [7:4]
 775         * MDNIE_PWM0_SEL       [8:11]
 776         * MIPI0_SEL            [12:15]
 777         * set lcd0 src clock 0x6: SCLK_MPLL
 778         */
 779        cfg = readl(&clk->src_lcd0);
 780        cfg &= ~(0xf);
 781        cfg |= 0x6;
 782        writel(cfg, &clk->src_lcd0);
 783
 784        /*
 785         * CLK_GATE_IP_LCD0
 786         * CLK_FIMD0            [0]
 787         * CLK_MIE0             [1]
 788         * CLK_MDNIE0           [2]
 789         * CLK_DSIM0            [3]
 790         * CLK_SMMUFIMD0        [4]
 791         * CLK_PPMULCD0         [5]
 792         * Gating all clocks for FIMD0
 793         */
 794        cfg = readl(&clk->gate_ip_lcd0);
 795        cfg |= 1 << 0;
 796        writel(cfg, &clk->gate_ip_lcd0);
 797
 798        /*
 799         * CLK_DIV_LCD0
 800         * FIMD0_RATIO          [3:0]
 801         * MDNIE0_RATIO         [7:4]
 802         * MDNIE_PWM0_RATIO     [11:8]
 803         * MDNIE_PWM_PRE_RATIO  [15:12]
 804         * MIPI0_RATIO          [19:16]
 805         * MIPI0_PRE_RATIO      [23:20]
 806         * set fimd ratio
 807         */
 808        cfg &= ~(0xf);
 809        cfg |= 0x1;
 810        writel(cfg, &clk->div_lcd0);
 811}
 812
 813void exynos5_set_lcd_clk(void)
 814{
 815        struct exynos5_clock *clk =
 816            (struct exynos5_clock *)samsung_get_base_clock();
 817        unsigned int cfg = 0;
 818
 819        /*
 820         * CLK_GATE_BLOCK
 821         * CLK_CAM      [0]
 822         * CLK_TV       [1]
 823         * CLK_MFC      [2]
 824         * CLK_G3D      [3]
 825         * CLK_LCD0     [4]
 826         * CLK_LCD1     [5]
 827         * CLK_GPS      [7]
 828         */
 829        cfg = readl(&clk->gate_block);
 830        cfg |= 1 << 4;
 831        writel(cfg, &clk->gate_block);
 832
 833        /*
 834         * CLK_SRC_LCD0
 835         * FIMD0_SEL            [3:0]
 836         * MDNIE0_SEL           [7:4]
 837         * MDNIE_PWM0_SEL       [8:11]
 838         * MIPI0_SEL            [12:15]
 839         * set lcd0 src clock 0x6: SCLK_MPLL
 840         */
 841        cfg = readl(&clk->src_disp1_0);
 842        cfg &= ~(0xf);
 843        cfg |= 0x6;
 844        writel(cfg, &clk->src_disp1_0);
 845
 846        /*
 847         * CLK_GATE_IP_LCD0
 848         * CLK_FIMD0            [0]
 849         * CLK_MIE0             [1]
 850         * CLK_MDNIE0           [2]
 851         * CLK_DSIM0            [3]
 852         * CLK_SMMUFIMD0        [4]
 853         * CLK_PPMULCD0         [5]
 854         * Gating all clocks for FIMD0
 855         */
 856        cfg = readl(&clk->gate_ip_disp1);
 857        cfg |= 1 << 0;
 858        writel(cfg, &clk->gate_ip_disp1);
 859
 860        /*
 861         * CLK_DIV_LCD0
 862         * FIMD0_RATIO          [3:0]
 863         * MDNIE0_RATIO         [7:4]
 864         * MDNIE_PWM0_RATIO     [11:8]
 865         * MDNIE_PWM_PRE_RATIO  [15:12]
 866         * MIPI0_RATIO          [19:16]
 867         * MIPI0_PRE_RATIO      [23:20]
 868         * set fimd ratio
 869         */
 870        cfg &= ~(0xf);
 871        cfg |= 0x0;
 872        writel(cfg, &clk->div_disp1_0);
 873}
 874
 875void exynos4_set_mipi_clk(void)
 876{
 877        struct exynos4_clock *clk =
 878            (struct exynos4_clock *)samsung_get_base_clock();
 879        unsigned int cfg = 0;
 880
 881        /*
 882         * CLK_SRC_LCD0
 883         * FIMD0_SEL            [3:0]
 884         * MDNIE0_SEL           [7:4]
 885         * MDNIE_PWM0_SEL       [8:11]
 886         * MIPI0_SEL            [12:15]
 887         * set mipi0 src clock 0x6: SCLK_MPLL
 888         */
 889        cfg = readl(&clk->src_lcd0);
 890        cfg &= ~(0xf << 12);
 891        cfg |= (0x6 << 12);
 892        writel(cfg, &clk->src_lcd0);
 893
 894        /*
 895         * CLK_SRC_MASK_LCD0
 896         * FIMD0_MASK           [0]
 897         * MDNIE0_MASK          [4]
 898         * MDNIE_PWM0_MASK      [8]
 899         * MIPI0_MASK           [12]
 900         * set src mask mipi0 0x1: Unmask
 901         */
 902        cfg = readl(&clk->src_mask_lcd0);
 903        cfg |= (0x1 << 12);
 904        writel(cfg, &clk->src_mask_lcd0);
 905
 906        /*
 907         * CLK_GATE_IP_LCD0
 908         * CLK_FIMD0            [0]
 909         * CLK_MIE0             [1]
 910         * CLK_MDNIE0           [2]
 911         * CLK_DSIM0            [3]
 912         * CLK_SMMUFIMD0        [4]
 913         * CLK_PPMULCD0         [5]
 914         * Gating all clocks for MIPI0
 915         */
 916        cfg = readl(&clk->gate_ip_lcd0);
 917        cfg |= 1 << 3;
 918        writel(cfg, &clk->gate_ip_lcd0);
 919
 920        /*
 921         * CLK_DIV_LCD0
 922         * FIMD0_RATIO          [3:0]
 923         * MDNIE0_RATIO         [7:4]
 924         * MDNIE_PWM0_RATIO     [11:8]
 925         * MDNIE_PWM_PRE_RATIO  [15:12]
 926         * MIPI0_RATIO          [19:16]
 927         * MIPI0_PRE_RATIO      [23:20]
 928         * set mipi ratio
 929         */
 930        cfg &= ~(0xf << 16);
 931        cfg |= (0x1 << 16);
 932        writel(cfg, &clk->div_lcd0);
 933}
 934
 935/*
 936 * I2C
 937 *
 938 * exynos5: obtaining the I2C clock
 939 */
 940static unsigned long exynos5_get_i2c_clk(void)
 941{
 942        struct exynos5_clock *clk =
 943                (struct exynos5_clock *)samsung_get_base_clock();
 944        unsigned long aclk_66, aclk_66_pre, sclk;
 945        unsigned int ratio;
 946
 947        sclk = get_pll_clk(MPLL);
 948
 949        ratio = (readl(&clk->div_top1)) >> 24;
 950        ratio &= 0x7;
 951        aclk_66_pre = sclk / (ratio + 1);
 952        ratio = readl(&clk->div_top0);
 953        ratio &= 0x7;
 954        aclk_66 = aclk_66_pre / (ratio + 1);
 955        return aclk_66;
 956}
 957
 958int exynos5_set_epll_clk(unsigned long rate)
 959{
 960        unsigned int epll_con, epll_con_k;
 961        unsigned int i;
 962        unsigned int lockcnt;
 963        unsigned int start;
 964        struct exynos5_clock *clk =
 965                (struct exynos5_clock *)samsung_get_base_clock();
 966
 967        epll_con = readl(&clk->epll_con0);
 968        epll_con &= ~((EPLL_CON0_LOCK_DET_EN_MASK <<
 969                        EPLL_CON0_LOCK_DET_EN_SHIFT) |
 970                EPLL_CON0_MDIV_MASK << EPLL_CON0_MDIV_SHIFT |
 971                EPLL_CON0_PDIV_MASK << EPLL_CON0_PDIV_SHIFT |
 972                EPLL_CON0_SDIV_MASK << EPLL_CON0_SDIV_SHIFT);
 973
 974        for (i = 0; i < ARRAY_SIZE(exynos5_epll_div); i++) {
 975                if (exynos5_epll_div[i].freq_out == rate)
 976                        break;
 977        }
 978
 979        if (i == ARRAY_SIZE(exynos5_epll_div))
 980                return -1;
 981
 982        epll_con_k = exynos5_epll_div[i].k_dsm << 0;
 983        epll_con |= exynos5_epll_div[i].en_lock_det <<
 984                                EPLL_CON0_LOCK_DET_EN_SHIFT;
 985        epll_con |= exynos5_epll_div[i].m_div << EPLL_CON0_MDIV_SHIFT;
 986        epll_con |= exynos5_epll_div[i].p_div << EPLL_CON0_PDIV_SHIFT;
 987        epll_con |= exynos5_epll_div[i].s_div << EPLL_CON0_SDIV_SHIFT;
 988
 989        /*
 990         * Required period ( in cycles) to genarate a stable clock output.
 991         * The maximum clock time can be up to 3000 * PDIV cycles of PLLs
 992         * frequency input (as per spec)
 993         */
 994        lockcnt = 3000 * exynos5_epll_div[i].p_div;
 995
 996        writel(lockcnt, &clk->epll_lock);
 997        writel(epll_con, &clk->epll_con0);
 998        writel(epll_con_k, &clk->epll_con1);
 999
1000        start = get_timer(0);
1001
1002         while (!(readl(&clk->epll_con0) &
1003                        (0x1 << EXYNOS5_EPLLCON0_LOCKED_SHIFT))) {
1004                if (get_timer(start) > TIMEOUT_EPLL_LOCK) {
1005                        debug("%s: Timeout waiting for EPLL lock\n", __func__);
1006                        return -1;
1007                }
1008        }
1009        return 0;
1010}
1011
1012void exynos5_set_i2s_clk_source(void)
1013{
1014        struct exynos5_clock *clk =
1015                (struct exynos5_clock *)samsung_get_base_clock();
1016
1017        clrsetbits_le32(&clk->src_peric1, AUDIO1_SEL_MASK,
1018                        (CLK_SRC_SCLK_EPLL));
1019}
1020
1021int exynos5_set_i2s_clk_prescaler(unsigned int src_frq,
1022                                        unsigned int dst_frq)
1023{
1024        struct exynos5_clock *clk =
1025                (struct exynos5_clock *)samsung_get_base_clock();
1026        unsigned int div;
1027
1028        if ((dst_frq == 0) || (src_frq == 0)) {
1029                debug("%s: Invalid requency input for prescaler\n", __func__);
1030                debug("src frq = %d des frq = %d ", src_frq, dst_frq);
1031                return -1;
1032        }
1033
1034        div = (src_frq / dst_frq);
1035        if (div > AUDIO_1_RATIO_MASK) {
1036                debug("%s: Frequency ratio is out of range\n", __func__);
1037                debug("src frq = %d des frq = %d ", src_frq, dst_frq);
1038                return -1;
1039        }
1040        clrsetbits_le32(&clk->div_peric4, AUDIO_1_RATIO_MASK,
1041                                (div & AUDIO_1_RATIO_MASK));
1042        return 0;
1043}
1044
1045/**
1046 * Linearly searches for the most accurate main and fine stage clock scalars
1047 * (divisors) for a specified target frequency and scalar bit sizes by checking
1048 * all multiples of main_scalar_bits values. Will always return scalars up to or
1049 * slower than target.
1050 *
1051 * @param main_scalar_bits      Number of main scalar bits, must be > 0 and < 32
1052 * @param fine_scalar_bits      Number of fine scalar bits, must be > 0 and < 32
1053 * @param input_freq            Clock frequency to be scaled in Hz
1054 * @param target_freq           Desired clock frequency in Hz
1055 * @param best_fine_scalar      Pointer to store the fine stage divisor
1056 *
1057 * @return best_main_scalar     Main scalar for desired frequency or -1 if none
1058 * found
1059 */
1060static int clock_calc_best_scalar(unsigned int main_scaler_bits,
1061        unsigned int fine_scalar_bits, unsigned int input_rate,
1062        unsigned int target_rate, unsigned int *best_fine_scalar)
1063{
1064        int i;
1065        int best_main_scalar = -1;
1066        unsigned int best_error = target_rate;
1067        const unsigned int cap = (1 << fine_scalar_bits) - 1;
1068        const unsigned int loops = 1 << main_scaler_bits;
1069
1070        debug("Input Rate is %u, Target is %u, Cap is %u\n", input_rate,
1071                        target_rate, cap);
1072
1073        assert(best_fine_scalar != NULL);
1074        assert(main_scaler_bits <= fine_scalar_bits);
1075
1076        *best_fine_scalar = 1;
1077
1078        if (input_rate == 0 || target_rate == 0)
1079                return -1;
1080
1081        if (target_rate >= input_rate)
1082                return 1;
1083
1084        for (i = 1; i <= loops; i++) {
1085                const unsigned int effective_div = max(min(input_rate / i /
1086                                                        target_rate, cap), 1);
1087                const unsigned int effective_rate = input_rate / i /
1088                                                        effective_div;
1089                const int error = target_rate - effective_rate;
1090
1091                debug("%d|effdiv:%u, effrate:%u, error:%d\n", i, effective_div,
1092                                effective_rate, error);
1093
1094                if (error >= 0 && error <= best_error) {
1095                        best_error = error;
1096                        best_main_scalar = i;
1097                        *best_fine_scalar = effective_div;
1098                }
1099        }
1100
1101        return best_main_scalar;
1102}
1103
1104static int exynos5_set_spi_clk(enum periph_id periph_id,
1105                                        unsigned int rate)
1106{
1107        struct exynos5_clock *clk =
1108                (struct exynos5_clock *)samsung_get_base_clock();
1109        int main;
1110        unsigned int fine;
1111        unsigned shift, pre_shift;
1112        unsigned mask = 0xff;
1113        u32 *reg;
1114
1115        main = clock_calc_best_scalar(4, 8, 400000000, rate, &fine);
1116        if (main < 0) {
1117                debug("%s: Cannot set clock rate for periph %d",
1118                                __func__, periph_id);
1119                return -1;
1120        }
1121        main = main - 1;
1122        fine = fine - 1;
1123
1124        switch (periph_id) {
1125        case PERIPH_ID_SPI0:
1126                reg = &clk->div_peric1;
1127                shift = 0;
1128                pre_shift = 8;
1129                break;
1130        case PERIPH_ID_SPI1:
1131                reg = &clk->div_peric1;
1132                shift = 16;
1133                pre_shift = 24;
1134                break;
1135        case PERIPH_ID_SPI2:
1136                reg = &clk->div_peric2;
1137                shift = 0;
1138                pre_shift = 8;
1139                break;
1140        case PERIPH_ID_SPI3:
1141                reg = &clk->sclk_div_isp;
1142                shift = 0;
1143                pre_shift = 4;
1144                break;
1145        case PERIPH_ID_SPI4:
1146                reg = &clk->sclk_div_isp;
1147                shift = 12;
1148                pre_shift = 16;
1149                break;
1150        default:
1151                debug("%s: Unsupported peripheral ID %d\n", __func__,
1152                      periph_id);
1153                return -1;
1154        }
1155        clrsetbits_le32(reg, mask << shift, (main & mask) << shift);
1156        clrsetbits_le32(reg, mask << pre_shift, (fine & mask) << pre_shift);
1157
1158        return 0;
1159}
1160
1161static unsigned long exynos4_get_i2c_clk(void)
1162{
1163        struct exynos4_clock *clk =
1164                (struct exynos4_clock *)samsung_get_base_clock();
1165        unsigned long sclk, aclk_100;
1166        unsigned int ratio;
1167
1168        sclk = get_pll_clk(APLL);
1169
1170        ratio = (readl(&clk->div_top)) >> 4;
1171        ratio &= 0xf;
1172        aclk_100 = sclk / (ratio + 1);
1173        return aclk_100;
1174}
1175
1176unsigned long get_pll_clk(int pllreg)
1177{
1178        if (cpu_is_exynos5())
1179                return exynos5_get_pll_clk(pllreg);
1180        else {
1181                if (proid_is_exynos4412())
1182                        return exynos4x12_get_pll_clk(pllreg);
1183                return exynos4_get_pll_clk(pllreg);
1184        }
1185}
1186
1187unsigned long get_arm_clk(void)
1188{
1189        if (cpu_is_exynos5())
1190                return exynos5_get_arm_clk();
1191        else {
1192                if (proid_is_exynos4412())
1193                        return exynos4x12_get_arm_clk();
1194                return exynos4_get_arm_clk();
1195        }
1196}
1197
1198unsigned long get_i2c_clk(void)
1199{
1200        if (cpu_is_exynos5()) {
1201                return exynos5_get_i2c_clk();
1202        } else if (cpu_is_exynos4()) {
1203                return exynos4_get_i2c_clk();
1204        } else {
1205                debug("I2C clock is not set for this CPU\n");
1206                return 0;
1207        }
1208}
1209
1210unsigned long get_pwm_clk(void)
1211{
1212        if (cpu_is_exynos5())
1213                return exynos5_get_pwm_clk();
1214        else {
1215                if (proid_is_exynos4412())
1216                        return exynos4x12_get_pwm_clk();
1217                return exynos4_get_pwm_clk();
1218        }
1219}
1220
1221unsigned long get_uart_clk(int dev_index)
1222{
1223        if (cpu_is_exynos5())
1224                return exynos5_get_uart_clk(dev_index);
1225        else {
1226                if (proid_is_exynos4412())
1227                        return exynos4x12_get_uart_clk(dev_index);
1228                return exynos4_get_uart_clk(dev_index);
1229        }
1230}
1231
1232unsigned long get_mmc_clk(int dev_index)
1233{
1234        if (cpu_is_exynos5())
1235                return exynos5_get_mmc_clk(dev_index);
1236        else
1237                return exynos4_get_mmc_clk(dev_index);
1238}
1239
1240void set_mmc_clk(int dev_index, unsigned int div)
1241{
1242        if (cpu_is_exynos5())
1243                exynos5_set_mmc_clk(dev_index, div);
1244        else {
1245                if (proid_is_exynos4412())
1246                        exynos4x12_set_mmc_clk(dev_index, div);
1247                exynos4_set_mmc_clk(dev_index, div);
1248        }
1249}
1250
1251unsigned long get_lcd_clk(void)
1252{
1253        if (cpu_is_exynos4())
1254                return exynos4_get_lcd_clk();
1255        else
1256                return exynos5_get_lcd_clk();
1257}
1258
1259void set_lcd_clk(void)
1260{
1261        if (cpu_is_exynos4())
1262                exynos4_set_lcd_clk();
1263        else
1264                exynos5_set_lcd_clk();
1265}
1266
1267void set_mipi_clk(void)
1268{
1269        if (cpu_is_exynos4())
1270                exynos4_set_mipi_clk();
1271}
1272
1273int set_spi_clk(int periph_id, unsigned int rate)
1274{
1275        if (cpu_is_exynos5())
1276                return exynos5_set_spi_clk(periph_id, rate);
1277        else
1278                return 0;
1279}
1280
1281int set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq)
1282{
1283
1284        if (cpu_is_exynos5())
1285                return exynos5_set_i2s_clk_prescaler(src_frq, dst_frq);
1286        else
1287                return 0;
1288}
1289
1290void set_i2s_clk_source(void)
1291{
1292        if (cpu_is_exynos5())
1293                exynos5_set_i2s_clk_source();
1294}
1295
1296int set_epll_clk(unsigned long rate)
1297{
1298        if (cpu_is_exynos5())
1299                return exynos5_set_epll_clk(rate);
1300        else
1301                return 0;
1302}
1303