xref: /OK3568_Linux_fs/kernel/arch/mips/loongson32/common/irq.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com>
4*4882a593Smuzhiyun  */
5*4882a593Smuzhiyun 
6*4882a593Smuzhiyun #include <linux/interrupt.h>
7*4882a593Smuzhiyun #include <linux/irq.h>
8*4882a593Smuzhiyun #include <asm/irq_cpu.h>
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <loongson1.h>
11*4882a593Smuzhiyun #include <irq.h>
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #define LS1X_INTC_REG(n, x) \
14*4882a593Smuzhiyun 		((void __iomem *)KSEG1ADDR(LS1X_INTC_BASE + (n * 0x18) + (x)))
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #define LS1X_INTC_INTISR(n)		LS1X_INTC_REG(n, 0x0)
17*4882a593Smuzhiyun #define LS1X_INTC_INTIEN(n)		LS1X_INTC_REG(n, 0x4)
18*4882a593Smuzhiyun #define LS1X_INTC_INTSET(n)		LS1X_INTC_REG(n, 0x8)
19*4882a593Smuzhiyun #define LS1X_INTC_INTCLR(n)		LS1X_INTC_REG(n, 0xc)
20*4882a593Smuzhiyun #define LS1X_INTC_INTPOL(n)		LS1X_INTC_REG(n, 0x10)
21*4882a593Smuzhiyun #define LS1X_INTC_INTEDGE(n)		LS1X_INTC_REG(n, 0x14)
22*4882a593Smuzhiyun 
ls1x_irq_ack(struct irq_data * d)23*4882a593Smuzhiyun static void ls1x_irq_ack(struct irq_data *d)
24*4882a593Smuzhiyun {
25*4882a593Smuzhiyun 	unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f;
26*4882a593Smuzhiyun 	unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5;
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun 	__raw_writel(__raw_readl(LS1X_INTC_INTCLR(n))
29*4882a593Smuzhiyun 			| (1 << bit), LS1X_INTC_INTCLR(n));
30*4882a593Smuzhiyun }
31*4882a593Smuzhiyun 
ls1x_irq_mask(struct irq_data * d)32*4882a593Smuzhiyun static void ls1x_irq_mask(struct irq_data *d)
33*4882a593Smuzhiyun {
34*4882a593Smuzhiyun 	unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f;
35*4882a593Smuzhiyun 	unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5;
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun 	__raw_writel(__raw_readl(LS1X_INTC_INTIEN(n))
38*4882a593Smuzhiyun 			& ~(1 << bit), LS1X_INTC_INTIEN(n));
39*4882a593Smuzhiyun }
40*4882a593Smuzhiyun 
ls1x_irq_mask_ack(struct irq_data * d)41*4882a593Smuzhiyun static void ls1x_irq_mask_ack(struct irq_data *d)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun 	unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f;
44*4882a593Smuzhiyun 	unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5;
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun 	__raw_writel(__raw_readl(LS1X_INTC_INTIEN(n))
47*4882a593Smuzhiyun 			& ~(1 << bit), LS1X_INTC_INTIEN(n));
48*4882a593Smuzhiyun 	__raw_writel(__raw_readl(LS1X_INTC_INTCLR(n))
49*4882a593Smuzhiyun 			| (1 << bit), LS1X_INTC_INTCLR(n));
50*4882a593Smuzhiyun }
51*4882a593Smuzhiyun 
ls1x_irq_unmask(struct irq_data * d)52*4882a593Smuzhiyun static void ls1x_irq_unmask(struct irq_data *d)
53*4882a593Smuzhiyun {
54*4882a593Smuzhiyun 	unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f;
55*4882a593Smuzhiyun 	unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5;
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun 	__raw_writel(__raw_readl(LS1X_INTC_INTIEN(n))
58*4882a593Smuzhiyun 			| (1 << bit), LS1X_INTC_INTIEN(n));
59*4882a593Smuzhiyun }
60*4882a593Smuzhiyun 
ls1x_irq_settype(struct irq_data * d,unsigned int type)61*4882a593Smuzhiyun static int ls1x_irq_settype(struct irq_data *d, unsigned int type)
62*4882a593Smuzhiyun {
63*4882a593Smuzhiyun 	unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f;
64*4882a593Smuzhiyun 	unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5;
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 	switch (type) {
67*4882a593Smuzhiyun 	case IRQ_TYPE_LEVEL_HIGH:
68*4882a593Smuzhiyun 		__raw_writel(__raw_readl(LS1X_INTC_INTPOL(n))
69*4882a593Smuzhiyun 			| (1 << bit), LS1X_INTC_INTPOL(n));
70*4882a593Smuzhiyun 		__raw_writel(__raw_readl(LS1X_INTC_INTEDGE(n))
71*4882a593Smuzhiyun 			& ~(1 << bit), LS1X_INTC_INTEDGE(n));
72*4882a593Smuzhiyun 		break;
73*4882a593Smuzhiyun 	case IRQ_TYPE_LEVEL_LOW:
74*4882a593Smuzhiyun 		__raw_writel(__raw_readl(LS1X_INTC_INTPOL(n))
75*4882a593Smuzhiyun 			& ~(1 << bit), LS1X_INTC_INTPOL(n));
76*4882a593Smuzhiyun 		__raw_writel(__raw_readl(LS1X_INTC_INTEDGE(n))
77*4882a593Smuzhiyun 			& ~(1 << bit), LS1X_INTC_INTEDGE(n));
78*4882a593Smuzhiyun 		break;
79*4882a593Smuzhiyun 	case IRQ_TYPE_EDGE_RISING:
80*4882a593Smuzhiyun 		__raw_writel(__raw_readl(LS1X_INTC_INTPOL(n))
81*4882a593Smuzhiyun 			| (1 << bit), LS1X_INTC_INTPOL(n));
82*4882a593Smuzhiyun 		__raw_writel(__raw_readl(LS1X_INTC_INTEDGE(n))
83*4882a593Smuzhiyun 			| (1 << bit), LS1X_INTC_INTEDGE(n));
84*4882a593Smuzhiyun 		break;
85*4882a593Smuzhiyun 	case IRQ_TYPE_EDGE_FALLING:
86*4882a593Smuzhiyun 		__raw_writel(__raw_readl(LS1X_INTC_INTPOL(n))
87*4882a593Smuzhiyun 			& ~(1 << bit), LS1X_INTC_INTPOL(n));
88*4882a593Smuzhiyun 		__raw_writel(__raw_readl(LS1X_INTC_INTEDGE(n))
89*4882a593Smuzhiyun 			| (1 << bit), LS1X_INTC_INTEDGE(n));
90*4882a593Smuzhiyun 		break;
91*4882a593Smuzhiyun 	case IRQ_TYPE_EDGE_BOTH:
92*4882a593Smuzhiyun 		__raw_writel(__raw_readl(LS1X_INTC_INTPOL(n))
93*4882a593Smuzhiyun 			& ~(1 << bit), LS1X_INTC_INTPOL(n));
94*4882a593Smuzhiyun 		__raw_writel(__raw_readl(LS1X_INTC_INTEDGE(n))
95*4882a593Smuzhiyun 			| (1 << bit), LS1X_INTC_INTEDGE(n));
96*4882a593Smuzhiyun 		break;
97*4882a593Smuzhiyun 	case IRQ_TYPE_NONE:
98*4882a593Smuzhiyun 		break;
99*4882a593Smuzhiyun 	default:
100*4882a593Smuzhiyun 		return -EINVAL;
101*4882a593Smuzhiyun 	}
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	return 0;
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun static struct irq_chip ls1x_irq_chip = {
107*4882a593Smuzhiyun 	.name		= "LS1X-INTC",
108*4882a593Smuzhiyun 	.irq_ack	= ls1x_irq_ack,
109*4882a593Smuzhiyun 	.irq_mask	= ls1x_irq_mask,
110*4882a593Smuzhiyun 	.irq_mask_ack	= ls1x_irq_mask_ack,
111*4882a593Smuzhiyun 	.irq_unmask	= ls1x_irq_unmask,
112*4882a593Smuzhiyun 	.irq_set_type   = ls1x_irq_settype,
113*4882a593Smuzhiyun };
114*4882a593Smuzhiyun 
ls1x_irq_dispatch(int n)115*4882a593Smuzhiyun static void ls1x_irq_dispatch(int n)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun 	u32 int_status, irq;
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	/* Get pending sources, masked by current enables */
120*4882a593Smuzhiyun 	int_status = __raw_readl(LS1X_INTC_INTISR(n)) &
121*4882a593Smuzhiyun 			__raw_readl(LS1X_INTC_INTIEN(n));
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	if (int_status) {
124*4882a593Smuzhiyun 		irq = LS1X_IRQ(n, __ffs(int_status));
125*4882a593Smuzhiyun 		do_IRQ(irq);
126*4882a593Smuzhiyun 	}
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun 
plat_irq_dispatch(void)129*4882a593Smuzhiyun asmlinkage void plat_irq_dispatch(void)
130*4882a593Smuzhiyun {
131*4882a593Smuzhiyun 	unsigned int pending;
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	pending = read_c0_cause() & read_c0_status() & ST0_IM;
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	if (pending & CAUSEF_IP7)
136*4882a593Smuzhiyun 		do_IRQ(TIMER_IRQ);
137*4882a593Smuzhiyun 	else if (pending & CAUSEF_IP2)
138*4882a593Smuzhiyun 		ls1x_irq_dispatch(0); /* INT0 */
139*4882a593Smuzhiyun 	else if (pending & CAUSEF_IP3)
140*4882a593Smuzhiyun 		ls1x_irq_dispatch(1); /* INT1 */
141*4882a593Smuzhiyun 	else if (pending & CAUSEF_IP4)
142*4882a593Smuzhiyun 		ls1x_irq_dispatch(2); /* INT2 */
143*4882a593Smuzhiyun 	else if (pending & CAUSEF_IP5)
144*4882a593Smuzhiyun 		ls1x_irq_dispatch(3); /* INT3 */
145*4882a593Smuzhiyun 	else if (pending & CAUSEF_IP6)
146*4882a593Smuzhiyun 		ls1x_irq_dispatch(4); /* INT4 */
147*4882a593Smuzhiyun 	else
148*4882a593Smuzhiyun 		spurious_interrupt();
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun 
ls1x_irq_init(int base)152*4882a593Smuzhiyun static void __init ls1x_irq_init(int base)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun 	int n;
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	/* Disable interrupts and clear pending,
157*4882a593Smuzhiyun 	 * setup all IRQs as high level triggered
158*4882a593Smuzhiyun 	 */
159*4882a593Smuzhiyun 	for (n = 0; n < INTN; n++) {
160*4882a593Smuzhiyun 		__raw_writel(0x0, LS1X_INTC_INTIEN(n));
161*4882a593Smuzhiyun 		__raw_writel(0xffffffff, LS1X_INTC_INTCLR(n));
162*4882a593Smuzhiyun 		__raw_writel(0xffffffff, LS1X_INTC_INTPOL(n));
163*4882a593Smuzhiyun 		/* set DMA0, DMA1 and DMA2 to edge trigger */
164*4882a593Smuzhiyun 		__raw_writel(n ? 0x0 : 0xe000, LS1X_INTC_INTEDGE(n));
165*4882a593Smuzhiyun 	}
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun 	for (n = base; n < NR_IRQS; n++) {
169*4882a593Smuzhiyun 		irq_set_chip_and_handler(n, &ls1x_irq_chip,
170*4882a593Smuzhiyun 					 handle_level_irq);
171*4882a593Smuzhiyun 	}
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	if (request_irq(INT0_IRQ, no_action, IRQF_NO_THREAD, "cascade", NULL))
174*4882a593Smuzhiyun 		pr_err("Failed to request irq %d (cascade)\n", INT0_IRQ);
175*4882a593Smuzhiyun 	if (request_irq(INT1_IRQ, no_action, IRQF_NO_THREAD, "cascade", NULL))
176*4882a593Smuzhiyun 		pr_err("Failed to request irq %d (cascade)\n", INT1_IRQ);
177*4882a593Smuzhiyun 	if (request_irq(INT2_IRQ, no_action, IRQF_NO_THREAD, "cascade", NULL))
178*4882a593Smuzhiyun 		pr_err("Failed to request irq %d (cascade)\n", INT2_IRQ);
179*4882a593Smuzhiyun 	if (request_irq(INT3_IRQ, no_action, IRQF_NO_THREAD, "cascade", NULL))
180*4882a593Smuzhiyun 		pr_err("Failed to request irq %d (cascade)\n", INT3_IRQ);
181*4882a593Smuzhiyun #if defined(CONFIG_LOONGSON1_LS1C)
182*4882a593Smuzhiyun 	if (request_irq(INT4_IRQ, no_action, IRQF_NO_THREAD, "cascade", NULL))
183*4882a593Smuzhiyun 		pr_err("Failed to request irq %d (cascade)\n", INT4_IRQ);
184*4882a593Smuzhiyun #endif
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun 
arch_init_irq(void)187*4882a593Smuzhiyun void __init arch_init_irq(void)
188*4882a593Smuzhiyun {
189*4882a593Smuzhiyun 	mips_cpu_irq_init();
190*4882a593Smuzhiyun 	ls1x_irq_init(LS1X_IRQ_BASE);
191*4882a593Smuzhiyun }
192