xref: /openbsd-src/sys/arch/riscv64/dev/mpfgpio.c (revision 3b631e80721f28fd06f68adc3d62cdb9c478ebef)
1 /*	$OpenBSD: mpfgpio.c,v 1.1 2022/02/18 10:51:43 visa Exp $	*/
2 
3 /*
4  * Copyright (c) 2022 Visa Hankala
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /*
20  * Driver for PolarFire SoC MSS GPIO controller.
21  */
22 
23 #include <sys/param.h>
24 #include <sys/systm.h>
25 #include <sys/device.h>
26 #include <sys/gpio.h>
27 
28 #include <machine/bus.h>
29 #include <machine/fdt.h>
30 
31 #include <dev/gpio/gpiovar.h>
32 
33 #include <dev/ofw/fdt.h>
34 #include <dev/ofw/openfirm.h>
35 #include <dev/ofw/ofw_clock.h>
36 #include <dev/ofw/ofw_gpio.h>
37 
38 #include "gpio.h"
39 
40 #define MPFGPIO_CONFIG(i)	(0x0000 + (i) * 4)
41 #define  MPFGPIO_CONFIG_EN_INT		(1 << 3)
42 #define  MPFGPIO_CONFIG_EN_OE_BUF	(1 << 2)
43 #define  MPFGPIO_CONFIG_EN_IN		(1 << 1)
44 #define  MPFGPIO_CONFIG_EN_OUT		(1 << 0)
45 #define MPFGPIO_GPIN		0x0084
46 #define MPFGPIO_GPOUT		0x0088
47 #define MPFGPIO_CLEAR_BITS	0x00a0
48 #define MPFGPIO_SET_BITS	0x00a4
49 
50 #define MPFGPIO_MAX_PINS	32
51 
52 struct mpfgpio_softc {
53 	struct device		sc_dev;
54 	bus_space_tag_t		sc_iot;
55 	bus_space_handle_t	sc_ioh;
56 	uint32_t		sc_npins;
57 
58 	struct gpio_controller	sc_gc;
59 
60 	struct gpio_chipset_tag	sc_gpio_tag;
61 	gpio_pin_t		sc_gpio_pins[MPFGPIO_MAX_PINS];
62 	uint8_t			sc_gpio_claimed[MPFGPIO_MAX_PINS];
63 };
64 
65 #define HREAD4(sc, reg) \
66 	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
67 #define HWRITE4(sc, reg, val) \
68 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
69 
70 int	mpfgpio_match(struct device *, void *, void*);
71 void	mpfgpio_attach(struct device *, struct device *, void *);
72 
73 void	mpfgpio_config_pin(void *, uint32_t *, int);
74 int	mpfgpio_get_pin(void *, uint32_t *);
75 void	mpfgpio_set_pin(void *, uint32_t *, int);
76 
77 int	mpfgpio_pin_read(void *, int);
78 void	mpfgpio_pin_write(void *, int, int);
79 void	mpfgpio_pin_ctl(void *, int, int);
80 void	mpfgpio_attach_gpio(struct device *);
81 
82 const struct cfattach mpfgpio_ca = {
83 	sizeof(struct mpfgpio_softc), mpfgpio_match, mpfgpio_attach
84 };
85 
86 struct cfdriver mpfgpio_cd = {
87 	NULL, "mpfgpio", DV_DULL
88 };
89 
90 int
mpfgpio_match(struct device * parent,void * match,void * aux)91 mpfgpio_match(struct device *parent, void *match, void *aux)
92 {
93 	struct fdt_attach_args *faa = aux;
94 
95 	if (faa->fa_nreg < 1)
96 		return 0;
97 	return OF_is_compatible(faa->fa_node, "microchip,mpfs-gpio");
98 }
99 
100 void
mpfgpio_attach(struct device * parent,struct device * self,void * aux)101 mpfgpio_attach(struct device *parent, struct device *self, void *aux)
102 {
103 	struct fdt_attach_args *faa = aux;
104 	struct mpfgpio_softc *sc = (struct mpfgpio_softc *)self;
105 	unsigned int unit;
106 
107 	sc->sc_iot = faa->fa_iot;
108 
109 	unit = (faa->fa_reg[0].addr >> 12) & 0x3;
110 	switch (unit) {
111 	case 0:
112 		sc->sc_npins = 14;
113 		break;
114 	case 1:
115 		sc->sc_npins = 24;
116 		break;
117 	case 2:
118 		sc->sc_npins = 32;
119 		break;
120 	default:
121 		printf(": unexpected GPIO unit %u\n", unit);
122 		return;
123 	}
124 	KASSERT(sc->sc_npins <= MPFGPIO_MAX_PINS);
125 
126 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, faa->fa_reg[0].size,
127 	    0, &sc->sc_ioh) != 0) {
128 		printf(": can't map registers\n");
129 		return;
130 	}
131 
132 	clock_enable_all(faa->fa_node);
133 
134 	printf(": unit %u\n", unit);
135 
136 	sc->sc_gc.gc_node = faa->fa_node;
137 	sc->sc_gc.gc_cookie = sc;
138 	sc->sc_gc.gc_config_pin = mpfgpio_config_pin;
139 	sc->sc_gc.gc_get_pin = mpfgpio_get_pin;
140 	sc->sc_gc.gc_set_pin = mpfgpio_set_pin;
141 	gpio_controller_register(&sc->sc_gc);
142 
143 #if NGPIO > 0
144 	config_mountroot(self, mpfgpio_attach_gpio);
145 #endif
146 }
147 
148 void
mpfgpio_config_pin(void * cookie,uint32_t * cells,int config)149 mpfgpio_config_pin(void *cookie, uint32_t *cells, int config)
150 {
151 	struct mpfgpio_softc *sc = cookie;
152 	uint32_t pin = cells[0];
153 	uint32_t val;
154 
155 	if (pin >= sc->sc_npins)
156 		return;
157 
158 	val = HREAD4(sc, MPFGPIO_CONFIG(pin));
159 	if (config & GPIO_CONFIG_OUTPUT) {
160 		val &= ~MPFGPIO_CONFIG_EN_IN;
161 		val |= MPFGPIO_CONFIG_EN_OUT;
162 	} else {
163 		val |= MPFGPIO_CONFIG_EN_IN;
164 		val &= ~MPFGPIO_CONFIG_EN_OUT;
165 	}
166 	val &= ~MPFGPIO_CONFIG_EN_INT;
167 	HWRITE4(sc, MPFGPIO_CONFIG(pin), val);
168 
169 	sc->sc_gpio_claimed[pin] = 1;
170 }
171 
172 int
mpfgpio_get_pin(void * cookie,uint32_t * cells)173 mpfgpio_get_pin(void *cookie, uint32_t *cells)
174 {
175 	struct mpfgpio_softc *sc = cookie;
176 	uint32_t pin = cells[0];
177 	uint32_t flags = cells[1];
178 	int val;
179 
180 	if (pin >= sc->sc_npins)
181 		return 0;
182 
183 	val = (HREAD4(sc, MPFGPIO_GPIN) >> pin) & 1;
184 	if (flags & GPIO_ACTIVE_LOW)
185 		val = !val;
186 	return val;
187 }
188 
189 void
mpfgpio_set_pin(void * cookie,uint32_t * cells,int val)190 mpfgpio_set_pin(void *cookie, uint32_t *cells, int val)
191 {
192 	struct mpfgpio_softc *sc = cookie;
193 	uint32_t pin = cells[0];
194 	uint32_t flags = cells[1];
195 
196 	if (pin >= sc->sc_npins)
197 		return;
198 
199 	if (flags & GPIO_ACTIVE_LOW)
200 		val = !val;
201 	if (val)
202 		HWRITE4(sc, MPFGPIO_SET_BITS, (1U << (pin % 32)));
203 	else
204 		HWRITE4(sc, MPFGPIO_CLEAR_BITS, (1U << (pin % 32)));
205 }
206 
207 #if NGPIO > 0
208 int
mpfgpio_pin_read(void * cookie,int pin)209 mpfgpio_pin_read(void *cookie, int pin)
210 {
211 	struct mpfgpio_softc *sc = cookie;
212 	uint32_t cells[2];
213 
214 	cells[0] = pin;
215 	cells[1] = 0;
216 
217 	return mpfgpio_get_pin(sc, cells) ? GPIO_PIN_HIGH : GPIO_PIN_LOW;
218 }
219 
220 void
mpfgpio_pin_write(void * cookie,int pin,int val)221 mpfgpio_pin_write(void *cookie, int pin, int val)
222 {
223 	struct mpfgpio_softc *sc = cookie;
224 	uint32_t cells[2];
225 
226 	cells[0] = pin;
227 	cells[1] = 0;
228 
229 	mpfgpio_set_pin(sc, cells, val);
230 }
231 
232 void
mpfgpio_pin_ctl(void * cookie,int pin,int flags)233 mpfgpio_pin_ctl(void *cookie, int pin, int flags)
234 {
235 	struct mpfgpio_softc *sc = cookie;
236 	uint32_t cells[2];
237 	uint32_t config = 0;
238 
239 	cells[0] = pin;
240 	cells[1] = 0;
241 
242 	if (flags & GPIO_PIN_OUTPUT)
243 		config |= GPIO_CONFIG_OUTPUT;
244 
245 	mpfgpio_config_pin(sc, cells, config);
246 }
247 
248 static const struct gpio_chipset_tag mpfgpio_gpio_tag = {
249 	.gp_pin_read	= mpfgpio_pin_read,
250 	.gp_pin_write	= mpfgpio_pin_write,
251 	.gp_pin_ctl	= mpfgpio_pin_ctl,
252 };
253 
254 void
mpfgpio_attach_gpio(struct device * parent)255 mpfgpio_attach_gpio(struct device *parent)
256 {
257 	struct gpiobus_attach_args gba;
258 	struct mpfgpio_softc *sc = (struct mpfgpio_softc *)parent;
259 	uint32_t cfgreg, pin;
260 	int flags, state;
261 
262 	for (pin = 0; pin < sc->sc_npins; pin++) {
263 		/* Skip pins claimed by other devices. */
264 		if (sc->sc_gpio_claimed[pin])
265 			continue;
266 
267 		cfgreg = HREAD4(sc, MPFGPIO_CONFIG(pin));
268 		if (cfgreg & MPFGPIO_CONFIG_EN_OUT)
269 			flags = GPIO_PIN_SET | GPIO_PIN_OUTPUT;
270 		else if (cfgreg & MPFGPIO_CONFIG_EN_IN)
271 			flags = GPIO_PIN_SET | GPIO_PIN_INPUT;
272 		else
273 			flags = GPIO_PIN_SET;
274 
275 		state = (HREAD4(sc, MPFGPIO_GPIN) >> pin) & 1;
276 
277 		sc->sc_gpio_pins[pin].pin_caps =
278 		    GPIO_PIN_INPUT | GPIO_PIN_OUTPUT;
279 		sc->sc_gpio_pins[pin].pin_flags = flags;
280 		sc->sc_gpio_pins[pin].pin_state = state;
281 		sc->sc_gpio_pins[pin].pin_num = pin;
282 	}
283 
284 	sc->sc_gpio_tag = mpfgpio_gpio_tag;
285 	sc->sc_gpio_tag.gp_cookie = sc;
286 
287 	gba.gba_name = "gpio";
288 	gba.gba_gc = &sc->sc_gpio_tag;
289 	gba.gba_pins = sc->sc_gpio_pins;
290 	gba.gba_npins = sc->sc_npins;
291 
292 	config_found(&sc->sc_dev, &gba, gpiobus_print);
293 }
294 #endif
295