2 * IBM Onboard Peripheral Bus Interrupt Controller
4 * Copyright 2010 Jack Miller, IBM Corporation.
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version.
12 #include <linux/interrupt.h>
14 #include <linux/irq.h>
16 #include <linux/slab.h>
17 #include <linux/time.h>
18 #include <linux/of_address.h>
19 #include <linux/of_irq.h>
21 #include <asm/reg_a2.h>
24 #define OPB_NR_IRQS 32
26 #define OPB_MLSASIER 0x04 /* MLS Accumulated Status IER */
27 #define OPB_MLSIR 0x50 /* MLS Interrupt Register */
28 #define OPB_MLSIER 0x54 /* MLS Interrupt Enable Register */
29 #define OPB_MLSIPR 0x58 /* MLS Interrupt Polarity Register */
30 #define OPB_MLSIIR 0x5c /* MLS Interrupt Inputs Register */
32 static int opb_index = 0;
35 struct irq_domain *host;
41 static u32 opb_in(struct opb_pic *opb, int offset)
43 return in_be32(opb->regs + offset);
46 static void opb_out(struct opb_pic *opb, int offset, u32 val)
48 out_be32(opb->regs + offset, val);
51 static void opb_unmask_irq(struct irq_data *d)
58 bitset = (1 << (31 - irqd_to_hwirq(d)));
60 spin_lock_irqsave(&opb->lock, flags);
62 ier = opb_in(opb, OPB_MLSIER);
63 opb_out(opb, OPB_MLSIER, ier | bitset);
64 ier = opb_in(opb, OPB_MLSIER);
66 spin_unlock_irqrestore(&opb->lock, flags);
69 static void opb_mask_irq(struct irq_data *d)
76 mask = ~(1 << (31 - irqd_to_hwirq(d)));
78 spin_lock_irqsave(&opb->lock, flags);
80 ier = opb_in(opb, OPB_MLSIER);
81 opb_out(opb, OPB_MLSIER, ier & mask);
82 ier = opb_in(opb, OPB_MLSIER); // Flush posted writes
84 spin_unlock_irqrestore(&opb->lock, flags);
87 static void opb_ack_irq(struct irq_data *d)
94 bitset = (1 << (31 - irqd_to_hwirq(d)));
96 spin_lock_irqsave(&opb->lock, flags);
98 opb_out(opb, OPB_MLSIR, bitset);
99 opb_in(opb, OPB_MLSIR); // Flush posted writes
101 spin_unlock_irqrestore(&opb->lock, flags);
104 static void opb_mask_ack_irq(struct irq_data *d)
112 bitset = (1 << (31 - irqd_to_hwirq(d)));
114 spin_lock_irqsave(&opb->lock, flags);
116 ier = opb_in(opb, OPB_MLSIER);
117 opb_out(opb, OPB_MLSIER, ier & ~bitset);
118 ier = opb_in(opb, OPB_MLSIER); // Flush posted writes
120 opb_out(opb, OPB_MLSIR, bitset);
121 ir = opb_in(opb, OPB_MLSIR); // Flush posted writes
123 spin_unlock_irqrestore(&opb->lock, flags);
126 static int opb_set_irq_type(struct irq_data *d, unsigned int flow)
130 int invert, ipr, mask, bit;
134 /* The only information we're interested in in the type is whether it's
135 * a high or low trigger. For high triggered interrupts, the polarity
136 * set for it in the MLS Interrupt Polarity Register is 0, for low
137 * interrupts it's 1 so that the proper input in the MLS Interrupt Input
138 * Register is interrupted as asserting the interrupt. */
145 case IRQ_TYPE_LEVEL_HIGH:
149 case IRQ_TYPE_LEVEL_LOW:
157 bit = (1 << (31 - irqd_to_hwirq(d)));
160 spin_lock_irqsave(&opb->lock, flags);
162 ipr = opb_in(opb, OPB_MLSIPR);
163 ipr = (ipr & mask) | (invert ? bit : 0);
164 opb_out(opb, OPB_MLSIPR, ipr);
165 ipr = opb_in(opb, OPB_MLSIPR); // Flush posted writes
167 spin_unlock_irqrestore(&opb->lock, flags);
169 /* Record the type in the interrupt descriptor */
170 irqd_set_trigger_type(d, flow);
175 static struct irq_chip opb_irq_chip = {
177 .irq_mask = opb_mask_irq,
178 .irq_unmask = opb_unmask_irq,
179 .irq_mask_ack = opb_mask_ack_irq,
180 .irq_ack = opb_ack_irq,
181 .irq_set_type = opb_set_irq_type
184 static int opb_host_map(struct irq_domain *host, unsigned int virq,
185 irq_hw_number_t hwirq)
189 opb = host->host_data;
191 /* Most of the important stuff is handled by the generic host code, like
192 * the lookup, so just attach some info to the virtual irq */
194 irq_set_chip_data(virq, opb);
195 irq_set_chip_and_handler(virq, &opb_irq_chip, handle_level_irq);
196 irq_set_irq_type(virq, IRQ_TYPE_NONE);
201 static const struct irq_domain_ops opb_host_ops = {
203 .xlate = irq_domain_xlate_twocell,
206 irqreturn_t opb_irq_handler(int irq, void *private)
209 u32 ir, src, subvirq;
211 opb = (struct opb_pic *) private;
213 /* Read the OPB MLS Interrupt Register for
214 * asserted interrupts */
215 ir = opb_in(opb, OPB_MLSIR);
220 /* Get 1 - 32 source, *NOT* bit */
223 /* Translate from the OPB's conception of interrupt number to
224 * Linux's virtual IRQ */
226 subvirq = irq_linear_revmap(opb->host, src);
228 generic_handle_irq(subvirq);
229 } while ((ir = opb_in(opb, OPB_MLSIR)));
234 struct opb_pic *opb_pic_init_one(struct device_node *dn)
239 if (of_address_to_resource(dn, 0, &res)) {
240 printk(KERN_ERR "opb: Couldn't translate resource\n");
244 opb = kzalloc(sizeof(struct opb_pic), GFP_KERNEL);
246 printk(KERN_ERR "opb: Failed to allocate opb struct!\n");
250 /* Get access to the OPB MMIO registers */
251 opb->regs = ioremap(res.start + 0x10000, 0x1000);
253 printk(KERN_ERR "opb: Failed to allocate register space!\n");
257 /* Allocate an irq domain so that Linux knows that despite only
258 * having one interrupt to issue, we're the controller for multiple
259 * hardware IRQs, so later we can lookup their virtual IRQs. */
261 opb->host = irq_domain_add_linear(dn, OPB_NR_IRQS, &opb_host_ops, opb);
263 printk(KERN_ERR "opb: Failed to allocate IRQ host!\n");
267 opb->index = opb_index++;
268 spin_lock_init(&opb->lock);
270 /* Disable all interrupts by default */
271 opb_out(opb, OPB_MLSASIER, 0);
272 opb_out(opb, OPB_MLSIER, 0);
274 /* ACK any interrupts left by FW */
275 opb_out(opb, OPB_MLSIR, 0xFFFFFFFF);
286 void __init opb_pic_init(void)
288 struct device_node *dn;
293 /* Call init_one for each OPB device */
294 for_each_compatible_node(dn, NULL, "ibm,opb") {
296 /* Fill in an OPB struct */
297 opb = opb_pic_init_one(dn);
299 printk(KERN_WARNING "opb: Failed to init node, skipped!\n");
303 /* Map / get opb's hardware virtual irq */
304 virq = irq_of_parse_and_map(dn, 0);
306 printk("opb: irq_op_parse_and_map failed!\n");
310 /* Attach opb interrupt handler to new virtual IRQ */
311 rc = request_irq(virq, opb_irq_handler, IRQF_NO_THREAD,
312 "OPB LS Cascade", opb);
314 printk("opb: request_irq failed: %d\n", rc);
318 printk("OPB%d init with %d IRQs at %p\n", opb->index,
319 OPB_NR_IRQS, opb->regs);