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
16 static struct irq_domain *irq_domain;
17
mask_loongarch_irq(struct irq_data * d)18 static void mask_loongarch_irq(struct irq_data *d)
19 {
20 clear_csr_ecfg(ECFGF(d->hwirq));
21 }
22
unmask_loongarch_irq(struct irq_data * d)23 static void unmask_loongarch_irq(struct irq_data *d)
24 {
25 set_csr_ecfg(ECFGF(d->hwirq));
26 }
27
28 static struct irq_chip cpu_irq_controller = {
29 .name = "LoongArch",
30 .irq_mask = mask_loongarch_irq,
31 .irq_unmask = unmask_loongarch_irq,
32 };
33
handle_cpu_irq(struct pt_regs * regs)34 static 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
get_ipi_irq(void)45 int get_ipi_irq(void)
46 {
47 return irq_create_mapping(irq_domain, INT_IPI);
48 }
49
get_pmc_irq(void)50 int get_pmc_irq(void)
51 {
52 return irq_create_mapping(irq_domain, INT_PCOV);
53 }
54
get_timer_irq(void)55 int get_timer_irq(void)
56 {
57 return irq_create_mapping(irq_domain, INT_TI);
58 }
59
loongarch_cpu_intc_map(struct irq_domain * d,unsigned int irq,irq_hw_number_t hwirq)60 static 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
69 static 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
loongarch_cpu_irq_init(void)74 struct 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