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> 19 #include <linux/bootmem.h> 20 #include <linux/cpumask.h> 21 #include <linux/init.h> 22 #include <linux/irq.h> 23 #include <linux/irqdomain.h> 24 #include <linux/memblock.h> 25 #include <linux/of_fdt.h> 26 #include <linux/smp.h> 27 28 int acpi_noirq = 1; /* skip ACPI IRQ initialization */ 29 int acpi_disabled = 1; 30 EXPORT_SYMBOL(acpi_disabled); 31 32 int acpi_pci_disabled = 1; /* skip ACPI PCI scan and IRQ initialization */ 33 EXPORT_SYMBOL(acpi_pci_disabled); 34 35 static bool param_acpi_off __initdata; 36 static bool param_acpi_force __initdata; 37 38 static int __init parse_acpi(char *arg) 39 { 40 if (!arg) 41 return -EINVAL; 42 43 /* "acpi=off" disables both ACPI table parsing and interpreter */ 44 if (strcmp(arg, "off") == 0) 45 param_acpi_off = true; 46 else if (strcmp(arg, "force") == 0) /* force ACPI to be enabled */ 47 param_acpi_force = true; 48 else 49 return -EINVAL; /* Core will print when we return error */ 50 51 return 0; 52 } 53 early_param("acpi", parse_acpi); 54 55 static int __init dt_scan_depth1_nodes(unsigned long node, 56 const char *uname, int depth, 57 void *data) 58 { 59 /* 60 * Return 1 as soon as we encounter a node at depth 1 that is 61 * not the /chosen node. 62 */ 63 if (depth == 1 && (strcmp(uname, "chosen") != 0)) 64 return 1; 65 return 0; 66 } 67 68 /* 69 * __acpi_map_table() will be called before page_init(), so early_ioremap() 70 * or early_memremap() should be called here to for ACPI table mapping. 71 */ 72 char *__init __acpi_map_table(unsigned long phys, unsigned long size) 73 { 74 if (!size) 75 return NULL; 76 77 return early_memremap(phys, size); 78 } 79 80 void __init __acpi_unmap_table(char *map, unsigned long size) 81 { 82 if (!map || !size) 83 return; 84 85 early_memunmap(map, size); 86 } 87 88 static int __init acpi_parse_fadt(struct acpi_table_header *table) 89 { 90 struct acpi_table_fadt *fadt = (struct acpi_table_fadt *)table; 91 92 /* 93 * Revision in table header is the FADT Major revision, and there 94 * is a minor revision of FADT which was introduced by ACPI 5.1, 95 * we only deal with ACPI 5.1 or newer revision to get GIC and SMP 96 * boot protocol configuration data, or we will disable ACPI. 97 */ 98 if (table->revision > 5 || 99 (table->revision == 5 && fadt->minor_revision >= 1)) 100 return 0; 101 102 pr_warn("Unsupported FADT revision %d.%d, should be 5.1+, will disable ACPI\n", 103 table->revision, fadt->minor_revision); 104 disable_acpi(); 105 106 return -EINVAL; 107 } 108 109 /* 110 * acpi_boot_table_init() called from setup_arch(), always. 111 * 1. find RSDP and get its address, and then find XSDT 112 * 2. extract all tables and checksums them all 113 * 3. check ACPI FADT revision 114 * 115 * We can parse ACPI boot-time tables such as MADT after 116 * this function is called. 117 */ 118 void __init acpi_boot_table_init(void) 119 { 120 /* 121 * Enable ACPI instead of device tree unless 122 * - ACPI has been disabled explicitly (acpi=off), or 123 * - the device tree is not empty (it has more than just a /chosen node) 124 * and ACPI has not been force enabled (acpi=force) 125 */ 126 if (param_acpi_off || 127 (!param_acpi_force && of_scan_flat_dt(dt_scan_depth1_nodes, NULL))) 128 return; 129 130 enable_acpi(); 131 132 /* Initialize the ACPI boot-time table parser. */ 133 if (acpi_table_init()) { 134 disable_acpi(); 135 return; 136 } 137 138 if (acpi_table_parse(ACPI_SIG_FADT, acpi_parse_fadt)) { 139 /* disable ACPI if no FADT is found */ 140 disable_acpi(); 141 pr_err("Can't find FADT\n"); 142 } 143 } 144