aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorChanghwan Youn <chaos.youn@samsung.com>2010-07-15 23:12:07 -0400
committerKukjin Kim <kgene.kim@samsung.com>2010-08-05 05:32:41 -0400
commit84bbc16c1f6210b2dfc39344b132d5801c357a70 (patch)
treee60e91c0e6c08913909e50006c1eb289818e829d /arch
parentc8bef14051b261f86278fad84ccc23c891242d25 (diff)
ARM: S5PV310: Add IRQ support
This patch adds IRQ support for S5PV310. ARM GIC is installed in S5PV310 instead of VIC which is in every other CPUs in S5P series. Several irq combiners are used to resolve the lack of irq lines in current implementation. Signed-off-by: Changhwan Youn <chaos.youn@samsung.com> Signed-off-by: Hyuk Lee <hyuk1.lee@samsung.com> Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-s5pv310/include/mach/irqs.h74
-rw-r--r--arch/arm/mach-s5pv310/include/mach/regs-irq.h19
-rw-r--r--arch/arm/mach-s5pv310/irq-combiner.c125
-rw-r--r--arch/arm/plat-s5p/irq.c2
4 files changed, 220 insertions, 0 deletions
diff --git a/arch/arm/mach-s5pv310/include/mach/irqs.h b/arch/arm/mach-s5pv310/include/mach/irqs.h
new file mode 100644
index 000000000000..56885ca3773c
--- /dev/null
+++ b/arch/arm/mach-s5pv310/include/mach/irqs.h
@@ -0,0 +1,74 @@
1/* linux/arch/arm/mach-s5pv310/include/mach/irqs.h
2 *
3 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com/
5 *
6 * S5PV210 - IRQ definitions
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11*/
12
13#ifndef __ASM_ARCH_IRQS_H
14#define __ASM_ARCH_IRQS_H __FILE__
15
16#include <plat/irqs.h>
17
18/* Private Peripheral Interrupt */
19#define IRQ_PPI(x) S5P_IRQ(x+16)
20
21#define IRQ_LOCALTIMER IRQ_PPI(13)
22
23/* Shared Peripheral Interrupt */
24#define IRQ_SPI(x) S5P_IRQ(x+32)
25
26#define IRQ_EINT0 IRQ_SPI(40)
27#define IRQ_EINT1 IRQ_SPI(41)
28#define IRQ_EINT2 IRQ_SPI(42)
29#define IRQ_EINT3 IRQ_SPI(43)
30#define IRQ_USB_HSOTG IRQ_SPI(44)
31#define IRQ_USB_HOST IRQ_SPI(45)
32#define IRQ_MODEM_IF IRQ_SPI(46)
33#define IRQ_ROTATOR IRQ_SPI(47)
34#define IRQ_JPEG IRQ_SPI(48)
35#define IRQ_2D IRQ_SPI(49)
36#define IRQ_PCIE IRQ_SPI(50)
37#define IRQ_SYSTEM_TIMER IRQ_SPI(51)
38#define IRQ_MFC IRQ_SPI(52)
39#define IRQ_WTD IRQ_SPI(53)
40#define IRQ_AUDIO_SS IRQ_SPI(54)
41#define IRQ_AC97 IRQ_SPI(55)
42#define IRQ_SPDIF IRQ_SPI(56)
43#define IRQ_KEYPAD IRQ_SPI(57)
44#define IRQ_INTFEEDCTRL_SSS IRQ_SPI(58)
45#define IRQ_SLIMBUS IRQ_SPI(59)
46#define IRQ_PMU IRQ_SPI(60)
47#define IRQ_TSI IRQ_SPI(61)
48#define IRQ_SATA IRQ_SPI(62)
49#define IRQ_GPS IRQ_SPI(63)
50
51#define MAX_IRQ_IN_COMBINER 8
52#define COMBINER_GROUP(x) ((x) * MAX_IRQ_IN_COMBINER + IRQ_SPI(64))
53#define COMBINER_IRQ(x, y) (COMBINER_GROUP(x) + y)
54
55#define IRQ_TIMER0_VIC COMBINER_IRQ(22, 0)
56#define IRQ_TIMER1_VIC COMBINER_IRQ(22, 1)
57#define IRQ_TIMER2_VIC COMBINER_IRQ(22, 2)
58#define IRQ_TIMER3_VIC COMBINER_IRQ(22, 3)
59#define IRQ_TIMER4_VIC COMBINER_IRQ(22, 4)
60
61#define IRQ_UART0 COMBINER_IRQ(26, 0)
62#define IRQ_UART1 COMBINER_IRQ(26, 1)
63#define IRQ_UART2 COMBINER_IRQ(26, 2)
64#define IRQ_UART3 COMBINER_IRQ(26, 3)
65#define IRQ_UART4 COMBINER_IRQ(26, 4)
66
67#define IRQ_IIC COMBINER_IRQ(27, 0)
68
69/* Set the default NR_IRQS */
70#define NR_IRQS COMBINER_IRQ(MAX_COMBINER_NR, 0)
71
72#define MAX_COMBINER_NR 39
73
74#endif /* ASM_ARCH_IRQS_H */
diff --git a/arch/arm/mach-s5pv310/include/mach/regs-irq.h b/arch/arm/mach-s5pv310/include/mach/regs-irq.h
new file mode 100644
index 000000000000..c6e09c7f9161
--- /dev/null
+++ b/arch/arm/mach-s5pv310/include/mach/regs-irq.h
@@ -0,0 +1,19 @@
1/* linux/arch/arm/mach-s5pv310/include/mach/regs-irq.h
2 *
3 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com/
5 *
6 * S5PV310 - IRQ register definitions
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11*/
12
13#ifndef __ASM_ARCH_REGS_IRQ_H
14#define __ASM_ARCH_REGS_IRQ_H __FILE__
15
16#include <asm/hardware/gic.h>
17#include <mach/map.h>
18
19#endif /* __ASM_ARCH_REGS_IRQ_H */
diff --git a/arch/arm/mach-s5pv310/irq-combiner.c b/arch/arm/mach-s5pv310/irq-combiner.c
new file mode 100644
index 000000000000..0f7052164f23
--- /dev/null
+++ b/arch/arm/mach-s5pv310/irq-combiner.c
@@ -0,0 +1,125 @@
1/* linux/arch/arm/mach-s5pv310/irq-combiner.c
2 *
3 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
5 *
6 * Based on arch/arm/common/gic.c
7 *
8 * IRQ COMBINER support
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13*/
14
15#include <linux/io.h>
16
17#include <asm/mach/irq.h>
18
19#define COMBINER_ENABLE_SET 0x0
20#define COMBINER_ENABLE_CLEAR 0x4
21#define COMBINER_INT_STATUS 0xC
22
23static DEFINE_SPINLOCK(irq_controller_lock);
24
25struct combiner_chip_data {
26 unsigned int irq_offset;
27 void __iomem *base;
28};
29
30static struct combiner_chip_data combiner_data[MAX_COMBINER_NR];
31
32static inline void __iomem *combiner_base(unsigned int irq)
33{
34 struct combiner_chip_data *combiner_data = get_irq_chip_data(irq);
35 return combiner_data->base;
36}
37
38static void combiner_mask_irq(unsigned int irq)
39{
40 u32 mask = 1 << (irq % 32);
41
42 __raw_writel(mask, combiner_base(irq) + COMBINER_ENABLE_CLEAR);
43}
44
45static void combiner_unmask_irq(unsigned int irq)
46{
47 u32 mask = 1 << (irq % 32);
48
49 __raw_writel(mask, combiner_base(irq) + COMBINER_ENABLE_SET);
50}
51
52static void combiner_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
53{
54 struct combiner_chip_data *chip_data = get_irq_data(irq);
55 struct irq_chip *chip = get_irq_chip(irq);
56 unsigned int cascade_irq, combiner_irq;
57 unsigned long status;
58
59 /* primary controller ack'ing */
60 chip->ack(irq);
61
62 spin_lock(&irq_controller_lock);
63 status = __raw_readl(chip_data->base + COMBINER_INT_STATUS);
64 spin_unlock(&irq_controller_lock);
65
66 if (status == 0)
67 goto out;
68
69 for (combiner_irq = 0; combiner_irq < 32; combiner_irq++) {
70 if (status & 0x1)
71 break;
72 status >>= 1;
73 }
74
75 cascade_irq = combiner_irq + (chip_data->irq_offset & ~31);
76 if (unlikely(cascade_irq >= NR_IRQS))
77 do_bad_IRQ(cascade_irq, desc);
78 else
79 generic_handle_irq(cascade_irq);
80
81 out:
82 /* primary controller unmasking */
83 chip->unmask(irq);
84}
85
86static struct irq_chip combiner_chip = {
87 .name = "COMBINER",
88 .mask = combiner_mask_irq,
89 .unmask = combiner_unmask_irq,
90};
91
92void __init combiner_cascade_irq(unsigned int combiner_nr, unsigned int irq)
93{
94 if (combiner_nr >= MAX_COMBINER_NR)
95 BUG();
96 if (set_irq_data(irq, &combiner_data[combiner_nr]) != 0)
97 BUG();
98 set_irq_chained_handler(irq, combiner_handle_cascade_irq);
99}
100
101void __init combiner_init(unsigned int combiner_nr, void __iomem *base,
102 unsigned int irq_start)
103{
104 unsigned int i;
105
106 if (combiner_nr >= MAX_COMBINER_NR)
107 BUG();
108
109 combiner_data[combiner_nr].base = base;
110 combiner_data[combiner_nr].irq_offset = irq_start;
111
112 /* Disable all interrupts */
113
114 __raw_writel(0xffffffff, base + COMBINER_ENABLE_CLEAR);
115
116 /* Setup the Linux IRQ subsystem */
117
118 for (i = irq_start; i < combiner_data[combiner_nr].irq_offset
119 + MAX_IRQ_IN_COMBINER; i++) {
120 set_irq_chip(i, &combiner_chip);
121 set_irq_chip_data(i, &combiner_data[combiner_nr]);
122 set_irq_handler(i, handle_level_irq);
123 set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
124 }
125}
diff --git a/arch/arm/plat-s5p/irq.c b/arch/arm/plat-s5p/irq.c
index 25e1eb6de59e..5560b12035d1 100644
--- a/arch/arm/plat-s5p/irq.c
+++ b/arch/arm/plat-s5p/irq.c
@@ -56,11 +56,13 @@ static struct s3c_uart_irq uart_irqs[] = {
56 56
57void __init s5p_init_irq(u32 *vic, u32 num_vic) 57void __init s5p_init_irq(u32 *vic, u32 num_vic)
58{ 58{
59#ifdef CONFIG_ARM_VIC
59 int irq; 60 int irq;
60 61
61 /* initialize the VICs */ 62 /* initialize the VICs */
62 for (irq = 0; irq < num_vic; irq++) 63 for (irq = 0; irq < num_vic; irq++)
63 vic_init(VA_VIC(irq), VIC_BASE(irq), vic[irq], 0); 64 vic_init(VA_VIC(irq), VIC_BASE(irq), vic[irq], 0);
65#endif
64 66
65 s3c_init_vic_timer_irq(IRQ_TIMER0_VIC, IRQ_TIMER0); 67 s3c_init_vic_timer_irq(IRQ_TIMER0_VIC, IRQ_TIMER0);
66 s3c_init_vic_timer_irq(IRQ_TIMER1_VIC, IRQ_TIMER1); 68 s3c_init_vic_timer_irq(IRQ_TIMER1_VIC, IRQ_TIMER1);