The diff below is a first stab at adding support for GPIOs as defined
in ACPI 5.0.  The primary target for this new ACPI feature is hardware
reduced platforms like those based on Intel's Bay Trail SoC.  The diff
adds a bytgpio(4) driver for the hardware found on that SoC.  This
driver registers itself with the acpi framework by setting the struct
acpi_gpio pointer on the AML node for the device.  Then this gets used
by the acpi sdhc(4) frontend to use the appropriate gpio as the card
detect signal.  This makes it possible to detectwhether a card is
inserted when the kernel boots.  Support for GPIO-based interrupts is
still missing, so hotplugging SD cards doesn't work yet.

There are some debug printfs here that will disappear eventually.

ok?


Index: acpi.c
===================================================================
RCS file: /cvs/src/sys/dev/acpi/acpi.c,v
retrieving revision 1.305
diff -u -p -r1.305 acpi.c
--- acpi.c      17 Jan 2016 09:04:18 -0000      1.305
+++ acpi.c      27 Mar 2016 19:18:31 -0000
@@ -2801,6 +2801,8 @@ acpi_foundhid(struct aml_node *node, voi
            !strcmp(dev, ACPI_DEV_TOSHIBA_SPA40)) {
                aaa.aaa_name = "acpitoshiba";
                acpi_toshiba_enabled = 1;
+       } else if (!strcmp(dev, "INT33FC")) {
+               aaa.aaa_name = "bytgpio";
        } else if (!strcmp(dev, "80860F14") || !strcmp(dev, "PNP0FFF")) {
                aaa.aaa_name = "sdhc";
        } else if (!strcmp(dev, ACPI_DEV_DWIIC1) ||
Index: amltypes.h
===================================================================
RCS file: /cvs/src/sys/dev/acpi/amltypes.h,v
retrieving revision 1.40
diff -u -p -r1.40 amltypes.h
--- amltypes.h  7 Sep 2012 19:19:59 -0000       1.40
+++ amltypes.h  27 Mar 2016 19:18:31 -0000
@@ -364,6 +364,11 @@ struct acpi_pci {
        int                             _s4w;
 };
 
+struct acpi_gpio {
+       void    *cookie;
+       int     (*read_pin)(void *, int);
+};
+
 struct aml_node {
        struct aml_node *parent;
 
@@ -377,6 +382,7 @@ struct aml_node {
 
        struct aml_value *value;
        struct acpi_pci  *pci;
+       struct acpi_gpio *gpio;
 };
 
 #define aml_bitmask(n)         (1L << ((n) & 0x7))
Index: bytgpio.c
===================================================================
RCS file: bytgpio.c
diff -N bytgpio.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ bytgpio.c   27 Mar 2016 19:18:31 -0000
@@ -0,0 +1,242 @@
+/*     $OpenBSD$       */
+/*
+ * Copyright (c) 2016 Mark Kettenis
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/malloc.h>
+#include <sys/systm.h>
+
+#include <dev/acpi/acpireg.h>
+#include <dev/acpi/acpivar.h>
+#include <dev/acpi/acpidev.h>
+#include <dev/acpi/amltypes.h>
+#include <dev/acpi/dsdt.h>
+
+#define BYTGPIO_PAD_VAL                0x00000001
+
+struct bytgpio_softc {
+       struct device sc_dev;
+       struct acpi_softc *sc_acpi;
+       struct aml_node *sc_node;
+
+       bus_space_tag_t sc_memt;
+       bus_space_handle_t sc_memh;
+       bus_addr_t sc_addr;
+       bus_size_t sc_size;
+
+       int sc_irq;
+       int sc_irq_flags;
+       void *sc_ih;
+
+       const int *sc_pins;
+       int sc_npins;
+
+       struct acpi_gpio sc_gpio;
+};
+
+int    bytgpio_match(struct device *, void *, void *);
+void   bytgpio_attach(struct device *, struct device *, void *);
+
+struct cfattach bytgpio_ca = {
+       sizeof(struct bytgpio_softc), bytgpio_match, bytgpio_attach
+};
+
+struct cfdriver bytgpio_cd = {
+       NULL, "bytgpio", DV_DULL
+};
+
+const char *bytgpio_hids[] = {
+       "INT33FC",
+       0
+};
+
+/*
+ * The pads for the pins are randomly ordered.
+ */
+
+const int byt_score_pins[] = {
+       85, 89, 93, 96, 99, 102, 98, 101, 34, 37, 36, 38, 39, 35, 40,
+       84, 62, 61, 64, 59, 54, 56, 60, 55, 63, 57, 51, 50, 53, 47,
+       52, 49, 48, 43, 46, 41, 45, 42, 58, 44, 95, 105, 70, 68, 67,
+       66, 69, 71, 65, 72, 86, 90, 88, 92, 103, 77, 79, 83, 78, 81,
+       80, 82, 13, 12, 15, 14, 17, 18, 19, 16, 2, 1, 0, 4, 6, 7, 9,
+       8, 33, 32, 31, 30, 29, 27, 25, 28, 26, 23, 21, 20, 24, 22, 5,
+       3, 10, 11, 106, 87, 91, 104, 97, 100
+};
+
+const int byt_ncore_pins[] = {
+       19, 18, 17, 20, 21, 22, 24, 25, 23, 16, 14, 15, 12, 26, 27,
+       1, 4, 8, 11, 0, 3, 6, 10, 13, 2, 5, 9, 7
+};
+
+const int byt_sus_pins[] = {
+        29, 33, 30, 31, 32, 34, 36, 35, 38, 37, 18, 7, 11, 20, 17, 1,
+       8, 10, 19, 12, 0, 2, 23, 39, 28, 27, 22, 21, 24, 25, 26, 51,
+       56, 54, 49, 55, 48, 57, 50, 58, 52, 53, 59, 40
+};
+
+int    bytgpio_parse_resources(union acpi_resource *, void *);
+int    bytgpio_read_pin(void *, int);
+int    bytgpio_intr(void *);
+
+int
+bytgpio_match(struct device *parent, void *match, void *aux)
+{
+       struct acpi_attach_args *aaa = aux;
+       struct cfdata *cf = match;
+       int64_t sta;
+
+       if (!acpi_matchhids(aaa, bytgpio_hids, cf->cf_driver->cd_name))
+               return 0;
+
+       if (aml_evalinteger((struct acpi_softc *)parent, aaa->aaa_node,
+           "_STA", 0, NULL, &sta))
+               sta = STA_PRESENT | STA_ENABLED | STA_DEV_OK | 0x1000;
+
+       if ((sta & STA_PRESENT) == 0)
+               return 0;
+
+       return 1;
+}
+
+void
+bytgpio_attach(struct device *parent, struct device *self, void *aux)
+{
+       struct acpi_attach_args *aaa = aux;
+       struct bytgpio_softc *sc = (struct bytgpio_softc *)self;
+       struct aml_value res;
+       int64_t uid;
+
+       sc->sc_acpi = (struct acpi_softc *)parent;
+       sc->sc_node = aaa->aaa_node;
+       printf(": %s", sc->sc_node->name);
+
+       if (aml_evalinteger(sc->sc_acpi, sc->sc_node, "_UID", 0, NULL, &uid)) {
+               printf(", can't find uid\n");
+               return;
+       }
+
+       printf(" uid %lld", uid);
+
+       switch (uid) {
+       case 1:
+               sc->sc_pins = byt_score_pins;
+               sc->sc_npins = nitems(byt_score_pins);
+               break;
+       case 2:
+               sc->sc_pins = byt_score_pins;
+               sc->sc_npins = nitems(byt_ncore_pins);
+               break;
+       case 3:
+               sc->sc_pins = byt_score_pins;
+               sc->sc_npins = nitems(byt_sus_pins);
+               break;
+       default:
+               return;
+       }
+
+       if (aml_evalname(sc->sc_acpi, sc->sc_node, "_CRS", 0, NULL, &res)) {
+               printf(", can't find registers\n");
+               return;
+       }
+
+       aml_parse_resource(&res, bytgpio_parse_resources, sc);
+       printf(" addr 0x%lx/0x%lx", sc->sc_addr, sc->sc_size);
+       if (sc->sc_addr == 0 || sc->sc_size == 0) {
+               printf("\n");
+               return;
+       }
+
+       printf(" irq %d", sc->sc_irq);
+
+       sc->sc_memt = aaa->aaa_memt;
+       if (bus_space_map(sc->sc_memt, sc->sc_addr, sc->sc_size, 0,
+           &sc->sc_memh)) {
+               printf(", can't map registers\n");
+               return;
+       }
+
+#if 0
+       sc->sc_ih = acpi_intr_establish(sc->sc_irq, sc->sc_irq_flags, IPL_BIO,
+           bytgpio_intr, sc, sc->sc_dev.dv_xname);
+       if (sc->sc_ih == NULL) {
+               printf(", can't establish interrupt\n");
+               return;
+       }
+#endif
+
+       sc->sc_gpio.cookie = sc;
+       sc->sc_gpio.read_pin = bytgpio_read_pin;
+       sc->sc_node->gpio = &sc->sc_gpio;
+
+       printf(", %d pins\n", sc->sc_npins);
+}
+
+int
+bytgpio_parse_resources(union acpi_resource *crs, void *arg)
+{
+       struct bytgpio_softc *sc = arg;
+       int type = AML_CRSTYPE(crs);
+
+       switch (type) {
+       case LR_MEM32FIXED:
+               sc->sc_addr = crs->lr_m32fixed._bas;
+               sc->sc_size = crs->lr_m32fixed._len;
+               break;
+       case LR_EXTIRQ:
+               sc->sc_irq = crs->lr_extirq.irq[0];
+               sc->sc_irq_flags = crs->lr_extirq.flags;
+               break;
+       default:
+               printf(" type 0x%x\n", type);
+               break;
+       }
+
+       return 0;
+}
+
+int
+bytgpio_read_pin(void *cookie, int pin)
+{
+       struct bytgpio_softc *sc = cookie;
+       uint32_t reg;
+
+       reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, sc->sc_pins[pin] * 16 
+ 8);
+       return (reg & BYTGPIO_PAD_VAL);
+}
+
+#if 0
+
+int
+bytgpio_intr(void *arg)
+{
+       struct bytgpio_softc *sc = arg;
+       uint32_t reg;
+       int pin;
+
+       for (pin = 0; pin < sc->sc_npins; pin++) {
+               if (pin % 32 == 0)
+                       reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, 0x800 
+ (pin / 8));
+               if (reg & (1 << (pin % 32))) {
+                       
+               }
+       }
+
+       printf("%s\n", __func__);
+       return 1;
+}
+
+#endif
Index: dsdt.h
===================================================================
RCS file: /cvs/src/sys/dev/acpi/dsdt.h,v
retrieving revision 1.68
diff -u -p -r1.68 dsdt.h
--- dsdt.h      14 Mar 2016 06:37:31 -0000      1.68
+++ dsdt.h      27 Mar 2016 19:18:31 -0000
@@ -103,6 +103,7 @@ const char          *aml_nodename(struct aml_nod
 #define LR_WORD                        0x88
 #define LR_EXTIRQ              0x89
 #define LR_QWORD               0x8A
+#define LR_GPIO                        0x8C
 #define LR_SERBUS              0x8E
 
 #define __amlflagbit(v,s,l)
@@ -226,6 +227,24 @@ union acpi_resource {
                uint8_t         src_index;
                char            src[1];
        } __packed lr_qword;
+       struct {
+               uint8_t         typecode;
+               uint16_t        length;
+               uint8_t         revid;
+               uint8_t         type;
+#define LR_GPIO_INT    0x00
+#define LR_GPIO_IO     0x01
+               uint16_t        flags;
+               uint16_t        tflags;
+               uint8_t         _ppi;
+               uint16_t        _drs;
+               uint16_t        _dbt;
+               uint16_t        pin_off;
+               uint8_t         residx;
+               uint16_t        res_off;
+               uint16_t        vd_off;
+               uint16_t        vd_len;
+       } __packed lr_gpio;
        struct {
                uint8_t         typecode;
                uint16_t        length;
Index: files.acpi
===================================================================
RCS file: /cvs/src/sys/dev/acpi/files.acpi,v
retrieving revision 1.30
diff -u -p -r1.30 files.acpi
--- files.acpi  12 Jan 2016 01:11:15 -0000      1.30
+++ files.acpi  27 Mar 2016 19:18:31 -0000
@@ -112,6 +112,11 @@ device     aibs
 attach aibs at acpi
 file   dev/acpi/atk0110.c              aibs
 
+# Intel Bay Trail GPIO
+device bytgpio
+attach bytgpio at acpi
+file   dev/acpi/bytgpio.c              bytgpio
+
 # SD Host Controller
 attach sdhc at acpi with sdhc_acpi
 file   dev/acpi/sdhc_acpi.c            sdhc_acpi
Index: sdhc_acpi.c
===================================================================
RCS file: /cvs/src/sys/dev/acpi/sdhc_acpi.c,v
retrieving revision 1.1
diff -u -p -r1.1 sdhc_acpi.c
--- sdhc_acpi.c 11 Jan 2016 07:36:10 -0000      1.1
+++ sdhc_acpi.c 27 Mar 2016 19:18:31 -0000
@@ -43,6 +43,11 @@ struct sdhc_acpi_softc {
        int sc_irq_flags;
        void *sc_ih;
 
+       struct aml_node *sc_gpio_int_node;
+       struct aml_node *sc_gpio_io_node;
+       uint16_t sc_gpio_int_pin;
+       uint16_t sc_gpio_io_pin;
+
        struct sdhc_host *sc_host;
 };
 
@@ -62,6 +67,7 @@ const char *sdhc_hids[] = {
 };
 
 int    sdhc_acpi_parse_resources(union acpi_resource *, void *);
+int    sdhc_acpi_card_detect(struct sdhc_softc *);
 
 int
 sdhc_acpi_match(struct device *parent, void *match, void *aux)
@@ -122,6 +128,9 @@ sdhc_acpi_attach(struct device *parent, 
                return;
        }
 
+       if (sc->sc_gpio_io_node != NULL)
+               sc->sc.sc_card_detect = sdhc_acpi_card_detect;
+
        printf("\n");
 
        sc->sc.sc_host = &sc->sc_host;
@@ -133,6 +142,8 @@ sdhc_acpi_parse_resources(union acpi_res
 {
        struct sdhc_acpi_softc *sc = arg;
        int type = AML_CRSTYPE(crs);
+       struct aml_node *node;
+       uint16_t pin;
 
        switch (type) {
        case LR_MEM32FIXED:
@@ -143,8 +154,21 @@ sdhc_acpi_parse_resources(union acpi_res
                sc->sc_irq = crs->lr_extirq.irq[0];
                sc->sc_irq_flags = crs->lr_extirq.flags;
                break;
-       case 0x8c:
-               /* XXX GPIO; use for card detect. */
+       case LR_GPIO:
+               node = aml_searchname(sc->sc_node, (char 
*)&crs->pad[crs->lr_gpio.res_off]);
+               pin = *(uint16_t *)&crs->pad[crs->lr_gpio.pin_off];
+               printf(" %s pin %d\n", node->name, pin);
+               if (crs->lr_gpio.type == LR_GPIO_INT) {
+                       sc->sc_gpio_int_node = node;
+                       sc->sc_gpio_int_pin = pin;
+               } else if (crs->lr_gpio.type == LR_GPIO_IO) {
+                       sc->sc_gpio_io_node = node;
+                       sc->sc_gpio_io_pin = pin;
+               }
+               printf(" tflags 0x%x\n", crs->lr_gpio.tflags);
+               printf(" ppi 0x%x\n", crs->lr_gpio._ppi);
+               printf(" drs 0x%x\n", crs->lr_gpio._drs);
+               printf(" dbt 0x%x\n", crs->lr_gpio._dbt);
                break;
        default:
                printf(" type 0x%x\n", type);
@@ -152,4 +176,14 @@ sdhc_acpi_parse_resources(union acpi_res
        }
 
        return 0;
+}
+
+int
+sdhc_acpi_card_detect(struct sdhc_softc *ssc)
+{
+       struct sdhc_acpi_softc *sc = (struct sdhc_acpi_softc *)ssc;
+       struct acpi_gpio *gpio = sc->sc_gpio_io_node->gpio;
+       uint16_t pin = sc->sc_gpio_io_pin;
+
+       return !gpio->read_pin(gpio->cookie, pin);
 }

Reply via email to