
New Exynos chips should implement clock drivers using CCF framework. In that case corresponding CCF functions can be used to get/set the clock rates. Moreover, already existing get_mmc_clk() and set_mmc_clk() calls are only implemented for CONFIG_CPU_V7A (i.e. ARM32 chips). In case of ARM64 chips that config option is not defined, so build will crash on linking stage, with errors like these:
ld: drivers/mmc/exynos_dw_mmc.o: in function `exynos_dwmci_get_sclk': undefined reference to `get_mmc_clk' ld: drivers/mmc/exynos_dw_mmc.o: in function `exynos_dwmci_set_sclk': undefined reference to `set_mmc_clk'
Fix that issue by using CCF clocks API on ARM64 platforms for getting and setting the source clock (sclk = SDCLKIN = CIU) rate. To implement this, first extract the existing ARM32 clock control code into helper functions with more generic signatures to abstract getting/setting the sclk rate. Then add CCF clock support to those functions for ARM64 platforms.
Fixes: a082a2dde061 ("EXYNOS5: DWMMC: Added FDT support for DWMMC") Signed-off-by: Sam Protsenko semen.protsenko@linaro.org --- drivers/mmc/exynos_dw_mmc.c | 87 +++++++++++++++++++++++++++++++++---- 1 file changed, 79 insertions(+), 8 deletions(-)
diff --git a/drivers/mmc/exynos_dw_mmc.c b/drivers/mmc/exynos_dw_mmc.c index 6d0872e0df50..8a3f73e3739c 100644 --- a/drivers/mmc/exynos_dw_mmc.c +++ b/drivers/mmc/exynos_dw_mmc.c @@ -4,6 +4,7 @@ * Jaehoon Chung jh80.chung@samsung.com */
+#include <clk.h> #include <common.h> #include <dwmmc.h> #include <fdtdec.h> @@ -16,6 +17,7 @@ #include <asm/arch/pinmux.h> #include <asm/arch/power.h> #include <asm/gpio.h> +#include <linux/err.h> #include <linux/printk.h>
#define DWMMC_MAX_CH_NUM 4 @@ -39,6 +41,7 @@ struct dwmci_exynos_priv_data { #ifdef CONFIG_DM_MMC struct dwmci_host host; #endif + struct clk clk; u32 sdr_timing; };
@@ -52,6 +55,61 @@ static struct dwmci_exynos_priv_data *exynos_dwmmc_get_priv( #endif }
+/** + * exynos_dwmmc_get_sclk - Get source clock (SDCLKIN) rate + * @host: MMC controller object + * @rate: Will contain clock rate, Hz + * + * Return: 0 on success or negative value on error + */ +static int exynos_dwmmc_get_sclk(struct dwmci_host *host, unsigned long *rate) +{ +#if CONFIG_IS_ENABLED(CPU_V7A) + *rate = get_mmc_clk(host->dev_index); +#else + struct dwmci_exynos_priv_data *priv = exynos_dwmmc_get_priv(host); + + *rate = clk_get_rate(&priv->clk); +#endif + + if (IS_ERR_VALUE(*rate)) + return *rate; + + return 0; +} + +/** + * exynos_dwmmc_set_sclk - Set source clock (SDCLKIN) rate + * @host: MMC controller object + * @rate: Desired clock rate, Hz + * + * Return: 0 on success or negative value on error + */ +static int exynos_dwmmc_set_sclk(struct dwmci_host *host, unsigned long rate) +{ + int err; + +#if CONFIG_IS_ENABLED(CPU_V7A) + unsigned long sclk; + unsigned int div; + + err = exynos_dwmmc_get_sclk(host, &sclk); + if (err) + return err; + + div = DIV_ROUND_UP(sclk, rate); + set_mmc_clk(host->dev_index, div); +#else + struct dwmci_exynos_priv_data *priv = exynos_dwmmc_get_priv(host); + + err = clk_set_rate(&priv->clk, rate); + if (err < 0) + return err; +#endif + + return 0; +} + /* * Function used as callback function to initialise the * CLKSEL register for every mmc channel. @@ -69,6 +127,7 @@ unsigned int exynos_dwmci_get_clk(struct dwmci_host *host, uint freq) { unsigned long sclk; int8_t clk_div; + int err;
/* * Since SDCLKIN is divided inside controller by the DIVRATIO @@ -78,7 +137,13 @@ unsigned int exynos_dwmci_get_clk(struct dwmci_host *host, uint freq) */ clk_div = ((dwmci_readl(host, DWMCI_CLKSEL) >> DWMCI_DIVRATIO_BIT) & DWMCI_DIVRATIO_MASK) + 1; - sclk = get_mmc_clk(host->dev_index); + + err = exynos_dwmmc_get_sclk(host, &sclk); + if (err) { + printf("DWMMC%d: failed to get clock rate (%d)\n", + host->dev_index, err); + return 0; + }
/* * Assume to know divider value. @@ -108,19 +173,19 @@ static void exynos_dwmci_board_init(struct dwmci_host *host)
static int exynos_dwmci_core_init(struct dwmci_host *host) { - unsigned int div; - unsigned long freq, sclk; + unsigned long freq; + int err;
if (host->bus_hz) freq = host->bus_hz; else freq = DWMMC_MAX_FREQ;
- /* request mmc clock vlaue of 52MHz. */ - sclk = get_mmc_clk(host->dev_index); - div = DIV_ROUND_UP(sclk, freq); - /* set the clock divisor for mmc */ - set_mmc_clk(host->dev_index, div); + err = exynos_dwmmc_set_sclk(host, freq); + if (err) { + printf("DWMMC%d: failed to set clock rate on probe (%d); " + "continue anyway\n", host->dev_index, err); + }
host->name = "EXYNOS DWMMC"; #ifdef CONFIG_EXYNOS5420 @@ -231,6 +296,12 @@ static int exynos_dwmmc_probe(struct udevice *dev) struct dwmci_host *host = &priv->host; int err;
+#if !CONFIG_IS_ENABLED(CPU_V7A) + err = clk_get_by_index(dev, 1, &priv->clk); /* ciu */ + if (err) + return err; +#endif + err = exynos_dwmci_get_config(dev, gd->fdt_blob, dev_of_offset(dev), host, priv); if (err)