diff options
Diffstat (limited to 'arch/arm/plat-versatile/fpga-irq.c')
-rw-r--r-- | arch/arm/plat-versatile/fpga-irq.c | 210 |
1 files changed, 0 insertions, 210 deletions
diff --git a/arch/arm/plat-versatile/fpga-irq.c b/arch/arm/plat-versatile/fpga-irq.c deleted file mode 100644 index 091ae1030045..000000000000 --- a/arch/arm/plat-versatile/fpga-irq.c +++ /dev/null | |||
@@ -1,210 +0,0 @@ | |||
1 | /* | ||
2 | * Support for Versatile FPGA-based IRQ controllers | ||
3 | */ | ||
4 | #include <linux/irq.h> | ||
5 | #include <linux/io.h> | ||
6 | #include <linux/irqdomain.h> | ||
7 | #include <linux/module.h> | ||
8 | #include <linux/of.h> | ||
9 | #include <linux/of_address.h> | ||
10 | |||
11 | #include <asm/exception.h> | ||
12 | #include <asm/mach/irq.h> | ||
13 | #include <plat/fpga-irq.h> | ||
14 | |||
15 | #define IRQ_STATUS 0x00 | ||
16 | #define IRQ_RAW_STATUS 0x04 | ||
17 | #define IRQ_ENABLE_SET 0x08 | ||
18 | #define IRQ_ENABLE_CLEAR 0x0c | ||
19 | #define INT_SOFT_SET 0x10 | ||
20 | #define INT_SOFT_CLEAR 0x14 | ||
21 | #define FIQ_STATUS 0x20 | ||
22 | #define FIQ_RAW_STATUS 0x24 | ||
23 | #define FIQ_ENABLE 0x28 | ||
24 | #define FIQ_ENABLE_SET 0x28 | ||
25 | #define FIQ_ENABLE_CLEAR 0x2C | ||
26 | |||
27 | /** | ||
28 | * struct fpga_irq_data - irq data container for the FPGA IRQ controller | ||
29 | * @base: memory offset in virtual memory | ||
30 | * @chip: chip container for this instance | ||
31 | * @domain: IRQ domain for this instance | ||
32 | * @valid: mask for valid IRQs on this controller | ||
33 | * @used_irqs: number of active IRQs on this controller | ||
34 | */ | ||
35 | struct fpga_irq_data { | ||
36 | void __iomem *base; | ||
37 | struct irq_chip chip; | ||
38 | u32 valid; | ||
39 | struct irq_domain *domain; | ||
40 | u8 used_irqs; | ||
41 | }; | ||
42 | |||
43 | /* we cannot allocate memory when the controllers are initially registered */ | ||
44 | static struct fpga_irq_data fpga_irq_devices[CONFIG_PLAT_VERSATILE_FPGA_IRQ_NR]; | ||
45 | static int fpga_irq_id; | ||
46 | |||
47 | static void fpga_irq_mask(struct irq_data *d) | ||
48 | { | ||
49 | struct fpga_irq_data *f = irq_data_get_irq_chip_data(d); | ||
50 | u32 mask = 1 << d->hwirq; | ||
51 | |||
52 | writel(mask, f->base + IRQ_ENABLE_CLEAR); | ||
53 | } | ||
54 | |||
55 | static void fpga_irq_unmask(struct irq_data *d) | ||
56 | { | ||
57 | struct fpga_irq_data *f = irq_data_get_irq_chip_data(d); | ||
58 | u32 mask = 1 << d->hwirq; | ||
59 | |||
60 | writel(mask, f->base + IRQ_ENABLE_SET); | ||
61 | } | ||
62 | |||
63 | static void fpga_irq_handle(unsigned int irq, struct irq_desc *desc) | ||
64 | { | ||
65 | struct fpga_irq_data *f = irq_desc_get_handler_data(desc); | ||
66 | u32 status = readl(f->base + IRQ_STATUS); | ||
67 | |||
68 | if (status == 0) { | ||
69 | do_bad_IRQ(irq, desc); | ||
70 | return; | ||
71 | } | ||
72 | |||
73 | do { | ||
74 | irq = ffs(status) - 1; | ||
75 | status &= ~(1 << irq); | ||
76 | generic_handle_irq(irq_find_mapping(f->domain, irq)); | ||
77 | } while (status); | ||
78 | } | ||
79 | |||
80 | /* | ||
81 | * Handle each interrupt in a single FPGA IRQ controller. Returns non-zero | ||
82 | * if we've handled at least one interrupt. This does a single read of the | ||
83 | * status register and handles all interrupts in order from LSB first. | ||
84 | */ | ||
85 | static int handle_one_fpga(struct fpga_irq_data *f, struct pt_regs *regs) | ||
86 | { | ||
87 | int handled = 0; | ||
88 | int irq; | ||
89 | u32 status; | ||
90 | |||
91 | while ((status = readl(f->base + IRQ_STATUS))) { | ||
92 | irq = ffs(status) - 1; | ||
93 | handle_IRQ(irq_find_mapping(f->domain, irq), regs); | ||
94 | handled = 1; | ||
95 | } | ||
96 | |||
97 | return handled; | ||
98 | } | ||
99 | |||
100 | /* | ||
101 | * Keep iterating over all registered FPGA IRQ controllers until there are | ||
102 | * no pending interrupts. | ||
103 | */ | ||
104 | asmlinkage void __exception_irq_entry fpga_handle_irq(struct pt_regs *regs) | ||
105 | { | ||
106 | int i, handled; | ||
107 | |||
108 | do { | ||
109 | for (i = 0, handled = 0; i < fpga_irq_id; ++i) | ||
110 | handled |= handle_one_fpga(&fpga_irq_devices[i], regs); | ||
111 | } while (handled); | ||
112 | } | ||
113 | |||
114 | static int fpga_irqdomain_map(struct irq_domain *d, unsigned int irq, | ||
115 | irq_hw_number_t hwirq) | ||
116 | { | ||
117 | struct fpga_irq_data *f = d->host_data; | ||
118 | |||
119 | /* Skip invalid IRQs, only register handlers for the real ones */ | ||
120 | if (!(f->valid & (1 << hwirq))) | ||
121 | return -ENOTSUPP; | ||
122 | irq_set_chip_data(irq, f); | ||
123 | irq_set_chip_and_handler(irq, &f->chip, | ||
124 | handle_level_irq); | ||
125 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | ||
126 | f->used_irqs++; | ||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | static struct irq_domain_ops fpga_irqdomain_ops = { | ||
131 | .map = fpga_irqdomain_map, | ||
132 | .xlate = irq_domain_xlate_onetwocell, | ||
133 | }; | ||
134 | |||
135 | static __init struct fpga_irq_data * | ||
136 | fpga_irq_prep_struct(void __iomem *base, const char *name, u32 valid) { | ||
137 | struct fpga_irq_data *f; | ||
138 | |||
139 | if (fpga_irq_id >= ARRAY_SIZE(fpga_irq_devices)) { | ||
140 | printk(KERN_ERR "%s: too few FPGA IRQ controllers, increase CONFIG_PLAT_VERSATILE_FPGA_IRQ_NR\n", __func__); | ||
141 | return NULL; | ||
142 | } | ||
143 | f = &fpga_irq_devices[fpga_irq_id]; | ||
144 | f->base = base; | ||
145 | f->chip.name = name; | ||
146 | f->chip.irq_ack = fpga_irq_mask; | ||
147 | f->chip.irq_mask = fpga_irq_mask; | ||
148 | f->chip.irq_unmask = fpga_irq_unmask; | ||
149 | f->valid = valid; | ||
150 | fpga_irq_id++; | ||
151 | |||
152 | return f; | ||
153 | } | ||
154 | |||
155 | void __init fpga_irq_init(void __iomem *base, const char *name, int irq_start, | ||
156 | int parent_irq, u32 valid, struct device_node *node) | ||
157 | { | ||
158 | struct fpga_irq_data *f; | ||
159 | |||
160 | f = fpga_irq_prep_struct(base, name, valid); | ||
161 | if (!f) | ||
162 | return; | ||
163 | |||
164 | if (parent_irq != -1) { | ||
165 | irq_set_handler_data(parent_irq, f); | ||
166 | irq_set_chained_handler(parent_irq, fpga_irq_handle); | ||
167 | } | ||
168 | |||
169 | f->domain = irq_domain_add_legacy(node, fls(valid), irq_start, 0, | ||
170 | &fpga_irqdomain_ops, f); | ||
171 | pr_info("FPGA IRQ chip %d \"%s\" @ %p, %u irqs\n", | ||
172 | fpga_irq_id, name, base, f->used_irqs); | ||
173 | } | ||
174 | |||
175 | #ifdef CONFIG_OF | ||
176 | int __init fpga_irq_of_init(struct device_node *node, | ||
177 | struct device_node *parent) | ||
178 | { | ||
179 | struct fpga_irq_data *f; | ||
180 | void __iomem *base; | ||
181 | u32 clear_mask; | ||
182 | u32 valid_mask; | ||
183 | |||
184 | if (WARN_ON(!node)) | ||
185 | return -ENODEV; | ||
186 | |||
187 | base = of_iomap(node, 0); | ||
188 | WARN(!base, "unable to map fpga irq registers\n"); | ||
189 | |||
190 | if (of_property_read_u32(node, "clear-mask", &clear_mask)) | ||
191 | clear_mask = 0; | ||
192 | |||
193 | if (of_property_read_u32(node, "valid-mask", &valid_mask)) | ||
194 | valid_mask = 0; | ||
195 | |||
196 | f = fpga_irq_prep_struct(base, node->name, valid_mask); | ||
197 | if (!f) | ||
198 | return -ENOMEM; | ||
199 | |||
200 | writel(clear_mask, base + IRQ_ENABLE_CLEAR); | ||
201 | writel(clear_mask, base + FIQ_ENABLE_CLEAR); | ||
202 | |||
203 | f->domain = irq_domain_add_linear(node, fls(valid_mask), &fpga_irqdomain_ops, f); | ||
204 | f->used_irqs = hweight32(valid_mask); | ||
205 | |||
206 | pr_info("FPGA IRQ chip %d \"%s\" @ %p, %u irqs\n", | ||
207 | fpga_irq_id, node->name, base, f->used_irqs); | ||
208 | return 0; | ||
209 | } | ||
210 | #endif | ||