aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/pm24xx.c
diff options
context:
space:
mode:
authorPaul Walmsley <paul@pwsan.com>2010-01-26 22:13:01 -0500
committerPaul Walmsley <paul@pwsan.com>2010-01-26 22:13:01 -0500
commit369d5614457384edcf62c5f39b03dd20be6ea1df (patch)
tree4ad04d48f3049ff2d88e8ddca35fb0ad8597d12c /arch/arm/mach-omap2/pm24xx.c
parente909d62a8afda7a224a7e322cf2f387d69ca771f (diff)
OMAP clockdomains: add usecounting for wakeup and sleep dependencies
Add usecounting for wakeup and sleep dependencies. In the current situation, if several functions add dependencies on the same clockdomains, when the first dependency removal function is called, the dependency will be incorrectly removed from the hardware. Add clkdm_clear_all_wkdeps() and clkdm_clear_all_sleepdeps(), which provide a fast and usecounting-consistent way to clear all hardware clockdomain dependencies, since accesses to these registers can be quite slow. pm{2,3}4xx.c has been updated to use these new functions. The original version of this patch did not touch these files, which previously wrote directly to the wkdep registers, and thus confused the usecounting code. This problem was found by Kevin Hilman <khilman@deeprootsystems.com>. N.B.: This patch introduces one significant functional difference over the previous pm34xx.c code: sleepdeps are now cleared during clockdomain initialization, whereas previously they were left untouched. This has been tested by Kevin and confirmed to work. The original version of this patch also did not take into consideration that some clockdomains do not have sleep or wakeup dependency sources, which caused NULL pointer dereferences. This problem was debugged and fixed by Kevin Hilman <khilman@deeprootsystems.com>. Signed-off-by: Paul Walmsley <paul@pwsan.com> Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com> Cc: Jouni Högander <jouni.hogander@nokia.com>
Diffstat (limited to 'arch/arm/mach-omap2/pm24xx.c')
-rw-r--r--arch/arm/mach-omap2/pm24xx.c49
1 files changed, 30 insertions, 19 deletions
diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c
index 754381857cb6..374299ea7ade 100644
--- a/arch/arm/mach-omap2/pm24xx.c
+++ b/arch/arm/mach-omap2/pm24xx.c
@@ -57,11 +57,8 @@ static void (*omap2_sram_idle)(void);
57static void (*omap2_sram_suspend)(u32 dllctrl, void __iomem *sdrc_dlla_ctrl, 57static void (*omap2_sram_suspend)(u32 dllctrl, void __iomem *sdrc_dlla_ctrl,
58 void __iomem *sdrc_power); 58 void __iomem *sdrc_power);
59 59
60static struct powerdomain *mpu_pwrdm; 60static struct powerdomain *mpu_pwrdm, *core_pwrdm;
61static struct powerdomain *core_pwrdm; 61static struct clockdomain *dsp_clkdm, *mpu_clkdm, *wkup_clkdm, *gfx_clkdm;
62
63static struct clockdomain *dsp_clkdm;
64static struct clockdomain *gfx_clkdm;
65 62
66static struct clk *osc_ck, *emul_ck; 63static struct clk *osc_ck, *emul_ck;
67 64
@@ -334,9 +331,17 @@ static struct platform_suspend_ops omap_pm_ops = {
334 .valid = suspend_valid_only_mem, 331 .valid = suspend_valid_only_mem,
335}; 332};
336 333
337static int _pm_clkdm_enable_hwsup(struct clockdomain *clkdm, void *unused) 334/* XXX This function should be shareable between OMAP2xxx and OMAP3 */
335static int __init clkdms_setup(struct clockdomain *clkdm, void *unused)
338{ 336{
339 omap2_clkdm_allow_idle(clkdm); 337 clkdm_clear_all_wkdeps(clkdm);
338 clkdm_clear_all_sleepdeps(clkdm);
339
340 if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO)
341 omap2_clkdm_allow_idle(clkdm);
342 else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP &&
343 atomic_read(&clkdm->usecount) == 0)
344 omap2_clkdm_sleep(clkdm);
340 return 0; 345 return 0;
341} 346}
342 347
@@ -349,14 +354,6 @@ static void __init prcm_setup_regs(void)
349 prm_write_mod_reg(OMAP24XX_AUTOIDLE, OCP_MOD, 354 prm_write_mod_reg(OMAP24XX_AUTOIDLE, OCP_MOD,
350 OMAP2_PRCM_SYSCONFIG_OFFSET); 355 OMAP2_PRCM_SYSCONFIG_OFFSET);
351 356
352 /* Set all domain wakeup dependencies */
353 prm_write_mod_reg(OMAP_EN_WKUP_MASK, MPU_MOD, PM_WKDEP);
354 prm_write_mod_reg(0, OMAP24XX_DSP_MOD, PM_WKDEP);
355 prm_write_mod_reg(0, GFX_MOD, PM_WKDEP);
356 prm_write_mod_reg(0, CORE_MOD, PM_WKDEP);
357 if (cpu_is_omap2430())
358 prm_write_mod_reg(0, OMAP2430_MDM_MOD, PM_WKDEP);
359
360 /* 357 /*
361 * Set CORE powerdomain memory banks to retain their contents 358 * Set CORE powerdomain memory banks to retain their contents
362 * during RETENTION 359 * during RETENTION
@@ -385,8 +382,12 @@ static void __init prcm_setup_regs(void)
385 pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF); 382 pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF);
386 omap2_clkdm_sleep(gfx_clkdm); 383 omap2_clkdm_sleep(gfx_clkdm);
387 384
388 /* Enable clockdomain hardware-supervised control for all clkdms */ 385 /*
389 clkdm_for_each(_pm_clkdm_enable_hwsup, NULL); 386 * Clear clockdomain wakeup dependencies and enable
387 * hardware-supervised idle for all clkdms
388 */
389 clkdm_for_each(clkdms_setup, NULL);
390 clkdm_add_wkdep(mpu_clkdm, wkup_clkdm);
390 391
391 /* Enable clock autoidle for all domains */ 392 /* Enable clock autoidle for all domains */
392 cm_write_mod_reg(OMAP24XX_AUTO_CAM | 393 cm_write_mod_reg(OMAP24XX_AUTO_CAM |
@@ -482,7 +483,7 @@ static int __init omap2_pm_init(void)
482 l = prm_read_mod_reg(OCP_MOD, OMAP2_PRCM_REVISION_OFFSET); 483 l = prm_read_mod_reg(OCP_MOD, OMAP2_PRCM_REVISION_OFFSET);
483 printk(KERN_INFO "PRCM revision %d.%d\n", (l >> 4) & 0x0f, l & 0x0f); 484 printk(KERN_INFO "PRCM revision %d.%d\n", (l >> 4) & 0x0f, l & 0x0f);
484 485
485 /* Look up important powerdomains, clockdomains */ 486 /* Look up important powerdomains */
486 487
487 mpu_pwrdm = pwrdm_lookup("mpu_pwrdm"); 488 mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
488 if (!mpu_pwrdm) 489 if (!mpu_pwrdm)
@@ -492,9 +493,19 @@ static int __init omap2_pm_init(void)
492 if (!core_pwrdm) 493 if (!core_pwrdm)
493 pr_err("PM: core_pwrdm not found\n"); 494 pr_err("PM: core_pwrdm not found\n");
494 495
496 /* Look up important clockdomains */
497
498 mpu_clkdm = clkdm_lookup("mpu_clkdm");
499 if (!mpu_clkdm)
500 pr_err("PM: mpu_clkdm not found\n");
501
502 wkup_clkdm = clkdm_lookup("wkup_clkdm");
503 if (!wkup_clkdm)
504 pr_err("PM: wkup_clkdm not found\n");
505
495 dsp_clkdm = clkdm_lookup("dsp_clkdm"); 506 dsp_clkdm = clkdm_lookup("dsp_clkdm");
496 if (!dsp_clkdm) 507 if (!dsp_clkdm)
497 pr_err("PM: mpu_clkdm not found\n"); 508 pr_err("PM: dsp_clkdm not found\n");
498 509
499 gfx_clkdm = clkdm_lookup("gfx_clkdm"); 510 gfx_clkdm = clkdm_lookup("gfx_clkdm");
500 if (!gfx_clkdm) 511 if (!gfx_clkdm)