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 29a60961a3SKever Yang #define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1)) 30a60961a3SKever Yang 31a60961a3SKever Yang #define PLL_DIVISORS(hz, _refdiv, _postdiv1, _postdiv2) {\ 32a60961a3SKever Yang .refdiv = _refdiv,\ 33a60961a3SKever Yang .fbdiv = (u32)((u64)hz * _refdiv * _postdiv1 * _postdiv2 / OSC_HZ),\ 34a60961a3SKever Yang .postdiv1 = _postdiv1, .postdiv2 = _postdiv2}; 3577ecce68SFinley Xiao static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 1, 1, 1); 36a60961a3SKever Yang 37a60961a3SKever Yang static const struct pll_div apll_816_cfg = PLL_DIVISORS(816 * MHz, 1, 2, 1); 38a60961a3SKever Yang static const struct pll_div apll_600_cfg = PLL_DIVISORS(600 * MHz, 1, 3, 1); 39a60961a3SKever Yang 40a60961a3SKever Yang static const struct pll_div *apll_cfgs[] = { 41a60961a3SKever Yang [APLL_816_MHZ] = &apll_816_cfg, 42a60961a3SKever Yang [APLL_600_MHZ] = &apll_600_cfg, 43a60961a3SKever Yang }; 44a60961a3SKever Yang 45bcefd077SFinley Xiao static u8 pll_mode_shift[PLL_COUNT] = { 46bcefd077SFinley Xiao APLL_MODE_SHIFT, DPLL_MODE_SHIFT, CPLL_MODE_SHIFT, 47bcefd077SFinley Xiao NPLL_MODE_SHIFT, GPLL_MODE_SHIFT 48bcefd077SFinley Xiao }; 49bcefd077SFinley Xiao static u32 pll_mode_mask[PLL_COUNT] = { 50bcefd077SFinley Xiao APLL_MODE_MASK, DPLL_MODE_MASK, CPLL_MODE_MASK, 51bcefd077SFinley Xiao NPLL_MODE_MASK, GPLL_MODE_MASK 52bcefd077SFinley Xiao }; 53bcefd077SFinley Xiao 54a60961a3SKever Yang /* 55a60961a3SKever Yang * the div restructions of pll in integer mode, these are defined in 56a60961a3SKever Yang * * CRU_*PLL_CON0 or PMUCRU_*PLL_CON0 57a60961a3SKever Yang */ 58a60961a3SKever Yang #define PLL_DIV_MIN 16 59a60961a3SKever Yang #define PLL_DIV_MAX 3200 60a60961a3SKever Yang 61a60961a3SKever Yang /* 62a60961a3SKever Yang * How to calculate the PLL(from TRM V0.3 Part 1 Page 63): 63a60961a3SKever Yang * Formulas also embedded within the Fractional PLL Verilog model: 64a60961a3SKever Yang * If DSMPD = 1 (DSM is disabled, "integer mode") 65a60961a3SKever Yang * FOUTVCO = FREF / REFDIV * FBDIV 66a60961a3SKever Yang * FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2 67a60961a3SKever Yang * Where: 68a60961a3SKever Yang * FOUTVCO = Fractional PLL non-divided output frequency 69a60961a3SKever Yang * FOUTPOSTDIV = Fractional PLL divided output frequency 70a60961a3SKever Yang * (output of second post divider) 71a60961a3SKever Yang * FREF = Fractional PLL input reference frequency, (the OSC_HZ 24MHz input) 72a60961a3SKever Yang * REFDIV = Fractional PLL input reference clock divider 73a60961a3SKever Yang * FBDIV = Integer value programmed into feedback divide 74a60961a3SKever Yang * 75a60961a3SKever Yang */ 76db235eb5SFinley Xiao static void rkclk_set_pll(struct px30_cru *cru, enum px30_pll_id pll_id, 77db235eb5SFinley Xiao const struct pll_div *div) 78a60961a3SKever Yang { 79db235eb5SFinley Xiao struct px30_pll *pll; 80db235eb5SFinley Xiao unsigned int *mode; 81a60961a3SKever Yang /* All PLLs have same VCO and output frequency range restrictions. */ 82a60961a3SKever Yang uint vco_hz = OSC_HZ / 1000 * div->fbdiv / div->refdiv * 1000; 83a60961a3SKever Yang uint output_hz = vco_hz / div->postdiv1 / div->postdiv2; 84db235eb5SFinley Xiao 85db235eb5SFinley Xiao if (pll_id == GPLL) { 86db235eb5SFinley Xiao pll = &cru->gpll; 87db235eb5SFinley Xiao mode = &cru->pmu_mode; 88db235eb5SFinley Xiao } else { 89db235eb5SFinley Xiao pll = &cru->pll[pll_id]; 90db235eb5SFinley Xiao mode = &cru->mode; 91db235eb5SFinley Xiao }; 92a60961a3SKever Yang 93a60961a3SKever Yang debug("PLL at %p: fb=%d, ref=%d, pst1=%d, pst2=%d, vco=%u Hz, output=%u Hz\n", 94a60961a3SKever Yang pll, div->fbdiv, div->refdiv, div->postdiv1, 95a60961a3SKever Yang div->postdiv2, vco_hz, output_hz); 96a60961a3SKever Yang assert(vco_hz >= VCO_MIN_HZ && vco_hz <= VCO_MAX_HZ && 97a60961a3SKever Yang output_hz >= OUTPUT_MIN_HZ && output_hz <= OUTPUT_MAX_HZ); 98a60961a3SKever Yang 99db235eb5SFinley Xiao /* 100db235eb5SFinley Xiao * When power on or changing PLL setting, 101db235eb5SFinley Xiao * we must force PLL into slow mode to ensure output stable clock. 102db235eb5SFinley Xiao */ 103bcefd077SFinley Xiao rk_clrsetreg(mode, pll_mode_mask[pll_id], 104bcefd077SFinley Xiao PLLMUX_FROM_XIN24M << pll_mode_shift[pll_id]); 105db235eb5SFinley Xiao 106a60961a3SKever Yang /* use integer mode */ 107a60961a3SKever Yang rk_setreg(&pll->con1, 1 << PLL_DSMPD_SHIFT); 108a60961a3SKever Yang /* Power down */ 109a60961a3SKever Yang rk_setreg(&pll->con1, 1 << PLL_PD_SHIFT); 110a60961a3SKever Yang 111a60961a3SKever Yang rk_clrsetreg(&pll->con0, 112a60961a3SKever Yang PLL_POSTDIV1_MASK | PLL_FBDIV_MASK, 113a60961a3SKever Yang (div->postdiv1 << PLL_POSTDIV1_SHIFT) | div->fbdiv); 114a60961a3SKever Yang rk_clrsetreg(&pll->con1, PLL_POSTDIV2_MASK | PLL_REFDIV_MASK, 115a60961a3SKever Yang (div->postdiv2 << PLL_POSTDIV2_SHIFT | 116a60961a3SKever Yang div->refdiv << PLL_REFDIV_SHIFT)); 117a60961a3SKever Yang 118a60961a3SKever Yang /* Power Up */ 119a60961a3SKever Yang rk_clrreg(&pll->con1, 1 << PLL_PD_SHIFT); 120a60961a3SKever Yang 121a60961a3SKever Yang /* waiting for pll lock */ 1226fb52eadSFinley Xiao while (!(readl(&pll->con1) & (1 << PLL_LOCK_STATUS_SHIFT))) 123a60961a3SKever Yang udelay(1); 124a60961a3SKever Yang 125bcefd077SFinley Xiao rk_clrsetreg(mode, pll_mode_mask[pll_id], 126bcefd077SFinley Xiao PLLMUX_FROM_PLL << pll_mode_shift[pll_id]); 127db235eb5SFinley Xiao 128a60961a3SKever Yang return; 129a60961a3SKever Yang } 130a60961a3SKever Yang 13130f1f38dSFinley Xiao static uint32_t rkclk_pll_get_rate(struct px30_cru *cru, 13230f1f38dSFinley Xiao enum px30_pll_id pll_id) 13330f1f38dSFinley Xiao { 13430f1f38dSFinley Xiao u32 refdiv, fbdiv, postdiv1, postdiv2; 13530f1f38dSFinley Xiao u32 con; 13630f1f38dSFinley Xiao struct px30_pll *pll; 13730f1f38dSFinley Xiao uint shift; 13830f1f38dSFinley Xiao uint mask; 13930f1f38dSFinley Xiao 14030f1f38dSFinley Xiao if (pll_id == GPLL) { 14130f1f38dSFinley Xiao pll = &cru->gpll; 14230f1f38dSFinley Xiao con = readl(&cru->pmu_mode); 14330f1f38dSFinley Xiao } else { 14430f1f38dSFinley Xiao pll = &cru->pll[pll_id]; 14530f1f38dSFinley Xiao con = readl(&cru->mode); 14630f1f38dSFinley Xiao } 14730f1f38dSFinley Xiao 148bcefd077SFinley Xiao shift = pll_mode_shift[pll_id]; 149bcefd077SFinley Xiao mask = pll_mode_mask[pll_id]; 15030f1f38dSFinley Xiao 15130f1f38dSFinley Xiao switch ((con & mask) >> shift) { 15230f1f38dSFinley Xiao case PLLMUX_FROM_XIN24M: 15330f1f38dSFinley Xiao return OSC_HZ; 15430f1f38dSFinley Xiao case PLLMUX_FROM_PLL: 15530f1f38dSFinley Xiao /* normal mode */ 15630f1f38dSFinley Xiao con = readl(&pll->con0); 15730f1f38dSFinley Xiao postdiv1 = (con & PLL_POSTDIV1_MASK) >> PLL_POSTDIV1_SHIFT; 15830f1f38dSFinley Xiao fbdiv = (con & PLL_FBDIV_MASK) >> PLL_FBDIV_SHIFT; 15930f1f38dSFinley Xiao con = readl(&pll->con1); 16030f1f38dSFinley Xiao postdiv2 = (con & PLL_POSTDIV2_MASK) >> PLL_POSTDIV2_SHIFT; 16130f1f38dSFinley Xiao refdiv = (con & PLL_REFDIV_MASK) >> PLL_REFDIV_SHIFT; 16230f1f38dSFinley Xiao return (24 * fbdiv / (refdiv * postdiv1 * postdiv2)) * 1000000; 16330f1f38dSFinley Xiao case PLLMUX_FROM_RTC32K: 16430f1f38dSFinley Xiao default: 16530f1f38dSFinley Xiao return 32768; 16630f1f38dSFinley Xiao } 16730f1f38dSFinley Xiao } 16830f1f38dSFinley Xiao 16930f1f38dSFinley Xiao static int pll_para_config(u32 freq_hz, struct pll_div *div) 17030f1f38dSFinley Xiao { 17130f1f38dSFinley Xiao u32 ref_khz = OSC_HZ / KHz, refdiv, fbdiv = 0; 17230f1f38dSFinley Xiao u32 postdiv1, postdiv2 = 1; 17330f1f38dSFinley Xiao u32 fref_khz; 17430f1f38dSFinley Xiao u32 diff_khz, best_diff_khz; 17530f1f38dSFinley Xiao const u32 max_refdiv = 63, max_fbdiv = 3200, min_fbdiv = 16; 17630f1f38dSFinley Xiao const u32 max_postdiv1 = 7, max_postdiv2 = 7; 17730f1f38dSFinley Xiao u32 vco_khz; 17830f1f38dSFinley Xiao u32 freq_khz = freq_hz / KHz; 17930f1f38dSFinley Xiao 18030f1f38dSFinley Xiao if (!freq_hz) { 18130f1f38dSFinley Xiao printf("%s: the frequency can't be 0 Hz\n", __func__); 18230f1f38dSFinley Xiao return -1; 18330f1f38dSFinley Xiao } 18430f1f38dSFinley Xiao 18530f1f38dSFinley Xiao postdiv1 = DIV_ROUND_UP(VCO_MIN_HZ / 1000, freq_khz); 18630f1f38dSFinley Xiao if (postdiv1 > max_postdiv1) { 18730f1f38dSFinley Xiao postdiv2 = DIV_ROUND_UP(postdiv1, max_postdiv1); 18830f1f38dSFinley Xiao postdiv1 = DIV_ROUND_UP(postdiv1, postdiv2); 18930f1f38dSFinley Xiao } 19030f1f38dSFinley Xiao 19130f1f38dSFinley Xiao vco_khz = freq_khz * postdiv1 * postdiv2; 19230f1f38dSFinley Xiao 19330f1f38dSFinley Xiao if (vco_khz < (VCO_MIN_HZ / KHz) || vco_khz > (VCO_MAX_HZ / KHz) || 19430f1f38dSFinley Xiao postdiv2 > max_postdiv2) { 19530f1f38dSFinley Xiao printf("%s: Cannot find out a supported VCO for Freq (%uHz)\n", 19630f1f38dSFinley Xiao __func__, freq_hz); 19730f1f38dSFinley Xiao return -1; 19830f1f38dSFinley Xiao } 19930f1f38dSFinley Xiao 20030f1f38dSFinley Xiao div->postdiv1 = postdiv1; 20130f1f38dSFinley Xiao div->postdiv2 = postdiv2; 20230f1f38dSFinley Xiao 20330f1f38dSFinley Xiao best_diff_khz = vco_khz; 20430f1f38dSFinley Xiao for (refdiv = 1; refdiv < max_refdiv && best_diff_khz; refdiv++) { 20530f1f38dSFinley Xiao fref_khz = ref_khz / refdiv; 20630f1f38dSFinley Xiao 20730f1f38dSFinley Xiao fbdiv = vco_khz / fref_khz; 20830f1f38dSFinley Xiao if ((fbdiv >= max_fbdiv) || (fbdiv <= min_fbdiv)) 20930f1f38dSFinley Xiao continue; 21030f1f38dSFinley Xiao diff_khz = vco_khz - fbdiv * fref_khz; 21130f1f38dSFinley Xiao if (fbdiv + 1 < max_fbdiv && diff_khz > fref_khz / 2) { 21230f1f38dSFinley Xiao fbdiv++; 21330f1f38dSFinley Xiao diff_khz = fref_khz - diff_khz; 21430f1f38dSFinley Xiao } 21530f1f38dSFinley Xiao 21630f1f38dSFinley Xiao if (diff_khz >= best_diff_khz) 21730f1f38dSFinley Xiao continue; 21830f1f38dSFinley Xiao 21930f1f38dSFinley Xiao best_diff_khz = diff_khz; 22030f1f38dSFinley Xiao div->refdiv = refdiv; 22130f1f38dSFinley Xiao div->fbdiv = fbdiv; 22230f1f38dSFinley Xiao } 22330f1f38dSFinley Xiao 22430f1f38dSFinley Xiao if (best_diff_khz > 4 * (MHz / KHz)) { 22530f1f38dSFinley Xiao printf("%s: Failed to match output frequency %u bestis %u Hz\n", 22630f1f38dSFinley Xiao __func__, freq_hz, 22730f1f38dSFinley Xiao best_diff_khz * KHz); 22830f1f38dSFinley Xiao return -1; 22930f1f38dSFinley Xiao } 23030f1f38dSFinley Xiao return 0; 23130f1f38dSFinley Xiao } 23230f1f38dSFinley Xiao 233a60961a3SKever Yang static void rkclk_init(struct px30_cru *cru) 234a60961a3SKever Yang { 235a60961a3SKever Yang u32 aclk_div; 236a60961a3SKever Yang 237a60961a3SKever Yang /* init pll */ 238db235eb5SFinley Xiao rkclk_set_pll(cru, APLL, apll_cfgs[APLL_816_MHZ]); 239db235eb5SFinley Xiao rkclk_set_pll(cru, GPLL, &gpll_init_cfg); 240a60961a3SKever Yang 241a60961a3SKever Yang /* 242a60961a3SKever Yang * select apll as cpu/core clock pll source and 243a60961a3SKever Yang * set up dependent divisors for PERI and ACLK clocks. 244a60961a3SKever Yang * core hz : apll = 1:1 245a60961a3SKever Yang */ 246a60961a3SKever Yang aclk_div = APLL_HZ / CORE_ACLK_HZ - 1; 247a60961a3SKever Yang rk_clrsetreg(&cru->clksel_con[0], 248a60961a3SKever Yang CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK | 249a60961a3SKever Yang CORE_ACLK_DIV_MASK, 250a60961a3SKever Yang aclk_div << CORE_ACLK_DIV_SHIFT | 251a60961a3SKever Yang CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT | 252a60961a3SKever Yang 0 << CORE_DIV_CON_SHIFT); 253a60961a3SKever Yang } 254a60961a3SKever Yang 255a60961a3SKever Yang static ulong px30_i2c_get_clk(struct px30_cru *cru, ulong clk_id) 256a60961a3SKever Yang { 257a60961a3SKever Yang u32 div, con; 258a60961a3SKever Yang 259a60961a3SKever Yang switch (clk_id) { 260a60961a3SKever Yang case SCLK_I2C0: 261f67f522bSFinley Xiao con = readl(&cru->clksel_con[49]); 262f67f522bSFinley Xiao div = con >> CLK_I2C0_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK; 263a60961a3SKever Yang break; 264a60961a3SKever Yang case SCLK_I2C1: 265f67f522bSFinley Xiao con = readl(&cru->clksel_con[49]); 266f67f522bSFinley Xiao div = con >> CLK_I2C1_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK; 267a60961a3SKever Yang break; 268a60961a3SKever Yang case SCLK_I2C2: 269f67f522bSFinley Xiao con = readl(&cru->clksel_con[50]); 270f67f522bSFinley Xiao div = con >> CLK_I2C2_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK; 271a60961a3SKever Yang break; 272a60961a3SKever Yang case SCLK_I2C3: 273f67f522bSFinley Xiao con = readl(&cru->clksel_con[50]); 274f67f522bSFinley Xiao div = con >> CLK_I2C3_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK; 275a60961a3SKever Yang break; 276a60961a3SKever Yang default: 277a60961a3SKever Yang printf("do not support this i2c bus\n"); 278a60961a3SKever Yang return -EINVAL; 279a60961a3SKever Yang } 280a60961a3SKever Yang 281a60961a3SKever Yang return DIV_TO_RATE(GPLL_HZ, div); 282a60961a3SKever Yang } 283a60961a3SKever Yang 284a60961a3SKever Yang static ulong px30_i2c_set_clk(struct px30_cru *cru, ulong clk_id, uint hz) 285a60961a3SKever Yang { 286a60961a3SKever Yang int src_clk_div; 287a60961a3SKever Yang 288a60961a3SKever Yang src_clk_div = GPLL_HZ / hz; 289a60961a3SKever Yang assert(src_clk_div - 1 < 127); 290a60961a3SKever Yang 291a60961a3SKever Yang switch (clk_id) { 292a60961a3SKever Yang case SCLK_I2C0: 293f67f522bSFinley Xiao rk_clrsetreg(&cru->clksel_con[49], 294f67f522bSFinley Xiao CLK_I2C_DIV_CON_MASK << CLK_I2C0_DIV_CON_SHIFT | 295f67f522bSFinley Xiao CLK_I2C_PLL_SEL_MASK << CLK_I2C0_PLL_SEL_SHIFT, 296f67f522bSFinley Xiao (src_clk_div - 1) << CLK_I2C0_DIV_CON_SHIFT | 297f67f522bSFinley Xiao CLK_I2C_PLL_SEL_GPLL << CLK_I2C0_PLL_SEL_SHIFT); 298a60961a3SKever Yang break; 299a60961a3SKever Yang case SCLK_I2C1: 300f67f522bSFinley Xiao rk_clrsetreg(&cru->clksel_con[49], 301f67f522bSFinley Xiao CLK_I2C_DIV_CON_MASK << CLK_I2C1_DIV_CON_SHIFT | 302f67f522bSFinley Xiao CLK_I2C_PLL_SEL_MASK << CLK_I2C1_PLL_SEL_SHIFT, 303f67f522bSFinley Xiao (src_clk_div - 1) << CLK_I2C1_DIV_CON_SHIFT | 304f67f522bSFinley Xiao CLK_I2C_PLL_SEL_GPLL << CLK_I2C1_PLL_SEL_SHIFT); 305a60961a3SKever Yang break; 306a60961a3SKever Yang case SCLK_I2C2: 307f67f522bSFinley Xiao rk_clrsetreg(&cru->clksel_con[50], 308f67f522bSFinley Xiao CLK_I2C_DIV_CON_MASK << CLK_I2C2_DIV_CON_SHIFT | 309f67f522bSFinley Xiao CLK_I2C_PLL_SEL_MASK << CLK_I2C2_PLL_SEL_SHIFT, 310f67f522bSFinley Xiao (src_clk_div - 1) << CLK_I2C2_DIV_CON_SHIFT | 311f67f522bSFinley Xiao CLK_I2C_PLL_SEL_GPLL << CLK_I2C2_PLL_SEL_SHIFT); 312a60961a3SKever Yang break; 313a60961a3SKever Yang case SCLK_I2C3: 314f67f522bSFinley Xiao rk_clrsetreg(&cru->clksel_con[50], 315f67f522bSFinley Xiao CLK_I2C_DIV_CON_MASK << CLK_I2C3_DIV_CON_SHIFT | 316f67f522bSFinley Xiao CLK_I2C_PLL_SEL_MASK << CLK_I2C3_PLL_SEL_SHIFT, 317f67f522bSFinley Xiao (src_clk_div - 1) << CLK_I2C3_DIV_CON_SHIFT | 318f67f522bSFinley Xiao CLK_I2C_PLL_SEL_GPLL << CLK_I2C3_PLL_SEL_SHIFT); 319a60961a3SKever Yang break; 320a60961a3SKever Yang default: 321a60961a3SKever Yang printf("do not support this i2c bus\n"); 322a60961a3SKever Yang return -EINVAL; 323a60961a3SKever Yang } 324a60961a3SKever Yang 325fce7cb7bSFinley Xiao return px30_i2c_get_clk(cru, clk_id); 326a60961a3SKever Yang } 327a60961a3SKever Yang 328a60961a3SKever Yang static ulong px30_mmc_get_clk(struct px30_cru *cru, uint clk_id) 329a60961a3SKever Yang { 330a60961a3SKever Yang u32 div, con, con_id; 331a60961a3SKever Yang 332a60961a3SKever Yang switch (clk_id) { 333a60961a3SKever Yang case HCLK_SDMMC: 334a60961a3SKever Yang case SCLK_SDMMC: 335a60961a3SKever Yang con_id = 16; 336a60961a3SKever Yang break; 337a60961a3SKever Yang case HCLK_EMMC: 338a60961a3SKever Yang case SCLK_EMMC: 33996f1b3d9SKever Yang case SCLK_EMMC_SAMPLE: 340a60961a3SKever Yang con_id = 20; 341a60961a3SKever Yang break; 342a60961a3SKever Yang default: 343a60961a3SKever Yang return -EINVAL; 344a60961a3SKever Yang } 345a60961a3SKever Yang 346a60961a3SKever Yang con = readl(&cru->clksel_con[con_id]); 347a60961a3SKever Yang div = (con & EMMC_DIV_MASK) >> EMMC_DIV_SHIFT; 348a60961a3SKever Yang 349a60961a3SKever Yang if ((con & EMMC_PLL_MASK) >> EMMC_PLL_SHIFT 350a60961a3SKever Yang == EMMC_SEL_24M) 351a60961a3SKever Yang return DIV_TO_RATE(OSC_HZ, div) / 2; 352a60961a3SKever Yang else 353a60961a3SKever Yang return DIV_TO_RATE(GPLL_HZ, div) / 2; 354a60961a3SKever Yang 355a60961a3SKever Yang } 356a60961a3SKever Yang 357a60961a3SKever Yang static ulong px30_mmc_set_clk(struct px30_cru *cru, 358a60961a3SKever Yang ulong clk_id, ulong set_rate) 359a60961a3SKever Yang { 360a60961a3SKever Yang int src_clk_div; 361a60961a3SKever Yang u32 con_id; 362a60961a3SKever Yang 363c4867301SKever Yang debug("%s %ld %ld\n", __func__, clk_id, set_rate); 364a60961a3SKever Yang switch (clk_id) { 365a60961a3SKever Yang case HCLK_SDMMC: 366a60961a3SKever Yang case SCLK_SDMMC: 367a60961a3SKever Yang con_id = 16; 368a60961a3SKever Yang break; 369a60961a3SKever Yang case HCLK_EMMC: 370a60961a3SKever Yang case SCLK_EMMC: 371a60961a3SKever Yang con_id = 20; 372a60961a3SKever Yang break; 373a60961a3SKever Yang default: 374a60961a3SKever Yang return -EINVAL; 375a60961a3SKever Yang } 376a60961a3SKever Yang /* Select clk_sdmmc/emmc source from GPLL by default */ 377a60961a3SKever Yang /* mmc clock defaulg div 2 internal, need provide double in cru */ 378a60961a3SKever Yang src_clk_div = DIV_ROUND_UP(GPLL_HZ / 2, set_rate); 379a60961a3SKever Yang 380a60961a3SKever Yang if (src_clk_div > 127) { 381a60961a3SKever Yang /* use 24MHz source for 400KHz clock */ 382a60961a3SKever Yang src_clk_div = DIV_ROUND_UP(OSC_HZ / 2, set_rate); 383a60961a3SKever Yang rk_clrsetreg(&cru->clksel_con[con_id], 384a60961a3SKever Yang EMMC_PLL_MASK | EMMC_DIV_MASK, 385a60961a3SKever Yang EMMC_SEL_24M << EMMC_PLL_SHIFT | 386a60961a3SKever Yang (src_clk_div - 1) << EMMC_DIV_SHIFT); 387a60961a3SKever Yang } else { 388a60961a3SKever Yang rk_clrsetreg(&cru->clksel_con[con_id], 389a60961a3SKever Yang EMMC_PLL_MASK | EMMC_DIV_MASK, 390a60961a3SKever Yang EMMC_SEL_GPLL << EMMC_PLL_SHIFT | 391a60961a3SKever Yang (src_clk_div - 1) << EMMC_DIV_SHIFT); 392a60961a3SKever Yang } 393a60961a3SKever Yang rk_clrsetreg(&cru->clksel_con[con_id +1], EMMC_CLK_SEL_MASK, 394a60961a3SKever Yang EMMC_CLK_SEL_EMMC); 395a60961a3SKever Yang 396a60961a3SKever Yang return px30_mmc_get_clk(cru, clk_id); 397a60961a3SKever Yang } 398a60961a3SKever Yang 399f67f522bSFinley Xiao static ulong px30_pwm_get_clk(struct px30_cru *cru, ulong clk_id) 400a60961a3SKever Yang { 401a60961a3SKever Yang u32 div, con; 402a60961a3SKever Yang 403f67f522bSFinley Xiao switch (clk_id) { 404f67f522bSFinley Xiao case SCLK_PWM0: 405f67f522bSFinley Xiao con = readl(&cru->clksel_con[52]); 406f67f522bSFinley Xiao div = con >> CLK_PWM0_DIV_CON_SHIFT & CLK_PWM_DIV_CON_MASK; 407f67f522bSFinley Xiao break; 408f67f522bSFinley Xiao case SCLK_PWM1: 409f67f522bSFinley Xiao con = readl(&cru->clksel_con[52]); 410f67f522bSFinley Xiao div = con >> CLK_PWM1_DIV_CON_SHIFT & CLK_PWM_DIV_CON_MASK; 411f67f522bSFinley Xiao break; 412f67f522bSFinley Xiao default: 413f67f522bSFinley Xiao printf("do not support this pwm bus\n"); 414f67f522bSFinley Xiao return -EINVAL; 415f67f522bSFinley Xiao } 416f67f522bSFinley Xiao 417a60961a3SKever Yang return DIV_TO_RATE(GPLL_HZ, div); 418a60961a3SKever Yang } 419a60961a3SKever Yang 420f67f522bSFinley Xiao static ulong px30_pwm_set_clk(struct px30_cru *cru, ulong clk_id, uint hz) 421a60961a3SKever Yang { 422f67f522bSFinley Xiao int src_clk_div; 423a60961a3SKever Yang 424f67f522bSFinley Xiao src_clk_div = GPLL_HZ / hz; 425f67f522bSFinley Xiao assert(src_clk_div - 1 < 127); 426f67f522bSFinley Xiao 427f67f522bSFinley Xiao switch (clk_id) { 428f67f522bSFinley Xiao case SCLK_PWM0: 429f67f522bSFinley Xiao rk_clrsetreg(&cru->clksel_con[52], 430f67f522bSFinley Xiao CLK_PWM_DIV_CON_MASK << CLK_PWM0_DIV_CON_SHIFT | 431f67f522bSFinley Xiao CLK_PWM_PLL_SEL_MASK << CLK_PWM0_PLL_SEL_SHIFT, 432f67f522bSFinley Xiao (src_clk_div - 1) << CLK_PWM0_DIV_CON_SHIFT | 433f67f522bSFinley Xiao CLK_PWM_PLL_SEL_GPLL << CLK_PWM0_PLL_SEL_SHIFT); 434f67f522bSFinley Xiao break; 435f67f522bSFinley Xiao case SCLK_PWM1: 436f67f522bSFinley Xiao rk_clrsetreg(&cru->clksel_con[52], 437f67f522bSFinley Xiao CLK_PWM_DIV_CON_MASK << CLK_PWM1_DIV_CON_SHIFT | 438f67f522bSFinley Xiao CLK_PWM_PLL_SEL_MASK << CLK_PWM1_PLL_SEL_SHIFT, 439f67f522bSFinley Xiao (src_clk_div - 1) << CLK_PWM1_DIV_CON_SHIFT | 440f67f522bSFinley Xiao CLK_PWM_PLL_SEL_GPLL << CLK_PWM1_PLL_SEL_SHIFT); 441f67f522bSFinley Xiao break; 442f67f522bSFinley Xiao default: 443f67f522bSFinley Xiao printf("do not support this pwm bus\n"); 444f67f522bSFinley Xiao return -EINVAL; 445f67f522bSFinley Xiao } 446f67f522bSFinley Xiao 447fce7cb7bSFinley Xiao return px30_pwm_get_clk(cru, clk_id); 448a60961a3SKever Yang } 449a60961a3SKever Yang 450a60961a3SKever Yang static ulong px30_saradc_get_clk(struct px30_cru *cru) 451a60961a3SKever Yang { 452f67f522bSFinley Xiao u32 div, con; 453f67f522bSFinley Xiao 454f67f522bSFinley Xiao con = readl(&cru->clksel_con[55]); 455f9157291SFinley Xiao div = con >> CLK_SARADC_DIV_CON_SHIFT & CLK_SARADC_DIV_CON_MASK; 456a60961a3SKever Yang 457a60961a3SKever Yang return DIV_TO_RATE(OSC_HZ, div); 458a60961a3SKever Yang } 459a60961a3SKever Yang 460a60961a3SKever Yang static ulong px30_saradc_set_clk(struct px30_cru *cru, uint hz) 461a60961a3SKever Yang { 462a60961a3SKever Yang int src_clk_div; 463a60961a3SKever Yang 464f67f522bSFinley Xiao src_clk_div = OSC_HZ / hz; 465f67f522bSFinley Xiao assert(src_clk_div - 1 < 2047); 466a60961a3SKever Yang 467f67f522bSFinley Xiao rk_clrsetreg(&cru->clksel_con[55], 468f67f522bSFinley Xiao CLK_SARADC_DIV_CON_MASK, 469fce7cb7bSFinley Xiao (src_clk_div - 1) << CLK_SARADC_DIV_CON_SHIFT); 470f67f522bSFinley Xiao 471fce7cb7bSFinley Xiao return px30_saradc_get_clk(cru); 472f67f522bSFinley Xiao } 473f67f522bSFinley Xiao 474f67f522bSFinley Xiao static ulong px30_spi_get_clk(struct px30_cru *cru, ulong clk_id) 475f67f522bSFinley Xiao { 476f67f522bSFinley Xiao u32 div, con; 477f67f522bSFinley Xiao 478f67f522bSFinley Xiao switch (clk_id) { 479fce7cb7bSFinley Xiao case SCLK_SPI0: 480f67f522bSFinley Xiao con = readl(&cru->clksel_con[53]); 481f67f522bSFinley Xiao div = con >> CLK_SPI0_DIV_CON_SHIFT & CLK_SPI_DIV_CON_MASK; 482f67f522bSFinley Xiao break; 483fce7cb7bSFinley Xiao case SCLK_SPI1: 484f67f522bSFinley Xiao con = readl(&cru->clksel_con[53]); 485f67f522bSFinley Xiao div = con >> CLK_SPI1_DIV_CON_SHIFT & CLK_SPI_DIV_CON_MASK; 486f67f522bSFinley Xiao break; 487f67f522bSFinley Xiao default: 488f67f522bSFinley Xiao printf("do not support this pwm bus\n"); 489f67f522bSFinley Xiao return -EINVAL; 490f67f522bSFinley Xiao } 491f67f522bSFinley Xiao 492f67f522bSFinley Xiao return DIV_TO_RATE(GPLL_HZ, div); 493f67f522bSFinley Xiao } 494f67f522bSFinley Xiao 495f67f522bSFinley Xiao static ulong px30_spi_set_clk(struct px30_cru *cru, ulong clk_id, uint hz) 496f67f522bSFinley Xiao { 497f67f522bSFinley Xiao int src_clk_div; 498f67f522bSFinley Xiao 499f67f522bSFinley Xiao src_clk_div = GPLL_HZ / hz; 500f67f522bSFinley Xiao assert(src_clk_div - 1 < 127); 501f67f522bSFinley Xiao 502f67f522bSFinley Xiao switch (clk_id) { 503f67f522bSFinley Xiao case SCLK_SPI0: 504f67f522bSFinley Xiao rk_clrsetreg(&cru->clksel_con[53], 505f67f522bSFinley Xiao CLK_SPI_DIV_CON_MASK << CLK_SPI0_DIV_CON_SHIFT | 506f67f522bSFinley Xiao CLK_SPI_PLL_SEL_MASK << CLK_SPI0_PLL_SEL_SHIFT, 507f67f522bSFinley Xiao (src_clk_div - 1) << CLK_SPI0_DIV_CON_SHIFT | 508f67f522bSFinley Xiao CLK_SPI_PLL_SEL_GPLL << CLK_SPI0_PLL_SEL_SHIFT); 509f67f522bSFinley Xiao break; 510f67f522bSFinley Xiao case SCLK_SPI1: 511f67f522bSFinley Xiao rk_clrsetreg(&cru->clksel_con[53], 512f67f522bSFinley Xiao CLK_SPI_DIV_CON_MASK << CLK_SPI1_DIV_CON_SHIFT | 513f67f522bSFinley Xiao CLK_SPI_PLL_SEL_MASK << CLK_SPI1_PLL_SEL_SHIFT, 514f67f522bSFinley Xiao (src_clk_div - 1) << CLK_SPI1_DIV_CON_SHIFT | 515f67f522bSFinley Xiao CLK_SPI_PLL_SEL_GPLL << CLK_SPI1_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 522fce7cb7bSFinley Xiao return px30_spi_get_clk(cru, clk_id); 523a60961a3SKever Yang } 524a60961a3SKever Yang 52530f1f38dSFinley Xiao static ulong px30_vop_get_clk(struct px30_cru *cru, ulong clk_id) 52630f1f38dSFinley Xiao { 52730f1f38dSFinley Xiao u32 div, con, parent; 52830f1f38dSFinley Xiao 52930f1f38dSFinley Xiao switch (clk_id) { 53030f1f38dSFinley Xiao case ACLK_VOPB: 53130f1f38dSFinley Xiao con = readl(&cru->clksel_con[3]); 53230f1f38dSFinley Xiao div = con & ACLK_VO_DIV_MASK; 53330f1f38dSFinley Xiao parent = GPLL_HZ; 53430f1f38dSFinley Xiao break; 53530f1f38dSFinley Xiao case DCLK_VOPB: 53630f1f38dSFinley Xiao con = readl(&cru->clksel_con[5]); 53730f1f38dSFinley Xiao div = con & DCLK_VOPB_DIV_MASK; 53830f1f38dSFinley Xiao parent = rkclk_pll_get_rate(cru, CPLL); 53930f1f38dSFinley Xiao break; 54030f1f38dSFinley Xiao default: 54130f1f38dSFinley Xiao return -ENOENT; 54230f1f38dSFinley Xiao } 54330f1f38dSFinley Xiao 54430f1f38dSFinley Xiao return DIV_TO_RATE(parent, div); 54530f1f38dSFinley Xiao } 54630f1f38dSFinley Xiao 54730f1f38dSFinley Xiao static ulong px30_vop_set_clk(struct px30_cru *cru, ulong clk_id, uint hz) 54830f1f38dSFinley Xiao { 54930f1f38dSFinley Xiao int src_clk_div; 55030f1f38dSFinley Xiao struct pll_div cpll_config = {0}; 55130f1f38dSFinley Xiao 55230f1f38dSFinley Xiao src_clk_div = GPLL_HZ / hz; 55330f1f38dSFinley Xiao assert(src_clk_div - 1 < 31); 55430f1f38dSFinley Xiao 55530f1f38dSFinley Xiao switch (clk_id) { 55630f1f38dSFinley Xiao case ACLK_VOPB: 55730f1f38dSFinley Xiao rk_clrsetreg(&cru->clksel_con[3], 55830f1f38dSFinley Xiao ACLK_VO_PLL_MASK | ACLK_VO_DIV_MASK, 55930f1f38dSFinley Xiao ACLK_VO_SEL_GPLL << ACLK_VO_PLL_SHIFT | 56030f1f38dSFinley Xiao (src_clk_div - 1) << ACLK_VO_DIV_SHIFT); 56130f1f38dSFinley Xiao break; 56230f1f38dSFinley Xiao case DCLK_VOPB: 56330f1f38dSFinley Xiao /* 56430f1f38dSFinley Xiao * vopb dclk source from cpll, and equals to 56530f1f38dSFinley Xiao * cpll(means div == 1) 56630f1f38dSFinley Xiao */ 56730f1f38dSFinley Xiao if (pll_para_config(hz, &cpll_config)) 56830f1f38dSFinley Xiao return -1; 56930f1f38dSFinley Xiao rkclk_set_pll(cru, CPLL, &cpll_config); 57030f1f38dSFinley Xiao 57130f1f38dSFinley Xiao rk_clrsetreg(&cru->clksel_con[5], 57230f1f38dSFinley Xiao DCLK_VOPB_SEL_MASK | DCLK_VOPB_PLL_SEL_MASK | 57330f1f38dSFinley Xiao DCLK_VOPB_DIV_MASK, 57430f1f38dSFinley Xiao DCLK_VOPB_SEL_DIVOUT << DCLK_VOPB_SEL_SHIFT | 57530f1f38dSFinley Xiao DCLK_VOPB_PLL_SEL_CPLL << DCLK_VOPB_PLL_SEL_SHIFT | 57630f1f38dSFinley Xiao (1 - 1) << DCLK_VOPB_DIV_SHIFT); 57730f1f38dSFinley Xiao break; 57830f1f38dSFinley Xiao default: 57930f1f38dSFinley Xiao printf("do not support this vop freq\n"); 58030f1f38dSFinley Xiao return -EINVAL; 58130f1f38dSFinley Xiao } 58230f1f38dSFinley Xiao 58330f1f38dSFinley Xiao return hz; 58430f1f38dSFinley Xiao } 58530f1f38dSFinley Xiao 586*df8f8a42SFinley Xiao static ulong px30_bus_get_clk(struct px30_cru *cru, ulong clk_id) 587*df8f8a42SFinley Xiao { 588*df8f8a42SFinley Xiao u32 div, con, parent; 589*df8f8a42SFinley Xiao 590*df8f8a42SFinley Xiao switch (clk_id) { 591*df8f8a42SFinley Xiao case ACLK_BUS_PRE: 592*df8f8a42SFinley Xiao con = readl(&cru->clksel_con[23]); 593*df8f8a42SFinley Xiao div = (con & BUS_ACLK_DIV_MASK) >> BUS_ACLK_DIV_SHIFT; 594*df8f8a42SFinley Xiao parent = GPLL_HZ; 595*df8f8a42SFinley Xiao break; 596*df8f8a42SFinley Xiao case HCLK_BUS_PRE: 597*df8f8a42SFinley Xiao con = readl(&cru->clksel_con[24]); 598*df8f8a42SFinley Xiao div = (con & BUS_HCLK_DIV_MASK) >> BUS_HCLK_DIV_SHIFT; 599*df8f8a42SFinley Xiao parent = GPLL_HZ; 600*df8f8a42SFinley Xiao break; 601*df8f8a42SFinley Xiao case PCLK_BUS_PRE: 602*df8f8a42SFinley Xiao parent = px30_bus_get_clk(cru, ACLK_BUS_PRE); 603*df8f8a42SFinley Xiao con = readl(&cru->clksel_con[24]); 604*df8f8a42SFinley Xiao div = (con & BUS_PCLK_DIV_MASK) >> BUS_PCLK_DIV_SHIFT; 605*df8f8a42SFinley Xiao break; 606*df8f8a42SFinley Xiao default: 607*df8f8a42SFinley Xiao return -ENOENT; 608*df8f8a42SFinley Xiao } 609*df8f8a42SFinley Xiao 610*df8f8a42SFinley Xiao return DIV_TO_RATE(parent, div); 611*df8f8a42SFinley Xiao } 612*df8f8a42SFinley Xiao 613*df8f8a42SFinley Xiao static ulong px30_bus_set_clk(struct px30_cru *cru, ulong clk_id, ulong hz) 614*df8f8a42SFinley Xiao { 615*df8f8a42SFinley Xiao int src_clk_div; 616*df8f8a42SFinley Xiao 617*df8f8a42SFinley Xiao /* 618*df8f8a42SFinley Xiao * select gpll as pd_bus bus clock source and 619*df8f8a42SFinley Xiao * set up dependent divisors for PCLK/HCLK and ACLK clocks. 620*df8f8a42SFinley Xiao */ 621*df8f8a42SFinley Xiao switch (clk_id) { 622*df8f8a42SFinley Xiao case ACLK_BUS_PRE: 623*df8f8a42SFinley Xiao src_clk_div = GPLL_HZ / hz; 624*df8f8a42SFinley Xiao assert(src_clk_div - 1 < 31); 625*df8f8a42SFinley Xiao rk_clrsetreg(&cru->clksel_con[23], 626*df8f8a42SFinley Xiao BUS_PLL_SEL_MASK | BUS_ACLK_DIV_MASK, 627*df8f8a42SFinley Xiao BUS_PLL_SEL_GPLL << BUS_PLL_SEL_SHIFT | 628*df8f8a42SFinley Xiao (src_clk_div - 1) << BUS_ACLK_DIV_SHIFT); 629*df8f8a42SFinley Xiao break; 630*df8f8a42SFinley Xiao case HCLK_BUS_PRE: 631*df8f8a42SFinley Xiao src_clk_div = GPLL_HZ / hz; 632*df8f8a42SFinley Xiao assert(src_clk_div - 1 < 31); 633*df8f8a42SFinley Xiao rk_clrsetreg(&cru->clksel_con[24], 634*df8f8a42SFinley Xiao BUS_PLL_SEL_MASK | BUS_HCLK_DIV_MASK, 635*df8f8a42SFinley Xiao BUS_PLL_SEL_GPLL << BUS_PLL_SEL_SHIFT | 636*df8f8a42SFinley Xiao (src_clk_div - 1) << BUS_HCLK_DIV_SHIFT); 637*df8f8a42SFinley Xiao break; 638*df8f8a42SFinley Xiao case PCLK_BUS_PRE: 639*df8f8a42SFinley Xiao src_clk_div = px30_bus_get_clk(cru, ACLK_BUS_PRE) / hz; 640*df8f8a42SFinley Xiao assert(src_clk_div - 1 < 3); 641*df8f8a42SFinley Xiao rk_clrsetreg(&cru->clksel_con[24], 642*df8f8a42SFinley Xiao BUS_PCLK_DIV_MASK, 643*df8f8a42SFinley Xiao (src_clk_div - 1) << BUS_PCLK_DIV_SHIFT); 644*df8f8a42SFinley Xiao break; 645*df8f8a42SFinley Xiao default: 646*df8f8a42SFinley Xiao printf("do not support this bus freq\n"); 647*df8f8a42SFinley Xiao return -EINVAL; 648*df8f8a42SFinley Xiao } 649*df8f8a42SFinley Xiao 650*df8f8a42SFinley Xiao return px30_bus_get_clk(cru, clk_id); 651*df8f8a42SFinley Xiao } 652*df8f8a42SFinley Xiao 653*df8f8a42SFinley Xiao static ulong px30_peri_get_clk(struct px30_cru *cru, ulong clk_id) 654*df8f8a42SFinley Xiao { 655*df8f8a42SFinley Xiao u32 div, con, parent; 656*df8f8a42SFinley Xiao 657*df8f8a42SFinley Xiao switch (clk_id) { 658*df8f8a42SFinley Xiao case ACLK_PERI_PRE: 659*df8f8a42SFinley Xiao con = readl(&cru->clksel_con[14]); 660*df8f8a42SFinley Xiao div = (con & PERI_ACLK_DIV_MASK) >> PERI_ACLK_DIV_SHIFT; 661*df8f8a42SFinley Xiao parent = GPLL_HZ; 662*df8f8a42SFinley Xiao break; 663*df8f8a42SFinley Xiao case HCLK_PERI_PRE: 664*df8f8a42SFinley Xiao con = readl(&cru->clksel_con[14]); 665*df8f8a42SFinley Xiao div = (con & PERI_HCLK_DIV_MASK) >> PERI_HCLK_DIV_SHIFT; 666*df8f8a42SFinley Xiao parent = GPLL_HZ; 667*df8f8a42SFinley Xiao break; 668*df8f8a42SFinley Xiao default: 669*df8f8a42SFinley Xiao return -ENOENT; 670*df8f8a42SFinley Xiao } 671*df8f8a42SFinley Xiao 672*df8f8a42SFinley Xiao return DIV_TO_RATE(parent, div); 673*df8f8a42SFinley Xiao } 674*df8f8a42SFinley Xiao 675*df8f8a42SFinley Xiao static ulong px30_peri_set_clk(struct px30_cru *cru, ulong clk_id, ulong hz) 676*df8f8a42SFinley Xiao { 677*df8f8a42SFinley Xiao int src_clk_div; 678*df8f8a42SFinley Xiao 679*df8f8a42SFinley Xiao src_clk_div = GPLL_HZ / hz; 680*df8f8a42SFinley Xiao assert(src_clk_div - 1 < 31); 681*df8f8a42SFinley Xiao 682*df8f8a42SFinley Xiao /* 683*df8f8a42SFinley Xiao * select gpll as pd_peri bus clock source and 684*df8f8a42SFinley Xiao * set up dependent divisors for HCLK and ACLK clocks. 685*df8f8a42SFinley Xiao */ 686*df8f8a42SFinley Xiao switch (clk_id) { 687*df8f8a42SFinley Xiao case ACLK_PERI_PRE: 688*df8f8a42SFinley Xiao rk_clrsetreg(&cru->clksel_con[14], 689*df8f8a42SFinley Xiao PERI_PLL_SEL_MASK | PERI_ACLK_DIV_MASK, 690*df8f8a42SFinley Xiao PERI_PLL_GPLL << PERI_PLL_SEL_SHIFT | 691*df8f8a42SFinley Xiao (src_clk_div - 1) << PERI_ACLK_DIV_SHIFT); 692*df8f8a42SFinley Xiao break; 693*df8f8a42SFinley Xiao case HCLK_PERI_PRE: 694*df8f8a42SFinley Xiao rk_clrsetreg(&cru->clksel_con[14], 695*df8f8a42SFinley Xiao PERI_PLL_SEL_MASK | PERI_HCLK_DIV_MASK, 696*df8f8a42SFinley Xiao PERI_PLL_GPLL << PERI_PLL_SEL_SHIFT | 697*df8f8a42SFinley Xiao (src_clk_div - 1) << PERI_HCLK_DIV_SHIFT); 698*df8f8a42SFinley Xiao break; 699*df8f8a42SFinley Xiao default: 700*df8f8a42SFinley Xiao printf("do not support this peri freq\n"); 701*df8f8a42SFinley Xiao return -EINVAL; 702*df8f8a42SFinley Xiao } 703*df8f8a42SFinley Xiao 704*df8f8a42SFinley Xiao return px30_peri_get_clk(cru, clk_id); 705*df8f8a42SFinley Xiao } 706*df8f8a42SFinley Xiao 707a60961a3SKever Yang static ulong px30_clk_get_rate(struct clk *clk) 708a60961a3SKever Yang { 709a60961a3SKever Yang struct px30_clk_priv *priv = dev_get_priv(clk->dev); 710a60961a3SKever Yang ulong rate = 0; 711a60961a3SKever Yang 712a60961a3SKever Yang switch (clk->id) { 713a60961a3SKever Yang case 0 ... 15: 714a60961a3SKever Yang return 0; 715a60961a3SKever Yang case HCLK_SDMMC: 716a60961a3SKever Yang case HCLK_EMMC: 717a60961a3SKever Yang case SCLK_SDMMC: 718a60961a3SKever Yang case SCLK_EMMC: 71996f1b3d9SKever Yang case SCLK_EMMC_SAMPLE: 720a60961a3SKever Yang rate = px30_mmc_get_clk(priv->cru, clk->id); 721a60961a3SKever Yang break; 722a60961a3SKever Yang case SCLK_I2C0: 723a60961a3SKever Yang case SCLK_I2C1: 724a60961a3SKever Yang case SCLK_I2C2: 725a60961a3SKever Yang case SCLK_I2C3: 726a60961a3SKever Yang rate = px30_i2c_get_clk(priv->cru, clk->id); 727a60961a3SKever Yang break; 728a60961a3SKever Yang case SCLK_PWM0: 729fce7cb7bSFinley Xiao case SCLK_PWM1: 730f67f522bSFinley Xiao rate = px30_pwm_get_clk(priv->cru, clk->id); 731a60961a3SKever Yang break; 732a60961a3SKever Yang case SCLK_SARADC: 733a60961a3SKever Yang rate = px30_saradc_get_clk(priv->cru); 734a60961a3SKever Yang break; 735f67f522bSFinley Xiao case SCLK_SPI0: 736f67f522bSFinley Xiao case SCLK_SPI1: 737f67f522bSFinley Xiao rate = px30_spi_get_clk(priv->cru, clk->id); 738f67f522bSFinley Xiao break; 73930f1f38dSFinley Xiao case ACLK_VOPB: 74030f1f38dSFinley Xiao case DCLK_VOPB: 74130f1f38dSFinley Xiao rate = px30_vop_get_clk(priv->cru, clk->id); 74230f1f38dSFinley Xiao break; 743*df8f8a42SFinley Xiao case ACLK_BUS_PRE: 744*df8f8a42SFinley Xiao case HCLK_BUS_PRE: 745*df8f8a42SFinley Xiao case PCLK_BUS_PRE: 746*df8f8a42SFinley Xiao rate = px30_bus_get_clk(priv->cru, clk->id); 747*df8f8a42SFinley Xiao break; 748*df8f8a42SFinley Xiao case ACLK_PERI_PRE: 749*df8f8a42SFinley Xiao case HCLK_PERI_PRE: 750*df8f8a42SFinley Xiao rate = px30_peri_get_clk(priv->cru, clk->id); 751*df8f8a42SFinley Xiao break; 752a60961a3SKever Yang default: 753a60961a3SKever Yang return -ENOENT; 754a60961a3SKever Yang } 755a60961a3SKever Yang 756a60961a3SKever Yang return rate; 757a60961a3SKever Yang } 758a60961a3SKever Yang 759a60961a3SKever Yang static ulong px30_clk_set_rate(struct clk *clk, ulong rate) 760a60961a3SKever Yang { 761a60961a3SKever Yang struct px30_clk_priv *priv = dev_get_priv(clk->dev); 762a60961a3SKever Yang ulong ret = 0; 763a60961a3SKever Yang 764c4867301SKever Yang debug("%s %ld %ld\n", __func__, clk->id, rate); 765a60961a3SKever Yang switch (clk->id) { 766a60961a3SKever Yang case 0 ... 15: 767a60961a3SKever Yang return 0; 768a60961a3SKever Yang case HCLK_SDMMC: 769a60961a3SKever Yang case HCLK_EMMC: 770a60961a3SKever Yang case SCLK_SDMMC: 771a60961a3SKever Yang case SCLK_EMMC: 772a60961a3SKever Yang ret = px30_mmc_set_clk(priv->cru, clk->id, rate); 773a60961a3SKever Yang break; 774a60961a3SKever Yang case SCLK_I2C0: 775a60961a3SKever Yang case SCLK_I2C1: 776a60961a3SKever Yang case SCLK_I2C2: 777a60961a3SKever Yang case SCLK_I2C3: 778a60961a3SKever Yang ret = px30_i2c_set_clk(priv->cru, clk->id, rate); 779a60961a3SKever Yang break; 780a60961a3SKever Yang case SCLK_PWM0: 781f67f522bSFinley Xiao case SCLK_PWM1: 782f67f522bSFinley Xiao ret = px30_pwm_set_clk(priv->cru, clk->id, rate); 783a60961a3SKever Yang break; 784a60961a3SKever Yang case SCLK_SARADC: 785a60961a3SKever Yang ret = px30_saradc_set_clk(priv->cru, rate); 786a60961a3SKever Yang break; 787f67f522bSFinley Xiao case SCLK_SPI0: 788f67f522bSFinley Xiao case SCLK_SPI1: 789f67f522bSFinley Xiao ret = px30_spi_set_clk(priv->cru, clk->id, rate); 790f67f522bSFinley Xiao break; 79130f1f38dSFinley Xiao case ACLK_VOPB: 79230f1f38dSFinley Xiao case DCLK_VOPB: 79330f1f38dSFinley Xiao ret = px30_vop_set_clk(priv->cru, clk->id, rate); 79430f1f38dSFinley Xiao break; 795*df8f8a42SFinley Xiao case ACLK_BUS_PRE: 796*df8f8a42SFinley Xiao case HCLK_BUS_PRE: 797*df8f8a42SFinley Xiao case PCLK_BUS_PRE: 798*df8f8a42SFinley Xiao ret = px30_bus_set_clk(priv->cru, clk->id, rate); 799*df8f8a42SFinley Xiao break; 800*df8f8a42SFinley Xiao case ACLK_PERI_PRE: 801*df8f8a42SFinley Xiao case HCLK_PERI_PRE: 802*df8f8a42SFinley Xiao ret = px30_peri_set_clk(priv->cru, clk->id, rate); 803*df8f8a42SFinley Xiao break; 804a60961a3SKever Yang default: 805a60961a3SKever Yang return -ENOENT; 806a60961a3SKever Yang } 807a60961a3SKever Yang 808a60961a3SKever Yang return ret; 809a60961a3SKever Yang } 810a60961a3SKever Yang 811a60961a3SKever Yang #define ROCKCHIP_MMC_DELAY_SEL BIT(10) 812a60961a3SKever Yang #define ROCKCHIP_MMC_DEGREE_MASK 0x3 813a60961a3SKever Yang #define ROCKCHIP_MMC_DELAYNUM_OFFSET 2 814a60961a3SKever Yang #define ROCKCHIP_MMC_DELAYNUM_MASK (0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET) 815a60961a3SKever Yang 816a60961a3SKever Yang #define PSECS_PER_SEC 1000000000000LL 817a60961a3SKever Yang /* 818a60961a3SKever Yang * Each fine delay is between 44ps-77ps. Assume each fine delay is 60ps to 819a60961a3SKever Yang * simplify calculations. So 45degs could be anywhere between 33deg and 57.8deg. 820a60961a3SKever Yang */ 821a60961a3SKever Yang #define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60 822a60961a3SKever Yang 823a60961a3SKever Yang int rockchip_mmc_get_phase(struct clk *clk) 824a60961a3SKever Yang { 825a60961a3SKever Yang struct px30_clk_priv *priv = dev_get_priv(clk->dev); 826a60961a3SKever Yang struct px30_cru *cru = priv->cru; 827a60961a3SKever Yang u32 raw_value, delay_num; 828a60961a3SKever Yang u16 degrees = 0; 829a60961a3SKever Yang ulong rate; 830a60961a3SKever Yang 831a60961a3SKever Yang rate = px30_clk_get_rate(clk); 832a60961a3SKever Yang 833a60961a3SKever Yang if (rate < 0) 834a60961a3SKever Yang return rate; 835a60961a3SKever Yang 836a60961a3SKever Yang if (clk->id == SCLK_EMMC_SAMPLE) 837a60961a3SKever Yang raw_value = readl(&cru->emmc_con[1]); 838a60961a3SKever Yang else 839a60961a3SKever Yang raw_value = readl(&cru->sdmmc_con[1]); 840a60961a3SKever Yang 84196f1b3d9SKever Yang raw_value >>= 1; 842a60961a3SKever Yang degrees = (raw_value & ROCKCHIP_MMC_DEGREE_MASK) * 90; 843a60961a3SKever Yang 844a60961a3SKever Yang if (raw_value & ROCKCHIP_MMC_DELAY_SEL) { 845a60961a3SKever Yang /* degrees/delaynum * 10000 */ 846a60961a3SKever Yang unsigned long factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) * 847a60961a3SKever Yang 36 * (rate / 1000000); 848a60961a3SKever Yang 849a60961a3SKever Yang delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK); 850a60961a3SKever Yang delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET; 851a60961a3SKever Yang degrees += DIV_ROUND_CLOSEST(delay_num * factor, 10000); 852a60961a3SKever Yang } 853a60961a3SKever Yang 854a60961a3SKever Yang return degrees % 360; 855a60961a3SKever Yang } 856a60961a3SKever Yang 857a60961a3SKever Yang int rockchip_mmc_set_phase(struct clk *clk, u32 degrees) 858a60961a3SKever Yang { 859a60961a3SKever Yang struct px30_clk_priv *priv = dev_get_priv(clk->dev); 860a60961a3SKever Yang struct px30_cru *cru = priv->cru; 861a60961a3SKever Yang u8 nineties, remainder, delay_num; 862a60961a3SKever Yang u32 raw_value, delay; 863a60961a3SKever Yang ulong rate; 864a60961a3SKever Yang 865a60961a3SKever Yang rate = px30_clk_get_rate(clk); 866a60961a3SKever Yang 867a60961a3SKever Yang if (rate < 0) 868a60961a3SKever Yang return rate; 869a60961a3SKever Yang 870a60961a3SKever Yang nineties = degrees / 90; 871a60961a3SKever Yang remainder = (degrees % 90); 872a60961a3SKever Yang 873a60961a3SKever Yang /* 874a60961a3SKever Yang * Convert to delay; do a little extra work to make sure we 875a60961a3SKever Yang * don't overflow 32-bit / 64-bit numbers. 876a60961a3SKever Yang */ 877a60961a3SKever Yang delay = 10000000; /* PSECS_PER_SEC / 10000 / 10 */ 878a60961a3SKever Yang delay *= remainder; 879a60961a3SKever Yang delay = DIV_ROUND_CLOSEST(delay, (rate / 1000) * 36 * 880a60961a3SKever Yang (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10)); 881a60961a3SKever Yang 882a60961a3SKever Yang delay_num = (u8)min_t(u32, delay, 255); 883a60961a3SKever Yang 884a60961a3SKever Yang raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0; 885a60961a3SKever Yang raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET; 886a60961a3SKever Yang raw_value |= nineties; 887a60961a3SKever Yang 88896f1b3d9SKever Yang raw_value <<= 1; 889a60961a3SKever Yang if (clk->id == SCLK_EMMC_SAMPLE) 890a60961a3SKever Yang writel(raw_value | 0xffff0000, &cru->emmc_con[1]); 891a60961a3SKever Yang else 892a60961a3SKever Yang writel(raw_value | 0xffff0000, &cru->sdmmc_con[1]); 893a60961a3SKever Yang 894a60961a3SKever Yang debug("mmc set_phase(%d) delay_nums=%u reg=%#x actual_degrees=%d\n", 895a60961a3SKever Yang degrees, delay_num, raw_value, rockchip_mmc_get_phase(clk)); 896a60961a3SKever Yang 897a60961a3SKever Yang return 0; 898a60961a3SKever Yang } 899a60961a3SKever Yang 900a60961a3SKever Yang static int px30_clk_get_phase(struct clk *clk) 901a60961a3SKever Yang { 902a60961a3SKever Yang int ret; 903a60961a3SKever Yang 904a60961a3SKever Yang switch (clk->id) { 905a60961a3SKever Yang case SCLK_EMMC_SAMPLE: 906a60961a3SKever Yang case SCLK_SDMMC_SAMPLE: 907a60961a3SKever Yang ret = rockchip_mmc_get_phase(clk); 908a60961a3SKever Yang break; 909a60961a3SKever Yang default: 910a60961a3SKever Yang return -ENOENT; 911a60961a3SKever Yang } 912a60961a3SKever Yang 913a60961a3SKever Yang return ret; 914a60961a3SKever Yang } 915a60961a3SKever Yang 916a60961a3SKever Yang static int px30_clk_set_phase(struct clk *clk, int degrees) 917a60961a3SKever Yang { 918a60961a3SKever Yang int ret; 919a60961a3SKever Yang 920a60961a3SKever Yang switch (clk->id) { 921a60961a3SKever Yang case SCLK_EMMC_SAMPLE: 922a60961a3SKever Yang case SCLK_SDMMC_SAMPLE: 923a60961a3SKever Yang ret = rockchip_mmc_set_phase(clk, degrees); 924a60961a3SKever Yang break; 925a60961a3SKever Yang default: 926a60961a3SKever Yang return -ENOENT; 927a60961a3SKever Yang } 928a60961a3SKever Yang 929a60961a3SKever Yang return ret; 930a60961a3SKever Yang } 931a60961a3SKever Yang 932a60961a3SKever Yang static struct clk_ops px30_clk_ops = { 933a60961a3SKever Yang .get_rate = px30_clk_get_rate, 934a60961a3SKever Yang .set_rate = px30_clk_set_rate, 935a60961a3SKever Yang .get_phase = px30_clk_get_phase, 936a60961a3SKever Yang .set_phase = px30_clk_set_phase, 937a60961a3SKever Yang }; 938a60961a3SKever Yang 939a60961a3SKever Yang static int px30_clk_probe(struct udevice *dev) 940a60961a3SKever Yang { 941a60961a3SKever Yang struct px30_clk_priv *priv = dev_get_priv(dev); 9420dc8896cSKever Yang u32 reg = readl(&priv->cru->clksel_con[23]); 943a60961a3SKever Yang 9440dc8896cSKever Yang /* Only do the rkclk_init() one time for boot up */ 9450dc8896cSKever Yang if (((reg & BUS_ACLK_DIV_MASK) >> BUS_ACLK_DIV_SHIFT) != 9460dc8896cSKever Yang (GPLL_HZ / BUS_ACLK_HZ - 1)) 947a60961a3SKever Yang rkclk_init(priv->cru); 948a60961a3SKever Yang 949a60961a3SKever Yang return 0; 950a60961a3SKever Yang } 951a60961a3SKever Yang 952a60961a3SKever Yang static int px30_clk_ofdata_to_platdata(struct udevice *dev) 953a60961a3SKever Yang { 954a60961a3SKever Yang struct px30_clk_priv *priv = dev_get_priv(dev); 955a60961a3SKever Yang 9564203970bSKever Yang priv->cru = dev_read_addr_ptr(dev); 957a60961a3SKever Yang 958a60961a3SKever Yang return 0; 959a60961a3SKever Yang } 960a60961a3SKever Yang 961a60961a3SKever Yang static int px30_clk_bind(struct udevice *dev) 962a60961a3SKever Yang { 963a60961a3SKever Yang int ret; 964a60961a3SKever Yang struct udevice *sys_child, *sf_child; 965a60961a3SKever Yang struct sysreset_reg *priv; 966a60961a3SKever Yang struct softreset_reg *sf_priv; 967a60961a3SKever Yang 968a60961a3SKever Yang /* The reset driver does not have a device node, so bind it here */ 969a60961a3SKever Yang ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset", 970a60961a3SKever Yang &sys_child); 971a60961a3SKever Yang if (ret) { 972a60961a3SKever Yang debug("Warning: No sysreset driver: ret=%d\n", ret); 973a60961a3SKever Yang } else { 974a60961a3SKever Yang priv = malloc(sizeof(struct sysreset_reg)); 975a60961a3SKever Yang priv->glb_srst_fst_value = offsetof(struct px30_cru, 976a60961a3SKever Yang glb_srst_fst); 977a60961a3SKever Yang priv->glb_srst_snd_value = offsetof(struct px30_cru, 978a60961a3SKever Yang glb_srst_snd); 979a60961a3SKever Yang sys_child->priv = priv; 980a60961a3SKever Yang } 981a60961a3SKever Yang 982a60961a3SKever Yang ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset", 983a60961a3SKever Yang dev_ofnode(dev), &sf_child); 984a60961a3SKever Yang if (ret) { 985a60961a3SKever Yang debug("Warning: No rockchip reset driver: ret=%d\n", ret); 986a60961a3SKever Yang } else { 987a60961a3SKever Yang sf_priv = malloc(sizeof(struct softreset_reg)); 988a60961a3SKever Yang sf_priv->sf_reset_offset = offsetof(struct px30_cru, 989a60961a3SKever Yang softrst_con[0]); 990a60961a3SKever Yang sf_priv->sf_reset_num = 12; 991a60961a3SKever Yang sf_child->priv = sf_priv; 992a60961a3SKever Yang } 993a60961a3SKever Yang 994a60961a3SKever Yang return 0; 995a60961a3SKever Yang } 996a60961a3SKever Yang 997a60961a3SKever Yang static const struct udevice_id px30_clk_ids[] = { 998a60961a3SKever Yang { .compatible = "rockchip,px30-cru" }, 999a60961a3SKever Yang { } 1000a60961a3SKever Yang }; 1001a60961a3SKever Yang 1002a60961a3SKever Yang U_BOOT_DRIVER(rockchip_px30_cru) = { 1003a60961a3SKever Yang .name = "rockchip_px30_cru", 1004a60961a3SKever Yang .id = UCLASS_CLK, 1005a60961a3SKever Yang .of_match = px30_clk_ids, 1006a60961a3SKever Yang .priv_auto_alloc_size = sizeof(struct px30_clk_priv), 1007a60961a3SKever Yang .ofdata_to_platdata = px30_clk_ofdata_to_platdata, 1008a60961a3SKever Yang .ops = &px30_clk_ops, 1009a60961a3SKever Yang .bind = px30_clk_bind, 1010a60961a3SKever Yang .probe = px30_clk_probe, 1011a60961a3SKever Yang }; 1012