1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2016 The FreeBSD Foundation
5 * Copyright (c) 2019 Colin Percival
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/bus.h>
33
34 #include <machine/bus.h>
35
36 #include <dev/pci/pcireg.h>
37
38 #include <dev/uart/uart.h>
39 #include <dev/uart/uart_bus.h>
40 #include <dev/uart/uart_cpu.h>
41 #include <dev/uart/uart_cpu_acpi.h>
42
43 #include <contrib/dev/acpica/include/acpi.h>
44 #include <contrib/dev/acpica/include/accommon.h>
45 #include <contrib/dev/acpica/include/actables.h>
46
47 static struct acpi_spcr_compat_data *
uart_cpu_acpi_scan(uint8_t interface_type)48 uart_cpu_acpi_scan(uint8_t interface_type)
49 {
50 struct acpi_spcr_compat_data **cd, *curcd;
51 int i;
52
53 SET_FOREACH(cd, uart_acpi_spcr_class_set) {
54 curcd = *cd;
55 for (i = 0; curcd[i].cd_class != NULL; i++) {
56 if (curcd[i].cd_port_subtype == interface_type)
57 return (&curcd[i]);
58 }
59 }
60
61 return (NULL);
62 }
63
64 static int
uart_cpu_acpi_init_devinfo(struct uart_devinfo * di,struct uart_class * class,ACPI_GENERIC_ADDRESS * addr)65 uart_cpu_acpi_init_devinfo(struct uart_devinfo *di, struct uart_class *class,
66 ACPI_GENERIC_ADDRESS *addr)
67 {
68 /* Fill in some fixed details. */
69 di->bas.chan = 0;
70 di->bas.rclk = 0;
71 di->databits = 8;
72 di->stopbits = 1;
73 di->parity = UART_PARITY_NONE;
74 di->ops = uart_getops(class);
75
76 /* Fill in details from SPCR table. */
77 switch (addr->SpaceId) {
78 case 0:
79 di->bas.bst = uart_bus_space_mem;
80 break;
81 case 1:
82 di->bas.bst = uart_bus_space_io;
83 break;
84 default:
85 printf("UART in unrecognized address space: %d!\n",
86 (int)addr->SpaceId);
87 return (ENXIO);
88 }
89 switch (addr->AccessWidth) {
90 case 0: /* EFI_ACPI_6_0_UNDEFINED */
91 /* FALLTHROUGH */
92 case 1: /* EFI_ACPI_6_0_BYTE */
93 di->bas.regiowidth = 1;
94 break;
95 case 2: /* EFI_ACPI_6_0_WORD */
96 di->bas.regiowidth = 2;
97 break;
98 case 3: /* EFI_ACPI_6_0_DWORD */
99 di->bas.regiowidth = 4;
100 break;
101 case 4: /* EFI_ACPI_6_0_QWORD */
102 di->bas.regiowidth = 8;
103 break;
104 default:
105 printf("UART unsupported access width: %d!\n",
106 (int)addr->AccessWidth);
107 return (ENXIO);
108 }
109 switch (addr->BitWidth) {
110 case 0:
111 /* FALLTHROUGH */
112 case 8:
113 di->bas.regshft = 0;
114 break;
115 case 16:
116 di->bas.regshft = 1;
117 break;
118 case 32:
119 di->bas.regshft = 2;
120 break;
121 case 64:
122 di->bas.regshft = 3;
123 break;
124 default:
125 printf("UART unsupported bit width: %d!\n",
126 (int)addr->BitWidth);
127 return (ENXIO);
128 }
129
130 return (0);
131 }
132
133 static int
uart_cpu_acpi_spcr(int devtype,struct uart_devinfo * di)134 uart_cpu_acpi_spcr(int devtype, struct uart_devinfo *di)
135 {
136 vm_paddr_t spcr_physaddr;
137 ACPI_TABLE_SPCR *spcr;
138 struct acpi_spcr_compat_data *cd;
139 struct uart_class *class;
140 int error = ENXIO;
141
142 /* Look for the SPCR table. */
143 spcr_physaddr = acpi_find_table(ACPI_SIG_SPCR);
144 if (spcr_physaddr == 0)
145 return (error);
146 spcr = acpi_map_table(spcr_physaddr, ACPI_SIG_SPCR);
147 if (spcr == NULL) {
148 printf("Unable to map the SPCR table!\n");
149 return (error);
150 }
151
152 /* Search for information about this SPCR interface type. */
153 cd = uart_cpu_acpi_scan(spcr->InterfaceType);
154 if (cd == NULL)
155 goto out;
156 class = cd->cd_class;
157
158 error = uart_cpu_acpi_init_devinfo(di, class, &spcr->SerialPort);
159 if (error != 0)
160 goto out;
161
162 /*
163 * SPCR Rev 4 and newer allow a precise baudrate to be passed in for
164 * things like 1.5M or 2.0M. If we have that, then use that value,
165 * otherwise try to decode the older enumeration.
166 */
167 if (spcr->Header.Revision >= 4 && spcr->PreciseBaudrate != 0) {
168 di->baudrate = spcr->PreciseBaudrate;
169 } else {
170 switch (spcr->BaudRate) {
171 case 0:
172 /* Special value; means "keep current value unchanged". */
173 di->baudrate = 0;
174 break;
175 case 3:
176 di->baudrate = 9600;
177 break;
178 case 4:
179 di->baudrate = 19200;
180 break;
181 case 6:
182 di->baudrate = 57600;
183 break;
184 case 7:
185 di->baudrate = 115200;
186 break;
187 default:
188 printf("SPCR has reserved BaudRate value: %d!\n",
189 (int)spcr->BaudRate);
190 goto out;
191 }
192 }
193
194 /*
195 * Rev 3 and newer can specify a rclk, use it if it's there. It's
196 * defined to be 0 when it's not known, and we've initialized rclk to 0
197 * in uart_cpu_acpi_init_devinfo, so we don't have to test for it.
198 */
199 if (spcr->Header.Revision >= 3)
200 di->bas.rclk = spcr->UartClkFreq;
201
202 /*
203 * If no rclk is set, then we will assume the BIOS has configured the
204 * hardware at the stated baudrate, so we can use it to guess the rclk
205 * relatively accurately, so make a note for later.
206 */
207 if (di->bas.rclk == 0)
208 di->bas.rclk_guess = 1;
209
210 if (spcr->PciVendorId != PCIV_INVALID &&
211 spcr->PciDeviceId != PCIV_INVALID) {
212 di->pci_info.vendor = spcr->PciVendorId;
213 di->pci_info.device = spcr->PciDeviceId;
214 }
215
216 /* Create a bus space handle. */
217 error = bus_space_map(di->bas.bst, spcr->SerialPort.Address,
218 uart_getrange(class), 0, &di->bas.bsh);
219
220 out:
221 acpi_unmap_table(spcr);
222 return (error);
223 }
224
225 static int
uart_cpu_acpi_dbg2(struct uart_devinfo * di)226 uart_cpu_acpi_dbg2(struct uart_devinfo *di)
227 {
228 vm_paddr_t dbg2_physaddr;
229 ACPI_TABLE_DBG2 *dbg2;
230 ACPI_DBG2_DEVICE *dbg2_dev;
231 ACPI_GENERIC_ADDRESS *base_address;
232 struct acpi_spcr_compat_data *cd;
233 struct uart_class *class;
234 int error;
235 bool found;
236
237 /* Look for the DBG2 table. */
238 dbg2_physaddr = acpi_find_table(ACPI_SIG_DBG2);
239 if (dbg2_physaddr == 0)
240 return (ENXIO);
241
242 dbg2 = acpi_map_table(dbg2_physaddr, ACPI_SIG_DBG2);
243 if (dbg2 == NULL) {
244 printf("Unable to map the DBG2 table!\n");
245 return (ENXIO);
246 }
247
248 error = ENXIO;
249
250 dbg2_dev = (ACPI_DBG2_DEVICE *)((uintptr_t)dbg2 + dbg2->InfoOffset);
251 found = false;
252 while ((uintptr_t)dbg2_dev + dbg2_dev->Length <=
253 (uintptr_t)dbg2 + dbg2->Header.Length) {
254 if (dbg2_dev->PortType != ACPI_DBG2_SERIAL_PORT)
255 goto next;
256
257 /* XXX: Too restrictive? */
258 if (dbg2_dev->RegisterCount != 1)
259 goto next;
260
261 cd = uart_cpu_acpi_scan(dbg2_dev->PortSubtype);
262 if (cd == NULL)
263 goto next;
264
265 class = cd->cd_class;
266 base_address = (ACPI_GENERIC_ADDRESS *)
267 ((uintptr_t)dbg2_dev + dbg2_dev->BaseAddressOffset);
268
269 error = uart_cpu_acpi_init_devinfo(di, class, base_address);
270 if (error == 0) {
271 found = true;
272 break;
273 }
274
275 next:
276 dbg2_dev = (ACPI_DBG2_DEVICE *)
277 ((uintptr_t)dbg2_dev + dbg2_dev->Length);
278 }
279 if (!found)
280 goto out;
281
282 /* XXX: Find the correct value */
283 di->baudrate = 115200;
284
285 /* Create a bus space handle. */
286 error = bus_space_map(di->bas.bst, base_address->Address,
287 uart_getrange(class), 0, &di->bas.bsh);
288
289 out:
290 acpi_unmap_table(dbg2);
291 return (error);
292 }
293
294 int
uart_cpu_acpi_setup(int devtype,struct uart_devinfo * di)295 uart_cpu_acpi_setup(int devtype, struct uart_devinfo *di)
296 {
297 char *cp;
298
299 switch(devtype) {
300 case UART_DEV_CONSOLE:
301 return (uart_cpu_acpi_spcr(devtype, di));
302 case UART_DEV_DBGPORT:
303 /* Use the Debug Port Table 2 (DBG2) to find a debug uart */
304 cp = kern_getenv("hw.acpi.enable_dbg2");
305 if (cp != NULL && strcasecmp(cp, "yes") == 0)
306 return (uart_cpu_acpi_dbg2(di));
307 break;
308 }
309 return (ENXIO);
310 }
311