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