mirror of
https://github.com/torvalds/linux.git
synced 2024-11-17 09:31:50 +00:00
omap mmc: force MMC module reset on boot
The bootloader may leave the MMC in a state which prevents hitting retention. Even when MMC is not compiled in, each MMC module needs to be forced into reset. Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
This commit is contained in:
parent
90c62bf08f
commit
917fa280e5
@ -14,6 +14,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <asm/mach-types.h>
|
||||
@ -299,6 +300,89 @@ static inline void omap_init_sha1_md5(void) { }
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#ifdef CONFIG_ARCH_OMAP3
|
||||
|
||||
#define MMCHS_SYSCONFIG 0x0010
|
||||
#define MMCHS_SYSCONFIG_SWRESET (1 << 1)
|
||||
#define MMCHS_SYSSTATUS 0x0014
|
||||
#define MMCHS_SYSSTATUS_RESETDONE (1 << 0)
|
||||
|
||||
static struct platform_device dummy_pdev = {
|
||||
.dev = {
|
||||
.bus = &platform_bus_type,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* omap_hsmmc_reset() - Full reset of each HS-MMC controller
|
||||
*
|
||||
* Ensure that each MMC controller is fully reset. Controllers
|
||||
* left in an unknown state (by bootloader) may prevent retention
|
||||
* or OFF-mode. This is especially important in cases where the
|
||||
* MMC driver is not enabled, _or_ built as a module.
|
||||
*
|
||||
* In order for reset to work, interface, functional and debounce
|
||||
* clocks must be enabled. The debounce clock comes from func_32k_clk
|
||||
* and is not under SW control, so we only enable i- and f-clocks.
|
||||
**/
|
||||
static void __init omap_hsmmc_reset(void)
|
||||
{
|
||||
u32 i, nr_controllers = cpu_is_omap34xx() ? OMAP34XX_NR_MMC :
|
||||
OMAP24XX_NR_MMC;
|
||||
|
||||
for (i = 0; i < nr_controllers; i++) {
|
||||
u32 v, base = 0;
|
||||
struct clk *iclk, *fclk;
|
||||
struct device *dev = &dummy_pdev.dev;
|
||||
|
||||
switch (i) {
|
||||
case 0:
|
||||
base = OMAP2_MMC1_BASE;
|
||||
break;
|
||||
case 1:
|
||||
base = OMAP2_MMC2_BASE;
|
||||
break;
|
||||
case 2:
|
||||
base = OMAP3_MMC3_BASE;
|
||||
break;
|
||||
}
|
||||
|
||||
dummy_pdev.id = i;
|
||||
iclk = clk_get(dev, "mmchs_ick");
|
||||
if (iclk && clk_enable(iclk))
|
||||
iclk = NULL;
|
||||
|
||||
fclk = clk_get(dev, "mmchs_fck");
|
||||
if (fclk && clk_enable(fclk))
|
||||
fclk = NULL;
|
||||
|
||||
if (!iclk || !fclk) {
|
||||
printk(KERN_WARNING
|
||||
"%s: Unable to enable clocks for MMC%d, "
|
||||
"cannot reset.\n", __func__, i);
|
||||
break;
|
||||
}
|
||||
|
||||
omap_writel(MMCHS_SYSCONFIG_SWRESET, base + MMCHS_SYSCONFIG);
|
||||
v = omap_readl(base + MMCHS_SYSSTATUS);
|
||||
while (!(omap_readl(base + MMCHS_SYSSTATUS) &
|
||||
MMCHS_SYSSTATUS_RESETDONE))
|
||||
cpu_relax();
|
||||
|
||||
if (fclk) {
|
||||
clk_disable(fclk);
|
||||
clk_put(fclk);
|
||||
}
|
||||
if (iclk) {
|
||||
clk_disable(iclk);
|
||||
clk_put(iclk);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
static inline void omap_hsmmc_reset(void) {}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) || \
|
||||
defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)
|
||||
|
||||
@ -418,6 +502,7 @@ static int __init omap2_init_devices(void)
|
||||
/* please keep these calls, and their implementations above,
|
||||
* in alphabetical order so they're easier to sort through.
|
||||
*/
|
||||
omap_hsmmc_reset();
|
||||
omap_init_mbox();
|
||||
omap_init_mcspi();
|
||||
omap_hdq_init();
|
||||
|
Loading…
Reference in New Issue
Block a user