upload tizen1.0 source
[kernel/linux-2.6.36.git] / arch / arm / mach-s5pv310 / cpu.c
1 /* linux/arch/arm/mach-s5pv310/cpu.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/clk.h>
12 #include <linux/err.h>
13 #include <linux/sched.h>
14 #include <linux/sysdev.h>
15 #include <linux/delay.h>
16 #include <asm/hardware/cache-l2x0.h>
17
18 #include <asm/mach/map.h>
19 #include <asm/mach/irq.h>
20
21 #include <asm/proc-fns.h>
22
23 #include <plat/cpu.h>
24 #include <plat/devs.h>
25 #include <plat/clock.h>
26 #include <plat/adc-core.h>
27 #include <plat/s5pv310.h>
28 #include <plat/mshci.h>
29 #include <plat/sdhci.h>
30 #include <plat/reset.h>
31
32 #include <mach/regs-irq.h>
33 #include <mach/regs-pmu.h>
34 #include <mach/irqs.h>
35 #include <mach/ext-gic.h>
36 void __iomem *gic_cpu_base_addr;
37
38 extern int combiner_init(unsigned int combiner_nr, void __iomem *base,
39                          unsigned int irq_start);
40 extern void combiner_cascade_irq(unsigned int combiner_nr, unsigned int irq);
41
42 #ifdef CONFIG_PM
43 extern int s3c_irq_wake(unsigned int irqno, unsigned int state);
44 #else
45 #define s3c_irq_wake NULL
46 #endif
47
48 unsigned int cpu_revision = 0;
49
50 static struct map_desc s5pv310_iodesc_evt0[] __initdata = {
51         {
52                 .virtual        = (unsigned long)S5P_VA_SYSRAM,
53                 .pfn            = __phys_to_pfn(S5PV310_PA_SYSRAM_EVT0),
54                 .length         = SZ_4K,
55                 .type           = MT_DEVICE,
56         },
57 };
58
59 static struct map_desc s5pv310_iodesc_evt1[] __initdata = {
60         {
61                 .virtual        = (unsigned long)S5P_VA_SYSRAM,
62                 .pfn            = __phys_to_pfn(S5PV310_PA_SYSRAM_EVT1),
63                 .length         = SZ_4K,
64                 .type           = MT_DEVICE,
65         },
66 };
67
68 /* Initial IO mappings */
69 static struct map_desc s5pv310_iodesc_common[] __initdata = {
70         {
71                 .virtual        = (unsigned long)S5P_VA_COREPERI_BASE,
72                 .pfn            = __phys_to_pfn(S5PV310_PA_COREPERI),
73                 .length         = SZ_8K,
74                 .type           = MT_DEVICE,
75         }, {
76                 .virtual        = (unsigned long)S5P_VA_EXTGIC_CPU,
77                 .pfn            = __phys_to_pfn(S5PV310_PA_EXTGIC_CPU),
78                 .length         = SZ_64K,
79                 .type           = MT_DEVICE,
80         }, {
81                 .virtual        = (unsigned long)S5P_VA_EXTGIC_DIST,
82                 .pfn            = __phys_to_pfn(S5PV310_PA_EXTGIC_DIST),
83                 .length         = SZ_64K,
84                 .type           = MT_DEVICE,
85         }, {
86                 .virtual        = (unsigned long)S5P_VA_EXTCOMBINER_BASE,
87                 .pfn            = __phys_to_pfn(S5PV310_PA_EXTCOMBINER),
88                 .length         = SZ_4K,
89                 .type           = MT_DEVICE,
90         },{
91                 .virtual        = (unsigned long)S5P_VA_COMBINER_BASE,
92                 .pfn            = __phys_to_pfn(S5PV310_PA_COMBINER),
93                 .length         = SZ_4K,
94                 .type           = MT_DEVICE,
95         }, {
96                 .virtual        = (unsigned long)S5P_VA_L2CC,
97                 .pfn            = __phys_to_pfn(S5PV310_PA_L2CC),
98                 .length         = SZ_4K,
99                 .type           = MT_DEVICE,
100         }, {
101                 .virtual        = (unsigned long)S5P_VA_CMU,
102                 .pfn            = __phys_to_pfn(S5PV310_PA_CMU),
103                 .length         = SZ_128K,
104                 .type           = MT_DEVICE,
105         }, {
106                 .virtual        = (unsigned long)S5P_VA_GPIO2,
107                 .pfn            = __phys_to_pfn(S5PV310_PA_GPIO2),
108                 .length         = SZ_4K,
109                 .type           = MT_DEVICE,
110         }, {
111                 .virtual        = (unsigned long)S5P_VA_GPIO3,
112                 .pfn            = __phys_to_pfn(S5PV310_PA_GPIO3),
113                 .length         = SZ_256K,
114                 .type           = MT_DEVICE,
115         }, {
116                 .virtual        = (unsigned long)S5P_VA_SROMC,
117                 .pfn            = __phys_to_pfn(S5PV310_PA_SROMC),
118                 .length         = SZ_4K,
119                 .type           = MT_DEVICE,
120         }, {
121                 .virtual        = (unsigned long)S5P_VA_PPMU_CPU,
122                 .pfn            = __phys_to_pfn(S5PV310_PA_PPMU_CPU),
123                 .length         = SZ_16K,
124                 .type           = MT_DEVICE,
125         }, {
126                 .virtual        = (unsigned long)S5P_VA_PPMU_LCD0,
127                 .pfn            = __phys_to_pfn(S5PV310_PA_PPMU_LCD0),
128                 .length         = SZ_16K,
129                 .type           = MT_DEVICE,
130         }, {
131                 .virtual        = (unsigned long)S5P_VA_AUDSS,
132                 .pfn            = __phys_to_pfn(S5PV310_PA_AUDSS),
133                 .length         = SZ_4K,
134                 .type           = MT_DEVICE,
135         }, {
136                 .virtual        = (unsigned long)S5PV310_VA_PMU,
137                 .pfn            = __phys_to_pfn(S5PV310_PA_PMU),
138                 .length         = SZ_64K,
139                 .type           = MT_DEVICE,
140         }, {
141                 .virtual        = (unsigned long)S5P_VA_SYSTIMER,
142                 .pfn            = __phys_to_pfn(S5PV310_PA_SYSTIMER),
143                 .length         = SZ_4K,
144                 .type           = MT_DEVICE,
145         }, {
146                 .virtual        = (unsigned long)S3C_VA_GPS,
147                 .pfn            = __phys_to_pfn(S5PV310_PA_GPS),
148                 .length         = SZ_4K,
149                 .type           = MT_DEVICE,
150         }, {
151                 .virtual        = (unsigned long)S5P_VA_DMC0,
152                 .pfn            = __phys_to_pfn(S5PV310_PA_DMC0),
153                 .length         = SZ_64K,
154                 .type           = MT_DEVICE,
155         }, {
156                 .virtual        = (unsigned long)S5P_VA_DMC1,
157                 .pfn            = __phys_to_pfn(S5PV310_PA_DMC1),
158                 .length         = SZ_64K,
159                 .type           = MT_DEVICE,
160         },
161
162
163 };
164
165 static void s5pv310_idle(void)
166 {
167         if (!need_resched())
168                 cpu_do_idle();
169
170         local_irq_enable();
171 }
172
173 static void s5pv310_power_off(void)
174 {
175         unsigned long value;
176
177         printk("Send a signal to S5P_PS_HOLD_CONTROL\n");
178         value = __raw_readl(S5P_PS_HOLD_CONTROL);
179         value &= ~(1 << 8);
180         __raw_writel(value, S5P_PS_HOLD_CONTROL);
181 }
182
183 /* s5pv310_map_io
184  *
185  * register the standard cpu IO areas
186 */
187 static void __init __s5pv310_map_io(void)
188 {
189         iotable_init(s5pv310_iodesc_common, ARRAY_SIZE(s5pv310_iodesc_common));
190
191         if (cpu_revision == 0)
192                 iotable_init(s5pv310_iodesc_evt0,
193                                 ARRAY_SIZE(s5pv310_iodesc_evt0));
194         else
195                 iotable_init(s5pv310_iodesc_evt1,
196                                 ARRAY_SIZE(s5pv310_iodesc_evt1));
197
198         /* initialize device information early */
199 #ifdef CONFIG_S3C_DEV_HSMMC
200         s5pv310_default_sdhci0();
201 #endif
202 #ifdef CONFIG_S3C_DEV_HSMMC1
203         s5pv310_default_sdhci1();
204 #endif
205 #ifdef CONFIG_S3C_DEV_HSMMC2
206         s5pv310_default_sdhci2();
207 #endif
208 #ifdef CONFIG_S3C_DEV_HSMMC3
209         s5pv310_default_sdhci3();
210 #endif
211 #ifdef CONFIG_S5P_DEV_MSHC
212         s5pv310_default_mshci();
213 #endif
214
215 #ifdef CONFIG_S3C_ADC
216         s3c_adc_setname("s5pv210-adc");
217 #endif
218 #ifdef CONFIG_S5P_ADC
219         s3c_adc_setname("s3c-adc");
220 #endif
221 }
222
223 void __init s5pv310_map_io_evt0(void)
224 {
225         cpu_revision = 0;
226         printk(KERN_INFO "S5PV310 Revision: EVT0\n");
227         __s5pv310_map_io();
228 }
229
230 void __init s5pv310_map_io_evt1(void)
231 {
232         cpu_revision = 1;
233         printk(KERN_INFO "S5PV310 Revision: EVT1\n");
234         __s5pv310_map_io();
235 }
236
237 void __init s5pv310_init_clocks(int xtal)
238 {
239         printk(KERN_DEBUG "%s: initializing clocks\n", __func__);
240
241         s3c24xx_register_baseclocks(xtal);
242         s5p_register_clocks(xtal);
243         s5pv310_register_clocks();
244         s5pv310_setup_clocks();
245 }
246
247 void __init s5pv310_init_irq(void)
248 {
249         int irq;
250
251 #ifdef CONFIG_USE_EXT_GIC
252         gic_cpu_base_addr = S5P_VA_EXTGIC_CPU;
253         gic_dist_init(0, S5P_VA_EXTGIC_DIST, IRQ_SPI(0));
254         gic_cpu_init(0, S5P_VA_EXTGIC_CPU);
255 #else
256         gic_cpu_base_addr = S5P_VA_GIC_CPU;
257         gic_dist_init(0, S5P_VA_GIC_DIST, IRQ_SPI(0));
258         gic_cpu_init(0, S5P_VA_GIC_CPU);
259 #endif
260
261         for (irq = 0; irq < MAX_COMBINER_NR; irq++) {
262
263 #ifdef CONFIG_USE_EXT_GIC
264                 combiner_init(irq, (void __iomem *)S5P_VA_EXTCOMBINER(irq),
265                                 COMBINER_IRQ(irq, 0));
266 #else
267                 /* EVT1: From SPI(0) to SPI(39) and SPI(51), SPI(53)
268                 * are connected to the interrupt combiner. These irqs
269                 * should be initialized to support cascade interrupt.
270                 */
271                 if ((cpu_revision == 0) && (irq >= 40))
272                         continue; /* EVT0: MAX = 39 */
273                 if ((irq >= 40) && !(irq == 51) && !(irq == 53))
274                         continue; /* EVT1: has 51, 53 */
275
276                 combiner_init(irq, (void __iomem *)S5P_VA_COMBINER(irq),
277                                 COMBINER_IRQ(irq, 0));
278 #endif
279                 combiner_cascade_irq(irq, IRQ_SPI(irq));
280         }
281
282         /* The parameters of s5p_init_irq() are for VIC init.
283          * Theses parameters should be NULL and 0 because S5PV310
284          * uses GIC instead of VIC.
285          */
286         s5p_init_irq(NULL, 0);
287
288         /* Set s3c_irq_wake as set_wake() of GIC irq_chip */
289         get_irq_chip(IRQ_RTC_ALARM)->set_wake = s3c_irq_wake;
290 }
291
292 #ifdef CONFIG_CACHE_L2X0
293 int s5p_l2x0_cache_init(void)
294 {
295         /* Data, TAG Latency is 2cycle */
296         __raw_writel(0x111, S5P_VA_L2CC + L2X0_TAG_LATENCY_CTRL);
297         __raw_writel(0x111, S5P_VA_L2CC + L2X0_DATA_LATENCY_CTRL);
298
299         /* L2 cache Prefetch Control Register setting */
300         __raw_writel(0x30000007, S5P_VA_L2CC + L2X0_PREFETCH_CTRL);
301
302         /* Power control register setting */
303         __raw_writel(L2X0_DYNAMIC_CLK_GATING_EN | L2X0_STNDBY_MODE_EN,
304                      S5P_VA_L2CC + L2X0_POWER_CTRL);
305
306         l2x0_init(S5P_VA_L2CC, 0x7C470001, 0xC200ffff);
307
308         return 0;
309 }
310 early_initcall(s5p_l2x0_cache_init);
311 #endif
312
313 struct sysdev_class s5pv310_sysclass = {
314         .name   = "s5pv310-core",
315 };
316
317 static struct sys_device s5pv310_sysdev = {
318         .cls    = &s5pv310_sysclass,
319 };
320
321 static int __init s5pv310_core_init(void)
322 {
323         return sysdev_class_register(&s5pv310_sysclass);
324 }
325
326 core_initcall(s5pv310_core_init);
327
328 #include <mach/regs-clock.h>
329 static void s5pv310_sw_reset(void)
330 {
331         /* Clear Sleep/Didle related registers */
332         __raw_writel(0x0, S5P_INFORM0);
333         __raw_writel(0x0, S5P_INFORM1);
334         /* Obsolete: for the compatibility with obsolete s-boot */
335         if (s5pv310_subrev() == 0)
336                 __raw_writel(0x0, S5P_INFORM7);
337
338         __raw_writel(0x1, S5P_SWRESET);
339 }
340
341 #include <mach/universal.h>
342 void s5pv310_inform6_set(char mode)
343 {
344         volatile u32 rst_check_flag = 0;
345
346         __raw_writel(0x0, S5P_INFORM6);
347
348 #ifdef CONFIG_CHARGER_DETECT_BOOT
349         /* do charger boot in case of power off with cables. */
350         if (mode == 'r') {
351                 rst_check_flag = rst_check_flag | RST_FLAG_CHARGE_REBOOT_CHECK;
352         }
353 #endif
354
355 #ifdef CONFIG_SAMSUNG_BOOT_MODE 
356         if (samsung_fota_config) {
357                 rst_check_flag = rst_check_flag | RST_FLAG_FOTA_REBOOT_CHECK;
358         }
359
360         if (samsung_fus_config) {
361                 rst_check_flag = rst_check_flag | RST_FLAG_FUS_REBOOT_CHECK;
362         }
363
364         if (samsung_rtl_config) {
365                 rst_check_flag = rst_check_flag | RST_FLAG_RTL_REBOOT_CHECK;
366         }
367 #endif
368
369         /* set for intended reset */
370         rst_check_flag |= (RST_FLAG_WDT_MAGIC_CODE << 16);
371         rst_check_flag |= RST_FLAG_INTENTIONAL_WATCHDOG_RESET_CHECK;
372
373         __raw_writel(CHECK_RST_FLAG_BIT(rst_check_flag), S5P_INFORM6);
374 }
375 EXPORT_SYMBOL(s5pv310_inform6_set);
376
377 static void s5pv310_sc_feedback(void)
378 {
379         unsigned int tmp;
380
381         tmp = __raw_readl(S5P_ARM_CORE0_OPTION);
382         tmp &= ~(1 << 0);
383         tmp |= (1 << 1);
384         __raw_writel(tmp, S5P_ARM_CORE0_OPTION);
385
386         tmp = __raw_readl(S5P_ARM_CORE1_OPTION);
387         tmp &= ~(1 << 0);
388         tmp |= (1 << 1);
389         __raw_writel(tmp, S5P_ARM_CORE1_OPTION);
390
391         __raw_writel(0x2, S5P_ARM_COMMON_OPTION);
392         __raw_writel(0x2, S5P_CAM_OPTION);
393         __raw_writel(0x2, S5P_TV_OPTION);
394         __raw_writel(0x2, S5P_MFC_OPTION);
395         __raw_writel(0x2, S5P_G3D_OPTION);
396         __raw_writel(0x2, S5P_LCD0_OPTION);
397         __raw_writel(0x2, S5P_LCD1_OPTION);
398         __raw_writel(0x2, S5P_GPS_OPTION);
399         __raw_writel(0x2, S5P_GPS_ALIVE_OPTION);
400 }
401
402 int s5pv310_get_max_speed(void)
403 {
404         static int max_speed = -1;
405
406         if (unlikely(max_speed < 0)) {
407                 struct clk *chipid_clk;
408                 unsigned int pro_id, pkg_id;
409
410                 chipid_clk = clk_get(NULL, "chipid");
411                 if (chipid_clk == NULL)
412                 {
413                         printk(KERN_ERR "failed to find chipid clock source\n");
414                         return -EINVAL;
415                 }
416                 clk_enable(chipid_clk);
417
418                 pro_id = __raw_readl(S5P_VA_CHIPID);
419                 printk(KERN_INFO "pro_id: 0x%08x\n", pro_id);
420
421                 if ((pro_id & 0xf) == 0x1) {
422                         pkg_id = __raw_readl(S5P_VA_CHIPID + 0x4);
423                         printk(KERN_INFO "pkg_id: 0x%08x\n", pkg_id);
424
425                         switch (pkg_id & 0x7) {
426                         case 1:
427                         case 5:
428                                 max_speed = 1200000;
429                                 break;
430                         case 0:
431                         case 3:
432                                 max_speed = 1000000;
433                                 break;
434                         default:
435                                 max_speed = 1000000;
436                                 break;
437                         }
438
439                 } else {
440                         max_speed = 1000000;
441                 }
442
443                 clk_disable(chipid_clk);
444                 clk_put(chipid_clk);
445         }
446
447         return max_speed;
448 }
449
450 int s5pv310_subrev(void)
451 {
452         static int subrev = -1;
453
454         if (unlikely(subrev < 0)) {
455                 struct clk *clk = clk_get(NULL, "chipid");
456
457                 if (IS_ERR_OR_NULL(clk))
458                         clk = NULL;
459                 if (clk)
460                         clk_enable(clk);
461
462                 subrev = readl(S5P_VA_CHIPID) & 0xf;
463
464                 if (clk) {
465                         clk_disable(clk);
466                         clk_put(clk);
467                 }
468         }
469
470         return subrev;
471 }
472
473 int __init s5pv310_init(void)
474 {
475         /* set idle function */
476         pm_idle = s5pv310_idle;
477
478         /* set power_off function */
479 //      pm_power_off = s5pv310_power_off; /* We don't use s5pv310_power_off (use each board's power off function) */
480
481         /* set sw_reset function */
482         s5p_reset_hook = s5pv310_sw_reset; /* Change reset function from sw_reset to watchdog reset */
483
484         s5pv310_sc_feedback();
485
486         return sysdev_register(&s5pv310_sysdev);
487 }