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