summaryrefslogtreecommitdiffstats
path: root/arch/sh/boards/harp/irq.c
blob: 52d0ba39031b7215a1a9c62dc3af49461c6f817f (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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/* 
 * Copyright (C) 2000 David J. Mckay (david.mckay@st.com)
 *
 * May be copied or modified under the terms of the GNU General Public
 * License.  See linux/COPYING for more information.                            
 *
 * Looks after interrupts on the HARP board.
 *
 * Bases on the IPR irq system
 */

#include <linux/config.h>
#include <linux/init.h>
#include <linux/irq.h>

#include <asm/system.h>
#include <asm/io.h>
#include <asm/harp/harp.h>


#define NUM_EXTERNAL_IRQS 16

// Early versions of the STB1 Overdrive required this nasty frig
//#define INVERT_INTMASK_WRITES

static void enable_harp_irq(unsigned int irq);
static void disable_harp_irq(unsigned int irq);

/* shutdown is same as "disable" */
#define shutdown_harp_irq disable_harp_irq

static void mask_and_ack_harp(unsigned int);
static void end_harp_irq(unsigned int irq);

static unsigned int startup_harp_irq(unsigned int irq)
{
	enable_harp_irq(irq);
	return 0;		/* never anything pending */
}

static struct hw_interrupt_type harp_irq_type = {
	.typename = "Harp-IRQ",
	.startup = startup_harp_irq,
	.shutdown = shutdown_harp_irq,
	.enable = enable_harp_irq,
	.disable = disable_harp_irq,
	.ack = mask_and_ack_harp,
	.end = end_harp_irq
};

static void disable_harp_irq(unsigned int irq)
{
	unsigned val, flags;
	unsigned maskReg;
	unsigned mask;
	int pri;

	if (irq < 0 || irq >= NUM_EXTERNAL_IRQS)
		return;

	pri = 15 - irq;

	if (pri < 8) {
		maskReg = EPLD_INTMASK0;
	} else {
		maskReg = EPLD_INTMASK1;
		pri -= 8;
	}

	local_irq_save(flags);
	mask = ctrl_inl(maskReg);
	mask &= (~(1 << pri));
#if defined(INVERT_INTMASK_WRITES)
	mask ^= 0xff;
#endif
	ctrl_outl(mask, maskReg);
	local_irq_restore(flags);
}

static void enable_harp_irq(unsigned int irq)
{
	unsigned flags;
	unsigned maskReg;
	unsigned mask;
	int pri;

	if (irq < 0 || irq >= NUM_EXTERNAL_IRQS)
		return;

	pri = 15 - irq;

	if (pri < 8) {
		maskReg = EPLD_INTMASK0;
	} else {
		maskReg = EPLD_INTMASK1;
		pri -= 8;
	}

	local_irq_save(flags);
	mask = ctrl_inl(maskReg);


	mask |= (1 << pri);

#if defined(INVERT_INTMASK_WRITES)
	mask ^= 0xff;
#endif
	ctrl_outl(mask, maskReg);

	local_irq_restore(flags);
}

/* This functions sets the desired irq handler to be an overdrive type */
static void __init make_harp_irq(unsigned int irq)
{
	disable_irq_nosync(irq);
	irq_desc[irq].handler = &harp_irq_type;
	disable_harp_irq(irq);
}

static void mask_and_ack_harp(unsigned int irq)
{
	disable_harp_irq(irq);
}

static void end_harp_irq(unsigned int irq)
{
	enable_harp_irq(irq);
}

void __init init_harp_irq(void)
{
	int i;

#if !defined(INVERT_INTMASK_WRITES)
	// On the harp these are set to enable an interrupt
	ctrl_outl(0x00, EPLD_INTMASK0);
	ctrl_outl(0x00, EPLD_INTMASK1);
#else
	// On the Overdrive the data is inverted before being stored in the reg
	ctrl_outl(0xff, EPLD_INTMASK0);
	ctrl_outl(0xff, EPLD_INTMASK1);
#endif

	for (i = 0; i < NUM_EXTERNAL_IRQS; i++) {
		make_harp_irq(i);
	}
}