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:
committed by
Tony Lindgren
parent
90c62bf08f
commit
917fa280e5
@@ -14,6 +14,7 @@
|
|||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
|
#include <linux/clk.h>
|
||||||
|
|
||||||
#include <mach/hardware.h>
|
#include <mach/hardware.h>
|
||||||
#include <asm/mach-types.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) || \
|
#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) || \
|
||||||
defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_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,
|
/* please keep these calls, and their implementations above,
|
||||||
* in alphabetical order so they're easier to sort through.
|
* in alphabetical order so they're easier to sort through.
|
||||||
*/
|
*/
|
||||||
|
omap_hsmmc_reset();
|
||||||
omap_init_mbox();
|
omap_init_mbox();
|
||||||
omap_init_mcspi();
|
omap_init_mcspi();
|
||||||
omap_hdq_init();
|
omap_hdq_init();
|
||||||
|
Reference in New Issue
Block a user