mirror of
https://source.denx.de/u-boot/u-boot.git
synced 2026-06-13 15:03:58 +03:00
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: a082a2dde0 ("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>
This commit is contained in:
committed by
Minkyu Kang
parent
f6b7f9e7bf
commit
8303fd6f57
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user