On Sat, Jun 30, 2018 at 02:41:02PM +0200, Mark Kettenis wrote:
> Diff below adds support for the com(4) driver to attach to acpi(4).
> This is needed to support serial console on arm64 ACPI machines. This
> diff is fairly complete. It looks at the SPCR table if present to
> determine if the serial port in question is the console. It also uses
> "Device Properties" to find out the clock frequencies and register
> access quirks. Note that this does deliberately not attach to the
> "classic" serial ports on amd64 and i386. Those continue to be attached
> to isa(4). But this driver could be used for the "low power" UART ports
> found on Intel SoCs as well.
>
> Personally I find this "Device Properties" stuff hilarious. ARM picked
> ACPI over device trees because it was so much more superior. So much
> more superior that they need to embed snippets of a device tree into the
> AML...
>
> Anyway, ok?
>
LGTM. go for it, ok mlarkin.
>
> Index: dev/acpi/acpi.c
> ===================================================================
> RCS file: /cvs/src/sys/dev/acpi/acpi.c,v
> retrieving revision 1.350
> diff -u -p -r1.350 acpi.c
> --- dev/acpi/acpi.c 30 Jun 2018 10:16:35 -0000 1.350
> +++ dev/acpi/acpi.c 30 Jun 2018 12:24:16 -0000
> @@ -2875,6 +2875,50 @@ acpi_foundsony(struct aml_node *node, vo
> return 0;
> }
>
> +/* Support for _DSD Device Properties. */
> +
> +uint32_t
> +acpi_getpropint(struct aml_node *node, const char *prop, uint32_t defval)
> +{
> + struct aml_value dsd;
> + int i;
> +
> + /* daffd814-6eba-4d8c-8a91-bc9bbf4aa301 */
> + static uint8_t prop_guid[] = {
> + 0x14, 0xd8, 0xff, 0xda, 0xba, 0x6e, 0x8c, 0x4d,
> + 0x8a, 0x91, 0xbc, 0x9b, 0xbf, 0x4a, 0xa3, 0x01,
> + };
> +
> + if (aml_evalname(acpi_softc, node, "_DSD", 0, NULL, &dsd))
> + return defval;
> +
> + if (dsd.type != AML_OBJTYPE_PACKAGE || dsd.length != 2 ||
> + dsd.v_package[0]->type != AML_OBJTYPE_BUFFER ||
> + dsd.v_package[1]->type != AML_OBJTYPE_PACKAGE)
> + return defval;
> +
> + /* Check UUID. */
> + if (dsd.v_package[0]->length != sizeof(prop_guid) ||
> + memcmp(dsd.v_package[0]->v_buffer, prop_guid,
> + sizeof(prop_guid)) != 0)
> + return defval;
> +
> + /* Check properties. */
> + for (i = 0; i < dsd.v_package[1]->length; i++) {
> + struct aml_value *res = dsd.v_package[1]->v_package[i];
> +
> + if (res->type != AML_OBJTYPE_PACKAGE || res->length != 2 ||
> + res->v_package[0]->type != AML_OBJTYPE_STRING ||
> + res->v_package[1]->type != AML_OBJTYPE_INTEGER)
> + continue;
> +
> + if (strcmp(res->v_package[0]->v_string, prop) == 0)
> + return res->v_package[1]->v_integer;
> + }
> +
> + return defval;
> +}
> +
> int
> acpi_parsehid(struct aml_node *node, void *arg, char *outcdev, char *outdev,
> size_t devlen)
> Index: dev/acpi/acpireg.h
> ===================================================================
> RCS file: /cvs/src/sys/dev/acpi/acpireg.h,v
> retrieving revision 1.41
> diff -u -p -r1.41 acpireg.h
> --- dev/acpi/acpireg.h 29 Jun 2018 17:39:18 -0000 1.41
> +++ dev/acpi/acpireg.h 30 Jun 2018 12:24:16 -0000
> @@ -417,6 +417,35 @@ struct acpi_mcfg {
> uint32_t reserved1;
> } __packed;
>
> +struct acpi_spcr {
> + struct acpi_table_header hdr;
> +#define SPCR_SIG "SPCR"
> + uint8_t interface_type;
> +#define SPCR_16550 0
> +#define SPCR_16450 1
> +#define SPCR_ARM_PL011 3
> +#define SPCR_ARM_SBSA 14
> + uint8_t reserved1[3];
> + struct acpi_gas base_address;
> + uint8_t interrupt_type;
> + uint8_t irq;
> + uint32_t gsiv;
> + uint8_t baud_rate;
> + uint8_t parity;
> + uint8_t stop_bits;
> + uint8_t flow_control;
> + uint8_t terminal_type;
> + uint8_t reserved2;
> + uint16_t pci_device_id;
> + uint16_t pci_vendor_id;
> + uint8_t pci_bus;
> + uint8_t pci_device;
> + uint8_t pci_function;
> + uint32_t pci_flags;
> + uint8_t pci_segment;
> + uint32_t reserved3;
> +};
> +
> struct acpi_facs {
> uint8_t signature[4];
> #define FACS_SIG "FACS"
> Index: dev/acpi/acpivar.h
> ===================================================================
> RCS file: /cvs/src/sys/dev/acpi/acpivar.h,v
> retrieving revision 1.93
> diff -u -p -r1.93 acpivar.h
> --- dev/acpi/acpivar.h 29 Jun 2018 17:39:18 -0000 1.93
> +++ dev/acpi/acpivar.h 30 Jun 2018 12:24:16 -0000
> @@ -365,6 +365,8 @@ void acpi_sleep(int, char *);
> int acpi_matchhids(struct acpi_attach_args *, const char *[], const char *);
> int acpi_parsehid(struct aml_node *, void *, char *, char *, size_t);
>
> +uint32_t acpi_getpropint(struct aml_node *, const char *, uint32_t);
> +
> int acpi_record_event(struct acpi_softc *, u_int);
>
> void acpi_addtask(struct acpi_softc *, void (*)(void *, int), void *, int);
> Index: dev/acpi/com_acpi.c
> ===================================================================
> RCS file: dev/acpi/com_acpi.c
> diff -N dev/acpi/com_acpi.c
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> +++ dev/acpi/com_acpi.c 30 Jun 2018 12:24:16 -0000
> @@ -0,0 +1,184 @@
> +/* $OpenBSD$ */
> +/*
> + * Copyright (c) 2018 Mark Kettenis
> + *
> + * 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 <sys/tty.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>
> +
> +#undef DEVNAME
> +#include <dev/ic/comreg.h>
> +#include <dev/ic/comvar.h>
> +#include <dev/cons.h>
> +
> +#define com_usr 31 /* Synopsys DesignWare UART */
> +
> +struct com_acpi_softc {
> + struct com_softc sc;
> + struct acpi_softc *sc_acpi;
> + struct aml_node *sc_node;
> +
> + bus_addr_t sc_addr;
> + bus_size_t sc_size;
> +
> + int sc_irq;
> + int sc_irq_flags;
> + void *sc_ih;
> +};
> +
> +int com_acpi_match(struct device *, void *, void *);
> +void com_acpi_attach(struct device *, struct device *, void *);
> +
> +struct cfattach com_acpi_ca = {
> + sizeof(struct com_acpi_softc), com_acpi_match, com_acpi_attach
> +};
> +
> +const char *com_hids[] = {
> + "HISI0031",
> + NULL
> +};
> +
> +int com_acpi_parse_resources(int, union acpi_resource *, void *);
> +int com_acpi_is_console(struct com_acpi_softc *);
> +int com_acpi_intr_designware(void *);
> +
> +int
> +com_acpi_match(struct device *parent, void *match, void *aux)
> +{
> + struct acpi_attach_args *aaa = aux;
> + struct cfdata *cf = match;
> +
> + return acpi_matchhids(aaa, com_hids, cf->cf_driver->cd_name);
> +}
> +
> +void
> +com_acpi_attach(struct device *parent, struct device *self, void *aux)
> +{
> + struct acpi_attach_args *aaa = aux;
> + struct com_acpi_softc *sc = (struct com_acpi_softc *)self;
> + struct aml_value res;
> + uint32_t freq;
> +
> + sc->sc_acpi = (struct acpi_softc *)parent;
> + sc->sc_node = aaa->aaa_node;
> + printf(": %s", sc->sc_node->name);
> +
> + if (aml_evalname(sc->sc_acpi, sc->sc_node, "_CRS", 0, NULL, &res)) {
> + printf(": can't find registers\n");
> + return;
> + }
> +
> + aml_parse_resource(&res, com_acpi_parse_resources, sc);
> + printf(" addr 0x%lx/0x%lx", sc->sc_addr, sc->sc_size);
> + if (sc->sc_addr == 0 || sc->sc_size == 0) {
> + printf("\n");
> + return;
> + }
> +
> + printf(" irq %d", sc->sc_irq);
> +
> + freq = acpi_getpropint(sc->sc_node, "clock-frequency", 0);
> +
> + sc->sc.sc_iot = aaa->aaa_memt;
> + sc->sc.sc_iobase = sc->sc_addr;
> + sc->sc.sc_uarttype = COM_UART_16550;
> + sc->sc.sc_frequency = freq ? freq : COM_FREQ;
> +
> + sc->sc.sc_reg_width = acpi_getpropint(sc->sc_node, "reg-io-width", 4);
> + sc->sc.sc_reg_shift = acpi_getpropint(sc->sc_node, "reg-shift", 2);
> +
> + if (com_acpi_is_console(sc)) {
> + SET(sc->sc.sc_hwflags, COM_HW_CONSOLE);
> + SET(sc->sc.sc_swflags, COM_SW_SOFTCAR);
> + comconsfreq = sc->sc.sc_frequency;
> + comconsrate = B115200;
> + }
> +
> + if (bus_space_map(sc->sc.sc_iot, sc->sc_addr, sc->sc_size, 0,
> + &sc->sc.sc_ioh)) {
> + printf(": can't map registers\n");
> + return;
> + }
> +
> + sc->sc_ih = acpi_intr_establish(sc->sc_irq, sc->sc_irq_flags, IPL_TTY,
> + com_acpi_intr_designware, sc, sc->sc.sc_dev.dv_xname);
> + if (sc->sc_ih == NULL) {
> + printf(": can't establish interrupt\n");
> + return;
> + }
> +
> + com_attach_subr(&sc->sc);
> +}
> +
> +int
> +com_acpi_parse_resources(int crsidx, union acpi_resource *crs, void *arg)
> +{
> + struct com_acpi_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;
> + }
> +
> + return 0;
> +}
> +
> +int
> +com_acpi_is_console(struct com_acpi_softc *sc)
> +{
> + struct acpi_table_header *hdr;
> + struct acpi_spcr *spcr;
> + struct acpi_gas *base;
> + struct acpi_q *entry;
> +
> + SIMPLEQ_FOREACH(entry, &sc->sc_acpi->sc_tables, q_next) {
> + hdr = entry->q_table;
> + if (strncmp(hdr->signature, SPCR_SIG,
> + sizeof(hdr->signature)) == 0) {
> + spcr = entry->q_table;
> + base = &spcr->base_address;
> + if (base->address_space_id == GAS_SYSTEM_MEMORY &&
> + base->address == sc->sc_addr)
> + return 1;
> + }
> + }
> +
> + return 0;
> +}
> +
> +int
> +com_acpi_intr_designware(void *cookie)
> +{
> + struct com_softc *sc = cookie;
> +
> + com_read_reg(sc, com_usr);
> +
> + return comintr(sc);
> +}
> Index: dev/acpi/files.acpi
> ===================================================================
> RCS file: /cvs/src/sys/dev/acpi/files.acpi,v
> retrieving revision 1.42
> diff -u -p -r1.42 files.acpi
> --- dev/acpi/files.acpi 21 May 2018 13:37:31 -0000 1.42
> +++ dev/acpi/files.acpi 30 Jun 2018 12:24:16 -0000
> @@ -137,6 +137,10 @@ device ccpmic
> attach ccpmic at i2c
> file dev/acpi/ccpmic.c ccpmic
>
> +# NS16550 compatible UART
> +attach com at acpi with com_acpi
> +file dev/acpi/com_acpi.c com_acpi
> +
> # SD Host Controller
> attach sdhc at acpi with sdhc_acpi
> file dev/acpi/sdhc_acpi.c sdhc_acpi
>