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