1a60961a3SKever Yang /* 2a60961a3SKever Yang * (C) Copyright 2017 Rockchip Electronics Co., Ltd 3a60961a3SKever Yang * 4a60961a3SKever Yang * SPDX-License-Identifier: GPL-2.0 5a60961a3SKever Yang */ 6a60961a3SKever Yang 7a60961a3SKever Yang #include <common.h> 8a60961a3SKever Yang #include <bitfield.h> 9a60961a3SKever Yang #include <clk-uclass.h> 10a60961a3SKever Yang #include <dm.h> 11a60961a3SKever Yang #include <errno.h> 12a60961a3SKever Yang #include <syscon.h> 13a60961a3SKever Yang #include <asm/arch/clock.h> 14a60961a3SKever Yang #include <asm/arch/cru_px30.h> 15a60961a3SKever Yang #include <asm/arch/hardware.h> 16a60961a3SKever Yang #include <asm/io.h> 17a60961a3SKever Yang #include <dm/lists.h> 18a60961a3SKever Yang #include <dt-bindings/clock/px30-cru.h> 19a60961a3SKever Yang 20a60961a3SKever Yang DECLARE_GLOBAL_DATA_PTR; 21a60961a3SKever Yang 22a60961a3SKever Yang enum { 23a60961a3SKever Yang VCO_MAX_HZ = 3200U * 1000000, 24a60961a3SKever Yang VCO_MIN_HZ = 800 * 1000000, 25a60961a3SKever Yang OUTPUT_MAX_HZ = 3200U * 1000000, 26a60961a3SKever Yang OUTPUT_MIN_HZ = 24 * 1000000, 27a60961a3SKever Yang }; 28a60961a3SKever Yang 29*f909d4a8SFinley Xiao #define PX30_VOP_PLL_LIMIT 600000000 30*f909d4a8SFinley Xiao 31cefa5186SFinley Xiao #define PX30_PLL_RATE(_rate, _refdiv, _fbdiv, _postdiv1, \ 32cefa5186SFinley Xiao _postdiv2, _dsmpd, _frac) \ 33cefa5186SFinley Xiao { \ 34cefa5186SFinley Xiao .rate = _rate##U, \ 35cefa5186SFinley Xiao .fbdiv = _fbdiv, \ 36cefa5186SFinley Xiao .postdiv1 = _postdiv1, \ 37cefa5186SFinley Xiao .refdiv = _refdiv, \ 38cefa5186SFinley Xiao .postdiv2 = _postdiv2, \ 39cefa5186SFinley Xiao .dsmpd = _dsmpd, \ 40cefa5186SFinley Xiao .frac = _frac, \ 41cefa5186SFinley Xiao } 42cefa5186SFinley Xiao 4337428b92SFinley Xiao #define PX30_CPUCLK_RATE(_rate, _aclk_div, _pclk_div) \ 4437428b92SFinley Xiao { \ 4537428b92SFinley Xiao .rate = _rate##U, \ 4637428b92SFinley Xiao .aclk_div = _aclk_div, \ 4737428b92SFinley Xiao .pclk_div = _pclk_div, \ 4837428b92SFinley Xiao } 4937428b92SFinley Xiao 50a60961a3SKever Yang #define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1)) 51a60961a3SKever Yang 527a1915c0SFinley Xiao #define PX30_CLK_DUMP(_id, _name, _iscru) \ 537a1915c0SFinley Xiao { \ 547a1915c0SFinley Xiao .id = _id, \ 557a1915c0SFinley Xiao .name = _name, \ 567a1915c0SFinley Xiao .is_cru = _iscru, \ 577a1915c0SFinley Xiao } 587a1915c0SFinley Xiao 59cefa5186SFinley Xiao static struct pll_rate_table px30_pll_rates[] = { 60cefa5186SFinley Xiao /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */ 61cefa5186SFinley Xiao PX30_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0), 62cefa5186SFinley Xiao PX30_PLL_RATE(1188000000, 2, 99, 1, 1, 1, 0), 63cefa5186SFinley Xiao PX30_PLL_RATE(1100000000, 12, 550, 1, 1, 1, 0), 6437428b92SFinley Xiao PX30_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0), 65cefa5186SFinley Xiao PX30_PLL_RATE(1000000000, 6, 500, 2, 1, 1, 0), 66cefa5186SFinley Xiao PX30_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0), 67dd472d4fSFinley Xiao PX30_PLL_RATE(600000000, 1, 75, 3, 1, 1, 0), 68a60961a3SKever Yang }; 69a60961a3SKever Yang 707a1915c0SFinley Xiao static const struct px30_clk_info clks_dump[] = { 717a1915c0SFinley Xiao PX30_CLK_DUMP(PLL_APLL, "apll", true), 727a1915c0SFinley Xiao PX30_CLK_DUMP(PLL_DPLL, "dpll", true), 737a1915c0SFinley Xiao PX30_CLK_DUMP(PLL_CPLL, "cpll", true), 747a1915c0SFinley Xiao PX30_CLK_DUMP(PLL_NPLL, "npll", true), 757a1915c0SFinley Xiao PX30_CLK_DUMP(PLL_GPLL, "gpll", false), 767a1915c0SFinley Xiao PX30_CLK_DUMP(ACLK_BUS_PRE, "aclk_bus", true), 777a1915c0SFinley Xiao PX30_CLK_DUMP(HCLK_BUS_PRE, "hclk_bus", true), 787a1915c0SFinley Xiao PX30_CLK_DUMP(PCLK_BUS_PRE, "pclk_bus", true), 797a1915c0SFinley Xiao PX30_CLK_DUMP(ACLK_PERI_PRE, "aclk_peri", true), 807a1915c0SFinley Xiao PX30_CLK_DUMP(HCLK_PERI_PRE, "hclk_peri", true), 817a1915c0SFinley Xiao PX30_CLK_DUMP(PCLK_PMU_PRE, "pclk_pmu", false), 827a1915c0SFinley Xiao }; 837a1915c0SFinley Xiao 8437428b92SFinley Xiao static struct cpu_rate_table px30_cpu_rates[] = { 8537428b92SFinley Xiao PX30_CPUCLK_RATE(1200000000, 1, 5), 8637428b92SFinley Xiao PX30_CPUCLK_RATE(1008000000, 1, 5), 8737428b92SFinley Xiao PX30_CPUCLK_RATE(816000000, 1, 3), 8837428b92SFinley Xiao PX30_CPUCLK_RATE(600000000, 1, 3), 8937428b92SFinley Xiao }; 9037428b92SFinley Xiao 91bcefd077SFinley Xiao static u8 pll_mode_shift[PLL_COUNT] = { 92bcefd077SFinley Xiao APLL_MODE_SHIFT, DPLL_MODE_SHIFT, CPLL_MODE_SHIFT, 93bcefd077SFinley Xiao NPLL_MODE_SHIFT, GPLL_MODE_SHIFT 94bcefd077SFinley Xiao }; 95bcefd077SFinley Xiao static u32 pll_mode_mask[PLL_COUNT] = { 96bcefd077SFinley Xiao APLL_MODE_MASK, DPLL_MODE_MASK, CPLL_MODE_MASK, 97bcefd077SFinley Xiao NPLL_MODE_MASK, GPLL_MODE_MASK 98bcefd077SFinley Xiao }; 99bcefd077SFinley Xiao 100cefa5186SFinley Xiao static struct pll_rate_table auto_table; 101cefa5186SFinley Xiao 102cefa5186SFinley Xiao static struct pll_rate_table *pll_clk_set_by_auto(u32 drate) 103cefa5186SFinley Xiao { 104cefa5186SFinley Xiao struct pll_rate_table *rate = &auto_table; 105cefa5186SFinley Xiao u32 ref_khz = OSC_HZ / KHz, refdiv, fbdiv = 0; 106cefa5186SFinley Xiao u32 postdiv1, postdiv2 = 1; 107cefa5186SFinley Xiao u32 fref_khz; 108cefa5186SFinley Xiao u32 diff_khz, best_diff_khz; 109cefa5186SFinley Xiao const u32 max_refdiv = 63, max_fbdiv = 3200, min_fbdiv = 16; 110cefa5186SFinley Xiao const u32 max_postdiv1 = 7, max_postdiv2 = 7; 111cefa5186SFinley Xiao u32 vco_khz; 112cefa5186SFinley Xiao u32 rate_khz = drate / KHz; 113cefa5186SFinley Xiao 114cefa5186SFinley Xiao if (!drate) { 115cefa5186SFinley Xiao printf("%s: the frequency can't be 0 Hz\n", __func__); 116cefa5186SFinley Xiao return NULL; 117cefa5186SFinley Xiao } 118cefa5186SFinley Xiao 119cefa5186SFinley Xiao postdiv1 = DIV_ROUND_UP(VCO_MIN_HZ / 1000, rate_khz); 120cefa5186SFinley Xiao if (postdiv1 > max_postdiv1) { 121cefa5186SFinley Xiao postdiv2 = DIV_ROUND_UP(postdiv1, max_postdiv1); 122cefa5186SFinley Xiao postdiv1 = DIV_ROUND_UP(postdiv1, postdiv2); 123cefa5186SFinley Xiao } 124cefa5186SFinley Xiao 125cefa5186SFinley Xiao vco_khz = rate_khz * postdiv1 * postdiv2; 126cefa5186SFinley Xiao 127cefa5186SFinley Xiao if (vco_khz < (VCO_MIN_HZ / KHz) || vco_khz > (VCO_MAX_HZ / KHz) || 128cefa5186SFinley Xiao postdiv2 > max_postdiv2) { 129cefa5186SFinley Xiao printf("%s: Cannot find out a supported VCO for Freq (%uHz)\n", 130cefa5186SFinley Xiao __func__, rate_khz); 131cefa5186SFinley Xiao return NULL; 132cefa5186SFinley Xiao } 133cefa5186SFinley Xiao 134cefa5186SFinley Xiao rate->postdiv1 = postdiv1; 135cefa5186SFinley Xiao rate->postdiv2 = postdiv2; 136cefa5186SFinley Xiao 137cefa5186SFinley Xiao best_diff_khz = vco_khz; 138cefa5186SFinley Xiao for (refdiv = 1; refdiv < max_refdiv && best_diff_khz; refdiv++) { 139cefa5186SFinley Xiao fref_khz = ref_khz / refdiv; 140cefa5186SFinley Xiao 141cefa5186SFinley Xiao fbdiv = vco_khz / fref_khz; 142cefa5186SFinley Xiao if ((fbdiv >= max_fbdiv) || (fbdiv <= min_fbdiv)) 143cefa5186SFinley Xiao continue; 144cefa5186SFinley Xiao diff_khz = vco_khz - fbdiv * fref_khz; 145cefa5186SFinley Xiao if (fbdiv + 1 < max_fbdiv && diff_khz > fref_khz / 2) { 146cefa5186SFinley Xiao fbdiv++; 147cefa5186SFinley Xiao diff_khz = fref_khz - diff_khz; 148cefa5186SFinley Xiao } 149cefa5186SFinley Xiao 150cefa5186SFinley Xiao if (diff_khz >= best_diff_khz) 151cefa5186SFinley Xiao continue; 152cefa5186SFinley Xiao 153cefa5186SFinley Xiao best_diff_khz = diff_khz; 154cefa5186SFinley Xiao rate->refdiv = refdiv; 155cefa5186SFinley Xiao rate->fbdiv = fbdiv; 156cefa5186SFinley Xiao } 157cefa5186SFinley Xiao 158cefa5186SFinley Xiao if (best_diff_khz > 4 * (MHz / KHz)) { 159cefa5186SFinley Xiao printf("%s: Failed to match output frequency %u bestis %u Hz\n", 160cefa5186SFinley Xiao __func__, rate_khz, 161cefa5186SFinley Xiao best_diff_khz * KHz); 162cefa5186SFinley Xiao return NULL; 163cefa5186SFinley Xiao } 164cefa5186SFinley Xiao 165cefa5186SFinley Xiao return rate; 166cefa5186SFinley Xiao } 167cefa5186SFinley Xiao 168cefa5186SFinley Xiao static const struct pll_rate_table *get_pll_settings(unsigned long rate) 169cefa5186SFinley Xiao { 170cefa5186SFinley Xiao unsigned int rate_count = ARRAY_SIZE(px30_pll_rates); 171cefa5186SFinley Xiao int i; 172cefa5186SFinley Xiao 173cefa5186SFinley Xiao for (i = 0; i < rate_count; i++) { 174cefa5186SFinley Xiao if (rate == px30_pll_rates[i].rate) 175cefa5186SFinley Xiao return &px30_pll_rates[i]; 176cefa5186SFinley Xiao } 177cefa5186SFinley Xiao 178cefa5186SFinley Xiao return pll_clk_set_by_auto(rate); 179cefa5186SFinley Xiao } 180a60961a3SKever Yang 18137428b92SFinley Xiao static const struct cpu_rate_table *get_cpu_settings(unsigned long rate) 18237428b92SFinley Xiao { 18337428b92SFinley Xiao unsigned int rate_count = ARRAY_SIZE(px30_cpu_rates); 18437428b92SFinley Xiao int i; 18537428b92SFinley Xiao 18637428b92SFinley Xiao for (i = 0; i < rate_count; i++) { 18737428b92SFinley Xiao if (rate == px30_cpu_rates[i].rate) 18837428b92SFinley Xiao return &px30_cpu_rates[i]; 18937428b92SFinley Xiao } 19037428b92SFinley Xiao 19137428b92SFinley Xiao return NULL; 19237428b92SFinley Xiao } 19337428b92SFinley Xiao 194a60961a3SKever Yang /* 195a60961a3SKever Yang * How to calculate the PLL(from TRM V0.3 Part 1 Page 63): 196a60961a3SKever Yang * Formulas also embedded within the Fractional PLL Verilog model: 197a60961a3SKever Yang * If DSMPD = 1 (DSM is disabled, "integer mode") 198a60961a3SKever Yang * FOUTVCO = FREF / REFDIV * FBDIV 199a60961a3SKever Yang * FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2 200a60961a3SKever Yang * Where: 201a60961a3SKever Yang * FOUTVCO = Fractional PLL non-divided output frequency 202a60961a3SKever Yang * FOUTPOSTDIV = Fractional PLL divided output frequency 203a60961a3SKever Yang * (output of second post divider) 204a60961a3SKever Yang * FREF = Fractional PLL input reference frequency, (the OSC_HZ 24MHz input) 205a60961a3SKever Yang * REFDIV = Fractional PLL input reference clock divider 206a60961a3SKever Yang * FBDIV = Integer value programmed into feedback divide 207a60961a3SKever Yang * 208a60961a3SKever Yang */ 209cefa5186SFinley Xiao static int rkclk_set_pll(struct px30_pll *pll, unsigned int *mode, 210cefa5186SFinley Xiao enum px30_pll_id pll_id, 211cefa5186SFinley Xiao unsigned long drate) 212a60961a3SKever Yang { 213cefa5186SFinley Xiao const struct pll_rate_table *rate; 214cefa5186SFinley Xiao uint vco_hz, output_hz; 215db235eb5SFinley Xiao 216cefa5186SFinley Xiao rate = get_pll_settings(drate); 217cefa5186SFinley Xiao if (!rate) { 218cefa5186SFinley Xiao printf("%s unsupport rate\n", __func__); 219cefa5186SFinley Xiao return -EINVAL; 220cefa5186SFinley Xiao } 221cefa5186SFinley Xiao 222cefa5186SFinley Xiao /* All PLLs have same VCO and output frequency range restrictions. */ 223cefa5186SFinley Xiao vco_hz = OSC_HZ / 1000 * rate->fbdiv / rate->refdiv * 1000; 224cefa5186SFinley Xiao output_hz = vco_hz / rate->postdiv1 / rate->postdiv2; 225a60961a3SKever Yang 226a60961a3SKever Yang debug("PLL at %p: fb=%d, ref=%d, pst1=%d, pst2=%d, vco=%u Hz, output=%u Hz\n", 227cefa5186SFinley Xiao pll, rate->fbdiv, rate->refdiv, rate->postdiv1, 228cefa5186SFinley Xiao rate->postdiv2, vco_hz, output_hz); 229a60961a3SKever Yang assert(vco_hz >= VCO_MIN_HZ && vco_hz <= VCO_MAX_HZ && 230a60961a3SKever Yang output_hz >= OUTPUT_MIN_HZ && output_hz <= OUTPUT_MAX_HZ); 231a60961a3SKever Yang 232db235eb5SFinley Xiao /* 233db235eb5SFinley Xiao * When power on or changing PLL setting, 234db235eb5SFinley Xiao * we must force PLL into slow mode to ensure output stable clock. 235db235eb5SFinley Xiao */ 236bcefd077SFinley Xiao rk_clrsetreg(mode, pll_mode_mask[pll_id], 237bcefd077SFinley Xiao PLLMUX_FROM_XIN24M << pll_mode_shift[pll_id]); 238db235eb5SFinley Xiao 239a60961a3SKever Yang /* use integer mode */ 240a60961a3SKever Yang rk_setreg(&pll->con1, 1 << PLL_DSMPD_SHIFT); 241a60961a3SKever Yang /* Power down */ 242a60961a3SKever Yang rk_setreg(&pll->con1, 1 << PLL_PD_SHIFT); 243a60961a3SKever Yang 244a60961a3SKever Yang rk_clrsetreg(&pll->con0, 245a60961a3SKever Yang PLL_POSTDIV1_MASK | PLL_FBDIV_MASK, 246cefa5186SFinley Xiao (rate->postdiv1 << PLL_POSTDIV1_SHIFT) | rate->fbdiv); 247a60961a3SKever Yang rk_clrsetreg(&pll->con1, PLL_POSTDIV2_MASK | PLL_REFDIV_MASK, 248cefa5186SFinley Xiao (rate->postdiv2 << PLL_POSTDIV2_SHIFT | 249cefa5186SFinley Xiao rate->refdiv << PLL_REFDIV_SHIFT)); 250a60961a3SKever Yang 251a60961a3SKever Yang /* Power Up */ 252a60961a3SKever Yang rk_clrreg(&pll->con1, 1 << PLL_PD_SHIFT); 253a60961a3SKever Yang 254a60961a3SKever Yang /* waiting for pll lock */ 2556fb52eadSFinley Xiao while (!(readl(&pll->con1) & (1 << PLL_LOCK_STATUS_SHIFT))) 256a60961a3SKever Yang udelay(1); 257a60961a3SKever Yang 258bcefd077SFinley Xiao rk_clrsetreg(mode, pll_mode_mask[pll_id], 259bcefd077SFinley Xiao PLLMUX_FROM_PLL << pll_mode_shift[pll_id]); 260db235eb5SFinley Xiao 261cefa5186SFinley Xiao return 0; 262a60961a3SKever Yang } 263a60961a3SKever Yang 264cefa5186SFinley Xiao static uint32_t rkclk_pll_get_rate(struct px30_pll *pll, unsigned int *mode, 26530f1f38dSFinley Xiao enum px30_pll_id pll_id) 26630f1f38dSFinley Xiao { 26730f1f38dSFinley Xiao u32 refdiv, fbdiv, postdiv1, postdiv2; 268cefa5186SFinley Xiao u32 con, shift, mask; 26930f1f38dSFinley Xiao 270cefa5186SFinley Xiao con = readl(mode); 271bcefd077SFinley Xiao shift = pll_mode_shift[pll_id]; 272bcefd077SFinley Xiao mask = pll_mode_mask[pll_id]; 27330f1f38dSFinley Xiao 27430f1f38dSFinley Xiao switch ((con & mask) >> shift) { 27530f1f38dSFinley Xiao case PLLMUX_FROM_XIN24M: 27630f1f38dSFinley Xiao return OSC_HZ; 27730f1f38dSFinley Xiao case PLLMUX_FROM_PLL: 27830f1f38dSFinley Xiao /* normal mode */ 27930f1f38dSFinley Xiao con = readl(&pll->con0); 28030f1f38dSFinley Xiao postdiv1 = (con & PLL_POSTDIV1_MASK) >> PLL_POSTDIV1_SHIFT; 28130f1f38dSFinley Xiao fbdiv = (con & PLL_FBDIV_MASK) >> PLL_FBDIV_SHIFT; 28230f1f38dSFinley Xiao con = readl(&pll->con1); 28330f1f38dSFinley Xiao postdiv2 = (con & PLL_POSTDIV2_MASK) >> PLL_POSTDIV2_SHIFT; 28430f1f38dSFinley Xiao refdiv = (con & PLL_REFDIV_MASK) >> PLL_REFDIV_SHIFT; 28530f1f38dSFinley Xiao return (24 * fbdiv / (refdiv * postdiv1 * postdiv2)) * 1000000; 28630f1f38dSFinley Xiao case PLLMUX_FROM_RTC32K: 28730f1f38dSFinley Xiao default: 28830f1f38dSFinley Xiao return 32768; 28930f1f38dSFinley Xiao } 29030f1f38dSFinley Xiao } 29130f1f38dSFinley Xiao 292cefa5186SFinley Xiao static ulong px30_i2c_get_clk(struct px30_clk_priv *priv, ulong clk_id) 29330f1f38dSFinley Xiao { 294cefa5186SFinley Xiao struct px30_cru *cru = priv->cru; 295a60961a3SKever Yang u32 div, con; 296a60961a3SKever Yang 297a60961a3SKever Yang switch (clk_id) { 298a60961a3SKever Yang case SCLK_I2C0: 299f67f522bSFinley Xiao con = readl(&cru->clksel_con[49]); 300f67f522bSFinley Xiao div = con >> CLK_I2C0_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK; 301a60961a3SKever Yang break; 302a60961a3SKever Yang case SCLK_I2C1: 303f67f522bSFinley Xiao con = readl(&cru->clksel_con[49]); 304f67f522bSFinley Xiao div = con >> CLK_I2C1_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK; 305a60961a3SKever Yang break; 306a60961a3SKever Yang case SCLK_I2C2: 307f67f522bSFinley Xiao con = readl(&cru->clksel_con[50]); 308f67f522bSFinley Xiao div = con >> CLK_I2C2_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK; 309a60961a3SKever Yang break; 310a60961a3SKever Yang case SCLK_I2C3: 311f67f522bSFinley Xiao con = readl(&cru->clksel_con[50]); 312f67f522bSFinley Xiao div = con >> CLK_I2C3_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK; 313a60961a3SKever Yang break; 314a60961a3SKever Yang default: 315a60961a3SKever Yang printf("do not support this i2c bus\n"); 316a60961a3SKever Yang return -EINVAL; 317a60961a3SKever Yang } 318a60961a3SKever Yang 319cefa5186SFinley Xiao return DIV_TO_RATE(priv->gpll_hz, div); 320a60961a3SKever Yang } 321a60961a3SKever Yang 322cefa5186SFinley Xiao static ulong px30_i2c_set_clk(struct px30_clk_priv *priv, ulong clk_id, uint hz) 323a60961a3SKever Yang { 324cefa5186SFinley Xiao struct px30_cru *cru = priv->cru; 325a60961a3SKever Yang int src_clk_div; 326a60961a3SKever Yang 327cefa5186SFinley Xiao src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz); 328cb981eeaSFinley Xiao assert(src_clk_div - 1 <= 127); 329a60961a3SKever Yang 330a60961a3SKever Yang switch (clk_id) { 331a60961a3SKever Yang case SCLK_I2C0: 332f67f522bSFinley Xiao rk_clrsetreg(&cru->clksel_con[49], 333f67f522bSFinley Xiao CLK_I2C_DIV_CON_MASK << CLK_I2C0_DIV_CON_SHIFT | 334f67f522bSFinley Xiao CLK_I2C_PLL_SEL_MASK << CLK_I2C0_PLL_SEL_SHIFT, 335f67f522bSFinley Xiao (src_clk_div - 1) << CLK_I2C0_DIV_CON_SHIFT | 336f67f522bSFinley Xiao CLK_I2C_PLL_SEL_GPLL << CLK_I2C0_PLL_SEL_SHIFT); 337a60961a3SKever Yang break; 338a60961a3SKever Yang case SCLK_I2C1: 339f67f522bSFinley Xiao rk_clrsetreg(&cru->clksel_con[49], 340f67f522bSFinley Xiao CLK_I2C_DIV_CON_MASK << CLK_I2C1_DIV_CON_SHIFT | 341f67f522bSFinley Xiao CLK_I2C_PLL_SEL_MASK << CLK_I2C1_PLL_SEL_SHIFT, 342f67f522bSFinley Xiao (src_clk_div - 1) << CLK_I2C1_DIV_CON_SHIFT | 343f67f522bSFinley Xiao CLK_I2C_PLL_SEL_GPLL << CLK_I2C1_PLL_SEL_SHIFT); 344a60961a3SKever Yang break; 345a60961a3SKever Yang case SCLK_I2C2: 346f67f522bSFinley Xiao rk_clrsetreg(&cru->clksel_con[50], 347f67f522bSFinley Xiao CLK_I2C_DIV_CON_MASK << CLK_I2C2_DIV_CON_SHIFT | 348f67f522bSFinley Xiao CLK_I2C_PLL_SEL_MASK << CLK_I2C2_PLL_SEL_SHIFT, 349f67f522bSFinley Xiao (src_clk_div - 1) << CLK_I2C2_DIV_CON_SHIFT | 350f67f522bSFinley Xiao CLK_I2C_PLL_SEL_GPLL << CLK_I2C2_PLL_SEL_SHIFT); 351a60961a3SKever Yang break; 352a60961a3SKever Yang case SCLK_I2C3: 353f67f522bSFinley Xiao rk_clrsetreg(&cru->clksel_con[50], 354f67f522bSFinley Xiao CLK_I2C_DIV_CON_MASK << CLK_I2C3_DIV_CON_SHIFT | 355f67f522bSFinley Xiao CLK_I2C_PLL_SEL_MASK << CLK_I2C3_PLL_SEL_SHIFT, 356f67f522bSFinley Xiao (src_clk_div - 1) << CLK_I2C3_DIV_CON_SHIFT | 357f67f522bSFinley Xiao CLK_I2C_PLL_SEL_GPLL << CLK_I2C3_PLL_SEL_SHIFT); 358a60961a3SKever Yang break; 359a60961a3SKever Yang default: 360a60961a3SKever Yang printf("do not support this i2c bus\n"); 361a60961a3SKever Yang return -EINVAL; 362a60961a3SKever Yang } 363a60961a3SKever Yang 364cefa5186SFinley Xiao return px30_i2c_get_clk(priv, clk_id); 365a60961a3SKever Yang } 366a60961a3SKever Yang 367cefa5186SFinley Xiao static ulong px30_nandc_get_clk(struct px30_clk_priv *priv) 368a60961a3SKever Yang { 369cefa5186SFinley Xiao struct px30_cru *cru = priv->cru; 370cefa5186SFinley Xiao u32 div, con; 371cefa5186SFinley Xiao 372cefa5186SFinley Xiao con = readl(&cru->clksel_con[15]); 373cefa5186SFinley Xiao div = (con & NANDC_DIV_MASK) >> NANDC_DIV_SHIFT; 374cefa5186SFinley Xiao 37560a1199eSYifeng Zhao return DIV_TO_RATE(priv->gpll_hz, div); 376cefa5186SFinley Xiao } 377cefa5186SFinley Xiao 378cefa5186SFinley Xiao static ulong px30_nandc_set_clk(struct px30_clk_priv *priv, 379cefa5186SFinley Xiao ulong set_rate) 380cefa5186SFinley Xiao { 381cefa5186SFinley Xiao struct px30_cru *cru = priv->cru; 382cefa5186SFinley Xiao int src_clk_div; 383cefa5186SFinley Xiao 384cefa5186SFinley Xiao /* Select nandc source from GPLL by default */ 385cefa5186SFinley Xiao /* nandc clock defaulg div 2 internal, need provide double in cru */ 38660a1199eSYifeng Zhao src_clk_div = DIV_ROUND_UP(priv->gpll_hz, set_rate); 387cb981eeaSFinley Xiao assert(src_clk_div - 1 <= 31); 388cefa5186SFinley Xiao 389cefa5186SFinley Xiao rk_clrsetreg(&cru->clksel_con[15], 390cefa5186SFinley Xiao NANDC_CLK_SEL_MASK | NANDC_PLL_MASK | 391cefa5186SFinley Xiao NANDC_DIV_MASK, 392cefa5186SFinley Xiao NANDC_CLK_SEL_NANDC << NANDC_CLK_SEL_SHIFT | 393cefa5186SFinley Xiao NANDC_SEL_GPLL << NANDC_PLL_SHIFT | 394cefa5186SFinley Xiao (src_clk_div - 1) << NANDC_DIV_SHIFT); 395cefa5186SFinley Xiao 396cefa5186SFinley Xiao return px30_nandc_get_clk(priv); 397cefa5186SFinley Xiao } 398cefa5186SFinley Xiao 399cefa5186SFinley Xiao static ulong px30_mmc_get_clk(struct px30_clk_priv *priv, uint clk_id) 400cefa5186SFinley Xiao { 401cefa5186SFinley Xiao struct px30_cru *cru = priv->cru; 402a60961a3SKever Yang u32 div, con, con_id; 403a60961a3SKever Yang 404a60961a3SKever Yang switch (clk_id) { 405a60961a3SKever Yang case HCLK_SDMMC: 406a60961a3SKever Yang case SCLK_SDMMC: 407a60961a3SKever Yang con_id = 16; 408a60961a3SKever Yang break; 409a60961a3SKever Yang case HCLK_EMMC: 410a60961a3SKever Yang case SCLK_EMMC: 41196f1b3d9SKever Yang case SCLK_EMMC_SAMPLE: 412a60961a3SKever Yang con_id = 20; 413a60961a3SKever Yang break; 414a60961a3SKever Yang default: 415a60961a3SKever Yang return -EINVAL; 416a60961a3SKever Yang } 417a60961a3SKever Yang 418a60961a3SKever Yang con = readl(&cru->clksel_con[con_id]); 419a60961a3SKever Yang div = (con & EMMC_DIV_MASK) >> EMMC_DIV_SHIFT; 420a60961a3SKever Yang 421a60961a3SKever Yang if ((con & EMMC_PLL_MASK) >> EMMC_PLL_SHIFT 422a60961a3SKever Yang == EMMC_SEL_24M) 423a60961a3SKever Yang return DIV_TO_RATE(OSC_HZ, div) / 2; 424a60961a3SKever Yang else 425cefa5186SFinley Xiao return DIV_TO_RATE(priv->gpll_hz, div) / 2; 426a60961a3SKever Yang 427a60961a3SKever Yang } 428a60961a3SKever Yang 429cefa5186SFinley Xiao static ulong px30_mmc_set_clk(struct px30_clk_priv *priv, 430a60961a3SKever Yang ulong clk_id, ulong set_rate) 431a60961a3SKever Yang { 432cefa5186SFinley Xiao struct px30_cru *cru = priv->cru; 433a60961a3SKever Yang int src_clk_div; 434a60961a3SKever Yang u32 con_id; 435a60961a3SKever Yang 436a60961a3SKever Yang switch (clk_id) { 437a60961a3SKever Yang case HCLK_SDMMC: 438a60961a3SKever Yang case SCLK_SDMMC: 439a60961a3SKever Yang con_id = 16; 440a60961a3SKever Yang break; 441a60961a3SKever Yang case HCLK_EMMC: 442a60961a3SKever Yang case SCLK_EMMC: 443a60961a3SKever Yang con_id = 20; 444a60961a3SKever Yang break; 445a60961a3SKever Yang default: 446a60961a3SKever Yang return -EINVAL; 447a60961a3SKever Yang } 448cefa5186SFinley Xiao 449a60961a3SKever Yang /* Select clk_sdmmc/emmc source from GPLL by default */ 450a60961a3SKever Yang /* mmc clock defaulg div 2 internal, need provide double in cru */ 451cefa5186SFinley Xiao src_clk_div = DIV_ROUND_UP(priv->gpll_hz / 2, set_rate); 452a60961a3SKever Yang 453a60961a3SKever Yang if (src_clk_div > 127) { 454a60961a3SKever Yang /* use 24MHz source for 400KHz clock */ 455a60961a3SKever Yang src_clk_div = DIV_ROUND_UP(OSC_HZ / 2, set_rate); 456a60961a3SKever Yang rk_clrsetreg(&cru->clksel_con[con_id], 457a60961a3SKever Yang EMMC_PLL_MASK | EMMC_DIV_MASK, 458a60961a3SKever Yang EMMC_SEL_24M << EMMC_PLL_SHIFT | 459a60961a3SKever Yang (src_clk_div - 1) << EMMC_DIV_SHIFT); 460a60961a3SKever Yang } else { 461a60961a3SKever Yang rk_clrsetreg(&cru->clksel_con[con_id], 462a60961a3SKever Yang EMMC_PLL_MASK | EMMC_DIV_MASK, 463a60961a3SKever Yang EMMC_SEL_GPLL << EMMC_PLL_SHIFT | 464a60961a3SKever Yang (src_clk_div - 1) << EMMC_DIV_SHIFT); 465a60961a3SKever Yang } 466a60961a3SKever Yang rk_clrsetreg(&cru->clksel_con[con_id +1], EMMC_CLK_SEL_MASK, 467a60961a3SKever Yang EMMC_CLK_SEL_EMMC); 468a60961a3SKever Yang 469cefa5186SFinley Xiao return px30_mmc_get_clk(priv, clk_id); 470a60961a3SKever Yang } 471a60961a3SKever Yang 472cefa5186SFinley Xiao static ulong px30_pwm_get_clk(struct px30_clk_priv *priv, ulong clk_id) 473a60961a3SKever Yang { 474cefa5186SFinley Xiao struct px30_cru *cru = priv->cru; 475a60961a3SKever Yang u32 div, con; 476a60961a3SKever Yang 477f67f522bSFinley Xiao switch (clk_id) { 478f67f522bSFinley Xiao case SCLK_PWM0: 479f67f522bSFinley Xiao con = readl(&cru->clksel_con[52]); 480f67f522bSFinley Xiao div = con >> CLK_PWM0_DIV_CON_SHIFT & CLK_PWM_DIV_CON_MASK; 481f67f522bSFinley Xiao break; 482f67f522bSFinley Xiao case SCLK_PWM1: 483f67f522bSFinley Xiao con = readl(&cru->clksel_con[52]); 484f67f522bSFinley Xiao div = con >> CLK_PWM1_DIV_CON_SHIFT & CLK_PWM_DIV_CON_MASK; 485f67f522bSFinley Xiao break; 486f67f522bSFinley Xiao default: 487f67f522bSFinley Xiao printf("do not support this pwm bus\n"); 488f67f522bSFinley Xiao return -EINVAL; 489f67f522bSFinley Xiao } 490f67f522bSFinley Xiao 491cefa5186SFinley Xiao return DIV_TO_RATE(priv->gpll_hz, div); 492a60961a3SKever Yang } 493a60961a3SKever Yang 494cefa5186SFinley Xiao static ulong px30_pwm_set_clk(struct px30_clk_priv *priv, ulong clk_id, uint hz) 495a60961a3SKever Yang { 496cefa5186SFinley Xiao struct px30_cru *cru = priv->cru; 497f67f522bSFinley Xiao int src_clk_div; 498a60961a3SKever Yang 499cefa5186SFinley Xiao src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz); 500cb981eeaSFinley Xiao assert(src_clk_div - 1 <= 127); 501f67f522bSFinley Xiao 502f67f522bSFinley Xiao switch (clk_id) { 503f67f522bSFinley Xiao case SCLK_PWM0: 504f67f522bSFinley Xiao rk_clrsetreg(&cru->clksel_con[52], 505f67f522bSFinley Xiao CLK_PWM_DIV_CON_MASK << CLK_PWM0_DIV_CON_SHIFT | 506f67f522bSFinley Xiao CLK_PWM_PLL_SEL_MASK << CLK_PWM0_PLL_SEL_SHIFT, 507f67f522bSFinley Xiao (src_clk_div - 1) << CLK_PWM0_DIV_CON_SHIFT | 508f67f522bSFinley Xiao CLK_PWM_PLL_SEL_GPLL << CLK_PWM0_PLL_SEL_SHIFT); 509f67f522bSFinley Xiao break; 510f67f522bSFinley Xiao case SCLK_PWM1: 511f67f522bSFinley Xiao rk_clrsetreg(&cru->clksel_con[52], 512f67f522bSFinley Xiao CLK_PWM_DIV_CON_MASK << CLK_PWM1_DIV_CON_SHIFT | 513f67f522bSFinley Xiao CLK_PWM_PLL_SEL_MASK << CLK_PWM1_PLL_SEL_SHIFT, 514f67f522bSFinley Xiao (src_clk_div - 1) << CLK_PWM1_DIV_CON_SHIFT | 515f67f522bSFinley Xiao CLK_PWM_PLL_SEL_GPLL << CLK_PWM1_PLL_SEL_SHIFT); 516f67f522bSFinley Xiao break; 517f67f522bSFinley Xiao default: 518f67f522bSFinley Xiao printf("do not support this pwm bus\n"); 519f67f522bSFinley Xiao return -EINVAL; 520f67f522bSFinley Xiao } 521f67f522bSFinley Xiao 522cefa5186SFinley Xiao return px30_pwm_get_clk(priv, clk_id); 523a60961a3SKever Yang } 524a60961a3SKever Yang 525cefa5186SFinley Xiao static ulong px30_saradc_get_clk(struct px30_clk_priv *priv) 526a60961a3SKever Yang { 527cefa5186SFinley Xiao struct px30_cru *cru = priv->cru; 528f67f522bSFinley Xiao u32 div, con; 529f67f522bSFinley Xiao 530f67f522bSFinley Xiao con = readl(&cru->clksel_con[55]); 531f9157291SFinley Xiao div = con >> CLK_SARADC_DIV_CON_SHIFT & CLK_SARADC_DIV_CON_MASK; 532a60961a3SKever Yang 533a60961a3SKever Yang return DIV_TO_RATE(OSC_HZ, div); 534a60961a3SKever Yang } 535a60961a3SKever Yang 536cefa5186SFinley Xiao static ulong px30_saradc_set_clk(struct px30_clk_priv *priv, uint hz) 537a60961a3SKever Yang { 538cefa5186SFinley Xiao struct px30_cru *cru = priv->cru; 539a60961a3SKever Yang int src_clk_div; 540a60961a3SKever Yang 541cefa5186SFinley Xiao src_clk_div = DIV_ROUND_UP(OSC_HZ, hz); 542cb981eeaSFinley Xiao assert(src_clk_div - 1 <= 2047); 543a60961a3SKever Yang 544f67f522bSFinley Xiao rk_clrsetreg(&cru->clksel_con[55], 545f67f522bSFinley Xiao CLK_SARADC_DIV_CON_MASK, 546fce7cb7bSFinley Xiao (src_clk_div - 1) << CLK_SARADC_DIV_CON_SHIFT); 547f67f522bSFinley Xiao 548cefa5186SFinley Xiao return px30_saradc_get_clk(priv); 549f67f522bSFinley Xiao } 550f67f522bSFinley Xiao 551cefa5186SFinley Xiao static ulong px30_spi_get_clk(struct px30_clk_priv *priv, ulong clk_id) 552f67f522bSFinley Xiao { 553cefa5186SFinley Xiao struct px30_cru *cru = priv->cru; 554f67f522bSFinley Xiao u32 div, con; 555f67f522bSFinley Xiao 556f67f522bSFinley Xiao switch (clk_id) { 557fce7cb7bSFinley Xiao case SCLK_SPI0: 558f67f522bSFinley Xiao con = readl(&cru->clksel_con[53]); 559f67f522bSFinley Xiao div = con >> CLK_SPI0_DIV_CON_SHIFT & CLK_SPI_DIV_CON_MASK; 560f67f522bSFinley Xiao break; 561fce7cb7bSFinley Xiao case SCLK_SPI1: 562f67f522bSFinley Xiao con = readl(&cru->clksel_con[53]); 563f67f522bSFinley Xiao div = con >> CLK_SPI1_DIV_CON_SHIFT & CLK_SPI_DIV_CON_MASK; 564f67f522bSFinley Xiao break; 565f67f522bSFinley Xiao default: 566f67f522bSFinley Xiao printf("do not support this pwm bus\n"); 567f67f522bSFinley Xiao return -EINVAL; 568f67f522bSFinley Xiao } 569f67f522bSFinley Xiao 570cefa5186SFinley Xiao return DIV_TO_RATE(priv->gpll_hz, div); 571f67f522bSFinley Xiao } 572f67f522bSFinley Xiao 573cefa5186SFinley Xiao static ulong px30_spi_set_clk(struct px30_clk_priv *priv, ulong clk_id, uint hz) 574f67f522bSFinley Xiao { 575cefa5186SFinley Xiao struct px30_cru *cru = priv->cru; 576f67f522bSFinley Xiao int src_clk_div; 577f67f522bSFinley Xiao 578cefa5186SFinley Xiao src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz); 579cb981eeaSFinley Xiao assert(src_clk_div - 1 <= 127); 580f67f522bSFinley Xiao 581f67f522bSFinley Xiao switch (clk_id) { 582f67f522bSFinley Xiao case SCLK_SPI0: 583f67f522bSFinley Xiao rk_clrsetreg(&cru->clksel_con[53], 584f67f522bSFinley Xiao CLK_SPI_DIV_CON_MASK << CLK_SPI0_DIV_CON_SHIFT | 585f67f522bSFinley Xiao CLK_SPI_PLL_SEL_MASK << CLK_SPI0_PLL_SEL_SHIFT, 586f67f522bSFinley Xiao (src_clk_div - 1) << CLK_SPI0_DIV_CON_SHIFT | 587f67f522bSFinley Xiao CLK_SPI_PLL_SEL_GPLL << CLK_SPI0_PLL_SEL_SHIFT); 588f67f522bSFinley Xiao break; 589f67f522bSFinley Xiao case SCLK_SPI1: 590f67f522bSFinley Xiao rk_clrsetreg(&cru->clksel_con[53], 591f67f522bSFinley Xiao CLK_SPI_DIV_CON_MASK << CLK_SPI1_DIV_CON_SHIFT | 592f67f522bSFinley Xiao CLK_SPI_PLL_SEL_MASK << CLK_SPI1_PLL_SEL_SHIFT, 593f67f522bSFinley Xiao (src_clk_div - 1) << CLK_SPI1_DIV_CON_SHIFT | 594f67f522bSFinley Xiao CLK_SPI_PLL_SEL_GPLL << CLK_SPI1_PLL_SEL_SHIFT); 595f67f522bSFinley Xiao break; 596f67f522bSFinley Xiao default: 597f67f522bSFinley Xiao printf("do not support this pwm bus\n"); 598f67f522bSFinley Xiao return -EINVAL; 599f67f522bSFinley Xiao } 600f67f522bSFinley Xiao 601cefa5186SFinley Xiao return px30_spi_get_clk(priv, clk_id); 602a60961a3SKever Yang } 603a60961a3SKever Yang 604cefa5186SFinley Xiao static ulong px30_vop_get_clk(struct px30_clk_priv *priv, ulong clk_id) 60530f1f38dSFinley Xiao { 606cefa5186SFinley Xiao struct px30_cru *cru = priv->cru; 60730f1f38dSFinley Xiao u32 div, con, parent; 60830f1f38dSFinley Xiao 60930f1f38dSFinley Xiao switch (clk_id) { 61030f1f38dSFinley Xiao case ACLK_VOPB: 61130f1f38dSFinley Xiao con = readl(&cru->clksel_con[3]); 61230f1f38dSFinley Xiao div = con & ACLK_VO_DIV_MASK; 613cefa5186SFinley Xiao parent = priv->gpll_hz; 61430f1f38dSFinley Xiao break; 61530f1f38dSFinley Xiao case DCLK_VOPB: 61630f1f38dSFinley Xiao con = readl(&cru->clksel_con[5]); 61730f1f38dSFinley Xiao div = con & DCLK_VOPB_DIV_MASK; 618cefa5186SFinley Xiao parent = rkclk_pll_get_rate(&cru->pll[CPLL], &cru->mode, CPLL); 61930f1f38dSFinley Xiao break; 62030f1f38dSFinley Xiao default: 62130f1f38dSFinley Xiao return -ENOENT; 62230f1f38dSFinley Xiao } 62330f1f38dSFinley Xiao 62430f1f38dSFinley Xiao return DIV_TO_RATE(parent, div); 62530f1f38dSFinley Xiao } 62630f1f38dSFinley Xiao 627cefa5186SFinley Xiao static ulong px30_vop_set_clk(struct px30_clk_priv *priv, ulong clk_id, uint hz) 62830f1f38dSFinley Xiao { 629cefa5186SFinley Xiao struct px30_cru *cru = priv->cru; 63030f1f38dSFinley Xiao int src_clk_div; 63130f1f38dSFinley Xiao 63230f1f38dSFinley Xiao switch (clk_id) { 63330f1f38dSFinley Xiao case ACLK_VOPB: 634*f909d4a8SFinley Xiao src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz); 635*f909d4a8SFinley Xiao assert(src_clk_div - 1 <= 31); 63630f1f38dSFinley Xiao rk_clrsetreg(&cru->clksel_con[3], 63730f1f38dSFinley Xiao ACLK_VO_PLL_MASK | ACLK_VO_DIV_MASK, 63830f1f38dSFinley Xiao ACLK_VO_SEL_GPLL << ACLK_VO_PLL_SHIFT | 63930f1f38dSFinley Xiao (src_clk_div - 1) << ACLK_VO_DIV_SHIFT); 64030f1f38dSFinley Xiao break; 64130f1f38dSFinley Xiao case DCLK_VOPB: 642*f909d4a8SFinley Xiao if (hz < PX30_VOP_PLL_LIMIT) 643*f909d4a8SFinley Xiao src_clk_div = DIV_ROUND_UP(PX30_VOP_PLL_LIMIT, hz); 644*f909d4a8SFinley Xiao else 645*f909d4a8SFinley Xiao src_clk_div = 1; 646*f909d4a8SFinley Xiao assert(src_clk_div - 1 <= 255); 647*f909d4a8SFinley Xiao rkclk_set_pll(&cru->pll[CPLL], &cru->mode, CPLL, hz * src_clk_div); 64830f1f38dSFinley Xiao rk_clrsetreg(&cru->clksel_con[5], 64930f1f38dSFinley Xiao DCLK_VOPB_SEL_MASK | DCLK_VOPB_PLL_SEL_MASK | 65030f1f38dSFinley Xiao DCLK_VOPB_DIV_MASK, 65130f1f38dSFinley Xiao DCLK_VOPB_SEL_DIVOUT << DCLK_VOPB_SEL_SHIFT | 65230f1f38dSFinley Xiao DCLK_VOPB_PLL_SEL_CPLL << DCLK_VOPB_PLL_SEL_SHIFT | 653*f909d4a8SFinley Xiao (src_clk_div - 1) << DCLK_VOPB_DIV_SHIFT); 65430f1f38dSFinley Xiao break; 65530f1f38dSFinley Xiao default: 65630f1f38dSFinley Xiao printf("do not support this vop freq\n"); 65730f1f38dSFinley Xiao return -EINVAL; 65830f1f38dSFinley Xiao } 65930f1f38dSFinley Xiao 660cefa5186SFinley Xiao return px30_vop_get_clk(priv, clk_id); 66130f1f38dSFinley Xiao } 66230f1f38dSFinley Xiao 663cefa5186SFinley Xiao static ulong px30_bus_get_clk(struct px30_clk_priv *priv, ulong clk_id) 664df8f8a42SFinley Xiao { 665cefa5186SFinley Xiao struct px30_cru *cru = priv->cru; 666df8f8a42SFinley Xiao u32 div, con, parent; 667df8f8a42SFinley Xiao 668df8f8a42SFinley Xiao switch (clk_id) { 669df8f8a42SFinley Xiao case ACLK_BUS_PRE: 670df8f8a42SFinley Xiao con = readl(&cru->clksel_con[23]); 671df8f8a42SFinley Xiao div = (con & BUS_ACLK_DIV_MASK) >> BUS_ACLK_DIV_SHIFT; 672cefa5186SFinley Xiao parent = priv->gpll_hz; 673df8f8a42SFinley Xiao break; 674df8f8a42SFinley Xiao case HCLK_BUS_PRE: 675df8f8a42SFinley Xiao con = readl(&cru->clksel_con[24]); 676df8f8a42SFinley Xiao div = (con & BUS_HCLK_DIV_MASK) >> BUS_HCLK_DIV_SHIFT; 677cefa5186SFinley Xiao parent = priv->gpll_hz; 678df8f8a42SFinley Xiao break; 679df8f8a42SFinley Xiao case PCLK_BUS_PRE: 680cefa5186SFinley Xiao parent = px30_bus_get_clk(priv, ACLK_BUS_PRE); 681df8f8a42SFinley Xiao con = readl(&cru->clksel_con[24]); 682df8f8a42SFinley Xiao div = (con & BUS_PCLK_DIV_MASK) >> BUS_PCLK_DIV_SHIFT; 683df8f8a42SFinley Xiao break; 684df8f8a42SFinley Xiao default: 685df8f8a42SFinley Xiao return -ENOENT; 686df8f8a42SFinley Xiao } 687df8f8a42SFinley Xiao 688df8f8a42SFinley Xiao return DIV_TO_RATE(parent, div); 689df8f8a42SFinley Xiao } 690df8f8a42SFinley Xiao 691cefa5186SFinley Xiao static ulong px30_bus_set_clk(struct px30_clk_priv *priv, ulong clk_id, 692cefa5186SFinley Xiao ulong hz) 693df8f8a42SFinley Xiao { 694cefa5186SFinley Xiao struct px30_cru *cru = priv->cru; 695df8f8a42SFinley Xiao int src_clk_div; 696df8f8a42SFinley Xiao 697df8f8a42SFinley Xiao /* 698df8f8a42SFinley Xiao * select gpll as pd_bus bus clock source and 699df8f8a42SFinley Xiao * set up dependent divisors for PCLK/HCLK and ACLK clocks. 700df8f8a42SFinley Xiao */ 701df8f8a42SFinley Xiao switch (clk_id) { 702df8f8a42SFinley Xiao case ACLK_BUS_PRE: 703cefa5186SFinley Xiao src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz); 704cb981eeaSFinley Xiao assert(src_clk_div - 1 <= 31); 705df8f8a42SFinley Xiao rk_clrsetreg(&cru->clksel_con[23], 706df8f8a42SFinley Xiao BUS_PLL_SEL_MASK | BUS_ACLK_DIV_MASK, 707df8f8a42SFinley Xiao BUS_PLL_SEL_GPLL << BUS_PLL_SEL_SHIFT | 708df8f8a42SFinley Xiao (src_clk_div - 1) << BUS_ACLK_DIV_SHIFT); 709df8f8a42SFinley Xiao break; 710df8f8a42SFinley Xiao case HCLK_BUS_PRE: 711cefa5186SFinley Xiao src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz); 712cb981eeaSFinley Xiao assert(src_clk_div - 1 <= 31); 713df8f8a42SFinley Xiao rk_clrsetreg(&cru->clksel_con[24], 714df8f8a42SFinley Xiao BUS_PLL_SEL_MASK | BUS_HCLK_DIV_MASK, 715df8f8a42SFinley Xiao BUS_PLL_SEL_GPLL << BUS_PLL_SEL_SHIFT | 716df8f8a42SFinley Xiao (src_clk_div - 1) << BUS_HCLK_DIV_SHIFT); 717df8f8a42SFinley Xiao break; 718df8f8a42SFinley Xiao case PCLK_BUS_PRE: 719cefa5186SFinley Xiao src_clk_div = 720cefa5186SFinley Xiao DIV_ROUND_UP(px30_bus_get_clk(priv, ACLK_BUS_PRE), hz); 721cb981eeaSFinley Xiao assert(src_clk_div - 1 <= 3); 722df8f8a42SFinley Xiao rk_clrsetreg(&cru->clksel_con[24], 723df8f8a42SFinley Xiao BUS_PCLK_DIV_MASK, 724df8f8a42SFinley Xiao (src_clk_div - 1) << BUS_PCLK_DIV_SHIFT); 725df8f8a42SFinley Xiao break; 726df8f8a42SFinley Xiao default: 727df8f8a42SFinley Xiao printf("do not support this bus freq\n"); 728df8f8a42SFinley Xiao return -EINVAL; 729df8f8a42SFinley Xiao } 730df8f8a42SFinley Xiao 731cefa5186SFinley Xiao return px30_bus_get_clk(priv, clk_id); 732df8f8a42SFinley Xiao } 733df8f8a42SFinley Xiao 734cefa5186SFinley Xiao static ulong px30_peri_get_clk(struct px30_clk_priv *priv, ulong clk_id) 735df8f8a42SFinley Xiao { 736cefa5186SFinley Xiao struct px30_cru *cru = priv->cru; 737df8f8a42SFinley Xiao u32 div, con, parent; 738df8f8a42SFinley Xiao 739df8f8a42SFinley Xiao switch (clk_id) { 740df8f8a42SFinley Xiao case ACLK_PERI_PRE: 741df8f8a42SFinley Xiao con = readl(&cru->clksel_con[14]); 742df8f8a42SFinley Xiao div = (con & PERI_ACLK_DIV_MASK) >> PERI_ACLK_DIV_SHIFT; 743cefa5186SFinley Xiao parent = priv->gpll_hz; 744df8f8a42SFinley Xiao break; 745df8f8a42SFinley Xiao case HCLK_PERI_PRE: 746df8f8a42SFinley Xiao con = readl(&cru->clksel_con[14]); 747df8f8a42SFinley Xiao div = (con & PERI_HCLK_DIV_MASK) >> PERI_HCLK_DIV_SHIFT; 748cefa5186SFinley Xiao parent = priv->gpll_hz; 749df8f8a42SFinley Xiao break; 750df8f8a42SFinley Xiao default: 751df8f8a42SFinley Xiao return -ENOENT; 752df8f8a42SFinley Xiao } 753df8f8a42SFinley Xiao 754df8f8a42SFinley Xiao return DIV_TO_RATE(parent, div); 755df8f8a42SFinley Xiao } 756df8f8a42SFinley Xiao 757cefa5186SFinley Xiao static ulong px30_peri_set_clk(struct px30_clk_priv *priv, ulong clk_id, 758cefa5186SFinley Xiao ulong hz) 759df8f8a42SFinley Xiao { 760cefa5186SFinley Xiao struct px30_cru *cru = priv->cru; 761df8f8a42SFinley Xiao int src_clk_div; 762df8f8a42SFinley Xiao 763cefa5186SFinley Xiao src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz); 764cb981eeaSFinley Xiao assert(src_clk_div - 1 <= 31); 765df8f8a42SFinley Xiao 766df8f8a42SFinley Xiao /* 767df8f8a42SFinley Xiao * select gpll as pd_peri bus clock source and 768df8f8a42SFinley Xiao * set up dependent divisors for HCLK and ACLK clocks. 769df8f8a42SFinley Xiao */ 770df8f8a42SFinley Xiao switch (clk_id) { 771df8f8a42SFinley Xiao case ACLK_PERI_PRE: 772df8f8a42SFinley Xiao rk_clrsetreg(&cru->clksel_con[14], 773df8f8a42SFinley Xiao PERI_PLL_SEL_MASK | PERI_ACLK_DIV_MASK, 774df8f8a42SFinley Xiao PERI_PLL_GPLL << PERI_PLL_SEL_SHIFT | 775df8f8a42SFinley Xiao (src_clk_div - 1) << PERI_ACLK_DIV_SHIFT); 776df8f8a42SFinley Xiao break; 777df8f8a42SFinley Xiao case HCLK_PERI_PRE: 778df8f8a42SFinley Xiao rk_clrsetreg(&cru->clksel_con[14], 779df8f8a42SFinley Xiao PERI_PLL_SEL_MASK | PERI_HCLK_DIV_MASK, 780df8f8a42SFinley Xiao PERI_PLL_GPLL << PERI_PLL_SEL_SHIFT | 781df8f8a42SFinley Xiao (src_clk_div - 1) << PERI_HCLK_DIV_SHIFT); 782df8f8a42SFinley Xiao break; 783df8f8a42SFinley Xiao default: 784df8f8a42SFinley Xiao printf("do not support this peri freq\n"); 785df8f8a42SFinley Xiao return -EINVAL; 786df8f8a42SFinley Xiao } 787df8f8a42SFinley Xiao 788cefa5186SFinley Xiao return px30_peri_get_clk(priv, clk_id); 789cefa5186SFinley Xiao } 790cefa5186SFinley Xiao 791cefa5186SFinley Xiao static int px30_clk_get_gpll_rate(ulong *rate) 792cefa5186SFinley Xiao { 793cefa5186SFinley Xiao struct udevice *pmucru_dev; 794cefa5186SFinley Xiao struct px30_pmuclk_priv *priv; 795cefa5186SFinley Xiao int ret; 796cefa5186SFinley Xiao 797cefa5186SFinley Xiao ret = uclass_get_device_by_driver(UCLASS_CLK, 798cefa5186SFinley Xiao DM_GET_DRIVER(rockchip_px30_pmucru), 799cefa5186SFinley Xiao &pmucru_dev); 800cefa5186SFinley Xiao if (ret) { 801cefa5186SFinley Xiao printf("%s: could not find pmucru device\n", __func__); 802cefa5186SFinley Xiao return ret; 803cefa5186SFinley Xiao } 804cefa5186SFinley Xiao priv = dev_get_priv(pmucru_dev); 805c4d4e4dcSFinley Xiao *rate = priv->gpll_hz; 806cefa5186SFinley Xiao 807cefa5186SFinley Xiao return 0; 808df8f8a42SFinley Xiao } 809df8f8a42SFinley Xiao 8108b1aed51SFinley Xiao static ulong px30_clk_get_pll_rate(struct px30_clk_priv *priv, 8118b1aed51SFinley Xiao enum px30_pll_id pll_id) 8128b1aed51SFinley Xiao { 8138b1aed51SFinley Xiao struct px30_cru *cru = priv->cru; 8148b1aed51SFinley Xiao 8158b1aed51SFinley Xiao return rkclk_pll_get_rate(&cru->pll[pll_id], &cru->mode, pll_id); 8168b1aed51SFinley Xiao } 8178b1aed51SFinley Xiao 818a221d6e6SFinley Xiao static ulong px30_clk_set_pll_rate(struct px30_clk_priv *priv, 819a221d6e6SFinley Xiao enum px30_pll_id pll_id, ulong hz) 820a221d6e6SFinley Xiao { 821a221d6e6SFinley Xiao struct px30_cru *cru = priv->cru; 822a221d6e6SFinley Xiao 823a221d6e6SFinley Xiao if (rkclk_set_pll(&cru->pll[pll_id], &cru->mode, pll_id, hz)) 824a221d6e6SFinley Xiao return -EINVAL; 825a221d6e6SFinley Xiao return rkclk_pll_get_rate(&cru->pll[pll_id], &cru->mode, pll_id); 826a221d6e6SFinley Xiao } 827a221d6e6SFinley Xiao 82837428b92SFinley Xiao static ulong px30_armclk_set_clk(struct px30_clk_priv *priv, ulong hz) 82937428b92SFinley Xiao { 83037428b92SFinley Xiao struct px30_cru *cru = priv->cru; 83137428b92SFinley Xiao const struct cpu_rate_table *rate; 83237428b92SFinley Xiao ulong old_rate; 83337428b92SFinley Xiao 83437428b92SFinley Xiao rate = get_cpu_settings(hz); 83537428b92SFinley Xiao if (!rate) { 83637428b92SFinley Xiao printf("%s unsupport rate\n", __func__); 83737428b92SFinley Xiao return -EINVAL; 83837428b92SFinley Xiao } 83937428b92SFinley Xiao 84037428b92SFinley Xiao /* 84137428b92SFinley Xiao * select apll as cpu/core clock pll source and 84237428b92SFinley Xiao * set up dependent divisors for PERI and ACLK clocks. 84337428b92SFinley Xiao * core hz : apll = 1:1 84437428b92SFinley Xiao */ 84537428b92SFinley Xiao old_rate = px30_clk_get_pll_rate(priv, APLL); 84637428b92SFinley Xiao if (old_rate > hz) { 84737428b92SFinley Xiao if (rkclk_set_pll(&cru->pll[APLL], &cru->mode, APLL, hz)) 84837428b92SFinley Xiao return -EINVAL; 84937428b92SFinley Xiao rk_clrsetreg(&cru->clksel_con[0], 85037428b92SFinley Xiao CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK | 85137428b92SFinley Xiao CORE_ACLK_DIV_MASK | CORE_DBG_DIV_MASK, 85237428b92SFinley Xiao rate->aclk_div << CORE_ACLK_DIV_SHIFT | 85337428b92SFinley Xiao rate->pclk_div << CORE_DBG_DIV_SHIFT | 85437428b92SFinley Xiao CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT | 85537428b92SFinley Xiao 0 << CORE_DIV_CON_SHIFT); 85637428b92SFinley Xiao } else if (old_rate < hz) { 85737428b92SFinley Xiao rk_clrsetreg(&cru->clksel_con[0], 85837428b92SFinley Xiao CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK | 85937428b92SFinley Xiao CORE_ACLK_DIV_MASK | CORE_DBG_DIV_MASK, 86037428b92SFinley Xiao rate->aclk_div << CORE_ACLK_DIV_SHIFT | 86137428b92SFinley Xiao rate->pclk_div << CORE_DBG_DIV_SHIFT | 86237428b92SFinley Xiao CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT | 86337428b92SFinley Xiao 0 << CORE_DIV_CON_SHIFT); 86437428b92SFinley Xiao if (rkclk_set_pll(&cru->pll[APLL], &cru->mode, APLL, hz)) 86537428b92SFinley Xiao return -EINVAL; 86637428b92SFinley Xiao } 86737428b92SFinley Xiao 86837428b92SFinley Xiao return px30_clk_get_pll_rate(priv, APLL); 86937428b92SFinley Xiao } 87037428b92SFinley Xiao 871a60961a3SKever Yang static ulong px30_clk_get_rate(struct clk *clk) 872a60961a3SKever Yang { 873a60961a3SKever Yang struct px30_clk_priv *priv = dev_get_priv(clk->dev); 874a60961a3SKever Yang ulong rate = 0; 875a60961a3SKever Yang 876c4d4e4dcSFinley Xiao if (!priv->gpll_hz && clk->id > ARMCLK) { 877c4d4e4dcSFinley Xiao printf("%s gpll=%lu\n", __func__, priv->gpll_hz); 878c4d4e4dcSFinley Xiao return -ENOENT; 879cefa5186SFinley Xiao } 880cefa5186SFinley Xiao 881cefa5186SFinley Xiao debug("%s %ld\n", __func__, clk->id); 882a60961a3SKever Yang switch (clk->id) { 8838b1aed51SFinley Xiao case PLL_APLL: 8848b1aed51SFinley Xiao rate = px30_clk_get_pll_rate(priv, APLL); 8858b1aed51SFinley Xiao break; 8868b1aed51SFinley Xiao case PLL_DPLL: 8878b1aed51SFinley Xiao rate = px30_clk_get_pll_rate(priv, DPLL); 8888b1aed51SFinley Xiao break; 8898b1aed51SFinley Xiao case PLL_CPLL: 8908b1aed51SFinley Xiao rate = px30_clk_get_pll_rate(priv, CPLL); 8918b1aed51SFinley Xiao break; 8928b1aed51SFinley Xiao case PLL_NPLL: 8938b1aed51SFinley Xiao rate = px30_clk_get_pll_rate(priv, NPLL); 8948b1aed51SFinley Xiao break; 89537428b92SFinley Xiao case ARMCLK: 89637428b92SFinley Xiao rate = px30_clk_get_pll_rate(priv, APLL); 89737428b92SFinley Xiao break; 898a60961a3SKever Yang case HCLK_SDMMC: 899a60961a3SKever Yang case HCLK_EMMC: 900a60961a3SKever Yang case SCLK_SDMMC: 901a60961a3SKever Yang case SCLK_EMMC: 90296f1b3d9SKever Yang case SCLK_EMMC_SAMPLE: 903cefa5186SFinley Xiao rate = px30_mmc_get_clk(priv, clk->id); 904a60961a3SKever Yang break; 905a60961a3SKever Yang case SCLK_I2C0: 906a60961a3SKever Yang case SCLK_I2C1: 907a60961a3SKever Yang case SCLK_I2C2: 908a60961a3SKever Yang case SCLK_I2C3: 909cefa5186SFinley Xiao rate = px30_i2c_get_clk(priv, clk->id); 910a60961a3SKever Yang break; 911a60961a3SKever Yang case SCLK_PWM0: 912fce7cb7bSFinley Xiao case SCLK_PWM1: 913cefa5186SFinley Xiao rate = px30_pwm_get_clk(priv, clk->id); 914a60961a3SKever Yang break; 915a60961a3SKever Yang case SCLK_SARADC: 916cefa5186SFinley Xiao rate = px30_saradc_get_clk(priv); 917a60961a3SKever Yang break; 918f67f522bSFinley Xiao case SCLK_SPI0: 919f67f522bSFinley Xiao case SCLK_SPI1: 920cefa5186SFinley Xiao rate = px30_spi_get_clk(priv, clk->id); 921f67f522bSFinley Xiao break; 92230f1f38dSFinley Xiao case ACLK_VOPB: 92330f1f38dSFinley Xiao case DCLK_VOPB: 924cefa5186SFinley Xiao rate = px30_vop_get_clk(priv, clk->id); 92530f1f38dSFinley Xiao break; 926df8f8a42SFinley Xiao case ACLK_BUS_PRE: 927df8f8a42SFinley Xiao case HCLK_BUS_PRE: 928df8f8a42SFinley Xiao case PCLK_BUS_PRE: 929cefa5186SFinley Xiao rate = px30_bus_get_clk(priv, clk->id); 930df8f8a42SFinley Xiao break; 931df8f8a42SFinley Xiao case ACLK_PERI_PRE: 932df8f8a42SFinley Xiao case HCLK_PERI_PRE: 933cefa5186SFinley Xiao rate = px30_peri_get_clk(priv, clk->id); 934df8f8a42SFinley Xiao break; 935a60961a3SKever Yang default: 936a60961a3SKever Yang return -ENOENT; 937a60961a3SKever Yang } 938a60961a3SKever Yang 939a60961a3SKever Yang return rate; 940a60961a3SKever Yang } 941a60961a3SKever Yang 942a60961a3SKever Yang static ulong px30_clk_set_rate(struct clk *clk, ulong rate) 943a60961a3SKever Yang { 944a60961a3SKever Yang struct px30_clk_priv *priv = dev_get_priv(clk->dev); 945a60961a3SKever Yang ulong ret = 0; 946a60961a3SKever Yang 947c4d4e4dcSFinley Xiao if (!priv->gpll_hz && clk->id > ARMCLK) { 948c4d4e4dcSFinley Xiao printf("%s gpll=%lu\n", __func__, priv->gpll_hz); 949c4d4e4dcSFinley Xiao return -ENOENT; 950cefa5186SFinley Xiao } 951cefa5186SFinley Xiao 952c4867301SKever Yang debug("%s %ld %ld\n", __func__, clk->id, rate); 953a60961a3SKever Yang switch (clk->id) { 954a221d6e6SFinley Xiao case PLL_NPLL: 955a221d6e6SFinley Xiao ret = px30_clk_set_pll_rate(priv, NPLL, rate); 956a221d6e6SFinley Xiao break; 95737428b92SFinley Xiao case ARMCLK: 95837428b92SFinley Xiao if (priv->armclk_hz) 95937428b92SFinley Xiao px30_armclk_set_clk(priv, rate); 96037428b92SFinley Xiao priv->armclk_hz = rate; 96137428b92SFinley Xiao break; 962a60961a3SKever Yang case HCLK_SDMMC: 963a60961a3SKever Yang case HCLK_EMMC: 964a60961a3SKever Yang case SCLK_SDMMC: 965a60961a3SKever Yang case SCLK_EMMC: 966cefa5186SFinley Xiao ret = px30_mmc_set_clk(priv, clk->id, rate); 967a60961a3SKever Yang break; 968a60961a3SKever Yang case SCLK_I2C0: 969a60961a3SKever Yang case SCLK_I2C1: 970a60961a3SKever Yang case SCLK_I2C2: 971a60961a3SKever Yang case SCLK_I2C3: 972cefa5186SFinley Xiao ret = px30_i2c_set_clk(priv, clk->id, rate); 973a60961a3SKever Yang break; 974a60961a3SKever Yang case SCLK_PWM0: 975f67f522bSFinley Xiao case SCLK_PWM1: 976cefa5186SFinley Xiao ret = px30_pwm_set_clk(priv, clk->id, rate); 977a60961a3SKever Yang break; 978a60961a3SKever Yang case SCLK_SARADC: 979cefa5186SFinley Xiao ret = px30_saradc_set_clk(priv, rate); 980a60961a3SKever Yang break; 981f67f522bSFinley Xiao case SCLK_SPI0: 982f67f522bSFinley Xiao case SCLK_SPI1: 983cefa5186SFinley Xiao ret = px30_spi_set_clk(priv, clk->id, rate); 984f67f522bSFinley Xiao break; 98530f1f38dSFinley Xiao case ACLK_VOPB: 98630f1f38dSFinley Xiao case DCLK_VOPB: 987cefa5186SFinley Xiao ret = px30_vop_set_clk(priv, clk->id, rate); 98830f1f38dSFinley Xiao break; 989df8f8a42SFinley Xiao case ACLK_BUS_PRE: 990df8f8a42SFinley Xiao case HCLK_BUS_PRE: 991df8f8a42SFinley Xiao case PCLK_BUS_PRE: 992cefa5186SFinley Xiao ret = px30_bus_set_clk(priv, clk->id, rate); 993df8f8a42SFinley Xiao break; 994df8f8a42SFinley Xiao case ACLK_PERI_PRE: 995df8f8a42SFinley Xiao case HCLK_PERI_PRE: 996cefa5186SFinley Xiao ret = px30_peri_set_clk(priv, clk->id, rate); 997df8f8a42SFinley Xiao break; 998a60961a3SKever Yang default: 999a60961a3SKever Yang return -ENOENT; 1000a60961a3SKever Yang } 1001a60961a3SKever Yang 1002a60961a3SKever Yang return ret; 1003a60961a3SKever Yang } 1004a60961a3SKever Yang 1005a60961a3SKever Yang #define ROCKCHIP_MMC_DELAY_SEL BIT(10) 1006a60961a3SKever Yang #define ROCKCHIP_MMC_DEGREE_MASK 0x3 1007a60961a3SKever Yang #define ROCKCHIP_MMC_DELAYNUM_OFFSET 2 1008a60961a3SKever Yang #define ROCKCHIP_MMC_DELAYNUM_MASK (0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET) 1009a60961a3SKever Yang 1010a60961a3SKever Yang #define PSECS_PER_SEC 1000000000000LL 1011a60961a3SKever Yang /* 1012a60961a3SKever Yang * Each fine delay is between 44ps-77ps. Assume each fine delay is 60ps to 1013a60961a3SKever Yang * simplify calculations. So 45degs could be anywhere between 33deg and 57.8deg. 1014a60961a3SKever Yang */ 1015a60961a3SKever Yang #define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60 1016a60961a3SKever Yang 1017a60961a3SKever Yang int rockchip_mmc_get_phase(struct clk *clk) 1018a60961a3SKever Yang { 1019a60961a3SKever Yang struct px30_clk_priv *priv = dev_get_priv(clk->dev); 1020a60961a3SKever Yang struct px30_cru *cru = priv->cru; 1021a60961a3SKever Yang u32 raw_value, delay_num; 1022a60961a3SKever Yang u16 degrees = 0; 1023a60961a3SKever Yang ulong rate; 1024a60961a3SKever Yang 1025a60961a3SKever Yang rate = px30_clk_get_rate(clk); 1026a60961a3SKever Yang 1027a60961a3SKever Yang if (rate < 0) 1028a60961a3SKever Yang return rate; 1029a60961a3SKever Yang 1030a60961a3SKever Yang if (clk->id == SCLK_EMMC_SAMPLE) 1031a60961a3SKever Yang raw_value = readl(&cru->emmc_con[1]); 1032a60961a3SKever Yang else 1033a60961a3SKever Yang raw_value = readl(&cru->sdmmc_con[1]); 1034a60961a3SKever Yang 103596f1b3d9SKever Yang raw_value >>= 1; 1036a60961a3SKever Yang degrees = (raw_value & ROCKCHIP_MMC_DEGREE_MASK) * 90; 1037a60961a3SKever Yang 1038a60961a3SKever Yang if (raw_value & ROCKCHIP_MMC_DELAY_SEL) { 1039a60961a3SKever Yang /* degrees/delaynum * 10000 */ 1040a60961a3SKever Yang unsigned long factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) * 1041a60961a3SKever Yang 36 * (rate / 1000000); 1042a60961a3SKever Yang 1043a60961a3SKever Yang delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK); 1044a60961a3SKever Yang delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET; 1045a60961a3SKever Yang degrees += DIV_ROUND_CLOSEST(delay_num * factor, 10000); 1046a60961a3SKever Yang } 1047a60961a3SKever Yang 1048a60961a3SKever Yang return degrees % 360; 1049a60961a3SKever Yang } 1050a60961a3SKever Yang 1051a60961a3SKever Yang int rockchip_mmc_set_phase(struct clk *clk, u32 degrees) 1052a60961a3SKever Yang { 1053a60961a3SKever Yang struct px30_clk_priv *priv = dev_get_priv(clk->dev); 1054a60961a3SKever Yang struct px30_cru *cru = priv->cru; 1055a60961a3SKever Yang u8 nineties, remainder, delay_num; 1056a60961a3SKever Yang u32 raw_value, delay; 1057a60961a3SKever Yang ulong rate; 1058a60961a3SKever Yang 1059a60961a3SKever Yang rate = px30_clk_get_rate(clk); 1060a60961a3SKever Yang 1061a60961a3SKever Yang if (rate < 0) 1062a60961a3SKever Yang return rate; 1063a60961a3SKever Yang 1064a60961a3SKever Yang nineties = degrees / 90; 1065a60961a3SKever Yang remainder = (degrees % 90); 1066a60961a3SKever Yang 1067a60961a3SKever Yang /* 1068a60961a3SKever Yang * Convert to delay; do a little extra work to make sure we 1069a60961a3SKever Yang * don't overflow 32-bit / 64-bit numbers. 1070a60961a3SKever Yang */ 1071a60961a3SKever Yang delay = 10000000; /* PSECS_PER_SEC / 10000 / 10 */ 1072a60961a3SKever Yang delay *= remainder; 1073a60961a3SKever Yang delay = DIV_ROUND_CLOSEST(delay, (rate / 1000) * 36 * 1074a60961a3SKever Yang (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10)); 1075a60961a3SKever Yang 1076a60961a3SKever Yang delay_num = (u8)min_t(u32, delay, 255); 1077a60961a3SKever Yang 1078a60961a3SKever Yang raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0; 1079a60961a3SKever Yang raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET; 1080a60961a3SKever Yang raw_value |= nineties; 1081a60961a3SKever Yang 108296f1b3d9SKever Yang raw_value <<= 1; 1083a60961a3SKever Yang if (clk->id == SCLK_EMMC_SAMPLE) 1084a60961a3SKever Yang writel(raw_value | 0xffff0000, &cru->emmc_con[1]); 1085a60961a3SKever Yang else 1086a60961a3SKever Yang writel(raw_value | 0xffff0000, &cru->sdmmc_con[1]); 1087a60961a3SKever Yang 1088a60961a3SKever Yang debug("mmc set_phase(%d) delay_nums=%u reg=%#x actual_degrees=%d\n", 1089a60961a3SKever Yang degrees, delay_num, raw_value, rockchip_mmc_get_phase(clk)); 1090a60961a3SKever Yang 1091a60961a3SKever Yang return 0; 1092a60961a3SKever Yang } 1093a60961a3SKever Yang 1094a60961a3SKever Yang static int px30_clk_get_phase(struct clk *clk) 1095a60961a3SKever Yang { 1096a60961a3SKever Yang int ret; 1097eb46e717SFinley Xiao 1098cefa5186SFinley Xiao debug("%s %ld\n", __func__, clk->id); 1099a60961a3SKever Yang switch (clk->id) { 1100a60961a3SKever Yang case SCLK_EMMC_SAMPLE: 1101a60961a3SKever Yang case SCLK_SDMMC_SAMPLE: 1102a60961a3SKever Yang ret = rockchip_mmc_get_phase(clk); 1103a60961a3SKever Yang break; 1104a60961a3SKever Yang default: 1105a60961a3SKever Yang return -ENOENT; 1106a60961a3SKever Yang } 1107a60961a3SKever Yang 1108a60961a3SKever Yang return ret; 1109a60961a3SKever Yang } 1110a60961a3SKever Yang 1111a60961a3SKever Yang static int px30_clk_set_phase(struct clk *clk, int degrees) 1112a60961a3SKever Yang { 1113a60961a3SKever Yang int ret; 1114a60961a3SKever Yang 1115cefa5186SFinley Xiao debug("%s %ld\n", __func__, clk->id); 1116a60961a3SKever Yang switch (clk->id) { 1117a60961a3SKever Yang case SCLK_EMMC_SAMPLE: 1118a60961a3SKever Yang case SCLK_SDMMC_SAMPLE: 1119a60961a3SKever Yang ret = rockchip_mmc_set_phase(clk, degrees); 1120a60961a3SKever Yang break; 1121a60961a3SKever Yang default: 1122a60961a3SKever Yang return -ENOENT; 1123a60961a3SKever Yang } 1124a60961a3SKever Yang 1125a60961a3SKever Yang return ret; 1126a60961a3SKever Yang } 1127a60961a3SKever Yang 1128a60961a3SKever Yang static struct clk_ops px30_clk_ops = { 1129a60961a3SKever Yang .get_rate = px30_clk_get_rate, 1130a60961a3SKever Yang .set_rate = px30_clk_set_rate, 1131a60961a3SKever Yang .get_phase = px30_clk_get_phase, 1132a60961a3SKever Yang .set_phase = px30_clk_set_phase, 1133a60961a3SKever Yang }; 1134a60961a3SKever Yang 1135a60961a3SKever Yang static int px30_clk_probe(struct udevice *dev) 1136a60961a3SKever Yang { 1137a60961a3SKever Yang struct px30_clk_priv *priv = dev_get_priv(dev); 1138c4d4e4dcSFinley Xiao int ret; 1139a60961a3SKever Yang 1140c4d4e4dcSFinley Xiao if (px30_clk_get_pll_rate(priv, APLL) != APLL_HZ) { 1141c4d4e4dcSFinley Xiao ret = px30_armclk_set_clk(priv, APLL_HZ); 1142c4d4e4dcSFinley Xiao if (ret < 0) 1143c4d4e4dcSFinley Xiao printf("%s failed to set armclk rate\n", __func__); 1144c4d4e4dcSFinley Xiao } 1145dd472d4fSFinley Xiao 1146c4d4e4dcSFinley Xiao /* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */ 1147c4d4e4dcSFinley Xiao ret = clk_set_defaults(dev); 1148c4d4e4dcSFinley Xiao if (ret) 1149c4d4e4dcSFinley Xiao debug("%s clk_set_defaults failed %d\n", __func__, ret); 1150c4d4e4dcSFinley Xiao 1151c4d4e4dcSFinley Xiao if (!priv->gpll_hz) { 1152c4d4e4dcSFinley Xiao ret = px30_clk_get_gpll_rate(&priv->gpll_hz); 1153c4d4e4dcSFinley Xiao if (ret) { 1154c4d4e4dcSFinley Xiao printf("%s failed to get gpll rate\n", __func__); 1155c4d4e4dcSFinley Xiao return ret; 1156c4d4e4dcSFinley Xiao } 1157c4d4e4dcSFinley Xiao } 1158a60961a3SKever Yang 1159a60961a3SKever Yang return 0; 1160a60961a3SKever Yang } 1161a60961a3SKever Yang 1162a60961a3SKever Yang static int px30_clk_ofdata_to_platdata(struct udevice *dev) 1163a60961a3SKever Yang { 1164a60961a3SKever Yang struct px30_clk_priv *priv = dev_get_priv(dev); 1165a60961a3SKever Yang 11664203970bSKever Yang priv->cru = dev_read_addr_ptr(dev); 1167a60961a3SKever Yang 1168a60961a3SKever Yang return 0; 1169a60961a3SKever Yang } 1170a60961a3SKever Yang 1171a60961a3SKever Yang static int px30_clk_bind(struct udevice *dev) 1172a60961a3SKever Yang { 1173a60961a3SKever Yang int ret; 1174a60961a3SKever Yang struct udevice *sys_child, *sf_child; 1175a60961a3SKever Yang struct sysreset_reg *priv; 1176a60961a3SKever Yang struct softreset_reg *sf_priv; 1177a60961a3SKever Yang 1178a60961a3SKever Yang /* The reset driver does not have a device node, so bind it here */ 1179a60961a3SKever Yang ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset", 1180a60961a3SKever Yang &sys_child); 1181a60961a3SKever Yang if (ret) { 1182a60961a3SKever Yang debug("Warning: No sysreset driver: ret=%d\n", ret); 1183a60961a3SKever Yang } else { 1184a60961a3SKever Yang priv = malloc(sizeof(struct sysreset_reg)); 1185a60961a3SKever Yang priv->glb_srst_fst_value = offsetof(struct px30_cru, 1186a60961a3SKever Yang glb_srst_fst); 1187a60961a3SKever Yang priv->glb_srst_snd_value = offsetof(struct px30_cru, 1188a60961a3SKever Yang glb_srst_snd); 1189a60961a3SKever Yang sys_child->priv = priv; 1190a60961a3SKever Yang } 1191a60961a3SKever Yang 1192a60961a3SKever Yang ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset", 1193a60961a3SKever Yang dev_ofnode(dev), &sf_child); 1194a60961a3SKever Yang if (ret) { 1195a60961a3SKever Yang debug("Warning: No rockchip reset driver: ret=%d\n", ret); 1196a60961a3SKever Yang } else { 1197a60961a3SKever Yang sf_priv = malloc(sizeof(struct softreset_reg)); 1198a60961a3SKever Yang sf_priv->sf_reset_offset = offsetof(struct px30_cru, 1199a60961a3SKever Yang softrst_con[0]); 1200a60961a3SKever Yang sf_priv->sf_reset_num = 12; 1201a60961a3SKever Yang sf_child->priv = sf_priv; 1202a60961a3SKever Yang } 1203a60961a3SKever Yang 1204a60961a3SKever Yang return 0; 1205a60961a3SKever Yang } 1206a60961a3SKever Yang 1207a60961a3SKever Yang static const struct udevice_id px30_clk_ids[] = { 1208a60961a3SKever Yang { .compatible = "rockchip,px30-cru" }, 1209a60961a3SKever Yang { } 1210a60961a3SKever Yang }; 1211a60961a3SKever Yang 1212a60961a3SKever Yang U_BOOT_DRIVER(rockchip_px30_cru) = { 1213a60961a3SKever Yang .name = "rockchip_px30_cru", 1214a60961a3SKever Yang .id = UCLASS_CLK, 1215a60961a3SKever Yang .of_match = px30_clk_ids, 1216a60961a3SKever Yang .priv_auto_alloc_size = sizeof(struct px30_clk_priv), 1217a60961a3SKever Yang .ofdata_to_platdata = px30_clk_ofdata_to_platdata, 1218a60961a3SKever Yang .ops = &px30_clk_ops, 1219a60961a3SKever Yang .bind = px30_clk_bind, 1220a60961a3SKever Yang .probe = px30_clk_probe, 1221a60961a3SKever Yang }; 1222cefa5186SFinley Xiao 1223cefa5186SFinley Xiao static ulong px30_pclk_pmu_get_pmuclk(struct px30_pmuclk_priv *priv) 1224cefa5186SFinley Xiao { 1225cefa5186SFinley Xiao struct px30_pmucru *pmucru = priv->pmucru; 1226cefa5186SFinley Xiao u32 div, con; 1227cefa5186SFinley Xiao 1228cefa5186SFinley Xiao con = readl(&pmucru->pmu_clksel_con[0]); 1229cefa5186SFinley Xiao div = (con & CLK_PMU_PCLK_DIV_MASK) >> CLK_PMU_PCLK_DIV_SHIFT; 1230cefa5186SFinley Xiao 1231cefa5186SFinley Xiao return DIV_TO_RATE(priv->gpll_hz, div); 1232cefa5186SFinley Xiao } 1233cefa5186SFinley Xiao 1234cefa5186SFinley Xiao static ulong px30_pclk_pmu_set_pmuclk(struct px30_pmuclk_priv *priv, ulong hz) 1235cefa5186SFinley Xiao { 1236cefa5186SFinley Xiao struct px30_pmucru *pmucru = priv->pmucru; 1237cefa5186SFinley Xiao int src_clk_div; 1238cefa5186SFinley Xiao 1239cefa5186SFinley Xiao src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz); 1240cb981eeaSFinley Xiao assert(src_clk_div - 1 <= 31); 1241cefa5186SFinley Xiao 1242cefa5186SFinley Xiao rk_clrsetreg(&pmucru->pmu_clksel_con[0], 1243cefa5186SFinley Xiao CLK_PMU_PCLK_DIV_MASK, 1244cefa5186SFinley Xiao (src_clk_div - 1) << CLK_PMU_PCLK_DIV_SHIFT); 1245cefa5186SFinley Xiao 1246cefa5186SFinley Xiao return px30_pclk_pmu_get_pmuclk(priv); 1247cefa5186SFinley Xiao } 1248cefa5186SFinley Xiao 1249cefa5186SFinley Xiao static ulong px30_gpll_get_pmuclk(struct px30_pmuclk_priv *priv) 1250cefa5186SFinley Xiao { 1251cefa5186SFinley Xiao struct px30_pmucru *pmucru = priv->pmucru; 1252cefa5186SFinley Xiao 1253cefa5186SFinley Xiao return rkclk_pll_get_rate(&pmucru->pll, &pmucru->pmu_mode, GPLL); 1254cefa5186SFinley Xiao } 1255cefa5186SFinley Xiao 1256cefa5186SFinley Xiao static ulong px30_gpll_set_pmuclk(struct px30_pmuclk_priv *priv, ulong hz) 1257cefa5186SFinley Xiao { 1258cefa5186SFinley Xiao struct udevice *cru_dev; 1259cefa5186SFinley Xiao struct px30_clk_priv *cru_priv; 1260cefa5186SFinley Xiao struct px30_pmucru *pmucru = priv->pmucru; 1261cefa5186SFinley Xiao u32 div; 1262cefa5186SFinley Xiao ulong emmc_rate, sdmmc_rate, nandc_rate; 1263eb46e717SFinley Xiao ulong aclk_bus_rate, hclk_bus_rate, pclk_bus_rate; 1264eb46e717SFinley Xiao ulong aclk_peri_rate, hclk_peri_rate, pclk_pmu_rate; 1265cefa5186SFinley Xiao int ret; 1266cefa5186SFinley Xiao 1267cefa5186SFinley Xiao ret = uclass_get_device_by_name(UCLASS_CLK, 1268cefa5186SFinley Xiao "clock-controller@ff2b0000", 1269cefa5186SFinley Xiao &cru_dev); 1270cefa5186SFinley Xiao if (ret) { 1271cefa5186SFinley Xiao printf("%s failed to get cru device\n", __func__); 1272cefa5186SFinley Xiao return ret; 1273cefa5186SFinley Xiao } 1274cefa5186SFinley Xiao cru_priv = dev_get_priv(cru_dev); 1275bf97d0d6SFinley Xiao 1276bf97d0d6SFinley Xiao if (priv->gpll_hz == hz) 1277bf97d0d6SFinley Xiao return priv->gpll_hz; 1278bf97d0d6SFinley Xiao 1279cefa5186SFinley Xiao cru_priv->gpll_hz = priv->gpll_hz; 1280cefa5186SFinley Xiao div = DIV_ROUND_UP(hz, priv->gpll_hz); 1281cefa5186SFinley Xiao 1282eb46e717SFinley Xiao /* save clock rate */ 1283eb46e717SFinley Xiao aclk_bus_rate = px30_bus_get_clk(cru_priv, ACLK_BUS_PRE); 1284eb46e717SFinley Xiao hclk_bus_rate = px30_bus_get_clk(cru_priv, HCLK_BUS_PRE); 1285eb46e717SFinley Xiao pclk_bus_rate = px30_bus_get_clk(cru_priv, PCLK_BUS_PRE); 1286eb46e717SFinley Xiao aclk_peri_rate = px30_peri_get_clk(cru_priv, ACLK_PERI_PRE); 1287eb46e717SFinley Xiao hclk_peri_rate = px30_peri_get_clk(cru_priv, HCLK_PERI_PRE); 1288eb46e717SFinley Xiao pclk_pmu_rate = px30_pclk_pmu_get_pmuclk(priv); 1289eb46e717SFinley Xiao debug("%s aclk_bus=%lu, hclk_bus=%lu, pclk_bus=%lu\n", __func__, 1290eb46e717SFinley Xiao aclk_bus_rate, hclk_bus_rate, pclk_bus_rate); 1291eb46e717SFinley Xiao debug("%s aclk_peri=%lu, hclk_peri=%lu, pclk_pmu=%lu\n", __func__, 1292eb46e717SFinley Xiao aclk_peri_rate, hclk_peri_rate, pclk_pmu_rate); 1293cefa5186SFinley Xiao emmc_rate = px30_mmc_get_clk(cru_priv, SCLK_EMMC); 1294cefa5186SFinley Xiao sdmmc_rate = px30_mmc_get_clk(cru_priv, SCLK_SDMMC); 1295cefa5186SFinley Xiao nandc_rate = px30_nandc_get_clk(cru_priv); 1296eb46e717SFinley Xiao debug("%s emmc=%lu, sdmmc=%lu, nandc=%lu\n", __func__, 1297eb46e717SFinley Xiao emmc_rate, sdmmc_rate, nandc_rate); 1298eb46e717SFinley Xiao 12994a9de4c9SFinley Xiao /* avoid rate too large, reduce rate first */ 1300eb46e717SFinley Xiao px30_bus_set_clk(cru_priv, ACLK_BUS_PRE, aclk_bus_rate / div); 1301eb46e717SFinley Xiao px30_bus_set_clk(cru_priv, HCLK_BUS_PRE, hclk_bus_rate / div); 1302eb46e717SFinley Xiao px30_bus_set_clk(cru_priv, PCLK_BUS_PRE, pclk_bus_rate / div); 1303eb46e717SFinley Xiao px30_peri_set_clk(cru_priv, ACLK_PERI_PRE, aclk_peri_rate / div); 1304eb46e717SFinley Xiao px30_peri_set_clk(cru_priv, HCLK_PERI_PRE, hclk_peri_rate / div); 1305eb46e717SFinley Xiao px30_pclk_pmu_set_pmuclk(priv, pclk_pmu_rate / div); 1306eb46e717SFinley Xiao 13074a9de4c9SFinley Xiao px30_mmc_set_clk(cru_priv, SCLK_EMMC, emmc_rate / div); 13084a9de4c9SFinley Xiao px30_mmc_set_clk(cru_priv, SCLK_SDMMC, sdmmc_rate / div); 13094a9de4c9SFinley Xiao px30_nandc_set_clk(cru_priv, nandc_rate / div); 1310cefa5186SFinley Xiao 1311eb46e717SFinley Xiao /* change gpll rate */ 1312cefa5186SFinley Xiao rkclk_set_pll(&pmucru->pll, &pmucru->pmu_mode, GPLL, hz); 1313cefa5186SFinley Xiao priv->gpll_hz = px30_gpll_get_pmuclk(priv); 1314cefa5186SFinley Xiao cru_priv->gpll_hz = priv->gpll_hz; 1315cefa5186SFinley Xiao 1316eb46e717SFinley Xiao /* restore clock rate */ 1317eb46e717SFinley Xiao px30_bus_set_clk(cru_priv, ACLK_BUS_PRE, aclk_bus_rate); 1318eb46e717SFinley Xiao px30_bus_set_clk(cru_priv, HCLK_BUS_PRE, hclk_bus_rate); 1319eb46e717SFinley Xiao px30_bus_set_clk(cru_priv, PCLK_BUS_PRE, pclk_bus_rate); 1320eb46e717SFinley Xiao px30_peri_set_clk(cru_priv, ACLK_PERI_PRE, aclk_peri_rate); 1321eb46e717SFinley Xiao px30_peri_set_clk(cru_priv, HCLK_PERI_PRE, hclk_peri_rate); 1322eb46e717SFinley Xiao px30_pclk_pmu_set_pmuclk(priv, pclk_pmu_rate); 1323eb46e717SFinley Xiao 1324cefa5186SFinley Xiao px30_mmc_set_clk(cru_priv, SCLK_EMMC, emmc_rate); 1325cefa5186SFinley Xiao px30_mmc_set_clk(cru_priv, SCLK_SDMMC, sdmmc_rate); 1326cefa5186SFinley Xiao px30_nandc_set_clk(cru_priv, nandc_rate); 1327cefa5186SFinley Xiao 1328cefa5186SFinley Xiao return priv->gpll_hz; 1329cefa5186SFinley Xiao } 1330cefa5186SFinley Xiao 1331cefa5186SFinley Xiao static ulong px30_pmuclk_get_rate(struct clk *clk) 1332cefa5186SFinley Xiao { 1333cefa5186SFinley Xiao struct px30_pmuclk_priv *priv = dev_get_priv(clk->dev); 1334cefa5186SFinley Xiao ulong rate = 0; 1335cefa5186SFinley Xiao 1336cefa5186SFinley Xiao debug("%s %ld\n", __func__, clk->id); 1337cefa5186SFinley Xiao switch (clk->id) { 1338cefa5186SFinley Xiao case PLL_GPLL: 1339cefa5186SFinley Xiao rate = px30_gpll_get_pmuclk(priv); 1340cefa5186SFinley Xiao break; 1341cefa5186SFinley Xiao case PCLK_PMU_PRE: 1342cefa5186SFinley Xiao rate = px30_pclk_pmu_get_pmuclk(priv); 1343cefa5186SFinley Xiao break; 1344cefa5186SFinley Xiao default: 1345cefa5186SFinley Xiao return -ENOENT; 1346cefa5186SFinley Xiao } 1347cefa5186SFinley Xiao 1348cefa5186SFinley Xiao return rate; 1349cefa5186SFinley Xiao } 1350cefa5186SFinley Xiao 1351cefa5186SFinley Xiao static ulong px30_pmuclk_set_rate(struct clk *clk, ulong rate) 1352cefa5186SFinley Xiao { 1353cefa5186SFinley Xiao struct px30_pmuclk_priv *priv = dev_get_priv(clk->dev); 1354cefa5186SFinley Xiao ulong ret = 0; 1355cefa5186SFinley Xiao 1356cefa5186SFinley Xiao debug("%s %ld %ld\n", __func__, clk->id, rate); 1357cefa5186SFinley Xiao switch (clk->id) { 1358cefa5186SFinley Xiao case PLL_GPLL: 1359cefa5186SFinley Xiao ret = px30_gpll_set_pmuclk(priv, rate); 1360cefa5186SFinley Xiao break; 1361cefa5186SFinley Xiao case PCLK_PMU_PRE: 1362cefa5186SFinley Xiao ret = px30_pclk_pmu_set_pmuclk(priv, rate); 1363cefa5186SFinley Xiao break; 1364cefa5186SFinley Xiao default: 1365cefa5186SFinley Xiao return -ENOENT; 1366cefa5186SFinley Xiao } 1367cefa5186SFinley Xiao 1368cefa5186SFinley Xiao return ret; 1369cefa5186SFinley Xiao } 1370cefa5186SFinley Xiao 1371cefa5186SFinley Xiao static struct clk_ops px30_pmuclk_ops = { 1372cefa5186SFinley Xiao .get_rate = px30_pmuclk_get_rate, 1373cefa5186SFinley Xiao .set_rate = px30_pmuclk_set_rate, 1374cefa5186SFinley Xiao }; 1375cefa5186SFinley Xiao 1376cefa5186SFinley Xiao static int px30_pmuclk_probe(struct udevice *dev) 1377cefa5186SFinley Xiao { 1378c4d4e4dcSFinley Xiao struct px30_pmuclk_priv *priv = dev_get_priv(dev); 1379c4d4e4dcSFinley Xiao int ret; 1380c4d4e4dcSFinley Xiao 1381c4d4e4dcSFinley Xiao priv->gpll_hz = px30_gpll_get_pmuclk(priv); 1382c4d4e4dcSFinley Xiao 1383c4d4e4dcSFinley Xiao /* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */ 1384c4d4e4dcSFinley Xiao ret = clk_set_defaults(dev); 1385c4d4e4dcSFinley Xiao if (ret) 1386c4d4e4dcSFinley Xiao debug("%s clk_set_defaults failed %d\n", __func__, ret); 1387c4d4e4dcSFinley Xiao 1388cefa5186SFinley Xiao return 0; 1389cefa5186SFinley Xiao } 1390cefa5186SFinley Xiao 1391cefa5186SFinley Xiao static int px30_pmuclk_ofdata_to_platdata(struct udevice *dev) 1392cefa5186SFinley Xiao { 1393cefa5186SFinley Xiao struct px30_pmuclk_priv *priv = dev_get_priv(dev); 1394cefa5186SFinley Xiao 1395cefa5186SFinley Xiao priv->pmucru = dev_read_addr_ptr(dev); 1396cefa5186SFinley Xiao 1397cefa5186SFinley Xiao return 0; 1398cefa5186SFinley Xiao } 1399cefa5186SFinley Xiao 1400cefa5186SFinley Xiao static const struct udevice_id px30_pmuclk_ids[] = { 1401cefa5186SFinley Xiao { .compatible = "rockchip,px30-pmucru" }, 1402cefa5186SFinley Xiao { } 1403cefa5186SFinley Xiao }; 1404cefa5186SFinley Xiao 1405cefa5186SFinley Xiao U_BOOT_DRIVER(rockchip_px30_pmucru) = { 1406cefa5186SFinley Xiao .name = "rockchip_px30_pmucru", 1407cefa5186SFinley Xiao .id = UCLASS_CLK, 1408cefa5186SFinley Xiao .of_match = px30_pmuclk_ids, 1409cefa5186SFinley Xiao .priv_auto_alloc_size = sizeof(struct px30_pmuclk_priv), 1410cefa5186SFinley Xiao .ofdata_to_platdata = px30_pmuclk_ofdata_to_platdata, 1411cefa5186SFinley Xiao .ops = &px30_pmuclk_ops, 1412cefa5186SFinley Xiao .probe = px30_pmuclk_probe, 1413cefa5186SFinley Xiao }; 14147a1915c0SFinley Xiao 14157a1915c0SFinley Xiao /** 14167a1915c0SFinley Xiao * soc_clk_dump() - Print clock frequencies 14177a1915c0SFinley Xiao * Returns zero on success 14187a1915c0SFinley Xiao * 14197a1915c0SFinley Xiao * Implementation for the clk dump command. 14207a1915c0SFinley Xiao */ 14217a1915c0SFinley Xiao int soc_clk_dump(void) 14227a1915c0SFinley Xiao { 14237a1915c0SFinley Xiao struct udevice *cru_dev, *pmucru_dev; 14247a1915c0SFinley Xiao const struct px30_clk_info *clk_dump; 14257a1915c0SFinley Xiao struct clk clk; 14267a1915c0SFinley Xiao unsigned long clk_count = ARRAY_SIZE(clks_dump); 14277a1915c0SFinley Xiao unsigned long rate; 14287a1915c0SFinley Xiao int i, ret; 14297a1915c0SFinley Xiao 14307a1915c0SFinley Xiao ret = uclass_get_device_by_driver(UCLASS_CLK, 14317a1915c0SFinley Xiao DM_GET_DRIVER(rockchip_px30_cru), 14327a1915c0SFinley Xiao &cru_dev); 14337a1915c0SFinley Xiao if (ret) { 14347a1915c0SFinley Xiao printf("%s failed to get cru device\n", __func__); 14357a1915c0SFinley Xiao return ret; 14367a1915c0SFinley Xiao } 14377a1915c0SFinley Xiao 14387a1915c0SFinley Xiao ret = uclass_get_device_by_driver(UCLASS_CLK, 14397a1915c0SFinley Xiao DM_GET_DRIVER(rockchip_px30_pmucru), 14407a1915c0SFinley Xiao &pmucru_dev); 14417a1915c0SFinley Xiao if (ret) { 14427a1915c0SFinley Xiao printf("%s failed to get pmucru device\n", __func__); 14437a1915c0SFinley Xiao return ret; 14447a1915c0SFinley Xiao } 14457a1915c0SFinley Xiao 144656dd66cfSFinley Xiao printf("CLK:\n"); 14477a1915c0SFinley Xiao for (i = 0; i < clk_count; i++) { 14487a1915c0SFinley Xiao clk_dump = &clks_dump[i]; 14497a1915c0SFinley Xiao if (clk_dump->name) { 14507a1915c0SFinley Xiao clk.id = clk_dump->id; 14517a1915c0SFinley Xiao if (clk_dump->is_cru) 14527a1915c0SFinley Xiao ret = clk_request(cru_dev, &clk); 14537a1915c0SFinley Xiao else 14547a1915c0SFinley Xiao ret = clk_request(pmucru_dev, &clk); 14557a1915c0SFinley Xiao if (ret < 0) 14567a1915c0SFinley Xiao return ret; 14577a1915c0SFinley Xiao 14587a1915c0SFinley Xiao rate = clk_get_rate(&clk); 14597a1915c0SFinley Xiao clk_free(&clk); 14607a1915c0SFinley Xiao if (i == 0) { 14617a1915c0SFinley Xiao if (rate < 0) 146256dd66cfSFinley Xiao printf("%s %s\n", clk_dump->name, 14637a1915c0SFinley Xiao "unknown"); 14647a1915c0SFinley Xiao else 146556dd66cfSFinley Xiao printf("%s %lu KHz\n", clk_dump->name, 146656dd66cfSFinley Xiao rate / 1000); 14677a1915c0SFinley Xiao } else { 14687a1915c0SFinley Xiao if (rate < 0) 146956dd66cfSFinley Xiao printf("%s %s\n", clk_dump->name, 14707a1915c0SFinley Xiao "unknown"); 14717a1915c0SFinley Xiao else 147256dd66cfSFinley Xiao printf("%s %lu KHz\n", clk_dump->name, 147356dd66cfSFinley Xiao rate / 1000); 14747a1915c0SFinley Xiao } 14757a1915c0SFinley Xiao } 14767a1915c0SFinley Xiao } 14777a1915c0SFinley Xiao 14787a1915c0SFinley Xiao return 0; 14797a1915c0SFinley Xiao } 1480