0001
0002
0003
0004
0005
0006
0007
0008 #define pr_fmt(fmt) "ACPI: SPCR: " fmt
0009
0010 #include <linux/acpi.h>
0011 #include <linux/console.h>
0012 #include <linux/kernel.h>
0013 #include <linux/serial_core.h>
0014
0015
0016
0017
0018
0019
0020
0021
0022 bool qdf2400_e44_present;
0023 EXPORT_SYMBOL(qdf2400_e44_present);
0024
0025
0026
0027
0028
0029
0030 static bool qdf2400_erratum_44_present(struct acpi_table_header *h)
0031 {
0032 if (memcmp(h->oem_id, "QCOM ", ACPI_OEM_ID_SIZE))
0033 return false;
0034
0035 if (!memcmp(h->oem_table_id, "QDF2432 ", ACPI_OEM_TABLE_ID_SIZE))
0036 return true;
0037
0038 if (!memcmp(h->oem_table_id, "QDF2400 ", ACPI_OEM_TABLE_ID_SIZE) &&
0039 h->oem_revision == 1)
0040 return true;
0041
0042 return false;
0043 }
0044
0045
0046
0047
0048
0049
0050 static bool xgene_8250_erratum_present(struct acpi_table_spcr *tb)
0051 {
0052 bool xgene_8250 = false;
0053
0054 if (tb->interface_type != ACPI_DBG2_16550_COMPATIBLE)
0055 return false;
0056
0057 if (memcmp(tb->header.oem_id, "APMC0D", ACPI_OEM_ID_SIZE) &&
0058 memcmp(tb->header.oem_id, "HPE ", ACPI_OEM_ID_SIZE))
0059 return false;
0060
0061 if (!memcmp(tb->header.oem_table_id, "XGENESPC",
0062 ACPI_OEM_TABLE_ID_SIZE) && tb->header.oem_revision == 0)
0063 xgene_8250 = true;
0064
0065 if (!memcmp(tb->header.oem_table_id, "ProLiant",
0066 ACPI_OEM_TABLE_ID_SIZE) && tb->header.oem_revision == 1)
0067 xgene_8250 = true;
0068
0069 return xgene_8250;
0070 }
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087 int __init acpi_parse_spcr(bool enable_earlycon, bool enable_console)
0088 {
0089 static char opts[64];
0090 struct acpi_table_spcr *table;
0091 acpi_status status;
0092 char *uart;
0093 char *iotype;
0094 int baud_rate;
0095 int err;
0096
0097 if (acpi_disabled)
0098 return -ENODEV;
0099
0100 status = acpi_get_table(ACPI_SIG_SPCR, 0,
0101 (struct acpi_table_header **)&table);
0102
0103 if (ACPI_FAILURE(status))
0104 return -ENOENT;
0105
0106 if (table->header.revision < 2)
0107 pr_info("SPCR table version %d\n", table->header.revision);
0108
0109 if (table->serial_port.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
0110 u32 bit_width = table->serial_port.access_width;
0111
0112 if (bit_width > ACPI_ACCESS_BIT_MAX) {
0113 pr_err("Unacceptable wide SPCR Access Width. Defaulting to byte size\n");
0114 bit_width = ACPI_ACCESS_BIT_DEFAULT;
0115 }
0116 switch (ACPI_ACCESS_BIT_WIDTH((bit_width))) {
0117 default:
0118 pr_err("Unexpected SPCR Access Width. Defaulting to byte size\n");
0119 fallthrough;
0120 case 8:
0121 iotype = "mmio";
0122 break;
0123 case 16:
0124 iotype = "mmio16";
0125 break;
0126 case 32:
0127 iotype = "mmio32";
0128 break;
0129 }
0130 } else
0131 iotype = "io";
0132
0133 switch (table->interface_type) {
0134 case ACPI_DBG2_ARM_SBSA_32BIT:
0135 iotype = "mmio32";
0136 fallthrough;
0137 case ACPI_DBG2_ARM_PL011:
0138 case ACPI_DBG2_ARM_SBSA_GENERIC:
0139 case ACPI_DBG2_BCM2835:
0140 uart = "pl011";
0141 break;
0142 case ACPI_DBG2_16550_COMPATIBLE:
0143 case ACPI_DBG2_16550_SUBSET:
0144 case ACPI_DBG2_16550_WITH_GAS:
0145 case ACPI_DBG2_16550_NVIDIA:
0146 uart = "uart";
0147 break;
0148 default:
0149 err = -ENOENT;
0150 goto done;
0151 }
0152
0153 switch (table->baud_rate) {
0154 case 0:
0155
0156
0157
0158
0159 baud_rate = 0;
0160 break;
0161 case 3:
0162 baud_rate = 9600;
0163 break;
0164 case 4:
0165 baud_rate = 19200;
0166 break;
0167 case 6:
0168 baud_rate = 57600;
0169 break;
0170 case 7:
0171 baud_rate = 115200;
0172 break;
0173 default:
0174 err = -ENOENT;
0175 goto done;
0176 }
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196 if (qdf2400_erratum_44_present(&table->header)) {
0197 qdf2400_e44_present = true;
0198 if (enable_earlycon)
0199 uart = "qdf2400_e44";
0200 }
0201
0202 if (xgene_8250_erratum_present(table)) {
0203 iotype = "mmio32";
0204
0205
0206
0207
0208
0209 baud_rate = 0;
0210 }
0211
0212 if (!baud_rate) {
0213 snprintf(opts, sizeof(opts), "%s,%s,0x%llx", uart, iotype,
0214 table->serial_port.address);
0215 } else {
0216 snprintf(opts, sizeof(opts), "%s,%s,0x%llx,%d", uart, iotype,
0217 table->serial_port.address, baud_rate);
0218 }
0219
0220 pr_info("console: %s\n", opts);
0221
0222 if (enable_earlycon)
0223 setup_earlycon(opts);
0224
0225 if (enable_console)
0226 err = add_preferred_console(uart, 0, opts + strlen(uart) + 1);
0227 else
0228 err = 0;
0229 done:
0230 acpi_put_table((struct acpi_table_header *)table);
0231 return err;
0232 }