1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2 /*
3  * Copyright (C) Sunplus Technology Co., Ltd.
4  *       All rights reserved.
5  */
6 #include <linux/irq.h>
7 #include <linux/irqdomain.h>
8 #include <linux/io.h>
9 #include <linux/irqchip.h>
10 #include <linux/irqchip/chained_irq.h>
11 #include <linux/of_address.h>
12 #include <linux/of_irq.h>
13 
14 #define SP_INTC_HWIRQ_MIN	0
15 #define SP_INTC_HWIRQ_MAX	223
16 
17 #define SP_INTC_NR_IRQS		(SP_INTC_HWIRQ_MAX - SP_INTC_HWIRQ_MIN + 1)
18 #define SP_INTC_NR_GROUPS	DIV_ROUND_UP(SP_INTC_NR_IRQS, 32)
19 #define SP_INTC_REG_SIZE	(SP_INTC_NR_GROUPS * 4)
20 
21 /* REG_GROUP_0 regs */
22 #define REG_INTR_TYPE		(sp_intc.g0)
23 #define REG_INTR_POLARITY	(REG_INTR_TYPE     + SP_INTC_REG_SIZE)
24 #define REG_INTR_PRIORITY	(REG_INTR_POLARITY + SP_INTC_REG_SIZE)
25 #define REG_INTR_MASK		(REG_INTR_PRIORITY + SP_INTC_REG_SIZE)
26 
27 /* REG_GROUP_1 regs */
28 #define REG_INTR_CLEAR		(sp_intc.g1)
29 #define REG_MASKED_EXT1		(REG_INTR_CLEAR    + SP_INTC_REG_SIZE)
30 #define REG_MASKED_EXT0		(REG_MASKED_EXT1   + SP_INTC_REG_SIZE)
31 #define REG_INTR_GROUP		(REG_INTR_CLEAR    + 31 * 4)
32 
33 #define GROUP_MASK		(BIT(SP_INTC_NR_GROUPS) - 1)
34 #define GROUP_SHIFT_EXT1	(0)
35 #define GROUP_SHIFT_EXT0	(8)
36 
37 /*
38  * When GPIO_INT0~7 set to edge trigger, doesn't work properly.
39  * WORKAROUND: change it to level trigger, and toggle the polarity
40  * at ACK/Handler to make the HW work.
41  */
42 #define GPIO_INT0_HWIRQ		120
43 #define GPIO_INT7_HWIRQ		127
44 #define IS_GPIO_INT(irq)					\
45 ({								\
46 	u32 i = irq;						\
47 	(i >= GPIO_INT0_HWIRQ) && (i <= GPIO_INT7_HWIRQ);	\
48 })
49 
50 /* index of states */
51 enum {
52 	_IS_EDGE = 0,
53 	_IS_LOW,
54 	_IS_ACTIVE
55 };
56 
57 #define STATE_BIT(irq, idx)		(((irq) - GPIO_INT0_HWIRQ) * 3 + (idx))
58 #define ASSIGN_STATE(irq, idx, v)	assign_bit(STATE_BIT(irq, idx), sp_intc.states, v)
59 #define TEST_STATE(irq, idx)		test_bit(STATE_BIT(irq, idx), sp_intc.states)
60 
61 static struct sp_intctl {
62 	/*
63 	 * REG_GROUP_0: include type/polarity/priority/mask regs.
64 	 * REG_GROUP_1: include clear/masked_ext0/masked_ext1/group regs.
65 	 */
66 	void __iomem *g0; // REG_GROUP_0 base
67 	void __iomem *g1; // REG_GROUP_1 base
68 
69 	struct irq_domain *domain;
70 	raw_spinlock_t lock;
71 
72 	/*
73 	 * store GPIO_INT states
74 	 * each interrupt has 3 states: is_edge, is_low, is_active
75 	 */
76 	DECLARE_BITMAP(states, (GPIO_INT7_HWIRQ - GPIO_INT0_HWIRQ + 1) * 3);
77 } sp_intc;
78 
79 static struct irq_chip sp_intc_chip;
80 
sp_intc_assign_bit(u32 hwirq,void __iomem * base,bool value)81 static void sp_intc_assign_bit(u32 hwirq, void __iomem *base, bool value)
82 {
83 	u32 offset, mask;
84 	unsigned long flags;
85 	void __iomem *reg;
86 
87 	offset = (hwirq / 32) * 4;
88 	reg = base + offset;
89 
90 	raw_spin_lock_irqsave(&sp_intc.lock, flags);
91 	mask = readl_relaxed(reg);
92 	if (value)
93 		mask |= BIT(hwirq % 32);
94 	else
95 		mask &= ~BIT(hwirq % 32);
96 	writel_relaxed(mask, reg);
97 	raw_spin_unlock_irqrestore(&sp_intc.lock, flags);
98 }
99 
sp_intc_ack_irq(struct irq_data * d)100 static void sp_intc_ack_irq(struct irq_data *d)
101 {
102 	u32 hwirq = d->hwirq;
103 
104 	if (unlikely(IS_GPIO_INT(hwirq) && TEST_STATE(hwirq, _IS_EDGE))) { // WORKAROUND
105 		sp_intc_assign_bit(hwirq, REG_INTR_POLARITY, !TEST_STATE(hwirq, _IS_LOW));
106 		ASSIGN_STATE(hwirq, _IS_ACTIVE, true);
107 	}
108 
109 	sp_intc_assign_bit(hwirq, REG_INTR_CLEAR, 1);
110 }
111 
sp_intc_mask_irq(struct irq_data * d)112 static void sp_intc_mask_irq(struct irq_data *d)
113 {
114 	sp_intc_assign_bit(d->hwirq, REG_INTR_MASK, 0);
115 }
116 
sp_intc_unmask_irq(struct irq_data * d)117 static void sp_intc_unmask_irq(struct irq_data *d)
118 {
119 	sp_intc_assign_bit(d->hwirq, REG_INTR_MASK, 1);
120 }
121 
sp_intc_set_type(struct irq_data * d,unsigned int type)122 static int sp_intc_set_type(struct irq_data *d, unsigned int type)
123 {
124 	u32 hwirq = d->hwirq;
125 	bool is_edge = !(type & IRQ_TYPE_LEVEL_MASK);
126 	bool is_low = (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_EDGE_FALLING);
127 
128 	irq_set_handler_locked(d, is_edge ? handle_edge_irq : handle_level_irq);
129 
130 	if (unlikely(IS_GPIO_INT(hwirq) && is_edge)) { // WORKAROUND
131 		/* store states */
132 		ASSIGN_STATE(hwirq, _IS_EDGE, is_edge);
133 		ASSIGN_STATE(hwirq, _IS_LOW, is_low);
134 		ASSIGN_STATE(hwirq, _IS_ACTIVE, false);
135 		/* change to level */
136 		is_edge = false;
137 	}
138 
139 	sp_intc_assign_bit(hwirq, REG_INTR_TYPE, is_edge);
140 	sp_intc_assign_bit(hwirq, REG_INTR_POLARITY, is_low);
141 
142 	return 0;
143 }
144 
sp_intc_get_ext_irq(int ext_num)145 static int sp_intc_get_ext_irq(int ext_num)
146 {
147 	void __iomem *base = ext_num ? REG_MASKED_EXT1 : REG_MASKED_EXT0;
148 	u32 shift = ext_num ? GROUP_SHIFT_EXT1 : GROUP_SHIFT_EXT0;
149 	u32 groups;
150 	u32 pending_group;
151 	u32 group;
152 	u32 pending_irq;
153 
154 	groups = readl_relaxed(REG_INTR_GROUP);
155 	pending_group = (groups >> shift) & GROUP_MASK;
156 	if (!pending_group)
157 		return -1;
158 
159 	group = fls(pending_group) - 1;
160 	pending_irq = readl_relaxed(base + group * 4);
161 	if (!pending_irq)
162 		return -1;
163 
164 	return (group * 32) + fls(pending_irq) - 1;
165 }
166 
sp_intc_handle_ext_cascaded(struct irq_desc * desc)167 static void sp_intc_handle_ext_cascaded(struct irq_desc *desc)
168 {
169 	struct irq_chip *chip = irq_desc_get_chip(desc);
170 	int ext_num = (uintptr_t)irq_desc_get_handler_data(desc);
171 	int hwirq;
172 
173 	chained_irq_enter(chip, desc);
174 
175 	while ((hwirq = sp_intc_get_ext_irq(ext_num)) >= 0) {
176 		if (unlikely(IS_GPIO_INT(hwirq) && TEST_STATE(hwirq, _IS_ACTIVE))) { // WORKAROUND
177 			ASSIGN_STATE(hwirq, _IS_ACTIVE, false);
178 			sp_intc_assign_bit(hwirq, REG_INTR_POLARITY, TEST_STATE(hwirq, _IS_LOW));
179 		} else {
180 			generic_handle_domain_irq(sp_intc.domain, hwirq);
181 		}
182 	}
183 
184 	chained_irq_exit(chip, desc);
185 }
186 
187 static struct irq_chip sp_intc_chip = {
188 	.name = "sp_intc",
189 	.irq_ack = sp_intc_ack_irq,
190 	.irq_mask = sp_intc_mask_irq,
191 	.irq_unmask = sp_intc_unmask_irq,
192 	.irq_set_type = sp_intc_set_type,
193 };
194 
sp_intc_irq_domain_map(struct irq_domain * domain,unsigned int irq,irq_hw_number_t hwirq)195 static int sp_intc_irq_domain_map(struct irq_domain *domain,
196 				  unsigned int irq, irq_hw_number_t hwirq)
197 {
198 	irq_set_chip_and_handler(irq, &sp_intc_chip, handle_level_irq);
199 	irq_set_chip_data(irq, &sp_intc_chip);
200 	irq_set_noprobe(irq);
201 
202 	return 0;
203 }
204 
205 static const struct irq_domain_ops sp_intc_dm_ops = {
206 	.xlate = irq_domain_xlate_twocell,
207 	.map = sp_intc_irq_domain_map,
208 };
209 
sp_intc_irq_map(struct device_node * node,int i)210 static int sp_intc_irq_map(struct device_node *node, int i)
211 {
212 	unsigned int irq;
213 
214 	irq = irq_of_parse_and_map(node, i);
215 	if (!irq)
216 		return -ENOENT;
217 
218 	irq_set_chained_handler_and_data(irq, sp_intc_handle_ext_cascaded, (void *)(uintptr_t)i);
219 
220 	return 0;
221 }
222 
sp_intc_init_dt(struct device_node * node,struct device_node * parent)223 static int __init sp_intc_init_dt(struct device_node *node, struct device_node *parent)
224 {
225 	int i, ret;
226 
227 	sp_intc.g0 = of_iomap(node, 0);
228 	if (!sp_intc.g0)
229 		return -ENXIO;
230 
231 	sp_intc.g1 = of_iomap(node, 1);
232 	if (!sp_intc.g1) {
233 		ret = -ENXIO;
234 		goto out_unmap0;
235 	}
236 
237 	ret = sp_intc_irq_map(node, 0); // EXT_INT0
238 	if (ret)
239 		goto out_unmap1;
240 
241 	ret = sp_intc_irq_map(node, 1); // EXT_INT1
242 	if (ret)
243 		goto out_unmap1;
244 
245 	/* initial regs */
246 	for (i = 0; i < SP_INTC_NR_GROUPS; i++) {
247 		/* all mask */
248 		writel_relaxed(0, REG_INTR_MASK + i * 4);
249 		/* all edge */
250 		writel_relaxed(~0, REG_INTR_TYPE + i * 4);
251 		/* all high-active */
252 		writel_relaxed(0, REG_INTR_POLARITY + i * 4);
253 		/* all EXT_INT0 */
254 		writel_relaxed(~0, REG_INTR_PRIORITY + i * 4);
255 		/* all clear */
256 		writel_relaxed(~0, REG_INTR_CLEAR + i * 4);
257 	}
258 
259 	sp_intc.domain = irq_domain_add_linear(node, SP_INTC_NR_IRQS,
260 					       &sp_intc_dm_ops, &sp_intc);
261 	if (!sp_intc.domain) {
262 		ret = -ENOMEM;
263 		goto out_unmap1;
264 	}
265 
266 	raw_spin_lock_init(&sp_intc.lock);
267 
268 	return 0;
269 
270 out_unmap1:
271 	iounmap(sp_intc.g1);
272 out_unmap0:
273 	iounmap(sp_intc.g0);
274 
275 	return ret;
276 }
277 
278 IRQCHIP_DECLARE(sp_intc, "sunplus,sp7021-intc", sp_intc_init_dt);
279