diff options
author | Simon Glass <sjg@chromium.org> | 2011-06-03 09:12:34 -0700 |
---|---|---|
committer | Simon Glass <sjg@chromium.org> | 2011-08-29 10:39:14 -0700 |
commit | 3ae75e44809b5c64c2df3e41a56f189f8ddba112 (patch) | |
tree | 3b5a36176706007541941431083c3f9d91fd2643 /drivers/mmc | |
parent | 3ed809965c6beafddb38431f8f2c78e0b03790d8 (diff) |
Tidy up MMC to use to clock API
The MMC driver now uses the peripheral ID to identify which peripheral
to use rather than the address of that peripheral.
BUG=chromium-os:11623
TEST=build and boot U-Boot on Seaboard
mmc part 0; ext2ls mmc 0:3
Change-Id: I42c09bca572349f2c9c2469959857d247a6a359f
Reviewed-on: http://gerrit.chromium.org/gerrit/2035
Tested-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Anton Staaf <robotboy@chromium.org>
Tested-by: Anton Staaf <robotboy@chromium.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/tegra2_mmc.c | 149 | ||||
-rw-r--r-- | drivers/mmc/tegra2_mmc.h | 27 |
2 files changed, 68 insertions, 108 deletions
diff --git a/drivers/mmc/tegra2_mmc.c b/drivers/mmc/tegra2_mmc.c index f0fd888e4e3..5ef3e33c67b 100644 --- a/drivers/mmc/tegra2_mmc.c +++ b/drivers/mmc/tegra2_mmc.c @@ -27,37 +27,34 @@ #include <asm/arch/clk_rst.h> #include <asm/arch/clock.h> #include <malloc.h> +#include <asm/clocks.h> #include "tegra2_mmc.h" -/* support 4 mmc hosts */ -struct mmc mmc_dev[4]; -struct mmc_host mmc_host[4]; +enum { + MAX_HOSTS = 4, /* support 4 mmc hosts */ +}; -static inline struct tegra2_mmc *tegra2_get_base_mmc(int dev_index) -{ - unsigned long offset; - debug("tegra2_get_base_mmc: dev_index = %d\n", dev_index); - - switch (dev_index) { - case 0: - offset = TEGRA2_SDMMC4_BASE; - break; - case 1: - offset = TEGRA2_SDMMC3_BASE; - break; - case 2: - offset = TEGRA2_SDMMC2_BASE; - break; - case 3: - offset = TEGRA2_SDMMC1_BASE; - break; - default: - offset = TEGRA2_SDMMC4_BASE; - break; - } - return (struct tegra2_mmc *)(offset); -} +struct mmc_host { + struct tegra2_mmc *reg; + unsigned int version; /* SDHCI spec. version */ + unsigned int clock; /* Current clock (MHz) */ + enum periph_id mmc_id; /* Peripheral ID of the SDMMC we are using */ + + /* + * We need a per-host bounce buffer that will be optionally used + * when the mmc_send_cmd function is called with an unaligned + * buffer. The bounce buffer will be allocated in that case and + * a copy to and from it will be used so that DMA destination and + * source pointers can be aligned. + */ + char * bounce; + uint bounce_size; + struct mmc_data bounce_data; +}; + +struct mmc mmc_dev[MAX_HOSTS]; +struct mmc_host mmc_host[MAX_HOSTS]; /* * Flush the data cache lines associated with the given mmc_data structs buffer. @@ -280,7 +277,6 @@ static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_host *host = (struct mmc_host *)mmc->priv; int flags, i; int result; - unsigned int timeout; unsigned int mask; unsigned int retry = 0x100000; debug(" mmc_send_cmd called\n"); @@ -449,52 +445,24 @@ static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, static void mmc_change_clock(struct mmc_host *host, uint clock) { - int div, hw_div; + int div; unsigned short clk; unsigned long timeout; - unsigned int hostbase; - enum periph_id mmc_id = PERIPH_ID_SDMMC1; debug(" mmc_change_clock called\n"); - /* Change Tegra2 SDMMCx clock divisor here */ - /* Source is 216MHz, PLLP_OUT0 */ + /* + * Change Tegra2 SDMMCx clock divisor here. Source is 216MHz, + * PLLP_OUT0 + */ if (clock == 0) goto out; - - div = 1; - if (clock <= 400000) { - hw_div = ((9-1)<<1); /* Best match is 375KHz */ - div = 64; - } else if (clock <= 20000000) - hw_div = ((11-1)<<1); /* Best match is 19.6MHz */ - else if (clock <= 26000000) - hw_div = ((9-1)<<1); /* Use 24MHz */ - else - hw_div = ((4-1)<<1) + 1; /* 4.5 divisor for 48MHz */ - - debug("mmc_change_clock: hw_div = %d, card clock div = %d\n", - hw_div, div); - - /* Change SDMMCx divisor */ - - hostbase = readl(&host->base); - debug("mmc_change_clock: hostbase = %08X\n", hostbase); - - /* TODO: We need to record the PERIPH_ID, not the hostbase */ - if (hostbase == TEGRA2_SDMMC1_BASE) - mmc_id = PERIPH_ID_SDMMC1; - else if (hostbase == TEGRA2_SDMMC2_BASE) - mmc_id = PERIPH_ID_SDMMC2; - else if (hostbase == TEGRA2_SDMMC3_BASE) - mmc_id = PERIPH_ID_SDMMC3; - else if (hostbase == TEGRA2_SDMMC4_BASE) - mmc_id = PERIPH_ID_SDMMC4; - clock_ll_set_source_divisor(mmc_id, 0, hw_div); + clock_adjust_periph_pll_div(host->mmc_id, CLOCK_ID_PERIPH, clock, + &div); + debug("div = %d\n", div); writew(0, &host->reg->clkcon); - div >>= 1; /* * CLKCON * SELFREQ[15:8] : base clock divided by value @@ -502,6 +470,7 @@ static void mmc_change_clock(struct mmc_host *host, uint clock) * STBLINTCLK[1] : Internal Clock Stable * ENINTCLK[0] : Internal Clock Enable */ + div >>= 1; clk = (div << 8) | (1 << 0); writew(clk, &host->reg->clkcon); @@ -534,7 +503,6 @@ static void mmc_set_ios(struct mmc *mmc) debug("bus_width: %x, clock: %d\n", mmc->bus_width, mmc->clock); /* Change clock first */ - mmc_change_clock(host, mmc->clock); ctrl = readb(&host->reg->hostctl); @@ -627,16 +595,31 @@ static int mmc_core_init(struct mmc *mmc) return 0; } -static int tegra2_mmc_initialize(int dev_index, int bus_width) +static int init_port(unsigned dev_index, enum periph_id mmc_id, + struct tegra2_mmc *reg, int bus_width) { + struct mmc_host *host; struct mmc *mmc; - debug(" mmc_initialize called\n"); + debug(" tegra2_mmc_init: index %d, bus width %d\n", + dev_index, bus_width); + if (dev_index >= MAX_HOSTS) + return -1; + + /* Do the SDMMC resets/clock enables */ + clock_start_periph_pll(mmc_id, CLOCK_ID_PERIPH, CLK_20M); mmc = &mmc_dev[dev_index]; sprintf(mmc->name, "Tegra2 SD/MMC"); - mmc->priv = &mmc_host[dev_index]; + host = &mmc_host[dev_index]; + host->clock = 0; + host->reg = reg; + host->mmc_id = mmc_id; + host->bounce = NULL; + host->bounce_size = 0; + + mmc->priv = host; mmc->send_cmd = mmc_send_cmd; mmc->set_ios = mmc_set_ios; mmc->init = mmc_core_init; @@ -653,26 +636,28 @@ static int tegra2_mmc_initialize(int dev_index, int bus_width) * low-speed SDIO card frequency (actually 400KHz) * max freq is highest HS eMMC clock as per the SD/MMC spec * (actually 52MHz) - * Both of these are the closest equivalents w/216MHz source - * clock and Tegra2 SDMMC divisors. */ - mmc->f_min = 375000; - mmc->f_max = 48000000; - - mmc_host[dev_index].clock = 0; - mmc_host[dev_index].reg = tegra2_get_base_mmc(dev_index); - mmc_host[dev_index].base = (unsigned int)mmc_host[dev_index].reg; - mmc_host[dev_index].bounce = NULL; - mmc_host[dev_index].bounce_size = 0; + mmc->f_min = CLK_400K; + mmc->f_max = CLK_52M; mmc_register(mmc); return 0; } -int tegra2_mmc_init(int dev_index, int bus_width) + +int tegra2_mmc_init(const void *blob) { - debug(" tegra2_mmc_init: index %d, bus width %d\n", - dev_index, bus_width); - return tegra2_mmc_initialize(dev_index, bus_width); + /* For now these are still hard-coded for Seaboard */ + + /* init dev 0, eMMC chip, with 4-bit bus */ + if (init_port(0, PERIPH_ID_SDMMC4, + (struct tegra2_mmc *)NV_PA_SDMMC4_BASE, 4)) + return -1; + + /* init dev 1, SD slot, with 4-bit bus */ + if (init_port(1, PERIPH_ID_SDMMC3, + (struct tegra2_mmc *)NV_PA_SDMMC3_BASE, 4)) + return -1; + return 0; } diff --git a/drivers/mmc/tegra2_mmc.h b/drivers/mmc/tegra2_mmc.h index d37818653d6..f9c22d6d987 100644 --- a/drivers/mmc/tegra2_mmc.h +++ b/drivers/mmc/tegra2_mmc.h @@ -23,13 +23,6 @@ #ifndef __TEGRA2_MMC_H_ #define __TEGRA2_MMC_H_ -#include <mmc.h> - -#define TEGRA2_SDMMC1_BASE 0xC8000000 -#define TEGRA2_SDMMC2_BASE 0xC8000200 -#define TEGRA2_SDMMC3_BASE 0xC8000400 -#define TEGRA2_SDMMC4_BASE 0xC8000600 - #ifndef __ASSEMBLY__ struct tegra2_mmc { unsigned int sysad; /* _SYSTEM_ADDRESS_0 */ @@ -71,25 +64,7 @@ struct tegra2_mmc { unsigned char res6[0x100]; /* RESERVED, offset 100h-1FFh */ }; -struct mmc_host { - struct tegra2_mmc *reg; - unsigned int version; /* SDHCI spec. version */ - unsigned int clock; /* Current clock (MHz) */ - unsigned int base; /* Base address, SDMMC1/2/3/4 */ - - /* - * We need a per-host bounce buffer that will be optionally used - * when the mmc_send_cmd function is called with an unaligned - * buffer. The bounce buffer will be allocated in that case and - * a copy to and from it will be used so that DMA destination and - * source pointers can be aligned. - */ - char * bounce; - uint bounce_size; - struct mmc_data bounce_data; -}; - -int tegra2_mmc_init(int dev_index, int bus_width); +int tegra2_mmc_init(const void *blob); #endif /* __ASSEMBLY__ */ #endif /* __TEGRA2_MMC_H_ */ |