diff options
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/mach-davinci/Kconfig | 3 | ||||
-rw-r--r-- | arch/arm/mach-davinci/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-davinci/cp_intc.c | 161 | ||||
-rw-r--r-- | arch/arm/mach-davinci/include/mach/cp_intc.h | 57 |
4 files changed, 222 insertions, 0 deletions
diff --git a/arch/arm/mach-davinci/Kconfig b/arch/arm/mach-davinci/Kconfig index a9c78bc72b84..56cd03f908e2 100644 --- a/arch/arm/mach-davinci/Kconfig +++ b/arch/arm/mach-davinci/Kconfig | |||
@@ -1,5 +1,8 @@ | |||
1 | if ARCH_DAVINCI | 1 | if ARCH_DAVINCI |
2 | 2 | ||
3 | config CP_INTC | ||
4 | bool | ||
5 | |||
3 | menu "TI DaVinci Implementations" | 6 | menu "TI DaVinci Implementations" |
4 | 7 | ||
5 | comment "DaVinci Core Type" | 8 | comment "DaVinci Core Type" |
diff --git a/arch/arm/mach-davinci/Makefile b/arch/arm/mach-davinci/Makefile index 1674661942f3..9a696ae60fca 100644 --- a/arch/arm/mach-davinci/Makefile +++ b/arch/arm/mach-davinci/Makefile | |||
@@ -8,6 +8,7 @@ obj-y := time.o irq.o clock.o serial.o io.o id.o psc.o \ | |||
8 | gpio.o devices.o dma.o usb.o | 8 | gpio.o devices.o dma.o usb.o |
9 | 9 | ||
10 | obj-$(CONFIG_DAVINCI_MUX) += mux.o | 10 | obj-$(CONFIG_DAVINCI_MUX) += mux.o |
11 | obj-$(CONFIG_CP_INTC) += cp_intc.o | ||
11 | 12 | ||
12 | # Chip specific | 13 | # Chip specific |
13 | obj-$(CONFIG_ARCH_DAVINCI_DM644x) += dm644x.o | 14 | obj-$(CONFIG_ARCH_DAVINCI_DM644x) += dm644x.o |
diff --git a/arch/arm/mach-davinci/cp_intc.c b/arch/arm/mach-davinci/cp_intc.c new file mode 100644 index 000000000000..96c8e97a7deb --- /dev/null +++ b/arch/arm/mach-davinci/cp_intc.c | |||
@@ -0,0 +1,161 @@ | |||
1 | /* | ||
2 | * TI Common Platform Interrupt Controller (cp_intc) driver | ||
3 | * | ||
4 | * Author: Steve Chen <schen@mvista.com> | ||
5 | * Copyright (C) 2008-2009, MontaVista Software, Inc. <source@mvista.com> | ||
6 | * | ||
7 | * This file is licensed under the terms of the GNU General Public License | ||
8 | * version 2. This program is licensed "as is" without any warranty of any | ||
9 | * kind, whether express or implied. | ||
10 | */ | ||
11 | |||
12 | #include <linux/init.h> | ||
13 | #include <linux/sched.h> | ||
14 | #include <linux/interrupt.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/irq.h> | ||
17 | #include <linux/io.h> | ||
18 | |||
19 | #include <mach/cp_intc.h> | ||
20 | |||
21 | static void __iomem *cp_intc_base; | ||
22 | |||
23 | static inline unsigned int cp_intc_read(unsigned offset) | ||
24 | { | ||
25 | return __raw_readl(cp_intc_base + offset); | ||
26 | } | ||
27 | |||
28 | static inline void cp_intc_write(unsigned long value, unsigned offset) | ||
29 | { | ||
30 | __raw_writel(value, cp_intc_base + offset); | ||
31 | } | ||
32 | |||
33 | static void cp_intc_ack_irq(unsigned int irq) | ||
34 | { | ||
35 | cp_intc_write(irq, CP_INTC_SYS_STAT_IDX_CLR); | ||
36 | } | ||
37 | |||
38 | /* Disable interrupt */ | ||
39 | static void cp_intc_mask_irq(unsigned int irq) | ||
40 | { | ||
41 | /* XXX don't know why we need to disable nIRQ here... */ | ||
42 | cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_CLR); | ||
43 | cp_intc_write(irq, CP_INTC_SYS_ENABLE_IDX_CLR); | ||
44 | cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_SET); | ||
45 | } | ||
46 | |||
47 | /* Enable interrupt */ | ||
48 | static void cp_intc_unmask_irq(unsigned int irq) | ||
49 | { | ||
50 | cp_intc_write(irq, CP_INTC_SYS_ENABLE_IDX_SET); | ||
51 | } | ||
52 | |||
53 | static int cp_intc_set_irq_type(unsigned int irq, unsigned int flow_type) | ||
54 | { | ||
55 | unsigned reg = BIT_WORD(irq); | ||
56 | unsigned mask = BIT_MASK(irq); | ||
57 | unsigned polarity = cp_intc_read(CP_INTC_SYS_POLARITY(reg)); | ||
58 | unsigned type = cp_intc_read(CP_INTC_SYS_TYPE(reg)); | ||
59 | |||
60 | switch (flow_type) { | ||
61 | case IRQ_TYPE_EDGE_RISING: | ||
62 | polarity |= mask; | ||
63 | type |= mask; | ||
64 | break; | ||
65 | case IRQ_TYPE_EDGE_FALLING: | ||
66 | polarity &= ~mask; | ||
67 | type |= mask; | ||
68 | break; | ||
69 | case IRQ_TYPE_LEVEL_HIGH: | ||
70 | polarity |= mask; | ||
71 | type &= ~mask; | ||
72 | break; | ||
73 | case IRQ_TYPE_LEVEL_LOW: | ||
74 | polarity &= ~mask; | ||
75 | type &= ~mask; | ||
76 | break; | ||
77 | default: | ||
78 | return -EINVAL; | ||
79 | } | ||
80 | |||
81 | cp_intc_write(polarity, CP_INTC_SYS_POLARITY(reg)); | ||
82 | cp_intc_write(type, CP_INTC_SYS_TYPE(reg)); | ||
83 | |||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | static struct irq_chip cp_intc_irq_chip = { | ||
88 | .name = "cp_intc", | ||
89 | .ack = cp_intc_ack_irq, | ||
90 | .mask = cp_intc_mask_irq, | ||
91 | .unmask = cp_intc_unmask_irq, | ||
92 | .set_type = cp_intc_set_irq_type, | ||
93 | }; | ||
94 | |||
95 | void __init cp_intc_init(void __iomem *base, unsigned short num_irq, | ||
96 | u8 *irq_prio) | ||
97 | { | ||
98 | unsigned num_reg = BITS_TO_LONGS(num_irq); | ||
99 | int i; | ||
100 | |||
101 | cp_intc_base = base; | ||
102 | |||
103 | cp_intc_write(0, CP_INTC_GLOBAL_ENABLE); | ||
104 | |||
105 | /* Disable all host interrupts */ | ||
106 | cp_intc_write(0, CP_INTC_HOST_ENABLE(0)); | ||
107 | |||
108 | /* Disable system interrupts */ | ||
109 | for (i = 0; i < num_reg; i++) | ||
110 | cp_intc_write(~0, CP_INTC_SYS_ENABLE_CLR(i)); | ||
111 | |||
112 | /* Set to normal mode, no nesting, no priority hold */ | ||
113 | cp_intc_write(0, CP_INTC_CTRL); | ||
114 | cp_intc_write(0, CP_INTC_HOST_CTRL); | ||
115 | |||
116 | /* Clear system interrupt status */ | ||
117 | for (i = 0; i < num_reg; i++) | ||
118 | cp_intc_write(~0, CP_INTC_SYS_STAT_CLR(i)); | ||
119 | |||
120 | /* Enable nIRQ (what about nFIQ?) */ | ||
121 | cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_SET); | ||
122 | |||
123 | /* | ||
124 | * Priority is determined by host channel: lower channel number has | ||
125 | * higher priority i.e. channel 0 has highest priority and channel 31 | ||
126 | * had the lowest priority. | ||
127 | */ | ||
128 | num_reg = (num_irq + 3) >> 2; /* 4 channels per register */ | ||
129 | if (irq_prio) { | ||
130 | unsigned j, k; | ||
131 | u32 val; | ||
132 | |||
133 | for (k = i = 0; i < num_reg; i++) { | ||
134 | for (val = j = 0; j < 4; j++, k++) { | ||
135 | val >>= 8; | ||
136 | if (k < num_irq) | ||
137 | val |= irq_prio[k] << 24; | ||
138 | } | ||
139 | |||
140 | cp_intc_write(val, CP_INTC_CHAN_MAP(i)); | ||
141 | } | ||
142 | } else { | ||
143 | /* | ||
144 | * Default everything to channel 15 if priority not specified. | ||
145 | * Note that channel 0-1 are mapped to nFIQ and channels 2-31 | ||
146 | * are mapped to nIRQ. | ||
147 | */ | ||
148 | for (i = 0; i < num_reg; i++) | ||
149 | cp_intc_write(0x0f0f0f0f, CP_INTC_CHAN_MAP(i)); | ||
150 | } | ||
151 | |||
152 | /* Set up genirq dispatching for cp_intc */ | ||
153 | for (i = 0; i < num_irq; i++) { | ||
154 | set_irq_chip(i, &cp_intc_irq_chip); | ||
155 | set_irq_flags(i, IRQF_VALID | IRQF_PROBE); | ||
156 | set_irq_handler(i, handle_edge_irq); | ||
157 | } | ||
158 | |||
159 | /* Enable global interrupt */ | ||
160 | cp_intc_write(1, CP_INTC_GLOBAL_ENABLE); | ||
161 | } | ||
diff --git a/arch/arm/mach-davinci/include/mach/cp_intc.h b/arch/arm/mach-davinci/include/mach/cp_intc.h new file mode 100644 index 000000000000..c4d27eec8064 --- /dev/null +++ b/arch/arm/mach-davinci/include/mach/cp_intc.h | |||
@@ -0,0 +1,57 @@ | |||
1 | /* | ||
2 | * TI Common Platform Interrupt Controller (cp_intc) definitions | ||
3 | * | ||
4 | * Author: Steve Chen <schen@mvista.com> | ||
5 | * Copyright (C) 2008-2009, MontaVista Software, Inc. <source@mvista.com> | ||
6 | * | ||
7 | * This file is licensed under the terms of the GNU General Public License | ||
8 | * version 2. This program is licensed "as is" without any warranty of any | ||
9 | * kind, whether express or implied. | ||
10 | */ | ||
11 | #ifndef __ASM_HARDWARE_CP_INTC_H | ||
12 | #define __ASM_HARDWARE_CP_INTC_H | ||
13 | |||
14 | #define CP_INTC_REV 0x00 | ||
15 | #define CP_INTC_CTRL 0x04 | ||
16 | #define CP_INTC_HOST_CTRL 0x0C | ||
17 | #define CP_INTC_GLOBAL_ENABLE 0x10 | ||
18 | #define CP_INTC_GLOBAL_NESTING_LEVEL 0x1C | ||
19 | #define CP_INTC_SYS_STAT_IDX_SET 0x20 | ||
20 | #define CP_INTC_SYS_STAT_IDX_CLR 0x24 | ||
21 | #define CP_INTC_SYS_ENABLE_IDX_SET 0x28 | ||
22 | #define CP_INTC_SYS_ENABLE_IDX_CLR 0x2C | ||
23 | #define CP_INTC_GLOBAL_WAKEUP_ENABLE 0x30 | ||
24 | #define CP_INTC_HOST_ENABLE_IDX_SET 0x34 | ||
25 | #define CP_INTC_HOST_ENABLE_IDX_CLR 0x38 | ||
26 | #define CP_INTC_PACING_PRESCALE 0x40 | ||
27 | #define CP_INTC_VECTOR_BASE 0x50 | ||
28 | #define CP_INTC_VECTOR_SIZE 0x54 | ||
29 | #define CP_INTC_VECTOR_NULL 0x58 | ||
30 | #define CP_INTC_PRIO_IDX 0x80 | ||
31 | #define CP_INTC_PRIO_VECTOR 0x84 | ||
32 | #define CP_INTC_SECURE_ENABLE 0x90 | ||
33 | #define CP_INTC_SECURE_PRIO_IDX 0x94 | ||
34 | #define CP_INTC_PACING_PARAM(n) (0x0100 + (n << 4)) | ||
35 | #define CP_INTC_PACING_DEC(n) (0x0104 + (n << 4)) | ||
36 | #define CP_INTC_PACING_MAP(n) (0x0108 + (n << 4)) | ||
37 | #define CP_INTC_SYS_RAW_STAT(n) (0x0200 + (n << 2)) | ||
38 | #define CP_INTC_SYS_STAT_CLR(n) (0x0280 + (n << 2)) | ||
39 | #define CP_INTC_SYS_ENABLE_SET(n) (0x0300 + (n << 2)) | ||
40 | #define CP_INTC_SYS_ENABLE_CLR(n) (0x0380 + (n << 2)) | ||
41 | #define CP_INTC_CHAN_MAP(n) (0x0400 + (n << 2)) | ||
42 | #define CP_INTC_HOST_MAP(n) (0x0800 + (n << 2)) | ||
43 | #define CP_INTC_HOST_PRIO_IDX(n) (0x0900 + (n << 2)) | ||
44 | #define CP_INTC_SYS_POLARITY(n) (0x0D00 + (n << 2)) | ||
45 | #define CP_INTC_SYS_TYPE(n) (0x0D80 + (n << 2)) | ||
46 | #define CP_INTC_WAKEUP_ENABLE(n) (0x0E00 + (n << 2)) | ||
47 | #define CP_INTC_DEBUG_SELECT(n) (0x0F00 + (n << 2)) | ||
48 | #define CP_INTC_SYS_SECURE_ENABLE(n) (0x1000 + (n << 2)) | ||
49 | #define CP_INTC_HOST_NESTING_LEVEL(n) (0x1100 + (n << 2)) | ||
50 | #define CP_INTC_HOST_ENABLE(n) (0x1500 + (n << 2)) | ||
51 | #define CP_INTC_HOST_PRIO_VECTOR(n) (0x1600 + (n << 2)) | ||
52 | #define CP_INTC_VECTOR_ADDR(n) (0x2000 + (n << 2)) | ||
53 | |||
54 | void __init cp_intc_init(void __iomem *base, unsigned short num_irq, | ||
55 | u8 *irq_prio); | ||
56 | |||
57 | #endif /* __ASM_HARDWARE_CP_INTC_H */ | ||