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