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
> 

  • com@acpi Mark Kettenis
    • Re: com@acpi Mike Larkin

Reply via email to