1 /*-
2 * Copyright (c) 2015, 2019 Ruslan Bukin <br@bsdpad.com>
3 * All rights reserved.
4 *
5 * This software was developed by SRI International and the University of
6 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
7 * ("CTSRD"), as part of the DARPA CRASH research programme.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 /*
32 * Synopsys® DesignWare® APB General Purpose Programming I/O
33 * (DW_apb_gpio) peripheral.
34 *
35 * Chapter 22, Cyclone V Device Handbook (CV-5V2 2014.07.22)
36 */
37
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD$");
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/bus.h>
44 #include <sys/kernel.h>
45 #include <sys/module.h>
46 #include <sys/malloc.h>
47 #include <sys/rman.h>
48 #include <sys/timeet.h>
49 #include <sys/timetc.h>
50 #include <sys/watchdog.h>
51 #include <sys/mutex.h>
52 #include <sys/gpio.h>
53 #include <sys/reboot.h>
54
55 #include <dev/gpio/gpiobusvar.h>
56 #include <dev/ofw/openfirm.h>
57 #include <dev/ofw/ofw_bus.h>
58 #include <dev/ofw/ofw_bus_subr.h>
59
60 #include <machine/bus.h>
61 #include <machine/cpu.h>
62 #include <machine/intr.h>
63
64 #include "gpio_if.h"
65 #include "dwgpio_if.h"
66
67 #define READ4(_sc, _reg) DWGPIO_READ((_sc)->parent, _reg)
68 #define WRITE4(_sc, _reg, _val) DWGPIO_WRITE((_sc)->parent, _reg, _val)
69
70 #define GPIO_SWPORT_DR(n) (0x00 + 0xc * (n)) /* Port n Data Register */
71 #define GPIO_SWPORT_DDR(n) (0x04 + 0xc * (n)) /* Port n Data Direction */
72 #define GPIO_INTEN 0x30 /* Interrupt Enable Register */
73 #define GPIO_INTMASK 0x34 /* Interrupt Mask Register */
74 #define GPIO_INTTYPE_LEVEL 0x38 /* Interrupt Level Register */
75 #define GPIO_INT_POLARITY 0x3C /* Interrupt Polarity Register */
76 #define GPIO_INTSTATUS 0x40 /* Interrupt Status Register */
77 #define GPIO_RAW_INTSTATUS 0x44 /* Raw Interrupt Status Register */
78 #define GPIO_DEBOUNCE 0x48 /* Debounce Enable Register */
79 #define GPIO_PORTA_EOI 0x4C /* Clear Interrupt Register */
80 #define GPIO_EXT_PORT(n) (0x50 + 0x4 * (n)) /* External Port n */
81 #define GPIO_LS_SYNC 0x60 /* Synchronization Level Register */
82 #define GPIO_ID_CODE 0x64 /* ID Code Register */
83 #define GPIO_VER_ID_CODE 0x6C /* GPIO Version Register */
84 #define GPIO_CONFIG_REG2 0x70 /* Configuration Register 2 */
85 #define ENCODED_ID_PWIDTH_M 0x1f /* Width of GPIO Port N Mask */
86 #define ENCODED_ID_PWIDTH_S(n) (5 * n) /* Width of GPIO Port N Shift */
87 #define GPIO_CONFIG_REG1 0x74 /* Configuration Register 1 */
88
89 #define NR_GPIO_MAX 32 /* Maximum pins per port */
90
91 #define GPIO_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
92 #define GPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
93
94 #define DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)
95
96 /*
97 * GPIO interface
98 */
99 static device_t dwgpio_get_bus(device_t);
100 static int dwgpio_pin_max(device_t, int *);
101 static int dwgpio_pin_getcaps(device_t, uint32_t, uint32_t *);
102 static int dwgpio_pin_getname(device_t, uint32_t, char *);
103 static int dwgpio_pin_getflags(device_t, uint32_t, uint32_t *);
104 static int dwgpio_pin_setflags(device_t, uint32_t, uint32_t);
105 static int dwgpio_pin_set(device_t, uint32_t, unsigned int);
106 static int dwgpio_pin_get(device_t, uint32_t, unsigned int *);
107 static int dwgpio_pin_toggle(device_t, uint32_t pin);
108
109 struct dwgpio_softc {
110 device_t dev;
111 device_t busdev;
112 device_t parent;
113 struct mtx sc_mtx;
114 int gpio_npins;
115 struct gpio_pin gpio_pins[NR_GPIO_MAX];
116 phandle_t node;
117 int port;
118 };
119
120 static int
121 dwgpio_probe(device_t dev)
122 {
123
124 if (!ofw_bus_status_okay(dev))
125 return (ENXIO);
126
127 if (!ofw_bus_is_compatible(dev, "snps,dw-apb-gpio-port"))
128 return (ENXIO);
129
130 device_set_desc(dev, "DesignWare General-Purpose I/O Interface");
131 return (BUS_PROBE_DEFAULT);
132 }
133
134 static int
135 dwgpio_attach(device_t dev)
136 {
137 struct dwgpio_softc *sc;
138 int version;
139 int nr_pins;
140 int cfg2;
141 int i;
142
143 sc = device_get_softc(dev);
144 sc->parent = device_get_parent(dev);
145 sc->node = ofw_bus_get_node(dev);
146 sc->dev = dev;
147 mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
148
149 if ((OF_getencprop(sc->node, "reg", &sc->port, sizeof(sc->port))) <= 0)
150 return (ENXIO);
151
152 printf("port %d\n", sc->port);
153
154 version = READ4(sc, GPIO_VER_ID_CODE);
155 if (boothowto & RB_VERBOSE)
156 device_printf(sc->dev, "Version = 0x%08x\n", version);
157
158 /* Grab number of pins from hardware. */
159 cfg2 = READ4(sc, GPIO_CONFIG_REG2);
160 nr_pins = (cfg2 >> ENCODED_ID_PWIDTH_S(sc->port)) & \
161 ENCODED_ID_PWIDTH_M;
162 sc->gpio_npins = nr_pins + 1;
163
164 for (i = 0; i < sc->gpio_npins; i++) {
165 sc->gpio_pins[i].gp_pin = i;
166 sc->gpio_pins[i].gp_caps = DEFAULT_CAPS;
167 sc->gpio_pins[i].gp_flags =
168 (READ4(sc, GPIO_SWPORT_DDR(sc->port)) & (1 << i)) ?
169 GPIO_PIN_OUTPUT: GPIO_PIN_INPUT;
170 snprintf(sc->gpio_pins[i].gp_name, GPIOMAXNAME,
171 "dwgpio%d.%d", device_get_unit(dev), i);
172 }
173 sc->busdev = gpiobus_attach_bus(dev);
174 if (sc->busdev == NULL) {
175 mtx_destroy(&sc->sc_mtx);
176 return (ENXIO);
177 }
178
179 return (0);
180 }
181
182 static device_t
183 dwgpio_get_bus(device_t dev)
184 {
185 struct dwgpio_softc *sc;
186
187 sc = device_get_softc(dev);
188
189 return (sc->busdev);
190 }
191
192 static int
193 dwgpio_pin_max(device_t dev, int *maxpin)
194 {
195 struct dwgpio_softc *sc;
196
197 sc = device_get_softc(dev);
198
199 *maxpin = sc->gpio_npins - 1;
200
201 return (0);
202 }
203
204 static int
205 dwgpio_pin_getname(device_t dev, uint32_t pin, char *name)
206 {
207 struct dwgpio_softc *sc;
208 int i;
209
210 sc = device_get_softc(dev);
211 for (i = 0; i < sc->gpio_npins; i++) {
212 if (sc->gpio_pins[i].gp_pin == pin)
213 break;
214 }
215
216 if (i >= sc->gpio_npins)
217 return (EINVAL);
218
219 GPIO_LOCK(sc);
220 memcpy(name, sc->gpio_pins[i].gp_name, GPIOMAXNAME);
221 GPIO_UNLOCK(sc);
222
223 return (0);
224 }
225
226 static int
227 dwgpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
228 {
229 struct dwgpio_softc *sc;
230 int i;
231
232 sc = device_get_softc(dev);
233 for (i = 0; i < sc->gpio_npins; i++) {
234 if (sc->gpio_pins[i].gp_pin == pin)
235 break;
236 }
237
238 if (i >= sc->gpio_npins)
239 return (EINVAL);
240
241 GPIO_LOCK(sc);
242 *caps = sc->gpio_pins[i].gp_caps;
243 GPIO_UNLOCK(sc);
244
245 return (0);
246 }
247
248 static int
249 dwgpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
250 {
251 struct dwgpio_softc *sc;
252 int i;
253
254 sc = device_get_softc(dev);
255 for (i = 0; i < sc->gpio_npins; i++) {
256 if (sc->gpio_pins[i].gp_pin == pin)
257 break;
258 }
259
260 if (i >= sc->gpio_npins)
261 return (EINVAL);
262
263 GPIO_LOCK(sc);
264 *flags = sc->gpio_pins[i].gp_flags;
265 GPIO_UNLOCK(sc);
266
267 return (0);
268 }
269
270 static int
271 dwgpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
272 {
273 struct dwgpio_softc *sc;
274 int i;
275
276 sc = device_get_softc(dev);
277 for (i = 0; i < sc->gpio_npins; i++) {
278 if (sc->gpio_pins[i].gp_pin == pin)
279 break;
280 }
281
282 if (i >= sc->gpio_npins)
283 return (EINVAL);
284
285 GPIO_LOCK(sc);
286 *val = (READ4(sc, GPIO_EXT_PORT(sc->port)) & (1 << i)) ? 1 : 0;
287 GPIO_UNLOCK(sc);
288
289 return (0);
290 }
291
292 static int
293 dwgpio_pin_toggle(device_t dev, uint32_t pin)
294 {
295 struct dwgpio_softc *sc;
296 int reg;
297 int i;
298
299 sc = device_get_softc(dev);
300 for (i = 0; i < sc->gpio_npins; i++) {
301 if (sc->gpio_pins[i].gp_pin == pin)
302 break;
303 }
304
305 if (i >= sc->gpio_npins)
306 return (EINVAL);
307
308 GPIO_LOCK(sc);
309 reg = READ4(sc, GPIO_SWPORT_DR(sc->port));
310 if (reg & (1 << i))
311 reg &= ~(1 << i);
312 else
313 reg |= (1 << i);
314 WRITE4(sc, GPIO_SWPORT_DR(sc->port), reg);
315 GPIO_UNLOCK(sc);
316
317 return (0);
318 }
319
320
321 static void
322 dwgpio_pin_configure(struct dwgpio_softc *sc,
323 struct gpio_pin *pin, unsigned int flags)
324 {
325 int reg;
326
327 GPIO_LOCK(sc);
328
329 /*
330 * Manage input/output
331 */
332
333 reg = READ4(sc, GPIO_SWPORT_DDR(sc->port));
334 if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) {
335 pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT);
336 if (flags & GPIO_PIN_OUTPUT) {
337 pin->gp_flags |= GPIO_PIN_OUTPUT;
338 reg |= (1 << pin->gp_pin);
339 } else {
340 pin->gp_flags |= GPIO_PIN_INPUT;
341 reg &= ~(1 << pin->gp_pin);
342 }
343 }
344
345 WRITE4(sc, GPIO_SWPORT_DDR(sc->port), reg);
346 GPIO_UNLOCK(sc);
347 }
348
349
350 static int
351 dwgpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
352 {
353 struct dwgpio_softc *sc;
354 int i;
355
356 sc = device_get_softc(dev);
357 for (i = 0; i < sc->gpio_npins; i++) {
358 if (sc->gpio_pins[i].gp_pin == pin)
359 break;
360 }
361
362 if (i >= sc->gpio_npins)
363 return (EINVAL);
364
365 dwgpio_pin_configure(sc, &sc->gpio_pins[i], flags);
366
367 return (0);
368 }
369
370 static int
371 dwgpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
372 {
373 struct dwgpio_softc *sc;
374 int reg;
375 int i;
376
377 sc = device_get_softc(dev);
378
379 for (i = 0; i < sc->gpio_npins; i++) {
380 if (sc->gpio_pins[i].gp_pin == pin)
381 break;
382 }
383
384 if (i >= sc->gpio_npins)
385 return (EINVAL);
386
387 GPIO_LOCK(sc);
388 reg = READ4(sc, GPIO_SWPORT_DR(sc->port));
389 if (value)
390 reg |= (1 << i);
391 else
392 reg &= ~(1 << i);
393 WRITE4(sc, GPIO_SWPORT_DR(sc->port), reg);
394 GPIO_UNLOCK(sc);
395
396 return (0);
397 }
398
399 static device_method_t dwgpio_methods[] = {
400 DEVMETHOD(device_probe, dwgpio_probe),
401 DEVMETHOD(device_attach, dwgpio_attach),
402
403 /* GPIO protocol */
404 DEVMETHOD(gpio_get_bus, dwgpio_get_bus),
405 DEVMETHOD(gpio_pin_max, dwgpio_pin_max),
406 DEVMETHOD(gpio_pin_getname, dwgpio_pin_getname),
407 DEVMETHOD(gpio_pin_getcaps, dwgpio_pin_getcaps),
408 DEVMETHOD(gpio_pin_getflags, dwgpio_pin_getflags),
409 DEVMETHOD(gpio_pin_get, dwgpio_pin_get),
410 DEVMETHOD(gpio_pin_toggle, dwgpio_pin_toggle),
411 DEVMETHOD(gpio_pin_setflags, dwgpio_pin_setflags),
412 DEVMETHOD(gpio_pin_set, dwgpio_pin_set),
413 { 0, 0 }
414 };
415
416 static driver_t dwgpio_driver = {
417 "gpio",
418 dwgpio_methods,
419 sizeof(struct dwgpio_softc),
420 };
421
422 DRIVER_MODULE(dwgpio, dwgpiobus, dwgpio_driver, 0, 0);
Cache object: 8e85f287bfaf299a72280dd7d1eec04b
|