1*d1dcf852SAndy Yan /* 2*d1dcf852SAndy Yan * (C) Copyright 2017 Rockchip Electronics Co., Ltd 3*d1dcf852SAndy Yan * Author: Andy Yan <andy.yan@rock-chips.com> 4*d1dcf852SAndy Yan * SPDX-License-Identifier: GPL-2.0 5*d1dcf852SAndy Yan */ 6*d1dcf852SAndy Yan 7*d1dcf852SAndy Yan #include <common.h> 8*d1dcf852SAndy Yan #include <clk-uclass.h> 9*d1dcf852SAndy Yan #include <dm.h> 10*d1dcf852SAndy Yan #include <errno.h> 11*d1dcf852SAndy Yan #include <syscon.h> 12*d1dcf852SAndy Yan #include <asm/arch/clock.h> 13*d1dcf852SAndy Yan #include <asm/arch/cru_rk3368.h> 14*d1dcf852SAndy Yan #include <asm/arch/hardware.h> 15*d1dcf852SAndy Yan #include <asm/io.h> 16*d1dcf852SAndy Yan #include <dm/lists.h> 17*d1dcf852SAndy Yan #include <dt-bindings/clock/rk3368-cru.h> 18*d1dcf852SAndy Yan 19*d1dcf852SAndy Yan DECLARE_GLOBAL_DATA_PTR; 20*d1dcf852SAndy Yan 21*d1dcf852SAndy Yan struct pll_div { 22*d1dcf852SAndy Yan u32 nr; 23*d1dcf852SAndy Yan u32 nf; 24*d1dcf852SAndy Yan u32 no; 25*d1dcf852SAndy Yan }; 26*d1dcf852SAndy Yan 27*d1dcf852SAndy Yan #define OSC_HZ (24 * 1000 * 1000) 28*d1dcf852SAndy Yan #define APLL_L_HZ (800 * 1000 * 1000) 29*d1dcf852SAndy Yan #define APLL_B_HZ (816 * 1000 * 1000) 30*d1dcf852SAndy Yan #define GPLL_HZ (576 * 1000 * 1000) 31*d1dcf852SAndy Yan #define CPLL_HZ (400 * 1000 * 1000) 32*d1dcf852SAndy Yan 33*d1dcf852SAndy Yan #define RATE_TO_DIV(input_rate, output_rate) \ 34*d1dcf852SAndy Yan ((input_rate) / (output_rate) - 1); 35*d1dcf852SAndy Yan 36*d1dcf852SAndy Yan #define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1)) 37*d1dcf852SAndy Yan 38*d1dcf852SAndy Yan #define PLL_DIVISORS(hz, _nr, _no) { \ 39*d1dcf852SAndy Yan .nr = _nr, .nf = (u32)((u64)hz * _nr * _no / OSC_HZ), .no = _no}; \ 40*d1dcf852SAndy Yan _Static_assert(((u64)hz * _nr * _no / OSC_HZ) * OSC_HZ /\ 41*d1dcf852SAndy Yan (_nr * _no) == hz, #hz "Hz cannot be hit with PLL " \ 42*d1dcf852SAndy Yan "divisors on line " __stringify(__LINE__)); 43*d1dcf852SAndy Yan 44*d1dcf852SAndy Yan static const struct pll_div apll_l_init_cfg = PLL_DIVISORS(APLL_L_HZ, 12, 2); 45*d1dcf852SAndy Yan static const struct pll_div apll_b_init_cfg = PLL_DIVISORS(APLL_B_HZ, 1, 2); 46*d1dcf852SAndy Yan static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 1, 2); 47*d1dcf852SAndy Yan static const struct pll_div cpll_init_cfg = PLL_DIVISORS(CPLL_HZ, 1, 6); 48*d1dcf852SAndy Yan 49*d1dcf852SAndy Yan /* Get pll rate by id */ 50*d1dcf852SAndy Yan static uint32_t rkclk_pll_get_rate(struct rk3368_cru *cru, 51*d1dcf852SAndy Yan enum rk3368_pll_id pll_id) 52*d1dcf852SAndy Yan { 53*d1dcf852SAndy Yan uint32_t nr, no, nf; 54*d1dcf852SAndy Yan uint32_t con; 55*d1dcf852SAndy Yan struct rk3368_pll *pll = &cru->pll[pll_id]; 56*d1dcf852SAndy Yan 57*d1dcf852SAndy Yan con = readl(&pll->con3); 58*d1dcf852SAndy Yan 59*d1dcf852SAndy Yan switch ((con & PLL_MODE_MASK) >> PLL_MODE_SHIFT) { 60*d1dcf852SAndy Yan case PLL_MODE_SLOW: 61*d1dcf852SAndy Yan return OSC_HZ; 62*d1dcf852SAndy Yan case PLL_MODE_NORMAL: 63*d1dcf852SAndy Yan con = readl(&pll->con0); 64*d1dcf852SAndy Yan no = ((con & PLL_OD_MASK) >> PLL_OD_SHIFT) + 1; 65*d1dcf852SAndy Yan nr = ((con & PLL_NR_MASK) >> PLL_NR_SHIFT) + 1; 66*d1dcf852SAndy Yan con = readl(&pll->con1); 67*d1dcf852SAndy Yan nf = ((con & PLL_NF_MASK) >> PLL_NF_SHIFT) + 1; 68*d1dcf852SAndy Yan 69*d1dcf852SAndy Yan return (24 * nf / (nr * no)) * 1000000; 70*d1dcf852SAndy Yan case PLL_MODE_DEEP_SLOW: 71*d1dcf852SAndy Yan default: 72*d1dcf852SAndy Yan return 32768; 73*d1dcf852SAndy Yan } 74*d1dcf852SAndy Yan } 75*d1dcf852SAndy Yan 76*d1dcf852SAndy Yan static int rkclk_set_pll(struct rk3368_cru *cru, enum rk3368_pll_id pll_id, 77*d1dcf852SAndy Yan const struct pll_div *div, bool has_bwadj) 78*d1dcf852SAndy Yan { 79*d1dcf852SAndy Yan struct rk3368_pll *pll = &cru->pll[pll_id]; 80*d1dcf852SAndy Yan /* All PLLs have same VCO and output frequency range restrictions*/ 81*d1dcf852SAndy Yan uint vco_hz = OSC_HZ / 1000 * div->nf / div->nr * 1000; 82*d1dcf852SAndy Yan uint output_hz = vco_hz / div->no; 83*d1dcf852SAndy Yan 84*d1dcf852SAndy Yan debug("PLL at %p: nf=%d, nr=%d, no=%d, vco=%u Hz, output=%u Hz\n", 85*d1dcf852SAndy Yan pll, div->nf, div->nr, div->no, vco_hz, output_hz); 86*d1dcf852SAndy Yan 87*d1dcf852SAndy Yan /* enter slow mode and reset pll */ 88*d1dcf852SAndy Yan rk_clrsetreg(&pll->con3, PLL_MODE_MASK | PLL_RESET_MASK, 89*d1dcf852SAndy Yan PLL_RESET << PLL_RESET_SHIFT); 90*d1dcf852SAndy Yan 91*d1dcf852SAndy Yan rk_clrsetreg(&pll->con0, PLL_NR_MASK | PLL_OD_MASK, 92*d1dcf852SAndy Yan ((div->nr - 1) << PLL_NR_SHIFT) | 93*d1dcf852SAndy Yan ((div->no - 1) << PLL_OD_SHIFT)); 94*d1dcf852SAndy Yan writel((div->nf - 1) << PLL_NF_SHIFT, &pll->con1); 95*d1dcf852SAndy Yan udelay(10); 96*d1dcf852SAndy Yan 97*d1dcf852SAndy Yan /* return from reset */ 98*d1dcf852SAndy Yan rk_clrreg(&pll->con3, PLL_RESET_MASK); 99*d1dcf852SAndy Yan 100*d1dcf852SAndy Yan /* waiting for pll lock */ 101*d1dcf852SAndy Yan while (!(readl(&pll->con1) & PLL_LOCK_STA)) 102*d1dcf852SAndy Yan udelay(1); 103*d1dcf852SAndy Yan 104*d1dcf852SAndy Yan rk_clrsetreg(&pll->con3, PLL_MODE_MASK, 105*d1dcf852SAndy Yan PLL_MODE_NORMAL << PLL_MODE_SHIFT); 106*d1dcf852SAndy Yan 107*d1dcf852SAndy Yan return 0; 108*d1dcf852SAndy Yan } 109*d1dcf852SAndy Yan 110*d1dcf852SAndy Yan static void rkclk_init(struct rk3368_cru *cru) 111*d1dcf852SAndy Yan { 112*d1dcf852SAndy Yan u32 apllb, aplll, dpll, cpll, gpll; 113*d1dcf852SAndy Yan 114*d1dcf852SAndy Yan rkclk_set_pll(cru, APLLB, &apll_b_init_cfg, false); 115*d1dcf852SAndy Yan rkclk_set_pll(cru, APLLL, &apll_l_init_cfg, false); 116*d1dcf852SAndy Yan rkclk_set_pll(cru, GPLL, &gpll_init_cfg, false); 117*d1dcf852SAndy Yan rkclk_set_pll(cru, CPLL, &cpll_init_cfg, false); 118*d1dcf852SAndy Yan 119*d1dcf852SAndy Yan apllb = rkclk_pll_get_rate(cru, APLLB); 120*d1dcf852SAndy Yan aplll = rkclk_pll_get_rate(cru, APLLL); 121*d1dcf852SAndy Yan dpll = rkclk_pll_get_rate(cru, DPLL); 122*d1dcf852SAndy Yan cpll = rkclk_pll_get_rate(cru, CPLL); 123*d1dcf852SAndy Yan gpll = rkclk_pll_get_rate(cru, GPLL); 124*d1dcf852SAndy Yan 125*d1dcf852SAndy Yan debug("%s apllb(%d) apll(%d) dpll(%d) cpll(%d) gpll(%d)\n", 126*d1dcf852SAndy Yan __func__, apllb, aplll, dpll, cpll, gpll); 127*d1dcf852SAndy Yan } 128*d1dcf852SAndy Yan 129*d1dcf852SAndy Yan static ulong rk3368_mmc_get_clk(struct rk3368_cru *cru, uint clk_id) 130*d1dcf852SAndy Yan { 131*d1dcf852SAndy Yan u32 div, con, con_id, rate; 132*d1dcf852SAndy Yan u32 pll_rate; 133*d1dcf852SAndy Yan 134*d1dcf852SAndy Yan switch (clk_id) { 135*d1dcf852SAndy Yan case SCLK_SDMMC: 136*d1dcf852SAndy Yan con_id = 50; 137*d1dcf852SAndy Yan break; 138*d1dcf852SAndy Yan case SCLK_EMMC: 139*d1dcf852SAndy Yan con_id = 51; 140*d1dcf852SAndy Yan break; 141*d1dcf852SAndy Yan case SCLK_SDIO0: 142*d1dcf852SAndy Yan con_id = 48; 143*d1dcf852SAndy Yan break; 144*d1dcf852SAndy Yan default: 145*d1dcf852SAndy Yan return -EINVAL; 146*d1dcf852SAndy Yan } 147*d1dcf852SAndy Yan 148*d1dcf852SAndy Yan con = readl(&cru->clksel_con[con_id]); 149*d1dcf852SAndy Yan switch ((con & MMC_PLL_SEL_MASK) >> MMC_PLL_SEL_SHIFT) { 150*d1dcf852SAndy Yan case MMC_PLL_SEL_GPLL: 151*d1dcf852SAndy Yan pll_rate = rkclk_pll_get_rate(cru, GPLL); 152*d1dcf852SAndy Yan break; 153*d1dcf852SAndy Yan case MMC_PLL_SEL_24M: 154*d1dcf852SAndy Yan pll_rate = OSC_HZ; 155*d1dcf852SAndy Yan break; 156*d1dcf852SAndy Yan case MMC_PLL_SEL_CPLL: 157*d1dcf852SAndy Yan case MMC_PLL_SEL_USBPHY_480M: 158*d1dcf852SAndy Yan default: 159*d1dcf852SAndy Yan return -EINVAL; 160*d1dcf852SAndy Yan } 161*d1dcf852SAndy Yan div = (con & MMC_CLK_DIV_MASK) >> MMC_CLK_DIV_SHIFT; 162*d1dcf852SAndy Yan rate = DIV_TO_RATE(pll_rate, div); 163*d1dcf852SAndy Yan 164*d1dcf852SAndy Yan return rate >> 1; 165*d1dcf852SAndy Yan } 166*d1dcf852SAndy Yan 167*d1dcf852SAndy Yan static ulong rk3368_mmc_set_clk(struct rk3368_cru *cru, 168*d1dcf852SAndy Yan ulong clk_id, ulong rate) 169*d1dcf852SAndy Yan { 170*d1dcf852SAndy Yan u32 div; 171*d1dcf852SAndy Yan u32 con_id; 172*d1dcf852SAndy Yan u32 gpll_rate = rkclk_pll_get_rate(cru, GPLL); 173*d1dcf852SAndy Yan 174*d1dcf852SAndy Yan div = RATE_TO_DIV(gpll_rate, rate << 1); 175*d1dcf852SAndy Yan 176*d1dcf852SAndy Yan switch (clk_id) { 177*d1dcf852SAndy Yan case SCLK_SDMMC: 178*d1dcf852SAndy Yan con_id = 50; 179*d1dcf852SAndy Yan break; 180*d1dcf852SAndy Yan case SCLK_EMMC: 181*d1dcf852SAndy Yan con_id = 51; 182*d1dcf852SAndy Yan break; 183*d1dcf852SAndy Yan case SCLK_SDIO0: 184*d1dcf852SAndy Yan con_id = 48; 185*d1dcf852SAndy Yan break; 186*d1dcf852SAndy Yan default: 187*d1dcf852SAndy Yan return -EINVAL; 188*d1dcf852SAndy Yan } 189*d1dcf852SAndy Yan 190*d1dcf852SAndy Yan if (div > 0x3f) { 191*d1dcf852SAndy Yan div = RATE_TO_DIV(OSC_HZ, rate); 192*d1dcf852SAndy Yan rk_clrsetreg(&cru->clksel_con[con_id], 193*d1dcf852SAndy Yan MMC_PLL_SEL_MASK | MMC_CLK_DIV_MASK, 194*d1dcf852SAndy Yan (MMC_PLL_SEL_24M << MMC_PLL_SEL_SHIFT) | 195*d1dcf852SAndy Yan (div << MMC_CLK_DIV_SHIFT)); 196*d1dcf852SAndy Yan } else { 197*d1dcf852SAndy Yan rk_clrsetreg(&cru->clksel_con[con_id], 198*d1dcf852SAndy Yan MMC_PLL_SEL_MASK | MMC_CLK_DIV_MASK, 199*d1dcf852SAndy Yan (MMC_PLL_SEL_GPLL << MMC_PLL_SEL_SHIFT) | 200*d1dcf852SAndy Yan div << MMC_CLK_DIV_SHIFT); 201*d1dcf852SAndy Yan } 202*d1dcf852SAndy Yan 203*d1dcf852SAndy Yan return rk3368_mmc_get_clk(cru, clk_id); 204*d1dcf852SAndy Yan } 205*d1dcf852SAndy Yan 206*d1dcf852SAndy Yan static ulong rk3368_clk_get_rate(struct clk *clk) 207*d1dcf852SAndy Yan { 208*d1dcf852SAndy Yan struct rk3368_clk_priv *priv = dev_get_priv(clk->dev); 209*d1dcf852SAndy Yan ulong rate = 0; 210*d1dcf852SAndy Yan 211*d1dcf852SAndy Yan debug("%s id:%ld\n", __func__, clk->id); 212*d1dcf852SAndy Yan switch (clk->id) { 213*d1dcf852SAndy Yan case HCLK_SDMMC: 214*d1dcf852SAndy Yan case HCLK_EMMC: 215*d1dcf852SAndy Yan rate = rk3368_mmc_get_clk(priv->cru, clk->id); 216*d1dcf852SAndy Yan break; 217*d1dcf852SAndy Yan default: 218*d1dcf852SAndy Yan return -ENOENT; 219*d1dcf852SAndy Yan } 220*d1dcf852SAndy Yan 221*d1dcf852SAndy Yan return rate; 222*d1dcf852SAndy Yan } 223*d1dcf852SAndy Yan 224*d1dcf852SAndy Yan static ulong rk3368_clk_set_rate(struct clk *clk, ulong rate) 225*d1dcf852SAndy Yan { 226*d1dcf852SAndy Yan struct rk3368_clk_priv *priv = dev_get_priv(clk->dev); 227*d1dcf852SAndy Yan ulong ret = 0; 228*d1dcf852SAndy Yan 229*d1dcf852SAndy Yan debug("%s id:%ld rate:%ld\n", __func__, clk->id, rate); 230*d1dcf852SAndy Yan switch (clk->id) { 231*d1dcf852SAndy Yan case SCLK_SDMMC: 232*d1dcf852SAndy Yan case SCLK_EMMC: 233*d1dcf852SAndy Yan ret = rk3368_mmc_set_clk(priv->cru, clk->id, rate); 234*d1dcf852SAndy Yan break; 235*d1dcf852SAndy Yan default: 236*d1dcf852SAndy Yan return -ENOENT; 237*d1dcf852SAndy Yan } 238*d1dcf852SAndy Yan 239*d1dcf852SAndy Yan return ret; 240*d1dcf852SAndy Yan } 241*d1dcf852SAndy Yan 242*d1dcf852SAndy Yan static struct clk_ops rk3368_clk_ops = { 243*d1dcf852SAndy Yan .get_rate = rk3368_clk_get_rate, 244*d1dcf852SAndy Yan .set_rate = rk3368_clk_set_rate, 245*d1dcf852SAndy Yan }; 246*d1dcf852SAndy Yan 247*d1dcf852SAndy Yan static int rk3368_clk_probe(struct udevice *dev) 248*d1dcf852SAndy Yan { 249*d1dcf852SAndy Yan struct rk3368_clk_priv *priv = dev_get_priv(dev); 250*d1dcf852SAndy Yan 251*d1dcf852SAndy Yan rkclk_init(priv->cru); 252*d1dcf852SAndy Yan 253*d1dcf852SAndy Yan return 0; 254*d1dcf852SAndy Yan } 255*d1dcf852SAndy Yan 256*d1dcf852SAndy Yan static int rk3368_clk_ofdata_to_platdata(struct udevice *dev) 257*d1dcf852SAndy Yan { 258*d1dcf852SAndy Yan struct rk3368_clk_priv *priv = dev_get_priv(dev); 259*d1dcf852SAndy Yan 260*d1dcf852SAndy Yan priv->cru = (struct rk3368_cru *)devfdt_get_addr(dev); 261*d1dcf852SAndy Yan 262*d1dcf852SAndy Yan return 0; 263*d1dcf852SAndy Yan } 264*d1dcf852SAndy Yan 265*d1dcf852SAndy Yan static int rk3368_clk_bind(struct udevice *dev) 266*d1dcf852SAndy Yan { 267*d1dcf852SAndy Yan int ret; 268*d1dcf852SAndy Yan 269*d1dcf852SAndy Yan /* The reset driver does not have a device node, so bind it here */ 270*d1dcf852SAndy Yan ret = device_bind_driver(gd->dm_root, "rk3368_sysreset", "reset", &dev); 271*d1dcf852SAndy Yan if (ret) 272*d1dcf852SAndy Yan error("bind RK3368 reset driver failed: ret=%d\n", ret); 273*d1dcf852SAndy Yan 274*d1dcf852SAndy Yan return ret; 275*d1dcf852SAndy Yan } 276*d1dcf852SAndy Yan 277*d1dcf852SAndy Yan static const struct udevice_id rk3368_clk_ids[] = { 278*d1dcf852SAndy Yan { .compatible = "rockchip,rk3368-cru" }, 279*d1dcf852SAndy Yan { } 280*d1dcf852SAndy Yan }; 281*d1dcf852SAndy Yan 282*d1dcf852SAndy Yan U_BOOT_DRIVER(rockchip_rk3368_cru) = { 283*d1dcf852SAndy Yan .name = "rockchip_rk3368_cru", 284*d1dcf852SAndy Yan .id = UCLASS_CLK, 285*d1dcf852SAndy Yan .of_match = rk3368_clk_ids, 286*d1dcf852SAndy Yan .priv_auto_alloc_size = sizeof(struct rk3368_cru), 287*d1dcf852SAndy Yan .ofdata_to_platdata = rk3368_clk_ofdata_to_platdata, 288*d1dcf852SAndy Yan .ops = &rk3368_clk_ops, 289*d1dcf852SAndy Yan .bind = rk3368_clk_bind, 290*d1dcf852SAndy Yan .probe = rk3368_clk_probe, 291*d1dcf852SAndy Yan }; 292