Commit | Line | Data |
---|---|---|
37655163 AS |
1 | /* |
2 | * ARM64 Specific Low-Level ACPI Boot Support | |
3 | * | |
4 | * Copyright (C) 2013-2014, Linaro Ltd. | |
5 | * Author: Al Stone <al.stone@linaro.org> | |
6 | * Author: Graeme Gregory <graeme.gregory@linaro.org> | |
7 | * Author: Hanjun Guo <hanjun.guo@linaro.org> | |
8 | * Author: Tomasz Nowicki <tomasz.nowicki@linaro.org> | |
9 | * Author: Naresh Bhat <naresh.bhat@linaro.org> | |
10 | * | |
11 | * This program is free software; you can redistribute it and/or modify | |
12 | * it under the terms of the GNU General Public License version 2 as | |
13 | * published by the Free Software Foundation. | |
14 | */ | |
15 | ||
16 | #define pr_fmt(fmt) "ACPI: " fmt | |
17 | ||
18 | #include <linux/acpi.h> | |
37655163 | 19 | #include <linux/cpumask.h> |
09ffcb0d | 20 | #include <linux/efi.h> |
6e7300cf | 21 | #include <linux/efi-bgrt.h> |
37655163 AS |
22 | #include <linux/init.h> |
23 | #include <linux/irq.h> | |
24 | #include <linux/irqdomain.h> | |
25 | #include <linux/memblock.h> | |
b10d79f7 | 26 | #include <linux/of_fdt.h> |
37655163 | 27 | #include <linux/smp.h> |
888125a7 | 28 | #include <linux/serial_core.h> |
37655163 | 29 | |
fccb9a81 HG |
30 | #include <asm/cputype.h> |
31 | #include <asm/cpu_ops.h> | |
09ffcb0d | 32 | #include <asm/pgtable.h> |
fccb9a81 HG |
33 | #include <asm/smp_plat.h> |
34 | ||
b10d79f7 AS |
35 | int acpi_noirq = 1; /* skip ACPI IRQ initialization */ |
36 | int acpi_disabled = 1; | |
37655163 AS |
37 | EXPORT_SYMBOL(acpi_disabled); |
38 | ||
b10d79f7 | 39 | int acpi_pci_disabled = 1; /* skip ACPI PCI scan and IRQ initialization */ |
37655163 AS |
40 | EXPORT_SYMBOL(acpi_pci_disabled); |
41 | ||
b10d79f7 | 42 | static bool param_acpi_off __initdata; |
6a1f5471 | 43 | static bool param_acpi_on __initdata; |
fb094eb1 | 44 | static bool param_acpi_force __initdata; |
b10d79f7 AS |
45 | |
46 | static int __init parse_acpi(char *arg) | |
47 | { | |
48 | if (!arg) | |
49 | return -EINVAL; | |
50 | ||
51 | /* "acpi=off" disables both ACPI table parsing and interpreter */ | |
52 | if (strcmp(arg, "off") == 0) | |
53 | param_acpi_off = true; | |
6a1f5471 AB |
54 | else if (strcmp(arg, "on") == 0) /* prefer ACPI over DT */ |
55 | param_acpi_on = true; | |
b10d79f7 AS |
56 | else if (strcmp(arg, "force") == 0) /* force ACPI to be enabled */ |
57 | param_acpi_force = true; | |
58 | else | |
59 | return -EINVAL; /* Core will print when we return error */ | |
60 | ||
61 | return 0; | |
62 | } | |
63 | early_param("acpi", parse_acpi); | |
64 | ||
65 | static int __init dt_scan_depth1_nodes(unsigned long node, | |
66 | const char *uname, int depth, | |
67 | void *data) | |
68 | { | |
69 | /* | |
9981293f MR |
70 | * Ignore anything not directly under the root node; we'll |
71 | * catch its parent instead. | |
b10d79f7 | 72 | */ |
9981293f MR |
73 | if (depth != 1) |
74 | return 0; | |
2366c7fd | 75 | |
9981293f MR |
76 | if (strcmp(uname, "chosen") == 0) |
77 | return 0; | |
78 | ||
79 | if (strcmp(uname, "hypervisor") == 0 && | |
80 | of_flat_dt_is_compatible(node, "xen,xen")) | |
81 | return 0; | |
82 | ||
83 | /* | |
84 | * This node at depth 1 is neither a chosen node nor a xen node, | |
85 | * which we do not expect. | |
86 | */ | |
87 | return 1; | |
b10d79f7 AS |
88 | } |
89 | ||
37655163 AS |
90 | /* |
91 | * __acpi_map_table() will be called before page_init(), so early_ioremap() | |
92 | * or early_memremap() should be called here to for ACPI table mapping. | |
93 | */ | |
6c9a58e8 | 94 | void __init __iomem *__acpi_map_table(unsigned long phys, unsigned long size) |
37655163 AS |
95 | { |
96 | if (!size) | |
97 | return NULL; | |
98 | ||
99 | return early_memremap(phys, size); | |
100 | } | |
101 | ||
6c9a58e8 | 102 | void __init __acpi_unmap_table(void __iomem *map, unsigned long size) |
37655163 AS |
103 | { |
104 | if (!map || !size) | |
105 | return; | |
106 | ||
107 | early_memunmap(map, size); | |
108 | } | |
109 | ||
c5a13305 MR |
110 | bool __init acpi_psci_present(void) |
111 | { | |
112 | return acpi_gbl_FADT.arm_boot_flags & ACPI_FADT_PSCI_COMPLIANT; | |
113 | } | |
114 | ||
115 | /* Whether HVC must be used instead of SMC as the PSCI conduit */ | |
fa31ab77 | 116 | bool acpi_psci_use_hvc(void) |
c5a13305 MR |
117 | { |
118 | return acpi_gbl_FADT.arm_boot_flags & ACPI_FADT_PSCI_USE_HVC; | |
119 | } | |
120 | ||
54971e43 LP |
121 | /* |
122 | * acpi_fadt_sanity_check() - Check FADT presence and carry out sanity | |
123 | * checks on it | |
124 | * | |
125 | * Return 0 on success, <0 on failure | |
126 | */ | |
127 | static int __init acpi_fadt_sanity_check(void) | |
37655163 | 128 | { |
54971e43 LP |
129 | struct acpi_table_header *table; |
130 | struct acpi_table_fadt *fadt; | |
131 | acpi_status status; | |
54971e43 LP |
132 | int ret = 0; |
133 | ||
134 | /* | |
135 | * FADT is required on arm64; retrieve it to check its presence | |
136 | * and carry out revision and ACPI HW reduced compliancy tests | |
137 | */ | |
6b11d1d6 | 138 | status = acpi_get_table(ACPI_SIG_FADT, 0, &table); |
54971e43 LP |
139 | if (ACPI_FAILURE(status)) { |
140 | const char *msg = acpi_format_exception(status); | |
141 | ||
142 | pr_err("Failed to get FADT table, %s\n", msg); | |
143 | return -ENODEV; | |
144 | } | |
145 | ||
146 | fadt = (struct acpi_table_fadt *)table; | |
37655163 AS |
147 | |
148 | /* | |
149 | * Revision in table header is the FADT Major revision, and there | |
150 | * is a minor revision of FADT which was introduced by ACPI 5.1, | |
151 | * we only deal with ACPI 5.1 or newer revision to get GIC and SMP | |
54971e43 | 152 | * boot protocol configuration data. |
37655163 | 153 | */ |
54971e43 LP |
154 | if (table->revision < 5 || |
155 | (table->revision == 5 && fadt->minor_revision < 1)) { | |
156 | pr_err("Unsupported FADT revision %d.%d, should be 5.1+\n", | |
157 | table->revision, fadt->minor_revision); | |
158 | ret = -EINVAL; | |
159 | goto out; | |
fccb9a81 | 160 | } |
37655163 | 161 | |
54971e43 LP |
162 | if (!(fadt->flags & ACPI_FADT_HW_REDUCED)) { |
163 | pr_err("FADT not ACPI hardware reduced compliant\n"); | |
164 | ret = -EINVAL; | |
165 | } | |
37655163 | 166 | |
54971e43 LP |
167 | out: |
168 | /* | |
6b11d1d6 | 169 | * acpi_get_table() creates FADT table mapping that |
54971e43 LP |
170 | * should be released after parsing and before resuming boot |
171 | */ | |
6b11d1d6 | 172 | acpi_put_table(table); |
54971e43 | 173 | return ret; |
37655163 AS |
174 | } |
175 | ||
176 | /* | |
177 | * acpi_boot_table_init() called from setup_arch(), always. | |
178 | * 1. find RSDP and get its address, and then find XSDT | |
179 | * 2. extract all tables and checksums them all | |
180 | * 3. check ACPI FADT revision | |
54971e43 | 181 | * 4. check ACPI FADT HW reduced flag |
37655163 AS |
182 | * |
183 | * We can parse ACPI boot-time tables such as MADT after | |
184 | * this function is called. | |
54971e43 | 185 | * |
fb094eb1 LP |
186 | * On return ACPI is enabled if either: |
187 | * | |
188 | * - ACPI tables are initialized and sanity checks passed | |
189 | * - acpi=force was passed in the command line and ACPI was not disabled | |
190 | * explicitly through acpi=off command line parameter | |
191 | * | |
192 | * ACPI is disabled on function return otherwise | |
37655163 AS |
193 | */ |
194 | void __init acpi_boot_table_init(void) | |
195 | { | |
b10d79f7 AS |
196 | /* |
197 | * Enable ACPI instead of device tree unless | |
198 | * - ACPI has been disabled explicitly (acpi=off), or | |
2366c7fd SZ |
199 | * - the device tree is not empty (it has more than just a /chosen node, |
200 | * and a /hypervisor node when running on Xen) | |
6a1f5471 | 201 | * and ACPI has not been [force] enabled (acpi=on|force) |
b10d79f7 AS |
202 | */ |
203 | if (param_acpi_off || | |
6a1f5471 AB |
204 | (!param_acpi_on && !param_acpi_force && |
205 | of_scan_flat_dt(dt_scan_depth1_nodes, NULL))) | |
888125a7 | 206 | goto done; |
37655163 | 207 | |
54971e43 LP |
208 | /* |
209 | * ACPI is disabled at this point. Enable it in order to parse | |
210 | * the ACPI tables and carry out sanity checks | |
211 | */ | |
b10d79f7 AS |
212 | enable_acpi(); |
213 | ||
54971e43 LP |
214 | /* |
215 | * If ACPI tables are initialized and FADT sanity checks passed, | |
216 | * leave ACPI enabled and carry on booting; otherwise disable ACPI | |
217 | * on initialization error. | |
fb094eb1 LP |
218 | * If acpi=force was passed on the command line it forces ACPI |
219 | * to be enabled even if its initialization failed. | |
54971e43 LP |
220 | */ |
221 | if (acpi_table_init() || acpi_fadt_sanity_check()) { | |
222 | pr_err("Failed to init ACPI tables\n"); | |
fb094eb1 LP |
223 | if (!param_acpi_force) |
224 | disable_acpi(); | |
37655163 | 225 | } |
888125a7 AM |
226 | |
227 | done: | |
228 | if (acpi_disabled) { | |
0231d000 | 229 | if (earlycon_acpi_spcr_enable) |
888125a7 AM |
230 | early_init_dt_scan_chosen_stdout(); |
231 | } else { | |
0231d000 | 232 | acpi_parse_spcr(earlycon_acpi_spcr_enable, true); |
6e7300cf BS |
233 | if (IS_ENABLED(CONFIG_ACPI_BGRT)) |
234 | acpi_table_parse(ACPI_SIG_BGRT, acpi_parse_bgrt); | |
888125a7 | 235 | } |
37655163 | 236 | } |
d60fc389 | 237 | |
09ffcb0d | 238 | pgprot_t __acpi_get_mem_attribute(phys_addr_t addr) |
89e44b51 JZZ |
239 | { |
240 | /* | |
241 | * According to "Table 8 Map: EFI memory types to AArch64 memory | |
242 | * types" of UEFI 2.5 section 2.3.6.1, each EFI memory type is | |
243 | * mapped to a corresponding MAIR attribute encoding. | |
244 | * The EFI memory attribute advises all possible capabilities | |
245 | * of a memory region. We use the most efficient capability. | |
246 | */ | |
247 | ||
248 | u64 attr; | |
249 | ||
250 | attr = efi_mem_attributes(addr); | |
251 | if (attr & EFI_MEMORY_WB) | |
252 | return PAGE_KERNEL; | |
253 | if (attr & EFI_MEMORY_WT) | |
254 | return __pgprot(PROT_NORMAL_WT); | |
255 | if (attr & EFI_MEMORY_WC) | |
256 | return __pgprot(PROT_NORMAL_NC); | |
257 | return __pgprot(PROT_DEVICE_nGnRnE); | |
258 | } |