1 /* $OpenBSD: com_acpi.c,v 1.1 2018/07/01 10:29:30 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 41 bus_addr_t sc_addr; 42 bus_size_t sc_size; 43 44 int sc_irq; 45 int sc_irq_flags; 46 void *sc_ih; 47 }; 48 49 int com_acpi_match(struct device *, void *, void *); 50 void com_acpi_attach(struct device *, struct device *, void *); 51 52 struct cfattach com_acpi_ca = { 53 sizeof(struct com_acpi_softc), com_acpi_match, com_acpi_attach 54 }; 55 56 const char *com_hids[] = { 57 "HISI0031", 58 NULL 59 }; 60 61 int com_acpi_parse_resources(int, union acpi_resource *, void *); 62 int com_acpi_is_console(struct com_acpi_softc *); 63 int com_acpi_intr_designware(void *); 64 65 int 66 com_acpi_match(struct device *parent, void *match, void *aux) 67 { 68 struct acpi_attach_args *aaa = aux; 69 struct cfdata *cf = match; 70 71 return acpi_matchhids(aaa, com_hids, cf->cf_driver->cd_name); 72 } 73 74 void 75 com_acpi_attach(struct device *parent, struct device *self, void *aux) 76 { 77 struct acpi_attach_args *aaa = aux; 78 struct com_acpi_softc *sc = (struct com_acpi_softc *)self; 79 struct aml_value res; 80 uint32_t freq; 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 if (aml_evalname(sc->sc_acpi, sc->sc_node, "_CRS", 0, NULL, &res)) { 87 printf(": can't find registers\n"); 88 return; 89 } 90 91 aml_parse_resource(&res, com_acpi_parse_resources, sc); 92 printf(" addr 0x%lx/0x%lx", sc->sc_addr, sc->sc_size); 93 if (sc->sc_addr == 0 || sc->sc_size == 0) { 94 printf("\n"); 95 return; 96 } 97 98 printf(" irq %d", sc->sc_irq); 99 100 freq = acpi_getpropint(sc->sc_node, "clock-frequency", 0); 101 102 sc->sc.sc_iot = aaa->aaa_memt; 103 sc->sc.sc_iobase = sc->sc_addr; 104 sc->sc.sc_uarttype = COM_UART_16550; 105 sc->sc.sc_frequency = freq ? freq : COM_FREQ; 106 107 sc->sc.sc_reg_width = acpi_getpropint(sc->sc_node, "reg-io-width", 4); 108 sc->sc.sc_reg_shift = acpi_getpropint(sc->sc_node, "reg-shift", 2); 109 110 if (com_acpi_is_console(sc)) { 111 SET(sc->sc.sc_hwflags, COM_HW_CONSOLE); 112 SET(sc->sc.sc_swflags, COM_SW_SOFTCAR); 113 comconsfreq = sc->sc.sc_frequency; 114 comconsrate = B115200; 115 } 116 117 if (bus_space_map(sc->sc.sc_iot, sc->sc_addr, sc->sc_size, 0, 118 &sc->sc.sc_ioh)) { 119 printf(": can't map registers\n"); 120 return; 121 } 122 123 sc->sc_ih = acpi_intr_establish(sc->sc_irq, sc->sc_irq_flags, IPL_TTY, 124 com_acpi_intr_designware, sc, sc->sc.sc_dev.dv_xname); 125 if (sc->sc_ih == NULL) { 126 printf(": can't establish interrupt\n"); 127 return; 128 } 129 130 com_attach_subr(&sc->sc); 131 } 132 133 int 134 com_acpi_parse_resources(int crsidx, union acpi_resource *crs, void *arg) 135 { 136 struct com_acpi_softc *sc = arg; 137 int type = AML_CRSTYPE(crs); 138 139 switch (type) { 140 case LR_MEM32FIXED: 141 sc->sc_addr = crs->lr_m32fixed._bas; 142 sc->sc_size = crs->lr_m32fixed._len; 143 break; 144 case LR_EXTIRQ: 145 sc->sc_irq = crs->lr_extirq.irq[0]; 146 sc->sc_irq_flags = crs->lr_extirq.flags; 147 break; 148 } 149 150 return 0; 151 } 152 153 int 154 com_acpi_is_console(struct com_acpi_softc *sc) 155 { 156 struct acpi_table_header *hdr; 157 struct acpi_spcr *spcr; 158 struct acpi_gas *base; 159 struct acpi_q *entry; 160 161 SIMPLEQ_FOREACH(entry, &sc->sc_acpi->sc_tables, q_next) { 162 hdr = entry->q_table; 163 if (strncmp(hdr->signature, SPCR_SIG, 164 sizeof(hdr->signature)) == 0) { 165 spcr = entry->q_table; 166 base = &spcr->base_address; 167 if (base->address_space_id == GAS_SYSTEM_MEMORY && 168 base->address == sc->sc_addr) 169 return 1; 170 } 171 } 172 173 return 0; 174 } 175 176 int 177 com_acpi_intr_designware(void *cookie) 178 { 179 struct com_softc *sc = cookie; 180 181 com_read_reg(sc, com_usr); 182 183 return comintr(sc); 184 } 185