]> rtime.felk.cvut.cz Git - linux-imx.git/blobdiff - arch/arm/mach-omap2/pm44xx.c
ARM: OMAP4+: PM: Consolidate OMAP4 PM code to re-use it for OMAP5
[linux-imx.git] / arch / arm / mach-omap2 / pm44xx.c
index aa6fd98f606e30aa96c164b2ce3dd40719777e0c..228deca8fb938a65a9bddce28c1b23992e4a8b21 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * OMAP4 Power Management Routines
+ * OMAP4+ Power Management Routines
  *
- * Copyright (C) 2010-2011 Texas Instruments, Inc.
+ * Copyright (C) 2010-2013 Texas Instruments, Inc.
  * Rajendra Nayak <rnayak@ti.com>
  * Santosh Shilimkar <santosh.shilimkar@ti.com>
  *
@@ -77,10 +77,20 @@ static int omap4_pm_suspend(void)
                omap_set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state);
                pwrdm_set_logic_retst(pwrst->pwrdm, pwrst->saved_logic_state);
        }
-       if (ret)
+       if (ret) {
                pr_crit("Could not enter target state in pm_suspend\n");
-       else
+               /*
+                * OMAP4 chip PM currently works only with certain (newer)
+                * versions of bootloaders. This is due to missing code in the
+                * kernel to properly reset and initialize some devices.
+                * Warn the user about the bootloader version being one of the
+                * possible causes.
+                * http://www.spinics.net/lists/arm-kernel/msg218641.html
+                */
+               pr_warn("A possible cause could be an old bootloader - try u-boot >= v2012.07\n");
+       } else {
                pr_info("Successfully put all powerdomains to target state\n");
+       }
 
        return 0;
 }
@@ -121,24 +131,20 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
  */
 static void omap_default_idle(void)
 {
-       local_fiq_disable();
-
        omap_do_wfi();
-
-       local_fiq_enable();
 }
 
 /**
- * omap4_pm_init - Init routine for OMAP4 PM
+ * omap4_init_static_deps - Add OMAP4 static dependencies
  *
- * Initializes all powerdomain and clockdomain target states
- * and all PRCM settings.
+ * Add needed static clockdomain dependencies on OMAP4 devices.
+ * Return: 0 on success or 'err' on failures
  */
-int __init omap4_pm_init(void)
+static inline int omap4_init_static_deps(void)
 {
-       int ret;
-       struct clockdomain *emif_clkdm, *mpuss_clkdm, *l3_1_clkdm, *l4wkup;
-       struct clockdomain *ducati_clkdm, *l3_2_clkdm, *l4_per_clkdm;
+       struct clockdomain *emif_clkdm, *mpuss_clkdm, *l3_1_clkdm;
+       struct clockdomain *ducati_clkdm, *l3_2_clkdm;
+       int ret = 0;
 
        if (omap_rev() == OMAP4430_REV_ES1_0) {
                WARN(1, "Power Management not supported on OMAP4430 ES1.0\n");
@@ -146,11 +152,18 @@ int __init omap4_pm_init(void)
        }
 
        pr_err("Power Management for TI OMAP4.\n");
+       /*
+        * OMAP4 chip PM currently works only with certain (newer)
+        * versions of bootloaders. This is due to missing code in the
+        * kernel to properly reset and initialize some devices.
+        * http://www.spinics.net/lists/arm-kernel/msg218641.html
+        */
+       pr_warn("OMAP4 PM: u-boot >= v2012.07 is required for full PM support\n");
 
        ret = pwrdm_for_each(pwrdms_setup, NULL);
        if (ret) {
                pr_err("Failed to setup powerdomains\n");
-               goto err2;
+               return ret;
        }
 
        /*
@@ -167,25 +180,54 @@ int __init omap4_pm_init(void)
        emif_clkdm = clkdm_lookup("l3_emif_clkdm");
        l3_1_clkdm = clkdm_lookup("l3_1_clkdm");
        l3_2_clkdm = clkdm_lookup("l3_2_clkdm");
-       l4_per_clkdm = clkdm_lookup("l4_per_clkdm");
-       l4wkup = clkdm_lookup("l4_wkup_clkdm");
        ducati_clkdm = clkdm_lookup("ducati_clkdm");
-       if ((!mpuss_clkdm) || (!emif_clkdm) || (!l3_1_clkdm) || (!l4wkup) ||
-               (!l3_2_clkdm) || (!ducati_clkdm) || (!l4_per_clkdm))
-               goto err2;
+       if ((!mpuss_clkdm) || (!emif_clkdm) || (!l3_1_clkdm) ||
+               (!l3_2_clkdm) || (!ducati_clkdm))
+               return -EINVAL;
 
        ret = clkdm_add_wkdep(mpuss_clkdm, emif_clkdm);
        ret |= clkdm_add_wkdep(mpuss_clkdm, l3_1_clkdm);
        ret |= clkdm_add_wkdep(mpuss_clkdm, l3_2_clkdm);
-       ret |= clkdm_add_wkdep(mpuss_clkdm, l4_per_clkdm);
-       ret |= clkdm_add_wkdep(mpuss_clkdm, l4wkup);
        ret |= clkdm_add_wkdep(ducati_clkdm, l3_1_clkdm);
        ret |= clkdm_add_wkdep(ducati_clkdm, l3_2_clkdm);
        if (ret) {
                pr_err("Failed to add MPUSS -> L3/EMIF/L4PER, DUCATI -> L3 wakeup dependency\n");
+               return -EINVAL;
+       }
+
+       return ret;
+}
+
+/**
+ * omap4_pm_init - Init routine for OMAP4+ devices
+ *
+ * Initializes all powerdomain and clockdomain target states
+ * and all PRCM settings.
+ * Return: Returns the error code returned by called functions.
+ */
+int __init omap4_pm_init(void)
+{
+       int ret = 0;
+
+       if (omap_rev() == OMAP4430_REV_ES1_0) {
+               WARN(1, "Power Management not supported on OMAP4430 ES1.0\n");
+               return -ENODEV;
+       }
+
+       pr_info("Power Management for TI OMAP4+ devices.\n");
+
+       ret = pwrdm_for_each(pwrdms_setup, NULL);
+       if (ret) {
+               pr_err("Failed to setup powerdomains.\n");
                goto err2;
        }
 
+       if (cpu_is_omap44xx()) {
+               ret = omap4_init_static_deps();
+               if (ret)
+                       goto err2;
+       }
+
        ret = omap4_mpuss_init();
        if (ret) {
                pr_err("Failed to initialise OMAP4 MPUSS\n");
@@ -201,7 +243,8 @@ int __init omap4_pm_init(void)
        /* Overwrite the default cpu_do_idle() */
        arm_pm_idle = omap_default_idle;
 
-       omap4_idle_init();
+       if (cpu_is_omap44xx())
+               omap4_idle_init();
 
 err2:
        return ret;