Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/mips/loongson32/common/irq.c
26481 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* Copyright (c) 2011 Zhang, Keguang <[email protected]>
4
*/
5
6
#include <linux/interrupt.h>
7
#include <linux/irq.h>
8
#include <asm/irq_cpu.h>
9
10
#include <loongson1.h>
11
#include <irq.h>
12
13
#define LS1X_INTC_REG(n, x) \
14
((void __iomem *)KSEG1ADDR(LS1X_INTC_BASE + (n * 0x18) + (x)))
15
16
#define LS1X_INTC_INTISR(n) LS1X_INTC_REG(n, 0x0)
17
#define LS1X_INTC_INTIEN(n) LS1X_INTC_REG(n, 0x4)
18
#define LS1X_INTC_INTSET(n) LS1X_INTC_REG(n, 0x8)
19
#define LS1X_INTC_INTCLR(n) LS1X_INTC_REG(n, 0xc)
20
#define LS1X_INTC_INTPOL(n) LS1X_INTC_REG(n, 0x10)
21
#define LS1X_INTC_INTEDGE(n) LS1X_INTC_REG(n, 0x14)
22
23
static void ls1x_irq_ack(struct irq_data *d)
24
{
25
unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f;
26
unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5;
27
28
__raw_writel(__raw_readl(LS1X_INTC_INTCLR(n))
29
| (1 << bit), LS1X_INTC_INTCLR(n));
30
}
31
32
static void ls1x_irq_mask(struct irq_data *d)
33
{
34
unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f;
35
unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5;
36
37
__raw_writel(__raw_readl(LS1X_INTC_INTIEN(n))
38
& ~(1 << bit), LS1X_INTC_INTIEN(n));
39
}
40
41
static void ls1x_irq_mask_ack(struct irq_data *d)
42
{
43
unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f;
44
unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5;
45
46
__raw_writel(__raw_readl(LS1X_INTC_INTIEN(n))
47
& ~(1 << bit), LS1X_INTC_INTIEN(n));
48
__raw_writel(__raw_readl(LS1X_INTC_INTCLR(n))
49
| (1 << bit), LS1X_INTC_INTCLR(n));
50
}
51
52
static void ls1x_irq_unmask(struct irq_data *d)
53
{
54
unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f;
55
unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5;
56
57
__raw_writel(__raw_readl(LS1X_INTC_INTIEN(n))
58
| (1 << bit), LS1X_INTC_INTIEN(n));
59
}
60
61
static int ls1x_irq_settype(struct irq_data *d, unsigned int type)
62
{
63
unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f;
64
unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5;
65
66
switch (type) {
67
case IRQ_TYPE_LEVEL_HIGH:
68
__raw_writel(__raw_readl(LS1X_INTC_INTPOL(n))
69
| (1 << bit), LS1X_INTC_INTPOL(n));
70
__raw_writel(__raw_readl(LS1X_INTC_INTEDGE(n))
71
& ~(1 << bit), LS1X_INTC_INTEDGE(n));
72
break;
73
case IRQ_TYPE_LEVEL_LOW:
74
__raw_writel(__raw_readl(LS1X_INTC_INTPOL(n))
75
& ~(1 << bit), LS1X_INTC_INTPOL(n));
76
__raw_writel(__raw_readl(LS1X_INTC_INTEDGE(n))
77
& ~(1 << bit), LS1X_INTC_INTEDGE(n));
78
break;
79
case IRQ_TYPE_EDGE_RISING:
80
__raw_writel(__raw_readl(LS1X_INTC_INTPOL(n))
81
| (1 << bit), LS1X_INTC_INTPOL(n));
82
__raw_writel(__raw_readl(LS1X_INTC_INTEDGE(n))
83
| (1 << bit), LS1X_INTC_INTEDGE(n));
84
break;
85
case IRQ_TYPE_EDGE_FALLING:
86
__raw_writel(__raw_readl(LS1X_INTC_INTPOL(n))
87
& ~(1 << bit), LS1X_INTC_INTPOL(n));
88
__raw_writel(__raw_readl(LS1X_INTC_INTEDGE(n))
89
| (1 << bit), LS1X_INTC_INTEDGE(n));
90
break;
91
case IRQ_TYPE_EDGE_BOTH:
92
__raw_writel(__raw_readl(LS1X_INTC_INTPOL(n))
93
& ~(1 << bit), LS1X_INTC_INTPOL(n));
94
__raw_writel(__raw_readl(LS1X_INTC_INTEDGE(n))
95
| (1 << bit), LS1X_INTC_INTEDGE(n));
96
break;
97
case IRQ_TYPE_NONE:
98
break;
99
default:
100
return -EINVAL;
101
}
102
103
return 0;
104
}
105
106
static struct irq_chip ls1x_irq_chip = {
107
.name = "LS1X-INTC",
108
.irq_ack = ls1x_irq_ack,
109
.irq_mask = ls1x_irq_mask,
110
.irq_mask_ack = ls1x_irq_mask_ack,
111
.irq_unmask = ls1x_irq_unmask,
112
.irq_set_type = ls1x_irq_settype,
113
};
114
115
static void ls1x_irq_dispatch(int n)
116
{
117
u32 int_status, irq;
118
119
/* Get pending sources, masked by current enables */
120
int_status = __raw_readl(LS1X_INTC_INTISR(n)) &
121
__raw_readl(LS1X_INTC_INTIEN(n));
122
123
if (int_status) {
124
irq = LS1X_IRQ(n, __ffs(int_status));
125
do_IRQ(irq);
126
}
127
}
128
129
asmlinkage void plat_irq_dispatch(void)
130
{
131
unsigned int pending;
132
133
pending = read_c0_cause() & read_c0_status() & ST0_IM;
134
135
if (pending & CAUSEF_IP7)
136
do_IRQ(TIMER_IRQ);
137
else if (pending & CAUSEF_IP2)
138
ls1x_irq_dispatch(0); /* INT0 */
139
else if (pending & CAUSEF_IP3)
140
ls1x_irq_dispatch(1); /* INT1 */
141
else if (pending & CAUSEF_IP4)
142
ls1x_irq_dispatch(2); /* INT2 */
143
else if (pending & CAUSEF_IP5)
144
ls1x_irq_dispatch(3); /* INT3 */
145
else if (pending & CAUSEF_IP6)
146
ls1x_irq_dispatch(4); /* INT4 */
147
else
148
spurious_interrupt();
149
150
}
151
152
static void __init ls1x_irq_init(int base)
153
{
154
int n;
155
156
/* Disable interrupts and clear pending,
157
* setup all IRQs as high level triggered
158
*/
159
for (n = 0; n < INTN; n++) {
160
__raw_writel(0x0, LS1X_INTC_INTIEN(n));
161
__raw_writel(0xffffffff, LS1X_INTC_INTCLR(n));
162
__raw_writel(0xffffffff, LS1X_INTC_INTPOL(n));
163
/* set DMA0, DMA1 and DMA2 to edge trigger */
164
__raw_writel(n ? 0x0 : 0xe000, LS1X_INTC_INTEDGE(n));
165
}
166
167
168
for (n = base; n < NR_IRQS; n++) {
169
irq_set_chip_and_handler(n, &ls1x_irq_chip,
170
handle_level_irq);
171
}
172
173
if (request_irq(INT0_IRQ, no_action, IRQF_NO_THREAD, "cascade", NULL))
174
pr_err("Failed to request irq %d (cascade)\n", INT0_IRQ);
175
if (request_irq(INT1_IRQ, no_action, IRQF_NO_THREAD, "cascade", NULL))
176
pr_err("Failed to request irq %d (cascade)\n", INT1_IRQ);
177
if (request_irq(INT2_IRQ, no_action, IRQF_NO_THREAD, "cascade", NULL))
178
pr_err("Failed to request irq %d (cascade)\n", INT2_IRQ);
179
if (request_irq(INT3_IRQ, no_action, IRQF_NO_THREAD, "cascade", NULL))
180
pr_err("Failed to request irq %d (cascade)\n", INT3_IRQ);
181
#if defined(CONFIG_LOONGSON1_LS1C)
182
if (request_irq(INT4_IRQ, no_action, IRQF_NO_THREAD, "cascade", NULL))
183
pr_err("Failed to request irq %d (cascade)\n", INT4_IRQ);
184
#endif
185
}
186
187
void __init arch_init_irq(void)
188
{
189
mips_cpu_irq_init();
190
ls1x_irq_init(LS1X_IRQ_BASE);
191
}
192
193