1c6f7c1a3SJoseph Chen // SPDX-License-Identifier: GPL-2.0 2c6f7c1a3SJoseph Chen /* 3c6f7c1a3SJoseph Chen * Copyright (c) 2022 Fuzhou Rockchip Electronics Co., Ltd 4c6f7c1a3SJoseph Chen * Author: Joseph Chen <chenjh@rock-chips.com> 5c6f7c1a3SJoseph Chen */ 6c6f7c1a3SJoseph Chen 7c6f7c1a3SJoseph Chen #include <common.h> 8c6f7c1a3SJoseph Chen #include <clk-uclass.h> 9c6f7c1a3SJoseph Chen #include <dm.h> 10c6f7c1a3SJoseph Chen #include <syscon.h> 11c6f7c1a3SJoseph Chen #include <asm/arch/clock.h> 12c6f7c1a3SJoseph Chen #include <asm/arch/cru_rk3528.h> 13c6f7c1a3SJoseph Chen #include <asm/arch/grf_rk3528.h> 14c6f7c1a3SJoseph Chen #include <asm/arch/hardware.h> 15c6f7c1a3SJoseph Chen #include <asm/io.h> 16c6f7c1a3SJoseph Chen #include <dm/lists.h> 17c6f7c1a3SJoseph Chen #include <dt-bindings/clock/rk3528-cru.h> 18c6f7c1a3SJoseph Chen 19c6f7c1a3SJoseph Chen DECLARE_GLOBAL_DATA_PTR; 20c6f7c1a3SJoseph Chen 21c6f7c1a3SJoseph Chen #define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1)) 22c6f7c1a3SJoseph Chen 23c6f7c1a3SJoseph Chen /* 24c6f7c1a3SJoseph Chen * PLL attention. 25c6f7c1a3SJoseph Chen * 26c6f7c1a3SJoseph Chen * [FRAC PLL]: GPLL, PPLL, DPLL 27c6f7c1a3SJoseph Chen * - frac mode: refdiv can be 1 or 2 only 28c6f7c1a3SJoseph Chen * - int mode: refdiv has no special limit 29c6f7c1a3SJoseph Chen * - VCO range: [950, 3800] MHZ 30c6f7c1a3SJoseph Chen * 31c6f7c1a3SJoseph Chen * [INT PLL]: CPLL, APLL 32c6f7c1a3SJoseph Chen * - int mode: refdiv can be 1 or 2 only 33c6f7c1a3SJoseph Chen * - VCO range: [475, 1900] MHZ 34c6f7c1a3SJoseph Chen * 35c6f7c1a3SJoseph Chen * [PPLL]: normal mode only. 36c6f7c1a3SJoseph Chen * 37c6f7c1a3SJoseph Chen */ 38c6f7c1a3SJoseph Chen static struct rockchip_pll_rate_table rk3528_pll_rates[] = { 39c6f7c1a3SJoseph Chen /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */ 40c6f7c1a3SJoseph Chen RK3036_PLL_RATE(1896000000, 1, 79, 1, 1, 1, 0), 41c6f7c1a3SJoseph Chen RK3036_PLL_RATE(1800000000, 1, 75, 1, 1, 1, 0), 42c6f7c1a3SJoseph Chen RK3036_PLL_RATE(1704000000, 1, 71, 1, 1, 1, 0), 43c6f7c1a3SJoseph Chen RK3036_PLL_RATE(1608000000, 1, 67, 1, 1, 1, 0), 44c6f7c1a3SJoseph Chen RK3036_PLL_RATE(1512000000, 1, 63, 1, 1, 1, 0), 45c6f7c1a3SJoseph Chen RK3036_PLL_RATE(1416000000, 1, 59, 1, 1, 1, 0), 46c6f7c1a3SJoseph Chen RK3036_PLL_RATE(1296000000, 1, 54, 1, 1, 1, 0), 47c6f7c1a3SJoseph Chen RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0), 48c6f7c1a3SJoseph Chen RK3036_PLL_RATE(1188000000, 1, 99, 2, 1, 1, 0), /* GPLL */ 49c6f7c1a3SJoseph Chen RK3036_PLL_RATE(1092000000, 2, 91, 1, 1, 1, 0), 50c6f7c1a3SJoseph Chen RK3036_PLL_RATE(1008000000, 1, 42, 1, 1, 1, 0), 51c6f7c1a3SJoseph Chen RK3036_PLL_RATE(1000000000, 1, 125, 3, 1, 1, 0), /* PPLL */ 52c6f7c1a3SJoseph Chen RK3036_PLL_RATE(996000000, 2, 83, 1, 1, 1, 0), /* CPLL */ 53c6f7c1a3SJoseph Chen RK3036_PLL_RATE(960000000, 1, 40, 1, 1, 1, 0), 54c6f7c1a3SJoseph Chen RK3036_PLL_RATE(912000000, 1, 76, 2, 1, 1, 0), 55c6f7c1a3SJoseph Chen RK3036_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0), 56c6f7c1a3SJoseph Chen RK3036_PLL_RATE(600000000, 1, 50, 2, 1, 1, 0), 57c6f7c1a3SJoseph Chen RK3036_PLL_RATE(594000000, 2, 99, 2, 1, 1, 0), 58c6f7c1a3SJoseph Chen RK3036_PLL_RATE(408000000, 1, 68, 2, 2, 1, 0), 59c6f7c1a3SJoseph Chen RK3036_PLL_RATE(312000000, 1, 78, 6, 1, 1, 0), 60c6f7c1a3SJoseph Chen RK3036_PLL_RATE(216000000, 1, 72, 4, 2, 1, 0), 61c6f7c1a3SJoseph Chen RK3036_PLL_RATE(96000000, 1, 24, 3, 2, 1, 0), 62c6f7c1a3SJoseph Chen { /* sentinel */ }, 63c6f7c1a3SJoseph Chen }; 64c6f7c1a3SJoseph Chen 65c6f7c1a3SJoseph Chen static struct rockchip_pll_clock rk3528_pll_clks[] = { 66c6f7c1a3SJoseph Chen [APLL] = PLL(pll_rk3328, PLL_APLL, RK3528_PLL_CON(0), 67c6f7c1a3SJoseph Chen RK3528_MODE_CON, 0, 10, 0, rk3528_pll_rates), 68c6f7c1a3SJoseph Chen 69c6f7c1a3SJoseph Chen [CPLL] = PLL(pll_rk3328, PLL_CPLL, RK3528_PLL_CON(8), 70c6f7c1a3SJoseph Chen RK3528_MODE_CON, 2, 10, 0, rk3528_pll_rates), 71c6f7c1a3SJoseph Chen 72c6f7c1a3SJoseph Chen [GPLL] = PLL(pll_rk3328, PLL_GPLL, RK3528_PLL_CON(24), 73c6f7c1a3SJoseph Chen RK3528_MODE_CON, 4, 10, 0, rk3528_pll_rates), 74c6f7c1a3SJoseph Chen 75c6f7c1a3SJoseph Chen [PPLL] = PLL(pll_rk3328, PLL_PPLL, RK3528_PCIE_PLL_CON(32), 76c6f7c1a3SJoseph Chen RK3528_MODE_CON, 6, 10, ROCKCHIP_PLL_FIXED_MODE, rk3528_pll_rates), 77c6f7c1a3SJoseph Chen 78c6f7c1a3SJoseph Chen [DPLL] = PLL(pll_rk3328, PLL_DPLL, RK3528_DDRPHY_PLL_CON(16), 79c6f7c1a3SJoseph Chen RK3528_DDRPHY_MODE_CON, 0, 10, 0, rk3528_pll_rates), 80c6f7c1a3SJoseph Chen }; 81c6f7c1a3SJoseph Chen 82c6f7c1a3SJoseph Chen #define RK3528_CPUCLK_RATE(_rate, _aclk_m_core, _pclk_dbg) \ 83c6f7c1a3SJoseph Chen { \ 84c6f7c1a3SJoseph Chen .rate = _rate##U, \ 85c6f7c1a3SJoseph Chen .aclk_div = (_aclk_m_core), \ 86c6f7c1a3SJoseph Chen .pclk_div = (_pclk_dbg), \ 87c6f7c1a3SJoseph Chen } 88c6f7c1a3SJoseph Chen 89c6f7c1a3SJoseph Chen /* sign-off: _aclk_m_core: 550M, _pclk_dbg: 137.5M, */ 90c6f7c1a3SJoseph Chen static struct rockchip_cpu_rate_table rk3528_cpu_rates[] = { 91c6f7c1a3SJoseph Chen RK3528_CPUCLK_RATE(1896000000, 1, 13), 92c6f7c1a3SJoseph Chen RK3528_CPUCLK_RATE(1800000000, 1, 12), 93c6f7c1a3SJoseph Chen RK3528_CPUCLK_RATE(1704000000, 1, 11), 94c6f7c1a3SJoseph Chen RK3528_CPUCLK_RATE(1608000000, 1, 11), 95c6f7c1a3SJoseph Chen RK3528_CPUCLK_RATE(1512000000, 1, 11), 96c6f7c1a3SJoseph Chen RK3528_CPUCLK_RATE(1416000000, 1, 9), 97c6f7c1a3SJoseph Chen RK3528_CPUCLK_RATE(1296000000, 1, 8), 98c6f7c1a3SJoseph Chen RK3528_CPUCLK_RATE(1200000000, 1, 8), 99c6f7c1a3SJoseph Chen RK3528_CPUCLK_RATE(1188000000, 1, 8), 100c6f7c1a3SJoseph Chen RK3528_CPUCLK_RATE(1092000000, 1, 7), 101c6f7c1a3SJoseph Chen RK3528_CPUCLK_RATE(1008000000, 1, 6), 102c6f7c1a3SJoseph Chen RK3528_CPUCLK_RATE(1000000000, 1, 6), 103c6f7c1a3SJoseph Chen RK3528_CPUCLK_RATE(996000000, 1, 6), 104c6f7c1a3SJoseph Chen RK3528_CPUCLK_RATE(960000000, 1, 6), 105c6f7c1a3SJoseph Chen RK3528_CPUCLK_RATE(912000000, 1, 6), 106c6f7c1a3SJoseph Chen RK3528_CPUCLK_RATE(816000000, 1, 5), 107c6f7c1a3SJoseph Chen RK3528_CPUCLK_RATE(600000000, 1, 3), 108c6f7c1a3SJoseph Chen RK3528_CPUCLK_RATE(594000000, 1, 3), 109c6f7c1a3SJoseph Chen RK3528_CPUCLK_RATE(408000000, 1, 2), 110c6f7c1a3SJoseph Chen RK3528_CPUCLK_RATE(312000000, 1, 2), 111c6f7c1a3SJoseph Chen RK3528_CPUCLK_RATE(216000000, 1, 1), 112c6f7c1a3SJoseph Chen RK3528_CPUCLK_RATE(96000000, 1, 0), 113c6f7c1a3SJoseph Chen }; 114c6f7c1a3SJoseph Chen 115c6f7c1a3SJoseph Chen #ifndef CONFIG_SPL_BUILD 116c6f7c1a3SJoseph Chen #define RK3528_CLK_DUMP(_id, _name) \ 117c6f7c1a3SJoseph Chen { \ 118c6f7c1a3SJoseph Chen .id = _id, \ 119c6f7c1a3SJoseph Chen .name = _name, \ 120c6f7c1a3SJoseph Chen } 121c6f7c1a3SJoseph Chen 122c6f7c1a3SJoseph Chen static const struct rk3528_clk_info clks_dump[] = { 123c6f7c1a3SJoseph Chen RK3528_CLK_DUMP(PLL_APLL, "apll"), 124c6f7c1a3SJoseph Chen RK3528_CLK_DUMP(PLL_GPLL, "gpll"), 125c6f7c1a3SJoseph Chen RK3528_CLK_DUMP(PLL_CPLL, "cpll"), 126c6f7c1a3SJoseph Chen RK3528_CLK_DUMP(PLL_DPLL, "dpll"), 127c6f7c1a3SJoseph Chen RK3528_CLK_DUMP(PLL_PPLL, "ppll"), 128c6f7c1a3SJoseph Chen RK3528_CLK_DUMP(CLK_MATRIX_50M_SRC, "clk_50m"), 129c6f7c1a3SJoseph Chen RK3528_CLK_DUMP(CLK_MATRIX_100M_SRC, "clk_100m"), 130c6f7c1a3SJoseph Chen RK3528_CLK_DUMP(CLK_MATRIX_150M_SRC, "clk_150m"), 131c6f7c1a3SJoseph Chen RK3528_CLK_DUMP(CLK_MATRIX_200M_SRC, "clk_200m"), 132c6f7c1a3SJoseph Chen RK3528_CLK_DUMP(CLK_MATRIX_250M_SRC, "clk_250m"), 133c6f7c1a3SJoseph Chen RK3528_CLK_DUMP(CLK_MATRIX_300M_SRC, "clk_300m"), 134c6f7c1a3SJoseph Chen RK3528_CLK_DUMP(CLK_MATRIX_339M_SRC, "clk_339m"), 135c6f7c1a3SJoseph Chen RK3528_CLK_DUMP(CLK_MATRIX_400M_SRC, "clk_400m"), 136c6f7c1a3SJoseph Chen RK3528_CLK_DUMP(CLK_MATRIX_500M_SRC, "clk_600m"), 137c6f7c1a3SJoseph Chen RK3528_CLK_DUMP(CLK_MATRIX_600M_SRC, "clk_600m"), 138c6f7c1a3SJoseph Chen RK3528_CLK_DUMP(CLK_PPLL_50M_MATRIX, "clk_ppll_50m"), 139c6f7c1a3SJoseph Chen RK3528_CLK_DUMP(CLK_PPLL_100M_MATRIX, "clk_ppll_100m"), 140c6f7c1a3SJoseph Chen RK3528_CLK_DUMP(CLK_PPLL_125M_MATRIX, "clk_ppll_125m"), 141c6f7c1a3SJoseph Chen }; 142c6f7c1a3SJoseph Chen #endif 143c6f7c1a3SJoseph Chen 144c6f7c1a3SJoseph Chen /* 145c6f7c1a3SJoseph Chen * 146c6f7c1a3SJoseph Chen * rational_best_approximation(31415, 10000, 147c6f7c1a3SJoseph Chen * (1 << 8) - 1, (1 << 5) - 1, &n, &d); 148c6f7c1a3SJoseph Chen * 149c6f7c1a3SJoseph Chen * you may look at given_numerator as a fixed point number, 150c6f7c1a3SJoseph Chen * with the fractional part size described in given_denominator. 151c6f7c1a3SJoseph Chen * 152c6f7c1a3SJoseph Chen * for theoretical background, see: 153c6f7c1a3SJoseph Chen * http://en.wikipedia.org/wiki/Continued_fraction 154c6f7c1a3SJoseph Chen */ 155c6f7c1a3SJoseph Chen static void rational_best_approximation(unsigned long given_numerator, 156c6f7c1a3SJoseph Chen unsigned long given_denominator, 157c6f7c1a3SJoseph Chen unsigned long max_numerator, 158c6f7c1a3SJoseph Chen unsigned long max_denominator, 159c6f7c1a3SJoseph Chen unsigned long *best_numerator, 160c6f7c1a3SJoseph Chen unsigned long *best_denominator) 161c6f7c1a3SJoseph Chen { 162c6f7c1a3SJoseph Chen unsigned long n, d, n0, d0, n1, d1; 163c6f7c1a3SJoseph Chen 164c6f7c1a3SJoseph Chen n = given_numerator; 165c6f7c1a3SJoseph Chen d = given_denominator; 166c6f7c1a3SJoseph Chen n0 = 0; 167c6f7c1a3SJoseph Chen d1 = 0; 168c6f7c1a3SJoseph Chen n1 = 1; 169c6f7c1a3SJoseph Chen d0 = 1; 170c6f7c1a3SJoseph Chen for (;;) { 171c6f7c1a3SJoseph Chen unsigned long t, a; 172c6f7c1a3SJoseph Chen 173c6f7c1a3SJoseph Chen if (n1 > max_numerator || d1 > max_denominator) { 174c6f7c1a3SJoseph Chen n1 = n0; 175c6f7c1a3SJoseph Chen d1 = d0; 176c6f7c1a3SJoseph Chen break; 177c6f7c1a3SJoseph Chen } 178c6f7c1a3SJoseph Chen if (d == 0) 179c6f7c1a3SJoseph Chen break; 180c6f7c1a3SJoseph Chen t = d; 181c6f7c1a3SJoseph Chen a = n / d; 182c6f7c1a3SJoseph Chen d = n % d; 183c6f7c1a3SJoseph Chen n = t; 184c6f7c1a3SJoseph Chen t = n0 + a * n1; 185c6f7c1a3SJoseph Chen n0 = n1; 186c6f7c1a3SJoseph Chen n1 = t; 187c6f7c1a3SJoseph Chen t = d0 + a * d1; 188c6f7c1a3SJoseph Chen d0 = d1; 189c6f7c1a3SJoseph Chen d1 = t; 190c6f7c1a3SJoseph Chen } 191c6f7c1a3SJoseph Chen *best_numerator = n1; 192c6f7c1a3SJoseph Chen *best_denominator = d1; 193c6f7c1a3SJoseph Chen } 194c6f7c1a3SJoseph Chen 195c6f7c1a3SJoseph Chen static int rk3528_armclk_set_clk(struct rk3528_clk_priv *priv, ulong new_rate) 196c6f7c1a3SJoseph Chen { 197c6f7c1a3SJoseph Chen const struct rockchip_cpu_rate_table *rate; 198c6f7c1a3SJoseph Chen struct rk3528_cru *cru = priv->cru; 199c6f7c1a3SJoseph Chen ulong old_rate; 200c6f7c1a3SJoseph Chen 201c6f7c1a3SJoseph Chen rate = rockchip_get_cpu_settings(rk3528_cpu_rates, new_rate); 202c6f7c1a3SJoseph Chen if (!rate) { 203c6f7c1a3SJoseph Chen printf("%s unsupported rate\n", __func__); 204c6f7c1a3SJoseph Chen return -EINVAL; 205c6f7c1a3SJoseph Chen } 206c6f7c1a3SJoseph Chen 207c6f7c1a3SJoseph Chen /* 208c6f7c1a3SJoseph Chen * set up dependent divisors for DBG and ACLK clocks. 209c6f7c1a3SJoseph Chen */ 210c6f7c1a3SJoseph Chen old_rate = rockchip_pll_get_rate(&rk3528_pll_clks[APLL], priv->cru, APLL); 211c6f7c1a3SJoseph Chen if (old_rate > new_rate) { 212c6f7c1a3SJoseph Chen if (rockchip_pll_set_rate(&rk3528_pll_clks[APLL], 213c6f7c1a3SJoseph Chen priv->cru, APLL, new_rate)) 214c6f7c1a3SJoseph Chen return -EINVAL; 215c6f7c1a3SJoseph Chen 216c6f7c1a3SJoseph Chen rk_clrsetreg(&cru->clksel_con[40], RK3528_DIV_PCLK_DBG_MASK, 217c6f7c1a3SJoseph Chen rate->pclk_div << RK3528_DIV_PCLK_DBG_SHIFT); 218c6f7c1a3SJoseph Chen 219c6f7c1a3SJoseph Chen rk_clrsetreg(&cru->clksel_con[5], RK3528_DIV_ACLK_M_CORE_MASK, 220c6f7c1a3SJoseph Chen rate->aclk_div << RK3528_DIV_ACLK_M_CORE_SHIFT); 221c6f7c1a3SJoseph Chen } else if (old_rate < new_rate) { 222c6f7c1a3SJoseph Chen rk_clrsetreg(&cru->clksel_con[40], RK3528_DIV_PCLK_DBG_MASK, 223c6f7c1a3SJoseph Chen rate->pclk_div << RK3528_DIV_PCLK_DBG_SHIFT); 224c6f7c1a3SJoseph Chen 225c6f7c1a3SJoseph Chen rk_clrsetreg(&cru->clksel_con[5], RK3528_DIV_ACLK_M_CORE_MASK, 226c6f7c1a3SJoseph Chen rate->aclk_div << RK3528_DIV_ACLK_M_CORE_SHIFT); 227c6f7c1a3SJoseph Chen 228c6f7c1a3SJoseph Chen if (rockchip_pll_set_rate(&rk3528_pll_clks[APLL], 229c6f7c1a3SJoseph Chen priv->cru, APLL, new_rate)) 230c6f7c1a3SJoseph Chen return -EINVAL; 231c6f7c1a3SJoseph Chen } 232c6f7c1a3SJoseph Chen 233c6f7c1a3SJoseph Chen return 0; 234c6f7c1a3SJoseph Chen } 235c6f7c1a3SJoseph Chen 236c6f7c1a3SJoseph Chen static ulong rk3528_ppll_matrix_get_rate(struct rk3528_clk_priv *priv, 237c6f7c1a3SJoseph Chen ulong clk_id) 238c6f7c1a3SJoseph Chen { 239c6f7c1a3SJoseph Chen struct rk3528_cru *cru = priv->cru; 240c6f7c1a3SJoseph Chen u32 div, mask, shift; 241c6f7c1a3SJoseph Chen void *reg; 242c6f7c1a3SJoseph Chen 243c6f7c1a3SJoseph Chen switch (clk_id) { 244c6f7c1a3SJoseph Chen case CLK_PPLL_50M_MATRIX: 245c6f7c1a3SJoseph Chen case CLK_GMAC1_RMII_VPU: 246c6f7c1a3SJoseph Chen mask = PCEICRU_CLKSEL_CON01_CLK_MATRIX_50M_SRC_DIV_MASK; 247c6f7c1a3SJoseph Chen shift = PCEICRU_CLKSEL_CON01_CLK_MATRIX_50M_SRC_DIV_SHIFT; 248c6f7c1a3SJoseph Chen reg = &cru->pcieclksel_con[1]; 249c6f7c1a3SJoseph Chen break; 250c6f7c1a3SJoseph Chen 251c6f7c1a3SJoseph Chen case CLK_PPLL_100M_MATRIX: 252c6f7c1a3SJoseph Chen mask = PCEICRU_CLKSEL_CON01_CLK_MATRIX_100M_SRC_DIV_MASK; 253c6f7c1a3SJoseph Chen shift = PCEICRU_CLKSEL_CON01_CLK_MATRIX_100M_SRC_DIV_SHIFT; 254c6f7c1a3SJoseph Chen reg = &cru->pcieclksel_con[1]; 255c6f7c1a3SJoseph Chen break; 256c6f7c1a3SJoseph Chen 257c6f7c1a3SJoseph Chen case CLK_PPLL_125M_MATRIX: 258c6f7c1a3SJoseph Chen case CLK_GMAC1_SRC_VPU: 259c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON60_CLK_MATRIX_125M_SRC_DIV_MASK; 260c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON60_CLK_MATRIX_125M_SRC_DIV_SHIFT; 261c6f7c1a3SJoseph Chen reg = &cru->clksel_con[60]; 262c6f7c1a3SJoseph Chen break; 263c6f7c1a3SJoseph Chen 264c6f7c1a3SJoseph Chen case CLK_GMAC1_VPU_25M: 265c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON60_CLK_MATRIX_25M_SRC_DIV_MASK; 266c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON60_CLK_MATRIX_25M_SRC_DIV_SHIFT; 267c6f7c1a3SJoseph Chen reg = &cru->clksel_con[60]; 268c6f7c1a3SJoseph Chen break; 269c6f7c1a3SJoseph Chen default: 270c6f7c1a3SJoseph Chen return -ENOENT; 271c6f7c1a3SJoseph Chen } 272c6f7c1a3SJoseph Chen 273c6f7c1a3SJoseph Chen div = (readl(reg) & mask) >> shift; 274c6f7c1a3SJoseph Chen 275c6f7c1a3SJoseph Chen return DIV_TO_RATE(priv->ppll_hz, div); 276c6f7c1a3SJoseph Chen } 277c6f7c1a3SJoseph Chen 278c6f7c1a3SJoseph Chen static ulong rk3528_ppll_matrix_set_rate(struct rk3528_clk_priv *priv, 279c6f7c1a3SJoseph Chen ulong clk_id, ulong rate) 280c6f7c1a3SJoseph Chen { 281c6f7c1a3SJoseph Chen struct rk3528_cru *cru = priv->cru; 282c6f7c1a3SJoseph Chen u32 id, div, mask, shift; 283c6f7c1a3SJoseph Chen u8 is_pciecru = 0; 284c6f7c1a3SJoseph Chen 285c6f7c1a3SJoseph Chen switch (clk_id) { 286c6f7c1a3SJoseph Chen case CLK_PPLL_50M_MATRIX: 287c6f7c1a3SJoseph Chen id = 1; 288c6f7c1a3SJoseph Chen mask = PCEICRU_CLKSEL_CON01_CLK_MATRIX_50M_SRC_DIV_MASK; 289c6f7c1a3SJoseph Chen shift = PCEICRU_CLKSEL_CON01_CLK_MATRIX_50M_SRC_DIV_SHIFT; 290c6f7c1a3SJoseph Chen is_pciecru = 1; 291c6f7c1a3SJoseph Chen break; 292c6f7c1a3SJoseph Chen 293c6f7c1a3SJoseph Chen case CLK_PPLL_100M_MATRIX: 294c6f7c1a3SJoseph Chen id = 1; 295c6f7c1a3SJoseph Chen mask = PCEICRU_CLKSEL_CON01_CLK_MATRIX_100M_SRC_DIV_MASK; 296c6f7c1a3SJoseph Chen shift = PCEICRU_CLKSEL_CON01_CLK_MATRIX_100M_SRC_DIV_SHIFT; 297c6f7c1a3SJoseph Chen is_pciecru = 1; 298c6f7c1a3SJoseph Chen break; 299c6f7c1a3SJoseph Chen 300c6f7c1a3SJoseph Chen case CLK_PPLL_125M_MATRIX: 301c6f7c1a3SJoseph Chen id = 60; 302c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON60_CLK_MATRIX_125M_SRC_DIV_MASK; 303c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON60_CLK_MATRIX_125M_SRC_DIV_SHIFT; 304c6f7c1a3SJoseph Chen break; 305c6f7c1a3SJoseph Chen case CLK_GMAC1_VPU_25M: 306c6f7c1a3SJoseph Chen id = 60; 307c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON60_CLK_MATRIX_25M_SRC_DIV_MASK; 308c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON60_CLK_MATRIX_25M_SRC_DIV_SHIFT; 309c6f7c1a3SJoseph Chen break; 310c6f7c1a3SJoseph Chen default: 311c6f7c1a3SJoseph Chen return -ENOENT; 312c6f7c1a3SJoseph Chen } 313c6f7c1a3SJoseph Chen 314c6f7c1a3SJoseph Chen div = DIV_ROUND_UP(priv->ppll_hz, rate); 315c6f7c1a3SJoseph Chen if (is_pciecru) 316c6f7c1a3SJoseph Chen rk_clrsetreg(&cru->pcieclksel_con[id], mask, (div - 1) << shift); 317c6f7c1a3SJoseph Chen else 318c6f7c1a3SJoseph Chen rk_clrsetreg(&cru->clksel_con[id], mask, (div - 1) << shift); 319c6f7c1a3SJoseph Chen 320c6f7c1a3SJoseph Chen return rk3528_ppll_matrix_get_rate(priv, clk_id); 321c6f7c1a3SJoseph Chen } 322c6f7c1a3SJoseph Chen 323c6f7c1a3SJoseph Chen static ulong rk3528_cgpll_matrix_get_rate(struct rk3528_clk_priv *priv, 324c6f7c1a3SJoseph Chen ulong clk_id) 325c6f7c1a3SJoseph Chen { 326c6f7c1a3SJoseph Chen struct rk3528_cru *cru = priv->cru; 327c6f7c1a3SJoseph Chen u32 sel, div, mask, shift, con; 328c6f7c1a3SJoseph Chen u32 sel_mask = 0, sel_shift; 329c6f7c1a3SJoseph Chen u8 is_gpll_parent = 1; 330c6f7c1a3SJoseph Chen u8 is_halfdiv = 0; 331c6f7c1a3SJoseph Chen ulong prate; 332c6f7c1a3SJoseph Chen 333c6f7c1a3SJoseph Chen switch (clk_id) { 334c6f7c1a3SJoseph Chen case CLK_MATRIX_50M_SRC: 335c6f7c1a3SJoseph Chen con = 0; 336c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON00_CLK_MATRIX_50M_SRC_DIV_MASK; 337c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON00_CLK_MATRIX_50M_SRC_DIV_SHIFT; 338c6f7c1a3SJoseph Chen is_gpll_parent = 0; 339c6f7c1a3SJoseph Chen break; 340c6f7c1a3SJoseph Chen 341c6f7c1a3SJoseph Chen case CLK_MATRIX_100M_SRC: 342c6f7c1a3SJoseph Chen con = 0; 343c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON00_CLK_MATRIX_100M_SRC_DIV_MASK; 344c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON00_CLK_MATRIX_100M_SRC_DIV_SHIFT; 345c6f7c1a3SJoseph Chen is_gpll_parent = 0; 346c6f7c1a3SJoseph Chen break; 347c6f7c1a3SJoseph Chen 348c6f7c1a3SJoseph Chen case CLK_MATRIX_150M_SRC: 349c6f7c1a3SJoseph Chen con = 1; 350c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON01_CLK_MATRIX_150M_SRC_DIV_MASK; 351c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON01_CLK_MATRIX_150M_SRC_DIV_SHIFT; 352c6f7c1a3SJoseph Chen break; 353c6f7c1a3SJoseph Chen 354c6f7c1a3SJoseph Chen case CLK_MATRIX_200M_SRC: 355c6f7c1a3SJoseph Chen con = 1; 356c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON01_CLK_MATRIX_200M_SRC_DIV_MASK; 357c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON01_CLK_MATRIX_200M_SRC_DIV_SHIFT; 358c6f7c1a3SJoseph Chen break; 359c6f7c1a3SJoseph Chen 360c6f7c1a3SJoseph Chen case CLK_MATRIX_250M_SRC: 361c6f7c1a3SJoseph Chen con = 1; 362c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON01_CLK_MATRIX_250M_SRC_DIV_MASK; 363c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON01_CLK_MATRIX_250M_SRC_DIV_SHIFT; 364c6f7c1a3SJoseph Chen sel_mask = CRU_CLKSEL_CON01_CLK_MATRIX_250M_SRC_SEL_MASK; 365c6f7c1a3SJoseph Chen sel_shift = CRU_CLKSEL_CON01_CLK_MATRIX_250M_SRC_SEL_SHIFT; 366c6f7c1a3SJoseph Chen break; 367c6f7c1a3SJoseph Chen 368c6f7c1a3SJoseph Chen case CLK_MATRIX_300M_SRC: 369c6f7c1a3SJoseph Chen con = 2; 370c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON02_CLK_MATRIX_300M_SRC_DIV_MASK; 371c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON02_CLK_MATRIX_300M_SRC_DIV_SHIFT; 372c6f7c1a3SJoseph Chen break; 373c6f7c1a3SJoseph Chen 374c6f7c1a3SJoseph Chen case CLK_MATRIX_339M_SRC: 375c6f7c1a3SJoseph Chen con = 2; 376c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON02_CLK_MATRIX_339M_SRC_DIV_MASK; 377c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON02_CLK_MATRIX_339M_SRC_DIV_SHIFT; 378c6f7c1a3SJoseph Chen is_halfdiv = 1; 379c6f7c1a3SJoseph Chen break; 380c6f7c1a3SJoseph Chen 381c6f7c1a3SJoseph Chen case CLK_MATRIX_400M_SRC: 382c6f7c1a3SJoseph Chen con = 2; 383c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON02_CLK_MATRIX_400M_SRC_DIV_MASK; 384c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON02_CLK_MATRIX_400M_SRC_DIV_SHIFT; 385c6f7c1a3SJoseph Chen break; 386c6f7c1a3SJoseph Chen 387c6f7c1a3SJoseph Chen case CLK_MATRIX_500M_SRC: 388c6f7c1a3SJoseph Chen con = 3; 389c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON03_CLK_MATRIX_500M_SRC_DIV_MASK; 390c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON03_CLK_MATRIX_500M_SRC_DIV_SHIFT; 391c6f7c1a3SJoseph Chen sel_mask = CRU_CLKSEL_CON03_CLK_MATRIX_500M_SRC_SEL_MASK; 392c6f7c1a3SJoseph Chen sel_shift = CRU_CLKSEL_CON03_CLK_MATRIX_500M_SRC_SEL_SHIFT; 393c6f7c1a3SJoseph Chen break; 394c6f7c1a3SJoseph Chen 395c6f7c1a3SJoseph Chen case CLK_MATRIX_600M_SRC: 396c6f7c1a3SJoseph Chen con = 4; 397c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON04_CLK_MATRIX_600M_SRC_DIV_MASK; 398c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON04_CLK_MATRIX_600M_SRC_DIV_SHIFT; 399c6f7c1a3SJoseph Chen break; 400c6f7c1a3SJoseph Chen 401c6f7c1a3SJoseph Chen case ACLK_BUS_VOPGL_ROOT: 402c6f7c1a3SJoseph Chen case ACLK_BUS_VOPGL_BIU: 403c6f7c1a3SJoseph Chen con = 43; 404c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON43_ACLK_BUS_VOPGL_ROOT_DIV_MASK; 405c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON43_ACLK_BUS_VOPGL_ROOT_DIV_SHIFT; 406c6f7c1a3SJoseph Chen break; 407c6f7c1a3SJoseph Chen 408c6f7c1a3SJoseph Chen default: 409c6f7c1a3SJoseph Chen return -ENOENT; 410c6f7c1a3SJoseph Chen } 411c6f7c1a3SJoseph Chen 412c6f7c1a3SJoseph Chen if (sel_mask) { 413c6f7c1a3SJoseph Chen sel = (readl(&cru->clksel_con[con]) & sel_mask) >> sel_shift; 414c6f7c1a3SJoseph Chen if (sel == CLK_MATRIX_250M_SRC_SEL_CLK_GPLL_MUX) // TODO 415c6f7c1a3SJoseph Chen prate = priv->gpll_hz; 416c6f7c1a3SJoseph Chen else 417c6f7c1a3SJoseph Chen prate = priv->cpll_hz; 418c6f7c1a3SJoseph Chen } else { 419c6f7c1a3SJoseph Chen if (is_gpll_parent) 420c6f7c1a3SJoseph Chen prate = priv->gpll_hz; 421c6f7c1a3SJoseph Chen else 422c6f7c1a3SJoseph Chen prate = priv->cpll_hz; 423c6f7c1a3SJoseph Chen } 424c6f7c1a3SJoseph Chen 425c6f7c1a3SJoseph Chen div = (readl(&cru->clksel_con[con]) & mask) >> shift; 426c6f7c1a3SJoseph Chen 427c6f7c1a3SJoseph Chen return is_halfdiv ? DIV_TO_RATE(prate * 2, (3 + 2 * div) + 1) : DIV_TO_RATE(prate, div); 428c6f7c1a3SJoseph Chen } 429c6f7c1a3SJoseph Chen 430c6f7c1a3SJoseph Chen static ulong rk3528_cgpll_matrix_set_rate(struct rk3528_clk_priv *priv, 431c6f7c1a3SJoseph Chen ulong clk_id, ulong rate) 432c6f7c1a3SJoseph Chen { 433c6f7c1a3SJoseph Chen struct rk3528_cru *cru = priv->cru; 434c6f7c1a3SJoseph Chen u32 sel, div, mask, shift, con; 435c6f7c1a3SJoseph Chen u32 sel_mask = 0, sel_shift; 436c6f7c1a3SJoseph Chen u8 is_gpll_parent = 1; 437c6f7c1a3SJoseph Chen u8 is_halfdiv = 0; 438c6f7c1a3SJoseph Chen ulong prate = 0; 439c6f7c1a3SJoseph Chen 440c6f7c1a3SJoseph Chen switch (clk_id) { 441c6f7c1a3SJoseph Chen case CLK_MATRIX_50M_SRC: 442c6f7c1a3SJoseph Chen con = 0; 443c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON00_CLK_MATRIX_50M_SRC_DIV_MASK; 444c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON00_CLK_MATRIX_50M_SRC_DIV_SHIFT; 445c6f7c1a3SJoseph Chen is_gpll_parent = 0; 446c6f7c1a3SJoseph Chen break; 447c6f7c1a3SJoseph Chen 448c6f7c1a3SJoseph Chen case CLK_MATRIX_100M_SRC: 449c6f7c1a3SJoseph Chen con = 0; 450c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON00_CLK_MATRIX_100M_SRC_DIV_MASK; 451c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON00_CLK_MATRIX_100M_SRC_DIV_SHIFT; 452c6f7c1a3SJoseph Chen is_gpll_parent = 0; 453c6f7c1a3SJoseph Chen break; 454c6f7c1a3SJoseph Chen 455c6f7c1a3SJoseph Chen case CLK_MATRIX_150M_SRC: 456c6f7c1a3SJoseph Chen con = 1; 457c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON01_CLK_MATRIX_150M_SRC_DIV_MASK; 458c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON01_CLK_MATRIX_150M_SRC_DIV_SHIFT; 459c6f7c1a3SJoseph Chen break; 460c6f7c1a3SJoseph Chen 461c6f7c1a3SJoseph Chen case CLK_MATRIX_200M_SRC: 462c6f7c1a3SJoseph Chen con = 1; 463c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON01_CLK_MATRIX_200M_SRC_DIV_MASK; 464c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON01_CLK_MATRIX_200M_SRC_DIV_SHIFT; 465c6f7c1a3SJoseph Chen break; 466c6f7c1a3SJoseph Chen 467c6f7c1a3SJoseph Chen case CLK_MATRIX_250M_SRC: 468c6f7c1a3SJoseph Chen con = 1; 469c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON01_CLK_MATRIX_250M_SRC_DIV_MASK; 470c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON01_CLK_MATRIX_250M_SRC_DIV_SHIFT; 471c6f7c1a3SJoseph Chen sel_mask = CRU_CLKSEL_CON01_CLK_MATRIX_250M_SRC_SEL_MASK; 472c6f7c1a3SJoseph Chen sel_shift = CRU_CLKSEL_CON01_CLK_MATRIX_250M_SRC_SEL_SHIFT; 473c6f7c1a3SJoseph Chen break; 474c6f7c1a3SJoseph Chen 475c6f7c1a3SJoseph Chen case CLK_MATRIX_300M_SRC: 476c6f7c1a3SJoseph Chen con = 2; 477c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON02_CLK_MATRIX_300M_SRC_DIV_MASK; 478c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON02_CLK_MATRIX_300M_SRC_DIV_SHIFT; 479c6f7c1a3SJoseph Chen break; 480c6f7c1a3SJoseph Chen 481c6f7c1a3SJoseph Chen case CLK_MATRIX_339M_SRC: 482c6f7c1a3SJoseph Chen con = 2; 483c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON02_CLK_MATRIX_339M_SRC_DIV_MASK; 484c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON02_CLK_MATRIX_339M_SRC_DIV_SHIFT; 485c6f7c1a3SJoseph Chen is_halfdiv = 1; 486c6f7c1a3SJoseph Chen break; 487c6f7c1a3SJoseph Chen 488c6f7c1a3SJoseph Chen case CLK_MATRIX_400M_SRC: 489c6f7c1a3SJoseph Chen con = 2; 490c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON02_CLK_MATRIX_400M_SRC_DIV_MASK; 491c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON02_CLK_MATRIX_400M_SRC_DIV_SHIFT; 492c6f7c1a3SJoseph Chen break; 493c6f7c1a3SJoseph Chen 494c6f7c1a3SJoseph Chen case CLK_MATRIX_500M_SRC: 495c6f7c1a3SJoseph Chen con = 3; 496c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON03_CLK_MATRIX_500M_SRC_DIV_MASK; 497c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON03_CLK_MATRIX_500M_SRC_DIV_SHIFT; 498c6f7c1a3SJoseph Chen sel_mask = CRU_CLKSEL_CON03_CLK_MATRIX_500M_SRC_SEL_MASK; 499c6f7c1a3SJoseph Chen sel_shift = CRU_CLKSEL_CON03_CLK_MATRIX_500M_SRC_SEL_SHIFT; 500c6f7c1a3SJoseph Chen break; 501c6f7c1a3SJoseph Chen 502c6f7c1a3SJoseph Chen case CLK_MATRIX_600M_SRC: 503c6f7c1a3SJoseph Chen con = 4; 504c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON04_CLK_MATRIX_600M_SRC_DIV_MASK; 505c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON04_CLK_MATRIX_600M_SRC_DIV_SHIFT; 506c6f7c1a3SJoseph Chen break; 507c6f7c1a3SJoseph Chen 508c6f7c1a3SJoseph Chen case ACLK_BUS_VOPGL_ROOT: 509c6f7c1a3SJoseph Chen case ACLK_BUS_VOPGL_BIU: 510c6f7c1a3SJoseph Chen con = 43; 511c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON43_ACLK_BUS_VOPGL_ROOT_DIV_MASK; 512c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON43_ACLK_BUS_VOPGL_ROOT_DIV_SHIFT; 513c6f7c1a3SJoseph Chen break; 514c6f7c1a3SJoseph Chen 515c6f7c1a3SJoseph Chen default: 516c6f7c1a3SJoseph Chen return -ENOENT; 517c6f7c1a3SJoseph Chen } 518c6f7c1a3SJoseph Chen 519c6f7c1a3SJoseph Chen if (sel_mask) { 520c6f7c1a3SJoseph Chen if (priv->gpll_hz % rate == 0) { 521c6f7c1a3SJoseph Chen sel = CLK_MATRIX_250M_SRC_SEL_CLK_GPLL_MUX; // TODO 522c6f7c1a3SJoseph Chen prate = priv->gpll_hz; 523c6f7c1a3SJoseph Chen } else { 524c6f7c1a3SJoseph Chen sel = CLK_MATRIX_250M_SRC_SEL_CLK_CPLL_MUX; 525c6f7c1a3SJoseph Chen prate = priv->cpll_hz; 526c6f7c1a3SJoseph Chen } 527c6f7c1a3SJoseph Chen } else { 528c6f7c1a3SJoseph Chen if (is_gpll_parent) 529c6f7c1a3SJoseph Chen prate = priv->gpll_hz; 530c6f7c1a3SJoseph Chen else 531c6f7c1a3SJoseph Chen prate = priv->cpll_hz; 532c6f7c1a3SJoseph Chen } 533c6f7c1a3SJoseph Chen 534c6f7c1a3SJoseph Chen if (is_halfdiv) 535c6f7c1a3SJoseph Chen div = DIV_ROUND_UP((prate * 2) - (3 * rate), 2 * rate); 536c6f7c1a3SJoseph Chen else 537c6f7c1a3SJoseph Chen div = DIV_ROUND_UP(prate, rate); 538c6f7c1a3SJoseph Chen 539c6f7c1a3SJoseph Chen rk_clrsetreg(&cru->clksel_con[con], mask, (div - 1) << shift); 540c6f7c1a3SJoseph Chen if (sel_mask) 541c6f7c1a3SJoseph Chen rk_clrsetreg(&cru->clksel_con[con], sel_mask, sel << sel_shift); 542c6f7c1a3SJoseph Chen 543c6f7c1a3SJoseph Chen return rk3528_cgpll_matrix_get_rate(priv, clk_id); 544c6f7c1a3SJoseph Chen } 545c6f7c1a3SJoseph Chen 546c6f7c1a3SJoseph Chen static ulong rk3528_i2c_get_clk(struct rk3528_clk_priv *priv, ulong clk_id) 547c6f7c1a3SJoseph Chen { 548c6f7c1a3SJoseph Chen struct rk3528_cru *cru = priv->cru; 549c6f7c1a3SJoseph Chen u32 id, sel, con, mask, shift; 550c6f7c1a3SJoseph Chen u8 is_pmucru = 0; 551c6f7c1a3SJoseph Chen ulong rate; 552c6f7c1a3SJoseph Chen 553c6f7c1a3SJoseph Chen switch (clk_id) { 554c6f7c1a3SJoseph Chen case CLK_I2C0: 555c6f7c1a3SJoseph Chen id = 79; 556c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON79_CLK_I2C0_SEL_MASK; 557c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON79_CLK_I2C0_SEL_SHIFT; 558c6f7c1a3SJoseph Chen break; 559c6f7c1a3SJoseph Chen 560c6f7c1a3SJoseph Chen case CLK_I2C1: 561c6f7c1a3SJoseph Chen id = 79; 562c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON79_CLK_I2C1_SEL_MASK; 563c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON79_CLK_I2C1_SEL_SHIFT; 564c6f7c1a3SJoseph Chen break; 565c6f7c1a3SJoseph Chen 566c6f7c1a3SJoseph Chen case CLK_I2C2: 567c6f7c1a3SJoseph Chen id = 0; 568c6f7c1a3SJoseph Chen mask = PMUCRU_CLKSEL_CON0_CLK_I2C2_SEL_MASK; 569c6f7c1a3SJoseph Chen shift = PMUCRU_CLKSEL_CON0_CLK_I2C2_SEL_SHIFT; 570c6f7c1a3SJoseph Chen is_pmucru = 1; 571c6f7c1a3SJoseph Chen break; 572c6f7c1a3SJoseph Chen 573c6f7c1a3SJoseph Chen case CLK_I2C3: 574c6f7c1a3SJoseph Chen id = 63; 575c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON63_CLK_I2C3_SEL_MASK; 576c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON63_CLK_I2C3_SEL_SHIFT; 577c6f7c1a3SJoseph Chen break; 578c6f7c1a3SJoseph Chen 579c6f7c1a3SJoseph Chen case CLK_I2C4: 580c6f7c1a3SJoseph Chen id = 85; 581c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON85_CLK_I2C4_SEL_MASK; 582c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON85_CLK_I2C4_SEL_SHIFT; 583c6f7c1a3SJoseph Chen break; 584c6f7c1a3SJoseph Chen 585c6f7c1a3SJoseph Chen case CLK_I2C5: 586c6f7c1a3SJoseph Chen id = 63; 587c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON63_CLK_I2C5_SEL_MASK; 588c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON63_CLK_I2C5_SEL_SHIFT; 589c6f7c1a3SJoseph Chen break; 590c6f7c1a3SJoseph Chen 591c6f7c1a3SJoseph Chen case CLK_I2C6: 592c6f7c1a3SJoseph Chen id = 64; 593c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON64_CLK_I2C6_SEL_MASK; 594c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON64_CLK_I2C6_SEL_SHIFT; 595c6f7c1a3SJoseph Chen break; 596c6f7c1a3SJoseph Chen 597c6f7c1a3SJoseph Chen case CLK_I2C7: 598c6f7c1a3SJoseph Chen id = 86; 599c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON86_CLK_I2C7_SEL_MASK; 600c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON86_CLK_I2C7_SEL_SHIFT; 601c6f7c1a3SJoseph Chen break; 602c6f7c1a3SJoseph Chen 603c6f7c1a3SJoseph Chen default: 604c6f7c1a3SJoseph Chen return -ENOENT; 605c6f7c1a3SJoseph Chen } 606c6f7c1a3SJoseph Chen 607c6f7c1a3SJoseph Chen if (is_pmucru) 608c6f7c1a3SJoseph Chen con = readl(&cru->pmuclksel_con[id]); 609c6f7c1a3SJoseph Chen else 610c6f7c1a3SJoseph Chen con = readl(&cru->clksel_con[id]); 611c6f7c1a3SJoseph Chen sel = (con & mask) >> shift; 612c6f7c1a3SJoseph Chen if (sel == CLK_I2C3_SEL_CLK_MATRIX_200M_SRC) 613c6f7c1a3SJoseph Chen rate = 200 * MHz; 614c6f7c1a3SJoseph Chen else if (sel == CLK_I2C3_SEL_CLK_MATRIX_100M_SRC) 615c6f7c1a3SJoseph Chen rate = 100 * MHz; 616c6f7c1a3SJoseph Chen else if (sel == CLK_I2C3_SEL_CLK_MATRIX_50M_SRC) 617c6f7c1a3SJoseph Chen rate = 50 * MHz; 618c6f7c1a3SJoseph Chen else 619c6f7c1a3SJoseph Chen rate = OSC_HZ; 620c6f7c1a3SJoseph Chen 621c6f7c1a3SJoseph Chen return rate; 622c6f7c1a3SJoseph Chen } 623c6f7c1a3SJoseph Chen 624c6f7c1a3SJoseph Chen static ulong rk3528_i2c_set_clk(struct rk3528_clk_priv *priv, ulong clk_id, 625c6f7c1a3SJoseph Chen ulong rate) 626c6f7c1a3SJoseph Chen { 627c6f7c1a3SJoseph Chen struct rk3528_cru *cru = priv->cru; 628c6f7c1a3SJoseph Chen u32 id, sel, mask, shift; 629c6f7c1a3SJoseph Chen u8 is_pmucru = 0; 630c6f7c1a3SJoseph Chen 631c6f7c1a3SJoseph Chen if (rate == 200 * MHz) 632c6f7c1a3SJoseph Chen sel = CLK_I2C3_SEL_CLK_MATRIX_200M_SRC; 633c6f7c1a3SJoseph Chen else if (rate == 100 * MHz) 634c6f7c1a3SJoseph Chen sel = CLK_I2C3_SEL_CLK_MATRIX_100M_SRC; 635c6f7c1a3SJoseph Chen else if (rate == 50 * MHz) 636c6f7c1a3SJoseph Chen sel = CLK_I2C3_SEL_CLK_MATRIX_50M_SRC; 637c6f7c1a3SJoseph Chen else 638c6f7c1a3SJoseph Chen sel = CLK_I2C3_SEL_XIN_OSC0_FUNC; 639c6f7c1a3SJoseph Chen 640c6f7c1a3SJoseph Chen switch (clk_id) { 641c6f7c1a3SJoseph Chen case CLK_I2C0: 642c6f7c1a3SJoseph Chen id = 79; 643c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON79_CLK_I2C0_SEL_MASK; 644c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON79_CLK_I2C0_SEL_SHIFT; 645c6f7c1a3SJoseph Chen break; 646c6f7c1a3SJoseph Chen 647c6f7c1a3SJoseph Chen case CLK_I2C1: 648c6f7c1a3SJoseph Chen id = 79; 649c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON79_CLK_I2C1_SEL_MASK; 650c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON79_CLK_I2C1_SEL_SHIFT; 651c6f7c1a3SJoseph Chen break; 652c6f7c1a3SJoseph Chen 653c6f7c1a3SJoseph Chen case CLK_I2C2: 654c6f7c1a3SJoseph Chen id = 0; 655c6f7c1a3SJoseph Chen mask = PMUCRU_CLKSEL_CON0_CLK_I2C2_SEL_MASK; 656c6f7c1a3SJoseph Chen shift = PMUCRU_CLKSEL_CON0_CLK_I2C2_SEL_SHIFT; 657c6f7c1a3SJoseph Chen is_pmucru = 1; 658c6f7c1a3SJoseph Chen break; 659c6f7c1a3SJoseph Chen 660c6f7c1a3SJoseph Chen case CLK_I2C3: 661c6f7c1a3SJoseph Chen id = 63; 662c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON63_CLK_I2C3_SEL_MASK; 663c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON63_CLK_I2C3_SEL_SHIFT; 664c6f7c1a3SJoseph Chen break; 665c6f7c1a3SJoseph Chen 666c6f7c1a3SJoseph Chen case CLK_I2C4: 667c6f7c1a3SJoseph Chen id = 85; 668c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON85_CLK_I2C4_SEL_MASK; 669c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON85_CLK_I2C4_SEL_SHIFT; 670c6f7c1a3SJoseph Chen break; 671c6f7c1a3SJoseph Chen 672c6f7c1a3SJoseph Chen case CLK_I2C5: 673c6f7c1a3SJoseph Chen id = 63; 674c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON63_CLK_I2C5_SEL_MASK; 675c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON63_CLK_I2C5_SEL_SHIFT; 676c6f7c1a3SJoseph Chen 677c6f7c1a3SJoseph Chen case CLK_I2C6: 678c6f7c1a3SJoseph Chen id = 64; 679c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON64_CLK_I2C6_SEL_MASK; 680c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON64_CLK_I2C6_SEL_SHIFT; 681c6f7c1a3SJoseph Chen break; 682c6f7c1a3SJoseph Chen 683c6f7c1a3SJoseph Chen case CLK_I2C7: 684c6f7c1a3SJoseph Chen id = 86; 685c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON86_CLK_I2C7_SEL_MASK; 686c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON86_CLK_I2C7_SEL_SHIFT; 687c6f7c1a3SJoseph Chen break; 688c6f7c1a3SJoseph Chen 689c6f7c1a3SJoseph Chen default: 690c6f7c1a3SJoseph Chen return -ENOENT; 691c6f7c1a3SJoseph Chen } 692c6f7c1a3SJoseph Chen 693c6f7c1a3SJoseph Chen if (is_pmucru) 694c6f7c1a3SJoseph Chen rk_clrsetreg(&cru->pmuclksel_con[id], mask, sel << shift); 695c6f7c1a3SJoseph Chen else 696c6f7c1a3SJoseph Chen rk_clrsetreg(&cru->clksel_con[id], mask, sel << shift); 697c6f7c1a3SJoseph Chen 698c6f7c1a3SJoseph Chen return rk3528_i2c_get_clk(priv, clk_id); 699c6f7c1a3SJoseph Chen } 700c6f7c1a3SJoseph Chen 701c6f7c1a3SJoseph Chen static ulong rk3528_spi_get_clk(struct rk3528_clk_priv *priv, ulong clk_id) 702c6f7c1a3SJoseph Chen { 703c6f7c1a3SJoseph Chen struct rk3528_cru *cru = priv->cru; 704c6f7c1a3SJoseph Chen u32 id, sel, con, mask, shift; 705c6f7c1a3SJoseph Chen ulong rate; 706c6f7c1a3SJoseph Chen 707c6f7c1a3SJoseph Chen switch (clk_id) { 708c6f7c1a3SJoseph Chen case CLK_SPI0: 709c6f7c1a3SJoseph Chen id = 79; 710c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON79_CLK_SPI0_SEL_MASK; 711c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON79_CLK_SPI0_SEL_SHIFT; 712c6f7c1a3SJoseph Chen break; 713c6f7c1a3SJoseph Chen 714c6f7c1a3SJoseph Chen case CLK_SPI1: 715c6f7c1a3SJoseph Chen id = 63; 716c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON63_CLK_SPI1_SEL_MASK; 717c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON63_CLK_SPI1_SEL_SHIFT; 718c6f7c1a3SJoseph Chen break; 719c6f7c1a3SJoseph Chen default: 720c6f7c1a3SJoseph Chen return -ENOENT; 721c6f7c1a3SJoseph Chen } 722c6f7c1a3SJoseph Chen 723c6f7c1a3SJoseph Chen con = readl(&cru->clksel_con[id]); 724c6f7c1a3SJoseph Chen sel = (con & mask) >> shift; 725c6f7c1a3SJoseph Chen if (sel == CLK_SPI1_SEL_CLK_MATRIX_200M_SRC) 726c6f7c1a3SJoseph Chen rate = 200 * MHz; 727c6f7c1a3SJoseph Chen if (sel == CLK_SPI1_SEL_CLK_MATRIX_100M_SRC) 728c6f7c1a3SJoseph Chen rate = 100 * MHz; 729c6f7c1a3SJoseph Chen if (sel == CLK_SPI1_SEL_CLK_MATRIX_50M_SRC) 730c6f7c1a3SJoseph Chen rate = 50 * MHz; 731c6f7c1a3SJoseph Chen else 732c6f7c1a3SJoseph Chen rate = OSC_HZ; 733c6f7c1a3SJoseph Chen 734c6f7c1a3SJoseph Chen return rate; 735c6f7c1a3SJoseph Chen } 736c6f7c1a3SJoseph Chen 737c6f7c1a3SJoseph Chen static ulong rk3528_spi_set_clk(struct rk3528_clk_priv *priv, 738c6f7c1a3SJoseph Chen ulong clk_id, ulong rate) 739c6f7c1a3SJoseph Chen { 740c6f7c1a3SJoseph Chen struct rk3528_cru *cru = priv->cru; 741c6f7c1a3SJoseph Chen u32 id, sel, mask, shift; 742c6f7c1a3SJoseph Chen 743c6f7c1a3SJoseph Chen if (rate == 200 * MHz) 744c6f7c1a3SJoseph Chen sel = CLK_SPI1_SEL_CLK_MATRIX_200M_SRC; 745c6f7c1a3SJoseph Chen else if (rate == 100 * MHz) 746c6f7c1a3SJoseph Chen sel = CLK_SPI1_SEL_CLK_MATRIX_100M_SRC; 747c6f7c1a3SJoseph Chen else if (rate == 50 * MHz) 748c6f7c1a3SJoseph Chen sel = CLK_SPI1_SEL_CLK_MATRIX_50M_SRC; 749c6f7c1a3SJoseph Chen else 750c6f7c1a3SJoseph Chen sel = CLK_SPI1_SEL_XIN_OSC0_FUNC; 751c6f7c1a3SJoseph Chen 752c6f7c1a3SJoseph Chen switch (clk_id) { 753c6f7c1a3SJoseph Chen case CLK_SPI0: 754c6f7c1a3SJoseph Chen id = 79; 755c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON79_CLK_SPI0_SEL_MASK; 756c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON79_CLK_SPI0_SEL_SHIFT; 757c6f7c1a3SJoseph Chen break; 758c6f7c1a3SJoseph Chen 759c6f7c1a3SJoseph Chen case CLK_SPI1: 760c6f7c1a3SJoseph Chen id = 63; 761c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON63_CLK_SPI1_SEL_MASK; 762c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON63_CLK_SPI1_SEL_SHIFT; 763c6f7c1a3SJoseph Chen break; 764c6f7c1a3SJoseph Chen default: 765c6f7c1a3SJoseph Chen return -ENOENT; 766c6f7c1a3SJoseph Chen } 767c6f7c1a3SJoseph Chen 768c6f7c1a3SJoseph Chen rk_clrsetreg(&cru->clksel_con[id], mask, sel << shift); 769c6f7c1a3SJoseph Chen 770c6f7c1a3SJoseph Chen return rk3528_spi_get_clk(priv, clk_id); 771c6f7c1a3SJoseph Chen } 772c6f7c1a3SJoseph Chen 773c6f7c1a3SJoseph Chen static ulong rk3528_pwm_get_clk(struct rk3528_clk_priv *priv, ulong clk_id) 774c6f7c1a3SJoseph Chen { 775c6f7c1a3SJoseph Chen struct rk3528_cru *cru = priv->cru; 776c6f7c1a3SJoseph Chen u32 id, sel, con, mask, shift; 777c6f7c1a3SJoseph Chen ulong rate; 778c6f7c1a3SJoseph Chen 779c6f7c1a3SJoseph Chen switch (clk_id) { 780c6f7c1a3SJoseph Chen case CLK_PWM0: 781c6f7c1a3SJoseph Chen id = 44; 782c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON44_CLK_PWM0_SEL_MASK; 783c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON44_CLK_PWM0_SEL_SHIFT; 784c6f7c1a3SJoseph Chen break; 785c6f7c1a3SJoseph Chen 786c6f7c1a3SJoseph Chen case CLK_PWM1: 787c6f7c1a3SJoseph Chen id = 44; 788c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON44_CLK_PWM1_SEL_MASK; 789c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON44_CLK_PWM1_SEL_SHIFT; 790c6f7c1a3SJoseph Chen break; 791c6f7c1a3SJoseph Chen 792c6f7c1a3SJoseph Chen default: 793c6f7c1a3SJoseph Chen return -ENOENT; 794c6f7c1a3SJoseph Chen } 795c6f7c1a3SJoseph Chen 796c6f7c1a3SJoseph Chen con = readl(&cru->clksel_con[id]); 797c6f7c1a3SJoseph Chen sel = (con & mask) >> shift; 798c6f7c1a3SJoseph Chen if (sel == CLK_PWM0_SEL_CLK_MATRIX_100M_SRC) 799c6f7c1a3SJoseph Chen rate = 100 * MHz; 800c6f7c1a3SJoseph Chen if (sel == CLK_PWM0_SEL_CLK_MATRIX_50M_SRC) 801c6f7c1a3SJoseph Chen rate = 50 * MHz; 802c6f7c1a3SJoseph Chen else 803c6f7c1a3SJoseph Chen rate = OSC_HZ; 804c6f7c1a3SJoseph Chen 805c6f7c1a3SJoseph Chen return rate; 806c6f7c1a3SJoseph Chen } 807c6f7c1a3SJoseph Chen 808c6f7c1a3SJoseph Chen static ulong rk3528_pwm_set_clk(struct rk3528_clk_priv *priv, 809c6f7c1a3SJoseph Chen ulong clk_id, ulong rate) 810c6f7c1a3SJoseph Chen { 811c6f7c1a3SJoseph Chen struct rk3528_cru *cru = priv->cru; 812c6f7c1a3SJoseph Chen u32 id, sel, mask, shift; 813c6f7c1a3SJoseph Chen 814c6f7c1a3SJoseph Chen if (rate == 100 * MHz) 815c6f7c1a3SJoseph Chen sel = CLK_PWM0_SEL_CLK_MATRIX_100M_SRC; 816c6f7c1a3SJoseph Chen else if (rate == 50 * MHz) 817c6f7c1a3SJoseph Chen sel = CLK_PWM0_SEL_CLK_MATRIX_50M_SRC; 818c6f7c1a3SJoseph Chen else 819c6f7c1a3SJoseph Chen sel = CLK_PWM0_SEL_XIN_OSC0_FUNC; 820c6f7c1a3SJoseph Chen 821c6f7c1a3SJoseph Chen switch (clk_id) { 822c6f7c1a3SJoseph Chen case CLK_PWM0: 823c6f7c1a3SJoseph Chen id = 44; 824c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON44_CLK_PWM0_SEL_MASK; 825c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON44_CLK_PWM0_SEL_SHIFT; 826c6f7c1a3SJoseph Chen break; 827c6f7c1a3SJoseph Chen 828c6f7c1a3SJoseph Chen case CLK_PWM1: 829c6f7c1a3SJoseph Chen id = 44; 830c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON44_CLK_PWM1_SEL_MASK; 831c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON44_CLK_PWM1_SEL_SHIFT; 832c6f7c1a3SJoseph Chen break; 833c6f7c1a3SJoseph Chen 834c6f7c1a3SJoseph Chen default: 835c6f7c1a3SJoseph Chen return -ENOENT; 836c6f7c1a3SJoseph Chen } 837c6f7c1a3SJoseph Chen 838c6f7c1a3SJoseph Chen rk_clrsetreg(&cru->clksel_con[id], mask, sel << shift); 839c6f7c1a3SJoseph Chen 840c6f7c1a3SJoseph Chen return rk3528_pwm_get_clk(priv, clk_id); 841c6f7c1a3SJoseph Chen } 842c6f7c1a3SJoseph Chen 843c6f7c1a3SJoseph Chen static ulong rk3528_adc_get_clk(struct rk3528_clk_priv *priv, ulong clk_id) 844c6f7c1a3SJoseph Chen { 845c6f7c1a3SJoseph Chen struct rk3528_cru *cru = priv->cru; 846c6f7c1a3SJoseph Chen u32 div, con; 847c6f7c1a3SJoseph Chen 848c6f7c1a3SJoseph Chen con = readl(&cru->clksel_con[74]); 849c6f7c1a3SJoseph Chen switch (clk_id) { 850c6f7c1a3SJoseph Chen case CLK_SARADC: 851c6f7c1a3SJoseph Chen div = (con & CRU_CLKSEL_CON74_CLK_SARADC_DIV_MASK) >> 852c6f7c1a3SJoseph Chen CRU_CLKSEL_CON74_CLK_SARADC_DIV_SHIFT; 853c6f7c1a3SJoseph Chen break; 854c6f7c1a3SJoseph Chen 855c6f7c1a3SJoseph Chen case CLK_TSADC_TSEN: 856c6f7c1a3SJoseph Chen div = (con & CRU_CLKSEL_CON74_CLK_TSADC_TSEN_DIV_MASK) >> 857c6f7c1a3SJoseph Chen CRU_CLKSEL_CON74_CLK_TSADC_TSEN_DIV_SHIFT; 858c6f7c1a3SJoseph Chen break; 859c6f7c1a3SJoseph Chen 860c6f7c1a3SJoseph Chen case CLK_TSADC: 861c6f7c1a3SJoseph Chen div = (con & CRU_CLKSEL_CON74_CLK_TSADC_DIV_MASK) >> 862c6f7c1a3SJoseph Chen CRU_CLKSEL_CON74_CLK_TSADC_DIV_SHIFT; 863c6f7c1a3SJoseph Chen break; 864c6f7c1a3SJoseph Chen 865c6f7c1a3SJoseph Chen default: 866c6f7c1a3SJoseph Chen return -ENOENT; 867c6f7c1a3SJoseph Chen } 868c6f7c1a3SJoseph Chen 869c6f7c1a3SJoseph Chen return DIV_TO_RATE(OSC_HZ, div); 870c6f7c1a3SJoseph Chen } 871c6f7c1a3SJoseph Chen 872c6f7c1a3SJoseph Chen static ulong rk3528_adc_set_clk(struct rk3528_clk_priv *priv, 873c6f7c1a3SJoseph Chen ulong clk_id, ulong rate) 874c6f7c1a3SJoseph Chen { 875c6f7c1a3SJoseph Chen struct rk3528_cru *cru = priv->cru; 876c6f7c1a3SJoseph Chen u32 div, mask, shift; 877c6f7c1a3SJoseph Chen 878c6f7c1a3SJoseph Chen switch (clk_id) { 879c6f7c1a3SJoseph Chen case CLK_SARADC: 880c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON74_CLK_SARADC_DIV_MASK; 881c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON74_CLK_SARADC_DIV_SHIFT; 882c6f7c1a3SJoseph Chen break; 883c6f7c1a3SJoseph Chen 884c6f7c1a3SJoseph Chen case CLK_TSADC_TSEN: 885c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON74_CLK_TSADC_TSEN_DIV_MASK; 886c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON74_CLK_TSADC_TSEN_DIV_SHIFT; 887c6f7c1a3SJoseph Chen break; 888c6f7c1a3SJoseph Chen 889c6f7c1a3SJoseph Chen case CLK_TSADC: 890c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON74_CLK_TSADC_DIV_MASK; 891c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON74_CLK_TSADC_DIV_SHIFT; 892c6f7c1a3SJoseph Chen break; 893c6f7c1a3SJoseph Chen 894c6f7c1a3SJoseph Chen default: 895c6f7c1a3SJoseph Chen return -ENOENT; 896c6f7c1a3SJoseph Chen } 897c6f7c1a3SJoseph Chen 898c6f7c1a3SJoseph Chen div = DIV_ROUND_UP(OSC_HZ, rate); 899c6f7c1a3SJoseph Chen rk_clrsetreg(&cru->clksel_con[74], mask, (div - 1) << shift); 900c6f7c1a3SJoseph Chen 901c6f7c1a3SJoseph Chen return rk3528_adc_get_clk(priv, clk_id); 902c6f7c1a3SJoseph Chen } 903c6f7c1a3SJoseph Chen 904c6f7c1a3SJoseph Chen 905c6f7c1a3SJoseph Chen static ulong rk3528_crypto_get_rate(struct rk3528_clk_priv *priv, ulong clk_id) 906c6f7c1a3SJoseph Chen { 907c6f7c1a3SJoseph Chen struct rk3528_cru *cru = priv->cru; 908c6f7c1a3SJoseph Chen u32 id, sel, con, mask, shift; 909c6f7c1a3SJoseph Chen ulong rate; 910c6f7c1a3SJoseph Chen 911c6f7c1a3SJoseph Chen switch (clk_id) { 912c6f7c1a3SJoseph Chen case CLK_CORE_CRYPTO: 913c6f7c1a3SJoseph Chen id = 43; 914c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON43_CLK_CORE_CRYPTO_SEL_MASK; 915c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON43_CLK_CORE_CRYPTO_SEL_SHIFT; 916c6f7c1a3SJoseph Chen break; 917c6f7c1a3SJoseph Chen 918c6f7c1a3SJoseph Chen case CLK_PKA_CRYPTO: 919c6f7c1a3SJoseph Chen id = 44; 920c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON44_CLK_PKA_CRYPTO_SEL_MASK; 921c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON44_CLK_PKA_CRYPTO_SEL_SHIFT; 922c6f7c1a3SJoseph Chen break; 923c6f7c1a3SJoseph Chen 924c6f7c1a3SJoseph Chen default: 925c6f7c1a3SJoseph Chen return -ENOENT; 926c6f7c1a3SJoseph Chen } 927c6f7c1a3SJoseph Chen 928c6f7c1a3SJoseph Chen con = readl(&cru->clksel_con[id]); 929c6f7c1a3SJoseph Chen sel = (con & mask) >> shift; 930c6f7c1a3SJoseph Chen if (sel == CLK_CORE_CRYPTO_SEL_CLK_MATRIX_300M_SRC) 931c6f7c1a3SJoseph Chen rate = 300 * MHz; 932c6f7c1a3SJoseph Chen else if (sel == CLK_CORE_CRYPTO_SEL_CLK_MATRIX_200M_SRC) 933c6f7c1a3SJoseph Chen rate = 200 * MHz; 934c6f7c1a3SJoseph Chen else if (sel == CLK_CORE_CRYPTO_SEL_CLK_MATRIX_100M_SRC) 935c6f7c1a3SJoseph Chen rate = 100 * MHz; 936c6f7c1a3SJoseph Chen else 937c6f7c1a3SJoseph Chen rate = OSC_HZ; 938c6f7c1a3SJoseph Chen 939c6f7c1a3SJoseph Chen return rate; 940c6f7c1a3SJoseph Chen } 941c6f7c1a3SJoseph Chen 942c6f7c1a3SJoseph Chen static ulong rk3528_crypto_set_rate(struct rk3528_clk_priv *priv, 943c6f7c1a3SJoseph Chen ulong clk_id, ulong rate) 944c6f7c1a3SJoseph Chen { 945c6f7c1a3SJoseph Chen struct rk3528_cru *cru = priv->cru; 946c6f7c1a3SJoseph Chen u32 id, sel, mask, shift; 947c6f7c1a3SJoseph Chen 948c6f7c1a3SJoseph Chen if (rate == 300 * MHz) 949c6f7c1a3SJoseph Chen sel = CLK_CORE_CRYPTO_SEL_CLK_MATRIX_300M_SRC; 950c6f7c1a3SJoseph Chen else if (rate == 200 * MHz) 951c6f7c1a3SJoseph Chen sel = CLK_CORE_CRYPTO_SEL_CLK_MATRIX_200M_SRC; 952c6f7c1a3SJoseph Chen else if (rate == 100 * MHz) 953c6f7c1a3SJoseph Chen sel = CLK_CORE_CRYPTO_SEL_CLK_MATRIX_100M_SRC; 954c6f7c1a3SJoseph Chen else 955c6f7c1a3SJoseph Chen sel = CLK_CORE_CRYPTO_SEL_XIN_OSC0_FUNC; 956c6f7c1a3SJoseph Chen 957c6f7c1a3SJoseph Chen switch (clk_id) { 958c6f7c1a3SJoseph Chen case CLK_CORE_CRYPTO: 959c6f7c1a3SJoseph Chen id = 43; 960c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON43_CLK_CORE_CRYPTO_SEL_MASK; 961c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON43_CLK_CORE_CRYPTO_SEL_SHIFT; 962c6f7c1a3SJoseph Chen break; 963c6f7c1a3SJoseph Chen 964c6f7c1a3SJoseph Chen case CLK_PKA_CRYPTO: 965c6f7c1a3SJoseph Chen id = 44; 966c6f7c1a3SJoseph Chen mask = CRU_CLKSEL_CON44_CLK_PKA_CRYPTO_SEL_MASK; 967c6f7c1a3SJoseph Chen shift = CRU_CLKSEL_CON44_CLK_PKA_CRYPTO_SEL_SHIFT; 968c6f7c1a3SJoseph Chen break; 969c6f7c1a3SJoseph Chen 970c6f7c1a3SJoseph Chen default: 971c6f7c1a3SJoseph Chen return -ENOENT; 972c6f7c1a3SJoseph Chen } 973c6f7c1a3SJoseph Chen 974c6f7c1a3SJoseph Chen rk_clrsetreg(&cru->clksel_con[id], mask, sel << shift); 975c6f7c1a3SJoseph Chen 976c6f7c1a3SJoseph Chen return rk3528_crypto_get_rate(priv, clk_id); 977c6f7c1a3SJoseph Chen } 978c6f7c1a3SJoseph Chen 979c6f7c1a3SJoseph Chen static ulong rk3528_sdmmc_get_clk(struct rk3528_clk_priv *priv, ulong clk_id) 980c6f7c1a3SJoseph Chen { 981c6f7c1a3SJoseph Chen struct rk3528_cru *cru = priv->cru; 982c6f7c1a3SJoseph Chen u32 div, sel, con; 983c6f7c1a3SJoseph Chen ulong prate; 984c6f7c1a3SJoseph Chen 985c6f7c1a3SJoseph Chen con = readl(&cru->clksel_con[85]); 986c6f7c1a3SJoseph Chen div = (con & CRU_CLKSEL_CON85_CCLK_SRC_SDMMC0_DIV_MASK) >> 987c6f7c1a3SJoseph Chen CRU_CLKSEL_CON85_CCLK_SRC_SDMMC0_DIV_SHIFT; 988c6f7c1a3SJoseph Chen sel = (con & CRU_CLKSEL_CON85_CCLK_SRC_SDMMC0_SEL_MASK) >> 989c6f7c1a3SJoseph Chen CRU_CLKSEL_CON85_CCLK_SRC_SDMMC0_SEL_SHIFT; 990c6f7c1a3SJoseph Chen 991c6f7c1a3SJoseph Chen if (sel == CCLK_SRC_SDMMC0_SEL_CLK_GPLL_MUX) 992c6f7c1a3SJoseph Chen prate = priv->gpll_hz; 993c6f7c1a3SJoseph Chen else if (sel == CCLK_SRC_SDMMC0_SEL_CLK_CPLL_MUX) 994c6f7c1a3SJoseph Chen prate = priv->cpll_hz; 995c6f7c1a3SJoseph Chen else 996c6f7c1a3SJoseph Chen prate = OSC_HZ; 997c6f7c1a3SJoseph Chen 998c6f7c1a3SJoseph Chen return DIV_TO_RATE(prate, div); 999c6f7c1a3SJoseph Chen } 1000c6f7c1a3SJoseph Chen 1001c6f7c1a3SJoseph Chen static ulong rk3528_sdmmc_set_clk(struct rk3528_clk_priv *priv, 1002c6f7c1a3SJoseph Chen ulong clk_id, ulong rate) 1003c6f7c1a3SJoseph Chen { 1004c6f7c1a3SJoseph Chen struct rk3528_cru *cru = priv->cru; 1005c6f7c1a3SJoseph Chen u32 div, sel; 1006c6f7c1a3SJoseph Chen 1007c6f7c1a3SJoseph Chen if (OSC_HZ % rate == 0) { 1008c6f7c1a3SJoseph Chen div = DIV_ROUND_UP(OSC_HZ, rate); 1009c6f7c1a3SJoseph Chen sel = CCLK_SRC_SDMMC0_SEL_XIN_OSC0_FUNC; 1010c6f7c1a3SJoseph Chen } else if ((priv->cpll_hz % rate) == 0) { 1011c6f7c1a3SJoseph Chen div = DIV_ROUND_UP(priv->cpll_hz, rate); 1012c6f7c1a3SJoseph Chen sel = CCLK_SRC_SDMMC0_SEL_CLK_CPLL_MUX; 1013c6f7c1a3SJoseph Chen } else { 1014c6f7c1a3SJoseph Chen div = DIV_ROUND_UP(priv->gpll_hz, rate); 1015c6f7c1a3SJoseph Chen sel = CCLK_SRC_SDMMC0_SEL_CLK_GPLL_MUX; 1016c6f7c1a3SJoseph Chen } 1017c6f7c1a3SJoseph Chen 1018c6f7c1a3SJoseph Chen assert(div - 1 <= 31); 1019c6f7c1a3SJoseph Chen rk_clrsetreg(&cru->clksel_con[85], 1020c6f7c1a3SJoseph Chen CRU_CLKSEL_CON85_CCLK_SRC_SDMMC0_SEL_MASK | 1021c6f7c1a3SJoseph Chen CRU_CLKSEL_CON85_CCLK_SRC_SDMMC0_DIV_MASK, 1022c6f7c1a3SJoseph Chen sel << CRU_CLKSEL_CON85_CCLK_SRC_SDMMC0_SEL_SHIFT | 1023c6f7c1a3SJoseph Chen (div - 1) << CRU_CLKSEL_CON85_CCLK_SRC_SDMMC0_DIV_SHIFT); 1024c6f7c1a3SJoseph Chen 1025c6f7c1a3SJoseph Chen return rk3528_sdmmc_get_clk(priv, clk_id); 1026c6f7c1a3SJoseph Chen } 1027c6f7c1a3SJoseph Chen 1028c6f7c1a3SJoseph Chen static ulong rk3528_sfc_get_clk(struct rk3528_clk_priv *priv) 1029c6f7c1a3SJoseph Chen { 1030c6f7c1a3SJoseph Chen struct rk3528_cru *cru = priv->cru; 1031c6f7c1a3SJoseph Chen u32 div, sel, con, parent; 1032c6f7c1a3SJoseph Chen 1033c6f7c1a3SJoseph Chen con = readl(&cru->clksel_con[61]); 1034c6f7c1a3SJoseph Chen div = (con & CRU_CLKSEL_CON61_SCLK_SFC_DIV_MASK) >> 1035c6f7c1a3SJoseph Chen CRU_CLKSEL_CON61_SCLK_SFC_DIV_SHIFT; 1036c6f7c1a3SJoseph Chen sel = (con & CRU_CLKSEL_CON61_SCLK_SFC_SEL_MASK) >> 1037c6f7c1a3SJoseph Chen CRU_CLKSEL_CON61_SCLK_SFC_SEL_SHIFT; 1038c6f7c1a3SJoseph Chen if (sel == SCLK_SFC_SEL_CLK_GPLL_MUX) 1039c6f7c1a3SJoseph Chen parent = priv->gpll_hz; 1040c6f7c1a3SJoseph Chen else if (sel == SCLK_SFC_SEL_CLK_CPLL_MUX) 1041c6f7c1a3SJoseph Chen parent = priv->cpll_hz; 1042c6f7c1a3SJoseph Chen else 1043c6f7c1a3SJoseph Chen parent = OSC_HZ; 1044c6f7c1a3SJoseph Chen 1045c6f7c1a3SJoseph Chen return DIV_TO_RATE(parent, div); 1046c6f7c1a3SJoseph Chen } 1047c6f7c1a3SJoseph Chen 1048c6f7c1a3SJoseph Chen static ulong rk3528_sfc_set_clk(struct rk3528_clk_priv *priv, ulong rate) 1049c6f7c1a3SJoseph Chen { 1050c6f7c1a3SJoseph Chen struct rk3528_cru *cru = priv->cru; 1051c6f7c1a3SJoseph Chen int div, sel; 1052c6f7c1a3SJoseph Chen 1053c6f7c1a3SJoseph Chen if (OSC_HZ % rate == 0) { 1054c6f7c1a3SJoseph Chen div = DIV_ROUND_UP(OSC_HZ, rate); 1055c6f7c1a3SJoseph Chen sel = SCLK_SFC_SEL_XIN_OSC0_FUNC; 1056c6f7c1a3SJoseph Chen } else if ((priv->cpll_hz % rate) == 0) { 1057c6f7c1a3SJoseph Chen div = DIV_ROUND_UP(priv->cpll_hz, rate); 1058c6f7c1a3SJoseph Chen sel = SCLK_SFC_SEL_CLK_CPLL_MUX; 1059c6f7c1a3SJoseph Chen } else { 1060c6f7c1a3SJoseph Chen div = DIV_ROUND_UP(priv->gpll_hz, rate); 1061c6f7c1a3SJoseph Chen sel = SCLK_SFC_SEL_CLK_GPLL_MUX; 1062c6f7c1a3SJoseph Chen } 1063c6f7c1a3SJoseph Chen 1064c6f7c1a3SJoseph Chen assert(div - 1 <= 63); 1065c6f7c1a3SJoseph Chen rk_clrsetreg(&cru->clksel_con[61], 1066c6f7c1a3SJoseph Chen CRU_CLKSEL_CON61_SCLK_SFC_SEL_MASK | 1067c6f7c1a3SJoseph Chen CRU_CLKSEL_CON61_SCLK_SFC_DIV_MASK, 1068c6f7c1a3SJoseph Chen sel << CRU_CLKSEL_CON61_SCLK_SFC_SEL_SHIFT | 1069c6f7c1a3SJoseph Chen (div - 1) << CRU_CLKSEL_CON61_SCLK_SFC_DIV_SHIFT); 1070c6f7c1a3SJoseph Chen 1071c6f7c1a3SJoseph Chen return rk3528_sfc_get_clk(priv); 1072c6f7c1a3SJoseph Chen } 1073c6f7c1a3SJoseph Chen 1074c6f7c1a3SJoseph Chen static ulong rk3528_emmc_get_clk(struct rk3528_clk_priv *priv) 1075c6f7c1a3SJoseph Chen { 1076c6f7c1a3SJoseph Chen struct rk3528_cru *cru = priv->cru; 1077c6f7c1a3SJoseph Chen u32 div, sel, con, parent; 1078c6f7c1a3SJoseph Chen 1079c6f7c1a3SJoseph Chen con = readl(&cru->clksel_con[62]); 1080c6f7c1a3SJoseph Chen div = (con & CRU_CLKSEL_CON62_CCLK_SRC_EMMC_DIV_MASK) >> 1081c6f7c1a3SJoseph Chen CRU_CLKSEL_CON62_CCLK_SRC_EMMC_DIV_SHIFT; 1082c6f7c1a3SJoseph Chen sel = (con & CRU_CLKSEL_CON62_CCLK_SRC_EMMC_SEL_MASK) >> 1083c6f7c1a3SJoseph Chen CRU_CLKSEL_CON62_CCLK_SRC_EMMC_SEL_SHIFT; 1084c6f7c1a3SJoseph Chen 1085c6f7c1a3SJoseph Chen if (sel == CCLK_SRC_EMMC_SEL_CLK_GPLL_MUX) 1086c6f7c1a3SJoseph Chen parent = priv->gpll_hz; 1087c6f7c1a3SJoseph Chen else if (sel == CCLK_SRC_EMMC_SEL_CLK_CPLL_MUX) 1088c6f7c1a3SJoseph Chen parent = priv->cpll_hz; 1089c6f7c1a3SJoseph Chen else 1090c6f7c1a3SJoseph Chen parent = OSC_HZ; 1091c6f7c1a3SJoseph Chen 1092c6f7c1a3SJoseph Chen return DIV_TO_RATE(parent, div); 1093c6f7c1a3SJoseph Chen } 1094c6f7c1a3SJoseph Chen 1095c6f7c1a3SJoseph Chen static ulong rk3528_emmc_set_clk(struct rk3528_clk_priv *priv, ulong rate) 1096c6f7c1a3SJoseph Chen { 1097c6f7c1a3SJoseph Chen struct rk3528_cru *cru = priv->cru; 1098c6f7c1a3SJoseph Chen u32 div, sel; 1099c6f7c1a3SJoseph Chen 1100c6f7c1a3SJoseph Chen if (OSC_HZ % rate == 0) { 1101c6f7c1a3SJoseph Chen div = DIV_ROUND_UP(OSC_HZ, rate); 1102c6f7c1a3SJoseph Chen sel = CCLK_SRC_EMMC_SEL_XIN_OSC0_FUNC; 1103c6f7c1a3SJoseph Chen } else if ((priv->cpll_hz % rate) == 0) { 1104c6f7c1a3SJoseph Chen div = DIV_ROUND_UP(priv->cpll_hz, rate); 1105c6f7c1a3SJoseph Chen sel = CCLK_SRC_EMMC_SEL_CLK_CPLL_MUX; 1106c6f7c1a3SJoseph Chen } else { 1107c6f7c1a3SJoseph Chen div = DIV_ROUND_UP(priv->gpll_hz, rate); 1108c6f7c1a3SJoseph Chen sel = CCLK_SRC_EMMC_SEL_CLK_GPLL_MUX; 1109c6f7c1a3SJoseph Chen } 1110c6f7c1a3SJoseph Chen 1111c6f7c1a3SJoseph Chen assert(div - 1 <= 31); 1112c6f7c1a3SJoseph Chen rk_clrsetreg(&cru->clksel_con[62], 1113c6f7c1a3SJoseph Chen CRU_CLKSEL_CON62_CCLK_SRC_EMMC_SEL_MASK | 1114c6f7c1a3SJoseph Chen CRU_CLKSEL_CON62_CCLK_SRC_EMMC_DIV_MASK, 1115c6f7c1a3SJoseph Chen sel << CRU_CLKSEL_CON62_CCLK_SRC_EMMC_SEL_SHIFT | 1116c6f7c1a3SJoseph Chen (div - 1) << CRU_CLKSEL_CON62_CCLK_SRC_EMMC_DIV_SHIFT); 1117c6f7c1a3SJoseph Chen 1118c6f7c1a3SJoseph Chen return rk3528_emmc_get_clk(priv); 1119c6f7c1a3SJoseph Chen } 1120c6f7c1a3SJoseph Chen 1121c6f7c1a3SJoseph Chen static ulong rk3528_dclk_vop_get_clk(struct rk3528_clk_priv *priv, ulong clk_id) 1122c6f7c1a3SJoseph Chen { 1123c6f7c1a3SJoseph Chen struct rk3528_cru *cru = priv->cru; 1124c6f7c1a3SJoseph Chen u32 div_mask, div_shift; 1125c6f7c1a3SJoseph Chen u32 sel_mask, sel_shift; 1126c6f7c1a3SJoseph Chen u32 id, con, sel, div; 1127c6f7c1a3SJoseph Chen ulong prate; 1128c6f7c1a3SJoseph Chen 1129c6f7c1a3SJoseph Chen switch (clk_id) { 1130c6f7c1a3SJoseph Chen case DCLK_VOP0: 1131c6f7c1a3SJoseph Chen id = 32; 1132c6f7c1a3SJoseph Chen sel_mask = CRU_CLKSEL_CON32_DCLK_VOP_SRC0_SEL_MASK; 1133c6f7c1a3SJoseph Chen sel_shift = CRU_CLKSEL_CON32_DCLK_VOP_SRC0_SEL_SHIFT; 1134c6f7c1a3SJoseph Chen /* FIXME if need src: clk_hdmiphy_pixel_io */ 1135c6f7c1a3SJoseph Chen div_mask = CRU_CLKSEL_CON32_DCLK_VOP_SRC0_DIV_MASK; 1136c6f7c1a3SJoseph Chen div_shift = CRU_CLKSEL_CON32_DCLK_VOP_SRC0_DIV_SHIFT; 1137c6f7c1a3SJoseph Chen break; 1138c6f7c1a3SJoseph Chen 1139c6f7c1a3SJoseph Chen case DCLK_VOP1: 1140c6f7c1a3SJoseph Chen id = 33; 1141c6f7c1a3SJoseph Chen sel_mask = CRU_CLKSEL_CON33_DCLK_VOP_SRC1_SEL_MASK; 1142c6f7c1a3SJoseph Chen sel_shift = CRU_CLKSEL_CON33_DCLK_VOP_SRC1_SEL_SHIFT; 1143c6f7c1a3SJoseph Chen div_mask = CRU_CLKSEL_CON33_DCLK_VOP_SRC1_DIV_MASK; 1144c6f7c1a3SJoseph Chen div_shift = CRU_CLKSEL_CON33_DCLK_VOP_SRC1_DIV_SHIFT; 1145c6f7c1a3SJoseph Chen break; 1146c6f7c1a3SJoseph Chen 1147c6f7c1a3SJoseph Chen default: 1148c6f7c1a3SJoseph Chen return -ENOENT; 1149c6f7c1a3SJoseph Chen } 1150c6f7c1a3SJoseph Chen 1151c6f7c1a3SJoseph Chen con = readl(&cru->clksel_con[id]); 1152c6f7c1a3SJoseph Chen div = (con & div_mask) >> div_shift; 1153c6f7c1a3SJoseph Chen sel = (con & sel_mask) >> sel_shift; 1154c6f7c1a3SJoseph Chen if (sel == DCLK_VOP_SRC_SEL_CLK_GPLL_MUX) 1155c6f7c1a3SJoseph Chen prate = priv->gpll_hz; 1156c6f7c1a3SJoseph Chen else 1157c6f7c1a3SJoseph Chen prate = priv->cpll_hz; 1158c6f7c1a3SJoseph Chen 1159c6f7c1a3SJoseph Chen return DIV_TO_RATE(prate, div); 1160c6f7c1a3SJoseph Chen } 1161c6f7c1a3SJoseph Chen 1162c6f7c1a3SJoseph Chen static ulong rk3528_dclk_vop_set_clk(struct rk3528_clk_priv *priv, 1163c6f7c1a3SJoseph Chen ulong clk_id, ulong rate) 1164c6f7c1a3SJoseph Chen { 1165c6f7c1a3SJoseph Chen struct rk3528_cru *cru = priv->cru; 1166c6f7c1a3SJoseph Chen u32 div_mask, div_shift; 1167c6f7c1a3SJoseph Chen u32 sel_mask, sel_shift; 1168c6f7c1a3SJoseph Chen u32 id, sel, div; 1169c6f7c1a3SJoseph Chen ulong prate; 1170c6f7c1a3SJoseph Chen 1171c6f7c1a3SJoseph Chen switch (clk_id) { 1172c6f7c1a3SJoseph Chen case DCLK_VOP0: 1173c6f7c1a3SJoseph Chen id = 32; 1174c6f7c1a3SJoseph Chen sel_mask = CRU_CLKSEL_CON32_DCLK_VOP_SRC0_SEL_MASK; 1175c6f7c1a3SJoseph Chen sel_shift = CRU_CLKSEL_CON32_DCLK_VOP_SRC0_SEL_SHIFT; 1176c6f7c1a3SJoseph Chen /* FIXME if need src: clk_hdmiphy_pixel_io */ 1177c6f7c1a3SJoseph Chen div_mask = CRU_CLKSEL_CON32_DCLK_VOP_SRC0_DIV_MASK; 1178c6f7c1a3SJoseph Chen div_shift = CRU_CLKSEL_CON32_DCLK_VOP_SRC0_DIV_SHIFT; 1179c6f7c1a3SJoseph Chen break; 1180c6f7c1a3SJoseph Chen 1181c6f7c1a3SJoseph Chen case DCLK_VOP1: 1182c6f7c1a3SJoseph Chen id = 33; 1183c6f7c1a3SJoseph Chen sel_mask = CRU_CLKSEL_CON33_DCLK_VOP_SRC1_SEL_MASK; 1184c6f7c1a3SJoseph Chen sel_shift = CRU_CLKSEL_CON33_DCLK_VOP_SRC1_SEL_SHIFT; 1185c6f7c1a3SJoseph Chen div_mask = CRU_CLKSEL_CON33_DCLK_VOP_SRC1_DIV_MASK; 1186c6f7c1a3SJoseph Chen div_shift = CRU_CLKSEL_CON33_DCLK_VOP_SRC1_DIV_SHIFT; 1187c6f7c1a3SJoseph Chen break; 1188c6f7c1a3SJoseph Chen 1189c6f7c1a3SJoseph Chen default: 1190c6f7c1a3SJoseph Chen return -ENOENT; 1191c6f7c1a3SJoseph Chen } 1192c6f7c1a3SJoseph Chen 1193c6f7c1a3SJoseph Chen if ((priv->gpll_hz % rate) == 0) { 1194c6f7c1a3SJoseph Chen prate = priv->gpll_hz; 1195*9d012e64SJoseph Chen sel = (DCLK_VOP_SRC_SEL_CLK_GPLL_MUX << sel_shift) & sel_mask; 1196c6f7c1a3SJoseph Chen } else { 1197c6f7c1a3SJoseph Chen prate = priv->cpll_hz; 1198*9d012e64SJoseph Chen sel = (DCLK_VOP_SRC_SEL_CLK_CPLL_MUX << sel_shift) & sel_mask; 1199c6f7c1a3SJoseph Chen } 1200c6f7c1a3SJoseph Chen 1201*9d012e64SJoseph Chen div = ((DIV_ROUND_UP(prate, rate) - 1) << div_shift) & div_mask; 1202c6f7c1a3SJoseph Chen rk_clrsetreg(&cru->clksel_con[id], sel, div); 1203c6f7c1a3SJoseph Chen 1204c6f7c1a3SJoseph Chen return rk3528_dclk_vop_get_clk(priv, clk_id); 1205c6f7c1a3SJoseph Chen } 1206c6f7c1a3SJoseph Chen 1207c6f7c1a3SJoseph Chen static ulong rk3528_uart_get_rate(struct rk3528_clk_priv *priv, ulong clk_id) 1208c6f7c1a3SJoseph Chen { 1209c6f7c1a3SJoseph Chen struct rk3528_cru *cru = priv->cru; 1210c6f7c1a3SJoseph Chen u32 sel_shift, sel_mask, div_shift, div_mask; 1211c6f7c1a3SJoseph Chen u32 sel, id, con, frac_div, div; 1212c6f7c1a3SJoseph Chen ulong m, n, rate; 1213c6f7c1a3SJoseph Chen 1214c6f7c1a3SJoseph Chen switch (clk_id) { 1215c6f7c1a3SJoseph Chen case SCLK_UART0: 1216c6f7c1a3SJoseph Chen id = 6; 1217c6f7c1a3SJoseph Chen sel_shift = CRU_CLKSEL_CON06_SCLK_UART0_SRC_SEL_SHIFT; 1218c6f7c1a3SJoseph Chen sel_mask = CRU_CLKSEL_CON06_SCLK_UART0_SRC_SEL_MASK; 1219c6f7c1a3SJoseph Chen div_shift = CRU_CLKSEL_CON04_CLK_UART0_SRC_DIV_SHIFT; 1220c6f7c1a3SJoseph Chen div_mask = CRU_CLKSEL_CON04_CLK_UART0_SRC_DIV_MASK; 1221c6f7c1a3SJoseph Chen break; 1222c6f7c1a3SJoseph Chen 1223c6f7c1a3SJoseph Chen case SCLK_UART1: 1224c6f7c1a3SJoseph Chen id = 8; 1225c6f7c1a3SJoseph Chen sel_shift = CRU_CLKSEL_CON08_SCLK_UART1_SRC_SEL_SHIFT; 1226c6f7c1a3SJoseph Chen sel_mask = CRU_CLKSEL_CON08_SCLK_UART1_SRC_SEL_MASK; 1227c6f7c1a3SJoseph Chen div_shift = CRU_CLKSEL_CON06_CLK_UART1_SRC_DIV_SHIFT; 1228c6f7c1a3SJoseph Chen div_mask = CRU_CLKSEL_CON06_CLK_UART1_SRC_DIV_MASK; 1229c6f7c1a3SJoseph Chen break; 1230c6f7c1a3SJoseph Chen 1231c6f7c1a3SJoseph Chen case SCLK_UART2: 1232c6f7c1a3SJoseph Chen id = 10; 1233c6f7c1a3SJoseph Chen sel_shift = CRU_CLKSEL_CON10_SCLK_UART2_SRC_SEL_SHIFT; 1234c6f7c1a3SJoseph Chen sel_mask = CRU_CLKSEL_CON10_SCLK_UART2_SRC_SEL_MASK; 1235c6f7c1a3SJoseph Chen div_shift = CRU_CLKSEL_CON08_CLK_UART2_SRC_DIV_SHIFT; 1236c6f7c1a3SJoseph Chen div_mask = CRU_CLKSEL_CON08_CLK_UART2_SRC_DIV_MASK; 1237c6f7c1a3SJoseph Chen break; 1238c6f7c1a3SJoseph Chen 1239c6f7c1a3SJoseph Chen case SCLK_UART3: 1240c6f7c1a3SJoseph Chen id = 12; 1241c6f7c1a3SJoseph Chen sel_shift = CRU_CLKSEL_CON12_SCLK_UART3_SRC_SEL_SHIFT; 1242c6f7c1a3SJoseph Chen sel_mask = CRU_CLKSEL_CON12_SCLK_UART3_SRC_SEL_MASK; 1243c6f7c1a3SJoseph Chen div_shift = CRU_CLKSEL_CON10_CLK_UART3_SRC_DIV_SHIFT; 1244c6f7c1a3SJoseph Chen div_mask = CRU_CLKSEL_CON10_CLK_UART3_SRC_DIV_MASK; 1245c6f7c1a3SJoseph Chen break; 1246c6f7c1a3SJoseph Chen 1247c6f7c1a3SJoseph Chen case SCLK_UART4: 1248c6f7c1a3SJoseph Chen id = 14; 1249c6f7c1a3SJoseph Chen sel_shift = CRU_CLKSEL_CON14_SCLK_UART4_SRC_SEL_SHIFT; 1250c6f7c1a3SJoseph Chen sel_mask = CRU_CLKSEL_CON14_SCLK_UART4_SRC_SEL_MASK; 1251c6f7c1a3SJoseph Chen div_shift = CRU_CLKSEL_CON12_CLK_UART4_SRC_DIV_SHIFT; 1252c6f7c1a3SJoseph Chen div_mask = CRU_CLKSEL_CON12_CLK_UART4_SRC_DIV_MASK; 1253c6f7c1a3SJoseph Chen break; 1254c6f7c1a3SJoseph Chen 1255c6f7c1a3SJoseph Chen case SCLK_UART5: 1256c6f7c1a3SJoseph Chen id = 16; 1257c6f7c1a3SJoseph Chen sel_shift = CRU_CLKSEL_CON16_SCLK_UART5_SRC_SEL_SHIFT; 1258c6f7c1a3SJoseph Chen sel_mask = CRU_CLKSEL_CON16_SCLK_UART5_SRC_SEL_MASK; 1259c6f7c1a3SJoseph Chen div_shift = CRU_CLKSEL_CON14_CLK_UART5_SRC_DIV_SHIFT; 1260c6f7c1a3SJoseph Chen div_mask = CRU_CLKSEL_CON14_CLK_UART5_SRC_DIV_MASK; 1261c6f7c1a3SJoseph Chen break; 1262c6f7c1a3SJoseph Chen 1263c6f7c1a3SJoseph Chen case SCLK_UART6: 1264c6f7c1a3SJoseph Chen id = 18; 1265c6f7c1a3SJoseph Chen sel_shift = CRU_CLKSEL_CON18_SCLK_UART6_SRC_SEL_SHIFT; 1266c6f7c1a3SJoseph Chen sel_mask = CRU_CLKSEL_CON18_SCLK_UART6_SRC_SEL_MASK; 1267c6f7c1a3SJoseph Chen div_shift = CRU_CLKSEL_CON16_CLK_UART6_SRC_DIV_SHIFT; 1268c6f7c1a3SJoseph Chen div_mask = CRU_CLKSEL_CON16_CLK_UART6_SRC_DIV_MASK; 1269c6f7c1a3SJoseph Chen break; 1270c6f7c1a3SJoseph Chen 1271c6f7c1a3SJoseph Chen case SCLK_UART7: 1272c6f7c1a3SJoseph Chen id = 20; 1273c6f7c1a3SJoseph Chen sel_shift = CRU_CLKSEL_CON20_SCLK_UART7_SRC_SEL_SHIFT; 1274c6f7c1a3SJoseph Chen sel_mask = CRU_CLKSEL_CON20_SCLK_UART7_SRC_SEL_MASK; 1275c6f7c1a3SJoseph Chen div_shift = CRU_CLKSEL_CON18_CLK_UART7_SRC_DIV_SHIFT; 1276c6f7c1a3SJoseph Chen div_mask = CRU_CLKSEL_CON18_CLK_UART7_SRC_DIV_MASK; 1277c6f7c1a3SJoseph Chen break; 1278c6f7c1a3SJoseph Chen 1279c6f7c1a3SJoseph Chen default: 1280c6f7c1a3SJoseph Chen return -ENOENT; 1281c6f7c1a3SJoseph Chen } 1282c6f7c1a3SJoseph Chen 1283c6f7c1a3SJoseph Chen con = readl(&cru->clksel_con[id - 2]); 1284c6f7c1a3SJoseph Chen div = (con & div_mask) >> div_shift; 1285c6f7c1a3SJoseph Chen 1286c6f7c1a3SJoseph Chen con = readl(&cru->clksel_con[id]); 1287c6f7c1a3SJoseph Chen sel = (con & sel_mask) >> sel_shift; 1288c6f7c1a3SJoseph Chen 1289c6f7c1a3SJoseph Chen if (sel == SCLK_UART0_SRC_SEL_CLK_UART0_SRC) { 1290c6f7c1a3SJoseph Chen rate = DIV_TO_RATE(priv->gpll_hz, div); 1291c6f7c1a3SJoseph Chen } else if (sel == SCLK_UART0_SRC_SEL_CLK_UART0_FRAC) { 1292c6f7c1a3SJoseph Chen frac_div = readl(&cru->clksel_con[id - 1]); 1293c6f7c1a3SJoseph Chen n = (frac_div & 0xffff0000) >> 16; 1294c6f7c1a3SJoseph Chen m = frac_div & 0x0000ffff; 1295c6f7c1a3SJoseph Chen rate = DIV_TO_RATE(priv->gpll_hz, div) * n / m; 1296c6f7c1a3SJoseph Chen } else { 1297c6f7c1a3SJoseph Chen rate = OSC_HZ; 1298c6f7c1a3SJoseph Chen } 1299c6f7c1a3SJoseph Chen 1300c6f7c1a3SJoseph Chen return rate; 1301c6f7c1a3SJoseph Chen } 1302c6f7c1a3SJoseph Chen 1303c6f7c1a3SJoseph Chen static ulong rk3528_uart_set_rate(struct rk3528_clk_priv *priv, 1304c6f7c1a3SJoseph Chen ulong clk_id, ulong rate) 1305c6f7c1a3SJoseph Chen { 1306c6f7c1a3SJoseph Chen struct rk3528_cru *cru = priv->cru; 1307c6f7c1a3SJoseph Chen u32 sel_shift, sel_mask, div_shift, div_mask; 1308c6f7c1a3SJoseph Chen u32 sel, id, div; 1309c6f7c1a3SJoseph Chen ulong m = 0, n = 0, val; 1310c6f7c1a3SJoseph Chen 1311c6f7c1a3SJoseph Chen if (rate == OSC_HZ) { 1312c6f7c1a3SJoseph Chen sel = SCLK_UART0_SRC_SEL_XIN_OSC0_FUNC; 1313c6f7c1a3SJoseph Chen div = DIV_ROUND_UP(OSC_HZ, rate); 1314c6f7c1a3SJoseph Chen } else if (priv->gpll_hz % rate == 0) { 1315c6f7c1a3SJoseph Chen sel = SCLK_UART0_SRC_SEL_CLK_UART0_SRC; 1316c6f7c1a3SJoseph Chen div = DIV_ROUND_UP(priv->gpll_hz, rate); 1317c6f7c1a3SJoseph Chen } else { 1318c6f7c1a3SJoseph Chen sel = SCLK_UART0_SRC_SEL_CLK_UART0_FRAC; 1319c6f7c1a3SJoseph Chen div = 2; 1320c6f7c1a3SJoseph Chen rational_best_approximation(rate, priv->gpll_hz / div, 1321c6f7c1a3SJoseph Chen GENMASK(16 - 1, 0), 1322c6f7c1a3SJoseph Chen GENMASK(16 - 1, 0), 1323c6f7c1a3SJoseph Chen &n, &m); 1324c6f7c1a3SJoseph Chen } 1325c6f7c1a3SJoseph Chen 1326c6f7c1a3SJoseph Chen switch (clk_id) { 1327c6f7c1a3SJoseph Chen case SCLK_UART0: 1328c6f7c1a3SJoseph Chen id = 6; 1329c6f7c1a3SJoseph Chen sel_shift = CRU_CLKSEL_CON06_SCLK_UART0_SRC_SEL_SHIFT; 1330c6f7c1a3SJoseph Chen sel_mask = CRU_CLKSEL_CON06_SCLK_UART0_SRC_SEL_MASK; 1331c6f7c1a3SJoseph Chen div_shift = CRU_CLKSEL_CON04_CLK_UART0_SRC_DIV_SHIFT; 1332c6f7c1a3SJoseph Chen div_mask = CRU_CLKSEL_CON04_CLK_UART0_SRC_DIV_MASK; 1333c6f7c1a3SJoseph Chen break; 1334c6f7c1a3SJoseph Chen 1335c6f7c1a3SJoseph Chen case SCLK_UART1: 1336c6f7c1a3SJoseph Chen id = 8; 1337c6f7c1a3SJoseph Chen sel_shift = CRU_CLKSEL_CON08_SCLK_UART1_SRC_SEL_SHIFT; 1338c6f7c1a3SJoseph Chen sel_mask = CRU_CLKSEL_CON08_SCLK_UART1_SRC_SEL_MASK; 1339c6f7c1a3SJoseph Chen div_shift = CRU_CLKSEL_CON06_CLK_UART1_SRC_DIV_SHIFT; 1340c6f7c1a3SJoseph Chen div_mask = CRU_CLKSEL_CON06_CLK_UART1_SRC_DIV_MASK; 1341c6f7c1a3SJoseph Chen break; 1342c6f7c1a3SJoseph Chen 1343c6f7c1a3SJoseph Chen case SCLK_UART2: 1344c6f7c1a3SJoseph Chen id = 10; 1345c6f7c1a3SJoseph Chen sel_shift = CRU_CLKSEL_CON10_SCLK_UART2_SRC_SEL_SHIFT; 1346c6f7c1a3SJoseph Chen sel_mask = CRU_CLKSEL_CON10_SCLK_UART2_SRC_SEL_MASK; 1347c6f7c1a3SJoseph Chen div_shift = CRU_CLKSEL_CON08_CLK_UART2_SRC_DIV_SHIFT; 1348c6f7c1a3SJoseph Chen div_mask = CRU_CLKSEL_CON08_CLK_UART2_SRC_DIV_MASK; 1349c6f7c1a3SJoseph Chen break; 1350c6f7c1a3SJoseph Chen 1351c6f7c1a3SJoseph Chen case SCLK_UART3: 1352c6f7c1a3SJoseph Chen id = 12; 1353c6f7c1a3SJoseph Chen sel_shift = CRU_CLKSEL_CON12_SCLK_UART3_SRC_SEL_SHIFT; 1354c6f7c1a3SJoseph Chen sel_mask = CRU_CLKSEL_CON12_SCLK_UART3_SRC_SEL_MASK; 1355c6f7c1a3SJoseph Chen div_shift = CRU_CLKSEL_CON10_CLK_UART3_SRC_DIV_SHIFT; 1356c6f7c1a3SJoseph Chen div_mask = CRU_CLKSEL_CON10_CLK_UART3_SRC_DIV_MASK; 1357c6f7c1a3SJoseph Chen break; 1358c6f7c1a3SJoseph Chen 1359c6f7c1a3SJoseph Chen case SCLK_UART4: 1360c6f7c1a3SJoseph Chen id = 14; 1361c6f7c1a3SJoseph Chen sel_shift = CRU_CLKSEL_CON14_SCLK_UART4_SRC_SEL_SHIFT; 1362c6f7c1a3SJoseph Chen sel_mask = CRU_CLKSEL_CON14_SCLK_UART4_SRC_SEL_MASK; 1363c6f7c1a3SJoseph Chen div_shift = CRU_CLKSEL_CON12_CLK_UART4_SRC_DIV_SHIFT; 1364c6f7c1a3SJoseph Chen div_mask = CRU_CLKSEL_CON12_CLK_UART4_SRC_DIV_MASK; 1365c6f7c1a3SJoseph Chen break; 1366c6f7c1a3SJoseph Chen 1367c6f7c1a3SJoseph Chen case SCLK_UART5: 1368c6f7c1a3SJoseph Chen id = 16; 1369c6f7c1a3SJoseph Chen sel_shift = CRU_CLKSEL_CON16_SCLK_UART5_SRC_SEL_SHIFT; 1370c6f7c1a3SJoseph Chen sel_mask = CRU_CLKSEL_CON16_SCLK_UART5_SRC_SEL_MASK; 1371c6f7c1a3SJoseph Chen div_shift = CRU_CLKSEL_CON14_CLK_UART5_SRC_DIV_SHIFT; 1372c6f7c1a3SJoseph Chen div_mask = CRU_CLKSEL_CON14_CLK_UART5_SRC_DIV_MASK; 1373c6f7c1a3SJoseph Chen break; 1374c6f7c1a3SJoseph Chen 1375c6f7c1a3SJoseph Chen case SCLK_UART6: 1376c6f7c1a3SJoseph Chen id = 18; 1377c6f7c1a3SJoseph Chen sel_shift = CRU_CLKSEL_CON18_SCLK_UART6_SRC_SEL_SHIFT; 1378c6f7c1a3SJoseph Chen sel_mask = CRU_CLKSEL_CON18_SCLK_UART6_SRC_SEL_MASK; 1379c6f7c1a3SJoseph Chen div_shift = CRU_CLKSEL_CON16_CLK_UART6_SRC_DIV_SHIFT; 1380c6f7c1a3SJoseph Chen div_mask = CRU_CLKSEL_CON16_CLK_UART6_SRC_DIV_MASK; 1381c6f7c1a3SJoseph Chen break; 1382c6f7c1a3SJoseph Chen 1383c6f7c1a3SJoseph Chen case SCLK_UART7: 1384c6f7c1a3SJoseph Chen id = 20; 1385c6f7c1a3SJoseph Chen sel_shift = CRU_CLKSEL_CON20_SCLK_UART7_SRC_SEL_SHIFT; 1386c6f7c1a3SJoseph Chen sel_mask = CRU_CLKSEL_CON20_SCLK_UART7_SRC_SEL_MASK; 1387c6f7c1a3SJoseph Chen div_shift = CRU_CLKSEL_CON18_CLK_UART7_SRC_DIV_SHIFT; 1388c6f7c1a3SJoseph Chen div_mask = CRU_CLKSEL_CON18_CLK_UART7_SRC_DIV_MASK; 1389c6f7c1a3SJoseph Chen break; 1390c6f7c1a3SJoseph Chen 1391c6f7c1a3SJoseph Chen default: 1392c6f7c1a3SJoseph Chen return -ENOENT; 1393c6f7c1a3SJoseph Chen } 1394c6f7c1a3SJoseph Chen 1395c6f7c1a3SJoseph Chen rk_clrsetreg(&cru->clksel_con[id - 2], div_mask, (div - 1) << div_shift); 1396c6f7c1a3SJoseph Chen rk_clrsetreg(&cru->clksel_con[id], sel_mask, sel << sel_shift); 1397c6f7c1a3SJoseph Chen if (m && n) { 1398c6f7c1a3SJoseph Chen val = n << 16 | m; 1399c6f7c1a3SJoseph Chen writel(val, &cru->clksel_con[id - 1]); 1400c6f7c1a3SJoseph Chen } 1401c6f7c1a3SJoseph Chen 1402c6f7c1a3SJoseph Chen return rk3528_uart_get_rate(priv, clk_id); 1403c6f7c1a3SJoseph Chen } 1404c6f7c1a3SJoseph Chen 1405c6f7c1a3SJoseph Chen static ulong rk3528_clk_get_rate(struct clk *clk) 1406c6f7c1a3SJoseph Chen { 1407c6f7c1a3SJoseph Chen struct rk3528_clk_priv *priv = dev_get_priv(clk->dev); 1408c6f7c1a3SJoseph Chen ulong rate = 0; 1409c6f7c1a3SJoseph Chen 1410c6f7c1a3SJoseph Chen if (!priv->gpll_hz || !priv->cpll_hz) { 1411c6f7c1a3SJoseph Chen printf("%s: gpll=%lu, cpll=%ld\n", 1412c6f7c1a3SJoseph Chen __func__, priv->gpll_hz, priv->cpll_hz); 1413c6f7c1a3SJoseph Chen return -ENOENT; 1414c6f7c1a3SJoseph Chen } 1415c6f7c1a3SJoseph Chen 1416c6f7c1a3SJoseph Chen switch (clk->id) { 1417c6f7c1a3SJoseph Chen case PLL_APLL: 1418c6f7c1a3SJoseph Chen case ARMCLK: 1419c6f7c1a3SJoseph Chen rate = rockchip_pll_get_rate(&rk3528_pll_clks[APLL], priv->cru, 1420c6f7c1a3SJoseph Chen APLL); 1421c6f7c1a3SJoseph Chen break; 1422c6f7c1a3SJoseph Chen case PLL_CPLL: 1423c6f7c1a3SJoseph Chen rate = rockchip_pll_get_rate(&rk3528_pll_clks[CPLL], priv->cru, 1424c6f7c1a3SJoseph Chen CPLL); 1425c6f7c1a3SJoseph Chen break; 1426c6f7c1a3SJoseph Chen case PLL_GPLL: 1427c6f7c1a3SJoseph Chen rate = rockchip_pll_get_rate(&rk3528_pll_clks[GPLL], priv->cru, 1428c6f7c1a3SJoseph Chen GPLL); 1429c6f7c1a3SJoseph Chen break; 1430c6f7c1a3SJoseph Chen 1431c6f7c1a3SJoseph Chen case PLL_PPLL: 1432c6f7c1a3SJoseph Chen rate = rockchip_pll_get_rate(&rk3528_pll_clks[PPLL], priv->cru, 1433c6f7c1a3SJoseph Chen PPLL); 1434c6f7c1a3SJoseph Chen break; 1435c6f7c1a3SJoseph Chen case PLL_DPLL: 1436c6f7c1a3SJoseph Chen rate = rockchip_pll_get_rate(&rk3528_pll_clks[DPLL], priv->cru, 1437c6f7c1a3SJoseph Chen DPLL); 1438c6f7c1a3SJoseph Chen break; 1439c6f7c1a3SJoseph Chen 1440c6f7c1a3SJoseph Chen case TCLK_WDT_NS: 1441c6f7c1a3SJoseph Chen rate = OSC_HZ; 1442c6f7c1a3SJoseph Chen break; 1443c6f7c1a3SJoseph Chen case CLK_I2C0: 1444c6f7c1a3SJoseph Chen case CLK_I2C1: 1445c6f7c1a3SJoseph Chen case CLK_I2C2: 1446c6f7c1a3SJoseph Chen case CLK_I2C3: 1447c6f7c1a3SJoseph Chen case CLK_I2C4: 1448c6f7c1a3SJoseph Chen case CLK_I2C5: 1449c6f7c1a3SJoseph Chen case CLK_I2C6: 1450c6f7c1a3SJoseph Chen case CLK_I2C7: 1451c6f7c1a3SJoseph Chen rate = rk3528_i2c_get_clk(priv, clk->id); 1452c6f7c1a3SJoseph Chen break; 1453c6f7c1a3SJoseph Chen case CLK_SPI0: 1454c6f7c1a3SJoseph Chen case CLK_SPI1: 1455c6f7c1a3SJoseph Chen rate = rk3528_spi_get_clk(priv, clk->id); 1456c6f7c1a3SJoseph Chen break; 1457c6f7c1a3SJoseph Chen case CLK_PWM0: 1458c6f7c1a3SJoseph Chen case CLK_PWM1: 1459c6f7c1a3SJoseph Chen rate = rk3528_pwm_get_clk(priv, clk->id); 1460c6f7c1a3SJoseph Chen break; 1461c6f7c1a3SJoseph Chen case CLK_SARADC: 1462c6f7c1a3SJoseph Chen case CLK_TSADC: 1463c6f7c1a3SJoseph Chen case CLK_TSADC_TSEN: 1464c6f7c1a3SJoseph Chen rate = rk3528_adc_get_clk(priv, clk->id); 1465c6f7c1a3SJoseph Chen break; 1466c6f7c1a3SJoseph Chen case CCLK_SRC_EMMC: 1467c6f7c1a3SJoseph Chen rate = rk3528_emmc_get_clk(priv); 1468c6f7c1a3SJoseph Chen break; 1469c6f7c1a3SJoseph Chen case HCLK_SDMMC0: 1470c6f7c1a3SJoseph Chen case CCLK_SRC_SDMMC0: 1471c6f7c1a3SJoseph Chen rate = rk3528_sdmmc_get_clk(priv, clk->id); 1472c6f7c1a3SJoseph Chen break; 1473c6f7c1a3SJoseph Chen case SCLK_SFC: 1474c6f7c1a3SJoseph Chen rate = rk3528_sfc_get_clk(priv); 1475c6f7c1a3SJoseph Chen break; 1476c6f7c1a3SJoseph Chen case DCLK_VOP0: 1477c6f7c1a3SJoseph Chen case DCLK_VOP1: 1478c6f7c1a3SJoseph Chen rate = rk3528_dclk_vop_get_clk(priv, clk->id); 1479c6f7c1a3SJoseph Chen break; 1480c6f7c1a3SJoseph Chen case DCLK_CVBS: 1481c6f7c1a3SJoseph Chen rate = rk3528_dclk_vop_get_clk(priv, DCLK_VOP1) / 4; 1482c6f7c1a3SJoseph Chen break; 1483c6f7c1a3SJoseph Chen case DCLK_4X_CVBS: 1484c6f7c1a3SJoseph Chen rate = rk3528_dclk_vop_get_clk(priv, DCLK_VOP1); 1485c6f7c1a3SJoseph Chen break; 1486c6f7c1a3SJoseph Chen case SCLK_UART0: 1487c6f7c1a3SJoseph Chen case SCLK_UART1: 1488c6f7c1a3SJoseph Chen case SCLK_UART2: 1489c6f7c1a3SJoseph Chen case SCLK_UART3: 1490c6f7c1a3SJoseph Chen case SCLK_UART4: 1491c6f7c1a3SJoseph Chen case SCLK_UART5: 1492c6f7c1a3SJoseph Chen case SCLK_UART6: 1493c6f7c1a3SJoseph Chen case SCLK_UART7: 1494c6f7c1a3SJoseph Chen rate = rk3528_uart_get_rate(priv, clk->id); 1495c6f7c1a3SJoseph Chen break; 1496c6f7c1a3SJoseph Chen case CLK_CORE_CRYPTO: 1497c6f7c1a3SJoseph Chen case CLK_PKA_CRYPTO: 1498c6f7c1a3SJoseph Chen rate = rk3528_crypto_get_rate(priv, clk->id); 1499c6f7c1a3SJoseph Chen break; 1500c6f7c1a3SJoseph Chen case CLK_MATRIX_50M_SRC: 1501c6f7c1a3SJoseph Chen case CLK_MATRIX_100M_SRC: 1502c6f7c1a3SJoseph Chen case CLK_MATRIX_150M_SRC: 1503c6f7c1a3SJoseph Chen case CLK_MATRIX_200M_SRC: 1504c6f7c1a3SJoseph Chen case CLK_MATRIX_250M_SRC: 1505c6f7c1a3SJoseph Chen case CLK_MATRIX_300M_SRC: 1506c6f7c1a3SJoseph Chen case CLK_MATRIX_339M_SRC: 1507c6f7c1a3SJoseph Chen case CLK_MATRIX_400M_SRC: 1508c6f7c1a3SJoseph Chen case CLK_MATRIX_500M_SRC: 1509c6f7c1a3SJoseph Chen case CLK_MATRIX_600M_SRC: 1510c6f7c1a3SJoseph Chen case ACLK_BUS_VOPGL_BIU: 1511c6f7c1a3SJoseph Chen rate = rk3528_cgpll_matrix_get_rate(priv, clk->id); 1512c6f7c1a3SJoseph Chen break; 1513c6f7c1a3SJoseph Chen case CLK_PPLL_50M_MATRIX: 1514c6f7c1a3SJoseph Chen case CLK_PPLL_100M_MATRIX: 1515c6f7c1a3SJoseph Chen case CLK_PPLL_125M_MATRIX: 1516c6f7c1a3SJoseph Chen case CLK_GMAC1_VPU_25M: 1517c6f7c1a3SJoseph Chen case CLK_GMAC1_RMII_VPU: 1518c6f7c1a3SJoseph Chen case CLK_GMAC1_SRC_VPU: 1519c6f7c1a3SJoseph Chen rate = rk3528_ppll_matrix_get_rate(priv, clk->id); 1520c6f7c1a3SJoseph Chen break; 1521c6f7c1a3SJoseph Chen default: 1522c6f7c1a3SJoseph Chen return -ENOENT; 1523c6f7c1a3SJoseph Chen } 1524c6f7c1a3SJoseph Chen 1525c6f7c1a3SJoseph Chen return rate; 1526c6f7c1a3SJoseph Chen }; 1527c6f7c1a3SJoseph Chen 1528c6f7c1a3SJoseph Chen static ulong rk3528_clk_set_rate(struct clk *clk, ulong rate) 1529c6f7c1a3SJoseph Chen { 1530c6f7c1a3SJoseph Chen struct rk3528_clk_priv *priv = dev_get_priv(clk->dev); 1531c6f7c1a3SJoseph Chen ulong ret = 0; 1532c6f7c1a3SJoseph Chen 1533c6f7c1a3SJoseph Chen if (!priv->gpll_hz) { 1534c6f7c1a3SJoseph Chen printf("%s gpll=%lu\n", __func__, priv->gpll_hz); 1535c6f7c1a3SJoseph Chen return -ENOENT; 1536c6f7c1a3SJoseph Chen } 1537c6f7c1a3SJoseph Chen 1538c6f7c1a3SJoseph Chen switch (clk->id) { 1539c6f7c1a3SJoseph Chen case PLL_APLL: 1540c6f7c1a3SJoseph Chen case ARMCLK: 1541c6f7c1a3SJoseph Chen if (priv->armclk_hz) 1542c6f7c1a3SJoseph Chen rk3528_armclk_set_clk(priv, rate); 1543c6f7c1a3SJoseph Chen priv->armclk_hz = rate; 1544c6f7c1a3SJoseph Chen break; 1545c6f7c1a3SJoseph Chen case PLL_CPLL: 1546c6f7c1a3SJoseph Chen ret = rockchip_pll_set_rate(&rk3528_pll_clks[CPLL], priv->cru, 1547c6f7c1a3SJoseph Chen CPLL, rate); 1548c6f7c1a3SJoseph Chen priv->cpll_hz = rockchip_pll_get_rate(&rk3528_pll_clks[CPLL], 1549c6f7c1a3SJoseph Chen priv->cru, CPLL); 1550c6f7c1a3SJoseph Chen break; 1551c6f7c1a3SJoseph Chen case PLL_GPLL: 1552c6f7c1a3SJoseph Chen ret = rockchip_pll_set_rate(&rk3528_pll_clks[GPLL], priv->cru, 1553c6f7c1a3SJoseph Chen GPLL, rate); 1554c6f7c1a3SJoseph Chen priv->gpll_hz = rockchip_pll_get_rate(&rk3528_pll_clks[GPLL], 1555c6f7c1a3SJoseph Chen priv->cru, GPLL); 1556c6f7c1a3SJoseph Chen break; 1557c6f7c1a3SJoseph Chen case PLL_PPLL: 1558c6f7c1a3SJoseph Chen ret = rockchip_pll_set_rate(&rk3528_pll_clks[PPLL], priv->cru, 1559c6f7c1a3SJoseph Chen PPLL, rate); 1560c6f7c1a3SJoseph Chen priv->ppll_hz = rockchip_pll_get_rate(&rk3528_pll_clks[PPLL], 1561c6f7c1a3SJoseph Chen priv->cru, PPLL); 1562c6f7c1a3SJoseph Chen break; 1563c6f7c1a3SJoseph Chen case TCLK_WDT_NS: 1564c6f7c1a3SJoseph Chen return (rate == OSC_HZ) ? 0 : -EINVAL; 1565c6f7c1a3SJoseph Chen case CLK_I2C0: 1566c6f7c1a3SJoseph Chen case CLK_I2C1: 1567c6f7c1a3SJoseph Chen case CLK_I2C2: 1568c6f7c1a3SJoseph Chen case CLK_I2C3: 1569c6f7c1a3SJoseph Chen case CLK_I2C4: 1570c6f7c1a3SJoseph Chen case CLK_I2C5: 1571c6f7c1a3SJoseph Chen case CLK_I2C6: 1572c6f7c1a3SJoseph Chen case CLK_I2C7: 1573c6f7c1a3SJoseph Chen ret = rk3528_i2c_set_clk(priv, clk->id, rate); 1574c6f7c1a3SJoseph Chen break; 1575c6f7c1a3SJoseph Chen case CLK_SPI0: 1576c6f7c1a3SJoseph Chen case CLK_SPI1: 1577c6f7c1a3SJoseph Chen ret = rk3528_spi_set_clk(priv, clk->id, rate); 1578c6f7c1a3SJoseph Chen break; 1579c6f7c1a3SJoseph Chen case CLK_PWM0: 1580c6f7c1a3SJoseph Chen case CLK_PWM1: 1581c6f7c1a3SJoseph Chen ret = rk3528_pwm_set_clk(priv, clk->id, rate); 1582c6f7c1a3SJoseph Chen break; 1583c6f7c1a3SJoseph Chen case CLK_SARADC: 1584c6f7c1a3SJoseph Chen case CLK_TSADC: 1585c6f7c1a3SJoseph Chen case CLK_TSADC_TSEN: 1586c6f7c1a3SJoseph Chen ret = rk3528_adc_set_clk(priv, clk->id, rate); 1587c6f7c1a3SJoseph Chen break; 1588c6f7c1a3SJoseph Chen case HCLK_SDMMC0: 1589c6f7c1a3SJoseph Chen case CCLK_SRC_SDMMC0: 1590c6f7c1a3SJoseph Chen ret = rk3528_sdmmc_set_clk(priv, clk->id, rate); 1591c6f7c1a3SJoseph Chen break; 1592c6f7c1a3SJoseph Chen case SCLK_SFC: 1593c6f7c1a3SJoseph Chen ret = rk3528_sfc_set_clk(priv, rate); 1594c6f7c1a3SJoseph Chen break; 1595c6f7c1a3SJoseph Chen case CCLK_SRC_EMMC: 1596c6f7c1a3SJoseph Chen ret = rk3528_emmc_set_clk(priv, rate); 1597c6f7c1a3SJoseph Chen break; 1598c6f7c1a3SJoseph Chen case DCLK_VOP0: 1599c6f7c1a3SJoseph Chen case DCLK_VOP1: 1600c6f7c1a3SJoseph Chen ret = rk3528_dclk_vop_set_clk(priv, clk->id, rate); 1601c6f7c1a3SJoseph Chen break; 1602c6f7c1a3SJoseph Chen case SCLK_UART0: 1603c6f7c1a3SJoseph Chen case SCLK_UART1: 1604c6f7c1a3SJoseph Chen case SCLK_UART2: 1605c6f7c1a3SJoseph Chen case SCLK_UART3: 1606c6f7c1a3SJoseph Chen case SCLK_UART4: 1607c6f7c1a3SJoseph Chen case SCLK_UART5: 1608c6f7c1a3SJoseph Chen case SCLK_UART6: 1609c6f7c1a3SJoseph Chen case SCLK_UART7: 1610c6f7c1a3SJoseph Chen ret = rk3528_uart_set_rate(priv, clk->id, rate); 1611c6f7c1a3SJoseph Chen break; 1612c6f7c1a3SJoseph Chen case CLK_CORE_CRYPTO: 1613c6f7c1a3SJoseph Chen case CLK_PKA_CRYPTO: 1614c6f7c1a3SJoseph Chen ret = rk3528_crypto_set_rate(priv, clk->id, rate); 1615c6f7c1a3SJoseph Chen break; 1616c6f7c1a3SJoseph Chen case CLK_MATRIX_50M_SRC: 1617c6f7c1a3SJoseph Chen case CLK_MATRIX_100M_SRC: 1618c6f7c1a3SJoseph Chen case CLK_MATRIX_150M_SRC: 1619c6f7c1a3SJoseph Chen case CLK_MATRIX_200M_SRC: 1620c6f7c1a3SJoseph Chen case CLK_MATRIX_250M_SRC: 1621c6f7c1a3SJoseph Chen case CLK_MATRIX_300M_SRC: 1622c6f7c1a3SJoseph Chen case CLK_MATRIX_339M_SRC: 1623c6f7c1a3SJoseph Chen case CLK_MATRIX_400M_SRC: 1624c6f7c1a3SJoseph Chen case CLK_MATRIX_500M_SRC: 1625c6f7c1a3SJoseph Chen case CLK_MATRIX_600M_SRC: 1626c6f7c1a3SJoseph Chen case ACLK_BUS_VOPGL_BIU: 1627c6f7c1a3SJoseph Chen ret = rk3528_cgpll_matrix_set_rate(priv, clk->id, rate); 1628c6f7c1a3SJoseph Chen break; 1629c6f7c1a3SJoseph Chen case CLK_PPLL_50M_MATRIX: 1630c6f7c1a3SJoseph Chen case CLK_PPLL_100M_MATRIX: 1631c6f7c1a3SJoseph Chen case CLK_PPLL_125M_MATRIX: 1632c6f7c1a3SJoseph Chen case CLK_GMAC1_VPU_25M: 1633c6f7c1a3SJoseph Chen ret = rk3528_ppll_matrix_set_rate(priv, clk->id, rate); 1634c6f7c1a3SJoseph Chen break; 1635a9533156SJoseph Chen case CLK_GMAC1_RMII_VPU: 1636a9533156SJoseph Chen case CLK_GMAC1_SRC_VPU: 1637a9533156SJoseph Chen /* dummy set */ 1638a9533156SJoseph Chen ret = rk3528_ppll_matrix_get_rate(priv, clk->id); 1639a9533156SJoseph Chen break; 1640c6f7c1a3SJoseph Chen default: 1641c6f7c1a3SJoseph Chen return -ENOENT; 1642c6f7c1a3SJoseph Chen } 1643c6f7c1a3SJoseph Chen 1644c6f7c1a3SJoseph Chen return ret; 1645c6f7c1a3SJoseph Chen }; 1646c6f7c1a3SJoseph Chen 1647c6f7c1a3SJoseph Chen 1648c6f7c1a3SJoseph Chen static struct clk_ops rk3528_clk_ops = { 1649c6f7c1a3SJoseph Chen .get_rate = rk3528_clk_get_rate, 1650c6f7c1a3SJoseph Chen .set_rate = rk3528_clk_set_rate, 1651c6f7c1a3SJoseph Chen }; 1652c6f7c1a3SJoseph Chen 1653c6f7c1a3SJoseph Chen static ulong rk3528_grfclk_get_rate(struct clk *clk) 1654c6f7c1a3SJoseph Chen { 1655c6f7c1a3SJoseph Chen struct rk3528_clk_priv *priv; 1656c6f7c1a3SJoseph Chen struct udevice *cru_dev; 1657c6f7c1a3SJoseph Chen ulong rate = 0; 1658c6f7c1a3SJoseph Chen int ret; 1659c6f7c1a3SJoseph Chen 1660c6f7c1a3SJoseph Chen ret = uclass_get_device_by_driver(UCLASS_CLK, 1661c6f7c1a3SJoseph Chen DM_GET_DRIVER(rockchip_rk3528_cru), 1662c6f7c1a3SJoseph Chen &cru_dev); 1663c6f7c1a3SJoseph Chen if (ret) { 1664c6f7c1a3SJoseph Chen printf("%s: could not find cru device\n", __func__); 1665c6f7c1a3SJoseph Chen return ret; 1666c6f7c1a3SJoseph Chen } 1667c6f7c1a3SJoseph Chen priv = dev_get_priv(cru_dev); 1668c6f7c1a3SJoseph Chen 1669c6f7c1a3SJoseph Chen switch (clk->id) { 1670c6f7c1a3SJoseph Chen case SCLK_SDMMC_SAMPLE: 1671c6f7c1a3SJoseph Chen rate = rk3528_sdmmc_get_clk(priv, CCLK_SRC_SDMMC0) / 2; 1672c6f7c1a3SJoseph Chen break; 1673c6f7c1a3SJoseph Chen default: 1674c6f7c1a3SJoseph Chen return -ENOENT; 1675c6f7c1a3SJoseph Chen } 1676c6f7c1a3SJoseph Chen 1677c6f7c1a3SJoseph Chen return rate; 1678c6f7c1a3SJoseph Chen }; 1679c6f7c1a3SJoseph Chen 1680c6f7c1a3SJoseph Chen #define ROCKCHIP_MMC_DELAY_SEL BIT(11) 1681c6f7c1a3SJoseph Chen #define ROCKCHIP_MMC_DEGREE_MASK 0x3 1682c6f7c1a3SJoseph Chen #define ROCKCHIP_MMC_DELAYNUM_OFFSET 3 1683c6f7c1a3SJoseph Chen #define ROCKCHIP_MMC_DELAYNUM_MASK (0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET) 1684c6f7c1a3SJoseph Chen #define PSECS_PER_SEC 1000000000000LL 1685c6f7c1a3SJoseph Chen /* 1686c6f7c1a3SJoseph Chen * Each fine delay is between 44ps-77ps. Assume each fine delay is 60ps to 1687c6f7c1a3SJoseph Chen * simplify calculations. So 45degs could be anywhere between 33deg and 57.8deg. 1688c6f7c1a3SJoseph Chen */ 1689c6f7c1a3SJoseph Chen #define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60 1690c6f7c1a3SJoseph Chen 1691c6f7c1a3SJoseph Chen int rk3528_mmc_get_phase(struct clk *clk) 1692c6f7c1a3SJoseph Chen { 1693c6f7c1a3SJoseph Chen struct rk3528_grf_clk_priv *priv = dev_get_priv(clk->dev); 1694c6f7c1a3SJoseph Chen u32 raw_value = 0, delay_num; 1695c6f7c1a3SJoseph Chen u16 degrees = 0; 1696c6f7c1a3SJoseph Chen ulong rate; 1697c6f7c1a3SJoseph Chen 1698c6f7c1a3SJoseph Chen rate = rk3528_grfclk_get_rate(clk); 1699c6f7c1a3SJoseph Chen if (rate < 0) 1700c6f7c1a3SJoseph Chen return rate; 1701c6f7c1a3SJoseph Chen 1702c6f7c1a3SJoseph Chen if (clk->id == SCLK_SDMMC_SAMPLE) 1703c6f7c1a3SJoseph Chen raw_value = readl(&priv->grf->sdmmc_con1); 1704c6f7c1a3SJoseph Chen else 1705c6f7c1a3SJoseph Chen return -ENONET; 1706c6f7c1a3SJoseph Chen 1707c6f7c1a3SJoseph Chen raw_value >>= 1; 1708c6f7c1a3SJoseph Chen degrees = (raw_value & ROCKCHIP_MMC_DEGREE_MASK) * 90; 1709c6f7c1a3SJoseph Chen 1710c6f7c1a3SJoseph Chen if (raw_value & ROCKCHIP_MMC_DELAY_SEL) { 1711c6f7c1a3SJoseph Chen /* degrees/delaynum * 10000 */ 1712c6f7c1a3SJoseph Chen unsigned long factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) * 1713c6f7c1a3SJoseph Chen 36 * (rate / 1000000); 1714c6f7c1a3SJoseph Chen 1715c6f7c1a3SJoseph Chen delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK); 1716c6f7c1a3SJoseph Chen delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET; 1717c6f7c1a3SJoseph Chen degrees += DIV_ROUND_CLOSEST(delay_num * factor, 10000); 1718c6f7c1a3SJoseph Chen } 1719c6f7c1a3SJoseph Chen 1720c6f7c1a3SJoseph Chen return degrees % 360; 1721c6f7c1a3SJoseph Chen } 1722c6f7c1a3SJoseph Chen 1723c6f7c1a3SJoseph Chen int rk3528_mmc_set_phase(struct clk *clk, u32 degrees) 1724c6f7c1a3SJoseph Chen { 1725c6f7c1a3SJoseph Chen struct rk3528_grf_clk_priv *priv = dev_get_priv(clk->dev); 1726c6f7c1a3SJoseph Chen u8 nineties, remainder, delay_num; 1727c6f7c1a3SJoseph Chen u32 raw_value, delay; 1728c6f7c1a3SJoseph Chen ulong rate; 1729c6f7c1a3SJoseph Chen 1730c6f7c1a3SJoseph Chen rate = rk3528_grfclk_get_rate(clk); 1731c6f7c1a3SJoseph Chen if (rate < 0) 1732c6f7c1a3SJoseph Chen return rate; 1733c6f7c1a3SJoseph Chen 1734c6f7c1a3SJoseph Chen nineties = degrees / 90; 1735c6f7c1a3SJoseph Chen remainder = (degrees % 90); 1736c6f7c1a3SJoseph Chen 1737c6f7c1a3SJoseph Chen /* 1738c6f7c1a3SJoseph Chen * Convert to delay; do a little extra work to make sure we 1739c6f7c1a3SJoseph Chen * don't overflow 32-bit / 64-bit numbers. 1740c6f7c1a3SJoseph Chen */ 1741c6f7c1a3SJoseph Chen delay = 10000000; /* PSECS_PER_SEC / 10000 / 10 */ 1742c6f7c1a3SJoseph Chen delay *= remainder; 1743c6f7c1a3SJoseph Chen delay = DIV_ROUND_CLOSEST(delay, (rate / 1000) * 36 * 1744c6f7c1a3SJoseph Chen (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10)); 1745c6f7c1a3SJoseph Chen 1746c6f7c1a3SJoseph Chen delay_num = (u8)min_t(u32, delay, 255); 1747c6f7c1a3SJoseph Chen 1748c6f7c1a3SJoseph Chen raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0; 1749c6f7c1a3SJoseph Chen raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET; 1750c6f7c1a3SJoseph Chen raw_value |= nineties; 1751c6f7c1a3SJoseph Chen 1752c6f7c1a3SJoseph Chen raw_value <<= 1; 1753c6f7c1a3SJoseph Chen if (clk->id == SCLK_SDMMC_SAMPLE) 1754c6f7c1a3SJoseph Chen writel(raw_value | 0xffff0000, &priv->grf->sdmmc_con1); 1755c6f7c1a3SJoseph Chen else 1756c6f7c1a3SJoseph Chen return -ENONET; 1757c6f7c1a3SJoseph Chen 1758c6f7c1a3SJoseph Chen debug("mmc set_phase(%d) delay_nums=%u reg=%#x actual_degrees=%d\n", 1759c6f7c1a3SJoseph Chen degrees, delay_num, raw_value, rk3528_mmc_get_phase(clk)); 1760c6f7c1a3SJoseph Chen 1761c6f7c1a3SJoseph Chen return 0; 1762c6f7c1a3SJoseph Chen } 1763c6f7c1a3SJoseph Chen 1764c6f7c1a3SJoseph Chen static int rk3528_grfclk_get_phase(struct clk *clk) 1765c6f7c1a3SJoseph Chen { 1766c6f7c1a3SJoseph Chen int ret; 1767c6f7c1a3SJoseph Chen 1768c6f7c1a3SJoseph Chen debug("%s %ld\n", __func__, clk->id); 1769c6f7c1a3SJoseph Chen switch (clk->id) { 1770c6f7c1a3SJoseph Chen case SCLK_SDMMC_SAMPLE: 1771c6f7c1a3SJoseph Chen ret = rk3528_mmc_get_phase(clk); 1772c6f7c1a3SJoseph Chen break; 1773c6f7c1a3SJoseph Chen default: 1774c6f7c1a3SJoseph Chen return -ENOENT; 1775c6f7c1a3SJoseph Chen } 1776c6f7c1a3SJoseph Chen 1777c6f7c1a3SJoseph Chen return ret; 1778c6f7c1a3SJoseph Chen } 1779c6f7c1a3SJoseph Chen 1780c6f7c1a3SJoseph Chen static int rk3528_grfclk_set_phase(struct clk *clk, int degrees) 1781c6f7c1a3SJoseph Chen { 1782c6f7c1a3SJoseph Chen int ret; 1783c6f7c1a3SJoseph Chen 1784c6f7c1a3SJoseph Chen debug("%s %ld\n", __func__, clk->id); 1785c6f7c1a3SJoseph Chen switch (clk->id) { 1786c6f7c1a3SJoseph Chen case SCLK_SDMMC_SAMPLE: 1787c6f7c1a3SJoseph Chen ret = rk3528_mmc_set_phase(clk, degrees); 1788c6f7c1a3SJoseph Chen break; 1789c6f7c1a3SJoseph Chen default: 1790c6f7c1a3SJoseph Chen return -ENOENT; 1791c6f7c1a3SJoseph Chen } 1792c6f7c1a3SJoseph Chen 1793c6f7c1a3SJoseph Chen return ret; 1794c6f7c1a3SJoseph Chen } 1795c6f7c1a3SJoseph Chen 1796c6f7c1a3SJoseph Chen static struct clk_ops rk3528_grfclk_ops = { 1797c6f7c1a3SJoseph Chen .get_rate = rk3528_grfclk_get_rate, 1798c6f7c1a3SJoseph Chen .get_phase = rk3528_grfclk_get_phase, 1799c6f7c1a3SJoseph Chen .set_phase = rk3528_grfclk_set_phase, 1800c6f7c1a3SJoseph Chen }; 1801c6f7c1a3SJoseph Chen 1802c6f7c1a3SJoseph Chen #ifndef CONFIG_SPL_BUILD 1803c6f7c1a3SJoseph Chen /** 1804c6f7c1a3SJoseph Chen * soc_clk_dump() - Print clock frequencies 1805c6f7c1a3SJoseph Chen * Returns zero on success 1806c6f7c1a3SJoseph Chen * 1807c6f7c1a3SJoseph Chen * Implementation for the clk dump command. 1808c6f7c1a3SJoseph Chen */ 1809c6f7c1a3SJoseph Chen int soc_clk_dump(void) 1810c6f7c1a3SJoseph Chen { 1811c6f7c1a3SJoseph Chen const struct rk3528_clk_info *clk_dump; 1812c6f7c1a3SJoseph Chen struct rk3528_clk_priv *priv; 1813c6f7c1a3SJoseph Chen struct udevice *cru_dev; 1814c6f7c1a3SJoseph Chen struct clk clk; 1815c6f7c1a3SJoseph Chen ulong clk_count = ARRAY_SIZE(clks_dump); 1816c6f7c1a3SJoseph Chen ulong rate; 1817c6f7c1a3SJoseph Chen int i, ret; 1818c6f7c1a3SJoseph Chen 1819c6f7c1a3SJoseph Chen ret = uclass_get_device_by_driver(UCLASS_CLK, 1820c6f7c1a3SJoseph Chen DM_GET_DRIVER(rockchip_rk3528_cru), 1821c6f7c1a3SJoseph Chen &cru_dev); 1822c6f7c1a3SJoseph Chen if (ret) { 1823c6f7c1a3SJoseph Chen printf("%s failed to get cru device\n", __func__); 1824c6f7c1a3SJoseph Chen return ret; 1825c6f7c1a3SJoseph Chen } 1826c6f7c1a3SJoseph Chen 1827c6f7c1a3SJoseph Chen priv = dev_get_priv(cru_dev); 1828c6f7c1a3SJoseph Chen printf("CLK: (%s. arm: enter %lu KHz, init %lu KHz, kernel %lu%s)\n", 1829c6f7c1a3SJoseph Chen priv->sync_kernel ? "sync kernel" : "uboot", 1830c6f7c1a3SJoseph Chen priv->armclk_enter_hz / 1000, 1831c6f7c1a3SJoseph Chen priv->armclk_init_hz / 1000, 1832c6f7c1a3SJoseph Chen priv->set_armclk_rate ? priv->armclk_hz / 1000 : 0, 1833c6f7c1a3SJoseph Chen priv->set_armclk_rate ? " KHz" : "N/A"); 1834c6f7c1a3SJoseph Chen for (i = 0; i < clk_count; i++) { 1835c6f7c1a3SJoseph Chen clk_dump = &clks_dump[i]; 1836c6f7c1a3SJoseph Chen if (clk_dump->name) { 1837c6f7c1a3SJoseph Chen clk.id = clk_dump->id; 1838c6f7c1a3SJoseph Chen ret = clk_request(cru_dev, &clk); 1839c6f7c1a3SJoseph Chen if (ret < 0) 1840c6f7c1a3SJoseph Chen return ret; 1841c6f7c1a3SJoseph Chen 1842c6f7c1a3SJoseph Chen rate = clk_get_rate(&clk); 1843c6f7c1a3SJoseph Chen clk_free(&clk); 1844c6f7c1a3SJoseph Chen if (i == 0) { 1845c6f7c1a3SJoseph Chen if (rate < 0) 1846c6f7c1a3SJoseph Chen printf(" %s %s\n", clk_dump->name, 1847c6f7c1a3SJoseph Chen "unknown"); 1848c6f7c1a3SJoseph Chen else 1849c6f7c1a3SJoseph Chen printf(" %s %lu KHz\n", clk_dump->name, 1850c6f7c1a3SJoseph Chen rate / 1000); 1851c6f7c1a3SJoseph Chen } else { 1852c6f7c1a3SJoseph Chen if (rate < 0) 1853c6f7c1a3SJoseph Chen printf(" %s %s\n", clk_dump->name, 1854c6f7c1a3SJoseph Chen "unknown"); 1855c6f7c1a3SJoseph Chen else 1856c6f7c1a3SJoseph Chen printf(" %s %lu KHz\n", clk_dump->name, 1857c6f7c1a3SJoseph Chen rate / 1000); 1858c6f7c1a3SJoseph Chen } 1859c6f7c1a3SJoseph Chen } 1860c6f7c1a3SJoseph Chen } 1861c6f7c1a3SJoseph Chen 1862c6f7c1a3SJoseph Chen return 0; 1863c6f7c1a3SJoseph Chen } 1864c6f7c1a3SJoseph Chen #endif 1865c6f7c1a3SJoseph Chen 1866c6f7c1a3SJoseph Chen static int rk3528_grfclk_probe(struct udevice *dev) 1867c6f7c1a3SJoseph Chen { 1868c6f7c1a3SJoseph Chen struct rk3528_grf_clk_priv *priv = dev_get_priv(dev); 1869c6f7c1a3SJoseph Chen 1870c6f7c1a3SJoseph Chen priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); 1871c6f7c1a3SJoseph Chen if (IS_ERR(priv->grf)) 1872c6f7c1a3SJoseph Chen return PTR_ERR(priv->grf); 1873c6f7c1a3SJoseph Chen 1874c6f7c1a3SJoseph Chen return 0; 1875c6f7c1a3SJoseph Chen } 1876c6f7c1a3SJoseph Chen 1877c6f7c1a3SJoseph Chen static const struct udevice_id rk3528_grf_cru_ids[] = { 1878c6f7c1a3SJoseph Chen { .compatible = "rockchip,rk3528-grf-cru" }, 1879c6f7c1a3SJoseph Chen { } 1880c6f7c1a3SJoseph Chen }; 1881c6f7c1a3SJoseph Chen 1882c6f7c1a3SJoseph Chen U_BOOT_DRIVER(rockchip_rk3528_grf_cru) = { 1883c6f7c1a3SJoseph Chen .name = "rockchip_rk3528_grf_cru", 1884c6f7c1a3SJoseph Chen .id = UCLASS_CLK, 1885c6f7c1a3SJoseph Chen .of_match = rk3528_grf_cru_ids, 1886c6f7c1a3SJoseph Chen .priv_auto_alloc_size = sizeof(struct rk3528_grf_clk_priv), 1887c6f7c1a3SJoseph Chen .ops = &rk3528_grfclk_ops, 1888c6f7c1a3SJoseph Chen .probe = rk3528_grfclk_probe, 1889c6f7c1a3SJoseph Chen }; 1890c6f7c1a3SJoseph Chen 1891c6f7c1a3SJoseph Chen static void rk3528_clk_init(struct rk3528_clk_priv *priv) 1892c6f7c1a3SJoseph Chen { 1893c6f7c1a3SJoseph Chen int ret; 1894c6f7c1a3SJoseph Chen 1895c6f7c1a3SJoseph Chen priv->sync_kernel = false; 1896c6f7c1a3SJoseph Chen if (!priv->armclk_enter_hz) { 1897c6f7c1a3SJoseph Chen priv->armclk_enter_hz = 1898c6f7c1a3SJoseph Chen rockchip_pll_get_rate(&rk3528_pll_clks[APLL], 1899c6f7c1a3SJoseph Chen priv->cru, APLL); 1900c6f7c1a3SJoseph Chen priv->armclk_init_hz = priv->armclk_enter_hz; 1901c6f7c1a3SJoseph Chen } 1902c6f7c1a3SJoseph Chen 1903c6f7c1a3SJoseph Chen if (priv->armclk_init_hz != APLL_HZ) { 1904c6f7c1a3SJoseph Chen ret = rk3528_armclk_set_clk(priv, APLL_HZ); 1905c6f7c1a3SJoseph Chen if (!ret) 1906c6f7c1a3SJoseph Chen priv->armclk_init_hz = APLL_HZ; 1907c6f7c1a3SJoseph Chen } 1908c6f7c1a3SJoseph Chen 1909c6f7c1a3SJoseph Chen if (priv->cpll_hz != CPLL_HZ) { 1910c6f7c1a3SJoseph Chen ret = rockchip_pll_set_rate(&rk3528_pll_clks[CPLL], priv->cru, 1911c6f7c1a3SJoseph Chen CPLL, CPLL_HZ); 1912c6f7c1a3SJoseph Chen if (!ret) 1913c6f7c1a3SJoseph Chen priv->cpll_hz = CPLL_HZ; 1914c6f7c1a3SJoseph Chen } 1915c6f7c1a3SJoseph Chen 1916c6f7c1a3SJoseph Chen if (priv->gpll_hz != GPLL_HZ) { 1917c6f7c1a3SJoseph Chen ret = rockchip_pll_set_rate(&rk3528_pll_clks[GPLL], priv->cru, 1918c6f7c1a3SJoseph Chen GPLL, GPLL_HZ); 1919c6f7c1a3SJoseph Chen if (!ret) 1920c6f7c1a3SJoseph Chen priv->gpll_hz = GPLL_HZ; 1921c6f7c1a3SJoseph Chen } 1922c6f7c1a3SJoseph Chen #if 0 1923c6f7c1a3SJoseph Chen if (priv->ppll_hz != PPLL_HZ) { 1924c6f7c1a3SJoseph Chen ret = rockchip_pll_set_rate(&rk3528_pll_clks[PPLL], priv->cru, 1925c6f7c1a3SJoseph Chen PPLL, PPLL_HZ); 1926c6f7c1a3SJoseph Chen if (!ret) 1927c6f7c1a3SJoseph Chen priv->ppll_hz = PPLL_HZ; 1928c6f7c1a3SJoseph Chen } 1929c6f7c1a3SJoseph Chen #endif 1930c6f7c1a3SJoseph Chen /* The default rate is 100Mhz, it's not friendly for remote IR module */ 1931c6f7c1a3SJoseph Chen rk3528_pwm_set_clk(priv, CLK_PWM0, 24000000); 1932c6f7c1a3SJoseph Chen rk3528_pwm_set_clk(priv, CLK_PWM1, 24000000); 1933c6f7c1a3SJoseph Chen } 1934c6f7c1a3SJoseph Chen 1935c6f7c1a3SJoseph Chen static int rk3528_clk_probe(struct udevice *dev) 1936c6f7c1a3SJoseph Chen { 1937c6f7c1a3SJoseph Chen struct rk3528_clk_priv *priv = dev_get_priv(dev); 1938c6f7c1a3SJoseph Chen int ret; 1939c6f7c1a3SJoseph Chen 1940c6f7c1a3SJoseph Chen priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); 1941c6f7c1a3SJoseph Chen if (IS_ERR(priv->grf)) 1942c6f7c1a3SJoseph Chen return PTR_ERR(priv->grf); 1943c6f7c1a3SJoseph Chen 1944c6f7c1a3SJoseph Chen rk3528_clk_init(priv); 1945c6f7c1a3SJoseph Chen 1946c6f7c1a3SJoseph Chen /* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */ 1947c6f7c1a3SJoseph Chen ret = clk_set_defaults(dev); 1948c6f7c1a3SJoseph Chen if (ret) 1949c6f7c1a3SJoseph Chen debug("%s clk_set_defaults failed %d\n", __func__, ret); 1950c6f7c1a3SJoseph Chen else 1951c6f7c1a3SJoseph Chen priv->sync_kernel = true; 1952c6f7c1a3SJoseph Chen 1953c6f7c1a3SJoseph Chen return 0; 1954c6f7c1a3SJoseph Chen } 1955c6f7c1a3SJoseph Chen 1956c6f7c1a3SJoseph Chen static int rk3528_clk_ofdata_to_platdata(struct udevice *dev) 1957c6f7c1a3SJoseph Chen { 1958c6f7c1a3SJoseph Chen struct rk3528_clk_priv *priv = dev_get_priv(dev); 1959c6f7c1a3SJoseph Chen 1960c6f7c1a3SJoseph Chen priv->cru = dev_read_addr_ptr(dev); 1961c6f7c1a3SJoseph Chen 1962c6f7c1a3SJoseph Chen return 0; 1963c6f7c1a3SJoseph Chen } 1964c6f7c1a3SJoseph Chen 1965c6f7c1a3SJoseph Chen static int rk3528_clk_bind(struct udevice *dev) 1966c6f7c1a3SJoseph Chen { 1967c6f7c1a3SJoseph Chen struct udevice *sys_child, *sf_child; 1968c6f7c1a3SJoseph Chen struct softreset_reg *sf_priv; 1969c6f7c1a3SJoseph Chen struct sysreset_reg *priv; 1970c6f7c1a3SJoseph Chen int ret; 1971c6f7c1a3SJoseph Chen 1972c6f7c1a3SJoseph Chen /* The reset driver does not have a device node, so bind it here */ 1973c6f7c1a3SJoseph Chen ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset", 1974c6f7c1a3SJoseph Chen &sys_child); 1975c6f7c1a3SJoseph Chen if (ret) { 1976c6f7c1a3SJoseph Chen debug("Warning: No sysreset driver: ret=%d\n", ret); 1977c6f7c1a3SJoseph Chen } else { 1978c6f7c1a3SJoseph Chen priv = malloc(sizeof(struct sysreset_reg)); 1979c6f7c1a3SJoseph Chen priv->glb_srst_fst_value = offsetof(struct rk3528_cru, 1980c6f7c1a3SJoseph Chen glb_srst_fst); 1981c6f7c1a3SJoseph Chen priv->glb_srst_snd_value = offsetof(struct rk3528_cru, 1982c6f7c1a3SJoseph Chen glb_srst_snd); 1983c6f7c1a3SJoseph Chen sys_child->priv = priv; 1984c6f7c1a3SJoseph Chen } 1985c6f7c1a3SJoseph Chen 1986c6f7c1a3SJoseph Chen ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset", 1987c6f7c1a3SJoseph Chen dev_ofnode(dev), &sf_child); 1988c6f7c1a3SJoseph Chen if (ret) { 1989c6f7c1a3SJoseph Chen debug("Warning: No rockchip reset driver: ret=%d\n", ret); 1990c6f7c1a3SJoseph Chen } else { 1991c6f7c1a3SJoseph Chen sf_priv = malloc(sizeof(struct softreset_reg)); 1992c6f7c1a3SJoseph Chen sf_priv->sf_reset_offset = offsetof(struct rk3528_cru, 1993c6f7c1a3SJoseph Chen softrst_con[0]); 1994c6f7c1a3SJoseph Chen sf_priv->sf_reset_num = 47; 1995c6f7c1a3SJoseph Chen sf_child->priv = sf_priv; 1996c6f7c1a3SJoseph Chen } 1997c6f7c1a3SJoseph Chen 1998c6f7c1a3SJoseph Chen return 0; 1999c6f7c1a3SJoseph Chen } 2000c6f7c1a3SJoseph Chen 2001c6f7c1a3SJoseph Chen static const struct udevice_id rk3528_clk_ids[] = { 2002c6f7c1a3SJoseph Chen { .compatible = "rockchip,rk3528-cru" }, 2003c6f7c1a3SJoseph Chen { } 2004c6f7c1a3SJoseph Chen }; 2005c6f7c1a3SJoseph Chen 2006c6f7c1a3SJoseph Chen U_BOOT_DRIVER(rockchip_rk3528_cru) = { 2007c6f7c1a3SJoseph Chen .name = "rockchip_rk3528_cru", 2008c6f7c1a3SJoseph Chen .id = UCLASS_CLK, 2009c6f7c1a3SJoseph Chen .of_match = rk3528_clk_ids, 2010c6f7c1a3SJoseph Chen .priv_auto_alloc_size = sizeof(struct rk3528_clk_priv), 2011c6f7c1a3SJoseph Chen .ofdata_to_platdata = rk3528_clk_ofdata_to_platdata, 2012c6f7c1a3SJoseph Chen .ops = &rk3528_clk_ops, 2013c6f7c1a3SJoseph Chen .bind = rk3528_clk_bind, 2014c6f7c1a3SJoseph Chen .probe = rk3528_clk_probe, 2015c6f7c1a3SJoseph Chen }; 2016c6f7c1a3SJoseph Chen 2017