• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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