1// SPDX-License-Identifier: GPL-2.0
2/*
3 *  Copyright (C) 2020 Loongson Technology Corporation Limited
4 */
5#include <linux/compiler.h>
6#include <linux/delay.h>
7#include <linux/init.h>
8#include <linux/interrupt.h>
9#include <linux/irqchip.h>
10#include <linux/irqdomain.h>
11#include <linux/mm.h>
12#include <linux/module.h>
13#include <linux/stddef.h>
14#include <asm/irq.h>
15#include <asm/numa.h>
16#include <asm/setup.h>
17#include <asm/loongarchregs.h>
18#include <loongson.h>
19
20struct acpi_madt_lio_pic *acpi_liointc;
21struct acpi_madt_eio_pic *acpi_eiointc[MAX_IO_PICS];
22
23struct acpi_madt_ht_pic *acpi_htintc;
24struct acpi_madt_lpc_pic *acpi_pchlpc;
25struct acpi_madt_msi_pic *acpi_pchmsi[MAX_IO_PICS];
26struct acpi_madt_bio_pic *acpi_pchpic[MAX_IO_PICS];
27
28struct irq_domain *cpu_domain;
29struct irq_domain *liointc_domain;
30struct irq_domain *pch_lpc_domain;
31struct irq_domain *pch_msi_domain[MAX_IO_PICS];
32struct irq_domain *pch_pic_domain[MAX_IO_PICS];
33
34int find_pch_pic(u32 gsi)
35{
36	int i, start, end;
37
38	/* Find the PCH_PIC that manages this GSI. */
39	for(i = 0; i < loongson_sysconf.nr_io_pics; i++) {
40		struct acpi_madt_bio_pic *irq_cfg = acpi_pchpic[i];
41
42		start = irq_cfg->gsi_base;
43		end   = irq_cfg->gsi_base + irq_cfg->size;
44		if (gsi >= start && gsi < end)
45			return i;
46	}
47
48	printk(KERN_ERR "ERROR: Unable to locate PCH_PIC for GSI %d\n", gsi);
49	return -1;
50}
51
52void __init setup_IRQ(void)
53{
54	int i;
55	struct irq_domain *parent_domain;
56
57	if (!acpi_eiointc[0])
58		cpu_data[0].options &= ~LOONGARCH_CPU_EXTIOI;
59
60	cpu_domain = loongarch_cpu_irq_init();
61	liointc_domain = liointc_acpi_init(cpu_domain, acpi_liointc);
62
63	if (cpu_has_extioi) {
64		pr_info("Using EIOINTC interrupt mode\n");
65		for(i = 0; i < loongson_sysconf.nr_io_pics; i++) {
66			parent_domain = eiointc_acpi_init(cpu_domain, acpi_eiointc[i]);
67			pch_pic_domain[i] = pch_pic_acpi_init(parent_domain, acpi_pchpic[i]);
68			pch_msi_domain[i] = pch_msi_acpi_init(parent_domain, acpi_pchmsi[i]);
69		}
70	} else {
71		pr_info("Using HTVECINTC interrupt mode\n");
72		parent_domain = htvec_acpi_init(liointc_domain, acpi_htintc);
73		pch_pic_domain[0] = pch_pic_acpi_init(parent_domain, acpi_pchpic[0]);
74		pch_msi_domain[0] = pch_msi_acpi_init(parent_domain, acpi_pchmsi[0]);
75	}
76
77	irq_set_default_host(pch_pic_domain[0]);
78	pch_lpc_domain = pch_lpc_acpi_init(pch_pic_domain[0], acpi_pchlpc);
79}
80
81void __init arch_init_irq(void)
82{
83	int r, ipi_irq;
84	static int ipi_dummy_dev;
85
86	clear_csr_ecfg(ECFG0_IM);
87	clear_csr_estat(ESTATF_IP);
88
89	setup_IRQ();
90#ifdef CONFIG_SMP
91	ipi_irq = get_ipi_irq();
92	irq_set_percpu_devid(ipi_irq);
93	r = request_percpu_irq(ipi_irq, loongson3_ipi_interrupt, "IPI", &ipi_dummy_dev);
94	if (r < 0)
95		panic("IPI IRQ request failed\n");
96#endif
97
98	set_csr_ecfg(ECFGF_IP0 | ECFGF_IP1 | ECFGF_IP2 | ECFGF_IPI | ECFGF_PMC);
99}
100