summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2018-05-17 20:21:16 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2018-05-17 20:21:16 +0000
commit641bee903b7ac7f39242ddf95ec1d453670c1840 (patch)
tree0cf7bafd9064ca1bf30889eae069b78d52d3c6d2
parent40b9165f194868b48de0f9535ad742474f5274ee (diff)
Implement GenericSerialBus OpRegion support.
ok mlarkin@
-rw-r--r--sys/dev/acpi/acpi.c19
-rw-r--r--sys/dev/acpi/acpivar.h3
-rw-r--r--sys/dev/acpi/amltypes.h7
-rw-r--r--sys/dev/acpi/dsdt.c105
-rw-r--r--sys/dev/acpi/dwiic_acpi.c5
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;
}