diff options
-rw-r--r-- | drivers/acpi/spcr.c | 36 | ||||
-rw-r--r-- | drivers/tty/serial/amba-pl011.c | 37 | ||||
-rw-r--r-- | include/linux/acpi.h | 1 |
3 files changed, 54 insertions, 20 deletions
diff --git a/drivers/acpi/spcr.c b/drivers/acpi/spcr.c index 4ac3e06b41d8..98aa8c808a33 100644 --- a/drivers/acpi/spcr.c +++ b/drivers/acpi/spcr.c | |||
@@ -17,6 +17,16 @@ | |||
17 | #include <linux/serial_core.h> | 17 | #include <linux/serial_core.h> |
18 | 18 | ||
19 | /* | 19 | /* |
20 | * Erratum 44 for QDF2432v1 and QDF2400v1 SoCs describes the BUSY bit as | ||
21 | * occasionally getting stuck as 1. To avoid the potential for a hang, check | ||
22 | * TXFE == 0 instead of BUSY == 1. This may not be suitable for all UART | ||
23 | * implementations, so only do so if an affected platform is detected in | ||
24 | * parse_spcr(). | ||
25 | */ | ||
26 | bool qdf2400_e44_present; | ||
27 | EXPORT_SYMBOL(qdf2400_e44_present); | ||
28 | |||
29 | /* | ||
20 | * Some Qualcomm Datacenter Technologies SoCs have a defective UART BUSY bit. | 30 | * Some Qualcomm Datacenter Technologies SoCs have a defective UART BUSY bit. |
21 | * Detect them by examining the OEM fields in the SPCR header, similiar to PCI | 31 | * Detect them by examining the OEM fields in the SPCR header, similiar to PCI |
22 | * quirk detection in pci_mcfg.c. | 32 | * quirk detection in pci_mcfg.c. |
@@ -147,8 +157,30 @@ int __init parse_spcr(bool earlycon) | |||
147 | goto done; | 157 | goto done; |
148 | } | 158 | } |
149 | 159 | ||
150 | if (qdf2400_erratum_44_present(&table->header)) | 160 | /* |
151 | uart = "qdf2400_e44"; | 161 | * If the E44 erratum is required, then we need to tell the pl011 |
162 | * driver to implement the work-around. | ||
163 | * | ||
164 | * The global variable is used by the probe function when it | ||
165 | * creates the UARTs, whether or not they're used as a console. | ||
166 | * | ||
167 | * If the user specifies "traditional" earlycon, the qdf2400_e44 | ||
168 | * console name matches the EARLYCON_DECLARE() statement, and | ||
169 | * SPCR is not used. Parameter "earlycon" is false. | ||
170 | * | ||
171 | * If the user specifies "SPCR" earlycon, then we need to update | ||
172 | * the console name so that it also says "qdf2400_e44". Parameter | ||
173 | * "earlycon" is true. | ||
174 | * | ||
175 | * For consistency, if we change the console name, then we do it | ||
176 | * for everyone, not just earlycon. | ||
177 | */ | ||
178 | if (qdf2400_erratum_44_present(&table->header)) { | ||
179 | qdf2400_e44_present = true; | ||
180 | if (earlycon) | ||
181 | uart = "qdf2400_e44"; | ||
182 | } | ||
183 | |||
152 | if (xgene_8250_erratum_present(table)) | 184 | if (xgene_8250_erratum_present(table)) |
153 | iotype = "mmio32"; | 185 | iotype = "mmio32"; |
154 | 186 | ||
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 8a857bb34fbb..1888d168a41c 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c | |||
@@ -142,15 +142,7 @@ static struct vendor_data vendor_sbsa = { | |||
142 | .fixed_options = true, | 142 | .fixed_options = true, |
143 | }; | 143 | }; |
144 | 144 | ||
145 | /* | 145 | #ifdef CONFIG_ACPI_SPCR_TABLE |
146 | * Erratum 44 for QDF2432v1 and QDF2400v1 SoCs describes the BUSY bit as | ||
147 | * occasionally getting stuck as 1. To avoid the potential for a hang, check | ||
148 | * TXFE == 0 instead of BUSY == 1. This may not be suitable for all UART | ||
149 | * implementations, so only do so if an affected platform is detected in | ||
150 | * parse_spcr(). | ||
151 | */ | ||
152 | static bool qdf2400_e44_present = false; | ||
153 | |||
154 | static struct vendor_data vendor_qdt_qdf2400_e44 = { | 146 | static struct vendor_data vendor_qdt_qdf2400_e44 = { |
155 | .reg_offset = pl011_std_offsets, | 147 | .reg_offset = pl011_std_offsets, |
156 | .fr_busy = UART011_FR_TXFE, | 148 | .fr_busy = UART011_FR_TXFE, |
@@ -165,6 +157,7 @@ static struct vendor_data vendor_qdt_qdf2400_e44 = { | |||
165 | .always_enabled = true, | 157 | .always_enabled = true, |
166 | .fixed_options = true, | 158 | .fixed_options = true, |
167 | }; | 159 | }; |
160 | #endif | ||
168 | 161 | ||
169 | static u16 pl011_st_offsets[REG_ARRAY_SIZE] = { | 162 | static u16 pl011_st_offsets[REG_ARRAY_SIZE] = { |
170 | [REG_DR] = UART01x_DR, | 163 | [REG_DR] = UART01x_DR, |
@@ -2375,12 +2368,14 @@ static int __init pl011_console_match(struct console *co, char *name, int idx, | |||
2375 | resource_size_t addr; | 2368 | resource_size_t addr; |
2376 | int i; | 2369 | int i; |
2377 | 2370 | ||
2378 | if (strcmp(name, "qdf2400_e44") == 0) { | 2371 | /* |
2379 | pr_info_once("UART: Working around QDF2400 SoC erratum 44"); | 2372 | * Systems affected by the Qualcomm Technologies QDF2400 E44 erratum |
2380 | qdf2400_e44_present = true; | 2373 | * have a distinct console name, so make sure we check for that. |
2381 | } else if (strcmp(name, "pl011") != 0) { | 2374 | * The actual implementation of the erratum occurs in the probe |
2375 | * function. | ||
2376 | */ | ||
2377 | if ((strcmp(name, "qdf2400_e44") != 0) && (strcmp(name, "pl011") != 0)) | ||
2382 | return -ENODEV; | 2378 | return -ENODEV; |
2383 | } | ||
2384 | 2379 | ||
2385 | if (uart_parse_earlycon(options, &iotype, &addr, &options)) | 2380 | if (uart_parse_earlycon(options, &iotype, &addr, &options)) |
2386 | return -ENODEV; | 2381 | return -ENODEV; |
@@ -2734,11 +2729,17 @@ static int sbsa_uart_probe(struct platform_device *pdev) | |||
2734 | } | 2729 | } |
2735 | uap->port.irq = ret; | 2730 | uap->port.irq = ret; |
2736 | 2731 | ||
2737 | uap->reg_offset = vendor_sbsa.reg_offset; | 2732 | #ifdef CONFIG_ACPI_SPCR_TABLE |
2738 | uap->vendor = qdf2400_e44_present ? | 2733 | if (qdf2400_e44_present) { |
2739 | &vendor_qdt_qdf2400_e44 : &vendor_sbsa; | 2734 | dev_info(&pdev->dev, "working around QDF2400 SoC erratum 44\n"); |
2735 | uap->vendor = &vendor_qdt_qdf2400_e44; | ||
2736 | } else | ||
2737 | #endif | ||
2738 | uap->vendor = &vendor_sbsa; | ||
2739 | |||
2740 | uap->reg_offset = uap->vendor->reg_offset; | ||
2740 | uap->fifosize = 32; | 2741 | uap->fifosize = 32; |
2741 | uap->port.iotype = vendor_sbsa.access_32b ? UPIO_MEM32 : UPIO_MEM; | 2742 | uap->port.iotype = uap->vendor->access_32b ? UPIO_MEM32 : UPIO_MEM; |
2742 | uap->port.ops = &sbsa_uart_pops; | 2743 | uap->port.ops = &sbsa_uart_pops; |
2743 | uap->fixed_baud = baudrate; | 2744 | uap->fixed_baud = baudrate; |
2744 | 2745 | ||
diff --git a/include/linux/acpi.h b/include/linux/acpi.h index c749eef1daa1..27b4b6615263 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h | |||
@@ -1209,6 +1209,7 @@ static inline bool acpi_has_watchdog(void) { return false; } | |||
1209 | #endif | 1209 | #endif |
1210 | 1210 | ||
1211 | #ifdef CONFIG_ACPI_SPCR_TABLE | 1211 | #ifdef CONFIG_ACPI_SPCR_TABLE |
1212 | extern bool qdf2400_e44_present; | ||
1212 | int parse_spcr(bool earlycon); | 1213 | int parse_spcr(bool earlycon); |
1213 | #else | 1214 | #else |
1214 | static inline int parse_spcr(bool earlycon) { return 0; } | 1215 | static inline int parse_spcr(bool earlycon) { return 0; } |