summaryrefslogtreecommitdiff
path: root/arch/ppc/platforms/adir_pic.c
blob: 9947cba52af55dd60b6512bffb9ca303481ddd30 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/*
 * arch/ppc/platforms/adir_pic.c
 *
 * Interrupt controller support for SBS Adirondack
 *
 * By Michael Sokolov <msokolov@ivan.Harhan.ORG>
 * based on the K2 and SCM versions by Matt Porter <mporter@mvista.com>
 */

#include <linux/stddef.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/pci.h>
#include <linux/interrupt.h>

#include <asm/io.h>
#include <asm/i8259.h>
#include "adir.h"

static void adir_onboard_pic_enable(unsigned int irq);
static void adir_onboard_pic_disable(unsigned int irq);

__init static void
adir_onboard_pic_init(void)
{
	volatile u_short *maskreg = (volatile u_short *) ADIR_PROCA_INT_MASK;

	/* Disable all Adirondack onboard interrupts */
	out_be16(maskreg, 0xFFFF);
}

static int
adir_onboard_pic_get_irq(void)
{
	volatile u_short *statreg = (volatile u_short *) ADIR_PROCA_INT_STAT;
	int irq;
	u_short int_status, int_test;

	int_status = in_be16(statreg);
	for (irq = 0, int_test = 1; irq < 16; irq++, int_test <<= 1) {
		if (int_status & int_test)
			break;
	}

	if (irq == 16)
		return -1;

	return (irq+16);
}

static void
adir_onboard_pic_enable(unsigned int irq)
{
	volatile u_short *maskreg = (volatile u_short *) ADIR_PROCA_INT_MASK;

	/* Change irq to Adirondack onboard native value */
	irq -= 16;

	/* Enable requested irq number */
	out_be16(maskreg, in_be16(maskreg) & ~(1 << irq));
}

static void
adir_onboard_pic_disable(unsigned int irq)
{
	volatile u_short *maskreg = (volatile u_short *) ADIR_PROCA_INT_MASK;

	/* Change irq to Adirondack onboard native value */
	irq -= 16;

	/* Disable requested irq number */
	out_be16(maskreg, in_be16(maskreg) | (1 << irq));
}

static struct hw_interrupt_type adir_onboard_pic = {
	" ADIR PIC ",
	NULL,
	NULL,
	adir_onboard_pic_enable,		/* unmask */
	adir_onboard_pic_disable,		/* mask */
	adir_onboard_pic_disable,		/* mask and ack */
	NULL,
	NULL
};

static struct irqaction noop_action = {
	.handler	= no_action,
	.flags          = SA_INTERRUPT,
	.mask           = CPU_MASK_NONE,
	.name           = "82c59 primary cascade",
};

/*
 * Linux interrupt values are assigned as follows:
 *
 * 	0-15		VT82C686 8259 interrupts
 * 	16-31		Adirondack CPLD interrupts
 */
__init void
adir_init_IRQ(void)
{
	int	i;

	/* Initialize the cascaded 8259's on the VT82C686 */
	for (i=0; i<16; i++)
		irq_desc[i].handler = &i8259_pic;
	i8259_init(NULL);

	/* Initialize Adirondack CPLD PIC and enable 8259 interrupt cascade */
	for (i=16; i<32; i++)
		irq_desc[i].handler = &adir_onboard_pic;
	adir_onboard_pic_init();

	/* Enable 8259 interrupt cascade */
	setup_irq(ADIR_IRQ_VT82C686_INTR, &noop_action);
}

int
adir_get_irq(struct pt_regs *regs)
{
	int	irq;

	if ((irq = adir_onboard_pic_get_irq()) < 0)
		return irq;

	if (irq == ADIR_IRQ_VT82C686_INTR)
		irq = i8259_irq(regs);

	return irq;
}