Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/riscv/sifive/sifive_gpio.c
39478 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2021 Jessica Clarke <[email protected]>
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
* 1. Redistributions of source code must retain the above copyright
10
* notice, this list of conditions and the following disclaimer.
11
* 2. Redistributions in binary form must reproduce the above copyright
12
* notice, this list of conditions and the following disclaimer in the
13
* documentation and/or other materials provided with the distribution.
14
*
15
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25
* SUCH DAMAGE.
26
*
27
*/
28
29
/* TODO: Provide interrupt controller interface */
30
31
#include <sys/param.h>
32
#include <sys/systm.h>
33
#include <sys/bus.h>
34
#include <sys/kernel.h>
35
#include <sys/module.h>
36
#include <sys/rman.h>
37
#include <sys/lock.h>
38
#include <sys/mutex.h>
39
#include <sys/gpio.h>
40
41
#include <dev/gpio/gpiobusvar.h>
42
#include <dev/ofw/ofw_bus.h>
43
#include <dev/ofw/ofw_bus_subr.h>
44
45
#include <machine/bus.h>
46
47
/* Registers are 32-bit so can only fit 32 pins */
48
#define SFGPIO_MAX_PINS 32
49
50
#define SFGPIO_DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)
51
52
#define SFGPIO_INPUT_VAL 0x0
53
#define SFGPIO_INPUT_EN 0x4
54
#define SFGPIO_OUTPUT_EN 0x8
55
#define SFGPIO_OUTPUT_VAL 0xc
56
#define SFGPIO_RISE_IE 0x18
57
#define SFGPIO_RISE_IP 0x1c
58
#define SFGPIO_FALL_IE 0x20
59
#define SFGPIO_FALL_IP 0x24
60
#define SFGPIO_HIGH_IE 0x28
61
#define SFGPIO_HIGH_IP 0x2c
62
#define SFGPIO_LOW_IE 0x30
63
#define SFGPIO_LOW_IP 0x34
64
65
struct sfgpio_softc {
66
device_t dev;
67
device_t busdev;
68
struct mtx mtx;
69
struct resource *mem_res;
70
int mem_rid;
71
struct resource *irq_res;
72
int irq_rid;
73
int npins;
74
struct gpio_pin gpio_pins[SFGPIO_MAX_PINS];
75
};
76
77
#define SFGPIO_LOCK(_sc) mtx_lock(&(_sc)->mtx)
78
#define SFGPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->mtx)
79
80
#define SFGPIO_READ(_sc, _off) \
81
bus_read_4((_sc)->mem_res, (_off))
82
#define SFGPIO_WRITE(_sc, _off, _val) \
83
bus_write_4((_sc)->mem_res, (_off), (_val))
84
85
static struct ofw_compat_data compat_data[] = {
86
{ "sifive,gpio0", 1 },
87
{ NULL, 0 },
88
};
89
90
static int
91
sfgpio_probe(device_t dev)
92
{
93
if (!ofw_bus_status_okay(dev))
94
return (ENXIO);
95
96
if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
97
return (ENXIO);
98
99
device_set_desc(dev, "SiFive GPIO Controller");
100
101
return (BUS_PROBE_DEFAULT);
102
}
103
104
static int
105
sfgpio_attach(device_t dev)
106
{
107
struct sfgpio_softc *sc;
108
phandle_t node;
109
int error, i;
110
pcell_t npins;
111
uint32_t input_en, output_en;
112
113
sc = device_get_softc(dev);
114
sc->dev = dev;
115
116
node = ofw_bus_get_node(dev);
117
118
mtx_init(&sc->mtx, device_get_nameunit(sc->dev), NULL, MTX_DEF);
119
120
sc->mem_rid = 0;
121
sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
122
&sc->mem_rid, RF_ACTIVE);
123
if (sc->mem_res == NULL) {
124
device_printf(dev, "Cannot allocate memory resource\n");
125
error = ENXIO;
126
goto fail;
127
}
128
129
if (OF_getencprop(node, "ngpios", &npins, sizeof(npins)) <= 0) {
130
/* Optional; defaults to 16 */
131
npins = 16;
132
} else if (npins > SFGPIO_MAX_PINS) {
133
device_printf(dev, "Too many pins: %d\n", npins);
134
error = ENXIO;
135
goto fail;
136
}
137
sc->npins = npins;
138
139
sc->irq_rid = 0;
140
sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid,
141
RF_ACTIVE);
142
if (sc->irq_res == NULL) {
143
device_printf(dev, "Cannot allocate IRQ resource\n");
144
error = ENXIO;
145
goto fail;
146
}
147
148
input_en = SFGPIO_READ(sc, SFGPIO_INPUT_EN);
149
output_en = SFGPIO_READ(sc, SFGPIO_OUTPUT_EN);
150
for (i = 0; i < sc->npins; ++i) {
151
sc->gpio_pins[i].gp_pin = i;
152
sc->gpio_pins[i].gp_caps = SFGPIO_DEFAULT_CAPS;
153
sc->gpio_pins[i].gp_flags =
154
((input_en & (1u << i)) ? GPIO_PIN_INPUT : 0) |
155
((output_en & (1u << i)) ? GPIO_PIN_OUTPUT : 0);
156
snprintf(sc->gpio_pins[i].gp_name, GPIOMAXNAME, "GPIO%d", i);
157
sc->gpio_pins[i].gp_name[GPIOMAXNAME - 1] = '\0';
158
}
159
160
sc->busdev = gpiobus_add_bus(dev);
161
if (sc->busdev == NULL) {
162
device_printf(dev, "Cannot attach gpiobus\n");
163
error = ENXIO;
164
goto fail;
165
}
166
167
bus_attach_children(dev);
168
return (0);
169
170
fail:
171
if (sc->busdev != NULL)
172
gpiobus_detach_bus(dev);
173
if (sc->irq_res != NULL)
174
bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid,
175
sc->irq_res);
176
if (sc->mem_res != NULL)
177
bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid,
178
sc->mem_res);
179
mtx_destroy(&sc->mtx);
180
return (error);
181
}
182
183
static device_t
184
sfgpio_get_bus(device_t dev)
185
{
186
struct sfgpio_softc *sc;
187
188
sc = device_get_softc(dev);
189
190
return (sc->busdev);
191
}
192
193
static int
194
sfgpio_pin_max(device_t dev, int *maxpin)
195
{
196
struct sfgpio_softc *sc;
197
198
sc = device_get_softc(dev);
199
200
*maxpin = sc->npins - 1;
201
202
return (0);
203
}
204
205
static int
206
sfgpio_pin_set(device_t dev, uint32_t pin, unsigned int val)
207
{
208
struct sfgpio_softc *sc;
209
uint32_t reg;
210
211
sc = device_get_softc(dev);
212
213
if (pin >= sc->npins)
214
return (EINVAL);
215
216
SFGPIO_LOCK(sc);
217
reg = SFGPIO_READ(sc, SFGPIO_OUTPUT_VAL);
218
if (val)
219
reg |= (1u << pin);
220
else
221
reg &= ~(1u << pin);
222
SFGPIO_WRITE(sc, SFGPIO_OUTPUT_VAL, reg);
223
SFGPIO_UNLOCK(sc);
224
225
return (0);
226
}
227
228
static int
229
sfgpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
230
{
231
struct sfgpio_softc *sc;
232
uint32_t reg;
233
234
sc = device_get_softc(dev);
235
236
if (pin >= sc->npins)
237
return (EINVAL);
238
239
SFGPIO_LOCK(sc);
240
if (sc->gpio_pins[pin].gp_flags & GPIO_PIN_OUTPUT)
241
reg = SFGPIO_READ(sc, SFGPIO_OUTPUT_VAL);
242
else
243
reg = SFGPIO_READ(sc, SFGPIO_INPUT_VAL);
244
*val = (reg & (1u << pin)) ? 1 : 0;
245
SFGPIO_UNLOCK(sc);
246
247
return (0);
248
}
249
250
static int
251
sfgpio_pin_toggle(device_t dev, uint32_t pin)
252
{
253
struct sfgpio_softc *sc;
254
uint32_t reg;
255
256
sc = device_get_softc(dev);
257
258
if (pin >= sc->npins)
259
return (EINVAL);
260
261
SFGPIO_LOCK(sc);
262
reg = SFGPIO_READ(sc, SFGPIO_OUTPUT_VAL);
263
reg ^= (1u << pin);
264
SFGPIO_WRITE(sc, SFGPIO_OUTPUT_VAL, reg);
265
SFGPIO_UNLOCK(sc);
266
267
return (0);
268
}
269
270
static int
271
sfgpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
272
{
273
struct sfgpio_softc *sc;
274
275
sc = device_get_softc(dev);
276
277
if (pin >= sc->npins)
278
return (EINVAL);
279
280
SFGPIO_LOCK(sc);
281
*caps = sc->gpio_pins[pin].gp_caps;
282
SFGPIO_UNLOCK(sc);
283
284
return (0);
285
}
286
287
static int
288
sfgpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
289
{
290
struct sfgpio_softc *sc;
291
292
sc = device_get_softc(dev);
293
294
if (pin >= sc->npins)
295
return (EINVAL);
296
297
SFGPIO_LOCK(sc);
298
*flags = sc->gpio_pins[pin].gp_flags;
299
SFGPIO_UNLOCK(sc);
300
301
return (0);
302
}
303
304
static int
305
sfgpio_pin_getname(device_t dev, uint32_t pin, char *name)
306
{
307
struct sfgpio_softc *sc;
308
309
sc = device_get_softc(dev);
310
311
if (pin >= sc->npins)
312
return (EINVAL);
313
314
SFGPIO_LOCK(sc);
315
memcpy(name, sc->gpio_pins[pin].gp_name, GPIOMAXNAME);
316
SFGPIO_UNLOCK(sc);
317
318
return (0);
319
}
320
321
static int
322
sfgpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
323
{
324
struct sfgpio_softc *sc;
325
uint32_t reg;
326
327
sc = device_get_softc(dev);
328
329
if (pin >= sc->npins)
330
return (EINVAL);
331
332
SFGPIO_LOCK(sc);
333
334
reg = SFGPIO_READ(sc, SFGPIO_INPUT_EN);
335
if (flags & GPIO_PIN_INPUT) {
336
reg |= (1u << pin);
337
sc->gpio_pins[pin].gp_flags |= GPIO_PIN_INPUT;
338
} else {
339
reg &= ~(1u << pin);
340
sc->gpio_pins[pin].gp_flags &= ~GPIO_PIN_INPUT;
341
}
342
SFGPIO_WRITE(sc, SFGPIO_INPUT_EN, reg);
343
344
reg = SFGPIO_READ(sc, SFGPIO_OUTPUT_EN);
345
if (flags & GPIO_PIN_OUTPUT) {
346
reg |= (1u << pin);
347
sc->gpio_pins[pin].gp_flags |= GPIO_PIN_OUTPUT;
348
} else {
349
reg &= ~(1u << pin);
350
sc->gpio_pins[pin].gp_flags &= ~GPIO_PIN_OUTPUT;
351
}
352
SFGPIO_WRITE(sc, SFGPIO_OUTPUT_EN, reg);
353
354
SFGPIO_UNLOCK(sc);
355
356
return (0);
357
}
358
359
static int
360
sfgpio_pin_access_32(device_t dev, uint32_t first_pin, uint32_t clear_pins,
361
uint32_t change_pins, uint32_t *orig_pins)
362
{
363
struct sfgpio_softc *sc;
364
uint32_t reg;
365
366
if (first_pin != 0)
367
return (EINVAL);
368
369
sc = device_get_softc(dev);
370
371
SFGPIO_LOCK(sc);
372
373
reg = SFGPIO_READ(sc, SFGPIO_OUTPUT_VAL);
374
375
if (orig_pins != NULL)
376
/* Only input_val is implicitly masked by input_en */
377
*orig_pins = SFGPIO_READ(sc, SFGPIO_INPUT_VAL) |
378
(reg & SFGPIO_READ(sc, SFGPIO_OUTPUT_EN));
379
380
if ((clear_pins | change_pins) != 0)
381
SFGPIO_WRITE(sc, SFGPIO_OUTPUT_VAL,
382
(reg & ~clear_pins) ^ change_pins);
383
384
SFGPIO_UNLOCK(sc);
385
386
return (0);
387
}
388
389
static int
390
sfgpio_pin_config_32(device_t dev, uint32_t first_pin, uint32_t num_pins,
391
uint32_t *pin_flags)
392
{
393
struct sfgpio_softc *sc;
394
uint32_t ireg, oreg;
395
int i;
396
397
sc = device_get_softc(dev);
398
399
if (first_pin != 0 || num_pins > sc->npins)
400
return (EINVAL);
401
402
SFGPIO_LOCK(sc);
403
404
ireg = SFGPIO_READ(sc, SFGPIO_INPUT_EN);
405
oreg = SFGPIO_READ(sc, SFGPIO_OUTPUT_EN);
406
for (i = 0; i < num_pins; ++i) {
407
if (pin_flags[i] & GPIO_PIN_INPUT) {
408
ireg |= (1u << i);
409
oreg &= ~(1u << i);
410
sc->gpio_pins[i].gp_flags |= GPIO_PIN_INPUT;
411
sc->gpio_pins[i].gp_flags &= ~GPIO_PIN_OUTPUT;
412
} else if (pin_flags[i] & GPIO_PIN_OUTPUT) {
413
ireg &= ~(1u << i);
414
oreg |= (1u << i);
415
sc->gpio_pins[i].gp_flags &= ~GPIO_PIN_INPUT;
416
sc->gpio_pins[i].gp_flags |= GPIO_PIN_OUTPUT;
417
}
418
}
419
SFGPIO_WRITE(sc, SFGPIO_INPUT_EN, ireg);
420
SFGPIO_WRITE(sc, SFGPIO_OUTPUT_EN, oreg);
421
422
SFGPIO_UNLOCK(sc);
423
424
return (0);
425
}
426
427
static phandle_t
428
sfgpio_get_node(device_t bus, device_t dev)
429
{
430
return (ofw_bus_get_node(bus));
431
}
432
433
static device_method_t sfgpio_methods[] = {
434
/* Device interface */
435
DEVMETHOD(device_probe, sfgpio_probe),
436
DEVMETHOD(device_attach, sfgpio_attach),
437
438
/* GPIO protocol */
439
DEVMETHOD(gpio_get_bus, sfgpio_get_bus),
440
DEVMETHOD(gpio_pin_max, sfgpio_pin_max),
441
DEVMETHOD(gpio_pin_set, sfgpio_pin_set),
442
DEVMETHOD(gpio_pin_get, sfgpio_pin_get),
443
DEVMETHOD(gpio_pin_toggle, sfgpio_pin_toggle),
444
DEVMETHOD(gpio_pin_getcaps, sfgpio_pin_getcaps),
445
DEVMETHOD(gpio_pin_getflags, sfgpio_pin_getflags),
446
DEVMETHOD(gpio_pin_getname, sfgpio_pin_getname),
447
DEVMETHOD(gpio_pin_setflags, sfgpio_pin_setflags),
448
DEVMETHOD(gpio_pin_access_32, sfgpio_pin_access_32),
449
DEVMETHOD(gpio_pin_config_32, sfgpio_pin_config_32),
450
451
/* ofw_bus interface */
452
DEVMETHOD(ofw_bus_get_node, sfgpio_get_node),
453
454
DEVMETHOD_END
455
};
456
457
DEFINE_CLASS_0(gpio, sfgpio_driver, sfgpio_methods,
458
sizeof(struct sfgpio_softc));
459
EARLY_DRIVER_MODULE(gpio, simplebus, sfgpio_driver, 0, 0,
460
BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE);
461
MODULE_DEPEND(sfgpio, gpiobus, 1, 1, 1);
462
463