summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Wu <david.wu@rock-chips.com>2019-03-13 11:33:55 +0800
committerJianhong Chen <chenjh@rock-chips.com>2019-04-09 11:09:22 +0800
commit200683ea3d1db7d51b77da840b8e8333c04dcdf7 (patch)
tree99f28115a2fd1478e1843459c0eb54f200ac2de2
parentc4ff7367d6e344ed78dde06b38da64676f0e363c (diff)
clk: rockchip: Add mac clock support for rk3308
Change-Id: I972e2b7977f0f94164c72ae2205ec51780eb7373 Signed-off-by: David Wu <david.wu@rock-chips.com>
-rw-r--r--arch/arm/include/asm/arch-rockchip/cru_rk3308.h17
-rw-r--r--drivers/clk/rockchip/clk_rk3308.c87
2 files changed, 104 insertions, 0 deletions
diff --git a/arch/arm/include/asm/arch-rockchip/cru_rk3308.h b/arch/arm/include/asm/arch-rockchip/cru_rk3308.h
index 0f0b5e43bb..8ebd6e1903 100644
--- a/arch/arm/include/asm/arch-rockchip/cru_rk3308.h
+++ b/arch/arm/include/asm/arch-rockchip/cru_rk3308.h
@@ -261,6 +261,23 @@ enum {
EMMC_DIV_SHIFT = 0,
EMMC_DIV_MASK = 0xff << EMMC_DIV_SHIFT,
+ /* CRU_CLKSEL43_CON */
+ MAC_CLK_SPEED_SEL_SHIFT = 15,
+ MAC_CLK_SPEED_SEL_MASK = 1 << MAC_CLK_SPEED_SEL_SHIFT,
+ MAC_CLK_SPEED_SEL_10M = 0,
+ MAC_CLK_SPEED_SEL_100M,
+ MAC_CLK_SOURCE_SEL_SHIFT = 14,
+ MAC_CLK_SOURCE_SEL_MASK = 1 << MAC_CLK_SOURCE_SEL_SHIFT,
+ MAC_CLK_SOURCE_SEL_INTERNAL = 0,
+ MAC_CLK_SOURCE_SEL_EXTERNAL,
+ MAC_PLL_SHIFT = 6,
+ MAC_PLL_MASK = 0x3 << MAC_PLL_SHIFT,
+ MAC_SEL_DPLL = 0,
+ MAC_SEL_VPLL0,
+ MAC_SEL_VPLL1,
+ MAC_DIV_SHIFT = 0,
+ MAC_DIV_MASK = 0x1f << MAC_DIV_SHIFT,
+
/* CRU_CLK_SEL45_CON */
AUDIO_PCLK_DIV_SHIFT = 8,
AUDIO_PCLK_DIV_MASK = 0x1f << AUDIO_PCLK_DIV_SHIFT,
diff --git a/drivers/clk/rockchip/clk_rk3308.c b/drivers/clk/rockchip/clk_rk3308.c
index fa16d7449c..e36d64670e 100644
--- a/drivers/clk/rockchip/clk_rk3308.c
+++ b/drivers/clk/rockchip/clk_rk3308.c
@@ -206,6 +206,52 @@ static ulong rk3308_i2c_set_clk(struct clk *clk, uint hz)
return rk3308_i2c_get_clk(clk);
}
+static ulong rk3308_mac_set_clk(struct clk *clk, uint hz)
+{
+ struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
+ struct rk3308_cru *cru = priv->cru;
+ u32 con = readl(&cru->clksel_con[43]);
+ ulong pll_rate;
+ u8 div;
+
+ if ((con >> MAC_PLL_SHIFT) & MAC_SEL_VPLL0)
+ pll_rate = rockchip_pll_get_rate(&rk3308_pll_clks[VPLL0],
+ priv->cru, VPLL0);
+ else if ((con >> MAC_PLL_SHIFT) & MAC_SEL_VPLL1)
+ pll_rate = rockchip_pll_get_rate(&rk3308_pll_clks[VPLL1],
+ priv->cru, VPLL1);
+ else
+ pll_rate = rockchip_pll_get_rate(&rk3308_pll_clks[DPLL],
+ priv->cru, DPLL);
+
+ /*default set 50MHZ for gmac*/
+ if (!hz)
+ hz = 50000000;
+
+ div = DIV_ROUND_UP(pll_rate, hz) - 1;
+ assert(div < 32);
+ rk_clrsetreg(&cru->clksel_con[43], MAC_DIV_MASK,
+ div << MAC_DIV_SHIFT);
+
+ return DIV_TO_RATE(pll_rate, div);
+}
+
+static int rk3308_mac_set_speed_clk(struct clk *clk, uint hz)
+{
+ struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
+ struct rk3308_cru *cru = priv->cru;
+
+ if (hz != 2500000 && hz != 25000000) {
+ debug("Unsupported mac speed:%d\n", hz);
+ return -EINVAL;
+ }
+
+ rk_clrsetreg(&cru->clksel_con[43], MAC_CLK_SPEED_SEL_MASK,
+ ((hz == 2500000) ? 0 : 1) << MAC_CLK_SPEED_SEL_SHIFT);
+
+ return 0;
+}
+
static ulong rk3308_mmc_get_clk(struct clk *clk)
{
struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
@@ -867,6 +913,12 @@ static ulong rk3308_clk_set_rate(struct clk *clk, ulong rate)
case SCLK_I2C3:
ret = rk3308_i2c_set_clk(clk, rate);
break;
+ case SCLK_MAC:
+ ret = rk3308_mac_set_clk(clk, rate);
+ break;
+ case SCLK_MAC_RMII:
+ ret = rk3308_mac_set_speed_clk(clk, rate);
+ break;
case SCLK_SARADC:
ret = rk3308_saradc_set_clk(clk, rate);
break;
@@ -1033,11 +1085,46 @@ static int rk3308_clk_set_phase(struct clk *clk, int degrees)
return ret;
}
+static int __maybe_unused rk3308_mac_set_parent(struct clk *clk, struct clk *parent)
+{
+ struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
+
+ /*
+ * If the requested parent is in the same clock-controller and
+ * the id is SCLK_MAC_SRC, switch to the internal clock.
+ */
+ if (parent->id == SCLK_MAC_SRC) {
+ debug("%s: switching RMII to SCLK_MAC\n", __func__);
+ rk_clrreg(&priv->cru->clksel_con[43], BIT(14));
+ } else {
+ debug("%s: switching RMII to CLKIN\n", __func__);
+ rk_setreg(&priv->cru->clksel_con[43], BIT(14));
+ }
+
+ return 0;
+}
+
+static int __maybe_unused rk3308_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ switch (clk->id) {
+ case SCLK_MAC:
+ return rk3308_mac_set_parent(clk, parent);
+ default:
+ break;
+ }
+
+ debug("%s: unsupported clk %ld\n", __func__, clk->id);
+ return -ENOENT;
+}
+
static struct clk_ops rk3308_clk_ops = {
.get_rate = rk3308_clk_get_rate,
.set_rate = rk3308_clk_set_rate,
.get_phase = rk3308_clk_get_phase,
.set_phase = rk3308_clk_set_phase,
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
+ .set_parent = rk3308_clk_set_parent,
+#endif
};
static void rk3308_clk_init(struct udevice *dev)