From: Sam Protsenko Date: Thu, 8 Aug 2024 03:14:26 +0000 (-0500) Subject: mmc: exynos_dw_mmc: Obtain and use CIU clock via CCF API X-Git-Url: http://git.dujemihanovic.xyz/img/%7B%7B%20%24image.RelPermalink%20%7D%7D?a=commitdiff_plain;h=8303fd6f5755d32d84c0625165d4707d9e49558a;p=u-boot.git mmc: exynos_dw_mmc: Obtain and use CIU clock via CCF API 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 Signed-off-by: Minkyu Kang --- diff --git a/drivers/mmc/exynos_dw_mmc.c b/drivers/mmc/exynos_dw_mmc.c index ed27523916..4d28ede0d7 100644 --- a/drivers/mmc/exynos_dw_mmc.c +++ b/drivers/mmc/exynos_dw_mmc.c @@ -4,6 +4,7 @@ * Jaehoon Chung */ +#include #include #include #include @@ -15,6 +16,7 @@ #include #include #include +#include #include #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)