[U-Boot] [PATCH 20/42] clk: sunxi: Implement direct MMC clocks

Jagan Teki jagan at amarulasolutions.com
Mon Aug 6 17:37:41 UTC 2018


Implement direct MMC clocks for all Allwinner SoC
clock drivers via clock map descriptor table.

This includes adding ccu_clk_set_rate function pointer,
which indeed support CLK set_rate API, so update clock
handling in sunxi_mmc driver to support both no-dm and dm code.

Signed-off-by: Jagan Teki <jagan at amarulasolutions.com>
---
 arch/arm/include/asm/arch-sunxi/ccu.h | 10 +++++
 drivers/clk/sunxi/clk_a10.c           |  5 +++
 drivers/clk/sunxi/clk_a10s.c          |  6 +++
 drivers/clk/sunxi/clk_a23.c           |  6 +++
 drivers/clk/sunxi/clk_a31.c           |  5 +++
 drivers/clk/sunxi/clk_a64.c           |  4 ++
 drivers/clk/sunxi/clk_a83t.c          |  4 ++
 drivers/clk/sunxi/clk_h3.c            |  4 ++
 drivers/clk/sunxi/clk_r40.c           |  4 ++
 drivers/clk/sunxi/clk_sunxi.c         | 19 +++++++++
 drivers/clk/sunxi/clk_v3s.c           |  4 ++
 drivers/mmc/sunxi_mmc.c               | 58 +++++++++++++++++----------
 12 files changed, 107 insertions(+), 22 deletions(-)

