|
@@ -13,18 +13,27 @@
|
|
|
#include <linux/io.h>
|
|
|
#include <linux/err.h>
|
|
|
#include <asm/cacheflush.h>
|
|
|
+#include <asm/system_misc.h>
|
|
|
#include <asm/tlbflush.h>
|
|
|
#include <mach/common.h>
|
|
|
#include <mach/hardware.h>
|
|
|
#include "crm-regs-imx5.h"
|
|
|
|
|
|
-static struct clk *gpc_dvfs_clk;
|
|
|
+/*
|
|
|
+ * The WAIT_UNCLOCKED_POWER_OFF state only requires <= 500ns to exit.
|
|
|
+ * This is also the lowest power state possible without affecting
|
|
|
+ * non-cpu parts of the system. For these reasons, imx5 should default
|
|
|
+ * to always using this state for cpu idling. The PM_SUSPEND_STANDBY also
|
|
|
+ * uses this state and needs to take no action when registers remain confgiured
|
|
|
+ * for this state.
|
|
|
+ */
|
|
|
+#define IMX5_DEFAULT_CPU_IDLE_STATE WAIT_UNCLOCKED_POWER_OFF
|
|
|
|
|
|
/*
|
|
|
* set cpu low power mode before WFI instruction. This function is called
|
|
|
* mx5 because it can be used for mx50, mx51, and mx53.
|
|
|
*/
|
|
|
-void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode)
|
|
|
+static void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode)
|
|
|
{
|
|
|
u32 plat_lpc, arm_srpgcr, ccm_clpcr;
|
|
|
u32 empgc0, empgc1;
|
|
@@ -87,11 +96,6 @@ void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static int mx5_suspend_prepare(void)
|
|
|
-{
|
|
|
- return clk_prepare_enable(gpc_dvfs_clk);
|
|
|
-}
|
|
|
-
|
|
|
static int mx5_suspend_enter(suspend_state_t state)
|
|
|
{
|
|
|
switch (state) {
|
|
@@ -99,7 +103,7 @@ static int mx5_suspend_enter(suspend_state_t state)
|
|
|
mx5_cpu_lp_set(STOP_POWER_OFF);
|
|
|
break;
|
|
|
case PM_SUSPEND_STANDBY:
|
|
|
- mx5_cpu_lp_set(WAIT_UNCLOCKED_POWER_OFF);
|
|
|
+ /* DEFAULT_IDLE_STATE already configured */
|
|
|
break;
|
|
|
default:
|
|
|
return -EINVAL;
|
|
@@ -114,12 +118,10 @@ static int mx5_suspend_enter(suspend_state_t state)
|
|
|
__raw_writel(0, MXC_SRPG_EMPGC1_SRPGCR);
|
|
|
}
|
|
|
cpu_do_idle();
|
|
|
- return 0;
|
|
|
-}
|
|
|
|
|
|
-static void mx5_suspend_finish(void)
|
|
|
-{
|
|
|
- clk_disable_unprepare(gpc_dvfs_clk);
|
|
|
+ /* return registers to default idle state */
|
|
|
+ mx5_cpu_lp_set(IMX5_DEFAULT_CPU_IDLE_STATE);
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
static int mx5_pm_valid(suspend_state_t state)
|
|
@@ -129,25 +131,38 @@ static int mx5_pm_valid(suspend_state_t state)
|
|
|
|
|
|
static const struct platform_suspend_ops mx5_suspend_ops = {
|
|
|
.valid = mx5_pm_valid,
|
|
|
- .prepare = mx5_suspend_prepare,
|
|
|
.enter = mx5_suspend_enter,
|
|
|
- .finish = mx5_suspend_finish,
|
|
|
};
|
|
|
|
|
|
-static int __init mx5_pm_init(void)
|
|
|
+static void imx5_pm_idle(void)
|
|
|
{
|
|
|
- if (!cpu_is_mx51() && !cpu_is_mx53())
|
|
|
- return 0;
|
|
|
+ if (likely(!tzic_enable_wake()))
|
|
|
+ cpu_do_idle();
|
|
|
+}
|
|
|
+
|
|
|
+static int __init imx5_pm_common_init(void)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+ struct clk *gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs");
|
|
|
+
|
|
|
+ if (IS_ERR(gpc_dvfs_clk))
|
|
|
+ return PTR_ERR(gpc_dvfs_clk);
|
|
|
|
|
|
- if (gpc_dvfs_clk == NULL)
|
|
|
- gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs");
|
|
|
+ ret = clk_prepare_enable(gpc_dvfs_clk);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
|
|
|
- if (!IS_ERR(gpc_dvfs_clk)) {
|
|
|
- if (cpu_is_mx51())
|
|
|
- suspend_set_ops(&mx5_suspend_ops);
|
|
|
- } else
|
|
|
- return -EPERM;
|
|
|
+ arm_pm_idle = imx5_pm_idle;
|
|
|
+
|
|
|
+ /* Set the registers to the default cpu idle state. */
|
|
|
+ mx5_cpu_lp_set(IMX5_DEFAULT_CPU_IDLE_STATE);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
-device_initcall(mx5_pm_init);
|
|
|
+
|
|
|
+void __init imx51_pm_init(void)
|
|
|
+{
|
|
|
+ int ret = imx5_pm_common_init();
|
|
|
+ if (!ret)
|
|
|
+ suspend_set_ops(&mx5_suspend_ops);
|
|
|
+}
|