]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
mmc: exynos_dw_mmc: Refactor fixed CIU clock divider
authorSam Protsenko <semen.protsenko@linaro.org>
Thu, 8 Aug 2024 03:14:31 +0000 (22:14 -0500)
committerMinkyu Kang <mk7.kang@samsung.com>
Mon, 19 Aug 2024 07:09:06 +0000 (16:09 +0900)
Some chips like Exynos4412 have fixed internal CIU clock divider.
Instead of reading it from non-standard "div" dts property, store its
value in the driver internally, in static chip data associated with
corresponding compatible. This makes it possible to avoid using
host->div for storing it, so the latter can be removed safely. Also
create a helper function called exynos_dwmmc_get_ciu_div() for getting
the current div value: in case the fixed div is provided in the chip
data it will be used, otherwise the current div value is being read from
CLKSEL register.

The insights for this change were taken from dw_mmc-exynos.c driver in
Linux kernel.

No functional change.

Signed-off-by: Sam Protsenko <semen.protsenko@linaro.org>
Signed-off-by: Minkyu Kang <mk7.kang@samsung.com>
drivers/mmc/ca_dw_mmc.c
drivers/mmc/exynos_dw_mmc.c
include/dwmmc.h

index 54a2ba4795e3bb3b96187ea6df85905c75927364..1af5ec0532ea0933981e2663d97e6474eadccbba 100644 (file)
@@ -86,7 +86,7 @@ unsigned int ca_dwmci_get_mmc_clock(struct dwmci_host *host, uint freq)
                clk_div = 1;
        }
 
-       return SD_SCLK_MAX / clk_div / (host->div + 1);
+       return SD_SCLK_MAX / clk_div;
 }
 
 static int ca_dwmmc_of_to_plat(struct udevice *dev)
index fd2ced3d711d7bc8e8106f7866c43be7eddf9e4e..b5c8f592c7e85f6ecad1f2ec8eb22f71c68f226e 100644 (file)
@@ -23,6 +23,8 @@
 #define        DWMMC_MMC0_SDR_TIMING_VAL       0x03030001
 #define        DWMMC_MMC2_SDR_TIMING_VAL       0x03020001
 
+#define EXYNOS4412_FIXED_CIU_CLK_DIV   4
+
 #ifdef CONFIG_DM_MMC
 #include <dm.h>
 DECLARE_GLOBAL_DATA_PTR;
@@ -36,6 +38,7 @@ struct exynos_mmc_plat {
 /* Chip specific data */
 struct exynos_dwmmc_variant {
        u32 clksel;             /* CLKSEL register offset */
+       u8 div;                 /* (optional) fixed clock divider value: 0..7 */
 };
 
 /* Exynos implmentation specific drver private data */
@@ -126,12 +129,18 @@ static int exynos_dwmci_clksel(struct dwmci_host *host)
        return 0;
 }
 
-unsigned int exynos_dwmci_get_clk(struct dwmci_host *host, uint freq)
+/**
+ * exynos_dwmmc_get_ciu_div - Get internal clock divider value
+ * @host: MMC controller object
+ *
+ * Returns: Divider value, in range of 1..8
+ */
+static u8 exynos_dwmmc_get_ciu_div(struct dwmci_host *host)
 {
        struct dwmci_exynos_priv_data *priv = exynos_dwmmc_get_priv(host);
-       unsigned long sclk;
-       int8_t clk_div;
-       int err;
+
+       if (priv->chip->div)
+               return priv->chip->div + 1;
 
        /*
         * Since SDCLKIN is divided inside controller by the DIVRATIO
@@ -139,9 +148,17 @@ unsigned int exynos_dwmci_get_clk(struct dwmci_host *host, uint freq)
         * clock value to calculate the CLKDIV value.
         * as per user manual:cclk_in = SDCLKIN / (DIVRATIO + 1)
         */
-       clk_div = ((dwmci_readl(host, priv->chip->clksel) >> DWMCI_DIVRATIO_BIT)
-                       & DWMCI_DIVRATIO_MASK) + 1;
+       return ((dwmci_readl(host, priv->chip->clksel) >> DWMCI_DIVRATIO_BIT)
+                               & DWMCI_DIVRATIO_MASK) + 1;
+}
 
+unsigned int exynos_dwmci_get_clk(struct dwmci_host *host, uint freq)
+{
+       unsigned long sclk;
+       u8 clk_div;
+       int err;
+
+       clk_div = exynos_dwmmc_get_ciu_div(host);
        err = exynos_dwmmc_get_sclk(host, &sclk);
        if (err) {
                printf("DWMMC%d: failed to get clock rate (%d)\n",
@@ -149,11 +166,7 @@ unsigned int exynos_dwmci_get_clk(struct dwmci_host *host, uint freq)
                return 0;
        }
 
-       /*
-        * Assume to know divider value.
-        * When clock unit is broken, need to set "host->div"
-        */
-       return sclk / clk_div / (host->div + 1);
+       return sclk / clk_div;
 }
 
 static void exynos_dwmci_board_init(struct dwmci_host *host)
@@ -270,8 +283,10 @@ static int exynos_dwmmc_of_to_plat(struct udevice *dev)
                return -EINVAL;
        }
 
-       /* Extract the timing info from the node */
-       div = dev_read_u32_default(dev, "samsung,dw-mshc-ciu-div", 0);
+       if (priv->chip->div)
+               div = priv->chip->div;
+       else
+               div = dev_read_u32_default(dev, "samsung,dw-mshc-ciu-div", 0);
        err = dev_read_u32_array(dev, "samsung,dw-mshc-sdr-timing", timing, 2);
        if (err) {
                printf("DWMMC%d: Can't get sdr-timings\n", host->dev_index);
@@ -292,7 +307,6 @@ static int exynos_dwmmc_of_to_plat(struct udevice *dev)
 
        host->fifo_depth = dev_read_u32_default(dev, "fifo-depth", 0);
        host->bus_hz = dev_read_u32_default(dev, "bus_hz", 0);
-       host->div = dev_read_u32_default(dev, "div", 0);
 
        return 0;
 }
@@ -333,6 +347,7 @@ static int exynos_dwmmc_bind(struct udevice *dev)
 
 static const struct exynos_dwmmc_variant exynos4_drv_data = {
        .clksel = DWMCI_CLKSEL,
+       .div    = EXYNOS4412_FIXED_CIU_CLK_DIV - 1,
 };
 
 static const struct exynos_dwmmc_variant exynos5_drv_data = {
index a99b2f3bf0ccaf8ce90c120bcb717d956ce29dbf..8c2500da9efe4314c0d83ad521f50b0f64f0c0c5 100644 (file)
@@ -184,7 +184,6 @@ struct dwmci_idmac_regs {
  * @caps:      Capabilities - see MMC_MODE_...
  * @clock:     Current clock frequency (after internal divider), Hz
  * @bus_hz:    Bus speed in Hz, if @get_mmc_clk() is NULL
- * @div:       Arbitrary clock divider value for use by controller
  * @dev_index: Arbitrary device index for use by controller
  * @dev_id:    Arbitrary device ID for use by controller
  * @buswidth:  Bus width in bits (8 or 4)
@@ -205,7 +204,6 @@ struct dwmci_host {
        unsigned int caps;
        unsigned int clock;
        unsigned int bus_hz;
-       unsigned int div;
        int dev_index;
        int dev_id;
        int buswidth;