diff options
Diffstat (limited to 'arch/arm/mach-exynos/common.c')
-rw-r--r-- | arch/arm/mach-exynos/common.c | 532 |
1 files changed, 20 insertions, 512 deletions
diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c index 745e304ad0de..81e6320ca091 100644 --- a/arch/arm/mach-exynos/common.c +++ b/arch/arm/mach-exynos/common.c | |||
@@ -10,12 +10,14 @@ | |||
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
13 | #include <linux/bitops.h> | ||
13 | #include <linux/interrupt.h> | 14 | #include <linux/interrupt.h> |
14 | #include <linux/irq.h> | 15 | #include <linux/irq.h> |
15 | #include <linux/irqchip.h> | 16 | #include <linux/irqchip.h> |
16 | #include <linux/io.h> | 17 | #include <linux/io.h> |
17 | #include <linux/device.h> | 18 | #include <linux/device.h> |
18 | #include <linux/gpio.h> | 19 | #include <linux/gpio.h> |
20 | #include <clocksource/samsung_pwm.h> | ||
19 | #include <linux/sched.h> | 21 | #include <linux/sched.h> |
20 | #include <linux/serial_core.h> | 22 | #include <linux/serial_core.h> |
21 | #include <linux/of.h> | 23 | #include <linux/of.h> |
@@ -38,20 +40,9 @@ | |||
38 | 40 | ||
39 | #include <mach/regs-irq.h> | 41 | #include <mach/regs-irq.h> |
40 | #include <mach/regs-pmu.h> | 42 | #include <mach/regs-pmu.h> |
41 | #include <mach/regs-gpio.h> | ||
42 | #include <mach/irqs.h> | ||
43 | 43 | ||
44 | #include <plat/cpu.h> | 44 | #include <plat/cpu.h> |
45 | #include <plat/devs.h> | ||
46 | #include <plat/pm.h> | 45 | #include <plat/pm.h> |
47 | #include <plat/sdhci.h> | ||
48 | #include <plat/gpio-cfg.h> | ||
49 | #include <plat/adc-core.h> | ||
50 | #include <plat/fb-core.h> | ||
51 | #include <plat/fimc-core.h> | ||
52 | #include <plat/iic-core.h> | ||
53 | #include <plat/tv-core.h> | ||
54 | #include <plat/spi-core.h> | ||
55 | #include <plat/regs-serial.h> | 46 | #include <plat/regs-serial.h> |
56 | 47 | ||
57 | #include "common.h" | 48 | #include "common.h" |
@@ -67,31 +58,25 @@ static const char name_exynos5440[] = "EXYNOS5440"; | |||
67 | static void exynos4_map_io(void); | 58 | static void exynos4_map_io(void); |
68 | static void exynos5_map_io(void); | 59 | static void exynos5_map_io(void); |
69 | static void exynos5440_map_io(void); | 60 | static void exynos5440_map_io(void); |
70 | static void exynos4_init_uarts(struct s3c2410_uartcfg *cfg, int no); | ||
71 | static int exynos_init(void); | 61 | static int exynos_init(void); |
72 | 62 | ||
73 | unsigned long xxti_f = 0, xusbxti_f = 0; | ||
74 | |||
75 | static struct cpu_table cpu_ids[] __initdata = { | 63 | static struct cpu_table cpu_ids[] __initdata = { |
76 | { | 64 | { |
77 | .idcode = EXYNOS4210_CPU_ID, | 65 | .idcode = EXYNOS4210_CPU_ID, |
78 | .idmask = EXYNOS4_CPU_MASK, | 66 | .idmask = EXYNOS4_CPU_MASK, |
79 | .map_io = exynos4_map_io, | 67 | .map_io = exynos4_map_io, |
80 | .init_uarts = exynos4_init_uarts, | ||
81 | .init = exynos_init, | 68 | .init = exynos_init, |
82 | .name = name_exynos4210, | 69 | .name = name_exynos4210, |
83 | }, { | 70 | }, { |
84 | .idcode = EXYNOS4212_CPU_ID, | 71 | .idcode = EXYNOS4212_CPU_ID, |
85 | .idmask = EXYNOS4_CPU_MASK, | 72 | .idmask = EXYNOS4_CPU_MASK, |
86 | .map_io = exynos4_map_io, | 73 | .map_io = exynos4_map_io, |
87 | .init_uarts = exynos4_init_uarts, | ||
88 | .init = exynos_init, | 74 | .init = exynos_init, |
89 | .name = name_exynos4212, | 75 | .name = name_exynos4212, |
90 | }, { | 76 | }, { |
91 | .idcode = EXYNOS4412_CPU_ID, | 77 | .idcode = EXYNOS4412_CPU_ID, |
92 | .idmask = EXYNOS4_CPU_MASK, | 78 | .idmask = EXYNOS4_CPU_MASK, |
93 | .map_io = exynos4_map_io, | 79 | .map_io = exynos4_map_io, |
94 | .init_uarts = exynos4_init_uarts, | ||
95 | .init = exynos_init, | 80 | .init = exynos_init, |
96 | .name = name_exynos4412, | 81 | .name = name_exynos4412, |
97 | }, { | 82 | }, { |
@@ -111,15 +96,6 @@ static struct cpu_table cpu_ids[] __initdata = { | |||
111 | 96 | ||
112 | /* Initial IO mappings */ | 97 | /* Initial IO mappings */ |
113 | 98 | ||
114 | static struct map_desc exynos_iodesc[] __initdata = { | ||
115 | { | ||
116 | .virtual = (unsigned long)S5P_VA_CHIPID, | ||
117 | .pfn = __phys_to_pfn(EXYNOS_PA_CHIPID), | ||
118 | .length = SZ_4K, | ||
119 | .type = MT_DEVICE, | ||
120 | }, | ||
121 | }; | ||
122 | |||
123 | static struct map_desc exynos4_iodesc[] __initdata = { | 99 | static struct map_desc exynos4_iodesc[] __initdata = { |
124 | { | 100 | { |
125 | .virtual = (unsigned long)S3C_VA_SYS, | 101 | .virtual = (unsigned long)S3C_VA_SYS, |
@@ -317,9 +293,16 @@ void exynos5_restart(char mode, const char *cmd) | |||
317 | val = 0x1; | 293 | val = 0x1; |
318 | addr = EXYNOS_SWRESET; | 294 | addr = EXYNOS_SWRESET; |
319 | } else if (of_machine_is_compatible("samsung,exynos5440")) { | 295 | } else if (of_machine_is_compatible("samsung,exynos5440")) { |
296 | u32 status; | ||
320 | np = of_find_compatible_node(NULL, NULL, "samsung,exynos5440-clock"); | 297 | np = of_find_compatible_node(NULL, NULL, "samsung,exynos5440-clock"); |
298 | |||
299 | addr = of_iomap(np, 0) + 0xbc; | ||
300 | status = __raw_readl(addr); | ||
301 | |||
321 | addr = of_iomap(np, 0) + 0xcc; | 302 | addr = of_iomap(np, 0) + 0xcc; |
322 | val = (0xfff << 20) | (0x1 << 16); | 303 | val = __raw_readl(addr); |
304 | |||
305 | val = (val & 0xffff0000) | (status & 0xffff); | ||
323 | } else { | 306 | } else { |
324 | pr_err("%s: cannot support non-DT\n", __func__); | 307 | pr_err("%s: cannot support non-DT\n", __func__); |
325 | return; | 308 | return; |
@@ -337,8 +320,7 @@ void __init exynos_init_late(void) | |||
337 | exynos_pm_late_initcall(); | 320 | exynos_pm_late_initcall(); |
338 | } | 321 | } |
339 | 322 | ||
340 | #ifdef CONFIG_OF | 323 | static int __init exynos_fdt_map_chipid(unsigned long node, const char *uname, |
341 | int __init exynos_fdt_map_chipid(unsigned long node, const char *uname, | ||
342 | int depth, void *data) | 324 | int depth, void *data) |
343 | { | 325 | { |
344 | struct map_desc iodesc; | 326 | struct map_desc iodesc; |
@@ -360,7 +342,6 @@ int __init exynos_fdt_map_chipid(unsigned long node, const char *uname, | |||
360 | iotable_init(&iodesc, 1); | 342 | iotable_init(&iodesc, 1); |
361 | return 1; | 343 | return 1; |
362 | } | 344 | } |
363 | #endif | ||
364 | 345 | ||
365 | /* | 346 | /* |
366 | * exynos_map_io | 347 | * exynos_map_io |
@@ -368,17 +349,11 @@ int __init exynos_fdt_map_chipid(unsigned long node, const char *uname, | |||
368 | * register the standard cpu IO areas | 349 | * register the standard cpu IO areas |
369 | */ | 350 | */ |
370 | 351 | ||
371 | void __init exynos_init_io(struct map_desc *mach_desc, int size) | 352 | void __init exynos_init_io(void) |
372 | { | 353 | { |
373 | #ifdef CONFIG_OF | 354 | debug_ll_io_init(); |
374 | if (initial_boot_params) | ||
375 | of_scan_flat_dt(exynos_fdt_map_chipid, NULL); | ||
376 | else | ||
377 | #endif | ||
378 | iotable_init(exynos_iodesc, ARRAY_SIZE(exynos_iodesc)); | ||
379 | 355 | ||
380 | if (mach_desc) | 356 | of_scan_flat_dt(exynos_fdt_map_chipid, NULL); |
381 | iotable_init(mach_desc, size); | ||
382 | 357 | ||
383 | /* detect cpu id and rev. */ | 358 | /* detect cpu id and rev. */ |
384 | s5p_init_cpu(S5P_VA_CHIPID); | 359 | s5p_init_cpu(S5P_VA_CHIPID); |
@@ -399,34 +374,6 @@ static void __init exynos4_map_io(void) | |||
399 | iotable_init(exynos4210_iodesc, ARRAY_SIZE(exynos4210_iodesc)); | 374 | iotable_init(exynos4210_iodesc, ARRAY_SIZE(exynos4210_iodesc)); |
400 | if (soc_is_exynos4212() || soc_is_exynos4412()) | 375 | if (soc_is_exynos4212() || soc_is_exynos4412()) |
401 | iotable_init(exynos4x12_iodesc, ARRAY_SIZE(exynos4x12_iodesc)); | 376 | iotable_init(exynos4x12_iodesc, ARRAY_SIZE(exynos4x12_iodesc)); |
402 | |||
403 | /* initialize device information early */ | ||
404 | exynos4_default_sdhci0(); | ||
405 | exynos4_default_sdhci1(); | ||
406 | exynos4_default_sdhci2(); | ||
407 | exynos4_default_sdhci3(); | ||
408 | |||
409 | s3c_adc_setname("samsung-adc-v3"); | ||
410 | |||
411 | s3c_fimc_setname(0, "exynos4-fimc"); | ||
412 | s3c_fimc_setname(1, "exynos4-fimc"); | ||
413 | s3c_fimc_setname(2, "exynos4-fimc"); | ||
414 | s3c_fimc_setname(3, "exynos4-fimc"); | ||
415 | |||
416 | s3c_sdhci_setname(0, "exynos4-sdhci"); | ||
417 | s3c_sdhci_setname(1, "exynos4-sdhci"); | ||
418 | s3c_sdhci_setname(2, "exynos4-sdhci"); | ||
419 | s3c_sdhci_setname(3, "exynos4-sdhci"); | ||
420 | |||
421 | /* The I2C bus controllers are directly compatible with s3c2440 */ | ||
422 | s3c_i2c0_setname("s3c2440-i2c"); | ||
423 | s3c_i2c1_setname("s3c2440-i2c"); | ||
424 | s3c_i2c2_setname("s3c2440-i2c"); | ||
425 | |||
426 | s5p_fb_setname(0, "exynos4-fb"); | ||
427 | s5p_hdmi_setname("exynos4-hdmi"); | ||
428 | |||
429 | s3c64xx_spi_setname("exynos4210-spi"); | ||
430 | } | 377 | } |
431 | 378 | ||
432 | static void __init exynos5_map_io(void) | 379 | static void __init exynos5_map_io(void) |
@@ -444,60 +391,8 @@ static void __init exynos5440_map_io(void) | |||
444 | 391 | ||
445 | void __init exynos_init_time(void) | 392 | void __init exynos_init_time(void) |
446 | { | 393 | { |
447 | if (of_have_populated_dt()) { | 394 | of_clk_init(NULL); |
448 | #ifdef CONFIG_OF | 395 | clocksource_of_init(); |
449 | of_clk_init(NULL); | ||
450 | clocksource_of_init(); | ||
451 | #endif | ||
452 | } else { | ||
453 | /* todo: remove after migrating legacy E4 platforms to dt */ | ||
454 | #ifdef CONFIG_ARCH_EXYNOS4 | ||
455 | exynos4_clk_init(NULL, !soc_is_exynos4210(), S5P_VA_CMU, readl(S5P_VA_CHIPID + 8) & 1); | ||
456 | exynos4_clk_register_fixed_ext(xxti_f, xusbxti_f); | ||
457 | #endif | ||
458 | mct_init(S5P_VA_SYSTIMER, EXYNOS4_IRQ_MCT_G0, EXYNOS4_IRQ_MCT_L0, EXYNOS4_IRQ_MCT_L1); | ||
459 | } | ||
460 | } | ||
461 | |||
462 | static unsigned int max_combiner_nr(void) | ||
463 | { | ||
464 | if (soc_is_exynos5250()) | ||
465 | return EXYNOS5_MAX_COMBINER_NR; | ||
466 | else if (soc_is_exynos4412()) | ||
467 | return EXYNOS4412_MAX_COMBINER_NR; | ||
468 | else if (soc_is_exynos4212()) | ||
469 | return EXYNOS4212_MAX_COMBINER_NR; | ||
470 | else | ||
471 | return EXYNOS4210_MAX_COMBINER_NR; | ||
472 | } | ||
473 | |||
474 | |||
475 | void __init exynos4_init_irq(void) | ||
476 | { | ||
477 | unsigned int gic_bank_offset; | ||
478 | |||
479 | gic_bank_offset = soc_is_exynos4412() ? 0x4000 : 0x8000; | ||
480 | |||
481 | if (!of_have_populated_dt()) | ||
482 | gic_init_bases(0, IRQ_PPI(0), S5P_VA_GIC_DIST, S5P_VA_GIC_CPU, gic_bank_offset, NULL); | ||
483 | #ifdef CONFIG_OF | ||
484 | else | ||
485 | irqchip_init(); | ||
486 | #endif | ||
487 | |||
488 | if (!of_have_populated_dt()) | ||
489 | combiner_init(S5P_VA_COMBINER_BASE, NULL, | ||
490 | max_combiner_nr(), COMBINER_IRQ(0, 0)); | ||
491 | |||
492 | gic_arch_extn.irq_set_wake = s3c_irq_wake; | ||
493 | } | ||
494 | |||
495 | void __init exynos5_init_irq(void) | ||
496 | { | ||
497 | #ifdef CONFIG_OF | ||
498 | irqchip_init(); | ||
499 | #endif | ||
500 | gic_arch_extn.irq_set_wake = s3c_irq_wake; | ||
501 | } | 396 | } |
502 | 397 | ||
503 | struct bus_type exynos_subsys = { | 398 | struct bus_type exynos_subsys = { |
@@ -515,59 +410,19 @@ static int __init exynos_core_init(void) | |||
515 | } | 410 | } |
516 | core_initcall(exynos_core_init); | 411 | core_initcall(exynos_core_init); |
517 | 412 | ||
518 | #ifdef CONFIG_CACHE_L2X0 | ||
519 | static int __init exynos4_l2x0_cache_init(void) | 413 | static int __init exynos4_l2x0_cache_init(void) |
520 | { | 414 | { |
521 | int ret; | 415 | int ret; |
522 | 416 | ||
523 | if (soc_is_exynos5250() || soc_is_exynos5440()) | ||
524 | return 0; | ||
525 | |||
526 | ret = l2x0_of_init(L2_AUX_VAL, L2_AUX_MASK); | 417 | ret = l2x0_of_init(L2_AUX_VAL, L2_AUX_MASK); |
527 | if (!ret) { | 418 | if (ret) |
528 | l2x0_regs_phys = virt_to_phys(&l2x0_saved_regs); | 419 | return ret; |
529 | clean_dcache_area(&l2x0_regs_phys, sizeof(unsigned long)); | ||
530 | return 0; | ||
531 | } | ||
532 | |||
533 | if (!(__raw_readl(S5P_VA_L2CC + L2X0_CTRL) & 0x1)) { | ||
534 | l2x0_saved_regs.phy_base = EXYNOS4_PA_L2CC; | ||
535 | /* TAG, Data Latency Control: 2 cycles */ | ||
536 | l2x0_saved_regs.tag_latency = 0x110; | ||
537 | |||
538 | if (soc_is_exynos4212() || soc_is_exynos4412()) | ||
539 | l2x0_saved_regs.data_latency = 0x120; | ||
540 | else | ||
541 | l2x0_saved_regs.data_latency = 0x110; | ||
542 | |||
543 | l2x0_saved_regs.prefetch_ctrl = 0x30000007; | ||
544 | l2x0_saved_regs.pwr_ctrl = | ||
545 | (L2X0_DYNAMIC_CLK_GATING_EN | L2X0_STNDBY_MODE_EN); | ||
546 | |||
547 | l2x0_regs_phys = virt_to_phys(&l2x0_saved_regs); | ||
548 | |||
549 | __raw_writel(l2x0_saved_regs.tag_latency, | ||
550 | S5P_VA_L2CC + L2X0_TAG_LATENCY_CTRL); | ||
551 | __raw_writel(l2x0_saved_regs.data_latency, | ||
552 | S5P_VA_L2CC + L2X0_DATA_LATENCY_CTRL); | ||
553 | |||
554 | /* L2X0 Prefetch Control */ | ||
555 | __raw_writel(l2x0_saved_regs.prefetch_ctrl, | ||
556 | S5P_VA_L2CC + L2X0_PREFETCH_CTRL); | ||
557 | 420 | ||
558 | /* L2X0 Power Control */ | 421 | l2x0_regs_phys = virt_to_phys(&l2x0_saved_regs); |
559 | __raw_writel(l2x0_saved_regs.pwr_ctrl, | 422 | clean_dcache_area(&l2x0_regs_phys, sizeof(unsigned long)); |
560 | S5P_VA_L2CC + L2X0_POWER_CTRL); | ||
561 | |||
562 | clean_dcache_area(&l2x0_regs_phys, sizeof(unsigned long)); | ||
563 | clean_dcache_area(&l2x0_saved_regs, sizeof(struct l2x0_regs)); | ||
564 | } | ||
565 | |||
566 | l2x0_init(S5P_VA_L2CC, L2_AUX_VAL, L2_AUX_MASK); | ||
567 | return 0; | 423 | return 0; |
568 | } | 424 | } |
569 | early_initcall(exynos4_l2x0_cache_init); | 425 | early_initcall(exynos4_l2x0_cache_init); |
570 | #endif | ||
571 | 426 | ||
572 | static int __init exynos_init(void) | 427 | static int __init exynos_init(void) |
573 | { | 428 | { |
@@ -575,350 +430,3 @@ static int __init exynos_init(void) | |||
575 | 430 | ||
576 | return device_register(&exynos4_dev); | 431 | return device_register(&exynos4_dev); |
577 | } | 432 | } |
578 | |||
579 | /* uart registration process */ | ||
580 | |||
581 | static void __init exynos4_init_uarts(struct s3c2410_uartcfg *cfg, int no) | ||
582 | { | ||
583 | struct s3c2410_uartcfg *tcfg = cfg; | ||
584 | u32 ucnt; | ||
585 | |||
586 | for (ucnt = 0; ucnt < no; ucnt++, tcfg++) | ||
587 | tcfg->has_fracval = 1; | ||
588 | |||
589 | s3c24xx_init_uartdevs("exynos4210-uart", exynos4_uart_resources, cfg, no); | ||
590 | } | ||
591 | |||
592 | static void __iomem *exynos_eint_base; | ||
593 | |||
594 | static DEFINE_SPINLOCK(eint_lock); | ||
595 | |||
596 | static unsigned int eint0_15_data[16]; | ||
597 | |||
598 | static inline int exynos4_irq_to_gpio(unsigned int irq) | ||
599 | { | ||
600 | if (irq < IRQ_EINT(0)) | ||
601 | return -EINVAL; | ||
602 | |||
603 | irq -= IRQ_EINT(0); | ||
604 | if (irq < 8) | ||
605 | return EXYNOS4_GPX0(irq); | ||
606 | |||
607 | irq -= 8; | ||
608 | if (irq < 8) | ||
609 | return EXYNOS4_GPX1(irq); | ||
610 | |||
611 | irq -= 8; | ||
612 | if (irq < 8) | ||
613 | return EXYNOS4_GPX2(irq); | ||
614 | |||
615 | irq -= 8; | ||
616 | if (irq < 8) | ||
617 | return EXYNOS4_GPX3(irq); | ||
618 | |||
619 | return -EINVAL; | ||
620 | } | ||
621 | |||
622 | static inline int exynos5_irq_to_gpio(unsigned int irq) | ||
623 | { | ||
624 | if (irq < IRQ_EINT(0)) | ||
625 | return -EINVAL; | ||
626 | |||
627 | irq -= IRQ_EINT(0); | ||
628 | if (irq < 8) | ||
629 | return EXYNOS5_GPX0(irq); | ||
630 | |||
631 | irq -= 8; | ||
632 | if (irq < 8) | ||
633 | return EXYNOS5_GPX1(irq); | ||
634 | |||
635 | irq -= 8; | ||
636 | if (irq < 8) | ||
637 | return EXYNOS5_GPX2(irq); | ||
638 | |||
639 | irq -= 8; | ||
640 | if (irq < 8) | ||
641 | return EXYNOS5_GPX3(irq); | ||
642 | |||
643 | return -EINVAL; | ||
644 | } | ||
645 | |||
646 | static unsigned int exynos4_eint0_15_src_int[16] = { | ||
647 | EXYNOS4_IRQ_EINT0, | ||
648 | EXYNOS4_IRQ_EINT1, | ||
649 | EXYNOS4_IRQ_EINT2, | ||
650 | EXYNOS4_IRQ_EINT3, | ||
651 | EXYNOS4_IRQ_EINT4, | ||
652 | EXYNOS4_IRQ_EINT5, | ||
653 | EXYNOS4_IRQ_EINT6, | ||
654 | EXYNOS4_IRQ_EINT7, | ||
655 | EXYNOS4_IRQ_EINT8, | ||
656 | EXYNOS4_IRQ_EINT9, | ||
657 | EXYNOS4_IRQ_EINT10, | ||
658 | EXYNOS4_IRQ_EINT11, | ||
659 | EXYNOS4_IRQ_EINT12, | ||
660 | EXYNOS4_IRQ_EINT13, | ||
661 | EXYNOS4_IRQ_EINT14, | ||
662 | EXYNOS4_IRQ_EINT15, | ||
663 | }; | ||
664 | |||
665 | static unsigned int exynos5_eint0_15_src_int[16] = { | ||
666 | EXYNOS5_IRQ_EINT0, | ||
667 | EXYNOS5_IRQ_EINT1, | ||
668 | EXYNOS5_IRQ_EINT2, | ||
669 | EXYNOS5_IRQ_EINT3, | ||
670 | EXYNOS5_IRQ_EINT4, | ||
671 | EXYNOS5_IRQ_EINT5, | ||
672 | EXYNOS5_IRQ_EINT6, | ||
673 | EXYNOS5_IRQ_EINT7, | ||
674 | EXYNOS5_IRQ_EINT8, | ||
675 | EXYNOS5_IRQ_EINT9, | ||
676 | EXYNOS5_IRQ_EINT10, | ||
677 | EXYNOS5_IRQ_EINT11, | ||
678 | EXYNOS5_IRQ_EINT12, | ||
679 | EXYNOS5_IRQ_EINT13, | ||
680 | EXYNOS5_IRQ_EINT14, | ||
681 | EXYNOS5_IRQ_EINT15, | ||
682 | }; | ||
683 | static inline void exynos_irq_eint_mask(struct irq_data *data) | ||
684 | { | ||
685 | u32 mask; | ||
686 | |||
687 | spin_lock(&eint_lock); | ||
688 | mask = __raw_readl(EINT_MASK(exynos_eint_base, data->irq)); | ||
689 | mask |= EINT_OFFSET_BIT(data->irq); | ||
690 | __raw_writel(mask, EINT_MASK(exynos_eint_base, data->irq)); | ||
691 | spin_unlock(&eint_lock); | ||
692 | } | ||
693 | |||
694 | static void exynos_irq_eint_unmask(struct irq_data *data) | ||
695 | { | ||
696 | u32 mask; | ||
697 | |||
698 | spin_lock(&eint_lock); | ||
699 | mask = __raw_readl(EINT_MASK(exynos_eint_base, data->irq)); | ||
700 | mask &= ~(EINT_OFFSET_BIT(data->irq)); | ||
701 | __raw_writel(mask, EINT_MASK(exynos_eint_base, data->irq)); | ||
702 | spin_unlock(&eint_lock); | ||
703 | } | ||
704 | |||
705 | static inline void exynos_irq_eint_ack(struct irq_data *data) | ||
706 | { | ||
707 | __raw_writel(EINT_OFFSET_BIT(data->irq), | ||
708 | EINT_PEND(exynos_eint_base, data->irq)); | ||
709 | } | ||
710 | |||
711 | static void exynos_irq_eint_maskack(struct irq_data *data) | ||
712 | { | ||
713 | exynos_irq_eint_mask(data); | ||
714 | exynos_irq_eint_ack(data); | ||
715 | } | ||
716 | |||
717 | static int exynos_irq_eint_set_type(struct irq_data *data, unsigned int type) | ||
718 | { | ||
719 | int offs = EINT_OFFSET(data->irq); | ||
720 | int shift; | ||
721 | u32 ctrl, mask; | ||
722 | u32 newvalue = 0; | ||
723 | |||
724 | switch (type) { | ||
725 | case IRQ_TYPE_EDGE_RISING: | ||
726 | newvalue = S5P_IRQ_TYPE_EDGE_RISING; | ||
727 | break; | ||
728 | |||
729 | case IRQ_TYPE_EDGE_FALLING: | ||
730 | newvalue = S5P_IRQ_TYPE_EDGE_FALLING; | ||
731 | break; | ||
732 | |||
733 | case IRQ_TYPE_EDGE_BOTH: | ||
734 | newvalue = S5P_IRQ_TYPE_EDGE_BOTH; | ||
735 | break; | ||
736 | |||
737 | case IRQ_TYPE_LEVEL_LOW: | ||
738 | newvalue = S5P_IRQ_TYPE_LEVEL_LOW; | ||
739 | break; | ||
740 | |||
741 | case IRQ_TYPE_LEVEL_HIGH: | ||
742 | newvalue = S5P_IRQ_TYPE_LEVEL_HIGH; | ||
743 | break; | ||
744 | |||
745 | default: | ||
746 | printk(KERN_ERR "No such irq type %d", type); | ||
747 | return -EINVAL; | ||
748 | } | ||
749 | |||
750 | shift = (offs & 0x7) * 4; | ||
751 | mask = 0x7 << shift; | ||
752 | |||
753 | spin_lock(&eint_lock); | ||
754 | ctrl = __raw_readl(EINT_CON(exynos_eint_base, data->irq)); | ||
755 | ctrl &= ~mask; | ||
756 | ctrl |= newvalue << shift; | ||
757 | __raw_writel(ctrl, EINT_CON(exynos_eint_base, data->irq)); | ||
758 | spin_unlock(&eint_lock); | ||
759 | |||
760 | if (soc_is_exynos5250()) | ||
761 | s3c_gpio_cfgpin(exynos5_irq_to_gpio(data->irq), S3C_GPIO_SFN(0xf)); | ||
762 | else | ||
763 | s3c_gpio_cfgpin(exynos4_irq_to_gpio(data->irq), S3C_GPIO_SFN(0xf)); | ||
764 | |||
765 | return 0; | ||
766 | } | ||
767 | |||
768 | static struct irq_chip exynos_irq_eint = { | ||
769 | .name = "exynos-eint", | ||
770 | .irq_mask = exynos_irq_eint_mask, | ||
771 | .irq_unmask = exynos_irq_eint_unmask, | ||
772 | .irq_mask_ack = exynos_irq_eint_maskack, | ||
773 | .irq_ack = exynos_irq_eint_ack, | ||
774 | .irq_set_type = exynos_irq_eint_set_type, | ||
775 | #ifdef CONFIG_PM | ||
776 | .irq_set_wake = s3c_irqext_wake, | ||
777 | #endif | ||
778 | }; | ||
779 | |||
780 | /* | ||
781 | * exynos4_irq_demux_eint | ||
782 | * | ||
783 | * This function demuxes the IRQ from from EINTs 16 to 31. | ||
784 | * It is designed to be inlined into the specific handler | ||
785 | * s5p_irq_demux_eintX_Y. | ||
786 | * | ||
787 | * Each EINT pend/mask registers handle eight of them. | ||
788 | */ | ||
789 | static inline void exynos_irq_demux_eint(unsigned int start) | ||
790 | { | ||
791 | unsigned int irq; | ||
792 | |||
793 | u32 status = __raw_readl(EINT_PEND(exynos_eint_base, start)); | ||
794 | u32 mask = __raw_readl(EINT_MASK(exynos_eint_base, start)); | ||
795 | |||
796 | status &= ~mask; | ||
797 | status &= 0xff; | ||
798 | |||
799 | while (status) { | ||
800 | irq = fls(status) - 1; | ||
801 | generic_handle_irq(irq + start); | ||
802 | status &= ~(1 << irq); | ||
803 | } | ||
804 | } | ||
805 | |||
806 | static void exynos_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc) | ||
807 | { | ||
808 | struct irq_chip *chip = irq_get_chip(irq); | ||
809 | chained_irq_enter(chip, desc); | ||
810 | exynos_irq_demux_eint(IRQ_EINT(16)); | ||
811 | exynos_irq_demux_eint(IRQ_EINT(24)); | ||
812 | chained_irq_exit(chip, desc); | ||
813 | } | ||
814 | |||
815 | static void exynos_irq_eint0_15(unsigned int irq, struct irq_desc *desc) | ||
816 | { | ||
817 | u32 *irq_data = irq_get_handler_data(irq); | ||
818 | struct irq_chip *chip = irq_get_chip(irq); | ||
819 | |||
820 | chained_irq_enter(chip, desc); | ||
821 | generic_handle_irq(*irq_data); | ||
822 | chained_irq_exit(chip, desc); | ||
823 | } | ||
824 | |||
825 | static int __init exynos_init_irq_eint(void) | ||
826 | { | ||
827 | int irq; | ||
828 | |||
829 | #ifdef CONFIG_PINCTRL_SAMSUNG | ||
830 | /* | ||
831 | * The Samsung pinctrl driver provides an integrated gpio/pinmux/pinconf | ||
832 | * functionality along with support for external gpio and wakeup | ||
833 | * interrupts. If the samsung pinctrl driver is enabled and includes | ||
834 | * the wakeup interrupt support, then the setting up external wakeup | ||
835 | * interrupts here can be skipped. This check here is temporary to | ||
836 | * allow exynos4 platforms that do not use Samsung pinctrl driver to | ||
837 | * co-exist with platforms that do. When all of the Samsung Exynos4 | ||
838 | * platforms switch over to using the pinctrl driver, the wakeup | ||
839 | * interrupt support code here can be completely removed. | ||
840 | */ | ||
841 | static const struct of_device_id exynos_pinctrl_ids[] = { | ||
842 | { .compatible = "samsung,exynos4210-pinctrl", }, | ||
843 | { .compatible = "samsung,exynos4x12-pinctrl", }, | ||
844 | { .compatible = "samsung,exynos5250-pinctrl", }, | ||
845 | }; | ||
846 | struct device_node *pctrl_np, *wkup_np; | ||
847 | const char *wkup_compat = "samsung,exynos4210-wakeup-eint"; | ||
848 | |||
849 | for_each_matching_node(pctrl_np, exynos_pinctrl_ids) { | ||
850 | if (of_device_is_available(pctrl_np)) { | ||
851 | wkup_np = of_find_compatible_node(pctrl_np, NULL, | ||
852 | wkup_compat); | ||
853 | if (wkup_np) | ||
854 | return -ENODEV; | ||
855 | } | ||
856 | } | ||
857 | #endif | ||
858 | if (soc_is_exynos5440()) | ||
859 | return 0; | ||
860 | |||
861 | if (soc_is_exynos5250()) | ||
862 | exynos_eint_base = ioremap(EXYNOS5_PA_GPIO1, SZ_4K); | ||
863 | else | ||
864 | exynos_eint_base = ioremap(EXYNOS4_PA_GPIO2, SZ_4K); | ||
865 | |||
866 | if (exynos_eint_base == NULL) { | ||
867 | pr_err("unable to ioremap for EINT base address\n"); | ||
868 | return -ENOMEM; | ||
869 | } | ||
870 | |||
871 | for (irq = 0 ; irq <= 31 ; irq++) { | ||
872 | irq_set_chip_and_handler(IRQ_EINT(irq), &exynos_irq_eint, | ||
873 | handle_level_irq); | ||
874 | set_irq_flags(IRQ_EINT(irq), IRQF_VALID); | ||
875 | } | ||
876 | |||
877 | irq_set_chained_handler(EXYNOS_IRQ_EINT16_31, exynos_irq_demux_eint16_31); | ||
878 | |||
879 | for (irq = 0 ; irq <= 15 ; irq++) { | ||
880 | eint0_15_data[irq] = IRQ_EINT(irq); | ||
881 | |||
882 | if (soc_is_exynos5250()) { | ||
883 | irq_set_handler_data(exynos5_eint0_15_src_int[irq], | ||
884 | &eint0_15_data[irq]); | ||
885 | irq_set_chained_handler(exynos5_eint0_15_src_int[irq], | ||
886 | exynos_irq_eint0_15); | ||
887 | } else { | ||
888 | irq_set_handler_data(exynos4_eint0_15_src_int[irq], | ||
889 | &eint0_15_data[irq]); | ||
890 | irq_set_chained_handler(exynos4_eint0_15_src_int[irq], | ||
891 | exynos_irq_eint0_15); | ||
892 | } | ||
893 | } | ||
894 | |||
895 | return 0; | ||
896 | } | ||
897 | arch_initcall(exynos_init_irq_eint); | ||
898 | |||
899 | static struct resource exynos4_pmu_resource[] = { | ||
900 | DEFINE_RES_IRQ(EXYNOS4_IRQ_PMU), | ||
901 | DEFINE_RES_IRQ(EXYNOS4_IRQ_PMU_CPU1), | ||
902 | #if defined(CONFIG_SOC_EXYNOS4412) | ||
903 | DEFINE_RES_IRQ(EXYNOS4_IRQ_PMU_CPU2), | ||
904 | DEFINE_RES_IRQ(EXYNOS4_IRQ_PMU_CPU3), | ||
905 | #endif | ||
906 | }; | ||
907 | |||
908 | static struct platform_device exynos4_device_pmu = { | ||
909 | .name = "arm-pmu", | ||
910 | .num_resources = ARRAY_SIZE(exynos4_pmu_resource), | ||
911 | .resource = exynos4_pmu_resource, | ||
912 | }; | ||
913 | |||
914 | static int __init exynos_armpmu_init(void) | ||
915 | { | ||
916 | if (!of_have_populated_dt()) { | ||
917 | if (soc_is_exynos4210() || soc_is_exynos4212()) | ||
918 | exynos4_device_pmu.num_resources = 2; | ||
919 | platform_device_register(&exynos4_device_pmu); | ||
920 | } | ||
921 | |||
922 | return 0; | ||
923 | } | ||
924 | arch_initcall(exynos_armpmu_init); | ||