Merge branch 'master' of git://git.denx.de/u-boot
[oweals/u-boot.git] / drivers / clk / rockchip / clk_rk3399.c
index 2e85ac7df2ce2980841b5b9a2439e78a289b89f7..d822acace14be9ba955c96f1c484e14ee0e8137f 100644 (file)
@@ -1,8 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * (C) Copyright 2015 Google, Inc
  * (C) 2017 Theobroma Systems Design und Consulting GmbH
- *
- * SPDX-License-Identifier:    GPL-2.0
  */
 
 #include <common.h>
 #include <dm.h>
 #include <dt-structs.h>
 #include <errno.h>
+#include <malloc.h>
 #include <mapmem.h>
 #include <syscon.h>
 #include <bitfield.h>
 #include <asm/io.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/cru_rk3399.h>
-#include <asm/arch/hardware.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/cru.h>
+#include <asm/arch-rockchip/hardware.h>
 #include <dm/lists.h>
 #include <dt-bindings/clock/rk3399-cru.h>
 
-DECLARE_GLOBAL_DATA_PTR;
-
 #if CONFIG_IS_ENABLED(OF_PLATDATA)
 struct rk3399_clk_plat {
        struct dtd_rockchip_rk3399_cru dtd;
@@ -41,8 +39,8 @@ struct pll_div {
 };
 
 #define RATE_TO_DIV(input_rate, output_rate) \
-       ((input_rate) / (output_rate) - 1);
-#define DIV_TO_RATE(input_rate, div)    ((input_rate) / ((div) + 1))
+       ((input_rate) / (output_rate) - 1)
+#define DIV_TO_RATE(input_rate, div)           ((input_rate) / ((div) + 1))
 
 #define PLL_DIVISORS(hz, _refdiv, _postdiv1, _postdiv2) {\
        .refdiv = _refdiv,\
@@ -56,14 +54,19 @@ static const struct pll_div cpll_init_cfg = PLL_DIVISORS(CPLL_HZ, 1, 2, 2);
 static const struct pll_div ppll_init_cfg = PLL_DIVISORS(PPLL_HZ, 2, 2, 1);
 #endif
 
-static const struct pll_div apll_l_1600_cfg = PLL_DIVISORS(1600*MHz, 3, 1, 1);
-static const struct pll_div apll_l_600_cfg = PLL_DIVISORS(600*MHz, 1, 2, 1);
+static const struct pll_div apll_l_1600_cfg = PLL_DIVISORS(1600 * MHz, 3, 1, 1);
+static const struct pll_div apll_l_600_cfg = PLL_DIVISORS(600 * MHz, 1, 2, 1);
 
 static const struct pll_div *apll_l_cfgs[] = {
        [APLL_L_1600_MHZ] = &apll_l_1600_cfg,
        [APLL_L_600_MHZ] = &apll_l_600_cfg,
 };
 
+static const struct pll_div apll_b_600_cfg = PLL_DIVISORS(600 * MHz, 1, 2, 1);
+static const struct pll_div *apll_b_cfgs[] = {
+       [APLL_B_600_MHZ] = &apll_b_600_cfg,
+};
+
 enum {
        /* PLL_CON0 */
        PLL_FBDIV_MASK                  = 0xfff,
@@ -131,6 +134,24 @@ enum {
        ATCLK_CORE_L_DIV_SHIFT          = 0,
        ATCLK_CORE_L_DIV_MASK           = 0x1f << ATCLK_CORE_L_DIV_SHIFT,
 
+       /* CLKSEL_CON2 */
+       ACLKM_CORE_B_DIV_CON_SHIFT      = 8,
+       ACLKM_CORE_B_DIV_CON_MASK       = 0x1f << ACLKM_CORE_B_DIV_CON_SHIFT,
+       CLK_CORE_B_PLL_SEL_SHIFT        = 6,
+       CLK_CORE_B_PLL_SEL_MASK         = 3 << CLK_CORE_B_PLL_SEL_SHIFT,
+       CLK_CORE_B_PLL_SEL_ALPLL        = 0x0,
+       CLK_CORE_B_PLL_SEL_ABPLL        = 0x1,
+       CLK_CORE_B_PLL_SEL_DPLL         = 0x10,
+       CLK_CORE_B_PLL_SEL_GPLL         = 0x11,
+       CLK_CORE_B_DIV_MASK             = 0x1f,
+       CLK_CORE_B_DIV_SHIFT            = 0,
+
+       /* CLKSEL_CON3 */
+       PCLK_DBG_B_DIV_SHIFT            = 0x8,
+       PCLK_DBG_B_DIV_MASK             = 0x1f << PCLK_DBG_B_DIV_SHIFT,
+       ATCLK_CORE_B_DIV_SHIFT          = 0,
+       ATCLK_CORE_B_DIV_MASK           = 0x1f << ATCLK_CORE_B_DIV_SHIFT,
+
        /* CLKSEL_CON14 */
        PCLK_PERIHP_DIV_CON_SHIFT       = 12,
        PCLK_PERIHP_DIV_CON_MASK        = 0x7 << PCLK_PERIHP_DIV_CON_SHIFT,
@@ -373,7 +394,7 @@ static int pll_para_config(u32 freq_hz, struct pll_div *div)
                fref_khz = ref_khz / refdiv;
 
                fbdiv = vco_khz / fref_khz;
-               if ((fbdiv >= max_fbdiv) || (fbdiv <= min_fbdiv))
+               if (fbdiv >= max_fbdiv || fbdiv <= min_fbdiv)
                        continue;
                diff_khz = vco_khz - fbdiv * fref_khz;
                if (fbdiv + 1 < max_fbdiv && diff_khz > fref_khz / 2) {
@@ -389,7 +410,7 @@ static int pll_para_config(u32 freq_hz, struct pll_div *div)
                div->fbdiv = fbdiv;
        }
 
-       if (best_diff_khz > 4 * (MHz/KHz)) {
+       if (best_diff_khz > 4 * (MHz / KHz)) {
                printf("%s: Failed to match output frequency %u, "
                       "difference is %u Hz,exceed 4MHZ\n", __func__, freq_hz,
                       best_diff_khz * KHz);
@@ -398,25 +419,26 @@ static int pll_para_config(u32 freq_hz, struct pll_div *div)
        return 0;
 }
 
-void rk3399_configure_cpu(struct rk3399_cru *cru,
-                         enum apll_l_frequencies apll_l_freq)
+void rk3399_configure_cpu_l(struct rockchip_cru *cru,
+                           enum apll_l_frequencies apll_l_freq)
 {
        u32 aclkm_div;
        u32 pclk_dbg_div;
        u32 atclk_div;
 
+       /* Setup cluster L */
        rkclk_set_pll(&cru->apll_l_con[0], apll_l_cfgs[apll_l_freq]);
 
-       aclkm_div = APLL_HZ / ACLKM_CORE_HZ - 1;
-       assert((aclkm_div + 1) * ACLKM_CORE_HZ == APLL_HZ &&
+       aclkm_div = LPLL_HZ / ACLKM_CORE_L_HZ - 1;
+       assert((aclkm_div + 1) * ACLKM_CORE_L_HZ == LPLL_HZ &&
               aclkm_div < 0x1f);
 
-       pclk_dbg_div = APLL_HZ / PCLK_DBG_HZ - 1;
-       assert((pclk_dbg_div + 1) * PCLK_DBG_HZ == APLL_HZ &&
+       pclk_dbg_div = LPLL_HZ / PCLK_DBG_L_HZ - 1;
+       assert((pclk_dbg_div + 1) * PCLK_DBG_L_HZ == LPLL_HZ &&
               pclk_dbg_div < 0x1f);
 
-       atclk_div = APLL_HZ / ATCLK_CORE_HZ - 1;
-       assert((atclk_div + 1) * ATCLK_CORE_HZ == APLL_HZ &&
+       atclk_div = LPLL_HZ / ATCLK_CORE_L_HZ - 1;
+       assert((atclk_div + 1) * ATCLK_CORE_L_HZ == LPLL_HZ &&
               atclk_div < 0x1f);
 
        rk_clrsetreg(&cru->clksel_con[0],
@@ -431,31 +453,60 @@ void rk3399_configure_cpu(struct rk3399_cru *cru,
                     pclk_dbg_div << PCLK_DBG_L_DIV_SHIFT |
                     atclk_div << ATCLK_CORE_L_DIV_SHIFT);
 }
+
+void rk3399_configure_cpu_b(struct rockchip_cru *cru,
+                           enum apll_b_frequencies apll_b_freq)
+{
+       u32 aclkm_div;
+       u32 pclk_dbg_div;
+       u32 atclk_div;
+
+       /* Setup cluster B */
+       rkclk_set_pll(&cru->apll_b_con[0], apll_b_cfgs[apll_b_freq]);
+
+       aclkm_div = BPLL_HZ / ACLKM_CORE_B_HZ - 1;
+       assert((aclkm_div + 1) * ACLKM_CORE_B_HZ == BPLL_HZ &&
+              aclkm_div < 0x1f);
+
+       pclk_dbg_div = BPLL_HZ / PCLK_DBG_B_HZ - 1;
+       assert((pclk_dbg_div + 1) * PCLK_DBG_B_HZ == BPLL_HZ &&
+              pclk_dbg_div < 0x1f);
+
+       atclk_div = BPLL_HZ / ATCLK_CORE_B_HZ - 1;
+       assert((atclk_div + 1) * ATCLK_CORE_B_HZ == BPLL_HZ &&
+              atclk_div < 0x1f);
+
+       rk_clrsetreg(&cru->clksel_con[2],
+                    ACLKM_CORE_B_DIV_CON_MASK | CLK_CORE_B_PLL_SEL_MASK |
+                    CLK_CORE_B_DIV_MASK,
+                    aclkm_div << ACLKM_CORE_B_DIV_CON_SHIFT |
+                    CLK_CORE_B_PLL_SEL_ABPLL << CLK_CORE_B_PLL_SEL_SHIFT |
+                    0 << CLK_CORE_B_DIV_SHIFT);
+
+       rk_clrsetreg(&cru->clksel_con[3],
+                    PCLK_DBG_B_DIV_MASK | ATCLK_CORE_B_DIV_MASK,
+                    pclk_dbg_div << PCLK_DBG_B_DIV_SHIFT |
+                    atclk_div << ATCLK_CORE_B_DIV_SHIFT);
+}
+
 #define I2C_CLK_REG_MASK(bus) \
-                       (I2C_DIV_CON_MASK << \
-                       CLK_I2C ##bus## _DIV_CON_SHIFT | \
-                       CLK_I2C_PLL_SEL_MASK << \
-                       CLK_I2C ##bus## _PLL_SEL_SHIFT)
+       (I2C_DIV_CON_MASK << CLK_I2C ##bus## _DIV_CON_SHIFT | \
+        CLK_I2C_PLL_SEL_MASK << CLK_I2C ##bus## _PLL_SEL_SHIFT)
 
 #define I2C_CLK_REG_VALUE(bus, clk_div) \
-                             ((clk_div - 1) << \
-                                       CLK_I2C ##bus## _DIV_CON_SHIFT | \
-                             CLK_I2C_PLL_SEL_GPLL << \
-                                       CLK_I2C ##bus## _PLL_SEL_SHIFT)
+       ((clk_div - 1) << CLK_I2C ##bus## _DIV_CON_SHIFT | \
+        CLK_I2C_PLL_SEL_GPLL << CLK_I2C ##bus## _PLL_SEL_SHIFT)
 
 #define I2C_CLK_DIV_VALUE(con, bus) \
-                       (con >> CLK_I2C ##bus## _DIV_CON_SHIFT) & \
-                               I2C_DIV_CON_MASK;
+       ((con >> CLK_I2C ##bus## _DIV_CON_SHIFT) & I2C_DIV_CON_MASK)
 
 #define I2C_PMUCLK_REG_MASK(bus) \
-                       (I2C_DIV_CON_MASK << \
-                        CLK_I2C ##bus## _DIV_CON_SHIFT)
+       (I2C_DIV_CON_MASK << CLK_I2C ##bus## _DIV_CON_SHIFT)
 
 #define I2C_PMUCLK_REG_VALUE(bus, clk_div) \
-                               ((clk_div - 1) << \
-                               CLK_I2C ##bus## _DIV_CON_SHIFT)
+       ((clk_div - 1) << CLK_I2C ##bus## _DIV_CON_SHIFT)
 
-static ulong rk3399_i2c_get_clk(struct rk3399_cru *cru, ulong clk_id)
+static ulong rk3399_i2c_get_clk(struct rockchip_cru *cru, ulong clk_id)
 {
        u32 div, con;
 
@@ -492,7 +543,7 @@ static ulong rk3399_i2c_get_clk(struct rk3399_cru *cru, ulong clk_id)
        return DIV_TO_RATE(GPLL_HZ, div);
 }
 
-static ulong rk3399_i2c_set_clk(struct rk3399_cru *cru, ulong clk_id, uint hz)
+static ulong rk3399_i2c_set_clk(struct rockchip_cru *cru, ulong clk_id, uint hz)
 {
        int src_clk_div;
 
@@ -540,9 +591,9 @@ static ulong rk3399_i2c_set_clk(struct rk3399_cru *cru, ulong clk_id, uint hz)
  */
 
 struct spi_clkreg {
-       uint8_t reg;  /* CLKSEL_CON[reg] register in CRU */
-       uint8_t div_shift;
-       uint8_t sel_shift;
+       u8 reg;  /* CLKSEL_CON[reg] register in CRU */
+       u8 div_shift;
+       u8 sel_shift;
 };
 
 /*
@@ -569,7 +620,7 @@ static const struct spi_clkreg spi_clkregs[] = {
                .sel_shift = CLK_SPI5_PLL_SEL_SHIFT, },
 };
 
-static ulong rk3399_spi_get_clk(struct rk3399_cru *cru, ulong clk_id)
+static ulong rk3399_spi_get_clk(struct rockchip_cru *cru, ulong clk_id)
 {
        const struct spi_clkreg *spiclk = NULL;
        u32 div, val;
@@ -591,7 +642,7 @@ static ulong rk3399_spi_get_clk(struct rk3399_cru *cru, ulong clk_id)
        return DIV_TO_RATE(GPLL_HZ, div);
 }
 
-static ulong rk3399_spi_set_clk(struct rk3399_cru *cru, ulong clk_id, uint hz)
+static ulong rk3399_spi_set_clk(struct rockchip_cru *cru, ulong clk_id, uint hz)
 {
        const struct spi_clkreg *spiclk = NULL;
        int src_clk_div;
@@ -618,10 +669,10 @@ static ulong rk3399_spi_set_clk(struct rk3399_cru *cru, ulong clk_id, uint hz)
        return rk3399_spi_get_clk(cru, clk_id);
 }
 
-static ulong rk3399_vop_set_clk(struct rk3399_cru *cru, ulong clk_id, u32 hz)
+static ulong rk3399_vop_set_clk(struct rockchip_cru *cru, ulong clk_id, u32 hz)
 {
        struct pll_div vpll_config = {0};
-       int aclk_vop = 198*MHz;
+       int aclk_vop = 198 * MHz;
        void *aclkreg_addr, *dclkreg_addr;
        u32 div;
 
@@ -653,7 +704,7 @@ static ulong rk3399_vop_set_clk(struct rk3399_cru *cru, ulong clk_id, u32 hz)
        rkclk_set_pll(&cru->vpll_con[0], &vpll_config);
 
        rk_clrsetreg(dclkreg_addr,
-                    DCLK_VOP_DCLK_SEL_MASK | DCLK_VOP_PLL_SEL_MASK|
+                    DCLK_VOP_DCLK_SEL_MASK | DCLK_VOP_PLL_SEL_MASK |
                     DCLK_VOP_DIV_CON_MASK,
                     DCLK_VOP_DCLK_SEL_DIVOUT << DCLK_VOP_DCLK_SEL_SHIFT |
                     DCLK_VOP_PLL_SEL_VPLL << DCLK_VOP_PLL_SEL_SHIFT |
@@ -662,7 +713,7 @@ static ulong rk3399_vop_set_clk(struct rk3399_cru *cru, ulong clk_id, u32 hz)
        return hz;
 }
 
-static ulong rk3399_mmc_get_clk(struct rk3399_cru *cru, uint clk_id)
+static ulong rk3399_mmc_get_clk(struct rockchip_cru *cru, uint clk_id)
 {
        u32 div, con;
 
@@ -689,11 +740,11 @@ static ulong rk3399_mmc_get_clk(struct rk3399_cru *cru, uint clk_id)
                return DIV_TO_RATE(GPLL_HZ, div);
 }
 
-static ulong rk3399_mmc_set_clk(struct rk3399_cru *cru,
+static ulong rk3399_mmc_set_clk(struct rockchip_cru *cru,
                                ulong clk_id, ulong set_rate)
 {
        int src_clk_div;
-       int aclk_emmc = 198*MHz;
+       int aclk_emmc = 198 * MHz;
 
        switch (clk_id) {
        case HCLK_SDMMC:
@@ -719,7 +770,7 @@ static ulong rk3399_mmc_set_clk(struct rk3399_cru *cru,
                break;
        case SCLK_EMMC:
                /* Select aclk_emmc source from GPLL */
-               src_clk_div = DIV_ROUND_UP(GPLL_HZ , aclk_emmc);
+               src_clk_div = DIV_ROUND_UP(GPLL_HZ, aclk_emmc);
                assert(src_clk_div - 1 < 32);
 
                rk_clrsetreg(&cru->clksel_con[21],
@@ -742,8 +793,32 @@ static ulong rk3399_mmc_set_clk(struct rk3399_cru *cru,
        return rk3399_mmc_get_clk(cru, clk_id);
 }
 
+static ulong rk3399_gmac_set_clk(struct rockchip_cru *cru, ulong rate)
+{
+       ulong ret;
+
+       /*
+        * The RGMII CLK can be derived either from an external "clkin"
+        * or can be generated from internally by a divider from SCLK_MAC.
+        */
+       if (readl(&cru->clksel_con[19]) & BIT(4)) {
+               /* An external clock will always generate the right rate... */
+               ret = rate;
+       } else {
+               /*
+                * No platform uses an internal clock to date.
+                * Implement this once it becomes necessary and print an error
+                * if someone tries to use it (while it remains unimplemented).
+                */
+               pr_err("%s: internal clock is UNIMPLEMENTED\n", __func__);
+               ret = 0;
+       }
+
+       return ret;
+}
+
 #define PMUSGRF_DDR_RGN_CON16 0xff330040
-static ulong rk3399_ddr_set_clk(struct rk3399_cru *cru,
+static ulong rk3399_ddr_set_clk(struct rockchip_cru *cru,
                                ulong set_rate)
 {
        struct pll_div dpll_cfg;
@@ -753,23 +828,31 @@ static ulong rk3399_ddr_set_clk(struct rk3399_cru *cru,
 
        /*  clk_ddrc == DPLL = 24MHz / refdiv * fbdiv / postdiv1 / postdiv2 */
        switch (set_rate) {
-       case 200*MHz:
+       case 50 * MHz:
+               dpll_cfg = (struct pll_div)
+               {.refdiv = 1, .fbdiv = 12, .postdiv1 = 3, .postdiv2 = 2};
+               break;
+       case 200 * MHz:
                dpll_cfg = (struct pll_div)
                {.refdiv = 1, .fbdiv = 50, .postdiv1 = 6, .postdiv2 = 1};
                break;
-       case 300*MHz:
+       case 300 * MHz:
                dpll_cfg = (struct pll_div)
                {.refdiv = 2, .fbdiv = 100, .postdiv1 = 4, .postdiv2 = 1};
                break;
-       case 666*MHz:
+       case 400 * MHz:
+               dpll_cfg = (struct pll_div)
+               {.refdiv = 1, .fbdiv = 50, .postdiv1 = 3, .postdiv2 = 1};
+               break;
+       case 666 * MHz:
                dpll_cfg = (struct pll_div)
                {.refdiv = 2, .fbdiv = 111, .postdiv1 = 2, .postdiv2 = 1};
                break;
-       case 800*MHz:
+       case 800 * MHz:
                dpll_cfg = (struct pll_div)
                {.refdiv = 1, .fbdiv = 100, .postdiv1 = 3, .postdiv2 = 1};
                break;
-       case 933*MHz:
+       case 933 * MHz:
                dpll_cfg = (struct pll_div)
                {.refdiv = 1, .fbdiv = 116, .postdiv1 = 3, .postdiv2 = 1};
                break;
@@ -781,7 +864,7 @@ static ulong rk3399_ddr_set_clk(struct rk3399_cru *cru,
        return set_rate;
 }
 
-static ulong rk3399_saradc_get_clk(struct rk3399_cru *cru)
+static ulong rk3399_saradc_get_clk(struct rockchip_cru *cru)
 {
        u32 div, val;
 
@@ -792,7 +875,7 @@ static ulong rk3399_saradc_get_clk(struct rk3399_cru *cru)
        return DIV_TO_RATE(OSC_HZ, div);
 }
 
-static ulong rk3399_saradc_set_clk(struct rk3399_cru *cru, uint hz)
+static ulong rk3399_saradc_set_clk(struct rockchip_cru *cru, uint hz)
 {
        int src_clk_div;
 
@@ -831,9 +914,10 @@ static ulong rk3399_clk_get_rate(struct clk *clk)
                rate = rk3399_spi_get_clk(priv->cru, clk->id);
                break;
        case SCLK_UART0:
+       case SCLK_UART1:
        case SCLK_UART2:
+       case SCLK_UART3:
                return 24000000;
-               break;
        case PCLK_HDMI_CTRL:
                break;
        case DCLK_VOP0:
@@ -844,7 +928,13 @@ static ulong rk3399_clk_get_rate(struct clk *clk)
        case SCLK_SARADC:
                rate = rk3399_saradc_get_clk(priv->cru);
                break;
+       case ACLK_VIO:
+       case ACLK_HDCP:
+       case ACLK_GIC_PRE:
+       case PCLK_DDR:
+               break;
        default:
+               log_debug("Unknown clock %lu\n", clk->id);
                return -ENOENT;
        }
 
@@ -859,14 +949,31 @@ static ulong rk3399_clk_set_rate(struct clk *clk, ulong rate)
        switch (clk->id) {
        case 0 ... 63:
                return 0;
+
+       case ACLK_PERIHP:
+       case HCLK_PERIHP:
+       case PCLK_PERIHP:
+               return 0;
+
+       case ACLK_PERILP0:
+       case HCLK_PERILP0:
+       case PCLK_PERILP0:
+               return 0;
+
+       case ACLK_CCI:
+               return 0;
+
+       case HCLK_PERILP1:
+       case PCLK_PERILP1:
+               return 0;
+
        case HCLK_SDMMC:
        case SCLK_SDMMC:
        case SCLK_EMMC:
                ret = rk3399_mmc_set_clk(priv->cru, clk->id, rate);
                break;
        case SCLK_MAC:
-               /* nothing to do, as this is an external clock */
-               ret = rate;
+               ret = rk3399_gmac_set_clk(priv->cru, rate);
                break;
        case SCLK_I2C1:
        case SCLK_I2C2:
@@ -887,6 +994,14 @@ static ulong rk3399_clk_set_rate(struct clk *clk, ulong rate)
        case DCLK_VOP1:
                ret = rk3399_vop_set_clk(priv->cru, clk->id, rate);
                break;
+       case ACLK_VOP1:
+       case HCLK_VOP1:
+       case HCLK_SD:
+               /**
+                * assigned-clocks handling won't require for vopl, so
+                * return 0 to satisfy clk_set_defaults during device probe.
+                */
+               return 0;
        case SCLK_DDRCLK:
                ret = rk3399_ddr_set_clk(priv->cru, rate);
                break;
@@ -895,23 +1010,63 @@ static ulong rk3399_clk_set_rate(struct clk *clk, ulong rate)
        case SCLK_SARADC:
                ret = rk3399_saradc_set_clk(priv->cru, rate);
                break;
+       case ACLK_VIO:
+       case ACLK_HDCP:
+       case ACLK_GIC_PRE:
+       case PCLK_DDR:
+               return 0;
        default:
+               log_debug("Unknown clock %lu\n", clk->id);
                return -ENOENT;
        }
 
        return ret;
 }
 
-static int rk3399_clk_enable(struct clk *clk)
+static int __maybe_unused rk3399_gmac_set_parent(struct clk *clk,
+                                                struct clk *parent)
 {
-       switch (clk->id) {
-       case HCLK_HOST0:
-       case HCLK_HOST0_ARB:
-       case HCLK_HOST1:
-       case HCLK_HOST1_ARB:
+       struct rk3399_clk_priv *priv = dev_get_priv(clk->dev);
+       const char *clock_output_name;
+       int ret;
+
+       /*
+        * If the requested parent is in the same clock-controller and
+        * the id is SCLK_MAC ("clk_gmac"), switch to the internal clock.
+        */
+       if (parent->dev == clk->dev && parent->id == SCLK_MAC) {
+               debug("%s: switching RGMII to SCLK_MAC\n", __func__);
+               rk_clrreg(&priv->cru->clksel_con[19], BIT(4));
+               return 0;
+       }
+
+       /*
+        * Otherwise, we need to check the clock-output-names of the
+        * requested parent to see if the requested id is "clkin_gmac".
+        */
+       ret = dev_read_string_index(parent->dev, "clock-output-names",
+                                   parent->id, &clock_output_name);
+       if (ret < 0)
+               return -ENODATA;
+
+       /* If this is "clkin_gmac", switch to the external clock input */
+       if (!strcmp(clock_output_name, "clkin_gmac")) {
+               debug("%s: switching RGMII to CLKIN\n", __func__);
+               rk_setreg(&priv->cru->clksel_con[19], BIT(4));
                return 0;
        }
 
+       return -EINVAL;
+}
+
+static int __maybe_unused rk3399_clk_set_parent(struct clk *clk,
+                                               struct clk *parent)
+{
+       switch (clk->id) {
+       case SCLK_RMII_SRC:
+               return rk3399_gmac_set_parent(clk, parent);
+       }
+
        debug("%s: unsupported clk %ld\n", __func__, clk->id);
        return -ENOENT;
 }
@@ -919,17 +1074,20 @@ static int rk3399_clk_enable(struct clk *clk)
 static struct clk_ops rk3399_clk_ops = {
        .get_rate = rk3399_clk_get_rate,
        .set_rate = rk3399_clk_set_rate,
-       .enable = rk3399_clk_enable,
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
+       .set_parent = rk3399_clk_set_parent,
+#endif
 };
 
 #ifdef CONFIG_SPL_BUILD
-static void rkclk_init(struct rk3399_cru *cru)
+static void rkclk_init(struct rockchip_cru *cru)
 {
        u32 aclk_div;
        u32 hclk_div;
        u32 pclk_div;
 
-       rk3399_configure_cpu(cru, APLL_L_600_MHZ);
+       rk3399_configure_cpu_l(cru, APLL_L_600_MHZ);
+       rk3399_configure_cpu_b(cru, APLL_B_600_MHZ);
        /*
         * some cru registers changed by bootrom, we'd better reset them to
         * reset/default values described in TRM to avoid confusion in kernel.
@@ -1039,13 +1197,20 @@ static int rk3399_clk_bind(struct udevice *dev)
                debug("Warning: No sysreset driver: ret=%d\n", ret);
        } else {
                priv = malloc(sizeof(struct sysreset_reg));
-               priv->glb_srst_fst_value = offsetof(struct rk3399_cru,
+               priv->glb_srst_fst_value = offsetof(struct rockchip_cru,
                                                    glb_srst_fst_value);
-               priv->glb_srst_snd_value = offsetof(struct rk3399_cru,
+               priv->glb_srst_snd_value = offsetof(struct rockchip_cru,
                                                    glb_srst_snd_value);
                sys_child->priv = priv;
        }
 
+#if CONFIG_IS_ENABLED(RESET_ROCKCHIP)
+       ret = offsetof(struct rockchip_cru, softrst_con[0]);
+       ret = rockchip_reset_bind(dev, ret, 21);
+       if (ret)
+               debug("Warning: software reset driver bind faile\n");
+#endif
+
        return 0;
 }
 
@@ -1139,6 +1304,8 @@ static ulong rk3399_pmuclk_get_rate(struct clk *clk)
        ulong rate = 0;
 
        switch (clk->id) {
+       case PLL_PPLL:
+               return PPLL_HZ;
        case PCLK_RKPWM_PMU:
                rate = rk3399_pwm_get_clk(priv->pmucru);
                break;
@@ -1160,6 +1327,13 @@ static ulong rk3399_pmuclk_set_rate(struct clk *clk, ulong rate)
        ulong ret = 0;
 
        switch (clk->id) {
+       case PLL_PPLL:
+               /*
+                * This has already been set up and we don't want/need
+                * to change it here.  Accept the request though, as the
+                * device-tree has this in an 'assigned-clocks' list.
+                */
+               return PPLL_HZ;
        case SCLK_I2C0_PMU:
        case SCLK_I2C4_PMU:
        case SCLK_I2C8_PMU:
@@ -1221,6 +1395,19 @@ static int rk3399_pmuclk_ofdata_to_platdata(struct udevice *dev)
        return 0;
 }
 
+static int rk3399_pmuclk_bind(struct udevice *dev)
+{
+#if CONFIG_IS_ENABLED(CONFIG_RESET_ROCKCHIP)
+       int ret;
+
+       ret = offsetof(struct rk3399_pmucru, pmucru_softrst_con[0]);
+       ret = rockchip_reset_bind(dev, ret, 2);
+       if (ret)
+               debug("Warning: software reset driver bind faile\n");
+#endif
+       return 0;
+}
+
 static const struct udevice_id rk3399_pmuclk_ids[] = {
        { .compatible = "rockchip,rk3399-pmucru" },
        { }
@@ -1234,6 +1421,7 @@ U_BOOT_DRIVER(rockchip_rk3399_pmuclk) = {
        .ofdata_to_platdata = rk3399_pmuclk_ofdata_to_platdata,
        .ops            = &rk3399_pmuclk_ops,
        .probe          = rk3399_pmuclk_probe,
+       .bind           = rk3399_pmuclk_bind,
 #if CONFIG_IS_ENABLED(OF_PLATDATA)
        .platdata_auto_alloc_size = sizeof(struct rk3399_pmuclk_plat),
 #endif