zy7_gpio.c revision 249997
1/*-
2 * Copyright (C) 2013, Thomas Skibo.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 *   notice, this list of conditions and the following disclaimer.
9 * * 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 * * The names of contributors may not be used to endorse or promote products
13 *   derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND 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 AUTHORS OR CONTRIBUTORS BE LIABLE FOR
19 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 * 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 SUCH
25 * DAMAGE.
26 *
27 */
28
29/* A GPIO driver for Xilinx Zynq-7000.
30 *
31 * The GPIO peripheral on Zynq allows controlling 114 general purpose I/Os.
32 *
33 * Pins 53-0 are sent to the MIO.  Any MIO pins not used by a PS peripheral are
34 * available as a GPIO pin.  Pins 64-127 are sent to the PL (FPGA) section of
35 * Zynq as EMIO signals.
36 *
37 * The hardware provides a way to use IOs as interrupt sources but the
38 * gpio framework doesn't seem to have hooks for this.
39 *
40 * Reference: Zynq-7000 All Programmable SoC Technical Reference Manual.
41 * (v1.4) November 16, 2012.  Xilinx doc UG585.  GPIO is covered in
42 * chater 14.  Register definitions are in appendix B.19.
43 */
44
45#include <sys/cdefs.h>
46__FBSDID("$FreeBSD: head/sys/arm/xilinx/zy7_gpio.c 249997 2013-04-27 22:38:29Z wkoszek $");
47
48#include <sys/param.h>
49#include <sys/systm.h>
50#include <sys/conf.h>
51#include <sys/bus.h>
52#include <sys/kernel.h>
53#include <sys/module.h>
54#include <sys/lock.h>
55#include <sys/mutex.h>
56#include <sys/resource.h>
57#include <sys/rman.h>
58#include <sys/gpio.h>
59
60#include <machine/bus.h>
61#include <machine/resource.h>
62#include <machine/stdarg.h>
63
64#include <dev/fdt/fdt_common.h>
65#include <dev/ofw/ofw_bus.h>
66#include <dev/ofw/ofw_bus_subr.h>
67
68#include "gpio_if.h"
69
70#define NUMBANKS	4
71#define MAXPIN		(32*NUMBANKS)
72
73#define MIO_PIN		0	/* pins 0-53 go to MIO */
74#define NUM_MIO_PINS	54
75#define EMIO_PIN	64	/* pins 64-127 go to PL */
76#define NUM_EMIO_PINS	64
77
78#define VALID_PIN(u)	(((u) >= MIO_PIN && (u) < MIO_PIN + NUM_MIO_PINS) || \
79			 ((u) >= EMIO_PIN && (u) < EMIO_PIN + NUM_EMIO_PINS))
80
81#define ZGPIO_LOCK(sc)			mtx_lock(&(sc)->sc_mtx)
82#define	ZGPIO_UNLOCK(sc)		mtx_unlock(&(sc)->sc_mtx)
83#define ZGPIO_LOCK_INIT(sc) \
84	mtx_init(&(sc)->sc_mtx, device_get_nameunit((sc)->dev),	\
85	    "gpio", MTX_DEF)
86#define ZGPIO_LOCK_DESTROY(_sc)	mtx_destroy(&_sc->sc_mtx);
87
88struct zy7_gpio_softc {
89	device_t	dev;
90	struct mtx	sc_mtx;
91	struct resource *mem_res;	/* Memory resource */
92};
93
94#define WR4(sc, off, val)	bus_write_4((sc)->mem_res, (off), (val))
95#define RD4(sc, off)		bus_read_4((sc)->mem_res, (off))
96
97
98/* Xilinx Zynq-7000 GPIO register definitions:
99 */
100#define ZY7_GPIO_MASK_DATA_LSW(b)	(0x0000+8*(b))	/* maskable wr lo */
101#define ZY7_GPIO_MASK_DATA_MSW(b)	(0x0004+8*(b))	/* maskable wr hi */
102#define ZY7_GPIO_DATA(b)		(0x0040+4*(b))	/* in/out data */
103#define ZY7_GPIO_DATA_RO(b)		(0x0060+4*(b))	/* input data */
104
105#define ZY7_GPIO_DIRM(b)		(0x0204+0x40*(b)) /* direction mode */
106#define ZY7_GPIO_OEN(b)			(0x0208+0x40*(b)) /* output enable */
107#define ZY7_GPIO_INT_MASK(b)		(0x020c+0x40*(b)) /* int mask */
108#define ZY7_GPIO_INT_EN(b)		(0x0210+0x40*(b)) /* int enable */
109#define ZY7_GPIO_INT_DIS(b)		(0x0214+0x40*(b)) /* int disable */
110#define ZY7_GPIO_INT_STAT(b)		(0x0218+0x40*(b)) /* int status */
111#define ZY7_GPIO_INT_TYPE(b)		(0x021c+0x40*(b)) /* int type */
112#define ZY7_GPIO_INT_POLARITY(b)	(0x0220+0x40*(b)) /* int polarity */
113#define ZY7_GPIO_INT_ANY(b)		(0x0224+0x40*(b)) /* any edge */
114
115
116static int
117zy7_gpio_pin_max(device_t dev, int *maxpin)
118{
119
120	*maxpin = MAXPIN;
121	return (0);
122}
123
124/* Get a specific pin's capabilities. */
125static int
126zy7_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
127{
128
129	if (!VALID_PIN(pin))
130		return (EINVAL);
131
132	*caps = (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_TRISTATE);
133
134	return (0);
135}
136
137/* Get a specific pin's name. */
138static int
139zy7_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
140{
141
142	if (!VALID_PIN(pin))
143		return (EINVAL);
144
145	if (pin < NUM_MIO_PINS) {
146		snprintf(name, GPIOMAXNAME, "MIO_%d", pin);
147		name[GPIOMAXNAME - 1] = '\0';
148	} else {
149		snprintf(name, GPIOMAXNAME, "EMIO_%d", pin - EMIO_PIN);
150		name[GPIOMAXNAME - 1] = '\0';
151	}
152
153	return (0);
154}
155
156/* Get a specific pin's current in/out/tri state. */
157static int
158zy7_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
159{
160	struct zy7_gpio_softc *sc = device_get_softc(dev);
161
162	if (!VALID_PIN(pin))
163		return (EINVAL);
164
165	ZGPIO_LOCK(sc);
166
167	if ((RD4(sc, ZY7_GPIO_DIRM(pin >> 5)) & (1 << (pin & 31))) != 0) {
168		/* output */
169		if ((RD4(sc, ZY7_GPIO_OEN(pin >> 5)) & (1 << (pin & 31))) == 0)
170			*flags = (GPIO_PIN_OUTPUT | GPIO_PIN_TRISTATE);
171		else
172			*flags = GPIO_PIN_OUTPUT;
173	} else
174		/* input */
175		*flags = GPIO_PIN_INPUT;
176
177	ZGPIO_UNLOCK(sc);
178
179	return (0);
180}
181
182/* Set a specific pin's in/out/tri state. */
183static int
184zy7_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
185{
186	struct zy7_gpio_softc *sc = device_get_softc(dev);
187
188	if (!VALID_PIN(pin))
189		return (EINVAL);
190
191	ZGPIO_LOCK(sc);
192
193	if ((flags & GPIO_PIN_OUTPUT) != 0) {
194		/* Output.  Set or reset OEN too. */
195		WR4(sc, ZY7_GPIO_DIRM(pin >> 5),
196		    RD4(sc, ZY7_GPIO_DIRM(pin >> 5)) | (1 << (pin & 31)));
197
198		if ((flags & GPIO_PIN_TRISTATE) != 0)
199			WR4(sc, ZY7_GPIO_OEN(pin >> 5),
200			    RD4(sc, ZY7_GPIO_OEN(pin >> 5)) &
201			    ~(1 << (pin & 31)));
202		else
203			WR4(sc, ZY7_GPIO_OEN(pin >> 5),
204			    RD4(sc, ZY7_GPIO_OEN(pin >> 5)) |
205			    (1 << (pin & 31)));
206	} else {
207		/* Input.  Turn off OEN. */
208		WR4(sc, ZY7_GPIO_DIRM(pin >> 5),
209		    RD4(sc, ZY7_GPIO_DIRM(pin >> 5)) & ~(1 << (pin & 31)));
210		WR4(sc, ZY7_GPIO_OEN(pin >> 5),
211		    RD4(sc, ZY7_GPIO_OEN(pin >> 5)) & ~(1 << (pin & 31)));
212	}
213
214	ZGPIO_UNLOCK(sc);
215
216	return (0);
217}
218
219/* Set a specific output pin's value. */
220static int
221zy7_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
222{
223	struct zy7_gpio_softc *sc = device_get_softc(dev);
224
225	if (!VALID_PIN(pin) || value > 1)
226		return (EINVAL);
227
228	/* Fancy register tricks allow atomic set or reset. */
229	if ((pin & 16) != 0)
230		WR4(sc, ZY7_GPIO_MASK_DATA_MSW(pin >> 5),
231		    (0xffff0000 ^ (0x10000 << (pin & 15))) |
232		    (value << (pin & 15)));
233	else
234		WR4(sc, ZY7_GPIO_MASK_DATA_LSW(pin >> 5),
235		    (0xffff0000 ^ (0x10000 << (pin & 15))) |
236		    (value << (pin & 15)));
237
238	return (0);
239}
240
241/* Get a specific pin's input value. */
242static int
243zy7_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *value)
244{
245	struct zy7_gpio_softc *sc = device_get_softc(dev);
246
247	if (!VALID_PIN(pin))
248		return (EINVAL);
249
250	*value = (RD4(sc, ZY7_GPIO_DATA_RO(pin >> 5)) >> (pin & 31)) & 1;
251
252	return (0);
253}
254
255/* Toggle a pin's output value. */
256static int
257zy7_gpio_pin_toggle(device_t dev, uint32_t pin)
258{
259	struct zy7_gpio_softc *sc = device_get_softc(dev);
260
261	if (!VALID_PIN(pin))
262		return (EINVAL);
263
264	ZGPIO_LOCK(sc);
265
266	WR4(sc, ZY7_GPIO_DATA(pin >> 5),
267	    RD4(sc, ZY7_GPIO_DATA(pin >> 5)) ^ (1 << (pin & 31)));
268
269	ZGPIO_UNLOCK(sc);
270
271	return (0);
272}
273
274static int
275zy7_gpio_probe(device_t dev)
276{
277
278	if (!ofw_bus_is_compatible(dev, "xlnx,zy7_gpio"))
279		return (ENXIO);
280
281	device_set_desc(dev, "Zynq-7000 GPIO driver");
282	return (0);
283}
284
285static void
286zy7_gpio_hw_reset(struct zy7_gpio_softc *sc)
287{
288	int i;
289
290	for (i = 0; i < NUMBANKS; i++) {
291		WR4(sc, ZY7_GPIO_DATA(i), 0);
292		WR4(sc, ZY7_GPIO_DIRM(i), 0);
293		WR4(sc, ZY7_GPIO_OEN(i), 0);
294		WR4(sc, ZY7_GPIO_INT_DIS(i), 0xffffffff);
295		WR4(sc, ZY7_GPIO_INT_POLARITY(i), 0);
296		WR4(sc, ZY7_GPIO_INT_TYPE(i),
297		    i == 1 ? 0x003fffff : 0xffffffff);
298		WR4(sc, ZY7_GPIO_INT_ANY(i), 0);
299		WR4(sc, ZY7_GPIO_INT_STAT(i), 0xffffffff);
300	}
301}
302
303static int zy7_gpio_detach(device_t dev);
304
305static int
306zy7_gpio_attach(device_t dev)
307{
308	struct zy7_gpio_softc *sc = device_get_softc(dev);
309	int rid;
310
311	sc->dev = dev;
312
313	ZGPIO_LOCK_INIT(sc);
314
315	/* Allocate memory. */
316	rid = 0;
317	sc->mem_res = bus_alloc_resource_any(dev,
318		     SYS_RES_MEMORY, &rid, RF_ACTIVE);
319	if (sc->mem_res == NULL) {
320		device_printf(dev, "Can't allocate memory for device");
321		zy7_gpio_detach(dev);
322		return (ENOMEM);
323	}
324
325	/* Completely reset. */
326	zy7_gpio_hw_reset(sc);
327
328	device_add_child(dev, "gpioc", device_get_unit(dev));
329	device_add_child(dev, "gpiobus", device_get_unit(dev));
330
331	return (bus_generic_attach(dev));
332}
333
334static int
335zy7_gpio_detach(device_t dev)
336{
337	struct zy7_gpio_softc *sc = device_get_softc(dev);
338
339	bus_generic_detach(dev);
340
341	if (sc->mem_res != NULL) {
342		/* Release memory resource. */
343		bus_release_resource(dev, SYS_RES_MEMORY,
344				     rman_get_rid(sc->mem_res), sc->mem_res);
345	}
346
347	ZGPIO_LOCK_DESTROY(sc);
348
349	return (0);
350}
351
352static device_method_t zy7_gpio_methods[] = {
353	/* device_if */
354	DEVMETHOD(device_probe, 	zy7_gpio_probe),
355	DEVMETHOD(device_attach, 	zy7_gpio_attach),
356	DEVMETHOD(device_detach, 	zy7_gpio_detach),
357
358	/* GPIO protocol */
359	DEVMETHOD(gpio_pin_max, 	zy7_gpio_pin_max),
360	DEVMETHOD(gpio_pin_getname, 	zy7_gpio_pin_getname),
361	DEVMETHOD(gpio_pin_getflags, 	zy7_gpio_pin_getflags),
362	DEVMETHOD(gpio_pin_getcaps, 	zy7_gpio_pin_getcaps),
363	DEVMETHOD(gpio_pin_setflags, 	zy7_gpio_pin_setflags),
364	DEVMETHOD(gpio_pin_get, 	zy7_gpio_pin_get),
365	DEVMETHOD(gpio_pin_set, 	zy7_gpio_pin_set),
366	DEVMETHOD(gpio_pin_toggle, 	zy7_gpio_pin_toggle),
367
368	DEVMETHOD_END
369};
370
371static driver_t zy7_gpio_driver = {
372	"zy7_gpio",
373	zy7_gpio_methods,
374	sizeof(struct zy7_gpio_softc),
375};
376static devclass_t zy7_gpio_devclass;
377
378extern devclass_t gpiobus_devclass, gpioc_devclass;
379extern driver_t gpiobus_driver, gpioc_driver;
380
381DRIVER_MODULE(zy7_gpio, simplebus, zy7_gpio_driver, zy7_gpio_devclass, \
382	      NULL, NULL);
383DRIVER_MODULE(gpiobus, zy7_gpio, gpiobus_driver, gpiobus_devclass, 0, 0);
384DRIVER_MODULE(gpioc, zy7_gpio, gpioc_driver, gpioc_devclass, 0, 0);
385