]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/altera/socfpga/socfpga_gpio.c
Update to Zstandard 1.4.2
[FreeBSD/FreeBSD.git] / sys / arm / altera / socfpga / socfpga_gpio.c
1 /*-
2  * Copyright (c) 2015 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  * SOCFPGA General-Purpose I/O Interface.
33  * Chapter 22, Cyclone V Device Handbook (CV-5V2 2014.07.22)
34  */
35
36 /*
37  * The GPIO modules are instances of the Synopsys® DesignWare® APB General
38  * Purpose Programming I/O (DW_apb_gpio) peripheral.
39  */
40
41 #include <sys/cdefs.h>
42 __FBSDID("$FreeBSD$");
43
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/bus.h>
47 #include <sys/kernel.h>
48 #include <sys/module.h>
49 #include <sys/malloc.h>
50 #include <sys/rman.h>
51 #include <sys/timeet.h>
52 #include <sys/timetc.h>
53 #include <sys/watchdog.h>
54 #include <sys/mutex.h>
55 #include <sys/gpio.h>
56
57 #include <dev/gpio/gpiobusvar.h>
58 #include <dev/ofw/openfirm.h>
59 #include <dev/ofw/ofw_bus.h>
60 #include <dev/ofw/ofw_bus_subr.h>
61
62 #include <machine/bus.h>
63 #include <machine/cpu.h>
64 #include <machine/intr.h>
65
66 #include "gpio_if.h"
67
68 #define READ4(_sc, _reg) \
69         bus_read_4((_sc)->res[0], _reg)
70 #define WRITE4(_sc, _reg, _val) \
71         bus_write_4((_sc)->res[0], _reg, _val)
72
73 #define GPIO_SWPORTA_DR         0x00    /* Port A Data Register */
74 #define GPIO_SWPORTA_DDR        0x04    /* Port A Data Direction Register */
75 #define GPIO_INTEN              0x30    /* Interrupt Enable Register */
76 #define GPIO_INTMASK            0x34    /* Interrupt Mask Register */
77 #define GPIO_INTTYPE_LEVEL      0x38    /* Interrupt Level Register */
78 #define GPIO_INT_POLARITY       0x3C    /* Interrupt Polarity Register */
79 #define GPIO_INTSTATUS          0x40    /* Interrupt Status Register */
80 #define GPIO_RAW_INTSTATUS      0x44    /* Raw Interrupt Status Register */
81 #define GPIO_DEBOUNCE           0x48    /* Debounce Enable Register */
82 #define GPIO_PORTA_EOI          0x4C    /* Clear Interrupt Register */
83 #define GPIO_EXT_PORTA          0x50    /* External Port A Register */
84 #define GPIO_LS_SYNC            0x60    /* Synchronization Level Register */
85 #define GPIO_ID_CODE            0x64    /* ID Code Register */
86 #define GPIO_VER_ID_CODE        0x6C    /* GPIO Version Register */
87 #define GPIO_CONFIG_REG2        0x70    /* Configuration Register 2 */
88 #define  ENCODED_ID_PWIDTH_M    0x1f    /* Width of GPIO Port N Mask */
89 #define  ENCODED_ID_PWIDTH_S(n) (5 * n) /* Width of GPIO Port N Shift */
90 #define GPIO_CONFIG_REG1        0x74    /* Configuration Register 1 */
91
92 enum port_no {
93         PORTA,
94         PORTB,
95         PORTC,
96         PORTD,
97 };
98
99 #define NR_GPIO_MAX     32      /* Maximum pins per port */
100
101 #define GPIO_LOCK(_sc)          mtx_lock(&(_sc)->sc_mtx)
102 #define GPIO_UNLOCK(_sc)        mtx_unlock(&(_sc)->sc_mtx)
103
104 #define DEFAULT_CAPS    (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)
105
106 /*
107  * GPIO interface
108  */
109 static device_t socfpga_gpio_get_bus(device_t);
110 static int socfpga_gpio_pin_max(device_t, int *);
111 static int socfpga_gpio_pin_getcaps(device_t, uint32_t, uint32_t *);
112 static int socfpga_gpio_pin_getname(device_t, uint32_t, char *);
113 static int socfpga_gpio_pin_getflags(device_t, uint32_t, uint32_t *);
114 static int socfpga_gpio_pin_setflags(device_t, uint32_t, uint32_t);
115 static int socfpga_gpio_pin_set(device_t, uint32_t, unsigned int);
116 static int socfpga_gpio_pin_get(device_t, uint32_t, unsigned int *);
117 static int socfpga_gpio_pin_toggle(device_t, uint32_t pin);
118
119 struct socfpga_gpio_softc {
120         struct resource         *res[1];
121         bus_space_tag_t         bst;
122         bus_space_handle_t      bsh;
123
124         device_t                dev;
125         device_t                busdev;
126         struct mtx              sc_mtx;
127         int                     gpio_npins;
128         struct gpio_pin         gpio_pins[NR_GPIO_MAX];
129 };
130
131 struct socfpga_gpio_softc *gpio_sc;
132
133 static struct resource_spec socfpga_gpio_spec[] = {
134         { SYS_RES_MEMORY,       0,      RF_ACTIVE },
135         { -1, 0 }
136 };
137
138 static int
139 socfpga_gpio_probe(device_t dev)
140 {
141
142         if (!ofw_bus_status_okay(dev))
143                 return (ENXIO);
144
145         if (!ofw_bus_is_compatible(dev, "snps,dw-apb-gpio"))
146                 return (ENXIO);
147
148         device_set_desc(dev, "DesignWare General-Purpose I/O Interface");
149         return (BUS_PROBE_DEFAULT);
150 }
151
152 static int
153 socfpga_gpio_attach(device_t dev)
154 {
155         struct socfpga_gpio_softc *sc;
156         int version;
157         int nr_pins;
158         int cfg2;
159         int i;
160
161         sc = device_get_softc(dev);
162         sc->dev = dev;
163         mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
164
165         if (bus_alloc_resources(dev, socfpga_gpio_spec, sc->res)) {
166                 device_printf(dev, "could not allocate resources\n");
167                 mtx_destroy(&sc->sc_mtx);
168                 return (ENXIO);
169         }
170
171         /* Memory interface */
172         sc->bst = rman_get_bustag(sc->res[0]);
173         sc->bsh = rman_get_bushandle(sc->res[0]);
174
175         gpio_sc = sc;
176
177         version =  READ4(sc, GPIO_VER_ID_CODE);
178 #if 0
179         device_printf(sc->dev, "Version = 0x%08x\n", version);
180 #endif
181
182         /*
183          * Take number of pins from hardware.
184          * XXX: Assume we have GPIO port A only.
185          */
186         cfg2 = READ4(sc, GPIO_CONFIG_REG2);
187         nr_pins = (cfg2 >> ENCODED_ID_PWIDTH_S(PORTA)) & \
188                         ENCODED_ID_PWIDTH_M;
189         sc->gpio_npins = nr_pins + 1;
190
191         for (i = 0; i < sc->gpio_npins; i++) {
192                 sc->gpio_pins[i].gp_pin = i;
193                 sc->gpio_pins[i].gp_caps = DEFAULT_CAPS;
194                 sc->gpio_pins[i].gp_flags =
195                     (READ4(sc, GPIO_SWPORTA_DDR) & (1 << i)) ?
196                     GPIO_PIN_OUTPUT: GPIO_PIN_INPUT;
197                 snprintf(sc->gpio_pins[i].gp_name, GPIOMAXNAME,
198                     "socfpga_gpio%d.%d", device_get_unit(dev), i);
199         }
200         sc->busdev = gpiobus_attach_bus(dev);
201         if (sc->busdev == NULL) {
202                 bus_release_resources(dev, socfpga_gpio_spec, sc->res);
203                 mtx_destroy(&sc->sc_mtx);
204                 return (ENXIO);
205         }
206
207         return (0);
208 }
209
210 static device_t
211 socfpga_gpio_get_bus(device_t dev)
212 {
213         struct socfpga_gpio_softc *sc;
214
215         sc = device_get_softc(dev);
216
217         return (sc->busdev);
218 }
219
220 static int
221 socfpga_gpio_pin_max(device_t dev, int *maxpin)
222 {
223         struct socfpga_gpio_softc *sc;
224
225         sc = device_get_softc(dev);
226
227         *maxpin = sc->gpio_npins - 1;
228
229         return (0);
230 }
231
232 static int
233 socfpga_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
234 {
235         struct socfpga_gpio_softc *sc;
236         int i;
237
238         sc = device_get_softc(dev);
239         for (i = 0; i < sc->gpio_npins; i++) {
240                 if (sc->gpio_pins[i].gp_pin == pin)
241                         break;
242         }
243
244         if (i >= sc->gpio_npins)
245                 return (EINVAL);
246
247         GPIO_LOCK(sc);
248         memcpy(name, sc->gpio_pins[i].gp_name, GPIOMAXNAME);
249         GPIO_UNLOCK(sc);
250
251         return (0);
252 }
253
254 static int
255 socfpga_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
256 {
257         struct socfpga_gpio_softc *sc;
258         int i;
259
260         sc = device_get_softc(dev);
261         for (i = 0; i < sc->gpio_npins; i++) {
262                 if (sc->gpio_pins[i].gp_pin == pin)
263                         break;
264         }
265
266         if (i >= sc->gpio_npins)
267                 return (EINVAL);
268
269         GPIO_LOCK(sc);
270         *caps = sc->gpio_pins[i].gp_caps;
271         GPIO_UNLOCK(sc);
272
273         return (0);
274 }
275
276 static int
277 socfpga_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
278 {
279         struct socfpga_gpio_softc *sc;
280         int i;
281
282         sc = device_get_softc(dev);
283         for (i = 0; i < sc->gpio_npins; i++) {
284                 if (sc->gpio_pins[i].gp_pin == pin)
285                         break;
286         }
287
288         if (i >= sc->gpio_npins)
289                 return (EINVAL);
290
291         GPIO_LOCK(sc);
292         *flags = sc->gpio_pins[i].gp_flags;
293         GPIO_UNLOCK(sc);
294
295         return (0);
296 }
297
298 static int
299 socfpga_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
300 {
301         struct socfpga_gpio_softc *sc;
302         int i;
303
304         sc = device_get_softc(dev);
305         for (i = 0; i < sc->gpio_npins; i++) {
306                 if (sc->gpio_pins[i].gp_pin == pin)
307                         break;
308         }
309
310         if (i >= sc->gpio_npins)
311                 return (EINVAL);
312
313         GPIO_LOCK(sc);
314         *val = (READ4(sc, GPIO_EXT_PORTA) & (1 << i)) ? 1 : 0;
315         GPIO_UNLOCK(sc);
316
317         return (0);
318 }
319
320 static int
321 socfpga_gpio_pin_toggle(device_t dev, uint32_t pin)
322 {
323         struct socfpga_gpio_softc *sc;
324         int reg;
325         int i;
326
327         sc = device_get_softc(dev);
328         for (i = 0; i < sc->gpio_npins; i++) {
329                 if (sc->gpio_pins[i].gp_pin == pin)
330                         break;
331         }
332
333         if (i >= sc->gpio_npins)
334                 return (EINVAL);
335
336         GPIO_LOCK(sc);
337         reg = READ4(sc, GPIO_SWPORTA_DR);
338         if (reg & (1 << i))
339                 reg &= ~(1 << i);
340         else
341                 reg |= (1 << i);
342         WRITE4(sc, GPIO_SWPORTA_DR, reg);
343         GPIO_UNLOCK(sc);
344
345         return (0);
346 }
347
348
349 static void
350 socfpga_gpio_pin_configure(struct socfpga_gpio_softc *sc,
351     struct gpio_pin *pin, unsigned int flags)
352 {
353         int reg;
354
355         GPIO_LOCK(sc);
356
357         /*
358          * Manage input/output
359          */
360
361         reg = READ4(sc, GPIO_SWPORTA_DDR);
362         if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) {
363                 pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT);
364                 if (flags & GPIO_PIN_OUTPUT) {
365                         pin->gp_flags |= GPIO_PIN_OUTPUT;
366                         reg |= (1 << pin->gp_pin);
367                 } else {
368                         pin->gp_flags |= GPIO_PIN_INPUT;
369                         reg &= ~(1 << pin->gp_pin);
370                 }
371         }
372
373         WRITE4(sc, GPIO_SWPORTA_DDR, reg);
374         GPIO_UNLOCK(sc);
375 }
376
377
378 static int
379 socfpga_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
380 {
381         struct socfpga_gpio_softc *sc;
382         int i;
383
384         sc = device_get_softc(dev);
385         for (i = 0; i < sc->gpio_npins; i++) {
386                 if (sc->gpio_pins[i].gp_pin == pin)
387                         break;
388         }
389
390         if (i >= sc->gpio_npins)
391                 return (EINVAL);
392
393         socfpga_gpio_pin_configure(sc, &sc->gpio_pins[i], flags);
394
395         return (0);
396 }
397
398 static int
399 socfpga_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
400 {
401         struct socfpga_gpio_softc *sc;
402         int reg;
403         int i;
404
405         sc = device_get_softc(dev);
406
407         for (i = 0; i < sc->gpio_npins; i++) {
408                 if (sc->gpio_pins[i].gp_pin == pin)
409                         break;
410         }
411
412         if (i >= sc->gpio_npins)
413                 return (EINVAL);
414
415         GPIO_LOCK(sc);
416         reg = READ4(sc, GPIO_SWPORTA_DR);
417         if (value)
418                 reg |= (1 << i);
419         else
420                 reg &= ~(1 << i);
421         WRITE4(sc, GPIO_SWPORTA_DR, reg);
422         GPIO_UNLOCK(sc);
423
424         return (0);
425 }
426
427 static device_method_t socfpga_gpio_methods[] = {
428         DEVMETHOD(device_probe,         socfpga_gpio_probe),
429         DEVMETHOD(device_attach,        socfpga_gpio_attach),
430
431         /* GPIO protocol */
432         DEVMETHOD(gpio_get_bus,         socfpga_gpio_get_bus),
433         DEVMETHOD(gpio_pin_max,         socfpga_gpio_pin_max),
434         DEVMETHOD(gpio_pin_getname,     socfpga_gpio_pin_getname),
435         DEVMETHOD(gpio_pin_getcaps,     socfpga_gpio_pin_getcaps),
436         DEVMETHOD(gpio_pin_getflags,    socfpga_gpio_pin_getflags),
437         DEVMETHOD(gpio_pin_get,         socfpga_gpio_pin_get),
438         DEVMETHOD(gpio_pin_toggle,      socfpga_gpio_pin_toggle),
439         DEVMETHOD(gpio_pin_setflags,    socfpga_gpio_pin_setflags),
440         DEVMETHOD(gpio_pin_set,         socfpga_gpio_pin_set),
441         { 0, 0 }
442 };
443
444 static driver_t socfpga_gpio_driver = {
445         "gpio",
446         socfpga_gpio_methods,
447         sizeof(struct socfpga_gpio_softc),
448 };
449
450 static devclass_t socfpga_gpio_devclass;
451
452 DRIVER_MODULE(socfpga_gpio, simplebus, socfpga_gpio_driver,
453     socfpga_gpio_devclass, 0, 0);