acpi_platform.c revision 1.18 1 /* $NetBSD: acpi_platform.c,v 1.18 2019/09/22 18:31:59 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 "wsdisplay.h"
35 #include "genfb.h"
36 #include "opt_efi.h"
37 #include "opt_multiprocessor.h"
38
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: acpi_platform.c,v 1.18 2019/09/22 18:31:59 jmcneill Exp $");
41
42 #include <sys/param.h>
43 #include <sys/bus.h>
44 #include <sys/cpu.h>
45 #include <sys/device.h>
46 #include <sys/termios.h>
47
48 #include <dev/fdt/fdtvar.h>
49 #include <arm/fdt/arm_fdtvar.h>
50
51 #include <uvm/uvm_extern.h>
52
53 #include <machine/bootconfig.h>
54 #include <arm/cpufunc.h>
55 #include <arm/locore.h>
56
57 #include <arm/cortex/gtmr_var.h>
58
59 #include <arm/arm/psci.h>
60 #include <arm/fdt/psci_fdtvar.h>
61
62 #include <evbarm/fdt/platform.h>
63
64 #include <evbarm/dev/plcomreg.h>
65 #include <evbarm/dev/plcomvar.h>
66 #include <dev/ic/ns16550reg.h>
67 #include <dev/ic/comreg.h>
68 #include <dev/ic/comvar.h>
69
70 #if NCOM > 0
71 #include <dev/pci/pcireg.h>
72 #include <dev/pci/pcivar.h>
73 #include <dev/pci/pucvar.h>
74 #endif
75
76 #if NWSDISPLAY > 0 && NGENFB > 0
77 #include <arm/acpi/acpi_simplefb.h>
78 #endif
79
80 #ifdef EFI_RUNTIME
81 #include <arm/arm/efi_runtime.h>
82 #endif
83
84 #include <dev/acpi/acpireg.h>
85 #include <dev/acpi/acpivar.h>
86 #include <arm/acpi/acpi_table.h>
87
88 #include <libfdt.h>
89
90 #define SPCR_BAUD_UNKNOWN 0
91 #define SPCR_BAUD_9600 3
92 #define SPCR_BAUD_19200 4
93 #define SPCR_BAUD_57600 6
94 #define SPCR_BAUD_115200 7
95
96 extern struct bus_space arm_generic_bs_tag;
97 extern struct bus_space arm_generic_a4x_bs_tag;
98
99 #if NPLCOM > 0
100 static struct plcom_instance plcom_console;
101 #endif
102
103 struct arm32_bus_dma_tag acpi_coherent_dma_tag;
104 static struct arm32_dma_range acpi_coherent_ranges[] = {
105 [0] = {
106 .dr_sysbase = 0,
107 .dr_busbase = 0,
108 .dr_len = UINTPTR_MAX,
109 .dr_flags = _BUS_DMAMAP_COHERENT,
110 }
111 };
112
113 static const struct pmap_devmap *
114 acpi_platform_devmap(void)
115 {
116 static const struct pmap_devmap devmap[] = {
117 DEVMAP_ENTRY_END
118 };
119
120 return devmap;
121 }
122
123 static void
124 acpi_platform_bootstrap(void)
125 {
126 extern struct arm32_bus_dma_tag arm_generic_dma_tag;
127
128 acpi_coherent_dma_tag = arm_generic_dma_tag;
129 acpi_coherent_dma_tag._ranges = acpi_coherent_ranges;
130 acpi_coherent_dma_tag._nranges = __arraycount(acpi_coherent_ranges);
131 }
132
133 static void
134 acpi_platform_startup(void)
135 {
136 ACPI_TABLE_SPCR *spcr;
137 ACPI_TABLE_FADT *fadt;
138 #ifdef MULTIPROCESSOR
139 ACPI_TABLE_MADT *madt;
140 #endif
141 int baud_rate;
142
143 /*
144 * Setup serial console device
145 */
146 if (ACPI_SUCCESS(acpi_table_find(ACPI_SIG_SPCR, (void **)&spcr))) {
147
148 switch (spcr->BaudRate) {
149 case SPCR_BAUD_9600:
150 baud_rate = 9600;
151 break;
152 case SPCR_BAUD_19200:
153 baud_rate = 19200;
154 break;
155 case SPCR_BAUD_57600:
156 baud_rate = 57600;
157 break;
158 case SPCR_BAUD_115200:
159 case SPCR_BAUD_UNKNOWN:
160 default:
161 baud_rate = 115200;
162 break;
163 }
164
165 if (spcr->SerialPort.SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY &&
166 spcr->SerialPort.Address != 0) {
167 switch (spcr->InterfaceType) {
168 #if NPLCOM > 0
169 case ACPI_DBG2_ARM_PL011:
170 case ACPI_DBG2_ARM_SBSA_32BIT:
171 case ACPI_DBG2_ARM_SBSA_GENERIC:
172 plcom_console.pi_type = PLCOM_TYPE_PL011;
173 plcom_console.pi_iot = &arm_generic_bs_tag;
174 plcom_console.pi_iobase = spcr->SerialPort.Address;
175 plcom_console.pi_size = PL011COM_UART_SIZE;
176 plcom_console.pi_flags = PLC_FLAG_32BIT_ACCESS;
177
178 plcomcnattach(&plcom_console, baud_rate, 0, TTYDEF_CFLAG, -1);
179 break;
180 #endif
181 #if NCOM > 0
182 case ACPI_DBG2_16550_COMPATIBLE:
183 case ACPI_DBG2_16550_SUBSET:
184 if (ACPI_ACCESS_BIT_WIDTH(spcr->SerialPort.AccessWidth) == 8) {
185 comcnattach(&arm_generic_bs_tag, spcr->SerialPort.Address, baud_rate, -1,
186 COM_TYPE_NORMAL, TTYDEF_CFLAG);
187 } else {
188 comcnattach(&arm_generic_a4x_bs_tag, spcr->SerialPort.Address, baud_rate, -1,
189 COM_TYPE_NORMAL, TTYDEF_CFLAG);
190 }
191 break;
192 case ACPI_DBG2_BCM2835:
193 comcnattach(&arm_generic_a4x_bs_tag, spcr->SerialPort.Address + 0x40, baud_rate, -1,
194 COM_TYPE_BCMAUXUART, TTYDEF_CFLAG);
195 cn_set_magic("+++++");
196 break;
197 #endif
198 default:
199 printf("SPCR: kernel does not support interface type %#x\n", spcr->InterfaceType);
200 break;
201 }
202 }
203 acpi_table_unmap((ACPI_TABLE_HEADER *)spcr);
204 }
205
206 /*
207 * Initialize PSCI 0.2+ if implemented
208 */
209 if (ACPI_SUCCESS(acpi_table_find(ACPI_SIG_FADT, (void **)&fadt))) {
210 if (fadt->ArmBootFlags & ACPI_FADT_PSCI_COMPLIANT) {
211 if (fadt->ArmBootFlags & ACPI_FADT_PSCI_USE_HVC) {
212 psci_init(psci_call_hvc);
213 } else {
214 psci_init(psci_call_smc);
215 }
216 }
217 acpi_table_unmap((ACPI_TABLE_HEADER *)fadt);
218 }
219
220 #ifdef MULTIPROCESSOR
221 /*
222 * Count CPUs
223 */
224 if (ACPI_SUCCESS(acpi_table_find(ACPI_SIG_MADT, (void **)&madt))) {
225 char *end = (char *)madt + madt->Header.Length;
226 char *where = (char *)madt + sizeof(ACPI_TABLE_MADT);
227 while (where < end) {
228 ACPI_SUBTABLE_HEADER *subtable = (ACPI_SUBTABLE_HEADER *)where;
229 if (subtable->Type == ACPI_MADT_TYPE_GENERIC_INTERRUPT)
230 arm_cpu_max++;
231 where += subtable->Length;
232 }
233 acpi_table_unmap((ACPI_TABLE_HEADER *)madt);
234 }
235 #endif /* MULTIPROCESSOR */
236 }
237
238 static void
239 acpi_platform_init_attach_args(struct fdt_attach_args *faa)
240 {
241 extern struct bus_space arm_generic_bs_tag;
242 extern struct bus_space arm_generic_a4x_bs_tag;
243
244 faa->faa_bst = &arm_generic_bs_tag;
245 faa->faa_a4x_bst = &arm_generic_a4x_bs_tag;
246 faa->faa_dmat = &acpi_coherent_dma_tag;
247 }
248
249 static void
250 acpi_platform_device_register(device_t self, void *aux)
251 {
252 #if NWSDISPLAY > 0 && NGENFB > 0
253 if (device_is_a(self, "armfdt")) {
254 /*
255 * Setup framebuffer console, if present.
256 */
257 acpi_simplefb_preattach();
258 }
259 #endif
260
261 #if NCOM > 0
262 prop_dictionary_t prop = device_properties(self);
263
264 if (device_is_a(self, "com")) {
265 ACPI_TABLE_SPCR *spcr;
266
267 if (ACPI_FAILURE(acpi_table_find(ACPI_SIG_SPCR, (void **)&spcr)))
268 return;
269
270 if (spcr->SerialPort.SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY)
271 goto spcr_unmap;
272 if (spcr->SerialPort.Address == 0)
273 goto spcr_unmap;
274 if (spcr->InterfaceType != ACPI_DBG2_16550_COMPATIBLE &&
275 spcr->InterfaceType != ACPI_DBG2_16550_SUBSET)
276 goto spcr_unmap;
277
278 if (device_is_a(device_parent(self), "puc")) {
279 const struct puc_attach_args * const paa = aux;
280 int b, d, f;
281
282 const int s = pci_get_segment(paa->pc);
283 pci_decompose_tag(paa->pc, paa->tag, &b, &d, &f);
284
285 if (spcr->PciSegment == s && spcr->PciBus == b &&
286 spcr->PciDevice == d && spcr->PciFunction == f)
287 prop_dictionary_set_bool(prop, "force_console", true);
288 }
289
290 if (device_is_a(device_parent(self), "acpi")) {
291 struct acpi_attach_args * const aa = aux;
292 struct acpi_resources res;
293 struct acpi_mem *mem;
294
295 if (ACPI_FAILURE(acpi_resource_parse(self, aa->aa_node->ad_handle, "_CRS",
296 &res, &acpi_resource_parse_ops_quiet)))
297 goto spcr_unmap;
298
299 mem = acpi_res_mem(&res, 0);
300 if (mem == NULL)
301 goto crs_cleanup;
302
303 if (mem->ar_base == spcr->SerialPort.Address)
304 prop_dictionary_set_bool(prop, "force_console", true);
305
306 crs_cleanup:
307 acpi_resource_cleanup(&res);
308 }
309
310 spcr_unmap:
311 acpi_table_unmap((ACPI_TABLE_HEADER *)spcr);
312 }
313 #endif
314 }
315
316 static void
317 acpi_platform_reset(void)
318 {
319 #ifdef EFI_RUNTIME
320 if (arm_efirt_reset(EFI_RESET_COLD) == 0)
321 return;
322 #endif
323 if (psci_available())
324 psci_system_reset();
325 }
326
327 static u_int
328 acpi_platform_uart_freq(void)
329 {
330 return 0;
331 }
332
333 static const struct arm_platform acpi_platform = {
334 .ap_devmap = acpi_platform_devmap,
335 .ap_bootstrap = acpi_platform_bootstrap,
336 .ap_startup = acpi_platform_startup,
337 .ap_init_attach_args = acpi_platform_init_attach_args,
338 .ap_device_register = acpi_platform_device_register,
339 .ap_reset = acpi_platform_reset,
340 .ap_delay = gtmr_delay,
341 .ap_uart_freq = acpi_platform_uart_freq,
342 };
343
344 ARM_PLATFORM(acpi, "netbsd,generic-acpi", &acpi_platform);
345