diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2016-05-07 18:08:28 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2016-05-07 18:08:28 +0000 |
commit | 33d8693716b4a6d503e0ba97f94a783905b87f28 (patch) | |
tree | fc63c2cc0157db70b11f71c4f52f227a034257e0 /sys/dev/acpi | |
parent | ef6e6a90fa2a91dc60567be11eb4cf99f4e9952d (diff) |
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@
Diffstat (limited to 'sys/dev/acpi')
-rw-r--r-- | sys/dev/acpi/bytgpio.c | 17 | ||||
-rw-r--r-- | sys/dev/acpi/dsdt.c | 71 |
2 files changed, 78 insertions, 10 deletions
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 <jordan@openbsd.org> * @@ -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); @@ -2332,6 +2333,37 @@ aml_rwgas(struct aml_value *rgn, int bpos, int blen, struct aml_value *val, } 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) { struct aml_value tmp, *ref1, *ref2; @@ -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; } |