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; } |
