[U-Boot] [PATCH v2 20/53] clk: sunxi: Implement direct MMC clocks
Jagan Teki
jagan at amarulasolutions.com
Fri Aug 10 06:06:38 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.
Cc: Jaehoon Chung <jh80.chung at samsung.com>
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 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 */
--
2.18.0.321.gffc6fa0e3
More information about the U-Boot
mailing list