exynos5420: Setup clocks for MMC bus controller.

To configure source clocks on Exynos 5420 for MMC drivers.
Some registers are different from the 5250. FSYS now has two parts
and MMC uses FSYS2. The MMC block uses MPLL as the clock source.
The "high-speed" MMC interface runs as 52MHz, so divider is set
accordingly.

Also, the MMC driver has changed from MSHCI (Mobile Storage Host Controller
Interface) to DWMCI (DesignWare MMC Controller Interface).

Change-Id: I9ba9cf43e2f2dcd9da747888c0c7676bd545177b
Signed-off-by: Hung-Te Lin <hungte@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/60858
Reviewed-by: David Hendricks <dhendrix@chromium.org>
Reviewed-on: http://review.coreboot.org/4354
Tested-by: build bot (Jenkins)
Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
This commit is contained in:
Hung-Te Lin 2013-07-03 19:07:21 +08:00 committed by Stefan Reinauer
parent 865912cec0
commit f6d6e62aaf
4 changed files with 64 additions and 15 deletions

View File

@ -85,6 +85,15 @@ unsigned long clock_get_periph_rate(enum periph_id peripheral);
*/ */
int clock_set_mshci(enum periph_id peripheral); int clock_set_mshci(enum periph_id peripheral);
/*
* Set dwmci controller instances clock drivder
*
* @param enum periph_id instance of the dwmci controller
*
* Return 0 if ok else -1
*/
int clock_set_dwmci(enum periph_id peripheral);
/* /*
* Sets the epll clockrate * Sets the epll clockrate
* *

View File

@ -66,6 +66,11 @@ static struct st_epll_con_val epll_div[] = {
{ 180633600, 0, 45, 3, 1, 10381 } { 180633600, 0, 45, 3, 1, 10381 }
}; };
static inline unsigned long div_round_up(unsigned int n, unsigned int d)
{
return (n + d - 1) / d;
}
/* exynos5: return pll clock frequency */ /* exynos5: return pll clock frequency */
unsigned long get_pll_clk(int pllreg) unsigned long get_pll_clk(int pllreg)
{ {
@ -177,13 +182,6 @@ unsigned long clock_get_periph_rate(enum periph_id peripheral)
src = readl(&clk->clk_src_isp); src = readl(&clk->clk_src_isp);
div = readl(&clk->clk_div_isp1); div = readl(&clk->clk_div_isp1);
break; break;
case PERIPH_ID_SDMMC0:
case PERIPH_ID_SDMMC1:
case PERIPH_ID_SDMMC2:
case PERIPH_ID_SDMMC3:
src = readl(&clk->clk_src_fsys);
div = readl(&clk->clk_div_fsys1);
break;
case PERIPH_ID_I2C0: case PERIPH_ID_I2C0:
case PERIPH_ID_I2C1: case PERIPH_ID_I2C1:
case PERIPH_ID_I2C2: case PERIPH_ID_I2C2:
@ -250,6 +248,35 @@ unsigned long get_arm_clk(void)
return armclk; return armclk;
} }
/* exynos5: get the mmc clock */
static unsigned long get_mmc_clk(int dev_index)
{
struct exynos5420_clock *clk = samsung_get_base_clock();
unsigned long uclk, sclk;
unsigned int sel, ratio;
int shift = 0;
sel = readl(&clk->clk_src_fsys);
sel = (sel >> ((dev_index * 4) + 8)) & 0x7;
if (sel == 0x3)
sclk = get_pll_clk(MPLL);
else if (sel == 0x6)
sclk = get_pll_clk(EPLL);
else
return 0;
ratio = readl(&clk->clk_div_fsys1);
shift = dev_index * 10;
ratio = (ratio >> shift) & 0x3ff;
uclk = (sclk / (ratio + 1));
printk(BIOS_DEBUG, "%s(%d): %lu\n", __func__, dev_index, uclk);
return uclk;
}
/* exynos5: set the mmc clock */ /* exynos5: set the mmc clock */
void set_mmc_clk(int dev_index, unsigned int div) void set_mmc_clk(int dev_index, unsigned int div)
{ {
@ -266,6 +293,24 @@ void set_mmc_clk(int dev_index, unsigned int div)
writel(val, addr); writel(val, addr);
} }
/* Set DW MMC Controller clock */
int clock_set_dwmci(enum periph_id peripheral)
{
/* Request MMC clock value to 52MHz. */
const unsigned long freq = 52000000;
unsigned long sclk, div;
int device_index = (int)peripheral - (int)PERIPH_ID_SDMMC0;
ASSERT(device_index >= 0 && device_index < 4);
sclk = get_mmc_clk(device_index);
if (!sclk) {
return -1;
}
div = div_round_up(sclk, freq);
set_mmc_clk(device_index, div);
return 0;
}
void clock_ll_set_pre_ratio(enum periph_id periph_id, unsigned divisor) void clock_ll_set_pre_ratio(enum periph_id periph_id, unsigned divisor)
{ {
struct exynos5420_clock *clk = samsung_get_base_clock(); struct exynos5420_clock *clk = samsung_get_base_clock();

View File

@ -80,8 +80,8 @@ static void exynos_pinmux_sdmmc(int start, int start_ext)
void exynos_pinmux_sdmmc0(void) void exynos_pinmux_sdmmc0(void)
{ {
gpio_set_pull(GPIO_C02, GPIO_PULL_UP);
exynos_pinmux_sdmmc(GPIO_C00, GPIO_C30); exynos_pinmux_sdmmc(GPIO_C00, GPIO_C30);
gpio_set_pull(GPIO_C02, GPIO_PULL_UP);
} }
void exynos_pinmux_sdmmc1(void) void exynos_pinmux_sdmmc1(void)

View File

@ -113,17 +113,12 @@ static void setup_power(int is_resume)
static void setup_storage(void) static void setup_storage(void)
{ {
/* MMC0: Fixed, 8 bit mode, connected with GPIO. */ /* MMC0: Fixed, 8 bit mode, connected with GPIO. */
if (clock_set_mshci(PERIPH_ID_SDMMC0)) if (clock_set_dwmci(PERIPH_ID_SDMMC0))
printk(BIOS_CRIT, "%s: Failed to set MMC0 clock.\n", __func__); printk(BIOS_CRIT, "%s: Failed to set MMC0 clock.\n", __func__);
if (gpio_direction_output(MMC0_GPIO_PIN, 1)) {
printk(BIOS_CRIT, "%s: Unable to power on MMC0.\n", __func__);
}
gpio_set_pull(MMC0_GPIO_PIN, GPIO_PULL_NONE);
gpio_set_drv(MMC0_GPIO_PIN, GPIO_DRV_4X);
exynos_pinmux_sdmmc0(); exynos_pinmux_sdmmc0();
/* MMC2: Removable, 4 bit mode, no GPIO. */ /* MMC2: Removable, 4 bit mode, no GPIO. */
clock_set_mshci(PERIPH_ID_SDMMC2); clock_set_dwmci(PERIPH_ID_SDMMC2);
exynos_pinmux_sdmmc2(); exynos_pinmux_sdmmc2();
} }