Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 917fa280 authored by Kevin Hilman's avatar Kevin Hilman Committed by Tony Lindgren
Browse files

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: default avatarKevin Hilman <khilman@deeprootsystems.com>

parent 90c62bf0
Loading
Loading
Loading
Loading
+85 −0
Original line number Diff line number Diff line
@@ -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();