upload tizen1.0 source
[kernel/linux-2.6.36.git] / arch / arm / mach-s5pv310 / cpuidle.c
1 /* linux/arch/arm/mach-s5pv310/cpuidle.c
2  *
3  * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4  *              http://www.samsung.com
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 version 2 as
8  * published by the Free Software Foundation.
9 */
10
11 #include <linux/kernel.h>
12 #include <linux/init.h>
13 #include <linux/platform_device.h>
14 #include <linux/cpuidle.h>
15 #include <linux/io.h>
16 #include <linux/dma-mapping.h>
17 #include <linux/rfkill.h>
18
19 #include <asm/proc-fns.h>
20 #include <asm/cacheflush.h>
21 #include <asm/hardware/cache-l2x0.h>
22
23 #include <plat/pm.h>
24 #include <plat/cpu.h>
25 #include <plat/devs.h>
26 #include <plat/s5pv310.h>
27 #include <plat/regs-otg.h>
28
29 #include <mach/regs-clock.h>
30 #include <mach/regs-pmu.h>
31 #include <mach/gpio.h>
32 #include <mach/regs-gpio.h>
33
34 #include <mach/ext-gic.h>
35
36 #define MAX_CHK_DEV 0xf
37
38 #define REG_DIRECTGO_ADDR       (s5pv310_subrev() == 0 ?\
39                                 (S5P_VA_SYSRAM + 0x24) : S5P_INFORM7)
40 #define REG_DIRECTGO_FLAG       (s5pv310_subrev() == 0 ?\
41                                 (S5P_VA_SYSRAM + 0x20) : S5P_INFORM6)
42
43 static unsigned int cpu_core;
44 static unsigned int old_div;
45 /* Shared with pm-hotplug.c, which waits for idle to complete */
46 DEFINE_SPINLOCK(idle_lock);
47 bool hotplugging = false;
48 bool idling = false;
49
50 enum hc_type {
51         HC_SDHCI,
52         HC_MSHCI,
53 };
54
55 struct check_device_op {
56         void __iomem    *base;
57         struct platform_device  *pdev;
58         enum hc_type type;
59 };
60
61 static struct check_device_op chk_dev_op[] = {
62 #if defined(CONFIG_S3C_DEV_HSMMC)
63         {.base = 0, .pdev = &s3c_device_hsmmc0, .type = HC_SDHCI},
64 #endif
65 #if defined(CONFIG_S3C_DEV_HSMMC1)
66         {.base = 0, .pdev = &s3c_device_hsmmc1, .type = HC_SDHCI},
67 #endif
68 #if defined(CONFIG_S3C_DEV_HSMMC2)
69         {.base = 0, .pdev = &s3c_device_hsmmc2, .type = HC_SDHCI},
70 #endif
71 #if defined(CONFIG_S3C_DEV_HSMMC3)
72         {.base = 0, .pdev = &s3c_device_hsmmc3, .type = HC_SDHCI},
73 #endif
74 #if defined(CONFIG_S3C_DEV_HSMMC4)
75         {.base = 0, .pdev = &s3c_device_hsmmc4, .type = HC_MSHCI},
76 #endif
77 };
78
79 static unsigned long *regs_save;
80 static dma_addr_t phy_regs_save;
81
82 static struct sleep_save s5pv310_aftr_save[] = {
83         /* GIC side */
84 #ifndef CONFIG_USE_EXT_GIC
85         SAVE_ITEM(S5P_VA_GIC_CPU + 0x000),
86         SAVE_ITEM(S5P_VA_GIC_CPU + 0x004),
87         SAVE_ITEM(S5P_VA_GIC_CPU + 0x008),
88         SAVE_ITEM(S5P_VA_GIC_CPU + 0x014),
89         SAVE_ITEM(S5P_VA_GIC_CPU + 0x018),
90         SAVE_ITEM(S5P_VA_GIC_DIST + 0x000),
91         SAVE_ITEM(S5P_VA_GIC_DIST + 0x004),
92         SAVE_ITEM(S5P_VA_GIC_DIST + 0x100),
93         SAVE_ITEM(S5P_VA_GIC_DIST + 0x104),
94         SAVE_ITEM(S5P_VA_GIC_DIST + 0x108),
95         SAVE_ITEM(S5P_VA_GIC_DIST + 0x300),
96         SAVE_ITEM(S5P_VA_GIC_DIST + 0x304),
97         SAVE_ITEM(S5P_VA_GIC_DIST + 0x308),
98         SAVE_ITEM(S5P_VA_GIC_DIST + 0x400),
99         SAVE_ITEM(S5P_VA_GIC_DIST + 0x404),
100         SAVE_ITEM(S5P_VA_GIC_DIST + 0x408),
101         SAVE_ITEM(S5P_VA_GIC_DIST + 0x40C),
102         SAVE_ITEM(S5P_VA_GIC_DIST + 0x410),
103         SAVE_ITEM(S5P_VA_GIC_DIST + 0x414),
104         SAVE_ITEM(S5P_VA_GIC_DIST + 0x418),
105         SAVE_ITEM(S5P_VA_GIC_DIST + 0x41C),
106         SAVE_ITEM(S5P_VA_GIC_DIST + 0x420),
107         SAVE_ITEM(S5P_VA_GIC_DIST + 0x424),
108         SAVE_ITEM(S5P_VA_GIC_DIST + 0x428),
109         SAVE_ITEM(S5P_VA_GIC_DIST + 0x42C),
110         SAVE_ITEM(S5P_VA_GIC_DIST + 0x430),
111         SAVE_ITEM(S5P_VA_GIC_DIST + 0x434),
112         SAVE_ITEM(S5P_VA_GIC_DIST + 0x438),
113         SAVE_ITEM(S5P_VA_GIC_DIST + 0x43C),
114         SAVE_ITEM(S5P_VA_GIC_DIST + 0x440),
115         SAVE_ITEM(S5P_VA_GIC_DIST + 0x444),
116         SAVE_ITEM(S5P_VA_GIC_DIST + 0x448),
117         SAVE_ITEM(S5P_VA_GIC_DIST + 0x44C),
118         SAVE_ITEM(S5P_VA_GIC_DIST + 0x450),
119         SAVE_ITEM(S5P_VA_GIC_DIST + 0x454),
120         SAVE_ITEM(S5P_VA_GIC_DIST + 0x458),
121         SAVE_ITEM(S5P_VA_GIC_DIST + 0x45C),
122
123         SAVE_ITEM(S5P_VA_GIC_DIST + 0x800),
124         SAVE_ITEM(S5P_VA_GIC_DIST + 0x804),
125         SAVE_ITEM(S5P_VA_GIC_DIST + 0x808),
126         SAVE_ITEM(S5P_VA_GIC_DIST + 0x80C),
127         SAVE_ITEM(S5P_VA_GIC_DIST + 0x810),
128         SAVE_ITEM(S5P_VA_GIC_DIST + 0x814),
129         SAVE_ITEM(S5P_VA_GIC_DIST + 0x818),
130         SAVE_ITEM(S5P_VA_GIC_DIST + 0x81C),
131         SAVE_ITEM(S5P_VA_GIC_DIST + 0x820),
132         SAVE_ITEM(S5P_VA_GIC_DIST + 0x824),
133         SAVE_ITEM(S5P_VA_GIC_DIST + 0x828),
134         SAVE_ITEM(S5P_VA_GIC_DIST + 0x82C),
135         SAVE_ITEM(S5P_VA_GIC_DIST + 0x830),
136         SAVE_ITEM(S5P_VA_GIC_DIST + 0x834),
137         SAVE_ITEM(S5P_VA_GIC_DIST + 0x838),
138         SAVE_ITEM(S5P_VA_GIC_DIST + 0x83C),
139         SAVE_ITEM(S5P_VA_GIC_DIST + 0x840),
140         SAVE_ITEM(S5P_VA_GIC_DIST + 0x844),
141         SAVE_ITEM(S5P_VA_GIC_DIST + 0x848),
142         SAVE_ITEM(S5P_VA_GIC_DIST + 0x84C),
143         SAVE_ITEM(S5P_VA_GIC_DIST + 0x850),
144         SAVE_ITEM(S5P_VA_GIC_DIST + 0x854),
145         SAVE_ITEM(S5P_VA_GIC_DIST + 0x858),
146         SAVE_ITEM(S5P_VA_GIC_DIST + 0x85C),
147
148         SAVE_ITEM(S5P_VA_GIC_DIST + 0xC00),
149         SAVE_ITEM(S5P_VA_GIC_DIST + 0xC04),
150         SAVE_ITEM(S5P_VA_GIC_DIST + 0xC08),
151         SAVE_ITEM(S5P_VA_GIC_DIST + 0xC0C),
152         SAVE_ITEM(S5P_VA_GIC_DIST + 0xC10),
153         SAVE_ITEM(S5P_VA_GIC_DIST + 0xC14),
154
155         SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x000),
156         SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x010),
157         SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x020),
158         SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x030),
159         SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x040),
160         SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x050),
161         SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x060),
162         SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x070),
163         SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x080),
164         SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x090),
165         SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x0C0),
166         SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x0D0),
167 #endif
168 };
169
170 static struct sleep_save s5pv310_lpa_save[] = {
171         /* GIC side */
172 #ifndef CONFIG_USE_EXT_GIC
173         SAVE_ITEM(S5P_VA_GIC_CPU + 0x000),
174         SAVE_ITEM(S5P_VA_GIC_CPU + 0x004),
175         SAVE_ITEM(S5P_VA_GIC_CPU + 0x008),
176         SAVE_ITEM(S5P_VA_GIC_CPU + 0x014),
177         SAVE_ITEM(S5P_VA_GIC_CPU + 0x018),
178         SAVE_ITEM(S5P_VA_GIC_DIST + 0x000),
179         SAVE_ITEM(S5P_VA_GIC_DIST + 0x004),
180         SAVE_ITEM(S5P_VA_GIC_DIST + 0x100),
181         SAVE_ITEM(S5P_VA_GIC_DIST + 0x104),
182         SAVE_ITEM(S5P_VA_GIC_DIST + 0x108),
183         SAVE_ITEM(S5P_VA_GIC_DIST + 0x300),
184         SAVE_ITEM(S5P_VA_GIC_DIST + 0x304),
185         SAVE_ITEM(S5P_VA_GIC_DIST + 0x308),
186         SAVE_ITEM(S5P_VA_GIC_DIST + 0x400),
187         SAVE_ITEM(S5P_VA_GIC_DIST + 0x404),
188         SAVE_ITEM(S5P_VA_GIC_DIST + 0x408),
189         SAVE_ITEM(S5P_VA_GIC_DIST + 0x40C),
190         SAVE_ITEM(S5P_VA_GIC_DIST + 0x410),
191         SAVE_ITEM(S5P_VA_GIC_DIST + 0x414),
192         SAVE_ITEM(S5P_VA_GIC_DIST + 0x418),
193         SAVE_ITEM(S5P_VA_GIC_DIST + 0x41C),
194         SAVE_ITEM(S5P_VA_GIC_DIST + 0x420),
195         SAVE_ITEM(S5P_VA_GIC_DIST + 0x424),
196         SAVE_ITEM(S5P_VA_GIC_DIST + 0x428),
197         SAVE_ITEM(S5P_VA_GIC_DIST + 0x42C),
198         SAVE_ITEM(S5P_VA_GIC_DIST + 0x430),
199         SAVE_ITEM(S5P_VA_GIC_DIST + 0x434),
200         SAVE_ITEM(S5P_VA_GIC_DIST + 0x438),
201         SAVE_ITEM(S5P_VA_GIC_DIST + 0x43C),
202         SAVE_ITEM(S5P_VA_GIC_DIST + 0x440),
203         SAVE_ITEM(S5P_VA_GIC_DIST + 0x444),
204         SAVE_ITEM(S5P_VA_GIC_DIST + 0x448),
205         SAVE_ITEM(S5P_VA_GIC_DIST + 0x44C),
206         SAVE_ITEM(S5P_VA_GIC_DIST + 0x450),
207         SAVE_ITEM(S5P_VA_GIC_DIST + 0x454),
208         SAVE_ITEM(S5P_VA_GIC_DIST + 0x458),
209         SAVE_ITEM(S5P_VA_GIC_DIST + 0x45C),
210
211         SAVE_ITEM(S5P_VA_GIC_DIST + 0x800),
212         SAVE_ITEM(S5P_VA_GIC_DIST + 0x804),
213         SAVE_ITEM(S5P_VA_GIC_DIST + 0x808),
214         SAVE_ITEM(S5P_VA_GIC_DIST + 0x80C),
215         SAVE_ITEM(S5P_VA_GIC_DIST + 0x810),
216         SAVE_ITEM(S5P_VA_GIC_DIST + 0x814),
217         SAVE_ITEM(S5P_VA_GIC_DIST + 0x818),
218         SAVE_ITEM(S5P_VA_GIC_DIST + 0x81C),
219         SAVE_ITEM(S5P_VA_GIC_DIST + 0x820),
220         SAVE_ITEM(S5P_VA_GIC_DIST + 0x824),
221         SAVE_ITEM(S5P_VA_GIC_DIST + 0x828),
222         SAVE_ITEM(S5P_VA_GIC_DIST + 0x82C),
223         SAVE_ITEM(S5P_VA_GIC_DIST + 0x830),
224         SAVE_ITEM(S5P_VA_GIC_DIST + 0x834),
225         SAVE_ITEM(S5P_VA_GIC_DIST + 0x838),
226         SAVE_ITEM(S5P_VA_GIC_DIST + 0x83C),
227         SAVE_ITEM(S5P_VA_GIC_DIST + 0x840),
228         SAVE_ITEM(S5P_VA_GIC_DIST + 0x844),
229         SAVE_ITEM(S5P_VA_GIC_DIST + 0x848),
230         SAVE_ITEM(S5P_VA_GIC_DIST + 0x84C),
231         SAVE_ITEM(S5P_VA_GIC_DIST + 0x850),
232         SAVE_ITEM(S5P_VA_GIC_DIST + 0x854),
233         SAVE_ITEM(S5P_VA_GIC_DIST + 0x858),
234         SAVE_ITEM(S5P_VA_GIC_DIST + 0x85C),
235
236         SAVE_ITEM(S5P_VA_GIC_DIST + 0xC00),
237         SAVE_ITEM(S5P_VA_GIC_DIST + 0xC04),
238         SAVE_ITEM(S5P_VA_GIC_DIST + 0xC08),
239         SAVE_ITEM(S5P_VA_GIC_DIST + 0xC0C),
240         SAVE_ITEM(S5P_VA_GIC_DIST + 0xC10),
241         SAVE_ITEM(S5P_VA_GIC_DIST + 0xC14),
242
243         SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x000),
244         SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x010),
245         SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x020),
246         SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x030),
247         SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x040),
248         SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x050),
249         SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x060),
250         SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x070),
251         SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x080),
252         SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x090),
253         SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x0C0),
254         SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x0D0),
255 #endif
256         /* CMU side */
257         SAVE_ITEM(S5P_CLKSRC_MASK_TOP),
258         SAVE_ITEM(S5P_CLKSRC_MASK_CAM),
259         SAVE_ITEM(S5P_CLKSRC_MASK_TV),
260         SAVE_ITEM(S5P_CLKSRC_MASK_LCD0),
261         SAVE_ITEM(S5P_CLKSRC_MASK_LCD1),
262         SAVE_ITEM(S5P_CLKSRC_MASK_MAUDIO),
263         SAVE_ITEM(S5P_CLKSRC_MASK_FSYS),
264         SAVE_ITEM(S5P_CLKSRC_MASK_PERIL0),
265         SAVE_ITEM(S5P_CLKSRC_MASK_PERIL1),
266         SAVE_ITEM(S5P_CLKSRC_MASK_DMC),
267 };
268
269 static struct sleep_save s5pv310_aftr[] = {
270         { .reg = S5P_ARM_CORE0_LOWPWR                   , .val = 0x0, },
271         { .reg = S5P_DIS_IRQ_CORE0                      , .val = 0x0, },
272         { .reg = S5P_DIS_IRQ_CENTRAL0                   , .val = 0x0, },
273         { .reg = S5P_ARM_CORE1_LOWPWR                   , .val = 0x0, },
274         { .reg = S5P_DIS_IRQ_CORE1                      , .val = 0x0, },
275         { .reg = S5P_DIS_IRQ_CENTRAL1                   , .val = 0x0, },
276         { .reg = S5P_ARM_COMMON_LOWPWR                  , .val = 0x0, },
277         { .reg = S5P_L2_0_LOWPWR                        , .val = 0x2, },
278         { .reg = S5P_L2_1_LOWPWR                        , .val = 0x2, },
279         { .reg = S5P_CMU_ACLKSTOP_LOWPWR                , .val = 0x1, },
280         { .reg = S5P_CMU_SCLKSTOP_LOWPWR                , .val = 0x1, },
281         { .reg = S5P_CMU_RESET_LOWPWR                   , .val = 0x1, },
282         { .reg = S5P_APLL_SYSCLK_LOWPWR                 , .val = 0x1, },
283         { .reg = S5P_MPLL_SYSCLK_LOWPWR                 , .val = 0x1, },
284         { .reg = S5P_VPLL_SYSCLK_LOWPWR                 , .val = 0x1, },
285         { .reg = S5P_EPLL_SYSCLK_LOWPWR                 , .val = 0x1, },
286         { .reg = S5P_CMU_CLKSTOP_GPS_ALIVE_LOWPWR       , .val = 0x1, },
287         { .reg = S5P_CMU_RESET_GPSALIVE_LOWPWR          , .val = 0x1, },
288         { .reg = S5P_CMU_CLKSTOP_CAM_LOWPWR             , .val = 0x1, },
289         { .reg = S5P_CMU_CLKSTOP_TV_LOWPWR              , .val = 0x1, },
290         { .reg = S5P_CMU_CLKSTOP_MFC_LOWPWR             , .val = 0x1, },
291         { .reg = S5P_CMU_CLKSTOP_G3D_LOWPWR             , .val = 0x1, },
292         { .reg = S5P_CMU_CLKSTOP_LCD0_LOWPWR            , .val = 0x1, },
293         { .reg = S5P_CMU_CLKSTOP_LCD1_LOWPWR            , .val = 0x1, },
294         { .reg = S5P_CMU_CLKSTOP_MAUDIO_LOWPWR          , .val = 0x1, },
295         { .reg = S5P_CMU_CLKSTOP_GPS_LOWPWR             , .val = 0x1, },
296         { .reg = S5P_CMU_RESET_CAM_LOWPWR               , .val = 0x1, },
297         { .reg = S5P_CMU_RESET_TV_LOWPWR                , .val = 0x1, },
298         { .reg = S5P_CMU_RESET_MFC_LOWPWR               , .val = 0x1, },
299         { .reg = S5P_CMU_RESET_G3D_LOWPWR               , .val = 0x1, },
300         { .reg = S5P_CMU_RESET_LCD0_LOWPWR              , .val = 0x1, },
301         { .reg = S5P_CMU_RESET_LCD1_LOWPWR              , .val = 0x1, },
302         { .reg = S5P_CMU_RESET_MAUDIO_LOWPWR            , .val = 0x1, },
303         { .reg = S5P_CMU_RESET_GPS_LOWPWR               , .val = 0x1, },
304         { .reg = S5P_TOP_BUS_LOWPWR                     , .val = 0x3, },
305         { .reg = S5P_TOP_RETENTION_LOWPWR               , .val = 0x1, },
306         { .reg = S5P_TOP_PWR_LOWPWR                     , .val = 0x3, },
307         { .reg = S5P_LOGIC_RESET_LOWPWR                 , .val = 0x1, },
308         { .reg = S5P_ONENAND_MEM_LOWPWR                 , .val = 0x3, },
309         { .reg = S5P_MODIMIF_MEM_LOWPWR                 , .val = 0x3, },
310         { .reg = S5P_G2D_ACP_MEM_LOWPWR                 , .val = 0x3, },
311         { .reg = S5P_USBOTG_MEM_LOWPWR                  , .val = 0x3, },
312         { .reg = S5P_HSMMC_MEM_LOWPWR                   , .val = 0x3, },
313         { .reg = S5P_CSSYS_MEM_LOWPWR                   , .val = 0x3, },
314         { .reg = S5P_SECSS_MEM_LOWPWR                   , .val = 0x3, },
315         { .reg = S5P_PCIE_MEM_LOWPWR                    , .val = 0x3, },
316         { .reg = S5P_SATA_MEM_LOWPWR                    , .val = 0x3, },
317         { .reg = S5P_PAD_RETENTION_DRAM_LOWPWR          , .val = 0x1, },
318         { .reg = S5P_PAD_RETENTION_MAUDIO_LOWPWR        , .val = 0x1, },
319         { .reg = S5P_PAD_RETENTION_GPIO_LOWPWR          , .val = 0x1, },
320         { .reg = S5P_PAD_RETENTION_UART_LOWPWR          , .val = 0x1, },
321         { .reg = S5P_PAD_RETENTION_MMCA_LOWPWR          , .val = 0x1, },
322         { .reg = S5P_PAD_RETENTION_MMCB_LOWPWR          , .val = 0x1, },
323         { .reg = S5P_PAD_RETENTION_EBIA_LOWPWR          , .val = 0x1, },
324         { .reg = S5P_PAD_RETENTION_EBIB_LOWPWR          , .val = 0x1, },
325         { .reg = S5P_PAD_RETENTION_ISOLATION_LOWPWR     , .val = 0x1, },
326         { .reg = S5P_PAD_RETENTION_ALV_SEL_LOWPWR       , .val = 0x1, },
327         { .reg = S5P_XUSBXTI_LOWPWR                     , .val = 0x1, },
328         { .reg = S5P_XXTI_LOWPWR                        , .val = 0x1, },
329         { .reg = S5P_EXT_REGULATOR_LOWPWR               , .val = 0x1, },
330         { .reg = S5P_GPIO_MODE_LOWPWR                   , .val = 0x1, },
331         { .reg = S5P_GPIO_MODE_MAUDIO_LOWPWR            , .val = 0x1, },
332         { .reg = S5P_CAM_LOWPWR                         , .val = 0x7, },
333         { .reg = S5P_TV_LOWPWR                          , .val = 0x7, },
334         { .reg = S5P_MFC_LOWPWR                         , .val = 0x7, },
335         { .reg = S5P_G3D_LOWPWR                         , .val = 0x7, },
336         { .reg = S5P_LCD0_LOWPWR                        , .val = 0x7, },
337         { .reg = S5P_LCD1_LOWPWR                        , .val = 0x7, },
338         { .reg = S5P_MAUDIO_LOWPWR                      , .val = 0x7, },
339         { .reg = S5P_GPS_LOWPWR                         , .val = 0x7, },
340         { .reg = S5P_GPS_ALIVE_LOWPWR                   , .val = 0x7, },
341 };
342
343 static struct sleep_save s5pv310_lpa[] = {
344         { .reg = S5P_ARM_CORE0_LOWPWR                   , .val = 0x0, },
345         { .reg = S5P_DIS_IRQ_CORE0                      , .val = 0x0, },
346         { .reg = S5P_DIS_IRQ_CENTRAL0                   , .val = 0x0, },
347         { .reg = S5P_ARM_CORE1_LOWPWR                   , .val = 0x0, },
348         { .reg = S5P_DIS_IRQ_CORE1                      , .val = 0x0, },
349         { .reg = S5P_DIS_IRQ_CENTRAL1                   , .val = 0x0, },
350         { .reg = S5P_ARM_COMMON_LOWPWR                  , .val = 0x0, },
351         { .reg = S5P_L2_0_LOWPWR                        , .val = 0x2, },
352         { .reg = S5P_L2_1_LOWPWR                        , .val = 0x2, },
353         { .reg = S5P_CMU_ACLKSTOP_LOWPWR                , .val = 0x0, },
354         { .reg = S5P_CMU_SCLKSTOP_LOWPWR                , .val = 0x0, },
355         { .reg = S5P_CMU_RESET_LOWPWR                   , .val = 0x1, },
356         { .reg = S5P_APLL_SYSCLK_LOWPWR                 , .val = 0x0, },
357         { .reg = S5P_MPLL_SYSCLK_LOWPWR                 , .val = 0x0, },
358         { .reg = S5P_VPLL_SYSCLK_LOWPWR                 , .val = 0x0, },
359         { .reg = S5P_EPLL_SYSCLK_LOWPWR                 , .val = 0x1, },
360         { .reg = S5P_CMU_CLKSTOP_GPS_ALIVE_LOWPWR       , .val = 0x1, },
361         { .reg = S5P_CMU_RESET_GPSALIVE_LOWPWR          , .val = 0x1, },
362         { .reg = S5P_CMU_CLKSTOP_CAM_LOWPWR             , .val = 0x1, },
363         { .reg = S5P_CMU_CLKSTOP_TV_LOWPWR              , .val = 0x1, },
364         { .reg = S5P_CMU_CLKSTOP_MFC_LOWPWR             , .val = 0x1, },
365         { .reg = S5P_CMU_CLKSTOP_G3D_LOWPWR             , .val = 0x1, },
366         { .reg = S5P_CMU_CLKSTOP_LCD0_LOWPWR            , .val = 0x1, },
367         { .reg = S5P_CMU_CLKSTOP_LCD1_LOWPWR            , .val = 0x1, },
368         { .reg = S5P_CMU_CLKSTOP_MAUDIO_LOWPWR          , .val = 0x1, },
369         { .reg = S5P_CMU_CLKSTOP_GPS_LOWPWR             , .val = 0x1, },
370         { .reg = S5P_CMU_RESET_CAM_LOWPWR               , .val = 0x1, },
371         { .reg = S5P_CMU_RESET_TV_LOWPWR                , .val = 0x1, },
372         { .reg = S5P_CMU_RESET_MFC_LOWPWR               , .val = 0x1, },
373         { .reg = S5P_CMU_RESET_G3D_LOWPWR               , .val = 0x1, },
374         { .reg = S5P_CMU_RESET_LCD0_LOWPWR              , .val = 0x1, },
375         { .reg = S5P_CMU_RESET_LCD1_LOWPWR              , .val = 0x1, },
376         { .reg = S5P_CMU_RESET_MAUDIO_LOWPWR            , .val = 0x1, },
377         { .reg = S5P_CMU_RESET_GPS_LOWPWR               , .val = 0x1, },
378         { .reg = S5P_TOP_BUS_LOWPWR                     , .val = 0x0, },
379         { .reg = S5P_TOP_RETENTION_LOWPWR               , .val = 0x0, },
380         { .reg = S5P_TOP_PWR_LOWPWR                     , .val = 0x0, },
381         { .reg = S5P_LOGIC_RESET_LOWPWR                 , .val = 0x1, },
382         { .reg = S5P_ONENAND_MEM_LOWPWR                 , .val = 0x0, },
383         { .reg = S5P_MODIMIF_MEM_LOWPWR                 , .val = 0x0, },
384         { .reg = S5P_G2D_ACP_MEM_LOWPWR                 , .val = 0x0, },
385         { .reg = S5P_USBOTG_MEM_LOWPWR                  , .val = 0x0, },
386         { .reg = S5P_HSMMC_MEM_LOWPWR                   , .val = 0x0, },
387         { .reg = S5P_CSSYS_MEM_LOWPWR                   , .val = 0x0, },
388         { .reg = S5P_SECSS_MEM_LOWPWR                   , .val = 0x0, },
389         { .reg = S5P_PCIE_MEM_LOWPWR                    , .val = 0x0, },
390         { .reg = S5P_SATA_MEM_LOWPWR                    , .val = 0x0, },
391         { .reg = S5P_PAD_RETENTION_DRAM_LOWPWR          , .val = 0x0, },
392         { .reg = S5P_PAD_RETENTION_MAUDIO_LOWPWR        , .val = 0x1, },
393         { .reg = S5P_PAD_RETENTION_GPIO_LOWPWR          , .val = 0x0, },
394         { .reg = S5P_PAD_RETENTION_UART_LOWPWR          , .val = 0x0, },
395         { .reg = S5P_PAD_RETENTION_MMCA_LOWPWR          , .val = 0x0, },
396         { .reg = S5P_PAD_RETENTION_MMCB_LOWPWR          , .val = 0x0, },
397         { .reg = S5P_PAD_RETENTION_EBIA_LOWPWR          , .val = 0x0, },
398         { .reg = S5P_PAD_RETENTION_EBIB_LOWPWR          , .val = 0x0, },
399         { .reg = S5P_PAD_RETENTION_ISOLATION_LOWPWR     , .val = 0x0, },
400         { .reg = S5P_PAD_RETENTION_ALV_SEL_LOWPWR       , .val = 0x0, },
401         { .reg = S5P_XUSBXTI_LOWPWR                     , .val = 0x1, },
402         { .reg = S5P_XXTI_LOWPWR                        , .val = 0x1, },
403         { .reg = S5P_EXT_REGULATOR_LOWPWR               , .val = 0x1, },
404         { .reg = S5P_GPIO_MODE_LOWPWR                   , .val = 0x0, },
405         { .reg = S5P_GPIO_MODE_MAUDIO_LOWPWR            , .val = 0x1, },
406         { .reg = S5P_CAM_LOWPWR                         , .val = 0x0, },
407         { .reg = S5P_TV_LOWPWR                          , .val = 0x0, },
408         { .reg = S5P_MFC_LOWPWR                         , .val = 0x0, },
409         { .reg = S5P_G3D_LOWPWR                         , .val = 0x0, },
410         { .reg = S5P_LCD0_LOWPWR                        , .val = 0x0, },
411         { .reg = S5P_LCD1_LOWPWR                        , .val = 0x0, },
412         { .reg = S5P_MAUDIO_LOWPWR                      , .val = 0x7, },
413         { .reg = S5P_GPS_LOWPWR                         , .val = 0x0, },
414         { .reg = S5P_GPS_ALIVE_LOWPWR                   , .val = 0x0, },
415 };
416
417 static struct sleep_save s5pv310_set_clksrc[] = {
418         { .reg = S5P_CLKSRC_MASK_TOP                    , .val = 0x00000001, },
419         { .reg = S5P_CLKSRC_MASK_CAM                    , .val = 0x11111111, },
420         { .reg = S5P_CLKSRC_MASK_TV                     , .val = 0x00000111, },
421         { .reg = S5P_CLKSRC_MASK_LCD0                   , .val = 0x00001111, },
422         { .reg = S5P_CLKSRC_MASK_LCD1                   , .val = 0x00001111, },
423         { .reg = S5P_CLKSRC_MASK_MAUDIO                 , .val = 0x00000001, },
424         { .reg = S5P_CLKSRC_MASK_FSYS                   , .val = 0x01011111, },
425         { .reg = S5P_CLKSRC_MASK_PERIL0                 , .val = 0x01111111, },
426         { .reg = S5P_CLKSRC_MASK_PERIL1                 , .val = 0x01110111, },
427         { .reg = S5P_CLKSRC_MASK_DMC                    , .val = 0x00010000, },
428 };
429
430 /*
431  * This function is called by s3c_cpu_save() in sleep.S. The contents of
432  * the SVC mode stack area and s3c_sleep_save_phys variable should be
433  * updated to physical memory until entering AFTR mode. The memory contents
434  * are used by s3c_cpu_resume() and resume_with_mmu before enabling L2 cache.
435  */
436 void s5p_aftr_cache_clean(void *stack_addr)
437 {
438         unsigned long tmp;
439
440         clean_dcache_area(stack_addr, 0x5f);
441         clean_dcache_area(&s3c_sleep_save_phys, 1);
442 #ifdef CONFIG_OUTER_CACHE
443         /* SVC mode stack area is cleaned from L2 cache */
444         tmp = virt_to_phys(stack_addr);
445         outer_cache.clean_range(tmp, tmp + 0x5f);
446
447         /* The variable is cleaned from L2 cache */
448         tmp = virt_to_phys(&s3c_sleep_save_phys);
449         outer_cache.clean_range(tmp, tmp + 1);
450 #endif
451 }
452
453 enum gic_loc {
454         INT_GIC,
455         EXT_GIC,
456         END_GIC,
457
458 };
459
460 static void s5pv310_gic_ctrl(enum gic_loc gic, unsigned int ctrl)
461 {
462         if (ctrl > 1 || gic >= END_GIC) {
463                 printk(KERN_ERR "Invalid input argument: %s, %d\n",
464                        __func__, __LINE__);
465                 return;
466         }
467
468         switch (gic) {
469         case INT_GIC:
470                 __raw_writel(ctrl, S5P_VA_GIC_DIST + 0x00);
471                 __raw_writel(ctrl, S5P_VA_GIC_CPU + 0x00);
472                 break;
473         case EXT_GIC:
474                 __raw_writel(ctrl, S5P_VA_EXTGIC_DIST + 0x00);
475                 __raw_writel(ctrl, S5P_VA_EXTGIC_CPU + 0x00);
476                 break;
477         default:
478                 break;
479         }
480 }
481
482 static int s5pv310_enter_idle(struct cpuidle_device *dev,
483                               struct cpuidle_state *state);
484
485 static int s5pv310_enter_lowpower(struct cpuidle_device *dev,
486                               struct cpuidle_state *state);
487
488 static struct cpuidle_state s5pv310_cpuidle_set[] = {
489         [0] = {
490                 .enter                  = s5pv310_enter_idle,
491                 .exit_latency           = 1,
492                 .target_residency       = 1000,
493                 .flags                  = CPUIDLE_FLAG_TIME_VALID,
494                 .name                   = "IDLE",
495                 .desc                   = "ARM clock gating(WFI)",
496         },
497 #if 0
498         [1] = {
499                 .enter                  = s5pv310_enter_lowpower,
500                 .exit_latency           = 10,
501                 .target_residency       = 10000,
502                 .flags                  = CPUIDLE_FLAG_TIME_VALID,
503                 .name                   = "LOW_POWER",
504                 .desc                   = "ARM power down",
505         },
506 #endif
507 };
508
509 static DEFINE_PER_CPU(struct cpuidle_device, s5pv310_cpuidle_device);
510
511 static struct cpuidle_driver s5pv310_idle_driver = {
512         .name           = "s5pv310_idle",
513         .owner          = THIS_MODULE,
514 };
515
516 void s5pv310_set_core0_pwroff(void)
517 {
518         unsigned long tmp;
519         /*
520          * Setting Central Sequence Register for power down mode
521          */
522         tmp = __raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION);
523         tmp &= ~(S5P_CENTRAL_LOWPWR_CFG);
524         __raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION);
525
526         flush_cache_all();
527
528         cpu_do_idle();
529 }
530
531 static int s5pv310_check_gic_pending(enum gic_loc gic)
532 {
533         unsigned long tmp;
534
535         if (gic >= END_GIC) {
536                 printk(KERN_ERR "Invalid input argument: %s, %d\n",
537                        __func__, __LINE__);
538                 return 0;
539         }
540         if (gic  == INT_GIC)
541                 tmp = __raw_readl(S5P_VA_GIC_CPU + 0x0c);
542         else
543                 tmp = __raw_readl(S5P_VA_EXTGIC_CPU + 0x0c);
544
545         if (tmp != 0x3ff) {
546                 if (gic  == INT_GIC)
547                         __raw_writel(tmp, S5P_VA_GIC_CPU + 0x10);
548                 else
549                         __raw_writel(tmp, S5P_VA_EXTGIC_CPU + 0x10);
550
551                 return 1;
552         } else
553                 return 0;
554 }
555
556 #define GPIO_OFFSET             0x20
557 #define GPIO_PUD_OFFSET         0x08
558 #define GPIO_CON_PDN_OFFSET     0x10
559 #define GPIO_PUD_PDN_OFFSET     0x14
560 #define GPIO_END_OFFSET         0x200
561 static void s5pv310_gpio_conpdn_reg(void)
562 {
563         void __iomem *gpio_base = S5P_VA_GPIO;
564         unsigned int val;
565
566         do {
567                 /* Keep the previous state in didle mode */
568                 __raw_writel(0xffff, gpio_base + GPIO_CON_PDN_OFFSET);
569
570                 /* Pull up-down state in didle is same as normal */
571                 val = __raw_readl(gpio_base + GPIO_PUD_OFFSET);
572                 __raw_writel(val, gpio_base + GPIO_PUD_PDN_OFFSET);
573
574                 gpio_base += GPIO_OFFSET;
575
576                 if (gpio_base == S5P_VA_GPIO + GPIO_END_OFFSET)
577                         gpio_base = S5PV310_VA_GPIO2;
578
579         } while (gpio_base <= S5PV310_VA_GPIO2 + GPIO_END_OFFSET);
580
581         /* set the GPZ */
582         gpio_base = S5P_VA_GPIO3;
583         __raw_writel(0xffff, gpio_base + GPIO_CON_PDN_OFFSET);
584
585         val = __raw_readl(gpio_base + GPIO_PUD_OFFSET);
586         __raw_writel(val, gpio_base + GPIO_PUD_PDN_OFFSET);
587 }
588
589 static void s5pv310_set_wakeupmask(void)
590 {
591         __raw_writel(0x0000ff3e, S5P_WAKEUP_MASK);
592 }
593
594 static int s5pv310_enter_core0_aftr(struct cpuidle_device *dev,
595                                     struct cpuidle_state *state)
596 {
597         struct timeval before, after;
598         int idle_time;
599         unsigned long tmp;
600
601         s3c_pm_do_save(s5pv310_aftr_save, ARRAY_SIZE(s5pv310_aftr_save));
602
603         s3c_sleep_save_phys = phy_regs_save;
604
605         local_irq_disable();
606         do_gettimeofday(&before);
607
608         s5pv310_set_wakeupmask();
609 #ifndef CONFIG_USE_EXT_GIC
610         if (s5pv310_check_gic_pending(INT_GIC))
611                 goto early_wakeup;
612
613         remap_ext_gic();
614         s5pv310_gic_ctrl(INT_GIC, 0);
615         s5pv310_gic_ctrl(EXT_GIC, 1);
616 #endif
617         /* ensure at least INFORM0 has the resume address */
618         __raw_writel(virt_to_phys(s3c_cpu_resume), S5P_INFORM0);
619
620         __raw_writel(virt_to_phys(s3c_cpu_resume), REG_DIRECTGO_ADDR);
621         __raw_writel(0xfcba0d10, REG_DIRECTGO_FLAG);
622
623         /* Set value of power down register for aftr mode */
624         s3c_pm_do_restore(s5pv310_aftr, ARRAY_SIZE(s5pv310_aftr));
625         __raw_writel(S5P_CHECK_DIDLE, S5P_INFORM1);
626         /* Obsolete: for the compatibility with obsolete s-boot */
627         if (s5pv310_subrev() == 0)
628                 __raw_writel(S5P_CHECK_DIDLE, S5P_INFORM7);
629
630         if (s3c_cpu_save(regs_save) == 0) {
631                 /*
632                  * Clear Central Sequence Register in exiting early wakeup
633                  */
634                 tmp = __raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION);
635                 tmp |= (S5P_CENTRAL_LOWPWR_CFG);
636                 __raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION);
637 #ifndef CONFIG_USE_EXT_GIC
638                 /* Clear Ext GIC interrupt pending */
639                 tmp = s5pv310_check_gic_pending(EXT_GIC);
640
641                 /* Disable external GIC */
642                 s5pv310_gic_ctrl(EXT_GIC, 0);
643
644                 /* Enable internal GIC */
645                 s5pv310_gic_ctrl(INT_GIC, 1);
646 #endif
647                 goto early_wakeup;
648         }
649
650         cpu_init();
651 #ifndef CONFIG_USE_EXT_GIC
652         /* Disable external GIC */
653         s5pv310_gic_ctrl(EXT_GIC, 0);
654 #endif
655         s3c_pm_do_restore_core(s5pv310_aftr_save,
656                                        ARRAY_SIZE(s5pv310_aftr_save));
657 early_wakeup:
658
659         /* Clear wakeup state register */
660         __raw_writel(0x0, S5P_WAKEUP_STAT);
661
662         do_gettimeofday(&after);
663
664         local_irq_enable();
665         idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
666                     (after.tv_usec - before.tv_usec);
667
668         return idle_time;
669 }
670
671 static int s5pv310_check_enter(void)
672 {
673         unsigned int ret;
674         unsigned int check_val;
675
676         ret = 0;
677
678         /* Check UART for console is empty */
679         check_val = __raw_readl(S5P_VA_UART(CONFIG_S3C_LOWLEVEL_UART_PORT) +
680                                 0x18);
681
682         ret = ((check_val >> 16) & 0xff);
683
684         return ret;
685 }
686
687 static int s5pv310_enter_core0_lpa(struct cpuidle_device *dev,
688                                    struct cpuidle_state *state)
689 {
690         struct timeval before, after;
691         int idle_time;
692         unsigned long tmp;
693
694         printk(KERN_DEBUG "+++ %s\n", __func__);
695
696         s3c_pm_do_save(s5pv310_lpa_save, ARRAY_SIZE(s5pv310_lpa_save));
697
698         /*
699          * Before enter central sequence mode, clock src register have to set
700          */
701         s3c_pm_do_restore_core(s5pv310_set_clksrc,
702                                ARRAY_SIZE(s5pv310_set_clksrc));
703
704         s3c_sleep_save_phys = phy_regs_save;
705
706         local_irq_disable();
707         do_gettimeofday(&before);
708
709         /*
710          * Unmasking all wakeup source.
711          */
712         __raw_writel(0x0, S5P_WAKEUP_MASK);
713
714         /* Configure GPIO Power down control register */
715         s5pv310_gpio_conpdn_reg();
716
717         /* ensure at least INFORM0 has the resume address */
718         __raw_writel(virt_to_phys(s3c_cpu_resume), S5P_INFORM0);
719
720         __raw_writel(virt_to_phys(s3c_cpu_resume), REG_DIRECTGO_ADDR);
721         __raw_writel(0xfcba0d10, REG_DIRECTGO_FLAG);
722
723         __raw_writel(S5P_CHECK_LPA, S5P_INFORM1);
724         /* Obsolete: for the compatibility with obsolete s-boot */
725         if (s5pv310_subrev() == 0)
726                 __raw_writel(S5P_CHECK_LPA, S5P_INFORM7);
727         s3c_pm_do_restore(s5pv310_lpa, ARRAY_SIZE(s5pv310_lpa));
728
729         __raw_writel(0xfcba0d10, S5P_VA_SYSRAM + 0x20);
730
731
732         do {
733         } while (s5pv310_check_enter());
734
735
736         if (s3c_cpu_save(regs_save) == 0) {
737
738                 tmp = __raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION);
739                 tmp |= (S5P_CENTRAL_LOWPWR_CFG);
740                 __raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION);
741
742                 goto early_wakeup;
743         }
744
745         cpu_init();
746
747         s3c_pm_do_restore_core(s5pv310_lpa_save,
748                                ARRAY_SIZE(s5pv310_lpa_save));
749
750         /* For release retention */
751         __raw_writel((1 << 28), S5P_PAD_RET_GPIO_OPTION);
752         __raw_writel((1 << 28), S5P_PAD_RET_UART_OPTION);
753         __raw_writel((1 << 28), S5P_PAD_RET_MMCA_OPTION);
754         __raw_writel((1 << 28), S5P_PAD_RET_MMCB_OPTION);
755         __raw_writel((1 << 28), S5P_PAD_RET_EBIA_OPTION);
756         __raw_writel((1 << 28), S5P_PAD_RET_EBIB_OPTION);
757
758 early_wakeup:
759
760         /* Clear wakeup state register */
761         __raw_writel(0x0, S5P_WAKEUP_STAT);
762
763         __raw_writel(0x0, S5P_WAKEUP_MASK);
764
765         do_gettimeofday(&after);
766
767         local_irq_enable();
768         idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
769                     (after.tv_usec - before.tv_usec);
770
771         printk(KERN_DEBUG "--- %s\n", __func__);
772
773         return idle_time;
774 }
775
776 static int s5pv310_enter_idle(struct cpuidle_device *dev,
777                               struct cpuidle_state *state)
778 {
779         struct timeval before, after;
780         int idle_time;
781         int cpu;
782         unsigned int tmp, nr_cores;
783
784         local_irq_disable();
785         do_gettimeofday(&before);
786
787         cpu = get_cpu();
788
789         spin_lock(&idle_lock);
790
791         /* Let hotplug cpu_down/up finish first */
792         if (hotplugging) {
793                 spin_unlock(&idle_lock);
794
795                 put_cpu();
796                 do_gettimeofday(&after);
797                 local_irq_enable();
798                 idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
799                         (after.tv_usec - before.tv_usec);
800                 return idle_time;
801         }
802         idling = true;
803
804         cpu_core |= (1 << cpu);
805
806         if (cpu_online(1))
807                 nr_cores = 0x3;
808         else
809                 nr_cores = 0x1;
810
811         if (cpu_core == nr_cores) {
812                 old_div = __raw_readl(S5P_CLKDIV_CPU);
813                 tmp = old_div;
814                 tmp |= ((0x7 << 28) | (0x7 << 0));
815                 __raw_writel(tmp , S5P_CLKDIV_CPU);
816
817                 do {
818                         tmp = __raw_readl(S5P_CLKDIV_STATCPU);
819                 } while (tmp & 0x10000001);
820         }
821
822         spin_unlock(&idle_lock);
823
824         cpu_do_idle();
825
826         spin_lock(&idle_lock);
827
828         if (cpu_core == nr_cores) {
829                 __raw_writel(old_div, S5P_CLKDIV_CPU);
830
831                 do {
832                         tmp = __raw_readl(S5P_CLKDIV_STATCPU);
833                 } while (tmp & 0x10000001);
834         }
835
836         cpu_core &= ~(1 << cpu);
837
838         idling = false;
839         spin_unlock(&idle_lock);
840
841         put_cpu();
842
843         do_gettimeofday(&after);
844         local_irq_enable();
845         idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
846                     (after.tv_usec - before.tv_usec);
847
848         return idle_time;
849 }
850
851 /*
852  * Check conditions to enter LPA mode 
853  */
854 static int check_power_domain(void)
855 {
856         unsigned long tmp;
857
858         tmp = __raw_readl(S5P_PMU_LCD0_CONF);
859         if ((tmp & S5P_INT_LOCAL_PWR_EN) == S5P_INT_LOCAL_PWR_EN)
860                 return 1;
861
862         tmp = __raw_readl(S5P_PMU_MFC_CONF);
863         if ((tmp & S5P_INT_LOCAL_PWR_EN) == S5P_INT_LOCAL_PWR_EN)
864                 return 1;
865
866         tmp = __raw_readl(S5P_PMU_G3D_CONF);
867         if ((tmp & S5P_INT_LOCAL_PWR_EN) == S5P_INT_LOCAL_PWR_EN)
868                 return 1;
869
870         tmp = __raw_readl(S5P_PMU_CAM_CONF);
871         if ((tmp & S5P_INT_LOCAL_PWR_EN) == S5P_INT_LOCAL_PWR_EN)
872                 return 1;
873
874         tmp = __raw_readl(S5P_PMU_TV_CONF);
875         if ((tmp & S5P_INT_LOCAL_PWR_EN) == S5P_INT_LOCAL_PWR_EN)
876                 return 1;
877
878         tmp = __raw_readl(S5P_PMU_GPS_CONF);
879         if ((tmp & S5P_INT_LOCAL_PWR_EN) == S5P_INT_LOCAL_PWR_EN)
880                 return 1;
881
882         return 0;
883 }
884
885 static int check_clock_gating(void)
886 {
887         unsigned long tmp;
888
889         tmp = __raw_readl(S5P_CLKGATE_IP_IMAGE);
890         if (tmp & (S5P_CLKGATE_IP_IMAGE_MDMA_MASK
891                 | S5P_CLKGATE_IP_IMAGE_SMMUMDMA_MASK
892                 | S5P_CLKGATE_IP_IMAGE_QEMDMA_MASK)) {
893                 printk(KERN_DEBUG "MDMA is in use (CLKGATE_IP_IMAGE:0x%x\n", tmp);
894                 return 1;
895         }
896
897         tmp = __raw_readl(S5P_CLKGATE_IP_FSYS);
898         if (tmp & (S5P_CLKGATE_IP_FSYS_PDMA0_MASK
899                 | S5P_CLKGATE_IP_FSYS_PDMA1_MASK)) {
900                 printk(KERN_DEBUG "PDMA is in use (CLKGATE_IP_FSYS:0x%x\n", tmp);
901                 return 1;
902         }
903
904         /* I2C0 ~ I2C8 */
905         tmp = __raw_readl(S5P_CLKGATE_IP_PERIL);
906         if (tmp & S5P_CLKGATE_IP_PERIL_I2C0_8_MASK) {
907                 printk(KERN_DEBUG "I2C is in use (CLKGATE_IP_PERIL:0x%x)\n", tmp);
908                 return 1;
909         }
910
911         return 0;
912 }
913
914 /* MMC */
915 #define SDHCI_PRNSTS                    (0x24)
916 #define SDHCI_PRNSTS_CMDINHCMD          (0x1 << 0)
917 #define SDHCI_PRNSTS_CMDINHDAT          (0x1 << 1)
918 #define SDHCI_CLKCON                    (0x2c)
919 #define SDHCI_CLKCON_ENSDCLK            (0x1 << 2)
920
921 #define MSHCI_CLKENA                    (0x10)  /* Clock enable */
922 #define MSHCI_STATUS                    (0x48)  /* Status */
923 #define MSHCI_DATA_BUSY                 (0x1 << 9)
924 #define MSHCI_ENCLK                     (0x1 << 0)
925
926 static int sdmmc_dev_num = 0;
927 static int check_sdmmc_op(unsigned int ch)
928 {
929         unsigned int reg1, reg2;
930         void __iomem *base_addr;
931
932         if (unlikely(ch > sdmmc_dev_num)) {
933                 printk(KERN_ERR "Invalid ch[%d] for SD/MMC\n", ch);
934                 return 0;
935         }
936
937         if (chk_dev_op[ch].type == HC_SDHCI) {
938                 base_addr = chk_dev_op[ch].base;
939
940                 /* Check CMDINHDAT[1] and CMDINHCMD [0] */
941                 reg1 = readl(base_addr + SDHCI_PRNSTS);
942                 /* Check CLKCON [2]: ENSDCLK */
943                 reg2 = readl(base_addr + SDHCI_CLKCON);
944
945                 if (reg1 & (SDHCI_PRNSTS_CMDINHCMD | SDHCI_PRNSTS_CMDINHDAT)) {
946                         printk(KERN_DEBUG "%s is in use(CMD/DATA)\n",
947                                 dev_name(&chk_dev_op[ch].pdev->dev));
948                         return 1;
949                 } else if (reg2 & (SDHCI_CLKCON_ENSDCLK)) {
950                         printk(KERN_DEBUG "%s is clock on\n",
951                                 dev_name(&chk_dev_op[ch].pdev->dev));
952                         return 1;
953                 }
954
955         } else if (chk_dev_op[ch].type == HC_MSHCI) {
956                 base_addr = chk_dev_op[ch].base;
957
958                 base_addr = chk_dev_op[ch].base;
959                 /* Check STATUS [9] for data busy */
960                 reg1 = readl(base_addr + MSHCI_STATUS);
961                 /* Check CLKENA [0] for clock on/off */
962                 reg2 = readl(base_addr + MSHCI_CLKENA);
963
964                 if (reg1 & (MSHCI_DATA_BUSY)) {
965                         printk(KERN_DEBUG "\t%s: DATA BUSY\n",
966                                 dev_name(&chk_dev_op[ch].pdev->dev));
967                 }
968                 if (reg2 & (MSHCI_ENCLK)) {
969                         printk(KERN_DEBUG "\t%s: CLKENA\n",
970                                 dev_name(&chk_dev_op[ch].pdev->dev));
971                 }
972
973                 return (reg1 & (MSHCI_DATA_BUSY)) ||
974                        (reg2 & (MSHCI_ENCLK));
975         }
976         return 0;
977 }
978
979 /* Check all sdmmc controller */
980 static int check_sdmmc_state(void)
981 {
982         unsigned int i;
983
984         for (i = 0; i < sdmmc_dev_num + 1; i++) {
985                 if (check_sdmmc_op(i))
986                         return 1;
987         }
988         return 0;
989 }
990
991 extern int is_usb_host_phy_suspend(void);
992 static int check_usb_host_op(void)
993 {
994         return is_usb_host_phy_suspend();
995 }
996
997 /*
998  * Check USBOTG is working or not
999  * GOTGCTL(0xEC000000)
1000  * BSesVld (Indicates the Device mode transceiver status)
1001  * BSesVld =    1b : B-session is valid
1002  *              0b : B-session is not valid
1003  */
1004 static int check_usb_otg_op(void)
1005 {
1006         unsigned int val;
1007
1008         val = __raw_readl(S3C_UDC_OTG_GOTGCTL);
1009         return val & (A_SESSION_VALID | B_SESSION_VALID);
1010 }
1011
1012 bool extern rfkill_get_global_sw_state(const enum rfkill_type type);
1013 static int check_wireless_op(void)
1014 {
1015         if (!rfkill_get_global_sw_state(RFKILL_TYPE_BLUETOOTH)) {
1016                 printk(KERN_DEBUG "BT: rfkill s/w state is unblocked\n");
1017                 return 1;
1018         } else if (!rfkill_get_global_sw_state(RFKILL_TYPE_WLAN)) {
1019                 printk(KERN_DEBUG "WLAN: rfkill s/w state is unblocked\n");
1020                 return 1;
1021         }
1022
1023         /* FIXME: GPS is always on becuase don't off GPS using rfkill on platform. */
1024         /*
1025         else if (!rfkill_get_global_sw_state(RFKILL_TYPE_GPS))
1026                 return 1;
1027         */
1028
1029         return 0;
1030 }
1031
1032 static int s5pv310_check_entermode(void)
1033 {
1034         unsigned int ret;
1035
1036         ret = S5P_CHECK_DIDLE;
1037
1038         if (check_power_domain())
1039                 return ret;
1040         else if (check_clock_gating())
1041                 return ret;
1042         else if (check_sdmmc_state())
1043                 return ret;
1044         else if (check_usb_host_op() || check_usb_otg_op())
1045                 return ret;
1046         else if (check_wireless_op())
1047                 return ret;
1048
1049         ret = S5P_CHECK_LPA;
1050
1051         return ret;
1052 }
1053
1054 static int s5pv310_enter_lowpower(struct cpuidle_device *dev,
1055                               struct cpuidle_state *state)
1056 {
1057         struct cpuidle_state *new_state = state;
1058         unsigned int enter_mode;
1059
1060         /* This mode only can be entered when Core1 is offline */
1061         if (cpu_online(1)) {
1062                 BUG_ON(!dev->safe_state);
1063                 new_state = dev->safe_state;
1064         }
1065         dev->last_state = new_state;
1066
1067         if (new_state == &dev->states[0])
1068                 return s5pv310_enter_idle(dev, new_state);
1069         else {
1070                 enter_mode = s5pv310_check_entermode();
1071
1072                 if (enter_mode == S5P_CHECK_DIDLE)
1073                         return s5pv310_enter_core0_aftr(dev, new_state);
1074                 else
1075                         return s5pv310_enter_core0_lpa(dev, new_state);
1076         }
1077
1078         return s5pv310_enter_idle(dev, new_state);
1079 }
1080
1081 static int s5pv310_init_cpuidle(void)
1082 {
1083         int i, max_cpuidle_state, cpu_id;
1084         struct cpuidle_device *device;
1085         struct platform_device *pdev;
1086         struct resource *res;
1087
1088         cpuidle_register_driver(&s5pv310_idle_driver);
1089
1090         for_each_cpu(cpu_id, cpu_online_mask) {
1091                 device = &per_cpu(s5pv310_cpuidle_device, cpu_id);
1092                 device->cpu = cpu_id;
1093
1094                 if (cpu_id == 0)
1095                         device->state_count = (sizeof(s5pv310_cpuidle_set) /
1096                                                sizeof(struct cpuidle_state));
1097                 else
1098                         device->state_count = 1;        /* Support IDLE only */
1099
1100                 max_cpuidle_state = device->state_count;
1101
1102                 for (i = 0; i < max_cpuidle_state; i++) {
1103                         memcpy(&device->states[i], &s5pv310_cpuidle_set[i],
1104                                         sizeof(struct cpuidle_state));
1105                 }
1106
1107                 device->safe_state = &device->states[0];
1108
1109                 if (cpuidle_register_device(device)) {
1110                         printk(KERN_ERR "CPUidle register device failed\n,");
1111                         return -EIO;
1112                 }
1113         }
1114
1115         sdmmc_dev_num = ARRAY_SIZE(chk_dev_op);
1116         for (i = 0 ; i < sdmmc_dev_num ; i++) {
1117
1118                 pdev = chk_dev_op[i].pdev;
1119
1120                 if (pdev == NULL)
1121                         break;
1122
1123                 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1124                 if (!res) {
1125                         printk(KERN_ERR "failed to get iomem region\n");
1126                         return -EINVAL;
1127                 }
1128                 chk_dev_op[i].base = ioremap_nocache(res->start, 4096);
1129
1130                 if (!chk_dev_op[i].base) {
1131                         printk(KERN_ERR "failed to map io region\n");
1132                         return -EINVAL;
1133                 }
1134         }
1135
1136         regs_save = dma_alloc_coherent(NULL, 4096, &phy_regs_save, GFP_KERNEL);
1137         if (regs_save == NULL) {
1138                 printk(KERN_ERR "Alloc memory for CPUIDLE failed\n");
1139                 return -1;
1140         }
1141 #ifndef CONFIG_USE_EXT_GIC
1142         ext_gic_init();
1143 #endif
1144         return 0;
1145 }
1146
1147 device_initcall(s5pv310_init_cpuidle);