diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2018-05-17 20:21:16 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2018-05-17 20:21:16 +0000 |
commit | 641bee903b7ac7f39242ddf95ec1d453670c1840 (patch) | |
tree | 0cf7bafd9064ca1bf30889eae069b78d52d3c6d2 | |
parent | 40b9165f194868b48de0f9535ad742474f5274ee (diff) |
Implement GenericSerialBus OpRegion support.
ok mlarkin@
-rw-r--r-- | sys/dev/acpi/acpi.c | 19 | ||||
-rw-r--r-- | sys/dev/acpi/acpivar.h | 3 | ||||
-rw-r--r-- | sys/dev/acpi/amltypes.h | 7 | ||||
-rw-r--r-- | sys/dev/acpi/dsdt.c | 105 | ||||
-rw-r--r-- | sys/dev/acpi/dwiic_acpi.c | 5 |
5 files changed, 131 insertions, 8 deletions
diff --git a/sys/dev/acpi/acpi.c b/sys/dev/acpi/acpi.c index ae863d03625..ffffae80f5e 100644 --- a/sys/dev/acpi/acpi.c +++ b/sys/dev/acpi/acpi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpi.c,v 1.341 2018/03/27 21:11:16 kettenis Exp $ */ +/* $OpenBSD: acpi.c,v 1.342 2018/05/17 20:21:15 kettenis Exp $ */ /* * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> * Copyright (c) 2005 Jordan Hargrave <jordan@openbsd.org> @@ -920,6 +920,23 @@ acpi_register_gpio(struct acpi_softc *sc, struct aml_node *devnode) } void +acpi_register_gsb(struct acpi_softc *sc, struct aml_node *devnode) +{ + struct aml_value arg[2]; + struct aml_node *node; + + /* Register GenericSerialBus address space. */ + memset(&arg, 0, sizeof(arg)); + arg[0].type = AML_OBJTYPE_INTEGER; + arg[0].v_integer = ACPI_OPREG_GSB; + arg[1].type = AML_OBJTYPE_INTEGER; + arg[1].v_integer = 1; + node = aml_searchname(devnode, "_REG"); + if (node && aml_evalnode(sc, node, 2, arg, NULL)) + printf("%s: _REG failed\n", node->name); +} + +void acpi_attach(struct device *parent, struct device *self, void *aux) { struct bios_attach_args *ba = aux; diff --git a/sys/dev/acpi/acpivar.h b/sys/dev/acpi/acpivar.h index e953c5cecdf..82fc12ba740 100644 --- a/sys/dev/acpi/acpivar.h +++ b/sys/dev/acpi/acpivar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: acpivar.h,v 1.89 2017/11/29 22:51:01 kettenis Exp $ */ +/* $OpenBSD: acpivar.h,v 1.90 2018/05/17 20:21:15 kettenis Exp $ */ /* * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> * @@ -333,6 +333,7 @@ void acpi_wakeup(void *); int acpi_gasio(struct acpi_softc *, int, int, uint64_t, int, int, void *); void acpi_register_gpio(struct acpi_softc *, struct aml_node *); +void acpi_register_gsb(struct acpi_softc *, struct aml_node *); int acpi_set_gpehandler(struct acpi_softc *, int, int (*)(struct acpi_softc *, int, void *), void *, int); diff --git a/sys/dev/acpi/amltypes.h b/sys/dev/acpi/amltypes.h index ad90260070a..ed6c576aef2 100644 --- a/sys/dev/acpi/amltypes.h +++ b/sys/dev/acpi/amltypes.h @@ -1,4 +1,4 @@ -/* $OpenBSD: amltypes.h,v 1.45 2016/05/08 11:08:01 kettenis Exp $ */ +/* $OpenBSD: amltypes.h,v 1.46 2018/05/17 20:21:15 kettenis Exp $ */ /* * Copyright (c) 2005 Jordan Hargrave <jordan@openbsd.org> * @@ -371,6 +371,8 @@ struct acpi_gpio { void (*intr_establish)(void *, int, int, int (*)(void *), void *); }; +struct i2c_controller; + struct aml_node { struct aml_node *parent; @@ -385,8 +387,9 @@ struct aml_node { u_int8_t *end; struct aml_value *value; - struct acpi_pci *pci; + struct acpi_pci *pci; struct acpi_gpio *gpio; + struct i2c_controller *i2c; }; #define aml_bitmask(n) (1L << ((n) & 0x7)) diff --git a/sys/dev/acpi/dsdt.c b/sys/dev/acpi/dsdt.c index 339f745c845..1a995166004 100644 --- a/sys/dev/acpi/dsdt.c +++ b/sys/dev/acpi/dsdt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dsdt.c,v 1.237 2018/05/17 09:22:18 kettenis Exp $ */ +/* $OpenBSD: dsdt.c,v 1.238 2018/05/17 20:21:15 kettenis Exp $ */ /* * Copyright (c) 2005 Jordan Hargrave <jordan@openbsd.org> * @@ -33,6 +33,8 @@ #include <dev/acpi/amltypes.h> #include <dev/acpi/dsdt.h> +#include <dev/i2c/i2cvar.h> + #ifdef SMALL_KERNEL #undef ACPI_DEBUG #endif @@ -2291,6 +2293,7 @@ aml_register_regionspace(struct aml_node *node, int iospace, void *cookie, void aml_rwgen(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_rwgsb(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); @@ -2515,6 +2518,96 @@ aml_rwgpio(struct aml_value *conn, int bpos, int blen, struct aml_value *val, } void +aml_rwgsb(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; + i2c_tag_t tag; + i2c_op_t op; + i2c_addr_t addr; + int cmdlen, buflen; + uint8_t cmd; + uint8_t *buf; + int err; + + if (conn->type != AML_OBJTYPE_BUFFER || conn->length < 5 || + AML_CRSTYPE(crs) != LR_SERBUS || AML_CRSLEN(crs) > conn->length || + crs->lr_i2cbus.revid != 1 || crs->lr_i2cbus.type != LR_SERBUS_I2C) + aml_die("Invalid GenericSerialBus"); + if (AML_FIELD_ACCESS(flag) != AML_FIELD_BUFFERACC || + bpos & 0x3 || blen != 8) + aml_die("Invalid GenericSerialBus access"); + + node = aml_searchname(conn->node, + (char *)&crs->lr_i2cbus.vdata[crs->lr_i2cbus.tlength - 6]); + + if (node == NULL || node->i2c == NULL) + aml_die("Could not find GenericSerialBus controller"); + + switch (((flag >> 6) & 0x3)) { + case 0: /* Normal */ + switch (AML_FIELD_ATTR(flag)) { + case 0x02: /* AttribQuick */ + cmdlen = 0; + buflen = 0; + break; + case 0x04: /* AttribSendReceive */ + cmdlen = 0; + buflen = 1; + break; + case 0x06: /* AttribByte */ + cmdlen = 1; + buflen = 1; + break; + case 0x08: /* AttribWord */ + cmdlen = 1; + buflen = 2; + break; + default: + aml_die("unsupported access type 0x%x", flag); + break; + } + break; + case 1: /* AttribBytes */ + cmdlen = 1; + buflen = AML_FIELD_ATTR(flag); + break; + case 2: /* AttribRawBytes */ + cmdlen = 0; + buflen = AML_FIELD_ATTR(flag); + break; + default: + aml_die("unsupported access type 0x%x", flag); + break; + } + + if (mode == ACPI_IOREAD) { + _aml_setvalue(val, AML_OBJTYPE_BUFFER, buflen + 2, NULL); + op = I2C_OP_READ_WITH_STOP; + } else { + op = I2C_OP_WRITE_WITH_STOP; + } + + tag = node->i2c; + addr = crs->lr_i2cbus._adr; + cmd = bpos >> 3; + buf = val->v_buffer; + + iic_acquire_bus(tag, 0); + err = iic_exec(tag, op, addr, &cmd, cmdlen, &buf[2], buflen, 0); + iic_release_bus(tag, 0); + + /* + * The ACPI specification doesn't tell us what the status + * codes mean beyond implying that zero means success. So use + * the error returned from the transfer. All possible error + * numbers should fit in a single byte. + */ + buf[0] = err; +} + +void aml_rwindexfield(struct aml_value *fld, struct aml_value *val, int mode) { struct aml_value tmp, *ref1, *ref2; @@ -2615,6 +2708,10 @@ aml_rwfield(struct aml_value *fld, int bpos, int blen, struct aml_value *val, aml_rwgpio(ref2, bpos, blen, val, mode, fld->v_field.flags); break; + case ACPI_OPREG_GSB: + aml_rwgsb(ref2, fld->v_field.bitpos + bpos, blen, + val, mode, fld->v_field.flags); + break; default: aml_rwgen(ref1, fld->v_field.bitpos + bpos, blen, val, mode, fld->v_field.flags); @@ -2702,9 +2799,11 @@ aml_parsefieldlist(struct aml_scope *mscope, int opcode, int flags, mscope->pos++; blen = aml_parselength(mscope); break; - case 0x01: /* flags */ - mscope->pos += 3; + case 0x01: /* attrib */ + mscope->pos++; blen = 0; + flags = aml_get8(mscope->pos++); + flags |= aml_get8(mscope->pos++) << 8; break; case 0x02: /* connection */ mscope->pos++; diff --git a/sys/dev/acpi/dwiic_acpi.c b/sys/dev/acpi/dwiic_acpi.c index cb086bcbf73..c668053b865 100644 --- a/sys/dev/acpi/dwiic_acpi.c +++ b/sys/dev/acpi/dwiic_acpi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dwiic_acpi.c,v 1.3 2018/01/19 18:20:38 jcs Exp $ */ +/* $OpenBSD: dwiic_acpi.c,v 1.4 2018/05/17 20:21:15 kettenis Exp $ */ /* * Synopsys DesignWare I2C controller * @@ -193,6 +193,9 @@ dwiic_acpi_attach(struct device *parent, struct device *self, void *aux) config_found((struct device *)sc, &sc->sc_iba, iicbus_print); + sc->sc_devnode->i2c = &sc->sc_i2c_tag; + acpi_register_gsb(sc->sc_acpi, sc->sc_devnode); + return; } |