acpi_platform.c revision 1.13 1 /* $NetBSD: acpi_platform.c,v 1.13 2019/06/19 13:39:18 jmcneill Exp $ */
2
3 /*-
4 * Copyright (c) 2018 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jared McNeill <jmcneill (at) invisible.ca>.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include "com.h"
33 #include "plcom.h"
34 #include "opt_efi.h"
35 #include "opt_multiprocessor.h"
36
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: acpi_platform.c,v 1.13 2019/06/19 13:39:18 jmcneill Exp $");
39
40 #include <sys/param.h>
41 #include <sys/bus.h>
42 #include <sys/cpu.h>
43 #include <sys/device.h>
44 #include <sys/termios.h>
45
46 #include <dev/fdt/fdtvar.h>
47 #include <arm/fdt/arm_fdtvar.h>
48
49 #include <uvm/uvm_extern.h>
50
51 #include <machine/bootconfig.h>
52 #include <arm/cpufunc.h>
53 #include <arm/locore.h>
54
55 #include <arm/cortex/gtmr_var.h>
56
57 #include <arm/arm/psci.h>
58 #include <arm/fdt/psci_fdtvar.h>
59
60 #include <evbarm/fdt/platform.h>
61
62 #include <evbarm/dev/plcomreg.h>
63 #include <evbarm/dev/plcomvar.h>
64 #include <dev/ic/ns16550reg.h>
65 #include <dev/ic/comreg.h>
66 #include <dev/ic/comvar.h>
67
68 #if NCOM > 0
69 #include <dev/pci/pcireg.h>
70 #include <dev/pci/pcivar.h>
71 #include <dev/pci/pucvar.h>
72 #endif
73
74 #ifdef EFI_RUNTIME
75 #include <arm/arm/efi_runtime.h>
76 #endif
77
78 #include <dev/acpi/acpireg.h>
79 #include <dev/acpi/acpivar.h>
80 #include <arm/acpi/acpi_table.h>
81
82 #include <libfdt.h>
83
84 #define SPCR_BAUD_UNKNOWN 0
85 #define SPCR_BAUD_9600 3
86 #define SPCR_BAUD_19200 4
87 #define SPCR_BAUD_57600 6
88 #define SPCR_BAUD_115200 7
89
90 extern struct bus_space arm_generic_bs_tag;
91 extern struct bus_space arm_generic_a4x_bs_tag;
92
93 #if NPLCOM > 0
94 static struct plcom_instance plcom_console;
95 #endif
96
97 struct arm32_bus_dma_tag acpi_coherent32_dma_tag;
98 static struct arm32_dma_range acpi_coherent32_ranges[] = {
99 [0] = {
100 .dr_sysbase = 0,
101 .dr_busbase = 0,
102 .dr_len = 0xffffffffU,
103 .dr_flags = _BUS_DMAMAP_COHERENT,
104 }
105 };
106
107 struct arm32_bus_dma_tag acpi_coherent64_dma_tag;
108 static struct arm32_dma_range acpi_coherent64_ranges[] = {
109 [0] = {
110 .dr_sysbase = 0,
111 .dr_busbase = 0,
112 .dr_len = UINTPTR_MAX,
113 .dr_flags = _BUS_DMAMAP_COHERENT,
114 }
115 };
116
117 static const struct pmap_devmap *
118 acpi_platform_devmap(void)
119 {
120 static const struct pmap_devmap devmap[] = {
121 DEVMAP_ENTRY_END
122 };
123
124 return devmap;
125 }
126
127 static void
128 acpi_platform_bootstrap(void)
129 {
130 extern struct arm32_bus_dma_tag arm_generic_dma_tag;
131
132 acpi_coherent32_dma_tag = arm_generic_dma_tag;
133 acpi_coherent32_dma_tag._ranges = acpi_coherent32_ranges;
134 acpi_coherent32_dma_tag._nranges = __arraycount(acpi_coherent32_ranges);
135
136 acpi_coherent64_dma_tag = arm_generic_dma_tag;
137 acpi_coherent64_dma_tag._ranges = acpi_coherent64_ranges;
138 acpi_coherent64_dma_tag._nranges = __arraycount(acpi_coherent64_ranges);
139 }
140
141 static void
142 acpi_platform_startup(void)
143 {
144 ACPI_TABLE_SPCR *spcr;
145 ACPI_TABLE_FADT *fadt;
146 #ifdef MULTIPROCESSOR
147 ACPI_TABLE_MADT *madt;
148 #endif
149 int baud_rate;
150
151 /*
152 * Setup serial console device
153 */
154 if (ACPI_SUCCESS(acpi_table_find(ACPI_SIG_SPCR, (void **)&spcr))) {
155
156 switch (spcr->BaudRate) {
157 case SPCR_BAUD_9600:
158 baud_rate = 9600;
159 break;
160 case SPCR_BAUD_19200:
161 baud_rate = 19200;
162 break;
163 case SPCR_BAUD_57600:
164 baud_rate = 57600;
165 break;
166 case SPCR_BAUD_115200:
167 case SPCR_BAUD_UNKNOWN:
168 default:
169 baud_rate = 115200;
170 break;
171 }
172
173 if (spcr->SerialPort.SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY &&
174 spcr->SerialPort.Address != 0) {
175 switch (spcr->InterfaceType) {
176 #if NPLCOM > 0
177 case ACPI_DBG2_ARM_PL011:
178 case ACPI_DBG2_ARM_SBSA_32BIT:
179 case ACPI_DBG2_ARM_SBSA_GENERIC:
180 plcom_console.pi_type = PLCOM_TYPE_PL011;
181 plcom_console.pi_iot = &arm_generic_bs_tag;
182 plcom_console.pi_iobase = spcr->SerialPort.Address;
183 plcom_console.pi_size = PL011COM_UART_SIZE;
184 if (spcr->InterfaceType == ACPI_DBG2_ARM_SBSA_32BIT) {
185 plcom_console.pi_flags = PLC_FLAG_32BIT_ACCESS;
186 } else {
187 plcom_console.pi_flags = ACPI_ACCESS_BIT_WIDTH(spcr->SerialPort.AccessWidth) == 8 ?
188 0 : PLC_FLAG_32BIT_ACCESS;
189 }
190
191 plcomcnattach(&plcom_console, baud_rate, 0, TTYDEF_CFLAG, -1);
192 break;
193 #endif
194 #if NCOM > 0
195 case ACPI_DBG2_16550_COMPATIBLE:
196 case ACPI_DBG2_16550_SUBSET:
197 if (ACPI_ACCESS_BIT_WIDTH(spcr->SerialPort.AccessWidth) == 8) {
198 comcnattach(&arm_generic_bs_tag, spcr->SerialPort.Address, baud_rate, -1,
199 COM_TYPE_NORMAL, TTYDEF_CFLAG);
200 } else {
201 comcnattach(&arm_generic_a4x_bs_tag, spcr->SerialPort.Address, baud_rate, -1,
202 COM_TYPE_NORMAL, TTYDEF_CFLAG);
203 }
204 break;
205 case ACPI_DBG2_BCM2835:
206 comcnattach(&arm_generic_a4x_bs_tag, spcr->SerialPort.Address + 0x40, baud_rate, -1,
207 COM_TYPE_BCMAUXUART, TTYDEF_CFLAG);
208 cn_set_magic("+++++");
209 break;
210 #endif
211 default:
212 printf("SPCR: kernel does not support interface type %#x\n", spcr->InterfaceType);
213 break;
214 }
215 }
216 acpi_table_unmap((ACPI_TABLE_HEADER *)spcr);
217 }
218
219 /*
220 * Initialize PSCI 0.2+ if implemented
221 */
222 if (ACPI_SUCCESS(acpi_table_find(ACPI_SIG_FADT, (void **)&fadt))) {
223 if (fadt->ArmBootFlags & ACPI_FADT_PSCI_COMPLIANT) {
224 if (fadt->ArmBootFlags & ACPI_FADT_PSCI_USE_HVC) {
225 psci_init(psci_call_hvc);
226 } else {
227 psci_init(psci_call_smc);
228 }
229 }
230 acpi_table_unmap((ACPI_TABLE_HEADER *)fadt);
231 }
232
233 #ifdef MULTIPROCESSOR
234 /*
235 * Count CPUs
236 */
237 if (ACPI_SUCCESS(acpi_table_find(ACPI_SIG_MADT, (void **)&madt))) {
238 char *end = (char *)madt + madt->Header.Length;
239 char *where = (char *)madt + sizeof(ACPI_TABLE_MADT);
240 while (where < end) {
241 ACPI_SUBTABLE_HEADER *subtable = (ACPI_SUBTABLE_HEADER *)where;
242 if (subtable->Type == ACPI_MADT_TYPE_GENERIC_INTERRUPT)
243 arm_cpu_max++;
244 where += subtable->Length;
245 }
246 acpi_table_unmap((ACPI_TABLE_HEADER *)madt);
247 }
248 #endif /* MULTIPROCESSOR */
249 }
250
251 static void
252 acpi_platform_init_attach_args(struct fdt_attach_args *faa)
253 {
254 extern struct bus_space arm_generic_bs_tag;
255 extern struct bus_space arm_generic_a4x_bs_tag;
256
257 faa->faa_bst = &arm_generic_bs_tag;
258 faa->faa_a4x_bst = &arm_generic_a4x_bs_tag;
259 faa->faa_dmat = &acpi_coherent64_dma_tag;
260 }
261
262 static void
263 acpi_platform_device_register(device_t self, void *aux)
264 {
265 #if NCOM > 0
266 prop_dictionary_t prop = device_properties(self);
267
268 if (device_is_a(self, "com")) {
269 ACPI_TABLE_SPCR *spcr;
270
271 if (ACPI_FAILURE(acpi_table_find(ACPI_SIG_SPCR, (void **)&spcr)))
272 return;
273
274 if (spcr->SerialPort.SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY)
275 goto spcr_unmap;
276 if (spcr->SerialPort.Address == 0)
277 goto spcr_unmap;
278 if (spcr->InterfaceType != ACPI_DBG2_16550_COMPATIBLE &&
279 spcr->InterfaceType != ACPI_DBG2_16550_SUBSET)
280 goto spcr_unmap;
281
282 if (device_is_a(device_parent(self), "puc")) {
283 const struct puc_attach_args * const paa = aux;
284 int b, d, f;
285
286 const int s = pci_get_segment(paa->pc);
287 pci_decompose_tag(paa->pc, paa->tag, &b, &d, &f);
288
289 if (spcr->PciSegment == s && spcr->PciBus == b &&
290 spcr->PciDevice == d && spcr->PciFunction == f)
291 prop_dictionary_set_bool(prop, "force_console", true);
292 }
293
294 if (device_is_a(device_parent(self), "acpi")) {
295 struct acpi_attach_args * const aa = aux;
296 struct acpi_resources res;
297 struct acpi_mem *mem;
298
299 if (ACPI_FAILURE(acpi_resource_parse(self, aa->aa_node->ad_handle, "_CRS",
300 &res, &acpi_resource_parse_ops_quiet)))
301 goto spcr_unmap;
302
303 mem = acpi_res_mem(&res, 0);
304 if (mem == NULL)
305 goto crs_cleanup;
306
307 if (mem->ar_base == spcr->SerialPort.Address)
308 prop_dictionary_set_bool(prop, "force_console", true);
309
310 crs_cleanup:
311 acpi_resource_cleanup(&res);
312 }
313
314 spcr_unmap:
315 acpi_table_unmap((ACPI_TABLE_HEADER *)spcr);
316 }
317 #endif
318 }
319
320 static void
321 acpi_platform_reset(void)
322 {
323 #ifdef EFI_RUNTIME
324 if (arm_efirt_reset(EFI_RESET_COLD) == 0)
325 return;
326 #endif
327 if (psci_available())
328 psci_system_reset();
329 }
330
331 static u_int
332 acpi_platform_uart_freq(void)
333 {
334 return 0;
335 }
336
337 static const struct arm_platform acpi_platform = {
338 .ap_devmap = acpi_platform_devmap,
339 .ap_bootstrap = acpi_platform_bootstrap,
340 .ap_startup = acpi_platform_startup,
341 .ap_init_attach_args = acpi_platform_init_attach_args,
342 .ap_device_register = acpi_platform_device_register,
343 .ap_reset = acpi_platform_reset,
344 .ap_delay = gtmr_delay,
345 .ap_uart_freq = acpi_platform_uart_freq,
346 };
347
348 ARM_PLATFORM(virt, "netbsd,generic-acpi", &acpi_platform);
349