1 #include <linux/kernel.h>
2 #include <linux/module.h>
3 #include <linux/stddef.h>
4 #include <linux/init.h>
5 #include <linux/sched.h>
6 #include <linux/signal.h>
8 #include <linux/dma-mapping.h>
12 #include <asm/8xx_immap.h>
13 #include <asm/mpc8xx.h>
15 #include "mpc8xx_pic.h"
18 #define PIC_VEC_SPURRIOUS 15
20 extern int cpm_get_irq(struct pt_regs
*regs
);
22 static struct device_node
*mpc8xx_pic_node
;
23 static struct irq_host
*mpc8xx_pic_host
;
24 #define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
25 static unsigned long ppc_cached_irq_mask
[NR_MASK_WORDS
];
26 static sysconf8xx_t
*siu_reg
;
28 int cpm_get_irq(struct pt_regs
*regs
);
30 static void mpc8xx_unmask_irq(unsigned int virq
)
33 unsigned int irq_nr
= (unsigned int)irq_map
[virq
].hwirq
;
38 ppc_cached_irq_mask
[word
] |= (1 << (31-bit
));
39 out_be32(&siu_reg
->sc_simask
, ppc_cached_irq_mask
[word
]);
42 static void mpc8xx_mask_irq(unsigned int virq
)
45 unsigned int irq_nr
= (unsigned int)irq_map
[virq
].hwirq
;
50 ppc_cached_irq_mask
[word
] &= ~(1 << (31-bit
));
51 out_be32(&siu_reg
->sc_simask
, ppc_cached_irq_mask
[word
]);
54 static void mpc8xx_ack(unsigned int virq
)
57 unsigned int irq_nr
= (unsigned int)irq_map
[virq
].hwirq
;
60 out_be32(&siu_reg
->sc_sipend
, 1 << (31-bit
));
63 static void mpc8xx_end_irq(unsigned int virq
)
66 unsigned int irq_nr
= (unsigned int)irq_map
[virq
].hwirq
;
71 ppc_cached_irq_mask
[word
] |= (1 << (31-bit
));
72 out_be32(&siu_reg
->sc_simask
, ppc_cached_irq_mask
[word
]);
75 static int mpc8xx_set_irq_type(unsigned int virq
, unsigned int flow_type
)
77 struct irq_desc
*desc
= get_irq_desc(virq
);
79 desc
->status
&= ~(IRQ_TYPE_SENSE_MASK
| IRQ_LEVEL
);
80 desc
->status
|= flow_type
& IRQ_TYPE_SENSE_MASK
;
81 if (flow_type
& (IRQ_TYPE_LEVEL_HIGH
| IRQ_TYPE_LEVEL_LOW
))
82 desc
->status
|= IRQ_LEVEL
;
84 if (flow_type
& IRQ_TYPE_EDGE_FALLING
) {
85 irq_hw_number_t hw
= (unsigned int)irq_map
[virq
].hwirq
;
86 unsigned int siel
= in_be32(&siu_reg
->sc_siel
);
88 /* only external IRQ senses are programmable */
90 siel
|= (0x80000000 >> hw
);
91 out_be32(&siu_reg
->sc_siel
, siel
);
92 desc
->handle_irq
= handle_edge_irq
;
98 static struct irq_chip mpc8xx_pic
= {
99 .typename
= " MPC8XX SIU ",
100 .unmask
= mpc8xx_unmask_irq
,
101 .mask
= mpc8xx_mask_irq
,
103 .eoi
= mpc8xx_end_irq
,
104 .set_type
= mpc8xx_set_irq_type
,
107 unsigned int mpc8xx_get_irq(void)
111 /* For MPC8xx, read the SIVEC register and shift the bits down
112 * to get the irq number.
114 irq
= in_be32(&siu_reg
->sc_sivec
) >> 26;
116 if (irq
== PIC_VEC_SPURRIOUS
)
119 return irq_linear_revmap(mpc8xx_pic_host
, irq
);
123 static int mpc8xx_pic_host_match(struct irq_host
*h
, struct device_node
*node
)
125 return mpc8xx_pic_node
== node
;
128 static int mpc8xx_pic_host_map(struct irq_host
*h
, unsigned int virq
,
131 pr_debug("mpc8xx_pic_host_map(%d, 0x%lx)\n", virq
, hw
);
133 /* Set default irq handle */
134 set_irq_chip_and_handler(virq
, &mpc8xx_pic
, handle_level_irq
);
139 static int mpc8xx_pic_host_xlate(struct irq_host
*h
, struct device_node
*ct
,
140 u32
*intspec
, unsigned int intsize
,
141 irq_hw_number_t
*out_hwirq
, unsigned int *out_flags
)
143 static unsigned char map_pic_senses
[4] = {
144 IRQ_TYPE_EDGE_RISING
,
147 IRQ_TYPE_EDGE_FALLING
,
150 *out_hwirq
= intspec
[0];
151 if (intsize
> 1 && intspec
[1] < 4)
152 *out_flags
= map_pic_senses
[intspec
[1]];
154 *out_flags
= IRQ_TYPE_NONE
;
160 static struct irq_host_ops mpc8xx_pic_host_ops
= {
161 .match
= mpc8xx_pic_host_match
,
162 .map
= mpc8xx_pic_host_map
,
163 .xlate
= mpc8xx_pic_host_xlate
,
166 int mpc8xx_pic_init(void)
169 struct device_node
*np
= NULL
;
172 np
= of_find_node_by_type(np
, "mpc8xx-pic");
175 printk(KERN_ERR
"Could not find open-pic node\n");
179 mpc8xx_pic_node
= of_node_get(np
);
181 ret
= of_address_to_resource(np
, 0, &res
);
186 siu_reg
= (void *)ioremap(res
.start
, res
.end
- res
.start
+ 1);
190 mpc8xx_pic_host
= irq_alloc_host(IRQ_HOST_MAP_LINEAR
, 64, &mpc8xx_pic_host_ops
, 64);
191 if (mpc8xx_pic_host
== NULL
) {
192 printk(KERN_ERR
"MPC8xx PIC: failed to allocate irq host!\n");