uboot/drivers/clk/rockchip/clk_rk3328.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2017 Rockchip Electronics Co., Ltd
   3 *
   4 * SPDX-License-Identifier:     GPL-2.0
   5 */
   6
   7#include <common.h>
   8#include <bitfield.h>
   9#include <clk-uclass.h>
  10#include <dm.h>
  11#include <errno.h>
  12#include <syscon.h>
  13#include <asm/arch/clock.h>
  14#include <asm/arch/cru_rk3328.h>
  15#include <asm/arch/hardware.h>
  16#include <asm/io.h>
  17#include <dm/lists.h>
  18#include <dt-bindings/clock/rk3328-cru.h>
  19
  20DECLARE_GLOBAL_DATA_PTR;
  21
  22struct pll_div {
  23        u32 refdiv;
  24        u32 fbdiv;
  25        u32 postdiv1;
  26        u32 postdiv2;
  27        u32 frac;
  28};
  29
  30#define RATE_TO_DIV(input_rate, output_rate) \
  31        ((input_rate) / (output_rate) - 1);
  32#define DIV_TO_RATE(input_rate, div)    ((input_rate) / ((div) + 1))
  33
  34#define PLL_DIVISORS(hz, _refdiv, _postdiv1, _postdiv2) {\
  35        .refdiv = _refdiv,\
  36        .fbdiv = (u32)((u64)hz * _refdiv * _postdiv1 * _postdiv2 / OSC_HZ),\
  37        .postdiv1 = _postdiv1, .postdiv2 = _postdiv2};
  38
  39static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 1, 4, 1);
  40static const struct pll_div cpll_init_cfg = PLL_DIVISORS(CPLL_HZ, 2, 2, 1);
  41
  42static const struct pll_div apll_816_cfg = PLL_DIVISORS(816 * MHz, 1, 2, 1);
  43static const struct pll_div apll_600_cfg = PLL_DIVISORS(600 * MHz, 1, 3, 1);
  44
  45static const struct pll_div *apll_cfgs[] = {
  46        [APLL_816_MHZ] = &apll_816_cfg,
  47        [APLL_600_MHZ] = &apll_600_cfg,
  48};
  49
  50enum {
  51        /* PLL_CON0 */
  52        PLL_POSTDIV1_SHIFT              = 12,
  53        PLL_POSTDIV1_MASK               = 0x7 << PLL_POSTDIV1_SHIFT,
  54        PLL_FBDIV_SHIFT                 = 0,
  55        PLL_FBDIV_MASK                  = 0xfff,
  56
  57        /* PLL_CON1 */
  58        PLL_DSMPD_SHIFT                 = 12,
  59        PLL_DSMPD_MASK                  = 1 << PLL_DSMPD_SHIFT,
  60        PLL_INTEGER_MODE                = 1,
  61        PLL_LOCK_STATUS_SHIFT           = 10,
  62        PLL_LOCK_STATUS_MASK            = 1 << PLL_LOCK_STATUS_SHIFT,
  63        PLL_POSTDIV2_SHIFT              = 6,
  64        PLL_POSTDIV2_MASK               = 0x7 << PLL_POSTDIV2_SHIFT,
  65        PLL_REFDIV_SHIFT                = 0,
  66        PLL_REFDIV_MASK                 = 0x3f,
  67
  68        /* PLL_CON2 */
  69        PLL_FRACDIV_SHIFT               = 0,
  70        PLL_FRACDIV_MASK                = 0xffffff,
  71
  72        /* MODE_CON */
  73        APLL_MODE_SHIFT                 = 0,
  74        NPLL_MODE_SHIFT                 = 1,
  75        DPLL_MODE_SHIFT                 = 4,
  76        CPLL_MODE_SHIFT                 = 8,
  77        GPLL_MODE_SHIFT                 = 12,
  78        PLL_MODE_SLOW                   = 0,
  79        PLL_MODE_NORM,
  80
  81        /* CLKSEL_CON0 */
  82        CLK_CORE_PLL_SEL_APLL           = 0,
  83        CLK_CORE_PLL_SEL_GPLL,
  84        CLK_CORE_PLL_SEL_DPLL,
  85        CLK_CORE_PLL_SEL_NPLL,
  86        CLK_CORE_PLL_SEL_SHIFT          = 6,
  87        CLK_CORE_PLL_SEL_MASK           = 3 << CLK_CORE_PLL_SEL_SHIFT,
  88        CLK_CORE_DIV_SHIFT              = 0,
  89        CLK_CORE_DIV_MASK               = 0x1f,
  90
  91        /* CLKSEL_CON1 */
  92        ACLKM_CORE_DIV_SHIFT            = 4,
  93        ACLKM_CORE_DIV_MASK             = 0x7 << ACLKM_CORE_DIV_SHIFT,
  94        PCLK_DBG_DIV_SHIFT              = 0,
  95        PCLK_DBG_DIV_MASK               = 0xF << PCLK_DBG_DIV_SHIFT,
  96
  97        /* CLKSEL_CON28 */
  98        ACLK_PERIHP_PLL_SEL_CPLL        = 0,
  99        ACLK_PERIHP_PLL_SEL_GPLL,
 100        ACLK_PERIHP_PLL_SEL_HDMIPHY,
 101        ACLK_PERIHP_PLL_SEL_SHIFT       = 6,
 102        ACLK_PERIHP_PLL_SEL_MASK        = 3 << ACLK_PERIHP_PLL_SEL_SHIFT,
 103        ACLK_PERIHP_DIV_CON_SHIFT       = 0,
 104        ACLK_PERIHP_DIV_CON_MASK        = 0x1f,
 105
 106        /* CLKSEL_CON29 */
 107        PCLK_PERIHP_DIV_CON_SHIFT       = 4,
 108        PCLK_PERIHP_DIV_CON_MASK        = 0x7 << PCLK_PERIHP_DIV_CON_SHIFT,
 109        HCLK_PERIHP_DIV_CON_SHIFT       = 0,
 110        HCLK_PERIHP_DIV_CON_MASK        = 3 << HCLK_PERIHP_DIV_CON_SHIFT,
 111
 112        /* CLKSEL_CON22 */
 113        CLK_TSADC_DIV_CON_SHIFT         = 0,
 114        CLK_TSADC_DIV_CON_MASK          = 0x3ff,
 115
 116        /* CLKSEL_CON23 */
 117        CLK_SARADC_DIV_CON_SHIFT        = 0,
 118        CLK_SARADC_DIV_CON_MASK         = GENMASK(9, 0),
 119        CLK_SARADC_DIV_CON_WIDTH        = 10,
 120
 121        /* CLKSEL_CON24 */
 122        CLK_PWM_PLL_SEL_CPLL            = 0,
 123        CLK_PWM_PLL_SEL_GPLL,
 124        CLK_PWM_PLL_SEL_SHIFT           = 15,
 125        CLK_PWM_PLL_SEL_MASK            = 1 << CLK_PWM_PLL_SEL_SHIFT,
 126        CLK_PWM_DIV_CON_SHIFT           = 8,
 127        CLK_PWM_DIV_CON_MASK            = 0x7f << CLK_PWM_DIV_CON_SHIFT,
 128
 129        CLK_SPI_PLL_SEL_CPLL            = 0,
 130        CLK_SPI_PLL_SEL_GPLL,
 131        CLK_SPI_PLL_SEL_SHIFT           = 7,
 132        CLK_SPI_PLL_SEL_MASK            = 1 << CLK_SPI_PLL_SEL_SHIFT,
 133        CLK_SPI_DIV_CON_SHIFT           = 0,
 134        CLK_SPI_DIV_CON_MASK            = 0x7f << CLK_SPI_DIV_CON_SHIFT,
 135
 136        /* CLKSEL_CON30 */
 137        CLK_SDMMC_PLL_SEL_CPLL          = 0,
 138        CLK_SDMMC_PLL_SEL_GPLL,
 139        CLK_SDMMC_PLL_SEL_24M,
 140        CLK_SDMMC_PLL_SEL_USBPHY,
 141        CLK_SDMMC_PLL_SHIFT             = 8,
 142        CLK_SDMMC_PLL_MASK              = 0x3 << CLK_SDMMC_PLL_SHIFT,
 143        CLK_SDMMC_DIV_CON_SHIFT          = 0,
 144        CLK_SDMMC_DIV_CON_MASK           = 0xff << CLK_SDMMC_DIV_CON_SHIFT,
 145
 146        /* CLKSEL_CON32 */
 147        CLK_EMMC_PLL_SEL_CPLL           = 0,
 148        CLK_EMMC_PLL_SEL_GPLL,
 149        CLK_EMMC_PLL_SEL_24M,
 150        CLK_EMMC_PLL_SEL_USBPHY,
 151        CLK_EMMC_PLL_SHIFT              = 8,
 152        CLK_EMMC_PLL_MASK               = 0x3 << CLK_EMMC_PLL_SHIFT,
 153        CLK_EMMC_DIV_CON_SHIFT          = 0,
 154        CLK_EMMC_DIV_CON_MASK           = 0xff << CLK_EMMC_DIV_CON_SHIFT,
 155
 156        /* CLKSEL_CON34 */
 157        CLK_I2C_PLL_SEL_CPLL            = 0,
 158        CLK_I2C_PLL_SEL_GPLL,
 159        CLK_I2C_DIV_CON_MASK            = 0x7f,
 160        CLK_I2C_PLL_SEL_MASK            = 1,
 161        CLK_I2C1_PLL_SEL_SHIFT          = 15,
 162        CLK_I2C1_DIV_CON_SHIFT          = 8,
 163        CLK_I2C0_PLL_SEL_SHIFT          = 7,
 164        CLK_I2C0_DIV_CON_SHIFT          = 0,
 165
 166        /* CLKSEL_CON35 */
 167        CLK_I2C3_PLL_SEL_SHIFT          = 15,
 168        CLK_I2C3_DIV_CON_SHIFT          = 8,
 169        CLK_I2C2_PLL_SEL_SHIFT          = 7,
 170        CLK_I2C2_DIV_CON_SHIFT          = 0,
 171};
 172
 173#define VCO_MAX_KHZ     (3200 * (MHz / KHz))
 174#define VCO_MIN_KHZ     (800 * (MHz / KHz))
 175#define OUTPUT_MAX_KHZ  (3200 * (MHz / KHz))
 176#define OUTPUT_MIN_KHZ  (16 * (MHz / KHz))
 177
 178/*
 179 *  the div restructions of pll in integer mode, these are defined in
 180 *  * CRU_*PLL_CON0 or PMUCRU_*PLL_CON0
 181 */
 182#define PLL_DIV_MIN     16
 183#define PLL_DIV_MAX     3200
 184
 185/*
 186 * How to calculate the PLL(from TRM V0.3 Part 1 Page 63):
 187 * Formulas also embedded within the Fractional PLL Verilog model:
 188 * If DSMPD = 1 (DSM is disabled, "integer mode")
 189 * FOUTVCO = FREF / REFDIV * FBDIV
 190 * FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2
 191 * Where:
 192 * FOUTVCO = Fractional PLL non-divided output frequency
 193 * FOUTPOSTDIV = Fractional PLL divided output frequency
 194 *               (output of second post divider)
 195 * FREF = Fractional PLL input reference frequency, (the OSC_HZ 24MHz input)
 196 * REFDIV = Fractional PLL input reference clock divider
 197 * FBDIV = Integer value programmed into feedback divide
 198 *
 199 */
 200static void rkclk_set_pll(struct rk3328_cru *cru, enum rk_clk_id clk_id,
 201                        const struct pll_div *div)
 202{
 203        u32 *pll_con;
 204        u32 mode_shift, mode_mask;
 205
 206        pll_con = NULL;
 207        mode_shift = 0;
 208        switch (clk_id) {
 209        case CLK_ARM:
 210                pll_con = cru->apll_con;
 211                mode_shift = APLL_MODE_SHIFT;
 212                break;
 213        case CLK_DDR:
 214                pll_con = cru->dpll_con;
 215                mode_shift = DPLL_MODE_SHIFT;
 216                break;
 217        case CLK_CODEC:
 218                pll_con = cru->cpll_con;
 219                mode_shift = CPLL_MODE_SHIFT;
 220                break;
 221        case CLK_GENERAL:
 222                pll_con = cru->gpll_con;
 223                mode_shift = GPLL_MODE_SHIFT;
 224                break;
 225        case CLK_NEW:
 226                pll_con = cru->npll_con;
 227                mode_shift = NPLL_MODE_SHIFT;
 228                break;
 229        default:
 230                break;
 231        }
 232        mode_mask = 1 << mode_shift;
 233
 234        /* All 8 PLLs have same VCO and output frequency range restrictions. */
 235        u32 vco_khz = OSC_HZ / 1000 * div->fbdiv / div->refdiv;
 236        u32 output_khz = vco_khz / div->postdiv1 / div->postdiv2;
 237
 238        debug("PLL at %p: fbdiv=%d, refdiv=%d, postdiv1=%d, \
 239              postdiv2=%d, vco=%u khz, output=%u khz\n",
 240              pll_con, div->fbdiv, div->refdiv, div->postdiv1,
 241              div->postdiv2, vco_khz, output_khz);
 242        assert(vco_khz >= VCO_MIN_KHZ && vco_khz <= VCO_MAX_KHZ &&
 243               output_khz >= OUTPUT_MIN_KHZ && output_khz <= OUTPUT_MAX_KHZ &&
 244               div->fbdiv >= PLL_DIV_MIN && div->fbdiv <= PLL_DIV_MAX);
 245
 246        /*
 247         * When power on or changing PLL setting,
 248         * we must force PLL into slow mode to ensure output stable clock.
 249         */
 250        rk_clrsetreg(&cru->mode_con, mode_mask, PLL_MODE_SLOW << mode_shift);
 251
 252        /* use integer mode */
 253        rk_clrsetreg(&pll_con[1], PLL_DSMPD_MASK,
 254                     PLL_INTEGER_MODE << PLL_DSMPD_SHIFT);
 255
 256        rk_clrsetreg(&pll_con[0],
 257                     PLL_FBDIV_MASK | PLL_POSTDIV1_MASK,
 258                     (div->fbdiv << PLL_FBDIV_SHIFT) |
 259                     (div->postdiv1 << PLL_POSTDIV1_SHIFT));
 260        rk_clrsetreg(&pll_con[1],
 261                     PLL_POSTDIV2_MASK | PLL_REFDIV_MASK,
 262                     (div->postdiv2 << PLL_POSTDIV2_SHIFT) |
 263                     (div->refdiv << PLL_REFDIV_SHIFT));
 264
 265        /* waiting for pll lock */
 266        while (!(readl(&pll_con[1]) & (1 << PLL_LOCK_STATUS_SHIFT)))
 267                udelay(1);
 268
 269        /* pll enter normal mode */
 270        rk_clrsetreg(&cru->mode_con, mode_mask, PLL_MODE_NORM << mode_shift);
 271}
 272
 273static void rkclk_init(struct rk3328_cru *cru)
 274{
 275        u32 aclk_div;
 276        u32 hclk_div;
 277        u32 pclk_div;
 278
 279        /* configure gpll cpll */
 280        rkclk_set_pll(cru, CLK_GENERAL, &gpll_init_cfg);
 281        rkclk_set_pll(cru, CLK_CODEC, &cpll_init_cfg);
 282
 283        /* configure perihp aclk, hclk, pclk */
 284        aclk_div = GPLL_HZ / PERIHP_ACLK_HZ - 1;
 285        hclk_div = PERIHP_ACLK_HZ / PERIHP_HCLK_HZ - 1;
 286        pclk_div = PERIHP_ACLK_HZ / PERIHP_PCLK_HZ - 1;
 287
 288        rk_clrsetreg(&cru->clksel_con[28],
 289                     ACLK_PERIHP_PLL_SEL_MASK | ACLK_PERIHP_DIV_CON_MASK,
 290                     ACLK_PERIHP_PLL_SEL_GPLL << ACLK_PERIHP_PLL_SEL_SHIFT |
 291                     aclk_div << ACLK_PERIHP_DIV_CON_SHIFT);
 292        rk_clrsetreg(&cru->clksel_con[29],
 293                     PCLK_PERIHP_DIV_CON_MASK | HCLK_PERIHP_DIV_CON_MASK,
 294                     pclk_div << PCLK_PERIHP_DIV_CON_SHIFT |
 295                     hclk_div << HCLK_PERIHP_DIV_CON_SHIFT);
 296}
 297
 298void rk3328_configure_cpu(struct rk3328_cru *cru,
 299                          enum apll_frequencies apll_freq)
 300{
 301        u32 clk_core_div;
 302        u32 aclkm_div;
 303        u32 pclk_dbg_div;
 304
 305        rkclk_set_pll(cru, CLK_ARM, apll_cfgs[apll_freq]);
 306
 307        clk_core_div = APLL_HZ / CLK_CORE_HZ - 1;
 308        aclkm_div = APLL_HZ / ACLKM_CORE_HZ / (clk_core_div + 1) - 1;
 309        pclk_dbg_div = APLL_HZ / PCLK_DBG_HZ / (clk_core_div + 1) - 1;
 310
 311        rk_clrsetreg(&cru->clksel_con[0],
 312                     CLK_CORE_PLL_SEL_MASK | CLK_CORE_DIV_MASK,
 313                     CLK_CORE_PLL_SEL_APLL << CLK_CORE_PLL_SEL_SHIFT |
 314                     clk_core_div << CLK_CORE_DIV_SHIFT);
 315
 316        rk_clrsetreg(&cru->clksel_con[1],
 317                     PCLK_DBG_DIV_MASK | ACLKM_CORE_DIV_MASK,
 318                     pclk_dbg_div << PCLK_DBG_DIV_SHIFT |
 319                     aclkm_div << ACLKM_CORE_DIV_SHIFT);
 320}
 321
 322
 323static ulong rk3328_i2c_get_clk(struct rk3328_cru *cru, ulong clk_id)
 324{
 325        u32 div, con;
 326
 327        switch (clk_id) {
 328        case SCLK_I2C0:
 329                con = readl(&cru->clksel_con[34]);
 330                div = con >> CLK_I2C0_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK;
 331                break;
 332        case SCLK_I2C1:
 333                con = readl(&cru->clksel_con[34]);
 334                div = con >> CLK_I2C1_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK;
 335                break;
 336        case SCLK_I2C2:
 337                con = readl(&cru->clksel_con[35]);
 338                div = con >> CLK_I2C2_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK;
 339                break;
 340        case SCLK_I2C3:
 341                con = readl(&cru->clksel_con[35]);
 342                div = con >> CLK_I2C3_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK;
 343                break;
 344        default:
 345                printf("do not support this i2c bus\n");
 346                return -EINVAL;
 347        }
 348
 349        return DIV_TO_RATE(GPLL_HZ, div);
 350}
 351
 352static ulong rk3328_i2c_set_clk(struct rk3328_cru *cru, ulong clk_id, uint hz)
 353{
 354        int src_clk_div;
 355
 356        src_clk_div = GPLL_HZ / hz;
 357        assert(src_clk_div - 1 < 127);
 358
 359        switch (clk_id) {
 360        case SCLK_I2C0:
 361                rk_clrsetreg(&cru->clksel_con[34],
 362                             CLK_I2C_DIV_CON_MASK << CLK_I2C0_DIV_CON_SHIFT |
 363                             CLK_I2C_PLL_SEL_MASK << CLK_I2C0_PLL_SEL_SHIFT,
 364                             (src_clk_div - 1) << CLK_I2C0_DIV_CON_SHIFT |
 365                             CLK_I2C_PLL_SEL_GPLL << CLK_I2C0_PLL_SEL_SHIFT);
 366                break;
 367        case SCLK_I2C1:
 368                rk_clrsetreg(&cru->clksel_con[34],
 369                             CLK_I2C_DIV_CON_MASK << CLK_I2C1_DIV_CON_SHIFT |
 370                             CLK_I2C_PLL_SEL_MASK << CLK_I2C1_PLL_SEL_SHIFT,
 371                             (src_clk_div - 1) << CLK_I2C1_DIV_CON_SHIFT |
 372                             CLK_I2C_PLL_SEL_GPLL << CLK_I2C1_PLL_SEL_SHIFT);
 373                break;
 374        case SCLK_I2C2:
 375                rk_clrsetreg(&cru->clksel_con[35],
 376                             CLK_I2C_DIV_CON_MASK << CLK_I2C2_DIV_CON_SHIFT |
 377                             CLK_I2C_PLL_SEL_MASK << CLK_I2C2_PLL_SEL_SHIFT,
 378                             (src_clk_div - 1) << CLK_I2C2_DIV_CON_SHIFT |
 379                             CLK_I2C_PLL_SEL_GPLL << CLK_I2C2_PLL_SEL_SHIFT);
 380                break;
 381        case SCLK_I2C3:
 382                rk_clrsetreg(&cru->clksel_con[35],
 383                             CLK_I2C_DIV_CON_MASK << CLK_I2C3_DIV_CON_SHIFT |
 384                             CLK_I2C_PLL_SEL_MASK << CLK_I2C3_PLL_SEL_SHIFT,
 385                             (src_clk_div - 1) << CLK_I2C3_DIV_CON_SHIFT |
 386                             CLK_I2C_PLL_SEL_GPLL << CLK_I2C3_PLL_SEL_SHIFT);
 387                break;
 388        default:
 389                printf("do not support this i2c bus\n");
 390                return -EINVAL;
 391        }
 392
 393        return DIV_TO_RATE(GPLL_HZ, src_clk_div);
 394}
 395
 396static ulong rk3328_mmc_get_clk(struct rk3328_cru *cru, uint clk_id)
 397{
 398        u32 div, con, con_id;
 399
 400        switch (clk_id) {
 401        case HCLK_SDMMC:
 402        case SCLK_SDMMC:
 403                con_id = 30;
 404                break;
 405        case HCLK_EMMC:
 406        case SCLK_EMMC:
 407                con_id = 32;
 408                break;
 409        default:
 410                return -EINVAL;
 411        }
 412        con = readl(&cru->clksel_con[con_id]);
 413        div = (con & CLK_EMMC_DIV_CON_MASK) >> CLK_EMMC_DIV_CON_SHIFT;
 414
 415        if ((con & CLK_EMMC_PLL_MASK) >> CLK_EMMC_PLL_SHIFT
 416            == CLK_EMMC_PLL_SEL_24M)
 417                return DIV_TO_RATE(OSC_HZ, div) / 2;
 418        else
 419                return DIV_TO_RATE(GPLL_HZ, div) / 2;
 420}
 421
 422static ulong rk3328_mmc_set_clk(struct rk3328_cru *cru,
 423                                ulong clk_id, ulong set_rate)
 424{
 425        int src_clk_div;
 426        u32 con_id;
 427
 428        switch (clk_id) {
 429        case HCLK_SDMMC:
 430        case SCLK_SDMMC:
 431                con_id = 30;
 432                break;
 433        case HCLK_EMMC:
 434        case SCLK_EMMC:
 435                con_id = 32;
 436                break;
 437        default:
 438                return -EINVAL;
 439        }
 440        /* Select clk_sdmmc/emmc source from GPLL by default */
 441        /* mmc clock defaulg div 2 internal, need provide double in cru */
 442        src_clk_div = DIV_ROUND_UP(GPLL_HZ / 2, set_rate);
 443
 444        if (src_clk_div > 127) {
 445                /* use 24MHz source for 400KHz clock */
 446                src_clk_div = DIV_ROUND_UP(OSC_HZ / 2, set_rate);
 447                rk_clrsetreg(&cru->clksel_con[con_id],
 448                             CLK_EMMC_PLL_MASK | CLK_EMMC_DIV_CON_MASK,
 449                             CLK_EMMC_PLL_SEL_24M << CLK_EMMC_PLL_SHIFT |
 450                             (src_clk_div - 1) << CLK_EMMC_DIV_CON_SHIFT);
 451        } else {
 452                rk_clrsetreg(&cru->clksel_con[con_id],
 453                             CLK_EMMC_PLL_MASK | CLK_EMMC_DIV_CON_MASK,
 454                             CLK_EMMC_PLL_SEL_GPLL << CLK_EMMC_PLL_SHIFT |
 455                             (src_clk_div - 1) << CLK_EMMC_DIV_CON_SHIFT);
 456        }
 457
 458        return rk3328_mmc_get_clk(cru, clk_id);
 459}
 460
 461static ulong rk3328_pwm_get_clk(struct rk3328_cru *cru)
 462{
 463        u32 div, con;
 464
 465        con = readl(&cru->clksel_con[24]);
 466        div = (con & CLK_PWM_DIV_CON_MASK) >> CLK_PWM_DIV_CON_SHIFT;
 467
 468        return DIV_TO_RATE(GPLL_HZ, div);
 469}
 470
 471static ulong rk3328_pwm_set_clk(struct rk3328_cru *cru, uint hz)
 472{
 473        u32 div = GPLL_HZ / hz;
 474
 475        rk_clrsetreg(&cru->clksel_con[24],
 476                     CLK_PWM_PLL_SEL_MASK | CLK_PWM_DIV_CON_MASK,
 477                     CLK_PWM_PLL_SEL_GPLL << CLK_PWM_PLL_SEL_SHIFT |
 478                     (div - 1) << CLK_PWM_DIV_CON_SHIFT);
 479
 480        return DIV_TO_RATE(GPLL_HZ, div);
 481}
 482
 483static ulong rk3328_saradc_get_clk(struct rk3328_cru *cru)
 484{
 485        u32 div, val;
 486
 487        val = readl(&cru->clksel_con[23]);
 488        div = bitfield_extract(val, CLK_SARADC_DIV_CON_SHIFT,
 489                               CLK_SARADC_DIV_CON_WIDTH);
 490
 491        return DIV_TO_RATE(OSC_HZ, div);
 492}
 493
 494static ulong rk3328_saradc_set_clk(struct rk3328_cru *cru, uint hz)
 495{
 496        int src_clk_div;
 497
 498        src_clk_div = DIV_ROUND_UP(OSC_HZ, hz) - 1;
 499        assert(src_clk_div < 128);
 500
 501        rk_clrsetreg(&cru->clksel_con[23],
 502                     CLK_SARADC_DIV_CON_MASK,
 503                     src_clk_div << CLK_SARADC_DIV_CON_SHIFT);
 504
 505        return rk3328_saradc_get_clk(cru);
 506}
 507
 508static ulong rk3328_clk_get_rate(struct clk *clk)
 509{
 510        struct rk3328_clk_priv *priv = dev_get_priv(clk->dev);
 511        ulong rate = 0;
 512
 513        switch (clk->id) {
 514        case 0 ... 29:
 515                return 0;
 516        case HCLK_SDMMC:
 517        case HCLK_EMMC:
 518        case SCLK_SDMMC:
 519        case SCLK_EMMC:
 520                rate = rk3328_mmc_get_clk(priv->cru, clk->id);
 521                break;
 522        case SCLK_I2C0:
 523        case SCLK_I2C1:
 524        case SCLK_I2C2:
 525        case SCLK_I2C3:
 526                rate = rk3328_i2c_get_clk(priv->cru, clk->id);
 527                break;
 528        case SCLK_PWM:
 529                rate = rk3328_pwm_get_clk(priv->cru);
 530                break;
 531        case SCLK_SARADC:
 532                rate = rk3328_saradc_get_clk(priv->cru);
 533                break;
 534        default:
 535                return -ENOENT;
 536        }
 537
 538        return rate;
 539}
 540
 541static ulong rk3328_clk_set_rate(struct clk *clk, ulong rate)
 542{
 543        struct rk3328_clk_priv *priv = dev_get_priv(clk->dev);
 544        ulong ret = 0;
 545
 546        switch (clk->id) {
 547        case 0 ... 29:
 548                return 0;
 549        case HCLK_SDMMC:
 550        case HCLK_EMMC:
 551        case SCLK_SDMMC:
 552        case SCLK_EMMC:
 553                ret = rk3328_mmc_set_clk(priv->cru, clk->id, rate);
 554                break;
 555        case SCLK_I2C0:
 556        case SCLK_I2C1:
 557        case SCLK_I2C2:
 558        case SCLK_I2C3:
 559                ret = rk3328_i2c_set_clk(priv->cru, clk->id, rate);
 560                break;
 561        case SCLK_PWM:
 562                ret = rk3328_pwm_set_clk(priv->cru, rate);
 563                break;
 564        case SCLK_SARADC:
 565                ret = rk3328_saradc_set_clk(priv->cru, rate);
 566                break;
 567        default:
 568                return -ENOENT;
 569        }
 570
 571        return ret;
 572}
 573
 574static struct clk_ops rk3328_clk_ops = {
 575        .get_rate = rk3328_clk_get_rate,
 576        .set_rate = rk3328_clk_set_rate,
 577};
 578
 579static int rk3328_clk_probe(struct udevice *dev)
 580{
 581        struct rk3328_clk_priv *priv = dev_get_priv(dev);
 582
 583        rkclk_init(priv->cru);
 584
 585        return 0;
 586}
 587
 588static int rk3328_clk_ofdata_to_platdata(struct udevice *dev)
 589{
 590        struct rk3328_clk_priv *priv = dev_get_priv(dev);
 591
 592        priv->cru = (struct rk3328_cru *)devfdt_get_addr(dev);
 593
 594        return 0;
 595}
 596
 597static int rk3328_clk_bind(struct udevice *dev)
 598{
 599        int ret;
 600        struct udevice *sys_child;
 601        struct sysreset_reg *priv;
 602
 603        /* The reset driver does not have a device node, so bind it here */
 604        ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
 605                                 &sys_child);
 606        if (ret) {
 607                debug("Warning: No sysreset driver: ret=%d\n", ret);
 608        } else {
 609                priv = malloc(sizeof(struct sysreset_reg));
 610                priv->glb_srst_fst_value = offsetof(struct rk3328_cru,
 611                                                    glb_srst_fst_value);
 612                priv->glb_srst_snd_value = offsetof(struct rk3328_cru,
 613                                                    glb_srst_snd_value);
 614                sys_child->priv = priv;
 615        }
 616
 617        return ret;
 618}
 619
 620static const struct udevice_id rk3328_clk_ids[] = {
 621        { .compatible = "rockchip,rk3328-cru" },
 622        { }
 623};
 624
 625U_BOOT_DRIVER(rockchip_rk3328_cru) = {
 626        .name           = "rockchip_rk3328_cru",
 627        .id             = UCLASS_CLK,
 628        .of_match       = rk3328_clk_ids,
 629        .priv_auto_alloc_size = sizeof(struct rk3328_clk_priv),
 630        .ofdata_to_platdata = rk3328_clk_ofdata_to_platdata,
 631        .ops            = &rk3328_clk_ops,
 632        .bind           = rk3328_clk_bind,
 633        .probe          = rk3328_clk_probe,
 634};
 635