2 * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
4 * The code contained herein is licensed under the GNU General Public
5 * License. You may obtain a copy of the GNU General Public License
6 * Version 2 or later at the following locations:
8 * http://www.opensource.org/licenses/gpl-license.html
9 * http://www.gnu.org/copyleft/gpl.html
11 #include <linux/suspend.h>
12 #include <linux/clk.h>
14 #include <linux/err.h>
15 #include <linux/export.h>
16 #include <asm/cacheflush.h>
17 #include <asm/system_misc.h>
18 #include <asm/tlbflush.h>
24 #define MXC_CCM_CLPCR 0x54
25 #define MXC_CCM_CLPCR_LPM_OFFSET 0
26 #define MXC_CCM_CLPCR_LPM_MASK 0x3
27 #define MXC_CCM_CLPCR_STBY_COUNT_OFFSET 9
28 #define MXC_CCM_CLPCR_VSTBY (0x1 << 8)
29 #define MXC_CCM_CLPCR_SBYOS (0x1 << 6)
31 #define MXC_CORTEXA8_PLAT_LPC 0xc
32 #define MXC_CORTEXA8_PLAT_LPC_DSM (1 << 0)
33 #define MXC_CORTEXA8_PLAT_LPC_DBG_DSM (1 << 1)
35 #define MXC_SRPG_NEON_SRPGCR 0x280
36 #define MXC_SRPG_ARM_SRPGCR 0x2a0
37 #define MXC_SRPG_EMPGC0_SRPGCR 0x2c0
38 #define MXC_SRPG_EMPGC1_SRPGCR 0x2d0
40 #define MXC_SRPGCR_PCR 1
43 * The WAIT_UNCLOCKED_POWER_OFF state only requires <= 500ns to exit.
44 * This is also the lowest power state possible without affecting
45 * non-cpu parts of the system. For these reasons, imx5 should default
46 * to always using this state for cpu idling. The PM_SUSPEND_STANDBY also
47 * uses this state and needs to take no action when registers remain confgiured
50 #define IMX5_DEFAULT_CPU_IDLE_STATE WAIT_UNCLOCKED_POWER_OFF
53 phys_addr_t cortex_addr
;
57 static const struct imx5_pm_data imx51_pm_data __initconst
= {
58 .cortex_addr
= 0x83fa0000,
59 .gpc_addr
= 0x73fd8000,
62 static const struct imx5_pm_data imx53_pm_data __initconst
= {
63 .cortex_addr
= 0x63fa0000,
64 .gpc_addr
= 0x53fd8000,
67 static void __iomem
*ccm_base
;
68 static void __iomem
*cortex_base
;
69 static void __iomem
*gpc_base
;
71 void __init
imx5_pm_set_ccm_base(void __iomem
*base
)
77 * set cpu low power mode before WFI instruction. This function is called
78 * mx5 because it can be used for mx51, and mx53.
80 static void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode
)
82 u32 plat_lpc
, arm_srpgcr
, ccm_clpcr
;
86 /* always allow platform to issue a deep sleep mode request */
87 plat_lpc
= __raw_readl(cortex_base
+ MXC_CORTEXA8_PLAT_LPC
) &
88 ~(MXC_CORTEXA8_PLAT_LPC_DSM
);
89 ccm_clpcr
= __raw_readl(ccm_base
+ MXC_CCM_CLPCR
) &
90 ~(MXC_CCM_CLPCR_LPM_MASK
);
91 arm_srpgcr
= __raw_readl(gpc_base
+ MXC_SRPG_ARM_SRPGCR
) &
93 empgc0
= __raw_readl(gpc_base
+ MXC_SRPG_EMPGC0_SRPGCR
) &
95 empgc1
= __raw_readl(gpc_base
+ MXC_SRPG_EMPGC1_SRPGCR
) &
102 ccm_clpcr
|= 0x1 << MXC_CCM_CLPCR_LPM_OFFSET
;
104 case WAIT_UNCLOCKED_POWER_OFF
:
106 plat_lpc
|= MXC_CORTEXA8_PLAT_LPC_DSM
107 | MXC_CORTEXA8_PLAT_LPC_DBG_DSM
;
108 if (mode
== WAIT_UNCLOCKED_POWER_OFF
) {
109 ccm_clpcr
|= 0x1 << MXC_CCM_CLPCR_LPM_OFFSET
;
110 ccm_clpcr
&= ~MXC_CCM_CLPCR_VSTBY
;
111 ccm_clpcr
&= ~MXC_CCM_CLPCR_SBYOS
;
114 ccm_clpcr
|= 0x2 << MXC_CCM_CLPCR_LPM_OFFSET
;
115 ccm_clpcr
|= 0x3 << MXC_CCM_CLPCR_STBY_COUNT_OFFSET
;
116 ccm_clpcr
|= MXC_CCM_CLPCR_VSTBY
;
117 ccm_clpcr
|= MXC_CCM_CLPCR_SBYOS
;
120 arm_srpgcr
|= MXC_SRPGCR_PCR
;
123 ccm_clpcr
|= 0x2 << MXC_CCM_CLPCR_LPM_OFFSET
;
126 printk(KERN_WARNING
"UNKNOWN cpu power mode: %d\n", mode
);
130 __raw_writel(plat_lpc
, cortex_base
+ MXC_CORTEXA8_PLAT_LPC
);
131 __raw_writel(ccm_clpcr
, ccm_base
+ MXC_CCM_CLPCR
);
132 __raw_writel(arm_srpgcr
, gpc_base
+ MXC_SRPG_ARM_SRPGCR
);
133 __raw_writel(arm_srpgcr
, gpc_base
+ MXC_SRPG_NEON_SRPGCR
);
136 empgc0
|= MXC_SRPGCR_PCR
;
137 empgc1
|= MXC_SRPGCR_PCR
;
139 __raw_writel(empgc0
, gpc_base
+ MXC_SRPG_EMPGC0_SRPGCR
);
140 __raw_writel(empgc1
, gpc_base
+ MXC_SRPG_EMPGC1_SRPGCR
);
144 static int mx5_suspend_enter(suspend_state_t state
)
148 mx5_cpu_lp_set(STOP_POWER_OFF
);
150 case PM_SUSPEND_STANDBY
:
151 /* DEFAULT_IDLE_STATE already configured */
157 if (state
== PM_SUSPEND_MEM
) {
158 local_flush_tlb_all();
161 /*clear the EMPGC0/1 bits */
162 __raw_writel(0, gpc_base
+ MXC_SRPG_EMPGC0_SRPGCR
);
163 __raw_writel(0, gpc_base
+ MXC_SRPG_EMPGC1_SRPGCR
);
167 /* return registers to default idle state */
168 mx5_cpu_lp_set(IMX5_DEFAULT_CPU_IDLE_STATE
);
172 static int mx5_pm_valid(suspend_state_t state
)
174 return (state
> PM_SUSPEND_ON
&& state
<= PM_SUSPEND_MAX
);
177 static const struct platform_suspend_ops mx5_suspend_ops
= {
178 .valid
= mx5_pm_valid
,
179 .enter
= mx5_suspend_enter
,
182 static inline int imx5_cpu_do_idle(void)
184 int ret
= tzic_enable_wake();
192 static void imx5_pm_idle(void)
197 static int __init
imx5_pm_common_init(const struct imx5_pm_data
*data
)
200 struct clk
*gpc_dvfs_clk
= clk_get(NULL
, "gpc_dvfs");
202 if (IS_ERR(gpc_dvfs_clk
))
203 return PTR_ERR(gpc_dvfs_clk
);
205 ret
= clk_prepare_enable(gpc_dvfs_clk
);
209 arm_pm_idle
= imx5_pm_idle
;
211 cortex_base
= ioremap(data
->cortex_addr
, SZ_16K
);
212 gpc_base
= ioremap(data
->gpc_addr
, SZ_16K
);
213 WARN_ON(!ccm_base
|| !cortex_base
|| !gpc_base
);
215 /* Set the registers to the default cpu idle state. */
216 mx5_cpu_lp_set(IMX5_DEFAULT_CPU_IDLE_STATE
);
218 ret
= imx5_cpuidle_init();
220 pr_warn("%s: cpuidle init failed %d\n", __func__
, ret
);
222 suspend_set_ops(&mx5_suspend_ops
);
227 void __init
imx51_pm_init(void)
229 imx5_pm_common_init(&imx51_pm_data
);
232 void __init
imx53_pm_init(void)
234 imx5_pm_common_init(&imx53_pm_data
);