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 /arch/arm/mach-omap2/devices.c | |
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>
Diffstat (limited to 'arch/arm/mach-omap2/devices.c')
-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(); |