aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-exynos4
diff options
context:
space:
mode:
authorKukjin Kim <kgene.kim@samsung.com>2011-02-14 02:10:55 -0500
committerKukjin Kim <kgene.kim@samsung.com>2011-02-21 23:51:15 -0500
commitc81a24ff8f4efda02ffaa0c3170155550bcae339 (patch)
treee26a5c26cda9291b4d4881be128db254cbf66fe5 /arch/arm/mach-exynos4
parentb3ed3a174c419702eddf9fb28636f6e4baa29d03 (diff)
ARM: EXYNOS4: Update IRQ part
This patch updates IRQ part of EXYNOS4 according to the change of ARCH name, EXYNOS4. Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
Diffstat (limited to 'arch/arm/mach-exynos4')
-rw-r--r--arch/arm/mach-exynos4/include/mach/irqs.h146
-rw-r--r--arch/arm/mach-exynos4/include/mach/regs-irq.h19
-rw-r--r--arch/arm/mach-exynos4/irq-combiner.c127
-rw-r--r--arch/arm/mach-exynos4/irq-eint.c229
4 files changed, 521 insertions, 0 deletions
diff --git a/arch/arm/mach-exynos4/include/mach/irqs.h b/arch/arm/mach-exynos4/include/mach/irqs.h
new file mode 100644
index 000000000000..2dc590085a9b
--- /dev/null
+++ b/arch/arm/mach-exynos4/include/mach/irqs.h
@@ -0,0 +1,146 @@
1/* linux/arch/arm/mach-exynos4/include/mach/irqs.h
2 *
3 * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
5 *
6 * EXYNOS4 - 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/* PPI: Private Peripheral Interrupt */
19
20#define IRQ_PPI(x) S5P_IRQ(x+16)
21
22#define IRQ_LOCALTIMER IRQ_PPI(13)
23
24/* SPI: Shared Peripheral Interrupt */
25
26#define IRQ_SPI(x) S5P_IRQ(x+32)
27
28#define IRQ_MCT1 IRQ_SPI(35)
29
30#define IRQ_EINT0 IRQ_SPI(40)
31#define IRQ_EINT1 IRQ_SPI(41)
32#define IRQ_EINT2 IRQ_SPI(42)
33#define IRQ_EINT3 IRQ_SPI(43)
34#define IRQ_USB_HSOTG IRQ_SPI(44)
35#define IRQ_USB_HOST IRQ_SPI(45)
36#define IRQ_MODEM_IF IRQ_SPI(46)
37#define IRQ_ROTATOR IRQ_SPI(47)
38#define IRQ_JPEG IRQ_SPI(48)
39#define IRQ_2D IRQ_SPI(49)
40#define IRQ_PCIE IRQ_SPI(50)
41#define IRQ_MCT0 IRQ_SPI(51)
42#define IRQ_MFC IRQ_SPI(52)
43#define IRQ_AUDIO_SS IRQ_SPI(54)
44#define IRQ_AC97 IRQ_SPI(55)
45#define IRQ_SPDIF IRQ_SPI(56)
46#define IRQ_KEYPAD IRQ_SPI(57)
47#define IRQ_INTFEEDCTRL_SSS IRQ_SPI(58)
48#define IRQ_SLIMBUS IRQ_SPI(59)
49#define IRQ_PMU IRQ_SPI(60)
50#define IRQ_TSI IRQ_SPI(61)
51#define IRQ_SATA IRQ_SPI(62)
52#define IRQ_GPS IRQ_SPI(63)
53
54#define MAX_IRQ_IN_COMBINER 8
55#define COMBINER_GROUP(x) ((x) * MAX_IRQ_IN_COMBINER + IRQ_SPI(64))
56#define COMBINER_IRQ(x, y) (COMBINER_GROUP(x) + y)
57
58#define IRQ_SYSMMU_MDMA0_0 COMBINER_IRQ(4, 0)
59#define IRQ_SYSMMU_SSS_0 COMBINER_IRQ(4, 1)
60#define IRQ_SYSMMU_FIMC0_0 COMBINER_IRQ(4, 2)
61#define IRQ_SYSMMU_FIMC1_0 COMBINER_IRQ(4, 3)
62#define IRQ_SYSMMU_FIMC2_0 COMBINER_IRQ(4, 4)
63#define IRQ_SYSMMU_FIMC3_0 COMBINER_IRQ(4, 5)
64#define IRQ_SYSMMU_JPEG_0 COMBINER_IRQ(4, 6)
65#define IRQ_SYSMMU_2D_0 COMBINER_IRQ(4, 7)
66
67#define IRQ_SYSMMU_ROTATOR_0 COMBINER_IRQ(5, 0)
68#define IRQ_SYSMMU_MDMA1_0 COMBINER_IRQ(5, 1)
69#define IRQ_SYSMMU_LCD0_M0_0 COMBINER_IRQ(5, 2)
70#define IRQ_SYSMMU_LCD1_M1_0 COMBINER_IRQ(5, 3)
71#define IRQ_SYSMMU_TV_M0_0 COMBINER_IRQ(5, 4)
72#define IRQ_SYSMMU_MFC_M0_0 COMBINER_IRQ(5, 5)
73#define IRQ_SYSMMU_MFC_M1_0 COMBINER_IRQ(5, 6)
74#define IRQ_SYSMMU_PCIE_0 COMBINER_IRQ(5, 7)
75
76#define IRQ_PDMA0 COMBINER_IRQ(21, 0)
77#define IRQ_PDMA1 COMBINER_IRQ(21, 1)
78
79#define IRQ_TIMER0_VIC COMBINER_IRQ(22, 0)
80#define IRQ_TIMER1_VIC COMBINER_IRQ(22, 1)
81#define IRQ_TIMER2_VIC COMBINER_IRQ(22, 2)
82#define IRQ_TIMER3_VIC COMBINER_IRQ(22, 3)
83#define IRQ_TIMER4_VIC COMBINER_IRQ(22, 4)
84
85#define IRQ_RTC_ALARM COMBINER_IRQ(23, 0)
86#define IRQ_RTC_TIC COMBINER_IRQ(23, 1)
87
88#define IRQ_UART0 COMBINER_IRQ(26, 0)
89#define IRQ_UART1 COMBINER_IRQ(26, 1)
90#define IRQ_UART2 COMBINER_IRQ(26, 2)
91#define IRQ_UART3 COMBINER_IRQ(26, 3)
92#define IRQ_UART4 COMBINER_IRQ(26, 4)
93
94#define IRQ_IIC COMBINER_IRQ(27, 0)
95#define IRQ_IIC1 COMBINER_IRQ(27, 1)
96#define IRQ_IIC2 COMBINER_IRQ(27, 2)
97#define IRQ_IIC3 COMBINER_IRQ(27, 3)
98#define IRQ_IIC4 COMBINER_IRQ(27, 4)
99#define IRQ_IIC5 COMBINER_IRQ(27, 5)
100#define IRQ_IIC6 COMBINER_IRQ(27, 6)
101#define IRQ_IIC7 COMBINER_IRQ(27, 7)
102
103#define IRQ_HSMMC0 COMBINER_IRQ(29, 0)
104#define IRQ_HSMMC1 COMBINER_IRQ(29, 1)
105#define IRQ_HSMMC2 COMBINER_IRQ(29, 2)
106#define IRQ_HSMMC3 COMBINER_IRQ(29, 3)
107
108#define IRQ_MIPI_CSIS0 COMBINER_IRQ(30, 0)
109#define IRQ_MIPI_CSIS1 COMBINER_IRQ(30, 1)
110
111#define IRQ_ONENAND_AUDI COMBINER_IRQ(34, 0)
112
113#define IRQ_MCT_L1 COMBINER_IRQ(35, 3)
114
115#define IRQ_EINT4 COMBINER_IRQ(37, 0)
116#define IRQ_EINT5 COMBINER_IRQ(37, 1)
117#define IRQ_EINT6 COMBINER_IRQ(37, 2)
118#define IRQ_EINT7 COMBINER_IRQ(37, 3)
119#define IRQ_EINT8 COMBINER_IRQ(38, 0)
120
121#define IRQ_EINT9 COMBINER_IRQ(38, 1)
122#define IRQ_EINT10 COMBINER_IRQ(38, 2)
123#define IRQ_EINT11 COMBINER_IRQ(38, 3)
124#define IRQ_EINT12 COMBINER_IRQ(38, 4)
125#define IRQ_EINT13 COMBINER_IRQ(38, 5)
126#define IRQ_EINT14 COMBINER_IRQ(38, 6)
127#define IRQ_EINT15 COMBINER_IRQ(38, 7)
128
129#define IRQ_EINT16_31 COMBINER_IRQ(39, 0)
130
131#define IRQ_MCT_L0 COMBINER_IRQ(51, 0)
132
133#define IRQ_WDT COMBINER_IRQ(53, 0)
134
135#define MAX_COMBINER_NR 54
136
137#define S5P_IRQ_EINT_BASE COMBINER_IRQ(MAX_COMBINER_NR, 0)
138
139#define S5P_EINT_BASE1 (S5P_IRQ_EINT_BASE + 0)
140#define S5P_EINT_BASE2 (S5P_IRQ_EINT_BASE + 16)
141
142/* Set the default NR_IRQS */
143
144#define NR_IRQS (S5P_IRQ_EINT_BASE + 32)
145
146#endif /* __ASM_ARCH_IRQS_H */
diff --git a/arch/arm/mach-exynos4/include/mach/regs-irq.h b/arch/arm/mach-exynos4/include/mach/regs-irq.h
new file mode 100644
index 000000000000..9c7b4bfd546f
--- /dev/null
+++ b/arch/arm/mach-exynos4/include/mach/regs-irq.h
@@ -0,0 +1,19 @@
1/* linux/arch/arm/mach-exynos4/include/mach/regs-irq.h
2 *
3 * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
5 *
6 * EXYNOS4 - 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-exynos4/irq-combiner.c b/arch/arm/mach-exynos4/irq-combiner.c
new file mode 100644
index 000000000000..31618d91ce15
--- /dev/null
+++ b/arch/arm/mach-exynos4/irq-combiner.c
@@ -0,0 +1,127 @@
1/* linux/arch/arm/mach-exynos4/irq-combiner.c
2 *
3 * Copyright (c) 2010-2011 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 unsigned int irq_mask;
28 void __iomem *base;
29};
30
31static struct combiner_chip_data combiner_data[MAX_COMBINER_NR];
32
33static inline void __iomem *combiner_base(struct irq_data *data)
34{
35 struct combiner_chip_data *combiner_data =
36 irq_data_get_irq_chip_data(data);
37
38 return combiner_data->base;
39}
40
41static void combiner_mask_irq(struct irq_data *data)
42{
43 u32 mask = 1 << (data->irq % 32);
44
45 __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_CLEAR);
46}
47
48static void combiner_unmask_irq(struct irq_data *data)
49{
50 u32 mask = 1 << (data->irq % 32);
51
52 __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_SET);
53}
54
55static void combiner_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
56{
57 struct combiner_chip_data *chip_data = get_irq_data(irq);
58 struct irq_chip *chip = get_irq_chip(irq);
59 unsigned int cascade_irq, combiner_irq;
60 unsigned long status;
61
62 /* primary controller ack'ing */
63 chip->irq_ack(&desc->irq_data);
64
65 spin_lock(&irq_controller_lock);
66 status = __raw_readl(chip_data->base + COMBINER_INT_STATUS);
67 spin_unlock(&irq_controller_lock);
68 status &= chip_data->irq_mask;
69
70 if (status == 0)
71 goto out;
72
73 combiner_irq = __ffs(status);
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->irq_unmask(&desc->irq_data);
84}
85
86static struct irq_chip combiner_chip = {
87 .name = "COMBINER",
88 .irq_mask = combiner_mask_irq,
89 .irq_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 combiner_data[combiner_nr].irq_mask = 0xff << ((combiner_nr % 4) << 3);
112
113 /* Disable all interrupts */
114
115 __raw_writel(combiner_data[combiner_nr].irq_mask,
116 base + COMBINER_ENABLE_CLEAR);
117
118 /* Setup the Linux IRQ subsystem */
119
120 for (i = irq_start; i < combiner_data[combiner_nr].irq_offset
121 + MAX_IRQ_IN_COMBINER; i++) {
122 set_irq_chip(i, &combiner_chip);
123 set_irq_chip_data(i, &combiner_data[combiner_nr]);
124 set_irq_handler(i, handle_level_irq);
125 set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
126 }
127}
diff --git a/arch/arm/mach-exynos4/irq-eint.c b/arch/arm/mach-exynos4/irq-eint.c
new file mode 100644
index 000000000000..4f7ad4a796e4
--- /dev/null
+++ b/arch/arm/mach-exynos4/irq-eint.c
@@ -0,0 +1,229 @@
1/* linux/arch/arm/mach-exynos4/irq-eint.c
2 *
3 * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
5 *
6 * EXYNOS4 - IRQ EINT support
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#include <linux/kernel.h>
14#include <linux/interrupt.h>
15#include <linux/irq.h>
16#include <linux/io.h>
17#include <linux/sysdev.h>
18#include <linux/gpio.h>
19
20#include <plat/pm.h>
21#include <plat/cpu.h>
22#include <plat/gpio-cfg.h>
23
24#include <mach/regs-gpio.h>
25
26static DEFINE_SPINLOCK(eint_lock);
27
28static unsigned int eint0_15_data[16];
29
30static unsigned int exynos4_get_irq_nr(unsigned int number)
31{
32 u32 ret = 0;
33
34 switch (number) {
35 case 0 ... 3:
36 ret = (number + IRQ_EINT0);
37 break;
38 case 4 ... 7:
39 ret = (number + (IRQ_EINT4 - 4));
40 break;
41 case 8 ... 15:
42 ret = (number + (IRQ_EINT8 - 8));
43 break;
44 default:
45 printk(KERN_ERR "number available : %d\n", number);
46 }
47
48 return ret;
49}
50
51static inline void exynos4_irq_eint_mask(struct irq_data *data)
52{
53 u32 mask;
54
55 spin_lock(&eint_lock);
56 mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(data->irq)));
57 mask |= eint_irq_to_bit(data->irq);
58 __raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(data->irq)));
59 spin_unlock(&eint_lock);
60}
61
62static void exynos4_irq_eint_unmask(struct irq_data *data)
63{
64 u32 mask;
65
66 spin_lock(&eint_lock);
67 mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(data->irq)));
68 mask &= ~(eint_irq_to_bit(data->irq));
69 __raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(data->irq)));
70 spin_unlock(&eint_lock);
71}
72
73static inline void exynos4_irq_eint_ack(struct irq_data *data)
74{
75 __raw_writel(eint_irq_to_bit(data->irq),
76 S5P_EINT_PEND(EINT_REG_NR(data->irq)));
77}
78
79static void exynos4_irq_eint_maskack(struct irq_data *data)
80{
81 exynos4_irq_eint_mask(data);
82 exynos4_irq_eint_ack(data);
83}
84
85static int exynos4_irq_eint_set_type(struct irq_data *data, unsigned int type)
86{
87 int offs = EINT_OFFSET(data->irq);
88 int shift;
89 u32 ctrl, mask;
90 u32 newvalue = 0;
91
92 switch (type) {
93 case IRQ_TYPE_EDGE_RISING:
94 newvalue = S5P_IRQ_TYPE_EDGE_RISING;
95 break;
96
97 case IRQ_TYPE_EDGE_FALLING:
98 newvalue = S5P_IRQ_TYPE_EDGE_FALLING;
99 break;
100
101 case IRQ_TYPE_EDGE_BOTH:
102 newvalue = S5P_IRQ_TYPE_EDGE_BOTH;
103 break;
104
105 case IRQ_TYPE_LEVEL_LOW:
106 newvalue = S5P_IRQ_TYPE_LEVEL_LOW;
107 break;
108
109 case IRQ_TYPE_LEVEL_HIGH:
110 newvalue = S5P_IRQ_TYPE_LEVEL_HIGH;
111 break;
112
113 default:
114 printk(KERN_ERR "No such irq type %d", type);
115 return -EINVAL;
116 }
117
118 shift = (offs & 0x7) * 4;
119 mask = 0x7 << shift;
120
121 spin_lock(&eint_lock);
122 ctrl = __raw_readl(S5P_EINT_CON(EINT_REG_NR(data->irq)));
123 ctrl &= ~mask;
124 ctrl |= newvalue << shift;
125 __raw_writel(ctrl, S5P_EINT_CON(EINT_REG_NR(data->irq)));
126 spin_unlock(&eint_lock);
127
128 switch (offs) {
129 case 0 ... 7:
130 s3c_gpio_cfgpin(EINT_GPIO_0(offs & 0x7), EINT_MODE);
131 break;
132 case 8 ... 15:
133 s3c_gpio_cfgpin(EINT_GPIO_1(offs & 0x7), EINT_MODE);
134 break;
135 case 16 ... 23:
136 s3c_gpio_cfgpin(EINT_GPIO_2(offs & 0x7), EINT_MODE);
137 break;
138 case 24 ... 31:
139 s3c_gpio_cfgpin(EINT_GPIO_3(offs & 0x7), EINT_MODE);
140 break;
141 default:
142 printk(KERN_ERR "No such irq number %d", offs);
143 }
144
145 return 0;
146}
147
148static struct irq_chip exynos4_irq_eint = {
149 .name = "exynos4-eint",
150 .irq_mask = exynos4_irq_eint_mask,
151 .irq_unmask = exynos4_irq_eint_unmask,
152 .irq_mask_ack = exynos4_irq_eint_maskack,
153 .irq_ack = exynos4_irq_eint_ack,
154 .irq_set_type = exynos4_irq_eint_set_type,
155#ifdef CONFIG_PM
156 .irq_set_wake = s3c_irqext_wake,
157#endif
158};
159
160/* exynos4_irq_demux_eint
161 *
162 * This function demuxes the IRQ from from EINTs 16 to 31.
163 * It is designed to be inlined into the specific handler
164 * s5p_irq_demux_eintX_Y.
165 *
166 * Each EINT pend/mask registers handle eight of them.
167 */
168static inline void exynos4_irq_demux_eint(unsigned int start)
169{
170 unsigned int irq;
171
172 u32 status = __raw_readl(S5P_EINT_PEND(EINT_REG_NR(start)));
173 u32 mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(start)));
174
175 status &= ~mask;
176 status &= 0xff;
177
178 while (status) {
179 irq = fls(status) - 1;
180 generic_handle_irq(irq + start);
181 status &= ~(1 << irq);
182 }
183}
184
185static void exynos4_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc)
186{
187 exynos4_irq_demux_eint(IRQ_EINT(16));
188 exynos4_irq_demux_eint(IRQ_EINT(24));
189}
190
191static void exynos4_irq_eint0_15(unsigned int irq, struct irq_desc *desc)
192{
193 u32 *irq_data = get_irq_data(irq);
194 struct irq_chip *chip = get_irq_chip(irq);
195
196 chip->irq_mask(&desc->irq_data);
197
198 if (chip->irq_ack)
199 chip->irq_ack(&desc->irq_data);
200
201 generic_handle_irq(*irq_data);
202
203 chip->irq_unmask(&desc->irq_data);
204}
205
206int __init exynos4_init_irq_eint(void)
207{
208 int irq;
209
210 for (irq = 0 ; irq <= 31 ; irq++) {
211 set_irq_chip(IRQ_EINT(irq), &exynos4_irq_eint);
212 set_irq_handler(IRQ_EINT(irq), handle_level_irq);
213 set_irq_flags(IRQ_EINT(irq), IRQF_VALID);
214 }
215
216 set_irq_chained_handler(IRQ_EINT16_31, exynos4_irq_demux_eint16_31);
217
218 for (irq = 0 ; irq <= 15 ; irq++) {
219 eint0_15_data[irq] = IRQ_EINT(irq);
220
221 set_irq_data(exynos4_get_irq_nr(irq), &eint0_15_data[irq]);
222 set_irq_chained_handler(exynos4_get_irq_nr(irq),
223 exynos4_irq_eint0_15);
224 }
225
226 return 0;
227}
228
229arch_initcall(exynos4_init_irq_eint);