Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/mips/kernel/irq-msc01.c
10817 views
1
/*
2
* This program is free software; you can redistribute it and/or modify it
3
* under the terms of the GNU General Public License as published by the
4
* Free Software Foundation; either version 2 of the License, or (at your
5
* option) any later version.
6
*
7
* Copyright (c) 2004 MIPS Inc
8
* Author: [email protected]
9
*
10
* Copyright (C) 2004, 06 Ralf Baechle <[email protected]>
11
*/
12
#include <linux/module.h>
13
#include <linux/interrupt.h>
14
#include <linux/kernel.h>
15
#include <linux/sched.h>
16
#include <linux/kernel_stat.h>
17
#include <asm/io.h>
18
#include <asm/irq.h>
19
#include <asm/msc01_ic.h>
20
#include <asm/traps.h>
21
22
static unsigned long _icctrl_msc;
23
#define MSC01_IC_REG_BASE _icctrl_msc
24
25
#define MSCIC_WRITE(reg, data) do { *(volatile u32 *)(reg) = data; } while (0)
26
#define MSCIC_READ(reg, data) do { data = *(volatile u32 *)(reg); } while (0)
27
28
static unsigned int irq_base;
29
30
/* mask off an interrupt */
31
static inline void mask_msc_irq(struct irq_data *d)
32
{
33
unsigned int irq = d->irq;
34
35
if (irq < (irq_base + 32))
36
MSCIC_WRITE(MSC01_IC_DISL, 1<<(irq - irq_base));
37
else
38
MSCIC_WRITE(MSC01_IC_DISH, 1<<(irq - irq_base - 32));
39
}
40
41
/* unmask an interrupt */
42
static inline void unmask_msc_irq(struct irq_data *d)
43
{
44
unsigned int irq = d->irq;
45
46
if (irq < (irq_base + 32))
47
MSCIC_WRITE(MSC01_IC_ENAL, 1<<(irq - irq_base));
48
else
49
MSCIC_WRITE(MSC01_IC_ENAH, 1<<(irq - irq_base - 32));
50
}
51
52
/*
53
* Masks and ACKs an IRQ
54
*/
55
static void level_mask_and_ack_msc_irq(struct irq_data *d)
56
{
57
unsigned int irq = d->irq;
58
59
mask_msc_irq(d);
60
if (!cpu_has_veic)
61
MSCIC_WRITE(MSC01_IC_EOI, 0);
62
/* This actually needs to be a call into platform code */
63
smtc_im_ack_irq(irq);
64
}
65
66
/*
67
* Masks and ACKs an IRQ
68
*/
69
static void edge_mask_and_ack_msc_irq(struct irq_data *d)
70
{
71
unsigned int irq = d->irq;
72
73
mask_msc_irq(d);
74
if (!cpu_has_veic)
75
MSCIC_WRITE(MSC01_IC_EOI, 0);
76
else {
77
u32 r;
78
MSCIC_READ(MSC01_IC_SUP+irq*8, r);
79
MSCIC_WRITE(MSC01_IC_SUP+irq*8, r | ~MSC01_IC_SUP_EDGE_BIT);
80
MSCIC_WRITE(MSC01_IC_SUP+irq*8, r);
81
}
82
smtc_im_ack_irq(irq);
83
}
84
85
/*
86
* Interrupt handler for interrupts coming from SOC-it.
87
*/
88
void ll_msc_irq(void)
89
{
90
unsigned int irq;
91
92
/* read the interrupt vector register */
93
MSCIC_READ(MSC01_IC_VEC, irq);
94
if (irq < 64)
95
do_IRQ(irq + irq_base);
96
else {
97
/* Ignore spurious interrupt */
98
}
99
}
100
101
static void msc_bind_eic_interrupt(int irq, int set)
102
{
103
MSCIC_WRITE(MSC01_IC_RAMW,
104
(irq<<MSC01_IC_RAMW_ADDR_SHF) | (set<<MSC01_IC_RAMW_DATA_SHF));
105
}
106
107
static struct irq_chip msc_levelirq_type = {
108
.name = "SOC-it-Level",
109
.irq_ack = level_mask_and_ack_msc_irq,
110
.irq_mask = mask_msc_irq,
111
.irq_mask_ack = level_mask_and_ack_msc_irq,
112
.irq_unmask = unmask_msc_irq,
113
.irq_eoi = unmask_msc_irq,
114
};
115
116
static struct irq_chip msc_edgeirq_type = {
117
.name = "SOC-it-Edge",
118
.irq_ack = edge_mask_and_ack_msc_irq,
119
.irq_mask = mask_msc_irq,
120
.irq_mask_ack = edge_mask_and_ack_msc_irq,
121
.irq_unmask = unmask_msc_irq,
122
.irq_eoi = unmask_msc_irq,
123
};
124
125
126
void __init init_msc_irqs(unsigned long icubase, unsigned int irqbase, msc_irqmap_t *imp, int nirq)
127
{
128
_icctrl_msc = (unsigned long) ioremap(icubase, 0x40000);
129
130
/* Reset interrupt controller - initialises all registers to 0 */
131
MSCIC_WRITE(MSC01_IC_RST, MSC01_IC_RST_RST_BIT);
132
133
board_bind_eic_interrupt = &msc_bind_eic_interrupt;
134
135
for (; nirq >= 0; nirq--, imp++) {
136
int n = imp->im_irq;
137
138
switch (imp->im_type) {
139
case MSC01_IRQ_EDGE:
140
irq_set_chip_and_handler_name(irqbase + n,
141
&msc_edgeirq_type,
142
handle_edge_irq,
143
"edge");
144
if (cpu_has_veic)
145
MSCIC_WRITE(MSC01_IC_SUP+n*8, MSC01_IC_SUP_EDGE_BIT);
146
else
147
MSCIC_WRITE(MSC01_IC_SUP+n*8, MSC01_IC_SUP_EDGE_BIT | imp->im_lvl);
148
break;
149
case MSC01_IRQ_LEVEL:
150
irq_set_chip_and_handler_name(irqbase + n,
151
&msc_levelirq_type,
152
handle_level_irq,
153
"level");
154
if (cpu_has_veic)
155
MSCIC_WRITE(MSC01_IC_SUP+n*8, 0);
156
else
157
MSCIC_WRITE(MSC01_IC_SUP+n*8, imp->im_lvl);
158
}
159
}
160
161
irq_base = irqbase;
162
163
MSCIC_WRITE(MSC01_IC_GENA, MSC01_IC_GENA_GENA_BIT); /* Enable interrupt generation */
164
165
}
166
167