xref: /rk3399_rockchip-uboot/drivers/clk/rockchip/clk_rk3506.c (revision 826d54fb7246ec19f68b3bc16f5d93a9540c9e66)
15b7480cdSFinley Xiao // SPDX-License-Identifier: GPL-2.0
25b7480cdSFinley Xiao /*
35b7480cdSFinley Xiao  * Copyright (c) 2023 Rockchip Electronics Co., Ltd
45b7480cdSFinley Xiao  * Author: Finley Xiao <finley.xiao@rock-chips.com>
55b7480cdSFinley Xiao  */
65b7480cdSFinley Xiao 
75b7480cdSFinley Xiao #include <common.h>
85b7480cdSFinley Xiao #include <clk-uclass.h>
95b7480cdSFinley Xiao #include <dm.h>
105b7480cdSFinley Xiao #include <syscon.h>
115b7480cdSFinley Xiao #include <asm/arch/clock.h>
125b7480cdSFinley Xiao #include <asm/arch/cru_rk3506.h>
135b7480cdSFinley Xiao #include <asm/arch/grf_rk3506.h>
145b7480cdSFinley Xiao #include <asm/arch/hardware.h>
155b7480cdSFinley Xiao #include <asm/io.h>
165b7480cdSFinley Xiao #include <dm/lists.h>
175b7480cdSFinley Xiao #include <dt-bindings/clock/rockchip,rk3506-cru.h>
185b7480cdSFinley Xiao 
195b7480cdSFinley Xiao DECLARE_GLOBAL_DATA_PTR;
205b7480cdSFinley Xiao 
21f8d37df5SFinley Xiao #define RK3506_CRU_BASE  0xFF9A0000
222ecab49fSFinley Xiao #define RK3506_SCRU_BASE 0xFF9A8000
232ecab49fSFinley Xiao 
245b7480cdSFinley Xiao #define DIV_TO_RATE(input_rate, div)    ((input_rate) / ((div) + 1))
255b7480cdSFinley Xiao 
265b7480cdSFinley Xiao /*
275b7480cdSFinley Xiao  * [FRAC PLL]: GPLL, V0PLL, V1PLL
285b7480cdSFinley Xiao  *   - VCO Frequency: 950MHz to 3800MHZ
295b7480cdSFinley Xiao  *   - Output Frequency: 19MHz to 3800MHZ
305b7480cdSFinley Xiao  *   - refdiv: 1 to 63 (Int Mode), 1 to 2 (Frac Mode)
315b7480cdSFinley Xiao  *   - fbdiv: 16 to 3800 (Int Mode), 20 to 380 (Frac Mode)
325b7480cdSFinley Xiao  *   - post1div: 1 to 7
335b7480cdSFinley Xiao  *   - post2div: 1 to 7
345b7480cdSFinley Xiao  */
355b7480cdSFinley Xiao static struct rockchip_pll_rate_table rk3506_pll_rates[] = {
365b7480cdSFinley Xiao 	/* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
375b7480cdSFinley Xiao 	RK3036_PLL_RATE(1896000000, 1, 79, 1, 1, 1, 0),
385b7480cdSFinley Xiao 	RK3036_PLL_RATE(1800000000, 1, 75, 1, 1, 1, 0),
395b7480cdSFinley Xiao 	RK3036_PLL_RATE(1704000000, 1, 71, 1, 1, 1, 0),
405b7480cdSFinley Xiao 	RK3036_PLL_RATE(1608000000, 1, 67, 1, 1, 1, 0),
415b7480cdSFinley Xiao 	RK3036_PLL_RATE(1512000000, 1, 63, 1, 1, 1, 0),
425b7480cdSFinley Xiao 	RK3036_PLL_RATE(1416000000, 1, 59, 1, 1, 1, 0),
435b7480cdSFinley Xiao 	RK3036_PLL_RATE(1350000000, 4, 225, 1, 1, 1, 0),
445b7480cdSFinley Xiao 	RK3036_PLL_RATE(1296000000, 1, 54, 1, 1, 1, 0),
455b7480cdSFinley Xiao 	RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0),
465b7480cdSFinley Xiao 	RK3036_PLL_RATE(1188000000, 1, 99, 2, 1, 1, 0),
475b7480cdSFinley Xiao 	RK3036_PLL_RATE(1179648000, 1, 49, 1, 1, 0, 2550137),
485b7480cdSFinley Xiao 	RK3036_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0),
495b7480cdSFinley Xiao 	RK3036_PLL_RATE(1000000000, 3, 125, 1, 1, 1, 0),
505b7480cdSFinley Xiao 	RK3036_PLL_RATE(993484800, 1, 41, 1, 1, 0, 6630355),
515b7480cdSFinley Xiao 	RK3036_PLL_RATE(983040000, 1, 40, 1, 1, 0, 16106127),
525b7480cdSFinley Xiao 	RK3036_PLL_RATE(960000000, 1, 80, 2, 1, 1, 0),
535b7480cdSFinley Xiao 	RK3036_PLL_RATE(912000000, 1, 76, 2, 1, 1, 0),
545b7480cdSFinley Xiao 	RK3036_PLL_RATE(903168000, 1, 75, 2, 1, 0, 4429185),
555b7480cdSFinley Xiao 	RK3036_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0),
565b7480cdSFinley Xiao 	RK3036_PLL_RATE(800000000, 3, 200, 2, 1, 1, 0),
575b7480cdSFinley Xiao 	RK3036_PLL_RATE(600000000, 1, 50, 2, 1, 1, 0),
585b7480cdSFinley Xiao 	RK3036_PLL_RATE(594000000, 2, 99, 2, 1, 1, 0),
595b7480cdSFinley Xiao 	RK3036_PLL_RATE(408000000, 1, 68, 2, 2, 1, 0),
605b7480cdSFinley Xiao 	RK3036_PLL_RATE(312000000, 1, 78, 6, 1, 1, 0),
615b7480cdSFinley Xiao 	RK3036_PLL_RATE(216000000, 1, 72, 4, 2, 1, 0),
625b7480cdSFinley Xiao 	RK3036_PLL_RATE(96000000, 1, 48, 6, 2, 1, 0),
635b7480cdSFinley Xiao 	{ /* sentinel */ },
645b7480cdSFinley Xiao };
655b7480cdSFinley Xiao 
665b7480cdSFinley Xiao static struct rockchip_pll_clock rk3506_pll_clks[] = {
675b7480cdSFinley Xiao 	[GPLL] = PLL(pll_rk3328, PLL_GPLL, RK3506_PLL_CON(0),
685b7480cdSFinley Xiao 		     RK3506_MODE_CON, 0, 10, 0, rk3506_pll_rates),
695b7480cdSFinley Xiao 	[V0PLL] = PLL(pll_rk3328, PLL_V0PLL, RK3506_PLL_CON(8),
705b7480cdSFinley Xiao 		     RK3506_MODE_CON, 2, 10, 0, rk3506_pll_rates),
715b7480cdSFinley Xiao 	[V1PLL] = PLL(pll_rk3328, PLL_V1PLL, RK3506_PLL_CON(16),
725b7480cdSFinley Xiao 		     RK3506_MODE_CON, 4, 10, 0, rk3506_pll_rates),
735b7480cdSFinley Xiao };
745b7480cdSFinley Xiao 
755b7480cdSFinley Xiao #define RK3506_CPUCLK_RATE(_rate, _aclk_m_core, _pclk_dbg)	\
765b7480cdSFinley Xiao {								\
775b7480cdSFinley Xiao 	.rate = _rate##U,					\
785b7480cdSFinley Xiao 	.aclk_div = _aclk_m_core,				\
795b7480cdSFinley Xiao 	.pclk_div = _pclk_dbg,					\
805b7480cdSFinley Xiao }
815b7480cdSFinley Xiao 
825b7480cdSFinley Xiao /* SIGN-OFF: aclk_core: 500M, pclk_core: 125M, */
835b7480cdSFinley Xiao static struct rockchip_cpu_rate_table rk3506_cpu_rates[] = {
845b7480cdSFinley Xiao 	RK3506_CPUCLK_RATE(1179648000, 1, 6),
855b7480cdSFinley Xiao 	RK3506_CPUCLK_RATE(903168000, 1, 5),
865b7480cdSFinley Xiao 	RK3506_CPUCLK_RATE(800000000, 1, 4),
875b7480cdSFinley Xiao 	RK3506_CPUCLK_RATE(589824000, 1, 3),
885b7480cdSFinley Xiao 	RK3506_CPUCLK_RATE(400000000, 1, 2),
895b7480cdSFinley Xiao 	RK3506_CPUCLK_RATE(200000000, 1, 1),
905b7480cdSFinley Xiao 	{ /* sentinel */ },
915b7480cdSFinley Xiao };
925b7480cdSFinley Xiao 
935b7480cdSFinley Xiao #ifndef CONFIG_SPL_BUILD
945b7480cdSFinley Xiao #define RK3506_CLK_DUMP(_id, _name)		\
955b7480cdSFinley Xiao {						\
965b7480cdSFinley Xiao 	.id = _id,				\
975b7480cdSFinley Xiao 	.name = _name,				\
985b7480cdSFinley Xiao }
995b7480cdSFinley Xiao 
1005b7480cdSFinley Xiao static const struct rk3506_clk_info clks_dump[] = {
1015b7480cdSFinley Xiao 	RK3506_CLK_DUMP(PLL_GPLL, "gpll"),
1025b7480cdSFinley Xiao 	RK3506_CLK_DUMP(PLL_V0PLL, "v0pll"),
1035b7480cdSFinley Xiao 	RK3506_CLK_DUMP(PLL_V1PLL, "v1pll"),
1045b7480cdSFinley Xiao 	RK3506_CLK_DUMP(CLK_GPLL_DIV, "clk_gpll_div"),
1055b7480cdSFinley Xiao 	RK3506_CLK_DUMP(CLK_GPLL_DIV_100M, "clk_gpll_div_100m"),
1065b7480cdSFinley Xiao 	RK3506_CLK_DUMP(CLK_V0PLL_DIV, "clk_v0pll_div"),
1075b7480cdSFinley Xiao 	RK3506_CLK_DUMP(CLK_V1PLL_DIV, "clk_v1pll_div"),
1085b7480cdSFinley Xiao 	RK3506_CLK_DUMP(ACLK_BUS_ROOT, "aclk_bus_root"),
1095b7480cdSFinley Xiao 	RK3506_CLK_DUMP(HCLK_BUS_ROOT, "hclk_bus_root"),
1105b7480cdSFinley Xiao 	RK3506_CLK_DUMP(PCLK_BUS_ROOT, "pclk_bus_root"),
1115b7480cdSFinley Xiao 	RK3506_CLK_DUMP(ACLK_HSPERI_ROOT, "aclk_hsperi_root"),
1125b7480cdSFinley Xiao 	RK3506_CLK_DUMP(HCLK_LSPERI_ROOT, "hclk_ksperi_root"),
1135b7480cdSFinley Xiao };
1145b7480cdSFinley Xiao 
1155b7480cdSFinley Xiao /**
1165b7480cdSFinley Xiao  * soc_clk_dump() - Print clock frequencies
1175b7480cdSFinley Xiao  * Returns zero on success
1185b7480cdSFinley Xiao  *
1195b7480cdSFinley Xiao  * Implementation for the clk dump command.
1205b7480cdSFinley Xiao  */
soc_clk_dump(void)1215b7480cdSFinley Xiao int soc_clk_dump(void)
1225b7480cdSFinley Xiao {
1235b7480cdSFinley Xiao 	const struct rk3506_clk_info *clk_dump;
1245b7480cdSFinley Xiao 	struct rk3506_clk_priv *priv;
1255b7480cdSFinley Xiao 	struct udevice *cru_dev;
1265b7480cdSFinley Xiao 	struct clk clk;
1275b7480cdSFinley Xiao 	ulong clk_count = ARRAY_SIZE(clks_dump);
1285b7480cdSFinley Xiao 	ulong rate;
1295b7480cdSFinley Xiao 	int i, ret;
1305de46d87SFinley Xiao 	u32 sel;
1315b7480cdSFinley Xiao 
1325b7480cdSFinley Xiao 	ret = uclass_get_device_by_driver(UCLASS_CLK,
1335b7480cdSFinley Xiao 					  DM_GET_DRIVER(rockchip_rk3506_cru),
1345b7480cdSFinley Xiao 					  &cru_dev);
1355b7480cdSFinley Xiao 	if (ret) {
1365b7480cdSFinley Xiao 		printf("%s failed to get cru device\n", __func__);
1375b7480cdSFinley Xiao 		return ret;
1385b7480cdSFinley Xiao 	}
1395b7480cdSFinley Xiao 
1405b7480cdSFinley Xiao 	priv = dev_get_priv(cru_dev);
1415de46d87SFinley Xiao 	sel = (readl(&priv->cru->clksel_con[15]) &
1425de46d87SFinley Xiao 	       CLK_CORE_SRC_PVTMUX_SEL_MASK) >>
1435de46d87SFinley Xiao 	       CLK_CORE_SRC_PVTMUX_SEL_SHIFT;
1445de46d87SFinley Xiao 	if (sel == CLK_CORE_PVTPLL_SRC)
1455de46d87SFinley Xiao 		printf("CLK: (arm clk use pvtpll, rate = 1200M)\n");
1465de46d87SFinley Xiao 	else
1475b7480cdSFinley Xiao 		printf("CLK: (%s. arm: enter %lu KHz, init %lu KHz, kernel %lu%s)\n",
1485b7480cdSFinley Xiao 		       priv->sync_kernel ? "sync kernel" : "uboot",
1495b7480cdSFinley Xiao 		       priv->armclk_enter_hz / 1000,
1505b7480cdSFinley Xiao 		       priv->armclk_init_hz / 1000,
1515b7480cdSFinley Xiao 		       priv->set_armclk_rate ? priv->armclk_hz / 1000 : 0,
1525b7480cdSFinley Xiao 		       priv->set_armclk_rate ? " KHz" : "N/A");
1535b7480cdSFinley Xiao 	for (i = 0; i < clk_count; i++) {
1545b7480cdSFinley Xiao 		clk_dump = &clks_dump[i];
1555b7480cdSFinley Xiao 		if (clk_dump->name) {
1565b7480cdSFinley Xiao 			clk.id = clk_dump->id;
1575b7480cdSFinley Xiao 			ret = clk_request(cru_dev, &clk);
1585b7480cdSFinley Xiao 			if (ret < 0)
1595b7480cdSFinley Xiao 				return ret;
1605b7480cdSFinley Xiao 
1615b7480cdSFinley Xiao 			rate = clk_get_rate(&clk);
1625b7480cdSFinley Xiao 			clk_free(&clk);
1635b7480cdSFinley Xiao 			if (i == 0) {
1645b7480cdSFinley Xiao 				if (rate < 0)
1655b7480cdSFinley Xiao 					printf("  %s %s\n", clk_dump->name,
1665b7480cdSFinley Xiao 					       "unknown");
1675b7480cdSFinley Xiao 				else
1685b7480cdSFinley Xiao 					printf("  %s %lu KHz\n", clk_dump->name,
1695b7480cdSFinley Xiao 					       rate / 1000);
1705b7480cdSFinley Xiao 			} else {
1715b7480cdSFinley Xiao 				if (rate < 0)
1725b7480cdSFinley Xiao 					printf("  %s %s\n", clk_dump->name,
1735b7480cdSFinley Xiao 					       "unknown");
1745b7480cdSFinley Xiao 				else
1755b7480cdSFinley Xiao 					printf("  %s %lu KHz\n", clk_dump->name,
1765b7480cdSFinley Xiao 					       rate / 1000);
1775b7480cdSFinley Xiao 			}
1785b7480cdSFinley Xiao 		}
1795b7480cdSFinley Xiao 	}
1805b7480cdSFinley Xiao 
1815b7480cdSFinley Xiao 	return 0;
1825b7480cdSFinley Xiao }
1835b7480cdSFinley Xiao #endif
1845b7480cdSFinley Xiao 
rk3506_armclk_get_rate(struct rk3506_clk_priv * priv)1855b7480cdSFinley Xiao static int rk3506_armclk_get_rate(struct rk3506_clk_priv *priv)
1865b7480cdSFinley Xiao {
1875b7480cdSFinley Xiao 	struct rk3506_cru *cru = priv->cru;
1885b7480cdSFinley Xiao 	u32 sel, con, div;
1895b7480cdSFinley Xiao 	ulong prate;
1905b7480cdSFinley Xiao 
1915b7480cdSFinley Xiao 	con = readl(&cru->clksel_con[15]);
1925b7480cdSFinley Xiao 	sel = (con & CLK_CORE_SRC_SEL_MASK) >> CLK_CORE_SRC_SEL_SHIFT;
1935b7480cdSFinley Xiao 	div = (con & CLK_CORE_SRC_DIV_MASK) >> CLK_CORE_SRC_DIV_SHIFT;
1945b7480cdSFinley Xiao 
1955b7480cdSFinley Xiao 	if (sel == CLK_CORE_SEL_GPLL)
1965b7480cdSFinley Xiao 		prate = priv->gpll_hz;
1975b7480cdSFinley Xiao 	else if (sel ==  CLK_CORE_SEL_V0PLL)
1985b7480cdSFinley Xiao 		prate = priv->v0pll_hz;
1995b7480cdSFinley Xiao 	else if (sel ==  CLK_CORE_SEL_V1PLL)
2005b7480cdSFinley Xiao 		prate = priv->v1pll_hz;
2015b7480cdSFinley Xiao 	else
2025b7480cdSFinley Xiao 		return -EINVAL;
2035b7480cdSFinley Xiao 
2045b7480cdSFinley Xiao 	return DIV_TO_RATE(prate, div);
2055b7480cdSFinley Xiao }
2065b7480cdSFinley Xiao 
rk3506_armclk_set_rate(struct rk3506_clk_priv * priv,ulong new_rate)2075b7480cdSFinley Xiao static int rk3506_armclk_set_rate(struct rk3506_clk_priv *priv, ulong new_rate)
2085b7480cdSFinley Xiao {
2095b7480cdSFinley Xiao 	const struct rockchip_cpu_rate_table *rate;
2105b7480cdSFinley Xiao 	struct rk3506_cru *cru = priv->cru;
2115b7480cdSFinley Xiao 	ulong old_rate, prate;
2125b7480cdSFinley Xiao 	u32 con, sel, div, old_div;
2135b7480cdSFinley Xiao 
2145b7480cdSFinley Xiao 	rate = rockchip_get_cpu_settings(rk3506_cpu_rates, new_rate);
2155b7480cdSFinley Xiao 	if (!rate) {
2165b7480cdSFinley Xiao 		printf("%s unsupported rate\n", __func__);
2175b7480cdSFinley Xiao 		return -EINVAL;
2185b7480cdSFinley Xiao 	}
2195b7480cdSFinley Xiao 
2205b7480cdSFinley Xiao 	/*
2215b7480cdSFinley Xiao 	 * set up dependent divisors for PCLK and ACLK clocks.
2225b7480cdSFinley Xiao 	 */
2235b7480cdSFinley Xiao 	old_rate = rk3506_armclk_get_rate(priv);
2245b7480cdSFinley Xiao 	if (new_rate >= old_rate) {
2255b7480cdSFinley Xiao 		rk_clrsetreg(&cru->clksel_con[15], ACLK_CORE_DIV_MASK,
2265b7480cdSFinley Xiao 			     rate->aclk_div << ACLK_CORE_DIV_SHIFT);
2275b7480cdSFinley Xiao 		rk_clrsetreg(&cru->clksel_con[16], PCLK_CORE_DIV_MASK,
2285b7480cdSFinley Xiao 			     rate->pclk_div << PCLK_CORE_DIV_SHIFT);
2295b7480cdSFinley Xiao 	}
2305b7480cdSFinley Xiao 
2315b7480cdSFinley Xiao 	if (new_rate == 589824000 || new_rate == 1179648000) {
2325b7480cdSFinley Xiao 		sel = CLK_CORE_SEL_V0PLL;
2335b7480cdSFinley Xiao 		div = DIV_ROUND_UP(priv->v0pll_hz, new_rate);
2345b7480cdSFinley Xiao 		prate = priv->v0pll_hz;
2355b7480cdSFinley Xiao 	} else if (new_rate == 903168000) {
2365b7480cdSFinley Xiao 		sel = CLK_CORE_SEL_V1PLL;
2375b7480cdSFinley Xiao 		div = DIV_ROUND_UP(priv->v1pll_hz, new_rate);
2385b7480cdSFinley Xiao 		prate = priv->v1pll_hz;
2395b7480cdSFinley Xiao 	} else {
2405b7480cdSFinley Xiao 		sel = CLK_CORE_SEL_GPLL;
2415b7480cdSFinley Xiao 		div = DIV_ROUND_UP(priv->gpll_hz, new_rate);
2425b7480cdSFinley Xiao 		prate = priv->gpll_hz;
2435b7480cdSFinley Xiao 	}
2445b7480cdSFinley Xiao 	assert(div - 1 <= 31);
2455b7480cdSFinley Xiao 
2465b7480cdSFinley Xiao 	con = readl(&cru->clksel_con[15]);
2475b7480cdSFinley Xiao 	old_div = (con & CLK_CORE_SRC_DIV_MASK) >> CLK_CORE_SRC_DIV_SHIFT;
2485b7480cdSFinley Xiao 	if (DIV_TO_RATE(prate, old_div) > new_rate) {
2495b7480cdSFinley Xiao 		rk_clrsetreg(&cru->clksel_con[15], CLK_CORE_SRC_DIV_MASK,
2505b7480cdSFinley Xiao 			     (div - 1) << CLK_CORE_SRC_DIV_SHIFT);
2515b7480cdSFinley Xiao 		rk_clrsetreg(&cru->clksel_con[15], CLK_CORE_SRC_SEL_MASK,
2525b7480cdSFinley Xiao 			     sel << CLK_CORE_SRC_SEL_SHIFT);
2535b7480cdSFinley Xiao 	} else {
2545b7480cdSFinley Xiao 		rk_clrsetreg(&cru->clksel_con[15], CLK_CORE_SRC_SEL_MASK,
2555b7480cdSFinley Xiao 			     sel << CLK_CORE_SRC_SEL_SHIFT);
2565b7480cdSFinley Xiao 		rk_clrsetreg(&cru->clksel_con[15], CLK_CORE_SRC_DIV_MASK,
2575b7480cdSFinley Xiao 			     (div - 1) << CLK_CORE_SRC_DIV_SHIFT);
2585b7480cdSFinley Xiao 	}
2595b7480cdSFinley Xiao 
2605b7480cdSFinley Xiao 	if (new_rate < old_rate) {
2615b7480cdSFinley Xiao 		rk_clrsetreg(&cru->clksel_con[15], ACLK_CORE_DIV_MASK,
2625b7480cdSFinley Xiao 			     rate->aclk_div << ACLK_CORE_DIV_SHIFT);
2635b7480cdSFinley Xiao 		rk_clrsetreg(&cru->clksel_con[16], PCLK_CORE_DIV_MASK,
2645b7480cdSFinley Xiao 			     rate->pclk_div << PCLK_CORE_DIV_SHIFT);
2655b7480cdSFinley Xiao 	}
2665b7480cdSFinley Xiao 
2675b7480cdSFinley Xiao 	return 0;
2685b7480cdSFinley Xiao }
2695b7480cdSFinley Xiao 
rk3506_pll_div_get_rate(struct rk3506_clk_priv * priv,ulong clk_id)2705b7480cdSFinley Xiao static ulong rk3506_pll_div_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
2715b7480cdSFinley Xiao {
2725b7480cdSFinley Xiao 	struct rk3506_cru *cru = priv->cru;
2735b7480cdSFinley Xiao 	u32 con, div;
2745b7480cdSFinley Xiao 	ulong prate;
2755b7480cdSFinley Xiao 
2765b7480cdSFinley Xiao 	switch (clk_id) {
2775b7480cdSFinley Xiao 	case CLK_GPLL_DIV:
2785b7480cdSFinley Xiao 		con = readl(&cru->clksel_con[0]);
2795b7480cdSFinley Xiao 		div = (con & CLK_GPLL_DIV_MASK) >> CLK_GPLL_DIV_SHIFT;
2805b7480cdSFinley Xiao 		prate = priv->gpll_hz;
2815b7480cdSFinley Xiao 		break;
2825b7480cdSFinley Xiao 	case CLK_GPLL_DIV_100M:
2835b7480cdSFinley Xiao 		con = readl(&cru->clksel_con[0]);
2845b7480cdSFinley Xiao 		div = (con & CLK_GPLL_DIV_100M_MASK) >> CLK_GPLL_DIV_100M_SHIFT;
2855b7480cdSFinley Xiao 		prate = priv->gpll_div_hz;
2865b7480cdSFinley Xiao 		break;
2875b7480cdSFinley Xiao 	case CLK_V0PLL_DIV:
2885b7480cdSFinley Xiao 		con = readl(&cru->clksel_con[1]);
2895b7480cdSFinley Xiao 		div = (con & CLK_V0PLL_DIV_MASK) >> CLK_V0PLL_DIV_SHIFT;
2905b7480cdSFinley Xiao 		prate = priv->v0pll_hz;
2915b7480cdSFinley Xiao 		break;
2925b7480cdSFinley Xiao 	case CLK_V1PLL_DIV:
2935b7480cdSFinley Xiao 		con = readl(&cru->clksel_con[1]);
2945b7480cdSFinley Xiao 		div = (con & CLK_V1PLL_DIV_MASK) >> CLK_V1PLL_DIV_SHIFT;
2955b7480cdSFinley Xiao 		prate = priv->v1pll_hz;
2965b7480cdSFinley Xiao 		break;
2975b7480cdSFinley Xiao 	default:
2985b7480cdSFinley Xiao 		return -ENOENT;
2995b7480cdSFinley Xiao 	}
3005b7480cdSFinley Xiao 
3015b7480cdSFinley Xiao 	return DIV_TO_RATE(prate, div);
3025b7480cdSFinley Xiao }
3035b7480cdSFinley Xiao 
rk3506_pll_div_set_rate(struct rk3506_clk_priv * priv,ulong clk_id,ulong rate)3045b7480cdSFinley Xiao static ulong rk3506_pll_div_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
3055b7480cdSFinley Xiao 				 ulong rate)
3065b7480cdSFinley Xiao {
3075b7480cdSFinley Xiao 	struct rk3506_cru *cru = priv->cru;
3085b7480cdSFinley Xiao 	u32 div;
3095b7480cdSFinley Xiao 
3105b7480cdSFinley Xiao 	switch (clk_id) {
3115b7480cdSFinley Xiao 	case CLK_GPLL_DIV:
3125b7480cdSFinley Xiao 		div = DIV_ROUND_UP(priv->gpll_hz, rate);
3135b7480cdSFinley Xiao 		assert(div - 1 <= 15);
3145b7480cdSFinley Xiao 		rk_clrsetreg(&cru->clksel_con[0], CLK_GPLL_DIV_MASK,
3155b7480cdSFinley Xiao 			     ((div - 1) << CLK_GPLL_DIV_SHIFT));
3165b7480cdSFinley Xiao 		break;
3175b7480cdSFinley Xiao 	case CLK_GPLL_DIV_100M:
3185b7480cdSFinley Xiao 		div = DIV_ROUND_UP(priv->gpll_div_hz, rate);
3195b7480cdSFinley Xiao 		assert(div - 1 <= 15);
3205b7480cdSFinley Xiao 		rk_clrsetreg(&cru->clksel_con[0], CLK_GPLL_DIV_100M_MASK,
3215b7480cdSFinley Xiao 			     ((div - 1) << CLK_GPLL_DIV_100M_SHIFT));
3225b7480cdSFinley Xiao 		break;
3235b7480cdSFinley Xiao 	case CLK_V0PLL_DIV:
3245b7480cdSFinley Xiao 		div = DIV_ROUND_UP(priv->v0pll_hz, rate);
3255b7480cdSFinley Xiao 		assert(div - 1 <= 15);
3265b7480cdSFinley Xiao 		rk_clrsetreg(&cru->clksel_con[1], CLK_V0PLL_DIV_MASK,
3275b7480cdSFinley Xiao 			     ((div - 1) << CLK_V0PLL_DIV_SHIFT));
3285b7480cdSFinley Xiao 		break;
3295b7480cdSFinley Xiao 	case CLK_V1PLL_DIV:
3305b7480cdSFinley Xiao 		div = DIV_ROUND_UP(priv->v1pll_hz, rate);
3315b7480cdSFinley Xiao 		assert(div - 1 <= 15);
3325b7480cdSFinley Xiao 		rk_clrsetreg(&cru->clksel_con[1], CLK_V1PLL_DIV_MASK,
3335b7480cdSFinley Xiao 			     ((div - 1) << CLK_V1PLL_DIV_SHIFT));
3345b7480cdSFinley Xiao 		break;
3355b7480cdSFinley Xiao 	default:
3365b7480cdSFinley Xiao 		return -ENOENT;
3375b7480cdSFinley Xiao 	}
3385b7480cdSFinley Xiao 
3395b7480cdSFinley Xiao 	return rk3506_pll_div_get_rate(priv, clk_id);
3405b7480cdSFinley Xiao }
3415b7480cdSFinley Xiao 
rk3506_bus_get_rate(struct rk3506_clk_priv * priv,ulong clk_id)3425b7480cdSFinley Xiao static ulong rk3506_bus_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
3435b7480cdSFinley Xiao {
3445b7480cdSFinley Xiao 	struct rk3506_cru *cru = priv->cru;
3455b7480cdSFinley Xiao 	u32 sel, con, div;
3465b7480cdSFinley Xiao 	ulong prate;
3475b7480cdSFinley Xiao 
3485b7480cdSFinley Xiao 	switch (clk_id) {
3495b7480cdSFinley Xiao 	case ACLK_BUS_ROOT:
3505b7480cdSFinley Xiao 		con = readl(&cru->clksel_con[21]);
3515b7480cdSFinley Xiao 		sel = (con & ACLK_BUS_SEL_MASK) >> ACLK_BUS_SEL_SHIFT;
3525b7480cdSFinley Xiao 		div = (con & ACLK_BUS_DIV_MASK) >> ACLK_BUS_DIV_SHIFT;
3535b7480cdSFinley Xiao 		break;
3545b7480cdSFinley Xiao 	case HCLK_BUS_ROOT:
3555b7480cdSFinley Xiao 		con = readl(&cru->clksel_con[21]);
3565b7480cdSFinley Xiao 		sel = (con & HCLK_BUS_SEL_MASK) >> HCLK_BUS_SEL_SHIFT;
3575b7480cdSFinley Xiao 		div = (con & HCLK_BUS_DIV_MASK) >> HCLK_BUS_DIV_SHIFT;
3585b7480cdSFinley Xiao 		break;
3595b7480cdSFinley Xiao 	case PCLK_BUS_ROOT:
3605b7480cdSFinley Xiao 		con = readl(&cru->clksel_con[22]);
3615b7480cdSFinley Xiao 		sel = (con & PCLK_BUS_SEL_MASK) >> PCLK_BUS_SEL_SHIFT;
3625b7480cdSFinley Xiao 		div = (con & PCLK_BUS_DIV_MASK) >> PCLK_BUS_DIV_SHIFT;
3635b7480cdSFinley Xiao 		break;
3645b7480cdSFinley Xiao 	default:
3655b7480cdSFinley Xiao 		return -ENOENT;
3665b7480cdSFinley Xiao 	}
3675b7480cdSFinley Xiao 
3685b7480cdSFinley Xiao 	if (sel == ACLK_BUS_SEL_GPLL_DIV)
3695b7480cdSFinley Xiao 		prate = priv->gpll_div_hz;
3705b7480cdSFinley Xiao 	else if (sel == ACLK_BUS_SEL_V0PLL_DIV)
3715b7480cdSFinley Xiao 		prate = priv->v0pll_div_hz;
3725b7480cdSFinley Xiao 	else if (sel == ACLK_BUS_SEL_V1PLL_DIV)
3735b7480cdSFinley Xiao 		prate = priv->v1pll_div_hz;
3745b7480cdSFinley Xiao 	else
3755b7480cdSFinley Xiao 		return -EINVAL;
3765b7480cdSFinley Xiao 
3775b7480cdSFinley Xiao 	return DIV_TO_RATE(prate, div);
3785b7480cdSFinley Xiao }
3795b7480cdSFinley Xiao 
rk3506_bus_set_rate(struct rk3506_clk_priv * priv,ulong clk_id,ulong rate)3805b7480cdSFinley Xiao static ulong rk3506_bus_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
3815b7480cdSFinley Xiao 				 ulong rate)
3825b7480cdSFinley Xiao {
3835b7480cdSFinley Xiao 	struct rk3506_cru *cru = priv->cru;
3845b7480cdSFinley Xiao 	u32 sel, div;
3855b7480cdSFinley Xiao 
3865b7480cdSFinley Xiao 	if (priv->v0pll_div_hz % rate == 0) {
3875b7480cdSFinley Xiao 		sel = ACLK_BUS_SEL_V0PLL_DIV;
3885b7480cdSFinley Xiao 		div = DIV_ROUND_UP(priv->v0pll_div_hz, rate);
3895b7480cdSFinley Xiao 	} else if (priv->v1pll_div_hz % rate == 0) {
3905b7480cdSFinley Xiao 		sel= ACLK_BUS_SEL_V1PLL_DIV;
3915b7480cdSFinley Xiao 		div = DIV_ROUND_UP(priv->v1pll_div_hz, rate);
3925b7480cdSFinley Xiao 	} else {
3935b7480cdSFinley Xiao 		sel= ACLK_BUS_SEL_GPLL_DIV;
3945b7480cdSFinley Xiao 		div = DIV_ROUND_UP(priv->gpll_div_hz, rate);
3955b7480cdSFinley Xiao 	}
3965b7480cdSFinley Xiao 	assert(div - 1 <= 31);
3975b7480cdSFinley Xiao 
3985b7480cdSFinley Xiao 	switch (clk_id) {
3995b7480cdSFinley Xiao 	case ACLK_BUS_ROOT:
4005b7480cdSFinley Xiao 		rk_clrsetreg(&cru->clksel_con[21],
4015b7480cdSFinley Xiao 			     ACLK_BUS_DIV_MASK | ACLK_BUS_SEL_MASK,
4025b7480cdSFinley Xiao 			     (sel << ACLK_BUS_SEL_SHIFT) |
4035b7480cdSFinley Xiao 			     ((div - 1) << ACLK_BUS_DIV_SHIFT));
4045b7480cdSFinley Xiao 		break;
4055b7480cdSFinley Xiao 	case HCLK_BUS_ROOT:
4065b7480cdSFinley Xiao 		rk_clrsetreg(&cru->clksel_con[21],
4075b7480cdSFinley Xiao 			     HCLK_BUS_SEL_MASK | HCLK_BUS_DIV_MASK,
4085b7480cdSFinley Xiao 			     (sel << HCLK_BUS_SEL_SHIFT) |
4095b7480cdSFinley Xiao 			     ((div - 1) << HCLK_BUS_DIV_SHIFT));
4105b7480cdSFinley Xiao 		break;
4115b7480cdSFinley Xiao 	case PCLK_BUS_ROOT:
4125b7480cdSFinley Xiao 		rk_clrsetreg(&cru->clksel_con[22],
4135b7480cdSFinley Xiao 			     PCLK_BUS_SEL_MASK | PCLK_BUS_DIV_MASK,
4145b7480cdSFinley Xiao 			     (sel << PCLK_BUS_SEL_SHIFT) |
4155b7480cdSFinley Xiao 			     ((div - 1) << PCLK_BUS_DIV_SHIFT));
4165b7480cdSFinley Xiao 		break;
4175b7480cdSFinley Xiao 	default:
4185b7480cdSFinley Xiao 		return -ENOENT;
4195b7480cdSFinley Xiao 	}
4205b7480cdSFinley Xiao 
4215b7480cdSFinley Xiao 	return rk3506_bus_get_rate(priv, clk_id);
4225b7480cdSFinley Xiao }
4235b7480cdSFinley Xiao 
rk3506_peri_get_rate(struct rk3506_clk_priv * priv,ulong clk_id)4245b7480cdSFinley Xiao static ulong rk3506_peri_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
4255b7480cdSFinley Xiao {
4265b7480cdSFinley Xiao 	struct rk3506_cru *cru = priv->cru;
4275b7480cdSFinley Xiao 	u32 sel, con, div;
4285b7480cdSFinley Xiao 	ulong prate;
4295b7480cdSFinley Xiao 
4305b7480cdSFinley Xiao 	switch (clk_id) {
4315b7480cdSFinley Xiao 	case ACLK_HSPERI_ROOT:
4325b7480cdSFinley Xiao 		con = readl(&cru->clksel_con[49]);
4335b7480cdSFinley Xiao 		sel = (con & ACLK_HSPERI_SEL_MASK) >> ACLK_HSPERI_SEL_SHIFT;
4345b7480cdSFinley Xiao 		div = (con & ACLK_HSPERI_DIV_MASK) >> ACLK_HSPERI_DIV_SHIFT;
4355b7480cdSFinley Xiao 		break;
4365b7480cdSFinley Xiao 	case HCLK_LSPERI_ROOT:
4375b7480cdSFinley Xiao 		con = readl(&cru->clksel_con[29]);
4385b7480cdSFinley Xiao 		sel = (con & HCLK_LSPERI_SEL_MASK) >> HCLK_LSPERI_SEL_SHIFT;
4395b7480cdSFinley Xiao 		div = (con & HCLK_LSPERI_DIV_MASK) >> HCLK_LSPERI_DIV_SHIFT;
4405b7480cdSFinley Xiao 		break;
4415b7480cdSFinley Xiao 	default:
4425b7480cdSFinley Xiao 		return -ENOENT;
4435b7480cdSFinley Xiao 	}
4445b7480cdSFinley Xiao 
4455b7480cdSFinley Xiao 	if (sel == ACLK_HSPERI_SEL_GPLL_DIV)
4465b7480cdSFinley Xiao 		prate = priv->gpll_div_hz;
4475b7480cdSFinley Xiao 	else if (sel == ACLK_HSPERI_SEL_V0PLL_DIV)
4485b7480cdSFinley Xiao 		prate = priv->v0pll_div_hz;
4495b7480cdSFinley Xiao 	else if (sel == ACLK_HSPERI_SEL_V1PLL_DIV)
4505b7480cdSFinley Xiao 		prate = priv->v1pll_div_hz;
4515b7480cdSFinley Xiao 	else
4525b7480cdSFinley Xiao 		return -EINVAL;
4535b7480cdSFinley Xiao 
4545b7480cdSFinley Xiao 	return DIV_TO_RATE(prate, div);
4555b7480cdSFinley Xiao }
4565b7480cdSFinley Xiao 
rk3506_peri_set_rate(struct rk3506_clk_priv * priv,ulong clk_id,ulong rate)4575b7480cdSFinley Xiao static ulong rk3506_peri_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
4585b7480cdSFinley Xiao 				  ulong rate)
4595b7480cdSFinley Xiao {
4605b7480cdSFinley Xiao 	struct rk3506_cru *cru = priv->cru;
4615b7480cdSFinley Xiao 	u32 sel, div;
4625b7480cdSFinley Xiao 
4635b7480cdSFinley Xiao 	if (priv->v0pll_div_hz % rate == 0) {
4645b7480cdSFinley Xiao 		sel = ACLK_BUS_SEL_V0PLL_DIV;
4655b7480cdSFinley Xiao 		div = DIV_ROUND_UP(priv->v0pll_div_hz, rate);
4665b7480cdSFinley Xiao 	} else if (priv->v1pll_div_hz % rate == 0) {
4675b7480cdSFinley Xiao 		sel = ACLK_BUS_SEL_V1PLL_DIV;
4685b7480cdSFinley Xiao 		div = DIV_ROUND_UP(priv->v1pll_div_hz, rate);
4695b7480cdSFinley Xiao 	} else {
4705b7480cdSFinley Xiao 		sel = ACLK_BUS_SEL_GPLL_DIV;
4715b7480cdSFinley Xiao 		div = DIV_ROUND_UP(priv->gpll_div_hz, rate);
4725b7480cdSFinley Xiao 	}
4735b7480cdSFinley Xiao 	assert(div - 1 <= 31);
4745b7480cdSFinley Xiao 
4755b7480cdSFinley Xiao 	switch (clk_id) {
4765b7480cdSFinley Xiao 	case ACLK_HSPERI_ROOT:
4775b7480cdSFinley Xiao 		rk_clrsetreg(&cru->clksel_con[49],
4785b7480cdSFinley Xiao 			     ACLK_HSPERI_SEL_MASK | ACLK_HSPERI_DIV_MASK,
4795b7480cdSFinley Xiao 			     (sel << ACLK_HSPERI_SEL_SHIFT) |
4805b7480cdSFinley Xiao 			     ((div - 1) << ACLK_HSPERI_DIV_SHIFT));
4815b7480cdSFinley Xiao 		break;
4825b7480cdSFinley Xiao 	case HCLK_LSPERI_ROOT:
4835b7480cdSFinley Xiao 		rk_clrsetreg(&cru->clksel_con[29],
4845b7480cdSFinley Xiao 			     HCLK_LSPERI_SEL_MASK | HCLK_LSPERI_DIV_MASK,
4855b7480cdSFinley Xiao 			     (sel << HCLK_LSPERI_SEL_SHIFT) |
4865b7480cdSFinley Xiao 			     ((div - 1) << HCLK_LSPERI_DIV_SHIFT));
4875b7480cdSFinley Xiao 		break;
4885b7480cdSFinley Xiao 	default:
4895b7480cdSFinley Xiao 		return -ENOENT;
4905b7480cdSFinley Xiao 	}
4915b7480cdSFinley Xiao 
4925b7480cdSFinley Xiao 	return rk3506_peri_get_rate(priv, clk_id);
4935b7480cdSFinley Xiao }
4945b7480cdSFinley Xiao 
rk3506_sdmmc_get_rate(struct rk3506_clk_priv * priv,ulong clk_id)4955b7480cdSFinley Xiao static ulong rk3506_sdmmc_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
4965b7480cdSFinley Xiao {
4975b7480cdSFinley Xiao 	struct rk3506_cru *cru = priv->cru;
4985b7480cdSFinley Xiao 	u32 sel, con, div;
4995b7480cdSFinley Xiao 	ulong prate;
5005b7480cdSFinley Xiao 
5015b7480cdSFinley Xiao 	con = readl(&cru->clksel_con[49]);
5025b7480cdSFinley Xiao 	sel = (con & CCLK_SDMMC_SEL_MASK) >> CCLK_SDMMC_SEL_SHIFT;
5035b7480cdSFinley Xiao 	div = (con & CCLK_SDMMC_DIV_MASK) >> CCLK_SDMMC_DIV_SHIFT;
5045b7480cdSFinley Xiao 
5055b7480cdSFinley Xiao 	if (sel == CCLK_SDMMC_SEL_24M)
5065b7480cdSFinley Xiao 		prate = OSC_HZ;
5075b7480cdSFinley Xiao 	else if (sel == CCLK_SDMMC_SEL_GPLL)
5085b7480cdSFinley Xiao 		prate = priv->gpll_hz;
5095b7480cdSFinley Xiao 	else if (sel == CCLK_SDMMC_SEL_V0PLL)
5105b7480cdSFinley Xiao 		prate = priv->v0pll_hz;
5115b7480cdSFinley Xiao 	else if (sel == CCLK_SDMMC_SEL_V1PLL)
5125b7480cdSFinley Xiao 		prate = priv->v1pll_hz;
5135b7480cdSFinley Xiao 	else
5145b7480cdSFinley Xiao 		return -EINVAL;
5155b7480cdSFinley Xiao 
5165b7480cdSFinley Xiao 	return DIV_TO_RATE(prate, div);
5175b7480cdSFinley Xiao }
5185b7480cdSFinley Xiao 
rk3506_sdmmc_set_rate(struct rk3506_clk_priv * priv,ulong clk_id,ulong rate)5195b7480cdSFinley Xiao static ulong rk3506_sdmmc_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
5205b7480cdSFinley Xiao 				  ulong rate)
5215b7480cdSFinley Xiao {
5225b7480cdSFinley Xiao 	struct rk3506_cru *cru = priv->cru;
5235b7480cdSFinley Xiao 	u32 sel, div;
5245b7480cdSFinley Xiao 
5255b7480cdSFinley Xiao 	if (OSC_HZ % rate == 0) {
5265b7480cdSFinley Xiao 		sel = CCLK_SDMMC_SEL_24M;
5275b7480cdSFinley Xiao 		div = DIV_ROUND_UP(OSC_HZ, rate);
5285b7480cdSFinley Xiao 	} else if (priv->v0pll_hz % rate == 0) {
5295b7480cdSFinley Xiao 		sel = CCLK_SDMMC_SEL_V0PLL;
5305b7480cdSFinley Xiao 		div = DIV_ROUND_UP(priv->v0pll_hz, rate);
5315b7480cdSFinley Xiao 	} else if (priv->v1pll_hz % rate == 0) {
5325b7480cdSFinley Xiao 		sel= CCLK_SDMMC_SEL_V1PLL;
5335b7480cdSFinley Xiao 		div = DIV_ROUND_UP(priv->v1pll_hz, rate);
5345b7480cdSFinley Xiao 	} else {
5355b7480cdSFinley Xiao 		sel= CCLK_SDMMC_SEL_GPLL;
5365b7480cdSFinley Xiao 		div = DIV_ROUND_UP(priv->gpll_hz, rate);
5375b7480cdSFinley Xiao 	}
5385b7480cdSFinley Xiao 	assert(div - 1 <= 63);
5395b7480cdSFinley Xiao 
5405b7480cdSFinley Xiao 	rk_clrsetreg(&cru->clksel_con[49],
5415b7480cdSFinley Xiao 		     CCLK_SDMMC_SEL_MASK | CCLK_SDMMC_DIV_MASK,
5425b7480cdSFinley Xiao 		     (sel << CCLK_SDMMC_SEL_SHIFT) |
5435b7480cdSFinley Xiao 		     ((div - 1) << CCLK_SDMMC_DIV_SHIFT));
5445b7480cdSFinley Xiao 
5455b7480cdSFinley Xiao 	return rk3506_sdmmc_get_rate(priv, clk_id);
5465b7480cdSFinley Xiao }
5475b7480cdSFinley Xiao 
rk3506_saradc_get_rate(struct rk3506_clk_priv * priv,ulong clk_id)5485b7480cdSFinley Xiao static ulong rk3506_saradc_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
5495b7480cdSFinley Xiao {
5505b7480cdSFinley Xiao 	struct rk3506_cru *cru = priv->cru;
5515b7480cdSFinley Xiao 	u32 div, con, sel;
5525b7480cdSFinley Xiao 	ulong prate;
5535b7480cdSFinley Xiao 
5545b7480cdSFinley Xiao 	con = readl(&cru->clksel_con[54]);
5555b7480cdSFinley Xiao 	div = (con & CLK_SARADC_DIV_MASK) >> CLK_SARADC_DIV_SHIFT;
5565b7480cdSFinley Xiao 	sel = (con & CLK_SARADC_SEL_MASK) >> CLK_SARADC_SEL_SHIFT;
5575b7480cdSFinley Xiao 
5585b7480cdSFinley Xiao 	if (sel == CLK_SARADC_SEL_24M)
5595b7480cdSFinley Xiao 		prate = OSC_HZ;
5605b7480cdSFinley Xiao 	else if (sel == CLK_SARADC_SEL_400K)
5615b7480cdSFinley Xiao 		prate = 400000;
5625b7480cdSFinley Xiao 	else if (sel == CLK_SARADC_SEL_32K)
5635b7480cdSFinley Xiao 		prate = 32000;
5645b7480cdSFinley Xiao 	else
5655b7480cdSFinley Xiao 		return -EINVAL;
5665b7480cdSFinley Xiao 
5675b7480cdSFinley Xiao 	return DIV_TO_RATE(prate, div);
5685b7480cdSFinley Xiao }
5695b7480cdSFinley Xiao 
rk3506_saradc_set_rate(struct rk3506_clk_priv * priv,ulong clk_id,ulong rate)5705b7480cdSFinley Xiao static ulong rk3506_saradc_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
5715b7480cdSFinley Xiao 				    ulong rate)
5725b7480cdSFinley Xiao {
5735b7480cdSFinley Xiao 	struct rk3506_cru *cru = priv->cru;
5745b7480cdSFinley Xiao 	u32 div, sel;
5755b7480cdSFinley Xiao 
5765b7480cdSFinley Xiao 	if (32000 % rate == 0) {
5775b7480cdSFinley Xiao 		sel = CLK_SARADC_SEL_32K;
5785b7480cdSFinley Xiao 		div = 1;
5795b7480cdSFinley Xiao 	} else if (400000 % rate == 0) {
5805b7480cdSFinley Xiao 		sel = CLK_SARADC_SEL_400K;
5815b7480cdSFinley Xiao 		div = 1;
5825b7480cdSFinley Xiao 	} else {
5835b7480cdSFinley Xiao 		sel= CLK_SARADC_SEL_24M;
5845b7480cdSFinley Xiao 		div = DIV_ROUND_UP(OSC_HZ, rate);
5855b7480cdSFinley Xiao 	}
5865b7480cdSFinley Xiao 	assert(div - 1 <= 15);
5875b7480cdSFinley Xiao 
5885b7480cdSFinley Xiao 	rk_clrsetreg(&cru->clksel_con[54],
5895b7480cdSFinley Xiao 		     CLK_SARADC_SEL_MASK | CLK_SARADC_DIV_MASK,
5905b7480cdSFinley Xiao 		     (sel << CLK_SARADC_SEL_SHIFT) |
5915b7480cdSFinley Xiao 		     ((div - 1) << CLK_SARADC_DIV_SHIFT));
5925b7480cdSFinley Xiao 
5935b7480cdSFinley Xiao 	return rk3506_saradc_get_rate(priv, clk_id);
5945b7480cdSFinley Xiao }
5955b7480cdSFinley Xiao 
rk3506_tsadc_get_rate(struct rk3506_clk_priv * priv,ulong clk_id)5965b7480cdSFinley Xiao static ulong rk3506_tsadc_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
5975b7480cdSFinley Xiao {
5985b7480cdSFinley Xiao 	struct rk3506_cru *cru = priv->cru;
5995b7480cdSFinley Xiao 	u32 div, con;
6005b7480cdSFinley Xiao 
6015b7480cdSFinley Xiao 	con = readl(&cru->clksel_con[61]);
6025b7480cdSFinley Xiao 	switch (clk_id) {
6035b7480cdSFinley Xiao 	case CLK_TSADC_TSEN:
6045b7480cdSFinley Xiao 		div = (con & CLK_TSADC_TSEN_DIV_MASK) >> CLK_TSADC_TSEN_DIV_SHIFT;
6055b7480cdSFinley Xiao 		break;
6065b7480cdSFinley Xiao 	case CLK_TSADC:
6075b7480cdSFinley Xiao 		div = (con & CLK_TSADC_DIV_MASK) >> CLK_TSADC_DIV_SHIFT;
6085b7480cdSFinley Xiao 		break;
6095b7480cdSFinley Xiao 	default:
6105b7480cdSFinley Xiao 		return -ENOENT;
6115b7480cdSFinley Xiao 	}
6125b7480cdSFinley Xiao 
6135b7480cdSFinley Xiao 	return DIV_TO_RATE(OSC_HZ, div);
6145b7480cdSFinley Xiao }
6155b7480cdSFinley Xiao 
rk3506_tsadc_set_rate(struct rk3506_clk_priv * priv,ulong clk_id,ulong rate)6165b7480cdSFinley Xiao static ulong rk3506_tsadc_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
6175b7480cdSFinley Xiao 				   ulong rate)
6185b7480cdSFinley Xiao {
6195b7480cdSFinley Xiao 	struct rk3506_cru *cru = priv->cru;
6205b7480cdSFinley Xiao 	u32 div;
6215b7480cdSFinley Xiao 
6225b7480cdSFinley Xiao 	switch (clk_id) {
6235b7480cdSFinley Xiao 	case CLK_TSADC_TSEN:
6245b7480cdSFinley Xiao 		div = DIV_ROUND_UP(OSC_HZ, rate);
6255b7480cdSFinley Xiao 		assert(div - 1 <= 7);
6265b7480cdSFinley Xiao 		rk_clrsetreg(&cru->clksel_con[61], CLK_TSADC_TSEN_DIV_MASK,
6275b7480cdSFinley Xiao 			     (div - 1) << CLK_TSADC_TSEN_DIV_SHIFT);
6285b7480cdSFinley Xiao 		break;
6295b7480cdSFinley Xiao 	case CLK_TSADC:
6305b7480cdSFinley Xiao 		div = DIV_ROUND_UP(OSC_HZ, rate);
6315b7480cdSFinley Xiao 		assert(div - 1 <= 255);
6325b7480cdSFinley Xiao 		rk_clrsetreg(&cru->clksel_con[61], CLK_TSADC_DIV_MASK,
6335b7480cdSFinley Xiao 			     (div - 1) << CLK_TSADC_DIV_SHIFT);
6345b7480cdSFinley Xiao 		break;
6355b7480cdSFinley Xiao 	default:
6365b7480cdSFinley Xiao 		return -ENOENT;
6375b7480cdSFinley Xiao 	}
6385b7480cdSFinley Xiao 
6395b7480cdSFinley Xiao 
6405b7480cdSFinley Xiao 	return rk3506_tsadc_get_rate(priv, clk_id);
6415b7480cdSFinley Xiao }
6425b7480cdSFinley Xiao 
rk3506_i2c_get_rate(struct rk3506_clk_priv * priv,ulong clk_id)6435b7480cdSFinley Xiao static ulong rk3506_i2c_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
6445b7480cdSFinley Xiao {
6455b7480cdSFinley Xiao 	struct rk3506_cru *cru = priv->cru;
6465b7480cdSFinley Xiao 	u32 sel, con, div;
6475b7480cdSFinley Xiao 	ulong prate;
6485b7480cdSFinley Xiao 
6495b7480cdSFinley Xiao 	switch (clk_id) {
6505b7480cdSFinley Xiao 	case CLK_I2C0:
6515b7480cdSFinley Xiao 		con = readl(&cru->clksel_con[32]);
6525b7480cdSFinley Xiao 		sel = (con & CLK_I2C0_SEL_MASK) >> CLK_I2C0_SEL_SHIFT;
6535b7480cdSFinley Xiao 		div = (con & CLK_I2C0_DIV_MASK) >> CLK_I2C0_DIV_SHIFT;
6545b7480cdSFinley Xiao 	case CLK_I2C1:
6555b7480cdSFinley Xiao 		con = readl(&cru->clksel_con[32]);
6565b7480cdSFinley Xiao 		sel = (con & CLK_I2C1_SEL_MASK) >> CLK_I2C1_SEL_SHIFT;
6575b7480cdSFinley Xiao 		div = (con & CLK_I2C1_DIV_MASK) >> CLK_I2C1_DIV_SHIFT;
6585b7480cdSFinley Xiao 	case CLK_I2C2:
6595b7480cdSFinley Xiao 		con = readl(&cru->clksel_con[33]);
6605b7480cdSFinley Xiao 		sel = (con & CLK_I2C2_SEL_MASK) >> CLK_I2C2_SEL_SHIFT;
6615b7480cdSFinley Xiao 		div = (con & CLK_I2C2_DIV_MASK) >> CLK_I2C2_DIV_SHIFT;
6625b7480cdSFinley Xiao 		break;
6635b7480cdSFinley Xiao 	default:
6645b7480cdSFinley Xiao 		return -ENOENT;
6655b7480cdSFinley Xiao 	}
6665b7480cdSFinley Xiao 
6675b7480cdSFinley Xiao 	if (sel == CLK_I2C_SEL_GPLL)
6685b7480cdSFinley Xiao 		prate = priv->gpll_hz;
6695b7480cdSFinley Xiao 	else if (sel == CLK_I2C_SEL_V0PLL)
6705b7480cdSFinley Xiao 		prate = priv->v0pll_hz;
6715b7480cdSFinley Xiao 	else if (sel == CLK_I2C_SEL_V1PLL)
6725b7480cdSFinley Xiao 		prate = priv->v1pll_hz;
6735b7480cdSFinley Xiao 	else
6745b7480cdSFinley Xiao 		return -EINVAL;
6755b7480cdSFinley Xiao 
6765b7480cdSFinley Xiao 	return DIV_TO_RATE(prate, div);
6775b7480cdSFinley Xiao }
6785b7480cdSFinley Xiao 
rk3506_i2c_set_rate(struct rk3506_clk_priv * priv,ulong clk_id,ulong rate)6795b7480cdSFinley Xiao static ulong rk3506_i2c_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
6805b7480cdSFinley Xiao 				 ulong rate)
6815b7480cdSFinley Xiao {
6825b7480cdSFinley Xiao 	struct rk3506_cru *cru = priv->cru;
6835b7480cdSFinley Xiao 	u32 sel, div;
6845b7480cdSFinley Xiao 
6855b7480cdSFinley Xiao 	if (priv->v0pll_hz % rate == 0) {
6865b7480cdSFinley Xiao 		sel = CLK_I2C_SEL_V0PLL;
6875b7480cdSFinley Xiao 		div = DIV_ROUND_UP(priv->v0pll_hz, rate);
6885b7480cdSFinley Xiao 	} else if (priv->v1pll_hz % rate == 0) {
6895b7480cdSFinley Xiao 		sel = CLK_I2C_SEL_V1PLL;
6905b7480cdSFinley Xiao 		div = DIV_ROUND_UP(priv->v1pll_hz, rate);
6915b7480cdSFinley Xiao 	} else {
6925b7480cdSFinley Xiao 		sel = CLK_I2C_SEL_GPLL;
6935b7480cdSFinley Xiao 		div = DIV_ROUND_UP(priv->gpll_hz, rate);
6945b7480cdSFinley Xiao 	}
6955b7480cdSFinley Xiao 	assert(div - 1 <= 15);
6965b7480cdSFinley Xiao 
6975b7480cdSFinley Xiao 	switch (clk_id) {
6985b7480cdSFinley Xiao 	case CLK_I2C0:
6995b7480cdSFinley Xiao 		rk_clrsetreg(&cru->clksel_con[32],
7005b7480cdSFinley Xiao 			     CLK_I2C0_SEL_MASK | CLK_I2C0_DIV_MASK,
7015b7480cdSFinley Xiao 			     (sel << CLK_I2C0_SEL_SHIFT) |
7025b7480cdSFinley Xiao 			     ((div - 1) << CLK_I2C0_DIV_SHIFT));
7035b7480cdSFinley Xiao 		break;
7045b7480cdSFinley Xiao 	case CLK_I2C1:
7055b7480cdSFinley Xiao 		rk_clrsetreg(&cru->clksel_con[32],
7065b7480cdSFinley Xiao 			     CLK_I2C1_SEL_MASK | CLK_I2C1_DIV_MASK,
7075b7480cdSFinley Xiao 			     (sel << CLK_I2C1_SEL_SHIFT) |
7085b7480cdSFinley Xiao 			     ((div - 1) << CLK_I2C1_DIV_SHIFT));
7095b7480cdSFinley Xiao 		break;
7105b7480cdSFinley Xiao 	case CLK_I2C2:
7115b7480cdSFinley Xiao 		rk_clrsetreg(&cru->clksel_con[33],
7125b7480cdSFinley Xiao 			     CLK_I2C2_SEL_MASK | CLK_I2C2_DIV_MASK,
7135b7480cdSFinley Xiao 			     (sel << CLK_I2C2_SEL_SHIFT) |
7145b7480cdSFinley Xiao 			     ((div - 1) << CLK_I2C2_DIV_SHIFT));
7155b7480cdSFinley Xiao 		break;
7165b7480cdSFinley Xiao 	default:
7175b7480cdSFinley Xiao 		return -ENOENT;
7185b7480cdSFinley Xiao 	}
7195b7480cdSFinley Xiao 
7205b7480cdSFinley Xiao 
7215b7480cdSFinley Xiao 	return rk3506_i2c_get_rate(priv, clk_id);
7225b7480cdSFinley Xiao }
7235b7480cdSFinley Xiao 
rk3506_pwm_get_rate(struct rk3506_clk_priv * priv,ulong clk_id)7245b7480cdSFinley Xiao static ulong rk3506_pwm_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
7255b7480cdSFinley Xiao {
7265b7480cdSFinley Xiao 	struct rk3506_cru *cru = priv->cru;
7275b7480cdSFinley Xiao 	u32 sel, con, div;
7285b7480cdSFinley Xiao 	ulong prate;
7295b7480cdSFinley Xiao 
7305b7480cdSFinley Xiao 	switch (clk_id) {
7315b7480cdSFinley Xiao 	case CLK_PWM0:
7325b7480cdSFinley Xiao 		con = readl(&cru->pmuclksel_con[0]);
7335b7480cdSFinley Xiao 		div = (con & CLK_PWM0_DIV_MASK) >> CLK_PWM0_DIV_SHIFT;
7345b7480cdSFinley Xiao 		prate = priv->gpll_div_100mhz;
7355b7480cdSFinley Xiao 		break;
7365b7480cdSFinley Xiao 	case CLK_PWM1:
7375b7480cdSFinley Xiao 		con = readl(&cru->clksel_con[33]);
7385b7480cdSFinley Xiao 		sel = (con & CLK_PWM1_SEL_MASK) >> CLK_PWM1_SEL_SHIFT;
7395b7480cdSFinley Xiao 		div = (con & CLK_PWM1_DIV_MASK) >> CLK_PWM1_DIV_SHIFT;
7405b7480cdSFinley Xiao 		if (sel == CLK_PWM1_SEL_GPLL_DIV)
7415b7480cdSFinley Xiao 			prate = priv->gpll_div_hz;
7425b7480cdSFinley Xiao 		else if (sel == CLK_PWM1_SEL_V0PLL_DIV)
7435b7480cdSFinley Xiao 			prate = priv->v0pll_div_hz;
7445b7480cdSFinley Xiao 		else if (sel == CLK_PWM1_SEL_V1PLL_DIV)
7455b7480cdSFinley Xiao 			prate = priv->v1pll_div_hz;
7465b7480cdSFinley Xiao 		else
7475b7480cdSFinley Xiao 			return -EINVAL;
7485b7480cdSFinley Xiao 		break;
7495b7480cdSFinley Xiao 	default:
7505b7480cdSFinley Xiao 		return -ENOENT;
7515b7480cdSFinley Xiao 	}
7525b7480cdSFinley Xiao 
7535b7480cdSFinley Xiao 	return DIV_TO_RATE(prate, div);
7545b7480cdSFinley Xiao }
7555b7480cdSFinley Xiao 
rk3506_pwm_set_rate(struct rk3506_clk_priv * priv,ulong clk_id,ulong rate)7565b7480cdSFinley Xiao static ulong rk3506_pwm_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
7575b7480cdSFinley Xiao 				 ulong rate)
7585b7480cdSFinley Xiao {
7595b7480cdSFinley Xiao 	struct rk3506_cru *cru = priv->cru;
7605b7480cdSFinley Xiao 	u32 sel, div;
7615b7480cdSFinley Xiao 
7625b7480cdSFinley Xiao 	switch (clk_id) {
7635b7480cdSFinley Xiao 	case CLK_PWM0:
7645b7480cdSFinley Xiao 		div = DIV_ROUND_UP(priv->gpll_div_100mhz, rate);
7655b7480cdSFinley Xiao 		assert(div - 1 <= 15);
7665b7480cdSFinley Xiao 		rk_clrsetreg(&cru->pmuclksel_con[0], CLK_PWM0_DIV_MASK,
7675b7480cdSFinley Xiao 			     (div - 1) << CLK_PWM0_DIV_SHIFT);
7685b7480cdSFinley Xiao 		break;
7695b7480cdSFinley Xiao 	case CLK_PWM1:
7705b7480cdSFinley Xiao 		if (priv->v0pll_hz % rate == 0) {
7715b7480cdSFinley Xiao 			sel = CLK_PWM1_SEL_V0PLL_DIV;
7725b7480cdSFinley Xiao 			div = DIV_ROUND_UP(priv->v0pll_div_hz, rate);
7735b7480cdSFinley Xiao 		} else if (priv->v1pll_hz % rate == 0) {
7745b7480cdSFinley Xiao 			sel = CLK_PWM1_SEL_V1PLL_DIV;
7755b7480cdSFinley Xiao 			div = DIV_ROUND_UP(priv->v1pll_div_hz, rate);
7765b7480cdSFinley Xiao 		} else {
7775b7480cdSFinley Xiao 			sel = CLK_PWM1_SEL_GPLL_DIV;
7785b7480cdSFinley Xiao 			div = DIV_ROUND_UP(priv->gpll_div_hz, rate);
7795b7480cdSFinley Xiao 		}
7805b7480cdSFinley Xiao 		assert(div - 1 <= 15);
7815b7480cdSFinley Xiao 		rk_clrsetreg(&cru->clksel_con[33],
7825b7480cdSFinley Xiao 			     CLK_PWM1_SEL_MASK | CLK_PWM1_DIV_MASK,
7835b7480cdSFinley Xiao 			     (sel << CLK_PWM1_SEL_SHIFT) |
7845b7480cdSFinley Xiao 			     ((div - 1) << CLK_PWM1_DIV_SHIFT));
7855b7480cdSFinley Xiao 		break;
7865b7480cdSFinley Xiao 	default:
7875b7480cdSFinley Xiao 		return -ENOENT;
7885b7480cdSFinley Xiao 	}
7895b7480cdSFinley Xiao 
7905b7480cdSFinley Xiao 	return rk3506_pwm_get_rate(priv, clk_id);
7915b7480cdSFinley Xiao }
7925b7480cdSFinley Xiao 
rk3506_spi_get_rate(struct rk3506_clk_priv * priv,ulong clk_id)7935b7480cdSFinley Xiao static ulong rk3506_spi_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
7945b7480cdSFinley Xiao {
7955b7480cdSFinley Xiao 	struct rk3506_cru *cru = priv->cru;
7965b7480cdSFinley Xiao 	u32 sel, con, div;
7975b7480cdSFinley Xiao 	ulong prate;
7985b7480cdSFinley Xiao 
7995b7480cdSFinley Xiao 	switch (clk_id) {
8005b7480cdSFinley Xiao 	case CLK_SPI0:
8015b7480cdSFinley Xiao 		con = readl(&cru->clksel_con[34]);
8025b7480cdSFinley Xiao 		sel = (con & CLK_SPI0_SEL_MASK) >> CLK_SPI0_SEL_SHIFT;
8035b7480cdSFinley Xiao 		div = (con & CLK_SPI0_DIV_MASK) >> CLK_SPI0_DIV_SHIFT;
8045b7480cdSFinley Xiao 		break;
8055b7480cdSFinley Xiao 	case CLK_SPI1:
8065b7480cdSFinley Xiao 		con = readl(&cru->clksel_con[34]);
8075b7480cdSFinley Xiao 		sel = (con & CLK_SPI1_SEL_MASK) >> CLK_SPI1_SEL_SHIFT;
8085b7480cdSFinley Xiao 		div = (con & CLK_SPI1_DIV_MASK) >> CLK_SPI1_DIV_SHIFT;
8095b7480cdSFinley Xiao 		break;
8105b7480cdSFinley Xiao 	default:
8115b7480cdSFinley Xiao 		return -ENOENT;
8125b7480cdSFinley Xiao 	}
8135b7480cdSFinley Xiao 
8145b7480cdSFinley Xiao 	if (sel == CLK_SPI_SEL_24M)
8155b7480cdSFinley Xiao 		prate = OSC_HZ;
8165b7480cdSFinley Xiao 	else if (sel == CLK_SPI_SEL_GPLL_DIV)
8175b7480cdSFinley Xiao 		prate = priv->gpll_div_hz;
8185b7480cdSFinley Xiao 	else if (sel == CLK_SPI_SEL_V0PLL_DIV)
8195b7480cdSFinley Xiao 		prate = priv->v0pll_div_hz;
8205b7480cdSFinley Xiao 	else if (sel == CLK_SPI_SEL_V1PLL_DIV)
8215b7480cdSFinley Xiao 		prate = priv->v1pll_div_hz;
8225b7480cdSFinley Xiao 	else
8235b7480cdSFinley Xiao 		return -EINVAL;
8245b7480cdSFinley Xiao 
8255b7480cdSFinley Xiao 	return DIV_TO_RATE(prate, div);
8265b7480cdSFinley Xiao }
8275b7480cdSFinley Xiao 
rk3506_spi_set_rate(struct rk3506_clk_priv * priv,ulong clk_id,ulong rate)8285b7480cdSFinley Xiao static ulong rk3506_spi_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
8295b7480cdSFinley Xiao 				 ulong rate)
8305b7480cdSFinley Xiao {
8315b7480cdSFinley Xiao 	struct rk3506_cru *cru = priv->cru;
8325b7480cdSFinley Xiao 	u32 sel, div;
8335b7480cdSFinley Xiao 
8345b7480cdSFinley Xiao 	if (OSC_HZ % rate == 0) {
8355b7480cdSFinley Xiao 		sel = CLK_SPI_SEL_24M;
8365b7480cdSFinley Xiao 		div = DIV_ROUND_UP(OSC_HZ, rate);
8375b7480cdSFinley Xiao 	} else if (priv->v0pll_div_hz % rate == 0) {
8385b7480cdSFinley Xiao 		sel = CLK_SPI_SEL_V0PLL_DIV;
8395b7480cdSFinley Xiao 		div = DIV_ROUND_UP(priv->v0pll_div_hz, rate);
8405b7480cdSFinley Xiao 	} else if (priv->v1pll_div_hz % rate == 0) {
8415b7480cdSFinley Xiao 		sel = CLK_SPI_SEL_V1PLL_DIV;
8425b7480cdSFinley Xiao 		div = DIV_ROUND_UP(priv->v1pll_div_hz, rate);
8435b7480cdSFinley Xiao 	} else {
8445b7480cdSFinley Xiao 		sel = CLK_SPI_SEL_GPLL_DIV;
8455b7480cdSFinley Xiao 		div = DIV_ROUND_UP(priv->gpll_div_hz, rate);
8465b7480cdSFinley Xiao 	}
8475b7480cdSFinley Xiao 	assert(div - 1 <= 15);
8485b7480cdSFinley Xiao 
8495b7480cdSFinley Xiao 	switch (clk_id) {
8505b7480cdSFinley Xiao 	case CLK_SPI0:
8515b7480cdSFinley Xiao 		rk_clrsetreg(&cru->clksel_con[34],
8525b7480cdSFinley Xiao 			     CLK_SPI0_SEL_MASK | CLK_SPI0_DIV_MASK,
8535b7480cdSFinley Xiao 			     (sel << CLK_SPI0_SEL_SHIFT) |
8545b7480cdSFinley Xiao 			     ((div - 1) << CLK_SPI0_DIV_SHIFT));
8555b7480cdSFinley Xiao 		break;
8565b7480cdSFinley Xiao 	case CLK_SPI1:
8575b7480cdSFinley Xiao 		rk_clrsetreg(&cru->clksel_con[34],
8585b7480cdSFinley Xiao 			     CLK_SPI1_SEL_MASK | CLK_SPI1_DIV_MASK,
8595b7480cdSFinley Xiao 			     (sel << CLK_SPI1_SEL_SHIFT) |
8605b7480cdSFinley Xiao 			     ((div - 1) << CLK_SPI1_DIV_SHIFT));
8615b7480cdSFinley Xiao 		break;
8625b7480cdSFinley Xiao 	default:
8635b7480cdSFinley Xiao 		return -ENOENT;
8645b7480cdSFinley Xiao 	}
8655b7480cdSFinley Xiao 
8665b7480cdSFinley Xiao 	return rk3506_spi_get_rate(priv, clk_id);
8675b7480cdSFinley Xiao }
8685b7480cdSFinley Xiao 
rk3506_fspi_get_rate(struct rk3506_clk_priv * priv)8695b7480cdSFinley Xiao static ulong rk3506_fspi_get_rate(struct rk3506_clk_priv *priv)
8705b7480cdSFinley Xiao {
8715b7480cdSFinley Xiao 	struct rk3506_cru *cru = priv->cru;
8725b7480cdSFinley Xiao 	u32 div, sel, con, prate;
8735b7480cdSFinley Xiao 
8745b7480cdSFinley Xiao 	con = readl(&cru->clksel_con[50]);
8755b7480cdSFinley Xiao 	div = (con & SCLK_FSPI_DIV_MASK) >> SCLK_FSPI_DIV_SHIFT;
8765b7480cdSFinley Xiao 	sel = (con & SCLK_FSPI_SEL_MASK) >> SCLK_FSPI_SEL_SHIFT;
8775b7480cdSFinley Xiao 	if (sel == SCLK_FSPI_SEL_24M)
8785b7480cdSFinley Xiao 		prate = OSC_HZ;
8795b7480cdSFinley Xiao 	else if (sel == SCLK_FSPI_SEL_GPLL)
8805b7480cdSFinley Xiao 		prate = priv->gpll_hz;
8815b7480cdSFinley Xiao 	else if (sel == SCLK_FSPI_SEL_V0PLL)
8825b7480cdSFinley Xiao 		prate = priv->v0pll_hz;
8835b7480cdSFinley Xiao 	else if (sel == SCLK_FSPI_SEL_V1PLL)
8845b7480cdSFinley Xiao 		prate = priv->v1pll_hz;
8855b7480cdSFinley Xiao 	else
8865b7480cdSFinley Xiao 		return -EINVAL;
8875b7480cdSFinley Xiao 
8885b7480cdSFinley Xiao 	return DIV_TO_RATE(prate, div);
8895b7480cdSFinley Xiao }
8905b7480cdSFinley Xiao 
rk3506_fspi_set_rate(struct rk3506_clk_priv * priv,ulong rate)8915b7480cdSFinley Xiao static ulong rk3506_fspi_set_rate(struct rk3506_clk_priv *priv, ulong rate)
8925b7480cdSFinley Xiao {
8935b7480cdSFinley Xiao 	struct rk3506_cru *cru = priv->cru;
8945b7480cdSFinley Xiao 	int div, sel;
8955b7480cdSFinley Xiao 
8965b7480cdSFinley Xiao 	if (OSC_HZ % rate == 0) {
8975b7480cdSFinley Xiao 		sel = SCLK_FSPI_SEL_24M;
8985b7480cdSFinley Xiao 		div = DIV_ROUND_UP(OSC_HZ, rate);
8995b7480cdSFinley Xiao 	} else if ((priv->v0pll_hz % rate) == 0) {
9005b7480cdSFinley Xiao 		sel = SCLK_FSPI_SEL_V0PLL;
9015b7480cdSFinley Xiao 		div = DIV_ROUND_UP(priv->v0pll_hz, rate);
9025b7480cdSFinley Xiao 	} else if ((priv->v1pll_hz % rate) == 0) {
9035b7480cdSFinley Xiao 		sel = SCLK_FSPI_SEL_V1PLL;
9045b7480cdSFinley Xiao 		div = DIV_ROUND_UP(priv->v1pll_hz, rate);
9055b7480cdSFinley Xiao 	} else {
9065b7480cdSFinley Xiao 		sel = SCLK_FSPI_SEL_GPLL;
9075b7480cdSFinley Xiao 		div = DIV_ROUND_UP(priv->gpll_hz, rate);
9085b7480cdSFinley Xiao 	}
9095b7480cdSFinley Xiao 	assert(div - 1 <= 31);
9105b7480cdSFinley Xiao 
9115b7480cdSFinley Xiao 	rk_clrsetreg(&cru->clksel_con[50],
9125b7480cdSFinley Xiao 		     SCLK_FSPI_SEL_MASK | SCLK_FSPI_DIV_MASK,
9135b7480cdSFinley Xiao 		     sel << SCLK_FSPI_SEL_SHIFT |
9145b7480cdSFinley Xiao 		     (div - 1) << SCLK_FSPI_DIV_SHIFT);
9155b7480cdSFinley Xiao 
9165b7480cdSFinley Xiao 	return rk3506_fspi_get_rate(priv);
9175b7480cdSFinley Xiao }
9185b7480cdSFinley Xiao 
rk3506_vop_dclk_get_rate(struct rk3506_clk_priv * priv)9195b7480cdSFinley Xiao static ulong rk3506_vop_dclk_get_rate(struct rk3506_clk_priv *priv)
9205b7480cdSFinley Xiao {
9215b7480cdSFinley Xiao 	struct rk3506_cru *cru = priv->cru;
9225b7480cdSFinley Xiao 	u32 div, sel, con, prate;
9235b7480cdSFinley Xiao 
9245b7480cdSFinley Xiao 	con = readl(&cru->clksel_con[60]);
9255b7480cdSFinley Xiao 	div = (con & DCLK_VOP_DIV_MASK) >> DCLK_VOP_DIV_SHIFT;
9265b7480cdSFinley Xiao 	sel = (con & DCLK_VOP_SEL_MASK) >> DCLK_VOP_SEL_SHIFT;
9275b7480cdSFinley Xiao 
9285b7480cdSFinley Xiao 	if (sel == DCLK_VOP_SEL_24M)
9295b7480cdSFinley Xiao 		prate = OSC_HZ;
9305b7480cdSFinley Xiao 	else if (sel == DCLK_VOP_SEL_GPLL)
9315b7480cdSFinley Xiao 		prate = priv->gpll_hz;
9325b7480cdSFinley Xiao 	else if (sel == DCLK_VOP_SEL_V0PLL)
9335b7480cdSFinley Xiao 		prate = priv->v0pll_hz;
9345b7480cdSFinley Xiao 	else if (sel == DCLK_VOP_SEL_V1PLL)
9355b7480cdSFinley Xiao 		prate = priv->v1pll_hz;
9365b7480cdSFinley Xiao 	else
9375b7480cdSFinley Xiao 		return -EINVAL;
9385b7480cdSFinley Xiao 
9395b7480cdSFinley Xiao 	return DIV_TO_RATE(prate, div);
9405b7480cdSFinley Xiao }
9415b7480cdSFinley Xiao 
rk3506_vop_dclk_set_rate(struct rk3506_clk_priv * priv,ulong rate)9425b7480cdSFinley Xiao static ulong rk3506_vop_dclk_set_rate(struct rk3506_clk_priv *priv, ulong rate)
9435b7480cdSFinley Xiao {
9445b7480cdSFinley Xiao 	struct rk3506_cru *cru = priv->cru;
9455b7480cdSFinley Xiao 	int div, sel;
9465b7480cdSFinley Xiao 
9475b7480cdSFinley Xiao 	if (OSC_HZ % rate == 0) {
9485b7480cdSFinley Xiao 		sel = DCLK_VOP_SEL_24M;
9495b7480cdSFinley Xiao 		div = DIV_ROUND_UP(OSC_HZ, rate);
9505b7480cdSFinley Xiao 	} else if ((priv->v0pll_hz % rate) == 0) {
9515b7480cdSFinley Xiao 		sel = DCLK_VOP_SEL_V0PLL;
9525b7480cdSFinley Xiao 		div = DIV_ROUND_UP(priv->v0pll_hz, rate);
9535b7480cdSFinley Xiao 	} else if ((priv->v1pll_hz % rate) == 0) {
9545b7480cdSFinley Xiao 		sel = DCLK_VOP_SEL_V1PLL;
9555b7480cdSFinley Xiao 		div = DIV_ROUND_UP(priv->v1pll_hz, rate);
9565b7480cdSFinley Xiao 	} else {
9575b7480cdSFinley Xiao 		sel = DCLK_VOP_SEL_GPLL;
9585b7480cdSFinley Xiao 		div = DIV_ROUND_UP(priv->gpll_hz, rate);
9595b7480cdSFinley Xiao 	}
9605b7480cdSFinley Xiao 	assert(div - 1 <= 255);
9615b7480cdSFinley Xiao 
9625b7480cdSFinley Xiao 	rk_clrsetreg(&cru->clksel_con[60],
9635b7480cdSFinley Xiao 		     DCLK_VOP_SEL_MASK | DCLK_VOP_DIV_MASK,
9645b7480cdSFinley Xiao 		     sel << DCLK_VOP_SEL_SHIFT |
9655b7480cdSFinley Xiao 		     (div - 1) << DCLK_VOP_DIV_SHIFT);
9665b7480cdSFinley Xiao 
9675b7480cdSFinley Xiao 	return rk3506_vop_dclk_get_rate(priv);
9685b7480cdSFinley Xiao }
9695b7480cdSFinley Xiao 
rk3506_mac_get_rate(struct rk3506_clk_priv * priv,ulong clk_id)970e434c7b0SFinley Xiao static ulong rk3506_mac_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
971e434c7b0SFinley Xiao {
972e434c7b0SFinley Xiao 	struct rk3506_cru *cru = priv->cru;
973e434c7b0SFinley Xiao 	u32 div, con;
974e434c7b0SFinley Xiao 
975e434c7b0SFinley Xiao 	switch (clk_id) {
976e434c7b0SFinley Xiao 	case CLK_MAC0:
977e434c7b0SFinley Xiao 	case CLK_MAC1:
978e434c7b0SFinley Xiao 		con = readl(&cru->clksel_con[50]);
979e434c7b0SFinley Xiao 		div = (con & CLK_MAC_DIV_MASK) >> CLK_MAC_DIV_SHIFT;
980e434c7b0SFinley Xiao 		break;
981e434c7b0SFinley Xiao 	case CLK_MAC_OUT:
982e434c7b0SFinley Xiao 		con = readl(&cru->pmuclksel_con[0]);
983e434c7b0SFinley Xiao 		div = (con & CLK_MAC_OUT_DIV_MASK) >> CLK_MAC_OUT_DIV_SHIFT;
984*826d54fbSFinley Xiao 		break;
985e434c7b0SFinley Xiao 	default:
986e434c7b0SFinley Xiao 		return -ENOENT;
987e434c7b0SFinley Xiao 	}
988e434c7b0SFinley Xiao 
989e434c7b0SFinley Xiao 	return DIV_TO_RATE(priv->gpll_hz, div);
990e434c7b0SFinley Xiao }
991e434c7b0SFinley Xiao 
rk3506_mac_set_rate(struct rk3506_clk_priv * priv,ulong clk_id,ulong rate)992e434c7b0SFinley Xiao static ulong rk3506_mac_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
993e434c7b0SFinley Xiao 				 ulong rate)
994e434c7b0SFinley Xiao {
995e434c7b0SFinley Xiao 	struct rk3506_cru *cru = priv->cru;
996e434c7b0SFinley Xiao 	u32 div;
997e434c7b0SFinley Xiao 
998e434c7b0SFinley Xiao 	switch (clk_id) {
999e434c7b0SFinley Xiao 	case CLK_MAC0:
1000e434c7b0SFinley Xiao 	case CLK_MAC1:
1001e434c7b0SFinley Xiao 		div = DIV_ROUND_UP(priv->gpll_hz, rate);
1002e434c7b0SFinley Xiao 		rk_clrsetreg(&cru->clksel_con[50], CLK_MAC_DIV_MASK,
1003e434c7b0SFinley Xiao 			     ((div - 1) << CLK_MAC_DIV_SHIFT));
1004e434c7b0SFinley Xiao 		break;
1005e434c7b0SFinley Xiao 	case CLK_MAC_OUT:
1006e434c7b0SFinley Xiao 		div = DIV_ROUND_UP(priv->gpll_hz, rate);
1007e434c7b0SFinley Xiao 		rk_clrsetreg(&cru->pmuclksel_con[0], CLK_MAC_OUT_DIV_MASK,
1008e434c7b0SFinley Xiao 			     ((div - 1) << CLK_MAC_OUT_DIV_SHIFT));
1009*826d54fbSFinley Xiao 		break;
1010e434c7b0SFinley Xiao 	default:
1011e434c7b0SFinley Xiao 		return -ENOENT;
1012e434c7b0SFinley Xiao 	}
1013e434c7b0SFinley Xiao 
1014e434c7b0SFinley Xiao 	return rk3506_mac_get_rate(priv, clk_id);
1015e434c7b0SFinley Xiao }
1016e434c7b0SFinley Xiao 
rk3506_clk_get_rate(struct clk * clk)10175b7480cdSFinley Xiao static ulong rk3506_clk_get_rate(struct clk *clk)
10185b7480cdSFinley Xiao {
10195b7480cdSFinley Xiao 	struct rk3506_clk_priv *priv = dev_get_priv(clk->dev);
10205b7480cdSFinley Xiao 	ulong rate = 0;
10215b7480cdSFinley Xiao 
10225b7480cdSFinley Xiao 	if (!priv->gpll_hz || !priv->v0pll_hz || !priv->v1pll_hz) {
10235b7480cdSFinley Xiao 		printf("%s: gpll=%lu, v0pll=%lu, v1pll=%lu\n",
10245b7480cdSFinley Xiao 		       __func__, priv->gpll_hz, priv->v0pll_hz, priv->v1pll_hz);
10255b7480cdSFinley Xiao 		return -ENOENT;
10265b7480cdSFinley Xiao 	}
10275b7480cdSFinley Xiao 
10285b7480cdSFinley Xiao 	switch (clk->id) {
10295b7480cdSFinley Xiao 	case PLL_GPLL:
10305b7480cdSFinley Xiao 		rate = priv->gpll_hz;
10315b7480cdSFinley Xiao 		break;
10325b7480cdSFinley Xiao 	case PLL_V0PLL:
10335b7480cdSFinley Xiao 		rate = priv->v0pll_hz;
10345b7480cdSFinley Xiao 		break;
10355b7480cdSFinley Xiao 	case PLL_V1PLL:
10365b7480cdSFinley Xiao 		rate = priv->v1pll_hz;
10375b7480cdSFinley Xiao 		break;
10385b7480cdSFinley Xiao 	case ARMCLK:
10395b7480cdSFinley Xiao 		rate = rk3506_armclk_get_rate(priv);
10405b7480cdSFinley Xiao 		break;
10415b7480cdSFinley Xiao 	case CLK_GPLL_DIV:
10425b7480cdSFinley Xiao 	case CLK_GPLL_DIV_100M:
10435b7480cdSFinley Xiao 	case CLK_V0PLL_DIV:
10445b7480cdSFinley Xiao 	case CLK_V1PLL_DIV:
10455b7480cdSFinley Xiao 		rate = rk3506_pll_div_get_rate(priv, clk->id);
10465b7480cdSFinley Xiao 		break;
10475b7480cdSFinley Xiao 	case ACLK_BUS_ROOT:
10485b7480cdSFinley Xiao 	case HCLK_BUS_ROOT:
10495b7480cdSFinley Xiao 	case PCLK_BUS_ROOT:
10505b7480cdSFinley Xiao 		rate = rk3506_bus_get_rate(priv, clk->id);
10515b7480cdSFinley Xiao 		break;
10525b7480cdSFinley Xiao 	case ACLK_HSPERI_ROOT:
10535b7480cdSFinley Xiao 	case HCLK_LSPERI_ROOT:
10545b7480cdSFinley Xiao 		rate = rk3506_peri_get_rate(priv, clk->id);
10555b7480cdSFinley Xiao 		break;
10565b7480cdSFinley Xiao 	case HCLK_SDMMC:
10575b7480cdSFinley Xiao 	case CCLK_SRC_SDMMC:
10585b7480cdSFinley Xiao 		rate = rk3506_sdmmc_get_rate(priv, clk->id);
10595b7480cdSFinley Xiao 		break;
10605b7480cdSFinley Xiao 	case CLK_SARADC:
10615b7480cdSFinley Xiao 		rate = rk3506_saradc_get_rate(priv, clk->id);
10625b7480cdSFinley Xiao 		break;
10635b7480cdSFinley Xiao 	case CLK_TSADC:
10645b7480cdSFinley Xiao 	case CLK_TSADC_TSEN:
10655b7480cdSFinley Xiao 		rate = rk3506_tsadc_get_rate(priv, clk->id);
10665b7480cdSFinley Xiao 		break;
10675b7480cdSFinley Xiao 	case CLK_I2C0:
10685b7480cdSFinley Xiao 	case CLK_I2C1:
10695b7480cdSFinley Xiao 	case CLK_I2C2:
10705b7480cdSFinley Xiao 		rate = rk3506_i2c_get_rate(priv, clk->id);
10715b7480cdSFinley Xiao 		break;
10725b7480cdSFinley Xiao 	case CLK_PWM0:
10735b7480cdSFinley Xiao 	case CLK_PWM1:
10745b7480cdSFinley Xiao 		rate = rk3506_pwm_get_rate(priv, clk->id);
10755b7480cdSFinley Xiao 		break;
10765b7480cdSFinley Xiao 	case CLK_SPI0:
10775b7480cdSFinley Xiao 	case CLK_SPI1:
10785b7480cdSFinley Xiao 		rate = rk3506_spi_get_rate(priv, clk->id);
10795b7480cdSFinley Xiao 		break;
10805b7480cdSFinley Xiao 	case SCLK_FSPI:
10815b7480cdSFinley Xiao 		rate = rk3506_fspi_get_rate(priv);
10825b7480cdSFinley Xiao 		break;
10835b7480cdSFinley Xiao 	case DCLK_VOP:
10845b7480cdSFinley Xiao 		rate = rk3506_vop_dclk_get_rate(priv);
10855b7480cdSFinley Xiao 		break;
1086e434c7b0SFinley Xiao 	case CLK_MAC0:
1087e434c7b0SFinley Xiao 	case CLK_MAC1:
1088e434c7b0SFinley Xiao 	case CLK_MAC_OUT:
1089e434c7b0SFinley Xiao 		rate = rk3506_mac_get_rate(priv, clk->id);
1090e434c7b0SFinley Xiao 		break;
10915b7480cdSFinley Xiao 	default:
10925b7480cdSFinley Xiao 		return -ENOENT;
10935b7480cdSFinley Xiao 	}
10945b7480cdSFinley Xiao 
10955b7480cdSFinley Xiao 	return rate;
10965b7480cdSFinley Xiao };
10975b7480cdSFinley Xiao 
rk3506_clk_set_rate(struct clk * clk,ulong rate)10985b7480cdSFinley Xiao static ulong rk3506_clk_set_rate(struct clk *clk, ulong rate)
10995b7480cdSFinley Xiao {
11005b7480cdSFinley Xiao 	struct rk3506_clk_priv *priv = dev_get_priv(clk->dev);
11015b7480cdSFinley Xiao 	ulong ret = 0;
11025b7480cdSFinley Xiao 
11035b7480cdSFinley Xiao 	if (!priv->gpll_hz || !priv->v0pll_hz || !priv->v1pll_hz) {
11045b7480cdSFinley Xiao 		printf("%s: gpll=%lu, v0pll=%lu, v1pll=%lu\n",
11055b7480cdSFinley Xiao 		       __func__, priv->gpll_hz, priv->v0pll_hz, priv->v1pll_hz);
11065b7480cdSFinley Xiao 		return -ENOENT;
11075b7480cdSFinley Xiao 	}
11085b7480cdSFinley Xiao 
11095b7480cdSFinley Xiao 	debug("%s: id=%ld, rate=%ld\n", __func__, clk->id, rate);
11105b7480cdSFinley Xiao 
11115b7480cdSFinley Xiao 	switch (clk->id) {
11125b7480cdSFinley Xiao 	case ARMCLK:
11135b7480cdSFinley Xiao 		if (priv->armclk_hz)
11145b7480cdSFinley Xiao 			rk3506_armclk_set_rate(priv, rate);
11155b7480cdSFinley Xiao 		priv->armclk_hz = rate;
11165b7480cdSFinley Xiao 		break;
11175b7480cdSFinley Xiao 	case CLK_GPLL_DIV:
11185b7480cdSFinley Xiao 	case CLK_GPLL_DIV_100M:
11195b7480cdSFinley Xiao 	case CLK_V0PLL_DIV:
11205b7480cdSFinley Xiao 	case CLK_V1PLL_DIV:
11215b7480cdSFinley Xiao 		ret = rk3506_pll_div_set_rate(priv, clk->id, rate);
11225b7480cdSFinley Xiao 		break;
11235b7480cdSFinley Xiao 	case ACLK_BUS_ROOT:
11245b7480cdSFinley Xiao 	case HCLK_BUS_ROOT:
11255b7480cdSFinley Xiao 	case PCLK_BUS_ROOT:
11265b7480cdSFinley Xiao 		ret = rk3506_bus_set_rate(priv, clk->id, rate);
11275b7480cdSFinley Xiao 		break;
11285b7480cdSFinley Xiao 	case ACLK_HSPERI_ROOT:
11295b7480cdSFinley Xiao 	case HCLK_LSPERI_ROOT:
11305b7480cdSFinley Xiao 		ret = rk3506_peri_set_rate(priv, clk->id, rate);
11315b7480cdSFinley Xiao 		break;
11325b7480cdSFinley Xiao 	case HCLK_SDMMC:
11335b7480cdSFinley Xiao 	case CCLK_SRC_SDMMC:
11345b7480cdSFinley Xiao 		ret = rk3506_sdmmc_set_rate(priv, clk->id, rate);
11355b7480cdSFinley Xiao 		break;
11365b7480cdSFinley Xiao 	case CLK_SARADC:
11375b7480cdSFinley Xiao 		ret = rk3506_saradc_set_rate(priv, clk->id, rate);
11385b7480cdSFinley Xiao 		break;
11395b7480cdSFinley Xiao 	case CLK_TSADC:
11405b7480cdSFinley Xiao 	case CLK_TSADC_TSEN:
11415b7480cdSFinley Xiao 		ret = rk3506_tsadc_set_rate(priv, clk->id, rate);
11425b7480cdSFinley Xiao 		break;
11435b7480cdSFinley Xiao 	case CLK_I2C0:
11445b7480cdSFinley Xiao 	case CLK_I2C1:
11455b7480cdSFinley Xiao 	case CLK_I2C2:
11465b7480cdSFinley Xiao 		ret = rk3506_i2c_set_rate(priv, clk->id, rate);
11475b7480cdSFinley Xiao 		break;
11485b7480cdSFinley Xiao 	case CLK_PWM0:
11495b7480cdSFinley Xiao 	case CLK_PWM1:
11505b7480cdSFinley Xiao 		ret = rk3506_pwm_set_rate(priv, clk->id, rate);
11515b7480cdSFinley Xiao 		break;
11525b7480cdSFinley Xiao 	case CLK_SPI0:
11535b7480cdSFinley Xiao 	case CLK_SPI1:
11545b7480cdSFinley Xiao 		ret = rk3506_spi_set_rate(priv, clk->id, rate);
11555b7480cdSFinley Xiao 		break;
11565b7480cdSFinley Xiao 	case HCLK_FSPI:
11575b7480cdSFinley Xiao 	case SCLK_FSPI:
11585b7480cdSFinley Xiao 		ret = rk3506_fspi_set_rate(priv, rate);
11595b7480cdSFinley Xiao 		break;
11605b7480cdSFinley Xiao 	case DCLK_VOP:
11615b7480cdSFinley Xiao 		ret = rk3506_vop_dclk_set_rate(priv, rate);
11625b7480cdSFinley Xiao 		break;
1163e434c7b0SFinley Xiao 	case CLK_MAC0:
1164e434c7b0SFinley Xiao 	case CLK_MAC1:
1165e434c7b0SFinley Xiao 	case CLK_MAC_OUT:
1166e434c7b0SFinley Xiao 		ret = rk3506_mac_set_rate(priv, clk->id, rate);
1167e434c7b0SFinley Xiao 		break;
11685b7480cdSFinley Xiao 	default:
11695b7480cdSFinley Xiao 		return -ENOENT;
11705b7480cdSFinley Xiao 	}
11715b7480cdSFinley Xiao 
11725b7480cdSFinley Xiao 	return ret;
11735b7480cdSFinley Xiao };
11745b7480cdSFinley Xiao 
11755b7480cdSFinley Xiao static struct clk_ops rk3506_clk_ops = {
11765b7480cdSFinley Xiao 	.get_rate = rk3506_clk_get_rate,
11775b7480cdSFinley Xiao 	.set_rate = rk3506_clk_set_rate,
11785b7480cdSFinley Xiao };
11795b7480cdSFinley Xiao 
rk3506_clk_init(struct rk3506_clk_priv * priv)11805b7480cdSFinley Xiao static void rk3506_clk_init(struct rk3506_clk_priv *priv)
11815b7480cdSFinley Xiao {
11825b7480cdSFinley Xiao 	priv->sync_kernel = false;
11835b7480cdSFinley Xiao 
11845b7480cdSFinley Xiao 	if (!priv->gpll_hz) {
11855b7480cdSFinley Xiao 		priv->gpll_hz = rockchip_pll_get_rate(&rk3506_pll_clks[GPLL],
11865b7480cdSFinley Xiao 						      priv->cru, GPLL);
11875b7480cdSFinley Xiao 		priv->gpll_hz = roundup(priv->gpll_hz, 1000);
11885b7480cdSFinley Xiao 	}
11895b7480cdSFinley Xiao 	if (!priv->v0pll_hz) {
11905b7480cdSFinley Xiao 		priv->v0pll_hz = rockchip_pll_get_rate(&rk3506_pll_clks[V0PLL],
11915b7480cdSFinley Xiao 						       priv->cru, V0PLL);
11925b7480cdSFinley Xiao 		priv->v0pll_hz = roundup(priv->v0pll_hz, 1000);
11935b7480cdSFinley Xiao 	}
11945b7480cdSFinley Xiao 	if (!priv->v1pll_hz) {
11955b7480cdSFinley Xiao 		priv->v1pll_hz = rockchip_pll_get_rate(&rk3506_pll_clks[V1PLL],
11965b7480cdSFinley Xiao 						       priv->cru, V1PLL);
11975b7480cdSFinley Xiao 		priv->v1pll_hz = roundup(priv->v1pll_hz, 1000);
11985b7480cdSFinley Xiao 	}
11995b7480cdSFinley Xiao 	if (!priv->gpll_div_hz) {
12005b7480cdSFinley Xiao 		priv->gpll_div_hz = rk3506_pll_div_get_rate(priv, CLK_GPLL_DIV);
12015b7480cdSFinley Xiao 		priv->gpll_div_hz = roundup(priv->gpll_div_hz, 1000);
12025b7480cdSFinley Xiao 	}
12035b7480cdSFinley Xiao 	if (!priv->gpll_div_100mhz) {
12045b7480cdSFinley Xiao 		priv->gpll_div_100mhz = rk3506_pll_div_get_rate(priv, CLK_GPLL_DIV_100M);
12055b7480cdSFinley Xiao 		priv->gpll_div_100mhz = roundup(priv->gpll_div_100mhz, 1000);
12065b7480cdSFinley Xiao 	}
12075b7480cdSFinley Xiao 	if (!priv->v0pll_div_hz) {
12085b7480cdSFinley Xiao 		priv->v0pll_div_hz = rk3506_pll_div_get_rate(priv, CLK_V0PLL_DIV);
12095b7480cdSFinley Xiao 		priv->v0pll_div_hz = roundup(priv->v0pll_div_hz, 1000);
12105b7480cdSFinley Xiao 	}
12115b7480cdSFinley Xiao 	if (!priv->v1pll_div_hz) {
12125b7480cdSFinley Xiao 		priv->v1pll_div_hz = rk3506_pll_div_get_rate(priv, CLK_V1PLL_DIV);
12135b7480cdSFinley Xiao 		priv->v1pll_div_hz = roundup(priv->v1pll_div_hz, 1000);
12145b7480cdSFinley Xiao 	}
12155b7480cdSFinley Xiao 
12165de46d87SFinley Xiao 	if (!priv->armclk_enter_hz) {
12175b7480cdSFinley Xiao 		priv->armclk_enter_hz = rk3506_armclk_get_rate(priv);
12185de46d87SFinley Xiao 		priv->armclk_init_hz = priv->armclk_enter_hz;
12195b7480cdSFinley Xiao 	}
12205b7480cdSFinley Xiao }
12215b7480cdSFinley Xiao 
rk3506_clk_probe(struct udevice * dev)12225b7480cdSFinley Xiao static int rk3506_clk_probe(struct udevice *dev)
12235b7480cdSFinley Xiao {
12245b7480cdSFinley Xiao 	struct rk3506_clk_priv *priv = dev_get_priv(dev);
12255b7480cdSFinley Xiao 	int ret;
12265b7480cdSFinley Xiao 
12272ecab49fSFinley Xiao #ifdef CONFIG_SPL_BUILD
12282ecab49fSFinley Xiao 	/* Init pka crypto rate, sel=v0pll, div=3 */
12292ecab49fSFinley Xiao 	writel(0x3f801180, RK3506_SCRU_BASE + 0x0010);
1230f8d37df5SFinley Xiao 	/* Change clk core src rate, sel=gpll, div=3 */
1231f8d37df5SFinley Xiao 	writel(0x007f0003, RK3506_CRU_BASE + 0x033c);
12322ecab49fSFinley Xiao #endif
12335b7480cdSFinley Xiao 	rk3506_clk_init(priv);
12345b7480cdSFinley Xiao 
12355b7480cdSFinley Xiao 	/* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */
12365b7480cdSFinley Xiao 	ret = clk_set_defaults(dev);
12375b7480cdSFinley Xiao 	if (ret)
12385b7480cdSFinley Xiao 		debug("%s clk_set_defaults failed %d\n", __func__, ret);
12395b7480cdSFinley Xiao 	else
12405b7480cdSFinley Xiao 		priv->sync_kernel = true;
12415b7480cdSFinley Xiao 
12425b7480cdSFinley Xiao 	return 0;
12435b7480cdSFinley Xiao }
12445b7480cdSFinley Xiao 
rk3506_clk_ofdata_to_platdata(struct udevice * dev)12455b7480cdSFinley Xiao static int rk3506_clk_ofdata_to_platdata(struct udevice *dev)
12465b7480cdSFinley Xiao {
12475b7480cdSFinley Xiao 	struct rk3506_clk_priv *priv = dev_get_priv(dev);
12485b7480cdSFinley Xiao 
12495b7480cdSFinley Xiao 	priv->cru = dev_read_addr_ptr(dev);
12505b7480cdSFinley Xiao 
12515b7480cdSFinley Xiao 	return 0;
12525b7480cdSFinley Xiao }
12535b7480cdSFinley Xiao 
rk3506_clk_bind(struct udevice * dev)12545b7480cdSFinley Xiao static int rk3506_clk_bind(struct udevice *dev)
12555b7480cdSFinley Xiao {
12565b7480cdSFinley Xiao 	struct udevice *sys_child, *sf_child;
12575b7480cdSFinley Xiao 	struct softreset_reg *sf_priv;
12585b7480cdSFinley Xiao 	struct sysreset_reg *priv;
12595b7480cdSFinley Xiao 	int ret;
12605b7480cdSFinley Xiao 
12615b7480cdSFinley Xiao 	/* The reset driver does not have a device node, so bind it here */
12625b7480cdSFinley Xiao 	ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
12635b7480cdSFinley Xiao 				 &sys_child);
12645b7480cdSFinley Xiao 	if (ret) {
12655b7480cdSFinley Xiao 		debug("Warning: No sysreset driver: ret=%d\n", ret);
12665b7480cdSFinley Xiao 	} else {
12675b7480cdSFinley Xiao 		priv = malloc(sizeof(struct sysreset_reg));
12685b7480cdSFinley Xiao 		priv->glb_srst_fst_value = offsetof(struct rk3506_cru,
12695b7480cdSFinley Xiao 						    glb_srst_fst);
12705b7480cdSFinley Xiao 		priv->glb_srst_snd_value = offsetof(struct rk3506_cru,
12715b7480cdSFinley Xiao 						    glb_srst_snd);
12725b7480cdSFinley Xiao 		sys_child->priv = priv;
12735b7480cdSFinley Xiao 	}
12745b7480cdSFinley Xiao 
12755b7480cdSFinley Xiao 	ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset",
12765b7480cdSFinley Xiao 					 dev_ofnode(dev), &sf_child);
12775b7480cdSFinley Xiao 	if (ret) {
12785b7480cdSFinley Xiao 		debug("Warning: No rockchip reset driver: ret=%d\n", ret);
12795b7480cdSFinley Xiao 	} else {
12805b7480cdSFinley Xiao 		sf_priv = malloc(sizeof(struct softreset_reg));
12815b7480cdSFinley Xiao 		sf_priv->sf_reset_offset = offsetof(struct rk3506_cru,
12825b7480cdSFinley Xiao 						    softrst_con[0]);
12835b7480cdSFinley Xiao 		sf_priv->sf_reset_num = 23;
12845b7480cdSFinley Xiao 		sf_child->priv = sf_priv;
12855b7480cdSFinley Xiao 	}
12865b7480cdSFinley Xiao 
12875b7480cdSFinley Xiao 	return 0;
12885b7480cdSFinley Xiao }
12895b7480cdSFinley Xiao 
12905b7480cdSFinley Xiao static const struct udevice_id rk3506_clk_ids[] = {
12915b7480cdSFinley Xiao 	{ .compatible = "rockchip,rk3506-cru" },
12925b7480cdSFinley Xiao 	{ }
12935b7480cdSFinley Xiao };
12945b7480cdSFinley Xiao 
12955b7480cdSFinley Xiao U_BOOT_DRIVER(rockchip_rk3506_cru) = {
12965b7480cdSFinley Xiao 	.name		= "rockchip_rk3506_cru",
12975b7480cdSFinley Xiao 	.id		= UCLASS_CLK,
12985b7480cdSFinley Xiao 	.of_match	= rk3506_clk_ids,
12995b7480cdSFinley Xiao 	.priv_auto_alloc_size = sizeof(struct rk3506_clk_priv),
13005b7480cdSFinley Xiao 	.ofdata_to_platdata = rk3506_clk_ofdata_to_platdata,
13015b7480cdSFinley Xiao 	.ops		= &rk3506_clk_ops,
13025b7480cdSFinley Xiao 	.bind		= rk3506_clk_bind,
13035b7480cdSFinley Xiao 	.probe		= rk3506_clk_probe,
13045b7480cdSFinley Xiao };
1305