xref: /openbmc/linux/arch/loongarch/kernel/acpi.c (revision 46859ac8af52ae599e1b51992ddef3eb43f295fc)
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