ARM: imx5: reuse clock CCM mapping in pm code
[firefly-linux-kernel-4.4.55.git] / arch / arm / mach-imx / pm-imx5.c
1 /*
2  *  Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
3  *
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:
7  *
8  * http://www.opensource.org/licenses/gpl-license.html
9  * http://www.gnu.org/copyleft/gpl.html
10  */
11 #include <linux/suspend.h>
12 #include <linux/clk.h>
13 #include <linux/io.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>
19
20 #include "common.h"
21 #include "cpuidle.h"
22 #include "hardware.h"
23
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)
30
31 #define MX51_CORTEXA8_BASE              MX51_IO_ADDRESS(MX51_ARM_BASE_ADDR)
32 #define MXC_CORTEXA8_PLAT_LPC           (MX51_CORTEXA8_BASE + 0xc)
33 #define MXC_CORTEXA8_PLAT_LPC_DSM       (1 << 0)
34 #define MXC_CORTEXA8_PLAT_LPC_DBG_DSM   (1 << 1)
35
36 #define MX51_GPC_BASE                   MX51_IO_ADDRESS(MX51_GPC_BASE_ADDR)
37 #define MXC_SRPG_NEON_BASE              (MX51_GPC_BASE + 0x280)
38 #define MXC_SRPG_ARM_BASE               (MX51_GPC_BASE + 0x2a0)
39 #define MXC_SRPG_EMPGC0_BASE            (MX51_GPC_BASE + 0x2c0)
40 #define MXC_SRPG_EMPGC1_BASE            (MX51_GPC_BASE + 0x2d0)
41
42 #define MXC_SRPG_NEON_SRPGCR            (MXC_SRPG_NEON_BASE + 0x0)
43 #define MXC_SRPG_ARM_SRPGCR             (MXC_SRPG_ARM_BASE + 0x0)
44 #define MXC_SRPG_EMPGC0_SRPGCR          (MXC_SRPG_EMPGC0_BASE + 0x0)
45 #define MXC_SRPG_EMPGC1_SRPGCR          (MXC_SRPG_EMPGC1_BASE + 0x0)
46
47 #define MXC_SRPGCR_PCR                  1
48
49 /*
50  * The WAIT_UNCLOCKED_POWER_OFF state only requires <= 500ns to exit.
51  * This is also the lowest power state possible without affecting
52  * non-cpu parts of the system.  For these reasons, imx5 should default
53  * to always using this state for cpu idling.  The PM_SUSPEND_STANDBY also
54  * uses this state and needs to take no action when registers remain confgiured
55  * for this state.
56  */
57 #define IMX5_DEFAULT_CPU_IDLE_STATE WAIT_UNCLOCKED_POWER_OFF
58
59 static void __iomem *ccm_base;
60
61 void __init imx5_pm_set_ccm_base(void __iomem *base)
62 {
63         ccm_base = base;
64 }
65
66 /*
67  * set cpu low power mode before WFI instruction. This function is called
68  * mx5 because it can be used for mx51, and mx53.
69  */
70 static void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode)
71 {
72         u32 plat_lpc, arm_srpgcr, ccm_clpcr;
73         u32 empgc0, empgc1;
74         int stop_mode = 0;
75
76         /* always allow platform to issue a deep sleep mode request */
77         plat_lpc = __raw_readl(MXC_CORTEXA8_PLAT_LPC) &
78             ~(MXC_CORTEXA8_PLAT_LPC_DSM);
79         ccm_clpcr = __raw_readl(ccm_base + MXC_CCM_CLPCR) &
80                     ~(MXC_CCM_CLPCR_LPM_MASK);
81         arm_srpgcr = __raw_readl(MXC_SRPG_ARM_SRPGCR) & ~(MXC_SRPGCR_PCR);
82         empgc0 = __raw_readl(MXC_SRPG_EMPGC0_SRPGCR) & ~(MXC_SRPGCR_PCR);
83         empgc1 = __raw_readl(MXC_SRPG_EMPGC1_SRPGCR) & ~(MXC_SRPGCR_PCR);
84
85         switch (mode) {
86         case WAIT_CLOCKED:
87                 break;
88         case WAIT_UNCLOCKED:
89                 ccm_clpcr |= 0x1 << MXC_CCM_CLPCR_LPM_OFFSET;
90                 break;
91         case WAIT_UNCLOCKED_POWER_OFF:
92         case STOP_POWER_OFF:
93                 plat_lpc |= MXC_CORTEXA8_PLAT_LPC_DSM
94                             | MXC_CORTEXA8_PLAT_LPC_DBG_DSM;
95                 if (mode == WAIT_UNCLOCKED_POWER_OFF) {
96                         ccm_clpcr |= 0x1 << MXC_CCM_CLPCR_LPM_OFFSET;
97                         ccm_clpcr &= ~MXC_CCM_CLPCR_VSTBY;
98                         ccm_clpcr &= ~MXC_CCM_CLPCR_SBYOS;
99                         stop_mode = 0;
100                 } else {
101                         ccm_clpcr |= 0x2 << MXC_CCM_CLPCR_LPM_OFFSET;
102                         ccm_clpcr |= 0x3 << MXC_CCM_CLPCR_STBY_COUNT_OFFSET;
103                         ccm_clpcr |= MXC_CCM_CLPCR_VSTBY;
104                         ccm_clpcr |= MXC_CCM_CLPCR_SBYOS;
105                         stop_mode = 1;
106                 }
107                 arm_srpgcr |= MXC_SRPGCR_PCR;
108                 break;
109         case STOP_POWER_ON:
110                 ccm_clpcr |= 0x2 << MXC_CCM_CLPCR_LPM_OFFSET;
111                 break;
112         default:
113                 printk(KERN_WARNING "UNKNOWN cpu power mode: %d\n", mode);
114                 return;
115         }
116
117         __raw_writel(plat_lpc, MXC_CORTEXA8_PLAT_LPC);
118         __raw_writel(ccm_clpcr, ccm_base + MXC_CCM_CLPCR);
119         __raw_writel(arm_srpgcr, MXC_SRPG_ARM_SRPGCR);
120         __raw_writel(arm_srpgcr, MXC_SRPG_NEON_SRPGCR);
121
122         if (stop_mode) {
123                 empgc0 |= MXC_SRPGCR_PCR;
124                 empgc1 |= MXC_SRPGCR_PCR;
125
126                 __raw_writel(empgc0, MXC_SRPG_EMPGC0_SRPGCR);
127                 __raw_writel(empgc1, MXC_SRPG_EMPGC1_SRPGCR);
128         }
129 }
130
131 static int mx5_suspend_enter(suspend_state_t state)
132 {
133         switch (state) {
134         case PM_SUSPEND_MEM:
135                 mx5_cpu_lp_set(STOP_POWER_OFF);
136                 break;
137         case PM_SUSPEND_STANDBY:
138                 /* DEFAULT_IDLE_STATE already configured */
139                 break;
140         default:
141                 return -EINVAL;
142         }
143
144         if (state == PM_SUSPEND_MEM) {
145                 local_flush_tlb_all();
146                 flush_cache_all();
147
148                 /*clear the EMPGC0/1 bits */
149                 __raw_writel(0, MXC_SRPG_EMPGC0_SRPGCR);
150                 __raw_writel(0, MXC_SRPG_EMPGC1_SRPGCR);
151         }
152         cpu_do_idle();
153
154         /* return registers to default idle state */
155         mx5_cpu_lp_set(IMX5_DEFAULT_CPU_IDLE_STATE);
156         return 0;
157 }
158
159 static int mx5_pm_valid(suspend_state_t state)
160 {
161         return (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX);
162 }
163
164 static const struct platform_suspend_ops mx5_suspend_ops = {
165         .valid = mx5_pm_valid,
166         .enter = mx5_suspend_enter,
167 };
168
169 static inline int imx5_cpu_do_idle(void)
170 {
171         int ret = tzic_enable_wake();
172
173         if (likely(!ret))
174                 cpu_do_idle();
175
176         return ret;
177 }
178
179 static void imx5_pm_idle(void)
180 {
181         imx5_cpu_do_idle();
182 }
183
184 static int __init imx5_pm_common_init(void)
185 {
186         int ret;
187         struct clk *gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs");
188
189         if (IS_ERR(gpc_dvfs_clk))
190                 return PTR_ERR(gpc_dvfs_clk);
191
192         ret = clk_prepare_enable(gpc_dvfs_clk);
193         if (ret)
194                 return ret;
195
196         arm_pm_idle = imx5_pm_idle;
197
198         WARN_ON(!ccm_base);
199
200         /* Set the registers to the default cpu idle state. */
201         mx5_cpu_lp_set(IMX5_DEFAULT_CPU_IDLE_STATE);
202
203         return imx5_cpuidle_init();
204 }
205
206 void __init imx5_pm_init(void)
207 {
208         int ret = imx5_pm_common_init();
209         if (!ret)
210                 suspend_set_ops(&mx5_suspend_ops);
211 }