154d254feSAndy Yan /*
254d254feSAndy Yan * (C) Copyright 2017 Rockchip Electronics Co., Ltd
354d254feSAndy Yan *
454d254feSAndy Yan * SPDX-License-Identifier: GPL-2.0
554d254feSAndy Yan */
654d254feSAndy Yan #include <common.h>
754d254feSAndy Yan #include <bitfield.h>
854d254feSAndy Yan #include <clk-uclass.h>
954d254feSAndy Yan #include <dm.h>
101e180a56SFinley Xiao #include <div64.h>
1154d254feSAndy Yan #include <errno.h>
1254d254feSAndy Yan #include <syscon.h>
1354d254feSAndy Yan #include <asm/arch/clock.h>
1454d254feSAndy Yan #include <asm/arch/cru_rk3308.h>
1554d254feSAndy Yan #include <asm/arch/hardware.h>
1654d254feSAndy Yan #include <asm/io.h>
1754d254feSAndy Yan #include <dm/lists.h>
1854d254feSAndy Yan #include <dt-bindings/clock/rk3308-cru.h>
1954d254feSAndy Yan
2054d254feSAndy Yan DECLARE_GLOBAL_DATA_PTR;
2154d254feSAndy Yan
2254d254feSAndy Yan enum {
2354d254feSAndy Yan VCO_MAX_HZ = 3200U * 1000000,
2454d254feSAndy Yan VCO_MIN_HZ = 800 * 1000000,
2554d254feSAndy Yan OUTPUT_MAX_HZ = 3200U * 1000000,
2654d254feSAndy Yan OUTPUT_MIN_HZ = 24 * 1000000,
2754d254feSAndy Yan };
2854d254feSAndy Yan
2954d254feSAndy Yan #define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1))
3054d254feSAndy Yan
31efdbac34SFinley Xiao #define RK3308_CLK_DUMP(_id, _name) \
32efdbac34SFinley Xiao { \
33efdbac34SFinley Xiao .id = _id, \
34efdbac34SFinley Xiao .name = _name, \
35efdbac34SFinley Xiao }
36efdbac34SFinley Xiao
3703a6c029SFinley Xiao #define RK3308_CPUCLK_RATE(_rate, _aclk_div, _pclk_div) \
3803a6c029SFinley Xiao { \
3903a6c029SFinley Xiao .rate = _rate##U, \
4003a6c029SFinley Xiao .aclk_div = _aclk_div, \
4103a6c029SFinley Xiao .pclk_div = _pclk_div, \
4203a6c029SFinley Xiao }
4303a6c029SFinley Xiao
4427ee7641SFinley Xiao static struct rockchip_pll_rate_table rk3308_pll_rates[] = {
451e180a56SFinley Xiao /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
4627ee7641SFinley Xiao RK3036_PLL_RATE(1300000000, 6, 325, 1, 1, 1, 0),
4727ee7641SFinley Xiao RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0),
4827ee7641SFinley Xiao RK3036_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0),
4927ee7641SFinley Xiao RK3036_PLL_RATE(748000000, 2, 187, 3, 1, 1, 0),
5054d254feSAndy Yan };
5154d254feSAndy Yan
5203a6c029SFinley Xiao static struct rockchip_cpu_rate_table rk3308_cpu_rates[] = {
5303a6c029SFinley Xiao RK3308_CPUCLK_RATE(1200000000, 1, 5),
5403a6c029SFinley Xiao RK3308_CPUCLK_RATE(1008000000, 1, 5),
5503a6c029SFinley Xiao RK3308_CPUCLK_RATE(816000000, 1, 3),
5603a6c029SFinley Xiao RK3308_CPUCLK_RATE(600000000, 1, 3),
57e04b9c6bSJoseph Chen RK3308_CPUCLK_RATE(408000000, 1, 1),
5803a6c029SFinley Xiao };
5903a6c029SFinley Xiao
60efdbac34SFinley Xiao static const struct rk3308_clk_info clks_dump[] = {
61efdbac34SFinley Xiao RK3308_CLK_DUMP(PLL_APLL, "apll"),
62e8ca7128SFinley Xiao RK3308_CLK_DUMP(PLL_DPLL, "dpll"),
63efdbac34SFinley Xiao RK3308_CLK_DUMP(PLL_VPLL0, "vpll0"),
64efdbac34SFinley Xiao RK3308_CLK_DUMP(PLL_VPLL1, "vpll1"),
65efdbac34SFinley Xiao RK3308_CLK_DUMP(ACLK_BUS, "aclk_bus"),
66efdbac34SFinley Xiao RK3308_CLK_DUMP(HCLK_BUS, "hclk_bus"),
67efdbac34SFinley Xiao RK3308_CLK_DUMP(PCLK_BUS, "pclk_bus"),
68efdbac34SFinley Xiao RK3308_CLK_DUMP(ACLK_PERI, "aclk_peri"),
69efdbac34SFinley Xiao RK3308_CLK_DUMP(HCLK_PERI, "hclk_peri"),
70efdbac34SFinley Xiao RK3308_CLK_DUMP(PCLK_PERI, "pclk_peri"),
71efdbac34SFinley Xiao RK3308_CLK_DUMP(HCLK_AUDIO, "hclk_audio"),
72efdbac34SFinley Xiao RK3308_CLK_DUMP(PCLK_AUDIO, "pclk_audio"),
73efdbac34SFinley Xiao };
74efdbac34SFinley Xiao
7527ee7641SFinley Xiao static struct rockchip_pll_clock rk3308_pll_clks[] = {
7627ee7641SFinley Xiao [APLL] = PLL(pll_rk3328, PLL_APLL, RK3308_PLL_CON(0),
7727ee7641SFinley Xiao RK3308_MODE_CON, 0, 10, 0, rk3308_pll_rates),
7827ee7641SFinley Xiao [DPLL] = PLL(pll_rk3328, PLL_DPLL, RK3308_PLL_CON(8),
7927ee7641SFinley Xiao RK3308_MODE_CON, 2, 10, 0, NULL),
8027ee7641SFinley Xiao [VPLL0] = PLL(pll_rk3328, PLL_VPLL0, RK3308_PLL_CON(16),
8127ee7641SFinley Xiao RK3308_MODE_CON, 4, 10, 0, NULL),
8227ee7641SFinley Xiao [VPLL1] = PLL(pll_rk3328, PLL_VPLL1, RK3308_PLL_CON(24),
8327ee7641SFinley Xiao RK3308_MODE_CON, 6, 10, 0, NULL),
8427ee7641SFinley Xiao };
8527ee7641SFinley Xiao
861bbed247SFinley Xiao /*
871bbed247SFinley Xiao *
881bbed247SFinley Xiao * rational_best_approximation(31415, 10000,
891bbed247SFinley Xiao * (1 << 8) - 1, (1 << 5) - 1, &n, &d);
901bbed247SFinley Xiao *
911bbed247SFinley Xiao * you may look at given_numerator as a fixed point number,
921bbed247SFinley Xiao * with the fractional part size described in given_denominator.
931bbed247SFinley Xiao *
941bbed247SFinley Xiao * for theoretical background, see:
951bbed247SFinley Xiao * http://en.wikipedia.org/wiki/Continued_fraction
961bbed247SFinley Xiao */
rational_best_approximation(unsigned long given_numerator,unsigned long given_denominator,unsigned long max_numerator,unsigned long max_denominator,unsigned long * best_numerator,unsigned long * best_denominator)971bbed247SFinley Xiao static void rational_best_approximation(unsigned long given_numerator,
981bbed247SFinley Xiao unsigned long given_denominator,
991bbed247SFinley Xiao unsigned long max_numerator,
1001bbed247SFinley Xiao unsigned long max_denominator,
1011bbed247SFinley Xiao unsigned long *best_numerator,
1021bbed247SFinley Xiao unsigned long *best_denominator)
1031bbed247SFinley Xiao {
1041bbed247SFinley Xiao unsigned long n, d, n0, d0, n1, d1;
1051bbed247SFinley Xiao
1061bbed247SFinley Xiao n = given_numerator;
1071bbed247SFinley Xiao d = given_denominator;
1081bbed247SFinley Xiao n0 = 0;
1091bbed247SFinley Xiao d1 = 0;
1101bbed247SFinley Xiao n1 = 1;
1111bbed247SFinley Xiao d0 = 1;
1121bbed247SFinley Xiao for (;;) {
1131bbed247SFinley Xiao unsigned long t, a;
1141bbed247SFinley Xiao
1151bbed247SFinley Xiao if (n1 > max_numerator || d1 > max_denominator) {
1161bbed247SFinley Xiao n1 = n0;
1171bbed247SFinley Xiao d1 = d0;
1181bbed247SFinley Xiao break;
1191bbed247SFinley Xiao }
1201bbed247SFinley Xiao if (d == 0)
1211bbed247SFinley Xiao break;
1221bbed247SFinley Xiao t = d;
1231bbed247SFinley Xiao a = n / d;
1241bbed247SFinley Xiao d = n % d;
1251bbed247SFinley Xiao n = t;
1261bbed247SFinley Xiao t = n0 + a * n1;
1271bbed247SFinley Xiao n0 = n1;
1281bbed247SFinley Xiao n1 = t;
1291bbed247SFinley Xiao t = d0 + a * d1;
1301bbed247SFinley Xiao d0 = d1;
1311bbed247SFinley Xiao d1 = t;
1321bbed247SFinley Xiao }
1331bbed247SFinley Xiao *best_numerator = n1;
1341bbed247SFinley Xiao *best_denominator = d1;
1351bbed247SFinley Xiao }
1361bbed247SFinley Xiao
rk3308_armclk_set_clk(struct rk3308_clk_priv * priv,ulong hz)13703a6c029SFinley Xiao static ulong rk3308_armclk_set_clk(struct rk3308_clk_priv *priv, ulong hz)
13803a6c029SFinley Xiao {
13903a6c029SFinley Xiao struct rk3308_cru *cru = priv->cru;
14003a6c029SFinley Xiao const struct rockchip_cpu_rate_table *rate;
14103a6c029SFinley Xiao ulong old_rate;
14203a6c029SFinley Xiao
14303a6c029SFinley Xiao rate = rockchip_get_cpu_settings(rk3308_cpu_rates, hz);
14403a6c029SFinley Xiao if (!rate) {
14503a6c029SFinley Xiao printf("%s unsupport rate\n", __func__);
14603a6c029SFinley Xiao return -EINVAL;
14703a6c029SFinley Xiao }
14803a6c029SFinley Xiao
14903a6c029SFinley Xiao /*
15003a6c029SFinley Xiao * select apll as cpu/core clock pll source and
15103a6c029SFinley Xiao * set up dependent divisors for PERI and ACLK clocks.
15203a6c029SFinley Xiao * core hz : apll = 1:1
15303a6c029SFinley Xiao */
15403a6c029SFinley Xiao old_rate = rockchip_pll_get_rate(&rk3308_pll_clks[APLL],
15503a6c029SFinley Xiao priv->cru, APLL);
15603a6c029SFinley Xiao if (old_rate > hz) {
15703a6c029SFinley Xiao if (rockchip_pll_set_rate(&rk3308_pll_clks[APLL],
15803a6c029SFinley Xiao priv->cru, APLL, hz))
15903a6c029SFinley Xiao return -EINVAL;
16003a6c029SFinley Xiao rk_clrsetreg(&cru->clksel_con[0],
16103a6c029SFinley Xiao CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK |
16203a6c029SFinley Xiao CORE_ACLK_DIV_MASK | CORE_DBG_DIV_MASK,
16303a6c029SFinley Xiao rate->aclk_div << CORE_ACLK_DIV_SHIFT |
16403a6c029SFinley Xiao rate->pclk_div << CORE_DBG_DIV_SHIFT |
16503a6c029SFinley Xiao CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT |
16603a6c029SFinley Xiao 0 << CORE_DIV_CON_SHIFT);
16703a6c029SFinley Xiao } else if (old_rate < hz) {
16803a6c029SFinley Xiao rk_clrsetreg(&cru->clksel_con[0],
16903a6c029SFinley Xiao CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK |
17003a6c029SFinley Xiao CORE_ACLK_DIV_MASK | CORE_DBG_DIV_MASK,
17103a6c029SFinley Xiao rate->aclk_div << CORE_ACLK_DIV_SHIFT |
17203a6c029SFinley Xiao rate->pclk_div << CORE_DBG_DIV_SHIFT |
17303a6c029SFinley Xiao CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT |
17403a6c029SFinley Xiao 0 << CORE_DIV_CON_SHIFT);
17503a6c029SFinley Xiao if (rockchip_pll_set_rate(&rk3308_pll_clks[APLL],
17603a6c029SFinley Xiao priv->cru, APLL, hz))
17703a6c029SFinley Xiao return -EINVAL;
17803a6c029SFinley Xiao }
17903a6c029SFinley Xiao
18003a6c029SFinley Xiao return rockchip_pll_get_rate(&rk3308_pll_clks[APLL], priv->cru, APLL);
18103a6c029SFinley Xiao }
18203a6c029SFinley Xiao
rk3308_clk_get_pll_rate(struct rk3308_clk_priv * priv)1837b1c1c4bSFinley Xiao static void rk3308_clk_get_pll_rate(struct rk3308_clk_priv *priv)
1847b1c1c4bSFinley Xiao {
1857b1c1c4bSFinley Xiao if (!priv->dpll_hz)
18627ee7641SFinley Xiao priv->dpll_hz = rockchip_pll_get_rate(&rk3308_pll_clks[DPLL],
18727ee7641SFinley Xiao priv->cru, DPLL);
1887b1c1c4bSFinley Xiao if (!priv->vpll0_hz)
18927ee7641SFinley Xiao priv->vpll0_hz = rockchip_pll_get_rate(&rk3308_pll_clks[VPLL0],
19027ee7641SFinley Xiao priv->cru, VPLL0);
1917b1c1c4bSFinley Xiao if (!priv->vpll1_hz)
19227ee7641SFinley Xiao priv->vpll1_hz = rockchip_pll_get_rate(&rk3308_pll_clks[VPLL1],
19327ee7641SFinley Xiao priv->cru, VPLL1);
1947b1c1c4bSFinley Xiao }
1957b1c1c4bSFinley Xiao
rk3308_i2c_get_clk(struct clk * clk)196fc4a6bd4SFinley Xiao static ulong rk3308_i2c_get_clk(struct clk *clk)
19754d254feSAndy Yan {
198fc4a6bd4SFinley Xiao struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
199fc4a6bd4SFinley Xiao struct rk3308_cru *cru = priv->cru;
20054d254feSAndy Yan u32 div, con, con_id;
20154d254feSAndy Yan
202fc4a6bd4SFinley Xiao switch (clk->id) {
20354d254feSAndy Yan case SCLK_I2C0:
20454d254feSAndy Yan con_id = 25;
20554d254feSAndy Yan break;
20654d254feSAndy Yan case SCLK_I2C1:
20754d254feSAndy Yan con_id = 26;
20854d254feSAndy Yan break;
20954d254feSAndy Yan case SCLK_I2C2:
21054d254feSAndy Yan con_id = 27;
21154d254feSAndy Yan break;
21254d254feSAndy Yan case SCLK_I2C3:
21354d254feSAndy Yan con_id = 28;
21454d254feSAndy Yan break;
21554d254feSAndy Yan default:
21654d254feSAndy Yan printf("do not support this i2c bus\n");
21754d254feSAndy Yan return -EINVAL;
21854d254feSAndy Yan }
21954d254feSAndy Yan
22054d254feSAndy Yan con = readl(&cru->clksel_con[con_id]);
22154d254feSAndy Yan div = con >> CLK_I2C_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK;
22254d254feSAndy Yan
223fc4a6bd4SFinley Xiao return DIV_TO_RATE(priv->dpll_hz, div);
22454d254feSAndy Yan }
22554d254feSAndy Yan
rk3308_i2c_set_clk(struct clk * clk,uint hz)226fc4a6bd4SFinley Xiao static ulong rk3308_i2c_set_clk(struct clk *clk, uint hz)
22754d254feSAndy Yan {
228fc4a6bd4SFinley Xiao struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
229fc4a6bd4SFinley Xiao struct rk3308_cru *cru = priv->cru;
23054d254feSAndy Yan u32 src_clk_div, con_id;
23154d254feSAndy Yan
2324e6d5752SFinley Xiao src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz);
233e27c054aSFinley Xiao assert(src_clk_div - 1 <= 127);
23454d254feSAndy Yan
235fc4a6bd4SFinley Xiao switch (clk->id) {
23654d254feSAndy Yan case SCLK_I2C0:
23754d254feSAndy Yan con_id = 25;
23854d254feSAndy Yan break;
23954d254feSAndy Yan case SCLK_I2C1:
24054d254feSAndy Yan con_id = 26;
24154d254feSAndy Yan break;
24254d254feSAndy Yan case SCLK_I2C2:
24354d254feSAndy Yan con_id = 27;
24454d254feSAndy Yan break;
24554d254feSAndy Yan case SCLK_I2C3:
24654d254feSAndy Yan con_id = 28;
24754d254feSAndy Yan break;
24854d254feSAndy Yan default:
24954d254feSAndy Yan printf("do not support this i2c bus\n");
25054d254feSAndy Yan return -EINVAL;
25154d254feSAndy Yan }
25254d254feSAndy Yan rk_clrsetreg(&cru->clksel_con[con_id],
25354d254feSAndy Yan CLK_I2C_PLL_SEL_MASK | CLK_I2C_DIV_CON_MASK,
25454d254feSAndy Yan CLK_I2C_PLL_SEL_DPLL << CLK_I2C_PLL_SEL_SHIFT |
25554d254feSAndy Yan (src_clk_div - 1) << CLK_I2C_DIV_CON_SHIFT);
25654d254feSAndy Yan
257fc4a6bd4SFinley Xiao return rk3308_i2c_get_clk(clk);
25854d254feSAndy Yan }
25954d254feSAndy Yan
rk3308_mac_set_clk(struct clk * clk,uint hz)260200683eaSDavid Wu static ulong rk3308_mac_set_clk(struct clk *clk, uint hz)
261200683eaSDavid Wu {
262200683eaSDavid Wu struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
263200683eaSDavid Wu struct rk3308_cru *cru = priv->cru;
264200683eaSDavid Wu u32 con = readl(&cru->clksel_con[43]);
265200683eaSDavid Wu ulong pll_rate;
266200683eaSDavid Wu u8 div;
267200683eaSDavid Wu
268200683eaSDavid Wu if ((con >> MAC_PLL_SHIFT) & MAC_SEL_VPLL0)
269200683eaSDavid Wu pll_rate = rockchip_pll_get_rate(&rk3308_pll_clks[VPLL0],
270200683eaSDavid Wu priv->cru, VPLL0);
271200683eaSDavid Wu else if ((con >> MAC_PLL_SHIFT) & MAC_SEL_VPLL1)
272200683eaSDavid Wu pll_rate = rockchip_pll_get_rate(&rk3308_pll_clks[VPLL1],
273200683eaSDavid Wu priv->cru, VPLL1);
274200683eaSDavid Wu else
275200683eaSDavid Wu pll_rate = rockchip_pll_get_rate(&rk3308_pll_clks[DPLL],
276200683eaSDavid Wu priv->cru, DPLL);
277200683eaSDavid Wu
278200683eaSDavid Wu /*default set 50MHZ for gmac*/
279200683eaSDavid Wu if (!hz)
280200683eaSDavid Wu hz = 50000000;
281200683eaSDavid Wu
282200683eaSDavid Wu div = DIV_ROUND_UP(pll_rate, hz) - 1;
283200683eaSDavid Wu assert(div < 32);
284200683eaSDavid Wu rk_clrsetreg(&cru->clksel_con[43], MAC_DIV_MASK,
285200683eaSDavid Wu div << MAC_DIV_SHIFT);
286200683eaSDavid Wu
287200683eaSDavid Wu return DIV_TO_RATE(pll_rate, div);
288200683eaSDavid Wu }
289200683eaSDavid Wu
rk3308_mac_set_speed_clk(struct clk * clk,uint hz)290200683eaSDavid Wu static int rk3308_mac_set_speed_clk(struct clk *clk, uint hz)
291200683eaSDavid Wu {
292200683eaSDavid Wu struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
293200683eaSDavid Wu struct rk3308_cru *cru = priv->cru;
294200683eaSDavid Wu
295200683eaSDavid Wu if (hz != 2500000 && hz != 25000000) {
296200683eaSDavid Wu debug("Unsupported mac speed:%d\n", hz);
297200683eaSDavid Wu return -EINVAL;
298200683eaSDavid Wu }
299200683eaSDavid Wu
300200683eaSDavid Wu rk_clrsetreg(&cru->clksel_con[43], MAC_CLK_SPEED_SEL_MASK,
301200683eaSDavid Wu ((hz == 2500000) ? 0 : 1) << MAC_CLK_SPEED_SEL_SHIFT);
302200683eaSDavid Wu
303200683eaSDavid Wu return 0;
304200683eaSDavid Wu }
305200683eaSDavid Wu
rk3308_mmc_get_clk(struct clk * clk)306fc4a6bd4SFinley Xiao static ulong rk3308_mmc_get_clk(struct clk *clk)
30754d254feSAndy Yan {
308fc4a6bd4SFinley Xiao struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
309fc4a6bd4SFinley Xiao struct rk3308_cru *cru = priv->cru;
31054d254feSAndy Yan u32 div, con, con_id;
31154d254feSAndy Yan
312fc4a6bd4SFinley Xiao switch (clk->id) {
31354d254feSAndy Yan case HCLK_SDMMC:
31454d254feSAndy Yan case SCLK_SDMMC:
31554d254feSAndy Yan con_id = 39;
31654d254feSAndy Yan break;
31754d254feSAndy Yan case HCLK_EMMC:
31854d254feSAndy Yan case SCLK_EMMC:
31954d254feSAndy Yan case SCLK_EMMC_SAMPLE:
32054d254feSAndy Yan con_id = 41;
32154d254feSAndy Yan break;
32254d254feSAndy Yan default:
32354d254feSAndy Yan return -EINVAL;
32454d254feSAndy Yan }
32554d254feSAndy Yan
32654d254feSAndy Yan con = readl(&cru->clksel_con[con_id]);
32754d254feSAndy Yan div = (con & EMMC_DIV_MASK) >> EMMC_DIV_SHIFT;
32854d254feSAndy Yan
32954d254feSAndy Yan if ((con & EMMC_PLL_MASK) >> EMMC_PLL_SHIFT
33054d254feSAndy Yan == EMMC_SEL_24M)
33154d254feSAndy Yan return DIV_TO_RATE(OSC_HZ, div) / 2;
33254d254feSAndy Yan else
333fc4a6bd4SFinley Xiao return DIV_TO_RATE(priv->vpll0_hz, div) / 2;
33454d254feSAndy Yan }
33554d254feSAndy Yan
rk3308_mmc_set_clk(struct clk * clk,ulong set_rate)336fc4a6bd4SFinley Xiao static ulong rk3308_mmc_set_clk(struct clk *clk, ulong set_rate)
33754d254feSAndy Yan {
338fc4a6bd4SFinley Xiao struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
339fc4a6bd4SFinley Xiao struct rk3308_cru *cru = priv->cru;
34054d254feSAndy Yan int src_clk_div;
34154d254feSAndy Yan u32 con_id;
34254d254feSAndy Yan
343fc4a6bd4SFinley Xiao debug("%s %ld %ld\n", __func__, clk->id, set_rate);
34454d254feSAndy Yan
345fc4a6bd4SFinley Xiao switch (clk->id) {
34654d254feSAndy Yan case HCLK_SDMMC:
34754d254feSAndy Yan case SCLK_SDMMC:
34854d254feSAndy Yan con_id = 39;
34954d254feSAndy Yan break;
35054d254feSAndy Yan case HCLK_EMMC:
35154d254feSAndy Yan case SCLK_EMMC:
35254d254feSAndy Yan con_id = 41;
35354d254feSAndy Yan break;
35454d254feSAndy Yan default:
35554d254feSAndy Yan return -EINVAL;
35654d254feSAndy Yan }
35754d254feSAndy Yan /* Select clk_sdmmc/emmc source from VPLL0 by default */
35854d254feSAndy Yan /* mmc clock defaulg div 2 internal, need provide double in cru */
359fc4a6bd4SFinley Xiao src_clk_div = DIV_ROUND_UP(priv->vpll0_hz / 2, set_rate);
36054d254feSAndy Yan
36154d254feSAndy Yan if (src_clk_div > 127) {
36254d254feSAndy Yan /* use 24MHz source for 400KHz clock */
36354d254feSAndy Yan src_clk_div = DIV_ROUND_UP(OSC_HZ / 2, set_rate);
36454d254feSAndy Yan rk_clrsetreg(&cru->clksel_con[con_id],
36554d254feSAndy Yan EMMC_PLL_MASK | EMMC_DIV_MASK | EMMC_CLK_SEL_MASK,
36654d254feSAndy Yan EMMC_CLK_SEL_EMMC << EMMC_CLK_SEL_SHIFT |
36754d254feSAndy Yan EMMC_SEL_24M << EMMC_PLL_SHIFT |
36854d254feSAndy Yan (src_clk_div - 1) << EMMC_DIV_SHIFT);
36954d254feSAndy Yan } else {
37054d254feSAndy Yan rk_clrsetreg(&cru->clksel_con[con_id],
37154d254feSAndy Yan EMMC_PLL_MASK | EMMC_DIV_MASK | EMMC_CLK_SEL_MASK,
37254d254feSAndy Yan EMMC_CLK_SEL_EMMC << EMMC_CLK_SEL_SHIFT |
37354d254feSAndy Yan EMMC_SEL_VPLL0 << EMMC_PLL_SHIFT |
37454d254feSAndy Yan (src_clk_div - 1) << EMMC_DIV_SHIFT);
37554d254feSAndy Yan }
37654d254feSAndy Yan
377fc4a6bd4SFinley Xiao return rk3308_mmc_get_clk(clk);
37854d254feSAndy Yan }
37954d254feSAndy Yan
rk3308_saradc_get_clk(struct clk * clk)380fc4a6bd4SFinley Xiao static ulong rk3308_saradc_get_clk(struct clk *clk)
38154d254feSAndy Yan {
382fc4a6bd4SFinley Xiao struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
383fc4a6bd4SFinley Xiao struct rk3308_cru *cru = priv->cru;
38454d254feSAndy Yan u32 div, con;
38554d254feSAndy Yan
38654d254feSAndy Yan con = readl(&cru->clksel_con[34]);
38754d254feSAndy Yan div = con >> CLK_SARADC_DIV_CON_SHIFT & CLK_SARADC_DIV_CON_MASK;
38854d254feSAndy Yan
38954d254feSAndy Yan return DIV_TO_RATE(OSC_HZ, div);
39054d254feSAndy Yan }
39154d254feSAndy Yan
rk3308_saradc_set_clk(struct clk * clk,uint hz)392fc4a6bd4SFinley Xiao static ulong rk3308_saradc_set_clk(struct clk *clk, uint hz)
39354d254feSAndy Yan {
394fc4a6bd4SFinley Xiao struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
395fc4a6bd4SFinley Xiao struct rk3308_cru *cru = priv->cru;
39654d254feSAndy Yan int src_clk_div;
39754d254feSAndy Yan
3984e6d5752SFinley Xiao src_clk_div = DIV_ROUND_UP(OSC_HZ, hz);
399e27c054aSFinley Xiao assert(src_clk_div - 1 <= 2047);
40054d254feSAndy Yan
40154d254feSAndy Yan rk_clrsetreg(&cru->clksel_con[34],
40254d254feSAndy Yan CLK_SARADC_DIV_CON_MASK,
40354d254feSAndy Yan (src_clk_div - 1) << CLK_SARADC_DIV_CON_SHIFT);
40454d254feSAndy Yan
405fc4a6bd4SFinley Xiao return rk3308_saradc_get_clk(clk);
40654d254feSAndy Yan }
40754d254feSAndy Yan
rk3308_tsadc_get_clk(struct clk * clk)408cb3c37fcSElaine Zhang static ulong rk3308_tsadc_get_clk(struct clk *clk)
409cb3c37fcSElaine Zhang {
410cb3c37fcSElaine Zhang struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
411cb3c37fcSElaine Zhang struct rk3308_cru *cru = priv->cru;
412cb3c37fcSElaine Zhang u32 div, con;
413cb3c37fcSElaine Zhang
414cb3c37fcSElaine Zhang con = readl(&cru->clksel_con[33]);
415cb3c37fcSElaine Zhang div = con >> CLK_SARADC_DIV_CON_SHIFT & CLK_SARADC_DIV_CON_MASK;
416cb3c37fcSElaine Zhang
417cb3c37fcSElaine Zhang return DIV_TO_RATE(OSC_HZ, div);
418cb3c37fcSElaine Zhang }
419cb3c37fcSElaine Zhang
rk3308_tsadc_set_clk(struct clk * clk,uint hz)420cb3c37fcSElaine Zhang static ulong rk3308_tsadc_set_clk(struct clk *clk, uint hz)
421cb3c37fcSElaine Zhang {
422cb3c37fcSElaine Zhang struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
423cb3c37fcSElaine Zhang struct rk3308_cru *cru = priv->cru;
424cb3c37fcSElaine Zhang int src_clk_div;
425cb3c37fcSElaine Zhang
426cb3c37fcSElaine Zhang src_clk_div = DIV_ROUND_UP(OSC_HZ, hz);
427cb3c37fcSElaine Zhang assert(src_clk_div - 1 <= 2047);
428cb3c37fcSElaine Zhang
429cb3c37fcSElaine Zhang rk_clrsetreg(&cru->clksel_con[33],
430cb3c37fcSElaine Zhang CLK_SARADC_DIV_CON_MASK,
431cb3c37fcSElaine Zhang (src_clk_div - 1) << CLK_SARADC_DIV_CON_SHIFT);
432cb3c37fcSElaine Zhang
433cb3c37fcSElaine Zhang return rk3308_tsadc_get_clk(clk);
434cb3c37fcSElaine Zhang }
435cb3c37fcSElaine Zhang
rk3308_spi_get_clk(struct clk * clk)436fc4a6bd4SFinley Xiao static ulong rk3308_spi_get_clk(struct clk *clk)
43754d254feSAndy Yan {
438fc4a6bd4SFinley Xiao struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
439fc4a6bd4SFinley Xiao struct rk3308_cru *cru = priv->cru;
44054d254feSAndy Yan u32 div, con, con_id;
44154d254feSAndy Yan
442fc4a6bd4SFinley Xiao switch (clk->id) {
44354d254feSAndy Yan case SCLK_SPI0:
44454d254feSAndy Yan con_id = 30;
44554d254feSAndy Yan break;
44654d254feSAndy Yan case SCLK_SPI1:
44754d254feSAndy Yan con_id = 31;
44854d254feSAndy Yan break;
44954d254feSAndy Yan case SCLK_SPI2:
45054d254feSAndy Yan con_id = 32;
45154d254feSAndy Yan break;
45254d254feSAndy Yan default:
45354d254feSAndy Yan printf("do not support this spi bus\n");
45454d254feSAndy Yan return -EINVAL;
45554d254feSAndy Yan }
45654d254feSAndy Yan
45754d254feSAndy Yan con = readl(&cru->clksel_con[con_id]);
45854d254feSAndy Yan div = con >> CLK_SPI_DIV_CON_SHIFT & CLK_SPI_DIV_CON_MASK;
45954d254feSAndy Yan
460fc4a6bd4SFinley Xiao return DIV_TO_RATE(priv->dpll_hz, div);
46154d254feSAndy Yan }
46254d254feSAndy Yan
rk3308_spi_set_clk(struct clk * clk,uint hz)463fc4a6bd4SFinley Xiao static ulong rk3308_spi_set_clk(struct clk *clk, uint hz)
46454d254feSAndy Yan {
465fc4a6bd4SFinley Xiao struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
466fc4a6bd4SFinley Xiao struct rk3308_cru *cru = priv->cru;
46754d254feSAndy Yan u32 src_clk_div, con_id;
46854d254feSAndy Yan
4694e6d5752SFinley Xiao src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz);
470e27c054aSFinley Xiao assert(src_clk_div - 1 <= 127);
47154d254feSAndy Yan
472fc4a6bd4SFinley Xiao switch (clk->id) {
47354d254feSAndy Yan case SCLK_SPI0:
47454d254feSAndy Yan con_id = 30;
47554d254feSAndy Yan break;
47654d254feSAndy Yan case SCLK_SPI1:
47754d254feSAndy Yan con_id = 31;
47854d254feSAndy Yan break;
47954d254feSAndy Yan case SCLK_SPI2:
48054d254feSAndy Yan con_id = 32;
48154d254feSAndy Yan break;
48254d254feSAndy Yan default:
48354d254feSAndy Yan printf("do not support this spi bus\n");
48454d254feSAndy Yan return -EINVAL;
48554d254feSAndy Yan }
48654d254feSAndy Yan
48754d254feSAndy Yan rk_clrsetreg(&cru->clksel_con[con_id],
48854d254feSAndy Yan CLK_SPI_PLL_SEL_MASK | CLK_SPI_DIV_CON_MASK,
48954d254feSAndy Yan CLK_SPI_PLL_SEL_DPLL << CLK_SPI_PLL_SEL_SHIFT |
49054d254feSAndy Yan (src_clk_div - 1) << CLK_SPI_DIV_CON_SHIFT);
49154d254feSAndy Yan
492fc4a6bd4SFinley Xiao return rk3308_spi_get_clk(clk);
49354d254feSAndy Yan }
49454d254feSAndy Yan
rk3308_pwm_get_clk(struct clk * clk)495fc4a6bd4SFinley Xiao static ulong rk3308_pwm_get_clk(struct clk *clk)
49654d254feSAndy Yan {
497fc4a6bd4SFinley Xiao struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
498fc4a6bd4SFinley Xiao struct rk3308_cru *cru = priv->cru;
49954d254feSAndy Yan u32 div, con;
50054d254feSAndy Yan
50154d254feSAndy Yan con = readl(&cru->clksel_con[29]);
50254d254feSAndy Yan div = con >> CLK_PWM_DIV_CON_SHIFT & CLK_PWM_DIV_CON_MASK;
50354d254feSAndy Yan
504fc4a6bd4SFinley Xiao return DIV_TO_RATE(priv->dpll_hz, div);
50554d254feSAndy Yan }
50654d254feSAndy Yan
rk3308_pwm_set_clk(struct clk * clk,uint hz)507fc4a6bd4SFinley Xiao static ulong rk3308_pwm_set_clk(struct clk *clk, uint hz)
50854d254feSAndy Yan {
509fc4a6bd4SFinley Xiao struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
510fc4a6bd4SFinley Xiao struct rk3308_cru *cru = priv->cru;
51154d254feSAndy Yan int src_clk_div;
51254d254feSAndy Yan
5134e6d5752SFinley Xiao src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz);
514e27c054aSFinley Xiao assert(src_clk_div - 1 <= 127);
51554d254feSAndy Yan
51654d254feSAndy Yan rk_clrsetreg(&cru->clksel_con[29],
51754d254feSAndy Yan CLK_PWM_PLL_SEL_MASK | CLK_PWM_DIV_CON_MASK,
51854d254feSAndy Yan CLK_PWM_PLL_SEL_DPLL << CLK_PWM_PLL_SEL_SHIFT |
51954d254feSAndy Yan (src_clk_div - 1) << CLK_PWM_DIV_CON_SHIFT);
52054d254feSAndy Yan
521fc4a6bd4SFinley Xiao return rk3308_pwm_get_clk(clk);
52254d254feSAndy Yan }
52354d254feSAndy Yan
rk3308_vop_get_clk(struct clk * clk)524fc4a6bd4SFinley Xiao static ulong rk3308_vop_get_clk(struct clk *clk)
525ec20593dSFinley Xiao {
526fc4a6bd4SFinley Xiao struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
527fc4a6bd4SFinley Xiao struct rk3308_cru *cru = priv->cru;
528ec20593dSFinley Xiao u32 div, pll_sel, vol_sel, con, parent;
529ec20593dSFinley Xiao
530ec20593dSFinley Xiao con = readl(&cru->clksel_con[8]);
531ec20593dSFinley Xiao vol_sel = (con & DCLK_VOP_SEL_MASK) >> DCLK_VOP_SEL_SHIFT;
532ec20593dSFinley Xiao pll_sel = (con & DCLK_VOP_PLL_SEL_MASK) >> DCLK_VOP_PLL_SEL_SHIFT;
533ec20593dSFinley Xiao div = con & DCLK_VOP_DIV_MASK;
534ec20593dSFinley Xiao
535ec20593dSFinley Xiao if (vol_sel == DCLK_VOP_SEL_24M) {
536ec20593dSFinley Xiao parent = OSC_HZ;
537ec20593dSFinley Xiao } else if (vol_sel == DCLK_VOP_SEL_DIVOUT) {
538ec20593dSFinley Xiao switch (pll_sel) {
539ec20593dSFinley Xiao case DCLK_VOP_PLL_SEL_DPLL:
5407b1c1c4bSFinley Xiao parent = priv->dpll_hz;
541ec20593dSFinley Xiao break;
542ec20593dSFinley Xiao case DCLK_VOP_PLL_SEL_VPLL0:
5437b1c1c4bSFinley Xiao parent = priv->vpll0_hz;
544ec20593dSFinley Xiao break;
545ec20593dSFinley Xiao case DCLK_VOP_PLL_SEL_VPLL1:
5467b1c1c4bSFinley Xiao parent = priv->vpll0_hz;
547ec20593dSFinley Xiao break;
548ec20593dSFinley Xiao default:
549ec20593dSFinley Xiao printf("do not support this vop pll sel\n");
550ec20593dSFinley Xiao return -EINVAL;
551ec20593dSFinley Xiao }
552ec20593dSFinley Xiao } else {
553ec20593dSFinley Xiao printf("do not support this vop sel\n");
554ec20593dSFinley Xiao return -EINVAL;
555ec20593dSFinley Xiao }
556ec20593dSFinley Xiao
557ec20593dSFinley Xiao return DIV_TO_RATE(parent, div);
558ec20593dSFinley Xiao }
559ec20593dSFinley Xiao
rk3308_vop_set_clk(struct clk * clk,ulong hz)560fc4a6bd4SFinley Xiao static ulong rk3308_vop_set_clk(struct clk *clk, ulong hz)
561ec20593dSFinley Xiao {
562fc4a6bd4SFinley Xiao struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
563fc4a6bd4SFinley Xiao struct rk3308_cru *cru = priv->cru;
564ec20593dSFinley Xiao ulong pll_rate, now, best_rate = 0;
565ec20593dSFinley Xiao u32 i, div, best_div = 0, best_sel = 0;
566ec20593dSFinley Xiao
567ec20593dSFinley Xiao for (i = 0; i <= DCLK_VOP_PLL_SEL_VPLL1; i++) {
568ec20593dSFinley Xiao switch (i) {
569ec20593dSFinley Xiao case DCLK_VOP_PLL_SEL_DPLL:
570fc4a6bd4SFinley Xiao pll_rate = priv->dpll_hz;
571ec20593dSFinley Xiao break;
572ec20593dSFinley Xiao case DCLK_VOP_PLL_SEL_VPLL0:
573fc4a6bd4SFinley Xiao pll_rate = priv->vpll0_hz;
574ec20593dSFinley Xiao break;
575ec20593dSFinley Xiao case DCLK_VOP_PLL_SEL_VPLL1:
576fc4a6bd4SFinley Xiao pll_rate = priv->vpll1_hz;
577ec20593dSFinley Xiao break;
578ec20593dSFinley Xiao default:
579ec20593dSFinley Xiao printf("do not support this vop pll sel\n");
580ec20593dSFinley Xiao return -EINVAL;
581ec20593dSFinley Xiao }
582ec20593dSFinley Xiao
583ec20593dSFinley Xiao div = DIV_ROUND_UP(pll_rate, hz);
584ec20593dSFinley Xiao if (div > 255)
585ec20593dSFinley Xiao continue;
586ec20593dSFinley Xiao now = pll_rate / div;
587ec20593dSFinley Xiao if (abs(hz - now) < abs(hz - best_rate)) {
588ec20593dSFinley Xiao best_rate = now;
589ec20593dSFinley Xiao best_div = div;
590ec20593dSFinley Xiao best_sel = i;
591ec20593dSFinley Xiao }
592ec20593dSFinley Xiao debug("pll_rate=%lu, best_rate=%lu, best_div=%u, best_sel=%u\n",
593ec20593dSFinley Xiao pll_rate, best_rate, best_div, best_sel);
594ec20593dSFinley Xiao }
595ec20593dSFinley Xiao
596ec20593dSFinley Xiao if (best_rate != hz && hz == OSC_HZ) {
597ec20593dSFinley Xiao rk_clrsetreg(&cru->clksel_con[8],
598ec20593dSFinley Xiao DCLK_VOP_SEL_MASK,
599ec20593dSFinley Xiao DCLK_VOP_SEL_24M << DCLK_VOP_SEL_SHIFT);
600ec20593dSFinley Xiao } else if (best_rate) {
601ec20593dSFinley Xiao rk_clrsetreg(&cru->clksel_con[8],
602ec20593dSFinley Xiao DCLK_VOP_SEL_MASK | DCLK_VOP_PLL_SEL_MASK |
603ec20593dSFinley Xiao DCLK_VOP_DIV_MASK,
604ec20593dSFinley Xiao DCLK_VOP_SEL_DIVOUT << DCLK_VOP_SEL_SHIFT |
605ec20593dSFinley Xiao best_sel << DCLK_VOP_PLL_SEL_SHIFT |
606ec20593dSFinley Xiao (best_div - 1) << DCLK_VOP_DIV_SHIFT);
607ec20593dSFinley Xiao } else {
608ec20593dSFinley Xiao printf("do not support this vop freq\n");
609ec20593dSFinley Xiao return -EINVAL;
610ec20593dSFinley Xiao }
611ec20593dSFinley Xiao
612fc4a6bd4SFinley Xiao return rk3308_vop_get_clk(clk);
613ec20593dSFinley Xiao }
614ec20593dSFinley Xiao
rk3308_bus_get_clk(struct rk3308_clk_priv * priv,ulong clk_id)6156c96c4c3SFinley Xiao static ulong rk3308_bus_get_clk(struct rk3308_clk_priv *priv, ulong clk_id)
6166c96c4c3SFinley Xiao {
6176c96c4c3SFinley Xiao struct rk3308_cru *cru = priv->cru;
6186c96c4c3SFinley Xiao u32 div, con, parent = priv->dpll_hz;
6196c96c4c3SFinley Xiao
6206c96c4c3SFinley Xiao switch (clk_id) {
6216c96c4c3SFinley Xiao case ACLK_BUS:
6226c96c4c3SFinley Xiao con = readl(&cru->clksel_con[5]);
6236c96c4c3SFinley Xiao div = (con & BUS_ACLK_DIV_MASK) >> BUS_ACLK_DIV_SHIFT;
6246c96c4c3SFinley Xiao break;
6256c96c4c3SFinley Xiao case HCLK_BUS:
6266c96c4c3SFinley Xiao con = readl(&cru->clksel_con[6]);
6276c96c4c3SFinley Xiao div = (con & BUS_HCLK_DIV_MASK) >> BUS_HCLK_DIV_SHIFT;
6286c96c4c3SFinley Xiao break;
6296c96c4c3SFinley Xiao case PCLK_BUS:
630221585fbSElaine Zhang case PCLK_WDT:
6316c96c4c3SFinley Xiao con = readl(&cru->clksel_con[6]);
6326c96c4c3SFinley Xiao div = (con & BUS_PCLK_DIV_MASK) >> BUS_PCLK_DIV_SHIFT;
6336c96c4c3SFinley Xiao break;
6346c96c4c3SFinley Xiao default:
6356c96c4c3SFinley Xiao return -ENOENT;
6366c96c4c3SFinley Xiao }
6376c96c4c3SFinley Xiao
6386c96c4c3SFinley Xiao return DIV_TO_RATE(parent, div);
6396c96c4c3SFinley Xiao }
6406c96c4c3SFinley Xiao
rk3308_bus_set_clk(struct rk3308_clk_priv * priv,ulong clk_id,ulong hz)6416c96c4c3SFinley Xiao static ulong rk3308_bus_set_clk(struct rk3308_clk_priv *priv, ulong clk_id,
6426c96c4c3SFinley Xiao ulong hz)
6436c96c4c3SFinley Xiao {
6446c96c4c3SFinley Xiao struct rk3308_cru *cru = priv->cru;
6456c96c4c3SFinley Xiao int src_clk_div;
6466c96c4c3SFinley Xiao
6476c96c4c3SFinley Xiao src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz);
648e27c054aSFinley Xiao assert(src_clk_div - 1 <= 31);
6496c96c4c3SFinley Xiao
6506c96c4c3SFinley Xiao /*
6516c96c4c3SFinley Xiao * select dpll as pd_bus bus clock source and
6526c96c4c3SFinley Xiao * set up dependent divisors for PCLK/HCLK and ACLK clocks.
6536c96c4c3SFinley Xiao */
6546c96c4c3SFinley Xiao switch (clk_id) {
6556c96c4c3SFinley Xiao case ACLK_BUS:
6566c96c4c3SFinley Xiao rk_clrsetreg(&cru->clksel_con[5],
6576c96c4c3SFinley Xiao BUS_PLL_SEL_MASK | BUS_ACLK_DIV_MASK,
6586c96c4c3SFinley Xiao BUS_PLL_SEL_DPLL << BUS_PLL_SEL_SHIFT |
6596c96c4c3SFinley Xiao (src_clk_div - 1) << BUS_ACLK_DIV_SHIFT);
6606c96c4c3SFinley Xiao break;
6616c96c4c3SFinley Xiao case HCLK_BUS:
6626c96c4c3SFinley Xiao rk_clrsetreg(&cru->clksel_con[6],
6636c96c4c3SFinley Xiao BUS_HCLK_DIV_MASK,
6646c96c4c3SFinley Xiao (src_clk_div - 1) << BUS_HCLK_DIV_SHIFT);
6656c96c4c3SFinley Xiao break;
6666c96c4c3SFinley Xiao case PCLK_BUS:
6676c96c4c3SFinley Xiao rk_clrsetreg(&cru->clksel_con[6],
6686c96c4c3SFinley Xiao BUS_PCLK_DIV_MASK,
6696c96c4c3SFinley Xiao (src_clk_div - 1) << BUS_PCLK_DIV_SHIFT);
6706c96c4c3SFinley Xiao break;
6716c96c4c3SFinley Xiao default:
6726c96c4c3SFinley Xiao printf("do not support this bus freq\n");
6736c96c4c3SFinley Xiao return -EINVAL;
6746c96c4c3SFinley Xiao }
6756c96c4c3SFinley Xiao
6766c96c4c3SFinley Xiao return rk3308_bus_get_clk(priv, clk_id);
6776c96c4c3SFinley Xiao }
6786c96c4c3SFinley Xiao
rk3308_peri_get_clk(struct rk3308_clk_priv * priv,ulong clk_id)6796c96c4c3SFinley Xiao static ulong rk3308_peri_get_clk(struct rk3308_clk_priv *priv, ulong clk_id)
6806c96c4c3SFinley Xiao {
6816c96c4c3SFinley Xiao struct rk3308_cru *cru = priv->cru;
6826c96c4c3SFinley Xiao u32 div, con, parent = priv->dpll_hz;
6836c96c4c3SFinley Xiao
6846c96c4c3SFinley Xiao switch (clk_id) {
6856c96c4c3SFinley Xiao case ACLK_PERI:
6866c96c4c3SFinley Xiao con = readl(&cru->clksel_con[36]);
6876c96c4c3SFinley Xiao div = (con & PERI_ACLK_DIV_MASK) >> PERI_ACLK_DIV_SHIFT;
6886c96c4c3SFinley Xiao break;
6896c96c4c3SFinley Xiao case HCLK_PERI:
6906c96c4c3SFinley Xiao con = readl(&cru->clksel_con[37]);
6916c96c4c3SFinley Xiao div = (con & PERI_HCLK_DIV_MASK) >> PERI_HCLK_DIV_SHIFT;
6926c96c4c3SFinley Xiao break;
6936c96c4c3SFinley Xiao case PCLK_PERI:
6946c96c4c3SFinley Xiao con = readl(&cru->clksel_con[37]);
6956c96c4c3SFinley Xiao div = (con & PERI_PCLK_DIV_MASK) >> PERI_PCLK_DIV_SHIFT;
6966c96c4c3SFinley Xiao break;
6976c96c4c3SFinley Xiao default:
6986c96c4c3SFinley Xiao return -ENOENT;
6996c96c4c3SFinley Xiao }
7006c96c4c3SFinley Xiao
7016c96c4c3SFinley Xiao return DIV_TO_RATE(parent, div);
7026c96c4c3SFinley Xiao }
7036c96c4c3SFinley Xiao
rk3308_peri_set_clk(struct rk3308_clk_priv * priv,ulong clk_id,ulong hz)7046c96c4c3SFinley Xiao static ulong rk3308_peri_set_clk(struct rk3308_clk_priv *priv, ulong clk_id,
7056c96c4c3SFinley Xiao ulong hz)
7066c96c4c3SFinley Xiao {
7076c96c4c3SFinley Xiao struct rk3308_cru *cru = priv->cru;
7086c96c4c3SFinley Xiao int src_clk_div;
7096c96c4c3SFinley Xiao
7106c96c4c3SFinley Xiao src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz);
711e27c054aSFinley Xiao assert(src_clk_div - 1 <= 31);
7126c96c4c3SFinley Xiao
7136c96c4c3SFinley Xiao /*
7146c96c4c3SFinley Xiao * select dpll as pd_peri bus clock source and
7156c96c4c3SFinley Xiao * set up dependent divisors for PCLK/HCLK and ACLK clocks.
7166c96c4c3SFinley Xiao */
7176c96c4c3SFinley Xiao switch (clk_id) {
7186c96c4c3SFinley Xiao case ACLK_PERI:
7196c96c4c3SFinley Xiao rk_clrsetreg(&cru->clksel_con[36],
7206c96c4c3SFinley Xiao PERI_PLL_SEL_MASK | PERI_ACLK_DIV_MASK,
7216c96c4c3SFinley Xiao PERI_PLL_DPLL << PERI_PLL_SEL_SHIFT |
7226c96c4c3SFinley Xiao (src_clk_div - 1) << PERI_ACLK_DIV_SHIFT);
7236c96c4c3SFinley Xiao break;
7246c96c4c3SFinley Xiao case HCLK_PERI:
7256c96c4c3SFinley Xiao rk_clrsetreg(&cru->clksel_con[37],
7266c96c4c3SFinley Xiao PERI_HCLK_DIV_MASK,
7276c96c4c3SFinley Xiao (src_clk_div - 1) << PERI_HCLK_DIV_SHIFT);
7286c96c4c3SFinley Xiao break;
7296c96c4c3SFinley Xiao case PCLK_PERI:
7306c96c4c3SFinley Xiao rk_clrsetreg(&cru->clksel_con[37],
7316c96c4c3SFinley Xiao PERI_PCLK_DIV_MASK,
7326c96c4c3SFinley Xiao (src_clk_div - 1) << PERI_PCLK_DIV_SHIFT);
7336c96c4c3SFinley Xiao break;
7346c96c4c3SFinley Xiao default:
7356c96c4c3SFinley Xiao printf("do not support this peri freq\n");
7366c96c4c3SFinley Xiao return -EINVAL;
7376c96c4c3SFinley Xiao }
7386c96c4c3SFinley Xiao
7396c96c4c3SFinley Xiao return rk3308_peri_get_clk(priv, clk_id);
7406c96c4c3SFinley Xiao }
7416c96c4c3SFinley Xiao
rk3308_audio_get_clk(struct rk3308_clk_priv * priv,ulong clk_id)7426c96c4c3SFinley Xiao static ulong rk3308_audio_get_clk(struct rk3308_clk_priv *priv, ulong clk_id)
7436c96c4c3SFinley Xiao {
7446c96c4c3SFinley Xiao struct rk3308_cru *cru = priv->cru;
7456c96c4c3SFinley Xiao u32 div, con, parent = priv->vpll0_hz;
7466c96c4c3SFinley Xiao
7476c96c4c3SFinley Xiao switch (clk_id) {
7486c96c4c3SFinley Xiao case HCLK_AUDIO:
7496c96c4c3SFinley Xiao con = readl(&cru->clksel_con[45]);
7506c96c4c3SFinley Xiao div = (con & AUDIO_HCLK_DIV_MASK) >> AUDIO_HCLK_DIV_SHIFT;
7516c96c4c3SFinley Xiao break;
7526c96c4c3SFinley Xiao case PCLK_AUDIO:
7536c96c4c3SFinley Xiao con = readl(&cru->clksel_con[45]);
7546c96c4c3SFinley Xiao div = (con & AUDIO_PCLK_DIV_MASK) >> AUDIO_PCLK_DIV_SHIFT;
7556c96c4c3SFinley Xiao break;
7566c96c4c3SFinley Xiao default:
7576c96c4c3SFinley Xiao return -ENOENT;
7586c96c4c3SFinley Xiao }
7596c96c4c3SFinley Xiao
7606c96c4c3SFinley Xiao return DIV_TO_RATE(parent, div);
7616c96c4c3SFinley Xiao }
7626c96c4c3SFinley Xiao
rk3308_audio_set_clk(struct rk3308_clk_priv * priv,ulong clk_id,ulong hz)7636c96c4c3SFinley Xiao static ulong rk3308_audio_set_clk(struct rk3308_clk_priv *priv, ulong clk_id,
7646c96c4c3SFinley Xiao ulong hz)
7656c96c4c3SFinley Xiao {
7666c96c4c3SFinley Xiao struct rk3308_cru *cru = priv->cru;
7676c96c4c3SFinley Xiao int src_clk_div;
7686c96c4c3SFinley Xiao
7696c96c4c3SFinley Xiao src_clk_div = DIV_ROUND_UP(priv->vpll0_hz, hz);
770e27c054aSFinley Xiao assert(src_clk_div - 1 <= 31);
7716c96c4c3SFinley Xiao
7726c96c4c3SFinley Xiao /*
7736c96c4c3SFinley Xiao * select vpll0 as audio bus clock source and
7746c96c4c3SFinley Xiao * set up dependent divisors for HCLK and PCLK clocks.
7756c96c4c3SFinley Xiao */
7766c96c4c3SFinley Xiao switch (clk_id) {
7776c96c4c3SFinley Xiao case HCLK_AUDIO:
7786c96c4c3SFinley Xiao rk_clrsetreg(&cru->clksel_con[45],
7796c96c4c3SFinley Xiao AUDIO_PLL_SEL_MASK | AUDIO_HCLK_DIV_MASK,
7806c96c4c3SFinley Xiao AUDIO_PLL_VPLL0 << AUDIO_PLL_SEL_SHIFT |
7816c96c4c3SFinley Xiao (src_clk_div - 1) << AUDIO_HCLK_DIV_SHIFT);
7826c96c4c3SFinley Xiao break;
7836c96c4c3SFinley Xiao case PCLK_AUDIO:
7846c96c4c3SFinley Xiao rk_clrsetreg(&cru->clksel_con[45],
7856c96c4c3SFinley Xiao AUDIO_PLL_SEL_MASK | AUDIO_PCLK_DIV_MASK,
7866c96c4c3SFinley Xiao AUDIO_PLL_VPLL0 << AUDIO_PLL_SEL_SHIFT |
7876c96c4c3SFinley Xiao (src_clk_div - 1) << AUDIO_PCLK_DIV_SHIFT);
7886c96c4c3SFinley Xiao break;
7896c96c4c3SFinley Xiao default:
7906c96c4c3SFinley Xiao printf("do not support this audio freq\n");
7916c96c4c3SFinley Xiao return -EINVAL;
7926c96c4c3SFinley Xiao }
7936c96c4c3SFinley Xiao
7946c96c4c3SFinley Xiao return rk3308_peri_get_clk(priv, clk_id);
7956c96c4c3SFinley Xiao }
7966c96c4c3SFinley Xiao
rk3308_crypto_get_clk(struct rk3308_clk_priv * priv,ulong clk_id)7970cde5925SElaine Zhang static ulong rk3308_crypto_get_clk(struct rk3308_clk_priv *priv, ulong clk_id)
7980cde5925SElaine Zhang {
7990cde5925SElaine Zhang struct rk3308_cru *cru = priv->cru;
8000cde5925SElaine Zhang u32 div, con, parent;
8010cde5925SElaine Zhang
8020cde5925SElaine Zhang switch (clk_id) {
8030cde5925SElaine Zhang case SCLK_CRYPTO:
8040cde5925SElaine Zhang con = readl(&cru->clksel_con[7]);
8050cde5925SElaine Zhang div = (con & CRYPTO_DIV_MASK) >> CRYPTO_DIV_SHIFT;
8060cde5925SElaine Zhang parent = priv->vpll0_hz;
8070cde5925SElaine Zhang break;
8080cde5925SElaine Zhang case SCLK_CRYPTO_APK:
8090cde5925SElaine Zhang con = readl(&cru->clksel_con[7]);
8100cde5925SElaine Zhang div = (con & CRYPTO_APK_DIV_MASK) >> CRYPTO_APK_DIV_SHIFT;
8110cde5925SElaine Zhang parent = priv->vpll0_hz;
8120cde5925SElaine Zhang break;
8130cde5925SElaine Zhang default:
8140cde5925SElaine Zhang return -ENOENT;
8150cde5925SElaine Zhang }
8160cde5925SElaine Zhang
8170cde5925SElaine Zhang return DIV_TO_RATE(parent, div);
8180cde5925SElaine Zhang }
8190cde5925SElaine Zhang
rk3308_crypto_set_clk(struct rk3308_clk_priv * priv,ulong clk_id,ulong hz)8200cde5925SElaine Zhang static ulong rk3308_crypto_set_clk(struct rk3308_clk_priv *priv, ulong clk_id,
8210cde5925SElaine Zhang ulong hz)
8220cde5925SElaine Zhang {
8230cde5925SElaine Zhang struct rk3308_cru *cru = priv->cru;
8240cde5925SElaine Zhang int src_clk_div;
8250cde5925SElaine Zhang
8260cde5925SElaine Zhang src_clk_div = DIV_ROUND_UP(priv->vpll0_hz, hz);
8270cde5925SElaine Zhang assert(src_clk_div - 1 <= 31);
8280cde5925SElaine Zhang
8290cde5925SElaine Zhang /*
8300cde5925SElaine Zhang * select gpll as crypto clock source and
8310cde5925SElaine Zhang * set up dependent divisors for crypto clocks.
8320cde5925SElaine Zhang */
8330cde5925SElaine Zhang switch (clk_id) {
8340cde5925SElaine Zhang case SCLK_CRYPTO:
8350cde5925SElaine Zhang rk_clrsetreg(&cru->clksel_con[7],
8360cde5925SElaine Zhang CRYPTO_PLL_SEL_MASK | CRYPTO_DIV_MASK,
8370cde5925SElaine Zhang CRYPTO_PLL_SEL_VPLL0 << CRYPTO_PLL_SEL_SHIFT |
8380cde5925SElaine Zhang (src_clk_div - 1) << CRYPTO_DIV_SHIFT);
8390cde5925SElaine Zhang break;
8400cde5925SElaine Zhang case SCLK_CRYPTO_APK:
8410cde5925SElaine Zhang rk_clrsetreg(&cru->clksel_con[7],
8420cde5925SElaine Zhang CRYPTO_APK_PLL_SEL_MASK | CRYPTO_APK_DIV_MASK,
8430cde5925SElaine Zhang CRYPTO_PLL_SEL_VPLL0 << CRYPTO_APK_SEL_SHIFT |
8440cde5925SElaine Zhang (src_clk_div - 1) << CRYPTO_APK_DIV_SHIFT);
8450cde5925SElaine Zhang break;
8460cde5925SElaine Zhang default:
8470cde5925SElaine Zhang printf("do not support this peri freq\n");
8480cde5925SElaine Zhang return -EINVAL;
8490cde5925SElaine Zhang }
8500cde5925SElaine Zhang
8510cde5925SElaine Zhang return rk3308_crypto_get_clk(priv, clk_id);
8520cde5925SElaine Zhang }
8530cde5925SElaine Zhang
rk3308_rtc32k_get_clk(struct rk3308_clk_priv * priv,ulong clk_id)8541bbed247SFinley Xiao static ulong rk3308_rtc32k_get_clk(struct rk3308_clk_priv *priv, ulong clk_id)
8551bbed247SFinley Xiao {
8561bbed247SFinley Xiao struct rk3308_cru *cru = priv->cru;
8571bbed247SFinley Xiao unsigned long m, n;
8581bbed247SFinley Xiao u32 con, fracdiv;
8591bbed247SFinley Xiao
8601bbed247SFinley Xiao con = readl(&cru->clksel_con[2]);
8611bbed247SFinley Xiao if ((con & CLK_RTC32K_SEL_MASK) >> CLK_RTC32K_SEL_SHIFT !=
8621bbed247SFinley Xiao CLK_RTC32K_FRAC_DIV)
8631bbed247SFinley Xiao return -EINVAL;
8641bbed247SFinley Xiao
8651bbed247SFinley Xiao fracdiv = readl(&cru->clksel_con[3]);
8661bbed247SFinley Xiao m = fracdiv & CLK_RTC32K_FRAC_NUMERATOR_MASK;
8671bbed247SFinley Xiao m >>= CLK_RTC32K_FRAC_NUMERATOR_SHIFT;
8681bbed247SFinley Xiao n = fracdiv & CLK_RTC32K_FRAC_DENOMINATOR_MASK;
8691bbed247SFinley Xiao n >>= CLK_RTC32K_FRAC_DENOMINATOR_SHIFT;
8701bbed247SFinley Xiao
8711bbed247SFinley Xiao return OSC_HZ * m / n;
8721bbed247SFinley Xiao }
8731bbed247SFinley Xiao
rk3308_rtc32k_set_clk(struct rk3308_clk_priv * priv,ulong clk_id,ulong hz)8741bbed247SFinley Xiao static ulong rk3308_rtc32k_set_clk(struct rk3308_clk_priv *priv, ulong clk_id,
8751bbed247SFinley Xiao ulong hz)
8761bbed247SFinley Xiao {
8771bbed247SFinley Xiao struct rk3308_cru *cru = priv->cru;
8781bbed247SFinley Xiao unsigned long m, n, val;
8791bbed247SFinley Xiao
8801bbed247SFinley Xiao rational_best_approximation(hz, OSC_HZ,
8811bbed247SFinley Xiao GENMASK(16 - 1, 0),
8821bbed247SFinley Xiao GENMASK(16 - 1, 0),
8831bbed247SFinley Xiao &m, &n);
8841bbed247SFinley Xiao val = m << CLK_RTC32K_FRAC_NUMERATOR_SHIFT | n;
8851bbed247SFinley Xiao writel(val, &cru->clksel_con[3]);
886daf1d5f9SElaine Zhang rk_clrsetreg(&cru->clksel_con[2], CLK_RTC32K_SEL_MASK,
8871bbed247SFinley Xiao CLK_RTC32K_FRAC_DIV << CLK_RTC32K_SEL_SHIFT);
8881bbed247SFinley Xiao
8891bbed247SFinley Xiao return rk3308_rtc32k_get_clk(priv, clk_id);
8901bbed247SFinley Xiao }
8911bbed247SFinley Xiao
rk3308_sclk_sfc_get_clk(struct rk3308_clk_priv * priv)892d0999afbSFinley Xiao static ulong rk3308_sclk_sfc_get_clk(struct rk3308_clk_priv *priv)
893d0999afbSFinley Xiao {
894d0999afbSFinley Xiao struct rk3308_cru *cru = priv->cru;
895d0999afbSFinley Xiao u32 div, con, sel, parent;
896d0999afbSFinley Xiao
897d0999afbSFinley Xiao con = readl(&cru->clksel_con[42]);
898d0999afbSFinley Xiao div = (con & SCLK_SFC_DIV_MASK) >> SCLK_SFC_DIV_SHIFT;
899d0999afbSFinley Xiao sel = (con & SCLK_SFC_SEL_MASK) >> SCLK_SFC_SEL_SHIFT;
900d0999afbSFinley Xiao
901d0999afbSFinley Xiao if (sel == SCLK_SFC_SEL_DPLL)
902d0999afbSFinley Xiao parent = priv->dpll_hz;
903d0999afbSFinley Xiao else if (sel == SCLK_SFC_SEL_VPLL0)
904d0999afbSFinley Xiao parent = priv->vpll0_hz;
905d0999afbSFinley Xiao else if (sel == SCLK_SFC_SEL_VPLL1)
906d0999afbSFinley Xiao parent = priv->vpll1_hz;
907d0999afbSFinley Xiao else
908d0999afbSFinley Xiao return -EINVAL;
909d0999afbSFinley Xiao
910d0999afbSFinley Xiao return DIV_TO_RATE(parent, div);
911d0999afbSFinley Xiao }
912d0999afbSFinley Xiao
rk3308_sclk_sfc_set_clk(struct rk3308_clk_priv * priv,uint hz)913d0999afbSFinley Xiao static ulong rk3308_sclk_sfc_set_clk(struct rk3308_clk_priv *priv, uint hz)
914d0999afbSFinley Xiao {
915d0999afbSFinley Xiao struct rk3308_cru *cru = priv->cru;
916d0999afbSFinley Xiao int src_clk_div;
917d0999afbSFinley Xiao
918d0999afbSFinley Xiao src_clk_div = DIV_ROUND_UP(priv->vpll0_hz, hz);
919d0999afbSFinley Xiao assert(src_clk_div - 1 <= 127);
920d0999afbSFinley Xiao
921d0999afbSFinley Xiao rk_clrsetreg(&cru->clksel_con[42],
922d0999afbSFinley Xiao SCLK_SFC_SEL_MASK | SCLK_SFC_DIV_MASK,
923d0999afbSFinley Xiao SCLK_SFC_SEL_VPLL0 << SCLK_SFC_SEL_SHIFT |
924d0999afbSFinley Xiao (src_clk_div - 1) << SCLK_SFC_DIV_SHIFT);
925d0999afbSFinley Xiao
926d0999afbSFinley Xiao return rk3308_sclk_sfc_get_clk(priv);
927d0999afbSFinley Xiao }
928d0999afbSFinley Xiao
rk3308_clk_get_rate(struct clk * clk)92954d254feSAndy Yan static ulong rk3308_clk_get_rate(struct clk *clk)
93054d254feSAndy Yan {
9311e180a56SFinley Xiao struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
93254d254feSAndy Yan ulong rate = 0;
93354d254feSAndy Yan
93454d254feSAndy Yan debug("%s id:%ld\n", __func__, clk->id);
93554d254feSAndy Yan
93654d254feSAndy Yan switch (clk->id) {
9371e180a56SFinley Xiao case PLL_APLL:
93803a6c029SFinley Xiao case ARMCLK:
93927ee7641SFinley Xiao rate = rockchip_pll_get_rate(&rk3308_pll_clks[APLL],
94027ee7641SFinley Xiao priv->cru, APLL);
9411e180a56SFinley Xiao break;
9421e180a56SFinley Xiao case PLL_DPLL:
94327ee7641SFinley Xiao rate = rockchip_pll_get_rate(&rk3308_pll_clks[DPLL],
94427ee7641SFinley Xiao priv->cru, DPLL);
9451e180a56SFinley Xiao break;
9461e180a56SFinley Xiao case PLL_VPLL0:
94727ee7641SFinley Xiao rate = rockchip_pll_get_rate(&rk3308_pll_clks[VPLL0],
94827ee7641SFinley Xiao priv->cru, VPLL0);
9491e180a56SFinley Xiao break;
9501e180a56SFinley Xiao case PLL_VPLL1:
95127ee7641SFinley Xiao rate = rockchip_pll_get_rate(&rk3308_pll_clks[VPLL1],
95227ee7641SFinley Xiao priv->cru, VPLL1);
9531e180a56SFinley Xiao break;
95454d254feSAndy Yan case HCLK_SDMMC:
95554d254feSAndy Yan case HCLK_EMMC:
95654d254feSAndy Yan case SCLK_SDMMC:
95754d254feSAndy Yan case SCLK_EMMC:
95854d254feSAndy Yan case SCLK_EMMC_SAMPLE:
959fc4a6bd4SFinley Xiao rate = rk3308_mmc_get_clk(clk);
96054d254feSAndy Yan break;
96154d254feSAndy Yan case SCLK_I2C0:
96254d254feSAndy Yan case SCLK_I2C1:
96354d254feSAndy Yan case SCLK_I2C2:
96454d254feSAndy Yan case SCLK_I2C3:
965fc4a6bd4SFinley Xiao rate = rk3308_i2c_get_clk(clk);
96654d254feSAndy Yan break;
96754d254feSAndy Yan case SCLK_SARADC:
968fc4a6bd4SFinley Xiao rate = rk3308_saradc_get_clk(clk);
96954d254feSAndy Yan break;
970cb3c37fcSElaine Zhang case SCLK_TSADC:
971cb3c37fcSElaine Zhang rate = rk3308_tsadc_get_clk(clk);
972cb3c37fcSElaine Zhang break;
97354d254feSAndy Yan case SCLK_SPI0:
97454d254feSAndy Yan case SCLK_SPI1:
975fc4a6bd4SFinley Xiao rate = rk3308_spi_get_clk(clk);
97654d254feSAndy Yan break;
977a8d570efSZhiZhan Chen case SCLK_PWM0:
978a8d570efSZhiZhan Chen case SCLK_PWM1:
979a8d570efSZhiZhan Chen case SCLK_PWM2:
980fc4a6bd4SFinley Xiao rate = rk3308_pwm_get_clk(clk);
98154d254feSAndy Yan break;
982ec20593dSFinley Xiao case DCLK_VOP:
983fc4a6bd4SFinley Xiao rate = rk3308_vop_get_clk(clk);
984ec20593dSFinley Xiao break;
9856c96c4c3SFinley Xiao case ACLK_BUS:
9866c96c4c3SFinley Xiao case HCLK_BUS:
9876c96c4c3SFinley Xiao case PCLK_BUS:
988221585fbSElaine Zhang case PCLK_WDT:
9896c96c4c3SFinley Xiao rate = rk3308_bus_get_clk(priv, clk->id);
9906c96c4c3SFinley Xiao break;
9916c96c4c3SFinley Xiao case ACLK_PERI:
9926c96c4c3SFinley Xiao case HCLK_PERI:
9936c96c4c3SFinley Xiao case PCLK_PERI:
9946c96c4c3SFinley Xiao rate = rk3308_peri_get_clk(priv, clk->id);
9956c96c4c3SFinley Xiao break;
9966c96c4c3SFinley Xiao case HCLK_AUDIO:
9976c96c4c3SFinley Xiao case PCLK_AUDIO:
9986c96c4c3SFinley Xiao rate = rk3308_audio_get_clk(priv, clk->id);
9996c96c4c3SFinley Xiao break;
10000cde5925SElaine Zhang case SCLK_CRYPTO:
10010cde5925SElaine Zhang case SCLK_CRYPTO_APK:
10020cde5925SElaine Zhang rate = rk3308_crypto_get_clk(priv, clk->id);
10030cde5925SElaine Zhang break;
10041bbed247SFinley Xiao case SCLK_RTC32K:
10051bbed247SFinley Xiao rate = rk3308_rtc32k_get_clk(priv, clk->id);
10061bbed247SFinley Xiao break;
1007d0999afbSFinley Xiao case SCLK_SFC:
1008d0999afbSFinley Xiao rate = rk3308_sclk_sfc_get_clk(priv);
1009d0999afbSFinley Xiao break;
101054d254feSAndy Yan default:
101154d254feSAndy Yan return -ENOENT;
101254d254feSAndy Yan }
101354d254feSAndy Yan
101454d254feSAndy Yan return rate;
101554d254feSAndy Yan }
101654d254feSAndy Yan
rk3308_clk_set_rate(struct clk * clk,ulong rate)101754d254feSAndy Yan static ulong rk3308_clk_set_rate(struct clk *clk, ulong rate)
101854d254feSAndy Yan {
10191e180a56SFinley Xiao struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
102054d254feSAndy Yan ulong ret = 0;
102154d254feSAndy Yan
102254d254feSAndy Yan debug("%s %ld %ld\n", __func__, clk->id, rate);
10231e180a56SFinley Xiao
102454d254feSAndy Yan switch (clk->id) {
10251e180a56SFinley Xiao case PLL_DPLL:
102627ee7641SFinley Xiao ret = rockchip_pll_set_rate(&rk3308_pll_clks[DPLL], priv->cru,
102727ee7641SFinley Xiao DPLL, rate);
102827ee7641SFinley Xiao priv->dpll_hz = rockchip_pll_get_rate(&rk3308_pll_clks[DPLL],
102927ee7641SFinley Xiao priv->cru, DPLL);
10301e180a56SFinley Xiao break;
103103a6c029SFinley Xiao case ARMCLK:
1032*0c8b06efSJoseph Chen /*
1033*0c8b06efSJoseph Chen * Why add `rate < rockchip_pll_get_rate(&rk3308_pll_clks[APLL],
1034*0c8b06efSJoseph Chen * priv->cru, APLL)` ?
1035*0c8b06efSJoseph Chen *
1036*0c8b06efSJoseph Chen * rockchip_wtemp_dvfs.c may decrease the arm freq, don't
1037*0c8b06efSJoseph Chen * limit this decrease operation here.
1038*0c8b06efSJoseph Chen */
1039*0c8b06efSJoseph Chen if (priv->armclk_hz ||
1040*0c8b06efSJoseph Chen (rate < rockchip_pll_get_rate(&rk3308_pll_clks[APLL],
1041*0c8b06efSJoseph Chen priv->cru, APLL)))
104203a6c029SFinley Xiao rk3308_armclk_set_clk(priv, rate);
104303a6c029SFinley Xiao priv->armclk_hz = rate;
104403a6c029SFinley Xiao break;
104554d254feSAndy Yan case HCLK_SDMMC:
104654d254feSAndy Yan case HCLK_EMMC:
104754d254feSAndy Yan case SCLK_SDMMC:
104854d254feSAndy Yan case SCLK_EMMC:
1049fc4a6bd4SFinley Xiao ret = rk3308_mmc_set_clk(clk, rate);
105054d254feSAndy Yan break;
105154d254feSAndy Yan case SCLK_I2C0:
105254d254feSAndy Yan case SCLK_I2C1:
105354d254feSAndy Yan case SCLK_I2C2:
105454d254feSAndy Yan case SCLK_I2C3:
1055fc4a6bd4SFinley Xiao ret = rk3308_i2c_set_clk(clk, rate);
105654d254feSAndy Yan break;
1057200683eaSDavid Wu case SCLK_MAC:
1058200683eaSDavid Wu ret = rk3308_mac_set_clk(clk, rate);
1059200683eaSDavid Wu break;
1060200683eaSDavid Wu case SCLK_MAC_RMII:
1061200683eaSDavid Wu ret = rk3308_mac_set_speed_clk(clk, rate);
1062200683eaSDavid Wu break;
106354d254feSAndy Yan case SCLK_SARADC:
1064fc4a6bd4SFinley Xiao ret = rk3308_saradc_set_clk(clk, rate);
106554d254feSAndy Yan break;
1066cb3c37fcSElaine Zhang case SCLK_TSADC:
1067cb3c37fcSElaine Zhang ret = rk3308_tsadc_set_clk(clk, rate);
1068cb3c37fcSElaine Zhang break;
106954d254feSAndy Yan case SCLK_SPI0:
107054d254feSAndy Yan case SCLK_SPI1:
1071fc4a6bd4SFinley Xiao ret = rk3308_spi_set_clk(clk, rate);
107254d254feSAndy Yan break;
1073a8d570efSZhiZhan Chen case SCLK_PWM0:
1074a8d570efSZhiZhan Chen case SCLK_PWM1:
1075a8d570efSZhiZhan Chen case SCLK_PWM2:
1076fc4a6bd4SFinley Xiao ret = rk3308_pwm_set_clk(clk, rate);
107754d254feSAndy Yan break;
1078ec20593dSFinley Xiao case DCLK_VOP:
1079fc4a6bd4SFinley Xiao ret = rk3308_vop_set_clk(clk, rate);
1080ec20593dSFinley Xiao break;
10816c96c4c3SFinley Xiao case ACLK_BUS:
10826c96c4c3SFinley Xiao case HCLK_BUS:
10836c96c4c3SFinley Xiao case PCLK_BUS:
10846c96c4c3SFinley Xiao rate = rk3308_bus_set_clk(priv, clk->id, rate);
10856c96c4c3SFinley Xiao break;
10866c96c4c3SFinley Xiao case ACLK_PERI:
10876c96c4c3SFinley Xiao case HCLK_PERI:
10886c96c4c3SFinley Xiao case PCLK_PERI:
10896c96c4c3SFinley Xiao rate = rk3308_peri_set_clk(priv, clk->id, rate);
10906c96c4c3SFinley Xiao break;
10916c96c4c3SFinley Xiao case HCLK_AUDIO:
10926c96c4c3SFinley Xiao case PCLK_AUDIO:
10936c96c4c3SFinley Xiao rate = rk3308_audio_set_clk(priv, clk->id, rate);
10946c96c4c3SFinley Xiao break;
10950cde5925SElaine Zhang case SCLK_CRYPTO:
10960cde5925SElaine Zhang case SCLK_CRYPTO_APK:
10970cde5925SElaine Zhang ret = rk3308_crypto_set_clk(priv, clk->id, rate);
10980cde5925SElaine Zhang break;
10991bbed247SFinley Xiao case SCLK_RTC32K:
11001bbed247SFinley Xiao ret = rk3308_rtc32k_set_clk(priv, clk->id, rate);
11011bbed247SFinley Xiao break;
1102d0999afbSFinley Xiao case SCLK_SFC:
1103d0999afbSFinley Xiao ret = rk3308_sclk_sfc_set_clk(priv, rate);
1104d0999afbSFinley Xiao break;
110554d254feSAndy Yan default:
110654d254feSAndy Yan return -ENOENT;
110754d254feSAndy Yan }
110854d254feSAndy Yan
110954d254feSAndy Yan return ret;
111054d254feSAndy Yan }
111154d254feSAndy Yan
111254d254feSAndy Yan #define ROCKCHIP_MMC_DELAY_SEL BIT(11)
111354d254feSAndy Yan #define ROCKCHIP_MMC_DEGREE_OFFSET 1
111454d254feSAndy Yan #define ROCKCHIP_MMC_DEGREE_MASK (0x3 << ROCKCHIP_MMC_DEGREE_OFFSET)
111554d254feSAndy Yan #define ROCKCHIP_MMC_DELAYNUM_OFFSET 3
111654d254feSAndy Yan #define ROCKCHIP_MMC_DELAYNUM_MASK (0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET)
111754d254feSAndy Yan
111854d254feSAndy Yan #define PSECS_PER_SEC 1000000000000LL
111954d254feSAndy Yan /*
112054d254feSAndy Yan * Each fine delay is between 44ps-77ps. Assume each fine delay is 60ps to
112154d254feSAndy Yan * simplify calculations. So 45degs could be anywhere between 33deg and 57.8deg.
112254d254feSAndy Yan */
112354d254feSAndy Yan #define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60
112454d254feSAndy Yan
rockchip_mmc_get_phase(struct clk * clk)112554d254feSAndy Yan int rockchip_mmc_get_phase(struct clk *clk)
112654d254feSAndy Yan {
112754d254feSAndy Yan struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
112854d254feSAndy Yan struct rk3308_cru *cru = priv->cru;
112954d254feSAndy Yan u32 raw_value, delay_num;
113054d254feSAndy Yan u16 degrees = 0;
113154d254feSAndy Yan ulong rate;
113254d254feSAndy Yan
113354d254feSAndy Yan rate = rk3308_clk_get_rate(clk);
113454d254feSAndy Yan
113554d254feSAndy Yan if (rate < 0)
113654d254feSAndy Yan return rate;
113754d254feSAndy Yan
113854d254feSAndy Yan if (clk->id == SCLK_EMMC_SAMPLE)
113954d254feSAndy Yan raw_value = readl(&cru->emmc_con[1]);
114054d254feSAndy Yan else
114154d254feSAndy Yan raw_value = readl(&cru->sdmmc_con[1]);
114254d254feSAndy Yan
114354d254feSAndy Yan raw_value &= ROCKCHIP_MMC_DEGREE_MASK;
114454d254feSAndy Yan degrees = (raw_value >> ROCKCHIP_MMC_DEGREE_OFFSET) * 90;
114554d254feSAndy Yan
114654d254feSAndy Yan if (raw_value & ROCKCHIP_MMC_DELAY_SEL) {
114754d254feSAndy Yan /* degrees/delaynum * 10000 */
114854d254feSAndy Yan unsigned long factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) *
114954d254feSAndy Yan 36 * (rate / 1000000);
115054d254feSAndy Yan
115154d254feSAndy Yan delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK);
115254d254feSAndy Yan delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET;
115354d254feSAndy Yan degrees += DIV_ROUND_CLOSEST(delay_num * factor, 10000);
115454d254feSAndy Yan }
115554d254feSAndy Yan
115654d254feSAndy Yan return degrees % 360;
115754d254feSAndy Yan
115854d254feSAndy Yan }
115954d254feSAndy Yan
rockchip_mmc_set_phase(struct clk * clk,u32 degrees)116054d254feSAndy Yan int rockchip_mmc_set_phase(struct clk *clk, u32 degrees)
116154d254feSAndy Yan {
116254d254feSAndy Yan struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
116354d254feSAndy Yan struct rk3308_cru *cru = priv->cru;
116454d254feSAndy Yan u8 nineties, remainder, delay_num;
116554d254feSAndy Yan u32 raw_value, delay;
116654d254feSAndy Yan ulong rate;
116754d254feSAndy Yan
116854d254feSAndy Yan rate = rk3308_clk_get_rate(clk);
116954d254feSAndy Yan
117054d254feSAndy Yan if (rate < 0)
117154d254feSAndy Yan return rate;
117254d254feSAndy Yan
117354d254feSAndy Yan nineties = degrees / 90;
117454d254feSAndy Yan remainder = (degrees % 90);
117554d254feSAndy Yan
117654d254feSAndy Yan /*
117754d254feSAndy Yan * Convert to delay; do a little extra work to make sure we
117854d254feSAndy Yan * don't overflow 32-bit / 64-bit numbers.
117954d254feSAndy Yan */
118054d254feSAndy Yan delay = 10000000; /* PSECS_PER_SEC / 10000 / 10 */
118154d254feSAndy Yan delay *= remainder;
118254d254feSAndy Yan delay = DIV_ROUND_CLOSEST(delay, (rate / 1000) * 36 *
118354d254feSAndy Yan (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10));
118454d254feSAndy Yan
118554d254feSAndy Yan delay_num = (u8)min_t(u32, delay, 255);
118654d254feSAndy Yan
118754d254feSAndy Yan raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0;
118854d254feSAndy Yan raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET;
118954d254feSAndy Yan raw_value |= nineties << ROCKCHIP_MMC_DEGREE_OFFSET;
119054d254feSAndy Yan
119154d254feSAndy Yan if (clk->id == SCLK_EMMC_SAMPLE)
119254d254feSAndy Yan writel(raw_value | 0xffff0000, &cru->emmc_con[1]);
119354d254feSAndy Yan else
119454d254feSAndy Yan writel(raw_value | 0xffff0000, &cru->sdmmc_con[1]);
119554d254feSAndy Yan
119654d254feSAndy Yan debug("mmc set_phase(%d) delay_nums=%u reg=%#x actual_degrees=%d\n",
119754d254feSAndy Yan degrees, delay_num, raw_value, rockchip_mmc_get_phase(clk));
119854d254feSAndy Yan
119954d254feSAndy Yan return 0;
120054d254feSAndy Yan
120154d254feSAndy Yan }
120254d254feSAndy Yan
rk3308_clk_get_phase(struct clk * clk)120354d254feSAndy Yan static int rk3308_clk_get_phase(struct clk *clk)
120454d254feSAndy Yan {
120554d254feSAndy Yan int ret;
120654d254feSAndy Yan
120754d254feSAndy Yan switch (clk->id) {
120854d254feSAndy Yan case SCLK_EMMC_SAMPLE:
120954d254feSAndy Yan case SCLK_SDMMC_SAMPLE:
121054d254feSAndy Yan ret = rockchip_mmc_get_phase(clk);
121154d254feSAndy Yan break;
121254d254feSAndy Yan default:
121354d254feSAndy Yan return -ENOENT;
121454d254feSAndy Yan }
121554d254feSAndy Yan
121654d254feSAndy Yan return ret;
121754d254feSAndy Yan }
121854d254feSAndy Yan
rk3308_clk_set_phase(struct clk * clk,int degrees)121954d254feSAndy Yan static int rk3308_clk_set_phase(struct clk *clk, int degrees)
122054d254feSAndy Yan {
122154d254feSAndy Yan int ret;
122254d254feSAndy Yan
122354d254feSAndy Yan switch (clk->id) {
122454d254feSAndy Yan case SCLK_EMMC_SAMPLE:
122554d254feSAndy Yan case SCLK_SDMMC_SAMPLE:
122654d254feSAndy Yan ret = rockchip_mmc_set_phase(clk, degrees);
122754d254feSAndy Yan break;
122854d254feSAndy Yan default:
122954d254feSAndy Yan return -ENOENT;
123054d254feSAndy Yan }
123154d254feSAndy Yan
123254d254feSAndy Yan return ret;
123354d254feSAndy Yan }
123454d254feSAndy Yan
rk3308_mac_set_parent(struct clk * clk,struct clk * parent)1235200683eaSDavid Wu static int __maybe_unused rk3308_mac_set_parent(struct clk *clk, struct clk *parent)
1236200683eaSDavid Wu {
1237200683eaSDavid Wu struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
1238200683eaSDavid Wu
1239200683eaSDavid Wu /*
1240200683eaSDavid Wu * If the requested parent is in the same clock-controller and
1241200683eaSDavid Wu * the id is SCLK_MAC_SRC, switch to the internal clock.
1242200683eaSDavid Wu */
1243200683eaSDavid Wu if (parent->id == SCLK_MAC_SRC) {
1244200683eaSDavid Wu debug("%s: switching RMII to SCLK_MAC\n", __func__);
1245200683eaSDavid Wu rk_clrreg(&priv->cru->clksel_con[43], BIT(14));
1246200683eaSDavid Wu } else {
1247200683eaSDavid Wu debug("%s: switching RMII to CLKIN\n", __func__);
1248200683eaSDavid Wu rk_setreg(&priv->cru->clksel_con[43], BIT(14));
1249200683eaSDavid Wu }
1250200683eaSDavid Wu
1251200683eaSDavid Wu return 0;
1252200683eaSDavid Wu }
1253200683eaSDavid Wu
rk3308_clk_set_parent(struct clk * clk,struct clk * parent)1254200683eaSDavid Wu static int __maybe_unused rk3308_clk_set_parent(struct clk *clk, struct clk *parent)
1255200683eaSDavid Wu {
1256200683eaSDavid Wu switch (clk->id) {
1257200683eaSDavid Wu case SCLK_MAC:
1258200683eaSDavid Wu return rk3308_mac_set_parent(clk, parent);
1259200683eaSDavid Wu default:
1260200683eaSDavid Wu break;
1261200683eaSDavid Wu }
1262200683eaSDavid Wu
1263200683eaSDavid Wu debug("%s: unsupported clk %ld\n", __func__, clk->id);
1264200683eaSDavid Wu return -ENOENT;
1265200683eaSDavid Wu }
1266200683eaSDavid Wu
126754d254feSAndy Yan static struct clk_ops rk3308_clk_ops = {
126854d254feSAndy Yan .get_rate = rk3308_clk_get_rate,
126954d254feSAndy Yan .set_rate = rk3308_clk_set_rate,
127054d254feSAndy Yan .get_phase = rk3308_clk_get_phase,
127154d254feSAndy Yan .set_phase = rk3308_clk_set_phase,
1272200683eaSDavid Wu #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
1273200683eaSDavid Wu .set_parent = rk3308_clk_set_parent,
1274200683eaSDavid Wu #endif
127554d254feSAndy Yan };
127654d254feSAndy Yan
rk3308_clk_init(struct udevice * dev)127794058cdfSFinley Xiao static void rk3308_clk_init(struct udevice *dev)
127894058cdfSFinley Xiao {
127994058cdfSFinley Xiao struct rk3308_clk_priv *priv = dev_get_priv(dev);
128094058cdfSFinley Xiao int ret;
128194058cdfSFinley Xiao
128294058cdfSFinley Xiao if (rockchip_pll_get_rate(&rk3308_pll_clks[APLL],
128394058cdfSFinley Xiao priv->cru, APLL) != APLL_HZ) {
128494058cdfSFinley Xiao ret = rk3308_armclk_set_clk(priv, APLL_HZ);
128594058cdfSFinley Xiao if (ret < 0)
128694058cdfSFinley Xiao printf("%s failed to set armclk rate\n", __func__);
128794058cdfSFinley Xiao }
128894058cdfSFinley Xiao
128994058cdfSFinley Xiao rk3308_clk_get_pll_rate(priv);
129094058cdfSFinley Xiao
129194058cdfSFinley Xiao rk3308_bus_set_clk(priv, ACLK_BUS, BUS_ACLK_HZ);
129294058cdfSFinley Xiao rk3308_bus_set_clk(priv, HCLK_BUS, BUS_HCLK_HZ);
129394058cdfSFinley Xiao rk3308_bus_set_clk(priv, PCLK_BUS, BUS_PCLK_HZ);
129494058cdfSFinley Xiao
129594058cdfSFinley Xiao rk3308_peri_set_clk(priv, ACLK_PERI, PERI_ACLK_HZ);
129694058cdfSFinley Xiao rk3308_peri_set_clk(priv, HCLK_PERI, PERI_HCLK_HZ);
129794058cdfSFinley Xiao rk3308_peri_set_clk(priv, PCLK_PERI, PERI_PCLK_HZ);
129894058cdfSFinley Xiao
129994058cdfSFinley Xiao rk3308_audio_set_clk(priv, HCLK_AUDIO, AUDIO_HCLK_HZ);
130094058cdfSFinley Xiao rk3308_audio_set_clk(priv, PCLK_AUDIO, AUDIO_PCLK_HZ);
130194058cdfSFinley Xiao }
130294058cdfSFinley Xiao
rk3308_clk_probe(struct udevice * dev)130354d254feSAndy Yan static int rk3308_clk_probe(struct udevice *dev)
130454d254feSAndy Yan {
130521ab40a8SFinley Xiao struct rk3308_clk_priv *priv = dev_get_priv(dev);
130694058cdfSFinley Xiao int ret;
130794058cdfSFinley Xiao
1308093fdd9fSElaine Zhang priv->sync_kernel = false;
1309093fdd9fSElaine Zhang if (!priv->armclk_enter_hz)
1310093fdd9fSElaine Zhang priv->armclk_enter_hz =
1311093fdd9fSElaine Zhang rockchip_pll_get_rate(&rk3308_pll_clks[APLL],
1312093fdd9fSElaine Zhang priv->cru, APLL);
131394058cdfSFinley Xiao rk3308_clk_init(dev);
1314093fdd9fSElaine Zhang if (!priv->armclk_init_hz)
1315093fdd9fSElaine Zhang priv->armclk_init_hz =
1316093fdd9fSElaine Zhang rockchip_pll_get_rate(&rk3308_pll_clks[APLL],
1317093fdd9fSElaine Zhang priv->cru, APLL);
131894058cdfSFinley Xiao
131994058cdfSFinley Xiao /* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */
132094058cdfSFinley Xiao ret = clk_set_defaults(dev);
132194058cdfSFinley Xiao if (ret)
132294058cdfSFinley Xiao debug("%s clk_set_defaults failed %d\n", __func__, ret);
1323093fdd9fSElaine Zhang else
1324093fdd9fSElaine Zhang priv->sync_kernel = true;
132554d254feSAndy Yan
132654d254feSAndy Yan return 0;
132754d254feSAndy Yan }
132854d254feSAndy Yan
rk3308_clk_ofdata_to_platdata(struct udevice * dev)132954d254feSAndy Yan static int rk3308_clk_ofdata_to_platdata(struct udevice *dev)
133054d254feSAndy Yan {
133154d254feSAndy Yan struct rk3308_clk_priv *priv = dev_get_priv(dev);
133254d254feSAndy Yan
133354d254feSAndy Yan priv->cru = dev_read_addr_ptr(dev);
133454d254feSAndy Yan
133554d254feSAndy Yan return 0;
133654d254feSAndy Yan }
133754d254feSAndy Yan
rk3308_clk_bind(struct udevice * dev)133854d254feSAndy Yan static int rk3308_clk_bind(struct udevice *dev)
133954d254feSAndy Yan {
134054d254feSAndy Yan int ret;
134154d254feSAndy Yan struct udevice *sys_child, *sf_child;
134254d254feSAndy Yan struct sysreset_reg *priv;
134354d254feSAndy Yan struct softreset_reg *sf_priv;
134454d254feSAndy Yan
134554d254feSAndy Yan /* The reset driver does not have a device node, so bind it here */
134654d254feSAndy Yan ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
134754d254feSAndy Yan &sys_child);
134854d254feSAndy Yan if (ret) {
134954d254feSAndy Yan debug("Warning: No sysreset driver: ret=%d\n", ret);
135054d254feSAndy Yan } else {
135154d254feSAndy Yan priv = malloc(sizeof(struct sysreset_reg));
135254d254feSAndy Yan priv->glb_srst_fst_value = offsetof(struct rk3308_cru,
135354d254feSAndy Yan glb_srst_fst);
135454d254feSAndy Yan priv->glb_srst_snd_value = offsetof(struct rk3308_cru,
135554d254feSAndy Yan glb_srst_snd);
135654d254feSAndy Yan sys_child->priv = priv;
135754d254feSAndy Yan }
135854d254feSAndy Yan
135954d254feSAndy Yan ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset",
136054d254feSAndy Yan dev_ofnode(dev), &sf_child);
136154d254feSAndy Yan if (ret) {
136254d254feSAndy Yan debug("Warning: No rockchip reset driver: ret=%d\n", ret);
136354d254feSAndy Yan } else {
136454d254feSAndy Yan sf_priv = malloc(sizeof(struct softreset_reg));
136554d254feSAndy Yan sf_priv->sf_reset_offset = offsetof(struct rk3308_cru,
136654d254feSAndy Yan softrst_con[0]);
136754d254feSAndy Yan sf_priv->sf_reset_num = 12;
136854d254feSAndy Yan sf_child->priv = sf_priv;
136954d254feSAndy Yan }
137054d254feSAndy Yan
137154d254feSAndy Yan return 0;
137254d254feSAndy Yan }
137354d254feSAndy Yan
137454d254feSAndy Yan static const struct udevice_id rk3308_clk_ids[] = {
137554d254feSAndy Yan { .compatible = "rockchip,rk3308-cru" },
137654d254feSAndy Yan { }
137754d254feSAndy Yan };
137854d254feSAndy Yan
137954d254feSAndy Yan U_BOOT_DRIVER(rockchip_rk3308_cru) = {
138054d254feSAndy Yan .name = "rockchip_rk3308_cru",
138154d254feSAndy Yan .id = UCLASS_CLK,
138254d254feSAndy Yan .of_match = rk3308_clk_ids,
138354d254feSAndy Yan .priv_auto_alloc_size = sizeof(struct rk3308_clk_priv),
138454d254feSAndy Yan .ofdata_to_platdata = rk3308_clk_ofdata_to_platdata,
138554d254feSAndy Yan .ops = &rk3308_clk_ops,
138654d254feSAndy Yan .bind = rk3308_clk_bind,
138754d254feSAndy Yan .probe = rk3308_clk_probe,
138854d254feSAndy Yan };
1389efdbac34SFinley Xiao
1390efdbac34SFinley Xiao /**
1391efdbac34SFinley Xiao * soc_clk_dump() - Print clock frequencies
1392efdbac34SFinley Xiao * Returns zero on success
1393efdbac34SFinley Xiao *
1394efdbac34SFinley Xiao * Implementation for the clk dump command.
1395efdbac34SFinley Xiao */
soc_clk_dump(void)1396efdbac34SFinley Xiao int soc_clk_dump(void)
1397efdbac34SFinley Xiao {
1398efdbac34SFinley Xiao struct udevice *cru_dev;
1399093fdd9fSElaine Zhang struct rk3308_clk_priv *priv;
1400efdbac34SFinley Xiao const struct rk3308_clk_info *clk_dump;
1401efdbac34SFinley Xiao struct clk clk;
1402efdbac34SFinley Xiao unsigned long clk_count = ARRAY_SIZE(clks_dump);
1403efdbac34SFinley Xiao unsigned long rate;
1404efdbac34SFinley Xiao int i, ret;
1405efdbac34SFinley Xiao
1406efdbac34SFinley Xiao ret = uclass_get_device_by_driver(UCLASS_CLK,
1407efdbac34SFinley Xiao DM_GET_DRIVER(rockchip_rk3308_cru),
1408efdbac34SFinley Xiao &cru_dev);
1409efdbac34SFinley Xiao if (ret) {
1410efdbac34SFinley Xiao printf("%s failed to get cru device\n", __func__);
1411efdbac34SFinley Xiao return ret;
1412efdbac34SFinley Xiao }
1413efdbac34SFinley Xiao
1414093fdd9fSElaine Zhang priv = dev_get_priv(cru_dev);
1415093fdd9fSElaine Zhang printf("CLK: (%s. arm: enter %lu KHz, init %lu KHz, kernel %lu%s)\n",
1416093fdd9fSElaine Zhang priv->sync_kernel ? "sync kernel" : "uboot",
1417093fdd9fSElaine Zhang priv->armclk_enter_hz / 1000,
1418093fdd9fSElaine Zhang priv->armclk_init_hz / 1000,
1419093fdd9fSElaine Zhang priv->set_armclk_rate ? priv->armclk_hz / 1000 : 0,
1420093fdd9fSElaine Zhang priv->set_armclk_rate ? " KHz" : "N/A");
1421efdbac34SFinley Xiao for (i = 0; i < clk_count; i++) {
1422efdbac34SFinley Xiao clk_dump = &clks_dump[i];
1423efdbac34SFinley Xiao if (clk_dump->name) {
1424efdbac34SFinley Xiao clk.id = clk_dump->id;
1425efdbac34SFinley Xiao ret = clk_request(cru_dev, &clk);
1426efdbac34SFinley Xiao if (ret < 0)
1427efdbac34SFinley Xiao return ret;
1428efdbac34SFinley Xiao
1429efdbac34SFinley Xiao rate = clk_get_rate(&clk);
1430efdbac34SFinley Xiao clk_free(&clk);
1431efdbac34SFinley Xiao if (i == 0) {
1432efdbac34SFinley Xiao if (rate < 0)
14334ffb5e6cSFinley Xiao printf(" %s %s\n", clk_dump->name,
1434efdbac34SFinley Xiao "unknown");
1435efdbac34SFinley Xiao else
14364ffb5e6cSFinley Xiao printf(" %s %lu KHz\n", clk_dump->name,
14374ffb5e6cSFinley Xiao rate / 1000);
1438efdbac34SFinley Xiao } else {
1439efdbac34SFinley Xiao if (rate < 0)
14404ffb5e6cSFinley Xiao printf(" %s %s\n", clk_dump->name,
1441efdbac34SFinley Xiao "unknown");
1442efdbac34SFinley Xiao else
14434ffb5e6cSFinley Xiao printf(" %s %lu KHz\n", clk_dump->name,
14444ffb5e6cSFinley Xiao rate / 1000);
1445efdbac34SFinley Xiao }
1446efdbac34SFinley Xiao }
1447efdbac34SFinley Xiao }
1448efdbac34SFinley Xiao
1449efdbac34SFinley Xiao return 0;
1450efdbac34SFinley Xiao }
1451