summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/dev/acpi/chvgpio.c29
-rw-r--r--sys/dev/acpi/dsdt.c162
-rw-r--r--sys/dev/acpi/dsdt.h4
3 files changed, 173 insertions, 22 deletions
diff --git a/sys/dev/acpi/chvgpio.c b/sys/dev/acpi/chvgpio.c
index c3352dcbe81..a82e6c53fbb 100644
--- a/sys/dev/acpi/chvgpio.c
+++ b/sys/dev/acpi/chvgpio.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: chvgpio.c,v 1.6 2016/10/25 06:48:58 pirofti Exp $ */
+/* $OpenBSD: chvgpio.c,v 1.7 2017/11/29 15:22:22 kettenis Exp $ */
/*
* Copyright (c) 2016 Mark Kettenis
*
@@ -43,6 +43,9 @@
#define CHVGPIO_PAD_CFG1_INVRXTX_MASK 0x000000f0
#define CHVGPIO_PAD_CFG1_INVRXTX_RXDATA 0x00000040
+/* OEM defined RegionSpace. */
+#define CHVGPIO_REGIONSPACE_BASE 0x90
+
struct chvgpio_intrhand {
int (*ih_func)(void *);
void *ih_arg;
@@ -149,6 +152,7 @@ int chvgpio_read_pin(void *, int);
void chvgpio_write_pin(void *, int, int);
void chvgpio_intr_establish(void *, int, int, int (*)(), void *);
int chvgpio_intr(void *);
+int chvgpio_opreg_handler(void *, int, uint64_t, int, uint64_t *);
int
chvgpio_match(struct device *parent, void *match, void *aux)
@@ -247,7 +251,7 @@ chvgpio_attach(struct device *parent, struct device *self, void *aux)
printf(", %d pins\n", sc->sc_npins);
- /* Register address space. */
+ /* Register GeneralPurposeIO address space. */
memset(&arg, 0, sizeof(arg));
arg[0].type = AML_OBJTYPE_INTEGER;
arg[0].v_integer = ACPI_OPREG_GPIO;
@@ -257,6 +261,9 @@ chvgpio_attach(struct device *parent, struct device *self, void *aux)
if (node && aml_evalnode(sc->sc_acpi, node, 2, arg, NULL))
printf("%s: _REG failed\n", sc->sc_dev.dv_xname);
+ /* Register OEM defined address space. */
+ aml_register_regionspace(sc->sc_node, CHVGPIO_REGIONSPACE_BASE + uid,
+ sc, chvgpio_opreg_handler);
return;
unmap:
@@ -399,3 +406,21 @@ chvgpio_intr(void *arg)
return rc;
}
+
+int
+chvgpio_opreg_handler(void *cookie, int iodir, uint64_t address, int size,
+ uint64_t *value)
+{
+ struct chvgpio_softc *sc = cookie;
+
+ /* Only allow 32-bit access. */
+ if (size != 4 || address > sc->sc_size - size)
+ return -1;
+
+ if (iodir == ACPI_IOREAD)
+ *value = bus_space_read_4(sc->sc_memt, sc->sc_memh, address);
+ else
+ bus_space_write_4(sc->sc_memt, sc->sc_memh, address, *value);
+
+ return 0;
+}
diff --git a/sys/dev/acpi/dsdt.c b/sys/dev/acpi/dsdt.c
index 544c9cf7358..1c38be3bbfa 100644
--- a/sys/dev/acpi/dsdt.c
+++ b/sys/dev/acpi/dsdt.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: dsdt.c,v 1.235 2017/10/12 07:24:46 anton Exp $ */
+/* $OpenBSD: dsdt.c,v 1.236 2017/11/29 15:22:22 kettenis Exp $ */
/*
* Copyright (c) 2005 Jordan Hargrave <jordan@openbsd.org>
*
@@ -2208,8 +2208,6 @@ void aml_createfield(struct aml_value *, int, struct aml_value *, int, int,
void aml_parsefieldlist(struct aml_scope *, int, int,
struct aml_value *, struct aml_value *, int);
-#define GAS_PCI_CFG_SPACE_UNEVAL 0xCC
-
int
aml_evalhid(struct aml_node *node, struct aml_value *val)
{
@@ -2222,7 +2220,73 @@ aml_evalhid(struct aml_node *node, struct aml_value *val)
return (0);
}
-void aml_rwgas(struct aml_value *, int, int, struct aml_value *, int, int);
+int
+aml_opreg_sysmem_handler(void *cookie, int iodir, uint64_t address, int size,
+ uint64_t *value)
+{
+ return acpi_gasio(acpi_softc, iodir, GAS_SYSTEM_MEMORY,
+ address, size, size, value);
+}
+
+int
+aml_opreg_sysio_handler(void *cookie, int iodir, uint64_t address, int size,
+ uint64_t *value)
+{
+ return acpi_gasio(acpi_softc, iodir, GAS_SYSTEM_IOSPACE,
+ address, size, size, value);
+}
+
+int
+aml_opreg_pcicfg_handler(void *cookie, int iodir, uint64_t address, int size,
+ uint64_t *value)
+{
+ return acpi_gasio(acpi_softc, iodir, GAS_PCI_CFG_SPACE,
+ address, size, size, value);
+}
+
+int
+aml_opreg_ec_handler(void *cookie, int iodir, uint64_t address, int size,
+ uint64_t *value)
+{
+ return acpi_gasio(acpi_softc, iodir, GAS_EMBEDDED,
+ address, size, size, value);
+}
+
+struct aml_regionspace {
+ void *cookie;
+ int (*handler)(void *, int, uint64_t, int, uint64_t *);
+};
+
+struct aml_regionspace aml_regionspace[256] = {
+ [ACPI_OPREG_SYSMEM] = { NULL, aml_opreg_sysmem_handler },
+ [ACPI_OPREG_SYSIO] = { NULL, aml_opreg_sysio_handler },
+ [ACPI_OPREG_PCICFG] = { NULL, aml_opreg_pcicfg_handler },
+ [ACPI_OPREG_EC] = { NULL, aml_opreg_ec_handler },
+};
+
+void
+aml_register_regionspace(struct aml_node *node, int iospace, void *cookie,
+ int (*handler)(void *, int, uint64_t, int, uint64_t *))
+{
+ struct aml_value arg[2];
+
+ KASSERT(iospace >= 0 && iospace < 256);
+
+ aml_regionspace[iospace].cookie = cookie;
+ aml_regionspace[iospace].handler = handler;
+
+ /* Register address space. */
+ memset(&arg, 0, sizeof(arg));
+ arg[0].type = AML_OBJTYPE_INTEGER;
+ arg[0].v_integer = iospace;
+ arg[1].type = AML_OBJTYPE_INTEGER;
+ arg[1].v_integer = 1;
+ node = aml_searchname(node, "_REG");
+ if (node)
+ aml_evalnode(acpi_softc, node, 2, arg, NULL);
+}
+
+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_rwindexfield(struct aml_value *, struct aml_value *val, int);
void aml_rwfield(struct aml_value *, int, int, struct aml_value *, int);
@@ -2250,9 +2314,73 @@ aml_rdpciaddr(struct aml_node *pcidev, union amlpci_t *addr)
return (0);
}
+int
+acpi_genio(struct acpi_softc *sc, int iodir, int iospace, uint64_t address,
+ int access_size, int len, void *buffer)
+{
+ struct aml_regionspace *region = &aml_regionspace[iospace];
+ u_int8_t *pb;
+ int reg;
+
+ dnprintf(50, "genio: %.2x 0x%.8llx %s\n",
+ iospace, address, (iodir == ACPI_IOWRITE) ? "write" : "read");
+
+ KASSERT((len % access_size) == 0);
+
+ pb = (u_int8_t *)buffer;
+ for (reg = 0; reg < len; reg += access_size) {
+ uint64_t value;
+ int err;
+
+ if (iodir == ACPI_IOREAD) {
+ err = region->handler(region->cookie, iodir,
+ address + reg, access_size, &value);
+ if (err)
+ return err;
+ switch (access_size) {
+ case 1:
+ *(uint8_t *)(pb + reg) = value;
+ break;
+ case 2:
+ *(uint16_t *)(pb + reg) = value;
+ break;
+ case 4:
+ *(uint32_t *)(pb + reg) = value;
+ break;
+ default:
+ printf("%s: invalid access size %d on read\n",
+ __func__, access_size);
+ return -1;
+ }
+ } else {
+ switch (access_size) {
+ case 1:
+ value = *(uint8_t *)(pb + reg);
+ break;
+ case 2:
+ value = *(uint16_t *)(pb + reg);
+ break;
+ case 4:
+ value = *(uint32_t *)(pb + reg);
+ break;
+ default:
+ printf("%s: invalid access size %d on write\n",
+ __func__, access_size);
+ return -1;
+ }
+ err = region->handler(region->cookie, iodir,
+ address + reg, access_size, &value);
+ if (err)
+ return err;
+ }
+ }
+
+ return 0;
+}
+
/* Read/Write from opregion object */
void
-aml_rwgas(struct aml_value *rgn, int bpos, int blen, struct aml_value *val,
+aml_rwgen(struct aml_value *rgn, int bpos, int blen, struct aml_value *val,
int mode, int flag)
{
struct aml_value tmp;
@@ -2287,7 +2415,7 @@ aml_rwgas(struct aml_value *rgn, int bpos, int blen, struct aml_value *val,
bpos += ((rgn->v_opregion.iobase & (sz - 1)) << 3);
bpos &= ((sz << 3) - 1);
- if (rgn->v_opregion.iospace == GAS_PCI_CFG_SPACE) {
+ if (rgn->v_opregion.iospace == ACPI_OPREG_PCICFG) {
/* Get PCI Root Address for this opregion */
aml_rdpciaddr(rgn->node->parent, &pi);
}
@@ -2297,6 +2425,9 @@ aml_rwgas(struct aml_value *rgn, int bpos, int blen, struct aml_value *val,
tlen = roundup(bpos + blen, sz << 3);
type = rgn->v_opregion.iospace;
+ if (aml_regionspace[type].handler == NULL)
+ panic("%s: unregistered RegionSpace 0x%x\n", __func__, type);
+
/* Allocate temporary storage */
if (tlen > aml_intlen) {
_aml_setvalue(&tmp, AML_OBJTYPE_BUFFER, tlen >> 3, 0);
@@ -2327,21 +2458,21 @@ aml_rwgas(struct aml_value *rgn, int bpos, int blen, struct aml_value *val,
if (mode == ACPI_IOREAD) {
/* Read bits from opregion */
- acpi_gasio(acpi_softc, ACPI_IOREAD, type, pi.addr,
+ acpi_genio(acpi_softc, ACPI_IOREAD, type, pi.addr,
sz, tlen >> 3, tbit);
aml_bufcpy(vbit, 0, tbit, bpos, blen);
} else {
/* Write bits to opregion */
if (AML_FIELD_UPDATE(flag) == AML_FIELD_PRESERVE &&
(bpos != 0 || blen != tlen)) {
- acpi_gasio(acpi_softc, ACPI_IOREAD, type, pi.addr,
+ acpi_genio(acpi_softc, ACPI_IOREAD, type, pi.addr,
sz, tlen >> 3, tbit);
} else if (AML_FIELD_UPDATE(flag) == AML_FIELD_WRITEASONES) {
memset(tbit, 0xff, tmp.length);
}
/* Copy target bits, then write to region */
aml_bufcpy(tbit, bpos, vbit, 0, blen);
- acpi_gasio(acpi_softc, ACPI_IOWRITE, type, pi.addr,
+ acpi_genio(acpi_softc, ACPI_IOWRITE, type, pi.addr,
sz, tlen >> 3, tbit);
aml_delref(&val, "fld.write");
@@ -2473,7 +2604,7 @@ aml_rwfield(struct aml_value *fld, int bpos, int blen, struct aml_value *val,
} else if (fld->v_field.type == AMLOP_BANKFIELD) {
_aml_setvalue(&tmp, AML_OBJTYPE_INTEGER, fld->v_field.ref3, 0);
aml_rwfield(ref2, 0, aml_intlen, &tmp, ACPI_IOWRITE);
- aml_rwgas(ref1, fld->v_field.bitpos, fld->v_field.bitlen,
+ aml_rwgen(ref1, fld->v_field.bitpos, fld->v_field.bitlen,
val, mode, fld->v_field.flags);
} else if (fld->v_field.type == AMLOP_FIELD) {
switch (ref1->v_opregion.iospace) {
@@ -2481,16 +2612,9 @@ 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_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 0x%x",
- ref1->v_opregion.iospace);
+ aml_rwgen(ref1, fld->v_field.bitpos + bpos, blen,
+ val, mode, fld->v_field.flags);
break;
}
} else if (mode == ACPI_IOREAD) {
diff --git a/sys/dev/acpi/dsdt.h b/sys/dev/acpi/dsdt.h
index a3b871a5ecd..66e1ba73c99 100644
--- a/sys/dev/acpi/dsdt.h
+++ b/sys/dev/acpi/dsdt.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: dsdt.h,v 1.73 2016/10/25 06:48:58 pirofti Exp $ */
+/* $OpenBSD: dsdt.h,v 1.74 2017/11/29 15:22:22 kettenis Exp $ */
/*
* Copyright (c) 2005 Marco Peereboom <marco@openbsd.org>
*
@@ -60,6 +60,8 @@ int acpi_parse_aml(struct acpi_softc *, u_int8_t *,
void aml_register_notify(struct aml_node *, const char *,
int (*)(struct aml_node *, int, void *), void *,
int);
+void aml_register_regionspace(struct aml_node *, int, void *,
+ int (*)(void *, int, uint64_t, int, uint64_t *));
int aml_evalnode(struct acpi_softc *, struct aml_node *,
int, struct aml_value *, struct aml_value *);