1 1.44 jmcneill /* $NetBSD: com_acpi.c,v 1.44 2021/10/23 17:46:26 jmcneill Exp $ */ 2 1.1 jmcneill 3 1.1 jmcneill /* 4 1.1 jmcneill * Copyright (c) 2002 Jared D. McNeill <jmcneill (at) invisible.ca> 5 1.1 jmcneill * All rights reserved. 6 1.1 jmcneill * 7 1.1 jmcneill * Redistribution and use in source and binary forms, with or without 8 1.1 jmcneill * modification, are permitted provided that the following conditions 9 1.1 jmcneill * are met: 10 1.1 jmcneill * 1. Redistributions of source code must retain the above copyright 11 1.1 jmcneill * notice, this list of conditions and the following disclaimer. 12 1.1 jmcneill * 2. The name of the author may not be used to endorse or promote products 13 1.1 jmcneill * derived from this software without specific prior written permission. 14 1.1 jmcneill * 15 1.1 jmcneill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 1.1 jmcneill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 1.1 jmcneill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 1.1 jmcneill * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 1.1 jmcneill * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20 1.1 jmcneill * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 1.1 jmcneill * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 22 1.1 jmcneill * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 1.1 jmcneill * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 1.1 jmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 1.1 jmcneill * SUCH DAMAGE. 26 1.1 jmcneill */ 27 1.1 jmcneill 28 1.1 jmcneill #include <sys/cdefs.h> 29 1.44 jmcneill __KERNEL_RCSID(0, "$NetBSD: com_acpi.c,v 1.44 2021/10/23 17:46:26 jmcneill Exp $"); 30 1.1 jmcneill 31 1.1 jmcneill #include <sys/param.h> 32 1.31 jruoho #include <sys/device.h> 33 1.1 jmcneill #include <sys/systm.h> 34 1.1 jmcneill #include <sys/termios.h> 35 1.1 jmcneill 36 1.1 jmcneill #include <dev/acpi/acpivar.h> 37 1.37 jmcneill #include <dev/acpi/acpi_intr.h> 38 1.1 jmcneill 39 1.1 jmcneill #include <dev/ic/comvar.h> 40 1.1 jmcneill 41 1.27 cube static int com_acpi_match(device_t, cfdata_t , void *); 42 1.27 cube static void com_acpi_attach(device_t, device_t, void *); 43 1.1 jmcneill 44 1.1 jmcneill struct com_acpi_softc { 45 1.1 jmcneill struct com_softc sc_com; 46 1.1 jmcneill void *sc_ih; 47 1.1 jmcneill }; 48 1.1 jmcneill 49 1.27 cube CFATTACH_DECL_NEW(com_acpi, sizeof(struct com_acpi_softc), com_acpi_match, 50 1.30 dyoung com_acpi_attach, NULL, NULL); 51 1.1 jmcneill 52 1.1 jmcneill /* 53 1.1 jmcneill * Supported device IDs 54 1.1 jmcneill */ 55 1.1 jmcneill 56 1.41 thorpej static const struct device_compatible_entry compat_data[] = { 57 1.41 thorpej /* Standard PC COM port */ 58 1.41 thorpej { .compat = "PNP0500", .value = COM_TYPE_NORMAL }, 59 1.41 thorpej 60 1.41 thorpej /* 16550A-compatible COM port */ 61 1.41 thorpej { .compat = "PNP0501", .value = COM_TYPE_NORMAL }, 62 1.41 thorpej 63 1.41 thorpej /* Generic IRDA-compatible device */ 64 1.41 thorpej { .compat = "PNP0510", .value = COM_TYPE_NORMAL }, 65 1.41 thorpej 66 1.41 thorpej /* Generic IRDA-compatible device */ 67 1.41 thorpej { .compat = "PNP0511", .value = COM_TYPE_NORMAL }, 68 1.41 thorpej 69 1.41 thorpej /* IBM ThinkPad IRDA device */ 70 1.41 thorpej { .compat = "IBM0071", .value = COM_TYPE_NORMAL }, 71 1.41 thorpej 72 1.41 thorpej /* SMC SuperIO IRDA device */ 73 1.41 thorpej { .compat = "SMCF010", .value = COM_TYPE_NORMAL }, 74 1.41 thorpej 75 1.41 thorpej /* NSC IRDA device */ 76 1.41 thorpej { .compat = "NSC6001", .value = COM_TYPE_NORMAL }, 77 1.41 thorpej 78 1.41 thorpej /* Fujitsu Serial Pen Tablet */ 79 1.41 thorpej { .compat = "FUJ02E6", .value = COM_TYPE_NORMAL }, 80 1.41 thorpej 81 1.41 thorpej /* Hisilicon UART */ 82 1.41 thorpej { .compat = "HISI0031", .value = COM_TYPE_DW_APB }, 83 1.41 thorpej 84 1.41 thorpej /* Designware APB UART */ 85 1.41 thorpej { .compat = "8250dw", .value = COM_TYPE_DW_APB }, 86 1.37 jmcneill 87 1.41 thorpej DEVICE_COMPAT_EOL 88 1.1 jmcneill }; 89 1.1 jmcneill 90 1.1 jmcneill /* 91 1.1 jmcneill * com_acpi_match: autoconf(9) match routine 92 1.1 jmcneill */ 93 1.15 kochi static int 94 1.27 cube com_acpi_match(device_t parent, cfdata_t match, void *aux) 95 1.1 jmcneill { 96 1.1 jmcneill struct acpi_attach_args *aa = aux; 97 1.1 jmcneill 98 1.41 thorpej return acpi_compatible_match(aa, compat_data); 99 1.1 jmcneill } 100 1.1 jmcneill 101 1.1 jmcneill /* 102 1.1 jmcneill * com_acpi_attach: autoconf(9) attach routine 103 1.1 jmcneill */ 104 1.15 kochi static void 105 1.27 cube com_acpi_attach(device_t parent, device_t self, void *aux) 106 1.1 jmcneill { 107 1.27 cube struct com_acpi_softc *asc = device_private(self); 108 1.1 jmcneill struct com_softc *sc = &asc->sc_com; 109 1.1 jmcneill struct acpi_attach_args *aa = aux; 110 1.41 thorpej const struct device_compatible_entry *dce; 111 1.1 jmcneill struct acpi_resources res; 112 1.1 jmcneill struct acpi_io *io; 113 1.29 kiyohara struct acpi_mem *mem; 114 1.1 jmcneill struct acpi_irq *irq; 115 1.29 kiyohara bus_space_tag_t iot; 116 1.19 gdamore bus_space_handle_t ioh; 117 1.29 kiyohara bus_addr_t base; 118 1.29 kiyohara bus_size_t size; 119 1.1 jmcneill ACPI_STATUS rv; 120 1.37 jmcneill ACPI_INTEGER clock_freq; 121 1.43 jmcneill ACPI_INTEGER reg_shift; 122 1.1 jmcneill 123 1.27 cube sc->sc_dev = self; 124 1.27 cube 125 1.1 jmcneill /* parse resources */ 126 1.27 cube rv = acpi_resource_parse(sc->sc_dev, aa->aa_node->ad_handle, "_CRS", 127 1.13 kochi &res, &acpi_resource_parse_ops_default); 128 1.11 mycroft if (ACPI_FAILURE(rv)) 129 1.1 jmcneill return; 130 1.1 jmcneill 131 1.1 jmcneill /* find our i/o registers */ 132 1.1 jmcneill io = acpi_res_io(&res, 0); 133 1.29 kiyohara if (io != NULL) { 134 1.29 kiyohara iot = aa->aa_iot; 135 1.29 kiyohara base = io->ar_base; 136 1.29 kiyohara size = io->ar_length; 137 1.29 kiyohara } else { 138 1.29 kiyohara mem = acpi_res_mem(&res, 0); 139 1.29 kiyohara if (mem != NULL) { 140 1.29 kiyohara iot = aa->aa_memt; 141 1.29 kiyohara base = mem->ar_base; 142 1.29 kiyohara size = mem->ar_length; 143 1.29 kiyohara } else { 144 1.33 msaitoh aprint_error_dev(self, "unable to find i/o register " 145 1.33 msaitoh "and memory resource\n"); 146 1.29 kiyohara goto out; 147 1.29 kiyohara } 148 1.1 jmcneill } 149 1.1 jmcneill 150 1.1 jmcneill /* find our IRQ */ 151 1.1 jmcneill irq = acpi_res_irq(&res, 0); 152 1.1 jmcneill if (irq == NULL) { 153 1.44 jmcneill sc->sc_poll_ticks = 1; 154 1.1 jmcneill } 155 1.1 jmcneill 156 1.29 kiyohara if (!com_is_console(iot, base, &ioh)) 157 1.29 kiyohara if (bus_space_map(iot, base, size, 0, &ioh)) { 158 1.27 cube aprint_error_dev(self, "can't map i/o space\n"); 159 1.14 kochi goto out; 160 1.5 jmcneill } 161 1.43 jmcneill 162 1.43 jmcneill rv = acpi_dsd_integer(aa->aa_node->ad_handle, "reg-shift", 163 1.43 jmcneill ®_shift); 164 1.43 jmcneill if (ACPI_FAILURE(rv)) { 165 1.43 jmcneill reg_shift = 0; 166 1.43 jmcneill } 167 1.43 jmcneill 168 1.43 jmcneill com_init_regs_stride(&sc->sc_regs, iot, ioh, base, reg_shift); 169 1.1 jmcneill 170 1.27 cube aprint_normal("%s", device_xname(self)); 171 1.1 jmcneill 172 1.41 thorpej dce = acpi_compatible_lookup(aa, compat_data); 173 1.41 thorpej KASSERT(dce != NULL); 174 1.41 thorpej 175 1.41 thorpej sc->sc_type = dce->value; 176 1.41 thorpej 177 1.44 jmcneill if (com_probe_subr(&sc->sc_regs) == 0) { 178 1.44 jmcneill aprint_error(": com probe failed\n"); 179 1.44 jmcneill goto out; 180 1.1 jmcneill } 181 1.1 jmcneill 182 1.38 christos rv = acpi_dsd_integer(aa->aa_node->ad_handle, "clock-frequency", 183 1.38 christos &clock_freq); 184 1.37 jmcneill if (ACPI_SUCCESS(rv)) 185 1.37 jmcneill sc->sc_frequency = clock_freq; 186 1.37 jmcneill else 187 1.37 jmcneill sc->sc_frequency = 115200 * 16; 188 1.1 jmcneill 189 1.1 jmcneill com_attach_subr(sc); 190 1.1 jmcneill 191 1.44 jmcneill if (sc->sc_poll_ticks == 0) { 192 1.38 christos asc->sc_ih = acpi_intr_establish(self, 193 1.40 mlelstv (uint64_t)(uintptr_t)aa->aa_node->ad_handle, 194 1.37 jmcneill IPL_SERIAL, true, comintr, sc, device_xname(self)); 195 1.44 jmcneill } 196 1.25 xtraeme 197 1.25 xtraeme if (!pmf_device_register(self, NULL, com_resume)) 198 1.25 xtraeme aprint_error_dev(self, "couldn't establish a power handler\n"); 199 1.32 pgoyette goto cleanup; 200 1.25 xtraeme 201 1.32 pgoyette /* 202 1.32 pgoyette * In case of irq resource or i/o space mapping error, just set 203 1.32 pgoyette * a NULL power handler. This may allow us to sleep later on. 204 1.32 pgoyette */ 205 1.14 kochi out: 206 1.32 pgoyette if (!pmf_device_register(self, NULL, NULL)) 207 1.32 pgoyette aprint_error_dev(self, "couldn't establish a power handler\n"); 208 1.32 pgoyette 209 1.32 pgoyette cleanup: 210 1.14 kochi acpi_resource_cleanup(&res); 211 1.1 jmcneill } 212