14931c6fbSPaweł Jarosz /*
24931c6fbSPaweł Jarosz * (C) Copyright 2015 Google, Inc
34931c6fbSPaweł Jarosz * (C) Copyright 2016 Heiko Stuebner <heiko@sntech.de>
44931c6fbSPaweł Jarosz *
54931c6fbSPaweł Jarosz * SPDX-License-Identifier: GPL-2.0
64931c6fbSPaweł Jarosz */
74931c6fbSPaweł Jarosz
84931c6fbSPaweł Jarosz #include <common.h>
94931c6fbSPaweł Jarosz #include <clk-uclass.h>
104931c6fbSPaweł Jarosz #include <dm.h>
114931c6fbSPaweł Jarosz #include <dt-structs.h>
124931c6fbSPaweł Jarosz #include <errno.h>
134931c6fbSPaweł Jarosz #include <mapmem.h>
144931c6fbSPaweł Jarosz #include <syscon.h>
154931c6fbSPaweł Jarosz #include <asm/io.h>
164931c6fbSPaweł Jarosz #include <asm/arch/clock.h>
174931c6fbSPaweł Jarosz #include <asm/arch/cru_rk3066.h>
184931c6fbSPaweł Jarosz #include <asm/arch/grf_rk3066.h>
194931c6fbSPaweł Jarosz #include <asm/arch/hardware.h>
204931c6fbSPaweł Jarosz #include <dt-bindings/clock/rk3066a-cru.h>
214931c6fbSPaweł Jarosz #include <dm/device-internal.h>
224931c6fbSPaweł Jarosz #include <dm/lists.h>
234931c6fbSPaweł Jarosz #include <dm/uclass-internal.h>
244931c6fbSPaweł Jarosz #include <linux/log2.h>
254931c6fbSPaweł Jarosz
264931c6fbSPaweł Jarosz DECLARE_GLOBAL_DATA_PTR;
274931c6fbSPaweł Jarosz
284931c6fbSPaweł Jarosz enum rk3066_clk_type {
294931c6fbSPaweł Jarosz RK3066_CRU,
304931c6fbSPaweł Jarosz RK3066A_CRU,
314931c6fbSPaweł Jarosz };
324931c6fbSPaweł Jarosz
334931c6fbSPaweł Jarosz struct rk3066_clk_plat {
344931c6fbSPaweł Jarosz #if CONFIG_IS_ENABLED(OF_PLATDATA)
354931c6fbSPaweł Jarosz struct dtd_rockchip_rk3066a_cru dtd;
364931c6fbSPaweł Jarosz #endif
374931c6fbSPaweł Jarosz };
384931c6fbSPaweł Jarosz
39524f2646SElaine Zhang #ifndef CONFIG_SPL_BUILD
40524f2646SElaine Zhang #define RK3066_CLK_DUMP(_id, _name, _iscru) \
41524f2646SElaine Zhang { \
42524f2646SElaine Zhang .id = _id, \
43524f2646SElaine Zhang .name = _name, \
44524f2646SElaine Zhang .is_cru = _iscru, \
45524f2646SElaine Zhang }
46524f2646SElaine Zhang
47524f2646SElaine Zhang static const struct rk3066_clk_info clks_dump[] = {
48524f2646SElaine Zhang RK3066_CLK_DUMP(PLL_APLL, "apll", true),
49524f2646SElaine Zhang RK3066_CLK_DUMP(PLL_DPLL, "dpll", true),
50524f2646SElaine Zhang RK3066_CLK_DUMP(PLL_GPLL, "gpll", true),
51524f2646SElaine Zhang RK3066_CLK_DUMP(PLL_CPLL, "cpll", true),
52524f2646SElaine Zhang };
53524f2646SElaine Zhang #endif
54524f2646SElaine Zhang
554931c6fbSPaweł Jarosz struct pll_div {
564931c6fbSPaweł Jarosz u32 nr;
574931c6fbSPaweł Jarosz u32 nf;
584931c6fbSPaweł Jarosz u32 no;
594931c6fbSPaweł Jarosz };
604931c6fbSPaweł Jarosz
614931c6fbSPaweł Jarosz enum {
624931c6fbSPaweł Jarosz VCO_MAX_HZ = 1416U * 1000000,
634931c6fbSPaweł Jarosz VCO_MIN_HZ = 300 * 1000000,
644931c6fbSPaweł Jarosz OUTPUT_MAX_HZ = 1416U * 1000000,
654931c6fbSPaweł Jarosz OUTPUT_MIN_HZ = 30 * 1000000,
664931c6fbSPaweł Jarosz FREF_MAX_HZ = 1416U * 1000000,
674931c6fbSPaweł Jarosz FREF_MIN_HZ = 30 * 1000,
684931c6fbSPaweł Jarosz };
694931c6fbSPaweł Jarosz
704931c6fbSPaweł Jarosz enum {
714931c6fbSPaweł Jarosz /* PLL CON0 */
724931c6fbSPaweł Jarosz PLL_OD_MASK = 0x0f,
734931c6fbSPaweł Jarosz
744931c6fbSPaweł Jarosz /* PLL CON1 */
754931c6fbSPaweł Jarosz PLL_NF_MASK = 0x1fff,
764931c6fbSPaweł Jarosz
774931c6fbSPaweł Jarosz /* PLL CON2 */
784931c6fbSPaweł Jarosz PLL_BWADJ_MASK = 0x0fff,
794931c6fbSPaweł Jarosz
804931c6fbSPaweł Jarosz /* PLL CON3 */
814931c6fbSPaweł Jarosz PLL_RESET_SHIFT = 5,
824931c6fbSPaweł Jarosz
834931c6fbSPaweł Jarosz /* GRF_SOC_STATUS0 */
844931c6fbSPaweł Jarosz SOCSTS_DPLL_LOCK = 1 << 4,
854931c6fbSPaweł Jarosz SOCSTS_APLL_LOCK = 1 << 5,
864931c6fbSPaweł Jarosz SOCSTS_CPLL_LOCK = 1 << 6,
874931c6fbSPaweł Jarosz SOCSTS_GPLL_LOCK = 1 << 7,
884931c6fbSPaweł Jarosz };
894931c6fbSPaweł Jarosz
904931c6fbSPaweł Jarosz #define RATE_TO_DIV(input_rate, output_rate) \
914931c6fbSPaweł Jarosz ((input_rate) / (output_rate) - 1);
924931c6fbSPaweł Jarosz
934931c6fbSPaweł Jarosz #define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1))
944931c6fbSPaweł Jarosz
954931c6fbSPaweł Jarosz #define PLL_DIVISORS(hz, _nr, _no) {\
964931c6fbSPaweł Jarosz .nr = _nr, .nf = (u32)((u64)hz * _nr * _no / OSC_HZ), .no = _no};\
974931c6fbSPaweł Jarosz _Static_assert(((u64)hz * _nr * _no / OSC_HZ) * OSC_HZ /\
984931c6fbSPaweł Jarosz (_nr * _no) == hz, #hz "Hz cannot be hit with PLL "\
994931c6fbSPaweł Jarosz "divisors on line " __stringify(__LINE__));
1004931c6fbSPaweł Jarosz
1014931c6fbSPaweł Jarosz /* Keep divisors as low as possible to reduce jitter and power usage */
1024931c6fbSPaweł Jarosz #ifdef CONFIG_TPL_BUILD
1034931c6fbSPaweł Jarosz static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 2, 2);
1044931c6fbSPaweł Jarosz static const struct pll_div cpll_init_cfg = PLL_DIVISORS(CPLL_HZ, 1, 2);
1054931c6fbSPaweł Jarosz #endif
1064931c6fbSPaweł Jarosz
rkclk_set_pll(struct rk3066_cru * cru,enum rk_clk_id clk_id,const struct pll_div * div,bool has_bwadj)1074931c6fbSPaweł Jarosz static int rkclk_set_pll(struct rk3066_cru *cru, enum rk_clk_id clk_id,
1084931c6fbSPaweł Jarosz const struct pll_div *div, bool has_bwadj)
1094931c6fbSPaweł Jarosz {
1104931c6fbSPaweł Jarosz int pll_id = rk_pll_id(clk_id);
1114931c6fbSPaweł Jarosz struct rk3066_pll *pll = &cru->pll[pll_id];
1124931c6fbSPaweł Jarosz /* All PLLs have same VCO and output frequency range restrictions. */
1134931c6fbSPaweł Jarosz uint vco_hz = OSC_HZ / 1000 * div->nf / div->nr * 1000;
1144931c6fbSPaweł Jarosz uint output_hz = vco_hz / div->no;
1154931c6fbSPaweł Jarosz
1164931c6fbSPaweł Jarosz debug("PLL at %x: nf=%d, nr=%d, no=%d, vco=%u Hz, output=%u Hz\n",
1174931c6fbSPaweł Jarosz (uint)pll, div->nf, div->nr, div->no, vco_hz, output_hz);
1184931c6fbSPaweł Jarosz assert(vco_hz >= VCO_MIN_HZ && vco_hz <= VCO_MAX_HZ &&
1194931c6fbSPaweł Jarosz output_hz >= OUTPUT_MIN_HZ && output_hz <= OUTPUT_MAX_HZ &&
1204931c6fbSPaweł Jarosz (div->no == 1 || !(div->no % 2)));
1214931c6fbSPaweł Jarosz
1224931c6fbSPaweł Jarosz /* enter reset */
1234931c6fbSPaweł Jarosz rk_setreg(&pll->con3, 1 << PLL_RESET_SHIFT);
1244931c6fbSPaweł Jarosz
1254931c6fbSPaweł Jarosz rk_clrsetreg(&pll->con0,
1264931c6fbSPaweł Jarosz CLKR_MASK | PLL_OD_MASK,
1274931c6fbSPaweł Jarosz ((div->nr - 1) << CLKR_SHIFT) | (div->no - 1));
1284931c6fbSPaweł Jarosz rk_clrsetreg(&pll->con1, CLKF_MASK, div->nf - 1);
1294931c6fbSPaweł Jarosz
1304931c6fbSPaweł Jarosz if (has_bwadj)
1314931c6fbSPaweł Jarosz rk_clrsetreg(&pll->con2, PLL_BWADJ_MASK, (div->nf >> 1) - 1);
1324931c6fbSPaweł Jarosz
1334931c6fbSPaweł Jarosz udelay(10);
1344931c6fbSPaweł Jarosz
1354931c6fbSPaweł Jarosz /* return from reset */
1364931c6fbSPaweł Jarosz rk_clrreg(&pll->con3, 1 << PLL_RESET_SHIFT);
1374931c6fbSPaweł Jarosz
1384931c6fbSPaweł Jarosz return 0;
1394931c6fbSPaweł Jarosz }
1404931c6fbSPaweł Jarosz
rkclk_configure_ddr(struct rk3066_cru * cru,struct rk3066_grf * grf,unsigned int hz,bool has_bwadj)1414931c6fbSPaweł Jarosz static int rkclk_configure_ddr(struct rk3066_cru *cru, struct rk3066_grf *grf,
1424931c6fbSPaweł Jarosz unsigned int hz, bool has_bwadj)
1434931c6fbSPaweł Jarosz {
1444931c6fbSPaweł Jarosz static const struct pll_div dpll_cfg[] = {
1454931c6fbSPaweł Jarosz {.nf = 25, .nr = 2, .no = 1},
1464931c6fbSPaweł Jarosz {.nf = 400, .nr = 9, .no = 2},
1474931c6fbSPaweł Jarosz {.nf = 500, .nr = 9, .no = 2},
1484931c6fbSPaweł Jarosz {.nf = 100, .nr = 3, .no = 1},
1494931c6fbSPaweł Jarosz };
1504931c6fbSPaweł Jarosz int cfg;
1514931c6fbSPaweł Jarosz
1524931c6fbSPaweł Jarosz switch (hz) {
1534931c6fbSPaweł Jarosz case 300000000:
1544931c6fbSPaweł Jarosz cfg = 0;
1554931c6fbSPaweł Jarosz break;
1564931c6fbSPaweł Jarosz case 533000000: /* actually 533.3P MHz */
1574931c6fbSPaweł Jarosz cfg = 1;
1584931c6fbSPaweł Jarosz break;
1594931c6fbSPaweł Jarosz case 666000000: /* actually 666.6P MHz */
1604931c6fbSPaweł Jarosz cfg = 2;
1614931c6fbSPaweł Jarosz break;
1624931c6fbSPaweł Jarosz case 800000000:
1634931c6fbSPaweł Jarosz cfg = 3;
1644931c6fbSPaweł Jarosz break;
1654931c6fbSPaweł Jarosz default:
1664931c6fbSPaweł Jarosz debug("Unsupported SDRAM frequency");
1674931c6fbSPaweł Jarosz return -EINVAL;
1684931c6fbSPaweł Jarosz }
1694931c6fbSPaweł Jarosz
1704931c6fbSPaweł Jarosz /* pll enter slow-mode */
1714931c6fbSPaweł Jarosz rk_clrsetreg(&cru->cru_mode_con, DPLL_MODE_MASK,
1724931c6fbSPaweł Jarosz DPLL_MODE_SLOW << DPLL_MODE_SHIFT);
1734931c6fbSPaweł Jarosz
1744931c6fbSPaweł Jarosz rkclk_set_pll(cru, CLK_DDR, &dpll_cfg[cfg], has_bwadj);
1754931c6fbSPaweł Jarosz
1764931c6fbSPaweł Jarosz /* wait for pll lock */
1774931c6fbSPaweł Jarosz while (!(readl(&grf->soc_status0) & SOCSTS_DPLL_LOCK))
1784931c6fbSPaweł Jarosz udelay(1);
1794931c6fbSPaweł Jarosz
1804931c6fbSPaweł Jarosz /* PLL enter normal-mode */
1814931c6fbSPaweł Jarosz rk_clrsetreg(&cru->cru_mode_con, DPLL_MODE_MASK,
1824931c6fbSPaweł Jarosz DPLL_MODE_NORMAL << DPLL_MODE_SHIFT);
1834931c6fbSPaweł Jarosz
1844931c6fbSPaweł Jarosz return 0;
1854931c6fbSPaweł Jarosz }
1864931c6fbSPaweł Jarosz
rkclk_configure_cpu(struct rk3066_cru * cru,struct rk3066_grf * grf,unsigned int hz,bool has_bwadj)1874931c6fbSPaweł Jarosz static int rkclk_configure_cpu(struct rk3066_cru *cru, struct rk3066_grf *grf,
1884931c6fbSPaweł Jarosz unsigned int hz, bool has_bwadj)
1894931c6fbSPaweł Jarosz {
1904931c6fbSPaweł Jarosz static const struct pll_div apll_cfg[] = {
1914931c6fbSPaweł Jarosz {.nf = 50, .nr = 1, .no = 2},
1924931c6fbSPaweł Jarosz {.nf = 59, .nr = 1, .no = 1},
1934931c6fbSPaweł Jarosz };
1944931c6fbSPaweł Jarosz int div_core_peri, div_aclk_core, cfg;
1954931c6fbSPaweł Jarosz
1964931c6fbSPaweł Jarosz /*
1974931c6fbSPaweł Jarosz * We support two possible frequencies, the safe 600MHz
1984931c6fbSPaweł Jarosz * which will work with default pmic settings and will
1994931c6fbSPaweł Jarosz * be set to get away from the 24MHz default and
2004931c6fbSPaweł Jarosz * the maximum of 1.416Ghz, which boards can set if they
2014931c6fbSPaweł Jarosz * were able to get pmic support for it.
2024931c6fbSPaweł Jarosz */
2034931c6fbSPaweł Jarosz switch (hz) {
2044931c6fbSPaweł Jarosz case APLL_SAFE_HZ:
2054931c6fbSPaweł Jarosz cfg = 0;
2064931c6fbSPaweł Jarosz div_core_peri = 1;
2074931c6fbSPaweł Jarosz div_aclk_core = 3;
2084931c6fbSPaweł Jarosz break;
2094931c6fbSPaweł Jarosz case APLL_HZ:
2104931c6fbSPaweł Jarosz cfg = 1;
2114931c6fbSPaweł Jarosz div_core_peri = 2;
2124931c6fbSPaweł Jarosz div_aclk_core = 3;
2134931c6fbSPaweł Jarosz break;
2144931c6fbSPaweł Jarosz default:
2154931c6fbSPaweł Jarosz debug("Unsupported ARMCLK frequency");
2164931c6fbSPaweł Jarosz return -EINVAL;
2174931c6fbSPaweł Jarosz }
2184931c6fbSPaweł Jarosz
2194931c6fbSPaweł Jarosz /* pll enter slow-mode */
2204931c6fbSPaweł Jarosz rk_clrsetreg(&cru->cru_mode_con, APLL_MODE_MASK,
2214931c6fbSPaweł Jarosz APLL_MODE_SLOW << APLL_MODE_SHIFT);
2224931c6fbSPaweł Jarosz
2234931c6fbSPaweł Jarosz rkclk_set_pll(cru, CLK_ARM, &apll_cfg[cfg], has_bwadj);
2244931c6fbSPaweł Jarosz
2254931c6fbSPaweł Jarosz /* waiting for pll lock */
2264931c6fbSPaweł Jarosz while (!(readl(&grf->soc_status0) & SOCSTS_APLL_LOCK))
2274931c6fbSPaweł Jarosz udelay(1);
2284931c6fbSPaweł Jarosz
2294931c6fbSPaweł Jarosz /* Set divider for peripherals attached to the cpu core. */
2304931c6fbSPaweł Jarosz rk_clrsetreg(&cru->cru_clksel_con[0],
2314931c6fbSPaweł Jarosz CORE_PERI_DIV_MASK,
2324931c6fbSPaweł Jarosz div_core_peri << CORE_PERI_DIV_SHIFT);
2334931c6fbSPaweł Jarosz
2344931c6fbSPaweł Jarosz /* set up dependent divisor for aclk_core */
2354931c6fbSPaweł Jarosz rk_clrsetreg(&cru->cru_clksel_con[1],
2364931c6fbSPaweł Jarosz CORE_ACLK_DIV_MASK,
2374931c6fbSPaweł Jarosz div_aclk_core << CORE_ACLK_DIV_SHIFT);
2384931c6fbSPaweł Jarosz
2394931c6fbSPaweł Jarosz /* PLL enter normal-mode */
2404931c6fbSPaweł Jarosz rk_clrsetreg(&cru->cru_mode_con, APLL_MODE_MASK,
2414931c6fbSPaweł Jarosz APLL_MODE_NORMAL << APLL_MODE_SHIFT);
2424931c6fbSPaweł Jarosz
2434931c6fbSPaweł Jarosz return hz;
2444931c6fbSPaweł Jarosz }
2454931c6fbSPaweł Jarosz
2464931c6fbSPaweł Jarosz /* Get pll rate by id */
rkclk_pll_get_rate(struct rk3066_cru * cru,enum rk_clk_id clk_id)2474931c6fbSPaweł Jarosz static uint32_t rkclk_pll_get_rate(struct rk3066_cru *cru,
2484931c6fbSPaweł Jarosz enum rk_clk_id clk_id)
2494931c6fbSPaweł Jarosz {
2504931c6fbSPaweł Jarosz uint32_t nr, no, nf;
2514931c6fbSPaweł Jarosz uint32_t con;
2524931c6fbSPaweł Jarosz int pll_id = rk_pll_id(clk_id);
2534931c6fbSPaweł Jarosz struct rk3066_pll *pll = &cru->pll[pll_id];
2544931c6fbSPaweł Jarosz static u8 clk_shift[CLK_COUNT] = {
2554931c6fbSPaweł Jarosz 0xff, APLL_MODE_SHIFT, DPLL_MODE_SHIFT, CPLL_MODE_SHIFT,
2564931c6fbSPaweł Jarosz GPLL_MODE_SHIFT
2574931c6fbSPaweł Jarosz };
2584931c6fbSPaweł Jarosz uint shift;
2594931c6fbSPaweł Jarosz
2604931c6fbSPaweł Jarosz con = readl(&cru->cru_mode_con);
2614931c6fbSPaweł Jarosz shift = clk_shift[clk_id];
2624931c6fbSPaweł Jarosz switch ((con >> shift) & APLL_MODE_MASK >> APLL_MODE_SHIFT) {
2634931c6fbSPaweł Jarosz case APLL_MODE_SLOW:
2644931c6fbSPaweł Jarosz return OSC_HZ;
2654931c6fbSPaweł Jarosz case APLL_MODE_NORMAL:
2664931c6fbSPaweł Jarosz /* normal mode */
2674931c6fbSPaweł Jarosz con = readl(&pll->con0);
2684931c6fbSPaweł Jarosz no = ((con >> CLKOD_SHIFT) & (CLKOD_MASK >> CLKOD_SHIFT)) + 1;
2694931c6fbSPaweł Jarosz nr = ((con >> CLKR_SHIFT) & (CLKR_MASK >> CLKR_SHIFT)) + 1;
2704931c6fbSPaweł Jarosz con = readl(&pll->con1);
2714931c6fbSPaweł Jarosz nf = ((con >> CLKF_SHIFT) & (CLKF_MASK >> CLKF_SHIFT)) + 1;
2724931c6fbSPaweł Jarosz
2734931c6fbSPaweł Jarosz return (24 * nf / (nr * no)) * 1000000;
2744931c6fbSPaweł Jarosz case APLL_MODE_DEEP:
2754931c6fbSPaweł Jarosz default:
2764931c6fbSPaweł Jarosz return 32768;
2774931c6fbSPaweł Jarosz }
2784931c6fbSPaweł Jarosz }
2794931c6fbSPaweł Jarosz
rockchip_mmc_get_clk(struct rk3066_cru * cru,uint gclk_rate,int periph)2804931c6fbSPaweł Jarosz static ulong rockchip_mmc_get_clk(struct rk3066_cru *cru, uint gclk_rate,
2814931c6fbSPaweł Jarosz int periph)
2824931c6fbSPaweł Jarosz {
2834931c6fbSPaweł Jarosz uint div;
2844931c6fbSPaweł Jarosz u32 con;
2854931c6fbSPaweł Jarosz
2864931c6fbSPaweł Jarosz switch (periph) {
2874931c6fbSPaweł Jarosz case HCLK_EMMC:
2884931c6fbSPaweł Jarosz con = readl(&cru->cru_clksel_con[12]);
2894931c6fbSPaweł Jarosz div = (con >> EMMC_DIV_SHIFT) & EMMC_DIV_MASK >> EMMC_DIV_SHIFT;
2904931c6fbSPaweł Jarosz break;
2914931c6fbSPaweł Jarosz case HCLK_SDMMC:
2924931c6fbSPaweł Jarosz con = readl(&cru->cru_clksel_con[11]);
2934931c6fbSPaweł Jarosz div = (con >> MMC0_DIV_SHIFT) & MMC0_DIV_MASK >> MMC0_DIV_SHIFT;
2944931c6fbSPaweł Jarosz break;
2954931c6fbSPaweł Jarosz case HCLK_SDIO:
2964931c6fbSPaweł Jarosz con = readl(&cru->cru_clksel_con[12]);
2974931c6fbSPaweł Jarosz div = (con >> SDIO_DIV_SHIFT) & SDIO_DIV_MASK >> SDIO_DIV_SHIFT;
2984931c6fbSPaweł Jarosz break;
2994931c6fbSPaweł Jarosz default:
3004931c6fbSPaweł Jarosz return -EINVAL;
3014931c6fbSPaweł Jarosz }
3024931c6fbSPaweł Jarosz
3034931c6fbSPaweł Jarosz return DIV_TO_RATE(gclk_rate, div);
3044931c6fbSPaweł Jarosz }
3054931c6fbSPaweł Jarosz
rockchip_mmc_set_clk(struct rk3066_cru * cru,uint gclk_rate,int periph,uint freq)3064931c6fbSPaweł Jarosz static ulong rockchip_mmc_set_clk(struct rk3066_cru *cru, uint gclk_rate,
3074931c6fbSPaweł Jarosz int periph, uint freq)
3084931c6fbSPaweł Jarosz {
3094931c6fbSPaweł Jarosz int src_clk_div;
3104931c6fbSPaweł Jarosz
3114931c6fbSPaweł Jarosz debug("%s: gclk_rate=%u\n", __func__, gclk_rate);
3124931c6fbSPaweł Jarosz src_clk_div = RATE_TO_DIV(gclk_rate, freq);
3134931c6fbSPaweł Jarosz if (src_clk_div > 0x3f)
3144931c6fbSPaweł Jarosz src_clk_div = 0x3f;
3154931c6fbSPaweł Jarosz
3164931c6fbSPaweł Jarosz switch (periph) {
3174931c6fbSPaweł Jarosz case HCLK_EMMC:
3184931c6fbSPaweł Jarosz rk_clrsetreg(&cru->cru_clksel_con[12],
3194931c6fbSPaweł Jarosz EMMC_DIV_MASK,
3204931c6fbSPaweł Jarosz src_clk_div << EMMC_DIV_SHIFT);
3214931c6fbSPaweł Jarosz break;
3224931c6fbSPaweł Jarosz case HCLK_SDMMC:
3234931c6fbSPaweł Jarosz rk_clrsetreg(&cru->cru_clksel_con[11],
3244931c6fbSPaweł Jarosz MMC0_DIV_MASK,
3254931c6fbSPaweł Jarosz src_clk_div << MMC0_DIV_SHIFT);
3264931c6fbSPaweł Jarosz break;
3274931c6fbSPaweł Jarosz case HCLK_SDIO:
3284931c6fbSPaweł Jarosz rk_clrsetreg(&cru->cru_clksel_con[12],
3294931c6fbSPaweł Jarosz SDIO_DIV_MASK,
3304931c6fbSPaweł Jarosz src_clk_div << SDIO_DIV_SHIFT);
3314931c6fbSPaweł Jarosz break;
3324931c6fbSPaweł Jarosz default:
3334931c6fbSPaweł Jarosz return -EINVAL;
3344931c6fbSPaweł Jarosz }
3354931c6fbSPaweł Jarosz
3364931c6fbSPaweł Jarosz return rockchip_mmc_get_clk(cru, gclk_rate, periph);
3374931c6fbSPaweł Jarosz }
3384931c6fbSPaweł Jarosz
rockchip_spi_get_clk(struct rk3066_cru * cru,uint gclk_rate,int periph)3394931c6fbSPaweł Jarosz static ulong rockchip_spi_get_clk(struct rk3066_cru *cru, uint gclk_rate,
3404931c6fbSPaweł Jarosz int periph)
3414931c6fbSPaweł Jarosz {
3424931c6fbSPaweł Jarosz uint div;
3434931c6fbSPaweł Jarosz u32 con;
3444931c6fbSPaweł Jarosz
3454931c6fbSPaweł Jarosz switch (periph) {
3464931c6fbSPaweł Jarosz case SCLK_SPI0:
3474931c6fbSPaweł Jarosz con = readl(&cru->cru_clksel_con[25]);
3484931c6fbSPaweł Jarosz div = (con >> SPI0_DIV_SHIFT) & SPI0_DIV_MASK >> SPI0_DIV_SHIFT;
3494931c6fbSPaweł Jarosz break;
3504931c6fbSPaweł Jarosz case SCLK_SPI1:
3514931c6fbSPaweł Jarosz con = readl(&cru->cru_clksel_con[25]);
3524931c6fbSPaweł Jarosz div = (con >> SPI1_DIV_SHIFT) & SPI1_DIV_MASK >> SPI1_DIV_SHIFT;
3534931c6fbSPaweł Jarosz break;
3544931c6fbSPaweł Jarosz default:
3554931c6fbSPaweł Jarosz return -EINVAL;
3564931c6fbSPaweł Jarosz }
3574931c6fbSPaweł Jarosz
3584931c6fbSPaweł Jarosz return DIV_TO_RATE(gclk_rate, div);
3594931c6fbSPaweł Jarosz }
3604931c6fbSPaweł Jarosz
rockchip_spi_set_clk(struct rk3066_cru * cru,uint gclk_rate,int periph,uint freq)3614931c6fbSPaweł Jarosz static ulong rockchip_spi_set_clk(struct rk3066_cru *cru, uint gclk_rate,
3624931c6fbSPaweł Jarosz int periph, uint freq)
3634931c6fbSPaweł Jarosz {
3644931c6fbSPaweł Jarosz int src_clk_div = RATE_TO_DIV(gclk_rate, freq);
3654931c6fbSPaweł Jarosz
3664931c6fbSPaweł Jarosz switch (periph) {
3674931c6fbSPaweł Jarosz case SCLK_SPI0:
3684931c6fbSPaweł Jarosz assert(src_clk_div <= SPI0_DIV_MASK >> SPI0_DIV_SHIFT);
3694931c6fbSPaweł Jarosz rk_clrsetreg(&cru->cru_clksel_con[25],
3704931c6fbSPaweł Jarosz SPI0_DIV_MASK,
3714931c6fbSPaweł Jarosz src_clk_div << SPI0_DIV_SHIFT);
3724931c6fbSPaweł Jarosz break;
3734931c6fbSPaweł Jarosz case SCLK_SPI1:
3744931c6fbSPaweł Jarosz assert(src_clk_div <= SPI1_DIV_MASK >> SPI1_DIV_SHIFT);
3754931c6fbSPaweł Jarosz rk_clrsetreg(&cru->cru_clksel_con[25],
3764931c6fbSPaweł Jarosz SPI1_DIV_MASK,
3774931c6fbSPaweł Jarosz src_clk_div << SPI1_DIV_SHIFT);
3784931c6fbSPaweł Jarosz break;
3794931c6fbSPaweł Jarosz default:
3804931c6fbSPaweł Jarosz return -EINVAL;
3814931c6fbSPaweł Jarosz }
3824931c6fbSPaweł Jarosz
3834931c6fbSPaweł Jarosz return rockchip_spi_get_clk(cru, gclk_rate, periph);
3844931c6fbSPaweł Jarosz }
3854931c6fbSPaweł Jarosz #ifdef CONFIG_TPL_BUILD
rkclk_init(struct rk3066_cru * cru,struct rk3066_grf * grf,bool has_bwadj)3864931c6fbSPaweł Jarosz static void rkclk_init(struct rk3066_cru *cru, struct rk3066_grf *grf,
3874931c6fbSPaweł Jarosz bool has_bwadj)
3884931c6fbSPaweł Jarosz {
3894931c6fbSPaweł Jarosz u32 aclk_div, hclk_div, pclk_div, h2p_div;
3904931c6fbSPaweł Jarosz
3914931c6fbSPaweł Jarosz /* pll enter slow-mode */
3924931c6fbSPaweł Jarosz rk_clrsetreg(&cru->cru_mode_con,
3934931c6fbSPaweł Jarosz GPLL_MODE_MASK |
3944931c6fbSPaweł Jarosz CPLL_MODE_MASK,
3954931c6fbSPaweł Jarosz GPLL_MODE_SLOW << GPLL_MODE_SHIFT |
3964931c6fbSPaweł Jarosz CPLL_MODE_SLOW << CPLL_MODE_SHIFT);
3974931c6fbSPaweł Jarosz
3984931c6fbSPaweł Jarosz /* init pll */
3994931c6fbSPaweł Jarosz rkclk_set_pll(cru, CLK_GENERAL, &gpll_init_cfg, has_bwadj);
4004931c6fbSPaweł Jarosz rkclk_set_pll(cru, CLK_CODEC, &cpll_init_cfg, has_bwadj);
4014931c6fbSPaweł Jarosz
4024931c6fbSPaweł Jarosz /* waiting for pll lock */
4034931c6fbSPaweł Jarosz while ((readl(&grf->soc_status0) &
4044931c6fbSPaweł Jarosz (SOCSTS_CPLL_LOCK | SOCSTS_GPLL_LOCK)) !=
4054931c6fbSPaweł Jarosz (SOCSTS_CPLL_LOCK | SOCSTS_GPLL_LOCK))
4064931c6fbSPaweł Jarosz udelay(1);
4074931c6fbSPaweł Jarosz
4084931c6fbSPaweł Jarosz /*
4094931c6fbSPaweł Jarosz * cpu clock pll source selection and
4104931c6fbSPaweł Jarosz * reparent aclk_cpu_pre from apll to gpll
4114931c6fbSPaweł Jarosz * set up dependent divisors for PCLK/HCLK and ACLK clocks.
4124931c6fbSPaweł Jarosz */
4134931c6fbSPaweł Jarosz aclk_div = RATE_TO_DIV(GPLL_HZ, CPU_ACLK_HZ);
414*27b00bb2SElaine Zhang assert((aclk_div + 1) * CPU_ACLK_HZ <= GPLL_HZ && aclk_div < 0x1f);
4154931c6fbSPaweł Jarosz
4164931c6fbSPaweł Jarosz rk_clrsetreg(&cru->cru_clksel_con[0],
4174931c6fbSPaweł Jarosz CPU_ACLK_PLL_MASK |
4184931c6fbSPaweł Jarosz A9_CPU_DIV_MASK,
4194931c6fbSPaweł Jarosz CPU_ACLK_PLL_SELECT_GPLL << CPU_ACLK_PLL_SHIFT |
4204931c6fbSPaweł Jarosz aclk_div << A9_CPU_DIV_SHIFT);
4214931c6fbSPaweł Jarosz
4224931c6fbSPaweł Jarosz hclk_div = ilog2(CPU_ACLK_HZ / CPU_HCLK_HZ);
423*27b00bb2SElaine Zhang assert((1 << hclk_div) * CPU_HCLK_HZ <= CPU_ACLK_HZ && hclk_div < 0x3);
4244931c6fbSPaweł Jarosz pclk_div = ilog2(CPU_ACLK_HZ / CPU_PCLK_HZ);
425*27b00bb2SElaine Zhang assert((1 << pclk_div) * CPU_PCLK_HZ <= CPU_ACLK_HZ && pclk_div < 0x4);
4264931c6fbSPaweł Jarosz h2p_div = ilog2(CPU_HCLK_HZ / CPU_H2P_HZ);
427*27b00bb2SElaine Zhang assert((1 << h2p_div) * CPU_H2P_HZ <= CPU_HCLK_HZ && pclk_div < 0x3);
4284931c6fbSPaweł Jarosz
4294931c6fbSPaweł Jarosz rk_clrsetreg(&cru->cru_clksel_con[1],
4304931c6fbSPaweł Jarosz AHB2APB_DIV_MASK |
4314931c6fbSPaweł Jarosz CPU_PCLK_DIV_MASK |
4324931c6fbSPaweł Jarosz CPU_HCLK_DIV_MASK,
4334931c6fbSPaweł Jarosz h2p_div << AHB2APB_DIV_SHIFT |
4344931c6fbSPaweł Jarosz pclk_div << CPU_PCLK_DIV_SHIFT |
4354931c6fbSPaweł Jarosz hclk_div << CPU_HCLK_DIV_SHIFT);
4364931c6fbSPaweł Jarosz
4374931c6fbSPaweł Jarosz /*
4384931c6fbSPaweł Jarosz * peri clock pll source selection and
4394931c6fbSPaweł Jarosz * set up dependent divisors for PCLK/HCLK and ACLK clocks.
4404931c6fbSPaweł Jarosz */
4414931c6fbSPaweł Jarosz aclk_div = GPLL_HZ / PERI_ACLK_HZ - 1;
442*27b00bb2SElaine Zhang assert((aclk_div + 1) * PERI_ACLK_HZ <= GPLL_HZ && aclk_div < 0x1f);
4434931c6fbSPaweł Jarosz
4444931c6fbSPaweł Jarosz hclk_div = ilog2(PERI_ACLK_HZ / PERI_HCLK_HZ);
445*27b00bb2SElaine Zhang assert((1 << hclk_div) * PERI_HCLK_HZ <=
4464931c6fbSPaweł Jarosz PERI_ACLK_HZ && (hclk_div < 0x4));
4474931c6fbSPaweł Jarosz
4484931c6fbSPaweł Jarosz pclk_div = ilog2(PERI_ACLK_HZ / PERI_PCLK_HZ);
449*27b00bb2SElaine Zhang assert((1 << pclk_div) * PERI_PCLK_HZ <=
4504931c6fbSPaweł Jarosz PERI_ACLK_HZ && (pclk_div < 0x4));
4514931c6fbSPaweł Jarosz
4524931c6fbSPaweł Jarosz rk_clrsetreg(&cru->cru_clksel_con[10],
4534931c6fbSPaweł Jarosz PERI_PCLK_DIV_MASK |
4544931c6fbSPaweł Jarosz PERI_HCLK_DIV_MASK |
4554931c6fbSPaweł Jarosz PERI_ACLK_DIV_MASK,
4564931c6fbSPaweł Jarosz PERI_SEL_GPLL << PERI_SEL_PLL_SHIFT |
4574931c6fbSPaweł Jarosz pclk_div << PERI_PCLK_DIV_SHIFT |
4584931c6fbSPaweł Jarosz hclk_div << PERI_HCLK_DIV_SHIFT |
4594931c6fbSPaweł Jarosz aclk_div << PERI_ACLK_DIV_SHIFT);
4604931c6fbSPaweł Jarosz
4614931c6fbSPaweł Jarosz /* PLL enter normal-mode */
4624931c6fbSPaweł Jarosz rk_clrsetreg(&cru->cru_mode_con,
4634931c6fbSPaweł Jarosz GPLL_MODE_MASK |
4644931c6fbSPaweł Jarosz CPLL_MODE_MASK,
4654931c6fbSPaweł Jarosz GPLL_MODE_NORMAL << GPLL_MODE_SHIFT |
4664931c6fbSPaweł Jarosz CPLL_MODE_NORMAL << CPLL_MODE_SHIFT);
4674931c6fbSPaweł Jarosz
4684931c6fbSPaweł Jarosz rockchip_mmc_set_clk(cru, PERI_HCLK_HZ, HCLK_SDMMC, 16000000);
4694931c6fbSPaweł Jarosz }
4704931c6fbSPaweł Jarosz #endif
4714931c6fbSPaweł Jarosz
rk3066_clk_get_rate(struct clk * clk)4724931c6fbSPaweł Jarosz static ulong rk3066_clk_get_rate(struct clk *clk)
4734931c6fbSPaweł Jarosz {
4744931c6fbSPaweł Jarosz struct rk3066_clk_priv *priv = dev_get_priv(clk->dev);
4754931c6fbSPaweł Jarosz ulong new_rate, gclk_rate;
4764931c6fbSPaweł Jarosz
4774931c6fbSPaweł Jarosz gclk_rate = rkclk_pll_get_rate(priv->cru, CLK_GENERAL);
4784931c6fbSPaweł Jarosz switch (clk->id) {
4794931c6fbSPaweł Jarosz case 1 ... 4:
4804931c6fbSPaweł Jarosz new_rate = rkclk_pll_get_rate(priv->cru, clk->id);
4814931c6fbSPaweł Jarosz break;
4824931c6fbSPaweł Jarosz case HCLK_EMMC:
4834931c6fbSPaweł Jarosz case HCLK_SDMMC:
4844931c6fbSPaweł Jarosz case HCLK_SDIO:
4854931c6fbSPaweł Jarosz new_rate = rockchip_mmc_get_clk(priv->cru, PERI_HCLK_HZ,
4864931c6fbSPaweł Jarosz clk->id);
4874931c6fbSPaweł Jarosz break;
4884931c6fbSPaweł Jarosz case SCLK_SPI0:
4894931c6fbSPaweł Jarosz case SCLK_SPI1:
4904931c6fbSPaweł Jarosz new_rate = rockchip_spi_get_clk(priv->cru, PERI_PCLK_HZ,
4914931c6fbSPaweł Jarosz clk->id);
4924931c6fbSPaweł Jarosz break;
4934931c6fbSPaweł Jarosz case PCLK_I2C0:
4944931c6fbSPaweł Jarosz case PCLK_I2C1:
4954931c6fbSPaweł Jarosz case PCLK_I2C2:
4964931c6fbSPaweł Jarosz case PCLK_I2C3:
4974931c6fbSPaweł Jarosz case PCLK_I2C4:
4984931c6fbSPaweł Jarosz return gclk_rate;
4994931c6fbSPaweł Jarosz default:
5004931c6fbSPaweł Jarosz return -ENOENT;
5014931c6fbSPaweł Jarosz }
5024931c6fbSPaweł Jarosz
5034931c6fbSPaweł Jarosz return new_rate;
5044931c6fbSPaweł Jarosz }
5054931c6fbSPaweł Jarosz
rk3066_clk_set_rate(struct clk * clk,ulong rate)5064931c6fbSPaweł Jarosz static ulong rk3066_clk_set_rate(struct clk *clk, ulong rate)
5074931c6fbSPaweł Jarosz {
5084931c6fbSPaweł Jarosz struct rk3066_clk_priv *priv = dev_get_priv(clk->dev);
5094931c6fbSPaweł Jarosz struct rk3066_cru *cru = priv->cru;
5104931c6fbSPaweł Jarosz ulong new_rate;
5114931c6fbSPaweł Jarosz
5124931c6fbSPaweł Jarosz switch (clk->id) {
5134931c6fbSPaweł Jarosz case PLL_APLL:
5144931c6fbSPaweł Jarosz new_rate = rkclk_configure_cpu(priv->cru, priv->grf, rate,
5154931c6fbSPaweł Jarosz priv->has_bwadj);
5164931c6fbSPaweł Jarosz break;
5174931c6fbSPaweł Jarosz case CLK_DDR:
5184931c6fbSPaweł Jarosz new_rate = rkclk_configure_ddr(priv->cru, priv->grf, rate,
5194931c6fbSPaweł Jarosz priv->has_bwadj);
5204931c6fbSPaweł Jarosz break;
5214931c6fbSPaweł Jarosz case HCLK_EMMC:
5224931c6fbSPaweł Jarosz case HCLK_SDMMC:
5234931c6fbSPaweł Jarosz case HCLK_SDIO:
5244931c6fbSPaweł Jarosz new_rate = rockchip_mmc_set_clk(cru, PERI_HCLK_HZ,
5254931c6fbSPaweł Jarosz clk->id, rate);
5264931c6fbSPaweł Jarosz break;
5274931c6fbSPaweł Jarosz case SCLK_SPI0:
5284931c6fbSPaweł Jarosz case SCLK_SPI1:
5294931c6fbSPaweł Jarosz new_rate = rockchip_spi_set_clk(cru, PERI_PCLK_HZ,
5304931c6fbSPaweł Jarosz clk->id, rate);
5314931c6fbSPaweł Jarosz break;
5324931c6fbSPaweł Jarosz default:
5334931c6fbSPaweł Jarosz return -ENOENT;
5344931c6fbSPaweł Jarosz }
5354931c6fbSPaweł Jarosz
5364931c6fbSPaweł Jarosz return new_rate;
5374931c6fbSPaweł Jarosz }
5384931c6fbSPaweł Jarosz
5394931c6fbSPaweł Jarosz static struct clk_ops rk3066_clk_ops = {
5404931c6fbSPaweł Jarosz .get_rate = rk3066_clk_get_rate,
5414931c6fbSPaweł Jarosz .set_rate = rk3066_clk_set_rate,
5424931c6fbSPaweł Jarosz };
5434931c6fbSPaweł Jarosz
rk3066_clk_ofdata_to_platdata(struct udevice * dev)5444931c6fbSPaweł Jarosz static int rk3066_clk_ofdata_to_platdata(struct udevice *dev)
5454931c6fbSPaweł Jarosz {
5464931c6fbSPaweł Jarosz #if !CONFIG_IS_ENABLED(OF_PLATDATA)
5474931c6fbSPaweł Jarosz struct rk3066_clk_priv *priv = dev_get_priv(dev);
5484931c6fbSPaweł Jarosz
54911143e9cSKever Yang priv->cru = dev_read_addr_ptr(dev);
5504931c6fbSPaweł Jarosz #endif
5514931c6fbSPaweł Jarosz
5524931c6fbSPaweł Jarosz return 0;
5534931c6fbSPaweł Jarosz }
5544931c6fbSPaweł Jarosz
rk3066_clk_probe(struct udevice * dev)5554931c6fbSPaweł Jarosz static int rk3066_clk_probe(struct udevice *dev)
5564931c6fbSPaweł Jarosz {
5574931c6fbSPaweł Jarosz struct rk3066_clk_priv *priv = dev_get_priv(dev);
5584931c6fbSPaweł Jarosz
5594931c6fbSPaweł Jarosz priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
5604931c6fbSPaweł Jarosz if (IS_ERR(priv->grf))
5614931c6fbSPaweł Jarosz return PTR_ERR(priv->grf);
5624931c6fbSPaweł Jarosz
5634931c6fbSPaweł Jarosz #ifdef CONFIG_TPL_BUILD
5644931c6fbSPaweł Jarosz #if CONFIG_IS_ENABLED(OF_PLATDATA)
5654931c6fbSPaweł Jarosz struct rk3066_clk_plat *plat = dev_get_platdata(dev);
5664931c6fbSPaweł Jarosz
5674931c6fbSPaweł Jarosz priv->cru = map_sysmem(plat->dtd.reg[0], plat->dtd.reg[1]);
5684931c6fbSPaweł Jarosz #endif
569524f2646SElaine Zhang priv->sync_kernel = false;
570524f2646SElaine Zhang if (!priv->armclk_enter_hz)
571524f2646SElaine Zhang priv->armclk_enter_hz = rkclk_pll_get_rate(priv->cru,
572524f2646SElaine Zhang CLK_ARM);
5734931c6fbSPaweł Jarosz rkclk_init(priv->cru, priv->grf, 1);
574524f2646SElaine Zhang if (!priv->armclk_init_hz)
575524f2646SElaine Zhang priv->armclk_init_hz = rkclk_pll_get_rate(priv->cru,
576524f2646SElaine Zhang CLK_ARM);
5774931c6fbSPaweł Jarosz #endif
5784931c6fbSPaweł Jarosz return 0;
5794931c6fbSPaweł Jarosz }
5804931c6fbSPaweł Jarosz
rk3066_clk_bind(struct udevice * dev)5814931c6fbSPaweł Jarosz static int rk3066_clk_bind(struct udevice *dev)
5824931c6fbSPaweł Jarosz {
5834931c6fbSPaweł Jarosz int ret;
5844931c6fbSPaweł Jarosz struct udevice *sys_child, *sf_child;
5854931c6fbSPaweł Jarosz struct sysreset_reg *priv;
5864931c6fbSPaweł Jarosz struct softreset_reg *sf_priv;
5874931c6fbSPaweł Jarosz
5884931c6fbSPaweł Jarosz /* The reset driver does not have a device node, so bind it here */
5894931c6fbSPaweł Jarosz ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
5904931c6fbSPaweł Jarosz &sys_child);
5914931c6fbSPaweł Jarosz if (ret) {
5924931c6fbSPaweł Jarosz debug("Warning: No sysreset driver: ret=%d\n", ret);
5934931c6fbSPaweł Jarosz } else {
5944931c6fbSPaweł Jarosz priv = malloc(sizeof(struct sysreset_reg));
5954931c6fbSPaweł Jarosz priv->glb_srst_fst_value = offsetof(struct rk3066_cru,
5964931c6fbSPaweł Jarosz cru_glb_srst_fst_value);
5974931c6fbSPaweł Jarosz priv->glb_srst_snd_value = offsetof(struct rk3066_cru,
5984931c6fbSPaweł Jarosz cru_glb_srst_snd_value);
5994931c6fbSPaweł Jarosz sys_child->priv = priv;
6004931c6fbSPaweł Jarosz }
6014931c6fbSPaweł Jarosz
6024931c6fbSPaweł Jarosz ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset",
6034931c6fbSPaweł Jarosz dev_ofnode(dev), &sf_child);
6044931c6fbSPaweł Jarosz if (ret) {
6054931c6fbSPaweł Jarosz debug("Warning: No rockchip reset driver: ret=%d\n", ret);
6064931c6fbSPaweł Jarosz } else {
6074931c6fbSPaweł Jarosz sf_priv = malloc(sizeof(struct softreset_reg));
6084931c6fbSPaweł Jarosz sf_priv->sf_reset_offset = offsetof(struct rk3066_cru,
6094931c6fbSPaweł Jarosz cru_softrst_con[0]);
6104931c6fbSPaweł Jarosz sf_priv->sf_reset_num = 9;
6114931c6fbSPaweł Jarosz sf_child->priv = sf_priv;
6124931c6fbSPaweł Jarosz }
6134931c6fbSPaweł Jarosz
6144931c6fbSPaweł Jarosz return 0;
6154931c6fbSPaweł Jarosz }
6164931c6fbSPaweł Jarosz
6174931c6fbSPaweł Jarosz static const struct udevice_id rk3066_clk_ids[] = {
6184931c6fbSPaweł Jarosz { .compatible = "rockchip,rk3066a-cru" },
6194931c6fbSPaweł Jarosz { }
6204931c6fbSPaweł Jarosz };
6214931c6fbSPaweł Jarosz
6224931c6fbSPaweł Jarosz U_BOOT_DRIVER(rockchip_rk3066a_cru) = {
6234931c6fbSPaweł Jarosz .name = "rockchip_rk3066a_cru",
6244931c6fbSPaweł Jarosz .id = UCLASS_CLK,
6254931c6fbSPaweł Jarosz .of_match = rk3066_clk_ids,
6264931c6fbSPaweł Jarosz .priv_auto_alloc_size = sizeof(struct rk3066_clk_priv),
6274931c6fbSPaweł Jarosz .platdata_auto_alloc_size = sizeof(struct rk3066_clk_plat),
6284931c6fbSPaweł Jarosz .ops = &rk3066_clk_ops,
6294931c6fbSPaweł Jarosz .bind = rk3066_clk_bind,
6304931c6fbSPaweł Jarosz .ofdata_to_platdata = rk3066_clk_ofdata_to_platdata,
6314931c6fbSPaweł Jarosz .probe = rk3066_clk_probe,
6324931c6fbSPaweł Jarosz };
633524f2646SElaine Zhang
634524f2646SElaine Zhang #ifndef CONFIG_SPL_BUILD
635524f2646SElaine Zhang /**
636524f2646SElaine Zhang * soc_clk_dump() - Print clock frequencies
637524f2646SElaine Zhang * Returns zero on success
638524f2646SElaine Zhang *
639524f2646SElaine Zhang * Implementation for the clk dump command.
640524f2646SElaine Zhang */
soc_clk_dump(void)641524f2646SElaine Zhang int soc_clk_dump(void)
642524f2646SElaine Zhang {
643524f2646SElaine Zhang struct udevice *cru_dev;
644524f2646SElaine Zhang struct rk3066_clk_priv *priv;
645524f2646SElaine Zhang const struct rk3066_clk_info *clk_dump;
646524f2646SElaine Zhang struct clk clk;
647524f2646SElaine Zhang unsigned long clk_count = ARRAY_SIZE(clks_dump);
648524f2646SElaine Zhang unsigned long rate;
649524f2646SElaine Zhang int i, ret;
650524f2646SElaine Zhang
651524f2646SElaine Zhang ret = uclass_get_device_by_driver(UCLASS_CLK,
652524f2646SElaine Zhang DM_GET_DRIVER(rockchip_rk3066a_cru),
653524f2646SElaine Zhang &cru_dev);
654524f2646SElaine Zhang if (ret) {
655524f2646SElaine Zhang printf("%s failed to get cru device\n", __func__);
656524f2646SElaine Zhang return ret;
657524f2646SElaine Zhang }
658524f2646SElaine Zhang
659524f2646SElaine Zhang priv = dev_get_priv(cru_dev);
660524f2646SElaine Zhang printf("CLK: (%s. arm: enter %lu KHz, init %lu KHz, kernel %lu%s)\n",
661524f2646SElaine Zhang priv->sync_kernel ? "sync kernel" : "uboot",
662524f2646SElaine Zhang priv->armclk_enter_hz / 1000,
663524f2646SElaine Zhang priv->armclk_init_hz / 1000,
664524f2646SElaine Zhang priv->set_armclk_rate ? priv->armclk_hz / 1000 : 0,
665524f2646SElaine Zhang priv->set_armclk_rate ? " KHz" : "N/A");
666524f2646SElaine Zhang for (i = 0; i < clk_count; i++) {
667524f2646SElaine Zhang clk_dump = &clks_dump[i];
668524f2646SElaine Zhang if (clk_dump->name) {
669524f2646SElaine Zhang clk.id = clk_dump->id;
670524f2646SElaine Zhang if (clk_dump->is_cru)
671524f2646SElaine Zhang ret = clk_request(cru_dev, &clk);
672524f2646SElaine Zhang if (ret < 0)
673524f2646SElaine Zhang return ret;
674524f2646SElaine Zhang
675524f2646SElaine Zhang rate = clk_get_rate(&clk);
676524f2646SElaine Zhang clk_free(&clk);
677524f2646SElaine Zhang if (i == 0) {
678524f2646SElaine Zhang if (rate < 0)
679524f2646SElaine Zhang printf(" %s %s\n", clk_dump->name,
680524f2646SElaine Zhang "unknown");
681524f2646SElaine Zhang else
682524f2646SElaine Zhang printf(" %s %lu KHz\n", clk_dump->name,
683524f2646SElaine Zhang rate / 1000);
684524f2646SElaine Zhang } else {
685524f2646SElaine Zhang if (rate < 0)
686524f2646SElaine Zhang printf(" %s %s\n", clk_dump->name,
687524f2646SElaine Zhang "unknown");
688524f2646SElaine Zhang else
689524f2646SElaine Zhang printf(" %s %lu KHz\n", clk_dump->name,
690524f2646SElaine Zhang rate / 1000);
691524f2646SElaine Zhang }
692524f2646SElaine Zhang }
693524f2646SElaine Zhang }
694524f2646SElaine Zhang
695524f2646SElaine Zhang return 0;
696524f2646SElaine Zhang }
697524f2646SElaine Zhang #endif
698524f2646SElaine Zhang
699