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 29cefa5186SFinley Xiao #define PX30_PLL_RATE(_rate, _refdiv, _fbdiv, _postdiv1, \ 30cefa5186SFinley Xiao _postdiv2, _dsmpd, _frac) \ 31cefa5186SFinley Xiao { \ 32cefa5186SFinley Xiao .rate = _rate##U, \ 33cefa5186SFinley Xiao .fbdiv = _fbdiv, \ 34cefa5186SFinley Xiao .postdiv1 = _postdiv1, \ 35cefa5186SFinley Xiao .refdiv = _refdiv, \ 36cefa5186SFinley Xiao .postdiv2 = _postdiv2, \ 37cefa5186SFinley Xiao .dsmpd = _dsmpd, \ 38cefa5186SFinley Xiao .frac = _frac, \ 39cefa5186SFinley Xiao } 40cefa5186SFinley Xiao 41a60961a3SKever Yang #define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1)) 42a60961a3SKever Yang 43cefa5186SFinley Xiao static struct pll_rate_table px30_pll_rates[] = { 44cefa5186SFinley Xiao /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */ 45cefa5186SFinley Xiao PX30_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0), 46cefa5186SFinley Xiao PX30_PLL_RATE(1188000000, 2, 99, 1, 1, 1, 0), 47cefa5186SFinley Xiao PX30_PLL_RATE(1100000000, 12, 550, 1, 1, 1, 0), 48cefa5186SFinley Xiao PX30_PLL_RATE(1000000000, 6, 500, 2, 1, 1, 0), 49cefa5186SFinley Xiao PX30_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0), 50a60961a3SKever Yang }; 51a60961a3SKever Yang 52bcefd077SFinley Xiao static u8 pll_mode_shift[PLL_COUNT] = { 53bcefd077SFinley Xiao APLL_MODE_SHIFT, DPLL_MODE_SHIFT, CPLL_MODE_SHIFT, 54bcefd077SFinley Xiao NPLL_MODE_SHIFT, GPLL_MODE_SHIFT 55bcefd077SFinley Xiao }; 56bcefd077SFinley Xiao static u32 pll_mode_mask[PLL_COUNT] = { 57bcefd077SFinley Xiao APLL_MODE_MASK, DPLL_MODE_MASK, CPLL_MODE_MASK, 58bcefd077SFinley Xiao NPLL_MODE_MASK, GPLL_MODE_MASK 59bcefd077SFinley Xiao }; 60bcefd077SFinley Xiao 61cefa5186SFinley Xiao static struct pll_rate_table auto_table; 62cefa5186SFinley Xiao 63cefa5186SFinley Xiao static struct pll_rate_table *pll_clk_set_by_auto(u32 drate) 64cefa5186SFinley Xiao { 65cefa5186SFinley Xiao struct pll_rate_table *rate = &auto_table; 66cefa5186SFinley Xiao u32 ref_khz = OSC_HZ / KHz, refdiv, fbdiv = 0; 67cefa5186SFinley Xiao u32 postdiv1, postdiv2 = 1; 68cefa5186SFinley Xiao u32 fref_khz; 69cefa5186SFinley Xiao u32 diff_khz, best_diff_khz; 70cefa5186SFinley Xiao const u32 max_refdiv = 63, max_fbdiv = 3200, min_fbdiv = 16; 71cefa5186SFinley Xiao const u32 max_postdiv1 = 7, max_postdiv2 = 7; 72cefa5186SFinley Xiao u32 vco_khz; 73cefa5186SFinley Xiao u32 rate_khz = drate / KHz; 74cefa5186SFinley Xiao 75cefa5186SFinley Xiao if (!drate) { 76cefa5186SFinley Xiao printf("%s: the frequency can't be 0 Hz\n", __func__); 77cefa5186SFinley Xiao return NULL; 78cefa5186SFinley Xiao } 79cefa5186SFinley Xiao 80cefa5186SFinley Xiao postdiv1 = DIV_ROUND_UP(VCO_MIN_HZ / 1000, rate_khz); 81cefa5186SFinley Xiao if (postdiv1 > max_postdiv1) { 82cefa5186SFinley Xiao postdiv2 = DIV_ROUND_UP(postdiv1, max_postdiv1); 83cefa5186SFinley Xiao postdiv1 = DIV_ROUND_UP(postdiv1, postdiv2); 84cefa5186SFinley Xiao } 85cefa5186SFinley Xiao 86cefa5186SFinley Xiao vco_khz = rate_khz * postdiv1 * postdiv2; 87cefa5186SFinley Xiao 88cefa5186SFinley Xiao if (vco_khz < (VCO_MIN_HZ / KHz) || vco_khz > (VCO_MAX_HZ / KHz) || 89cefa5186SFinley Xiao postdiv2 > max_postdiv2) { 90cefa5186SFinley Xiao printf("%s: Cannot find out a supported VCO for Freq (%uHz)\n", 91cefa5186SFinley Xiao __func__, rate_khz); 92cefa5186SFinley Xiao return NULL; 93cefa5186SFinley Xiao } 94cefa5186SFinley Xiao 95cefa5186SFinley Xiao rate->postdiv1 = postdiv1; 96cefa5186SFinley Xiao rate->postdiv2 = postdiv2; 97cefa5186SFinley Xiao 98cefa5186SFinley Xiao best_diff_khz = vco_khz; 99cefa5186SFinley Xiao for (refdiv = 1; refdiv < max_refdiv && best_diff_khz; refdiv++) { 100cefa5186SFinley Xiao fref_khz = ref_khz / refdiv; 101cefa5186SFinley Xiao 102cefa5186SFinley Xiao fbdiv = vco_khz / fref_khz; 103cefa5186SFinley Xiao if ((fbdiv >= max_fbdiv) || (fbdiv <= min_fbdiv)) 104cefa5186SFinley Xiao continue; 105cefa5186SFinley Xiao diff_khz = vco_khz - fbdiv * fref_khz; 106cefa5186SFinley Xiao if (fbdiv + 1 < max_fbdiv && diff_khz > fref_khz / 2) { 107cefa5186SFinley Xiao fbdiv++; 108cefa5186SFinley Xiao diff_khz = fref_khz - diff_khz; 109cefa5186SFinley Xiao } 110cefa5186SFinley Xiao 111cefa5186SFinley Xiao if (diff_khz >= best_diff_khz) 112cefa5186SFinley Xiao continue; 113cefa5186SFinley Xiao 114cefa5186SFinley Xiao best_diff_khz = diff_khz; 115cefa5186SFinley Xiao rate->refdiv = refdiv; 116cefa5186SFinley Xiao rate->fbdiv = fbdiv; 117cefa5186SFinley Xiao } 118cefa5186SFinley Xiao 119cefa5186SFinley Xiao if (best_diff_khz > 4 * (MHz / KHz)) { 120cefa5186SFinley Xiao printf("%s: Failed to match output frequency %u bestis %u Hz\n", 121cefa5186SFinley Xiao __func__, rate_khz, 122cefa5186SFinley Xiao best_diff_khz * KHz); 123cefa5186SFinley Xiao return NULL; 124cefa5186SFinley Xiao } 125cefa5186SFinley Xiao 126cefa5186SFinley Xiao return rate; 127cefa5186SFinley Xiao } 128cefa5186SFinley Xiao 129cefa5186SFinley Xiao static const struct pll_rate_table *get_pll_settings(unsigned long rate) 130cefa5186SFinley Xiao { 131cefa5186SFinley Xiao unsigned int rate_count = ARRAY_SIZE(px30_pll_rates); 132cefa5186SFinley Xiao int i; 133cefa5186SFinley Xiao 134cefa5186SFinley Xiao for (i = 0; i < rate_count; i++) { 135cefa5186SFinley Xiao if (rate == px30_pll_rates[i].rate) 136cefa5186SFinley Xiao return &px30_pll_rates[i]; 137cefa5186SFinley Xiao } 138cefa5186SFinley Xiao 139cefa5186SFinley Xiao return pll_clk_set_by_auto(rate); 140cefa5186SFinley Xiao } 141a60961a3SKever Yang 142a60961a3SKever Yang /* 143a60961a3SKever Yang * How to calculate the PLL(from TRM V0.3 Part 1 Page 63): 144a60961a3SKever Yang * Formulas also embedded within the Fractional PLL Verilog model: 145a60961a3SKever Yang * If DSMPD = 1 (DSM is disabled, "integer mode") 146a60961a3SKever Yang * FOUTVCO = FREF / REFDIV * FBDIV 147a60961a3SKever Yang * FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2 148a60961a3SKever Yang * Where: 149a60961a3SKever Yang * FOUTVCO = Fractional PLL non-divided output frequency 150a60961a3SKever Yang * FOUTPOSTDIV = Fractional PLL divided output frequency 151a60961a3SKever Yang * (output of second post divider) 152a60961a3SKever Yang * FREF = Fractional PLL input reference frequency, (the OSC_HZ 24MHz input) 153a60961a3SKever Yang * REFDIV = Fractional PLL input reference clock divider 154a60961a3SKever Yang * FBDIV = Integer value programmed into feedback divide 155a60961a3SKever Yang * 156a60961a3SKever Yang */ 157cefa5186SFinley Xiao static int rkclk_set_pll(struct px30_pll *pll, unsigned int *mode, 158cefa5186SFinley Xiao enum px30_pll_id pll_id, 159cefa5186SFinley Xiao unsigned long drate) 160a60961a3SKever Yang { 161cefa5186SFinley Xiao const struct pll_rate_table *rate; 162cefa5186SFinley Xiao uint vco_hz, output_hz; 163db235eb5SFinley Xiao 164cefa5186SFinley Xiao rate = get_pll_settings(drate); 165cefa5186SFinley Xiao if (!rate) { 166cefa5186SFinley Xiao printf("%s unsupport rate\n", __func__); 167cefa5186SFinley Xiao return -EINVAL; 168cefa5186SFinley Xiao } 169cefa5186SFinley Xiao 170cefa5186SFinley Xiao /* All PLLs have same VCO and output frequency range restrictions. */ 171cefa5186SFinley Xiao vco_hz = OSC_HZ / 1000 * rate->fbdiv / rate->refdiv * 1000; 172cefa5186SFinley Xiao output_hz = vco_hz / rate->postdiv1 / rate->postdiv2; 173a60961a3SKever Yang 174a60961a3SKever Yang debug("PLL at %p: fb=%d, ref=%d, pst1=%d, pst2=%d, vco=%u Hz, output=%u Hz\n", 175cefa5186SFinley Xiao pll, rate->fbdiv, rate->refdiv, rate->postdiv1, 176cefa5186SFinley Xiao rate->postdiv2, vco_hz, output_hz); 177a60961a3SKever Yang assert(vco_hz >= VCO_MIN_HZ && vco_hz <= VCO_MAX_HZ && 178a60961a3SKever Yang output_hz >= OUTPUT_MIN_HZ && output_hz <= OUTPUT_MAX_HZ); 179a60961a3SKever Yang 180db235eb5SFinley Xiao /* 181db235eb5SFinley Xiao * When power on or changing PLL setting, 182db235eb5SFinley Xiao * we must force PLL into slow mode to ensure output stable clock. 183db235eb5SFinley Xiao */ 184bcefd077SFinley Xiao rk_clrsetreg(mode, pll_mode_mask[pll_id], 185bcefd077SFinley Xiao PLLMUX_FROM_XIN24M << pll_mode_shift[pll_id]); 186db235eb5SFinley Xiao 187a60961a3SKever Yang /* use integer mode */ 188a60961a3SKever Yang rk_setreg(&pll->con1, 1 << PLL_DSMPD_SHIFT); 189a60961a3SKever Yang /* Power down */ 190a60961a3SKever Yang rk_setreg(&pll->con1, 1 << PLL_PD_SHIFT); 191a60961a3SKever Yang 192a60961a3SKever Yang rk_clrsetreg(&pll->con0, 193a60961a3SKever Yang PLL_POSTDIV1_MASK | PLL_FBDIV_MASK, 194cefa5186SFinley Xiao (rate->postdiv1 << PLL_POSTDIV1_SHIFT) | rate->fbdiv); 195a60961a3SKever Yang rk_clrsetreg(&pll->con1, PLL_POSTDIV2_MASK | PLL_REFDIV_MASK, 196cefa5186SFinley Xiao (rate->postdiv2 << PLL_POSTDIV2_SHIFT | 197cefa5186SFinley Xiao rate->refdiv << PLL_REFDIV_SHIFT)); 198a60961a3SKever Yang 199a60961a3SKever Yang /* Power Up */ 200a60961a3SKever Yang rk_clrreg(&pll->con1, 1 << PLL_PD_SHIFT); 201a60961a3SKever Yang 202a60961a3SKever Yang /* waiting for pll lock */ 2036fb52eadSFinley Xiao while (!(readl(&pll->con1) & (1 << PLL_LOCK_STATUS_SHIFT))) 204a60961a3SKever Yang udelay(1); 205a60961a3SKever Yang 206bcefd077SFinley Xiao rk_clrsetreg(mode, pll_mode_mask[pll_id], 207bcefd077SFinley Xiao PLLMUX_FROM_PLL << pll_mode_shift[pll_id]); 208db235eb5SFinley Xiao 209cefa5186SFinley Xiao return 0; 210a60961a3SKever Yang } 211a60961a3SKever Yang 212cefa5186SFinley Xiao static uint32_t rkclk_pll_get_rate(struct px30_pll *pll, unsigned int *mode, 21330f1f38dSFinley Xiao enum px30_pll_id pll_id) 21430f1f38dSFinley Xiao { 21530f1f38dSFinley Xiao u32 refdiv, fbdiv, postdiv1, postdiv2; 216cefa5186SFinley Xiao u32 con, shift, mask; 21730f1f38dSFinley Xiao 218cefa5186SFinley Xiao con = readl(mode); 219bcefd077SFinley Xiao shift = pll_mode_shift[pll_id]; 220bcefd077SFinley Xiao mask = pll_mode_mask[pll_id]; 22130f1f38dSFinley Xiao 22230f1f38dSFinley Xiao switch ((con & mask) >> shift) { 22330f1f38dSFinley Xiao case PLLMUX_FROM_XIN24M: 22430f1f38dSFinley Xiao return OSC_HZ; 22530f1f38dSFinley Xiao case PLLMUX_FROM_PLL: 22630f1f38dSFinley Xiao /* normal mode */ 22730f1f38dSFinley Xiao con = readl(&pll->con0); 22830f1f38dSFinley Xiao postdiv1 = (con & PLL_POSTDIV1_MASK) >> PLL_POSTDIV1_SHIFT; 22930f1f38dSFinley Xiao fbdiv = (con & PLL_FBDIV_MASK) >> PLL_FBDIV_SHIFT; 23030f1f38dSFinley Xiao con = readl(&pll->con1); 23130f1f38dSFinley Xiao postdiv2 = (con & PLL_POSTDIV2_MASK) >> PLL_POSTDIV2_SHIFT; 23230f1f38dSFinley Xiao refdiv = (con & PLL_REFDIV_MASK) >> PLL_REFDIV_SHIFT; 23330f1f38dSFinley Xiao return (24 * fbdiv / (refdiv * postdiv1 * postdiv2)) * 1000000; 23430f1f38dSFinley Xiao case PLLMUX_FROM_RTC32K: 23530f1f38dSFinley Xiao default: 23630f1f38dSFinley Xiao return 32768; 23730f1f38dSFinley Xiao } 23830f1f38dSFinley Xiao } 23930f1f38dSFinley Xiao 240cefa5186SFinley Xiao static ulong px30_i2c_get_clk(struct px30_clk_priv *priv, ulong clk_id) 24130f1f38dSFinley Xiao { 242cefa5186SFinley Xiao struct px30_cru *cru = priv->cru; 243a60961a3SKever Yang u32 div, con; 244a60961a3SKever Yang 245a60961a3SKever Yang switch (clk_id) { 246a60961a3SKever Yang case SCLK_I2C0: 247f67f522bSFinley Xiao con = readl(&cru->clksel_con[49]); 248f67f522bSFinley Xiao div = con >> CLK_I2C0_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK; 249a60961a3SKever Yang break; 250a60961a3SKever Yang case SCLK_I2C1: 251f67f522bSFinley Xiao con = readl(&cru->clksel_con[49]); 252f67f522bSFinley Xiao div = con >> CLK_I2C1_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK; 253a60961a3SKever Yang break; 254a60961a3SKever Yang case SCLK_I2C2: 255f67f522bSFinley Xiao con = readl(&cru->clksel_con[50]); 256f67f522bSFinley Xiao div = con >> CLK_I2C2_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK; 257a60961a3SKever Yang break; 258a60961a3SKever Yang case SCLK_I2C3: 259f67f522bSFinley Xiao con = readl(&cru->clksel_con[50]); 260f67f522bSFinley Xiao div = con >> CLK_I2C3_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK; 261a60961a3SKever Yang break; 262a60961a3SKever Yang default: 263a60961a3SKever Yang printf("do not support this i2c bus\n"); 264a60961a3SKever Yang return -EINVAL; 265a60961a3SKever Yang } 266a60961a3SKever Yang 267cefa5186SFinley Xiao return DIV_TO_RATE(priv->gpll_hz, div); 268a60961a3SKever Yang } 269a60961a3SKever Yang 270cefa5186SFinley Xiao static ulong px30_i2c_set_clk(struct px30_clk_priv *priv, ulong clk_id, uint hz) 271a60961a3SKever Yang { 272cefa5186SFinley Xiao struct px30_cru *cru = priv->cru; 273a60961a3SKever Yang int src_clk_div; 274a60961a3SKever Yang 275cefa5186SFinley Xiao src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz); 276a60961a3SKever Yang assert(src_clk_div - 1 < 127); 277a60961a3SKever Yang 278a60961a3SKever Yang switch (clk_id) { 279a60961a3SKever Yang case SCLK_I2C0: 280f67f522bSFinley Xiao rk_clrsetreg(&cru->clksel_con[49], 281f67f522bSFinley Xiao CLK_I2C_DIV_CON_MASK << CLK_I2C0_DIV_CON_SHIFT | 282f67f522bSFinley Xiao CLK_I2C_PLL_SEL_MASK << CLK_I2C0_PLL_SEL_SHIFT, 283f67f522bSFinley Xiao (src_clk_div - 1) << CLK_I2C0_DIV_CON_SHIFT | 284f67f522bSFinley Xiao CLK_I2C_PLL_SEL_GPLL << CLK_I2C0_PLL_SEL_SHIFT); 285a60961a3SKever Yang break; 286a60961a3SKever Yang case SCLK_I2C1: 287f67f522bSFinley Xiao rk_clrsetreg(&cru->clksel_con[49], 288f67f522bSFinley Xiao CLK_I2C_DIV_CON_MASK << CLK_I2C1_DIV_CON_SHIFT | 289f67f522bSFinley Xiao CLK_I2C_PLL_SEL_MASK << CLK_I2C1_PLL_SEL_SHIFT, 290f67f522bSFinley Xiao (src_clk_div - 1) << CLK_I2C1_DIV_CON_SHIFT | 291f67f522bSFinley Xiao CLK_I2C_PLL_SEL_GPLL << CLK_I2C1_PLL_SEL_SHIFT); 292a60961a3SKever Yang break; 293a60961a3SKever Yang case SCLK_I2C2: 294f67f522bSFinley Xiao rk_clrsetreg(&cru->clksel_con[50], 295f67f522bSFinley Xiao CLK_I2C_DIV_CON_MASK << CLK_I2C2_DIV_CON_SHIFT | 296f67f522bSFinley Xiao CLK_I2C_PLL_SEL_MASK << CLK_I2C2_PLL_SEL_SHIFT, 297f67f522bSFinley Xiao (src_clk_div - 1) << CLK_I2C2_DIV_CON_SHIFT | 298f67f522bSFinley Xiao CLK_I2C_PLL_SEL_GPLL << CLK_I2C2_PLL_SEL_SHIFT); 299a60961a3SKever Yang break; 300a60961a3SKever Yang case SCLK_I2C3: 301f67f522bSFinley Xiao rk_clrsetreg(&cru->clksel_con[50], 302f67f522bSFinley Xiao CLK_I2C_DIV_CON_MASK << CLK_I2C3_DIV_CON_SHIFT | 303f67f522bSFinley Xiao CLK_I2C_PLL_SEL_MASK << CLK_I2C3_PLL_SEL_SHIFT, 304f67f522bSFinley Xiao (src_clk_div - 1) << CLK_I2C3_DIV_CON_SHIFT | 305f67f522bSFinley Xiao CLK_I2C_PLL_SEL_GPLL << CLK_I2C3_PLL_SEL_SHIFT); 306a60961a3SKever Yang break; 307a60961a3SKever Yang default: 308a60961a3SKever Yang printf("do not support this i2c bus\n"); 309a60961a3SKever Yang return -EINVAL; 310a60961a3SKever Yang } 311a60961a3SKever Yang 312cefa5186SFinley Xiao return px30_i2c_get_clk(priv, clk_id); 313a60961a3SKever Yang } 314a60961a3SKever Yang 315cefa5186SFinley Xiao static ulong px30_nandc_get_clk(struct px30_clk_priv *priv) 316a60961a3SKever Yang { 317cefa5186SFinley Xiao struct px30_cru *cru = priv->cru; 318cefa5186SFinley Xiao u32 div, con; 319cefa5186SFinley Xiao 320cefa5186SFinley Xiao con = readl(&cru->clksel_con[15]); 321cefa5186SFinley Xiao div = (con & NANDC_DIV_MASK) >> NANDC_DIV_SHIFT; 322cefa5186SFinley Xiao 323cefa5186SFinley Xiao return DIV_TO_RATE(priv->gpll_hz, div) / 2; 324cefa5186SFinley Xiao } 325cefa5186SFinley Xiao 326cefa5186SFinley Xiao static ulong px30_nandc_set_clk(struct px30_clk_priv *priv, 327cefa5186SFinley Xiao ulong set_rate) 328cefa5186SFinley Xiao { 329cefa5186SFinley Xiao struct px30_cru *cru = priv->cru; 330cefa5186SFinley Xiao int src_clk_div; 331cefa5186SFinley Xiao 332cefa5186SFinley Xiao /* Select nandc source from GPLL by default */ 333cefa5186SFinley Xiao /* nandc clock defaulg div 2 internal, need provide double in cru */ 334cefa5186SFinley Xiao src_clk_div = DIV_ROUND_UP(priv->gpll_hz / 2, set_rate); 335cefa5186SFinley Xiao assert(src_clk_div - 1 < 31); 336cefa5186SFinley Xiao 337cefa5186SFinley Xiao rk_clrsetreg(&cru->clksel_con[15], 338cefa5186SFinley Xiao NANDC_CLK_SEL_MASK | NANDC_PLL_MASK | 339cefa5186SFinley Xiao NANDC_DIV_MASK, 340cefa5186SFinley Xiao NANDC_CLK_SEL_NANDC << NANDC_CLK_SEL_SHIFT | 341cefa5186SFinley Xiao NANDC_SEL_GPLL << NANDC_PLL_SHIFT | 342cefa5186SFinley Xiao (src_clk_div - 1) << NANDC_DIV_SHIFT); 343cefa5186SFinley Xiao 344cefa5186SFinley Xiao return px30_nandc_get_clk(priv); 345cefa5186SFinley Xiao } 346cefa5186SFinley Xiao 347cefa5186SFinley Xiao static ulong px30_mmc_get_clk(struct px30_clk_priv *priv, uint clk_id) 348cefa5186SFinley Xiao { 349cefa5186SFinley Xiao struct px30_cru *cru = priv->cru; 350a60961a3SKever Yang u32 div, con, con_id; 351a60961a3SKever Yang 352a60961a3SKever Yang switch (clk_id) { 353a60961a3SKever Yang case HCLK_SDMMC: 354a60961a3SKever Yang case SCLK_SDMMC: 355a60961a3SKever Yang con_id = 16; 356a60961a3SKever Yang break; 357a60961a3SKever Yang case HCLK_EMMC: 358a60961a3SKever Yang case SCLK_EMMC: 35996f1b3d9SKever Yang case SCLK_EMMC_SAMPLE: 360a60961a3SKever Yang con_id = 20; 361a60961a3SKever Yang break; 362a60961a3SKever Yang default: 363a60961a3SKever Yang return -EINVAL; 364a60961a3SKever Yang } 365a60961a3SKever Yang 366a60961a3SKever Yang con = readl(&cru->clksel_con[con_id]); 367a60961a3SKever Yang div = (con & EMMC_DIV_MASK) >> EMMC_DIV_SHIFT; 368a60961a3SKever Yang 369a60961a3SKever Yang if ((con & EMMC_PLL_MASK) >> EMMC_PLL_SHIFT 370a60961a3SKever Yang == EMMC_SEL_24M) 371a60961a3SKever Yang return DIV_TO_RATE(OSC_HZ, div) / 2; 372a60961a3SKever Yang else 373cefa5186SFinley Xiao return DIV_TO_RATE(priv->gpll_hz, div) / 2; 374a60961a3SKever Yang 375a60961a3SKever Yang } 376a60961a3SKever Yang 377cefa5186SFinley Xiao static ulong px30_mmc_set_clk(struct px30_clk_priv *priv, 378a60961a3SKever Yang ulong clk_id, ulong set_rate) 379a60961a3SKever Yang { 380cefa5186SFinley Xiao struct px30_cru *cru = priv->cru; 381a60961a3SKever Yang int src_clk_div; 382a60961a3SKever Yang u32 con_id; 383a60961a3SKever Yang 384a60961a3SKever Yang switch (clk_id) { 385a60961a3SKever Yang case HCLK_SDMMC: 386a60961a3SKever Yang case SCLK_SDMMC: 387a60961a3SKever Yang con_id = 16; 388a60961a3SKever Yang break; 389a60961a3SKever Yang case HCLK_EMMC: 390a60961a3SKever Yang case SCLK_EMMC: 391a60961a3SKever Yang con_id = 20; 392a60961a3SKever Yang break; 393a60961a3SKever Yang default: 394a60961a3SKever Yang return -EINVAL; 395a60961a3SKever Yang } 396cefa5186SFinley Xiao 397a60961a3SKever Yang /* Select clk_sdmmc/emmc source from GPLL by default */ 398a60961a3SKever Yang /* mmc clock defaulg div 2 internal, need provide double in cru */ 399cefa5186SFinley Xiao src_clk_div = DIV_ROUND_UP(priv->gpll_hz / 2, set_rate); 400a60961a3SKever Yang 401a60961a3SKever Yang if (src_clk_div > 127) { 402a60961a3SKever Yang /* use 24MHz source for 400KHz clock */ 403a60961a3SKever Yang src_clk_div = DIV_ROUND_UP(OSC_HZ / 2, set_rate); 404a60961a3SKever Yang rk_clrsetreg(&cru->clksel_con[con_id], 405a60961a3SKever Yang EMMC_PLL_MASK | EMMC_DIV_MASK, 406a60961a3SKever Yang EMMC_SEL_24M << EMMC_PLL_SHIFT | 407a60961a3SKever Yang (src_clk_div - 1) << EMMC_DIV_SHIFT); 408a60961a3SKever Yang } else { 409a60961a3SKever Yang rk_clrsetreg(&cru->clksel_con[con_id], 410a60961a3SKever Yang EMMC_PLL_MASK | EMMC_DIV_MASK, 411a60961a3SKever Yang EMMC_SEL_GPLL << EMMC_PLL_SHIFT | 412a60961a3SKever Yang (src_clk_div - 1) << EMMC_DIV_SHIFT); 413a60961a3SKever Yang } 414a60961a3SKever Yang rk_clrsetreg(&cru->clksel_con[con_id +1], EMMC_CLK_SEL_MASK, 415a60961a3SKever Yang EMMC_CLK_SEL_EMMC); 416a60961a3SKever Yang 417cefa5186SFinley Xiao return px30_mmc_get_clk(priv, clk_id); 418a60961a3SKever Yang } 419a60961a3SKever Yang 420cefa5186SFinley Xiao static ulong px30_pwm_get_clk(struct px30_clk_priv *priv, ulong clk_id) 421a60961a3SKever Yang { 422cefa5186SFinley Xiao struct px30_cru *cru = priv->cru; 423a60961a3SKever Yang u32 div, con; 424a60961a3SKever Yang 425f67f522bSFinley Xiao switch (clk_id) { 426f67f522bSFinley Xiao case SCLK_PWM0: 427f67f522bSFinley Xiao con = readl(&cru->clksel_con[52]); 428f67f522bSFinley Xiao div = con >> CLK_PWM0_DIV_CON_SHIFT & CLK_PWM_DIV_CON_MASK; 429f67f522bSFinley Xiao break; 430f67f522bSFinley Xiao case SCLK_PWM1: 431f67f522bSFinley Xiao con = readl(&cru->clksel_con[52]); 432f67f522bSFinley Xiao div = con >> CLK_PWM1_DIV_CON_SHIFT & CLK_PWM_DIV_CON_MASK; 433f67f522bSFinley Xiao break; 434f67f522bSFinley Xiao default: 435f67f522bSFinley Xiao printf("do not support this pwm bus\n"); 436f67f522bSFinley Xiao return -EINVAL; 437f67f522bSFinley Xiao } 438f67f522bSFinley Xiao 439cefa5186SFinley Xiao return DIV_TO_RATE(priv->gpll_hz, div); 440a60961a3SKever Yang } 441a60961a3SKever Yang 442cefa5186SFinley Xiao static ulong px30_pwm_set_clk(struct px30_clk_priv *priv, ulong clk_id, uint hz) 443a60961a3SKever Yang { 444cefa5186SFinley Xiao struct px30_cru *cru = priv->cru; 445f67f522bSFinley Xiao int src_clk_div; 446a60961a3SKever Yang 447cefa5186SFinley Xiao src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz); 448f67f522bSFinley Xiao assert(src_clk_div - 1 < 127); 449f67f522bSFinley Xiao 450f67f522bSFinley Xiao switch (clk_id) { 451f67f522bSFinley Xiao case SCLK_PWM0: 452f67f522bSFinley Xiao rk_clrsetreg(&cru->clksel_con[52], 453f67f522bSFinley Xiao CLK_PWM_DIV_CON_MASK << CLK_PWM0_DIV_CON_SHIFT | 454f67f522bSFinley Xiao CLK_PWM_PLL_SEL_MASK << CLK_PWM0_PLL_SEL_SHIFT, 455f67f522bSFinley Xiao (src_clk_div - 1) << CLK_PWM0_DIV_CON_SHIFT | 456f67f522bSFinley Xiao CLK_PWM_PLL_SEL_GPLL << CLK_PWM0_PLL_SEL_SHIFT); 457f67f522bSFinley Xiao break; 458f67f522bSFinley Xiao case SCLK_PWM1: 459f67f522bSFinley Xiao rk_clrsetreg(&cru->clksel_con[52], 460f67f522bSFinley Xiao CLK_PWM_DIV_CON_MASK << CLK_PWM1_DIV_CON_SHIFT | 461f67f522bSFinley Xiao CLK_PWM_PLL_SEL_MASK << CLK_PWM1_PLL_SEL_SHIFT, 462f67f522bSFinley Xiao (src_clk_div - 1) << CLK_PWM1_DIV_CON_SHIFT | 463f67f522bSFinley Xiao CLK_PWM_PLL_SEL_GPLL << CLK_PWM1_PLL_SEL_SHIFT); 464f67f522bSFinley Xiao break; 465f67f522bSFinley Xiao default: 466f67f522bSFinley Xiao printf("do not support this pwm bus\n"); 467f67f522bSFinley Xiao return -EINVAL; 468f67f522bSFinley Xiao } 469f67f522bSFinley Xiao 470cefa5186SFinley Xiao return px30_pwm_get_clk(priv, clk_id); 471a60961a3SKever Yang } 472a60961a3SKever Yang 473cefa5186SFinley Xiao static ulong px30_saradc_get_clk(struct px30_clk_priv *priv) 474a60961a3SKever Yang { 475cefa5186SFinley Xiao struct px30_cru *cru = priv->cru; 476f67f522bSFinley Xiao u32 div, con; 477f67f522bSFinley Xiao 478f67f522bSFinley Xiao con = readl(&cru->clksel_con[55]); 479f9157291SFinley Xiao div = con >> CLK_SARADC_DIV_CON_SHIFT & CLK_SARADC_DIV_CON_MASK; 480a60961a3SKever Yang 481a60961a3SKever Yang return DIV_TO_RATE(OSC_HZ, div); 482a60961a3SKever Yang } 483a60961a3SKever Yang 484cefa5186SFinley Xiao static ulong px30_saradc_set_clk(struct px30_clk_priv *priv, uint hz) 485a60961a3SKever Yang { 486cefa5186SFinley Xiao struct px30_cru *cru = priv->cru; 487a60961a3SKever Yang int src_clk_div; 488a60961a3SKever Yang 489cefa5186SFinley Xiao src_clk_div = DIV_ROUND_UP(OSC_HZ, hz); 490f67f522bSFinley Xiao assert(src_clk_div - 1 < 2047); 491a60961a3SKever Yang 492f67f522bSFinley Xiao rk_clrsetreg(&cru->clksel_con[55], 493f67f522bSFinley Xiao CLK_SARADC_DIV_CON_MASK, 494fce7cb7bSFinley Xiao (src_clk_div - 1) << CLK_SARADC_DIV_CON_SHIFT); 495f67f522bSFinley Xiao 496cefa5186SFinley Xiao return px30_saradc_get_clk(priv); 497f67f522bSFinley Xiao } 498f67f522bSFinley Xiao 499cefa5186SFinley Xiao static ulong px30_spi_get_clk(struct px30_clk_priv *priv, ulong clk_id) 500f67f522bSFinley Xiao { 501cefa5186SFinley Xiao struct px30_cru *cru = priv->cru; 502f67f522bSFinley Xiao u32 div, con; 503f67f522bSFinley Xiao 504f67f522bSFinley Xiao switch (clk_id) { 505fce7cb7bSFinley Xiao case SCLK_SPI0: 506f67f522bSFinley Xiao con = readl(&cru->clksel_con[53]); 507f67f522bSFinley Xiao div = con >> CLK_SPI0_DIV_CON_SHIFT & CLK_SPI_DIV_CON_MASK; 508f67f522bSFinley Xiao break; 509fce7cb7bSFinley Xiao case SCLK_SPI1: 510f67f522bSFinley Xiao con = readl(&cru->clksel_con[53]); 511f67f522bSFinley Xiao div = con >> CLK_SPI1_DIV_CON_SHIFT & CLK_SPI_DIV_CON_MASK; 512f67f522bSFinley Xiao break; 513f67f522bSFinley Xiao default: 514f67f522bSFinley Xiao printf("do not support this pwm bus\n"); 515f67f522bSFinley Xiao return -EINVAL; 516f67f522bSFinley Xiao } 517f67f522bSFinley Xiao 518cefa5186SFinley Xiao return DIV_TO_RATE(priv->gpll_hz, div); 519f67f522bSFinley Xiao } 520f67f522bSFinley Xiao 521cefa5186SFinley Xiao static ulong px30_spi_set_clk(struct px30_clk_priv *priv, ulong clk_id, uint hz) 522f67f522bSFinley Xiao { 523cefa5186SFinley Xiao struct px30_cru *cru = priv->cru; 524f67f522bSFinley Xiao int src_clk_div; 525f67f522bSFinley Xiao 526cefa5186SFinley Xiao src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz); 527f67f522bSFinley Xiao assert(src_clk_div - 1 < 127); 528f67f522bSFinley Xiao 529f67f522bSFinley Xiao switch (clk_id) { 530f67f522bSFinley Xiao case SCLK_SPI0: 531f67f522bSFinley Xiao rk_clrsetreg(&cru->clksel_con[53], 532f67f522bSFinley Xiao CLK_SPI_DIV_CON_MASK << CLK_SPI0_DIV_CON_SHIFT | 533f67f522bSFinley Xiao CLK_SPI_PLL_SEL_MASK << CLK_SPI0_PLL_SEL_SHIFT, 534f67f522bSFinley Xiao (src_clk_div - 1) << CLK_SPI0_DIV_CON_SHIFT | 535f67f522bSFinley Xiao CLK_SPI_PLL_SEL_GPLL << CLK_SPI0_PLL_SEL_SHIFT); 536f67f522bSFinley Xiao break; 537f67f522bSFinley Xiao case SCLK_SPI1: 538f67f522bSFinley Xiao rk_clrsetreg(&cru->clksel_con[53], 539f67f522bSFinley Xiao CLK_SPI_DIV_CON_MASK << CLK_SPI1_DIV_CON_SHIFT | 540f67f522bSFinley Xiao CLK_SPI_PLL_SEL_MASK << CLK_SPI1_PLL_SEL_SHIFT, 541f67f522bSFinley Xiao (src_clk_div - 1) << CLK_SPI1_DIV_CON_SHIFT | 542f67f522bSFinley Xiao CLK_SPI_PLL_SEL_GPLL << CLK_SPI1_PLL_SEL_SHIFT); 543f67f522bSFinley Xiao break; 544f67f522bSFinley Xiao default: 545f67f522bSFinley Xiao printf("do not support this pwm bus\n"); 546f67f522bSFinley Xiao return -EINVAL; 547f67f522bSFinley Xiao } 548f67f522bSFinley Xiao 549cefa5186SFinley Xiao return px30_spi_get_clk(priv, clk_id); 550a60961a3SKever Yang } 551a60961a3SKever Yang 552cefa5186SFinley Xiao static ulong px30_vop_get_clk(struct px30_clk_priv *priv, ulong clk_id) 55330f1f38dSFinley Xiao { 554cefa5186SFinley Xiao struct px30_cru *cru = priv->cru; 55530f1f38dSFinley Xiao u32 div, con, parent; 55630f1f38dSFinley Xiao 55730f1f38dSFinley Xiao switch (clk_id) { 55830f1f38dSFinley Xiao case ACLK_VOPB: 55930f1f38dSFinley Xiao con = readl(&cru->clksel_con[3]); 56030f1f38dSFinley Xiao div = con & ACLK_VO_DIV_MASK; 561cefa5186SFinley Xiao parent = priv->gpll_hz; 56230f1f38dSFinley Xiao break; 56330f1f38dSFinley Xiao case DCLK_VOPB: 56430f1f38dSFinley Xiao con = readl(&cru->clksel_con[5]); 56530f1f38dSFinley Xiao div = con & DCLK_VOPB_DIV_MASK; 566cefa5186SFinley Xiao parent = rkclk_pll_get_rate(&cru->pll[CPLL], &cru->mode, CPLL); 56730f1f38dSFinley Xiao break; 56830f1f38dSFinley Xiao default: 56930f1f38dSFinley Xiao return -ENOENT; 57030f1f38dSFinley Xiao } 57130f1f38dSFinley Xiao 57230f1f38dSFinley Xiao return DIV_TO_RATE(parent, div); 57330f1f38dSFinley Xiao } 57430f1f38dSFinley Xiao 575cefa5186SFinley Xiao static ulong px30_vop_set_clk(struct px30_clk_priv *priv, ulong clk_id, uint hz) 57630f1f38dSFinley Xiao { 577cefa5186SFinley Xiao struct px30_cru *cru = priv->cru; 57830f1f38dSFinley Xiao int src_clk_div; 57930f1f38dSFinley Xiao 580cefa5186SFinley Xiao src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz); 58130f1f38dSFinley Xiao assert(src_clk_div - 1 < 31); 58230f1f38dSFinley Xiao 58330f1f38dSFinley Xiao switch (clk_id) { 58430f1f38dSFinley Xiao case ACLK_VOPB: 58530f1f38dSFinley Xiao rk_clrsetreg(&cru->clksel_con[3], 58630f1f38dSFinley Xiao ACLK_VO_PLL_MASK | ACLK_VO_DIV_MASK, 58730f1f38dSFinley Xiao ACLK_VO_SEL_GPLL << ACLK_VO_PLL_SHIFT | 58830f1f38dSFinley Xiao (src_clk_div - 1) << ACLK_VO_DIV_SHIFT); 58930f1f38dSFinley Xiao break; 59030f1f38dSFinley Xiao case DCLK_VOPB: 59130f1f38dSFinley Xiao /* 59230f1f38dSFinley Xiao * vopb dclk source from cpll, and equals to 59330f1f38dSFinley Xiao * cpll(means div == 1) 59430f1f38dSFinley Xiao */ 595cefa5186SFinley Xiao rkclk_set_pll(&cru->pll[CPLL], &cru->mode, CPLL, hz); 59630f1f38dSFinley Xiao 59730f1f38dSFinley Xiao rk_clrsetreg(&cru->clksel_con[5], 59830f1f38dSFinley Xiao DCLK_VOPB_SEL_MASK | DCLK_VOPB_PLL_SEL_MASK | 59930f1f38dSFinley Xiao DCLK_VOPB_DIV_MASK, 60030f1f38dSFinley Xiao DCLK_VOPB_SEL_DIVOUT << DCLK_VOPB_SEL_SHIFT | 60130f1f38dSFinley Xiao DCLK_VOPB_PLL_SEL_CPLL << DCLK_VOPB_PLL_SEL_SHIFT | 60230f1f38dSFinley Xiao (1 - 1) << DCLK_VOPB_DIV_SHIFT); 60330f1f38dSFinley Xiao break; 60430f1f38dSFinley Xiao default: 60530f1f38dSFinley Xiao printf("do not support this vop freq\n"); 60630f1f38dSFinley Xiao return -EINVAL; 60730f1f38dSFinley Xiao } 60830f1f38dSFinley Xiao 609cefa5186SFinley Xiao return px30_vop_get_clk(priv, clk_id); 61030f1f38dSFinley Xiao } 61130f1f38dSFinley Xiao 612cefa5186SFinley Xiao static ulong px30_bus_get_clk(struct px30_clk_priv *priv, ulong clk_id) 613df8f8a42SFinley Xiao { 614cefa5186SFinley Xiao struct px30_cru *cru = priv->cru; 615df8f8a42SFinley Xiao u32 div, con, parent; 616df8f8a42SFinley Xiao 617df8f8a42SFinley Xiao switch (clk_id) { 618df8f8a42SFinley Xiao case ACLK_BUS_PRE: 619df8f8a42SFinley Xiao con = readl(&cru->clksel_con[23]); 620df8f8a42SFinley Xiao div = (con & BUS_ACLK_DIV_MASK) >> BUS_ACLK_DIV_SHIFT; 621cefa5186SFinley Xiao parent = priv->gpll_hz; 622df8f8a42SFinley Xiao break; 623df8f8a42SFinley Xiao case HCLK_BUS_PRE: 624df8f8a42SFinley Xiao con = readl(&cru->clksel_con[24]); 625df8f8a42SFinley Xiao div = (con & BUS_HCLK_DIV_MASK) >> BUS_HCLK_DIV_SHIFT; 626cefa5186SFinley Xiao parent = priv->gpll_hz; 627df8f8a42SFinley Xiao break; 628df8f8a42SFinley Xiao case PCLK_BUS_PRE: 629cefa5186SFinley Xiao parent = px30_bus_get_clk(priv, ACLK_BUS_PRE); 630df8f8a42SFinley Xiao con = readl(&cru->clksel_con[24]); 631df8f8a42SFinley Xiao div = (con & BUS_PCLK_DIV_MASK) >> BUS_PCLK_DIV_SHIFT; 632df8f8a42SFinley Xiao break; 633df8f8a42SFinley Xiao default: 634df8f8a42SFinley Xiao return -ENOENT; 635df8f8a42SFinley Xiao } 636df8f8a42SFinley Xiao 637df8f8a42SFinley Xiao return DIV_TO_RATE(parent, div); 638df8f8a42SFinley Xiao } 639df8f8a42SFinley Xiao 640cefa5186SFinley Xiao static ulong px30_bus_set_clk(struct px30_clk_priv *priv, ulong clk_id, 641cefa5186SFinley Xiao ulong hz) 642df8f8a42SFinley Xiao { 643cefa5186SFinley Xiao struct px30_cru *cru = priv->cru; 644df8f8a42SFinley Xiao int src_clk_div; 645df8f8a42SFinley Xiao 646df8f8a42SFinley Xiao /* 647df8f8a42SFinley Xiao * select gpll as pd_bus bus clock source and 648df8f8a42SFinley Xiao * set up dependent divisors for PCLK/HCLK and ACLK clocks. 649df8f8a42SFinley Xiao */ 650df8f8a42SFinley Xiao switch (clk_id) { 651df8f8a42SFinley Xiao case ACLK_BUS_PRE: 652cefa5186SFinley Xiao src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz); 653df8f8a42SFinley Xiao assert(src_clk_div - 1 < 31); 654df8f8a42SFinley Xiao rk_clrsetreg(&cru->clksel_con[23], 655df8f8a42SFinley Xiao BUS_PLL_SEL_MASK | BUS_ACLK_DIV_MASK, 656df8f8a42SFinley Xiao BUS_PLL_SEL_GPLL << BUS_PLL_SEL_SHIFT | 657df8f8a42SFinley Xiao (src_clk_div - 1) << BUS_ACLK_DIV_SHIFT); 658df8f8a42SFinley Xiao break; 659df8f8a42SFinley Xiao case HCLK_BUS_PRE: 660cefa5186SFinley Xiao src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz); 661df8f8a42SFinley Xiao assert(src_clk_div - 1 < 31); 662df8f8a42SFinley Xiao rk_clrsetreg(&cru->clksel_con[24], 663df8f8a42SFinley Xiao BUS_PLL_SEL_MASK | BUS_HCLK_DIV_MASK, 664df8f8a42SFinley Xiao BUS_PLL_SEL_GPLL << BUS_PLL_SEL_SHIFT | 665df8f8a42SFinley Xiao (src_clk_div - 1) << BUS_HCLK_DIV_SHIFT); 666df8f8a42SFinley Xiao break; 667df8f8a42SFinley Xiao case PCLK_BUS_PRE: 668cefa5186SFinley Xiao src_clk_div = 669cefa5186SFinley Xiao DIV_ROUND_UP(px30_bus_get_clk(priv, ACLK_BUS_PRE), hz); 670df8f8a42SFinley Xiao assert(src_clk_div - 1 < 3); 671df8f8a42SFinley Xiao rk_clrsetreg(&cru->clksel_con[24], 672df8f8a42SFinley Xiao BUS_PCLK_DIV_MASK, 673df8f8a42SFinley Xiao (src_clk_div - 1) << BUS_PCLK_DIV_SHIFT); 674df8f8a42SFinley Xiao break; 675df8f8a42SFinley Xiao default: 676df8f8a42SFinley Xiao printf("do not support this bus freq\n"); 677df8f8a42SFinley Xiao return -EINVAL; 678df8f8a42SFinley Xiao } 679df8f8a42SFinley Xiao 680cefa5186SFinley Xiao return px30_bus_get_clk(priv, clk_id); 681df8f8a42SFinley Xiao } 682df8f8a42SFinley Xiao 683cefa5186SFinley Xiao static ulong px30_peri_get_clk(struct px30_clk_priv *priv, ulong clk_id) 684df8f8a42SFinley Xiao { 685cefa5186SFinley Xiao struct px30_cru *cru = priv->cru; 686df8f8a42SFinley Xiao u32 div, con, parent; 687df8f8a42SFinley Xiao 688df8f8a42SFinley Xiao switch (clk_id) { 689df8f8a42SFinley Xiao case ACLK_PERI_PRE: 690df8f8a42SFinley Xiao con = readl(&cru->clksel_con[14]); 691df8f8a42SFinley Xiao div = (con & PERI_ACLK_DIV_MASK) >> PERI_ACLK_DIV_SHIFT; 692cefa5186SFinley Xiao parent = priv->gpll_hz; 693df8f8a42SFinley Xiao break; 694df8f8a42SFinley Xiao case HCLK_PERI_PRE: 695df8f8a42SFinley Xiao con = readl(&cru->clksel_con[14]); 696df8f8a42SFinley Xiao div = (con & PERI_HCLK_DIV_MASK) >> PERI_HCLK_DIV_SHIFT; 697cefa5186SFinley Xiao parent = priv->gpll_hz; 698df8f8a42SFinley Xiao break; 699df8f8a42SFinley Xiao default: 700df8f8a42SFinley Xiao return -ENOENT; 701df8f8a42SFinley Xiao } 702df8f8a42SFinley Xiao 703df8f8a42SFinley Xiao return DIV_TO_RATE(parent, div); 704df8f8a42SFinley Xiao } 705df8f8a42SFinley Xiao 706cefa5186SFinley Xiao static ulong px30_peri_set_clk(struct px30_clk_priv *priv, ulong clk_id, 707cefa5186SFinley Xiao ulong hz) 708df8f8a42SFinley Xiao { 709cefa5186SFinley Xiao struct px30_cru *cru = priv->cru; 710df8f8a42SFinley Xiao int src_clk_div; 711df8f8a42SFinley Xiao 712cefa5186SFinley Xiao src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz); 713df8f8a42SFinley Xiao assert(src_clk_div - 1 < 31); 714df8f8a42SFinley Xiao 715df8f8a42SFinley Xiao /* 716df8f8a42SFinley Xiao * select gpll as pd_peri bus clock source and 717df8f8a42SFinley Xiao * set up dependent divisors for HCLK and ACLK clocks. 718df8f8a42SFinley Xiao */ 719df8f8a42SFinley Xiao switch (clk_id) { 720df8f8a42SFinley Xiao case ACLK_PERI_PRE: 721df8f8a42SFinley Xiao rk_clrsetreg(&cru->clksel_con[14], 722df8f8a42SFinley Xiao PERI_PLL_SEL_MASK | PERI_ACLK_DIV_MASK, 723df8f8a42SFinley Xiao PERI_PLL_GPLL << PERI_PLL_SEL_SHIFT | 724df8f8a42SFinley Xiao (src_clk_div - 1) << PERI_ACLK_DIV_SHIFT); 725df8f8a42SFinley Xiao break; 726df8f8a42SFinley Xiao case HCLK_PERI_PRE: 727df8f8a42SFinley Xiao rk_clrsetreg(&cru->clksel_con[14], 728df8f8a42SFinley Xiao PERI_PLL_SEL_MASK | PERI_HCLK_DIV_MASK, 729df8f8a42SFinley Xiao PERI_PLL_GPLL << PERI_PLL_SEL_SHIFT | 730df8f8a42SFinley Xiao (src_clk_div - 1) << PERI_HCLK_DIV_SHIFT); 731df8f8a42SFinley Xiao break; 732df8f8a42SFinley Xiao default: 733df8f8a42SFinley Xiao printf("do not support this peri freq\n"); 734df8f8a42SFinley Xiao return -EINVAL; 735df8f8a42SFinley Xiao } 736df8f8a42SFinley Xiao 737cefa5186SFinley Xiao return px30_peri_get_clk(priv, clk_id); 738cefa5186SFinley Xiao } 739cefa5186SFinley Xiao 740cefa5186SFinley Xiao static int px30_clk_get_gpll_rate(ulong *rate) 741cefa5186SFinley Xiao { 742cefa5186SFinley Xiao struct udevice *pmucru_dev; 743cefa5186SFinley Xiao struct px30_pmuclk_priv *priv; 744cefa5186SFinley Xiao struct px30_pmucru *pmucru; 745cefa5186SFinley Xiao int ret; 746cefa5186SFinley Xiao 747cefa5186SFinley Xiao ret = uclass_get_device_by_driver(UCLASS_CLK, 748cefa5186SFinley Xiao DM_GET_DRIVER(rockchip_px30_pmucru), 749cefa5186SFinley Xiao &pmucru_dev); 750cefa5186SFinley Xiao if (ret) { 751cefa5186SFinley Xiao printf("%s: could not find pmucru device\n", __func__); 752cefa5186SFinley Xiao return ret; 753cefa5186SFinley Xiao } 754cefa5186SFinley Xiao priv = dev_get_priv(pmucru_dev); 755cefa5186SFinley Xiao pmucru = priv->pmucru; 756cefa5186SFinley Xiao *rate = rkclk_pll_get_rate(&pmucru->pll, &pmucru->pmu_mode, GPLL); 757cefa5186SFinley Xiao 758cefa5186SFinley Xiao return 0; 759df8f8a42SFinley Xiao } 760df8f8a42SFinley Xiao 761*8b1aed51SFinley Xiao static ulong px30_clk_get_pll_rate(struct px30_clk_priv *priv, 762*8b1aed51SFinley Xiao enum px30_pll_id pll_id) 763*8b1aed51SFinley Xiao { 764*8b1aed51SFinley Xiao struct px30_cru *cru = priv->cru; 765*8b1aed51SFinley Xiao 766*8b1aed51SFinley Xiao return rkclk_pll_get_rate(&cru->pll[pll_id], &cru->mode, pll_id); 767*8b1aed51SFinley Xiao } 768*8b1aed51SFinley Xiao 769a60961a3SKever Yang static ulong px30_clk_get_rate(struct clk *clk) 770a60961a3SKever Yang { 771a60961a3SKever Yang struct px30_clk_priv *priv = dev_get_priv(clk->dev); 772a60961a3SKever Yang ulong rate = 0; 773cefa5186SFinley Xiao int ret; 774a60961a3SKever Yang 775cefa5186SFinley Xiao if (!priv->gpll_hz) { 776cefa5186SFinley Xiao ret = px30_clk_get_gpll_rate(&priv->gpll_hz); 777cefa5186SFinley Xiao if (ret) { 778cefa5186SFinley Xiao printf("%s failed to get gpll rate\n", __func__); 779cefa5186SFinley Xiao return ret; 780cefa5186SFinley Xiao } 781cefa5186SFinley Xiao debug("%s gpll=%lu\n", __func__, priv->gpll_hz); 782cefa5186SFinley Xiao } 783cefa5186SFinley Xiao 784cefa5186SFinley Xiao debug("%s %ld\n", __func__, clk->id); 785a60961a3SKever Yang switch (clk->id) { 786*8b1aed51SFinley Xiao case PLL_APLL: 787*8b1aed51SFinley Xiao rate = px30_clk_get_pll_rate(priv, APLL); 788*8b1aed51SFinley Xiao break; 789*8b1aed51SFinley Xiao case PLL_DPLL: 790*8b1aed51SFinley Xiao rate = px30_clk_get_pll_rate(priv, DPLL); 791*8b1aed51SFinley Xiao break; 792*8b1aed51SFinley Xiao case PLL_CPLL: 793*8b1aed51SFinley Xiao rate = px30_clk_get_pll_rate(priv, CPLL); 794*8b1aed51SFinley Xiao break; 795*8b1aed51SFinley Xiao case PLL_NPLL: 796*8b1aed51SFinley Xiao rate = px30_clk_get_pll_rate(priv, NPLL); 797*8b1aed51SFinley Xiao break; 798a60961a3SKever Yang case HCLK_SDMMC: 799a60961a3SKever Yang case HCLK_EMMC: 800a60961a3SKever Yang case SCLK_SDMMC: 801a60961a3SKever Yang case SCLK_EMMC: 80296f1b3d9SKever Yang case SCLK_EMMC_SAMPLE: 803cefa5186SFinley Xiao rate = px30_mmc_get_clk(priv, clk->id); 804a60961a3SKever Yang break; 805a60961a3SKever Yang case SCLK_I2C0: 806a60961a3SKever Yang case SCLK_I2C1: 807a60961a3SKever Yang case SCLK_I2C2: 808a60961a3SKever Yang case SCLK_I2C3: 809cefa5186SFinley Xiao rate = px30_i2c_get_clk(priv, clk->id); 810a60961a3SKever Yang break; 811a60961a3SKever Yang case SCLK_PWM0: 812fce7cb7bSFinley Xiao case SCLK_PWM1: 813cefa5186SFinley Xiao rate = px30_pwm_get_clk(priv, clk->id); 814a60961a3SKever Yang break; 815a60961a3SKever Yang case SCLK_SARADC: 816cefa5186SFinley Xiao rate = px30_saradc_get_clk(priv); 817a60961a3SKever Yang break; 818f67f522bSFinley Xiao case SCLK_SPI0: 819f67f522bSFinley Xiao case SCLK_SPI1: 820cefa5186SFinley Xiao rate = px30_spi_get_clk(priv, clk->id); 821f67f522bSFinley Xiao break; 82230f1f38dSFinley Xiao case ACLK_VOPB: 82330f1f38dSFinley Xiao case DCLK_VOPB: 824cefa5186SFinley Xiao rate = px30_vop_get_clk(priv, clk->id); 82530f1f38dSFinley Xiao break; 826df8f8a42SFinley Xiao case ACLK_BUS_PRE: 827df8f8a42SFinley Xiao case HCLK_BUS_PRE: 828df8f8a42SFinley Xiao case PCLK_BUS_PRE: 829cefa5186SFinley Xiao rate = px30_bus_get_clk(priv, clk->id); 830df8f8a42SFinley Xiao break; 831df8f8a42SFinley Xiao case ACLK_PERI_PRE: 832df8f8a42SFinley Xiao case HCLK_PERI_PRE: 833cefa5186SFinley Xiao rate = px30_peri_get_clk(priv, clk->id); 834df8f8a42SFinley Xiao break; 835a60961a3SKever Yang default: 836a60961a3SKever Yang return -ENOENT; 837a60961a3SKever Yang } 838a60961a3SKever Yang 839a60961a3SKever Yang return rate; 840a60961a3SKever Yang } 841a60961a3SKever Yang 842a60961a3SKever Yang static ulong px30_clk_set_rate(struct clk *clk, ulong rate) 843a60961a3SKever Yang { 844a60961a3SKever Yang struct px30_clk_priv *priv = dev_get_priv(clk->dev); 845a60961a3SKever Yang ulong ret = 0; 846a60961a3SKever Yang 847cefa5186SFinley Xiao if (!priv->gpll_hz) { 848cefa5186SFinley Xiao ret = px30_clk_get_gpll_rate(&priv->gpll_hz); 849cefa5186SFinley Xiao if (ret) { 850cefa5186SFinley Xiao printf("%s failed to get gpll rate\n", __func__); 851cefa5186SFinley Xiao return ret; 852cefa5186SFinley Xiao } 853cefa5186SFinley Xiao debug("%s gpll=%lu\n", __func__, priv->gpll_hz); 854cefa5186SFinley Xiao } 855cefa5186SFinley Xiao 856c4867301SKever Yang debug("%s %ld %ld\n", __func__, clk->id, rate); 857a60961a3SKever Yang switch (clk->id) { 858a60961a3SKever Yang case 0 ... 15: 859a60961a3SKever Yang return 0; 860a60961a3SKever Yang case HCLK_SDMMC: 861a60961a3SKever Yang case HCLK_EMMC: 862a60961a3SKever Yang case SCLK_SDMMC: 863a60961a3SKever Yang case SCLK_EMMC: 864cefa5186SFinley Xiao ret = px30_mmc_set_clk(priv, clk->id, rate); 865a60961a3SKever Yang break; 866a60961a3SKever Yang case SCLK_I2C0: 867a60961a3SKever Yang case SCLK_I2C1: 868a60961a3SKever Yang case SCLK_I2C2: 869a60961a3SKever Yang case SCLK_I2C3: 870cefa5186SFinley Xiao ret = px30_i2c_set_clk(priv, clk->id, rate); 871a60961a3SKever Yang break; 872a60961a3SKever Yang case SCLK_PWM0: 873f67f522bSFinley Xiao case SCLK_PWM1: 874cefa5186SFinley Xiao ret = px30_pwm_set_clk(priv, clk->id, rate); 875a60961a3SKever Yang break; 876a60961a3SKever Yang case SCLK_SARADC: 877cefa5186SFinley Xiao ret = px30_saradc_set_clk(priv, rate); 878a60961a3SKever Yang break; 879f67f522bSFinley Xiao case SCLK_SPI0: 880f67f522bSFinley Xiao case SCLK_SPI1: 881cefa5186SFinley Xiao ret = px30_spi_set_clk(priv, clk->id, rate); 882f67f522bSFinley Xiao break; 88330f1f38dSFinley Xiao case ACLK_VOPB: 88430f1f38dSFinley Xiao case DCLK_VOPB: 885cefa5186SFinley Xiao ret = px30_vop_set_clk(priv, clk->id, rate); 88630f1f38dSFinley Xiao break; 887df8f8a42SFinley Xiao case ACLK_BUS_PRE: 888df8f8a42SFinley Xiao case HCLK_BUS_PRE: 889df8f8a42SFinley Xiao case PCLK_BUS_PRE: 890cefa5186SFinley Xiao ret = px30_bus_set_clk(priv, clk->id, rate); 891df8f8a42SFinley Xiao break; 892df8f8a42SFinley Xiao case ACLK_PERI_PRE: 893df8f8a42SFinley Xiao case HCLK_PERI_PRE: 894cefa5186SFinley Xiao ret = px30_peri_set_clk(priv, clk->id, rate); 895df8f8a42SFinley Xiao break; 896a60961a3SKever Yang default: 897a60961a3SKever Yang return -ENOENT; 898a60961a3SKever Yang } 899a60961a3SKever Yang 900a60961a3SKever Yang return ret; 901a60961a3SKever Yang } 902a60961a3SKever Yang 903a60961a3SKever Yang #define ROCKCHIP_MMC_DELAY_SEL BIT(10) 904a60961a3SKever Yang #define ROCKCHIP_MMC_DEGREE_MASK 0x3 905a60961a3SKever Yang #define ROCKCHIP_MMC_DELAYNUM_OFFSET 2 906a60961a3SKever Yang #define ROCKCHIP_MMC_DELAYNUM_MASK (0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET) 907a60961a3SKever Yang 908a60961a3SKever Yang #define PSECS_PER_SEC 1000000000000LL 909a60961a3SKever Yang /* 910a60961a3SKever Yang * Each fine delay is between 44ps-77ps. Assume each fine delay is 60ps to 911a60961a3SKever Yang * simplify calculations. So 45degs could be anywhere between 33deg and 57.8deg. 912a60961a3SKever Yang */ 913a60961a3SKever Yang #define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60 914a60961a3SKever Yang 915a60961a3SKever Yang int rockchip_mmc_get_phase(struct clk *clk) 916a60961a3SKever Yang { 917a60961a3SKever Yang struct px30_clk_priv *priv = dev_get_priv(clk->dev); 918a60961a3SKever Yang struct px30_cru *cru = priv->cru; 919a60961a3SKever Yang u32 raw_value, delay_num; 920a60961a3SKever Yang u16 degrees = 0; 921a60961a3SKever Yang ulong rate; 922a60961a3SKever Yang 923a60961a3SKever Yang rate = px30_clk_get_rate(clk); 924a60961a3SKever Yang 925a60961a3SKever Yang if (rate < 0) 926a60961a3SKever Yang return rate; 927a60961a3SKever Yang 928a60961a3SKever Yang if (clk->id == SCLK_EMMC_SAMPLE) 929a60961a3SKever Yang raw_value = readl(&cru->emmc_con[1]); 930a60961a3SKever Yang else 931a60961a3SKever Yang raw_value = readl(&cru->sdmmc_con[1]); 932a60961a3SKever Yang 93396f1b3d9SKever Yang raw_value >>= 1; 934a60961a3SKever Yang degrees = (raw_value & ROCKCHIP_MMC_DEGREE_MASK) * 90; 935a60961a3SKever Yang 936a60961a3SKever Yang if (raw_value & ROCKCHIP_MMC_DELAY_SEL) { 937a60961a3SKever Yang /* degrees/delaynum * 10000 */ 938a60961a3SKever Yang unsigned long factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) * 939a60961a3SKever Yang 36 * (rate / 1000000); 940a60961a3SKever Yang 941a60961a3SKever Yang delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK); 942a60961a3SKever Yang delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET; 943a60961a3SKever Yang degrees += DIV_ROUND_CLOSEST(delay_num * factor, 10000); 944a60961a3SKever Yang } 945a60961a3SKever Yang 946a60961a3SKever Yang return degrees % 360; 947a60961a3SKever Yang } 948a60961a3SKever Yang 949a60961a3SKever Yang int rockchip_mmc_set_phase(struct clk *clk, u32 degrees) 950a60961a3SKever Yang { 951a60961a3SKever Yang struct px30_clk_priv *priv = dev_get_priv(clk->dev); 952a60961a3SKever Yang struct px30_cru *cru = priv->cru; 953a60961a3SKever Yang u8 nineties, remainder, delay_num; 954a60961a3SKever Yang u32 raw_value, delay; 955a60961a3SKever Yang ulong rate; 956a60961a3SKever Yang 957a60961a3SKever Yang rate = px30_clk_get_rate(clk); 958a60961a3SKever Yang 959a60961a3SKever Yang if (rate < 0) 960a60961a3SKever Yang return rate; 961a60961a3SKever Yang 962a60961a3SKever Yang nineties = degrees / 90; 963a60961a3SKever Yang remainder = (degrees % 90); 964a60961a3SKever Yang 965a60961a3SKever Yang /* 966a60961a3SKever Yang * Convert to delay; do a little extra work to make sure we 967a60961a3SKever Yang * don't overflow 32-bit / 64-bit numbers. 968a60961a3SKever Yang */ 969a60961a3SKever Yang delay = 10000000; /* PSECS_PER_SEC / 10000 / 10 */ 970a60961a3SKever Yang delay *= remainder; 971a60961a3SKever Yang delay = DIV_ROUND_CLOSEST(delay, (rate / 1000) * 36 * 972a60961a3SKever Yang (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10)); 973a60961a3SKever Yang 974a60961a3SKever Yang delay_num = (u8)min_t(u32, delay, 255); 975a60961a3SKever Yang 976a60961a3SKever Yang raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0; 977a60961a3SKever Yang raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET; 978a60961a3SKever Yang raw_value |= nineties; 979a60961a3SKever Yang 98096f1b3d9SKever Yang raw_value <<= 1; 981a60961a3SKever Yang if (clk->id == SCLK_EMMC_SAMPLE) 982a60961a3SKever Yang writel(raw_value | 0xffff0000, &cru->emmc_con[1]); 983a60961a3SKever Yang else 984a60961a3SKever Yang writel(raw_value | 0xffff0000, &cru->sdmmc_con[1]); 985a60961a3SKever Yang 986a60961a3SKever Yang debug("mmc set_phase(%d) delay_nums=%u reg=%#x actual_degrees=%d\n", 987a60961a3SKever Yang degrees, delay_num, raw_value, rockchip_mmc_get_phase(clk)); 988a60961a3SKever Yang 989a60961a3SKever Yang return 0; 990a60961a3SKever Yang } 991a60961a3SKever Yang 992a60961a3SKever Yang static int px30_clk_get_phase(struct clk *clk) 993a60961a3SKever Yang { 994a60961a3SKever Yang int ret; 995cefa5186SFinley Xiao debug("%s %ld\n", __func__, clk->id); 996a60961a3SKever Yang switch (clk->id) { 997a60961a3SKever Yang case SCLK_EMMC_SAMPLE: 998a60961a3SKever Yang case SCLK_SDMMC_SAMPLE: 999a60961a3SKever Yang ret = rockchip_mmc_get_phase(clk); 1000a60961a3SKever Yang break; 1001a60961a3SKever Yang default: 1002a60961a3SKever Yang return -ENOENT; 1003a60961a3SKever Yang } 1004a60961a3SKever Yang 1005a60961a3SKever Yang return ret; 1006a60961a3SKever Yang } 1007a60961a3SKever Yang 1008a60961a3SKever Yang static int px30_clk_set_phase(struct clk *clk, int degrees) 1009a60961a3SKever Yang { 1010a60961a3SKever Yang int ret; 1011a60961a3SKever Yang 1012cefa5186SFinley Xiao debug("%s %ld\n", __func__, clk->id); 1013a60961a3SKever Yang switch (clk->id) { 1014a60961a3SKever Yang case SCLK_EMMC_SAMPLE: 1015a60961a3SKever Yang case SCLK_SDMMC_SAMPLE: 1016a60961a3SKever Yang ret = rockchip_mmc_set_phase(clk, degrees); 1017a60961a3SKever Yang break; 1018a60961a3SKever Yang default: 1019a60961a3SKever Yang return -ENOENT; 1020a60961a3SKever Yang } 1021a60961a3SKever Yang 1022a60961a3SKever Yang return ret; 1023a60961a3SKever Yang } 1024a60961a3SKever Yang 1025a60961a3SKever Yang static struct clk_ops px30_clk_ops = { 1026a60961a3SKever Yang .get_rate = px30_clk_get_rate, 1027a60961a3SKever Yang .set_rate = px30_clk_set_rate, 1028a60961a3SKever Yang .get_phase = px30_clk_get_phase, 1029a60961a3SKever Yang .set_phase = px30_clk_set_phase, 1030a60961a3SKever Yang }; 1031a60961a3SKever Yang 1032a60961a3SKever Yang static int px30_clk_probe(struct udevice *dev) 1033a60961a3SKever Yang { 1034a60961a3SKever Yang struct px30_clk_priv *priv = dev_get_priv(dev); 1035cefa5186SFinley Xiao struct px30_cru *cru = priv->cru; 1036cefa5186SFinley Xiao u32 aclk_div; 1037a60961a3SKever Yang 1038cefa5186SFinley Xiao /* init pll */ 1039cefa5186SFinley Xiao rkclk_set_pll(&cru->pll[APLL], &cru->mode, APLL, APLL_HZ); 1040cefa5186SFinley Xiao /* 1041cefa5186SFinley Xiao * select apll as cpu/core clock pll source and 1042cefa5186SFinley Xiao * set up dependent divisors for PERI and ACLK clocks. 1043cefa5186SFinley Xiao * core hz : apll = 1:1 1044cefa5186SFinley Xiao */ 1045cefa5186SFinley Xiao aclk_div = APLL_HZ / CORE_ACLK_HZ - 1; 1046cefa5186SFinley Xiao rk_clrsetreg(&cru->clksel_con[0], 1047cefa5186SFinley Xiao CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK | 1048cefa5186SFinley Xiao CORE_ACLK_DIV_MASK, 1049cefa5186SFinley Xiao aclk_div << CORE_ACLK_DIV_SHIFT | 1050cefa5186SFinley Xiao CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT | 1051cefa5186SFinley Xiao 0 << CORE_DIV_CON_SHIFT); 1052a60961a3SKever Yang 1053a60961a3SKever Yang return 0; 1054a60961a3SKever Yang } 1055a60961a3SKever Yang 1056a60961a3SKever Yang static int px30_clk_ofdata_to_platdata(struct udevice *dev) 1057a60961a3SKever Yang { 1058a60961a3SKever Yang struct px30_clk_priv *priv = dev_get_priv(dev); 1059a60961a3SKever Yang 10604203970bSKever Yang priv->cru = dev_read_addr_ptr(dev); 1061a60961a3SKever Yang 1062a60961a3SKever Yang return 0; 1063a60961a3SKever Yang } 1064a60961a3SKever Yang 1065a60961a3SKever Yang static int px30_clk_bind(struct udevice *dev) 1066a60961a3SKever Yang { 1067a60961a3SKever Yang int ret; 1068a60961a3SKever Yang struct udevice *sys_child, *sf_child; 1069a60961a3SKever Yang struct sysreset_reg *priv; 1070a60961a3SKever Yang struct softreset_reg *sf_priv; 1071a60961a3SKever Yang 1072a60961a3SKever Yang /* The reset driver does not have a device node, so bind it here */ 1073a60961a3SKever Yang ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset", 1074a60961a3SKever Yang &sys_child); 1075a60961a3SKever Yang if (ret) { 1076a60961a3SKever Yang debug("Warning: No sysreset driver: ret=%d\n", ret); 1077a60961a3SKever Yang } else { 1078a60961a3SKever Yang priv = malloc(sizeof(struct sysreset_reg)); 1079a60961a3SKever Yang priv->glb_srst_fst_value = offsetof(struct px30_cru, 1080a60961a3SKever Yang glb_srst_fst); 1081a60961a3SKever Yang priv->glb_srst_snd_value = offsetof(struct px30_cru, 1082a60961a3SKever Yang glb_srst_snd); 1083a60961a3SKever Yang sys_child->priv = priv; 1084a60961a3SKever Yang } 1085a60961a3SKever Yang 1086a60961a3SKever Yang ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset", 1087a60961a3SKever Yang dev_ofnode(dev), &sf_child); 1088a60961a3SKever Yang if (ret) { 1089a60961a3SKever Yang debug("Warning: No rockchip reset driver: ret=%d\n", ret); 1090a60961a3SKever Yang } else { 1091a60961a3SKever Yang sf_priv = malloc(sizeof(struct softreset_reg)); 1092a60961a3SKever Yang sf_priv->sf_reset_offset = offsetof(struct px30_cru, 1093a60961a3SKever Yang softrst_con[0]); 1094a60961a3SKever Yang sf_priv->sf_reset_num = 12; 1095a60961a3SKever Yang sf_child->priv = sf_priv; 1096a60961a3SKever Yang } 1097a60961a3SKever Yang 1098a60961a3SKever Yang return 0; 1099a60961a3SKever Yang } 1100a60961a3SKever Yang 1101a60961a3SKever Yang static const struct udevice_id px30_clk_ids[] = { 1102a60961a3SKever Yang { .compatible = "rockchip,px30-cru" }, 1103a60961a3SKever Yang { } 1104a60961a3SKever Yang }; 1105a60961a3SKever Yang 1106a60961a3SKever Yang U_BOOT_DRIVER(rockchip_px30_cru) = { 1107a60961a3SKever Yang .name = "rockchip_px30_cru", 1108a60961a3SKever Yang .id = UCLASS_CLK, 1109a60961a3SKever Yang .of_match = px30_clk_ids, 1110a60961a3SKever Yang .priv_auto_alloc_size = sizeof(struct px30_clk_priv), 1111a60961a3SKever Yang .ofdata_to_platdata = px30_clk_ofdata_to_platdata, 1112a60961a3SKever Yang .ops = &px30_clk_ops, 1113a60961a3SKever Yang .bind = px30_clk_bind, 1114a60961a3SKever Yang .probe = px30_clk_probe, 1115a60961a3SKever Yang }; 1116cefa5186SFinley Xiao 1117cefa5186SFinley Xiao static ulong px30_pclk_pmu_get_pmuclk(struct px30_pmuclk_priv *priv) 1118cefa5186SFinley Xiao { 1119cefa5186SFinley Xiao struct px30_pmucru *pmucru = priv->pmucru; 1120cefa5186SFinley Xiao u32 div, con; 1121cefa5186SFinley Xiao 1122cefa5186SFinley Xiao con = readl(&pmucru->pmu_clksel_con[0]); 1123cefa5186SFinley Xiao div = (con & CLK_PMU_PCLK_DIV_MASK) >> CLK_PMU_PCLK_DIV_SHIFT; 1124cefa5186SFinley Xiao 1125cefa5186SFinley Xiao return DIV_TO_RATE(priv->gpll_hz, div); 1126cefa5186SFinley Xiao } 1127cefa5186SFinley Xiao 1128cefa5186SFinley Xiao static ulong px30_pclk_pmu_set_pmuclk(struct px30_pmuclk_priv *priv, ulong hz) 1129cefa5186SFinley Xiao { 1130cefa5186SFinley Xiao struct px30_pmucru *pmucru = priv->pmucru; 1131cefa5186SFinley Xiao int src_clk_div; 1132cefa5186SFinley Xiao 1133cefa5186SFinley Xiao src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz); 1134cefa5186SFinley Xiao assert(src_clk_div - 1 < 31); 1135cefa5186SFinley Xiao 1136cefa5186SFinley Xiao rk_clrsetreg(&pmucru->pmu_clksel_con[0], 1137cefa5186SFinley Xiao CLK_PMU_PCLK_DIV_MASK, 1138cefa5186SFinley Xiao (src_clk_div - 1) << CLK_PMU_PCLK_DIV_SHIFT); 1139cefa5186SFinley Xiao 1140cefa5186SFinley Xiao return px30_pclk_pmu_get_pmuclk(priv); 1141cefa5186SFinley Xiao } 1142cefa5186SFinley Xiao 1143cefa5186SFinley Xiao static ulong px30_gpll_get_pmuclk(struct px30_pmuclk_priv *priv) 1144cefa5186SFinley Xiao { 1145cefa5186SFinley Xiao struct px30_pmucru *pmucru = priv->pmucru; 1146cefa5186SFinley Xiao 1147cefa5186SFinley Xiao return rkclk_pll_get_rate(&pmucru->pll, &pmucru->pmu_mode, GPLL); 1148cefa5186SFinley Xiao } 1149cefa5186SFinley Xiao 1150cefa5186SFinley Xiao static ulong px30_gpll_set_pmuclk(struct px30_pmuclk_priv *priv, ulong hz) 1151cefa5186SFinley Xiao { 1152cefa5186SFinley Xiao struct udevice *cru_dev; 1153cefa5186SFinley Xiao struct px30_clk_priv *cru_priv; 1154cefa5186SFinley Xiao struct px30_pmucru *pmucru = priv->pmucru; 1155cefa5186SFinley Xiao u32 div; 1156cefa5186SFinley Xiao ulong emmc_rate, sdmmc_rate, nandc_rate; 1157cefa5186SFinley Xiao int ret; 1158cefa5186SFinley Xiao 1159cefa5186SFinley Xiao priv->gpll_hz = px30_gpll_get_pmuclk(priv); 1160cefa5186SFinley Xiao 1161cefa5186SFinley Xiao ret = uclass_get_device_by_name(UCLASS_CLK, 1162cefa5186SFinley Xiao "clock-controller@ff2b0000", 1163cefa5186SFinley Xiao &cru_dev); 1164cefa5186SFinley Xiao if (ret) { 1165cefa5186SFinley Xiao printf("%s failed to get cru device\n", __func__); 1166cefa5186SFinley Xiao return ret; 1167cefa5186SFinley Xiao } 1168cefa5186SFinley Xiao cru_priv = dev_get_priv(cru_dev); 1169cefa5186SFinley Xiao cru_priv->gpll_hz = priv->gpll_hz; 1170cefa5186SFinley Xiao 1171cefa5186SFinley Xiao div = DIV_ROUND_UP(hz, priv->gpll_hz); 1172cefa5186SFinley Xiao 1173cefa5186SFinley Xiao /* 1174cefa5186SFinley Xiao * avoid bus and peri clock rate too large, reduce rate first. 1175cefa5186SFinley Xiao * they will be assigned by clk_set_defaults. 1176cefa5186SFinley Xiao */ 1177cefa5186SFinley Xiao px30_bus_set_clk(cru_priv, ACLK_BUS_PRE, 1178cefa5186SFinley Xiao px30_bus_get_clk(cru_priv, ACLK_BUS_PRE) / div); 1179cefa5186SFinley Xiao px30_bus_set_clk(cru_priv, HCLK_BUS_PRE, 1180cefa5186SFinley Xiao px30_bus_get_clk(cru_priv, HCLK_BUS_PRE) / div); 1181cefa5186SFinley Xiao px30_bus_set_clk(cru_priv, PCLK_BUS_PRE, 1182cefa5186SFinley Xiao px30_bus_get_clk(cru_priv, PCLK_BUS_PRE) / div); 1183cefa5186SFinley Xiao px30_peri_set_clk(cru_priv, ACLK_PERI_PRE, 1184cefa5186SFinley Xiao px30_bus_get_clk(cru_priv, ACLK_PERI_PRE) / div); 1185cefa5186SFinley Xiao px30_peri_set_clk(cru_priv, HCLK_PERI_PRE, 1186cefa5186SFinley Xiao px30_bus_get_clk(cru_priv, HCLK_PERI_PRE) / div); 1187cefa5186SFinley Xiao px30_pclk_pmu_set_pmuclk(priv, px30_pclk_pmu_get_pmuclk(priv) / div); 1188cefa5186SFinley Xiao 1189cefa5186SFinley Xiao /* 1190cefa5186SFinley Xiao * save emmc, sdmmc and nandc clock rate, 1191cefa5186SFinley Xiao * nandc clock rate should less than or equal to 150Mhz. 1192cefa5186SFinley Xiao */ 1193cefa5186SFinley Xiao emmc_rate = px30_mmc_get_clk(cru_priv, SCLK_EMMC); 1194cefa5186SFinley Xiao sdmmc_rate = px30_mmc_get_clk(cru_priv, SCLK_SDMMC); 1195cefa5186SFinley Xiao nandc_rate = px30_nandc_get_clk(cru_priv); 1196cefa5186SFinley Xiao debug("%s emmc=%lu, sdmmc=%lu, nandc=%lu\n", __func__, emmc_rate, 1197cefa5186SFinley Xiao sdmmc_rate, nandc_rate); 1198cefa5186SFinley Xiao 1199cefa5186SFinley Xiao rkclk_set_pll(&pmucru->pll, &pmucru->pmu_mode, GPLL, hz); 1200cefa5186SFinley Xiao priv->gpll_hz = px30_gpll_get_pmuclk(priv); 1201cefa5186SFinley Xiao cru_priv->gpll_hz = priv->gpll_hz; 1202cefa5186SFinley Xiao 1203cefa5186SFinley Xiao /* restore emmc, sdmmc and nandc clock rate */ 1204cefa5186SFinley Xiao px30_mmc_set_clk(cru_priv, SCLK_EMMC, emmc_rate); 1205cefa5186SFinley Xiao px30_mmc_set_clk(cru_priv, SCLK_SDMMC, sdmmc_rate); 1206cefa5186SFinley Xiao px30_nandc_set_clk(cru_priv, nandc_rate); 1207cefa5186SFinley Xiao 1208cefa5186SFinley Xiao return priv->gpll_hz; 1209cefa5186SFinley Xiao } 1210cefa5186SFinley Xiao 1211cefa5186SFinley Xiao static ulong px30_pmuclk_get_rate(struct clk *clk) 1212cefa5186SFinley Xiao { 1213cefa5186SFinley Xiao struct px30_pmuclk_priv *priv = dev_get_priv(clk->dev); 1214cefa5186SFinley Xiao ulong rate = 0; 1215cefa5186SFinley Xiao 1216cefa5186SFinley Xiao debug("%s %ld\n", __func__, clk->id); 1217cefa5186SFinley Xiao switch (clk->id) { 1218cefa5186SFinley Xiao case PLL_GPLL: 1219cefa5186SFinley Xiao rate = px30_gpll_get_pmuclk(priv); 1220cefa5186SFinley Xiao break; 1221cefa5186SFinley Xiao case PCLK_PMU_PRE: 1222cefa5186SFinley Xiao rate = px30_pclk_pmu_get_pmuclk(priv); 1223cefa5186SFinley Xiao break; 1224cefa5186SFinley Xiao default: 1225cefa5186SFinley Xiao return -ENOENT; 1226cefa5186SFinley Xiao } 1227cefa5186SFinley Xiao 1228cefa5186SFinley Xiao return rate; 1229cefa5186SFinley Xiao } 1230cefa5186SFinley Xiao 1231cefa5186SFinley Xiao static ulong px30_pmuclk_set_rate(struct clk *clk, ulong rate) 1232cefa5186SFinley Xiao { 1233cefa5186SFinley Xiao struct px30_pmuclk_priv *priv = dev_get_priv(clk->dev); 1234cefa5186SFinley Xiao ulong ret = 0; 1235cefa5186SFinley Xiao 1236cefa5186SFinley Xiao debug("%s %ld %ld\n", __func__, clk->id, rate); 1237cefa5186SFinley Xiao switch (clk->id) { 1238cefa5186SFinley Xiao case PLL_GPLL: 1239cefa5186SFinley Xiao ret = px30_gpll_set_pmuclk(priv, rate); 1240cefa5186SFinley Xiao break; 1241cefa5186SFinley Xiao case PCLK_PMU_PRE: 1242cefa5186SFinley Xiao ret = px30_pclk_pmu_set_pmuclk(priv, rate); 1243cefa5186SFinley Xiao break; 1244cefa5186SFinley Xiao default: 1245cefa5186SFinley Xiao return -ENOENT; 1246cefa5186SFinley Xiao } 1247cefa5186SFinley Xiao 1248cefa5186SFinley Xiao return ret; 1249cefa5186SFinley Xiao } 1250cefa5186SFinley Xiao 1251cefa5186SFinley Xiao static struct clk_ops px30_pmuclk_ops = { 1252cefa5186SFinley Xiao .get_rate = px30_pmuclk_get_rate, 1253cefa5186SFinley Xiao .set_rate = px30_pmuclk_set_rate, 1254cefa5186SFinley Xiao }; 1255cefa5186SFinley Xiao 1256cefa5186SFinley Xiao static int px30_pmuclk_probe(struct udevice *dev) 1257cefa5186SFinley Xiao { 1258cefa5186SFinley Xiao return 0; 1259cefa5186SFinley Xiao } 1260cefa5186SFinley Xiao 1261cefa5186SFinley Xiao static int px30_pmuclk_ofdata_to_platdata(struct udevice *dev) 1262cefa5186SFinley Xiao { 1263cefa5186SFinley Xiao struct px30_pmuclk_priv *priv = dev_get_priv(dev); 1264cefa5186SFinley Xiao 1265cefa5186SFinley Xiao priv->pmucru = dev_read_addr_ptr(dev); 1266cefa5186SFinley Xiao 1267cefa5186SFinley Xiao return 0; 1268cefa5186SFinley Xiao } 1269cefa5186SFinley Xiao 1270cefa5186SFinley Xiao static const struct udevice_id px30_pmuclk_ids[] = { 1271cefa5186SFinley Xiao { .compatible = "rockchip,px30-pmucru" }, 1272cefa5186SFinley Xiao { } 1273cefa5186SFinley Xiao }; 1274cefa5186SFinley Xiao 1275cefa5186SFinley Xiao U_BOOT_DRIVER(rockchip_px30_pmucru) = { 1276cefa5186SFinley Xiao .name = "rockchip_px30_pmucru", 1277cefa5186SFinley Xiao .id = UCLASS_CLK, 1278cefa5186SFinley Xiao .of_match = px30_pmuclk_ids, 1279cefa5186SFinley Xiao .priv_auto_alloc_size = sizeof(struct px30_pmuclk_priv), 1280cefa5186SFinley Xiao .ofdata_to_platdata = px30_pmuclk_ofdata_to_platdata, 1281cefa5186SFinley Xiao .ops = &px30_pmuclk_ops, 1282cefa5186SFinley Xiao .probe = px30_pmuclk_probe, 1283cefa5186SFinley Xiao }; 1284