1 /* $OpenBSD: com_acpi.c,v 1.2 2020/05/08 11:18:01 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2018 Mark Kettenis 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/malloc.h> 20 #include <sys/systm.h> 21 #include <sys/tty.h> 22 23 #include <dev/acpi/acpireg.h> 24 #include <dev/acpi/acpivar.h> 25 #include <dev/acpi/acpidev.h> 26 #include <dev/acpi/amltypes.h> 27 #include <dev/acpi/dsdt.h> 28 29 #undef DEVNAME 30 #include <dev/ic/comreg.h> 31 #include <dev/ic/comvar.h> 32 #include <dev/cons.h> 33 34 #define com_usr 31 /* Synopsys DesignWare UART */ 35 36 struct com_acpi_softc { 37 struct com_softc sc; 38 struct acpi_softc *sc_acpi; 39 struct aml_node *sc_node; 40 void *sc_ih; 41 }; 42 43 int com_acpi_match(struct device *, void *, void *); 44 void com_acpi_attach(struct device *, struct device *, void *); 45 46 struct cfattach com_acpi_ca = { 47 sizeof(struct com_acpi_softc), com_acpi_match, com_acpi_attach 48 }; 49 50 const char *com_hids[] = { 51 "HISI0031", 52 NULL 53 }; 54 55 int com_acpi_is_console(struct com_acpi_softc *); 56 int com_acpi_intr_designware(void *); 57 58 int 59 com_acpi_match(struct device *parent, void *match, void *aux) 60 { 61 struct acpi_attach_args *aaa = aux; 62 struct cfdata *cf = match; 63 64 return acpi_matchhids(aaa, com_hids, cf->cf_driver->cd_name); 65 } 66 67 void 68 com_acpi_attach(struct device *parent, struct device *self, void *aux) 69 { 70 struct com_acpi_softc *sc = (struct com_acpi_softc *)self; 71 struct acpi_attach_args *aaa = aux; 72 uint32_t freq; 73 74 sc->sc_acpi = (struct acpi_softc *)parent; 75 sc->sc_node = aaa->aaa_node; 76 printf(" %s", sc->sc_node->name); 77 78 if (aaa->aaa_naddr < 1) { 79 printf(": no registers\n"); 80 return; 81 } 82 83 if (aaa->aaa_nirq < 1) { 84 printf(": no interrupt\n"); 85 return; 86 } 87 88 printf(" addr 0x%llx/0x%llx", aaa->aaa_addr[0], aaa->aaa_size[0]); 89 printf(" irq %d", aaa->aaa_irq[0]); 90 91 freq = acpi_getpropint(sc->sc_node, "clock-frequency", 0); 92 93 sc->sc.sc_iot = aaa->aaa_bst[0]; 94 sc->sc.sc_iobase = aaa->aaa_addr[0]; 95 sc->sc.sc_uarttype = COM_UART_16550; 96 sc->sc.sc_frequency = freq ? freq : COM_FREQ; 97 98 sc->sc.sc_reg_width = acpi_getpropint(sc->sc_node, "reg-io-width", 4); 99 sc->sc.sc_reg_shift = acpi_getpropint(sc->sc_node, "reg-shift", 2); 100 101 if (com_acpi_is_console(sc)) { 102 SET(sc->sc.sc_hwflags, COM_HW_CONSOLE); 103 SET(sc->sc.sc_swflags, COM_SW_SOFTCAR); 104 comconsfreq = sc->sc.sc_frequency; 105 comconsrate = B115200; 106 } 107 108 if (bus_space_map(sc->sc.sc_iot, aaa->aaa_addr[0], aaa->aaa_size[0], 109 0, &sc->sc.sc_ioh)) { 110 printf(": can't map registers\n"); 111 return; 112 } 113 114 sc->sc_ih = acpi_intr_establish(aaa->aaa_irq[0], aaa->aaa_irq_flags[0], 115 IPL_TTY, com_acpi_intr_designware, sc, sc->sc.sc_dev.dv_xname); 116 if (sc->sc_ih == NULL) { 117 printf(": can't establish interrupt\n"); 118 return; 119 } 120 121 com_attach_subr(&sc->sc); 122 } 123 124 int 125 com_acpi_is_console(struct com_acpi_softc *sc) 126 { 127 struct acpi_table_header *hdr; 128 struct acpi_spcr *spcr; 129 struct acpi_gas *base; 130 struct acpi_q *entry; 131 132 SIMPLEQ_FOREACH(entry, &sc->sc_acpi->sc_tables, q_next) { 133 hdr = entry->q_table; 134 if (strncmp(hdr->signature, SPCR_SIG, 135 sizeof(hdr->signature)) == 0) { 136 spcr = entry->q_table; 137 base = &spcr->base_address; 138 if (base->address_space_id == GAS_SYSTEM_MEMORY && 139 base->address == sc->sc.sc_iobase) 140 return 1; 141 } 142 } 143 144 return 0; 145 } 146 147 int 148 com_acpi_intr_designware(void *cookie) 149 { 150 struct com_softc *sc = cookie; 151 152 com_read_reg(sc, com_usr); 153 154 return comintr(sc); 155 } 156