diff options
| author | Kevin Hilman <khilman@deeprootsystems.com> | 2008-12-10 20:37:17 -0500 |
|---|---|---|
| committer | Tony Lindgren <tony@atomide.com> | 2008-12-10 20:37:17 -0500 |
| commit | 917fa280e5e99edcae44a34feab295a59922d16c (patch) | |
| tree | bcd3aff12a5a40b1be58eced9bdb2f7a43922f2f | |
| parent | 90c62bf08f5823faa097271f3346a9142769b9ac (diff) | |
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>
| -rw-r--r-- | arch/arm/mach-omap2/devices.c | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c index 6e03272b0521..9d7216ff6c9f 100644 --- a/arch/arm/mach-omap2/devices.c +++ b/arch/arm/mach-omap2/devices.c | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
| 15 | #include <linux/platform_device.h> | 15 | #include <linux/platform_device.h> |
| 16 | #include <linux/io.h> | 16 | #include <linux/io.h> |
| 17 | #include <linux/clk.h> | ||
| 17 | 18 | ||
| 18 | #include <mach/hardware.h> | 19 | #include <mach/hardware.h> |
| 19 | #include <asm/mach-types.h> | 20 | #include <asm/mach-types.h> |
| @@ -299,6 +300,89 @@ static inline void omap_init_sha1_md5(void) { } | |||
| 299 | 300 | ||
| 300 | /*-------------------------------------------------------------------------*/ | 301 | /*-------------------------------------------------------------------------*/ |
| 301 | 302 | ||
| 303 | #ifdef CONFIG_ARCH_OMAP3 | ||
| 304 | |||
| 305 | #define MMCHS_SYSCONFIG 0x0010 | ||
| 306 | #define MMCHS_SYSCONFIG_SWRESET (1 << 1) | ||
| 307 | #define MMCHS_SYSSTATUS 0x0014 | ||
| 308 | #define MMCHS_SYSSTATUS_RESETDONE (1 << 0) | ||
| 309 | |||
| 310 | static struct platform_device dummy_pdev = { | ||
| 311 | .dev = { | ||
| 312 | .bus = &platform_bus_type, | ||
| 313 | }, | ||
| 314 | }; | ||
| 315 | |||
| 316 | /** | ||
| 317 | * omap_hsmmc_reset() - Full reset of each HS-MMC controller | ||
| 318 | * | ||
| 319 | * Ensure that each MMC controller is fully reset. Controllers | ||
| 320 | * left in an unknown state (by bootloader) may prevent retention | ||
| 321 | * or OFF-mode. This is especially important in cases where the | ||
| 322 | * MMC driver is not enabled, _or_ built as a module. | ||
| 323 | * | ||
| 324 | * In order for reset to work, interface, functional and debounce | ||
| 325 | * clocks must be enabled. The debounce clock comes from func_32k_clk | ||
| 326 | * and is not under SW control, so we only enable i- and f-clocks. | ||
| 327 | **/ | ||
| 328 | static void __init omap_hsmmc_reset(void) | ||
| 329 | { | ||
| 330 | u32 i, nr_controllers = cpu_is_omap34xx() ? OMAP34XX_NR_MMC : | ||
| 331 | OMAP24XX_NR_MMC; | ||
| 332 | |||
| 333 | for (i = 0; i < nr_controllers; i++) { | ||
| 334 | u32 v, base = 0; | ||
| 335 | struct clk *iclk, *fclk; | ||
| 336 | struct device *dev = &dummy_pdev.dev; | ||
| 337 | |||
| 338 | switch (i) { | ||
| 339 | case 0: | ||
| 340 | base = OMAP2_MMC1_BASE; | ||
| 341 | break; | ||
| 342 | case 1: | ||
| 343 | base = OMAP2_MMC2_BASE; | ||
| 344 | break; | ||
| 345 | case 2: | ||
| 346 | base = OMAP3_MMC3_BASE; | ||
| 347 | break; | ||
| 348 | } | ||
| 349 | |||
| 350 | dummy_pdev.id = i; | ||
| 351 | iclk = clk_get(dev, "mmchs_ick"); | ||
| 352 | if (iclk && clk_enable(iclk)) | ||
| 353 | iclk = NULL; | ||
| 354 | |||
| 355 | fclk = clk_get(dev, "mmchs_fck"); | ||
| 356 | if (fclk && clk_enable(fclk)) | ||
| 357 | fclk = NULL; | ||
| 358 | |||
| 359 | if (!iclk || !fclk) { | ||
| 360 | printk(KERN_WARNING | ||
| 361 | "%s: Unable to enable clocks for MMC%d, " | ||
| 362 | "cannot reset.\n", __func__, i); | ||
| 363 | break; | ||
| 364 | } | ||
| 365 | |||
| 366 | omap_writel(MMCHS_SYSCONFIG_SWRESET, base + MMCHS_SYSCONFIG); | ||
| 367 | v = omap_readl(base + MMCHS_SYSSTATUS); | ||
| 368 | while (!(omap_readl(base + MMCHS_SYSSTATUS) & | ||
| 369 | MMCHS_SYSSTATUS_RESETDONE)) | ||
| 370 | cpu_relax(); | ||
| 371 | |||
| 372 | if (fclk) { | ||
| 373 | clk_disable(fclk); | ||
| 374 | clk_put(fclk); | ||
| 375 | } | ||
| 376 | if (iclk) { | ||
| 377 | clk_disable(iclk); | ||
| 378 | clk_put(iclk); | ||
| 379 | } | ||
| 380 | } | ||
| 381 | } | ||
| 382 | #else | ||
| 383 | static inline void omap_hsmmc_reset(void) {} | ||
| 384 | #endif | ||
| 385 | |||
| 302 | #if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) || \ | 386 | #if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) || \ |
| 303 | defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE) | 387 | defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE) |
| 304 | 388 | ||
| @@ -418,6 +502,7 @@ static int __init omap2_init_devices(void) | |||
| 418 | /* please keep these calls, and their implementations above, | 502 | /* please keep these calls, and their implementations above, |
| 419 | * in alphabetical order so they're easier to sort through. | 503 | * in alphabetical order so they're easier to sort through. |
| 420 | */ | 504 | */ |
| 505 | omap_hsmmc_reset(); | ||
| 421 | omap_init_mbox(); | 506 | omap_init_mbox(); |
| 422 | omap_init_mcspi(); | 507 | omap_init_mcspi(); |
| 423 | omap_hdq_init(); | 508 | omap_hdq_init(); |
