diff options
author | Byungho Min <bhminjames@gmail.com> | 2009-06-23 08:40:03 -0400 |
---|---|---|
committer | Ben Dooks <ben-linux@fluff.org> | 2009-08-16 18:25:00 -0400 |
commit | c9b870e7e796eea515a261a314917317ebb1cb4a (patch) | |
tree | 09e360ea4c3f85153307009ee890e73992079f61 | |
parent | 0164cbf4390fbcd7125fc8d476a451a3efa14c5d (diff) |
ARM: S5PC100: IRQ and timer
S5PC100 has 3 VICs(Vectored Interrupt Controller). The VICs come from S3C64xx
series, so the driver source code can be shared with S3C families. The S5PC100
has 3 VICs while S3C64xx has only 2.
Signed-off-by: Byungho Min <bhmin@samsung.com>
[ben-linux@fluff.org: subject fixup]
Signed-off-by: Ben Dooks <ben-linux@fluff.org>
-rw-r--r-- | arch/arm/mach-s5pc100/include/mach/irqs.h | 14 | ||||
-rw-r--r-- | arch/arm/mach-s5pc100/include/mach/pwm-clock.h | 56 | ||||
-rw-r--r-- | arch/arm/mach-s5pc100/include/mach/regs-irq.h | 24 | ||||
-rw-r--r-- | arch/arm/mach-s5pc100/include/mach/tick.h | 29 | ||||
-rw-r--r-- | arch/arm/plat-s5pc1xx/include/plat/irqs.h | 182 | ||||
-rw-r--r-- | arch/arm/plat-s5pc1xx/irq.c | 259 |
6 files changed, 564 insertions, 0 deletions
diff --git a/arch/arm/mach-s5pc100/include/mach/irqs.h b/arch/arm/mach-s5pc100/include/mach/irqs.h new file mode 100644 index 000000000000..622720dba289 --- /dev/null +++ b/arch/arm/mach-s5pc100/include/mach/irqs.h | |||
@@ -0,0 +1,14 @@ | |||
1 | /* linux/arch/arm/mach-s5pc100/include/mach/irqs.h | ||
2 | * | ||
3 | * Copyright 2009 Samsung Electronics Co. | ||
4 | * Byungho Min <bhmin@samsung.com> | ||
5 | * | ||
6 | * S5PC100 - IRQ definitions | ||
7 | */ | ||
8 | |||
9 | #ifndef __ASM_ARCH_IRQS_H | ||
10 | #define __ASM_ARCH_IRQS_H __FILE__ | ||
11 | |||
12 | #include <plat/irqs.h> | ||
13 | |||
14 | #endif /* __ASM_ARCH_IRQ_H */ | ||
diff --git a/arch/arm/mach-s5pc100/include/mach/pwm-clock.h b/arch/arm/mach-s5pc100/include/mach/pwm-clock.h new file mode 100644 index 000000000000..b34d2f7aae52 --- /dev/null +++ b/arch/arm/mach-s5pc100/include/mach/pwm-clock.h | |||
@@ -0,0 +1,56 @@ | |||
1 | /* linux/arch/arm/mach-s5pc100/include/mach/pwm-clock.h | ||
2 | * | ||
3 | * Copyright 2009 Samsung Electronics Co. | ||
4 | * Byungho Min <bhmin@samsung.com> | ||
5 | * | ||
6 | * S5PC100 - pwm clock and timer support | ||
7 | * | ||
8 | * Based on mach-s3c6400/include/mach/pwm-clock.h | ||
9 | */ | ||
10 | |||
11 | /** | ||
12 | * pwm_cfg_src_is_tclk() - return whether the given mux config is a tclk | ||
13 | * @tcfg: The timer TCFG1 register bits shifted down to 0. | ||
14 | * | ||
15 | * Return true if the given configuration from TCFG1 is a TCLK instead | ||
16 | * any of the TDIV clocks. | ||
17 | */ | ||
18 | static inline int pwm_cfg_src_is_tclk(unsigned long tcfg) | ||
19 | { | ||
20 | return tcfg >= S3C64XX_TCFG1_MUX_TCLK; | ||
21 | } | ||
22 | |||
23 | /** | ||
24 | * tcfg_to_divisor() - convert tcfg1 setting to a divisor | ||
25 | * @tcfg1: The tcfg1 setting, shifted down. | ||
26 | * | ||
27 | * Get the divisor value for the given tcfg1 setting. We assume the | ||
28 | * caller has already checked to see if this is not a TCLK source. | ||
29 | */ | ||
30 | static inline unsigned long tcfg_to_divisor(unsigned long tcfg1) | ||
31 | { | ||
32 | return 1 << tcfg1; | ||
33 | } | ||
34 | |||
35 | /** | ||
36 | * pwm_tdiv_has_div1() - does the tdiv setting have a /1 | ||
37 | * | ||
38 | * Return true if we have a /1 in the tdiv setting. | ||
39 | */ | ||
40 | static inline unsigned int pwm_tdiv_has_div1(void) | ||
41 | { | ||
42 | return 1; | ||
43 | } | ||
44 | |||
45 | /** | ||
46 | * pwm_tdiv_div_bits() - calculate TCFG1 divisor value. | ||
47 | * @div: The divisor to calculate the bit information for. | ||
48 | * | ||
49 | * Turn a divisor into the necessary bit field for TCFG1. | ||
50 | */ | ||
51 | static inline unsigned long pwm_tdiv_div_bits(unsigned int div) | ||
52 | { | ||
53 | return ilog2(div); | ||
54 | } | ||
55 | |||
56 | #define S3C_TCFG1_MUX_TCLK S3C64XX_TCFG1_MUX_TCLK | ||
diff --git a/arch/arm/mach-s5pc100/include/mach/regs-irq.h b/arch/arm/mach-s5pc100/include/mach/regs-irq.h new file mode 100644 index 000000000000..751ac15438c8 --- /dev/null +++ b/arch/arm/mach-s5pc100/include/mach/regs-irq.h | |||
@@ -0,0 +1,24 @@ | |||
1 | /* linux/arch/arm/mach-s5pc100/include/mach/regs-irq.h | ||
2 | * | ||
3 | * Copyright 2009 Samsung Electronics Co. | ||
4 | * Byungho Min <bhmin@samsung.com> | ||
5 | * | ||
6 | * S5PC1XX - 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 <mach/map.h> | ||
17 | #include <asm/hardware/vic.h> | ||
18 | |||
19 | /* interrupt controller */ | ||
20 | #define S5PC1XX_VIC0REG(x) ((x) + S5PC1XX_VA_VIC(0)) | ||
21 | #define S5PC1XX_VIC1REG(x) ((x) + S5PC1XX_VA_VIC(1)) | ||
22 | #define S5PC1XX_VIC2REG(x) ((x) + S5PC1XX_VA_VIC(2)) | ||
23 | |||
24 | #endif /* __ASM_ARCH_REGS_IRQ_H */ | ||
diff --git a/arch/arm/mach-s5pc100/include/mach/tick.h b/arch/arm/mach-s5pc100/include/mach/tick.h new file mode 100644 index 000000000000..d3de0f3591ae --- /dev/null +++ b/arch/arm/mach-s5pc100/include/mach/tick.h | |||
@@ -0,0 +1,29 @@ | |||
1 | /* linux/arch/arm/mach-s5pc100/include/mach/tick.h | ||
2 | * | ||
3 | * Copyright 2009 Samsung Electronics Co. | ||
4 | * Byungho Min <bhmin@samsung.com> | ||
5 | * | ||
6 | * S3C64XX - Timer tick support definitions | ||
7 | * | ||
8 | * Based on mach-s3c6400/include/mach/tick.h | ||
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 | #ifndef __ASM_ARCH_TICK_H | ||
16 | #define __ASM_ARCH_TICK_H __FILE__ | ||
17 | |||
18 | /* note, the timer interrutps turn up in 2 places, the vic and then | ||
19 | * the timer block. We take the VIC as the base at the moment. | ||
20 | */ | ||
21 | static inline u32 s3c24xx_ostimer_pending(void) | ||
22 | { | ||
23 | u32 pend = __raw_readl(S3C_VA_VIC0 + VIC_RAW_STATUS); | ||
24 | return pend & 1 << (IRQ_TIMER4 - S5PC1XX_IRQ_VIC0(0)); | ||
25 | } | ||
26 | |||
27 | #define TICK_MAX (0xffffffff) | ||
28 | |||
29 | #endif /* __ASM_ARCH_TICK_H */ | ||
diff --git a/arch/arm/plat-s5pc1xx/include/plat/irqs.h b/arch/arm/plat-s5pc1xx/include/plat/irqs.h new file mode 100644 index 000000000000..f07d8c3b25d6 --- /dev/null +++ b/arch/arm/plat-s5pc1xx/include/plat/irqs.h | |||
@@ -0,0 +1,182 @@ | |||
1 | /* linux/arch/arm/plat-s5pc1xx/include/plat/irqs.h | ||
2 | * | ||
3 | * Copyright 2009 Samsung Electronics Co. | ||
4 | * Byungho Min <bhmin@samsung.com> | ||
5 | * | ||
6 | * S5PC1XX - Common IRQ support | ||
7 | * | ||
8 | * Based on plat-s3c64xx/include/plat/irqs.h | ||
9 | */ | ||
10 | |||
11 | #ifndef __ASM_PLAT_S5PC1XX_IRQS_H | ||
12 | #define __ASM_PLAT_S5PC1XX_IRQS_H __FILE__ | ||
13 | |||
14 | /* we keep the first set of CPU IRQs out of the range of | ||
15 | * the ISA space, so that the PC104 has them to itself | ||
16 | * and we don't end up having to do horrible things to the | ||
17 | * standard ISA drivers.... | ||
18 | * | ||
19 | * note, since we're using the VICs, our start must be a | ||
20 | * mulitple of 32 to allow the common code to work | ||
21 | */ | ||
22 | |||
23 | #define S3C_IRQ_OFFSET (32) | ||
24 | |||
25 | #define S3C_IRQ(x) ((x) + S3C_IRQ_OFFSET) | ||
26 | |||
27 | #define S3C_VIC0_BASE S3C_IRQ(0) | ||
28 | #define S3C_VIC1_BASE S3C_IRQ(32) | ||
29 | #define S3C_VIC2_BASE S3C_IRQ(64) | ||
30 | |||
31 | /* UART interrupts, each UART has 4 intterupts per channel so | ||
32 | * use the space between the ISA and S3C main interrupts. Note, these | ||
33 | * are not in the same order as the S3C24XX series! */ | ||
34 | |||
35 | #define IRQ_S3CUART_BASE0 (16) | ||
36 | #define IRQ_S3CUART_BASE1 (20) | ||
37 | #define IRQ_S3CUART_BASE2 (24) | ||
38 | #define IRQ_S3CUART_BASE3 (28) | ||
39 | |||
40 | #define UART_IRQ_RXD (0) | ||
41 | #define UART_IRQ_ERR (1) | ||
42 | #define UART_IRQ_TXD (2) | ||
43 | #define UART_IRQ_MODEM (3) | ||
44 | |||
45 | #define IRQ_S3CUART_RX0 (IRQ_S3CUART_BASE0 + UART_IRQ_RXD) | ||
46 | #define IRQ_S3CUART_TX0 (IRQ_S3CUART_BASE0 + UART_IRQ_TXD) | ||
47 | #define IRQ_S3CUART_ERR0 (IRQ_S3CUART_BASE0 + UART_IRQ_ERR) | ||
48 | |||
49 | #define IRQ_S3CUART_RX1 (IRQ_S3CUART_BASE1 + UART_IRQ_RXD) | ||
50 | #define IRQ_S3CUART_TX1 (IRQ_S3CUART_BASE1 + UART_IRQ_TXD) | ||
51 | #define IRQ_S3CUART_ERR1 (IRQ_S3CUART_BASE1 + UART_IRQ_ERR) | ||
52 | |||
53 | #define IRQ_S3CUART_RX2 (IRQ_S3CUART_BASE2 + UART_IRQ_RXD) | ||
54 | #define IRQ_S3CUART_TX2 (IRQ_S3CUART_BASE2 + UART_IRQ_TXD) | ||
55 | #define IRQ_S3CUART_ERR2 (IRQ_S3CUART_BASE2 + UART_IRQ_ERR) | ||
56 | |||
57 | #define IRQ_S3CUART_RX3 (IRQ_S3CUART_BASE3 + UART_IRQ_RXD) | ||
58 | #define IRQ_S3CUART_TX3 (IRQ_S3CUART_BASE3 + UART_IRQ_TXD) | ||
59 | #define IRQ_S3CUART_ERR3 (IRQ_S3CUART_BASE3 + UART_IRQ_ERR) | ||
60 | |||
61 | /* VIC based IRQs */ | ||
62 | |||
63 | #define S5PC1XX_IRQ_VIC0(x) (S3C_VIC0_BASE + (x)) | ||
64 | #define S5PC1XX_IRQ_VIC1(x) (S3C_VIC1_BASE + (x)) | ||
65 | #define S5PC1XX_IRQ_VIC2(x) (S3C_VIC2_BASE + (x)) | ||
66 | |||
67 | /* | ||
68 | * VIC0: system, DMA, timer | ||
69 | */ | ||
70 | #define IRQ_EINT0 S5PC1XX_IRQ_VIC0(0) | ||
71 | #define IRQ_EINT1 S5PC1XX_IRQ_VIC0(1) | ||
72 | #define IRQ_EINT2 S5PC1XX_IRQ_VIC0(2) | ||
73 | #define IRQ_EINT3 S5PC1XX_IRQ_VIC0(3) | ||
74 | #define IRQ_EINT4 S5PC1XX_IRQ_VIC0(4) | ||
75 | #define IRQ_EINT5 S5PC1XX_IRQ_VIC0(5) | ||
76 | #define IRQ_EINT6 S5PC1XX_IRQ_VIC0(6) | ||
77 | #define IRQ_EINT7 S5PC1XX_IRQ_VIC0(7) | ||
78 | #define IRQ_EINT8 S5PC1XX_IRQ_VIC0(8) | ||
79 | #define IRQ_EINT9 S5PC1XX_IRQ_VIC0(9) | ||
80 | #define IRQ_EINT10 S5PC1XX_IRQ_VIC0(10) | ||
81 | #define IRQ_EINT11 S5PC1XX_IRQ_VIC0(11) | ||
82 | #define IRQ_EINT12 S5PC1XX_IRQ_VIC0(12) | ||
83 | #define IRQ_EINT13 S5PC1XX_IRQ_VIC0(13) | ||
84 | #define IRQ_EINT14 S5PC1XX_IRQ_VIC0(14) | ||
85 | #define IRQ_EINT15 S5PC1XX_IRQ_VIC0(15) | ||
86 | #define IRQ_EINT16_31 S5PC1XX_IRQ_VIC0(16) | ||
87 | #define IRQ_BATF S5PC1XX_IRQ_VIC0(17) | ||
88 | #define IRQ_MDMA S5PC1XX_IRQ_VIC0(18) | ||
89 | #define IRQ_PDMA0 S5PC1XX_IRQ_VIC0(19) | ||
90 | #define IRQ_PDMA1 S5PC1XX_IRQ_VIC0(20) | ||
91 | #define IRQ_TIMER0 S5PC1XX_IRQ_VIC0(21) | ||
92 | #define IRQ_TIMER1 S5PC1XX_IRQ_VIC0(22) | ||
93 | #define IRQ_TIMER2 S5PC1XX_IRQ_VIC0(23) | ||
94 | #define IRQ_TIMER3 S5PC1XX_IRQ_VIC0(24) | ||
95 | #define IRQ_TIMER4 S5PC1XX_IRQ_VIC0(25) | ||
96 | #define IRQ_SYSTIMER S5PC1XX_IRQ_VIC0(26) | ||
97 | #define IRQ_WDT S5PC1XX_IRQ_VIC0(27) | ||
98 | #define IRQ_RTC_ALARM S5PC1XX_IRQ_VIC0(28) | ||
99 | #define IRQ_RTC_TIC S5PC1XX_IRQ_VIC0(29) | ||
100 | #define IRQ_GPIOINT S5PC1XX_IRQ_VIC0(30) | ||
101 | |||
102 | /* | ||
103 | * VIC1: ARM, power, memory, connectivity | ||
104 | */ | ||
105 | #define IRQ_CORTEX0 S5PC1XX_IRQ_VIC1(0) | ||
106 | #define IRQ_CORTEX1 S5PC1XX_IRQ_VIC1(1) | ||
107 | #define IRQ_CORTEX2 S5PC1XX_IRQ_VIC1(2) | ||
108 | #define IRQ_CORTEX3 S5PC1XX_IRQ_VIC1(3) | ||
109 | #define IRQ_CORTEX4 S5PC1XX_IRQ_VIC1(4) | ||
110 | #define IRQ_IEMAPC S5PC1XX_IRQ_VIC1(5) | ||
111 | #define IRQ_IEMIEC S5PC1XX_IRQ_VIC1(6) | ||
112 | #define IRQ_ONENAND S5PC1XX_IRQ_VIC1(7) | ||
113 | #define IRQ_NFC S5PC1XX_IRQ_VIC1(8) | ||
114 | #define IRQ_CFC S5PC1XX_IRQ_VIC1(9) | ||
115 | #define IRQ_UART0 S5PC1XX_IRQ_VIC1(10) | ||
116 | #define IRQ_UART1 S5PC1XX_IRQ_VIC1(11) | ||
117 | #define IRQ_UART2 S5PC1XX_IRQ_VIC1(12) | ||
118 | #define IRQ_UART3 S5PC1XX_IRQ_VIC1(13) | ||
119 | #define IRQ_IIC S5PC1XX_IRQ_VIC1(14) | ||
120 | #define IRQ_SPI0 S5PC1XX_IRQ_VIC1(15) | ||
121 | #define IRQ_SPI1 S5PC1XX_IRQ_VIC1(16) | ||
122 | #define IRQ_SPI2 S5PC1XX_IRQ_VIC1(17) | ||
123 | #define IRQ_IRDA S5PC1XX_IRQ_VIC1(18) | ||
124 | #define IRQ_CAN0 S5PC1XX_IRQ_VIC1(19) | ||
125 | #define IRQ_CAN1 S5PC1XX_IRQ_VIC1(20) | ||
126 | #define IRQ_HSIRX S5PC1XX_IRQ_VIC1(21) | ||
127 | #define IRQ_HSITX S5PC1XX_IRQ_VIC1(22) | ||
128 | #define IRQ_UHOST S5PC1XX_IRQ_VIC1(23) | ||
129 | #define IRQ_OTG S5PC1XX_IRQ_VIC1(24) | ||
130 | #define IRQ_MSM S5PC1XX_IRQ_VIC1(25) | ||
131 | #define IRQ_HSMMC0 S5PC1XX_IRQ_VIC1(26) | ||
132 | #define IRQ_HSMMC1 S5PC1XX_IRQ_VIC1(27) | ||
133 | #define IRQ_HSMMC2 S5PC1XX_IRQ_VIC1(28) | ||
134 | #define IRQ_MIPICSI S5PC1XX_IRQ_VIC1(29) | ||
135 | #define IRQ_MIPIDSI S5PC1XX_IRQ_VIC1(30) | ||
136 | |||
137 | /* | ||
138 | * VIC2: multimedia, audio, security | ||
139 | */ | ||
140 | #define IRQ_LCD0 S5PC1XX_IRQ_VIC2(0) | ||
141 | #define IRQ_LCD1 S5PC1XX_IRQ_VIC2(1) | ||
142 | #define IRQ_LCD2 S5PC1XX_IRQ_VIC2(2) | ||
143 | #define IRQ_LCD3 S5PC1XX_IRQ_VIC2(3) | ||
144 | #define IRQ_ROTATOR S5PC1XX_IRQ_VIC2(4) | ||
145 | #define IRQ_FIMC0 S5PC1XX_IRQ_VIC2(5) | ||
146 | #define IRQ_FIMC1 S5PC1XX_IRQ_VIC2(6) | ||
147 | #define IRQ_FIMC2 S5PC1XX_IRQ_VIC2(7) | ||
148 | #define IRQ_JPEG S5PC1XX_IRQ_VIC2(8) | ||
149 | #define IRQ_2D S5PC1XX_IRQ_VIC2(9) | ||
150 | #define IRQ_3D S5PC1XX_IRQ_VIC2(10) | ||
151 | #define IRQ_MIXER S5PC1XX_IRQ_VIC2(11) | ||
152 | #define IRQ_HDMI S5PC1XX_IRQ_VIC2(12) | ||
153 | #define IRQ_IIC1 S5PC1XX_IRQ_VIC2(13) | ||
154 | #define IRQ_MFC S5PC1XX_IRQ_VIC2(14) | ||
155 | #define IRQ_TVENC S5PC1XX_IRQ_VIC2(15) | ||
156 | #define IRQ_I2S0 S5PC1XX_IRQ_VIC2(16) | ||
157 | #define IRQ_I2S1 S5PC1XX_IRQ_VIC2(17) | ||
158 | #define IRQ_I2S2 S5PC1XX_IRQ_VIC2(18) | ||
159 | #define IRQ_AC97 S5PC1XX_IRQ_VIC2(19) | ||
160 | #define IRQ_PCM0 S5PC1XX_IRQ_VIC2(20) | ||
161 | #define IRQ_PCM1 S5PC1XX_IRQ_VIC2(21) | ||
162 | #define IRQ_SPDIF S5PC1XX_IRQ_VIC2(22) | ||
163 | #define IRQ_ADC S5PC1XX_IRQ_VIC2(23) | ||
164 | #define IRQ_PENDN S5PC1XX_IRQ_VIC2(24) | ||
165 | #define IRQ_TC IRQ_PENDN | ||
166 | #define IRQ_KEYPAD S5PC1XX_IRQ_VIC2(25) | ||
167 | #define IRQ_CG S5PC1XX_IRQ_VIC2(26) | ||
168 | #define IRQ_SEC S5PC1XX_IRQ_VIC2(27) | ||
169 | #define IRQ_SECRX S5PC1XX_IRQ_VIC2(28) | ||
170 | #define IRQ_SECTX S5PC1XX_IRQ_VIC2(29) | ||
171 | #define IRQ_SDMIRQ S5PC1XX_IRQ_VIC2(30) | ||
172 | #define IRQ_SDMFIQ S5PC1XX_IRQ_VIC2(31) | ||
173 | |||
174 | #define S3C_IRQ_EINT_BASE (IRQ_SDMFIQ + 1) | ||
175 | |||
176 | #define S3C_EINT(x) ((x) + S3C_IRQ_EINT_BASE) | ||
177 | #define IRQ_EINT(x) S3C_EINT(x) | ||
178 | |||
179 | #define NR_IRQS (IRQ_EINT(31)+1) | ||
180 | |||
181 | #endif /* __ASM_PLAT_S5PC1XX_IRQS_H */ | ||
182 | |||
diff --git a/arch/arm/plat-s5pc1xx/irq.c b/arch/arm/plat-s5pc1xx/irq.c new file mode 100644 index 000000000000..80d6dd942cb8 --- /dev/null +++ b/arch/arm/plat-s5pc1xx/irq.c | |||
@@ -0,0 +1,259 @@ | |||
1 | /* arch/arm/plat-s5pc1xx/irq.c | ||
2 | * | ||
3 | * Copyright 2009 Samsung Electronics Co. | ||
4 | * Byungho Min <bhmin@samsung.com> | ||
5 | * | ||
6 | * S5PC1XX - Interrupt handling | ||
7 | * | ||
8 | * Based on plat-s3c64xx/irq.c | ||
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/kernel.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/irq.h> | ||
18 | #include <linux/io.h> | ||
19 | |||
20 | #include <asm/hardware/vic.h> | ||
21 | |||
22 | #include <mach/map.h> | ||
23 | #include <plat/regs-timer.h> | ||
24 | #include <plat/cpu.h> | ||
25 | |||
26 | /* Timer interrupt handling */ | ||
27 | |||
28 | static void s3c_irq_demux_timer(unsigned int base_irq, unsigned int sub_irq) | ||
29 | { | ||
30 | generic_handle_irq(sub_irq); | ||
31 | } | ||
32 | |||
33 | static void s3c_irq_demux_timer0(unsigned int irq, struct irq_desc *desc) | ||
34 | { | ||
35 | s3c_irq_demux_timer(irq, IRQ_TIMER0); | ||
36 | } | ||
37 | |||
38 | static void s3c_irq_demux_timer1(unsigned int irq, struct irq_desc *desc) | ||
39 | { | ||
40 | s3c_irq_demux_timer(irq, IRQ_TIMER1); | ||
41 | } | ||
42 | |||
43 | static void s3c_irq_demux_timer2(unsigned int irq, struct irq_desc *desc) | ||
44 | { | ||
45 | s3c_irq_demux_timer(irq, IRQ_TIMER2); | ||
46 | } | ||
47 | |||
48 | static void s3c_irq_demux_timer3(unsigned int irq, struct irq_desc *desc) | ||
49 | { | ||
50 | s3c_irq_demux_timer(irq, IRQ_TIMER3); | ||
51 | } | ||
52 | |||
53 | static void s3c_irq_demux_timer4(unsigned int irq, struct irq_desc *desc) | ||
54 | { | ||
55 | s3c_irq_demux_timer(irq, IRQ_TIMER4); | ||
56 | } | ||
57 | |||
58 | /* We assume the IRQ_TIMER0..IRQ_TIMER4 range is continuous. */ | ||
59 | |||
60 | static void s3c_irq_timer_mask(unsigned int irq) | ||
61 | { | ||
62 | u32 reg = __raw_readl(S3C64XX_TINT_CSTAT); | ||
63 | |||
64 | reg &= 0x1f; /* mask out pending interrupts */ | ||
65 | reg &= ~(1 << (irq - IRQ_TIMER0)); | ||
66 | __raw_writel(reg, S3C64XX_TINT_CSTAT); | ||
67 | } | ||
68 | |||
69 | static void s3c_irq_timer_unmask(unsigned int irq) | ||
70 | { | ||
71 | u32 reg = __raw_readl(S3C64XX_TINT_CSTAT); | ||
72 | |||
73 | reg &= 0x1f; /* mask out pending interrupts */ | ||
74 | reg |= 1 << (irq - IRQ_TIMER0); | ||
75 | __raw_writel(reg, S3C64XX_TINT_CSTAT); | ||
76 | } | ||
77 | |||
78 | static void s3c_irq_timer_ack(unsigned int irq) | ||
79 | { | ||
80 | u32 reg = __raw_readl(S3C64XX_TINT_CSTAT); | ||
81 | |||
82 | reg &= 0x1f; | ||
83 | reg |= (1 << 5) << (irq - IRQ_TIMER0); | ||
84 | __raw_writel(reg, S3C64XX_TINT_CSTAT); | ||
85 | } | ||
86 | |||
87 | static struct irq_chip s3c_irq_timer = { | ||
88 | .name = "s3c-timer", | ||
89 | .mask = s3c_irq_timer_mask, | ||
90 | .unmask = s3c_irq_timer_unmask, | ||
91 | .ack = s3c_irq_timer_ack, | ||
92 | }; | ||
93 | |||
94 | struct uart_irq { | ||
95 | void __iomem *regs; | ||
96 | unsigned int base_irq; | ||
97 | unsigned int parent_irq; | ||
98 | }; | ||
99 | |||
100 | /* Note, we make use of the fact that the parent IRQs, IRQ_UART[0..3] | ||
101 | * are consecutive when looking up the interrupt in the demux routines. | ||
102 | */ | ||
103 | static struct uart_irq uart_irqs[] = { | ||
104 | [0] = { | ||
105 | .regs = (void *)S3C_VA_UART0, | ||
106 | .base_irq = IRQ_S3CUART_BASE0, | ||
107 | .parent_irq = IRQ_UART0, | ||
108 | }, | ||
109 | [1] = { | ||
110 | .regs = (void *)S3C_VA_UART1, | ||
111 | .base_irq = IRQ_S3CUART_BASE1, | ||
112 | .parent_irq = IRQ_UART1, | ||
113 | }, | ||
114 | [2] = { | ||
115 | .regs = (void *)S3C_VA_UART2, | ||
116 | .base_irq = IRQ_S3CUART_BASE2, | ||
117 | .parent_irq = IRQ_UART2, | ||
118 | }, | ||
119 | [3] = { | ||
120 | .regs = (void *)S3C_VA_UART3, | ||
121 | .base_irq = IRQ_S3CUART_BASE3, | ||
122 | .parent_irq = IRQ_UART3, | ||
123 | }, | ||
124 | }; | ||
125 | |||
126 | static inline void __iomem *s3c_irq_uart_base(unsigned int irq) | ||
127 | { | ||
128 | struct uart_irq *uirq = get_irq_chip_data(irq); | ||
129 | return uirq->regs; | ||
130 | } | ||
131 | |||
132 | static inline unsigned int s3c_irq_uart_bit(unsigned int irq) | ||
133 | { | ||
134 | return irq & 3; | ||
135 | } | ||
136 | |||
137 | /* UART interrupt registers, not worth adding to seperate include header */ | ||
138 | #define S3C64XX_UINTP 0x30 | ||
139 | #define S3C64XX_UINTSP 0x34 | ||
140 | #define S3C64XX_UINTM 0x38 | ||
141 | |||
142 | static void s3c_irq_uart_mask(unsigned int irq) | ||
143 | { | ||
144 | void __iomem *regs = s3c_irq_uart_base(irq); | ||
145 | unsigned int bit = s3c_irq_uart_bit(irq); | ||
146 | u32 reg; | ||
147 | |||
148 | reg = __raw_readl(regs + S3C64XX_UINTM); | ||
149 | reg |= (1 << bit); | ||
150 | __raw_writel(reg, regs + S3C64XX_UINTM); | ||
151 | } | ||
152 | |||
153 | static void s3c_irq_uart_maskack(unsigned int irq) | ||
154 | { | ||
155 | void __iomem *regs = s3c_irq_uart_base(irq); | ||
156 | unsigned int bit = s3c_irq_uart_bit(irq); | ||
157 | u32 reg; | ||
158 | |||
159 | reg = __raw_readl(regs + S3C64XX_UINTM); | ||
160 | reg |= (1 << bit); | ||
161 | __raw_writel(reg, regs + S3C64XX_UINTM); | ||
162 | __raw_writel(1 << bit, regs + S3C64XX_UINTP); | ||
163 | } | ||
164 | |||
165 | static void s3c_irq_uart_unmask(unsigned int irq) | ||
166 | { | ||
167 | void __iomem *regs = s3c_irq_uart_base(irq); | ||
168 | unsigned int bit = s3c_irq_uart_bit(irq); | ||
169 | u32 reg; | ||
170 | |||
171 | reg = __raw_readl(regs + S3C64XX_UINTM); | ||
172 | reg &= ~(1 << bit); | ||
173 | __raw_writel(reg, regs + S3C64XX_UINTM); | ||
174 | } | ||
175 | |||
176 | static void s3c_irq_uart_ack(unsigned int irq) | ||
177 | { | ||
178 | void __iomem *regs = s3c_irq_uart_base(irq); | ||
179 | unsigned int bit = s3c_irq_uart_bit(irq); | ||
180 | |||
181 | __raw_writel(1 << bit, regs + S3C64XX_UINTP); | ||
182 | } | ||
183 | |||
184 | static void s3c_irq_demux_uart(unsigned int irq, struct irq_desc *desc) | ||
185 | { | ||
186 | struct uart_irq *uirq = &uart_irqs[irq - IRQ_UART0]; | ||
187 | u32 pend = __raw_readl(uirq->regs + S3C64XX_UINTP); | ||
188 | int base = uirq->base_irq; | ||
189 | |||
190 | if (pend & (1 << 0)) | ||
191 | generic_handle_irq(base); | ||
192 | if (pend & (1 << 1)) | ||
193 | generic_handle_irq(base + 1); | ||
194 | if (pend & (1 << 2)) | ||
195 | generic_handle_irq(base + 2); | ||
196 | if (pend & (1 << 3)) | ||
197 | generic_handle_irq(base + 3); | ||
198 | } | ||
199 | |||
200 | static struct irq_chip s3c_irq_uart = { | ||
201 | .name = "s3c-uart", | ||
202 | .mask = s3c_irq_uart_mask, | ||
203 | .unmask = s3c_irq_uart_unmask, | ||
204 | .mask_ack = s3c_irq_uart_maskack, | ||
205 | .ack = s3c_irq_uart_ack, | ||
206 | }; | ||
207 | |||
208 | static void __init s5pc1xx_uart_irq(struct uart_irq *uirq) | ||
209 | { | ||
210 | void __iomem *reg_base = uirq->regs; | ||
211 | unsigned int irq; | ||
212 | int offs; | ||
213 | |||
214 | /* mask all interrupts at the start. */ | ||
215 | __raw_writel(0xf, reg_base + S3C64XX_UINTM); | ||
216 | |||
217 | for (offs = 0; offs < 3; offs++) { | ||
218 | irq = uirq->base_irq + offs; | ||
219 | |||
220 | set_irq_chip(irq, &s3c_irq_uart); | ||
221 | set_irq_chip_data(irq, uirq); | ||
222 | set_irq_handler(irq, handle_level_irq); | ||
223 | set_irq_flags(irq, IRQF_VALID); | ||
224 | } | ||
225 | |||
226 | set_irq_chained_handler(uirq->parent_irq, s3c_irq_demux_uart); | ||
227 | } | ||
228 | |||
229 | void __init s5pc1xx_init_irq(u32 *vic_valid, int num) | ||
230 | { | ||
231 | int i; | ||
232 | int uart, irq; | ||
233 | |||
234 | printk(KERN_DEBUG "%s: initialising interrupts\n", __func__); | ||
235 | |||
236 | /* initialise the pair of VICs */ | ||
237 | for (i = 0; i < num; i++) | ||
238 | vic_init((void *)S5PC1XX_VA_VIC(i), S3C_IRQ(i * S3C_IRQ_OFFSET), | ||
239 | vic_valid[i], 0); | ||
240 | |||
241 | /* add the timer sub-irqs */ | ||
242 | |||
243 | set_irq_chained_handler(IRQ_TIMER0, s3c_irq_demux_timer0); | ||
244 | set_irq_chained_handler(IRQ_TIMER1, s3c_irq_demux_timer1); | ||
245 | set_irq_chained_handler(IRQ_TIMER2, s3c_irq_demux_timer2); | ||
246 | set_irq_chained_handler(IRQ_TIMER3, s3c_irq_demux_timer3); | ||
247 | set_irq_chained_handler(IRQ_TIMER4, s3c_irq_demux_timer4); | ||
248 | |||
249 | for (irq = IRQ_TIMER0; irq <= IRQ_TIMER4; irq++) { | ||
250 | set_irq_chip(irq, &s3c_irq_timer); | ||
251 | set_irq_handler(irq, handle_level_irq); | ||
252 | set_irq_flags(irq, IRQF_VALID); | ||
253 | } | ||
254 | |||
255 | for (uart = 0; uart < ARRAY_SIZE(uart_irqs); uart++) | ||
256 | s5pc1xx_uart_irq(&uart_irqs[uart]); | ||
257 | } | ||
258 | |||
259 | |||