1*bae2f282SAndy Yan /* 2*bae2f282SAndy Yan * (C) Copyright 2016 Rockchip Electronics Co., Ltd 3*bae2f282SAndy Yan * Author: Andy Yan <andy.yan@rock-chips.com> 4*bae2f282SAndy Yan * SPDX-License-Identifier: GPL-2.0 5*bae2f282SAndy Yan */ 6*bae2f282SAndy Yan 7*bae2f282SAndy Yan #include <common.h> 8*bae2f282SAndy Yan #include <clk-uclass.h> 9*bae2f282SAndy Yan #include <dm.h> 10*bae2f282SAndy Yan #include <errno.h> 11*bae2f282SAndy Yan #include <syscon.h> 12*bae2f282SAndy Yan #include <asm/io.h> 13*bae2f282SAndy Yan #include <asm/arch/clock.h> 14*bae2f282SAndy Yan #include <asm/arch/cru_rv1108.h> 15*bae2f282SAndy Yan #include <asm/arch/hardware.h> 16*bae2f282SAndy Yan #include <dm/lists.h> 17*bae2f282SAndy Yan #include <dt-bindings/clock/rv1108-cru.h> 18*bae2f282SAndy Yan 19*bae2f282SAndy Yan DECLARE_GLOBAL_DATA_PTR; 20*bae2f282SAndy Yan 21*bae2f282SAndy Yan enum { 22*bae2f282SAndy Yan VCO_MAX_HZ = 2400U * 1000000, 23*bae2f282SAndy Yan VCO_MIN_HZ = 600 * 1000000, 24*bae2f282SAndy Yan OUTPUT_MAX_HZ = 2400U * 1000000, 25*bae2f282SAndy Yan OUTPUT_MIN_HZ = 24 * 1000000, 26*bae2f282SAndy Yan }; 27*bae2f282SAndy Yan 28*bae2f282SAndy Yan #define RATE_TO_DIV(input_rate, output_rate) \ 29*bae2f282SAndy Yan ((input_rate) / (output_rate) - 1); 30*bae2f282SAndy Yan 31*bae2f282SAndy Yan #define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1)) 32*bae2f282SAndy Yan 33*bae2f282SAndy Yan #define PLL_DIVISORS(hz, _refdiv, _postdiv1, _postdiv2) {\ 34*bae2f282SAndy Yan .refdiv = _refdiv,\ 35*bae2f282SAndy Yan .fbdiv = (u32)((u64)hz * _refdiv * _postdiv1 * _postdiv2 / OSC_HZ),\ 36*bae2f282SAndy Yan .postdiv1 = _postdiv1, .postdiv2 = _postdiv2};\ 37*bae2f282SAndy Yan _Static_assert(((u64)hz * _refdiv * _postdiv1 * _postdiv2 / OSC_HZ) *\ 38*bae2f282SAndy Yan OSC_HZ / (_refdiv * _postdiv1 * _postdiv2) == hz,\ 39*bae2f282SAndy Yan #hz "Hz cannot be hit with PLL "\ 40*bae2f282SAndy Yan "divisors on line " __stringify(__LINE__)); 41*bae2f282SAndy Yan 42*bae2f282SAndy Yan /* use interge mode*/ 43*bae2f282SAndy Yan static const struct pll_div apll_init_cfg = PLL_DIVISORS(APLL_HZ, 1, 3, 1); 44*bae2f282SAndy Yan static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 2, 2, 1); 45*bae2f282SAndy Yan 46*bae2f282SAndy Yan static inline int rv1108_pll_id(enum rk_clk_id clk_id) 47*bae2f282SAndy Yan { 48*bae2f282SAndy Yan int id = 0; 49*bae2f282SAndy Yan 50*bae2f282SAndy Yan switch (clk_id) { 51*bae2f282SAndy Yan case CLK_ARM: 52*bae2f282SAndy Yan case CLK_DDR: 53*bae2f282SAndy Yan id = clk_id - 1; 54*bae2f282SAndy Yan break; 55*bae2f282SAndy Yan case CLK_GENERAL: 56*bae2f282SAndy Yan id = 2; 57*bae2f282SAndy Yan break; 58*bae2f282SAndy Yan default: 59*bae2f282SAndy Yan printf("invalid pll id:%d\n", clk_id); 60*bae2f282SAndy Yan id = -1; 61*bae2f282SAndy Yan break; 62*bae2f282SAndy Yan } 63*bae2f282SAndy Yan 64*bae2f282SAndy Yan return id; 65*bae2f282SAndy Yan } 66*bae2f282SAndy Yan 67*bae2f282SAndy Yan static uint32_t rkclk_pll_get_rate(struct rv1108_cru *cru, 68*bae2f282SAndy Yan enum rk_clk_id clk_id) 69*bae2f282SAndy Yan { 70*bae2f282SAndy Yan uint32_t refdiv, fbdiv, postdiv1, postdiv2; 71*bae2f282SAndy Yan uint32_t con0, con1, con3; 72*bae2f282SAndy Yan int pll_id = rv1108_pll_id(clk_id); 73*bae2f282SAndy Yan struct rv1108_pll *pll = &cru->pll[pll_id]; 74*bae2f282SAndy Yan uint32_t freq; 75*bae2f282SAndy Yan 76*bae2f282SAndy Yan con3 = readl(&pll->con3); 77*bae2f282SAndy Yan 78*bae2f282SAndy Yan if (con3 & WORK_MODE_MASK) { 79*bae2f282SAndy Yan con0 = readl(&pll->con0); 80*bae2f282SAndy Yan con1 = readl(&pll->con1); 81*bae2f282SAndy Yan fbdiv = (con0 >> FBDIV_SHIFT) & FBDIV_MASK; 82*bae2f282SAndy Yan postdiv1 = (con1 & POSTDIV1_MASK) >> POSTDIV1_SHIFT; 83*bae2f282SAndy Yan postdiv2 = (con1 & POSTDIV2_MASK) >> POSTDIV2_SHIFT; 84*bae2f282SAndy Yan refdiv = (con1 & REFDIV_MASK) >> REFDIV_SHIFT; 85*bae2f282SAndy Yan freq = (24 * fbdiv / (refdiv * postdiv1 * postdiv2)) * 1000000; 86*bae2f282SAndy Yan } else { 87*bae2f282SAndy Yan freq = OSC_HZ; 88*bae2f282SAndy Yan } 89*bae2f282SAndy Yan 90*bae2f282SAndy Yan return freq; 91*bae2f282SAndy Yan } 92*bae2f282SAndy Yan 93*bae2f282SAndy Yan static int rv1108_mac_set_clk(struct rv1108_cru *cru, ulong rate) 94*bae2f282SAndy Yan { 95*bae2f282SAndy Yan uint32_t con = readl(&cru->clksel_con[24]); 96*bae2f282SAndy Yan ulong pll_rate; 97*bae2f282SAndy Yan uint8_t div; 98*bae2f282SAndy Yan 99*bae2f282SAndy Yan if ((con >> MAC_PLL_SEL_SHIFT) & MAC_PLL_SEL_GPLL) 100*bae2f282SAndy Yan pll_rate = rkclk_pll_get_rate(cru, CLK_GENERAL); 101*bae2f282SAndy Yan else 102*bae2f282SAndy Yan pll_rate = rkclk_pll_get_rate(cru, CLK_ARM); 103*bae2f282SAndy Yan 104*bae2f282SAndy Yan /*default set 50MHZ for gmac*/ 105*bae2f282SAndy Yan if (!rate) 106*bae2f282SAndy Yan rate = 50000000; 107*bae2f282SAndy Yan 108*bae2f282SAndy Yan div = DIV_ROUND_UP(pll_rate, rate) - 1; 109*bae2f282SAndy Yan if (div <= 0x1f) 110*bae2f282SAndy Yan rk_clrsetreg(&cru->clksel_con[24], MAC_CLK_DIV_MASK, 111*bae2f282SAndy Yan div << MAC_CLK_DIV_SHIFT); 112*bae2f282SAndy Yan else 113*bae2f282SAndy Yan debug("Unsupported div for gmac:%d\n", div); 114*bae2f282SAndy Yan 115*bae2f282SAndy Yan return DIV_TO_RATE(pll_rate, div); 116*bae2f282SAndy Yan } 117*bae2f282SAndy Yan 118*bae2f282SAndy Yan static int rv1108_sfc_set_clk(struct rv1108_cru *cru, uint rate) 119*bae2f282SAndy Yan { 120*bae2f282SAndy Yan u32 con = readl(&cru->clksel_con[27]); 121*bae2f282SAndy Yan u32 pll_rate; 122*bae2f282SAndy Yan u32 div; 123*bae2f282SAndy Yan 124*bae2f282SAndy Yan if ((con >> SFC_PLL_SEL_SHIFT) && SFC_PLL_SEL_GPLL) 125*bae2f282SAndy Yan pll_rate = rkclk_pll_get_rate(cru, CLK_GENERAL); 126*bae2f282SAndy Yan else 127*bae2f282SAndy Yan pll_rate = rkclk_pll_get_rate(cru, CLK_DDR); 128*bae2f282SAndy Yan 129*bae2f282SAndy Yan div = DIV_ROUND_UP(pll_rate, rate) - 1; 130*bae2f282SAndy Yan if (div <= 0x3f) 131*bae2f282SAndy Yan rk_clrsetreg(&cru->clksel_con[27], SFC_CLK_DIV_MASK, 132*bae2f282SAndy Yan div << SFC_CLK_DIV_SHIFT); 133*bae2f282SAndy Yan else 134*bae2f282SAndy Yan debug("Unsupported sfc clk rate:%d\n", rate); 135*bae2f282SAndy Yan 136*bae2f282SAndy Yan return DIV_TO_RATE(pll_rate, div); 137*bae2f282SAndy Yan } 138*bae2f282SAndy Yan 139*bae2f282SAndy Yan static ulong rv1108_clk_get_rate(struct clk *clk) 140*bae2f282SAndy Yan { 141*bae2f282SAndy Yan struct rv1108_clk_priv *priv = dev_get_priv(clk->dev); 142*bae2f282SAndy Yan 143*bae2f282SAndy Yan switch (clk->id) { 144*bae2f282SAndy Yan case 0 ... 63: 145*bae2f282SAndy Yan return rkclk_pll_get_rate(priv->cru, clk->id); 146*bae2f282SAndy Yan default: 147*bae2f282SAndy Yan return -ENOENT; 148*bae2f282SAndy Yan } 149*bae2f282SAndy Yan } 150*bae2f282SAndy Yan 151*bae2f282SAndy Yan static ulong rv1108_clk_set_rate(struct clk *clk, ulong rate) 152*bae2f282SAndy Yan { 153*bae2f282SAndy Yan struct rv1108_clk_priv *priv = dev_get_priv(clk->dev); 154*bae2f282SAndy Yan ulong new_rate; 155*bae2f282SAndy Yan 156*bae2f282SAndy Yan switch (clk->id) { 157*bae2f282SAndy Yan case SCLK_MAC: 158*bae2f282SAndy Yan new_rate = rv1108_mac_set_clk(priv->cru, rate); 159*bae2f282SAndy Yan break; 160*bae2f282SAndy Yan case SCLK_SFC: 161*bae2f282SAndy Yan new_rate = rv1108_sfc_set_clk(priv->cru, rate); 162*bae2f282SAndy Yan break; 163*bae2f282SAndy Yan default: 164*bae2f282SAndy Yan return -ENOENT; 165*bae2f282SAndy Yan } 166*bae2f282SAndy Yan 167*bae2f282SAndy Yan return new_rate; 168*bae2f282SAndy Yan } 169*bae2f282SAndy Yan 170*bae2f282SAndy Yan static const struct clk_ops rv1108_clk_ops = { 171*bae2f282SAndy Yan .get_rate = rv1108_clk_get_rate, 172*bae2f282SAndy Yan .set_rate = rv1108_clk_set_rate, 173*bae2f282SAndy Yan }; 174*bae2f282SAndy Yan 175*bae2f282SAndy Yan static void rkclk_init(struct rv1108_cru *cru) 176*bae2f282SAndy Yan { 177*bae2f282SAndy Yan unsigned int apll = rkclk_pll_get_rate(cru, CLK_ARM); 178*bae2f282SAndy Yan unsigned int dpll = rkclk_pll_get_rate(cru, CLK_DDR); 179*bae2f282SAndy Yan unsigned int gpll = rkclk_pll_get_rate(cru, CLK_GENERAL); 180*bae2f282SAndy Yan 181*bae2f282SAndy Yan rk_clrsetreg(&cru->clksel_con[0], CORE_CLK_DIV_MASK, 182*bae2f282SAndy Yan 0 << MAC_CLK_DIV_SHIFT); 183*bae2f282SAndy Yan 184*bae2f282SAndy Yan printf("APLL: %d DPLL:%d GPLL:%d\n", apll, dpll, gpll); 185*bae2f282SAndy Yan } 186*bae2f282SAndy Yan 187*bae2f282SAndy Yan static int rv1108_clk_probe(struct udevice *dev) 188*bae2f282SAndy Yan { 189*bae2f282SAndy Yan struct rv1108_clk_priv *priv = dev_get_priv(dev); 190*bae2f282SAndy Yan 191*bae2f282SAndy Yan priv->cru = (struct rv1108_cru *)devfdt_get_addr(dev); 192*bae2f282SAndy Yan 193*bae2f282SAndy Yan rkclk_init(priv->cru); 194*bae2f282SAndy Yan 195*bae2f282SAndy Yan return 0; 196*bae2f282SAndy Yan } 197*bae2f282SAndy Yan 198*bae2f282SAndy Yan static int rv1108_clk_bind(struct udevice *dev) 199*bae2f282SAndy Yan { 200*bae2f282SAndy Yan int ret; 201*bae2f282SAndy Yan 202*bae2f282SAndy Yan /* The reset driver does not have a device node, so bind it here */ 203*bae2f282SAndy Yan ret = device_bind_driver(gd->dm_root, "rv1108_sysreset", "reset", &dev); 204*bae2f282SAndy Yan if (ret) 205*bae2f282SAndy Yan error("No Rv1108 reset driver: ret=%d\n", ret); 206*bae2f282SAndy Yan 207*bae2f282SAndy Yan return 0; 208*bae2f282SAndy Yan } 209*bae2f282SAndy Yan 210*bae2f282SAndy Yan static const struct udevice_id rv1108_clk_ids[] = { 211*bae2f282SAndy Yan { .compatible = "rockchip,rv1108-cru" }, 212*bae2f282SAndy Yan { } 213*bae2f282SAndy Yan }; 214*bae2f282SAndy Yan 215*bae2f282SAndy Yan U_BOOT_DRIVER(clk_rv1108) = { 216*bae2f282SAndy Yan .name = "clk_rv1108", 217*bae2f282SAndy Yan .id = UCLASS_CLK, 218*bae2f282SAndy Yan .of_match = rv1108_clk_ids, 219*bae2f282SAndy Yan .priv_auto_alloc_size = sizeof(struct rv1108_clk_priv), 220*bae2f282SAndy Yan .ops = &rv1108_clk_ops, 221*bae2f282SAndy Yan .bind = rv1108_clk_bind, 222*bae2f282SAndy Yan .probe = rv1108_clk_probe, 223*bae2f282SAndy Yan }; 224