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