[U-Boot,v2,20/53] clk: sunxi: Implement direct MMC clocks

Message ID 20180810060711.6547-21-jagan@amarulasolutions.com
State Superseded
Delegated to: Jagannadha Sutradharudu Teki
Headers show
Series
  • clk: Add Allwinner CLK, RESET support
Related show

Commit Message

Jagan Teki Aug. 10, 2018, 6:06 a.m.
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.

Cc: Jaehoon Chung <jh80.chung@samsung.com>
Signed-off-by: Jagan Teki <jagan@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(-)

Patch

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 bc4ae7352b..fbac0ad751 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 62770a58fe..0b5406c5b3 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 71f3510c74..62cd6d6464 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 85dd06ee2d..f467187c01 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 ab2cc45640..e0d757debe 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 */