blob: 29050630f3da2941946f0770d4a090066688679b [file] [log] [blame]
Aleksey Makarovad1696f2016-09-27 23:54:13 +03001/*
2 * Copyright (c) 2012, Intel Corporation
3 * Copyright (c) 2015, Red Hat, Inc.
4 * Copyright (c) 2015, 2016 Linaro Ltd.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 */
11
12#define pr_fmt(fmt) "ACPI: SPCR: " fmt
13
14#include <linux/acpi.h>
15#include <linux/console.h>
16#include <linux/kernel.h>
17#include <linux/serial_core.h>
18
Christopher Covingtond8a49952017-02-15 16:39:43 -050019/*
20 * 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
22 * quirk detection in pci_mcfg.c.
23 */
24static bool qdf2400_erratum_44_present(struct acpi_table_header *h)
25{
26 if (memcmp(h->oem_id, "QCOM ", ACPI_OEM_ID_SIZE))
27 return false;
28
29 if (!memcmp(h->oem_table_id, "QDF2432 ", ACPI_OEM_TABLE_ID_SIZE))
30 return true;
31
32 if (!memcmp(h->oem_table_id, "QDF2400 ", ACPI_OEM_TABLE_ID_SIZE) &&
Timur Tabi542ed782017-02-28 14:30:33 -060033 h->oem_revision == 1)
Christopher Covingtond8a49952017-02-15 16:39:43 -050034 return true;
35
36 return false;
37}
38
Aleksey Makarovad1696f2016-09-27 23:54:13 +030039/**
40 * parse_spcr() - parse ACPI SPCR table and add preferred console
41 *
42 * @earlycon: set up earlycon for the console specified by the table
43 *
44 * For the architectures with support for ACPI, CONFIG_ACPI_SPCR_TABLE may be
45 * defined to parse ACPI SPCR table. As a result of the parsing preferred
46 * console is registered and if @earlycon is true, earlycon is set up.
47 *
48 * When CONFIG_ACPI_SPCR_TABLE is defined, this function should be called
Masahiro Yamada183b8022017-02-27 14:29:20 -080049 * from arch initialization code as soon as the DT/ACPI decision is made.
Aleksey Makarovad1696f2016-09-27 23:54:13 +030050 *
51 */
52int __init parse_spcr(bool earlycon)
53{
54 static char opts[64];
55 struct acpi_table_spcr *table;
Aleksey Makarovad1696f2016-09-27 23:54:13 +030056 acpi_status status;
57 char *uart;
58 char *iotype;
59 int baud_rate;
60 int err;
61
62 if (acpi_disabled)
63 return -ENODEV;
64
Lv Zheng6b11d1d2016-12-14 15:04:39 +080065 status = acpi_get_table(ACPI_SIG_SPCR, 0,
66 (struct acpi_table_header **)&table);
Aleksey Makarovad1696f2016-09-27 23:54:13 +030067
68 if (ACPI_FAILURE(status))
69 return -ENOENT;
70
71 if (table->header.revision < 2) {
72 err = -ENOENT;
73 pr_err("wrong table version\n");
74 goto done;
75 }
76
Loc Ho2bece492017-07-03 14:33:08 -070077 if (table->serial_port.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
78 switch (table->serial_port.access_width) {
79 default:
80 pr_err("Unexpected SPCR Access Width. Defaulting to byte size\n");
81 case ACPI_ACCESS_SIZE_BYTE:
82 iotype = "mmio";
83 break;
84 case ACPI_ACCESS_SIZE_WORD:
85 iotype = "mmio16";
86 break;
87 case ACPI_ACCESS_SIZE_DWORD:
88 iotype = "mmio32";
89 break;
90 }
91 } else
92 iotype = "io";
Aleksey Makarovad1696f2016-09-27 23:54:13 +030093
94 switch (table->interface_type) {
95 case ACPI_DBG2_ARM_SBSA_32BIT:
96 iotype = "mmio32";
97 /* fall through */
98 case ACPI_DBG2_ARM_PL011:
99 case ACPI_DBG2_ARM_SBSA_GENERIC:
100 case ACPI_DBG2_BCM2835:
101 uart = "pl011";
102 break;
103 case ACPI_DBG2_16550_COMPATIBLE:
104 case ACPI_DBG2_16550_SUBSET:
105 uart = "uart";
106 break;
107 default:
108 err = -ENOENT;
109 goto done;
110 }
111
112 switch (table->baud_rate) {
113 case 3:
114 baud_rate = 9600;
115 break;
116 case 4:
117 baud_rate = 19200;
118 break;
119 case 6:
120 baud_rate = 57600;
121 break;
122 case 7:
123 baud_rate = 115200;
124 break;
125 default:
126 err = -ENOENT;
127 goto done;
128 }
129
Christopher Covingtond8a49952017-02-15 16:39:43 -0500130 if (qdf2400_erratum_44_present(&table->header))
131 uart = "qdf2400_e44";
132
Aleksey Makarovad1696f2016-09-27 23:54:13 +0300133 snprintf(opts, sizeof(opts), "%s,%s,0x%llx,%d", uart, iotype,
134 table->serial_port.address, baud_rate);
135
136 pr_info("console: %s\n", opts);
137
138 if (earlycon)
139 setup_earlycon(opts);
140
141 err = add_preferred_console(uart, 0, opts + strlen(uart) + 1);
142
143done:
Lv Zheng6b11d1d2016-12-14 15:04:39 +0800144 acpi_put_table((struct acpi_table_header *)table);
Aleksey Makarovad1696f2016-09-27 23:54:13 +0300145 return err;
146}