1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (c) 2012, Intel Corporation
4*4882a593Smuzhiyun * Copyright (c) 2015, Red Hat, Inc.
5*4882a593Smuzhiyun * Copyright (c) 2015, 2016 Linaro Ltd.
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #define pr_fmt(fmt) "ACPI: SPCR: " fmt
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <linux/acpi.h>
11*4882a593Smuzhiyun #include <linux/console.h>
12*4882a593Smuzhiyun #include <linux/kernel.h>
13*4882a593Smuzhiyun #include <linux/serial_core.h>
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun /*
16*4882a593Smuzhiyun * Erratum 44 for QDF2432v1 and QDF2400v1 SoCs describes the BUSY bit as
17*4882a593Smuzhiyun * occasionally getting stuck as 1. To avoid the potential for a hang, check
18*4882a593Smuzhiyun * TXFE == 0 instead of BUSY == 1. This may not be suitable for all UART
19*4882a593Smuzhiyun * implementations, so only do so if an affected platform is detected in
20*4882a593Smuzhiyun * acpi_parse_spcr().
21*4882a593Smuzhiyun */
22*4882a593Smuzhiyun bool qdf2400_e44_present;
23*4882a593Smuzhiyun EXPORT_SYMBOL(qdf2400_e44_present);
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun /*
26*4882a593Smuzhiyun * Some Qualcomm Datacenter Technologies SoCs have a defective UART BUSY bit.
27*4882a593Smuzhiyun * Detect them by examining the OEM fields in the SPCR header, similar to PCI
28*4882a593Smuzhiyun * quirk detection in pci_mcfg.c.
29*4882a593Smuzhiyun */
qdf2400_erratum_44_present(struct acpi_table_header * h)30*4882a593Smuzhiyun static bool qdf2400_erratum_44_present(struct acpi_table_header *h)
31*4882a593Smuzhiyun {
32*4882a593Smuzhiyun if (memcmp(h->oem_id, "QCOM ", ACPI_OEM_ID_SIZE))
33*4882a593Smuzhiyun return false;
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun if (!memcmp(h->oem_table_id, "QDF2432 ", ACPI_OEM_TABLE_ID_SIZE))
36*4882a593Smuzhiyun return true;
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun if (!memcmp(h->oem_table_id, "QDF2400 ", ACPI_OEM_TABLE_ID_SIZE) &&
39*4882a593Smuzhiyun h->oem_revision == 1)
40*4882a593Smuzhiyun return true;
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun return false;
43*4882a593Smuzhiyun }
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun /*
46*4882a593Smuzhiyun * APM X-Gene v1 and v2 UART hardware is an 16550 like device but has its
47*4882a593Smuzhiyun * register aligned to 32-bit. In addition, the BIOS also encoded the
48*4882a593Smuzhiyun * access width to be 8 bits. This function detects this errata condition.
49*4882a593Smuzhiyun */
xgene_8250_erratum_present(struct acpi_table_spcr * tb)50*4882a593Smuzhiyun static bool xgene_8250_erratum_present(struct acpi_table_spcr *tb)
51*4882a593Smuzhiyun {
52*4882a593Smuzhiyun bool xgene_8250 = false;
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun if (tb->interface_type != ACPI_DBG2_16550_COMPATIBLE)
55*4882a593Smuzhiyun return false;
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun if (memcmp(tb->header.oem_id, "APMC0D", ACPI_OEM_ID_SIZE) &&
58*4882a593Smuzhiyun memcmp(tb->header.oem_id, "HPE ", ACPI_OEM_ID_SIZE))
59*4882a593Smuzhiyun return false;
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun if (!memcmp(tb->header.oem_table_id, "XGENESPC",
62*4882a593Smuzhiyun ACPI_OEM_TABLE_ID_SIZE) && tb->header.oem_revision == 0)
63*4882a593Smuzhiyun xgene_8250 = true;
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun if (!memcmp(tb->header.oem_table_id, "ProLiant",
66*4882a593Smuzhiyun ACPI_OEM_TABLE_ID_SIZE) && tb->header.oem_revision == 1)
67*4882a593Smuzhiyun xgene_8250 = true;
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun return xgene_8250;
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun /**
73*4882a593Smuzhiyun * acpi_parse_spcr() - parse ACPI SPCR table and add preferred console
74*4882a593Smuzhiyun *
75*4882a593Smuzhiyun * @enable_earlycon: set up earlycon for the console specified by the table
76*4882a593Smuzhiyun * @enable_console: setup the console specified by the table.
77*4882a593Smuzhiyun *
78*4882a593Smuzhiyun * For the architectures with support for ACPI, CONFIG_ACPI_SPCR_TABLE may be
79*4882a593Smuzhiyun * defined to parse ACPI SPCR table. As a result of the parsing preferred
80*4882a593Smuzhiyun * console is registered and if @enable_earlycon is true, earlycon is set up.
81*4882a593Smuzhiyun * If @enable_console is true the system console is also configured.
82*4882a593Smuzhiyun *
83*4882a593Smuzhiyun * When CONFIG_ACPI_SPCR_TABLE is defined, this function should be called
84*4882a593Smuzhiyun * from arch initialization code as soon as the DT/ACPI decision is made.
85*4882a593Smuzhiyun *
86*4882a593Smuzhiyun */
acpi_parse_spcr(bool enable_earlycon,bool enable_console)87*4882a593Smuzhiyun int __init acpi_parse_spcr(bool enable_earlycon, bool enable_console)
88*4882a593Smuzhiyun {
89*4882a593Smuzhiyun static char opts[64];
90*4882a593Smuzhiyun struct acpi_table_spcr *table;
91*4882a593Smuzhiyun acpi_status status;
92*4882a593Smuzhiyun char *uart;
93*4882a593Smuzhiyun char *iotype;
94*4882a593Smuzhiyun int baud_rate;
95*4882a593Smuzhiyun int err;
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun if (acpi_disabled)
98*4882a593Smuzhiyun return -ENODEV;
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun status = acpi_get_table(ACPI_SIG_SPCR, 0,
101*4882a593Smuzhiyun (struct acpi_table_header **)&table);
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun if (ACPI_FAILURE(status))
104*4882a593Smuzhiyun return -ENOENT;
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun if (table->header.revision < 2)
107*4882a593Smuzhiyun pr_info("SPCR table version %d\n", table->header.revision);
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun if (table->serial_port.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
110*4882a593Smuzhiyun switch (ACPI_ACCESS_BIT_WIDTH((
111*4882a593Smuzhiyun table->serial_port.access_width))) {
112*4882a593Smuzhiyun default:
113*4882a593Smuzhiyun pr_err("Unexpected SPCR Access Width. Defaulting to byte size\n");
114*4882a593Smuzhiyun fallthrough;
115*4882a593Smuzhiyun case 8:
116*4882a593Smuzhiyun iotype = "mmio";
117*4882a593Smuzhiyun break;
118*4882a593Smuzhiyun case 16:
119*4882a593Smuzhiyun iotype = "mmio16";
120*4882a593Smuzhiyun break;
121*4882a593Smuzhiyun case 32:
122*4882a593Smuzhiyun iotype = "mmio32";
123*4882a593Smuzhiyun break;
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun } else
126*4882a593Smuzhiyun iotype = "io";
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun switch (table->interface_type) {
129*4882a593Smuzhiyun case ACPI_DBG2_ARM_SBSA_32BIT:
130*4882a593Smuzhiyun iotype = "mmio32";
131*4882a593Smuzhiyun fallthrough;
132*4882a593Smuzhiyun case ACPI_DBG2_ARM_PL011:
133*4882a593Smuzhiyun case ACPI_DBG2_ARM_SBSA_GENERIC:
134*4882a593Smuzhiyun case ACPI_DBG2_BCM2835:
135*4882a593Smuzhiyun uart = "pl011";
136*4882a593Smuzhiyun break;
137*4882a593Smuzhiyun case ACPI_DBG2_16550_COMPATIBLE:
138*4882a593Smuzhiyun case ACPI_DBG2_16550_SUBSET:
139*4882a593Smuzhiyun uart = "uart";
140*4882a593Smuzhiyun break;
141*4882a593Smuzhiyun default:
142*4882a593Smuzhiyun err = -ENOENT;
143*4882a593Smuzhiyun goto done;
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun switch (table->baud_rate) {
147*4882a593Smuzhiyun case 0:
148*4882a593Smuzhiyun /*
149*4882a593Smuzhiyun * SPCR 1.04 defines 0 as a preconfigured state of UART.
150*4882a593Smuzhiyun * Assume firmware or bootloader configures console correctly.
151*4882a593Smuzhiyun */
152*4882a593Smuzhiyun baud_rate = 0;
153*4882a593Smuzhiyun break;
154*4882a593Smuzhiyun case 3:
155*4882a593Smuzhiyun baud_rate = 9600;
156*4882a593Smuzhiyun break;
157*4882a593Smuzhiyun case 4:
158*4882a593Smuzhiyun baud_rate = 19200;
159*4882a593Smuzhiyun break;
160*4882a593Smuzhiyun case 6:
161*4882a593Smuzhiyun baud_rate = 57600;
162*4882a593Smuzhiyun break;
163*4882a593Smuzhiyun case 7:
164*4882a593Smuzhiyun baud_rate = 115200;
165*4882a593Smuzhiyun break;
166*4882a593Smuzhiyun default:
167*4882a593Smuzhiyun err = -ENOENT;
168*4882a593Smuzhiyun goto done;
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun /*
172*4882a593Smuzhiyun * If the E44 erratum is required, then we need to tell the pl011
173*4882a593Smuzhiyun * driver to implement the work-around.
174*4882a593Smuzhiyun *
175*4882a593Smuzhiyun * The global variable is used by the probe function when it
176*4882a593Smuzhiyun * creates the UARTs, whether or not they're used as a console.
177*4882a593Smuzhiyun *
178*4882a593Smuzhiyun * If the user specifies "traditional" earlycon, the qdf2400_e44
179*4882a593Smuzhiyun * console name matches the EARLYCON_DECLARE() statement, and
180*4882a593Smuzhiyun * SPCR is not used. Parameter "earlycon" is false.
181*4882a593Smuzhiyun *
182*4882a593Smuzhiyun * If the user specifies "SPCR" earlycon, then we need to update
183*4882a593Smuzhiyun * the console name so that it also says "qdf2400_e44". Parameter
184*4882a593Smuzhiyun * "earlycon" is true.
185*4882a593Smuzhiyun *
186*4882a593Smuzhiyun * For consistency, if we change the console name, then we do it
187*4882a593Smuzhiyun * for everyone, not just earlycon.
188*4882a593Smuzhiyun */
189*4882a593Smuzhiyun if (qdf2400_erratum_44_present(&table->header)) {
190*4882a593Smuzhiyun qdf2400_e44_present = true;
191*4882a593Smuzhiyun if (enable_earlycon)
192*4882a593Smuzhiyun uart = "qdf2400_e44";
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun if (xgene_8250_erratum_present(table)) {
196*4882a593Smuzhiyun iotype = "mmio32";
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun /* for xgene v1 and v2 we don't know the clock rate of the
199*4882a593Smuzhiyun * UART so don't attempt to change to the baud rate state
200*4882a593Smuzhiyun * in the table because driver cannot calculate the dividers
201*4882a593Smuzhiyun */
202*4882a593Smuzhiyun baud_rate = 0;
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun if (!baud_rate) {
206*4882a593Smuzhiyun snprintf(opts, sizeof(opts), "%s,%s,0x%llx", uart, iotype,
207*4882a593Smuzhiyun table->serial_port.address);
208*4882a593Smuzhiyun } else {
209*4882a593Smuzhiyun snprintf(opts, sizeof(opts), "%s,%s,0x%llx,%d", uart, iotype,
210*4882a593Smuzhiyun table->serial_port.address, baud_rate);
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun pr_info("console: %s\n", opts);
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun if (enable_earlycon)
216*4882a593Smuzhiyun setup_earlycon(opts);
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun if (enable_console)
219*4882a593Smuzhiyun err = add_preferred_console(uart, 0, opts + strlen(uart) + 1);
220*4882a593Smuzhiyun else
221*4882a593Smuzhiyun err = 0;
222*4882a593Smuzhiyun done:
223*4882a593Smuzhiyun acpi_put_table((struct acpi_table_header *)table);
224*4882a593Smuzhiyun return err;
225*4882a593Smuzhiyun }
226