1/*
2 * BK Id: SCCS/s.ppc8xx_pic.c 1.13 12/01/01 17:19:48 trini
3 */
4#include <linux/config.h>
5#include <linux/stddef.h>
6#include <linux/init.h>
7#include <linux/sched.h>
8#include <linux/signal.h>
9#include <asm/irq.h>
10#include <asm/8xx_immap.h>
11#include <asm/mpc8xx.h>
12#include "ppc8xx_pic.h"
13
14/* The 8xx internal interrupt controller.  It is usually
15 * the only interrupt controller.  Some boards, like the MBX and
16 * Sandpoint have the 8259 as a secondary controller.  Depending
17 * upon the processor type, the internal controller can have as
18 * few as 16 interrups or as many as 64.  We could use  the
19 * "clear_bit()" and "set_bit()" functions like other platforms,
20 * but they are overkill for us.
21 */
22
23static void m8xx_mask_irq(unsigned int irq_nr)
24{
25	int	bit, word;
26
27	bit = irq_nr & 0x1f;
28	word = irq_nr >> 5;
29
30	ppc_cached_irq_mask[word] &= ~(1 << (31-bit));
31	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
32						ppc_cached_irq_mask[word];
33}
34
35static void m8xx_unmask_irq(unsigned int irq_nr)
36{
37	int	bit, word;
38
39	bit = irq_nr & 0x1f;
40	word = irq_nr >> 5;
41
42	ppc_cached_irq_mask[word] |= (1 << (31-bit));
43	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
44						ppc_cached_irq_mask[word];
45}
46
47static void m8xx_end_irq(unsigned int irq_nr)
48{
49	if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
50		int bit, word;
51
52		bit = irq_nr & 0x1f;
53		word = irq_nr >> 5;
54
55		ppc_cached_irq_mask[word] |= (1 << (31-bit));
56		((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
57			ppc_cached_irq_mask[word];
58	}
59}
60
61
62static void m8xx_mask_and_ack(unsigned int irq_nr)
63{
64	int	bit, word;
65
66	bit = irq_nr & 0x1f;
67	word = irq_nr >> 5;
68
69	ppc_cached_irq_mask[word] &= ~(1 << (31-bit));
70	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
71						ppc_cached_irq_mask[word];
72	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sipend = 1 << (31-bit);
73}
74
75struct hw_interrupt_type ppc8xx_pic = {
76	" 8xx SIU  ",
77	NULL,
78	NULL,
79	m8xx_unmask_irq,
80	m8xx_mask_irq,
81	m8xx_mask_and_ack,
82	m8xx_end_irq,
83	0
84};
85
86
87
88/*
89 * We either return a valid interrupt or -1 if there is nothing pending
90 */
91int
92m8xx_get_irq(struct pt_regs *regs)
93{
94	int irq;
95
96	/* For MPC8xx, read the SIVEC register and shift the bits down
97	 * to get the irq number.
98	 */
99	irq = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec >> 26;
100
101	/*
102	 * When we read the sivec without an interrupt to process, we will
103	 * get back SIU_LEVEL7.  In this case, return -1
104	 */
105	if (irq == SIU_LEVEL7)
106		return -1;
107
108	return irq;
109}
110
111/* The MBX is the only 8xx board that uses the 8259.
112*/
113#if defined(CONFIG_MBX) && defined(CONFIG_PCI)
114void mbx_i8259_action(int cpl, void *dev_id, struct pt_regs *regs)
115{
116	int bits, irq;
117
118	/* A bug in the QSpan chip causes it to give us 0xff always
119	 * when doing a character read.  So read 32 bits and shift.
120	 * This doesn't seem to return useful values anyway, but
121	 * read it to make sure things are acked.
122	 * -- Cort
123	 */
124	irq = (inl(0x508) >> 24)&0xff;
125	if ( irq != 0xff ) printk("iack %d\n", irq);
126
127	outb(0x0C, 0x20);
128	irq = inb(0x20) & 7;
129	if (irq == 2)
130	{
131		outb(0x0C, 0xA0);
132		irq = inb(0xA0);
133		irq = (irq&7) + 8;
134	}
135	bits = 1UL << irq;
136	irq += i8259_pic.irq_offset;
137	ppc_irq_dispatch_handler( regs, irq );
138}
139#endif
140
141/* Only the MBX uses the external 8259.  This allows us to catch standard
142 * drivers that may mess up the internal interrupt controllers, and also
143 * allow them to run without modification on the MBX.
144 */
145int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
146	unsigned long irqflags, const char * devname, void *dev_id)
147{
148
149#if defined(CONFIG_MBX) && defined(CONFIG_PCI)
150	irq += i8259_pic.irq_offset;
151	return (request_8xxirq(irq, handler, irqflags, devname, dev_id));
152#else
153	/*
154	 * Handle other "well-known" interrupts, but panic on unknown ones.
155	 */
156	switch (irq) {
157#ifdef	IDE0_INTERRUPT
158		case IDE0_INTERRUPT:	/* IDE0 */
159			return (request_8xxirq(irq, handler, irqflags, devname,
160						dev_id));
161#endif
162#ifdef	IDE1_INTERRUPT
163		case IDE1_INTERRUPT:	/* IDE1 */
164			return (request_8xxirq(irq, handler, irqflags, devname,
165						dev_id));
166#endif
167	default:			/* unknown IRQ -> panic */
168		panic("request_irq");
169	}
170#endif
171}
172