blob: 07d05227d5289ffe8ddf4a0cf0be3e1fe86c591f [file] [log] [blame]
yuezonghe824eb0c2024-06-27 02:32:26 -07001/*
2 * linux/arch/arm/mach-zx297510/pcu.c
3 *
4 * Copyright (C) 2013 ZTE-TSP
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11 #include <linux/errno.h>
12 #include <linux/irq.h>
13 #include <linux/module.h>
14
15 #include <asm/io.h>
16
17 #include <mach/iomap.h>
18 #include <mach/zx-pm.h>
19 #include <mach/zx297510-pm.h>
20 #include <mach/pcu.h>
21 #include <mach/spinlock.h>
22
23/*
24 * return external intterrupt number from ex8-ex15,
25 * return value is 8-15
26 */
27unsigned int pcu_int_vector_8in1(void)
28{
29 void __iomem *reg_base = EX_INT_VECTOR_REG;
30 unsigned int vector_8in1 = 0;
31
32 vector_8in1 = ioread32(reg_base);
33
34 return ((vector_8in1&0x7) + 8);
35}
36EXPORT_SYMBOL(pcu_int_vector_8in1);
37
38
39
40/*external int 8-15 need extra clear*/
41 void pcu_int_clear_8in1(PCU_INT_INDEX index)
42 {
43 void __iomem *reg_base = EX_INT_TOP_CLEAR_REG;
44 unsigned int vector=0;
45
46 if ( (index >= PCU_EX8_INT)&&(index <= PCU_EX15_INT) ){
47 /*
48 *in 7510 platform, 8in1 interrupt would be used by different cores.
49 *when any core installs a new 8in1 interrupt, another core may be
50 * responding another 8in1 interrupt, so 8in1 interrupt shouldn't be
51 *cleared. in this case, nothing to be done. but a new problem comes,
52 * the core install new 8in1 interrupt will receive a fake interrupt.
53 */
54 vector=pcu_int_vector_8in1();
55 if (index != (vector + PCU_EX0_INT) )
56 return;
57
58 reg_spin_lock();
59 iowrite32(0x1,reg_base);
60 reg_spin_unlock();
61 }
62 }
63EXPORT_SYMBOL(pcu_int_clear_8in1);
64
65/*only pulse int need be clear*/
66 void pcu_int_clear(PCU_INT_INDEX index)
67 {
68 unsigned int reg_num = index&0x100;
69 unsigned int bit_mask = 1<<(index&0x1f);
70 void __iomem *reg_base = NULL;
71 unsigned int tmp;
72
73 if (reg_num == 0x100)
74 reg_base = PCU_BASE_VA + 0xec;
75 else
76 reg_base = PCU_BASE_VA + 0x80;
77
78 reg_spin_lock();
79 tmp = ioread32(reg_base);
80 tmp |= bit_mask;
81 iowrite32(tmp,reg_base);
82 reg_spin_unlock();
83
84 pcu_int_clear_8in1(index);
85 }
86EXPORT_SYMBOL(pcu_int_clear);
87
88
89void pcu_int_set_type(PCU_INT_INDEX index,unsigned int type)
90{
91 unsigned int reg_num = index&0x100;
92 unsigned int bit_index = index&0x1f;
93 unsigned int bit_mask = 1<<bit_index;
94
95 void __iomem *level_regbase = NULL;
96 void __iomem *pol_regbase = NULL;
97 unsigned int tmp;
98 unsigned int level;
99 unsigned int pol;
100
101 if (reg_num == 0x100){
102 level_regbase = PCU_BASE_VA + 0xe4;
103 pol_regbase = PCU_BASE_VA + 0xe8;
104 }
105 else{
106 level_regbase = PCU_BASE_VA + 0x60;
107 pol_regbase = PCU_BASE_VA + 0x70;
108 }
109
110
111 switch (type) {
112 case IRQ_TYPE_LEVEL_HIGH:
113 level = 1;
114 pol = 1;
115 break;
116 case IRQ_TYPE_EDGE_RISING:
117 level = 0;
118 pol = 1;
119 break;
120 case IRQ_TYPE_LEVEL_LOW:
121 level = 1;
122 pol= 0;
123 break;
124 case IRQ_TYPE_EDGE_FALLING:
125 level = 0;
126 pol = 0;
127 break;
128 default:
129 BUG();
130 }
131
132 reg_spin_lock();
133 /* set level*/
134 tmp = ioread32(level_regbase);
135 tmp &= ~bit_mask;
136 tmp |= level<<bit_index;
137 iowrite32(tmp,level_regbase);
138
139 /* set polarity */
140 tmp = ioread32(pol_regbase);
141 tmp &= ~bit_mask;
142 tmp |= pol<<bit_index;
143 iowrite32(tmp,pol_regbase);
144 reg_spin_unlock();
145
146}
147EXPORT_SYMBOL(pcu_int_set_type);
148
149
150
151/* low power function */
152
153extern unsigned int wake_source_int_for_suspend[];
154extern unsigned int wake_source_int_for_dpidle[];
155/**
156 * enable wake source for cpu
157 *
158 */
159static void pcu_enable_wake_source(unsigned int *wake_source)
160{
161 unsigned int int1, int2, int_timer;
162
163 int1 = wake_source[0];
164 int2 = wake_source[1];
165 int_timer = wake_source[2];
166
167 reg_spin_lock();
168
169 pm_clr_reg(AP_INT_WAKE_DIS_REG1, int1);
170 pm_clr_reg(AP_INT_WAKE_DIS_REG2, int2);
171 pm_clr_reg(TIMER_INT_WAKE_DIS_REG, int_timer);
172
173 reg_spin_unlock();
174}
175
176static void pcu_set_wake_source(cpu_sleep_type_t sleep_type)
177{
178 if(CPU_SLEEP_TYPE_LP1 == sleep_type)
179 {
180 pcu_enable_wake_source(wake_source_int_for_suspend);
181 }
182 else if(CPU_SLEEP_TYPE_IDLE_LP2 == sleep_type || CPU_SLEEP_TYPE_LP3 == sleep_type)
183 {
184 pcu_enable_wake_source(wake_source_int_for_dpidle);
185 }
186}
187
188/**
189 * init pcu when pm initial.
190 *
191 */
192void zx297510_pcu_init(void)
193{
194 pr_info("[SLP] Power/PCU_INIT \n");
195
196 pm_clr_reg(ARM_AP_CONFIG_REG, PCU_MODE_MASK);
197 pm_set_pll_used();
198 pm_set_reg(ARM_AP_SLEEP_TIME_REG, PCU_AP_SLEEP_TIME_DIS);
199
200 pm_write_reg(AP_L2_POWER_ENABLE_REG, 0);
201
202 pm_write_reg(AP_INT_WAKE_DIS_REG1, 0xFFFFFFFF);
203 pm_write_reg(AP_INT_WAKE_DIS_REG2, 0xFFFFFFFF);
204
205 pm_set_reg(AP_LOW_POWER_REG1, 0); /* bypass disable */
206 pm_set_reg(AP_LOW_POWER_REG2, 0); /* 1 - enter DS 0 - exit DS */
207}
208
209/**
210 * set&enable PCU for interrupt/clock/powerdomain/pll/iram.
211 *
212 */
213int zx297510_set_pcu(void)
214{
215 cpu_sleep_type_t sleep_type;
216 u32 sleep_time;
217
218 sleep_type = pm_get_sleep_type();
219 sleep_time = pm_get_sleep_time();
220
221 pm_set_pll_used();
222
223 if(CPU_SLEEP_TYPE_LP1 == sleep_type) /* shutdown */
224 {
225 pm_set_reg(ARM_AP_CONFIG_REG, PCU_SHUTDOWN_MODE);
226 pm_set_reg(ARM_AP_CONFIG_REG, PCU_MG_CLK_RESET|PCU_L2_CLK_GATE|PCU_PLL_OFF);
227
228 pm_write_reg(ARM_AP_SLEEP_TIME_REG, 0xffffffff);
229
230 pm_write_reg(AP_L2_POWER_ENABLE_REG, 1);
231
232 }
233 else if(CPU_SLEEP_TYPE_IDLE_LP2 == sleep_type) /* dormant */
234 {
235 pm_set_reg(ARM_AP_CONFIG_REG, PCU_DORMANT_MODE);
236 pm_set_reg(ARM_AP_CONFIG_REG, PCU_MG_CLK_RESET|PCU_L2_CLK_GATE|PCU_PLL_OFF);
237
238 pm_write_reg(ARM_AP_SLEEP_TIME_REG, sleep_time);
239 }
240 else if(CPU_SLEEP_TYPE_LP3 == sleep_type)
241 {
242 pm_set_reg(ARM_AP_CONFIG_REG, PCU_STANDBY_MODE);
243 pm_clr_reg(ARM_AP_CONFIG_REG, PCU_PLL_OFF);
244 pm_set_reg(ARM_AP_CONFIG_REG, PCU_MG_CLK_RESET|PCU_L2_CLK_GATE);
245
246 pm_write_reg(ARM_AP_SLEEP_TIME_REG, sleep_time);
247 }
248 else
249 WARN_ON(1);
250
251 pcu_set_wake_source(sleep_type);
252
253 return 0;
254}
255
256/**
257 * clear&disable PCU for interrupt/clock/powerdomain/pll/iram.
258 *
259 */
260int zx297510_clear_pcu(void)
261{
262 reg_spin_lock();
263
264 pm_clr_reg(ARM_AP_CONFIG_REG, PCU_MODE_MASK);
265
266 pm_write_reg(AP_L2_POWER_ENABLE_REG, 0);
267
268 pm_write_reg(AP_INT_WAKE_DIS_REG1, 0xFFFFFFFF);
269 pm_write_reg(AP_INT_WAKE_DIS_REG2, 0xFFFFFFFF);
270
271 pm_set_reg(TIMER_INT_WAKE_DIS_REG, WAKE_SRC_TIMER3);
272
273 reg_spin_unlock();
274
275 return 0;
276}
277
278/**
279 * when sleep/dormant/poweroff, pll will be closed.
280 *
281 */
282void pcu_set_pll_used(unsigned pll)
283{
284 if(PCU_USE_PLL_MAIN == pll)
285 pm_clr_reg(ARM_AP_CONFIG_REG, pll);
286 else
287 pm_set_reg(ARM_AP_CONFIG_REG, pll);
288}
289
290/**
291 * get wakeup setting.
292 *
293 */
294void pcu_get_wakeup_setting(unsigned int *pointer)
295{
296 pointer[0] = pm_read_reg(AP_INT_WAKE_DIS_REG1);
297 pointer[1] = pm_read_reg(AP_INT_WAKE_DIS_REG2);
298 pointer[2] = pm_read_reg(TIMER_INT_WAKE_DIS_REG);
299}
300
301void pcu_clr_timer3_int(void)
302{
303 reg_spin_lock();
304
305 pm_set_reg(TIMER_INT_DDR_SW_CLEAR_REG, WAKE_SRC_TIMER3);
306
307 reg_spin_unlock();
308}
309
310/**
311 * set wakeup enable.
312 *
313 * now only support ext_int.
314 */
315void pcu_irq_wakeup(PCU_INT_INDEX index, int enable)
316{
317 if ( (index < PCU_EX0_INT) || (index > PCU_EX15_INT) )
318 return;
319
320 if(enable)
321 {
322 wake_source_int_for_suspend[0] |= (1<<index);
323 wake_source_int_for_dpidle[0] |= (1<<index);
324 }
325 else
326 {
327 wake_source_int_for_suspend[0] &= ~(1<<index);
328 wake_source_int_for_dpidle[0] &= ~(1<<index);
329 }
330}
331