From 33d8693716b4a6d503e0ba97f94a783905b87f28 Mon Sep 17 00:00:00 2001 From: Mark Kettenis Date: Sat, 7 May 2016 18:08:28 +0000 Subject: Implement ACPI 5.0 GeneralPurposeIo OpRegion support. This basically allows AML to peek and poke at GPIO pins as if it were reading and writing registers. For now this only implements peeking at pins. It will print a message if AML attempt to poke at a pin. And it will panic if the assumptions made in the code are violated. ok mlarkin@ --- sys/dev/acpi/bytgpio.c | 17 ++++++++++-- sys/dev/acpi/dsdt.c | 71 ++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 78 insertions(+), 10 deletions(-) (limited to 'sys/dev/acpi') diff --git a/sys/dev/acpi/bytgpio.c b/sys/dev/acpi/bytgpio.c index 11654f545ed..ec38f909f07 100644 --- a/sys/dev/acpi/bytgpio.c +++ b/sys/dev/acpi/bytgpio.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bytgpio.c,v 1.8 2016/05/04 08:30:56 kettenis Exp $ */ +/* $OpenBSD: bytgpio.c,v 1.9 2016/05/07 18:08:27 kettenis Exp $ */ /* * Copyright (c) 2016 Mark Kettenis * @@ -124,6 +124,8 @@ 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; + struct aml_value arg[2]; + struct aml_node *node; int64_t uid; uint32_t reg; int i; @@ -211,8 +213,19 @@ bytgpio_attach(struct device *parent, struct device *self, void *aux) reg &= ~BYTGPIO_CONF_GD_MASK; bus_space_write_4(sc->sc_memt, sc->sc_memh, sc->sc_pins[i] * 16, reg); } - + printf(", %d pins\n", sc->sc_npins); + + /* Register address space. */ + memset(&arg, 0, sizeof(arg)); + arg[0].type = AML_OBJTYPE_INTEGER; + arg[0].v_integer = ACPI_OPREG_GPIO; + arg[1].type = AML_OBJTYPE_INTEGER; + arg[1].v_integer = 1; + node = aml_searchname(sc->sc_node, "_REG"); + if (node && aml_evalnode(sc->sc_acpi, node, 2, arg, NULL)) + printf("%s: _REG failed\n", sc->sc_dev.dv_xname); + return; fail: diff --git a/sys/dev/acpi/dsdt.c b/sys/dev/acpi/dsdt.c index f04eb8f946d..60e659e1383 100644 --- a/sys/dev/acpi/dsdt.c +++ b/sys/dev/acpi/dsdt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dsdt.c,v 1.221 2016/03/14 06:37:31 guenther Exp $ */ +/* $OpenBSD: dsdt.c,v 1.222 2016/05/07 18:08:27 kettenis Exp $ */ /* * Copyright (c) 2005 Jordan Hargrave * @@ -2206,6 +2206,7 @@ aml_evalhid(struct aml_node *node, struct aml_value *val) } void aml_rwgas(struct aml_value *, int, int, struct aml_value *, int, int); +void aml_rwgpio(struct aml_value *, int, int, struct aml_value *, int, int); void aml_rwindexfield(struct aml_value *, struct aml_value *val, int); void aml_rwfield(struct aml_value *, int, int, struct aml_value *, int); @@ -2331,6 +2332,37 @@ aml_rwgas(struct aml_value *rgn, int bpos, int blen, struct aml_value *val, aml_freevalue(&tmp); } +void +aml_rwgpio(struct aml_value *conn, int bpos, int blen, struct aml_value *val, + int mode, int flag) +{ + union acpi_resource *crs = (union acpi_resource *)conn->v_buffer; + struct aml_node *node; + uint16_t pin; + int v = 0; + + if (conn->type != AML_OBJTYPE_BUFFER || conn->length < 5 || + AML_CRSTYPE(crs) != LR_GPIO || AML_CRSLEN(crs) > conn->length) + aml_die("Invalid GpioIo"); + if (bpos != 0 || blen != 1) + aml_die("Invalid GpioIo access"); + + node = aml_searchname(conn->node, + (char *)&crs->pad[crs->lr_gpio.res_off]); + pin = *(uint16_t *)&crs->pad[crs->lr_gpio.pin_off]; + + if (node == NULL || node->gpio == NULL) + aml_die("Could not find GpioIo pin"); + + if (mode == ACPI_IOWRITE) { + printf("GpioIO write unimplemented\n"); + return; + } + + v = node->gpio->read_pin(node->gpio->cookie, pin); + _aml_setvalue(val, AML_OBJTYPE_INTEGER, v, NULL); +} + void aml_rwindexfield(struct aml_value *fld, struct aml_value *val, int mode) { @@ -2427,8 +2459,22 @@ aml_rwfield(struct aml_value *fld, int bpos, int blen, struct aml_value *val, aml_rwgas(ref1, fld->v_field.bitpos, fld->v_field.bitlen, val, mode, fld->v_field.flags); } else if (fld->v_field.type == AMLOP_FIELD) { - aml_rwgas(ref1, fld->v_field.bitpos + bpos, blen, val, mode, - fld->v_field.flags); + switch (ref1->v_opregion.iospace) { + case ACPI_OPREG_GPIO: + aml_rwgpio(ref2, bpos, blen, val, mode, + fld->v_field.flags); + break; + case ACPI_OPREG_SYSMEM: + case ACPI_OPREG_SYSIO: + case ACPI_OPREG_PCICFG: + case ACPI_OPREG_EC: + aml_rwgas(ref1, fld->v_field.bitpos + bpos, blen, + val, mode, fld->v_field.flags); + break; + default: + aml_die("Unsupported RegionSpace"); + break; + } } else if (mode == ACPI_IOREAD) { /* bufferfield:read */ _aml_setvalue(val, AML_OBJTYPE_INTEGER, 0, 0); @@ -2498,6 +2544,7 @@ void aml_parsefieldlist(struct aml_scope *mscope, int opcode, int flags, struct aml_value *data, struct aml_value *index, int indexval) { + struct aml_value *conn = NULL; struct aml_value *rv; int bpos, blen; @@ -2506,20 +2553,28 @@ aml_parsefieldlist(struct aml_scope *mscope, int opcode, int flags, bpos = 0; while (mscope->pos < mscope->end) { switch (*mscope->pos) { - case 0x00: // reserved, length + case 0x00: /* reserved, length */ mscope->pos++; blen = aml_parselength(mscope); break; - case 0x01: // flags + case 0x01: /* flags */ mscope->pos += 3; blen = 0; break; - default: // 4-byte name, length + case 0x02: /* connection */ + mscope->pos++; + blen = 0; + conn = aml_parse(mscope, 'o', "Connection"); + if (conn == NULL) + aml_die("Could not parse connection"); + conn->node = mscope->node; + break; + default: /* 4-byte name, length */ mscope->pos = aml_parsename(mscope->node, mscope->pos, &rv, 1); blen = aml_parselength(mscope); - aml_createfield(rv, opcode, data, bpos, blen, index, - indexval, flags); + aml_createfield(rv, opcode, data, bpos, blen, + conn ? conn : index, indexval, flags); aml_delref(&rv, 0); break; } -- cgit v1.2.3