diff --git a/arch/arm/include/asm/arch-sunxi/ccu.h b/arch/arm/include/asm/arch-sunxi/ccu.h
index bacd052ef3..4e30ab330c 100644
--- a/arch/arm/include/asm/arch-sunxi/ccu.h
+++ b/arch/arm/include/asm/arch-sunxi/ccu.h
@@ -60,6 +60,16 @@ struct sunxi_clk_priv {
 
 extern struct clk_ops sunxi_clk_ops;
 
+/**
+ * mmc_clk_set_rate - mmc clock set rate
+ *
+ * @base:	clock register base address
+ * @bit:	clock bit value
+ * @rate:	clock input rate in Hz
+ * @return 0, or -ve error code.
+ */
+int mmc_clk_set_rate(void *base, u32 bit, ulong rate);
+
 /**
  * sunxi_reset_bind() - reset binding
  *
diff --git a/drivers/clk/sunxi/clk_a10.c b/drivers/clk/sunxi/clk_a10.c
index fb11231dd1..55176bc174 100644
--- a/drivers/clk/sunxi/clk_a10.c
+++ b/drivers/clk/sunxi/clk_a10.c
@@ -23,6 +23,11 @@ static struct ccu_clk_map a10_clks[] = {
 	[CLK_AHB_MMC2]		= { 0x060, BIT(10), NULL },
 	[CLK_AHB_MMC3]		= { 0x060, BIT(11), NULL },
 
+	[CLK_MMC0]		= { 0x088, BIT(31), &mmc_clk_set_rate },
+	[CLK_MMC1]		= { 0x08c, BIT(31), &mmc_clk_set_rate },
+	[CLK_MMC2]		= { 0x090, BIT(31), &mmc_clk_set_rate },
+	[CLK_MMC3]		= { 0x094, BIT(31), &mmc_clk_set_rate },
+
 	[CLK_USB_OHCI0]		= { 0x0cc, BIT(6), NULL },
 	[CLK_USB_OHCI1]		= { 0x0cc, BIT(7), NULL },
 	[CLK_USB_PHY]		= { 0x0cc, BIT(8), NULL },
diff --git a/drivers/clk/sunxi/clk_a10s.c b/drivers/clk/sunxi/clk_a10s.c
index ba5e2e323d..89c4897000 100644
--- a/drivers/clk/sunxi/clk_a10s.c
+++ b/drivers/clk/sunxi/clk_a10s.c
@@ -20,6 +20,12 @@ static struct ccu_clk_map a10s_clks[] = {
 	[CLK_AHB_MMC1]		= { 0x060, BIT(9), NULL },
 	[CLK_AHB_MMC2]		= { 0x060, BIT(10), NULL },
 
+#ifdef CONFIG_MMC
+	[CLK_MMC0]		= { 0x088, BIT(31), &mmc_clk_set_rate },
+	[CLK_MMC1]		= { 0x08c, BIT(31), &mmc_clk_set_rate },
+	[CLK_MMC2]		= { 0x090, BIT(31), &mmc_clk_set_rate },
+#endif
+
 	[CLK_USB_OHCI]		= { 0x0cc, BIT(6), NULL },
 	[CLK_USB_PHY0]		= { 0x0cc, BIT(8), NULL },
 	[CLK_USB_PHY1]		= { 0x0cc, BIT(9), NULL },
diff --git a/drivers/clk/sunxi/clk_a23.c b/drivers/clk/sunxi/clk_a23.c
index 43e6dd63bf..911d6987c8 100644
--- a/drivers/clk/sunxi/clk_a23.c
+++ b/drivers/clk/sunxi/clk_a23.c
@@ -20,6 +20,12 @@ static struct ccu_clk_map a23_clks[] = {
 	[CLK_BUS_EHCI]		= { 0x060, BIT(26), NULL },
 	[CLK_BUS_OHCI]		= { 0x060, BIT(29), NULL },
 
+#ifdef CONFIG_MMC
+	[CLK_MMC0]		= { 0x088, BIT(31), &mmc_clk_set_rate },
+	[CLK_MMC1]		= { 0x08c, BIT(31), &mmc_clk_set_rate },
+	[CLK_MMC2]		= { 0x090, BIT(31), &mmc_clk_set_rate },
+#endif
+
 	[CLK_USB_PHY0]		= { 0x0cc, BIT(8), NULL },
 	[CLK_USB_PHY1]		= { 0x0cc, BIT(9), NULL },
 	[CLK_USB_HSIC]		= { 0x0cc, BIT(10), NULL },
diff --git a/drivers/clk/sunxi/clk_a31.c b/drivers/clk/sunxi/clk_a31.c
index f314feff69..3c807bde77 100644
--- a/drivers/clk/sunxi/clk_a31.c
+++ b/drivers/clk/sunxi/clk_a31.c
@@ -24,6 +24,11 @@ static struct ccu_clk_map a31_clks[] = {
 	[CLK_AHB1_OHCI1]	= { 0x060, BIT(30), NULL },
 	[CLK_AHB1_OHCI2]	= { 0x060, BIT(31), NULL },
 
+	[CLK_MMC0]		= { 0x088, BIT(31), &mmc_clk_set_rate },
+	[CLK_MMC1]		= { 0x08c, BIT(31), &mmc_clk_set_rate },
+	[CLK_MMC2]		= { 0x090, BIT(31), &mmc_clk_set_rate },
+	[CLK_MMC3]		= { 0x094, BIT(31), &mmc_clk_set_rate },
+
 	[CLK_USB_PHY0]		= { 0x0cc, BIT(8), NULL },
 	[CLK_USB_PHY1]		= { 0x0cc, BIT(9), NULL },
 	[CLK_USB_PHY2]		= { 0x0cc, BIT(10), NULL },
diff --git a/drivers/clk/sunxi/clk_a64.c b/drivers/clk/sunxi/clk_a64.c
index 0574b88f9b..a3392d7e8f 100644
--- a/drivers/clk/sunxi/clk_a64.c
+++ b/drivers/clk/sunxi/clk_a64.c
@@ -22,6 +22,10 @@ static struct ccu_clk_map a64_clks[] = {
 	[CLK_BUS_OHCI0]		= { 0x060, BIT(28), NULL },
 	[CLK_BUS_OHCI1]		= { 0x060, BIT(29), NULL },
 
+	[CLK_MMC0]		= { 0x088, BIT(31), &mmc_clk_set_rate },
+	[CLK_MMC1]		= { 0x08c, BIT(31), &mmc_clk_set_rate },
+	[CLK_MMC2]		= { 0x090, BIT(31), &mmc_clk_set_rate },
+
 	[CLK_USB_PHY0]		= { 0x0cc, BIT(8), NULL },
 	[CLK_USB_PHY1]		= { 0x0cc, BIT(9), NULL },
 	[CLK_USB_HSIC]		= { 0x0cc, BIT(10), NULL },
diff --git a/drivers/clk/sunxi/clk_a83t.c b/drivers/clk/sunxi/clk_a83t.c
index cc18975a06..a2e0ac7a26 100644
--- a/drivers/clk/sunxi/clk_a83t.c
+++ b/drivers/clk/sunxi/clk_a83t.c
@@ -21,6 +21,10 @@ static struct ccu_clk_map a83t_clks[] = {
 	[CLK_BUS_EHCI1]		= { 0x060, BIT(27), NULL },
 	[CLK_BUS_OHCI0]		= { 0x060, BIT(29), NULL },
 
+	[CLK_MMC0]		= { 0x088, BIT(31), &mmc_clk_set_rate },
+	[CLK_MMC1]		= { 0x08c, BIT(31), &mmc_clk_set_rate },
+	[CLK_MMC2]		= { 0x090, BIT(31), &mmc_clk_set_rate },
+
 	[CLK_USB_PHY0]		= { 0x0cc, BIT(8), NULL },
 	[CLK_USB_PHY1]		= { 0x0cc, BIT(9), NULL },
 	[CLK_USB_HSIC]		= { 0x0cc, BIT(10), NULL },
diff --git a/drivers/clk/sunxi/clk_h3.c b/drivers/clk/sunxi/clk_h3.c
index 505616a889..316c20889d 100644
--- a/drivers/clk/sunxi/clk_h3.c
+++ b/drivers/clk/sunxi/clk_h3.c
@@ -26,6 +26,10 @@ static struct ccu_clk_map h3_clks[] = {
 	[CLK_BUS_OHCI2]		= { 0x060, BIT(30), NULL },
 	[CLK_BUS_OHCI3]		= { 0x060, BIT(31), NULL },
 
+	[CLK_MMC0]		= { 0x088, BIT(31), &mmc_clk_set_rate },
+	[CLK_MMC1]		= { 0x08c, BIT(31), &mmc_clk_set_rate },
+	[CLK_MMC2]		= { 0x090, BIT(31), &mmc_clk_set_rate },
+
 	[CLK_USB_PHY0]		= { 0x0cc, BIT(8), NULL },
 	[CLK_USB_PHY1]		= { 0x0cc, BIT(9), NULL },
 	[CLK_USB_PHY2]		= { 0x0cc, BIT(10), NULL },
diff --git a/drivers/clk/sunxi/clk_r40.c b/drivers/clk/sunxi/clk_r40.c
index 006aa138b6..9273f3b7ea 100644
--- a/drivers/clk/sunxi/clk_r40.c
+++ b/drivers/clk/sunxi/clk_r40.c
@@ -25,6 +25,10 @@ static struct ccu_clk_map r40_clks[] = {
 	[CLK_BUS_OHCI1]		= { 0x060, BIT(30), NULL },
 	[CLK_BUS_OHCI2]		= { 0x060, BIT(31), NULL },
 
+	[CLK_MMC0]		= { 0x088, BIT(31), &mmc_clk_set_rate },
+	[CLK_MMC1]		= { 0x08c, BIT(31), &mmc_clk_set_rate },
+	[CLK_MMC2]		= { 0x090, BIT(31), &mmc_clk_set_rate },
+	[CLK_MMC3]		= { 0x094, BIT(31), &mmc_clk_set_rate },
 
 	[CLK_USB_PHY0]		= { 0x0cc, BIT(8), NULL },
 	[CLK_USB_PHY1]		= { 0x0cc, BIT(9), NULL },
diff --git a/drivers/clk/sunxi/clk_sunxi.c b/drivers/clk/sunxi/clk_sunxi.c
index 791b1ac7f2..ca147ec9cc 100644
--- a/drivers/clk/sunxi/clk_sunxi.c
+++ b/drivers/clk/sunxi/clk_sunxi.c
@@ -12,6 +12,24 @@
 #include <asm/arch/ccu.h>
 #include <linux/log2.h>
 
+static ulong sunxi_clk_set_rate(struct clk *clk, ulong rate)
+{
+	struct sunxi_clk_priv *priv = dev_get_priv(clk->dev);
+	struct ccu_clk_map *map = &priv->desc->clks[clk->id];
+	u32 *base;
+
+	if (!map->ccu_clk_set_rate) {
+		debug("%s (CLK#%ld) unhandled\n", __func__, clk->id);
+		return 0;
+	}
+
+	debug("%s(#%ld) off#0x%x, BIT(%d)\n", __func__,
+	      clk->id, map->off, ilog2(map->bit));
+
+	base = priv->base + map->off;
+	return map->ccu_clk_set_rate(base, map->bit, rate);
+}
+
 static int sunxi_clk_enable(struct clk *clk)
 {
 	struct sunxi_clk_priv *priv = dev_get_priv(clk->dev);
@@ -55,4 +73,5 @@ static int sunxi_clk_disable(struct clk *clk)
 struct clk_ops sunxi_clk_ops = {
 	.enable = sunxi_clk_enable,
 	.disable = sunxi_clk_disable,
+	.set_rate = sunxi_clk_set_rate,
 };
diff --git a/drivers/clk/sunxi/clk_v3s.c b/drivers/clk/sunxi/clk_v3s.c
index 125b847bac..4af6b9abfb 100644
--- a/drivers/clk/sunxi/clk_v3s.c
+++ b/drivers/clk/sunxi/clk_v3s.c
@@ -18,6 +18,10 @@ static struct ccu_clk_map v3s_clks[] = {
 	[CLK_BUS_MMC2]		= { 0x060, BIT(10), NULL },
 	[CLK_BUS_OTG]		= { 0x060, BIT(24), NULL },
 
+	[CLK_MMC0]		= { 0x088, BIT(31), &mmc_clk_set_rate },
+	[CLK_MMC1]		= { 0x08c, BIT(31), &mmc_clk_set_rate },
+	[CLK_MMC2]		= { 0x090, BIT(31), &mmc_clk_set_rate },
+
 	[CLK_USB_PHY0]          = { 0x0cc, BIT(8), NULL },
 };
 
diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c
index 39f15eb423..bf82014a64 100644
--- a/drivers/mmc/sunxi_mmc.c
+++ b/drivers/mmc/sunxi_mmc.c
@@ -13,6 +13,7 @@
 #include <malloc.h>
 #include <mmc.h>
 #include <asm/io.h>
+#include <asm/arch/ccu.h>
 #include <asm/arch/clock.h>
 #include <asm/arch/cpu.h>
 #include <asm/arch/gpio.h>
@@ -34,6 +35,8 @@ struct sunxi_mmc_priv {
 	struct mmc_config cfg;
 };
 
+bool new_mode;
+
 #if !CONFIG_IS_ENABLED(DM_MMC)
 /* support 4 mmc hosts */
 struct sunxi_mmc_priv mmc_host[4];
@@ -95,23 +98,19 @@ static int mmc_resource_init(int sdc_no)
 }
 #endif
 
