xref: /OK3568_Linux_fs/kernel/drivers/acpi/spcr.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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