On Sun, Mar 27, 2016 at 09:28:25PM +0200, Mark Kettenis wrote:
> 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?
Works on ideapad 100s:
bytgpio0 at acpi0: GPO0 uid 1 addr 0xfed0c000/0x1000 irq 49, 102 pins
bytgpio1 at acpi0: GPO1 uid 2 addr 0xfed0d000/0x1000 irq 48, 28 pins
bytgpio2 at acpi0: GPO2 uid 3 addr 0xfed0e000/0x1000 irq 50, 44 pins
sdhc0 at acpi0: SDHA addr 0x9091d000/0x1000 irq 44
sdmmc0 at sdhc0
sdhc at acpi0 not configured
sdhc1 at acpi0: SDHD GPO0 pin 38
tflags 0x1d
ppi 0x3
drs 0x0
dbt 0x2710
GPO0 pin 38
tflags 0x9
ppi 0x0
drs 0x0
dbt 0x0
addr 0x90903000/0x1000 irq 47
sdmmc1 at sdhc1
...
scsibus1 at sdmmc0: 2 targets, initiator 0
sd0 at scsibus1 targ 1 lun 0: <SD/MMC, Drive #01, > SCSI2 0/direct fixed
sd0: 29820MB, 512 bytes/sector, 61071360 sectors
scsibus2 at sdmmc1: 2 targets, initiator 0
sd1 at scsibus2 targ 1 lun 0: <SD/MMC, Drive #01, > SCSI2 0/direct fixed
sd1: 15271MB, 512 bytes/sector, 31275008 sectors
sdmmc0 is emmc sdmmc1 is a usd card in the slot.
Though after some network traffic over usb the machine seems to hang.
Opening new windows in tmux over ssh works but shells don't spawn.
I can still type locally (with the polling diff) but can't login on tty.
Is it possible this somehow enables gpio interrupts that we then
don't acknowledge?
>
>
> 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);
> }
>