1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2016 The FreeBSD Foundation 5 * Copyright (c) 2019 Colin Percival 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/bus.h> 34 35 #include <machine/bus.h> 36 37 #include <dev/pci/pcireg.h> 38 39 #include <dev/uart/uart.h> 40 #include <dev/uart/uart_bus.h> 41 #include <dev/uart/uart_cpu.h> 42 #include <dev/uart/uart_cpu_acpi.h> 43 44 #include <contrib/dev/acpica/include/acpi.h> 45 #include <contrib/dev/acpica/include/accommon.h> 46 #include <contrib/dev/acpica/include/actables.h> 47 48 static struct acpi_uart_compat_data * 49 uart_cpu_acpi_scan(uint8_t interface_type) 50 { 51 struct acpi_uart_compat_data **cd, *curcd; 52 int i; 53 54 SET_FOREACH(cd, uart_acpi_class_and_device_set) { 55 curcd = *cd; 56 for (i = 0; curcd[i].cd_hid != NULL; i++) { 57 if (curcd[i].cd_port_subtype == interface_type) 58 return (&curcd[i]); 59 } 60 } 61 62 SET_FOREACH(cd, uart_acpi_class_set) { 63 curcd = *cd; 64 for (i = 0; curcd[i].cd_hid != NULL; i++) { 65 if (curcd[i].cd_port_subtype == interface_type) 66 return (&curcd[i]); 67 } 68 } 69 70 return (NULL); 71 } 72 73 static int 74 uart_cpu_acpi_init_devinfo(struct uart_devinfo *di, struct uart_class *class, 75 ACPI_GENERIC_ADDRESS *addr) 76 { 77 /* Fill in some fixed details. */ 78 di->bas.chan = 0; 79 di->bas.rclk = 0; 80 di->databits = 8; 81 di->stopbits = 1; 82 di->parity = UART_PARITY_NONE; 83 di->ops = uart_getops(class); 84 85 /* Fill in details from SPCR table. */ 86 switch (addr->SpaceId) { 87 case 0: 88 di->bas.bst = uart_bus_space_mem; 89 break; 90 case 1: 91 di->bas.bst = uart_bus_space_io; 92 break; 93 default: 94 printf("UART in unrecognized address space: %d!\n", 95 (int)addr->SpaceId); 96 return (ENXIO); 97 } 98 switch (addr->AccessWidth) { 99 case 0: /* EFI_ACPI_6_0_UNDEFINED */ 100 /* FALLTHROUGH */ 101 case 1: /* EFI_ACPI_6_0_BYTE */ 102 di->bas.regiowidth = 1; 103 break; 104 case 2: /* EFI_ACPI_6_0_WORD */ 105 di->bas.regiowidth = 2; 106 break; 107 case 3: /* EFI_ACPI_6_0_DWORD */ 108 di->bas.regiowidth = 4; 109 break; 110 case 4: /* EFI_ACPI_6_0_QWORD */ 111 di->bas.regiowidth = 8; 112 break; 113 default: 114 printf("UART unsupported access width: %d!\n", 115 (int)addr->AccessWidth); 116 return (ENXIO); 117 } 118 switch (addr->BitWidth) { 119 case 0: 120 /* FALLTHROUGH */ 121 case 8: 122 di->bas.regshft = 0; 123 break; 124 case 16: 125 di->bas.regshft = 1; 126 break; 127 case 32: 128 di->bas.regshft = 2; 129 break; 130 case 64: 131 di->bas.regshft = 3; 132 break; 133 default: 134 printf("UART unsupported bit width: %d!\n", 135 (int)addr->BitWidth); 136 return (ENXIO); 137 } 138 139 return (0); 140 } 141 142 int 143 uart_cpu_acpi_spcr(int devtype, struct uart_devinfo *di) 144 { 145 vm_paddr_t spcr_physaddr; 146 ACPI_TABLE_SPCR *spcr; 147 struct acpi_uart_compat_data *cd; 148 struct uart_class *class; 149 int error = ENXIO; 150 151 /* SPCR only tells us about consoles. */ 152 if (devtype != UART_DEV_CONSOLE) 153 return (error); 154 155 /* Look for the SPCR table. */ 156 spcr_physaddr = acpi_find_table(ACPI_SIG_SPCR); 157 if (spcr_physaddr == 0) 158 return (error); 159 spcr = acpi_map_table(spcr_physaddr, ACPI_SIG_SPCR); 160 if (spcr == NULL) { 161 printf("Unable to map the SPCR table!\n"); 162 return (error); 163 } 164 165 /* Search for information about this SPCR interface type. */ 166 cd = uart_cpu_acpi_scan(spcr->InterfaceType); 167 if (cd == NULL) 168 goto out; 169 class = cd->cd_class; 170 171 error = uart_cpu_acpi_init_devinfo(di, class, &spcr->SerialPort); 172 if (error != 0) 173 goto out; 174 175 switch (spcr->BaudRate) { 176 case 0: 177 /* Special value; means "keep current value unchanged". */ 178 di->baudrate = 0; 179 break; 180 case 3: 181 di->baudrate = 9600; 182 break; 183 case 4: 184 di->baudrate = 19200; 185 break; 186 case 6: 187 di->baudrate = 57600; 188 break; 189 case 7: 190 di->baudrate = 115200; 191 break; 192 default: 193 printf("SPCR has reserved BaudRate value: %d!\n", 194 (int)spcr->BaudRate); 195 goto out; 196 } 197 if (spcr->PciVendorId != PCIV_INVALID && 198 spcr->PciDeviceId != PCIV_INVALID) { 199 di->pci_info.vendor = spcr->PciVendorId; 200 di->pci_info.device = spcr->PciDeviceId; 201 } 202 203 /* Apply device tweaks. */ 204 if ((cd->cd_quirks & UART_F_IGNORE_SPCR_REGSHFT) == 205 UART_F_IGNORE_SPCR_REGSHFT) { 206 di->bas.regshft = cd->cd_regshft; 207 } 208 209 /* Create a bus space handle. */ 210 error = bus_space_map(di->bas.bst, spcr->SerialPort.Address, 211 uart_getrange(class), 0, &di->bas.bsh); 212 213 out: 214 acpi_unmap_table(spcr); 215 return (error); 216 } 217