1 /* $OpenBSD: chvgpio.c,v 1.13 2022/10/20 20:40:57 kettenis Exp $ */
2 /*
3 * Copyright (c) 2016 Mark Kettenis
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/malloc.h>
20 #include <sys/systm.h>
21
22 #include <dev/acpi/acpireg.h>
23 #include <dev/acpi/acpivar.h>
24 #include <dev/acpi/acpidev.h>
25 #include <dev/acpi/amltypes.h>
26 #include <dev/acpi/dsdt.h>
27
28 #define CHVGPIO_INTERRUPT_STATUS 0x0300
29 #define CHVGPIO_INTERRUPT_MASK 0x0380
30 #define CHVGPIO_PAD_CFG0 0x4400
31 #define CHVGPIO_PAD_CFG1 0x4404
32
33 #define CHVGPIO_PAD_CFG0_GPIORXSTATE 0x00000001
34 #define CHVGPIO_PAD_CFG0_GPIOTXSTATE 0x00000002
35 #define CHVGPIO_PAD_CFG0_INTSEL_MASK 0xf0000000
36 #define CHVGPIO_PAD_CFG0_INTSEL_SHIFT 28
37
38 #define CHVGPIO_PAD_CFG1_INTWAKECFG_MASK 0x00000007
39 #define CHVGPIO_PAD_CFG1_INTWAKECFG_FALLING 0x00000001
40 #define CHVGPIO_PAD_CFG1_INTWAKECFG_RISING 0x00000002
41 #define CHVGPIO_PAD_CFG1_INTWAKECFG_BOTH 0x00000003
42 #define CHVGPIO_PAD_CFG1_INTWAKECFG_LEVEL 0x00000004
43 #define CHVGPIO_PAD_CFG1_INVRXTX_MASK 0x000000f0
44 #define CHVGPIO_PAD_CFG1_INVRXTX_RXDATA 0x00000040
45
46 /* OEM defined RegionSpace. */
47 #define CHVGPIO_REGIONSPACE_BASE 0x90
48
49 struct chvgpio_intrhand {
50 int (*ih_func)(void *);
51 void *ih_arg;
52 };
53
54 struct chvgpio_softc {
55 struct device sc_dev;
56 struct acpi_softc *sc_acpi;
57 struct aml_node *sc_node;
58
59 bus_space_tag_t sc_memt;
60 bus_space_handle_t sc_memh;
61 bus_size_t sc_size;
62 void *sc_ih;
63
64 const int *sc_pins;
65 int sc_npins;
66 int sc_ngroups;
67
68 struct chvgpio_intrhand sc_pin_ih[16];
69
70 struct acpi_gpio sc_gpio;
71 };
72
73 static inline int
chvgpio_pad_cfg0_offset(int pin)74 chvgpio_pad_cfg0_offset(int pin)
75 {
76 return (CHVGPIO_PAD_CFG0 + 1024 * (pin / 15) + 8 * (pin % 15));
77 }
78
79 static inline int
chvgpio_read_pad_cfg0(struct chvgpio_softc * sc,int pin)80 chvgpio_read_pad_cfg0(struct chvgpio_softc *sc, int pin)
81 {
82 return bus_space_read_4(sc->sc_memt, sc->sc_memh,
83 chvgpio_pad_cfg0_offset(pin));
84 }
85
86 static inline void
chvgpio_write_pad_cfg0(struct chvgpio_softc * sc,int pin,uint32_t val)87 chvgpio_write_pad_cfg0(struct chvgpio_softc *sc, int pin, uint32_t val)
88 {
89 bus_space_write_4(sc->sc_memt, sc->sc_memh,
90 chvgpio_pad_cfg0_offset(pin), val);
91 }
92
93 static inline int
chvgpio_read_pad_cfg1(struct chvgpio_softc * sc,int pin)94 chvgpio_read_pad_cfg1(struct chvgpio_softc *sc, int pin)
95 {
96 return bus_space_read_4(sc->sc_memt, sc->sc_memh,
97 chvgpio_pad_cfg0_offset(pin) + 4);
98 }
99
100 static inline void
chvgpio_write_pad_cfg1(struct chvgpio_softc * sc,int pin,uint32_t val)101 chvgpio_write_pad_cfg1(struct chvgpio_softc *sc, int pin, uint32_t val)
102 {
103 bus_space_write_4(sc->sc_memt, sc->sc_memh,
104 chvgpio_pad_cfg0_offset(pin) + 4, val);
105 }
106
107 int chvgpio_match(struct device *, void *, void *);
108 void chvgpio_attach(struct device *, struct device *, void *);
109
110 const struct cfattach chvgpio_ca = {
111 sizeof(struct chvgpio_softc), chvgpio_match, chvgpio_attach
112 };
113
114 struct cfdriver chvgpio_cd = {
115 NULL, "chvgpio", DV_DULL
116 };
117
118 const char *chvgpio_hids[] = {
119 "INT33FF",
120 NULL
121 };
122
123 /*
124 * The pads for the pins are arranged in groups of maximal 15 pins.
125 * The arrays below give the number of pins per group, such that we
126 * can validate the (untrusted) pin numbers from ACPI.
127 */
128
129 const int chv_southwest_pins[] = {
130 8, 8, 8, 8, 8, 8, 8, -1
131 };
132
133 const int chv_north_pins[] = {
134 9, 13, 12, 12, 13, -1
135 };
136
137 const int chv_east_pins[] = {
138 12, 12, -1
139 };
140
141 const int chv_southeast_pins[] = {
142 8, 12, 6, 8, 10, 11, -1
143 };
144
145 int chvgpio_check_pin(struct chvgpio_softc *, int);
146 int chvgpio_read_pin(void *, int);
147 void chvgpio_write_pin(void *, int, int);
148 void chvgpio_intr_establish(void *, int, int, int (*)(void *), void *);
149 void chvgpio_intr_enable(void *, int);
150 void chvgpio_intr_disable(void *, int);
151 int chvgpio_intr(void *);
152 int chvgpio_opreg_handler(void *, int, uint64_t, int, uint64_t *);
153
154 int
chvgpio_match(struct device * parent,void * match,void * aux)155 chvgpio_match(struct device *parent, void *match, void *aux)
156 {
157 struct acpi_attach_args *aaa = aux;
158 struct cfdata *cf = match;
159
160 if (aaa->aaa_naddr < 1 || aaa->aaa_nirq < 1)
161 return 0;
162 return acpi_matchhids(aaa, chvgpio_hids, cf->cf_driver->cd_name);
163 }
164
165 void
chvgpio_attach(struct device * parent,struct device * self,void * aux)166 chvgpio_attach(struct device *parent, struct device *self, void *aux)
167 {
168 struct chvgpio_softc *sc = (struct chvgpio_softc *)self;
169 struct acpi_attach_args *aaa = aux;
170 int64_t uid;
171 int i;
172
173 sc->sc_acpi = (struct acpi_softc *)parent;
174 sc->sc_node = aaa->aaa_node;
175 printf(" %s", sc->sc_node->name);
176
177 if (aml_evalinteger(sc->sc_acpi, sc->sc_node, "_UID", 0, NULL, &uid)) {
178 printf(": can't find uid\n");
179 return;
180 }
181
182 printf(" uid %lld", uid);
183
184 switch (uid) {
185 case 1:
186 sc->sc_pins = chv_southwest_pins;
187 break;
188 case 2:
189 sc->sc_pins = chv_north_pins;
190 break;
191 case 3:
192 sc->sc_pins = chv_east_pins;
193 break;
194 case 4:
195 sc->sc_pins = chv_southeast_pins;
196 break;
197 default:
198 printf("\n");
199 return;
200 }
201
202 for (i = 0; sc->sc_pins[i] >= 0; i++) {
203 sc->sc_npins += sc->sc_pins[i];
204 sc->sc_ngroups++;
205 }
206
207 printf(" addr 0x%llx/0x%llx", aaa->aaa_addr[0], aaa->aaa_size[0]);
208 printf(" irq %d", aaa->aaa_irq[0]);
209
210 sc->sc_memt = aaa->aaa_bst[0];
211 sc->sc_size = aaa->aaa_size[0];
212 if (bus_space_map(sc->sc_memt, aaa->aaa_addr[0], aaa->aaa_size[0],
213 0, &sc->sc_memh)) {
214 printf(": can't map registers\n");
215 return;
216 }
217
218 sc->sc_ih = acpi_intr_establish(aaa->aaa_irq[0], aaa->aaa_irq_flags[0],
219 IPL_BIO, chvgpio_intr, sc, sc->sc_dev.dv_xname);
220 if (sc->sc_ih == NULL) {
221 printf(": can't establish interrupt\n");
222 goto unmap;
223 }
224
225 sc->sc_gpio.cookie = sc;
226 sc->sc_gpio.read_pin = chvgpio_read_pin;
227 sc->sc_gpio.write_pin = chvgpio_write_pin;
228 sc->sc_gpio.intr_establish = chvgpio_intr_establish;
229 sc->sc_gpio.intr_enable = chvgpio_intr_enable;
230 sc->sc_gpio.intr_disable = chvgpio_intr_disable;
231 sc->sc_node->gpio = &sc->sc_gpio;
232
233 /* Mask and ack all interrupts. */
234 bus_space_write_4(sc->sc_memt, sc->sc_memh,
235 CHVGPIO_INTERRUPT_MASK, 0);
236 bus_space_write_4(sc->sc_memt, sc->sc_memh,
237 CHVGPIO_INTERRUPT_STATUS, 0xffff);
238
239 printf(", %d pins\n", sc->sc_npins);
240
241 /* Register OEM defined address space. */
242 aml_register_regionspace(sc->sc_node, CHVGPIO_REGIONSPACE_BASE + uid,
243 sc, chvgpio_opreg_handler);
244
245 acpi_register_gpio(sc->sc_acpi, sc->sc_node);
246 return;
247
248 unmap:
249 bus_space_unmap(sc->sc_memt, sc->sc_memh, sc->sc_size);
250 }
251
252 int
chvgpio_check_pin(struct chvgpio_softc * sc,int pin)253 chvgpio_check_pin(struct chvgpio_softc *sc, int pin)
254 {
255 if (pin < 0)
256 return EINVAL;
257 if ((pin / 15) >= sc->sc_ngroups)
258 return EINVAL;
259 if ((pin % 15) >= sc->sc_pins[pin / 15])
260 return EINVAL;
261
262 return 0;
263 }
264
265 int
chvgpio_read_pin(void * cookie,int pin)266 chvgpio_read_pin(void *cookie, int pin)
267 {
268 struct chvgpio_softc *sc = cookie;
269 uint32_t reg;
270
271 KASSERT(chvgpio_check_pin(sc, pin) == 0);
272
273 reg = chvgpio_read_pad_cfg0(sc, pin);
274 return (reg & CHVGPIO_PAD_CFG0_GPIORXSTATE);
275 }
276
277 void
chvgpio_write_pin(void * cookie,int pin,int value)278 chvgpio_write_pin(void *cookie, int pin, int value)
279 {
280 struct chvgpio_softc *sc = cookie;
281 uint32_t reg;
282
283 KASSERT(chvgpio_check_pin(sc, pin) == 0);
284
285 reg = chvgpio_read_pad_cfg0(sc, pin);
286 if (value)
287 reg |= CHVGPIO_PAD_CFG0_GPIOTXSTATE;
288 else
289 reg &= ~CHVGPIO_PAD_CFG0_GPIOTXSTATE;
290 chvgpio_write_pad_cfg0(sc, pin, reg);
291 }
292
293 void
chvgpio_intr_establish(void * cookie,int pin,int flags,int (* func)(void *),void * arg)294 chvgpio_intr_establish(void *cookie, int pin, int flags,
295 int (*func)(void *), void *arg)
296 {
297 struct chvgpio_softc *sc = cookie;
298 uint32_t reg;
299 int line;
300
301 KASSERT(chvgpio_check_pin(sc, pin) == 0);
302
303 reg = chvgpio_read_pad_cfg0(sc, pin);
304 reg &= CHVGPIO_PAD_CFG0_INTSEL_MASK;
305 line = reg >> CHVGPIO_PAD_CFG0_INTSEL_SHIFT;
306
307 sc->sc_pin_ih[line].ih_func = func;
308 sc->sc_pin_ih[line].ih_arg = arg;
309
310 reg = chvgpio_read_pad_cfg1(sc, pin);
311 reg &= ~CHVGPIO_PAD_CFG1_INTWAKECFG_MASK;
312 reg &= ~CHVGPIO_PAD_CFG1_INVRXTX_MASK;
313 switch (flags & (LR_GPIO_MODE | LR_GPIO_POLARITY)) {
314 case LR_GPIO_LEVEL | LR_GPIO_ACTLO:
315 reg |= CHVGPIO_PAD_CFG1_INVRXTX_RXDATA;
316 /* FALLTHROUGH */
317 case LR_GPIO_LEVEL | LR_GPIO_ACTHI:
318 reg |= CHVGPIO_PAD_CFG1_INTWAKECFG_LEVEL;
319 break;
320 case LR_GPIO_EDGE | LR_GPIO_ACTLO:
321 reg |= CHVGPIO_PAD_CFG1_INTWAKECFG_FALLING;
322 break;
323 case LR_GPIO_EDGE | LR_GPIO_ACTHI:
324 reg |= CHVGPIO_PAD_CFG1_INTWAKECFG_RISING;
325 break;
326 case LR_GPIO_EDGE | LR_GPIO_ACTBOTH:
327 reg |= CHVGPIO_PAD_CFG1_INTWAKECFG_BOTH;
328 break;
329 default:
330 printf("%s: unsupported interrupt mode/polarity\n",
331 sc->sc_dev.dv_xname);
332 break;
333 }
334 chvgpio_write_pad_cfg1(sc, pin, reg);
335
336 reg = bus_space_read_4(sc->sc_memt, sc->sc_memh,
337 CHVGPIO_INTERRUPT_MASK);
338 bus_space_write_4(sc->sc_memt, sc->sc_memh,
339 CHVGPIO_INTERRUPT_MASK, reg | (1 << line));
340 }
341
342 void
chvgpio_intr_enable(void * cookie,int pin)343 chvgpio_intr_enable(void *cookie, int pin)
344 {
345 struct chvgpio_softc *sc = cookie;
346 uint32_t reg;
347 int line;
348
349 KASSERT(chvgpio_check_pin(sc, pin) == 0);
350
351 reg = chvgpio_read_pad_cfg0(sc, pin);
352 reg &= CHVGPIO_PAD_CFG0_INTSEL_MASK;
353 line = reg >> CHVGPIO_PAD_CFG0_INTSEL_SHIFT;
354
355 reg = bus_space_read_4(sc->sc_memt, sc->sc_memh,
356 CHVGPIO_INTERRUPT_MASK);
357 bus_space_write_4(sc->sc_memt, sc->sc_memh,
358 CHVGPIO_INTERRUPT_MASK, reg | (1 << line));
359 }
360
361 void
chvgpio_intr_disable(void * cookie,int pin)362 chvgpio_intr_disable(void *cookie, int pin)
363 {
364 struct chvgpio_softc *sc = cookie;
365 uint32_t reg;
366 int line;
367
368 KASSERT(chvgpio_check_pin(sc, pin) == 0);
369
370 reg = chvgpio_read_pad_cfg0(sc, pin);
371 reg &= CHVGPIO_PAD_CFG0_INTSEL_MASK;
372 line = reg >> CHVGPIO_PAD_CFG0_INTSEL_SHIFT;
373
374 reg = bus_space_read_4(sc->sc_memt, sc->sc_memh,
375 CHVGPIO_INTERRUPT_MASK);
376 bus_space_write_4(sc->sc_memt, sc->sc_memh,
377 CHVGPIO_INTERRUPT_MASK, reg & ~(1 << line));
378 }
379
380 int
chvgpio_intr(void * arg)381 chvgpio_intr(void *arg)
382 {
383 struct chvgpio_softc *sc = arg;
384 uint32_t reg;
385 int rc = 0;
386 int line;
387
388 reg = bus_space_read_4(sc->sc_memt, sc->sc_memh,
389 CHVGPIO_INTERRUPT_STATUS);
390 for (line = 0; line < 16; line++) {
391 if ((reg & (1 << line)) == 0)
392 continue;
393
394 bus_space_write_4(sc->sc_memt,sc->sc_memh,
395 CHVGPIO_INTERRUPT_STATUS, 1 << line);
396 if (sc->sc_pin_ih[line].ih_func)
397 sc->sc_pin_ih[line].ih_func(sc->sc_pin_ih[line].ih_arg);
398 rc = 1;
399 }
400
401 return rc;
402 }
403
404 int
chvgpio_opreg_handler(void * cookie,int iodir,uint64_t address,int size,uint64_t * value)405 chvgpio_opreg_handler(void *cookie, int iodir, uint64_t address, int size,
406 uint64_t *value)
407 {
408 struct chvgpio_softc *sc = cookie;
409
410 /* Only allow 32-bit access. */
411 if (size != 4 || address > sc->sc_size - size)
412 return -1;
413
414 if (iodir == ACPI_IOREAD)
415 *value = bus_space_read_4(sc->sc_memt, sc->sc_memh, address);
416 else
417 bus_space_write_4(sc->sc_memt, sc->sc_memh, address, *value);
418
419 return 0;
420 }
421