uboot/arch/arm/cpu/armv7/s5pc1xx/clock.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2009 Samsung Electronics
   3 * Minkyu Kang <mk7.kang@samsung.com>
   4 * Heungjun Kim <riverful.kim@samsung.com>
   5 *
   6 * SPDX-License-Identifier:     GPL-2.0+
   7 */
   8
   9#include <common.h>
  10#include <asm/io.h>
  11#include <asm/arch/clock.h>
  12#include <asm/arch/clk.h>
  13
  14#define CLK_M   0
  15#define CLK_D   1
  16#define CLK_P   2
  17
  18#ifndef CONFIG_SYS_CLK_FREQ_C100
  19#define CONFIG_SYS_CLK_FREQ_C100        12000000
  20#endif
  21#ifndef CONFIG_SYS_CLK_FREQ_C110
  22#define CONFIG_SYS_CLK_FREQ_C110        24000000
  23#endif
  24
  25/* s5pc110: return pll clock frequency */
  26static unsigned long s5pc100_get_pll_clk(int pllreg)
  27{
  28        struct s5pc100_clock *clk =
  29                (struct s5pc100_clock *)samsung_get_base_clock();
  30        unsigned long r, m, p, s, mask, fout;
  31        unsigned int freq;
  32
  33        switch (pllreg) {
  34        case APLL:
  35                r = readl(&clk->apll_con);
  36                break;
  37        case MPLL:
  38                r = readl(&clk->mpll_con);
  39                break;
  40        case EPLL:
  41                r = readl(&clk->epll_con);
  42                break;
  43        case HPLL:
  44                r = readl(&clk->hpll_con);
  45                break;
  46        default:
  47                printf("Unsupported PLL (%d)\n", pllreg);
  48                return 0;
  49        }
  50
  51        /*
  52         * APLL_CON: MIDV [25:16]
  53         * MPLL_CON: MIDV [23:16]
  54         * EPLL_CON: MIDV [23:16]
  55         * HPLL_CON: MIDV [23:16]
  56         */
  57        if (pllreg == APLL)
  58                mask = 0x3ff;
  59        else
  60                mask = 0x0ff;
  61
  62        m = (r >> 16) & mask;
  63
  64        /* PDIV [13:8] */
  65        p = (r >> 8) & 0x3f;
  66        /* SDIV [2:0] */
  67        s = r & 0x7;
  68
  69        /* FOUT = MDIV * FIN / (PDIV * 2^SDIV) */
  70        freq = CONFIG_SYS_CLK_FREQ_C100;
  71        fout = m * (freq / (p * (1 << s)));
  72
  73        return fout;
  74}
  75
  76/* s5pc100: return pll clock frequency */
  77static unsigned long s5pc110_get_pll_clk(int pllreg)
  78{
  79        struct s5pc110_clock *clk =
  80                (struct s5pc110_clock *)samsung_get_base_clock();
  81        unsigned long r, m, p, s, mask, fout;
  82        unsigned int freq;
  83
  84        switch (pllreg) {
  85        case APLL:
  86                r = readl(&clk->apll_con);
  87                break;
  88        case MPLL:
  89                r = readl(&clk->mpll_con);
  90                break;
  91        case EPLL:
  92                r = readl(&clk->epll_con);
  93                break;
  94        case VPLL:
  95                r = readl(&clk->vpll_con);
  96                break;
  97        default:
  98                printf("Unsupported PLL (%d)\n", pllreg);
  99                return 0;
 100        }
 101
 102        /*
 103         * APLL_CON: MIDV [25:16]
 104         * MPLL_CON: MIDV [25:16]
 105         * EPLL_CON: MIDV [24:16]
 106         * VPLL_CON: MIDV [24:16]
 107         */
 108        if (pllreg == APLL || pllreg == MPLL)
 109                mask = 0x3ff;
 110        else
 111                mask = 0x1ff;
 112
 113        m = (r >> 16) & mask;
 114
 115        /* PDIV [13:8] */
 116        p = (r >> 8) & 0x3f;
 117        /* SDIV [2:0] */
 118        s = r & 0x7;
 119
 120        freq = CONFIG_SYS_CLK_FREQ_C110;
 121        if (pllreg == APLL) {
 122                if (s < 1)
 123                        s = 1;
 124                /* FOUT = MDIV * FIN / (PDIV * 2^(SDIV - 1)) */
 125                fout = m * (freq / (p * (1 << (s - 1))));
 126        } else
 127                /* FOUT = MDIV * FIN / (PDIV * 2^SDIV) */
 128                fout = m * (freq / (p * (1 << s)));
 129
 130        return fout;
 131}
 132
 133/* s5pc110: return ARM clock frequency */
 134static unsigned long s5pc110_get_arm_clk(void)
 135{
 136        struct s5pc110_clock *clk =
 137                (struct s5pc110_clock *)samsung_get_base_clock();
 138        unsigned long div;
 139        unsigned long dout_apll, armclk;
 140        unsigned int apll_ratio;
 141
 142        div = readl(&clk->div0);
 143
 144        /* APLL_RATIO: [2:0] */
 145        apll_ratio = div & 0x7;
 146
 147        dout_apll = get_pll_clk(APLL) / (apll_ratio + 1);
 148        armclk = dout_apll;
 149
 150        return armclk;
 151}
 152
 153/* s5pc100: return ARM clock frequency */
 154static unsigned long s5pc100_get_arm_clk(void)
 155{
 156        struct s5pc100_clock *clk =
 157                (struct s5pc100_clock *)samsung_get_base_clock();
 158        unsigned long div;
 159        unsigned long dout_apll, armclk;
 160        unsigned int apll_ratio, arm_ratio;
 161
 162        div = readl(&clk->div0);
 163
 164        /* ARM_RATIO: [6:4] */
 165        arm_ratio = (div >> 4) & 0x7;
 166        /* APLL_RATIO: [0] */
 167        apll_ratio = div & 0x1;
 168
 169        dout_apll = get_pll_clk(APLL) / (apll_ratio + 1);
 170        armclk = dout_apll / (arm_ratio + 1);
 171
 172        return armclk;
 173}
 174
 175/* s5pc100: return HCLKD0 frequency */
 176static unsigned long get_hclk(void)
 177{
 178        struct s5pc100_clock *clk =
 179                (struct s5pc100_clock *)samsung_get_base_clock();
 180        unsigned long hclkd0;
 181        uint div, d0_bus_ratio;
 182
 183        div = readl(&clk->div0);
 184        /* D0_BUS_RATIO: [10:8] */
 185        d0_bus_ratio = (div >> 8) & 0x7;
 186
 187        hclkd0 = get_arm_clk() / (d0_bus_ratio + 1);
 188
 189        return hclkd0;
 190}
 191
 192/* s5pc100: return PCLKD1 frequency */
 193static unsigned long get_pclkd1(void)
 194{
 195        struct s5pc100_clock *clk =
 196                (struct s5pc100_clock *)samsung_get_base_clock();
 197        unsigned long d1_bus, pclkd1;
 198        uint div, d1_bus_ratio, pclkd1_ratio;
 199
 200        div = readl(&clk->div0);
 201        /* D1_BUS_RATIO: [14:12] */
 202        d1_bus_ratio = (div >> 12) & 0x7;
 203        /* PCLKD1_RATIO: [18:16] */
 204        pclkd1_ratio = (div >> 16) & 0x7;
 205
 206        /* ASYNC Mode */
 207        d1_bus = get_pll_clk(MPLL) / (d1_bus_ratio + 1);
 208        pclkd1 = d1_bus / (pclkd1_ratio + 1);
 209
 210        return pclkd1;
 211}
 212
 213/* s5pc110: return HCLKs frequency */
 214static unsigned long get_hclk_sys(int dom)
 215{
 216        struct s5pc110_clock *clk =
 217                (struct s5pc110_clock *)samsung_get_base_clock();
 218        unsigned long hclk;
 219        unsigned int div;
 220        unsigned int offset;
 221        unsigned int hclk_sys_ratio;
 222
 223        if (dom == CLK_M)
 224                return get_hclk();
 225
 226        div = readl(&clk->div0);
 227
 228        /*
 229         * HCLK_MSYS_RATIO: [10:8]
 230         * HCLK_DSYS_RATIO: [19:16]
 231         * HCLK_PSYS_RATIO: [27:24]
 232         */
 233        offset = 8 + (dom << 0x3);
 234
 235        hclk_sys_ratio = (div >> offset) & 0xf;
 236
 237        hclk = get_pll_clk(MPLL) / (hclk_sys_ratio + 1);
 238
 239        return hclk;
 240}
 241
 242/* s5pc110: return PCLKs frequency */
 243static unsigned long get_pclk_sys(int dom)
 244{
 245        struct s5pc110_clock *clk =
 246                (struct s5pc110_clock *)samsung_get_base_clock();
 247        unsigned long pclk;
 248        unsigned int div;
 249        unsigned int offset;
 250        unsigned int pclk_sys_ratio;
 251
 252        div = readl(&clk->div0);
 253
 254        /*
 255         * PCLK_MSYS_RATIO: [14:12]
 256         * PCLK_DSYS_RATIO: [22:20]
 257         * PCLK_PSYS_RATIO: [30:28]
 258         */
 259        offset = 12 + (dom << 0x3);
 260
 261        pclk_sys_ratio = (div >> offset) & 0x7;
 262
 263        pclk = get_hclk_sys(dom) / (pclk_sys_ratio + 1);
 264
 265        return pclk;
 266}
 267
 268/* s5pc110: return peripheral clock frequency */
 269static unsigned long s5pc110_get_pclk(void)
 270{
 271        return get_pclk_sys(CLK_P);
 272}
 273
 274/* s5pc100: return peripheral clock frequency */
 275static unsigned long s5pc100_get_pclk(void)
 276{
 277        return get_pclkd1();
 278}
 279
 280/* s5pc1xx: return uart clock frequency */
 281static unsigned long s5pc1xx_get_uart_clk(int dev_index)
 282{
 283        if (cpu_is_s5pc110())
 284                return s5pc110_get_pclk();
 285        else
 286                return s5pc100_get_pclk();
 287}
 288
 289/* s5pc1xx: return pwm clock frequency */
 290static unsigned long s5pc1xx_get_pwm_clk(void)
 291{
 292        if (cpu_is_s5pc110())
 293                return s5pc110_get_pclk();
 294        else
 295                return s5pc100_get_pclk();
 296}
 297
 298unsigned long get_pll_clk(int pllreg)
 299{
 300        if (cpu_is_s5pc110())
 301                return s5pc110_get_pll_clk(pllreg);
 302        else
 303                return s5pc100_get_pll_clk(pllreg);
 304}
 305
 306unsigned long get_arm_clk(void)
 307{
 308        if (cpu_is_s5pc110())
 309                return s5pc110_get_arm_clk();
 310        else
 311                return s5pc100_get_arm_clk();
 312}
 313
 314unsigned long get_pwm_clk(void)
 315{
 316        return s5pc1xx_get_pwm_clk();
 317}
 318
 319unsigned long get_uart_clk(int dev_index)
 320{
 321        return s5pc1xx_get_uart_clk(dev_index);
 322}
 323
 324void set_mmc_clk(int dev_index, unsigned int div)
 325{
 326        /* Do NOTHING */
 327}
 328