xref: /linux/drivers/irqchip/irq-starfive-jhb100-intc.c (revision 8b9db67396105f6b95bcc57a354e50ac20705704)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * StarFive JHB100 External Interrupt Controller driver
4  *
5  * Copyright (C) 2023 StarFive Technology Co., Ltd.
6  *
7  * Author: Changhuang Liang <changhuang.liang@starfivetech.com>
8  */
9 
10 #include <linux/bitops.h>
11 #include <linux/cleanup.h>
12 #include <linux/clk.h>
13 #include <linux/interrupt.h>
14 #include <linux/irq.h>
15 #include <linux/irqchip.h>
16 #include <linux/irqchip/chained_irq.h>
17 #include <linux/irqdomain.h>
18 #include <linux/of_irq.h>
19 #include <linux/platform_device.h>
20 #include <linux/reset.h>
21 #include <linux/spinlock.h>
22 
23 #define STARFIVE_INTC_SRC_TYPE(n)	(0x04 + ((n) * 0x20))
24 #define STARFIVE_INTC_SRC_CLEAR(n)	(0x10 + ((n) * 0x20))
25 #define STARFIVE_INTC_SRC_MASK(n)	(0x14 + ((n) * 0x20))
26 #define STARFIVE_INTC_SRC_INT(n)	(0x1c + ((n) * 0x20))
27 
28 #define STARFIVE_INTC_TRIGGER_MASK	0x3
29 #define STARFIVE_INTC_TRIGGER_HIGH	0
30 #define STARFIVE_INTC_TRIGGER_LOW	1
31 #define STARFIVE_INTC_TRIGGER_POSEDGE	2
32 #define STARFIVE_INTC_TRIGGER_NEGEDGE	3
33 
34 #define STARFIVE_INTC_NUM		2
35 #define STARFIVE_INTC_SRC_IRQ_NUM	32
36 #define STARFIVE_INTC_TYPE_NUM		16
37 
38 struct starfive_irq_chip {
39 	void __iomem		*base;
40 	struct irq_domain	*domain;
41 	raw_spinlock_t		lock;
42 };
43 
44 static void starfive_intc_mod(struct starfive_irq_chip *irqc, u32 reg, u32 mask, u32 data)
45 {
46 	u32 value;
47 
48 	value = ioread32(irqc->base + reg) & ~mask;
49 	data &= mask;
50 	data |= value;
51 	iowrite32(data, irqc->base + reg);
52 }
53 
54 static void starfive_intc_bit_set(struct starfive_irq_chip *irqc,
55 				  u32 reg, u32 bit_mask)
56 {
57 	u32 value;
58 
59 	value = ioread32(irqc->base + reg);
60 	value |= bit_mask;
61 	iowrite32(value, irqc->base + reg);
62 }
63 
64 static void starfive_intc_bit_clear(struct starfive_irq_chip *irqc,
65 				    u32 reg, u32 bit_mask)
66 {
67 	u32 value;
68 
69 	value = ioread32(irqc->base + reg);
70 	value &= ~bit_mask;
71 	iowrite32(value, irqc->base + reg);
72 }
73 
74 static void starfive_intc_unmask(struct irq_data *d)
75 {
76 	struct starfive_irq_chip *irqc = irq_data_get_irq_chip_data(d);
77 	int i, bitpos;
78 
79 	i = d->hwirq / STARFIVE_INTC_SRC_IRQ_NUM;
80 	bitpos = d->hwirq % STARFIVE_INTC_SRC_IRQ_NUM;
81 
82 	guard(raw_spinlock)(&irqc->lock);
83 	starfive_intc_bit_clear(irqc, STARFIVE_INTC_SRC_MASK(i), BIT(bitpos));
84 }
85 
86 static void starfive_intc_mask(struct irq_data *d)
87 {
88 	struct starfive_irq_chip *irqc = irq_data_get_irq_chip_data(d);
89 	int i, bitpos;
90 
91 	i = d->hwirq / STARFIVE_INTC_SRC_IRQ_NUM;
92 	bitpos = d->hwirq % STARFIVE_INTC_SRC_IRQ_NUM;
93 
94 	guard(raw_spinlock)(&irqc->lock);
95 	starfive_intc_bit_set(irqc, STARFIVE_INTC_SRC_MASK(i), BIT(bitpos));
96 }
97 
98 static void starfive_intc_ack(struct irq_data *d)
99 {
100 	/* for handle_edge_irq, nothing to do */
101 }
102 
103 static int starfive_intc_set_type(struct irq_data *d, unsigned int type)
104 {
105 	struct starfive_irq_chip *irqc = irq_data_get_irq_chip_data(d);
106 	u32 i, bitpos, ty_pos, ty_shift, trigger, typeval;
107 	irq_flow_handler_t handler;
108 
109 	i = d->hwirq / STARFIVE_INTC_SRC_IRQ_NUM;
110 	bitpos = d->hwirq % STARFIVE_INTC_SRC_IRQ_NUM;
111 	ty_pos = bitpos / STARFIVE_INTC_TYPE_NUM;
112 	ty_shift = (bitpos % STARFIVE_INTC_TYPE_NUM) * 2;
113 
114 	switch (type) {
115 	case IRQF_TRIGGER_LOW:
116 		trigger = STARFIVE_INTC_TRIGGER_LOW;
117 		handler = handle_level_irq;
118 		break;
119 	case IRQF_TRIGGER_HIGH:
120 		trigger = STARFIVE_INTC_TRIGGER_HIGH;
121 		handler = handle_level_irq;
122 		break;
123 	case IRQF_TRIGGER_FALLING:
124 		trigger = STARFIVE_INTC_TRIGGER_NEGEDGE;
125 		handler = handle_edge_irq;
126 		break;
127 	case IRQF_TRIGGER_RISING:
128 		trigger = STARFIVE_INTC_TRIGGER_POSEDGE;
129 		handler = handle_edge_irq;
130 		break;
131 	default:
132 		return -EINVAL;
133 	}
134 
135 	irq_set_handler_locked(d, handler);
136 	typeval = trigger << ty_shift;
137 
138 	guard(raw_spinlock)(&irqc->lock);
139 
140 	starfive_intc_mod(irqc, STARFIVE_INTC_SRC_TYPE(i) + 4 * ty_pos,
141 			  STARFIVE_INTC_TRIGGER_MASK << ty_shift, typeval);
142 
143 	/* Once the type is updated, clear interrupt can help to reset the type value */
144 	starfive_intc_bit_set(irqc, STARFIVE_INTC_SRC_CLEAR(i), BIT(bitpos));
145 	starfive_intc_bit_clear(irqc, STARFIVE_INTC_SRC_CLEAR(i), BIT(bitpos));
146 
147 	return 0;
148 }
149 
150 static struct irq_chip intc_dev = {
151 	.name		= "StarFive JHB100 INTC",
152 	.irq_unmask	= starfive_intc_unmask,
153 	.irq_mask	= starfive_intc_mask,
154 	.irq_ack	= starfive_intc_ack,
155 	.irq_set_type	= starfive_intc_set_type,
156 };
157 
158 static int starfive_intc_map(struct irq_domain *d, unsigned int irq,
159 			     irq_hw_number_t hwirq)
160 {
161 	irq_domain_set_info(d, irq, hwirq, &intc_dev, d->host_data,
162 			    handle_level_irq, NULL, NULL);
163 
164 	return 0;
165 }
166 
167 static const struct irq_domain_ops starfive_intc_domain_ops = {
168 	.xlate	= irq_domain_xlate_onecell,
169 	.map	= starfive_intc_map,
170 };
171 
172 static void starfive_intc_irq_handler(struct irq_desc *desc)
173 {
174 	struct starfive_irq_chip *irqc = irq_data_get_irq_handler_data(&desc->irq_data);
175 	struct irq_chip *chip = irq_desc_get_chip(desc);
176 	unsigned long value;
177 	int hwirq;
178 
179 	chained_irq_enter(chip, desc);
180 
181 	for (int i = 0; i < STARFIVE_INTC_NUM; i++) {
182 		value = ioread32(irqc->base + STARFIVE_INTC_SRC_INT(i));
183 		while (value) {
184 			hwirq = ffs(value) - 1;
185 
186 			generic_handle_domain_irq(irqc->domain,
187 						  hwirq + i * STARFIVE_INTC_SRC_IRQ_NUM);
188 
189 			starfive_intc_bit_set(irqc, STARFIVE_INTC_SRC_CLEAR(i), BIT(hwirq));
190 			starfive_intc_bit_clear(irqc, STARFIVE_INTC_SRC_CLEAR(i), BIT(hwirq));
191 
192 			__clear_bit(hwirq, &value);
193 		}
194 	}
195 
196 	chained_irq_exit(chip, desc);
197 }
198 
199 static int starfive_intc_probe(struct platform_device *pdev, struct device_node *parent)
200 {
201 	struct device_node *intc = pdev->dev.of_node;
202 	struct reset_control *rst;
203 	struct clk *clk;
204 	int parent_irq;
205 
206 	struct starfive_irq_chip *irqc __free(kfree) = kzalloc_obj(*irqc);
207 	if (!irqc)
208 		return -ENOMEM;
209 
210 	irqc->base = devm_platform_ioremap_resource(pdev, 0);
211 	if (IS_ERR(irqc->base))
212 		return dev_err_probe(&pdev->dev, PTR_ERR(irqc->base), "unable to map registers\n");
213 
214 	rst = devm_reset_control_get_optional_exclusive_deasserted(&pdev->dev, NULL);
215 	if (IS_ERR(rst))
216 		return dev_err_probe(&pdev->dev, PTR_ERR(rst),
217 				     "Unable to get and deassert reset control\n");
218 
219 	clk = devm_clk_get_optional_enabled(&pdev->dev, NULL);
220 	if (IS_ERR(clk))
221 		return dev_err_probe(&pdev->dev, PTR_ERR(clk), "Unable to get and enable clock\n");
222 
223 
224 	raw_spin_lock_init(&irqc->lock);
225 
226 	irqc->domain = irq_domain_create_linear(of_fwnode_handle(intc),
227 						STARFIVE_INTC_SRC_IRQ_NUM * STARFIVE_INTC_NUM,
228 						&starfive_intc_domain_ops, irqc);
229 	if (!irqc->domain)
230 		return dev_err_probe(&pdev->dev, -EINVAL, "Unable to create IRQ domain\n");
231 
232 	parent_irq = of_irq_get(intc, 0);
233 	if (parent_irq < 0) {
234 		irq_domain_remove(irqc->domain);
235 		return dev_err_probe(&pdev->dev, parent_irq, "Failed to get main IRQ\n");
236 	}
237 
238 	irq_set_chained_handler_and_data(parent_irq, starfive_intc_irq_handler,
239 					 irqc);
240 
241 	dev_info(&pdev->dev, "Interrupt controller register, nr_irqs %d\n",
242 		 STARFIVE_INTC_SRC_IRQ_NUM * STARFIVE_INTC_NUM);
243 
244 	retain_and_null_ptr(irqc);
245 	return 0;
246 }
247 
248 IRQCHIP_PLATFORM_DRIVER_BEGIN(starfive_intc)
249 IRQCHIP_MATCH("starfive,jhb100-intc", starfive_intc_probe)
250 IRQCHIP_PLATFORM_DRIVER_END(starfive_intc)
251 
252 MODULE_DESCRIPTION("StarFive JHB100 External Interrupt Controller");
253 MODULE_LICENSE("GPL");
254 MODULE_AUTHOR("Changhuang Liang <changhuang.liang@starfivetech.com>");
255