-static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz)
+int mmc_clk_set_rate(void *base, u32 bit, ulong rate)
 {
 	unsigned int pll, pll_hz, div, n, oclk_dly, sclk_dly;
-	bool new_mode = false;
 	u32 val = 0;
 
-	if (IS_ENABLED(CONFIG_MMC_SUNXI_HAS_NEW_MODE) && (priv->mmc_no == 2))
-		new_mode = true;
-
 	/*
 	 * The MMC clock has an extra /2 post-divider when operating in the new
 	 * mode.
 	 */
 	if (new_mode)
-		hz = hz * 2;
+		rate = rate * 2;
 
-	if (hz <= 24000000) {
+	if (rate <= 24000000) {
 		pll = CCM_MMC_CTRL_OSCM24;
 		pll_hz = 24000000;
 	} else {
@@ -127,8 +126,8 @@ static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz)
 #endif
 	}
 
-	div = pll_hz / hz;
-	if (pll_hz % hz)
+	div = pll_hz / rate;
+	if (pll_hz % rate)
 		div++;
 
 	n = 0;
@@ -138,32 +137,31 @@ static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz)
 	}
 
 	if (n > 3) {
-		printf("mmc %u error cannot set clock to %u\n", priv->mmc_no,
-		       hz);
+		printf("mmc error cannot set clock to %ld\n", rate);
 		return -1;
 	}
 
 	/* determine delays */
