]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
mmc: exynos_dw_mmc: Obtain and use CIU clock via CCF API
authorSam Protsenko <semen.protsenko@linaro.org>
Thu, 8 Aug 2024 03:14:26 +0000 (22:14 -0500)
committerMinkyu Kang <mk7.kang@samsung.com>
Mon, 19 Aug 2024 07:09:06 +0000 (16:09 +0900)
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>
Signed-off-by: Minkyu Kang <mk7.kang@samsung.com>
drivers/mmc/exynos_dw_mmc.c

index ed2752391603acf950863a42b1a7e4260e91f70e..4d28ede0d75680d736d5c534f7414ea8fb7dd884 100644 (file)
@@ -4,6 +4,7 @@
  * Jaehoon Chung <jh80.chung@samsung.com>
  */
 
+#include <clk.h>
 #include <dwmmc.h>
 #include <fdtdec.h>
 #include <asm/global_data.h>
@@ -15,6 +16,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
@@ -38,6 +40,7 @@ struct dwmci_exynos_priv_data {
 #ifdef CONFIG_DM_MMC
        struct dwmci_host host;
 #endif
+       struct clk clk;
        u32 sdr_timing;
 };
 
@@ -51,6 +54,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)
+{
+#ifdef CONFIG_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;
+
+#ifdef CONFIG_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.
@@ -68,6 +126,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
@@ -77,7 +136,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.
@@ -107,19 +172,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
@@ -230,6 +295,12 @@ static int exynos_dwmmc_probe(struct udevice *dev)
        struct dwmci_host *host = &priv->host;
        int err;
 
+#ifndef CONFIG_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)