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