-	if (hz <= 400000) {
+	if (rate <= 400000) {
 		oclk_dly = 0;
 		sclk_dly = 0;
-	} else if (hz <= 25000000) {
+	} else if (rate <= 25000000) {
 		oclk_dly = 0;
 		sclk_dly = 5;
 #ifdef CONFIG_MACH_SUN9I
-	} else if (hz <= 52000000) {
+	} else if (rate <= 52000000) {
 		oclk_dly = 5;
 		sclk_dly = 4;
 	} else {
-		/* hz > 52000000 */
+		/* rate > 52000000 */
 		oclk_dly = 2;
 		sclk_dly = 4;
 #else
-	} else if (hz <= 52000000) {
+	} else if (rate <= 52000000) {
 		oclk_dly = 3;
 		sclk_dly = 4;
 	} else {
-		/* hz > 52000000 */
+		/* rate > 52000000 */
 		oclk_dly = 1;
 		sclk_dly = 4;
 #endif
@@ -172,22 +170,35 @@ static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz)
 	if (new_mode) {
 #ifdef CONFIG_MMC_SUNXI_HAS_NEW_MODE
 		val = CCM_MMC_CTRL_MODE_SEL_NEW;
-		setbits_le32(&priv->reg->ntsr, SUNXI_MMC_NTSR_MODE_SEL_NEW);
 #endif
 	} else {
 		val = CCM_MMC_CTRL_OCLK_DLY(oclk_dly) |
 			CCM_MMC_CTRL_SCLK_DLY(sclk_dly);
 	}
 
-	writel(CCM_MMC_CTRL_ENABLE| pll | CCM_MMC_CTRL_N(n) |
-	       CCM_MMC_CTRL_M(div) | val, priv->mclkreg);
+	writel(bit | pll | CCM_MMC_CTRL_N(n) |
+	       CCM_MMC_CTRL_M(div) | val, base);
 
-	debug("mmc %u set mod-clk req %u parent %u n %u m %u rate %u\n",
-	      priv->mmc_no, hz, pll_hz, 1u << n, div, pll_hz / (1u << n) / div);
+	debug("mmc set mod-clk req %ld parent %u n %u m %u rate %u\n",
+	      rate, pll_hz, 1u << n, div, pll_hz / (1u << n) / div);
 
 	return 0;
 }
 
+static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz)
+{
+#if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(CLK)
+#else
+	if (IS_ENABLED(CONFIG_MMC_SUNXI_HAS_NEW_MODE) && (priv->mmc_no == 2))
+		new_mode = true;
+
+	if (new_mode)
+		setbits_le32(&priv->reg->ntsr, SUNXI_MMC_NTSR_MODE_SEL_NEW);
+
+	return mmc_clk_set_rate(priv->mclkreg, CCM_MMC_CTRL_ENABLE, hz);
+#endif
+}
+
 static int mmc_update_clk(struct sunxi_mmc_priv *priv)
 {
 	unsigned int cmd;
@@ -599,6 +610,9 @@ static int sunxi_mmc_probe(struct udevice *dev)
 	cfg->f_min = 400000;
 	cfg->f_max = 52000000;
 
+	if (device_is_compatible(dev, "allwinner,sun8i-a83t-emmc"))
+		new_mode = true;
+
 	priv->reg = (void *)dev_read_addr(dev);
 
 	/* We don't have a sunxi clock driver so find the clock address here */
-- 
2.18.0.321.gffc6fa0e3



More information about the U-Boot mailing list