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