1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) 2020 Loongson Technologies, Inc. 4 */ 5 6#include <linux/init.h> 7#include <linux/interrupt.h> 8#include <linux/kernel.h> 9#include <linux/irq.h> 10#include <linux/irqchip.h> 11#include <linux/irqdomain.h> 12 13#include <asm/setup.h> 14#include <asm/loongarchregs.h> 15 16static struct irq_domain *irq_domain; 17 18static void mask_loongarch_irq(struct irq_data *d) 19{ 20 clear_csr_ecfg(ECFGF(d->hwirq)); 21} 22 23static void unmask_loongarch_irq(struct irq_data *d) 24{ 25 set_csr_ecfg(ECFGF(d->hwirq)); 26} 27 28static struct irq_chip cpu_irq_controller = { 29 .name = "LoongArch", 30 .irq_mask = mask_loongarch_irq, 31 .irq_unmask = unmask_loongarch_irq, 32}; 33 34static void handle_cpu_irq(struct pt_regs *regs) 35{ 36 int hwirq; 37 unsigned int estat = read_csr_estat() & CSR_ESTAT_IS; 38 39 while ((hwirq = ffs(estat))) { 40 estat &= ~BIT(hwirq - 1); 41 handle_domain_irq(irq_domain, hwirq - 1, regs); 42 } 43} 44 45int get_ipi_irq(void) 46{ 47 return irq_create_mapping(irq_domain, INT_IPI); 48} 49 50int get_pmc_irq(void) 51{ 52 return irq_create_mapping(irq_domain, INT_PCOV); 53} 54 55int get_timer_irq(void) 56{ 57 return irq_create_mapping(irq_domain, INT_TI); 58} 59 60static int loongarch_cpu_intc_map(struct irq_domain *d, unsigned int irq, 61 irq_hw_number_t hwirq) 62{ 63 irq_set_noprobe(irq); 64 irq_set_chip_and_handler(irq, &cpu_irq_controller, handle_percpu_irq); 65 66 return 0; 67} 68 69static const struct irq_domain_ops loongarch_cpu_intc_irq_domain_ops = { 70 .map = loongarch_cpu_intc_map, 71 .xlate = irq_domain_xlate_onecell, 72}; 73 74struct irq_domain * __init loongarch_cpu_irq_init(void) 75{ 76 struct fwnode_handle *domain_handle; 77 78 /* Mask interrupts. */ 79 clear_csr_ecfg(ECFG0_IM); 80 clear_csr_estat(ESTATF_IP); 81 82 domain_handle = irq_domain_alloc_fwnode(NULL); 83 irq_domain = irq_domain_create_linear(domain_handle, EXCCODE_INT_NUM, 84 &loongarch_cpu_intc_irq_domain_ops, NULL); 85 86 if (!irq_domain) 87 panic("Failed to add irqdomain for LoongArch CPU"); 88 89 set_handle_irq(&handle_cpu_irq); 90 91 return irq_domain; 92} 93