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?


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

Reply via email to