diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2019-12-23 08:05:43 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2019-12-23 08:05:43 +0000 |
commit | 54a8a4670ad9f45c20946fd5715fbdb306a75ea3 (patch) | |
tree | 0a2995e59c9dae00aaeaf6fdffd80bce83729336 | |
parent | 5dfcefcd578ee48245f4c99b9cb4acf6105df54f (diff) |
Add amdgpio(4), a driver for the GPIO controller found on newer AMD
AMD SoCs/chipsets.
From James Hastings
-rw-r--r-- | share/man/man4/Makefile | 4 | ||||
-rw-r--r-- | share/man/man4/acpi.4 | 6 | ||||
-rw-r--r-- | share/man/man4/amdgpio.4 | 49 | ||||
-rw-r--r-- | sys/arch/amd64/conf/GENERIC | 3 | ||||
-rw-r--r-- | sys/arch/amd64/conf/RAMDISK_CD | 3 | ||||
-rw-r--r-- | sys/dev/acpi/amdgpio.c | 312 | ||||
-rw-r--r-- | sys/dev/acpi/files.acpi | 7 |
7 files changed, 377 insertions, 7 deletions
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile index 307bd44b66b..9d70964629a 100644 --- a/share/man/man4/Makefile +++ b/share/man/man4/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.746 2019/12/17 23:05:45 deraadt Exp $ +# $OpenBSD: Makefile,v 1.747 2019/12/23 08:05:42 kettenis Exp $ MAN= aac.4 abcrtc.4 ac97.4 acphy.4 acrtc.4 \ acpi.4 acpiac.4 acpials.4 acpiasus.4 acpibat.4 \ @@ -10,7 +10,7 @@ MAN= aac.4 abcrtc.4 ac97.4 acphy.4 acrtc.4 \ admtm.4 admtmp.4 admtt.4 adt.4 adtfsm.4 adv.4 age.4 alc.4 ale.4 \ aggr.4 agp.4 \ ahc.4 ahci.4 ahd.4 aibs.4 aic.4 \ - akbd.4 alipm.4 amas.4 amdiic.4 amdpm.4 ami.4 \ + akbd.4 alipm.4 amas.4 amdgpio.4 amdiic.4 amdpm.4 ami.4 \ amlclock.4 amldwusb.4 amliic.4 amlmmc.4 amlpciephy.4 amlpinctrl.4 \ amlpwm.4 amlreset.4 amlrng.4 amluart.4 amlusbphy.4 \ amphy.4 ams.4 an.4 andl.4 aplgpio.4 aps.4 arc.4 arcofi.4 \ diff --git a/share/man/man4/acpi.4 b/share/man/man4/acpi.4 index 794e61ace1e..3ae7f624009 100644 --- a/share/man/man4/acpi.4 +++ b/share/man/man4/acpi.4 @@ -1,4 +1,4 @@ -.\" $OpenBSD: acpi.4,v 1.59 2019/06/24 21:33:27 kettenis Exp $ +.\" $OpenBSD: acpi.4,v 1.60 2019/12/23 08:05:42 kettenis Exp $ .\" .\" Copyright (c) 2006 Alexander Yurchenko <grange@openbsd.org> .\" @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: June 24 2019 $ +.Dd $Mdocdate: December 23 2019 $ .Dt ACPI 4 .Os .Sh NAME @@ -90,6 +90,8 @@ ACPI video ACPI video output .It Xr aibs 4 ASUSTeK AI Booster ACPI ATK0110 temperature, voltage, and fan sensor +.It Xr amdgpio 4 +AMD GPIO controller .It Xr aplgpio 4 Intel Apollo Lake GPIO controller .It Xr bytgpio 4 diff --git a/share/man/man4/amdgpio.4 b/share/man/man4/amdgpio.4 new file mode 100644 index 00000000000..f7125c1af3b --- /dev/null +++ b/share/man/man4/amdgpio.4 @@ -0,0 +1,49 @@ +.\" $OpenBSD: amdgpio.4,v 1.1 2019/12/23 08:05:42 kettenis Exp $ +.\" +.\" Copyright (c) 2019 James Hastings +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: December 23 2019 $ +.Dt AMDGPIO 4 +.Os +.Sh NAME +.Nm amdgpio +.Nd AMD GPIO controller +.Sh SYNOPSIS +.Cd "amdgpio* at acpi?" +.Sh DESCRIPTION +The +.Nm +driver provides support for the GPIO controller found on AMD chipsets. +It does not provide direct device driver entry points but makes its +functions available to +.Xr acpi 4 . +.Sh SEE ALSO +.Xr acpi 4 , +.Xr intro 4 +.Sh HISTORY +The +.Nm +driver first appeared in +.Ox 6.7 . +.Sh AUTHORS +.An -nosplit +The +.Nm +driver was written by +.An James Hastings +based on the +.Xr bytgpio 4 +driver by +.An Mark Kettenis Aq Mt kettenis@openbsd.org . diff --git a/sys/arch/amd64/conf/GENERIC b/sys/arch/amd64/conf/GENERIC index 17e88a9eb51..a448bca467e 100644 --- a/sys/arch/amd64/conf/GENERIC +++ b/sys/arch/amd64/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.483 2019/12/17 13:08:54 reyk Exp $ +# $OpenBSD: GENERIC,v 1.484 2019/12/23 08:05:42 kettenis Exp $ # # For further information on compiling OpenBSD kernels, see the config(8) # man page. @@ -60,6 +60,7 @@ acpivideo* at acpi? acpivout* at acpivideo? acpipwrres* at acpi? aibs* at acpi? +amdgpio* at acpi? aplgpio* at acpi? bytgpio* at acpi? chvgpio* at acpi? diff --git a/sys/arch/amd64/conf/RAMDISK_CD b/sys/arch/amd64/conf/RAMDISK_CD index f53b64855b3..261061ff1aa 100644 --- a/sys/arch/amd64/conf/RAMDISK_CD +++ b/sys/arch/amd64/conf/RAMDISK_CD @@ -1,4 +1,4 @@ -# $OpenBSD: RAMDISK_CD,v 1.186 2019/11/19 02:01:58 kevlo Exp $ +# $OpenBSD: RAMDISK_CD,v 1.187 2019/12/23 08:05:42 kettenis Exp $ machine amd64 maxusers 4 @@ -40,6 +40,7 @@ acpiec* at acpi? acpiprt* at acpi? acpimadt0 at acpi? #acpitz* at acpi? +amdgpio* at acpi? aplgpio* at acpi? bytgpio* at acpi? sdhc* at acpi? diff --git a/sys/dev/acpi/amdgpio.c b/sys/dev/acpi/amdgpio.c new file mode 100644 index 00000000000..3c125552604 --- /dev/null +++ b/sys/dev/acpi/amdgpio.c @@ -0,0 +1,312 @@ +/* $OpenBSD: amdgpio.c,v 1.1 2019/12/23 08:05:42 kettenis Exp $ */ +/* + * Copyright (c) 2016 Mark Kettenis + * Copyright (c) 2019 James Hastings + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/malloc.h> +#include <sys/systm.h> + +#include <dev/acpi/acpireg.h> +#include <dev/acpi/acpivar.h> +#include <dev/acpi/acpidev.h> +#include <dev/acpi/amltypes.h> +#include <dev/acpi/dsdt.h> + +#define AMDGPIO_CONF_LEVEL 0x00000100 +#define AMDGPIO_CONF_ACTLO 0x00000200 +#define AMDGPIO_CONF_ACTBOTH 0x00000400 +#define AMDGPIO_CONF_MASK 0x00000600 +#define AMDGPIO_CONF_INT_EN 0x00000800 +#define AMDGPIO_CONF_INT_MASK 0x00001000 +#define AMDGPIO_CONF_RXSTATE 0x00010000 +#define AMDGPIO_CONF_TXSTATE 0x00400000 +#define AMDGPIO_CONF_TXSTATE_EN 0x00800000 +#define AMDGPIO_CONF_INT_STS 0x10000000 +#define AMDGPIO_IRQ_MASTER_EOI 0x20000000 +#define AMDGPIO_IRQ_BITS 46 +#define AMDGPIO_IRQ_PINS 4 + +#define AMDGPIO_IRQ_MASTER 0xfc +#define AMDGPIO_IRQ_STS 0x2f8 + +struct amdgpio_intrhand { + int (*ih_func)(void *); + void *ih_arg; +}; + +struct amdgpio_softc { + struct device sc_dev; + struct acpi_softc *sc_acpi; + struct aml_node *sc_node; + + bus_space_tag_t sc_memt; + bus_space_handle_t sc_memh; + bus_addr_t sc_addr; + bus_size_t sc_size; + + int sc_irq; + int sc_irq_flags; + void *sc_ih; + + int sc_npins; + struct amdgpio_intrhand *sc_pin_ih; + + struct acpi_gpio sc_gpio; +}; + +int amdgpio_match(struct device *, void *, void *); +void amdgpio_attach(struct device *, struct device *, void *); + +struct cfattach amdgpio_ca = { + sizeof(struct amdgpio_softc), amdgpio_match, amdgpio_attach +}; + +struct cfdriver amdgpio_cd = { + NULL, "amdgpio", DV_DULL +}; + +const char *amdgpio_hids[] = { + "AMDI0030", + "AMD0030", + NULL +}; + +int amdgpio_parse_resources(int, union acpi_resource *, void *); +int amdgpio_read_pin(void *, int); +void amdgpio_write_pin(void *, int, int); +void amdgpio_intr_establish(void *, int, int, int (*)(), void *); +int amdgpio_pin_intr(struct amdgpio_softc *, int); +int amdgpio_intr(void *); + +int +amdgpio_match(struct device *parent, void *match, void *aux) +{ + struct acpi_attach_args *aaa = aux; + struct cfdata *cf = match; + + return acpi_matchhids(aaa, amdgpio_hids, cf->cf_driver->cd_name); +} + +void +amdgpio_attach(struct device *parent, struct device *self, void *aux) +{ + struct acpi_attach_args *aaa = aux; + struct amdgpio_softc *sc = (struct amdgpio_softc *)self; + struct aml_value res; + int64_t uid; + + sc->sc_acpi = (struct acpi_softc *)parent; + sc->sc_node = aaa->aaa_node; + printf(": %s", sc->sc_node->name); + + if (aml_evalinteger(sc->sc_acpi, sc->sc_node, "_UID", 0, NULL, &uid)) { + printf(", can't find uid\n"); + return; + } + + printf(" uid %lld", uid); + + switch (uid) { + case 0: + sc->sc_npins = 184; + break; + default: + printf("\n"); + return; + } + + if (aml_evalname(sc->sc_acpi, sc->sc_node, "_CRS", 0, NULL, &res)) { + printf(", can't find registers\n"); + return; + } + + aml_parse_resource(&res, amdgpio_parse_resources, sc); + aml_freevalue(&res); + printf(" addr 0x%lx/0x%lx", sc->sc_addr, sc->sc_size); + if (sc->sc_addr == 0 || sc->sc_size == 0) { + printf("\n"); + return; + } + + sc->sc_pin_ih = mallocarray(sc->sc_npins, sizeof(*sc->sc_pin_ih), + M_DEVBUF, M_NOWAIT | M_ZERO); + if (sc->sc_pin_ih == NULL) { + printf("\n"); + return; + } + + printf(" irq %d", sc->sc_irq); + + sc->sc_memt = aaa->aaa_memt; + if (bus_space_map(sc->sc_memt, sc->sc_addr, sc->sc_size, 0, + &sc->sc_memh)) { + printf(", can't map registers\n"); + goto free; + } + + sc->sc_ih = acpi_intr_establish(sc->sc_irq, sc->sc_irq_flags, IPL_BIO, + amdgpio_intr, sc, sc->sc_dev.dv_xname); + if (sc->sc_ih == NULL) { + printf(", can't establish interrupt\n"); + goto unmap; + } + + sc->sc_gpio.cookie = sc; + sc->sc_gpio.read_pin = amdgpio_read_pin; + sc->sc_gpio.write_pin = amdgpio_write_pin; + sc->sc_gpio.intr_establish = amdgpio_intr_establish; + sc->sc_node->gpio = &sc->sc_gpio; + + printf(", %d pins\n", sc->sc_npins); + + acpi_register_gpio(sc->sc_acpi, sc->sc_node); + return; + +unmap: + bus_space_unmap(sc->sc_memt, sc->sc_memh, sc->sc_size); +free: + free(sc->sc_pin_ih, M_DEVBUF, sc->sc_npins * sizeof(*sc->sc_pin_ih)); +} + +int +amdgpio_parse_resources(int crsidx, union acpi_resource *crs, void *arg) +{ + struct amdgpio_softc *sc = arg; + int type = AML_CRSTYPE(crs); + + switch (type) { + case LR_MEM32FIXED: + sc->sc_addr = crs->lr_m32fixed._bas; + sc->sc_size = crs->lr_m32fixed._len; + break; + case LR_EXTIRQ: + sc->sc_irq = crs->lr_extirq.irq[0]; + sc->sc_irq_flags = crs->lr_extirq.flags; + break; + default: + printf(" type 0x%x\n", type); + break; + } + + return 0; +} + +int +amdgpio_read_pin(void *cookie, int pin) +{ + struct amdgpio_softc *sc = cookie; + uint32_t reg; + + reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, pin * 4); + + return !!(reg & AMDGPIO_CONF_RXSTATE); +} + +void +amdgpio_write_pin(void *cookie, int pin, int value) +{ + struct amdgpio_softc *sc = cookie; + uint32_t reg; + + reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, pin * 4); + reg |= AMDGPIO_CONF_TXSTATE_EN; + if (value) + reg |= AMDGPIO_CONF_TXSTATE; + else + reg &= ~AMDGPIO_CONF_TXSTATE; + bus_space_write_4(sc->sc_memt, sc->sc_memh, pin * 4, reg); +} + +void +amdgpio_intr_establish(void *cookie, int pin, int flags, + int (*func)(void *), void *arg) +{ + struct amdgpio_softc *sc = cookie; + uint32_t reg; + + KASSERT(pin >= 0 && pin != 63 && pin < sc->sc_npins); + + sc->sc_pin_ih[pin].ih_func = func; + sc->sc_pin_ih[pin].ih_arg = arg; + + reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, pin * 4); + reg &= ~(AMDGPIO_CONF_MASK | AMDGPIO_CONF_LEVEL | + AMDGPIO_CONF_TXSTATE_EN); + if ((flags & LR_GPIO_MODE) == 0) + reg |= AMDGPIO_CONF_LEVEL; + if ((flags & LR_GPIO_POLARITY) == LR_GPIO_ACTLO) + reg |= AMDGPIO_CONF_ACTLO; + if ((flags & LR_GPIO_POLARITY) == LR_GPIO_ACTBOTH) + reg |= AMDGPIO_CONF_ACTBOTH; + reg |= (AMDGPIO_CONF_INT_MASK | AMDGPIO_CONF_INT_EN); + bus_space_write_4(sc->sc_memt, sc->sc_memh, pin * 4, reg); +} + +int +amdgpio_pin_intr(struct amdgpio_softc *sc, int pin) +{ + uint32_t reg; + + reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, pin * 4); + if (!(reg & AMDGPIO_CONF_INT_STS) || + !(reg & AMDGPIO_CONF_INT_MASK)) + return 0; + + if (sc->sc_pin_ih[pin].ih_func) + sc->sc_pin_ih[pin].ih_func(sc->sc_pin_ih[pin].ih_arg); + + /* Clear interrupt */ + reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, pin * 4); + bus_space_write_4(sc->sc_memt, sc->sc_memh, pin * 4, reg); + + return 1; +} + +int +amdgpio_intr(void *arg) +{ + struct amdgpio_softc *sc = arg; + uint64_t status; + uint32_t reg; + int rc = 0, pin = 0; + int i, j; + + status = bus_space_read_4(sc->sc_memt, sc->sc_memh, + AMDGPIO_IRQ_STS + 4); + status <<= 32; + status |= bus_space_read_4(sc->sc_memt, sc->sc_memh, + AMDGPIO_IRQ_STS); + + /* One status bit for every four pins */ + for (i = 0; i < AMDGPIO_IRQ_BITS; i++, pin += 4) { + if (status & (1 << i)) { + for (j = 0; j < AMDGPIO_IRQ_PINS; j++) { + if (amdgpio_pin_intr(sc, pin + j)) + rc = 1; + } + } + } + + /* Signal end of interrupt */ + reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, + AMDGPIO_IRQ_MASTER); + reg |= AMDGPIO_IRQ_MASTER_EOI; + bus_space_write_4(sc->sc_memt, sc->sc_memh, + AMDGPIO_IRQ_MASTER, reg); + + return rc; +} diff --git a/sys/dev/acpi/files.acpi b/sys/dev/acpi/files.acpi index 054ef1a8e50..1a635fd86be 100644 --- a/sys/dev/acpi/files.acpi +++ b/sys/dev/acpi/files.acpi @@ -1,4 +1,4 @@ -# $OpenBSD: files.acpi,v 1.52 2019/06/24 21:33:27 kettenis Exp $ +# $OpenBSD: files.acpi,v 1.53 2019/12/23 08:05:42 kettenis Exp $ # # Config file and device description for machine-independent ACPI code. # Included by ports that need it. @@ -207,3 +207,8 @@ file dev/acpi/ipmi_acpi.c ipmi_acpi # AMD Cryptographic Co-processor attach ccp at acpi with ccp_acpi file dev/acpi/ccp_acpi.c ccp_acpi + +# AMD GPIO Controller +device amdgpio +attach amdgpio at acpi +file dev/acpi/amdgpio.c amdgpio |