18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2012, Intel Corporation 48c2ecf20Sopenharmony_ci * Copyright (c) 2015, Red Hat, Inc. 58c2ecf20Sopenharmony_ci * Copyright (c) 2015, 2016 Linaro Ltd. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "ACPI: SPCR: " fmt 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/acpi.h> 118c2ecf20Sopenharmony_ci#include <linux/console.h> 128c2ecf20Sopenharmony_ci#include <linux/kernel.h> 138c2ecf20Sopenharmony_ci#include <linux/serial_core.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci/* 168c2ecf20Sopenharmony_ci * Erratum 44 for QDF2432v1 and QDF2400v1 SoCs describes the BUSY bit as 178c2ecf20Sopenharmony_ci * occasionally getting stuck as 1. To avoid the potential for a hang, check 188c2ecf20Sopenharmony_ci * TXFE == 0 instead of BUSY == 1. This may not be suitable for all UART 198c2ecf20Sopenharmony_ci * implementations, so only do so if an affected platform is detected in 208c2ecf20Sopenharmony_ci * acpi_parse_spcr(). 218c2ecf20Sopenharmony_ci */ 228c2ecf20Sopenharmony_cibool qdf2400_e44_present; 238c2ecf20Sopenharmony_ciEXPORT_SYMBOL(qdf2400_e44_present); 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* 268c2ecf20Sopenharmony_ci * Some Qualcomm Datacenter Technologies SoCs have a defective UART BUSY bit. 278c2ecf20Sopenharmony_ci * Detect them by examining the OEM fields in the SPCR header, similar to PCI 288c2ecf20Sopenharmony_ci * quirk detection in pci_mcfg.c. 298c2ecf20Sopenharmony_ci */ 308c2ecf20Sopenharmony_cistatic bool qdf2400_erratum_44_present(struct acpi_table_header *h) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci if (memcmp(h->oem_id, "QCOM ", ACPI_OEM_ID_SIZE)) 338c2ecf20Sopenharmony_ci return false; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci if (!memcmp(h->oem_table_id, "QDF2432 ", ACPI_OEM_TABLE_ID_SIZE)) 368c2ecf20Sopenharmony_ci return true; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci if (!memcmp(h->oem_table_id, "QDF2400 ", ACPI_OEM_TABLE_ID_SIZE) && 398c2ecf20Sopenharmony_ci h->oem_revision == 1) 408c2ecf20Sopenharmony_ci return true; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci return false; 438c2ecf20Sopenharmony_ci} 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/* 468c2ecf20Sopenharmony_ci * APM X-Gene v1 and v2 UART hardware is an 16550 like device but has its 478c2ecf20Sopenharmony_ci * register aligned to 32-bit. In addition, the BIOS also encoded the 488c2ecf20Sopenharmony_ci * access width to be 8 bits. This function detects this errata condition. 498c2ecf20Sopenharmony_ci */ 508c2ecf20Sopenharmony_cistatic bool xgene_8250_erratum_present(struct acpi_table_spcr *tb) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci bool xgene_8250 = false; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci if (tb->interface_type != ACPI_DBG2_16550_COMPATIBLE) 558c2ecf20Sopenharmony_ci return false; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci if (memcmp(tb->header.oem_id, "APMC0D", ACPI_OEM_ID_SIZE) && 588c2ecf20Sopenharmony_ci memcmp(tb->header.oem_id, "HPE ", ACPI_OEM_ID_SIZE)) 598c2ecf20Sopenharmony_ci return false; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci if (!memcmp(tb->header.oem_table_id, "XGENESPC", 628c2ecf20Sopenharmony_ci ACPI_OEM_TABLE_ID_SIZE) && tb->header.oem_revision == 0) 638c2ecf20Sopenharmony_ci xgene_8250 = true; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci if (!memcmp(tb->header.oem_table_id, "ProLiant", 668c2ecf20Sopenharmony_ci ACPI_OEM_TABLE_ID_SIZE) && tb->header.oem_revision == 1) 678c2ecf20Sopenharmony_ci xgene_8250 = true; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci return xgene_8250; 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/** 738c2ecf20Sopenharmony_ci * acpi_parse_spcr() - parse ACPI SPCR table and add preferred console 748c2ecf20Sopenharmony_ci * 758c2ecf20Sopenharmony_ci * @enable_earlycon: set up earlycon for the console specified by the table 768c2ecf20Sopenharmony_ci * @enable_console: setup the console specified by the table. 778c2ecf20Sopenharmony_ci * 788c2ecf20Sopenharmony_ci * For the architectures with support for ACPI, CONFIG_ACPI_SPCR_TABLE may be 798c2ecf20Sopenharmony_ci * defined to parse ACPI SPCR table. As a result of the parsing preferred 808c2ecf20Sopenharmony_ci * console is registered and if @enable_earlycon is true, earlycon is set up. 818c2ecf20Sopenharmony_ci * If @enable_console is true the system console is also configured. 828c2ecf20Sopenharmony_ci * 838c2ecf20Sopenharmony_ci * When CONFIG_ACPI_SPCR_TABLE is defined, this function should be called 848c2ecf20Sopenharmony_ci * from arch initialization code as soon as the DT/ACPI decision is made. 858c2ecf20Sopenharmony_ci * 868c2ecf20Sopenharmony_ci */ 878c2ecf20Sopenharmony_ciint __init acpi_parse_spcr(bool enable_earlycon, bool enable_console) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci static char opts[64]; 908c2ecf20Sopenharmony_ci struct acpi_table_spcr *table; 918c2ecf20Sopenharmony_ci acpi_status status; 928c2ecf20Sopenharmony_ci char *uart; 938c2ecf20Sopenharmony_ci char *iotype; 948c2ecf20Sopenharmony_ci int baud_rate; 958c2ecf20Sopenharmony_ci int err; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci if (acpi_disabled) 988c2ecf20Sopenharmony_ci return -ENODEV; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci status = acpi_get_table(ACPI_SIG_SPCR, 0, 1018c2ecf20Sopenharmony_ci (struct acpi_table_header **)&table); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) 1048c2ecf20Sopenharmony_ci return -ENOENT; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci if (table->header.revision < 2) 1078c2ecf20Sopenharmony_ci pr_info("SPCR table version %d\n", table->header.revision); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci if (table->serial_port.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { 1108c2ecf20Sopenharmony_ci switch (ACPI_ACCESS_BIT_WIDTH(( 1118c2ecf20Sopenharmony_ci table->serial_port.access_width))) { 1128c2ecf20Sopenharmony_ci default: 1138c2ecf20Sopenharmony_ci pr_err("Unexpected SPCR Access Width. Defaulting to byte size\n"); 1148c2ecf20Sopenharmony_ci fallthrough; 1158c2ecf20Sopenharmony_ci case 8: 1168c2ecf20Sopenharmony_ci iotype = "mmio"; 1178c2ecf20Sopenharmony_ci break; 1188c2ecf20Sopenharmony_ci case 16: 1198c2ecf20Sopenharmony_ci iotype = "mmio16"; 1208c2ecf20Sopenharmony_ci break; 1218c2ecf20Sopenharmony_ci case 32: 1228c2ecf20Sopenharmony_ci iotype = "mmio32"; 1238c2ecf20Sopenharmony_ci break; 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci } else 1268c2ecf20Sopenharmony_ci iotype = "io"; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci switch (table->interface_type) { 1298c2ecf20Sopenharmony_ci case ACPI_DBG2_ARM_SBSA_32BIT: 1308c2ecf20Sopenharmony_ci iotype = "mmio32"; 1318c2ecf20Sopenharmony_ci fallthrough; 1328c2ecf20Sopenharmony_ci case ACPI_DBG2_ARM_PL011: 1338c2ecf20Sopenharmony_ci case ACPI_DBG2_ARM_SBSA_GENERIC: 1348c2ecf20Sopenharmony_ci case ACPI_DBG2_BCM2835: 1358c2ecf20Sopenharmony_ci uart = "pl011"; 1368c2ecf20Sopenharmony_ci break; 1378c2ecf20Sopenharmony_ci case ACPI_DBG2_16550_COMPATIBLE: 1388c2ecf20Sopenharmony_ci case ACPI_DBG2_16550_SUBSET: 1398c2ecf20Sopenharmony_ci uart = "uart"; 1408c2ecf20Sopenharmony_ci break; 1418c2ecf20Sopenharmony_ci default: 1428c2ecf20Sopenharmony_ci err = -ENOENT; 1438c2ecf20Sopenharmony_ci goto done; 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci switch (table->baud_rate) { 1478c2ecf20Sopenharmony_ci case 0: 1488c2ecf20Sopenharmony_ci /* 1498c2ecf20Sopenharmony_ci * SPCR 1.04 defines 0 as a preconfigured state of UART. 1508c2ecf20Sopenharmony_ci * Assume firmware or bootloader configures console correctly. 1518c2ecf20Sopenharmony_ci */ 1528c2ecf20Sopenharmony_ci baud_rate = 0; 1538c2ecf20Sopenharmony_ci break; 1548c2ecf20Sopenharmony_ci case 3: 1558c2ecf20Sopenharmony_ci baud_rate = 9600; 1568c2ecf20Sopenharmony_ci break; 1578c2ecf20Sopenharmony_ci case 4: 1588c2ecf20Sopenharmony_ci baud_rate = 19200; 1598c2ecf20Sopenharmony_ci break; 1608c2ecf20Sopenharmony_ci case 6: 1618c2ecf20Sopenharmony_ci baud_rate = 57600; 1628c2ecf20Sopenharmony_ci break; 1638c2ecf20Sopenharmony_ci case 7: 1648c2ecf20Sopenharmony_ci baud_rate = 115200; 1658c2ecf20Sopenharmony_ci break; 1668c2ecf20Sopenharmony_ci default: 1678c2ecf20Sopenharmony_ci err = -ENOENT; 1688c2ecf20Sopenharmony_ci goto done; 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci /* 1728c2ecf20Sopenharmony_ci * If the E44 erratum is required, then we need to tell the pl011 1738c2ecf20Sopenharmony_ci * driver to implement the work-around. 1748c2ecf20Sopenharmony_ci * 1758c2ecf20Sopenharmony_ci * The global variable is used by the probe function when it 1768c2ecf20Sopenharmony_ci * creates the UARTs, whether or not they're used as a console. 1778c2ecf20Sopenharmony_ci * 1788c2ecf20Sopenharmony_ci * If the user specifies "traditional" earlycon, the qdf2400_e44 1798c2ecf20Sopenharmony_ci * console name matches the EARLYCON_DECLARE() statement, and 1808c2ecf20Sopenharmony_ci * SPCR is not used. Parameter "earlycon" is false. 1818c2ecf20Sopenharmony_ci * 1828c2ecf20Sopenharmony_ci * If the user specifies "SPCR" earlycon, then we need to update 1838c2ecf20Sopenharmony_ci * the console name so that it also says "qdf2400_e44". Parameter 1848c2ecf20Sopenharmony_ci * "earlycon" is true. 1858c2ecf20Sopenharmony_ci * 1868c2ecf20Sopenharmony_ci * For consistency, if we change the console name, then we do it 1878c2ecf20Sopenharmony_ci * for everyone, not just earlycon. 1888c2ecf20Sopenharmony_ci */ 1898c2ecf20Sopenharmony_ci if (qdf2400_erratum_44_present(&table->header)) { 1908c2ecf20Sopenharmony_ci qdf2400_e44_present = true; 1918c2ecf20Sopenharmony_ci if (enable_earlycon) 1928c2ecf20Sopenharmony_ci uart = "qdf2400_e44"; 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci if (xgene_8250_erratum_present(table)) { 1968c2ecf20Sopenharmony_ci iotype = "mmio32"; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci /* for xgene v1 and v2 we don't know the clock rate of the 1998c2ecf20Sopenharmony_ci * UART so don't attempt to change to the baud rate state 2008c2ecf20Sopenharmony_ci * in the table because driver cannot calculate the dividers 2018c2ecf20Sopenharmony_ci */ 2028c2ecf20Sopenharmony_ci baud_rate = 0; 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci if (!baud_rate) { 2068c2ecf20Sopenharmony_ci snprintf(opts, sizeof(opts), "%s,%s,0x%llx", uart, iotype, 2078c2ecf20Sopenharmony_ci table->serial_port.address); 2088c2ecf20Sopenharmony_ci } else { 2098c2ecf20Sopenharmony_ci snprintf(opts, sizeof(opts), "%s,%s,0x%llx,%d", uart, iotype, 2108c2ecf20Sopenharmony_ci table->serial_port.address, baud_rate); 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci pr_info("console: %s\n", opts); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci if (enable_earlycon) 2168c2ecf20Sopenharmony_ci setup_earlycon(opts); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci if (enable_console) 2198c2ecf20Sopenharmony_ci err = add_preferred_console(uart, 0, opts + strlen(uart) + 1); 2208c2ecf20Sopenharmony_ci else 2218c2ecf20Sopenharmony_ci err = 0; 2228c2ecf20Sopenharmony_cidone: 2238c2ecf20Sopenharmony_ci acpi_put_table((struct acpi_table_header *)table); 2248c2ecf20Sopenharmony_ci return err; 2258c2ecf20Sopenharmony_ci} 226