From mboxrd@z Thu Jan 1 00:00:00 1970 From: Jagan Teki Date: Sun, 19 Aug 2018 19:26:36 +0530 Subject: [U-Boot] [PATCH v3 19/58] clk: sunxi: Implement direct MMC clocks In-Reply-To: <20180819135715.15799-1-jagan@amarulasolutions.com> References: <20180819135715.15799-1-jagan@amarulasolutions.com> Message-ID: <20180819135715.15799-20-jagan@amarulasolutions.com> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de 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 Signed-off-by: Jagan Teki --- 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 #include +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 #include #include +#include #include #include #include @@ -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