xref: /openbsd/sys/arch/riscv64/dev/stfpinctrl.c (revision 4bdff4be)
1 /*	$OpenBSD: stfpinctrl.c,v 1.3 2023/07/05 11:07:37 kettenis Exp $	*/
2 /*
3  * Copyright (c) 2022 Mark Kettenis <kettenis@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/systm.h>
20 #include <sys/device.h>
21 #include <sys/malloc.h>
22 #include <sys/evcount.h>
23 
24 #include <machine/intr.h>
25 #include <machine/bus.h>
26 #include <machine/fdt.h>
27 
28 #include <dev/ofw/openfirm.h>
29 #include <dev/ofw/ofw_clock.h>
30 #include <dev/ofw/ofw_gpio.h>
31 #include <dev/ofw/fdt.h>
32 
33 /* Registers. */
34 
35 #define GPIODIN(pin)			(0x0048 + (((pin) / 32) * 4))
36 #define GPIO_DOUT_CFG(pin)		(0x0050 + ((pin) * 8))
37 #define GPIO_DOEN_CFG(pin)		(0x0054 + ((pin) * 8))
38 #define  GPO_ENABLE			0
39 #define  GPO_DISABLE			1
40 
41 #define PAD_GPIO(pin)			(0x0000 + (((pin) / 2) * 4))
42 #define  PAD_INPUT_ENABLE		(1 << 7)
43 #define  PAD_INPUT_SCHMITT_ENABLE	(1 << 6)
44 #define  PAD_SHIFT(pin)			((pin % 2) * 16)
45 #define PAD_FUNC_SHARE(pin)		(0x0080 + (((pin) / 2) * 4))
46 #define IO_PADSHARE_SEL			0x01a0
47 
48 #define JH7110_DOEN(pin)		(0x0000 + (((pin) / 4) * 4))
49 #define  JH7110_DOEN_SHIFT(pin)		(((pin) % 4) * 8)
50 #define  JH7110_DOEN_MASK		0x3f
51 #define  JH7110_DOEN_ENABLE		0
52 #define  JH7110_DOEN_DISABLE		1
53 #define JH7110_DOUT(pin)		(0x0040 + (((pin) / 4) * 4))
54 #define  JH7110_DOUT_SHIFT(pin)		(((pin) % 4) * 8)
55 #define  JH7110_DOUT_MASK		0x7f
56 #define JH7110_GPIOIN(pin)		(0x0118 + (((pin) / 32) * 4))
57 #define JH7110_PADCFG(pin)		(0x0120 + ((pin) * 4))
58 #define  JH7110_PADCFG_IE		(1 << 0)
59 #define  JH7110_PADCFG_PU		(1 << 3)
60 #define  JH7110_PADCFG_PD		(1 << 4)
61 #define  JH7110_PADCFG_SMT		(1 << 6)
62 
63 #define GPIO_NUM_PINS		64
64 
65 struct stfpinctrl_softc {
66 	struct device		sc_dev;
67 	bus_space_tag_t		sc_iot;
68 	bus_space_handle_t	sc_gpio_ioh;
69 	bus_space_handle_t	sc_padctl_ioh;
70 	bus_size_t		sc_padctl_gpio;
71 	int			sc_node;
72 
73 	struct gpio_controller	sc_gc;
74 };
75 
76 int stfpinctrl_match(struct device *, void *, void *);
77 void stfpinctrl_attach(struct device *, struct device *, void *);
78 
79 const struct cfattach stfpinctrl_ca = {
80 	sizeof (struct stfpinctrl_softc), stfpinctrl_match, stfpinctrl_attach
81 };
82 
83 struct cfdriver stfpinctrl_cd = {
84 	NULL, "stfpinctrl", DV_DULL
85 };
86 
87 void	stfpinctrl_jh7100_config_pin(void *, uint32_t *, int);
88 int	stfpinctrl_jh7100_get_pin(void *, uint32_t *);
89 void	stfpinctrl_jh7100_set_pin(void *, uint32_t *, int);
90 
91 void	stfpinctrl_jh7110_config_pin(void *, uint32_t *, int);
92 int	stfpinctrl_jh7110_get_pin(void *, uint32_t *);
93 void	stfpinctrl_jh7110_set_pin(void *, uint32_t *, int);
94 
95 int
96 stfpinctrl_match(struct device *parent, void *match, void *aux)
97 {
98 	struct fdt_attach_args *faa = aux;
99 
100 	return OF_is_compatible(faa->fa_node, "starfive,jh7100-pinctrl") ||
101 	    OF_is_compatible(faa->fa_node, "starfive,jh7110-sys-pinctrl");
102 }
103 
104 void
105 stfpinctrl_attach(struct device *parent, struct device *self, void *aux)
106 {
107 	struct stfpinctrl_softc *sc = (struct stfpinctrl_softc *)self;
108 	struct fdt_attach_args *faa = aux;
109 	uint32_t sel;
110 
111 	if (faa->fa_nreg < 1) {
112 		printf(": no registers\n");
113 		return;
114 	}
115 
116 	if (OF_is_compatible(faa->fa_node, "starfive,jh7100-pinctrl") &&
117 	    faa->fa_nreg < 2) {
118 		printf(": no padctl registers\n");
119 		return;
120 	}
121 
122 	sc->sc_node = faa->fa_node;
123 	sc->sc_iot = faa->fa_iot;
124 
125 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
126 	    faa->fa_reg[0].size, 0, &sc->sc_gpio_ioh)) {
127 		printf(": can't map registers\n");
128 		return;
129 	}
130 
131 	if (OF_is_compatible(faa->fa_node, "starfive,jh7100-pinctrl") &&
132 	    bus_space_map(sc->sc_iot, faa->fa_reg[1].addr,
133 	    faa->fa_reg[1].size, 0, &sc->sc_padctl_ioh)) {
134 		bus_space_unmap(sc->sc_iot, sc->sc_gpio_ioh,
135 		    faa->fa_reg[0].size);
136 		printf(": can't map registers\n");
137 		return;
138 	}
139 
140 	printf("\n");
141 
142 	if (OF_is_compatible(faa->fa_node, "starfive,jh7100-pinctrl")) {
143 		sel = bus_space_read_4(sc->sc_iot, sc->sc_padctl_ioh,
144 		    IO_PADSHARE_SEL);
145 		switch (sel) {
146 		case 0:
147 		default:
148 			/* No GPIOs available. */
149 			return;
150 		case 1:
151 			sc->sc_padctl_gpio = PAD_GPIO(0);
152 			break;
153 		case 2:
154 			sc->sc_padctl_gpio = PAD_FUNC_SHARE(72);
155 			break;
156 		case 3:
157 			sc->sc_padctl_gpio = PAD_FUNC_SHARE(70);
158 			break;
159 		case 4:
160 		case 5:
161 		case 6:
162 			sc->sc_padctl_gpio = PAD_FUNC_SHARE(0);
163 			break;
164 		}
165 	} else {
166 		reset_deassert(faa->fa_node, NULL);
167 		clock_enable(faa->fa_node, NULL);
168 	}
169 
170 	sc->sc_gc.gc_node = faa->fa_node;
171 	sc->sc_gc.gc_cookie = sc;
172 	if (OF_is_compatible(faa->fa_node, "starfive,jh7100-pinctrl")) {
173 		sc->sc_gc.gc_config_pin = stfpinctrl_jh7100_config_pin;
174 		sc->sc_gc.gc_get_pin = stfpinctrl_jh7100_get_pin;
175 		sc->sc_gc.gc_set_pin = stfpinctrl_jh7100_set_pin;
176 	} else {
177 		sc->sc_gc.gc_config_pin = stfpinctrl_jh7110_config_pin;
178 		sc->sc_gc.gc_get_pin = stfpinctrl_jh7110_get_pin;
179 		sc->sc_gc.gc_set_pin = stfpinctrl_jh7110_set_pin;
180 	}
181 	gpio_controller_register(&sc->sc_gc);
182 }
183 
184 /* JH7100 */
185 
186 void
187 stfpinctrl_jh7100_config_pin(void *cookie, uint32_t *cells, int config)
188 {
189 	struct stfpinctrl_softc *sc = cookie;
190 	uint32_t pin = cells[0];
191 	uint32_t reg;
192 
193 	if (pin >= GPIO_NUM_PINS)
194 		return;
195 
196 	if (config & GPIO_CONFIG_OUTPUT) {
197 		bus_space_write_4(sc->sc_iot, sc->sc_gpio_ioh,
198 		    GPIO_DOEN_CFG(pin), GPO_ENABLE);
199 	} else {
200 		reg = bus_space_read_4(sc->sc_iot, sc->sc_padctl_ioh,
201 		    sc->sc_padctl_gpio + PAD_GPIO(pin));
202 		reg |= (PAD_INPUT_ENABLE << PAD_SHIFT(pin));
203 		reg |= (PAD_INPUT_SCHMITT_ENABLE << PAD_SHIFT(pin));
204 		bus_space_write_4(sc->sc_iot, sc->sc_padctl_ioh,
205 		    sc->sc_padctl_gpio + PAD_GPIO(pin), reg);
206 		bus_space_write_4(sc->sc_iot, sc->sc_gpio_ioh,
207 		    GPIO_DOEN_CFG(pin), GPO_DISABLE);
208 	}
209 }
210 
211 int
212 stfpinctrl_jh7100_get_pin(void *cookie, uint32_t *cells)
213 {
214 	struct stfpinctrl_softc *sc = cookie;
215 	uint32_t pin = cells[0];
216 	uint32_t flags = cells[1];
217 	uint32_t reg;
218 	int val;
219 
220 	if (pin >= GPIO_NUM_PINS)
221 		return 0;
222 
223 	reg = bus_space_read_4(sc->sc_iot, sc->sc_gpio_ioh, GPIODIN(pin));
224 	val = (reg >> (pin % 32)) & 1;
225 	if (flags & GPIO_ACTIVE_LOW)
226 		val = !val;
227 	return val;
228 }
229 
230 void
231 stfpinctrl_jh7100_set_pin(void *cookie, uint32_t *cells, int val)
232 {
233 	struct stfpinctrl_softc *sc = cookie;
234 	uint32_t pin = cells[0];
235 	uint32_t flags = cells[1];
236 
237 	if (pin >= GPIO_NUM_PINS)
238 		return;
239 
240 	if (flags & GPIO_ACTIVE_LOW)
241 		val = !val;
242 	bus_space_write_4(sc->sc_iot, sc->sc_gpio_ioh,
243 	    GPIO_DOUT_CFG(pin), val);
244 }
245 
246 /* JH7110 */
247 
248 void
249 stfpinctrl_jh7110_config_pin(void *cookie, uint32_t *cells, int config)
250 {
251 	struct stfpinctrl_softc *sc = cookie;
252 	uint32_t pin = cells[0];
253 	uint32_t doen, padcfg;
254 
255 	if (pin >= GPIO_NUM_PINS)
256 		return;
257 
258 	doen = bus_space_read_4(sc->sc_iot, sc->sc_gpio_ioh, JH7110_DOEN(pin));
259 	padcfg = bus_space_read_4(sc->sc_iot, sc->sc_gpio_ioh,
260 	    JH7110_PADCFG(pin));
261 	doen &= ~(JH7110_DOEN_MASK << JH7110_DOEN_SHIFT(pin));
262 	if (config & GPIO_CONFIG_OUTPUT) {
263 		doen |= (JH7110_DOEN_ENABLE << JH7110_DOEN_SHIFT(pin));
264 		bus_space_write_4(sc->sc_iot, sc->sc_gpio_ioh,
265 		    JH7110_DOEN(pin), doen);
266 		/* Disable input, Schmitt trigger and bias. */
267 		padcfg &= ~(JH7110_PADCFG_IE | JH7110_PADCFG_SMT);
268 		padcfg &= ~(JH7110_PADCFG_PU | JH7110_PADCFG_PD);
269 		bus_space_write_4(sc->sc_iot, sc->sc_gpio_ioh,
270 		    JH7110_PADCFG(pin), padcfg);
271 	} else {
272 		/* Enable input and Schmitt trigger. */
273 		padcfg |= JH7110_PADCFG_IE | JH7110_PADCFG_SMT;
274 		bus_space_write_4(sc->sc_iot, sc->sc_gpio_ioh,
275 		    JH7110_PADCFG(pin), padcfg);
276 		doen |= (JH7110_DOEN_DISABLE << JH7110_DOEN_SHIFT(pin));
277 		bus_space_write_4(sc->sc_iot, sc->sc_gpio_ioh,
278 		    JH7110_DOEN(pin), doen);
279 	}
280 }
281 
282 int
283 stfpinctrl_jh7110_get_pin(void *cookie, uint32_t *cells)
284 {
285 	struct stfpinctrl_softc *sc = cookie;
286 	uint32_t pin = cells[0];
287 	uint32_t flags = cells[1];
288 	uint32_t reg;
289 	int val;
290 
291 	if (pin >= GPIO_NUM_PINS)
292 		return 0;
293 
294 	reg = bus_space_read_4(sc->sc_iot, sc->sc_gpio_ioh,
295 	    JH7110_GPIOIN(pin));
296 	val = (reg >> (pin % 32)) & 1;
297 	if (flags & GPIO_ACTIVE_LOW)
298 		val = !val;
299 	return val;
300 }
301 
302 void
303 stfpinctrl_jh7110_set_pin(void *cookie, uint32_t *cells, int val)
304 {
305 	struct stfpinctrl_softc *sc = cookie;
306 	uint32_t pin = cells[0];
307 	uint32_t flags = cells[1];
308 	uint32_t reg;
309 
310 	if (pin >= GPIO_NUM_PINS)
311 		return;
312 
313 	if (flags & GPIO_ACTIVE_LOW)
314 		val = !val;
315 
316 	reg = bus_space_read_4(sc->sc_iot, sc->sc_gpio_ioh, JH7110_DOUT(pin));
317 	reg &= ~(JH7110_DOUT_MASK << JH7110_DOUT_SHIFT(pin));
318 	reg |= (val << JH7110_DOUT_SHIFT(pin));
319 	bus_space_write_4(sc->sc_iot, sc->sc_gpio_ioh, JH7110_DOUT(pin), reg);
320 }
321