aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-rpc/irq.c
blob: 803aeb126f0e9f9d6eaa061e26d7b21df6cc51b6 (plain) (blame)
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
// SPDX-License-Identifier: GPL-2.0
#include <linux/init.h>
#include <linux/list.h>
#include <linux/io.h>

#include <asm/mach/irq.h>
#include <asm/hardware/iomd.h>
#include <asm/irq.h>
#include <asm/fiq.h>

// These are offsets from the stat register for each IRQ bank
#define STAT	0x00
#define REQ	0x04
#define CLR	0x04
#define MASK	0x08

static void __iomem *iomd_get_base(struct irq_data *d)
{
	void *cd = irq_data_get_irq_chip_data(d);

	return (void __iomem *)(unsigned long)cd;
}

static void iomd_set_base_mask(unsigned int irq, void __iomem *base, u32 mask)
{
	struct irq_data *d = irq_get_irq_data(irq);

	d->mask = mask;
	irq_set_chip_data(irq, (void *)(unsigned long)base);
}

static void iomd_irq_mask_ack(struct irq_data *d)
{
	void __iomem *base = iomd_get_base(d);
	unsigned int val, mask = d->mask;

	val = readb(base + MASK);
	writeb(val & ~mask, base + MASK);
	writeb(mask, base + CLR);
}

static void iomd_irq_mask(struct irq_data *d)
{
	void __iomem *base = iomd_get_base(d);
	unsigned int val, mask = d->mask;

	val = readb(base + MASK);
	writeb(val & ~mask, base + MASK);
}

static void iomd_irq_unmask(struct irq_data *d)
{
	void __iomem *base = iomd_get_base(d);
	unsigned int val, mask = d->mask;

	val = readb(base + MASK);
	writeb(val | mask, base + MASK);
}

static struct irq_chip iomd_chip_clr = {
	.irq_mask_ack	= iomd_irq_mask_ack,
	.irq_mask	= iomd_irq_mask,
	.irq_unmask	= iomd_irq_unmask,
};

static struct irq_chip iomd_chip_noclr = {
	.irq_mask	= iomd_irq_mask,
	.irq_unmask	= iomd_irq_unmask,
};

extern unsigned char rpc_default_fiq_start, rpc_default_fiq_end;

void __init rpc_init_irq(void)
{
	unsigned int irq, clr, set;

	iomd_writeb(0, IOMD_IRQMASKA);
	iomd_writeb(0, IOMD_IRQMASKB);
	iomd_writeb(0, IOMD_FIQMASK);
	iomd_writeb(0, IOMD_DMAMASK);

	set_fiq_handler(&rpc_default_fiq_start,
		&rpc_default_fiq_end - &rpc_default_fiq_start);

	for (irq = 0; irq < NR_IRQS; irq++) {
		clr = IRQ_NOREQUEST;
		set = 0;

		if (irq <= 6 || (irq >= 9 && irq <= 15))
			clr |= IRQ_NOPROBE;

		if (irq == 21 || (irq >= 16 && irq <= 19) ||
		    irq == IRQ_KEYBOARDTX)
			set |= IRQ_NOAUTOEN;

		switch (irq) {
		case 0 ... 7:
			irq_set_chip_and_handler(irq, &iomd_chip_clr,
						 handle_level_irq);
			irq_modify_status(irq, clr, set);
			iomd_set_base_mask(irq, IOMD_BASE + IOMD_IRQSTATA,
					   BIT(irq));
			break;

		case 8 ... 15:
			irq_set_chip_and_handler(irq, &iomd_chip_noclr,
						 handle_level_irq);
			irq_modify_status(irq, clr, set);
			iomd_set_base_mask(irq, IOMD_BASE + IOMD_IRQSTATB,
					   BIT(irq - 8));
			break;

		case 16 ... 21:
			irq_set_chip_and_handler(irq, &iomd_chip_noclr,
						 handle_level_irq);
			irq_modify_status(irq, clr, set);
			iomd_set_base_mask(irq, IOMD_BASE + IOMD_DMASTAT,
					   BIT(irq - 16));
			break;

		case 64 ... 71:
			irq_set_chip(irq, &iomd_chip_noclr);
			irq_modify_status(irq, clr, set);
			iomd_set_base_mask(irq, IOMD_BASE + IOMD_FIQSTAT,
					   BIT(irq - 64));
			break;
		}
	}

	init_FIQ(FIQ_START);
}