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);
}