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