1 /* $OpenBSD: com_acpi.c,v 1.3 2021/12/16 08:03:17 anton 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 "PNP0501", 53 NULL 54 }; 55 56 int com_acpi_is_console(struct com_acpi_softc *); 57 int com_acpi_is_designware(const char *); 58 int com_acpi_intr_designware(void *); 59 60 int 61 com_acpi_match(struct device *parent, void *match, void *aux) 62 { 63 struct acpi_attach_args *aaa = aux; 64 struct cfdata *cf = match; 65 66 return acpi_matchhids(aaa, com_hids, cf->cf_driver->cd_name); 67 } 68 69 void 70 com_acpi_attach(struct device *parent, struct device *self, void *aux) 71 { 72 struct com_acpi_softc *sc = (struct com_acpi_softc *)self; 73 struct acpi_attach_args *aaa = aux; 74 int (*intrfn)(void *) = comintr; 75 76 sc->sc_acpi = (struct acpi_softc *)parent; 77 sc->sc_node = aaa->aaa_node; 78 printf(" %s", sc->sc_node->name); 79 80 if (aaa->aaa_naddr < 1) { 81 printf(": no registers\n"); 82 return; 83 } 84 85 if (aaa->aaa_nirq < 1) { 86 printf(": no interrupt\n"); 87 return; 88 } 89 90 printf(" addr 0x%llx/0x%llx", aaa->aaa_addr[0], aaa->aaa_size[0]); 91 printf(" irq %d", aaa->aaa_irq[0]); 92 93 sc->sc.sc_iot = aaa->aaa_bst[0]; 94 sc->sc.sc_iobase = aaa->aaa_addr[0]; 95 sc->sc.sc_frequency = acpi_getpropint(sc->sc_node, "clock-frequency", 96 COM_FREQ); 97 98 if (com_acpi_is_designware(aaa->aaa_dev)) { 99 intrfn = com_acpi_intr_designware; 100 sc->sc.sc_uarttype = COM_UART_16550; 101 sc->sc.sc_reg_width = acpi_getpropint(sc->sc_node, 102 "reg-io-width", 4); 103 sc->sc.sc_reg_shift = acpi_getpropint(sc->sc_node, 104 "reg-shift", 2); 105 106 if (com_acpi_is_console(sc)) { 107 SET(sc->sc.sc_hwflags, COM_HW_CONSOLE); 108 SET(sc->sc.sc_swflags, COM_SW_SOFTCAR); 109 comconsfreq = sc->sc.sc_frequency; 110 comconsrate = B115200; 111 } 112 } 113 114 if (sc->sc.sc_iobase == comconsaddr) { 115 sc->sc.sc_ioh = comconsioh; 116 } else { 117 if (bus_space_map(sc->sc.sc_iot, 118 aaa->aaa_addr[0], aaa->aaa_size[0], 0, &sc->sc.sc_ioh)) { 119 printf(": can't map registers\n"); 120 return; 121 } 122 } 123 124 sc->sc_ih = acpi_intr_establish(aaa->aaa_irq[0], aaa->aaa_irq_flags[0], 125 IPL_TTY, intrfn, sc, sc->sc.sc_dev.dv_xname); 126 if (sc->sc_ih == NULL) { 127 printf(": can't establish interrupt\n"); 128 return; 129 } 130 131 com_attach_subr(&sc->sc); 132 } 133 134 int 135 com_acpi_is_console(struct com_acpi_softc *sc) 136 { 137 struct acpi_table_header *hdr; 138 struct acpi_spcr *spcr; 139 struct acpi_gas *base; 140 struct acpi_q *entry; 141 142 SIMPLEQ_FOREACH(entry, &sc->sc_acpi->sc_tables, q_next) { 143 hdr = entry->q_table; 144 if (strncmp(hdr->signature, SPCR_SIG, 145 sizeof(hdr->signature)) == 0) { 146 spcr = entry->q_table; 147 base = &spcr->base_address; 148 if (base->address_space_id == GAS_SYSTEM_MEMORY && 149 base->address == sc->sc.sc_iobase) 150 return 1; 151 } 152 } 153 154 return 0; 155 } 156 157 int 158 com_acpi_is_designware(const char *hid) 159 { 160 return strcmp("HISI0031", hid) == 0; 161 } 162 163 int 164 com_acpi_intr_designware(void *cookie) 165 { 166 struct com_softc *sc = cookie; 167 168 com_read_reg(sc, com_usr); 169 170 return comintr(sc); 171 } 172