1 #include <linux/kernel.h>
2 #include <linux/stddef.h>
3 #include <linux/init.h>
4 #include <linux/sched.h>
5 #include <linux/signal.h>
7 #include <linux/dma-mapping.h>
11 #include <asm/8xx_immap.h>
13 #include "mpc8xx_pic.h"
16 #define PIC_VEC_SPURRIOUS 15
18 extern int cpm_get_irq(struct pt_regs
*regs
);
20 static struct irq_domain
*mpc8xx_pic_host
;
21 static unsigned long mpc8xx_cached_irq_mask
;
22 static sysconf8xx_t __iomem
*siu_reg
;
24 static inline unsigned long mpc8xx_irqd_to_bit(struct irq_data
*d
)
26 return 0x80000000 >> irqd_to_hwirq(d
);
29 static void mpc8xx_unmask_irq(struct irq_data
*d
)
31 mpc8xx_cached_irq_mask
|= mpc8xx_irqd_to_bit(d
);
32 out_be32(&siu_reg
->sc_simask
, mpc8xx_cached_irq_mask
);
35 static void mpc8xx_mask_irq(struct irq_data
*d
)
37 mpc8xx_cached_irq_mask
&= ~mpc8xx_irqd_to_bit(d
);
38 out_be32(&siu_reg
->sc_simask
, mpc8xx_cached_irq_mask
);
41 static void mpc8xx_ack(struct irq_data
*d
)
43 out_be32(&siu_reg
->sc_sipend
, mpc8xx_irqd_to_bit(d
));
46 static void mpc8xx_end_irq(struct irq_data
*d
)
48 mpc8xx_cached_irq_mask
|= mpc8xx_irqd_to_bit(d
);
49 out_be32(&siu_reg
->sc_simask
, mpc8xx_cached_irq_mask
);
52 static int mpc8xx_set_irq_type(struct irq_data
*d
, unsigned int flow_type
)
54 /* only external IRQ senses are programmable */
55 if ((flow_type
& IRQ_TYPE_EDGE_FALLING
) && !(irqd_to_hwirq(d
) & 1)) {
56 unsigned int siel
= in_be32(&siu_reg
->sc_siel
);
57 siel
|= mpc8xx_irqd_to_bit(d
);
58 out_be32(&siu_reg
->sc_siel
, siel
);
59 __irq_set_handler_locked(d
->irq
, handle_edge_irq
);
64 static struct irq_chip mpc8xx_pic
= {
66 .irq_unmask
= mpc8xx_unmask_irq
,
67 .irq_mask
= mpc8xx_mask_irq
,
68 .irq_ack
= mpc8xx_ack
,
69 .irq_eoi
= mpc8xx_end_irq
,
70 .irq_set_type
= mpc8xx_set_irq_type
,
73 unsigned int mpc8xx_get_irq(void)
77 /* For MPC8xx, read the SIVEC register and shift the bits down
78 * to get the irq number.
80 irq
= in_be32(&siu_reg
->sc_sivec
) >> 26;
82 if (irq
== PIC_VEC_SPURRIOUS
)
85 return irq_linear_revmap(mpc8xx_pic_host
, irq
);
89 static int mpc8xx_pic_host_map(struct irq_domain
*h
, unsigned int virq
,
92 pr_debug("mpc8xx_pic_host_map(%d, 0x%lx)\n", virq
, hw
);
94 /* Set default irq handle */
95 irq_set_chip_and_handler(virq
, &mpc8xx_pic
, handle_level_irq
);
100 static int mpc8xx_pic_host_xlate(struct irq_domain
*h
, struct device_node
*ct
,
101 const u32
*intspec
, unsigned int intsize
,
102 irq_hw_number_t
*out_hwirq
, unsigned int *out_flags
)
104 static unsigned char map_pic_senses
[4] = {
105 IRQ_TYPE_EDGE_RISING
,
108 IRQ_TYPE_EDGE_FALLING
,
111 if (intspec
[0] > 0x1f)
114 *out_hwirq
= intspec
[0];
115 if (intsize
> 1 && intspec
[1] < 4)
116 *out_flags
= map_pic_senses
[intspec
[1]];
118 *out_flags
= IRQ_TYPE_NONE
;
124 static struct irq_domain_ops mpc8xx_pic_host_ops
= {
125 .map
= mpc8xx_pic_host_map
,
126 .xlate
= mpc8xx_pic_host_xlate
,
129 int mpc8xx_pic_init(void)
132 struct device_node
*np
;
135 np
= of_find_compatible_node(NULL
, NULL
, "fsl,pq1-pic");
137 np
= of_find_node_by_type(NULL
, "mpc8xx-pic");
139 printk(KERN_ERR
"Could not find fsl,pq1-pic node\n");
143 ret
= of_address_to_resource(np
, 0, &res
);
147 siu_reg
= ioremap(res
.start
, resource_size(&res
));
148 if (siu_reg
== NULL
) {
153 mpc8xx_pic_host
= irq_domain_add_linear(np
, 64, &mpc8xx_pic_host_ops
, NULL
);
154 if (mpc8xx_pic_host
== NULL
) {
155 printk(KERN_ERR
"MPC8xx PIC: failed to allocate irq host!\n");