Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/vchiq/interface/vchiq_arm/vchiq_kmod.c
109341 views
1
/*-
2
* Copyright (c) 2012-2015 Oleksandr Tymoshenko <[email protected]>
3
*
4
* Redistribution and use in source and binary forms, with or without
5
* modification, are permitted provided that the following conditions
6
* are met:
7
* 1. Redistributions of source code must retain the above copyright
8
* notice, this list of conditions and the following disclaimer.
9
* 2. Redistributions in binary form must reproduce the above copyright
10
* notice, this list of conditions and the following disclaimer in the
11
* documentation and/or other materials provided with the distribution.
12
*
13
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23
* SUCH DAMAGE.
24
*/
25
26
#include <sys/cdefs.h>
27
__FBSDID("$FreeBSD$");
28
29
#include <sys/param.h>
30
#include <sys/systm.h>
31
#include <sys/bus.h>
32
#include <sys/kernel.h>
33
#include <sys/module.h>
34
#include <sys/malloc.h>
35
#include <sys/rman.h>
36
#include <sys/timeet.h>
37
#include <sys/timetc.h>
38
#include <sys/watchdog.h>
39
#include <machine/bus.h>
40
#include <machine/cpu.h>
41
#include <machine/frame.h>
42
#include <machine/intr.h>
43
44
#include <dev/fdt/fdt_common.h>
45
#include <dev/ofw/openfirm.h>
46
#include <dev/ofw/ofw_bus.h>
47
#include <dev/ofw/ofw_bus_subr.h>
48
49
#include <machine/bus.h>
50
/* XXXMDC Is this necessary at all? */
51
#if defined(__aarch64__)
52
#else
53
#include <machine/fdt.h>
54
#endif
55
56
#include "vchiq_arm.h"
57
#include "vchiq_2835.h"
58
59
#define VCHIQ_LOCK do { \
60
mtx_lock(&bcm_vchiq_sc->lock); \
61
} while(0)
62
63
#define VCHIQ_UNLOCK do { \
64
mtx_unlock(&bcm_vchiq_sc->lock); \
65
} while(0)
66
67
#ifdef DEBUG
68
#define dprintf(fmt, args...) printf(fmt, ##args)
69
#else
70
#define dprintf(fmt, args...)
71
#endif
72
73
struct bcm_vchiq_softc {
74
struct mtx lock;
75
struct resource * mem_res;
76
struct resource * irq_res;
77
void* intr_hl;
78
bus_space_tag_t bst;
79
bus_space_handle_t bsh;
80
int regs_offset;
81
};
82
83
static struct bcm_vchiq_softc *bcm_vchiq_sc = NULL;
84
85
86
#define CONFIG_INVALID 0
87
#define CONFIG_VALID 1 << 0
88
#define BSD_REG_ADDRS 1 << 1
89
#define LONG_BULK_SPACE 1 << 2
90
91
/*
92
* Also controls the use of the standard VC address offset for bulk data DMA
93
* (normal bulks use that offset; bulks for long address spaces use physical
94
* page addresses)
95
*/
96
extern unsigned int g_long_bulk_space;
97
98
99
/*
100
* XXXMDC
101
* The man page for ofw_bus_is_compatible describes ``features''
102
* as ``can be used''. Here we use understand them as ``must be used''
103
*/
104
105
static struct ofw_compat_data compat_data[] = {
106
{"broadcom,bcm2835-vchiq", BSD_REG_ADDRS | CONFIG_VALID},
107
{"brcm,bcm2835-vchiq", CONFIG_VALID},
108
{"brcm,bcm2711-vchiq", LONG_BULK_SPACE | CONFIG_VALID},
109
{NULL, CONFIG_INVALID}
110
};
111
112
#define vchiq_read_4(reg) \
113
bus_space_read_4(bcm_vchiq_sc->bst, bcm_vchiq_sc->bsh, (reg) + \
114
bcm_vchiq_sc->regs_offset)
115
#define vchiq_write_4(reg, val) \
116
bus_space_write_4(bcm_vchiq_sc->bst, bcm_vchiq_sc->bsh, (reg) + \
117
bcm_vchiq_sc->regs_offset, val)
118
119
/*
120
* Extern functions */
121
void vchiq_exit(void);
122
int vchiq_init(void);
123
124
extern VCHIQ_STATE_T g_state;
125
extern int g_cache_line_size;
126
127
static void
128
bcm_vchiq_intr(void *arg)
129
{
130
VCHIQ_STATE_T *state = &g_state;
131
unsigned int status;
132
133
/* Read (and clear) the doorbell */
134
status = vchiq_read_4(0x40);
135
136
if (status & 0x4) { /* Was the doorbell rung? */
137
remote_event_pollall(state);
138
}
139
}
140
141
void
142
remote_event_signal(REMOTE_EVENT_T *event)
143
{
144
145
wmb();
146
147
event->fired = 1;
148
/* The test on the next line also ensures the write on the previous line
149
has completed */
150
/* UPDATE: not on arm64, it would seem... */
151
#if defined(__aarch64__)
152
dsb(sy);
153
#endif
154
if (event->armed) {
155
/* trigger vc interrupt */
156
#if defined(__aarch64__)
157
dsb(sy);
158
#else
159
dsb();
160
#endif
161
vchiq_write_4(0x48, 0);
162
}
163
}
164
165
static int
166
bcm_vchiq_probe(device_t dev)
167
{
168
169
if ((ofw_bus_search_compatible(dev, compat_data)->ocd_data & CONFIG_VALID) == 0)
170
return (ENXIO);
171
172
device_set_desc(dev, "BCM2835 VCHIQ");
173
return (BUS_PROBE_DEFAULT);
174
}
175
176
/* debug_sysctl */
177
extern int vchiq_core_log_level;
178
extern int vchiq_arm_log_level;
179
180
static int
181
bcm_vchiq_attach(device_t dev)
182
{
183
struct bcm_vchiq_softc *sc = device_get_softc(dev);
184
phandle_t node;
185
pcell_t cell;
186
int rid = 0;
187
188
if (bcm_vchiq_sc != NULL)
189
return (EINVAL);
190
191
sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
192
if (sc->mem_res == NULL) {
193
device_printf(dev, "could not allocate memory resource\n");
194
return (ENXIO);
195
}
196
197
sc->bst = rman_get_bustag(sc->mem_res);
198
sc->bsh = rman_get_bushandle(sc->mem_res);
199
200
rid = 0;
201
sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
202
if (sc->irq_res == NULL) {
203
device_printf(dev, "could not allocate interrupt resource\n");
204
return (ENXIO);
205
}
206
207
uintptr_t dev_compat_d = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
208
/* XXXMDC: shouldn't happen (checked for in probe)--but, for symmetry */
209
if ((dev_compat_d & CONFIG_VALID) == 0){
210
device_printf(dev, "attempting to attach using invalid config.\n");
211
bus_release_resource(dev, SYS_RES_IRQ, rid, sc->irq_res);
212
return (EINVAL);
213
}
214
if ((dev_compat_d & BSD_REG_ADDRS) == 0)
215
sc->regs_offset = -0x40;
216
if(dev_compat_d & LONG_BULK_SPACE)
217
g_long_bulk_space = 1;
218
219
node = ofw_bus_get_node(dev);
220
if ((OF_getencprop(node, "cache-line-size", &cell, sizeof(cell))) > 0)
221
g_cache_line_size = cell;
222
223
vchiq_core_initialize();
224
225
/* debug_sysctl */
226
struct sysctl_ctx_list *ctx_l = device_get_sysctl_ctx(dev);
227
struct sysctl_oid *tree_node = device_get_sysctl_tree(dev);
228
struct sysctl_oid_list *tree = SYSCTL_CHILDREN(tree_node);
229
SYSCTL_ADD_INT(
230
ctx_l, tree, OID_AUTO, "log", CTLFLAG_RW,
231
&vchiq_core_log_level, vchiq_core_log_level, "log level"
232
);
233
SYSCTL_ADD_INT(
234
ctx_l, tree, OID_AUTO, "arm_log", CTLFLAG_RW,
235
&vchiq_arm_log_level, vchiq_arm_log_level, "arm log level"
236
);
237
238
/* Setup and enable the timer */
239
if (bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
240
NULL, bcm_vchiq_intr, sc,
241
&sc->intr_hl) != 0) {
242
bus_release_resource(dev, SYS_RES_IRQ, rid,
243
sc->irq_res);
244
device_printf(dev, "Unable to setup the clock irq handler.\n");
245
return (ENXIO);
246
}
247
248
mtx_init(&sc->lock, "vchiq", 0, MTX_DEF);
249
bcm_vchiq_sc = sc;
250
251
vchiq_init();
252
253
bus_identify_children(dev);
254
bus_attach_children(dev);
255
256
return (0);
257
}
258
259
static int
260
bcm_vchiq_detach(device_t dev)
261
{
262
struct bcm_vchiq_softc *sc = device_get_softc(dev);
263
264
vchiq_exit();
265
266
if (sc->intr_hl)
267
bus_teardown_intr(dev, sc->irq_res, sc->intr_hl);
268
bus_release_resource(dev, SYS_RES_IRQ, 0,
269
sc->irq_res);
270
bus_release_resource(dev, SYS_RES_MEMORY, 0,
271
sc->mem_res);
272
273
mtx_destroy(&sc->lock);
274
275
return (0);
276
}
277
278
279
static device_method_t bcm_vchiq_methods[] = {
280
DEVMETHOD(device_probe, bcm_vchiq_probe),
281
DEVMETHOD(device_attach, bcm_vchiq_attach),
282
DEVMETHOD(device_detach, bcm_vchiq_detach),
283
284
/* Bus interface */
285
DEVMETHOD(bus_add_child, bus_generic_add_child),
286
287
{ 0, 0 }
288
};
289
290
static driver_t bcm_vchiq_driver = {
291
"vchiq",
292
bcm_vchiq_methods,
293
sizeof(struct bcm_vchiq_softc),
294
};
295
296
DRIVER_MODULE(vchiq, simplebus, bcm_vchiq_driver, 0, 0);
297
MODULE_VERSION(vchiq, 1);
298
299