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 <ja...@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

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
https://lists.denx.de/listinfo/u-boot

Reply via email to