141793000SKever Yang /*
241793000SKever Yang * (C) Copyright 2017 Rockchip Electronics Co., Ltd
341793000SKever Yang *
441793000SKever Yang * SPDX-License-Identifier: GPL-2.0
541793000SKever Yang */
641793000SKever Yang
741793000SKever Yang #include <common.h>
8ae74d3d5SDavid Wu #include <bitfield.h>
941793000SKever Yang #include <clk-uclass.h>
1041793000SKever Yang #include <dm.h>
1141793000SKever Yang #include <errno.h>
1241793000SKever Yang #include <syscon.h>
1341793000SKever Yang #include <asm/arch/clock.h>
1441793000SKever Yang #include <asm/arch/cru_rk3328.h>
1541793000SKever Yang #include <asm/arch/hardware.h>
1607a48b3eSDavid Wu #include <asm/arch/grf_rk3328.h>
1741793000SKever Yang #include <asm/io.h>
1841793000SKever Yang #include <dm/lists.h>
1941793000SKever Yang #include <dt-bindings/clock/rk3328-cru.h>
2041793000SKever Yang
2141793000SKever Yang DECLARE_GLOBAL_DATA_PTR;
2241793000SKever Yang
2341793000SKever Yang #define RATE_TO_DIV(input_rate, output_rate) \
2441793000SKever Yang ((input_rate) / (output_rate) - 1);
2541793000SKever Yang #define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1))
2641793000SKever Yang
270b7db90fSElaine Zhang #ifndef CONFIG_SPL_BUILD
280b7db90fSElaine Zhang #define RK3328_CLK_DUMP(_id, _name, _iscru) \
290b7db90fSElaine Zhang { \
300b7db90fSElaine Zhang .id = _id, \
310b7db90fSElaine Zhang .name = _name, \
320b7db90fSElaine Zhang .is_cru = _iscru, \
330b7db90fSElaine Zhang }
340b7db90fSElaine Zhang #endif
3541793000SKever Yang
360b7db90fSElaine Zhang static struct rockchip_pll_rate_table rk3328_pll_rates[] = {
370b7db90fSElaine Zhang /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
380b7db90fSElaine Zhang RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0),
390b7db90fSElaine Zhang #ifndef CONFIG_SPL_BUILD
408e2239d5SElaine Zhang RK3036_PLL_RATE(1188000000, 1, 99, 2, 1, 1, 0),
410b7db90fSElaine Zhang RK3036_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0),
420b7db90fSElaine Zhang #endif
430b7db90fSElaine Zhang RK3036_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0),
448e2239d5SElaine Zhang RK3036_PLL_RATE(800000000, 1, 200, 6, 1, 1, 0),
450b7db90fSElaine Zhang RK3036_PLL_RATE(600000000, 1, 75, 3, 1, 1, 0),
460b7db90fSElaine Zhang #ifndef CONFIG_SPL_BUILD
478e2239d5SElaine Zhang RK3036_PLL_RATE(594000000, 1, 99, 4, 1, 1, 0),
488e2239d5SElaine Zhang RK3036_PLL_RATE(500000000, 1, 125, 6, 1, 1, 0),
490b7db90fSElaine Zhang #endif
500b7db90fSElaine Zhang { /* sentinel */ },
5141793000SKever Yang };
5241793000SKever Yang
530b7db90fSElaine Zhang static struct rockchip_pll_rate_table rk3328_pll_frac_rates[] = {
540b7db90fSElaine Zhang /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
550b7db90fSElaine Zhang #ifndef CONFIG_SPL_BUILD
560b7db90fSElaine Zhang RK3036_PLL_RATE(1016064000, 3, 127, 1, 1, 0, 134217),
570b7db90fSElaine Zhang /* vco = 1016064000 */
580b7db90fSElaine Zhang RK3036_PLL_RATE(983040000, 24, 983, 1, 1, 0, 671088),
590b7db90fSElaine Zhang /* vco = 983040000 */
600b7db90fSElaine Zhang #endif
610b7db90fSElaine Zhang RK3036_PLL_RATE(491520000, 24, 983, 2, 1, 0, 671088),
620b7db90fSElaine Zhang /* vco = 983040000 */
630b7db90fSElaine Zhang #ifndef CONFIG_SPL_BUILD
640b7db90fSElaine Zhang RK3036_PLL_RATE(61440000, 6, 215, 7, 2, 0, 671088),
650b7db90fSElaine Zhang /* vco = 860156000 */
660b7db90fSElaine Zhang RK3036_PLL_RATE(56448000, 12, 451, 4, 4, 0, 9797894),
670b7db90fSElaine Zhang /* vco = 903168000 */
680b7db90fSElaine Zhang RK3036_PLL_RATE(40960000, 12, 409, 4, 5, 0, 10066329),
690b7db90fSElaine Zhang /* vco = 819200000 */
700b7db90fSElaine Zhang #endif
710b7db90fSElaine Zhang { /* sentinel */ },
7241793000SKever Yang };
7341793000SKever Yang
740b7db90fSElaine Zhang #define RK3328_CPUCLK_RATE(_rate, _aclk_div, _pclk_div) \
750b7db90fSElaine Zhang { \
760b7db90fSElaine Zhang .rate = _rate##U, \
770b7db90fSElaine Zhang .aclk_div = _aclk_div, \
780b7db90fSElaine Zhang .pclk_div = _pclk_div, \
7941793000SKever Yang }
8041793000SKever Yang
810b7db90fSElaine Zhang static struct rockchip_cpu_rate_table rk3328_cpu_rates[] = {
820b7db90fSElaine Zhang RK3328_CPUCLK_RATE(1200000000, 1, 5),
830b7db90fSElaine Zhang RK3328_CPUCLK_RATE(1008000000, 1, 5),
840b7db90fSElaine Zhang RK3328_CPUCLK_RATE(816000000, 1, 3),
850b7db90fSElaine Zhang RK3328_CPUCLK_RATE(600000000, 1, 3),
860b7db90fSElaine Zhang };
870b7db90fSElaine Zhang
880b7db90fSElaine Zhang #ifndef CONFIG_SPL_BUILD
890b7db90fSElaine Zhang static const struct rk3328_clk_info clks_dump[] = {
900b7db90fSElaine Zhang RK3328_CLK_DUMP(PLL_APLL, "apll", true),
910b7db90fSElaine Zhang RK3328_CLK_DUMP(PLL_DPLL, "dpll", true),
920b7db90fSElaine Zhang RK3328_CLK_DUMP(PLL_CPLL, "cpll", true),
930b7db90fSElaine Zhang RK3328_CLK_DUMP(PLL_GPLL, "gpll", true),
940b7db90fSElaine Zhang RK3328_CLK_DUMP(PLL_NPLL, "npll", true),
950b7db90fSElaine Zhang RK3328_CLK_DUMP(ARMCLK, "armclk", true),
960b7db90fSElaine Zhang RK3328_CLK_DUMP(ACLK_BUS_PRE, "aclk_bus", true),
970b7db90fSElaine Zhang RK3328_CLK_DUMP(HCLK_BUS_PRE, "hclk_bus", true),
980b7db90fSElaine Zhang RK3328_CLK_DUMP(PCLK_BUS_PRE, "pclk_bus", true),
990b7db90fSElaine Zhang RK3328_CLK_DUMP(ACLK_PERI_PRE, "aclk_peri", true),
1000b7db90fSElaine Zhang RK3328_CLK_DUMP(HCLK_PERI, "hclk_peri", true),
1010b7db90fSElaine Zhang RK3328_CLK_DUMP(PCLK_PERI, "pclk_peri", true),
1020b7db90fSElaine Zhang };
1030b7db90fSElaine Zhang #endif
1040b7db90fSElaine Zhang
1050b7db90fSElaine Zhang static struct rockchip_pll_clock rk3328_pll_clks[] = {
1060b7db90fSElaine Zhang [APLL] = PLL(pll_rk3328, PLL_APLL, RK3328_PLL_CON(0),
1070b7db90fSElaine Zhang RK3328_MODE_CON, 0, 10, 0, rk3328_pll_frac_rates),
1080b7db90fSElaine Zhang [DPLL] = PLL(pll_rk3328, PLL_DPLL, RK3328_PLL_CON(8),
1090b7db90fSElaine Zhang RK3328_MODE_CON, 4, 10, 0, NULL),
1100b7db90fSElaine Zhang [CPLL] = PLL(pll_rk3328, PLL_CPLL, RK3328_PLL_CON(16),
1110b7db90fSElaine Zhang RK3328_MODE_CON, 8, 10, 0, rk3328_pll_rates),
1120b7db90fSElaine Zhang [GPLL] = PLL(pll_rk3328, PLL_GPLL, RK3328_PLL_CON(24),
1130b7db90fSElaine Zhang RK3328_MODE_CON, 12, 10, 0, rk3328_pll_frac_rates),
1140b7db90fSElaine Zhang [NPLL] = PLL(pll_rk3328, PLL_NPLL, RK3328_PLL_CON(40),
1150b7db90fSElaine Zhang RK3328_MODE_CON, 1, 10, 0, rk3328_pll_rates),
1160b7db90fSElaine Zhang };
1170b7db90fSElaine Zhang
rk3328_armclk_set_clk(struct rk3328_clk_priv * priv,ulong hz)1180b7db90fSElaine Zhang static ulong rk3328_armclk_set_clk(struct rk3328_clk_priv *priv, ulong hz)
11941793000SKever Yang {
1200b7db90fSElaine Zhang struct rk3328_cru *cru = priv->cru;
1210b7db90fSElaine Zhang const struct rockchip_cpu_rate_table *rate;
1220b7db90fSElaine Zhang ulong old_rate;
12341793000SKever Yang
1240b7db90fSElaine Zhang rate = rockchip_get_cpu_settings(rk3328_cpu_rates, hz);
1250b7db90fSElaine Zhang if (!rate) {
1268e2239d5SElaine Zhang printf("%s unsupported rate\n", __func__);
1270b7db90fSElaine Zhang return -EINVAL;
12841793000SKever Yang }
12941793000SKever Yang
1300b7db90fSElaine Zhang /*
1310b7db90fSElaine Zhang * select apll as cpu/core clock pll source and
1320b7db90fSElaine Zhang * set up dependent divisors for PERI and ACLK clocks.
1330b7db90fSElaine Zhang * core hz : apll = 1:1
1340b7db90fSElaine Zhang */
1350b7db90fSElaine Zhang old_rate = rockchip_pll_get_rate(&rk3328_pll_clks[NPLL],
1360b7db90fSElaine Zhang priv->cru, NPLL);
1370b7db90fSElaine Zhang if (old_rate > hz) {
1380b7db90fSElaine Zhang if (rockchip_pll_set_rate(&rk3328_pll_clks[NPLL],
1390b7db90fSElaine Zhang priv->cru, NPLL, hz))
1400b7db90fSElaine Zhang return -EINVAL;
14141793000SKever Yang rk_clrsetreg(&cru->clksel_con[0],
1420b7db90fSElaine Zhang CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK,
1430b7db90fSElaine Zhang CORE_CLK_PLL_SEL_NPLL << CORE_CLK_PLL_SEL_SHIFT |
1440b7db90fSElaine Zhang 0 << CORE_DIV_CON_SHIFT);
14541793000SKever Yang rk_clrsetreg(&cru->clksel_con[1],
1460b7db90fSElaine Zhang CORE_ACLK_DIV_MASK | CORE_DBG_DIV_MASK,
1470b7db90fSElaine Zhang rate->aclk_div << CORE_ACLK_DIV_SHIFT |
1480b7db90fSElaine Zhang rate->pclk_div << CORE_DBG_DIV_SHIFT);
1490b7db90fSElaine Zhang } else if (old_rate < hz) {
1500b7db90fSElaine Zhang rk_clrsetreg(&cru->clksel_con[1],
1510b7db90fSElaine Zhang CORE_ACLK_DIV_MASK | CORE_DBG_DIV_MASK,
1520b7db90fSElaine Zhang rate->aclk_div << CORE_ACLK_DIV_SHIFT |
1530b7db90fSElaine Zhang rate->pclk_div << CORE_DBG_DIV_SHIFT);
1540b7db90fSElaine Zhang rk_clrsetreg(&cru->clksel_con[0],
1550b7db90fSElaine Zhang CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK,
1560b7db90fSElaine Zhang CORE_CLK_PLL_SEL_NPLL << CORE_CLK_PLL_SEL_SHIFT |
1570b7db90fSElaine Zhang 0 << CORE_DIV_CON_SHIFT);
1580b7db90fSElaine Zhang if (rockchip_pll_set_rate(&rk3328_pll_clks[NPLL],
1590b7db90fSElaine Zhang priv->cru, NPLL, hz))
1600b7db90fSElaine Zhang return -EINVAL;
16141793000SKever Yang }
16241793000SKever Yang
1630b7db90fSElaine Zhang return rockchip_pll_get_rate(&rk3328_pll_clks[NPLL], priv->cru, NPLL);
1640b7db90fSElaine Zhang }
16541793000SKever Yang
1660b7db90fSElaine Zhang #ifndef CONFIG_SPL_BUILD
rk3328_i2c_get_clk(struct rk3328_clk_priv * priv,ulong clk_id)1670b7db90fSElaine Zhang static ulong rk3328_i2c_get_clk(struct rk3328_clk_priv *priv, ulong clk_id)
16841793000SKever Yang {
1690b7db90fSElaine Zhang struct rk3328_cru *cru = priv->cru;
17041793000SKever Yang u32 div, con;
17141793000SKever Yang
17241793000SKever Yang switch (clk_id) {
17341793000SKever Yang case SCLK_I2C0:
17441793000SKever Yang con = readl(&cru->clksel_con[34]);
17541793000SKever Yang div = con >> CLK_I2C0_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK;
17641793000SKever Yang break;
17741793000SKever Yang case SCLK_I2C1:
17841793000SKever Yang con = readl(&cru->clksel_con[34]);
17941793000SKever Yang div = con >> CLK_I2C1_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK;
18041793000SKever Yang break;
18141793000SKever Yang case SCLK_I2C2:
18241793000SKever Yang con = readl(&cru->clksel_con[35]);
18341793000SKever Yang div = con >> CLK_I2C2_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK;
18441793000SKever Yang break;
18541793000SKever Yang case SCLK_I2C3:
18641793000SKever Yang con = readl(&cru->clksel_con[35]);
18741793000SKever Yang div = con >> CLK_I2C3_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK;
18841793000SKever Yang break;
18941793000SKever Yang default:
19041793000SKever Yang printf("do not support this i2c bus\n");
19141793000SKever Yang return -EINVAL;
19241793000SKever Yang }
19341793000SKever Yang
1940b7db90fSElaine Zhang return DIV_TO_RATE(priv->gpll_hz, div);
19541793000SKever Yang }
19641793000SKever Yang
rk3328_i2c_set_clk(struct rk3328_clk_priv * priv,ulong clk_id,uint hz)1970b7db90fSElaine Zhang static ulong rk3328_i2c_set_clk(struct rk3328_clk_priv *priv,
1980b7db90fSElaine Zhang ulong clk_id, uint hz)
19941793000SKever Yang {
2000b7db90fSElaine Zhang struct rk3328_cru *cru = priv->cru;
20141793000SKever Yang int src_clk_div;
20241793000SKever Yang
2030b7db90fSElaine Zhang src_clk_div = priv->gpll_hz / hz;
20441793000SKever Yang assert(src_clk_div - 1 < 127);
20541793000SKever Yang
20641793000SKever Yang switch (clk_id) {
20741793000SKever Yang case SCLK_I2C0:
20841793000SKever Yang rk_clrsetreg(&cru->clksel_con[34],
20941793000SKever Yang CLK_I2C_DIV_CON_MASK << CLK_I2C0_DIV_CON_SHIFT |
21041793000SKever Yang CLK_I2C_PLL_SEL_MASK << CLK_I2C0_PLL_SEL_SHIFT,
21141793000SKever Yang (src_clk_div - 1) << CLK_I2C0_DIV_CON_SHIFT |
21241793000SKever Yang CLK_I2C_PLL_SEL_GPLL << CLK_I2C0_PLL_SEL_SHIFT);
21341793000SKever Yang break;
21441793000SKever Yang case SCLK_I2C1:
21541793000SKever Yang rk_clrsetreg(&cru->clksel_con[34],
21641793000SKever Yang CLK_I2C_DIV_CON_MASK << CLK_I2C1_DIV_CON_SHIFT |
21741793000SKever Yang CLK_I2C_PLL_SEL_MASK << CLK_I2C1_PLL_SEL_SHIFT,
21841793000SKever Yang (src_clk_div - 1) << CLK_I2C1_DIV_CON_SHIFT |
21941793000SKever Yang CLK_I2C_PLL_SEL_GPLL << CLK_I2C1_PLL_SEL_SHIFT);
22041793000SKever Yang break;
22141793000SKever Yang case SCLK_I2C2:
22241793000SKever Yang rk_clrsetreg(&cru->clksel_con[35],
22341793000SKever Yang CLK_I2C_DIV_CON_MASK << CLK_I2C2_DIV_CON_SHIFT |
22441793000SKever Yang CLK_I2C_PLL_SEL_MASK << CLK_I2C2_PLL_SEL_SHIFT,
22541793000SKever Yang (src_clk_div - 1) << CLK_I2C2_DIV_CON_SHIFT |
22641793000SKever Yang CLK_I2C_PLL_SEL_GPLL << CLK_I2C2_PLL_SEL_SHIFT);
22741793000SKever Yang break;
22841793000SKever Yang case SCLK_I2C3:
22941793000SKever Yang rk_clrsetreg(&cru->clksel_con[35],
23041793000SKever Yang CLK_I2C_DIV_CON_MASK << CLK_I2C3_DIV_CON_SHIFT |
23141793000SKever Yang CLK_I2C_PLL_SEL_MASK << CLK_I2C3_PLL_SEL_SHIFT,
23241793000SKever Yang (src_clk_div - 1) << CLK_I2C3_DIV_CON_SHIFT |
23341793000SKever Yang CLK_I2C_PLL_SEL_GPLL << CLK_I2C3_PLL_SEL_SHIFT);
23441793000SKever Yang break;
23541793000SKever Yang default:
23641793000SKever Yang printf("do not support this i2c bus\n");
23741793000SKever Yang return -EINVAL;
23841793000SKever Yang }
23941793000SKever Yang
2400b7db90fSElaine Zhang return DIV_TO_RATE(priv->gpll_hz, src_clk_div);
24141793000SKever Yang }
24241793000SKever Yang
rk3328_gmac2io_set_clk(struct rk3328_clk_priv * priv,ulong rate)2430b7db90fSElaine Zhang static ulong rk3328_gmac2io_set_clk(struct rk3328_clk_priv *priv, ulong rate)
24407a48b3eSDavid Wu {
2450b7db90fSElaine Zhang struct rk3328_cru *cru = priv->cru;
24607a48b3eSDavid Wu struct rk3328_grf_regs *grf;
24707a48b3eSDavid Wu ulong ret;
24807a48b3eSDavid Wu
24907a48b3eSDavid Wu grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
25007a48b3eSDavid Wu
25107a48b3eSDavid Wu /*
25207a48b3eSDavid Wu * The RGMII CLK can be derived either from an external "clkin"
25307a48b3eSDavid Wu * or can be generated from internally by a divider from SCLK_MAC.
25407a48b3eSDavid Wu */
25507a48b3eSDavid Wu if (readl(&grf->mac_con[1]) & BIT(10) &&
25607a48b3eSDavid Wu readl(&grf->soc_con[4]) & BIT(14)) {
25707a48b3eSDavid Wu /* An external clock will always generate the right rate... */
25807a48b3eSDavid Wu ret = rate;
25907a48b3eSDavid Wu } else {
26007a48b3eSDavid Wu u32 con = readl(&cru->clksel_con[27]);
26107a48b3eSDavid Wu ulong pll_rate;
26207a48b3eSDavid Wu u8 div;
26307a48b3eSDavid Wu
26407a48b3eSDavid Wu if ((con >> GMAC2IO_PLL_SEL_SHIFT) & GMAC2IO_PLL_SEL_GPLL)
2650b7db90fSElaine Zhang pll_rate = priv->gpll_hz;
26607a48b3eSDavid Wu else
2670b7db90fSElaine Zhang pll_rate = priv->cpll_hz;
26807a48b3eSDavid Wu
26907a48b3eSDavid Wu div = DIV_ROUND_UP(pll_rate, rate) - 1;
27007a48b3eSDavid Wu if (div <= 0x1f)
27107a48b3eSDavid Wu rk_clrsetreg(&cru->clksel_con[27], GMAC2IO_CLK_DIV_MASK,
27207a48b3eSDavid Wu div << GMAC2IO_CLK_DIV_SHIFT);
27307a48b3eSDavid Wu else
27407a48b3eSDavid Wu debug("Unsupported div for gmac:%d\n", div);
27507a48b3eSDavid Wu
27607a48b3eSDavid Wu return DIV_TO_RATE(pll_rate, div);
27707a48b3eSDavid Wu }
27807a48b3eSDavid Wu
27907a48b3eSDavid Wu return ret;
28007a48b3eSDavid Wu }
281*67a2a1ddSDavid Wu
rk3328_gmac2phy_src_set_clk(struct rk3328_cru * cru,ulong rate)282*67a2a1ddSDavid Wu static ulong rk3328_gmac2phy_src_set_clk(struct rk3328_cru *cru, ulong rate)
283*67a2a1ddSDavid Wu {
284*67a2a1ddSDavid Wu u32 con = readl(&cru->clksel_con[26]);
285*67a2a1ddSDavid Wu ulong pll_rate;
286*67a2a1ddSDavid Wu u8 div;
287*67a2a1ddSDavid Wu
288*67a2a1ddSDavid Wu if ((con >> GMAC2PHY_PLL_SEL_SHIFT) & GMAC2PHY_PLL_SEL_GPLL)
289*67a2a1ddSDavid Wu pll_rate = GPLL_HZ;
290*67a2a1ddSDavid Wu else
291*67a2a1ddSDavid Wu pll_rate = CPLL_HZ;
292*67a2a1ddSDavid Wu
293*67a2a1ddSDavid Wu div = DIV_ROUND_UP(pll_rate, rate) - 1;
294*67a2a1ddSDavid Wu if (div <= 0x1f)
295*67a2a1ddSDavid Wu rk_clrsetreg(&cru->clksel_con[26], GMAC2PHY_CLK_DIV_MASK,
296*67a2a1ddSDavid Wu div << GMAC2PHY_CLK_DIV_SHIFT);
297*67a2a1ddSDavid Wu else
298*67a2a1ddSDavid Wu debug("Unsupported div for gmac:%d\n", div);
299*67a2a1ddSDavid Wu
300*67a2a1ddSDavid Wu return DIV_TO_RATE(pll_rate, div);
301*67a2a1ddSDavid Wu }
302*67a2a1ddSDavid Wu
rk3328_gmac2phy_set_clk(struct rk3328_cru * cru,ulong rate)303*67a2a1ddSDavid Wu static ulong rk3328_gmac2phy_set_clk(struct rk3328_cru *cru, ulong rate)
304*67a2a1ddSDavid Wu {
305*67a2a1ddSDavid Wu struct rk3328_grf_regs *grf;
306*67a2a1ddSDavid Wu
307*67a2a1ddSDavid Wu grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
308*67a2a1ddSDavid Wu if (readl(&grf->mac_con[2]) & BIT(10))
309*67a2a1ddSDavid Wu /* An external clock will always generate the right rate... */
310*67a2a1ddSDavid Wu return rate;
311*67a2a1ddSDavid Wu else
312*67a2a1ddSDavid Wu return rk3328_gmac2phy_src_set_clk(cru, rate);
313*67a2a1ddSDavid Wu }
3140b7db90fSElaine Zhang #endif
31507a48b3eSDavid Wu
rk3328_mmc_get_clk(struct rk3328_clk_priv * priv,uint clk_id)3160b7db90fSElaine Zhang static ulong rk3328_mmc_get_clk(struct rk3328_clk_priv *priv, uint clk_id)
31741793000SKever Yang {
3180b7db90fSElaine Zhang struct rk3328_cru *cru = priv->cru;
31941793000SKever Yang u32 div, con, con_id;
32041793000SKever Yang
32141793000SKever Yang switch (clk_id) {
32241793000SKever Yang case HCLK_SDMMC:
32385c91cb6SXu Ziyuan case SCLK_SDMMC:
32441793000SKever Yang con_id = 30;
32541793000SKever Yang break;
32641793000SKever Yang case HCLK_EMMC:
32785c91cb6SXu Ziyuan case SCLK_EMMC:
32814262c55SJason Zhu case SCLK_EMMC_SAMPLE:
32941793000SKever Yang con_id = 32;
33041793000SKever Yang break;
33141793000SKever Yang default:
33241793000SKever Yang return -EINVAL;
33341793000SKever Yang }
33441793000SKever Yang con = readl(&cru->clksel_con[con_id]);
33541793000SKever Yang div = (con & CLK_EMMC_DIV_CON_MASK) >> CLK_EMMC_DIV_CON_SHIFT;
33641793000SKever Yang
33741793000SKever Yang if ((con & CLK_EMMC_PLL_MASK) >> CLK_EMMC_PLL_SHIFT
33841793000SKever Yang == CLK_EMMC_PLL_SEL_24M)
3393a94d75dSKever Yang return DIV_TO_RATE(OSC_HZ, div) / 2;
34041793000SKever Yang else
3410b7db90fSElaine Zhang return DIV_TO_RATE(priv->gpll_hz, div) / 2;
34241793000SKever Yang }
34341793000SKever Yang
rk3328_mmc_set_clk(struct rk3328_clk_priv * priv,ulong clk_id,ulong set_rate)3440b7db90fSElaine Zhang static ulong rk3328_mmc_set_clk(struct rk3328_clk_priv *priv,
34541793000SKever Yang ulong clk_id, ulong set_rate)
34641793000SKever Yang {
3470b7db90fSElaine Zhang struct rk3328_cru *cru = priv->cru;
34841793000SKever Yang int src_clk_div;
34941793000SKever Yang u32 con_id;
35041793000SKever Yang
35141793000SKever Yang switch (clk_id) {
35241793000SKever Yang case HCLK_SDMMC:
35385c91cb6SXu Ziyuan case SCLK_SDMMC:
35441793000SKever Yang con_id = 30;
35541793000SKever Yang break;
35641793000SKever Yang case HCLK_EMMC:
35785c91cb6SXu Ziyuan case SCLK_EMMC:
35841793000SKever Yang con_id = 32;
35941793000SKever Yang break;
36041793000SKever Yang default:
36141793000SKever Yang return -EINVAL;
36241793000SKever Yang }
36341793000SKever Yang /* Select clk_sdmmc/emmc source from GPLL by default */
3643a94d75dSKever Yang /* mmc clock defaulg div 2 internal, need provide double in cru */
3650b7db90fSElaine Zhang src_clk_div = DIV_ROUND_UP(priv->gpll_hz / 2, set_rate);
36641793000SKever Yang
36741793000SKever Yang if (src_clk_div > 127) {
36841793000SKever Yang /* use 24MHz source for 400KHz clock */
3693a94d75dSKever Yang src_clk_div = DIV_ROUND_UP(OSC_HZ / 2, set_rate);
37041793000SKever Yang rk_clrsetreg(&cru->clksel_con[con_id],
37141793000SKever Yang CLK_EMMC_PLL_MASK | CLK_EMMC_DIV_CON_MASK,
37241793000SKever Yang CLK_EMMC_PLL_SEL_24M << CLK_EMMC_PLL_SHIFT |
37341793000SKever Yang (src_clk_div - 1) << CLK_EMMC_DIV_CON_SHIFT);
37441793000SKever Yang } else {
37541793000SKever Yang rk_clrsetreg(&cru->clksel_con[con_id],
37641793000SKever Yang CLK_EMMC_PLL_MASK | CLK_EMMC_DIV_CON_MASK,
37741793000SKever Yang CLK_EMMC_PLL_SEL_GPLL << CLK_EMMC_PLL_SHIFT |
37841793000SKever Yang (src_clk_div - 1) << CLK_EMMC_DIV_CON_SHIFT);
37941793000SKever Yang }
38041793000SKever Yang
3810b7db90fSElaine Zhang return rk3328_mmc_get_clk(priv, clk_id);
38241793000SKever Yang }
38341793000SKever Yang
rk3328_spi_get_clk(struct rk3328_clk_priv * priv)3844333cc9aSYifeng Zhao static ulong rk3328_spi_get_clk(struct rk3328_clk_priv *priv)
3854333cc9aSYifeng Zhao {
3864333cc9aSYifeng Zhao struct rk3328_cru *cru = priv->cru;
3874333cc9aSYifeng Zhao u32 div, con, mux, p_rate;
3884333cc9aSYifeng Zhao
3894333cc9aSYifeng Zhao con = readl(&cru->clksel_con[24]);
3904333cc9aSYifeng Zhao div = (con & CLK_SPI_DIV_CON_MASK) >> CLK_SPI_DIV_CON_SHIFT;
3914333cc9aSYifeng Zhao mux = (con & CLK_SPI_PLL_SEL_MASK) >> CLK_SPI_PLL_SEL_SHIFT;
3924333cc9aSYifeng Zhao if (mux)
3934333cc9aSYifeng Zhao p_rate = priv->gpll_hz;
3944333cc9aSYifeng Zhao else
3954333cc9aSYifeng Zhao p_rate = priv->cpll_hz;
3964333cc9aSYifeng Zhao
3974333cc9aSYifeng Zhao return DIV_TO_RATE(p_rate, div);
3984333cc9aSYifeng Zhao }
3994333cc9aSYifeng Zhao
rk3328_spi_set_clk(struct rk3328_clk_priv * priv,uint hz)4004333cc9aSYifeng Zhao static ulong rk3328_spi_set_clk(struct rk3328_clk_priv *priv, uint hz)
4014333cc9aSYifeng Zhao {
4024333cc9aSYifeng Zhao struct rk3328_cru *cru = priv->cru;
4034333cc9aSYifeng Zhao u32 div = priv->gpll_hz / hz;
4044333cc9aSYifeng Zhao
4054333cc9aSYifeng Zhao rk_clrsetreg(&cru->clksel_con[24],
4064333cc9aSYifeng Zhao CLK_SPI_PLL_SEL_MASK | CLK_SPI_DIV_CON_MASK,
4074333cc9aSYifeng Zhao CLK_SPI_PLL_SEL_GPLL << CLK_SPI_PLL_SEL_SHIFT |
4084333cc9aSYifeng Zhao (div - 1) << CLK_SPI_DIV_CON_SHIFT);
4094333cc9aSYifeng Zhao
4104333cc9aSYifeng Zhao return DIV_TO_RATE(priv->gpll_hz, div);
4114333cc9aSYifeng Zhao }
4124333cc9aSYifeng Zhao
4130b7db90fSElaine Zhang #ifndef CONFIG_SPL_BUILD
rk3328_pwm_get_clk(struct rk3328_clk_priv * priv)4140b7db90fSElaine Zhang static ulong rk3328_pwm_get_clk(struct rk3328_clk_priv *priv)
41541793000SKever Yang {
4160b7db90fSElaine Zhang struct rk3328_cru *cru = priv->cru;
41741793000SKever Yang u32 div, con;
41841793000SKever Yang
41941793000SKever Yang con = readl(&cru->clksel_con[24]);
42041793000SKever Yang div = (con & CLK_PWM_DIV_CON_MASK) >> CLK_PWM_DIV_CON_SHIFT;
42141793000SKever Yang
4220b7db90fSElaine Zhang return DIV_TO_RATE(priv->gpll_hz, div);
42341793000SKever Yang }
42441793000SKever Yang
rk3328_pwm_set_clk(struct rk3328_clk_priv * priv,uint hz)4250b7db90fSElaine Zhang static ulong rk3328_pwm_set_clk(struct rk3328_clk_priv *priv, uint hz)
42641793000SKever Yang {
4270b7db90fSElaine Zhang struct rk3328_cru *cru = priv->cru;
4280b7db90fSElaine Zhang u32 div = priv->gpll_hz / hz;
42941793000SKever Yang
43041793000SKever Yang rk_clrsetreg(&cru->clksel_con[24],
43141793000SKever Yang CLK_PWM_PLL_SEL_MASK | CLK_PWM_DIV_CON_MASK,
43241793000SKever Yang CLK_PWM_PLL_SEL_GPLL << CLK_PWM_PLL_SEL_SHIFT |
43341793000SKever Yang (div - 1) << CLK_PWM_DIV_CON_SHIFT);
43441793000SKever Yang
4350b7db90fSElaine Zhang return DIV_TO_RATE(priv->gpll_hz, div);
43641793000SKever Yang }
43741793000SKever Yang
rk3328_saradc_get_clk(struct rk3328_clk_priv * priv)4380b7db90fSElaine Zhang static ulong rk3328_saradc_get_clk(struct rk3328_clk_priv *priv)
439ae74d3d5SDavid Wu {
4400b7db90fSElaine Zhang struct rk3328_cru *cru = priv->cru;
441ae74d3d5SDavid Wu u32 div, val;
442ae74d3d5SDavid Wu
443ae74d3d5SDavid Wu val = readl(&cru->clksel_con[23]);
444ae74d3d5SDavid Wu div = bitfield_extract(val, CLK_SARADC_DIV_CON_SHIFT,
445ae74d3d5SDavid Wu CLK_SARADC_DIV_CON_WIDTH);
446ae74d3d5SDavid Wu
447ae74d3d5SDavid Wu return DIV_TO_RATE(OSC_HZ, div);
448ae74d3d5SDavid Wu }
449ae74d3d5SDavid Wu
rk3328_saradc_set_clk(struct rk3328_clk_priv * priv,uint hz)4500b7db90fSElaine Zhang static ulong rk3328_saradc_set_clk(struct rk3328_clk_priv *priv, uint hz)
451ae74d3d5SDavid Wu {
4520b7db90fSElaine Zhang struct rk3328_cru *cru = priv->cru;
453ae74d3d5SDavid Wu int src_clk_div;
454ae74d3d5SDavid Wu
455ae74d3d5SDavid Wu src_clk_div = DIV_ROUND_UP(OSC_HZ, hz) - 1;
456ae74d3d5SDavid Wu assert(src_clk_div < 128);
457ae74d3d5SDavid Wu
458ae74d3d5SDavid Wu rk_clrsetreg(&cru->clksel_con[23],
459ae74d3d5SDavid Wu CLK_SARADC_DIV_CON_MASK,
460ae74d3d5SDavid Wu src_clk_div << CLK_SARADC_DIV_CON_SHIFT);
461ae74d3d5SDavid Wu
4620b7db90fSElaine Zhang return rk3328_saradc_get_clk(priv);
4630b7db90fSElaine Zhang }
4640b7db90fSElaine Zhang
rk3328_tsadc_get_clk(struct rk3328_clk_priv * priv)465cb3c37fcSElaine Zhang static ulong rk3328_tsadc_get_clk(struct rk3328_clk_priv *priv)
466cb3c37fcSElaine Zhang {
467cb3c37fcSElaine Zhang struct rk3328_cru *cru = priv->cru;
468cb3c37fcSElaine Zhang u32 div, val;
469cb3c37fcSElaine Zhang
470cb3c37fcSElaine Zhang val = readl(&cru->clksel_con[22]);
471cb3c37fcSElaine Zhang div = bitfield_extract(val, CLK_SARADC_DIV_CON_SHIFT,
472cb3c37fcSElaine Zhang CLK_SARADC_DIV_CON_WIDTH);
473cb3c37fcSElaine Zhang
474cb3c37fcSElaine Zhang return DIV_TO_RATE(OSC_HZ, div);
475cb3c37fcSElaine Zhang }
476cb3c37fcSElaine Zhang
rk3328_tsadc_set_clk(struct rk3328_clk_priv * priv,uint hz)477cb3c37fcSElaine Zhang static ulong rk3328_tsadc_set_clk(struct rk3328_clk_priv *priv, uint hz)
478cb3c37fcSElaine Zhang {
479cb3c37fcSElaine Zhang struct rk3328_cru *cru = priv->cru;
480cb3c37fcSElaine Zhang int src_clk_div;
481cb3c37fcSElaine Zhang
482cb3c37fcSElaine Zhang src_clk_div = DIV_ROUND_UP(OSC_HZ, hz) - 1;
483cb3c37fcSElaine Zhang assert(src_clk_div < 128);
484cb3c37fcSElaine Zhang
485cb3c37fcSElaine Zhang rk_clrsetreg(&cru->clksel_con[22],
486cb3c37fcSElaine Zhang CLK_SARADC_DIV_CON_MASK,
487cb3c37fcSElaine Zhang src_clk_div << CLK_SARADC_DIV_CON_SHIFT);
488cb3c37fcSElaine Zhang
489cb3c37fcSElaine Zhang return rk3328_tsadc_get_clk(priv);
490cb3c37fcSElaine Zhang }
491cb3c37fcSElaine Zhang
rk3328_vop_get_clk(struct rk3328_clk_priv * priv,ulong clk_id)4920b7db90fSElaine Zhang static ulong rk3328_vop_get_clk(struct rk3328_clk_priv *priv, ulong clk_id)
4930b7db90fSElaine Zhang {
4940b7db90fSElaine Zhang struct rk3328_cru *cru = priv->cru;
4950b7db90fSElaine Zhang u32 div, con, parent;
4960b7db90fSElaine Zhang
4970b7db90fSElaine Zhang switch (clk_id) {
4980b7db90fSElaine Zhang case ACLK_VOP_PRE:
4998e2239d5SElaine Zhang case ACLK_VOP:
5000b7db90fSElaine Zhang con = readl(&cru->clksel_con[39]);
5010b7db90fSElaine Zhang div = (con & ACLK_VOP_DIV_CON_MASK) >> ACLK_VOP_DIV_CON_SHIFT;
5020b7db90fSElaine Zhang parent = priv->cpll_hz;
5030b7db90fSElaine Zhang break;
5040b7db90fSElaine Zhang case ACLK_VIO_PRE:
5058e2239d5SElaine Zhang case ACLK_VIO:
5060b7db90fSElaine Zhang con = readl(&cru->clksel_con[37]);
5070b7db90fSElaine Zhang div = (con & ACLK_VIO_DIV_CON_MASK) >> ACLK_VIO_DIV_CON_SHIFT;
5080b7db90fSElaine Zhang parent = priv->cpll_hz;
5090b7db90fSElaine Zhang break;
5100b7db90fSElaine Zhang case HCLK_VIO_PRE:
5118e2239d5SElaine Zhang case HCLK_VIO:
5120b7db90fSElaine Zhang parent = rk3328_vop_get_clk(priv, ACLK_VIO_PRE);
5130b7db90fSElaine Zhang con = readl(&cru->clksel_con[37]);
5140b7db90fSElaine Zhang div = (con & HCLK_VIO_DIV_CON_MASK) >> HCLK_VIO_DIV_CON_SHIFT;
5150b7db90fSElaine Zhang break;
5160b7db90fSElaine Zhang default:
5170b7db90fSElaine Zhang return -ENOENT;
5180b7db90fSElaine Zhang }
5190b7db90fSElaine Zhang
5200b7db90fSElaine Zhang return DIV_TO_RATE(parent, div);
5210b7db90fSElaine Zhang }
5220b7db90fSElaine Zhang
rk3328_vop_set_clk(struct rk3328_clk_priv * priv,ulong clk_id,uint hz)5230b7db90fSElaine Zhang static ulong rk3328_vop_set_clk(struct rk3328_clk_priv *priv,
5240b7db90fSElaine Zhang ulong clk_id, uint hz)
5250b7db90fSElaine Zhang {
5260b7db90fSElaine Zhang struct rk3328_cru *cru = priv->cru;
5270b7db90fSElaine Zhang int src_clk_div;
5280b7db90fSElaine Zhang u32 con, parent;
5290b7db90fSElaine Zhang
5300b7db90fSElaine Zhang src_clk_div = DIV_ROUND_UP(priv->cpll_hz, hz);
5310b7db90fSElaine Zhang assert(src_clk_div - 1 < 31);
5320b7db90fSElaine Zhang
5330b7db90fSElaine Zhang switch (clk_id) {
5340b7db90fSElaine Zhang case ACLK_VOP_PRE:
5358e2239d5SElaine Zhang case ACLK_VOP:
5360b7db90fSElaine Zhang rk_clrsetreg(&cru->clksel_con[39],
5370b7db90fSElaine Zhang ACLK_VOP_PLL_SEL_MASK | ACLK_VOP_DIV_CON_MASK,
5380b7db90fSElaine Zhang ACLK_VOP_PLL_SEL_CPLL << ACLK_VOP_PLL_SEL_SHIFT |
5390b7db90fSElaine Zhang (src_clk_div - 1) << ACLK_VOP_DIV_CON_SHIFT);
5400b7db90fSElaine Zhang break;
5410b7db90fSElaine Zhang case ACLK_VIO_PRE:
5428e2239d5SElaine Zhang case ACLK_VIO:
5430b7db90fSElaine Zhang rk_clrsetreg(&cru->clksel_con[37],
5440b7db90fSElaine Zhang ACLK_VIO_PLL_SEL_MASK | ACLK_VIO_DIV_CON_MASK,
5450b7db90fSElaine Zhang ACLK_VIO_PLL_SEL_CPLL << ACLK_VIO_PLL_SEL_SHIFT |
5460b7db90fSElaine Zhang (src_clk_div - 1) << ACLK_VIO_DIV_CON_SHIFT);
5470b7db90fSElaine Zhang break;
5480b7db90fSElaine Zhang case HCLK_VIO_PRE:
5498e2239d5SElaine Zhang case HCLK_VIO:
5500b7db90fSElaine Zhang src_clk_div = DIV_ROUND_UP(rk3328_vop_get_clk(priv,
5510b7db90fSElaine Zhang ACLK_VIO_PRE),
5520b7db90fSElaine Zhang hz);
5530b7db90fSElaine Zhang rk_clrsetreg(&cru->clksel_con[37],
5540b7db90fSElaine Zhang HCLK_VIO_DIV_CON_MASK,
5550b7db90fSElaine Zhang (src_clk_div - 1) << HCLK_VIO_DIV_CON_SHIFT);
5560b7db90fSElaine Zhang break;
5570b7db90fSElaine Zhang case DCLK_LCDC:
5580b7db90fSElaine Zhang con = readl(&cru->clksel_con[40]);
5590b7db90fSElaine Zhang con = (con & DCLK_LCDC_SEL_MASK) >> DCLK_LCDC_SEL_SHIFT;
5600b7db90fSElaine Zhang if (con) {
5610b7db90fSElaine Zhang parent = readl(&cru->clksel_con[40]);
5620b7db90fSElaine Zhang parent = (parent & DCLK_LCDC_PLL_SEL_MASK) >>
5630b7db90fSElaine Zhang DCLK_LCDC_PLL_SEL_SHIFT;
5640b7db90fSElaine Zhang if (parent)
5650b7db90fSElaine Zhang src_clk_div = DIV_ROUND_UP(priv->cpll_hz, hz);
5660b7db90fSElaine Zhang else
5670b7db90fSElaine Zhang src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
5680b7db90fSElaine Zhang
5690b7db90fSElaine Zhang rk_clrsetreg(&cru->clksel_con[40],
5700b7db90fSElaine Zhang DCLK_LCDC_DIV_CON_MASK,
5710b7db90fSElaine Zhang (src_clk_div - 1) <<
5720b7db90fSElaine Zhang DCLK_LCDC_DIV_CON_SHIFT);
5730b7db90fSElaine Zhang }
5740b7db90fSElaine Zhang break;
5750b7db90fSElaine Zhang default:
5760b7db90fSElaine Zhang printf("do not support this vop freq\n");
5770b7db90fSElaine Zhang return -EINVAL;
5780b7db90fSElaine Zhang }
5790b7db90fSElaine Zhang
5800b7db90fSElaine Zhang return rk3328_vop_get_clk(priv, clk_id);
5810b7db90fSElaine Zhang }
5820b7db90fSElaine Zhang #endif
5830b7db90fSElaine Zhang
rk3328_bus_get_clk(struct rk3328_clk_priv * priv,ulong clk_id)5840b7db90fSElaine Zhang static ulong rk3328_bus_get_clk(struct rk3328_clk_priv *priv, ulong clk_id)
5850b7db90fSElaine Zhang {
5860b7db90fSElaine Zhang struct rk3328_cru *cru = priv->cru;
5870b7db90fSElaine Zhang u32 div, con, parent;
5880b7db90fSElaine Zhang
5890b7db90fSElaine Zhang switch (clk_id) {
5900b7db90fSElaine Zhang case ACLK_BUS_PRE:
5910b7db90fSElaine Zhang con = readl(&cru->clksel_con[0]);
5920b7db90fSElaine Zhang div = (con & ACLK_BUS_DIV_CON_MASK) >> ACLK_BUS_DIV_CON_SHIFT;
5930b7db90fSElaine Zhang parent = priv->cpll_hz;
5940b7db90fSElaine Zhang break;
5950b7db90fSElaine Zhang case HCLK_BUS_PRE:
5960b7db90fSElaine Zhang con = readl(&cru->clksel_con[1]);
5970b7db90fSElaine Zhang div = (con & HCLK_BUS_DIV_CON_MASK) >> HCLK_BUS_DIV_CON_SHIFT;
5980b7db90fSElaine Zhang parent = rk3328_bus_get_clk(priv, ACLK_BUS_PRE);
5990b7db90fSElaine Zhang break;
6000b7db90fSElaine Zhang case PCLK_BUS_PRE:
6010b7db90fSElaine Zhang con = readl(&cru->clksel_con[1]);
6020b7db90fSElaine Zhang div = (con & PCLK_BUS_DIV_CON_MASK) >> PCLK_BUS_DIV_CON_SHIFT;
6030b7db90fSElaine Zhang parent = rk3328_bus_get_clk(priv, ACLK_BUS_PRE);
6040b7db90fSElaine Zhang break;
6050b7db90fSElaine Zhang default:
6060b7db90fSElaine Zhang return -ENOENT;
6070b7db90fSElaine Zhang }
6080b7db90fSElaine Zhang
6090b7db90fSElaine Zhang return DIV_TO_RATE(parent, div);
6100b7db90fSElaine Zhang }
6110b7db90fSElaine Zhang
rk3328_bus_set_clk(struct rk3328_clk_priv * priv,ulong clk_id,ulong hz)6120b7db90fSElaine Zhang static ulong rk3328_bus_set_clk(struct rk3328_clk_priv *priv,
6130b7db90fSElaine Zhang ulong clk_id, ulong hz)
6140b7db90fSElaine Zhang {
6150b7db90fSElaine Zhang struct rk3328_cru *cru = priv->cru;
6160b7db90fSElaine Zhang int src_clk_div;
6170b7db90fSElaine Zhang
6180b7db90fSElaine Zhang /*
6190b7db90fSElaine Zhang * select gpll as pd_bus bus clock source and
6200b7db90fSElaine Zhang * set up dependent divisors for PCLK/HCLK and ACLK clocks.
6210b7db90fSElaine Zhang */
6220b7db90fSElaine Zhang switch (clk_id) {
6230b7db90fSElaine Zhang case ACLK_BUS_PRE:
6240b7db90fSElaine Zhang src_clk_div = DIV_ROUND_UP(priv->cpll_hz, hz);
6250b7db90fSElaine Zhang assert(src_clk_div - 1 < 31);
626514da391SElaine Zhang if (src_clk_div > 32)
627514da391SElaine Zhang src_clk_div = 32;
6280b7db90fSElaine Zhang rk_clrsetreg(&cru->clksel_con[0],
6290b7db90fSElaine Zhang CLK_BUS_PLL_SEL_MASK | ACLK_BUS_DIV_CON_MASK,
6300b7db90fSElaine Zhang CLK_BUS_PLL_SEL_CPLL << CLK_BUS_PLL_SEL_SHIFT |
6310b7db90fSElaine Zhang (src_clk_div - 1) << ACLK_BUS_DIV_CON_SHIFT);
6320b7db90fSElaine Zhang break;
6330b7db90fSElaine Zhang case HCLK_BUS_PRE:
6340b7db90fSElaine Zhang src_clk_div = DIV_ROUND_UP(rk3328_bus_get_clk(priv,
6350b7db90fSElaine Zhang ACLK_BUS_PRE),
6360b7db90fSElaine Zhang hz);
6370b7db90fSElaine Zhang assert(src_clk_div - 1 < 3);
6380b7db90fSElaine Zhang rk_clrsetreg(&cru->clksel_con[1],
6390b7db90fSElaine Zhang HCLK_BUS_DIV_CON_MASK,
6400b7db90fSElaine Zhang (src_clk_div - 1) << HCLK_BUS_DIV_CON_SHIFT);
6410b7db90fSElaine Zhang break;
6420b7db90fSElaine Zhang case PCLK_BUS_PRE:
6430b7db90fSElaine Zhang src_clk_div = DIV_ROUND_UP(rk3328_bus_get_clk(priv,
6440b7db90fSElaine Zhang ACLK_BUS_PRE),
6450b7db90fSElaine Zhang hz);
6460b7db90fSElaine Zhang assert(src_clk_div - 1 < 7);
6470b7db90fSElaine Zhang rk_clrsetreg(&cru->clksel_con[1],
6480b7db90fSElaine Zhang PCLK_BUS_DIV_CON_MASK,
6490b7db90fSElaine Zhang (src_clk_div - 1) << PCLK_BUS_DIV_CON_SHIFT);
6500b7db90fSElaine Zhang break;
6510b7db90fSElaine Zhang default:
6520b7db90fSElaine Zhang printf("do not support this bus freq\n");
6530b7db90fSElaine Zhang return -EINVAL;
6540b7db90fSElaine Zhang }
6550b7db90fSElaine Zhang return rk3328_bus_get_clk(priv, clk_id);
6560b7db90fSElaine Zhang }
6570b7db90fSElaine Zhang
rk3328_peri_get_clk(struct rk3328_clk_priv * priv,ulong clk_id)6580b7db90fSElaine Zhang static ulong rk3328_peri_get_clk(struct rk3328_clk_priv *priv, ulong clk_id)
6590b7db90fSElaine Zhang {
6600b7db90fSElaine Zhang struct rk3328_cru *cru = priv->cru;
6610b7db90fSElaine Zhang u32 div, con, parent;
6620b7db90fSElaine Zhang
6630b7db90fSElaine Zhang switch (clk_id) {
6640b7db90fSElaine Zhang case ACLK_PERI_PRE:
6650b7db90fSElaine Zhang con = readl(&cru->clksel_con[28]);
6660b7db90fSElaine Zhang div = (con & ACLK_PERI_DIV_CON_MASK) >> ACLK_PERI_DIV_CON_SHIFT;
6670b7db90fSElaine Zhang parent = priv->cpll_hz;
6680b7db90fSElaine Zhang break;
6690b7db90fSElaine Zhang case HCLK_PERI:
6700b7db90fSElaine Zhang con = readl(&cru->clksel_con[29]);
6710b7db90fSElaine Zhang div = (con & HCLK_PERI_DIV_CON_MASK) >> HCLK_PERI_DIV_CON_SHIFT;
6720b7db90fSElaine Zhang parent = rk3328_peri_get_clk(priv, ACLK_PERI_PRE);
6730b7db90fSElaine Zhang break;
6740b7db90fSElaine Zhang case PCLK_PERI:
6750b7db90fSElaine Zhang con = readl(&cru->clksel_con[29]);
6760b7db90fSElaine Zhang div = (con & PCLK_PERI_DIV_CON_MASK) >> PCLK_PERI_DIV_CON_SHIFT;
6770b7db90fSElaine Zhang parent = rk3328_peri_get_clk(priv, ACLK_PERI_PRE);
6780b7db90fSElaine Zhang break;
6790b7db90fSElaine Zhang default:
6800b7db90fSElaine Zhang return -ENOENT;
6810b7db90fSElaine Zhang }
6820b7db90fSElaine Zhang
6830b7db90fSElaine Zhang return DIV_TO_RATE(parent, div);
6840b7db90fSElaine Zhang }
6850b7db90fSElaine Zhang
rk3328_peri_set_clk(struct rk3328_clk_priv * priv,ulong clk_id,ulong hz)6860b7db90fSElaine Zhang static ulong rk3328_peri_set_clk(struct rk3328_clk_priv *priv,
6870b7db90fSElaine Zhang ulong clk_id, ulong hz)
6880b7db90fSElaine Zhang {
6890b7db90fSElaine Zhang struct rk3328_cru *cru = priv->cru;
6900b7db90fSElaine Zhang int src_clk_div;
6910b7db90fSElaine Zhang
6920b7db90fSElaine Zhang /*
6930b7db90fSElaine Zhang * select gpll as pd_bus bus clock source and
6940b7db90fSElaine Zhang * set up dependent divisors for PCLK/HCLK and ACLK clocks.
6950b7db90fSElaine Zhang */
6960b7db90fSElaine Zhang switch (clk_id) {
6970b7db90fSElaine Zhang case ACLK_PERI_PRE:
6980b7db90fSElaine Zhang src_clk_div = DIV_ROUND_UP(priv->cpll_hz, hz);
6990b7db90fSElaine Zhang assert(src_clk_div - 1 < 31);
700514da391SElaine Zhang if (src_clk_div > 32)
701514da391SElaine Zhang src_clk_div = 32;
7020b7db90fSElaine Zhang rk_clrsetreg(&cru->clksel_con[28],
7030b7db90fSElaine Zhang CLK_PERI_PLL_SEL_MASK | ACLK_PERI_DIV_CON_MASK,
7040b7db90fSElaine Zhang CLK_PERI_PLL_SEL_CPLL << CLK_PERI_PLL_SEL_SHIFT |
7050b7db90fSElaine Zhang (src_clk_div - 1) << ACLK_PERI_DIV_CON_SHIFT);
7060b7db90fSElaine Zhang break;
7070b7db90fSElaine Zhang case HCLK_PERI:
7080b7db90fSElaine Zhang src_clk_div = DIV_ROUND_UP(rk3328_peri_get_clk(priv,
7090b7db90fSElaine Zhang ACLK_PERI_PRE),
7100b7db90fSElaine Zhang hz);
7110b7db90fSElaine Zhang assert(src_clk_div - 1 < 3);
7120b7db90fSElaine Zhang rk_clrsetreg(&cru->clksel_con[29],
7130b7db90fSElaine Zhang HCLK_PERI_DIV_CON_MASK,
7140b7db90fSElaine Zhang (src_clk_div - 1) << HCLK_PERI_DIV_CON_SHIFT);
7150b7db90fSElaine Zhang break;
7160b7db90fSElaine Zhang case PCLK_PERI:
7170b7db90fSElaine Zhang src_clk_div = DIV_ROUND_UP(rk3328_peri_get_clk(priv,
7180b7db90fSElaine Zhang ACLK_PERI_PRE),
7190b7db90fSElaine Zhang hz);
7200b7db90fSElaine Zhang assert(src_clk_div - 1 < 7);
7210b7db90fSElaine Zhang rk_clrsetreg(&cru->clksel_con[29],
7220b7db90fSElaine Zhang PCLK_PERI_DIV_CON_MASK,
7230b7db90fSElaine Zhang (src_clk_div - 1) << PCLK_PERI_DIV_CON_SHIFT);
7240b7db90fSElaine Zhang break;
7250b7db90fSElaine Zhang default:
7260b7db90fSElaine Zhang printf("do not support this bus freq\n");
7270b7db90fSElaine Zhang return -EINVAL;
7280b7db90fSElaine Zhang }
7290b7db90fSElaine Zhang
7300b7db90fSElaine Zhang return rk3328_peri_get_clk(priv, clk_id);
731ae74d3d5SDavid Wu }
732ae74d3d5SDavid Wu
733cf04b7e8SElaine Zhang #ifndef CONFIG_SPL_BUILD
rk3328_crypto_get_clk(struct rk3328_clk_priv * priv,ulong clk_id)734cf04b7e8SElaine Zhang static ulong rk3328_crypto_get_clk(struct rk3328_clk_priv *priv, ulong clk_id)
735cf04b7e8SElaine Zhang {
736cf04b7e8SElaine Zhang struct rk3328_cru *cru = priv->cru;
737cf04b7e8SElaine Zhang u32 div, con, parent;
738cf04b7e8SElaine Zhang
739cf04b7e8SElaine Zhang switch (clk_id) {
740cf04b7e8SElaine Zhang case SCLK_CRYPTO:
741cf04b7e8SElaine Zhang con = readl(&cru->clksel_con[20]);
742cf04b7e8SElaine Zhang div = (con & CRYPTO_DIV_MASK) >> CRYPTO_DIV_SHIFT;
743cf04b7e8SElaine Zhang parent = priv->gpll_hz;
744cf04b7e8SElaine Zhang break;
745cf04b7e8SElaine Zhang default:
746cf04b7e8SElaine Zhang return -ENOENT;
747cf04b7e8SElaine Zhang }
748cf04b7e8SElaine Zhang
749cf04b7e8SElaine Zhang return DIV_TO_RATE(parent, div);
750cf04b7e8SElaine Zhang }
751cf04b7e8SElaine Zhang
rk3328_crypto_set_clk(struct rk3328_clk_priv * priv,ulong clk_id,ulong hz)752cf04b7e8SElaine Zhang static ulong rk3328_crypto_set_clk(struct rk3328_clk_priv *priv, ulong clk_id,
753cf04b7e8SElaine Zhang ulong hz)
754cf04b7e8SElaine Zhang {
755cf04b7e8SElaine Zhang struct rk3328_cru *cru = priv->cru;
756cf04b7e8SElaine Zhang int src_clk_div;
757cf04b7e8SElaine Zhang
758cf04b7e8SElaine Zhang src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
759cf04b7e8SElaine Zhang assert(src_clk_div - 1 <= 127);
760cf04b7e8SElaine Zhang
761cf04b7e8SElaine Zhang /*
762cf04b7e8SElaine Zhang * select gpll as crypto clock source and
763cf04b7e8SElaine Zhang * set up dependent divisors for crypto clocks.
764cf04b7e8SElaine Zhang */
765cf04b7e8SElaine Zhang switch (clk_id) {
766cf04b7e8SElaine Zhang case SCLK_CRYPTO:
767cf04b7e8SElaine Zhang rk_clrsetreg(&cru->clksel_con[20],
768cf04b7e8SElaine Zhang CRYPTO_PLL_SEL_MASK | CRYPTO_DIV_MASK,
769cf04b7e8SElaine Zhang CRYPTO_PLL_SEL_GPLL << CRYPTO_PLL_SEL_SHIFT |
770cf04b7e8SElaine Zhang (src_clk_div - 1) << CRYPTO_DIV_SHIFT);
771cf04b7e8SElaine Zhang break;
772cf04b7e8SElaine Zhang default:
773cf04b7e8SElaine Zhang printf("do not support this peri freq\n");
774cf04b7e8SElaine Zhang return -EINVAL;
775cf04b7e8SElaine Zhang }
776cf04b7e8SElaine Zhang
777cf04b7e8SElaine Zhang return rk3328_crypto_get_clk(priv, clk_id);
778cf04b7e8SElaine Zhang }
779cf04b7e8SElaine Zhang #endif
780cf04b7e8SElaine Zhang
rk3328_clk_get_rate(struct clk * clk)78141793000SKever Yang static ulong rk3328_clk_get_rate(struct clk *clk)
78241793000SKever Yang {
78341793000SKever Yang struct rk3328_clk_priv *priv = dev_get_priv(clk->dev);
78441793000SKever Yang ulong rate = 0;
78541793000SKever Yang
7860b7db90fSElaine Zhang #ifndef CONFIG_SPL_BUILD
7870b7db90fSElaine Zhang if (!priv->gpll_hz) {
7880b7db90fSElaine Zhang priv->gpll_hz = rockchip_pll_get_rate(&rk3328_pll_clks[GPLL],
7890b7db90fSElaine Zhang priv->cru, GPLL);
7900b7db90fSElaine Zhang debug("%s gpll=%lu\n", __func__, priv->gpll_hz);
7910b7db90fSElaine Zhang }
7920b7db90fSElaine Zhang if (!priv->cpll_hz) {
7930b7db90fSElaine Zhang priv->cpll_hz = rockchip_pll_get_rate(&rk3328_pll_clks[CPLL],
7940b7db90fSElaine Zhang priv->cru, CPLL);
7950b7db90fSElaine Zhang debug("%s cpll=%lu\n", __func__, priv->cpll_hz);
7960b7db90fSElaine Zhang }
7970b7db90fSElaine Zhang #endif
7980b7db90fSElaine Zhang
79941793000SKever Yang switch (clk->id) {
8000b7db90fSElaine Zhang case PLL_APLL:
8010b7db90fSElaine Zhang case PLL_DPLL:
8020b7db90fSElaine Zhang case PLL_CPLL:
8030b7db90fSElaine Zhang case PLL_GPLL:
8040b7db90fSElaine Zhang case PLL_NPLL:
8050b7db90fSElaine Zhang rate = rockchip_pll_get_rate(&rk3328_pll_clks[clk->id - 1],
8060b7db90fSElaine Zhang priv->cru, clk->id - 1);
8070b7db90fSElaine Zhang break;
8080b7db90fSElaine Zhang case ARMCLK:
8090b7db90fSElaine Zhang rate = rockchip_pll_get_rate(&rk3328_pll_clks[NPLL],
8100b7db90fSElaine Zhang priv->cru, NPLL);
8110b7db90fSElaine Zhang break;
8120b7db90fSElaine Zhang case ACLK_BUS_PRE:
8130b7db90fSElaine Zhang case HCLK_BUS_PRE:
8140b7db90fSElaine Zhang case PCLK_BUS_PRE:
8150b7db90fSElaine Zhang rate = rk3328_bus_get_clk(priv, clk->id);
8160b7db90fSElaine Zhang break;
8170b7db90fSElaine Zhang case ACLK_PERI_PRE:
8180b7db90fSElaine Zhang case HCLK_PERI:
8190b7db90fSElaine Zhang case PCLK_PERI:
8200b7db90fSElaine Zhang rate = rk3328_peri_get_clk(priv, clk->id);
8210b7db90fSElaine Zhang break;
82241793000SKever Yang case HCLK_SDMMC:
82341793000SKever Yang case HCLK_EMMC:
82485c91cb6SXu Ziyuan case SCLK_SDMMC:
82585c91cb6SXu Ziyuan case SCLK_EMMC:
82614262c55SJason Zhu case SCLK_EMMC_SAMPLE:
8270b7db90fSElaine Zhang rate = rk3328_mmc_get_clk(priv, clk->id);
82841793000SKever Yang break;
8294333cc9aSYifeng Zhao case SCLK_SPI:
8304333cc9aSYifeng Zhao rate = rk3328_spi_get_clk(priv);
8314333cc9aSYifeng Zhao break;
8320b7db90fSElaine Zhang #ifndef CONFIG_SPL_BUILD
83341793000SKever Yang case SCLK_I2C0:
83441793000SKever Yang case SCLK_I2C1:
83541793000SKever Yang case SCLK_I2C2:
83641793000SKever Yang case SCLK_I2C3:
8370b7db90fSElaine Zhang rate = rk3328_i2c_get_clk(priv, clk->id);
83841793000SKever Yang break;
83941793000SKever Yang case SCLK_PWM:
8400b7db90fSElaine Zhang rate = rk3328_pwm_get_clk(priv);
84141793000SKever Yang break;
842ae74d3d5SDavid Wu case SCLK_SARADC:
8430b7db90fSElaine Zhang rate = rk3328_saradc_get_clk(priv);
844ae74d3d5SDavid Wu break;
845cb3c37fcSElaine Zhang case SCLK_TSADC:
846cb3c37fcSElaine Zhang rate = rk3328_tsadc_get_clk(priv);
847cb3c37fcSElaine Zhang break;
8480b7db90fSElaine Zhang case ACLK_VOP_PRE:
8490b7db90fSElaine Zhang case ACLK_VIO_PRE:
8500b7db90fSElaine Zhang case HCLK_VIO_PRE:
8518e2239d5SElaine Zhang case ACLK_VOP:
8528e2239d5SElaine Zhang case ACLK_VIO:
8538e2239d5SElaine Zhang case HCLK_VIO:
8540b7db90fSElaine Zhang rate = rk3328_vop_get_clk(priv, clk->id);
8550b7db90fSElaine Zhang break;
856cf04b7e8SElaine Zhang case SCLK_CRYPTO:
857cf04b7e8SElaine Zhang rate = rk3328_crypto_get_clk(priv, clk->id);
858cf04b7e8SElaine Zhang break;
8590b7db90fSElaine Zhang #endif
86041793000SKever Yang default:
86141793000SKever Yang return -ENOENT;
86241793000SKever Yang }
86341793000SKever Yang
86441793000SKever Yang return rate;
86541793000SKever Yang }
86641793000SKever Yang
rk3328_clk_set_rate(struct clk * clk,ulong rate)86741793000SKever Yang static ulong rk3328_clk_set_rate(struct clk *clk, ulong rate)
86841793000SKever Yang {
86941793000SKever Yang struct rk3328_clk_priv *priv = dev_get_priv(clk->dev);
87041793000SKever Yang ulong ret = 0;
87141793000SKever Yang
87241793000SKever Yang switch (clk->id) {
8730b7db90fSElaine Zhang case PLL_APLL:
8740b7db90fSElaine Zhang case PLL_DPLL:
8750b7db90fSElaine Zhang case PLL_NPLL:
8760b7db90fSElaine Zhang ret = rockchip_pll_set_rate(&rk3328_pll_clks[clk->id - 1],
8770b7db90fSElaine Zhang priv->cru, clk->id - 1, rate);
8780b7db90fSElaine Zhang break;
8790b7db90fSElaine Zhang case PLL_CPLL:
8800b7db90fSElaine Zhang ret = rockchip_pll_set_rate(&rk3328_pll_clks[CPLL],
8810b7db90fSElaine Zhang priv->cru, CPLL, rate);
8820b7db90fSElaine Zhang priv->cpll_hz = rate;
8830b7db90fSElaine Zhang break;
8840b7db90fSElaine Zhang case PLL_GPLL:
8850b7db90fSElaine Zhang ret = rockchip_pll_set_rate(&rk3328_pll_clks[GPLL],
8860b7db90fSElaine Zhang priv->cru, GPLL, rate);
8870b7db90fSElaine Zhang priv->gpll_hz = rate;
8880b7db90fSElaine Zhang break;
8890b7db90fSElaine Zhang case ARMCLK:
890f7913bc1SElaine Zhang if (priv->armclk_hz)
8910b7db90fSElaine Zhang ret = rk3328_armclk_set_clk(priv, rate);
892f7913bc1SElaine Zhang priv->armclk_hz = rate;
8930b7db90fSElaine Zhang break;
8940b7db90fSElaine Zhang case ACLK_BUS_PRE:
8950b7db90fSElaine Zhang case HCLK_BUS_PRE:
8960b7db90fSElaine Zhang case PCLK_BUS_PRE:
8970b7db90fSElaine Zhang rate = rk3328_bus_set_clk(priv, clk->id, rate);
8980b7db90fSElaine Zhang break;
8990b7db90fSElaine Zhang case ACLK_PERI_PRE:
9000b7db90fSElaine Zhang case HCLK_PERI:
9010b7db90fSElaine Zhang case PCLK_PERI:
9020b7db90fSElaine Zhang rate = rk3328_peri_set_clk(priv, clk->id, rate);
9030b7db90fSElaine Zhang break;
90441793000SKever Yang case HCLK_SDMMC:
90541793000SKever Yang case HCLK_EMMC:
90685c91cb6SXu Ziyuan case SCLK_SDMMC:
90785c91cb6SXu Ziyuan case SCLK_EMMC:
9080b7db90fSElaine Zhang ret = rk3328_mmc_set_clk(priv, clk->id, rate);
90941793000SKever Yang break;
9104333cc9aSYifeng Zhao case SCLK_SPI:
9114333cc9aSYifeng Zhao ret = rk3328_spi_set_clk(priv, rate);
9124333cc9aSYifeng Zhao break;
9130b7db90fSElaine Zhang #ifndef CONFIG_SPL_BUILD
91441793000SKever Yang case SCLK_I2C0:
91541793000SKever Yang case SCLK_I2C1:
91641793000SKever Yang case SCLK_I2C2:
91741793000SKever Yang case SCLK_I2C3:
9180b7db90fSElaine Zhang ret = rk3328_i2c_set_clk(priv, clk->id, rate);
91941793000SKever Yang break;
92007a48b3eSDavid Wu case SCLK_MAC2IO:
9210b7db90fSElaine Zhang ret = rk3328_gmac2io_set_clk(priv, rate);
92207a48b3eSDavid Wu break;
923*67a2a1ddSDavid Wu case SCLK_MAC2PHY:
924*67a2a1ddSDavid Wu ret = rk3328_gmac2phy_set_clk(priv->cru, rate);
925*67a2a1ddSDavid Wu break;
926*67a2a1ddSDavid Wu case SCLK_MAC2PHY_SRC:
927*67a2a1ddSDavid Wu ret = rk3328_gmac2phy_src_set_clk(priv->cru, rate);
928*67a2a1ddSDavid Wu break;
92941793000SKever Yang case SCLK_PWM:
9300b7db90fSElaine Zhang ret = rk3328_pwm_set_clk(priv, rate);
93141793000SKever Yang break;
932ae74d3d5SDavid Wu case SCLK_SARADC:
9330b7db90fSElaine Zhang ret = rk3328_saradc_set_clk(priv, rate);
934ae74d3d5SDavid Wu break;
935cb3c37fcSElaine Zhang case SCLK_TSADC:
936cb3c37fcSElaine Zhang ret = rk3328_tsadc_set_clk(priv, rate);
937cb3c37fcSElaine Zhang break;
93807a48b3eSDavid Wu case DCLK_LCDC:
9390b7db90fSElaine Zhang case ACLK_VOP_PRE:
9400b7db90fSElaine Zhang case ACLK_VIO_PRE:
9410b7db90fSElaine Zhang case HCLK_VIO_PRE:
9428e2239d5SElaine Zhang case ACLK_VOP:
9438e2239d5SElaine Zhang case ACLK_VIO:
9448e2239d5SElaine Zhang case HCLK_VIO:
9450b7db90fSElaine Zhang rate = rk3328_vop_set_clk(priv, clk->id, rate);
9460b7db90fSElaine Zhang break;
947cf04b7e8SElaine Zhang case SCLK_CRYPTO:
948cf04b7e8SElaine Zhang rate = rk3328_crypto_set_clk(priv, clk->id, rate);
949cf04b7e8SElaine Zhang break;
9500b7db90fSElaine Zhang #endif
95107a48b3eSDavid Wu case SCLK_PDM:
95207a48b3eSDavid Wu case SCLK_RTC32K:
95307a48b3eSDavid Wu case SCLK_UART0:
95407a48b3eSDavid Wu case SCLK_UART1:
95507a48b3eSDavid Wu case SCLK_UART2:
95607a48b3eSDavid Wu case SCLK_SDIO:
95707a48b3eSDavid Wu case SCLK_TSP:
95807a48b3eSDavid Wu case SCLK_WIFI:
95907a48b3eSDavid Wu case ACLK_RGA_PRE:
96007a48b3eSDavid Wu case SCLK_RGA:
96107a48b3eSDavid Wu case ACLK_RKVDEC_PRE:
96207a48b3eSDavid Wu case ACLK_RKVENC:
96307a48b3eSDavid Wu case ACLK_VPU_PRE:
96407a48b3eSDavid Wu case SCLK_VDEC_CABAC:
96507a48b3eSDavid Wu case SCLK_VDEC_CORE:
96607a48b3eSDavid Wu case SCLK_VENC_CORE:
96707a48b3eSDavid Wu case SCLK_VENC_DSP:
96807a48b3eSDavid Wu case SCLK_EFUSE:
96907a48b3eSDavid Wu case PCLK_DDR:
97007a48b3eSDavid Wu case ACLK_GMAC:
97107a48b3eSDavid Wu case PCLK_GMAC:
97207a48b3eSDavid Wu case SCLK_USB3OTG_SUSPEND:
97307a48b3eSDavid Wu return 0;
97441793000SKever Yang default:
97541793000SKever Yang return -ENOENT;
97641793000SKever Yang }
97741793000SKever Yang
97841793000SKever Yang return ret;
97941793000SKever Yang }
98041793000SKever Yang
9810b7db90fSElaine Zhang #ifndef CONFIG_SPL_BUILD
rk3328_gmac2io_set_parent(struct clk * clk,struct clk * parent)98207a48b3eSDavid Wu static int rk3328_gmac2io_set_parent(struct clk *clk, struct clk *parent)
98307a48b3eSDavid Wu {
98407a48b3eSDavid Wu struct rk3328_grf_regs *grf;
98507a48b3eSDavid Wu const char *clock_output_name;
98607a48b3eSDavid Wu int ret;
98707a48b3eSDavid Wu
98807a48b3eSDavid Wu grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
98907a48b3eSDavid Wu
99007a48b3eSDavid Wu /*
99107a48b3eSDavid Wu * If the requested parent is in the same clock-controller and the id
99207a48b3eSDavid Wu * is SCLK_MAC2IO_SRC ("clk_mac2io_src"), switch to the internal clock.
99307a48b3eSDavid Wu */
99407a48b3eSDavid Wu if ((parent->dev == clk->dev) && (parent->id == SCLK_MAC2IO_SRC)) {
99507a48b3eSDavid Wu debug("%s: switching RGMII to SCLK_MAC2IO_SRC\n", __func__);
99607a48b3eSDavid Wu rk_clrreg(&grf->mac_con[1], BIT(10));
99707a48b3eSDavid Wu return 0;
99807a48b3eSDavid Wu }
99907a48b3eSDavid Wu
100007a48b3eSDavid Wu /*
100107a48b3eSDavid Wu * Otherwise, we need to check the clock-output-names of the
100207a48b3eSDavid Wu * requested parent to see if the requested id is "gmac_clkin".
100307a48b3eSDavid Wu */
100407a48b3eSDavid Wu ret = dev_read_string_index(parent->dev, "clock-output-names",
100507a48b3eSDavid Wu parent->id, &clock_output_name);
100607a48b3eSDavid Wu if (ret < 0)
100707a48b3eSDavid Wu return -ENODATA;
100807a48b3eSDavid Wu
100907a48b3eSDavid Wu /* If this is "gmac_clkin", switch to the external clock input */
101007a48b3eSDavid Wu if (!strcmp(clock_output_name, "gmac_clkin")) {
101107a48b3eSDavid Wu debug("%s: switching RGMII to CLKIN\n", __func__);
101207a48b3eSDavid Wu rk_setreg(&grf->mac_con[1], BIT(10));
101307a48b3eSDavid Wu return 0;
101407a48b3eSDavid Wu }
101507a48b3eSDavid Wu
101607a48b3eSDavid Wu return -EINVAL;
101707a48b3eSDavid Wu }
101807a48b3eSDavid Wu
rk3328_gmac2io_ext_set_parent(struct clk * clk,struct clk * parent)101907a48b3eSDavid Wu static int rk3328_gmac2io_ext_set_parent(struct clk *clk, struct clk *parent)
102007a48b3eSDavid Wu {
102107a48b3eSDavid Wu struct rk3328_grf_regs *grf;
102207a48b3eSDavid Wu const char *clock_output_name;
102307a48b3eSDavid Wu int ret;
102407a48b3eSDavid Wu
102507a48b3eSDavid Wu grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
102607a48b3eSDavid Wu
102707a48b3eSDavid Wu /*
102807a48b3eSDavid Wu * If the requested parent is in the same clock-controller and the id
102907a48b3eSDavid Wu * is SCLK_MAC2IO ("clk_mac2io"), switch to the internal clock.
103007a48b3eSDavid Wu */
103107a48b3eSDavid Wu if ((parent->dev == clk->dev) && (parent->id == SCLK_MAC2IO)) {
103207a48b3eSDavid Wu debug("%s: switching RGMII to SCLK_MAC2IO\n", __func__);
103307a48b3eSDavid Wu rk_clrreg(&grf->soc_con[4], BIT(14));
103407a48b3eSDavid Wu return 0;
103507a48b3eSDavid Wu }
103607a48b3eSDavid Wu
103707a48b3eSDavid Wu /*
103807a48b3eSDavid Wu * Otherwise, we need to check the clock-output-names of the
103907a48b3eSDavid Wu * requested parent to see if the requested id is "gmac_clkin".
104007a48b3eSDavid Wu */
104107a48b3eSDavid Wu ret = dev_read_string_index(parent->dev, "clock-output-names",
104207a48b3eSDavid Wu parent->id, &clock_output_name);
104307a48b3eSDavid Wu if (ret < 0)
104407a48b3eSDavid Wu return -ENODATA;
104507a48b3eSDavid Wu
104607a48b3eSDavid Wu /* If this is "gmac_clkin", switch to the external clock input */
104707a48b3eSDavid Wu if (!strcmp(clock_output_name, "gmac_clkin")) {
104807a48b3eSDavid Wu debug("%s: switching RGMII to CLKIN\n", __func__);
104907a48b3eSDavid Wu rk_setreg(&grf->soc_con[4], BIT(14));
105007a48b3eSDavid Wu return 0;
105107a48b3eSDavid Wu }
105207a48b3eSDavid Wu
105307a48b3eSDavid Wu return -EINVAL;
105407a48b3eSDavid Wu }
105507a48b3eSDavid Wu
rk3328_gmac2phy_set_parent(struct clk * clk,struct clk * parent)1056*67a2a1ddSDavid Wu static int rk3328_gmac2phy_set_parent(struct clk *clk, struct clk *parent)
1057*67a2a1ddSDavid Wu {
1058*67a2a1ddSDavid Wu struct rk3328_grf_regs *grf;
1059*67a2a1ddSDavid Wu const char *clock_output_name;
1060*67a2a1ddSDavid Wu int ret;
1061*67a2a1ddSDavid Wu
1062*67a2a1ddSDavid Wu grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
1063*67a2a1ddSDavid Wu
1064*67a2a1ddSDavid Wu /*
1065*67a2a1ddSDavid Wu * If the requested parent is in the same clock-controller and the id
1066*67a2a1ddSDavid Wu * is SCLK_MAC2PHY_SRC ("clk_mac2phy_src"), switch to the internal clock.
1067*67a2a1ddSDavid Wu */
1068*67a2a1ddSDavid Wu if ((parent->dev == clk->dev) && (parent->id == SCLK_MAC2PHY_SRC)) {
1069*67a2a1ddSDavid Wu debug("%s: switching MAC CLK to SCLK_MAC2IO_PHY\n", __func__);
1070*67a2a1ddSDavid Wu rk_clrreg(&grf->mac_con[2], BIT(10));
1071*67a2a1ddSDavid Wu return 0;
1072*67a2a1ddSDavid Wu }
1073*67a2a1ddSDavid Wu
1074*67a2a1ddSDavid Wu /*
1075*67a2a1ddSDavid Wu * Otherwise, we need to check the clock-output-names of the
1076*67a2a1ddSDavid Wu * requested parent to see if the requested id is "phy_50m_out".
1077*67a2a1ddSDavid Wu */
1078*67a2a1ddSDavid Wu ret = dev_read_string_index(parent->dev, "clock-output-names",
1079*67a2a1ddSDavid Wu parent->id, &clock_output_name);
1080*67a2a1ddSDavid Wu if (ret < 0)
1081*67a2a1ddSDavid Wu return -ENODATA;
1082*67a2a1ddSDavid Wu
1083*67a2a1ddSDavid Wu /* If this is "phy_50m_out", switch to the external clock input */
1084*67a2a1ddSDavid Wu if (!strcmp(clock_output_name, "phy_50m_out")) {
1085*67a2a1ddSDavid Wu debug("%s: switching MAC CLK to PHY_50M_OUT\n", __func__);
1086*67a2a1ddSDavid Wu rk_setreg(&grf->mac_con[2], BIT(10));
1087*67a2a1ddSDavid Wu return 0;
1088*67a2a1ddSDavid Wu }
1089*67a2a1ddSDavid Wu
1090*67a2a1ddSDavid Wu return -EINVAL;
1091*67a2a1ddSDavid Wu }
1092*67a2a1ddSDavid Wu
rk3328_lcdc_set_parent(struct clk * clk,struct clk * parent)10930b7db90fSElaine Zhang static int rk3328_lcdc_set_parent(struct clk *clk, struct clk *parent)
10940b7db90fSElaine Zhang {
10950b7db90fSElaine Zhang struct rk3328_clk_priv *priv = dev_get_priv(clk->dev);
10960b7db90fSElaine Zhang
10970b7db90fSElaine Zhang if (parent->id == HDMIPHY)
10980b7db90fSElaine Zhang rk_clrsetreg(&priv->cru->clksel_con[40],
10990b7db90fSElaine Zhang DCLK_LCDC_SEL_MASK,
11000b7db90fSElaine Zhang DCLK_LCDC_SEL_HDMIPHY << DCLK_LCDC_SEL_SHIFT);
11010b7db90fSElaine Zhang else if (parent->id == PLL_CPLL)
11020b7db90fSElaine Zhang rk_clrsetreg(&priv->cru->clksel_con[40],
11030b7db90fSElaine Zhang DCLK_LCDC_SEL_MASK | DCLK_LCDC_PLL_SEL_MASK,
11040b7db90fSElaine Zhang (DCLK_LCDC_SEL_PLL << DCLK_LCDC_SEL_SHIFT) |
11050b7db90fSElaine Zhang (DCLK_LCDC_PLL_SEL_CPLL <<
11060b7db90fSElaine Zhang DCLK_LCDC_PLL_SEL_SHIFT));
11070b7db90fSElaine Zhang else
11080b7db90fSElaine Zhang rk_clrsetreg(&priv->cru->clksel_con[40],
11090b7db90fSElaine Zhang DCLK_LCDC_SEL_MASK | DCLK_LCDC_PLL_SEL_MASK,
11100b7db90fSElaine Zhang (DCLK_LCDC_SEL_PLL << DCLK_LCDC_SEL_SHIFT) |
11110b7db90fSElaine Zhang (DCLK_LCDC_PLL_SEL_GPLL <<
11120b7db90fSElaine Zhang DCLK_LCDC_PLL_SEL_SHIFT));
11130b7db90fSElaine Zhang
11140b7db90fSElaine Zhang return 0;
11150b7db90fSElaine Zhang }
11160b7db90fSElaine Zhang #endif
11170b7db90fSElaine Zhang
rk3328_clk_set_parent(struct clk * clk,struct clk * parent)111807a48b3eSDavid Wu static int rk3328_clk_set_parent(struct clk *clk, struct clk *parent)
111907a48b3eSDavid Wu {
112007a48b3eSDavid Wu switch (clk->id) {
11210b7db90fSElaine Zhang #ifndef CONFIG_SPL_BUILD
112207a48b3eSDavid Wu case SCLK_MAC2IO:
112307a48b3eSDavid Wu return rk3328_gmac2io_set_parent(clk, parent);
112407a48b3eSDavid Wu case SCLK_MAC2IO_EXT:
112507a48b3eSDavid Wu return rk3328_gmac2io_ext_set_parent(clk, parent);
1126*67a2a1ddSDavid Wu case SCLK_MAC2PHY:
1127*67a2a1ddSDavid Wu return rk3328_gmac2phy_set_parent(clk, parent);
112807a48b3eSDavid Wu case DCLK_LCDC:
11290b7db90fSElaine Zhang return rk3328_lcdc_set_parent(clk, parent);
11300b7db90fSElaine Zhang #endif
113107a48b3eSDavid Wu case SCLK_PDM:
113207a48b3eSDavid Wu case SCLK_RTC32K:
113307a48b3eSDavid Wu case SCLK_UART0:
113407a48b3eSDavid Wu case SCLK_UART1:
113507a48b3eSDavid Wu case SCLK_UART2:
113607a48b3eSDavid Wu return 0;
113707a48b3eSDavid Wu }
113807a48b3eSDavid Wu
113907a48b3eSDavid Wu debug("%s: unsupported clk %ld\n", __func__, clk->id);
114007a48b3eSDavid Wu return -ENOENT;
114107a48b3eSDavid Wu }
114207a48b3eSDavid Wu
1143aa8c2987SElaine Zhang #define ROCKCHIP_MMC_DELAY_SEL BIT(10)
1144aa8c2987SElaine Zhang #define ROCKCHIP_MMC_DEGREE_MASK 0x3
1145aa8c2987SElaine Zhang #define ROCKCHIP_MMC_DELAYNUM_OFFSET 2
1146aa8c2987SElaine Zhang #define ROCKCHIP_MMC_DELAYNUM_MASK (0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET)
1147aa8c2987SElaine Zhang
1148aa8c2987SElaine Zhang #define PSECS_PER_SEC 1000000000000LL
1149aa8c2987SElaine Zhang /*
1150aa8c2987SElaine Zhang * Each fine delay is between 44ps-77ps. Assume each fine delay is 60ps to
1151aa8c2987SElaine Zhang * simplify calculations. So 45degs could be anywhere between 33deg and 57.8deg.
1152aa8c2987SElaine Zhang */
1153aa8c2987SElaine Zhang #define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60
1154aa8c2987SElaine Zhang
rk3328_mmc_get_phase(struct clk * clk)1155aa8c2987SElaine Zhang int rk3328_mmc_get_phase(struct clk *clk)
1156aa8c2987SElaine Zhang {
1157aa8c2987SElaine Zhang struct rk3328_clk_priv *priv = dev_get_priv(clk->dev);
1158aa8c2987SElaine Zhang struct rk3328_cru *cru = priv->cru;
1159aa8c2987SElaine Zhang u32 raw_value, delay_num;
1160aa8c2987SElaine Zhang u16 degrees = 0;
1161aa8c2987SElaine Zhang ulong rate;
1162aa8c2987SElaine Zhang
1163aa8c2987SElaine Zhang rate = rk3328_clk_get_rate(clk);
1164aa8c2987SElaine Zhang
1165aa8c2987SElaine Zhang if (rate < 0)
1166aa8c2987SElaine Zhang return rate;
1167aa8c2987SElaine Zhang
1168aa8c2987SElaine Zhang if (clk->id == SCLK_EMMC_SAMPLE)
1169aa8c2987SElaine Zhang raw_value = readl(&cru->emmc_con[1]);
1170aa8c2987SElaine Zhang else if (clk->id == SCLK_SDMMC_SAMPLE)
1171aa8c2987SElaine Zhang raw_value = readl(&cru->sdmmc_con[1]);
1172aa8c2987SElaine Zhang else
1173aa8c2987SElaine Zhang raw_value = readl(&cru->sdio_con[1]);
1174aa8c2987SElaine Zhang
1175aa8c2987SElaine Zhang raw_value >>= 1;
1176aa8c2987SElaine Zhang degrees = (raw_value & ROCKCHIP_MMC_DEGREE_MASK) * 90;
1177aa8c2987SElaine Zhang
1178aa8c2987SElaine Zhang if (raw_value & ROCKCHIP_MMC_DELAY_SEL) {
1179aa8c2987SElaine Zhang /* degrees/delaynum * 10000 */
1180aa8c2987SElaine Zhang unsigned long factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) *
1181aa8c2987SElaine Zhang 36 * (rate / 1000000);
1182aa8c2987SElaine Zhang
1183aa8c2987SElaine Zhang delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK);
1184aa8c2987SElaine Zhang delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET;
1185aa8c2987SElaine Zhang degrees += DIV_ROUND_CLOSEST(delay_num * factor, 10000);
1186aa8c2987SElaine Zhang }
1187aa8c2987SElaine Zhang
1188aa8c2987SElaine Zhang return degrees % 360;
1189aa8c2987SElaine Zhang }
1190aa8c2987SElaine Zhang
rk3328_mmc_set_phase(struct clk * clk,u32 degrees)1191aa8c2987SElaine Zhang int rk3328_mmc_set_phase(struct clk *clk, u32 degrees)
1192aa8c2987SElaine Zhang {
1193aa8c2987SElaine Zhang struct rk3328_clk_priv *priv = dev_get_priv(clk->dev);
1194aa8c2987SElaine Zhang struct rk3328_cru *cru = priv->cru;
1195aa8c2987SElaine Zhang u8 nineties, remainder, delay_num;
1196aa8c2987SElaine Zhang u32 raw_value, delay;
1197aa8c2987SElaine Zhang ulong rate;
1198aa8c2987SElaine Zhang
1199aa8c2987SElaine Zhang rate = rk3328_clk_get_rate(clk);
1200aa8c2987SElaine Zhang
1201aa8c2987SElaine Zhang if (rate < 0)
1202aa8c2987SElaine Zhang return rate;
1203aa8c2987SElaine Zhang
1204aa8c2987SElaine Zhang nineties = degrees / 90;
1205aa8c2987SElaine Zhang remainder = (degrees % 90);
1206aa8c2987SElaine Zhang
1207aa8c2987SElaine Zhang /*
1208aa8c2987SElaine Zhang * Convert to delay; do a little extra work to make sure we
1209aa8c2987SElaine Zhang * don't overflow 32-bit / 64-bit numbers.
1210aa8c2987SElaine Zhang */
1211aa8c2987SElaine Zhang delay = 10000000; /* PSECS_PER_SEC / 10000 / 10 */
1212aa8c2987SElaine Zhang delay *= remainder;
1213aa8c2987SElaine Zhang delay = DIV_ROUND_CLOSEST(delay, (rate / 1000) * 36 *
1214aa8c2987SElaine Zhang (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10));
1215aa8c2987SElaine Zhang
1216aa8c2987SElaine Zhang delay_num = (u8)min_t(u32, delay, 255);
1217aa8c2987SElaine Zhang
1218aa8c2987SElaine Zhang raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0;
1219aa8c2987SElaine Zhang raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET;
1220aa8c2987SElaine Zhang raw_value |= nineties;
1221aa8c2987SElaine Zhang
1222aa8c2987SElaine Zhang raw_value <<= 1;
1223aa8c2987SElaine Zhang if (clk->id == SCLK_EMMC_SAMPLE)
1224aa8c2987SElaine Zhang writel(raw_value | 0xffff0000, &cru->emmc_con[1]);
1225aa8c2987SElaine Zhang else if (clk->id == SCLK_SDMMC_SAMPLE)
1226aa8c2987SElaine Zhang writel(raw_value | 0xffff0000, &cru->sdmmc_con[1]);
1227aa8c2987SElaine Zhang else
1228aa8c2987SElaine Zhang writel(raw_value | 0xffff0000, &cru->sdio_con[1]);
1229aa8c2987SElaine Zhang
1230aa8c2987SElaine Zhang debug("mmc set_phase(%d) delay_nums=%u reg=%#x actual_degrees=%d\n",
1231aa8c2987SElaine Zhang degrees, delay_num, raw_value, rk3328_mmc_get_phase(clk));
1232aa8c2987SElaine Zhang
1233aa8c2987SElaine Zhang return 0;
1234aa8c2987SElaine Zhang }
1235aa8c2987SElaine Zhang
rk3328_clk_get_phase(struct clk * clk)1236aa8c2987SElaine Zhang static int rk3328_clk_get_phase(struct clk *clk)
1237aa8c2987SElaine Zhang {
1238aa8c2987SElaine Zhang int ret;
1239aa8c2987SElaine Zhang
1240aa8c2987SElaine Zhang debug("%s %ld\n", __func__, clk->id);
1241aa8c2987SElaine Zhang switch (clk->id) {
1242aa8c2987SElaine Zhang case SCLK_EMMC_SAMPLE:
1243aa8c2987SElaine Zhang case SCLK_SDMMC_SAMPLE:
1244aa8c2987SElaine Zhang case SCLK_SDIO_SAMPLE:
1245aa8c2987SElaine Zhang ret = rk3328_mmc_get_phase(clk);
1246aa8c2987SElaine Zhang break;
1247aa8c2987SElaine Zhang default:
1248aa8c2987SElaine Zhang return -ENOENT;
1249aa8c2987SElaine Zhang }
1250aa8c2987SElaine Zhang
1251aa8c2987SElaine Zhang return ret;
1252aa8c2987SElaine Zhang }
1253aa8c2987SElaine Zhang
rk3328_clk_set_phase(struct clk * clk,int degrees)1254aa8c2987SElaine Zhang static int rk3328_clk_set_phase(struct clk *clk, int degrees)
1255aa8c2987SElaine Zhang {
1256aa8c2987SElaine Zhang int ret;
1257aa8c2987SElaine Zhang
1258aa8c2987SElaine Zhang debug("%s %ld\n", __func__, clk->id);
1259aa8c2987SElaine Zhang switch (clk->id) {
1260aa8c2987SElaine Zhang case SCLK_EMMC_SAMPLE:
1261aa8c2987SElaine Zhang case SCLK_SDMMC_SAMPLE:
1262aa8c2987SElaine Zhang case SCLK_SDIO_SAMPLE:
1263aa8c2987SElaine Zhang ret = rk3328_mmc_set_phase(clk, degrees);
1264aa8c2987SElaine Zhang break;
1265aa8c2987SElaine Zhang default:
1266aa8c2987SElaine Zhang return -ENOENT;
1267aa8c2987SElaine Zhang }
1268aa8c2987SElaine Zhang
1269aa8c2987SElaine Zhang return ret;
1270aa8c2987SElaine Zhang }
1271aa8c2987SElaine Zhang
127241793000SKever Yang static struct clk_ops rk3328_clk_ops = {
127341793000SKever Yang .get_rate = rk3328_clk_get_rate,
127441793000SKever Yang .set_rate = rk3328_clk_set_rate,
127507a48b3eSDavid Wu .set_parent = rk3328_clk_set_parent,
1276aa8c2987SElaine Zhang .get_phase = rk3328_clk_get_phase,
1277aa8c2987SElaine Zhang .set_phase = rk3328_clk_set_phase,
127841793000SKever Yang };
127941793000SKever Yang
rkclk_init(struct rk3328_clk_priv * priv)12800b7db90fSElaine Zhang static void rkclk_init(struct rk3328_clk_priv *priv)
12810b7db90fSElaine Zhang {
12820b7db90fSElaine Zhang if (rockchip_pll_get_rate(&rk3328_pll_clks[NPLL],
12830b7db90fSElaine Zhang priv->cru, NPLL) != APLL_HZ)
12840b7db90fSElaine Zhang rk3328_armclk_set_clk(priv, APLL_HZ);
12850b7db90fSElaine Zhang
12868e2239d5SElaine Zhang priv->gpll_hz = rockchip_pll_get_rate(&rk3328_pll_clks[GPLL],
12878e2239d5SElaine Zhang priv->cru, GPLL);
12888e2239d5SElaine Zhang priv->cpll_hz = rockchip_pll_get_rate(&rk3328_pll_clks[CPLL],
12898e2239d5SElaine Zhang priv->cru, CPLL);
12908e2239d5SElaine Zhang
12918e2239d5SElaine Zhang /* before set pll set child div first */
12928e2239d5SElaine Zhang rk_clrsetreg(&priv->cru->clksel_con[24], (0x3f << 8) | (0x3f << 0),
12938e2239d5SElaine Zhang (0x17 << 8) | (0x17 << 0));
12948e2239d5SElaine Zhang rk_clrsetreg(&priv->cru->clksel_con[27], (0x1f << 8) | (0x1f << 0),
12958e2239d5SElaine Zhang (0x17 << 8) | (0x17 << 0));
12968e2239d5SElaine Zhang rk_clrsetreg(&priv->cru->clksel_con[31], 0xff << 0, 0xb << 0);
12978e2239d5SElaine Zhang rk_clrsetreg(&priv->cru->clksel_con[43], 0xff << 0, 0xb << 0);
12988e2239d5SElaine Zhang rk_clrsetreg(&priv->cru->clksel_con[52], 0x1f << 8, 0x5 << 8);
12998e2239d5SElaine Zhang
13000b7db90fSElaine Zhang rockchip_pll_set_rate(&rk3328_pll_clks[GPLL],
13010b7db90fSElaine Zhang priv->cru, GPLL, GPLL_HZ);
13020b7db90fSElaine Zhang priv->gpll_hz = GPLL_HZ;
13030b7db90fSElaine Zhang
13040b7db90fSElaine Zhang rockchip_pll_set_rate(&rk3328_pll_clks[CPLL],
13050b7db90fSElaine Zhang priv->cru, CPLL, CPLL_HZ);
13060b7db90fSElaine Zhang priv->cpll_hz = CPLL_HZ;
13070b7db90fSElaine Zhang
13080b7db90fSElaine Zhang rk3328_bus_set_clk(priv, ACLK_BUS_PRE, ACLK_BUS_HZ);
13090b7db90fSElaine Zhang rk3328_bus_set_clk(priv, HCLK_BUS_PRE, ACLK_BUS_HZ / 2);
13100b7db90fSElaine Zhang rk3328_bus_set_clk(priv, PCLK_BUS_PRE, ACLK_BUS_HZ / 2);
13110b7db90fSElaine Zhang rk3328_peri_set_clk(priv, ACLK_PERI_PRE, ACLK_PERI_HZ);
13120b7db90fSElaine Zhang rk3328_peri_set_clk(priv, HCLK_PERI, ACLK_PERI_HZ / 2);
13130b7db90fSElaine Zhang rk3328_peri_set_clk(priv, PCLK_PERI, ACLK_PERI_HZ / 2);
13140b7db90fSElaine Zhang /*rk3328_mmc_set_clk(priv, SCLK_EMMC, rate);*/
13150b7db90fSElaine Zhang
13160b7db90fSElaine Zhang /* set usbphy and hdmiphy from phy */
13170b7db90fSElaine Zhang rk_clrsetreg(&priv->cru->misc, (0x1 << 13) |
13180b7db90fSElaine Zhang (0x1 << 15), (0 << 15) | (0 << 13));
13190b7db90fSElaine Zhang }
13200b7db90fSElaine Zhang
rk3328_clk_probe(struct udevice * dev)132141793000SKever Yang static int rk3328_clk_probe(struct udevice *dev)
132241793000SKever Yang {
132341793000SKever Yang struct rk3328_clk_priv *priv = dev_get_priv(dev);
1324823ecf52SElaine Zhang int ret = 0;
132541793000SKever Yang
1326f7913bc1SElaine Zhang priv->sync_kernel = false;
1327f7913bc1SElaine Zhang if (!priv->armclk_enter_hz)
1328f7913bc1SElaine Zhang priv->armclk_enter_hz =
1329f7913bc1SElaine Zhang rockchip_pll_get_rate(&rk3328_pll_clks[NPLL],
1330f7913bc1SElaine Zhang priv->cru, NPLL);
13310b7db90fSElaine Zhang rkclk_init(priv);
1332f7913bc1SElaine Zhang if (!priv->armclk_init_hz)
1333f7913bc1SElaine Zhang priv->armclk_init_hz =
1334f7913bc1SElaine Zhang rockchip_pll_get_rate(&rk3328_pll_clks[NPLL],
1335f7913bc1SElaine Zhang priv->cru, NPLL);
133641793000SKever Yang
1337823ecf52SElaine Zhang ret = clk_set_defaults(dev);
1338823ecf52SElaine Zhang if (ret)
1339823ecf52SElaine Zhang debug("%s clk_set_defaults failed %d\n", __func__, ret);
1340f7913bc1SElaine Zhang else
1341f7913bc1SElaine Zhang priv->sync_kernel = true;
1342823ecf52SElaine Zhang
134341793000SKever Yang return 0;
134441793000SKever Yang }
134541793000SKever Yang
rk3328_clk_ofdata_to_platdata(struct udevice * dev)134641793000SKever Yang static int rk3328_clk_ofdata_to_platdata(struct udevice *dev)
134741793000SKever Yang {
134841793000SKever Yang struct rk3328_clk_priv *priv = dev_get_priv(dev);
134941793000SKever Yang
135005b226adSKever Yang priv->cru = dev_read_addr_ptr(dev);
135141793000SKever Yang
135241793000SKever Yang return 0;
135341793000SKever Yang }
135441793000SKever Yang
rk3328_clk_bind(struct udevice * dev)135541793000SKever Yang static int rk3328_clk_bind(struct udevice *dev)
135641793000SKever Yang {
135741793000SKever Yang int ret;
13583d555d75SElaine Zhang struct udevice *sys_child, *sf_child;
1359fbdd1558SKever Yang struct sysreset_reg *priv;
13603d555d75SElaine Zhang struct softreset_reg *sf_priv;
136141793000SKever Yang
136241793000SKever Yang /* The reset driver does not have a device node, so bind it here */
1363fbdd1558SKever Yang ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
1364fbdd1558SKever Yang &sys_child);
1365fbdd1558SKever Yang if (ret) {
1366fbdd1558SKever Yang debug("Warning: No sysreset driver: ret=%d\n", ret);
1367fbdd1558SKever Yang } else {
1368fbdd1558SKever Yang priv = malloc(sizeof(struct sysreset_reg));
1369fbdd1558SKever Yang priv->glb_srst_fst_value = offsetof(struct rk3328_cru,
1370fbdd1558SKever Yang glb_srst_fst_value);
1371fbdd1558SKever Yang priv->glb_srst_snd_value = offsetof(struct rk3328_cru,
1372fbdd1558SKever Yang glb_srst_snd_value);
1373fbdd1558SKever Yang sys_child->priv = priv;
1374fbdd1558SKever Yang }
137541793000SKever Yang
13763d555d75SElaine Zhang ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset",
13773d555d75SElaine Zhang dev_ofnode(dev), &sf_child);
13783d555d75SElaine Zhang if (ret) {
13793d555d75SElaine Zhang debug("Warning: No rockchip reset driver: ret=%d\n", ret);
13803d555d75SElaine Zhang } else {
13813d555d75SElaine Zhang sf_priv = malloc(sizeof(struct softreset_reg));
13823d555d75SElaine Zhang sf_priv->sf_reset_offset = offsetof(struct rk3328_cru,
13833d555d75SElaine Zhang softrst_con[0]);
13843d555d75SElaine Zhang sf_priv->sf_reset_num = 12;
13853d555d75SElaine Zhang sf_child->priv = sf_priv;
13863d555d75SElaine Zhang }
13873d555d75SElaine Zhang
1388692e3bb1SKever Yang return 0;
138941793000SKever Yang }
139041793000SKever Yang
139141793000SKever Yang static const struct udevice_id rk3328_clk_ids[] = {
139241793000SKever Yang { .compatible = "rockchip,rk3328-cru" },
139341793000SKever Yang { }
139441793000SKever Yang };
139541793000SKever Yang
139641793000SKever Yang U_BOOT_DRIVER(rockchip_rk3328_cru) = {
139741793000SKever Yang .name = "rockchip_rk3328_cru",
139841793000SKever Yang .id = UCLASS_CLK,
139941793000SKever Yang .of_match = rk3328_clk_ids,
140041793000SKever Yang .priv_auto_alloc_size = sizeof(struct rk3328_clk_priv),
140141793000SKever Yang .ofdata_to_platdata = rk3328_clk_ofdata_to_platdata,
140241793000SKever Yang .ops = &rk3328_clk_ops,
140341793000SKever Yang .bind = rk3328_clk_bind,
140441793000SKever Yang .probe = rk3328_clk_probe,
140541793000SKever Yang };
14060b7db90fSElaine Zhang
14070b7db90fSElaine Zhang #ifndef CONFIG_SPL_BUILD
14080b7db90fSElaine Zhang /**
14090b7db90fSElaine Zhang * soc_clk_dump() - Print clock frequencies
14100b7db90fSElaine Zhang * Returns zero on success
14110b7db90fSElaine Zhang *
14120b7db90fSElaine Zhang * Implementation for the clk dump command.
14130b7db90fSElaine Zhang */
soc_clk_dump(void)14140b7db90fSElaine Zhang int soc_clk_dump(void)
14150b7db90fSElaine Zhang {
14160b7db90fSElaine Zhang struct udevice *cru_dev;
1417f7913bc1SElaine Zhang struct rk3328_clk_priv *priv;
14180b7db90fSElaine Zhang const struct rk3328_clk_info *clk_dump;
14190b7db90fSElaine Zhang struct clk clk;
14200b7db90fSElaine Zhang unsigned long clk_count = ARRAY_SIZE(clks_dump);
14210b7db90fSElaine Zhang unsigned long rate;
14220b7db90fSElaine Zhang int i, ret;
14230b7db90fSElaine Zhang
14240b7db90fSElaine Zhang ret = uclass_get_device_by_driver(UCLASS_CLK,
14250b7db90fSElaine Zhang DM_GET_DRIVER(rockchip_rk3328_cru),
14260b7db90fSElaine Zhang &cru_dev);
14270b7db90fSElaine Zhang if (ret) {
14280b7db90fSElaine Zhang printf("%s failed to get cru device\n", __func__);
14290b7db90fSElaine Zhang return ret;
14300b7db90fSElaine Zhang }
14310b7db90fSElaine Zhang
1432f7913bc1SElaine Zhang priv = dev_get_priv(cru_dev);
1433f7913bc1SElaine Zhang printf("CLK: (%s. arm: enter %lu KHz, init %lu KHz, kernel %lu%s)\n",
1434f7913bc1SElaine Zhang priv->sync_kernel ? "sync kernel" : "uboot",
1435f7913bc1SElaine Zhang priv->armclk_enter_hz / 1000,
1436f7913bc1SElaine Zhang priv->armclk_init_hz / 1000,
1437f7913bc1SElaine Zhang priv->set_armclk_rate ? priv->armclk_hz / 1000 : 0,
1438f7913bc1SElaine Zhang priv->set_armclk_rate ? " KHz" : "N/A");
14390b7db90fSElaine Zhang for (i = 0; i < clk_count; i++) {
14400b7db90fSElaine Zhang clk_dump = &clks_dump[i];
14410b7db90fSElaine Zhang if (clk_dump->name) {
14420b7db90fSElaine Zhang clk.id = clk_dump->id;
14430b7db90fSElaine Zhang if (clk_dump->is_cru)
14440b7db90fSElaine Zhang ret = clk_request(cru_dev, &clk);
14450b7db90fSElaine Zhang if (ret < 0)
14460b7db90fSElaine Zhang return ret;
14470b7db90fSElaine Zhang
14480b7db90fSElaine Zhang rate = clk_get_rate(&clk);
14490b7db90fSElaine Zhang clk_free(&clk);
14500b7db90fSElaine Zhang if (i == 0) {
14510b7db90fSElaine Zhang if (rate < 0)
1452f7913bc1SElaine Zhang printf(" %s %s\n", clk_dump->name,
14530b7db90fSElaine Zhang "unknown");
14540b7db90fSElaine Zhang else
1455f7913bc1SElaine Zhang printf(" %s %lu KHz\n", clk_dump->name,
1456f7913bc1SElaine Zhang rate / 1000);
14570b7db90fSElaine Zhang } else {
14580b7db90fSElaine Zhang if (rate < 0)
1459f7913bc1SElaine Zhang printf(" %s %s\n", clk_dump->name,
14600b7db90fSElaine Zhang "unknown");
14610b7db90fSElaine Zhang else
1462f7913bc1SElaine Zhang printf(" %s %lu KHz\n", clk_dump->name,
1463f7913bc1SElaine Zhang rate / 1000);
14640b7db90fSElaine Zhang }
14650b7db90fSElaine Zhang }
14660b7db90fSElaine Zhang }
14670b7db90fSElaine Zhang
14680b7db90fSElaine Zhang return 0;
14690b7db90fSElaine Zhang }
14700b7db90fSElaine Zhang #endif
1471