[U-Boot] [PATCH v3 08/20] clk: rockchip: Add rk3328 gamc clock support

David Wu david.wu at rock-chips.com
Sat Jan 13 06:02:36 UTC 2018


The rk3328 soc has two gmac controllers, one is gmac2io,
the other is gmac2phy. We use the gmac2io rgmii interface
for 1000M phy here.

Signed-off-by: David Wu <david.wu at rock-chips.com>
---

Changes in v3:
- Add "set parent" for gmac2io
- Add internal mac clk div_sel for gmac2io

Changes in v2:
- New patch

 drivers/clk/rockchip/clk_rk3328.c      | 178 +++++++++++++++++++++++++++++++++
 include/dt-bindings/clock/rk3328-cru.h |   6 +-
 2 files changed, 181 insertions(+), 3 deletions(-)

diff --git a/drivers/clk/rockchip/clk_rk3328.c b/drivers/clk/rockchip/clk_rk3328.c
index fa0c777..2ccc798 100644
--- a/drivers/clk/rockchip/clk_rk3328.c
+++ b/drivers/clk/rockchip/clk_rk3328.c
@@ -13,6 +13,7 @@
 #include <asm/arch/clock.h>
 #include <asm/arch/cru_rk3328.h>
 #include <asm/arch/hardware.h>
+#include <asm/arch/grf_rk3328.h>
 #include <asm/io.h>
 #include <dm/lists.h>
 #include <dt-bindings/clock/rk3328-cru.h>
@@ -94,6 +95,14 @@ enum {
 	PCLK_DBG_DIV_SHIFT		= 0,
 	PCLK_DBG_DIV_MASK		= 0xF << PCLK_DBG_DIV_SHIFT,
 
+	/* CLKSEL_CON27 */
+	GMAC2IO_PLL_SEL_SHIFT		= 7,
+	GMAC2IO_PLL_SEL_MASK		= 1 << GMAC2IO_PLL_SEL_SHIFT,
+	GMAC2IO_PLL_SEL_CPLL		= 0,
+	GMAC2IO_PLL_SEL_GPLL		= 1,
+	GMAC2IO_CLK_DIV_MASK		= 0x1f,
+	GMAC2IO_CLK_DIV_SHIFT		= 0,
+
 	/* CLKSEL_CON28 */
 	ACLK_PERIHP_PLL_SEL_CPLL	= 0,
 	ACLK_PERIHP_PLL_SEL_GPLL,
@@ -393,6 +402,44 @@ static ulong rk3328_i2c_set_clk(struct rk3328_cru *cru, ulong clk_id, uint hz)
 	return DIV_TO_RATE(GPLL_HZ, src_clk_div);
 }
 
+static ulong rk3328_gmac2io_set_clk(struct rk3328_cru *cru, ulong rate)
+{
+	struct rk3328_grf_regs *grf;
+	ulong ret;
+
+	grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
+
+	/*
+	 * 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(&grf->mac_con[1]) & BIT(10) &&
+	    readl(&grf->soc_con[4]) & BIT(14)) {
+		/* An external clock will always generate the right rate... */
+		ret = rate;
+	} else {
+		u32 con = readl(&cru->clksel_con[27]);
+		ulong pll_rate;
+		u8 div;
+
+		if ((con >> GMAC2IO_PLL_SEL_SHIFT) & GMAC2IO_PLL_SEL_GPLL)
+			pll_rate = GPLL_HZ;
+		else
+			pll_rate = CPLL_HZ;
+
+		div = DIV_ROUND_UP(pll_rate, rate) - 1;
+		if (div <= 0x1f)
+			rk_clrsetreg(&cru->clksel_con[27], GMAC2IO_CLK_DIV_MASK,
+				     div << GMAC2IO_CLK_DIV_SHIFT);
+		else
+			debug("Unsupported div for gmac:%d\n", div);
+
+		return DIV_TO_RATE(pll_rate, div);
+	}
+
+	return ret;
+}
+
 static ulong rk3328_mmc_get_clk(struct rk3328_cru *cru, uint clk_id)
 {
 	u32 div, con, con_id;
@@ -558,12 +605,48 @@ static ulong rk3328_clk_set_rate(struct clk *clk, ulong rate)
 	case SCLK_I2C3:
 		ret = rk3328_i2c_set_clk(priv->cru, clk->id, rate);
 		break;
+	case SCLK_MAC2IO:
+		ret = rk3328_gmac2io_set_clk(priv->cru, rate);
+		break;
 	case SCLK_PWM:
 		ret = rk3328_pwm_set_clk(priv->cru, rate);
 		break;
 	case SCLK_SARADC:
 		ret = rk3328_saradc_set_clk(priv->cru, rate);
 		break;
+	case DCLK_LCDC:
+	case SCLK_PDM:
+	case SCLK_RTC32K:
+	case SCLK_UART0:
+	case SCLK_UART1:
+	case SCLK_UART2:
+	case SCLK_SDIO:
+	case SCLK_TSP:
+	case SCLK_WIFI:
+	case ACLK_BUS_PRE:
+	case HCLK_BUS_PRE:
+	case PCLK_BUS_PRE:
+	case ACLK_PERI_PRE:
+	case HCLK_PERI:
+	case PCLK_PERI:
+	case ACLK_VIO_PRE:
+	case HCLK_VIO_PRE:
+	case ACLK_RGA_PRE:
+	case SCLK_RGA:
+	case ACLK_VOP_PRE:
+	case ACLK_RKVDEC_PRE:
+	case ACLK_RKVENC:
+	case ACLK_VPU_PRE:
+	case SCLK_VDEC_CABAC:
+	case SCLK_VDEC_CORE:
+	case SCLK_VENC_CORE:
+	case SCLK_VENC_DSP:
+	case SCLK_EFUSE:
+	case PCLK_DDR:
+	case ACLK_GMAC:
+	case PCLK_GMAC:
+	case SCLK_USB3OTG_SUSPEND:
+		return 0;
 	default:
 		return -ENOENT;
 	}
