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