1045029cbSKever Yang /* 2045029cbSKever Yang * (C) Copyright 2017 Rockchip Electronics Co., Ltd 3045029cbSKever Yang * 4045029cbSKever Yang * SPDX-License-Identifier: GPL-2.0 5045029cbSKever Yang */ 6045029cbSKever Yang 7045029cbSKever Yang #include <common.h> 8045029cbSKever Yang #include <clk-uclass.h> 9045029cbSKever Yang #include <dm.h> 10045029cbSKever Yang #include <errno.h> 11045029cbSKever Yang #include <syscon.h> 12045029cbSKever Yang #include <asm/io.h> 13045029cbSKever Yang #include <asm/arch/clock.h> 14045029cbSKever Yang #include <asm/arch/cru_rk322x.h> 15045029cbSKever Yang #include <asm/arch/hardware.h> 16045029cbSKever Yang #include <dm/lists.h> 17045029cbSKever Yang #include <dt-bindings/clock/rk3228-cru.h> 18045029cbSKever Yang #include <linux/log2.h> 19045029cbSKever Yang 20045029cbSKever Yang DECLARE_GLOBAL_DATA_PTR; 21045029cbSKever Yang 22045029cbSKever Yang enum { 23045029cbSKever Yang VCO_MAX_HZ = 3200U * 1000000, 24045029cbSKever Yang VCO_MIN_HZ = 800 * 1000000, 25045029cbSKever Yang OUTPUT_MAX_HZ = 3200U * 1000000, 26045029cbSKever Yang OUTPUT_MIN_HZ = 24 * 1000000, 27045029cbSKever Yang }; 28045029cbSKever Yang 29045029cbSKever Yang #define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1)) 30045029cbSKever Yang 31045029cbSKever Yang #define PLL_DIVISORS(hz, _refdiv, _postdiv1, _postdiv2) {\ 32045029cbSKever Yang .refdiv = _refdiv,\ 33045029cbSKever Yang .fbdiv = (u32)((u64)hz * _refdiv * _postdiv1 * _postdiv2 / OSC_HZ), \ 34045029cbSKever Yang .postdiv1 = _postdiv1, .postdiv2 = _postdiv2};\ 35045029cbSKever Yang _Static_assert(((u64)hz * _refdiv * _postdiv1 * _postdiv2 / OSC_HZ) * \ 36045029cbSKever Yang OSC_HZ / (_refdiv * _postdiv1 * _postdiv2) == hz, \ 37045029cbSKever Yang #hz "Hz cannot be hit with PLL "\ 38045029cbSKever Yang "divisors on line " __stringify(__LINE__)); 39045029cbSKever Yang 40045029cbSKever Yang /* use integer mode*/ 41045029cbSKever Yang static const struct pll_div apll_init_cfg = PLL_DIVISORS(APLL_HZ, 1, 3, 1); 42045029cbSKever Yang static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 2, 2, 1); 43045029cbSKever Yang 44045029cbSKever Yang static int rkclk_set_pll(struct rk322x_cru *cru, enum rk_clk_id clk_id, 45045029cbSKever Yang const struct pll_div *div) 46045029cbSKever Yang { 47045029cbSKever Yang int pll_id = rk_pll_id(clk_id); 48045029cbSKever Yang struct rk322x_pll *pll = &cru->pll[pll_id]; 49045029cbSKever Yang 50045029cbSKever Yang /* All PLLs have same VCO and output frequency range restrictions. */ 51045029cbSKever Yang uint vco_hz = OSC_HZ / 1000 * div->fbdiv / div->refdiv * 1000; 52045029cbSKever Yang uint output_hz = vco_hz / div->postdiv1 / div->postdiv2; 53045029cbSKever Yang 54045029cbSKever Yang debug("PLL at %p: fb=%d, ref=%d, pst1=%d, pst2=%d, vco=%u Hz, output=%u Hz\n", 55045029cbSKever Yang pll, div->fbdiv, div->refdiv, div->postdiv1, 56045029cbSKever Yang div->postdiv2, vco_hz, output_hz); 57045029cbSKever Yang assert(vco_hz >= VCO_MIN_HZ && vco_hz <= VCO_MAX_HZ && 58045029cbSKever Yang output_hz >= OUTPUT_MIN_HZ && output_hz <= OUTPUT_MAX_HZ); 59045029cbSKever Yang 60045029cbSKever Yang /* use integer mode */ 61045029cbSKever Yang rk_setreg(&pll->con1, 1 << PLL_DSMPD_SHIFT); 62045029cbSKever Yang /* Power down */ 63045029cbSKever Yang rk_setreg(&pll->con1, 1 << PLL_PD_SHIFT); 64045029cbSKever Yang 65045029cbSKever Yang rk_clrsetreg(&pll->con0, 66045029cbSKever Yang PLL_POSTDIV1_MASK | PLL_FBDIV_MASK, 67045029cbSKever Yang (div->postdiv1 << PLL_POSTDIV1_SHIFT) | div->fbdiv); 68045029cbSKever Yang rk_clrsetreg(&pll->con1, PLL_POSTDIV2_MASK | PLL_REFDIV_MASK, 69045029cbSKever Yang (div->postdiv2 << PLL_POSTDIV2_SHIFT | 70045029cbSKever Yang div->refdiv << PLL_REFDIV_SHIFT)); 71045029cbSKever Yang 72045029cbSKever Yang /* Power Up */ 73045029cbSKever Yang rk_clrreg(&pll->con1, 1 << PLL_PD_SHIFT); 74045029cbSKever Yang 75045029cbSKever Yang /* waiting for pll lock */ 76045029cbSKever Yang while (readl(&pll->con1) & (1 << PLL_LOCK_STATUS_SHIFT)) 77045029cbSKever Yang udelay(1); 78045029cbSKever Yang 79045029cbSKever Yang return 0; 80045029cbSKever Yang } 81045029cbSKever Yang 82045029cbSKever Yang static void rkclk_init(struct rk322x_cru *cru) 83045029cbSKever Yang { 84045029cbSKever Yang u32 aclk_div; 85045029cbSKever Yang u32 hclk_div; 86045029cbSKever Yang u32 pclk_div; 87045029cbSKever Yang 88045029cbSKever Yang /* pll enter slow-mode */ 89045029cbSKever Yang rk_clrsetreg(&cru->cru_mode_con, 90045029cbSKever Yang GPLL_MODE_MASK | APLL_MODE_MASK, 91045029cbSKever Yang GPLL_MODE_SLOW << GPLL_MODE_SHIFT | 92045029cbSKever Yang APLL_MODE_SLOW << APLL_MODE_SHIFT); 93045029cbSKever Yang 94045029cbSKever Yang /* init pll */ 95045029cbSKever Yang rkclk_set_pll(cru, CLK_ARM, &apll_init_cfg); 96045029cbSKever Yang rkclk_set_pll(cru, CLK_GENERAL, &gpll_init_cfg); 97045029cbSKever Yang 98045029cbSKever Yang /* 99045029cbSKever Yang * select apll as cpu/core clock pll source and 100045029cbSKever Yang * set up dependent divisors for PERI and ACLK clocks. 101045029cbSKever Yang * core hz : apll = 1:1 102045029cbSKever Yang */ 103045029cbSKever Yang aclk_div = APLL_HZ / CORE_ACLK_HZ - 1; 104045029cbSKever Yang assert((aclk_div + 1) * CORE_ACLK_HZ == APLL_HZ && aclk_div < 0x7); 105045029cbSKever Yang 106045029cbSKever Yang pclk_div = APLL_HZ / CORE_PERI_HZ - 1; 107045029cbSKever Yang assert((pclk_div + 1) * CORE_PERI_HZ == APLL_HZ && pclk_div < 0xf); 108045029cbSKever Yang 109045029cbSKever Yang rk_clrsetreg(&cru->cru_clksel_con[0], 110045029cbSKever Yang CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK, 111045029cbSKever Yang CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT | 112045029cbSKever Yang 0 << CORE_DIV_CON_SHIFT); 113045029cbSKever Yang 114045029cbSKever Yang rk_clrsetreg(&cru->cru_clksel_con[1], 115045029cbSKever Yang CORE_ACLK_DIV_MASK | CORE_PERI_DIV_MASK, 116045029cbSKever Yang aclk_div << CORE_ACLK_DIV_SHIFT | 117045029cbSKever Yang pclk_div << CORE_PERI_DIV_SHIFT); 118045029cbSKever Yang 119045029cbSKever Yang /* 120f04b6e29SKever Yang * select gpll as pd_bus bus clock source and 121045029cbSKever Yang * set up dependent divisors for PCLK/HCLK and ACLK clocks. 122045029cbSKever Yang */ 123045029cbSKever Yang aclk_div = GPLL_HZ / BUS_ACLK_HZ - 1; 124045029cbSKever Yang assert((aclk_div + 1) * BUS_ACLK_HZ == GPLL_HZ && aclk_div <= 0x1f); 125045029cbSKever Yang 126f04b6e29SKever Yang pclk_div = BUS_ACLK_HZ / BUS_PCLK_HZ - 1; 127045029cbSKever Yang assert((pclk_div + 1) * BUS_PCLK_HZ == GPLL_HZ && pclk_div <= 0x7); 128045029cbSKever Yang 129f04b6e29SKever Yang hclk_div = BUS_ACLK_HZ / BUS_HCLK_HZ - 1; 130045029cbSKever Yang assert((hclk_div + 1) * BUS_HCLK_HZ == GPLL_HZ && hclk_div <= 0x3); 131045029cbSKever Yang 132045029cbSKever Yang rk_clrsetreg(&cru->cru_clksel_con[0], 133045029cbSKever Yang BUS_ACLK_PLL_SEL_MASK | BUS_ACLK_DIV_MASK, 134045029cbSKever Yang BUS_ACLK_PLL_SEL_GPLL << BUS_ACLK_PLL_SEL_SHIFT | 135045029cbSKever Yang aclk_div << BUS_ACLK_DIV_SHIFT); 136045029cbSKever Yang 137045029cbSKever Yang rk_clrsetreg(&cru->cru_clksel_con[1], 138045029cbSKever Yang BUS_PCLK_DIV_MASK | BUS_HCLK_DIV_MASK, 139045029cbSKever Yang pclk_div << BUS_PCLK_DIV_SHIFT | 140045029cbSKever Yang hclk_div << BUS_HCLK_DIV_SHIFT); 141045029cbSKever Yang 142045029cbSKever Yang /* 143045029cbSKever Yang * select gpll as pd_peri bus clock source and 144045029cbSKever Yang * set up dependent divisors for PCLK/HCLK and ACLK clocks. 145045029cbSKever Yang */ 146045029cbSKever Yang aclk_div = GPLL_HZ / PERI_ACLK_HZ - 1; 147045029cbSKever Yang assert((aclk_div + 1) * PERI_ACLK_HZ == GPLL_HZ && aclk_div < 0x1f); 148045029cbSKever Yang 149045029cbSKever Yang hclk_div = ilog2(PERI_ACLK_HZ / PERI_HCLK_HZ); 150045029cbSKever Yang assert((1 << hclk_div) * PERI_HCLK_HZ == 151045029cbSKever Yang PERI_ACLK_HZ && (hclk_div < 0x4)); 152045029cbSKever Yang 153045029cbSKever Yang pclk_div = ilog2(PERI_ACLK_HZ / PERI_PCLK_HZ); 154045029cbSKever Yang assert((1 << pclk_div) * PERI_PCLK_HZ == 155045029cbSKever Yang PERI_ACLK_HZ && pclk_div < 0x8); 156045029cbSKever Yang 157045029cbSKever Yang rk_clrsetreg(&cru->cru_clksel_con[10], 158045029cbSKever Yang PERI_PLL_SEL_MASK | PERI_PCLK_DIV_MASK | 159045029cbSKever Yang PERI_HCLK_DIV_MASK | PERI_ACLK_DIV_MASK, 160045029cbSKever Yang PERI_PLL_GPLL << PERI_PLL_SEL_SHIFT | 161045029cbSKever Yang pclk_div << PERI_PCLK_DIV_SHIFT | 162045029cbSKever Yang hclk_div << PERI_HCLK_DIV_SHIFT | 163045029cbSKever Yang aclk_div << PERI_ACLK_DIV_SHIFT); 164045029cbSKever Yang 165045029cbSKever Yang /* PLL enter normal-mode */ 166045029cbSKever Yang rk_clrsetreg(&cru->cru_mode_con, 167045029cbSKever Yang GPLL_MODE_MASK | APLL_MODE_MASK, 168045029cbSKever Yang GPLL_MODE_NORM << GPLL_MODE_SHIFT | 169045029cbSKever Yang APLL_MODE_NORM << APLL_MODE_SHIFT); 170045029cbSKever Yang } 171045029cbSKever Yang 172045029cbSKever Yang /* Get pll rate by id */ 173045029cbSKever Yang static uint32_t rkclk_pll_get_rate(struct rk322x_cru *cru, 174045029cbSKever Yang enum rk_clk_id clk_id) 175045029cbSKever Yang { 176045029cbSKever Yang uint32_t refdiv, fbdiv, postdiv1, postdiv2; 177045029cbSKever Yang uint32_t con; 178045029cbSKever Yang int pll_id = rk_pll_id(clk_id); 179045029cbSKever Yang struct rk322x_pll *pll = &cru->pll[pll_id]; 180045029cbSKever Yang static u8 clk_shift[CLK_COUNT] = { 181045029cbSKever Yang 0xff, APLL_MODE_SHIFT, DPLL_MODE_SHIFT, 0xff, 182045029cbSKever Yang GPLL_MODE_SHIFT, 0xff 183045029cbSKever Yang }; 184045029cbSKever Yang static u32 clk_mask[CLK_COUNT] = { 185045029cbSKever Yang 0xff, APLL_MODE_MASK, DPLL_MODE_MASK, 0xff, 186045029cbSKever Yang GPLL_MODE_MASK, 0xff 187045029cbSKever Yang }; 188045029cbSKever Yang uint shift; 189045029cbSKever Yang uint mask; 190045029cbSKever Yang 191045029cbSKever Yang con = readl(&cru->cru_mode_con); 192045029cbSKever Yang shift = clk_shift[clk_id]; 193045029cbSKever Yang mask = clk_mask[clk_id]; 194045029cbSKever Yang 195045029cbSKever Yang switch ((con & mask) >> shift) { 196045029cbSKever Yang case GPLL_MODE_SLOW: 197045029cbSKever Yang return OSC_HZ; 198045029cbSKever Yang case GPLL_MODE_NORM: 199045029cbSKever Yang 200045029cbSKever Yang /* normal mode */ 201045029cbSKever Yang con = readl(&pll->con0); 202045029cbSKever Yang postdiv1 = (con & PLL_POSTDIV1_MASK) >> PLL_POSTDIV1_SHIFT; 203045029cbSKever Yang fbdiv = (con & PLL_FBDIV_MASK) >> PLL_FBDIV_SHIFT; 204045029cbSKever Yang con = readl(&pll->con1); 205045029cbSKever Yang postdiv2 = (con & PLL_POSTDIV2_MASK) >> PLL_POSTDIV2_SHIFT; 206045029cbSKever Yang refdiv = (con & PLL_REFDIV_MASK) >> PLL_REFDIV_SHIFT; 207045029cbSKever Yang return (24 * fbdiv / (refdiv * postdiv1 * postdiv2)) * 1000000; 208045029cbSKever Yang default: 209045029cbSKever Yang return 32768; 210045029cbSKever Yang } 211045029cbSKever Yang } 212045029cbSKever Yang 213045029cbSKever Yang static ulong rockchip_mmc_get_clk(struct rk322x_cru *cru, uint clk_general_rate, 214045029cbSKever Yang int periph) 215045029cbSKever Yang { 216045029cbSKever Yang uint src_rate; 217045029cbSKever Yang uint div, mux; 218045029cbSKever Yang u32 con; 219045029cbSKever Yang 220045029cbSKever Yang switch (periph) { 221045029cbSKever Yang case HCLK_EMMC: 222045029cbSKever Yang case SCLK_EMMC: 2236c639845SKever Yang case SCLK_EMMC_SAMPLE: 224045029cbSKever Yang con = readl(&cru->cru_clksel_con[11]); 225045029cbSKever Yang mux = (con & EMMC_PLL_MASK) >> EMMC_PLL_SHIFT; 226045029cbSKever Yang con = readl(&cru->cru_clksel_con[12]); 227045029cbSKever Yang div = (con & EMMC_DIV_MASK) >> EMMC_DIV_SHIFT; 228045029cbSKever Yang break; 229045029cbSKever Yang case HCLK_SDMMC: 230045029cbSKever Yang case SCLK_SDMMC: 231045029cbSKever Yang con = readl(&cru->cru_clksel_con[11]); 232045029cbSKever Yang mux = (con & MMC0_PLL_MASK) >> MMC0_PLL_SHIFT; 233045029cbSKever Yang div = (con & MMC0_DIV_MASK) >> MMC0_DIV_SHIFT; 234045029cbSKever Yang break; 235045029cbSKever Yang default: 236045029cbSKever Yang return -EINVAL; 237045029cbSKever Yang } 238045029cbSKever Yang 239045029cbSKever Yang src_rate = mux == EMMC_SEL_24M ? OSC_HZ : clk_general_rate; 2403a94d75dSKever Yang return DIV_TO_RATE(src_rate, div) / 2; 241045029cbSKever Yang } 242045029cbSKever Yang 243045029cbSKever Yang static ulong rockchip_mmc_set_clk(struct rk322x_cru *cru, uint clk_general_rate, 244045029cbSKever Yang int periph, uint freq) 245045029cbSKever Yang { 246045029cbSKever Yang int src_clk_div; 247045029cbSKever Yang int mux; 248045029cbSKever Yang 249045029cbSKever Yang debug("%s: clk_general_rate=%u\n", __func__, clk_general_rate); 250045029cbSKever Yang 2513a94d75dSKever Yang /* mmc clock defaulg div 2 internal, need provide double in cru */ 2523a94d75dSKever Yang src_clk_div = DIV_ROUND_UP(clk_general_rate / 2, freq); 253045029cbSKever Yang 254217273cdSKever Yang if (src_clk_div > 128) { 2553a94d75dSKever Yang src_clk_div = DIV_ROUND_UP(OSC_HZ / 2, freq); 256217273cdSKever Yang assert(src_clk_div - 1 < 128); 257045029cbSKever Yang mux = EMMC_SEL_24M; 258045029cbSKever Yang } else { 259045029cbSKever Yang mux = EMMC_SEL_GPLL; 260045029cbSKever Yang } 261045029cbSKever Yang 262045029cbSKever Yang switch (periph) { 263045029cbSKever Yang case HCLK_EMMC: 264045029cbSKever Yang case SCLK_EMMC: 2656c639845SKever Yang case SCLK_EMMC_SAMPLE: 266045029cbSKever Yang rk_clrsetreg(&cru->cru_clksel_con[11], 267045029cbSKever Yang EMMC_PLL_MASK, 268045029cbSKever Yang mux << EMMC_PLL_SHIFT); 269045029cbSKever Yang rk_clrsetreg(&cru->cru_clksel_con[12], 270045029cbSKever Yang EMMC_DIV_MASK, 271045029cbSKever Yang (src_clk_div - 1) << EMMC_DIV_SHIFT); 272045029cbSKever Yang break; 273045029cbSKever Yang case HCLK_SDMMC: 274045029cbSKever Yang case SCLK_SDMMC: 275045029cbSKever Yang rk_clrsetreg(&cru->cru_clksel_con[11], 276045029cbSKever Yang MMC0_PLL_MASK | MMC0_DIV_MASK, 277045029cbSKever Yang mux << MMC0_PLL_SHIFT | 278045029cbSKever Yang (src_clk_div - 1) << MMC0_DIV_SHIFT); 279045029cbSKever Yang break; 280045029cbSKever Yang default: 281045029cbSKever Yang return -EINVAL; 282045029cbSKever Yang } 283045029cbSKever Yang 284045029cbSKever Yang return rockchip_mmc_get_clk(cru, clk_general_rate, periph); 285045029cbSKever Yang } 286045029cbSKever Yang 287045029cbSKever Yang static int rk322x_ddr_set_clk(struct rk322x_cru *cru, unsigned int set_rate) 288045029cbSKever Yang { 289045029cbSKever Yang struct pll_div dpll_cfg; 290045029cbSKever Yang 291045029cbSKever Yang /* clk_ddrc == DPLL = 24MHz / refdiv * fbdiv / postdiv1 / postdiv2 */ 292045029cbSKever Yang switch (set_rate) { 293045029cbSKever Yang case 400*MHz: 294045029cbSKever Yang dpll_cfg = (struct pll_div) 295045029cbSKever Yang {.refdiv = 1, .fbdiv = 50, .postdiv1 = 3, .postdiv2 = 1}; 296045029cbSKever Yang break; 297045029cbSKever Yang case 600*MHz: 298045029cbSKever Yang dpll_cfg = (struct pll_div) 299045029cbSKever Yang {.refdiv = 1, .fbdiv = 75, .postdiv1 = 3, .postdiv2 = 1}; 300045029cbSKever Yang break; 301045029cbSKever Yang case 800*MHz: 302045029cbSKever Yang dpll_cfg = (struct pll_div) 303045029cbSKever Yang {.refdiv = 1, .fbdiv = 100, .postdiv1 = 3, .postdiv2 = 1}; 304045029cbSKever Yang break; 305045029cbSKever Yang } 306045029cbSKever Yang 307045029cbSKever Yang /* pll enter slow-mode */ 308045029cbSKever Yang rk_clrsetreg(&cru->cru_mode_con, DPLL_MODE_MASK, 309045029cbSKever Yang DPLL_MODE_SLOW << DPLL_MODE_SHIFT); 310045029cbSKever Yang rkclk_set_pll(cru, CLK_DDR, &dpll_cfg); 311045029cbSKever Yang /* PLL enter normal-mode */ 312045029cbSKever Yang rk_clrsetreg(&cru->cru_mode_con, DPLL_MODE_MASK, 313045029cbSKever Yang DPLL_MODE_NORM << DPLL_MODE_SHIFT); 314045029cbSKever Yang 315045029cbSKever Yang return set_rate; 316045029cbSKever Yang } 317*eecd6f34SZhangbin Tong 318*eecd6f34SZhangbin Tong static ulong rk322x_get_bus_aclk(struct rk322x_cru *cru, ulong gclk_rate) 319*eecd6f34SZhangbin Tong { 320*eecd6f34SZhangbin Tong u32 con; 321*eecd6f34SZhangbin Tong u32 aclk_div; 322*eecd6f34SZhangbin Tong 323*eecd6f34SZhangbin Tong con = readl(&cru->cru_clksel_con[0]); 324*eecd6f34SZhangbin Tong aclk_div = ((con & BUS_ACLK_DIV_MASK) >> BUS_ACLK_DIV_SHIFT) + 1; 325*eecd6f34SZhangbin Tong 326*eecd6f34SZhangbin Tong return gclk_rate / aclk_div; 327*eecd6f34SZhangbin Tong } 328*eecd6f34SZhangbin Tong 329*eecd6f34SZhangbin Tong static ulong rk322x_get_bus_pclk(struct rk322x_cru *cru, ulong gclk_rate) 330*eecd6f34SZhangbin Tong { 331*eecd6f34SZhangbin Tong u32 con; 332*eecd6f34SZhangbin Tong u32 pclk_div; 333*eecd6f34SZhangbin Tong 334*eecd6f34SZhangbin Tong con = readl(&cru->cru_clksel_con[1]); 335*eecd6f34SZhangbin Tong pclk_div = ((con & BUS_PCLK_DIV_MASK) >> BUS_PCLK_DIV_SHIFT) + 1; 336*eecd6f34SZhangbin Tong 337*eecd6f34SZhangbin Tong return rk322x_get_bus_aclk(cru, gclk_rate) / pclk_div; 338*eecd6f34SZhangbin Tong } 339*eecd6f34SZhangbin Tong 340045029cbSKever Yang static ulong rk322x_clk_get_rate(struct clk *clk) 341045029cbSKever Yang { 342045029cbSKever Yang struct rk322x_clk_priv *priv = dev_get_priv(clk->dev); 343045029cbSKever Yang ulong rate, gclk_rate; 344045029cbSKever Yang 345045029cbSKever Yang gclk_rate = rkclk_pll_get_rate(priv->cru, CLK_GENERAL); 346045029cbSKever Yang switch (clk->id) { 347045029cbSKever Yang case 0 ... 63: 348045029cbSKever Yang rate = rkclk_pll_get_rate(priv->cru, clk->id); 349045029cbSKever Yang break; 350045029cbSKever Yang case HCLK_EMMC: 351045029cbSKever Yang case SCLK_EMMC: 352045029cbSKever Yang case HCLK_SDMMC: 353045029cbSKever Yang case SCLK_SDMMC: 354045029cbSKever Yang rate = rockchip_mmc_get_clk(priv->cru, gclk_rate, clk->id); 355045029cbSKever Yang break; 356*eecd6f34SZhangbin Tong case PCLK_GPIO0 ... PCLK_TIMER: 357*eecd6f34SZhangbin Tong rate = rk322x_get_bus_pclk(priv->cru, gclk_rate); 358*eecd6f34SZhangbin Tong break; 359045029cbSKever Yang default: 360045029cbSKever Yang return -ENOENT; 361045029cbSKever Yang } 362045029cbSKever Yang 363045029cbSKever Yang return rate; 364045029cbSKever Yang } 365045029cbSKever Yang 366045029cbSKever Yang static ulong rk322x_clk_set_rate(struct clk *clk, ulong rate) 367045029cbSKever Yang { 368045029cbSKever Yang struct rk322x_clk_priv *priv = dev_get_priv(clk->dev); 369045029cbSKever Yang ulong new_rate, gclk_rate; 370045029cbSKever Yang 371045029cbSKever Yang gclk_rate = rkclk_pll_get_rate(priv->cru, CLK_GENERAL); 372045029cbSKever Yang switch (clk->id) { 373045029cbSKever Yang case HCLK_EMMC: 374045029cbSKever Yang case SCLK_EMMC: 375045029cbSKever Yang case HCLK_SDMMC: 376045029cbSKever Yang case SCLK_SDMMC: 377045029cbSKever Yang new_rate = rockchip_mmc_set_clk(priv->cru, gclk_rate, 378045029cbSKever Yang clk->id, rate); 379045029cbSKever Yang break; 380045029cbSKever Yang case CLK_DDR: 381045029cbSKever Yang new_rate = rk322x_ddr_set_clk(priv->cru, rate); 382045029cbSKever Yang break; 383045029cbSKever Yang default: 384045029cbSKever Yang return -ENOENT; 385045029cbSKever Yang } 386045029cbSKever Yang 387045029cbSKever Yang return new_rate; 388045029cbSKever Yang } 389045029cbSKever Yang 390045029cbSKever Yang static struct clk_ops rk322x_clk_ops = { 391045029cbSKever Yang .get_rate = rk322x_clk_get_rate, 392045029cbSKever Yang .set_rate = rk322x_clk_set_rate, 393045029cbSKever Yang }; 394045029cbSKever Yang 395045029cbSKever Yang static int rk322x_clk_ofdata_to_platdata(struct udevice *dev) 396045029cbSKever Yang { 397045029cbSKever Yang struct rk322x_clk_priv *priv = dev_get_priv(dev); 398045029cbSKever Yang 399045029cbSKever Yang priv->cru = (struct rk322x_cru *)devfdt_get_addr(dev); 400045029cbSKever Yang 401045029cbSKever Yang return 0; 402045029cbSKever Yang } 403045029cbSKever Yang 404045029cbSKever Yang static int rk322x_clk_probe(struct udevice *dev) 405045029cbSKever Yang { 406045029cbSKever Yang struct rk322x_clk_priv *priv = dev_get_priv(dev); 407045029cbSKever Yang 408045029cbSKever Yang rkclk_init(priv->cru); 409045029cbSKever Yang 410045029cbSKever Yang return 0; 411045029cbSKever Yang } 412045029cbSKever Yang 413045029cbSKever Yang static int rk322x_clk_bind(struct udevice *dev) 414045029cbSKever Yang { 415045029cbSKever Yang int ret; 416045029cbSKever Yang 417045029cbSKever Yang /* The reset driver does not have a device node, so bind it here */ 418045029cbSKever Yang ret = device_bind_driver(gd->dm_root, "rk322x_sysreset", "reset", &dev); 419045029cbSKever Yang if (ret) 4206c9bca3cSKever Yang debug("Warning: No RK322x reset driver: ret=%d\n", ret); 421045029cbSKever Yang 422045029cbSKever Yang return 0; 423045029cbSKever Yang } 424045029cbSKever Yang 425045029cbSKever Yang static const struct udevice_id rk322x_clk_ids[] = { 426045029cbSKever Yang { .compatible = "rockchip,rk3228-cru" }, 427045029cbSKever Yang { } 428045029cbSKever Yang }; 429045029cbSKever Yang 430045029cbSKever Yang U_BOOT_DRIVER(rockchip_rk322x_cru) = { 431045029cbSKever Yang .name = "clk_rk322x", 432045029cbSKever Yang .id = UCLASS_CLK, 433045029cbSKever Yang .of_match = rk322x_clk_ids, 434045029cbSKever Yang .priv_auto_alloc_size = sizeof(struct rk322x_clk_priv), 435045029cbSKever Yang .ofdata_to_platdata = rk322x_clk_ofdata_to_platdata, 436045029cbSKever Yang .ops = &rk322x_clk_ops, 437045029cbSKever Yang .bind = rk322x_clk_bind, 438045029cbSKever Yang .probe = rk322x_clk_probe, 439045029cbSKever Yang }; 440