1 /*        $NetBSD: amdgpio.c,v 1.3 2025/03/02 13:47:35 riastradh Exp $          */
2 
3 /*-
4  * Copyright (c) 2024 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jared McNeill <jmcneill@invisible.ca>.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: amdgpio.c,v 1.3 2025/03/02 13:47:35 riastradh Exp $");
34 
35 #include <sys/param.h>
36 #include <sys/bus.h>
37 #include <sys/cpu.h>
38 #include <sys/device.h>
39 #include <sys/gpio.h>
40 #include <sys/kmem.h>
41 #include <sys/mutex.h>
42 #include <sys/queue.h>
43 
44 #include <dev/acpi/acpireg.h>
45 #include <dev/acpi/acpivar.h>
46 #include <dev/acpi/acpi_event.h>
47 #include <dev/acpi/acpi_gpio.h>
48 #include <dev/acpi/acpi_intr.h>
49 #include <dev/acpi/amdgpioreg.h>
50 
51 #include <dev/gpio/gpiovar.h>
52 
53 struct amdgpio_config {
54           u_int     num_pins;
55           int       (*translate)(ACPI_RESOURCE_GPIO *);
56 };
57 
58 struct amdgpio_intr_handler {
59           int       (*ih_func)(void *);
60           void      *ih_arg;
61           int       ih_pin;
62           LIST_ENTRY(amdgpio_intr_handler) ih_list;
63 };
64 
65 struct amdgpio_softc {
66           device_t                      sc_dev;
67           device_t                      sc_gpiodev;
68           bus_space_handle_t            sc_bsh;
69           bus_space_tag_t                         sc_bst;
70           const struct amdgpio_config   *sc_config;
71           struct gpio_chipset_tag                 sc_gc;
72           gpio_pin_t                              *sc_pins;
73           LIST_HEAD(, amdgpio_intr_handler) sc_intrs;
74           kmutex_t                      sc_lock;
75 };
76 
77 #define RD4(sc, reg)                    \
78           bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
79 #define WR4(sc, reg, val)     \
80           bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
81 
82 static int          amdgpio_match(device_t, cfdata_t, void *);
83 static void         amdgpio_attach(device_t, device_t, void *);
84 
85 static int          amdgpio_pin_read(void *, int);
86 static void         amdgpio_pin_write(void *, int, int);
87 static void         amdgpio_pin_ctl(void *, int, int);
88 static void *       amdgpio_intr_establish(void *, int, int, int,
89                         int (*)(void *), void *);
90 static void         amdgpio_intr_disestablish(void *, void *);
91 static bool         amdgpio_intr_str(void *, int, int, char *, size_t);
92 static void         amdgpio_intr_mask(void *, void *);
93 static void         amdgpio_intr_unmask(void *, void *);
94 
95 static int          amdgpio_acpi_translate(void *, ACPI_RESOURCE_GPIO *, void **);
96 static void         amdgpio_register_event(void *, struct acpi_event *,
97                         ACPI_RESOURCE_GPIO *);
98 static int          amdgpio_intr(void *);
99 
100 CFATTACH_DECL_NEW(amdgpio, sizeof(struct amdgpio_softc),
101     amdgpio_match, amdgpio_attach, NULL, NULL);
102 
103 #define AMDGPIO_NUM_PINS      184
104 
105 static int
amdgpio_translate(ACPI_RESOURCE_GPIO * gpio)106 amdgpio_translate(ACPI_RESOURCE_GPIO *gpio)
107 {
108           const ACPI_INTEGER pin = gpio->PinTable[0];
109 
110           if (pin < AMDGPIO_NUM_PINS) {
111                     return gpio->PinTable[0];
112           }
113 
114           switch (pin) {
115           case 0x0:
116           case 0x8: /* TPDD */
117           case 0x28: /* TPNL */
118           case 0x3a:
119           case 0x3b:
120           case 0x3d:
121           case 0x3e:
122                     return pin;
123           default:
124                     return -1;
125           }
126 }
127 
128 static struct amdgpio_config amdgpio_config = {
129           .num_pins = AMDGPIO_NUM_PINS,
130           .translate = amdgpio_translate, /* TODO: REMOVE */
131 };
132 
133 static const struct device_compatible_entry compat_data[] = {
134           { .compat = "AMDI0030",       .data = &amdgpio_config },
135           DEVICE_COMPAT_EOL
136 };
137 
138 static int
amdgpio_match(device_t parent,cfdata_t cf,void * aux)139 amdgpio_match(device_t parent, cfdata_t cf, void *aux)
140 {
141           struct acpi_attach_args *aa = aux;
142 
143           return acpi_compatible_match(aa, compat_data);
144 }
145 
146 static void
amdgpio_attach(device_t parent,device_t self,void * aux)147 amdgpio_attach(device_t parent, device_t self, void *aux)
148 {
149           struct amdgpio_softc * const sc = device_private(self);
150           struct acpi_attach_args *aa = aux;
151           struct gpiobus_attach_args gba;
152           ACPI_HANDLE hdl = aa->aa_node->ad_handle;
153           struct acpi_resources res;
154           struct acpi_mem *mem;
155           struct acpi_irq *irq;
156           ACPI_STATUS rv;
157           int error, pin;
158           void *ih;
159 
160           sc->sc_dev = self;
161           sc->sc_config = acpi_compatible_lookup(aa, compat_data)->data;
162           sc->sc_bst = aa->aa_memt;
163           KASSERT(sc->sc_config != NULL);
164           LIST_INIT(&sc->sc_intrs);
165           mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_VM);
166 
167           rv = acpi_resource_parse(sc->sc_dev, hdl, "_CRS",
168               &res, &acpi_resource_parse_ops_default);
169           if (ACPI_FAILURE(rv)) {
170                     return;
171           }
172 
173           mem = acpi_res_mem(&res, 0);
174           if (mem == NULL) {
175                     aprint_error_dev(self, "couldn't find mem resource\n");
176                     goto done;
177           }
178 
179           irq = acpi_res_irq(&res, 0);
180           if (irq == NULL) {
181                     aprint_error_dev(self, "couldn't find irq resource\n");
182                     goto done;
183           }
184 
185           error = bus_space_map(sc->sc_bst, mem->ar_base, mem->ar_length, 0,
186               &sc->sc_bsh);
187           if (error) {
188                     aprint_error_dev(self, "couldn't map registers\n");
189                     goto done;
190           }
191 
192           sc->sc_pins = kmem_zalloc(sizeof(*sc->sc_pins) *
193               sc->sc_config->num_pins, KM_SLEEP);
194           for (pin = 0; pin < sc->sc_config->num_pins; pin++) {
195                     sc->sc_pins[pin].pin_num = pin;
196                     sc->sc_pins[pin].pin_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT;
197                     sc->sc_pins[pin].pin_intrcaps =
198                         GPIO_INTR_POS_EDGE | GPIO_INTR_NEG_EDGE |
199                         GPIO_INTR_DOUBLE_EDGE | GPIO_INTR_HIGH_LEVEL |
200                         GPIO_INTR_LOW_LEVEL | GPIO_INTR_MPSAFE;
201                     /*
202                      * It's not safe to read all pins, so leave pin state
203                      * unknown
204                      */
205                     sc->sc_pins[pin].pin_state = 0;
206           }
207 
208           sc->sc_gc.gp_cookie = sc;
209           sc->sc_gc.gp_pin_read = amdgpio_pin_read;
210           sc->sc_gc.gp_pin_write = amdgpio_pin_write;
211           sc->sc_gc.gp_pin_ctl = amdgpio_pin_ctl;
212           sc->sc_gc.gp_intr_establish = amdgpio_intr_establish;
213           sc->sc_gc.gp_intr_disestablish = amdgpio_intr_disestablish;
214           sc->sc_gc.gp_intr_str = amdgpio_intr_str;
215           sc->sc_gc.gp_intr_mask = amdgpio_intr_mask;
216           sc->sc_gc.gp_intr_unmask = amdgpio_intr_unmask;
217 
218           rv = acpi_event_create_gpio(self, hdl, amdgpio_register_event, sc);
219           if (ACPI_FAILURE(rv)) {
220                     if (rv != AE_NOT_FOUND) {
221                               aprint_error_dev(self, "failed to create events: %s\n",
222                                   AcpiFormatException(rv));
223                     }
224                     goto done;
225           }
226 
227           ih = acpi_intr_establish(self, (uint64_t)(uintptr_t)hdl,
228               IPL_VM, false, amdgpio_intr, sc, device_xname(self));
229           if (ih == NULL) {
230                     aprint_error_dev(self, "couldn't establish interrupt\n");
231                     goto done;
232           }
233 
234           memset(&gba, 0, sizeof(gba));
235           gba.gba_gc = &sc->sc_gc;
236           gba.gba_pins = sc->sc_pins;
237           gba.gba_npins = sc->sc_config->num_pins;
238           sc->sc_gpiodev = config_found(self, &gba, gpiobus_print,
239               CFARGS(.iattr = "gpiobus"));
240           if (sc->sc_gpiodev != NULL) {
241                     acpi_gpio_register(aa->aa_node, self,
242                         amdgpio_acpi_translate, sc);
243           }
244 
245 done:
246           acpi_resource_cleanup(&res);
247 }
248 
249 static int
amdgpio_acpi_translate(void * priv,ACPI_RESOURCE_GPIO * gpio,void ** gpiop)250 amdgpio_acpi_translate(void *priv, ACPI_RESOURCE_GPIO *gpio, void **gpiop)
251 {
252           struct amdgpio_softc * const sc = priv;
253           const ACPI_INTEGER pin = gpio->PinTable[0];
254           int xpin;
255 
256           xpin = sc->sc_config->translate(gpio);
257 
258           aprint_debug_dev(sc->sc_dev, "translate %#lx -> %u\n", pin, xpin);
259 
260           if (gpiop != NULL) {
261                     if (sc->sc_gpiodev != NULL) {
262                               *gpiop = device_private(sc->sc_gpiodev);
263                     } else {
264                               device_printf(sc->sc_dev,
265                                   "no gpiodev for pin %#lx -> %u\n", pin, xpin);
266                               xpin = -1;
267                     }
268           }
269 
270           return xpin;
271 }
272 
273 static int
amdgpio_acpi_event(void * priv)274 amdgpio_acpi_event(void *priv)
275 {
276           struct acpi_event * const ev = priv;
277 
278           acpi_event_notify(ev);
279 
280           return 1;
281 }
282 
283 static void
amdgpio_register_event(void * priv,struct acpi_event * ev,ACPI_RESOURCE_GPIO * gpio)284 amdgpio_register_event(void *priv, struct acpi_event *ev,
285     ACPI_RESOURCE_GPIO *gpio)
286 {
287           struct amdgpio_softc * const sc = priv;
288           int irqmode;
289           void *ih;
290 
291           const int pin = amdgpio_acpi_translate(sc, gpio, NULL);
292 
293           if (pin < 0 || pin == 0x8) {
294                     aprint_error_dev(sc->sc_dev,
295                         "ignoring event for pin %#x (out of range)\n",
296                         gpio->PinTable[0]);
297                     return;
298           }
299 
300           if (gpio->Triggering == ACPI_LEVEL_SENSITIVE) {
301                     irqmode = gpio->Polarity == ACPI_ACTIVE_HIGH ?
302                         GPIO_INTR_HIGH_LEVEL : GPIO_INTR_LOW_LEVEL;
303           } else {
304                     KASSERT(gpio->Triggering == ACPI_EDGE_SENSITIVE);
305                     if (gpio->Polarity == ACPI_ACTIVE_LOW) {
306                               irqmode = GPIO_INTR_NEG_EDGE;
307                     } else if (gpio->Polarity == ACPI_ACTIVE_HIGH) {
308                               irqmode = GPIO_INTR_POS_EDGE;
309                     } else {
310                               KASSERT(gpio->Polarity == ACPI_ACTIVE_BOTH);
311                               irqmode = GPIO_INTR_DOUBLE_EDGE;
312                     }
313           }
314 
315           ih = amdgpio_intr_establish(sc, pin, IPL_VM, irqmode,
316               amdgpio_acpi_event, ev);
317           if (ih == NULL) {
318                     aprint_error_dev(sc->sc_dev,
319                         "couldn't register event for pin %#x\n",
320                         gpio->PinTable[0]);
321                     return;
322           }
323           if (gpio->Triggering == ACPI_LEVEL_SENSITIVE) {
324                     acpi_event_set_intrcookie(ev, ih);
325           }
326 }
327 
328 static int
amdgpio_pin_read(void * priv,int pin)329 amdgpio_pin_read(void *priv, int pin)
330 {
331           struct amdgpio_softc * const sc = priv;
332           uint32_t val;
333 
334           if (pin < 0 || pin >= sc->sc_config->num_pins) {
335                     return 0;
336           }
337           if ((sc->sc_pins[pin].pin_caps & GPIO_PIN_INPUT) == 0) {
338                     return 0;
339           }
340 
341           val = RD4(sc, AMDGPIO_PIN_REG(pin));
342           return (val & AMDGPIO_CONF_GPIORXSTATE) ? 1 : 0;
343 }
344 
345 static void
amdgpio_pin_write(void * priv,int pin,int pinval)346 amdgpio_pin_write(void *priv, int pin, int pinval)
347 {
348           struct amdgpio_softc * const sc = priv;
349           uint32_t val;
350 
351           if (pin < 0 || pin >= sc->sc_config->num_pins) {
352                     return;
353           }
354           if ((sc->sc_pins[pin].pin_caps & GPIO_PIN_OUTPUT) == 0) {
355                     return;
356           }
357 
358           val = RD4(sc, AMDGPIO_PIN_REG(pin));
359           if (pinval) {
360                     val |= AMDGPIO_CONF_GPIOTXSTATE;
361           } else {
362                     val &= ~AMDGPIO_CONF_GPIOTXSTATE;
363           }
364           WR4(sc, AMDGPIO_PIN_REG(pin), val);
365 }
366 
367 static void
amdgpio_pin_ctl(void * priv,int pin,int flags)368 amdgpio_pin_ctl(void *priv, int pin, int flags)
369 {
370           /* Nothing to do here, as firmware has already configured pins. */
371 }
372 
373 static void *
amdgpio_intr_establish(void * priv,int pin,int ipl,int irqmode,int (* func)(void *),void * arg)374 amdgpio_intr_establish(void *priv, int pin, int ipl, int irqmode,
375     int (*func)(void *), void *arg)
376 {
377           struct amdgpio_softc * const sc = priv;
378           struct amdgpio_intr_handler *aih, *aihp;
379           uint32_t dect;
380           uint32_t val;
381 
382           if (pin < 0 || pin >= sc->sc_config->num_pins) {
383                     return NULL;
384           }
385           if (ipl != IPL_VM) {
386                     device_printf(sc->sc_dev, "%s: only IPL_VM supported\n",
387                         __func__);
388                     return NULL;
389           }
390 
391           aih = kmem_alloc(sizeof(*aih), KM_SLEEP);
392           aih->ih_func = func;
393           aih->ih_arg = arg;
394           aih->ih_pin = pin;
395 
396           mutex_enter(&sc->sc_lock);
397 
398           LIST_FOREACH(aihp, &sc->sc_intrs, ih_list) {
399                     if (aihp->ih_pin == aih->ih_pin) {
400                               mutex_exit(&sc->sc_lock);
401                               kmem_free(aih, sizeof(*aih));
402                               device_printf(sc->sc_dev,
403                                   "%s: pin %d already establish\n", __func__, pin);
404                               return NULL;
405                     }
406           }
407 
408           LIST_INSERT_HEAD(&sc->sc_intrs, aih, ih_list);
409 
410           if ((irqmode & GPIO_INTR_LEVEL_MASK) != 0) {
411                     dect = AMDGPIO_CONF_LEVEL;
412           } else {
413                     KASSERT((irqmode & GPIO_INTR_EDGE_MASK) != 0);
414                     if ((irqmode & GPIO_INTR_NEG_EDGE) != 0) {
415                               dect = AMDGPIO_CONF_ACTLO;
416                     } else if ((irqmode & GPIO_INTR_POS_EDGE) != 0) {
417                               dect = 0;
418                     } else {
419                               KASSERT((irqmode & GPIO_INTR_DOUBLE_EDGE) != 0);
420                               dect = AMDGPIO_CONF_ACTBOTH;
421                     }
422           }
423 
424           val = RD4(sc, AMDGPIO_PIN_REG(pin));
425           val |= dect;
426           val |= AMDGPIO_CONF_INTR_MASK_EN | AMDGPIO_CONF_INTR_EN;
427           WR4(sc, AMDGPIO_PIN_REG(pin), val);
428 
429           mutex_exit(&sc->sc_lock);
430 
431           return aih;
432 }
433 
434 static void
amdgpio_intr_disestablish(void * priv,void * ih)435 amdgpio_intr_disestablish(void *priv, void *ih)
436 {
437           struct amdgpio_softc * const sc = priv;
438           struct amdgpio_intr_handler *aih = ih;
439           uint32_t val;
440 
441           mutex_enter(&sc->sc_lock);
442 
443           LIST_REMOVE(aih, ih_list);
444 
445           val = RD4(sc, AMDGPIO_PIN_REG(aih->ih_pin));
446           val &= ~(AMDGPIO_CONF_INTR_EN | AMDGPIO_CONF_INTR_MASK_EN);
447           WR4(sc, AMDGPIO_PIN_REG(aih->ih_pin), val);
448 
449           mutex_exit(&sc->sc_lock);
450 
451           kmem_free(aih, sizeof(*aih));
452 }
453 
454 static bool
amdgpio_intr_str(void * priv,int pin,int irqmode,char * buf,size_t buflen)455 amdgpio_intr_str(void *priv, int pin, int irqmode, char *buf, size_t buflen)
456 {
457           struct amdgpio_softc * const sc = priv;
458           int rv;
459 
460           rv = snprintf(buf, buflen, "%s pin %d", device_xname(sc->sc_dev), pin);
461 
462           return rv < buflen;
463 }
464 
465 static void
amdgpio_intr_mask(void * priv,void * ih)466 amdgpio_intr_mask(void *priv, void *ih)
467 {
468           struct amdgpio_softc * const sc = priv;
469           struct amdgpio_intr_handler *aih = ih;
470           uint32_t val;
471 
472           val = RD4(sc, AMDGPIO_PIN_REG(aih->ih_pin));
473           val &= ~AMDGPIO_CONF_INTR_MASK_EN;
474           WR4(sc, AMDGPIO_PIN_REG(aih->ih_pin), val);
475 }
476 
477 static void
amdgpio_intr_unmask(void * priv,void * ih)478 amdgpio_intr_unmask(void *priv, void *ih)
479 {
480           struct amdgpio_softc * const sc = priv;
481           struct amdgpio_intr_handler *aih = ih;
482           uint32_t val;
483 
484           val = RD4(sc, AMDGPIO_PIN_REG(aih->ih_pin));
485           val |= AMDGPIO_CONF_INTR_MASK_EN;
486           WR4(sc, AMDGPIO_PIN_REG(aih->ih_pin), val);
487 }
488 
489 static int
amdgpio_intr(void * priv)490 amdgpio_intr(void *priv)
491 {
492           struct amdgpio_softc * const sc = priv;
493           struct amdgpio_intr_handler *aih;
494           int rv = 0;
495           uint64_t status;
496           uint32_t val;
497 
498           mutex_enter(&sc->sc_lock);
499 
500           status = RD4(sc, AMDGPIO_INTR_STATUS(1));
501           status <<= 32;
502           status |= RD4(sc, AMDGPIO_INTR_STATUS(0));
503           status &= __BITS(0, AMDGPIO_INTR_STATUS_NBITS - 1);
504 
505           if (status == 0) {
506                     rv = 1;
507                     goto out;
508           }
509 
510           LIST_FOREACH(aih, &sc->sc_intrs, ih_list) {
511                     const int pin = aih->ih_pin;
512 
513                     if ((status & __BIT(pin / 4)) == 0) {
514                               continue;
515                     }
516 
517                     val = RD4(sc, AMDGPIO_PIN_REG(pin));
518                     if ((val & AMDGPIO_CONF_INTR_STATUS) != 0) {
519                               rv |= aih->ih_func(aih->ih_arg);
520 
521                               val &= ~(AMDGPIO_CONF_INTR_MASK_EN |
522                                   AMDGPIO_CONF_INTR_EN);
523                               WR4(sc, AMDGPIO_PIN_REG(pin), val);
524                     }
525           }
526 
527           /* Signal end of interrupt */
528           val = RD4(sc, AMDGPIO_INTR_MASTER);
529           val |= AMDGPIO_INTR_MASTER_EIO;
530           WR4(sc, AMDGPIO_INTR_MASTER, val);
531 
532 out:
533           mutex_exit(&sc->sc_lock);
534 
535           return rv;
536 }
537