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