Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/arm/nvidia/tegra_lic.c
39483 views
1
/*-
2
* Copyright (c) 2016 Michal Meloun <[email protected]>
3
* All rights reserved.
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
7
* are met:
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
13
*
14
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
* SUCH DAMAGE.
25
*/
26
27
#include <sys/cdefs.h>
28
/*
29
* Local interrupt controller driver for Tegra SoCs.
30
*/
31
#include <sys/param.h>
32
#include <sys/module.h>
33
#include <sys/systm.h>
34
#include <sys/bus.h>
35
#include <sys/conf.h>
36
#include <sys/kernel.h>
37
#include <sys/rman.h>
38
39
#include <machine/bus.h>
40
#include <machine/intr.h>
41
#include <machine/resource.h>
42
43
#include <dev/ofw/ofw_bus.h>
44
#include <dev/ofw/ofw_bus_subr.h>
45
46
#include "pic_if.h"
47
48
#define LIC_VIRQ_CPU 0x00
49
#define LIC_VIRQ_COP 0x04
50
#define LIC_VFRQ_CPU 0x08
51
#define LIC_VFRQ_COP 0x0c
52
#define LIC_ISR 0x10
53
#define LIC_FIR 0x14
54
#define LIC_FIR_SET 0x18
55
#define LIC_FIR_CLR 0x1c
56
#define LIC_CPU_IER 0x20
57
#define LIC_CPU_IER_SET 0x24
58
#define LIC_CPU_IER_CLR 0x28
59
#define LIC_CPU_IEP_CLASS 0x2C
60
#define LIC_COP_IER 0x30
61
#define LIC_COP_IER_SET 0x34
62
#define LIC_COP_IER_CLR 0x38
63
#define LIC_COP_IEP_CLASS 0x3c
64
65
#define WR4(_sc, _b, _r, _v) bus_write_4((_sc)->mem_res[_b], (_r), (_v))
66
#define RD4(_sc, _b, _r) bus_read_4((_sc)->mem_res[_b], (_r))
67
68
static struct resource_spec lic_spec[] = {
69
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
70
{ SYS_RES_MEMORY, 1, RF_ACTIVE },
71
{ SYS_RES_MEMORY, 2, RF_ACTIVE },
72
{ SYS_RES_MEMORY, 3, RF_ACTIVE },
73
{ SYS_RES_MEMORY, 4, RF_ACTIVE },
74
{ -1, 0 }
75
};
76
77
static struct ofw_compat_data compat_data[] = {
78
{"nvidia,tegra124-ictlr", 1},
79
{"nvidia,tegra210-ictlr", 1},
80
{NULL, 0}
81
};
82
83
struct tegra_lic_sc {
84
device_t dev;
85
struct resource *mem_res[nitems(lic_spec)];
86
device_t parent;
87
};
88
89
static int
90
tegra_lic_activate_intr(device_t dev, struct intr_irqsrc *isrc,
91
struct resource *res, struct intr_map_data *data)
92
{
93
struct tegra_lic_sc *sc = device_get_softc(dev);
94
95
return (PIC_ACTIVATE_INTR(sc->parent, isrc, res, data));
96
}
97
98
static void
99
tegra_lic_disable_intr(device_t dev, struct intr_irqsrc *isrc)
100
{
101
struct tegra_lic_sc *sc = device_get_softc(dev);
102
103
PIC_DISABLE_INTR(sc->parent, isrc);
104
}
105
106
static void
107
tegra_lic_enable_intr(device_t dev, struct intr_irqsrc *isrc)
108
{
109
struct tegra_lic_sc *sc = device_get_softc(dev);
110
111
PIC_ENABLE_INTR(sc->parent, isrc);
112
}
113
114
static int
115
tegra_lic_map_intr(device_t dev, struct intr_map_data *data,
116
struct intr_irqsrc **isrcp)
117
{
118
struct tegra_lic_sc *sc = device_get_softc(dev);
119
120
return (PIC_MAP_INTR(sc->parent, data, isrcp));
121
}
122
123
static int
124
tegra_lic_deactivate_intr(device_t dev, struct intr_irqsrc *isrc,
125
struct resource *res, struct intr_map_data *data)
126
{
127
struct tegra_lic_sc *sc = device_get_softc(dev);
128
129
return (PIC_DEACTIVATE_INTR(sc->parent, isrc, res, data));
130
}
131
132
static int
133
tegra_lic_setup_intr(device_t dev, struct intr_irqsrc *isrc,
134
struct resource *res, struct intr_map_data *data)
135
{
136
struct tegra_lic_sc *sc = device_get_softc(dev);
137
138
return (PIC_SETUP_INTR(sc->parent, isrc, res, data));
139
}
140
141
static int
142
tegra_lic_teardown_intr(device_t dev, struct intr_irqsrc *isrc,
143
struct resource *res, struct intr_map_data *data)
144
{
145
struct tegra_lic_sc *sc = device_get_softc(dev);
146
147
return (PIC_TEARDOWN_INTR(sc->parent, isrc, res, data));
148
}
149
150
static void
151
tegra_lic_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
152
{
153
struct tegra_lic_sc *sc = device_get_softc(dev);
154
155
PIC_PRE_ITHREAD(sc->parent, isrc);
156
}
157
158
static void
159
tegra_lic_post_ithread(device_t dev, struct intr_irqsrc *isrc)
160
{
161
struct tegra_lic_sc *sc = device_get_softc(dev);
162
163
PIC_POST_ITHREAD(sc->parent, isrc);
164
}
165
166
static void
167
tegra_lic_post_filter(device_t dev, struct intr_irqsrc *isrc)
168
{
169
struct tegra_lic_sc *sc = device_get_softc(dev);
170
171
PIC_POST_FILTER(sc->parent, isrc);
172
}
173
174
#ifdef SMP
175
static int
176
tegra_lic_bind_intr(device_t dev, struct intr_irqsrc *isrc)
177
{
178
struct tegra_lic_sc *sc = device_get_softc(dev);
179
180
return (PIC_BIND_INTR(sc->parent, isrc));
181
}
182
#endif
183
184
static int
185
tegra_lic_probe(device_t dev)
186
{
187
if (!ofw_bus_status_okay(dev))
188
return (ENXIO);
189
190
if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
191
return (ENXIO);
192
193
return (BUS_PROBE_DEFAULT);
194
}
195
196
static int
197
tegra_lic_attach(device_t dev)
198
{
199
struct tegra_lic_sc *sc;
200
phandle_t node;
201
phandle_t parent_xref;
202
int i, rv;
203
204
sc = device_get_softc(dev);
205
sc->dev = dev;
206
node = ofw_bus_get_node(dev);
207
208
rv = OF_getencprop(node, "interrupt-parent", &parent_xref,
209
sizeof(parent_xref));
210
if (rv <= 0) {
211
device_printf(dev, "Cannot read parent node property\n");
212
goto fail;
213
}
214
sc->parent = OF_device_from_xref(parent_xref);
215
if (sc->parent == NULL) {
216
device_printf(dev, "Cannott find parent controller\n");
217
goto fail;
218
}
219
220
if (bus_alloc_resources(dev, lic_spec, sc->mem_res)) {
221
device_printf(dev, "Cannott allocate resources\n");
222
goto fail;
223
}
224
225
/* Disable all interrupts, route all to irq */
226
for (i = 0; i < nitems(lic_spec); i++) {
227
if (sc->mem_res[i] == NULL)
228
continue;
229
WR4(sc, i, LIC_CPU_IER_CLR, 0xFFFFFFFF);
230
WR4(sc, i, LIC_CPU_IEP_CLASS, 0);
231
}
232
233
if (intr_pic_register(dev, OF_xref_from_node(node)) == NULL) {
234
device_printf(dev, "Cannot register PIC\n");
235
goto fail;
236
}
237
return (0);
238
239
fail:
240
bus_release_resources(dev, lic_spec, sc->mem_res);
241
return (ENXIO);
242
}
243
244
static int
245
tegra_lic_detach(device_t dev)
246
{
247
struct tegra_lic_sc *sc;
248
int i;
249
250
sc = device_get_softc(dev);
251
for (i = 0; i < nitems(lic_spec); i++) {
252
if (sc->mem_res[i] == NULL)
253
continue;
254
bus_release_resource(dev, SYS_RES_MEMORY, i,
255
sc->mem_res[i]);
256
}
257
return (0);
258
}
259
260
static device_method_t tegra_lic_methods[] = {
261
DEVMETHOD(device_probe, tegra_lic_probe),
262
DEVMETHOD(device_attach, tegra_lic_attach),
263
DEVMETHOD(device_detach, tegra_lic_detach),
264
265
/* Interrupt controller interface */
266
DEVMETHOD(pic_activate_intr, tegra_lic_activate_intr),
267
DEVMETHOD(pic_disable_intr, tegra_lic_disable_intr),
268
DEVMETHOD(pic_enable_intr, tegra_lic_enable_intr),
269
DEVMETHOD(pic_map_intr, tegra_lic_map_intr),
270
DEVMETHOD(pic_deactivate_intr, tegra_lic_deactivate_intr),
271
DEVMETHOD(pic_setup_intr, tegra_lic_setup_intr),
272
DEVMETHOD(pic_teardown_intr, tegra_lic_teardown_intr),
273
DEVMETHOD(pic_pre_ithread, tegra_lic_pre_ithread),
274
DEVMETHOD(pic_post_ithread, tegra_lic_post_ithread),
275
DEVMETHOD(pic_post_filter, tegra_lic_post_filter),
276
#ifdef SMP
277
DEVMETHOD(pic_bind_intr, tegra_lic_bind_intr),
278
#endif
279
DEVMETHOD_END
280
};
281
282
static DEFINE_CLASS_0(lic, tegra_lic_driver, tegra_lic_methods,
283
sizeof(struct tegra_lic_sc));
284
EARLY_DRIVER_MODULE(tegra_lic, simplebus, tegra_lic_driver, NULL, NULL,
285
BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE + 1);
286
287