xref: /rk3399_rockchip-uboot/drivers/clk/rockchip/clk_rk1808.c (revision 41bb8b737ca44deae0c0cd3a81d67972ec27dc36)
145a3782aSElaine Zhang // SPDX-License-Identifier: GPL-2.0
245a3782aSElaine Zhang /*
345a3782aSElaine Zhang  * Copyright (c) 2018 Fuzhou Rockchip Electronics Co., Ltd
445a3782aSElaine Zhang  */
545a3782aSElaine Zhang 
645a3782aSElaine Zhang #include <common.h>
745a3782aSElaine Zhang #include <bitfield.h>
845a3782aSElaine Zhang #include <clk-uclass.h>
945a3782aSElaine Zhang #include <dm.h>
1045a3782aSElaine Zhang #include <errno.h>
1145a3782aSElaine Zhang #include <syscon.h>
1245a3782aSElaine Zhang #include <clk.h>
1345a3782aSElaine Zhang #include <asm/arch/clock.h>
1445a3782aSElaine Zhang #include <asm/arch/cru_rk1808.h>
1545a3782aSElaine Zhang #include <asm/arch/hardware.h>
1645a3782aSElaine Zhang #include <asm/io.h>
1745a3782aSElaine Zhang #include <dm/lists.h>
1845a3782aSElaine Zhang #include <dt-bindings/clock/rk1808-cru.h>
1945a3782aSElaine Zhang #include <div64.h>
2045a3782aSElaine Zhang 
2145a3782aSElaine Zhang DECLARE_GLOBAL_DATA_PTR;
2245a3782aSElaine Zhang 
2345a3782aSElaine Zhang #define RK1808_CPUCLK_RATE(_rate, _aclk_div, _pclk_div)		\
2445a3782aSElaine Zhang {								\
2545a3782aSElaine Zhang 	.rate	= _rate##U,					\
2645a3782aSElaine Zhang 	.aclk_div = _aclk_div,					\
2745a3782aSElaine Zhang 	.pclk_div = _pclk_div,					\
2845a3782aSElaine Zhang }
2945a3782aSElaine Zhang 
3045a3782aSElaine Zhang #define DIV_TO_RATE(input_rate, div)    ((input_rate) / ((div) + 1))
3145a3782aSElaine Zhang 
3245a3782aSElaine Zhang static struct rockchip_pll_rate_table rk1808_pll_rates[] = {
3345a3782aSElaine Zhang 	/* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
3445a3782aSElaine Zhang 	RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0),
3545a3782aSElaine Zhang 	RK3036_PLL_RATE(1188000000, 2, 99, 1, 1, 1, 0),
3645a3782aSElaine Zhang 	RK3036_PLL_RATE(1100000000, 12, 550, 1, 1, 1, 0),
3745a3782aSElaine Zhang 	RK3036_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0),
3845a3782aSElaine Zhang 	RK3036_PLL_RATE(1000000000, 6, 500, 2, 1, 1, 0),
3945a3782aSElaine Zhang 	RK3036_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0),
4045a3782aSElaine Zhang 	RK3036_PLL_RATE(800000000, 6, 400, 2, 1, 1, 0),
4145a3782aSElaine Zhang 	RK3036_PLL_RATE(600000000, 1, 75, 3, 1, 1, 0),
4245a3782aSElaine Zhang 	RK3036_PLL_RATE(594000000, 2, 99, 2, 1, 1, 0),
4345a3782aSElaine Zhang 	RK3036_PLL_RATE(500000000, 6, 250, 2, 1, 1, 0),
4445a3782aSElaine Zhang 	RK3036_PLL_RATE(200000000, 1, 200, 6, 4, 1, 0),
456259b22eSElaine Zhang 	RK3036_PLL_RATE(100000000, 1, 150, 6, 6, 1, 0),
4645a3782aSElaine Zhang 	{ /* sentinel */ },
4745a3782aSElaine Zhang };
4845a3782aSElaine Zhang 
4945a3782aSElaine Zhang #ifndef CONFIG_SPL_BUILD
5045a3782aSElaine Zhang #define RK1808_CLK_DUMP(_id, _name, _iscru)	\
5145a3782aSElaine Zhang {						\
5245a3782aSElaine Zhang 	.id = _id,				\
5345a3782aSElaine Zhang 	.name = _name,				\
5445a3782aSElaine Zhang 	.is_cru = _iscru,			\
5545a3782aSElaine Zhang }
5645a3782aSElaine Zhang 
5745a3782aSElaine Zhang static const struct rk1808_clk_info clks_dump[] = {
5845a3782aSElaine Zhang 	RK1808_CLK_DUMP(PLL_APLL, "apll", true),
5945a3782aSElaine Zhang 	RK1808_CLK_DUMP(PLL_DPLL, "dpll", true),
6045a3782aSElaine Zhang 	RK1808_CLK_DUMP(PLL_CPLL, "cpll", true),
6145a3782aSElaine Zhang 	RK1808_CLK_DUMP(PLL_GPLL, "gpll", true),
6245a3782aSElaine Zhang 	RK1808_CLK_DUMP(PLL_NPLL, "npll", true),
6345a3782aSElaine Zhang 	RK1808_CLK_DUMP(PLL_PPLL, "ppll", true),
6445a3782aSElaine Zhang 	RK1808_CLK_DUMP(HSCLK_BUS_PRE, "hsclk_bus", true),
6545a3782aSElaine Zhang 	RK1808_CLK_DUMP(MSCLK_BUS_PRE, "msclk_bus", true),
6645a3782aSElaine Zhang 	RK1808_CLK_DUMP(LSCLK_BUS_PRE, "lsclk_bus", true),
6745a3782aSElaine Zhang 	RK1808_CLK_DUMP(MSCLK_PERI, "msclk_peri", true),
6845a3782aSElaine Zhang 	RK1808_CLK_DUMP(LSCLK_PERI, "lsclk_peri", true),
6945a3782aSElaine Zhang };
7045a3782aSElaine Zhang #endif
7145a3782aSElaine Zhang 
7245a3782aSElaine Zhang static struct rockchip_cpu_rate_table rk1808_cpu_rates[] = {
7345a3782aSElaine Zhang 	RK1808_CPUCLK_RATE(1200000000, 1, 5),
7445a3782aSElaine Zhang 	RK1808_CPUCLK_RATE(1008000000, 1, 5),
7545a3782aSElaine Zhang 	RK1808_CPUCLK_RATE(816000000, 1, 3),
7645a3782aSElaine Zhang 	RK1808_CPUCLK_RATE(600000000, 1, 3),
7745a3782aSElaine Zhang };
7845a3782aSElaine Zhang 
7945a3782aSElaine Zhang static struct rockchip_pll_clock rk1808_pll_clks[] = {
8045a3782aSElaine Zhang 	[APLL] = PLL(pll_rk3036, PLL_APLL, RK1808_PLL_CON(0),
8145a3782aSElaine Zhang 		     RK1808_MODE_CON, 0, 10, 0, rk1808_pll_rates),
8245a3782aSElaine Zhang 	[DPLL] = PLL(pll_rk3036, PLL_DPLL, RK1808_PLL_CON(8),
8345a3782aSElaine Zhang 		     RK1808_MODE_CON, 2, 10, 0, NULL),
8445a3782aSElaine Zhang 	[CPLL] = PLL(pll_rk3036, PLL_CPLL, RK1808_PLL_CON(16),
8545a3782aSElaine Zhang 		    RK1808_MODE_CON, 4, 10, 0, rk1808_pll_rates),
8645a3782aSElaine Zhang 	[GPLL] = PLL(pll_rk3036, PLL_GPLL, RK1808_PLL_CON(24),
8745a3782aSElaine Zhang 		     RK1808_MODE_CON, 6, 10, 0, rk1808_pll_rates),
881ae6d6e5SElaine Zhang 	[NPLL] = PLL(pll_rk3036, PLL_NPLL, RK1808_PLL_CON(32),
8945a3782aSElaine Zhang 		     RK1808_MODE_CON, 8, 10, 0, rk1808_pll_rates),
9045a3782aSElaine Zhang 	[PPLL] = PLL(pll_rk3036, PLL_PPLL, RK1808_PMU_PLL_CON(0),
9145a3782aSElaine Zhang 		     RK1808_PMU_MODE_CON, 0, 10, 0, rk1808_pll_rates),
9245a3782aSElaine Zhang };
9345a3782aSElaine Zhang 
9445a3782aSElaine Zhang #ifndef CONFIG_SPL_BUILD
rk1808_i2c_get_clk(struct rk1808_clk_priv * priv,ulong clk_id)9545a3782aSElaine Zhang static ulong rk1808_i2c_get_clk(struct rk1808_clk_priv *priv, ulong clk_id)
9645a3782aSElaine Zhang {
9745a3782aSElaine Zhang 	struct rk1808_cru *cru = priv->cru;
9845a3782aSElaine Zhang 	u32 div, con;
9945a3782aSElaine Zhang 
10045a3782aSElaine Zhang 	switch (clk_id) {
10145a3782aSElaine Zhang 	case SCLK_PMU_I2C0:
10245a3782aSElaine Zhang 		con = readl(&cru->pmu_clksel_con[7]);
10345a3782aSElaine Zhang 		div = (con & CLK_I2C0_DIV_CON_MASK) >> CLK_I2C0_DIV_CON_SHIFT;
10445a3782aSElaine Zhang 		break;
10545a3782aSElaine Zhang 	case SCLK_I2C1:
10645a3782aSElaine Zhang 		con = readl(&cru->clksel_con[59]);
10745a3782aSElaine Zhang 		div = (con & CLK_I2C1_DIV_CON_MASK)  >> CLK_I2C1_DIV_CON_SHIFT;
10845a3782aSElaine Zhang 		break;
10945a3782aSElaine Zhang 	case SCLK_I2C2:
11045a3782aSElaine Zhang 		con = readl(&cru->clksel_con[59]);
11145a3782aSElaine Zhang 		div = (con & CLK_I2C2_DIV_CON_MASK) >> CLK_I2C2_DIV_CON_SHIFT;
11245a3782aSElaine Zhang 		break;
11345a3782aSElaine Zhang 	case SCLK_I2C3:
11445a3782aSElaine Zhang 		con = readl(&cru->clksel_con[60]);
11545a3782aSElaine Zhang 		div = (con & CLK_I2C3_DIV_CON_MASK) >> CLK_I2C3_DIV_CON_SHIFT;
11645a3782aSElaine Zhang 		break;
11745a3782aSElaine Zhang 	case SCLK_I2C4:
11845a3782aSElaine Zhang 		con = readl(&cru->clksel_con[71]);
11945a3782aSElaine Zhang 		div = (con & CLK_I2C4_DIV_CON_MASK) >> CLK_I2C4_DIV_CON_SHIFT;
12045a3782aSElaine Zhang 		break;
12145a3782aSElaine Zhang 	case SCLK_I2C5:
12245a3782aSElaine Zhang 		con = readl(&cru->clksel_con[71]);
12345a3782aSElaine Zhang 		div = (con & CLK_I2C5_DIV_CON_MASK) >> CLK_I2C5_DIV_CON_SHIFT;
12445a3782aSElaine Zhang 		break;
12545a3782aSElaine Zhang 	default:
12645a3782aSElaine Zhang 		printf("do not support this i2c bus\n");
12745a3782aSElaine Zhang 		return -EINVAL;
12845a3782aSElaine Zhang 	}
12945a3782aSElaine Zhang 
13045a3782aSElaine Zhang 	return DIV_TO_RATE(priv->gpll_hz, div);
13145a3782aSElaine Zhang }
13245a3782aSElaine Zhang 
rk1808_i2c_set_clk(struct rk1808_clk_priv * priv,ulong clk_id,uint hz)13345a3782aSElaine Zhang static ulong rk1808_i2c_set_clk(struct rk1808_clk_priv *priv,
13445a3782aSElaine Zhang 				ulong clk_id, uint hz)
13545a3782aSElaine Zhang {
13645a3782aSElaine Zhang 	struct rk1808_cru *cru = priv->cru;
13745a3782aSElaine Zhang 	int src_clk_div;
13845a3782aSElaine Zhang 
13945a3782aSElaine Zhang 	src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
14045a3782aSElaine Zhang 	assert(src_clk_div - 1 < 127);
14145a3782aSElaine Zhang 
14245a3782aSElaine Zhang 	switch (clk_id) {
14345a3782aSElaine Zhang 	case SCLK_PMU_I2C0:
14445a3782aSElaine Zhang 		rk_clrsetreg(&cru->pmu_clksel_con[7],
14545a3782aSElaine Zhang 			     CLK_I2C0_DIV_CON_MASK | CLK_I2C0_PLL_SEL_MASK,
14645a3782aSElaine Zhang 			     (src_clk_div - 1) << CLK_I2C0_DIV_CON_SHIFT |
14745a3782aSElaine Zhang 			     CLK_I2C0_PLL_SEL_PPLL << CLK_I2C0_PLL_SEL_SHIFT);
14845a3782aSElaine Zhang 		break;
14945a3782aSElaine Zhang 	case SCLK_I2C1:
15045a3782aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[59],
15145a3782aSElaine Zhang 			     CLK_I2C1_DIV_CON_MASK | CLK_I2C1_PLL_SEL_MASK,
15245a3782aSElaine Zhang 			     (src_clk_div - 1) << CLK_I2C1_DIV_CON_SHIFT |
15345a3782aSElaine Zhang 			     CLK_I2C_PLL_SEL_GPLL << CLK_I2C1_PLL_SEL_SHIFT);
15445a3782aSElaine Zhang 		break;
15545a3782aSElaine Zhang 	case SCLK_I2C2:
15645a3782aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[59],
15745a3782aSElaine Zhang 			     CLK_I2C2_DIV_CON_MASK | CLK_I2C2_PLL_SEL_MASK,
15845a3782aSElaine Zhang 			     (src_clk_div - 1) << CLK_I2C2_DIV_CON_SHIFT |
15945a3782aSElaine Zhang 			     CLK_I2C_PLL_SEL_GPLL << CLK_I2C2_PLL_SEL_SHIFT);
16045a3782aSElaine Zhang 		break;
16145a3782aSElaine Zhang 	case SCLK_I2C3:
16245a3782aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[60],
16345a3782aSElaine Zhang 			     CLK_I2C3_DIV_CON_MASK | CLK_I2C3_PLL_SEL_MASK,
16445a3782aSElaine Zhang 			     (src_clk_div - 1) << CLK_I2C3_DIV_CON_SHIFT |
16545a3782aSElaine Zhang 			     CLK_I2C_PLL_SEL_GPLL << CLK_I2C3_PLL_SEL_SHIFT);
16645a3782aSElaine Zhang 		break;
16745a3782aSElaine Zhang 	case SCLK_I2C4:
16845a3782aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[71],
16945a3782aSElaine Zhang 			     CLK_I2C4_DIV_CON_MASK | CLK_I2C4_PLL_SEL_MASK,
17045a3782aSElaine Zhang 			     (src_clk_div - 1) << CLK_I2C4_DIV_CON_SHIFT |
17145a3782aSElaine Zhang 			     CLK_I2C_PLL_SEL_GPLL << CLK_I2C4_PLL_SEL_SHIFT);
17245a3782aSElaine Zhang 		break;
17345a3782aSElaine Zhang 	case SCLK_I2C5:
17445a3782aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[71],
17545a3782aSElaine Zhang 			     CLK_I2C5_DIV_CON_MASK | CLK_I2C5_PLL_SEL_MASK,
17645a3782aSElaine Zhang 			     (src_clk_div - 1) << CLK_I2C5_DIV_CON_SHIFT |
17745a3782aSElaine Zhang 			     CLK_I2C_PLL_SEL_GPLL << CLK_I2C5_PLL_SEL_SHIFT);
17845a3782aSElaine Zhang 		break;
17945a3782aSElaine Zhang 	default:
18045a3782aSElaine Zhang 		printf("do not support this i2c bus\n");
18145a3782aSElaine Zhang 		return -EINVAL;
18245a3782aSElaine Zhang 	}
18345a3782aSElaine Zhang 
18445a3782aSElaine Zhang 	return rk1808_i2c_get_clk(priv, clk_id);
18545a3782aSElaine Zhang }
18645a3782aSElaine Zhang #endif
18745a3782aSElaine Zhang 
rk1808_mmc_get_clk(struct rk1808_clk_priv * priv,uint clk_id)18845a3782aSElaine Zhang static ulong rk1808_mmc_get_clk(struct rk1808_clk_priv *priv, uint clk_id)
18945a3782aSElaine Zhang {
19045a3782aSElaine Zhang 	struct rk1808_cru *cru = priv->cru;
19145a3782aSElaine Zhang 	u32 div, con, con_id;
19245a3782aSElaine Zhang 
19345a3782aSElaine Zhang 	switch (clk_id) {
19445a3782aSElaine Zhang 	case HCLK_SDMMC:
19545a3782aSElaine Zhang 	case SCLK_SDMMC:
19645a3782aSElaine Zhang 		con_id = 20;
19745a3782aSElaine Zhang 		break;
19845a3782aSElaine Zhang 	case HCLK_SDIO:
19945a3782aSElaine Zhang 	case SCLK_SDIO:
20045a3782aSElaine Zhang 		con_id = 22;
20145a3782aSElaine Zhang 		break;
20245a3782aSElaine Zhang 	case HCLK_EMMC:
20345a3782aSElaine Zhang 	case SCLK_EMMC:
20445a3782aSElaine Zhang 	case SCLK_EMMC_SAMPLE:
20545a3782aSElaine Zhang 		con_id = 24;
20645a3782aSElaine Zhang 		break;
20745a3782aSElaine Zhang 	default:
20845a3782aSElaine Zhang 		return -EINVAL;
20945a3782aSElaine Zhang 	}
21045a3782aSElaine Zhang 
21145a3782aSElaine Zhang 	con = readl(&cru->clksel_con[con_id]);
21245a3782aSElaine Zhang 	div = (con & EMMC_DIV_MASK) >> EMMC_DIV_SHIFT;
21345a3782aSElaine Zhang 
21445a3782aSElaine Zhang 	if ((con & EMMC_PLL_MASK) >> EMMC_PLL_SHIFT
21545a3782aSElaine Zhang 	    == EMMC_SEL_24M)
21645a3782aSElaine Zhang 		return DIV_TO_RATE(OSC_HZ, div) / 2;
21745a3782aSElaine Zhang 	else
21845a3782aSElaine Zhang 		return DIV_TO_RATE(priv->gpll_hz, div) / 2;
21945a3782aSElaine Zhang }
22045a3782aSElaine Zhang 
rk1808_mmc_set_clk(struct rk1808_clk_priv * priv,ulong clk_id,ulong set_rate)22145a3782aSElaine Zhang static ulong rk1808_mmc_set_clk(struct rk1808_clk_priv *priv,
22245a3782aSElaine Zhang 				ulong clk_id, ulong set_rate)
22345a3782aSElaine Zhang {
22445a3782aSElaine Zhang 	struct rk1808_cru *cru = priv->cru;
22545a3782aSElaine Zhang 	int src_clk_div;
22645a3782aSElaine Zhang 	u32 con_id;
22745a3782aSElaine Zhang 
22845a3782aSElaine Zhang 	switch (clk_id) {
22945a3782aSElaine Zhang 	case HCLK_SDMMC:
23045a3782aSElaine Zhang 	case SCLK_SDMMC:
23145a3782aSElaine Zhang 		con_id = 20;
23245a3782aSElaine Zhang 		break;
23345a3782aSElaine Zhang 	case HCLK_SDIO:
23445a3782aSElaine Zhang 	case SCLK_SDIO:
23545a3782aSElaine Zhang 		con_id = 22;
23645a3782aSElaine Zhang 		break;
23745a3782aSElaine Zhang 	case HCLK_EMMC:
23845a3782aSElaine Zhang 	case SCLK_EMMC:
23945a3782aSElaine Zhang 		con_id = 24;
24045a3782aSElaine Zhang 		break;
24145a3782aSElaine Zhang 	default:
24245a3782aSElaine Zhang 		return -EINVAL;
24345a3782aSElaine Zhang 	}
24445a3782aSElaine Zhang 
24545a3782aSElaine Zhang 	/* Select clk_sdmmc/emmc source from GPLL by default */
24645a3782aSElaine Zhang 	/* mmc clock defaulg div 2 internal, need provide double in cru */
24745a3782aSElaine Zhang 	src_clk_div = DIV_ROUND_UP(priv->gpll_hz / 2, set_rate);
24845a3782aSElaine Zhang 
24945a3782aSElaine Zhang 	if (src_clk_div > 127) {
25045a3782aSElaine Zhang 		/* use 24MHz source for 400KHz clock */
25145a3782aSElaine Zhang 		src_clk_div = DIV_ROUND_UP(OSC_HZ / 2, set_rate);
25245a3782aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[con_id],
25345a3782aSElaine Zhang 			     EMMC_PLL_MASK | EMMC_DIV_MASK,
25445a3782aSElaine Zhang 			     EMMC_SEL_24M << EMMC_PLL_SHIFT |
25545a3782aSElaine Zhang 			     (src_clk_div - 1) << EMMC_DIV_SHIFT);
25645a3782aSElaine Zhang 	} else {
25745a3782aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[con_id],
25845a3782aSElaine Zhang 			     EMMC_PLL_MASK | EMMC_DIV_MASK,
25945a3782aSElaine Zhang 			     EMMC_SEL_GPLL << EMMC_PLL_SHIFT |
26045a3782aSElaine Zhang 			     (src_clk_div - 1) << EMMC_DIV_SHIFT);
26145a3782aSElaine Zhang 	}
26245a3782aSElaine Zhang 	rk_clrsetreg(&cru->clksel_con[con_id + 1], EMMC_CLK_SEL_MASK,
26345a3782aSElaine Zhang 		     EMMC_CLK_SEL_EMMC);
26445a3782aSElaine Zhang 
26545a3782aSElaine Zhang 	return rk1808_mmc_get_clk(priv, clk_id);
26645a3782aSElaine Zhang }
26745a3782aSElaine Zhang 
rk1808_sfc_get_clk(struct rk1808_clk_priv * priv,uint clk_id)268c2fb06deSElaine Zhang static ulong rk1808_sfc_get_clk(struct rk1808_clk_priv *priv, uint clk_id)
269c2fb06deSElaine Zhang {
270c2fb06deSElaine Zhang 	struct rk1808_cru *cru = priv->cru;
271c2fb06deSElaine Zhang 	u32 div, con;
272c2fb06deSElaine Zhang 
273c2fb06deSElaine Zhang 	con = readl(&cru->clksel_con[26]);
274c2fb06deSElaine Zhang 	div = (con & SFC_DIV_CON_MASK) >> SFC_DIV_CON_SHIFT;
275c2fb06deSElaine Zhang 
276c2fb06deSElaine Zhang 	return DIV_TO_RATE(priv->gpll_hz, div);
277c2fb06deSElaine Zhang }
278c2fb06deSElaine Zhang 
rk1808_sfc_set_clk(struct rk1808_clk_priv * priv,ulong clk_id,ulong set_rate)279c2fb06deSElaine Zhang static ulong rk1808_sfc_set_clk(struct rk1808_clk_priv *priv,
280c2fb06deSElaine Zhang 				ulong clk_id, ulong set_rate)
281c2fb06deSElaine Zhang {
282c2fb06deSElaine Zhang 	struct rk1808_cru *cru = priv->cru;
283c2fb06deSElaine Zhang 	int src_clk_div;
284c2fb06deSElaine Zhang 
285c2fb06deSElaine Zhang 	src_clk_div = DIV_ROUND_UP(priv->gpll_hz, set_rate);
286c2fb06deSElaine Zhang 	rk_clrsetreg(&cru->clksel_con[26],
287c2fb06deSElaine Zhang 		     SFC_PLL_SEL_MASK | SFC_DIV_CON_MASK,
288c2fb06deSElaine Zhang 		     0 << SFC_PLL_SEL_SHIFT |
289c2fb06deSElaine Zhang 		     (src_clk_div - 1) << SFC_DIV_CON_SHIFT);
290c2fb06deSElaine Zhang 
291c2fb06deSElaine Zhang 	return rk1808_sfc_get_clk(priv, clk_id);
292c2fb06deSElaine Zhang }
293c2fb06deSElaine Zhang 
rk1808_saradc_get_clk(struct rk1808_clk_priv * priv)294*3732e2b8SJason Zhu static ulong rk1808_saradc_get_clk(struct rk1808_clk_priv *priv)
295*3732e2b8SJason Zhu {
296*3732e2b8SJason Zhu 	struct rk1808_cru *cru = priv->cru;
297*3732e2b8SJason Zhu 	u32 div, con;
298*3732e2b8SJason Zhu 
299*3732e2b8SJason Zhu 	con = readl(&cru->clksel_con[63]);
300*3732e2b8SJason Zhu 	div = con & CLK_SARADC_DIV_CON_MASK;
301*3732e2b8SJason Zhu 
302*3732e2b8SJason Zhu 	return DIV_TO_RATE(OSC_HZ, div);
303*3732e2b8SJason Zhu }
304*3732e2b8SJason Zhu 
rk1808_saradc_set_clk(struct rk1808_clk_priv * priv,uint hz)305*3732e2b8SJason Zhu static ulong rk1808_saradc_set_clk(struct rk1808_clk_priv *priv, uint hz)
306*3732e2b8SJason Zhu {
307*3732e2b8SJason Zhu 	struct rk1808_cru *cru = priv->cru;
308*3732e2b8SJason Zhu 	int src_clk_div;
309*3732e2b8SJason Zhu 
310*3732e2b8SJason Zhu 	src_clk_div = DIV_ROUND_UP(OSC_HZ, hz);
311*3732e2b8SJason Zhu 	assert(src_clk_div - 1 < 2047);
312*3732e2b8SJason Zhu 
313*3732e2b8SJason Zhu 	rk_clrsetreg(&cru->clksel_con[63],
314*3732e2b8SJason Zhu 		     CLK_SARADC_DIV_CON_MASK,
315*3732e2b8SJason Zhu 		     (src_clk_div - 1) << CLK_SARADC_DIV_CON_SHIFT);
316*3732e2b8SJason Zhu 
317*3732e2b8SJason Zhu 	return rk1808_saradc_get_clk(priv);
318*3732e2b8SJason Zhu }
319*3732e2b8SJason Zhu 
32045a3782aSElaine Zhang #ifndef CONFIG_SPL_BUILD
rk1808_pwm_get_clk(struct rk1808_clk_priv * priv,ulong clk_id)32145a3782aSElaine Zhang static ulong rk1808_pwm_get_clk(struct rk1808_clk_priv *priv, ulong clk_id)
32245a3782aSElaine Zhang {
32345a3782aSElaine Zhang 	struct rk1808_cru *cru = priv->cru;
32445a3782aSElaine Zhang 	u32 div, con;
32545a3782aSElaine Zhang 
32645a3782aSElaine Zhang 	switch (clk_id) {
32745a3782aSElaine Zhang 	case SCLK_PWM0:
32845a3782aSElaine Zhang 		con = readl(&cru->clksel_con[69]);
32945a3782aSElaine Zhang 		div = (con & CLK_PWM0_DIV_CON_MASK) >> CLK_PWM0_DIV_CON_SHIFT;
33045a3782aSElaine Zhang 		break;
33145a3782aSElaine Zhang 	case SCLK_PWM1:
33245a3782aSElaine Zhang 		con = readl(&cru->clksel_con[69]);
33345a3782aSElaine Zhang 		div = (con & CLK_PWM1_DIV_CON_MASK) >> CLK_PWM1_DIV_CON_SHIFT;
33445a3782aSElaine Zhang 		break;
33545a3782aSElaine Zhang 	case SCLK_PWM2:
33645a3782aSElaine Zhang 		con = readl(&cru->clksel_con[70]);
33745a3782aSElaine Zhang 		div = (con & CLK_PWM2_DIV_CON_MASK) >> CLK_PWM2_DIV_CON_SHIFT;
33845a3782aSElaine Zhang 		break;
33945a3782aSElaine Zhang 	default:
34045a3782aSElaine Zhang 		printf("do not support this pwm bus\n");
34145a3782aSElaine Zhang 		return -EINVAL;
34245a3782aSElaine Zhang 	}
34345a3782aSElaine Zhang 
34445a3782aSElaine Zhang 	return DIV_TO_RATE(priv->gpll_hz, div);
34545a3782aSElaine Zhang }
34645a3782aSElaine Zhang 
rk1808_pwm_set_clk(struct rk1808_clk_priv * priv,ulong clk_id,uint hz)34745a3782aSElaine Zhang static ulong rk1808_pwm_set_clk(struct rk1808_clk_priv *priv,
34845a3782aSElaine Zhang 				ulong clk_id, uint hz)
34945a3782aSElaine Zhang {
35045a3782aSElaine Zhang 	struct rk1808_cru *cru = priv->cru;
35145a3782aSElaine Zhang 	int src_clk_div;
35245a3782aSElaine Zhang 
35345a3782aSElaine Zhang 	src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
35445a3782aSElaine Zhang 	assert(src_clk_div - 1 < 127);
35545a3782aSElaine Zhang 
35645a3782aSElaine Zhang 	switch (clk_id) {
35745a3782aSElaine Zhang 	case SCLK_PWM0:
35845a3782aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[69],
35945a3782aSElaine Zhang 			     CLK_PWM0_DIV_CON_MASK | CLK_PWM0_PLL_SEL_MASK,
36045a3782aSElaine Zhang 			     (src_clk_div - 1) << CLK_PWM0_DIV_CON_SHIFT |
36145a3782aSElaine Zhang 			     CLK_PWM_PLL_SEL_GPLL << CLK_PWM0_PLL_SEL_SHIFT);
36245a3782aSElaine Zhang 		break;
36345a3782aSElaine Zhang 	case SCLK_PWM1:
36445a3782aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[69],
36545a3782aSElaine Zhang 			     CLK_PWM1_DIV_CON_MASK | CLK_PWM1_PLL_SEL_MASK,
36645a3782aSElaine Zhang 			     (src_clk_div - 1) << CLK_PWM1_DIV_CON_SHIFT |
36745a3782aSElaine Zhang 			     CLK_PWM_PLL_SEL_GPLL << CLK_PWM1_PLL_SEL_SHIFT);
36845a3782aSElaine Zhang 		break;
36945a3782aSElaine Zhang 	case SCLK_PWM2:
37045a3782aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[70],
37145a3782aSElaine Zhang 			     CLK_PWM2_DIV_CON_MASK | CLK_PWM2_PLL_SEL_MASK,
37245a3782aSElaine Zhang 			     (src_clk_div - 1) << CLK_PWM2_DIV_CON_SHIFT |
37345a3782aSElaine Zhang 			     CLK_PWM_PLL_SEL_GPLL << CLK_PWM2_PLL_SEL_SHIFT);
37445a3782aSElaine Zhang 		break;
37545a3782aSElaine Zhang 	default:
37645a3782aSElaine Zhang 		printf("do not support this pwm bus\n");
37745a3782aSElaine Zhang 		return -EINVAL;
37845a3782aSElaine Zhang 	}
37945a3782aSElaine Zhang 
38045a3782aSElaine Zhang 	return rk1808_pwm_get_clk(priv, clk_id);
38145a3782aSElaine Zhang }
38245a3782aSElaine Zhang 
rk1808_tsadc_get_clk(struct rk1808_clk_priv * priv)383cb3c37fcSElaine Zhang static ulong rk1808_tsadc_get_clk(struct rk1808_clk_priv *priv)
384cb3c37fcSElaine Zhang {
385cb3c37fcSElaine Zhang 	struct rk1808_cru *cru = priv->cru;
386cb3c37fcSElaine Zhang 	u32 div, con;
387cb3c37fcSElaine Zhang 
388cb3c37fcSElaine Zhang 	con = readl(&cru->clksel_con[62]);
389cb3c37fcSElaine Zhang 	div = con & CLK_SARADC_DIV_CON_MASK;
390cb3c37fcSElaine Zhang 
391cb3c37fcSElaine Zhang 	return DIV_TO_RATE(OSC_HZ, div);
392cb3c37fcSElaine Zhang }
393cb3c37fcSElaine Zhang 
rk1808_tsadc_set_clk(struct rk1808_clk_priv * priv,uint hz)394cb3c37fcSElaine Zhang static ulong rk1808_tsadc_set_clk(struct rk1808_clk_priv *priv, uint hz)
395cb3c37fcSElaine Zhang {
396cb3c37fcSElaine Zhang 	struct rk1808_cru *cru = priv->cru;
397cb3c37fcSElaine Zhang 	int src_clk_div;
398cb3c37fcSElaine Zhang 
399cb3c37fcSElaine Zhang 	src_clk_div = DIV_ROUND_UP(OSC_HZ, hz);
400cb3c37fcSElaine Zhang 	assert(src_clk_div - 1 < 2047);
401cb3c37fcSElaine Zhang 
402cb3c37fcSElaine Zhang 	rk_clrsetreg(&cru->clksel_con[62],
403cb3c37fcSElaine Zhang 		     CLK_SARADC_DIV_CON_MASK,
404cb3c37fcSElaine Zhang 		     (src_clk_div - 1) << CLK_SARADC_DIV_CON_SHIFT);
405cb3c37fcSElaine Zhang 
406cb3c37fcSElaine Zhang 	return rk1808_tsadc_get_clk(priv);
407cb3c37fcSElaine Zhang }
408cb3c37fcSElaine Zhang 
rk1808_spi_get_clk(struct rk1808_clk_priv * priv,ulong clk_id)40945a3782aSElaine Zhang static ulong rk1808_spi_get_clk(struct rk1808_clk_priv *priv, ulong clk_id)
41045a3782aSElaine Zhang {
41145a3782aSElaine Zhang 	struct rk1808_cru *cru = priv->cru;
41245a3782aSElaine Zhang 	u32 div, con;
41345a3782aSElaine Zhang 
41445a3782aSElaine Zhang 	switch (clk_id) {
41545a3782aSElaine Zhang 	case SCLK_SPI0:
41645a3782aSElaine Zhang 		con = readl(&cru->clksel_con[60]);
41745a3782aSElaine Zhang 		div = (con & CLK_SPI0_DIV_CON_MASK) >> CLK_SPI0_DIV_CON_SHIFT;
41845a3782aSElaine Zhang 		break;
41945a3782aSElaine Zhang 	case SCLK_SPI1:
42045a3782aSElaine Zhang 		con = readl(&cru->clksel_con[61]);
42145a3782aSElaine Zhang 		div = (con & CLK_SPI1_DIV_CON_MASK) >> CLK_SPI1_DIV_CON_SHIFT;
42245a3782aSElaine Zhang 		break;
42345a3782aSElaine Zhang 	case SCLK_SPI2:
42445a3782aSElaine Zhang 		con = readl(&cru->clksel_con[61]);
42545a3782aSElaine Zhang 		div = (con & CLK_SPI2_DIV_CON_MASK) >> CLK_SPI2_DIV_CON_SHIFT;
42645a3782aSElaine Zhang 		break;
42745a3782aSElaine Zhang 	default:
42845a3782aSElaine Zhang 		printf("do not support this pwm bus\n");
42945a3782aSElaine Zhang 		return -EINVAL;
43045a3782aSElaine Zhang 	}
43145a3782aSElaine Zhang 
43245a3782aSElaine Zhang 	return DIV_TO_RATE(priv->gpll_hz, div);
43345a3782aSElaine Zhang }
43445a3782aSElaine Zhang 
rk1808_spi_set_clk(struct rk1808_clk_priv * priv,ulong clk_id,uint hz)43545a3782aSElaine Zhang static ulong rk1808_spi_set_clk(struct rk1808_clk_priv *priv,
43645a3782aSElaine Zhang 				ulong clk_id, uint hz)
43745a3782aSElaine Zhang {
43845a3782aSElaine Zhang 	struct rk1808_cru *cru = priv->cru;
43945a3782aSElaine Zhang 	int src_clk_div;
44045a3782aSElaine Zhang 
44145a3782aSElaine Zhang 	src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
44245a3782aSElaine Zhang 	assert(src_clk_div - 1 < 127);
44345a3782aSElaine Zhang 
44445a3782aSElaine Zhang 	switch (clk_id) {
44545a3782aSElaine Zhang 	case SCLK_SPI0:
44645a3782aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[60],
44745a3782aSElaine Zhang 			     CLK_SPI0_DIV_CON_MASK | CLK_SPI0_PLL_SEL_MASK,
44845a3782aSElaine Zhang 			     (src_clk_div - 1) << CLK_SPI0_DIV_CON_SHIFT |
44945a3782aSElaine Zhang 			     CLK_SPI_PLL_SEL_GPLL << CLK_SPI0_PLL_SEL_SHIFT);
45045a3782aSElaine Zhang 		break;
45145a3782aSElaine Zhang 	case SCLK_SPI1:
45245a3782aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[61],
45345a3782aSElaine Zhang 			     CLK_SPI1_DIV_CON_MASK | CLK_SPI1_PLL_SEL_MASK,
45445a3782aSElaine Zhang 			     (src_clk_div - 1) << CLK_SPI1_DIV_CON_SHIFT |
45545a3782aSElaine Zhang 			     CLK_SPI_PLL_SEL_GPLL << CLK_SPI1_PLL_SEL_SHIFT);
45645a3782aSElaine Zhang 		break;
45745a3782aSElaine Zhang 	case SCLK_SPI2:
45845a3782aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[61],
45945a3782aSElaine Zhang 			     CLK_SPI2_DIV_CON_MASK | CLK_SPI2_PLL_SEL_MASK,
46045a3782aSElaine Zhang 			     (src_clk_div - 1) << CLK_SPI2_DIV_CON_SHIFT |
46145a3782aSElaine Zhang 			     CLK_SPI_PLL_SEL_GPLL << CLK_SPI2_PLL_SEL_SHIFT);
46245a3782aSElaine Zhang 		break;
46345a3782aSElaine Zhang 	default:
46445a3782aSElaine Zhang 		printf("do not support this pwm bus\n");
46545a3782aSElaine Zhang 		return -EINVAL;
46645a3782aSElaine Zhang 	}
46745a3782aSElaine Zhang 
46845a3782aSElaine Zhang 	return rk1808_spi_get_clk(priv, clk_id);
46945a3782aSElaine Zhang }
47045a3782aSElaine Zhang 
47145a3782aSElaine Zhang #define RK1808_VOP_PLL_LIMIT_FREQ		600 * 1000000
rk1808_vop_get_clk(struct rk1808_clk_priv * priv,ulong clk_id)47245a3782aSElaine Zhang static ulong rk1808_vop_get_clk(struct rk1808_clk_priv *priv, ulong clk_id)
47345a3782aSElaine Zhang {
47445a3782aSElaine Zhang 	struct rk1808_cru *cru = priv->cru;
47545a3782aSElaine Zhang 	u32 div, con, parent;
47645a3782aSElaine Zhang 
47745a3782aSElaine Zhang 	switch (clk_id) {
47845a3782aSElaine Zhang 	case ACLK_VOPRAW:
47945a3782aSElaine Zhang 	case ACLK_VOPLITE:
48045a3782aSElaine Zhang 		con = readl(&cru->clksel_con[4]);
48145a3782aSElaine Zhang 		div = (con & ACLK_VOP_DIV_CON_MASK) >> ACLK_VOP_DIV_CON_SHIFT;
48245a3782aSElaine Zhang 		parent = priv->gpll_hz;
48345a3782aSElaine Zhang 		break;
48445a3782aSElaine Zhang 	case HCLK_VOPRAW:
48545a3782aSElaine Zhang 	case HCLK_VOPLITE:
48645a3782aSElaine Zhang 		parent = rk1808_vop_get_clk(priv, ACLK_VOPRAW);
48745a3782aSElaine Zhang 		con = readl(&cru->clksel_con[4]);
48845a3782aSElaine Zhang 		div = (con & HCLK_VOP_DIV_CON_MASK) >> HCLK_VOP_DIV_CON_SHIFT;
48945a3782aSElaine Zhang 		break;
49045a3782aSElaine Zhang 	case DCLK_VOPRAW:
49145a3782aSElaine Zhang 		con = readl(&cru->clksel_con[5]);
49245a3782aSElaine Zhang 		div = con & DCLK_VOPRAW_DIV_CON_MASK;
49345a3782aSElaine Zhang 		parent = rockchip_pll_get_rate(&rk1808_pll_clks[NPLL],
49445a3782aSElaine Zhang 					       priv->cru, NPLL);
49545a3782aSElaine Zhang 		break;
49645a3782aSElaine Zhang 	case DCLK_VOPLITE:
49745a3782aSElaine Zhang 		con = readl(&cru->clksel_con[7]);
49845a3782aSElaine Zhang 		div = con & DCLK_VOPLITE_DIV_CON_MASK;
49945a3782aSElaine Zhang 		parent = (con & DCLK_VOPLITE_PLL_SEL_MASK) >>
50045a3782aSElaine Zhang 			 DCLK_VOPLITE_PLL_SEL_SHIFT;
50145a3782aSElaine Zhang 		if (parent == DCLK_VOPLITE_PLL_SEL_NPLL)
50245a3782aSElaine Zhang 			parent = rockchip_pll_get_rate(&rk1808_pll_clks[NPLL],
50345a3782aSElaine Zhang 						       priv->cru, NPLL);
50445a3782aSElaine Zhang 		else if (parent == DCLK_VOPLITE_PLL_SEL_CPLL)
50545a3782aSElaine Zhang 			parent = priv->cpll_hz;
50645a3782aSElaine Zhang 		else
50745a3782aSElaine Zhang 			parent = priv->gpll_hz;
50845a3782aSElaine Zhang 		break;
50945a3782aSElaine Zhang 	default:
51045a3782aSElaine Zhang 		return -ENOENT;
51145a3782aSElaine Zhang 	}
51245a3782aSElaine Zhang 
51345a3782aSElaine Zhang 	return DIV_TO_RATE(parent, div);
51445a3782aSElaine Zhang }
51545a3782aSElaine Zhang 
rk1808_vop_set_clk(struct rk1808_clk_priv * priv,ulong clk_id,uint hz)51645a3782aSElaine Zhang static ulong rk1808_vop_set_clk(struct rk1808_clk_priv *priv,
51745a3782aSElaine Zhang 				ulong clk_id, uint hz)
51845a3782aSElaine Zhang {
51945a3782aSElaine Zhang 	struct rk1808_cru *cru = priv->cru;
52045a3782aSElaine Zhang 	int src_clk_div, parent;
52145a3782aSElaine Zhang 
52245a3782aSElaine Zhang 	src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
52345a3782aSElaine Zhang 	assert(src_clk_div - 1 < 31);
52445a3782aSElaine Zhang 
52545a3782aSElaine Zhang 	switch (clk_id) {
52645a3782aSElaine Zhang 	case ACLK_VOPRAW:
52745a3782aSElaine Zhang 	case ACLK_VOPLITE:
52845a3782aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[4],
52945a3782aSElaine Zhang 			     ACLK_VOP_PLL_SEL_MASK | ACLK_VOP_DIV_CON_MASK,
53045a3782aSElaine Zhang 			     ACLK_VOP_PLL_SEL_GPLL << ACLK_VOP_PLL_SEL_SHIFT |
53145a3782aSElaine Zhang 			     (src_clk_div - 1) << ACLK_VOP_DIV_CON_SHIFT);
53245a3782aSElaine Zhang 		break;
53345a3782aSElaine Zhang 	case HCLK_VOPRAW:
53445a3782aSElaine Zhang 	case HCLK_VOPLITE:
53545a3782aSElaine Zhang 		src_clk_div =
53645a3782aSElaine Zhang 			DIV_ROUND_UP(rk1808_vop_get_clk(priv, ACLK_VOPRAW), hz);
53745a3782aSElaine Zhang 		assert(src_clk_div - 1 < 15);
53845a3782aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[4],
53945a3782aSElaine Zhang 			     HCLK_VOP_DIV_CON_MASK,
54045a3782aSElaine Zhang 			     (src_clk_div - 1) << HCLK_VOP_DIV_CON_SHIFT);
54145a3782aSElaine Zhang 		break;
54245a3782aSElaine Zhang 	case DCLK_VOPRAW:
54345a3782aSElaine Zhang 		/*
54445a3782aSElaine Zhang 		 * vopb dclk source from npll, and equals to
54545a3782aSElaine Zhang 		 */
54645a3782aSElaine Zhang 		src_clk_div = DIV_ROUND_UP(RK1808_VOP_PLL_LIMIT_FREQ, hz);
54745a3782aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[5],
54845a3782aSElaine Zhang 			     DCLK_VOPRAW_SEL_MASK |
54945a3782aSElaine Zhang 			     DCLK_VOPRAW_PLL_SEL_MASK |
55045a3782aSElaine Zhang 			     DCLK_VOPRAW_DIV_CON_MASK,
551fab09610SElaine Zhang 			     (DCLK_VOPRAW_SEL_VOPRAW <<
552fab09610SElaine Zhang 			     DCLK_VOPRAW_SEL_SHIFT) |
553fab09610SElaine Zhang 			     (DCLK_VOPRAW_PLL_SEL_NPLL <<
554fab09610SElaine Zhang 			     DCLK_VOPRAW_PLL_SEL_SHIFT) |
555fab09610SElaine Zhang 			     ((src_clk_div - 1) << DCLK_VOPRAW_DIV_CON_SHIFT));
5561ae6d6e5SElaine Zhang 		rockchip_pll_set_rate(&rk1808_pll_clks[NPLL],
5571ae6d6e5SElaine Zhang 				      priv->cru, NPLL, src_clk_div * hz);
5581ae6d6e5SElaine Zhang 
55945a3782aSElaine Zhang 		break;
56045a3782aSElaine Zhang 	case DCLK_VOPLITE:
56145a3782aSElaine Zhang 		/*
56245a3782aSElaine Zhang 		 * vopl dclk source from cpll, and equals to
56345a3782aSElaine Zhang 		 */
564fab09610SElaine Zhang 		if (!(priv->cpll_hz % hz)) {
56545a3782aSElaine Zhang 			parent = DCLK_VOPLITE_PLL_SEL_CPLL;
566fab09610SElaine Zhang 			src_clk_div = DIV_ROUND_UP(priv->cpll_hz, hz);
567fab09610SElaine Zhang 		} else if (!(priv->gpll_hz % hz)) {
56845a3782aSElaine Zhang 			parent = DCLK_VOPLITE_PLL_SEL_GPLL;
56945a3782aSElaine Zhang 			src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
570fab09610SElaine Zhang 		} else {
571fab09610SElaine Zhang 			parent = DCLK_VOPLITE_PLL_SEL_NPLL;
572fab09610SElaine Zhang 			src_clk_div = DIV_ROUND_UP(RK1808_VOP_PLL_LIMIT_FREQ,
573fab09610SElaine Zhang 						   hz);
574fab09610SElaine Zhang 			rockchip_pll_set_rate(&rk1808_pll_clks[NPLL],
575fab09610SElaine Zhang 					      priv->cru, NPLL,
576fab09610SElaine Zhang 					      src_clk_div * hz);
57745a3782aSElaine Zhang 		}
57845a3782aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[7],
57945a3782aSElaine Zhang 			     DCLK_VOPLITE_SEL_MASK | DCLK_VOPLITE_PLL_SEL_MASK |
58045a3782aSElaine Zhang 			     DCLK_VOPLITE_DIV_CON_MASK,
5811ae6d6e5SElaine Zhang 			     (DCLK_VOPLITE_SEL_VOPRAW <<
5821ae6d6e5SElaine Zhang 			     DCLK_VOPLITE_SEL_SHIFT) |
5831ae6d6e5SElaine Zhang 			     (parent << DCLK_VOPLITE_PLL_SEL_SHIFT) |
5841ae6d6e5SElaine Zhang 			     ((src_clk_div - 1) << DCLK_VOPLITE_DIV_CON_SHIFT));
58545a3782aSElaine Zhang 		break;
58645a3782aSElaine Zhang 	default:
58745a3782aSElaine Zhang 		printf("do not support this vop freq\n");
58845a3782aSElaine Zhang 		return -EINVAL;
58945a3782aSElaine Zhang 	}
59045a3782aSElaine Zhang 
59145a3782aSElaine Zhang 	return rk1808_vop_get_clk(priv, clk_id);
59245a3782aSElaine Zhang }
593b9f59722SElaine Zhang 
rk1808_mac_set_clk(struct clk * clk,uint hz)594b9f59722SElaine Zhang static ulong rk1808_mac_set_clk(struct clk *clk, uint hz)
595b9f59722SElaine Zhang {
596b9f59722SElaine Zhang 	struct rk1808_clk_priv *priv = dev_get_priv(clk->dev);
597b9f59722SElaine Zhang 	struct rk1808_cru *cru = priv->cru;
598b9f59722SElaine Zhang 	u32 con = readl(&cru->clksel_con[26]);
599b9f59722SElaine Zhang 	ulong pll_rate;
600b9f59722SElaine Zhang 	u8 div;
601b9f59722SElaine Zhang 
602b9f59722SElaine Zhang 	if ((con >> GMAC_PLL_SEL_SHIFT) & GMAC_PLL_SEL_NPLL)
603b9f59722SElaine Zhang 		pll_rate = rockchip_pll_get_rate(&rk1808_pll_clks[NPLL],
604b9f59722SElaine Zhang 						 priv->cru, NPLL);
605b9f59722SElaine Zhang 	else if ((con >> GMAC_PLL_SEL_SHIFT) & GMAC_PLL_SEL_PPLL)
606b9f59722SElaine Zhang 		pll_rate = rockchip_pll_get_rate(&rk1808_pll_clks[PPLL],
607b9f59722SElaine Zhang 						 priv->cru, PPLL);
608b9f59722SElaine Zhang 	else
609b9f59722SElaine Zhang 		pll_rate = rockchip_pll_get_rate(&rk1808_pll_clks[CPLL],
610b9f59722SElaine Zhang 						 priv->cru, CPLL);
611b9f59722SElaine Zhang 
612b9f59722SElaine Zhang 	/*default set 50MHZ for gmac*/
613b9f59722SElaine Zhang 	if (!hz)
614b9f59722SElaine Zhang 		hz = 50000000;
615b9f59722SElaine Zhang 
616b9f59722SElaine Zhang 	div = DIV_ROUND_UP(pll_rate, hz) - 1;
617b9f59722SElaine Zhang 	assert(div < 32);
618b9f59722SElaine Zhang 	rk_clrsetreg(&cru->clksel_con[26], CLK_GMAC_DIV_MASK,
619b9f59722SElaine Zhang 		     div << CLK_GMAC_DIV_SHIFT);
620b9f59722SElaine Zhang 
621b9f59722SElaine Zhang 	return DIV_TO_RATE(pll_rate, div);
622b9f59722SElaine Zhang }
623b9f59722SElaine Zhang 
rk1808_mac_set_speed_clk(struct clk * clk,ulong clk_id,uint hz)624b9f59722SElaine Zhang static int rk1808_mac_set_speed_clk(struct clk *clk, ulong clk_id, uint hz)
625b9f59722SElaine Zhang {
626b9f59722SElaine Zhang 	struct rk1808_clk_priv *priv = dev_get_priv(clk->dev);
627b9f59722SElaine Zhang 	struct rk1808_cru *cru = priv->cru;
628b9f59722SElaine Zhang 	u32 sel;
629b9f59722SElaine Zhang 
630b9f59722SElaine Zhang 	switch (clk_id) {
631b9f59722SElaine Zhang 	case SCLK_GMAC_RGMII_SPEED:
632b9f59722SElaine Zhang 		if (hz == 125000000)
633b9f59722SElaine Zhang 			sel = 0;
634b9f59722SElaine Zhang 		else if (hz == 2500000)
635b9f59722SElaine Zhang 			sel = 2;
636b9f59722SElaine Zhang 		else
637b9f59722SElaine Zhang 			sel = 3;
638b9f59722SElaine Zhang 		rk_clrsetreg(&cru->clksel_con[27], RGMII_CLK_SEL_MASK,
639b9f59722SElaine Zhang 			     sel << RGMII_CLK_SEL_SHIFT);
640b9f59722SElaine Zhang 		break;
641b9f59722SElaine Zhang 	case SCLK_GMAC_RMII_SPEED:
642b9f59722SElaine Zhang 		if (hz == 2500000)
643b9f59722SElaine Zhang 			sel = 0;
644b9f59722SElaine Zhang 		else
645b9f59722SElaine Zhang 			sel = 1;
646b9f59722SElaine Zhang 		rk_clrsetreg(&cru->clksel_con[27], RMII_CLK_SEL_MASK,
647b9f59722SElaine Zhang 			     sel << RMII_CLK_SEL_SHIFT);
648b9f59722SElaine Zhang 		break;
649b9f59722SElaine Zhang 	default:
650b9f59722SElaine Zhang 		return -ENOENT;
651b9f59722SElaine Zhang 	}
652b9f59722SElaine Zhang 	return 0;
653b9f59722SElaine Zhang }
65432f0452dSElaine Zhang 
rk1808_crypto_get_clk(struct rk1808_clk_priv * priv,ulong clk_id)65532f0452dSElaine Zhang static ulong rk1808_crypto_get_clk(struct rk1808_clk_priv *priv, ulong clk_id)
65632f0452dSElaine Zhang {
65732f0452dSElaine Zhang 	struct rk1808_cru *cru = priv->cru;
65832f0452dSElaine Zhang 	u32 div, con, parent;
65932f0452dSElaine Zhang 
66032f0452dSElaine Zhang 	switch (clk_id) {
66132f0452dSElaine Zhang 	case SCLK_CRYPTO:
66232f0452dSElaine Zhang 		con = readl(&cru->clksel_con[29]);
66332f0452dSElaine Zhang 		div = (con & CRYPTO_DIV_MASK) >> CRYPTO_DIV_SHIFT;
66432f0452dSElaine Zhang 		parent = priv->gpll_hz;
66532f0452dSElaine Zhang 		break;
66632f0452dSElaine Zhang 	case SCLK_CRYPTO_APK:
66732f0452dSElaine Zhang 		con = readl(&cru->clksel_con[29]);
66832f0452dSElaine Zhang 		div = (con & CRYPTO_APK_DIV_MASK) >> CRYPTO_APK_DIV_SHIFT;
66932f0452dSElaine Zhang 		parent = priv->gpll_hz;
67032f0452dSElaine Zhang 		break;
67132f0452dSElaine Zhang 	default:
67232f0452dSElaine Zhang 		return -ENOENT;
67332f0452dSElaine Zhang 	}
67432f0452dSElaine Zhang 
67532f0452dSElaine Zhang 	return DIV_TO_RATE(parent, div);
67632f0452dSElaine Zhang }
67732f0452dSElaine Zhang 
rk1808_crypto_set_clk(struct rk1808_clk_priv * priv,ulong clk_id,ulong hz)67832f0452dSElaine Zhang static ulong rk1808_crypto_set_clk(struct rk1808_clk_priv *priv, ulong clk_id,
67932f0452dSElaine Zhang 				   ulong hz)
68032f0452dSElaine Zhang {
68132f0452dSElaine Zhang 	struct rk1808_cru *cru = priv->cru;
68232f0452dSElaine Zhang 	int src_clk_div;
68332f0452dSElaine Zhang 
68432f0452dSElaine Zhang 	src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
68532f0452dSElaine Zhang 	assert(src_clk_div - 1 <= 31);
68632f0452dSElaine Zhang 
68732f0452dSElaine Zhang 	/*
68832f0452dSElaine Zhang 	 * select gpll as crypto clock source and
68932f0452dSElaine Zhang 	 * set up dependent divisors for crypto clocks.
69032f0452dSElaine Zhang 	 */
69132f0452dSElaine Zhang 	switch (clk_id) {
69232f0452dSElaine Zhang 	case SCLK_CRYPTO:
69332f0452dSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[29],
69432f0452dSElaine Zhang 			     CRYPTO_PLL_SEL_MASK | CRYPTO_DIV_MASK,
69532f0452dSElaine Zhang 			     CRYPTO_PLL_SEL_GPLL << CRYPTO_PLL_SEL_SHIFT |
69632f0452dSElaine Zhang 			     (src_clk_div - 1) << CRYPTO_DIV_SHIFT);
69732f0452dSElaine Zhang 		break;
69832f0452dSElaine Zhang 	case SCLK_CRYPTO_APK:
69932f0452dSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[29],
70032f0452dSElaine Zhang 			     CRYPTO_APK_PLL_SEL_MASK | CRYPTO_APK_DIV_MASK,
70132f0452dSElaine Zhang 			     CRYPTO_PLL_SEL_GPLL << CRYPTO_APK_SEL_SHIFT |
70232f0452dSElaine Zhang 			     (src_clk_div - 1) << CRYPTO_APK_DIV_SHIFT);
70332f0452dSElaine Zhang 		break;
70432f0452dSElaine Zhang 	default:
70532f0452dSElaine Zhang 		printf("do not support this peri freq\n");
70632f0452dSElaine Zhang 		return -EINVAL;
70732f0452dSElaine Zhang 	}
70832f0452dSElaine Zhang 
70932f0452dSElaine Zhang 	return rk1808_crypto_get_clk(priv, clk_id);
71032f0452dSElaine Zhang }
71145a3782aSElaine Zhang #endif
71245a3782aSElaine Zhang 
rk1808_bus_get_clk(struct rk1808_clk_priv * priv,ulong clk_id)71345a3782aSElaine Zhang static ulong rk1808_bus_get_clk(struct rk1808_clk_priv *priv, ulong clk_id)
71445a3782aSElaine Zhang {
71545a3782aSElaine Zhang 	struct rk1808_cru *cru = priv->cru;
71645a3782aSElaine Zhang 	u32 div, con, parent;
71745a3782aSElaine Zhang 
71845a3782aSElaine Zhang 	switch (clk_id) {
71945a3782aSElaine Zhang 	case HSCLK_BUS_PRE:
72045a3782aSElaine Zhang 		con = readl(&cru->clksel_con[27]);
72145a3782aSElaine Zhang 		div = (con & HSCLK_BUS_DIV_CON_MASK) >> HSCLK_BUS_DIV_CON_SHIFT;
72245a3782aSElaine Zhang 		parent = priv->gpll_hz;
72345a3782aSElaine Zhang 		break;
72445a3782aSElaine Zhang 	case MSCLK_BUS_PRE:
72545a3782aSElaine Zhang 		con = readl(&cru->clksel_con[28]);
72645a3782aSElaine Zhang 		div = (con & MSCLK_BUS_DIV_CON_MASK) >> MSCLK_BUS_DIV_CON_SHIFT;
72745a3782aSElaine Zhang 		parent = priv->gpll_hz;
72845a3782aSElaine Zhang 		break;
72945a3782aSElaine Zhang 	case LSCLK_BUS_PRE:
73068d8964cSElaine Zhang 	case PCLK_WDT:
73145a3782aSElaine Zhang 		con = readl(&cru->clksel_con[28]);
73245a3782aSElaine Zhang 		div = (con & LSCLK_BUS_DIV_CON_MASK) >> LSCLK_BUS_DIV_CON_SHIFT;
73345a3782aSElaine Zhang 		parent = priv->gpll_hz;
73445a3782aSElaine Zhang 		break;
73545a3782aSElaine Zhang 	default:
73645a3782aSElaine Zhang 		return -ENOENT;
73745a3782aSElaine Zhang 	}
73845a3782aSElaine Zhang 
73945a3782aSElaine Zhang 	return DIV_TO_RATE(parent, div);
74045a3782aSElaine Zhang }
74145a3782aSElaine Zhang 
rk1808_bus_set_clk(struct rk1808_clk_priv * priv,ulong clk_id,ulong hz)74245a3782aSElaine Zhang static ulong rk1808_bus_set_clk(struct rk1808_clk_priv *priv,
74345a3782aSElaine Zhang 				ulong clk_id, ulong hz)
74445a3782aSElaine Zhang {
74545a3782aSElaine Zhang 	struct rk1808_cru *cru = priv->cru;
74645a3782aSElaine Zhang 	int src_clk_div;
74745a3782aSElaine Zhang 
74845a3782aSElaine Zhang 	/*
74945a3782aSElaine Zhang 	 * select gpll as pd_bus bus clock source and
75045a3782aSElaine Zhang 	 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
75145a3782aSElaine Zhang 	 */
75245a3782aSElaine Zhang 	switch (clk_id) {
75345a3782aSElaine Zhang 	case HSCLK_BUS_PRE:
75445a3782aSElaine Zhang 		src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
75545a3782aSElaine Zhang 		assert(src_clk_div - 1 < 31);
75645a3782aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[27],
75745a3782aSElaine Zhang 			     CLK_BUS_PLL_SEL_MASK | HSCLK_BUS_DIV_CON_MASK,
75845a3782aSElaine Zhang 			     CLK_BUS_PLL_SEL_GPLL << CLK_BUS_PLL_SEL_SHIFT |
75945a3782aSElaine Zhang 			     (src_clk_div - 1) << HSCLK_BUS_DIV_CON_SHIFT);
76045a3782aSElaine Zhang 		break;
76145a3782aSElaine Zhang 	case MSCLK_BUS_PRE:
76245a3782aSElaine Zhang 		src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
76345a3782aSElaine Zhang 		assert(src_clk_div - 1 < 31);
76445a3782aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[28],
76545a3782aSElaine Zhang 			     CLK_BUS_PLL_SEL_MASK | MSCLK_BUS_DIV_CON_MASK,
76645a3782aSElaine Zhang 			     CLK_BUS_PLL_SEL_GPLL << CLK_BUS_PLL_SEL_SHIFT |
76745a3782aSElaine Zhang 			     (src_clk_div - 1) << MSCLK_BUS_DIV_CON_SHIFT);
76845a3782aSElaine Zhang 		break;
76945a3782aSElaine Zhang 	case LSCLK_BUS_PRE:
77045a3782aSElaine Zhang 		src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
77145a3782aSElaine Zhang 		assert(src_clk_div - 1 < 31);
77245a3782aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[28],
77345a3782aSElaine Zhang 			     CLK_BUS_PLL_SEL_MASK | LSCLK_BUS_DIV_CON_MASK,
77445a3782aSElaine Zhang 			     CLK_BUS_PLL_SEL_GPLL << CLK_BUS_PLL_SEL_SHIFT |
77545a3782aSElaine Zhang 			     (src_clk_div - 1) << LSCLK_BUS_DIV_CON_SHIFT);
77645a3782aSElaine Zhang 		break;
77745a3782aSElaine Zhang 	default:
77845a3782aSElaine Zhang 		printf("do not support this bus freq\n");
77945a3782aSElaine Zhang 		return -EINVAL;
78045a3782aSElaine Zhang 	}
78145a3782aSElaine Zhang 
78245a3782aSElaine Zhang 	return rk1808_bus_get_clk(priv, clk_id);
78345a3782aSElaine Zhang }
78445a3782aSElaine Zhang 
rk1808_peri_get_clk(struct rk1808_clk_priv * priv,ulong clk_id)78545a3782aSElaine Zhang static ulong rk1808_peri_get_clk(struct rk1808_clk_priv *priv, ulong clk_id)
78645a3782aSElaine Zhang {
78745a3782aSElaine Zhang 	struct rk1808_cru *cru = priv->cru;
78845a3782aSElaine Zhang 	u32 div, con, parent;
78945a3782aSElaine Zhang 
79045a3782aSElaine Zhang 	switch (clk_id) {
79145a3782aSElaine Zhang 	case MSCLK_PERI:
79245a3782aSElaine Zhang 		con = readl(&cru->clksel_con[19]);
79345a3782aSElaine Zhang 		div = (con & MSCLK_PERI_DIV_CON_MASK) >>
79445a3782aSElaine Zhang 		      MSCLK_PERI_DIV_CON_SHIFT;
79545a3782aSElaine Zhang 		parent = priv->gpll_hz;
79645a3782aSElaine Zhang 		break;
79745a3782aSElaine Zhang 	case LSCLK_PERI:
79845a3782aSElaine Zhang 		con = readl(&cru->clksel_con[19]);
79945a3782aSElaine Zhang 		div = (con & LSCLK_PERI_DIV_CON_MASK) >>
80045a3782aSElaine Zhang 		      LSCLK_PERI_DIV_CON_SHIFT;
80145a3782aSElaine Zhang 		parent = priv->gpll_hz;
80245a3782aSElaine Zhang 		break;
80345a3782aSElaine Zhang 	default:
80445a3782aSElaine Zhang 		return -ENOENT;
80545a3782aSElaine Zhang 	}
80645a3782aSElaine Zhang 
80745a3782aSElaine Zhang 	return DIV_TO_RATE(parent, div);
80845a3782aSElaine Zhang }
80945a3782aSElaine Zhang 
rk1808_peri_set_clk(struct rk1808_clk_priv * priv,ulong clk_id,ulong hz)81045a3782aSElaine Zhang static ulong rk1808_peri_set_clk(struct rk1808_clk_priv *priv,
81145a3782aSElaine Zhang 				 ulong clk_id, ulong hz)
81245a3782aSElaine Zhang {
81345a3782aSElaine Zhang 	struct rk1808_cru *cru = priv->cru;
81445a3782aSElaine Zhang 	int src_clk_div;
81545a3782aSElaine Zhang 
81645a3782aSElaine Zhang 	src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
81745a3782aSElaine Zhang 	assert(src_clk_div - 1 < 31);
81845a3782aSElaine Zhang 
81945a3782aSElaine Zhang 	/*
82045a3782aSElaine Zhang 	 * select gpll as pd_peri bus clock source and
82145a3782aSElaine Zhang 	 * set up dependent divisors for HCLK and ACLK clocks.
82245a3782aSElaine Zhang 	 */
82345a3782aSElaine Zhang 	switch (clk_id) {
82445a3782aSElaine Zhang 	case MSCLK_PERI:
82545a3782aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[19],
82645a3782aSElaine Zhang 			     CLK_PERI_PLL_SEL_MASK | MSCLK_PERI_DIV_CON_MASK,
82745a3782aSElaine Zhang 			     CLK_PERI_PLL_SEL_GPLL << CLK_PERI_PLL_SEL_SHIFT |
82845a3782aSElaine Zhang 			     (src_clk_div - 1) << MSCLK_PERI_DIV_CON_SHIFT);
82945a3782aSElaine Zhang 		break;
83045a3782aSElaine Zhang 	case LSCLK_PERI:
83145a3782aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[19],
83245a3782aSElaine Zhang 			     CLK_PERI_PLL_SEL_MASK | LSCLK_PERI_DIV_CON_MASK,
83345a3782aSElaine Zhang 			     CLK_PERI_PLL_SEL_GPLL << CLK_PERI_PLL_SEL_SHIFT |
83445a3782aSElaine Zhang 			     (src_clk_div - 1) << LSCLK_PERI_DIV_CON_SHIFT);
83545a3782aSElaine Zhang 		break;
83645a3782aSElaine Zhang 	default:
83745a3782aSElaine Zhang 		printf("do not support this peri freq\n");
83845a3782aSElaine Zhang 		return -EINVAL;
83945a3782aSElaine Zhang 	}
84045a3782aSElaine Zhang 
84145a3782aSElaine Zhang 	return rk1808_peri_get_clk(priv, clk_id);
84245a3782aSElaine Zhang }
84345a3782aSElaine Zhang 
rk1808_pclk_pmu_set_clk(struct rk1808_clk_priv * priv,ulong clk_id,ulong parent_hz,ulong hz)844dad14895SElaine Zhang static ulong rk1808_pclk_pmu_set_clk(struct rk1808_clk_priv *priv,
845dad14895SElaine Zhang 				     ulong clk_id, ulong parent_hz, ulong hz)
846dad14895SElaine Zhang {
847dad14895SElaine Zhang 	struct rk1808_cru *cru = priv->cru;
848dad14895SElaine Zhang 	int src_clk_div;
849dad14895SElaine Zhang 
850dad14895SElaine Zhang 	src_clk_div = DIV_ROUND_UP(parent_hz, hz);
851dad14895SElaine Zhang 	assert(src_clk_div - 1 < 31);
852dad14895SElaine Zhang 
853dad14895SElaine Zhang 	rk_clrsetreg(&cru->pmu_clksel_con[0],
854dad14895SElaine Zhang 		     PCLK_PMU_DIV_CON_MASK,
855dad14895SElaine Zhang 		     (src_clk_div - 1) << PCLK_PMU_DIV_CON_SHIFT);
856dad14895SElaine Zhang 
857dad14895SElaine Zhang 	return parent_hz / src_clk_div;
858dad14895SElaine Zhang }
859dad14895SElaine Zhang 
rk1808_armclk_set_clk(struct rk1808_clk_priv * priv,ulong hz)86045a3782aSElaine Zhang static ulong rk1808_armclk_set_clk(struct rk1808_clk_priv *priv, ulong hz)
86145a3782aSElaine Zhang {
86245a3782aSElaine Zhang 	struct rk1808_cru *cru = priv->cru;
86345a3782aSElaine Zhang 	const struct rockchip_cpu_rate_table *rate;
86445a3782aSElaine Zhang 	ulong old_rate;
86545a3782aSElaine Zhang 
86645a3782aSElaine Zhang 	rate = rockchip_get_cpu_settings(rk1808_cpu_rates, hz);
86745a3782aSElaine Zhang 	if (!rate) {
86845a3782aSElaine Zhang 		printf("%s unsupported rate\n", __func__);
86945a3782aSElaine Zhang 		return -EINVAL;
87045a3782aSElaine Zhang 	}
87145a3782aSElaine Zhang 
87245a3782aSElaine Zhang 	/*
87345a3782aSElaine Zhang 	 * select apll as cpu/core clock pll source and
87445a3782aSElaine Zhang 	 * set up dependent divisors for PERI and ACLK clocks.
87545a3782aSElaine Zhang 	 * core hz : apll = 1:1
87645a3782aSElaine Zhang 	 */
87745a3782aSElaine Zhang 	old_rate = rockchip_pll_get_rate(&rk1808_pll_clks[APLL],
87845a3782aSElaine Zhang 					 priv->cru, APLL);
87945a3782aSElaine Zhang 	if (old_rate > hz) {
88045a3782aSElaine Zhang 		if (rockchip_pll_set_rate(&rk1808_pll_clks[APLL],
88145a3782aSElaine Zhang 					  priv->cru, APLL, hz))
88245a3782aSElaine Zhang 			return -EINVAL;
88345a3782aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[0],
88445a3782aSElaine Zhang 			     CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK |
88545a3782aSElaine Zhang 			     CORE_ACLK_DIV_MASK | CORE_DBG_DIV_MASK,
88645a3782aSElaine Zhang 			     rate->aclk_div << CORE_ACLK_DIV_SHIFT |
88745a3782aSElaine Zhang 			     rate->pclk_div << CORE_DBG_DIV_SHIFT |
88845a3782aSElaine Zhang 			     CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT |
88945a3782aSElaine Zhang 			     0 << CORE_DIV_CON_SHIFT);
89045a3782aSElaine Zhang 	} else if (old_rate < hz) {
89145a3782aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[0],
89245a3782aSElaine Zhang 			     CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK |
89345a3782aSElaine Zhang 			     CORE_ACLK_DIV_MASK | CORE_DBG_DIV_MASK,
89445a3782aSElaine Zhang 			     rate->aclk_div << CORE_ACLK_DIV_SHIFT |
89545a3782aSElaine Zhang 			     rate->pclk_div << CORE_DBG_DIV_SHIFT |
89645a3782aSElaine Zhang 			     CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT |
89745a3782aSElaine Zhang 			     0 << CORE_DIV_CON_SHIFT);
89845a3782aSElaine Zhang 		if (rockchip_pll_set_rate(&rk1808_pll_clks[APLL],
89945a3782aSElaine Zhang 					  priv->cru, APLL, hz))
90045a3782aSElaine Zhang 			return -EINVAL;
90145a3782aSElaine Zhang 	}
90245a3782aSElaine Zhang 
90345a3782aSElaine Zhang 	return rockchip_pll_get_rate(&rk1808_pll_clks[APLL], priv->cru, APLL);
90445a3782aSElaine Zhang }
90545a3782aSElaine Zhang 
rk1808_clk_get_rate(struct clk * clk)90645a3782aSElaine Zhang static ulong rk1808_clk_get_rate(struct clk *clk)
90745a3782aSElaine Zhang {
90845a3782aSElaine Zhang 	struct rk1808_clk_priv *priv = dev_get_priv(clk->dev);
90945a3782aSElaine Zhang 	ulong rate = 0;
91045a3782aSElaine Zhang 
91145a3782aSElaine Zhang 	debug("%s %ld\n", __func__, clk->id);
91245a3782aSElaine Zhang 	switch (clk->id) {
91345a3782aSElaine Zhang 	case PLL_APLL:
91445a3782aSElaine Zhang 	case PLL_DPLL:
91545a3782aSElaine Zhang 	case PLL_CPLL:
91645a3782aSElaine Zhang 	case PLL_GPLL:
91745a3782aSElaine Zhang 	case PLL_NPLL:
91845a3782aSElaine Zhang 	case PLL_PPLL:
91945a3782aSElaine Zhang 		rate = rockchip_pll_get_rate(&rk1808_pll_clks[clk->id - 1],
92045a3782aSElaine Zhang 					     priv->cru, clk->id - 1);
92145a3782aSElaine Zhang 		break;
92245a3782aSElaine Zhang 	case ARMCLK:
92345a3782aSElaine Zhang 		rate = rockchip_pll_get_rate(&rk1808_pll_clks[APLL],
92445a3782aSElaine Zhang 					     priv->cru, APLL);
92545a3782aSElaine Zhang 		break;
92645a3782aSElaine Zhang 	case HCLK_SDMMC:
92745a3782aSElaine Zhang 	case HCLK_EMMC:
92845a3782aSElaine Zhang 	case HCLK_SDIO:
92945a3782aSElaine Zhang 	case SCLK_SDMMC:
93045a3782aSElaine Zhang 	case SCLK_EMMC:
93145a3782aSElaine Zhang 	case SCLK_EMMC_SAMPLE:
93245a3782aSElaine Zhang 	case SCLK_SDIO:
93345a3782aSElaine Zhang 		rate = rk1808_mmc_get_clk(priv, clk->id);
93445a3782aSElaine Zhang 		break;
935c2fb06deSElaine Zhang 	case SCLK_SFC:
936c2fb06deSElaine Zhang 		rate = rk1808_sfc_get_clk(priv, clk->id);
937c2fb06deSElaine Zhang 		break;
938*3732e2b8SJason Zhu 	case SCLK_SARADC:
939*3732e2b8SJason Zhu 		rate = rk1808_saradc_get_clk(priv);
940*3732e2b8SJason Zhu 		break;
94145a3782aSElaine Zhang #ifndef CONFIG_SPL_BUILD
94245a3782aSElaine Zhang 	case SCLK_PMU_I2C0:
94345a3782aSElaine Zhang 	case SCLK_I2C1:
94445a3782aSElaine Zhang 	case SCLK_I2C2:
94545a3782aSElaine Zhang 	case SCLK_I2C3:
94645a3782aSElaine Zhang 	case SCLK_I2C4:
94745a3782aSElaine Zhang 	case SCLK_I2C5:
94845a3782aSElaine Zhang 		rate = rk1808_i2c_get_clk(priv, clk->id);
94945a3782aSElaine Zhang 		break;
95045a3782aSElaine Zhang 	case SCLK_PWM0:
95145a3782aSElaine Zhang 	case SCLK_PWM1:
95245a3782aSElaine Zhang 	case SCLK_PWM2:
95345a3782aSElaine Zhang 		rate = rk1808_pwm_get_clk(priv, clk->id);
95445a3782aSElaine Zhang 		break;
955cb3c37fcSElaine Zhang 	case SCLK_TSADC:
956cb3c37fcSElaine Zhang 		rate = rk1808_tsadc_get_clk(priv);
957cb3c37fcSElaine Zhang 		break;
95845a3782aSElaine Zhang 	case SCLK_SPI0:
95945a3782aSElaine Zhang 	case SCLK_SPI1:
96045a3782aSElaine Zhang 	case SCLK_SPI2:
96145a3782aSElaine Zhang 		rate = rk1808_spi_get_clk(priv, clk->id);
96245a3782aSElaine Zhang 		break;
96345a3782aSElaine Zhang 	case ACLK_VOPRAW:
96445a3782aSElaine Zhang 	case DCLK_VOPRAW:
96545a3782aSElaine Zhang 	case ACLK_VOPLITE:
96645a3782aSElaine Zhang 	case DCLK_VOPLITE:
96745a3782aSElaine Zhang 		rate = rk1808_vop_get_clk(priv, clk->id);
96845a3782aSElaine Zhang 		break;
96932f0452dSElaine Zhang 	case SCLK_CRYPTO:
97032f0452dSElaine Zhang 	case SCLK_CRYPTO_APK:
97132f0452dSElaine Zhang 		rate = rk1808_crypto_get_clk(priv, clk->id);
97232f0452dSElaine Zhang 		break;
97345a3782aSElaine Zhang #endif
97445a3782aSElaine Zhang 	case HSCLK_BUS_PRE:
97545a3782aSElaine Zhang 	case MSCLK_BUS_PRE:
97645a3782aSElaine Zhang 	case LSCLK_BUS_PRE:
97768d8964cSElaine Zhang 	case PCLK_WDT:
97845a3782aSElaine Zhang 		rate = rk1808_bus_get_clk(priv, clk->id);
97945a3782aSElaine Zhang 		break;
98045a3782aSElaine Zhang 	case MSCLK_PERI:
98145a3782aSElaine Zhang 	case LSCLK_PERI:
98245a3782aSElaine Zhang 		rate = rk1808_peri_get_clk(priv, clk->id);
98345a3782aSElaine Zhang 		break;
98445a3782aSElaine Zhang 	default:
98545a3782aSElaine Zhang 		return -ENOENT;
98645a3782aSElaine Zhang 	}
98745a3782aSElaine Zhang 
98845a3782aSElaine Zhang 	return rate;
98945a3782aSElaine Zhang }
99045a3782aSElaine Zhang 
rk1808_clk_set_rate(struct clk * clk,ulong rate)99145a3782aSElaine Zhang static ulong rk1808_clk_set_rate(struct clk *clk, ulong rate)
99245a3782aSElaine Zhang {
99345a3782aSElaine Zhang 	struct rk1808_clk_priv *priv = dev_get_priv(clk->dev);
99445a3782aSElaine Zhang 	ulong ret = 0;
99545a3782aSElaine Zhang 
99645a3782aSElaine Zhang 	debug("%s %ld %ld\n", __func__, clk->id, rate);
99745a3782aSElaine Zhang 	switch (clk->id) {
99845a3782aSElaine Zhang 	case PLL_APLL:
99945a3782aSElaine Zhang 	case PLL_DPLL:
100045a3782aSElaine Zhang 		ret = rockchip_pll_set_rate(&rk1808_pll_clks[clk->id - 1],
100145a3782aSElaine Zhang 					    priv->cru, clk->id - 1, rate);
100245a3782aSElaine Zhang 		break;
1003dad14895SElaine Zhang 	case PLL_PPLL:
1004dad14895SElaine Zhang 		ret = rk1808_pclk_pmu_set_clk(priv, clk->id, rate, PCLK_PMU_HZ);
1005dad14895SElaine Zhang 		ret = rockchip_pll_set_rate(&rk1808_pll_clks[PPLL],
1006dad14895SElaine Zhang 					    priv->cru, PPLL, rate);
1007dad14895SElaine Zhang 		break;
100845a3782aSElaine Zhang 	case PLL_CPLL:
100945a3782aSElaine Zhang 		ret = rockchip_pll_set_rate(&rk1808_pll_clks[CPLL],
101045a3782aSElaine Zhang 					    priv->cru, CPLL, rate);
101145a3782aSElaine Zhang 		if (ret == 0)
101245a3782aSElaine Zhang 			priv->cpll_hz = rate;
101345a3782aSElaine Zhang 		break;
101445a3782aSElaine Zhang 	case PLL_GPLL:
101545a3782aSElaine Zhang 		ret = rockchip_pll_set_rate(&rk1808_pll_clks[GPLL],
101645a3782aSElaine Zhang 					    priv->cru, GPLL, rate);
101745a3782aSElaine Zhang 		if (ret == 0)
101845a3782aSElaine Zhang 			priv->gpll_hz = rate;
101945a3782aSElaine Zhang 		break;
102045a3782aSElaine Zhang 	case PLL_NPLL:
102145a3782aSElaine Zhang 		ret = rockchip_pll_set_rate(&rk1808_pll_clks[NPLL],
102245a3782aSElaine Zhang 					    priv->cru, NPLL, rate);
102345a3782aSElaine Zhang 		if (ret == 0)
102445a3782aSElaine Zhang 			priv->npll_hz = rate;
102545a3782aSElaine Zhang 		break;
102645a3782aSElaine Zhang 	case ARMCLK:
102745a3782aSElaine Zhang 		if (priv->armclk_hz)
102845a3782aSElaine Zhang 			rk1808_armclk_set_clk(priv, rate);
102945a3782aSElaine Zhang 		priv->armclk_hz = rate;
103045a3782aSElaine Zhang 		break;
103145a3782aSElaine Zhang 	case HCLK_SDMMC:
103245a3782aSElaine Zhang 	case HCLK_EMMC:
103345a3782aSElaine Zhang 	case HCLK_SDIO:
103445a3782aSElaine Zhang 	case SCLK_SDMMC:
103545a3782aSElaine Zhang 	case SCLK_EMMC:
103645a3782aSElaine Zhang 	case SCLK_SDIO:
103745a3782aSElaine Zhang 		ret = rk1808_mmc_set_clk(priv, clk->id, rate);
103845a3782aSElaine Zhang 		break;
1039c2fb06deSElaine Zhang 	case SCLK_SFC:
1040c2fb06deSElaine Zhang 		ret = rk1808_sfc_set_clk(priv, clk->id, rate);
1041c2fb06deSElaine Zhang 		break;
1042*3732e2b8SJason Zhu 	case SCLK_SARADC:
1043*3732e2b8SJason Zhu 		ret = rk1808_saradc_set_clk(priv, rate);
1044*3732e2b8SJason Zhu 		break;
104545a3782aSElaine Zhang #ifndef CONFIG_SPL_BUILD
104645a3782aSElaine Zhang 	case SCLK_PMU_I2C0:
104745a3782aSElaine Zhang 	case SCLK_I2C1:
104845a3782aSElaine Zhang 	case SCLK_I2C2:
104945a3782aSElaine Zhang 	case SCLK_I2C3:
105045a3782aSElaine Zhang 	case SCLK_I2C4:
105145a3782aSElaine Zhang 	case SCLK_I2C5:
105245a3782aSElaine Zhang 		ret = rk1808_i2c_set_clk(priv, clk->id, rate);
105345a3782aSElaine Zhang 		break;
105445a3782aSElaine Zhang 	case SCLK_PWM0:
105545a3782aSElaine Zhang 	case SCLK_PWM1:
105645a3782aSElaine Zhang 	case SCLK_PWM2:
105745a3782aSElaine Zhang 		ret = rk1808_pwm_set_clk(priv, clk->id, rate);
105845a3782aSElaine Zhang 		break;
1059cb3c37fcSElaine Zhang 	case SCLK_TSADC:
1060cb3c37fcSElaine Zhang 		ret = rk1808_tsadc_set_clk(priv, rate);
1061cb3c37fcSElaine Zhang 		break;
106245a3782aSElaine Zhang 	case SCLK_SPI0:
106345a3782aSElaine Zhang 	case SCLK_SPI1:
106445a3782aSElaine Zhang 	case SCLK_SPI2:
106545a3782aSElaine Zhang 		ret = rk1808_spi_set_clk(priv, clk->id, rate);
106645a3782aSElaine Zhang 		break;
106745a3782aSElaine Zhang 	case ACLK_VOPRAW:
106845a3782aSElaine Zhang 	case DCLK_VOPRAW:
106945a3782aSElaine Zhang 	case ACLK_VOPLITE:
107045a3782aSElaine Zhang 	case DCLK_VOPLITE:
107145a3782aSElaine Zhang 		ret = rk1808_vop_set_clk(priv, clk->id, rate);
107245a3782aSElaine Zhang 		break;
1073b9f59722SElaine Zhang 	case SCLK_GMAC:
1074b9f59722SElaine Zhang 	case SCLK_GMAC_SRC:
1075b9f59722SElaine Zhang 		ret = rk1808_mac_set_clk(clk, rate);
1076b9f59722SElaine Zhang 		break;
1077b9f59722SElaine Zhang 	case SCLK_GMAC_RMII_SPEED:
1078b9f59722SElaine Zhang 	case SCLK_GMAC_RGMII_SPEED:
1079b9f59722SElaine Zhang 		ret = rk1808_mac_set_speed_clk(clk, clk->id, rate);
1080b9f59722SElaine Zhang 		break;
108132f0452dSElaine Zhang 	case SCLK_CRYPTO:
108232f0452dSElaine Zhang 	case SCLK_CRYPTO_APK:
108332f0452dSElaine Zhang 		ret = rk1808_crypto_set_clk(priv, clk->id, rate);
108432f0452dSElaine Zhang 		break;
108545a3782aSElaine Zhang #endif
108645a3782aSElaine Zhang 	case HSCLK_BUS_PRE:
108745a3782aSElaine Zhang 	case MSCLK_BUS_PRE:
108845a3782aSElaine Zhang 	case LSCLK_BUS_PRE:
108945a3782aSElaine Zhang 		ret = rk1808_bus_set_clk(priv, clk->id, rate);
109045a3782aSElaine Zhang 		break;
109145a3782aSElaine Zhang 	case MSCLK_PERI:
109245a3782aSElaine Zhang 	case LSCLK_PERI:
109345a3782aSElaine Zhang 		ret = rk1808_peri_set_clk(priv, clk->id, rate);
109445a3782aSElaine Zhang 		break;
10956b5ade5aSElaine Zhang 	case SCLK_32K_IOE:
10966b5ade5aSElaine Zhang 		return 0;
109745a3782aSElaine Zhang 	default:
109845a3782aSElaine Zhang 		return -ENOENT;
109945a3782aSElaine Zhang 	}
110045a3782aSElaine Zhang 
110145a3782aSElaine Zhang 	return ret;
110245a3782aSElaine Zhang }
110345a3782aSElaine Zhang 
110445a3782aSElaine Zhang #define ROCKCHIP_MMC_DELAY_SEL		BIT(10)
110545a3782aSElaine Zhang #define ROCKCHIP_MMC_DEGREE_MASK	0x3
110645a3782aSElaine Zhang #define ROCKCHIP_MMC_DELAYNUM_OFFSET	2
110745a3782aSElaine Zhang #define ROCKCHIP_MMC_DELAYNUM_MASK	(0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET)
110845a3782aSElaine Zhang 
110945a3782aSElaine Zhang #define PSECS_PER_SEC 1000000000000LL
111045a3782aSElaine Zhang /*
111145a3782aSElaine Zhang  * Each fine delay is between 44ps-77ps. Assume each fine delay is 60ps to
111245a3782aSElaine Zhang  * simplify calculations. So 45degs could be anywhere between 33deg and 57.8deg.
111345a3782aSElaine Zhang  */
111445a3782aSElaine Zhang #define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60
111545a3782aSElaine Zhang 
rk1808_mmc_get_phase(struct clk * clk)111645a3782aSElaine Zhang int rk1808_mmc_get_phase(struct clk *clk)
111745a3782aSElaine Zhang {
111845a3782aSElaine Zhang 	struct rk1808_clk_priv *priv = dev_get_priv(clk->dev);
111945a3782aSElaine Zhang 	struct rk1808_cru *cru = priv->cru;
112045a3782aSElaine Zhang 	u32 raw_value, delay_num;
112145a3782aSElaine Zhang 	u16 degrees = 0;
112245a3782aSElaine Zhang 	ulong rate;
112345a3782aSElaine Zhang 
112445a3782aSElaine Zhang 	rate = rk1808_clk_get_rate(clk);
112545a3782aSElaine Zhang 
112645a3782aSElaine Zhang 	if (rate < 0)
112745a3782aSElaine Zhang 		return rate;
112845a3782aSElaine Zhang 
112945a3782aSElaine Zhang 	if (clk->id == SCLK_EMMC_SAMPLE)
113045a3782aSElaine Zhang 		raw_value = readl(&cru->emmc_con[1]);
113145a3782aSElaine Zhang 	else if (clk->id == SCLK_SDMMC_SAMPLE)
113245a3782aSElaine Zhang 		raw_value = readl(&cru->sdmmc_con[1]);
113345a3782aSElaine Zhang 	else
113445a3782aSElaine Zhang 		raw_value = readl(&cru->sdio_con[1]);
113545a3782aSElaine Zhang 
113645a3782aSElaine Zhang 	raw_value >>= 1;
113745a3782aSElaine Zhang 	degrees = (raw_value & ROCKCHIP_MMC_DEGREE_MASK) * 90;
113845a3782aSElaine Zhang 
113945a3782aSElaine Zhang 	if (raw_value & ROCKCHIP_MMC_DELAY_SEL) {
114045a3782aSElaine Zhang 		/* degrees/delaynum * 10000 */
114145a3782aSElaine Zhang 		unsigned long factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) *
114245a3782aSElaine Zhang 					36 * (rate / 1000000);
114345a3782aSElaine Zhang 
114445a3782aSElaine Zhang 		delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK);
114545a3782aSElaine Zhang 		delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET;
114645a3782aSElaine Zhang 		degrees += DIV_ROUND_CLOSEST(delay_num * factor, 10000);
114745a3782aSElaine Zhang 	}
114845a3782aSElaine Zhang 
114945a3782aSElaine Zhang 	return degrees % 360;
115045a3782aSElaine Zhang }
115145a3782aSElaine Zhang 
rk1808_mmc_set_phase(struct clk * clk,u32 degrees)115245a3782aSElaine Zhang int rk1808_mmc_set_phase(struct clk *clk, u32 degrees)
115345a3782aSElaine Zhang {
115445a3782aSElaine Zhang 	struct rk1808_clk_priv *priv = dev_get_priv(clk->dev);
115545a3782aSElaine Zhang 	struct rk1808_cru *cru = priv->cru;
115645a3782aSElaine Zhang 	u8 nineties, remainder, delay_num;
115745a3782aSElaine Zhang 	u32 raw_value, delay;
115845a3782aSElaine Zhang 	ulong rate;
115945a3782aSElaine Zhang 
116045a3782aSElaine Zhang 	rate = rk1808_clk_get_rate(clk);
116145a3782aSElaine Zhang 
116245a3782aSElaine Zhang 	if (rate < 0)
116345a3782aSElaine Zhang 		return rate;
116445a3782aSElaine Zhang 
116545a3782aSElaine Zhang 	nineties = degrees / 90;
116645a3782aSElaine Zhang 	remainder = (degrees % 90);
116745a3782aSElaine Zhang 
116845a3782aSElaine Zhang 	/*
116945a3782aSElaine Zhang 	 * Convert to delay; do a little extra work to make sure we
117045a3782aSElaine Zhang 	 * don't overflow 32-bit / 64-bit numbers.
117145a3782aSElaine Zhang 	 */
117245a3782aSElaine Zhang 	delay = 10000000; /* PSECS_PER_SEC / 10000 / 10 */
117345a3782aSElaine Zhang 	delay *= remainder;
117445a3782aSElaine Zhang 	delay = DIV_ROUND_CLOSEST(delay, (rate / 1000) * 36 *
117545a3782aSElaine Zhang 				(ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10));
117645a3782aSElaine Zhang 
117745a3782aSElaine Zhang 	delay_num = (u8)min_t(u32, delay, 255);
117845a3782aSElaine Zhang 
117945a3782aSElaine Zhang 	raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0;
118045a3782aSElaine Zhang 	raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET;
118145a3782aSElaine Zhang 	raw_value |= nineties;
118245a3782aSElaine Zhang 
118345a3782aSElaine Zhang 	raw_value <<= 1;
118445a3782aSElaine Zhang 	if (clk->id == SCLK_EMMC_SAMPLE)
118545a3782aSElaine Zhang 		writel(raw_value | 0xffff0000, &cru->emmc_con[1]);
118645a3782aSElaine Zhang 	else if (clk->id == SCLK_SDMMC_SAMPLE)
118745a3782aSElaine Zhang 		writel(raw_value | 0xffff0000, &cru->sdmmc_con[1]);
118845a3782aSElaine Zhang 	else
118945a3782aSElaine Zhang 		writel(raw_value | 0xffff0000, &cru->sdio_con[1]);
119045a3782aSElaine Zhang 
119145a3782aSElaine Zhang 	debug("mmc set_phase(%d) delay_nums=%u reg=%#x actual_degrees=%d\n",
119245a3782aSElaine Zhang 	      degrees, delay_num, raw_value, rk1808_mmc_get_phase(clk));
119345a3782aSElaine Zhang 
119445a3782aSElaine Zhang 	return 0;
119545a3782aSElaine Zhang }
119645a3782aSElaine Zhang 
rk1808_clk_get_phase(struct clk * clk)119745a3782aSElaine Zhang static int rk1808_clk_get_phase(struct clk *clk)
119845a3782aSElaine Zhang {
119945a3782aSElaine Zhang 	int ret;
120045a3782aSElaine Zhang 
120145a3782aSElaine Zhang 	debug("%s %ld\n", __func__, clk->id);
120245a3782aSElaine Zhang 	switch (clk->id) {
120345a3782aSElaine Zhang 	case SCLK_EMMC_SAMPLE:
120445a3782aSElaine Zhang 	case SCLK_SDMMC_SAMPLE:
120545a3782aSElaine Zhang 	case SCLK_SDIO_SAMPLE:
120645a3782aSElaine Zhang 		ret = rk1808_mmc_get_phase(clk);
120745a3782aSElaine Zhang 		break;
120845a3782aSElaine Zhang 	default:
120945a3782aSElaine Zhang 		return -ENOENT;
121045a3782aSElaine Zhang 	}
121145a3782aSElaine Zhang 
121245a3782aSElaine Zhang 	return ret;
121345a3782aSElaine Zhang }
121445a3782aSElaine Zhang 
rk1808_clk_set_phase(struct clk * clk,int degrees)121545a3782aSElaine Zhang static int rk1808_clk_set_phase(struct clk *clk, int degrees)
121645a3782aSElaine Zhang {
121745a3782aSElaine Zhang 	int ret;
121845a3782aSElaine Zhang 
121945a3782aSElaine Zhang 	debug("%s %ld\n", __func__, clk->id);
122045a3782aSElaine Zhang 	switch (clk->id) {
122145a3782aSElaine Zhang 	case SCLK_EMMC_SAMPLE:
122245a3782aSElaine Zhang 	case SCLK_SDMMC_SAMPLE:
122345a3782aSElaine Zhang 	case SCLK_SDIO_SAMPLE:
122445a3782aSElaine Zhang 		ret = rk1808_mmc_set_phase(clk, degrees);
122545a3782aSElaine Zhang 		break;
122645a3782aSElaine Zhang 	default:
122745a3782aSElaine Zhang 		return -ENOENT;
122845a3782aSElaine Zhang 	}
122945a3782aSElaine Zhang 
123045a3782aSElaine Zhang 	return ret;
123145a3782aSElaine Zhang }
123245a3782aSElaine Zhang 
1233b9f59722SElaine Zhang #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
rk1808_gmac_set_parent(struct clk * clk,struct clk * parent)1234b9f59722SElaine Zhang static int rk1808_gmac_set_parent(struct clk *clk, struct clk *parent)
1235b9f59722SElaine Zhang {
1236b9f59722SElaine Zhang 	struct rk1808_clk_priv *priv = dev_get_priv(clk->dev);
1237b9f59722SElaine Zhang 	struct rk1808_cru *cru = priv->cru;
1238b9f59722SElaine Zhang 
1239b9f59722SElaine Zhang 	if (parent->id == SCLK_GMAC_SRC) {
1240b9f59722SElaine Zhang 		debug("%s: switching GAMC to SCLK_GMAC_SRC\n", __func__);
1241b9f59722SElaine Zhang 		rk_clrsetreg(&cru->clksel_con[27], RMII_EXTCLK_SEL_MASK,
1242b9f59722SElaine Zhang 			     RMII_EXTCLK_SEL_INT << RMII_EXTCLK_SEL_SHIFT);
1243b9f59722SElaine Zhang 	} else {
1244b9f59722SElaine Zhang 		debug("%s: switching GMAC to external clock\n", __func__);
1245b9f59722SElaine Zhang 		rk_clrsetreg(&cru->clksel_con[27], RMII_EXTCLK_SEL_MASK,
1246b9f59722SElaine Zhang 			     RMII_EXTCLK_SEL_EXT << RMII_EXTCLK_SEL_SHIFT);
1247b9f59722SElaine Zhang 	}
1248b9f59722SElaine Zhang 	return 0;
1249b9f59722SElaine Zhang }
1250b9f59722SElaine Zhang 
rk1808_clk_set_parent(struct clk * clk,struct clk * parent)1251b9f59722SElaine Zhang static int rk1808_clk_set_parent(struct clk *clk, struct clk *parent)
1252b9f59722SElaine Zhang {
1253b9f59722SElaine Zhang 	switch (clk->id) {
1254b9f59722SElaine Zhang 	case SCLK_GMAC:
1255b9f59722SElaine Zhang 		return rk1808_gmac_set_parent(clk, parent);
12566b5ade5aSElaine Zhang 	case SCLK_32K_IOE:
12576b5ade5aSElaine Zhang 		return 0;
1258b9f59722SElaine Zhang 	default:
1259b9f59722SElaine Zhang 		return -ENOENT;
1260b9f59722SElaine Zhang 	}
1261b9f59722SElaine Zhang }
1262b9f59722SElaine Zhang #endif
1263b9f59722SElaine Zhang 
126445a3782aSElaine Zhang static struct clk_ops rk1808_clk_ops = {
126545a3782aSElaine Zhang 	.get_rate = rk1808_clk_get_rate,
126645a3782aSElaine Zhang 	.set_rate = rk1808_clk_set_rate,
126745a3782aSElaine Zhang 	.get_phase	= rk1808_clk_get_phase,
126845a3782aSElaine Zhang 	.set_phase	= rk1808_clk_set_phase,
1269b9f59722SElaine Zhang #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
1270b9f59722SElaine Zhang 	.set_parent	= rk1808_clk_set_parent,
1271b9f59722SElaine Zhang #endif
127245a3782aSElaine Zhang };
127345a3782aSElaine Zhang 
rk1808_clk_probe(struct udevice * dev)127445a3782aSElaine Zhang static int rk1808_clk_probe(struct udevice *dev)
127545a3782aSElaine Zhang {
127645a3782aSElaine Zhang 	struct rk1808_clk_priv *priv = dev_get_priv(dev);
127745a3782aSElaine Zhang 	int ret;
127820769c64SElaine Zhang #ifndef CONFIG_SPL_BUILD
127920769c64SElaine Zhang 	ulong crypto_rate, crypto_apk_rate;
1280c2fb06deSElaine Zhang 	ulong emmc_rate, sdmmc_rate, sfc_rate;
128120769c64SElaine Zhang #endif
128245a3782aSElaine Zhang 
1283ed6f5d94SElaine Zhang 	priv->sync_kernel = false;
1284ed6f5d94SElaine Zhang 	if (!priv->armclk_enter_hz) {
1285ed6f5d94SElaine Zhang 		priv->armclk_enter_hz =
1286ed6f5d94SElaine Zhang 		rockchip_pll_get_rate(&rk1808_pll_clks[APLL],
1287ed6f5d94SElaine Zhang 				      priv->cru, APLL);
1288ed6f5d94SElaine Zhang 		priv->armclk_init_hz = priv->armclk_enter_hz;
1289ed6f5d94SElaine Zhang 	}
129045a3782aSElaine Zhang 	if (rockchip_pll_get_rate(&rk1808_pll_clks[APLL],
129145a3782aSElaine Zhang 				  priv->cru, APLL) != APLL_HZ) {
129245a3782aSElaine Zhang 		ret = rk1808_armclk_set_clk(priv, APLL_HZ);
129345a3782aSElaine Zhang 		if (ret < 0)
129445a3782aSElaine Zhang 			printf("%s failed to set armclk rate\n", __func__);
1295ed6f5d94SElaine Zhang 		priv->armclk_init_hz = APLL_HZ;
129645a3782aSElaine Zhang 	}
129728e9e98aSJason Zhu #ifdef CONFIG_SPL_BUILD
129828e9e98aSJason Zhu 	/*
129928e9e98aSJason Zhu 	 * The eMMC clk is depended on gpll, and the eMMC is needed to
130028e9e98aSJason Zhu 	 * run 150MHz in HS200 mode. So set gpll to GPLL_HZ(594000000)
130128e9e98aSJason Zhu 	 * which can be divided near to 150MHz.
130228e9e98aSJason Zhu 	 */
130328e9e98aSJason Zhu 	ret = rockchip_pll_set_rate(&rk1808_pll_clks[GPLL],
130428e9e98aSJason Zhu 				    priv->cru, GPLL, GPLL_HZ);
130528e9e98aSJason Zhu 	if (ret < 0)
130628e9e98aSJason Zhu 		printf("%s failed to set gpll rate\n", __func__);
130728e9e98aSJason Zhu #endif
130845a3782aSElaine Zhang 	priv->cpll_hz = rockchip_pll_get_rate(&rk1808_pll_clks[CPLL],
130945a3782aSElaine Zhang 					      priv->cru, CPLL);
131045a3782aSElaine Zhang 	priv->gpll_hz = rockchip_pll_get_rate(&rk1808_pll_clks[GPLL],
131145a3782aSElaine Zhang 					      priv->cru, GPLL);
13121ae6d6e5SElaine Zhang 	priv->npll_hz = rockchip_pll_get_rate(&rk1808_pll_clks[NPLL],
13131ae6d6e5SElaine Zhang 					      priv->cru, NPLL);
131445a3782aSElaine Zhang 
131520769c64SElaine Zhang #ifndef CONFIG_SPL_BUILD
131620769c64SElaine Zhang 	crypto_rate = rk1808_crypto_get_clk(priv, SCLK_CRYPTO);
131720769c64SElaine Zhang 	crypto_apk_rate = rk1808_crypto_get_clk(priv, SCLK_CRYPTO_APK);
1318c2fb06deSElaine Zhang 	emmc_rate = rk1808_mmc_get_clk(priv, SCLK_EMMC);
1319c2fb06deSElaine Zhang 	sdmmc_rate = rk1808_mmc_get_clk(priv, SCLK_SDMMC);
1320c2fb06deSElaine Zhang 	sfc_rate = rk1808_sfc_get_clk(priv, SCLK_SFC);
132120769c64SElaine Zhang #endif
132220769c64SElaine Zhang 
132345a3782aSElaine Zhang 	/* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */
132445a3782aSElaine Zhang 	ret = clk_set_defaults(dev);
132545a3782aSElaine Zhang 	if (ret)
132645a3782aSElaine Zhang 		debug("%s clk_set_defaults failed %d\n", __func__, ret);
1327ed6f5d94SElaine Zhang 	else
1328ed6f5d94SElaine Zhang 		priv->sync_kernel = true;
132945a3782aSElaine Zhang 
133020769c64SElaine Zhang #ifndef CONFIG_SPL_BUILD
133120769c64SElaine Zhang 	rk1808_crypto_set_clk(priv, SCLK_CRYPTO, crypto_rate);
133220769c64SElaine Zhang 	rk1808_crypto_set_clk(priv, SCLK_CRYPTO_APK, crypto_apk_rate);
1333c2fb06deSElaine Zhang 	rk1808_mmc_set_clk(priv, SCLK_EMMC, emmc_rate);
1334c2fb06deSElaine Zhang 	rk1808_mmc_set_clk(priv, SCLK_SDMMC, sdmmc_rate);
1335c2fb06deSElaine Zhang 	rk1808_sfc_set_clk(priv, SCLK_SFC, sfc_rate);
133620769c64SElaine Zhang #endif
133720769c64SElaine Zhang 
133845a3782aSElaine Zhang 	return 0;
133945a3782aSElaine Zhang }
134045a3782aSElaine Zhang 
rk1808_clk_ofdata_to_platdata(struct udevice * dev)134145a3782aSElaine Zhang static int rk1808_clk_ofdata_to_platdata(struct udevice *dev)
134245a3782aSElaine Zhang {
134345a3782aSElaine Zhang 	struct rk1808_clk_priv *priv = dev_get_priv(dev);
134445a3782aSElaine Zhang 
134545a3782aSElaine Zhang 	priv->cru = dev_read_addr_ptr(dev);
134645a3782aSElaine Zhang 
134745a3782aSElaine Zhang 	return 0;
134845a3782aSElaine Zhang }
134945a3782aSElaine Zhang 
rk1808_clk_bind(struct udevice * dev)135045a3782aSElaine Zhang static int rk1808_clk_bind(struct udevice *dev)
135145a3782aSElaine Zhang {
135245a3782aSElaine Zhang 	int ret;
135345a3782aSElaine Zhang 	struct udevice *sys_child, *sf_child;
135445a3782aSElaine Zhang 	struct sysreset_reg *priv;
135545a3782aSElaine Zhang 	struct softreset_reg *sf_priv;
135645a3782aSElaine Zhang 
135745a3782aSElaine Zhang 	/* The reset driver does not have a device node, so bind it here */
135845a3782aSElaine Zhang 	ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
135945a3782aSElaine Zhang 				 &sys_child);
136045a3782aSElaine Zhang 	if (ret) {
136145a3782aSElaine Zhang 		debug("Warning: No sysreset driver: ret=%d\n", ret);
136245a3782aSElaine Zhang 	} else {
136345a3782aSElaine Zhang 		priv = malloc(sizeof(struct sysreset_reg));
136445a3782aSElaine Zhang 		priv->glb_srst_fst_value = offsetof(struct rk1808_cru,
136545a3782aSElaine Zhang 						    glb_srst_fst);
136645a3782aSElaine Zhang 		priv->glb_srst_snd_value = offsetof(struct rk1808_cru,
136745a3782aSElaine Zhang 						    glb_srst_snd);
136845a3782aSElaine Zhang 		sys_child->priv = priv;
136945a3782aSElaine Zhang 	}
137045a3782aSElaine Zhang 
137145a3782aSElaine Zhang 	ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset",
137245a3782aSElaine Zhang 					 dev_ofnode(dev), &sf_child);
137345a3782aSElaine Zhang 	if (ret) {
137445a3782aSElaine Zhang 		debug("Warning: No rockchip reset driver: ret=%d\n", ret);
137545a3782aSElaine Zhang 	} else {
137645a3782aSElaine Zhang 		sf_priv = malloc(sizeof(struct softreset_reg));
137745a3782aSElaine Zhang 		sf_priv->sf_reset_offset = offsetof(struct rk1808_cru,
137845a3782aSElaine Zhang 						    softrst_con[0]);
137945a3782aSElaine Zhang 		sf_priv->sf_reset_num = 16;
138045a3782aSElaine Zhang 		sf_child->priv = sf_priv;
138145a3782aSElaine Zhang 	}
138245a3782aSElaine Zhang 
138345a3782aSElaine Zhang 	return 0;
138445a3782aSElaine Zhang }
138545a3782aSElaine Zhang 
138645a3782aSElaine Zhang static const struct udevice_id rk1808_clk_ids[] = {
138745a3782aSElaine Zhang 	{ .compatible = "rockchip,rk1808-cru" },
138845a3782aSElaine Zhang 	{ }
138945a3782aSElaine Zhang };
139045a3782aSElaine Zhang 
139145a3782aSElaine Zhang U_BOOT_DRIVER(rockchip_rk1808_cru) = {
139245a3782aSElaine Zhang 	.name		= "rockchip_rk1808_cru",
139345a3782aSElaine Zhang 	.id		= UCLASS_CLK,
139445a3782aSElaine Zhang 	.of_match	= rk1808_clk_ids,
139545a3782aSElaine Zhang 	.priv_auto_alloc_size = sizeof(struct rk1808_clk_priv),
139645a3782aSElaine Zhang 	.ofdata_to_platdata = rk1808_clk_ofdata_to_platdata,
139745a3782aSElaine Zhang 	.ops		= &rk1808_clk_ops,
139845a3782aSElaine Zhang 	.bind		= rk1808_clk_bind,
139945a3782aSElaine Zhang 	.probe		= rk1808_clk_probe,
140045a3782aSElaine Zhang };
140145a3782aSElaine Zhang 
140245a3782aSElaine Zhang #ifndef CONFIG_SPL_BUILD
140345a3782aSElaine Zhang /**
140445a3782aSElaine Zhang  * soc_clk_dump() - Print clock frequencies
140545a3782aSElaine Zhang  * Returns zero on success
140645a3782aSElaine Zhang  *
140745a3782aSElaine Zhang  * Implementation for the clk dump command.
140845a3782aSElaine Zhang  */
soc_clk_dump(void)140945a3782aSElaine Zhang int soc_clk_dump(void)
141045a3782aSElaine Zhang {
141145a3782aSElaine Zhang 	struct udevice *cru_dev;
1412ed6f5d94SElaine Zhang 	struct rk1808_clk_priv *priv;
141345a3782aSElaine Zhang 	const struct rk1808_clk_info *clk_dump;
141445a3782aSElaine Zhang 	struct clk clk;
141545a3782aSElaine Zhang 	unsigned long clk_count = ARRAY_SIZE(clks_dump);
141645a3782aSElaine Zhang 	unsigned long rate;
141745a3782aSElaine Zhang 	int i, ret;
141845a3782aSElaine Zhang 
141945a3782aSElaine Zhang 	ret = uclass_get_device_by_driver(UCLASS_CLK,
142045a3782aSElaine Zhang 					  DM_GET_DRIVER(rockchip_rk1808_cru),
142145a3782aSElaine Zhang 					  &cru_dev);
142245a3782aSElaine Zhang 	if (ret) {
142345a3782aSElaine Zhang 		printf("%s failed to get cru device\n", __func__);
142445a3782aSElaine Zhang 		return ret;
142545a3782aSElaine Zhang 	}
142645a3782aSElaine Zhang 
1427ed6f5d94SElaine Zhang 	priv = dev_get_priv(cru_dev);
1428ed6f5d94SElaine Zhang 	printf("CLK: (%s. arm: enter %lu KHz, init %lu KHz, kernel %lu%s)\n",
1429ed6f5d94SElaine Zhang 	       priv->sync_kernel ? "sync kernel" : "uboot",
1430ed6f5d94SElaine Zhang 	       priv->armclk_enter_hz / 1000,
1431ed6f5d94SElaine Zhang 	       priv->armclk_init_hz / 1000,
1432ed6f5d94SElaine Zhang 	       priv->set_armclk_rate ? priv->armclk_hz / 1000 : 0,
1433ed6f5d94SElaine Zhang 	       priv->set_armclk_rate ? " KHz" : "N/A");
1434ed6f5d94SElaine Zhang 
143545a3782aSElaine Zhang 	for (i = 0; i < clk_count; i++) {
143645a3782aSElaine Zhang 		clk_dump = &clks_dump[i];
143745a3782aSElaine Zhang 		if (clk_dump->name) {
143845a3782aSElaine Zhang 			clk.id = clk_dump->id;
143945a3782aSElaine Zhang 			if (clk_dump->is_cru)
144045a3782aSElaine Zhang 				ret = clk_request(cru_dev, &clk);
144145a3782aSElaine Zhang 			if (ret < 0)
144245a3782aSElaine Zhang 				return ret;
144345a3782aSElaine Zhang 
144445a3782aSElaine Zhang 			rate = clk_get_rate(&clk);
144545a3782aSElaine Zhang 			clk_free(&clk);
144645a3782aSElaine Zhang 			if (i == 0) {
144745a3782aSElaine Zhang 				if (rate < 0)
144845a3782aSElaine Zhang 					printf("  %s %s\n", clk_dump->name,
144945a3782aSElaine Zhang 					       "unknown");
145045a3782aSElaine Zhang 				else
145145a3782aSElaine Zhang 					printf("  %s %lu KHz\n", clk_dump->name,
145245a3782aSElaine Zhang 					       rate / 1000);
145345a3782aSElaine Zhang 			} else {
145445a3782aSElaine Zhang 				if (rate < 0)
145545a3782aSElaine Zhang 					printf("  %s %s\n", clk_dump->name,
145645a3782aSElaine Zhang 					       "unknown");
145745a3782aSElaine Zhang 				else
145845a3782aSElaine Zhang 					printf("  %s %lu KHz\n", clk_dump->name,
145945a3782aSElaine Zhang 					       rate / 1000);
146045a3782aSElaine Zhang 			}
146145a3782aSElaine Zhang 		}
146245a3782aSElaine Zhang 	}
146345a3782aSElaine Zhang 
146445a3782aSElaine Zhang 	return 0;
146545a3782aSElaine Zhang }
146645a3782aSElaine Zhang #endif
1467