@@ -571,9 +654,104 @@ static ulong rk3328_clk_set_rate(struct clk *clk, ulong rate)
 	return ret;
 }
 
+static int rk3328_gmac2io_set_parent(struct clk *clk, struct clk *parent)
+{
+	struct rk3328_grf_regs *grf;
+	const char *clock_output_name;
+	int ret;
+
+	grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
+
+	/*
+	 * If the requested parent is in the same clock-controller and the id
+	 * is SCLK_MAC2IO_SRC ("clk_mac2io_src"), switch to the internal clock.
+	 */
+	if ((parent->dev == clk->dev) && (parent->id == SCLK_MAC2IO_SRC)) {
+		debug("%s: switching RGMII to SCLK_MAC2IO_SRC\n", __func__);
+		rk_clrreg(&grf->mac_con[1], BIT(10));
+		return 0;
+	}
+
+	/*
+	 * Otherwise, we need to check the clock-output-names of the
+	 * requested parent to see if the requested id is "gmac_clkin".
+	 */
+	ret = dev_read_string_index(parent->dev, "clock-output-names",
+				    parent->id, &clock_output_name);
+	if (ret < 0)
+		return -ENODATA;
+
+	/* If this is "gmac_clkin", switch to the external clock input */
+	if (!strcmp(clock_output_name, "gmac_clkin")) {
+		debug("%s: switching RGMII to CLKIN\n", __func__);
+		rk_setreg(&grf->mac_con[1], BIT(10));
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int rk3328_gmac2io_ext_set_parent(struct clk *clk, struct clk *parent)
+{
+	struct rk3328_grf_regs *grf;
+	const char *clock_output_name;
+	int ret;
+
+	grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
+
+	/*
+	 * If the requested parent is in the same clock-controller and the id
+	 * is SCLK_MAC2IO ("clk_mac2io"), switch to the internal clock.
+	 */
+	if ((parent->dev == clk->dev) && (parent->id == SCLK_MAC2IO)) {
+		debug("%s: switching RGMII to SCLK_MAC2IO\n", __func__);
+		rk_clrreg(&grf->soc_con[4], BIT(14));
+		return 0;
+	}
+
+	/*
+	 * Otherwise, we need to check the clock-output-names of the
+	 * requested parent to see if the requested id is "gmac_clkin".
+	 */
+	ret = dev_read_string_index(parent->dev, "clock-output-names",
+				    parent->id, &clock_output_name);
+	if (ret < 0)
+		return -ENODATA;
+
+	/* If this is "gmac_clkin", switch to the external clock input */
+	if (!strcmp(clock_output_name, "gmac_clkin")) {
+		debug("%s: switching RGMII to CLKIN\n", __func__);
+		rk_setreg(&grf->soc_con[4], BIT(14));
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int rk3328_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	switch (clk->id) {
+	case SCLK_MAC2IO:
+		return rk3328_gmac2io_set_parent(clk, parent);
+	case SCLK_MAC2IO_EXT:
+		return rk3328_gmac2io_ext_set_parent(clk, parent);
+	case DCLK_LCDC:
+	case SCLK_PDM:
+	case SCLK_RTC32K:
+	case SCLK_UART0:
+	case SCLK_UART1:
+	case SCLK_UART2:
+		return 0;
+	}
+
+	debug("%s: unsupported clk %ld\n", __func__, clk->id);
+	return -ENOENT;
+}
+
 static struct clk_ops rk3328_clk_ops = {
 	.get_rate = rk3328_clk_get_rate,
 	.set_rate = rk3328_clk_set_rate,
+	.set_parent = rk3328_clk_set_parent,
 };
 
 static int rk3328_clk_probe(struct udevice *dev)
diff --git a/include/dt-bindings/clock/rk3328-cru.h b/include/dt-bindings/clock/rk3328-cru.h
index 6d8bf13..cdc0b33 100644
--- a/include/dt-bindings/clock/rk3328-cru.h
+++ b/include/dt-bindings/clock/rk3328-cru.h
@@ -86,6 +86,9 @@
 #define SCLK_USB3OTG_SUSPEND	97
 #define SCLK_REF_USB3OTG_SRC	98
 #define SCLK_MAC2IO_SRC		99
+#define SCLK_MAC2IO		100
+#define SCLK_MAC2PHY		101
+#define SCLK_MAC2IO_EXT		102
 
 /* dclk gates */
 #define DCLK_LCDC		180
@@ -199,9 +202,6 @@
 
 #define CLK_NR_CLKS		(HCLK_HDCP + 1)
 
-#define SCLK_MAC2IO		0
-#define SCLK_MAC2PHY		1
-
 #define CLKGRF_NR_CLKS		(SCLK_MAC2PHY + 1)
 
 /* soft-reset indices */
-- 
2.7.4




More information about the U-Boot mailing list