summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey Charkov <[email protected]>2026-05-04 17:45:08 +0400
committerKever <[email protected]>2026-06-10 00:19:05 +0800
commit957941943bdb7e48aa223737268c28a0ae2dcd6d (patch)
tree7697cfd45edf73cfa604543353973a030a7c4b1e
parent924f87b995fa6b451656df17f3b6be20a3cf9c4e (diff)
rockchip: clk: clk_rk3576: Add support for RK3576 GMAC 25MHz clock output
Rockchip RK3576 SoC has two built-in GMACs which connect to external PHYs via RGMII interface. The RGMII link can be clocked by either the PHY or the SoC. When the SoC is the master, as is the case on the RK3576 EVB1, the output clock needs to be configured in the CRU. Add the respective logic for getting and setting the RGMII reference clock output for both GMAC0 and GMAC1. Signed-off-by: Alexey Charkov <[email protected]> Reviewed-by: Quentin Schulz <[email protected]> Reviewed-by: Kever Yang <[email protected]>
-rw-r--r--arch/arm/include/asm/arch-rockchip/cru_rk3576.h14
-rw-r--r--drivers/clk/rockchip/clk_rk3576.c50
2 files changed, 64 insertions, 0 deletions
diff --git a/arch/arm/include/asm/arch-rockchip/cru_rk3576.h b/arch/arm/include/asm/arch-rockchip/cru_rk3576.h
index c51750beff2..fb77fbd7307 100644
--- a/arch/arm/include/asm/arch-rockchip/cru_rk3576.h
+++ b/arch/arm/include/asm/arch-rockchip/cru_rk3576.h
@@ -222,6 +222,20 @@ enum {
REF_CLK0_OUT_PLL_DIV_SHIFT = 0,
REF_CLK0_OUT_PLL_DIV_MASK = 0xff << REF_CLK0_OUT_PLL_DIV_SHIFT,
+ /* CRU_CLK_SEL36_CON */
+ CLK_REFCLKO25M_GMAC0_DIV_SHIFT = 0,
+ CLK_REFCLKO25M_GMAC0_DIV_MASK = 0x7f << CLK_REFCLKO25M_GMAC0_DIV_SHIFT,
+ CLK_REFCLKO25M_GMAC0_SEL_SHIFT = 7,
+ CLK_REFCLKO25M_GMAC0_SEL_MASK = 1 << CLK_REFCLKO25M_GMAC0_SEL_SHIFT,
+ CLK_REFCLKO25M_GMAC0_SEL_GPLL = 0,
+ CLK_REFCLKO25M_GMAC0_SEL_CPLL = 1,
+ CLK_REFCLKO25M_GMAC1_DIV_SHIFT = 8,
+ CLK_REFCLKO25M_GMAC1_DIV_MASK = 0x7f << CLK_REFCLKO25M_GMAC1_DIV_SHIFT,
+ CLK_REFCLKO25M_GMAC1_SEL_SHIFT = 15,
+ CLK_REFCLKO25M_GMAC1_SEL_MASK = 1 << CLK_REFCLKO25M_GMAC1_SEL_SHIFT,
+ CLK_REFCLKO25M_GMAC1_SEL_GPLL = 0,
+ CLK_REFCLKO25M_GMAC1_SEL_CPLL = 1,
+
/* CRU_CLK_SEL55_CON */
ACLK_BUS_ROOT_SEL_SHIFT = 9,
ACLK_BUS_ROOT_SEL_MASK = 1 << ACLK_BUS_ROOT_SEL_SHIFT,
diff --git a/drivers/clk/rockchip/clk_rk3576.c b/drivers/clk/rockchip/clk_rk3576.c
index dd8b59356ef..db8ce25852f 100644
--- a/drivers/clk/rockchip/clk_rk3576.c
+++ b/drivers/clk/rockchip/clk_rk3576.c
@@ -1549,6 +1549,24 @@ static ulong rk3576_gmac_get_clk(struct rk3576_clk_priv *priv, ulong clk_id)
con = readl(&cru->clksel_con[31]);
div = (con & CLK_GMAC1_125M_DIV_MASK) >> CLK_GMAC1_125M_DIV_SHIFT;
return DIV_TO_RATE(priv->cpll_hz, div);
+ case REFCLKO25M_GMAC0_OUT:
+ con = readl(&cru->clksel_con[36]);
+ div = (con & CLK_REFCLKO25M_GMAC0_DIV_MASK) >> CLK_REFCLKO25M_GMAC0_DIV_SHIFT;
+ src = (con & CLK_REFCLKO25M_GMAC0_SEL_MASK) >> CLK_REFCLKO25M_GMAC0_SEL_SHIFT;
+ if (src == CLK_REFCLKO25M_GMAC0_SEL_CPLL)
+ p_rate = priv->cpll_hz;
+ else
+ p_rate = priv->gpll_hz;
+ return DIV_TO_RATE(p_rate, div);
+ case REFCLKO25M_GMAC1_OUT:
+ con = readl(&cru->clksel_con[36]);
+ div = (con & CLK_REFCLKO25M_GMAC1_DIV_MASK) >> CLK_REFCLKO25M_GMAC1_DIV_SHIFT;
+ src = (con & CLK_REFCLKO25M_GMAC1_SEL_MASK) >> CLK_REFCLKO25M_GMAC1_SEL_SHIFT;
+ if (src == CLK_REFCLKO25M_GMAC1_SEL_CPLL)
+ p_rate = priv->cpll_hz;
+ else
+ p_rate = priv->gpll_hz;
+ return DIV_TO_RATE(p_rate, div);
default:
return -ENOENT;
}
@@ -1608,6 +1626,34 @@ static ulong rk3576_gmac_set_clk(struct rk3576_clk_priv *priv,
CLK_GMAC1_125M_DIV_MASK,
(div - 1) << CLK_GMAC1_125M_DIV_SHIFT);
break;
+ case REFCLKO25M_GMAC0_OUT:
+ if (!(priv->gpll_hz % rate)) {
+ src = CLK_REFCLKO25M_GMAC0_SEL_GPLL;
+ div = priv->gpll_hz / rate;
+ } else {
+ src = CLK_REFCLKO25M_GMAC0_SEL_CPLL;
+ div = priv->cpll_hz / rate;
+ }
+ rk_clrsetreg(&cru->clksel_con[36],
+ CLK_REFCLKO25M_GMAC0_SEL_MASK |
+ CLK_REFCLKO25M_GMAC0_DIV_MASK,
+ src << CLK_REFCLKO25M_GMAC0_SEL_SHIFT |
+ (div - 1) << CLK_REFCLKO25M_GMAC0_DIV_SHIFT);
+ break;
+ case REFCLKO25M_GMAC1_OUT:
+ if (!(priv->gpll_hz % rate)) {
+ src = CLK_REFCLKO25M_GMAC1_SEL_GPLL;
+ div = priv->gpll_hz / rate;
+ } else {
+ src = CLK_REFCLKO25M_GMAC1_SEL_CPLL;
+ div = priv->cpll_hz / rate;
+ }
+ rk_clrsetreg(&cru->clksel_con[36],
+ CLK_REFCLKO25M_GMAC1_SEL_MASK |
+ CLK_REFCLKO25M_GMAC1_DIV_MASK,
+ src << CLK_REFCLKO25M_GMAC1_SEL_SHIFT |
+ (div - 1) << CLK_REFCLKO25M_GMAC1_DIV_SHIFT);
+ break;
default:
return -ENOENT;
}
@@ -2016,6 +2062,8 @@ static ulong rk3576_clk_get_rate(struct clk *clk)
case CLK_GMAC1_PTP_REF:
case CLK_GMAC0_125M_SRC:
case CLK_GMAC1_125M_SRC:
+ case REFCLKO25M_GMAC0_OUT:
+ case REFCLKO25M_GMAC1_OUT:
rate = rk3576_gmac_get_clk(priv, clk->id);
break;
case CLK_UART_FRAC_0:
@@ -2197,6 +2245,8 @@ static ulong rk3576_clk_set_rate(struct clk *clk, ulong rate)
case CLK_GMAC1_PTP_REF:
case CLK_GMAC0_125M_SRC:
case CLK_GMAC1_125M_SRC:
+ case REFCLKO25M_GMAC0_OUT:
+ case REFCLKO25M_GMAC1_OUT:
ret = rk3576_gmac_set_clk(priv, clk->id, rate);
break;
case CLK_UART_FRAC_0: