1628c3bb4SHuacai Chen // SPDX-License-Identifier: GPL-2.0 2628c3bb4SHuacai Chen /* 3628c3bb4SHuacai Chen * acpi.c - Architecture-Specific Low-Level ACPI Boot Support 4628c3bb4SHuacai Chen * 5628c3bb4SHuacai Chen * Author: Jianmin Lv <lvjianmin@loongson.cn> 6628c3bb4SHuacai Chen * Huacai Chen <chenhuacai@loongson.cn> 7628c3bb4SHuacai Chen * Copyright (C) 2020-2022 Loongson Technology Corporation Limited 8628c3bb4SHuacai Chen */ 9628c3bb4SHuacai Chen 10628c3bb4SHuacai Chen #include <linux/init.h> 11628c3bb4SHuacai Chen #include <linux/acpi.h> 12628c3bb4SHuacai Chen #include <linux/irq.h> 13628c3bb4SHuacai Chen #include <linux/irqdomain.h> 14628c3bb4SHuacai Chen #include <linux/memblock.h> 15628c3bb4SHuacai Chen #include <linux/serial_core.h> 16628c3bb4SHuacai Chen #include <asm/io.h> 17628c3bb4SHuacai Chen #include <asm/loongson.h> 18628c3bb4SHuacai Chen 19628c3bb4SHuacai Chen int acpi_disabled; 20628c3bb4SHuacai Chen EXPORT_SYMBOL(acpi_disabled); 21628c3bb4SHuacai Chen int acpi_noirq; 22628c3bb4SHuacai Chen int acpi_pci_disabled; 23628c3bb4SHuacai Chen EXPORT_SYMBOL(acpi_pci_disabled); 24628c3bb4SHuacai Chen int acpi_strict = 1; /* We have no workarounds on LoongArch */ 25628c3bb4SHuacai Chen int num_processors; 26628c3bb4SHuacai Chen int disabled_cpus; 27628c3bb4SHuacai Chen enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_PLATFORM; 28628c3bb4SHuacai Chen 29628c3bb4SHuacai Chen u64 acpi_saved_sp; 30628c3bb4SHuacai Chen 31628c3bb4SHuacai Chen #define MAX_CORE_PIC 256 32628c3bb4SHuacai Chen 33628c3bb4SHuacai Chen #define PREFIX "ACPI: " 34628c3bb4SHuacai Chen 35628c3bb4SHuacai Chen int acpi_gsi_to_irq(u32 gsi, unsigned int *irqp) 36628c3bb4SHuacai Chen { 37628c3bb4SHuacai Chen if (irqp != NULL) 38628c3bb4SHuacai Chen *irqp = acpi_register_gsi(NULL, gsi, -1, -1); 39628c3bb4SHuacai Chen return (*irqp >= 0) ? 0 : -EINVAL; 40628c3bb4SHuacai Chen } 41628c3bb4SHuacai Chen EXPORT_SYMBOL_GPL(acpi_gsi_to_irq); 42628c3bb4SHuacai Chen 43628c3bb4SHuacai Chen int acpi_isa_irq_to_gsi(unsigned int isa_irq, u32 *gsi) 44628c3bb4SHuacai Chen { 45628c3bb4SHuacai Chen if (gsi) 46628c3bb4SHuacai Chen *gsi = isa_irq; 47628c3bb4SHuacai Chen return 0; 48628c3bb4SHuacai Chen } 49628c3bb4SHuacai Chen 50628c3bb4SHuacai Chen /* 51628c3bb4SHuacai Chen * success: return IRQ number (>=0) 52628c3bb4SHuacai Chen * failure: return < 0 53628c3bb4SHuacai Chen */ 54628c3bb4SHuacai Chen int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity) 55628c3bb4SHuacai Chen { 56628c3bb4SHuacai Chen struct irq_fwspec fwspec; 57628c3bb4SHuacai Chen 58628c3bb4SHuacai Chen switch (gsi) { 59628c3bb4SHuacai Chen case GSI_MIN_CPU_IRQ ... GSI_MAX_CPU_IRQ: 60628c3bb4SHuacai Chen fwspec.fwnode = liointc_domain->fwnode; 61628c3bb4SHuacai Chen fwspec.param[0] = gsi - GSI_MIN_CPU_IRQ; 62628c3bb4SHuacai Chen fwspec.param_count = 1; 63628c3bb4SHuacai Chen 64628c3bb4SHuacai Chen return irq_create_fwspec_mapping(&fwspec); 65628c3bb4SHuacai Chen 66628c3bb4SHuacai Chen case GSI_MIN_LPC_IRQ ... GSI_MAX_LPC_IRQ: 67628c3bb4SHuacai Chen if (!pch_lpc_domain) 68628c3bb4SHuacai Chen return -EINVAL; 69628c3bb4SHuacai Chen 70628c3bb4SHuacai Chen fwspec.fwnode = pch_lpc_domain->fwnode; 71628c3bb4SHuacai Chen fwspec.param[0] = gsi - GSI_MIN_LPC_IRQ; 72628c3bb4SHuacai Chen fwspec.param[1] = acpi_dev_get_irq_type(trigger, polarity); 73628c3bb4SHuacai Chen fwspec.param_count = 2; 74628c3bb4SHuacai Chen 75628c3bb4SHuacai Chen return irq_create_fwspec_mapping(&fwspec); 76628c3bb4SHuacai Chen 77628c3bb4SHuacai Chen case GSI_MIN_PCH_IRQ ... GSI_MAX_PCH_IRQ: 78628c3bb4SHuacai Chen if (!pch_pic_domain[0]) 79628c3bb4SHuacai Chen return -EINVAL; 80628c3bb4SHuacai Chen 81628c3bb4SHuacai Chen fwspec.fwnode = pch_pic_domain[0]->fwnode; 82628c3bb4SHuacai Chen fwspec.param[0] = gsi - GSI_MIN_PCH_IRQ; 83628c3bb4SHuacai Chen fwspec.param[1] = IRQ_TYPE_LEVEL_HIGH; 84628c3bb4SHuacai Chen fwspec.param_count = 2; 85628c3bb4SHuacai Chen 86628c3bb4SHuacai Chen return irq_create_fwspec_mapping(&fwspec); 87628c3bb4SHuacai Chen } 88628c3bb4SHuacai Chen 89628c3bb4SHuacai Chen return -EINVAL; 90628c3bb4SHuacai Chen } 91628c3bb4SHuacai Chen EXPORT_SYMBOL_GPL(acpi_register_gsi); 92628c3bb4SHuacai Chen 93628c3bb4SHuacai Chen void acpi_unregister_gsi(u32 gsi) 94628c3bb4SHuacai Chen { 95628c3bb4SHuacai Chen 96628c3bb4SHuacai Chen } 97628c3bb4SHuacai Chen EXPORT_SYMBOL_GPL(acpi_unregister_gsi); 98628c3bb4SHuacai Chen 99628c3bb4SHuacai Chen void __init __iomem * __acpi_map_table(unsigned long phys, unsigned long size) 100628c3bb4SHuacai Chen { 101628c3bb4SHuacai Chen 102628c3bb4SHuacai Chen if (!phys || !size) 103628c3bb4SHuacai Chen return NULL; 104628c3bb4SHuacai Chen 105628c3bb4SHuacai Chen return early_memremap(phys, size); 106628c3bb4SHuacai Chen } 107628c3bb4SHuacai Chen void __init __acpi_unmap_table(void __iomem *map, unsigned long size) 108628c3bb4SHuacai Chen { 109628c3bb4SHuacai Chen if (!map || !size) 110628c3bb4SHuacai Chen return; 111628c3bb4SHuacai Chen 112628c3bb4SHuacai Chen early_memunmap(map, size); 113628c3bb4SHuacai Chen } 114628c3bb4SHuacai Chen 115628c3bb4SHuacai Chen void __init __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size) 116628c3bb4SHuacai Chen { 117628c3bb4SHuacai Chen if (!memblock_is_memory(phys)) 118628c3bb4SHuacai Chen return ioremap(phys, size); 119628c3bb4SHuacai Chen else 120628c3bb4SHuacai Chen return ioremap_cache(phys, size); 121628c3bb4SHuacai Chen } 122628c3bb4SHuacai Chen 123628c3bb4SHuacai Chen void __init acpi_boot_table_init(void) 124628c3bb4SHuacai Chen { 125628c3bb4SHuacai Chen /* 126628c3bb4SHuacai Chen * If acpi_disabled, bail out 127628c3bb4SHuacai Chen */ 128628c3bb4SHuacai Chen if (acpi_disabled) 129628c3bb4SHuacai Chen return; 130628c3bb4SHuacai Chen 131628c3bb4SHuacai Chen /* 132628c3bb4SHuacai Chen * Initialize the ACPI boot-time table parser. 133628c3bb4SHuacai Chen */ 134628c3bb4SHuacai Chen if (acpi_table_init()) { 135628c3bb4SHuacai Chen disable_acpi(); 136628c3bb4SHuacai Chen return; 137628c3bb4SHuacai Chen } 138628c3bb4SHuacai Chen } 139628c3bb4SHuacai Chen 140*46859ac8SHuacai Chen static int set_processor_mask(u32 id, u32 flags) 141*46859ac8SHuacai Chen { 142*46859ac8SHuacai Chen 143*46859ac8SHuacai Chen int cpu, cpuid = id; 144*46859ac8SHuacai Chen 145*46859ac8SHuacai Chen if (num_processors >= nr_cpu_ids) { 146*46859ac8SHuacai Chen pr_warn(PREFIX "nr_cpus/possible_cpus limit of %i reached." 147*46859ac8SHuacai Chen " processor 0x%x ignored.\n", nr_cpu_ids, cpuid); 148*46859ac8SHuacai Chen 149*46859ac8SHuacai Chen return -ENODEV; 150*46859ac8SHuacai Chen 151*46859ac8SHuacai Chen } 152*46859ac8SHuacai Chen if (cpuid == loongson_sysconf.boot_cpu_id) 153*46859ac8SHuacai Chen cpu = 0; 154*46859ac8SHuacai Chen else 155*46859ac8SHuacai Chen cpu = cpumask_next_zero(-1, cpu_present_mask); 156*46859ac8SHuacai Chen 157*46859ac8SHuacai Chen if (flags & ACPI_MADT_ENABLED) { 158*46859ac8SHuacai Chen num_processors++; 159*46859ac8SHuacai Chen set_cpu_possible(cpu, true); 160*46859ac8SHuacai Chen set_cpu_present(cpu, true); 161*46859ac8SHuacai Chen __cpu_number_map[cpuid] = cpu; 162*46859ac8SHuacai Chen __cpu_logical_map[cpu] = cpuid; 163*46859ac8SHuacai Chen } else 164*46859ac8SHuacai Chen disabled_cpus++; 165*46859ac8SHuacai Chen 166*46859ac8SHuacai Chen return cpu; 167*46859ac8SHuacai Chen } 168*46859ac8SHuacai Chen 169628c3bb4SHuacai Chen static void __init acpi_process_madt(void) 170628c3bb4SHuacai Chen { 171*46859ac8SHuacai Chen int i; 172*46859ac8SHuacai Chen 173*46859ac8SHuacai Chen for (i = 0; i < NR_CPUS; i++) { 174*46859ac8SHuacai Chen __cpu_number_map[i] = -1; 175*46859ac8SHuacai Chen __cpu_logical_map[i] = -1; 176*46859ac8SHuacai Chen } 177*46859ac8SHuacai Chen 178628c3bb4SHuacai Chen loongson_sysconf.nr_cpus = num_processors; 179628c3bb4SHuacai Chen } 180628c3bb4SHuacai Chen 181628c3bb4SHuacai Chen int __init acpi_boot_init(void) 182628c3bb4SHuacai Chen { 183628c3bb4SHuacai Chen /* 184628c3bb4SHuacai Chen * If acpi_disabled, bail out 185628c3bb4SHuacai Chen */ 186628c3bb4SHuacai Chen if (acpi_disabled) 187628c3bb4SHuacai Chen return -1; 188628c3bb4SHuacai Chen 189628c3bb4SHuacai Chen loongson_sysconf.boot_cpu_id = read_csr_cpuid(); 190628c3bb4SHuacai Chen 191628c3bb4SHuacai Chen /* 192628c3bb4SHuacai Chen * Process the Multiple APIC Description Table (MADT), if present 193628c3bb4SHuacai Chen */ 194628c3bb4SHuacai Chen acpi_process_madt(); 195628c3bb4SHuacai Chen 196628c3bb4SHuacai Chen /* Do not enable ACPI SPCR console by default */ 197628c3bb4SHuacai Chen acpi_parse_spcr(earlycon_acpi_spcr_enable, false); 198628c3bb4SHuacai Chen 199628c3bb4SHuacai Chen return 0; 200628c3bb4SHuacai Chen } 201628c3bb4SHuacai Chen 202628c3bb4SHuacai Chen void __init arch_reserve_mem_area(acpi_physical_address addr, size_t size) 203628c3bb4SHuacai Chen { 204628c3bb4SHuacai Chen memblock_reserve(addr, size); 205628c3bb4SHuacai Chen } 206*46859ac8SHuacai Chen 207*46859ac8SHuacai Chen #ifdef CONFIG_ACPI_HOTPLUG_CPU 208*46859ac8SHuacai Chen 209*46859ac8SHuacai Chen #include <acpi/processor.h> 210*46859ac8SHuacai Chen 211*46859ac8SHuacai Chen int acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, u32 acpi_id, int *pcpu) 212*46859ac8SHuacai Chen { 213*46859ac8SHuacai Chen int cpu; 214*46859ac8SHuacai Chen 215*46859ac8SHuacai Chen cpu = set_processor_mask(physid, ACPI_MADT_ENABLED); 216*46859ac8SHuacai Chen if (cpu < 0) { 217*46859ac8SHuacai Chen pr_info(PREFIX "Unable to map lapic to logical cpu number\n"); 218*46859ac8SHuacai Chen return cpu; 219*46859ac8SHuacai Chen } 220*46859ac8SHuacai Chen 221*46859ac8SHuacai Chen *pcpu = cpu; 222*46859ac8SHuacai Chen 223*46859ac8SHuacai Chen return 0; 224*46859ac8SHuacai Chen } 225*46859ac8SHuacai Chen EXPORT_SYMBOL(acpi_map_cpu); 226*46859ac8SHuacai Chen 227*46859ac8SHuacai Chen int acpi_unmap_cpu(int cpu) 228*46859ac8SHuacai Chen { 229*46859ac8SHuacai Chen set_cpu_present(cpu, false); 230*46859ac8SHuacai Chen num_processors--; 231*46859ac8SHuacai Chen 232*46859ac8SHuacai Chen pr_info("cpu%d hot remove!\n", cpu); 233*46859ac8SHuacai Chen 234*46859ac8SHuacai Chen return 0; 235*46859ac8SHuacai Chen } 236*46859ac8SHuacai Chen EXPORT_SYMBOL(acpi_unmap_cpu); 237*46859ac8SHuacai Chen 238*46859ac8SHuacai Chen #endif /* CONFIG_ACPI_HOTPLUG_CPU */ 239