• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * PRU-ICSS INTC IRQChip driver for various TI SoCs
4  *
5  * Copyright (C) 2016-2020 Texas Instruments Incorporated - http://www.ti.com/
6  *
7  * Author(s):
8  *	Andrew F. Davis <afd@ti.com>
9  *	Suman Anna <s-anna@ti.com>
10  *	Grzegorz Jaszczyk <grzegorz.jaszczyk@linaro.org> for Texas Instruments
11  *
12  * Copyright (C) 2019 David Lechner <david@lechnology.com>
13  */
14 
15 #include <linux/interrupt.h>
16 #include <linux/irq.h>
17 #include <linux/irqchip/chained_irq.h>
18 #include <linux/irqdomain.h>
19 #include <linux/module.h>
20 #include <linux/of_device.h>
21 #include <linux/platform_device.h>
22 
23 /*
24  * Number of host interrupts reaching the main MPU sub-system. Note that this
25  * is not the same as the total number of host interrupts supported by the PRUSS
26  * INTC instance
27  */
28 #define MAX_NUM_HOST_IRQS	8
29 
30 /* minimum starting host interrupt number for MPU */
31 #define FIRST_PRU_HOST_INT	2
32 
33 /* PRU_ICSS_INTC registers */
34 #define PRU_INTC_REVID		0x0000
35 #define PRU_INTC_CR		0x0004
36 #define PRU_INTC_GER		0x0010
37 #define PRU_INTC_GNLR		0x001c
38 #define PRU_INTC_SISR		0x0020
39 #define PRU_INTC_SICR		0x0024
40 #define PRU_INTC_EISR		0x0028
41 #define PRU_INTC_EICR		0x002c
42 #define PRU_INTC_HIEISR		0x0034
43 #define PRU_INTC_HIDISR		0x0038
44 #define PRU_INTC_GPIR		0x0080
45 #define PRU_INTC_SRSR(x)	(0x0200 + (x) * 4)
46 #define PRU_INTC_SECR(x)	(0x0280 + (x) * 4)
47 #define PRU_INTC_ESR(x)		(0x0300 + (x) * 4)
48 #define PRU_INTC_ECR(x)		(0x0380 + (x) * 4)
49 #define PRU_INTC_CMR(x)		(0x0400 + (x) * 4)
50 #define PRU_INTC_HMR(x)		(0x0800 + (x) * 4)
51 #define PRU_INTC_HIPIR(x)	(0x0900 + (x) * 4)
52 #define PRU_INTC_SIPR(x)	(0x0d00 + (x) * 4)
53 #define PRU_INTC_SITR(x)	(0x0d80 + (x) * 4)
54 #define PRU_INTC_HINLR(x)	(0x1100 + (x) * 4)
55 #define PRU_INTC_HIER		0x1500
56 
57 /* CMR register bit-field macros */
58 #define CMR_EVT_MAP_MASK	0xf
59 #define CMR_EVT_MAP_BITS	8
60 #define CMR_EVT_PER_REG		4
61 
62 /* HMR register bit-field macros */
63 #define HMR_CH_MAP_MASK		0xf
64 #define HMR_CH_MAP_BITS		8
65 #define HMR_CH_PER_REG		4
66 
67 /* HIPIR register bit-fields */
68 #define INTC_HIPIR_NONE_HINT	0x80000000
69 
70 #define MAX_PRU_SYS_EVENTS 160
71 #define MAX_PRU_CHANNELS 20
72 
73 /**
74  * struct pruss_intc_map_record - keeps track of actual mapping state
75  * @value: The currently mapped value (channel or host)
76  * @ref_count: Keeps track of number of current users of this resource
77  */
78 struct pruss_intc_map_record {
79 	u8 value;
80 	u8 ref_count;
81 };
82 
83 /**
84  * struct pruss_intc_match_data - match data to handle SoC variations
85  * @num_system_events: number of input system events handled by the PRUSS INTC
86  * @num_host_events: number of host events (which is equal to number of
87  *		     channels) supported by the PRUSS INTC
88  */
89 struct pruss_intc_match_data {
90 	u8 num_system_events;
91 	u8 num_host_events;
92 };
93 
94 /**
95  * struct pruss_intc - PRUSS interrupt controller structure
96  * @event_channel: current state of system event to channel mappings
97  * @channel_host: current state of channel to host mappings
98  * @irqs: kernel irq numbers corresponding to PRUSS host interrupts
99  * @base: base virtual address of INTC register space
100  * @domain: irq domain for this interrupt controller
101  * @soc_config: cached PRUSS INTC IP configuration data
102  * @dev: PRUSS INTC device pointer
103  * @lock: mutex to serialize interrupts mapping
104  */
105 struct pruss_intc {
106 	struct pruss_intc_map_record event_channel[MAX_PRU_SYS_EVENTS];
107 	struct pruss_intc_map_record channel_host[MAX_PRU_CHANNELS];
108 	unsigned int irqs[MAX_NUM_HOST_IRQS];
109 	void __iomem *base;
110 	struct irq_domain *domain;
111 	const struct pruss_intc_match_data *soc_config;
112 	struct device *dev;
113 	struct mutex lock; /* PRUSS INTC lock */
114 };
115 
116 /**
117  * struct pruss_host_irq_data - PRUSS host irq data structure
118  * @intc: PRUSS interrupt controller pointer
119  * @host_irq: host irq number
120  */
121 struct pruss_host_irq_data {
122 	struct pruss_intc *intc;
123 	u8 host_irq;
124 };
125 
pruss_intc_read_reg(struct pruss_intc * intc,unsigned int reg)126 static inline u32 pruss_intc_read_reg(struct pruss_intc *intc, unsigned int reg)
127 {
128 	return readl_relaxed(intc->base + reg);
129 }
130 
pruss_intc_write_reg(struct pruss_intc * intc,unsigned int reg,u32 val)131 static inline void pruss_intc_write_reg(struct pruss_intc *intc,
132 					unsigned int reg, u32 val)
133 {
134 	writel_relaxed(val, intc->base + reg);
135 }
136 
pruss_intc_update_cmr(struct pruss_intc * intc,unsigned int evt,u8 ch)137 static void pruss_intc_update_cmr(struct pruss_intc *intc, unsigned int evt,
138 				  u8 ch)
139 {
140 	u32 idx, offset, val;
141 
142 	idx = evt / CMR_EVT_PER_REG;
143 	offset = (evt % CMR_EVT_PER_REG) * CMR_EVT_MAP_BITS;
144 
145 	val = pruss_intc_read_reg(intc, PRU_INTC_CMR(idx));
146 	val &= ~(CMR_EVT_MAP_MASK << offset);
147 	val |= ch << offset;
148 	pruss_intc_write_reg(intc, PRU_INTC_CMR(idx), val);
149 
150 	dev_dbg(intc->dev, "SYSEV%u -> CH%d (CMR%d 0x%08x)\n", evt, ch,
151 		idx, pruss_intc_read_reg(intc, PRU_INTC_CMR(idx)));
152 }
153 
pruss_intc_update_hmr(struct pruss_intc * intc,u8 ch,u8 host)154 static void pruss_intc_update_hmr(struct pruss_intc *intc, u8 ch, u8 host)
155 {
156 	u32 idx, offset, val;
157 
158 	idx = ch / HMR_CH_PER_REG;
159 	offset = (ch % HMR_CH_PER_REG) * HMR_CH_MAP_BITS;
160 
161 	val = pruss_intc_read_reg(intc, PRU_INTC_HMR(idx));
162 	val &= ~(HMR_CH_MAP_MASK << offset);
163 	val |= host << offset;
164 	pruss_intc_write_reg(intc, PRU_INTC_HMR(idx), val);
165 
166 	dev_dbg(intc->dev, "CH%d -> HOST%d (HMR%d 0x%08x)\n", ch, host, idx,
167 		pruss_intc_read_reg(intc, PRU_INTC_HMR(idx)));
168 }
169 
170 /**
171  * pruss_intc_map() - configure the PRUSS INTC
172  * @intc: PRUSS interrupt controller pointer
173  * @hwirq: the system event number
174  *
175  * Configures the PRUSS INTC with the provided configuration from the one parsed
176  * in the xlate function.
177  */
pruss_intc_map(struct pruss_intc * intc,unsigned long hwirq)178 static void pruss_intc_map(struct pruss_intc *intc, unsigned long hwirq)
179 {
180 	struct device *dev = intc->dev;
181 	u8 ch, host, reg_idx;
182 	u32 val;
183 
184 	mutex_lock(&intc->lock);
185 
186 	intc->event_channel[hwirq].ref_count++;
187 
188 	ch = intc->event_channel[hwirq].value;
189 	host = intc->channel_host[ch].value;
190 
191 	pruss_intc_update_cmr(intc, hwirq, ch);
192 
193 	reg_idx = hwirq / 32;
194 	val = BIT(hwirq  % 32);
195 
196 	/* clear and enable system event */
197 	pruss_intc_write_reg(intc, PRU_INTC_ESR(reg_idx), val);
198 	pruss_intc_write_reg(intc, PRU_INTC_SECR(reg_idx), val);
199 
200 	if (++intc->channel_host[ch].ref_count == 1) {
201 		pruss_intc_update_hmr(intc, ch, host);
202 
203 		/* enable host interrupts */
204 		pruss_intc_write_reg(intc, PRU_INTC_HIEISR, host);
205 	}
206 
207 	dev_dbg(dev, "mapped system_event = %lu channel = %d host = %d",
208 		hwirq, ch, host);
209 
210 	mutex_unlock(&intc->lock);
211 }
212 
213 /**
214  * pruss_intc_unmap() - unconfigure the PRUSS INTC
215  * @intc: PRUSS interrupt controller pointer
216  * @hwirq: the system event number
217  *
218  * Undo whatever was done in pruss_intc_map() for a PRU core.
219  * Mappings are reference counted, so resources are only disabled when there
220  * are no longer any users.
221  */
pruss_intc_unmap(struct pruss_intc * intc,unsigned long hwirq)222 static void pruss_intc_unmap(struct pruss_intc *intc, unsigned long hwirq)
223 {
224 	u8 ch, host, reg_idx;
225 	u32 val;
226 
227 	mutex_lock(&intc->lock);
228 
229 	ch = intc->event_channel[hwirq].value;
230 	host = intc->channel_host[ch].value;
231 
232 	if (--intc->channel_host[ch].ref_count == 0) {
233 		/* disable host interrupts */
234 		pruss_intc_write_reg(intc, PRU_INTC_HIDISR, host);
235 
236 		/* clear the map using reset value 0 */
237 		pruss_intc_update_hmr(intc, ch, 0);
238 	}
239 
240 	intc->event_channel[hwirq].ref_count--;
241 	reg_idx = hwirq / 32;
242 	val = BIT(hwirq  % 32);
243 
244 	/* disable system events */
245 	pruss_intc_write_reg(intc, PRU_INTC_ECR(reg_idx), val);
246 	/* clear any pending status */
247 	pruss_intc_write_reg(intc, PRU_INTC_SECR(reg_idx), val);
248 
249 	/* clear the map using reset value 0 */
250 	pruss_intc_update_cmr(intc, hwirq, 0);
251 
252 	dev_dbg(intc->dev, "unmapped system_event = %lu channel = %d host = %d\n",
253 		hwirq, ch, host);
254 
255 	mutex_unlock(&intc->lock);
256 }
257 
pruss_intc_init(struct pruss_intc * intc)258 static void pruss_intc_init(struct pruss_intc *intc)
259 {
260 	const struct pruss_intc_match_data *soc_config = intc->soc_config;
261 	int num_chnl_map_regs, num_host_intr_regs, num_event_type_regs, i;
262 
263 	num_chnl_map_regs = DIV_ROUND_UP(soc_config->num_system_events,
264 					 CMR_EVT_PER_REG);
265 	num_host_intr_regs = DIV_ROUND_UP(soc_config->num_host_events,
266 					  HMR_CH_PER_REG);
267 	num_event_type_regs = DIV_ROUND_UP(soc_config->num_system_events, 32);
268 
269 	/*
270 	 * configure polarity (SIPR register) to active high and
271 	 * type (SITR register) to level interrupt for all system events
272 	 */
273 	for (i = 0; i < num_event_type_regs; i++) {
274 		pruss_intc_write_reg(intc, PRU_INTC_SIPR(i), 0xffffffff);
275 		pruss_intc_write_reg(intc, PRU_INTC_SITR(i), 0);
276 	}
277 
278 	/* clear all interrupt channel map registers, 4 events per register */
279 	for (i = 0; i < num_chnl_map_regs; i++)
280 		pruss_intc_write_reg(intc, PRU_INTC_CMR(i), 0);
281 
282 	/* clear all host interrupt map registers, 4 channels per register */
283 	for (i = 0; i < num_host_intr_regs; i++)
284 		pruss_intc_write_reg(intc, PRU_INTC_HMR(i), 0);
285 
286 	/* global interrupt enable */
287 	pruss_intc_write_reg(intc, PRU_INTC_GER, 1);
288 }
289 
pruss_intc_irq_ack(struct irq_data * data)290 static void pruss_intc_irq_ack(struct irq_data *data)
291 {
292 	struct pruss_intc *intc = irq_data_get_irq_chip_data(data);
293 	unsigned int hwirq = data->hwirq;
294 
295 	pruss_intc_write_reg(intc, PRU_INTC_SICR, hwirq);
296 }
297 
pruss_intc_irq_mask(struct irq_data * data)298 static void pruss_intc_irq_mask(struct irq_data *data)
299 {
300 	struct pruss_intc *intc = irq_data_get_irq_chip_data(data);
301 	unsigned int hwirq = data->hwirq;
302 
303 	pruss_intc_write_reg(intc, PRU_INTC_EICR, hwirq);
304 }
305 
pruss_intc_irq_unmask(struct irq_data * data)306 static void pruss_intc_irq_unmask(struct irq_data *data)
307 {
308 	struct pruss_intc *intc = irq_data_get_irq_chip_data(data);
309 	unsigned int hwirq = data->hwirq;
310 
311 	pruss_intc_write_reg(intc, PRU_INTC_EISR, hwirq);
312 }
313 
pruss_intc_irq_reqres(struct irq_data * data)314 static int pruss_intc_irq_reqres(struct irq_data *data)
315 {
316 	if (!try_module_get(THIS_MODULE))
317 		return -ENODEV;
318 
319 	return 0;
320 }
321 
pruss_intc_irq_relres(struct irq_data * data)322 static void pruss_intc_irq_relres(struct irq_data *data)
323 {
324 	module_put(THIS_MODULE);
325 }
326 
pruss_intc_irq_get_irqchip_state(struct irq_data * data,enum irqchip_irq_state which,bool * state)327 static int pruss_intc_irq_get_irqchip_state(struct irq_data *data,
328 					    enum irqchip_irq_state which,
329 					    bool *state)
330 {
331 	struct pruss_intc *intc = irq_data_get_irq_chip_data(data);
332 	u32 reg, mask, srsr;
333 
334 	if (which != IRQCHIP_STATE_PENDING)
335 		return -EINVAL;
336 
337 	reg = PRU_INTC_SRSR(data->hwirq / 32);
338 	mask = BIT(data->hwirq % 32);
339 
340 	srsr = pruss_intc_read_reg(intc, reg);
341 
342 	*state = !!(srsr & mask);
343 
344 	return 0;
345 }
346 
pruss_intc_irq_set_irqchip_state(struct irq_data * data,enum irqchip_irq_state which,bool state)347 static int pruss_intc_irq_set_irqchip_state(struct irq_data *data,
348 					    enum irqchip_irq_state which,
349 					    bool state)
350 {
351 	struct pruss_intc *intc = irq_data_get_irq_chip_data(data);
352 
353 	if (which != IRQCHIP_STATE_PENDING)
354 		return -EINVAL;
355 
356 	if (state)
357 		pruss_intc_write_reg(intc, PRU_INTC_SISR, data->hwirq);
358 	else
359 		pruss_intc_write_reg(intc, PRU_INTC_SICR, data->hwirq);
360 
361 	return 0;
362 }
363 
364 static struct irq_chip pruss_irqchip = {
365 	.name			= "pruss-intc",
366 	.irq_ack		= pruss_intc_irq_ack,
367 	.irq_mask		= pruss_intc_irq_mask,
368 	.irq_unmask		= pruss_intc_irq_unmask,
369 	.irq_request_resources	= pruss_intc_irq_reqres,
370 	.irq_release_resources	= pruss_intc_irq_relres,
371 	.irq_get_irqchip_state	= pruss_intc_irq_get_irqchip_state,
372 	.irq_set_irqchip_state	= pruss_intc_irq_set_irqchip_state,
373 };
374 
pruss_intc_validate_mapping(struct pruss_intc * intc,int event,int channel,int host)375 static int pruss_intc_validate_mapping(struct pruss_intc *intc, int event,
376 				       int channel, int host)
377 {
378 	struct device *dev = intc->dev;
379 	int ret = 0;
380 
381 	mutex_lock(&intc->lock);
382 
383 	/* check if sysevent already assigned */
384 	if (intc->event_channel[event].ref_count > 0 &&
385 	    intc->event_channel[event].value != channel) {
386 		dev_err(dev, "event %d (req. ch %d) already assigned to channel %d\n",
387 			event, channel, intc->event_channel[event].value);
388 		ret = -EBUSY;
389 		goto unlock;
390 	}
391 
392 	/* check if channel already assigned */
393 	if (intc->channel_host[channel].ref_count > 0 &&
394 	    intc->channel_host[channel].value != host) {
395 		dev_err(dev, "channel %d (req. host %d) already assigned to host %d\n",
396 			channel, host, intc->channel_host[channel].value);
397 		ret = -EBUSY;
398 		goto unlock;
399 	}
400 
401 	intc->event_channel[event].value = channel;
402 	intc->channel_host[channel].value = host;
403 
404 unlock:
405 	mutex_unlock(&intc->lock);
406 	return ret;
407 }
408 
409 static int
pruss_intc_irq_domain_xlate(struct irq_domain * d,struct device_node * node,const u32 * intspec,unsigned int intsize,unsigned long * out_hwirq,unsigned int * out_type)410 pruss_intc_irq_domain_xlate(struct irq_domain *d, struct device_node *node,
411 			    const u32 *intspec, unsigned int intsize,
412 			    unsigned long *out_hwirq, unsigned int *out_type)
413 {
414 	struct pruss_intc *intc = d->host_data;
415 	struct device *dev = intc->dev;
416 	int ret, sys_event, channel, host;
417 
418 	if (intsize < 3)
419 		return -EINVAL;
420 
421 	sys_event = intspec[0];
422 	if (sys_event < 0 || sys_event >= intc->soc_config->num_system_events) {
423 		dev_err(dev, "%d is not valid event number\n", sys_event);
424 		return -EINVAL;
425 	}
426 
427 	channel = intspec[1];
428 	if (channel < 0 || channel >= intc->soc_config->num_host_events) {
429 		dev_err(dev, "%d is not valid channel number", channel);
430 		return -EINVAL;
431 	}
432 
433 	host = intspec[2];
434 	if (host < 0 || host >= intc->soc_config->num_host_events) {
435 		dev_err(dev, "%d is not valid host irq number\n", host);
436 		return -EINVAL;
437 	}
438 
439 	/* check if requested sys_event was already mapped, if so validate it */
440 	ret = pruss_intc_validate_mapping(intc, sys_event, channel, host);
441 	if (ret)
442 		return ret;
443 
444 	*out_hwirq = sys_event;
445 	*out_type = IRQ_TYPE_LEVEL_HIGH;
446 
447 	return 0;
448 }
449 
pruss_intc_irq_domain_map(struct irq_domain * d,unsigned int virq,irq_hw_number_t hw)450 static int pruss_intc_irq_domain_map(struct irq_domain *d, unsigned int virq,
451 				     irq_hw_number_t hw)
452 {
453 	struct pruss_intc *intc = d->host_data;
454 
455 	pruss_intc_map(intc, hw);
456 
457 	irq_set_chip_data(virq, intc);
458 	irq_set_chip_and_handler(virq, &pruss_irqchip, handle_level_irq);
459 
460 	return 0;
461 }
462 
pruss_intc_irq_domain_unmap(struct irq_domain * d,unsigned int virq)463 static void pruss_intc_irq_domain_unmap(struct irq_domain *d, unsigned int virq)
464 {
465 	struct pruss_intc *intc = d->host_data;
466 	unsigned long hwirq = irqd_to_hwirq(irq_get_irq_data(virq));
467 
468 	irq_set_chip_and_handler(virq, NULL, NULL);
469 	irq_set_chip_data(virq, NULL);
470 	pruss_intc_unmap(intc, hwirq);
471 }
472 
473 static const struct irq_domain_ops pruss_intc_irq_domain_ops = {
474 	.xlate	= pruss_intc_irq_domain_xlate,
475 	.map	= pruss_intc_irq_domain_map,
476 	.unmap	= pruss_intc_irq_domain_unmap,
477 };
478 
pruss_intc_irq_handler(struct irq_desc * desc)479 static void pruss_intc_irq_handler(struct irq_desc *desc)
480 {
481 	unsigned int irq = irq_desc_get_irq(desc);
482 	struct irq_chip *chip = irq_desc_get_chip(desc);
483 	struct pruss_host_irq_data *host_irq_data = irq_get_handler_data(irq);
484 	struct pruss_intc *intc = host_irq_data->intc;
485 	u8 host_irq = host_irq_data->host_irq + FIRST_PRU_HOST_INT;
486 
487 	chained_irq_enter(chip, desc);
488 
489 	while (true) {
490 		u32 hipir;
491 		unsigned int virq;
492 		int hwirq;
493 
494 		/* get highest priority pending PRUSS system event */
495 		hipir = pruss_intc_read_reg(intc, PRU_INTC_HIPIR(host_irq));
496 		if (hipir & INTC_HIPIR_NONE_HINT)
497 			break;
498 
499 		hwirq = hipir & GENMASK(9, 0);
500 		virq = irq_find_mapping(intc->domain, hwirq);
501 
502 		/*
503 		 * NOTE: manually ACK any system events that do not have a
504 		 * handler mapped yet
505 		 */
506 		if (WARN_ON_ONCE(!virq))
507 			pruss_intc_write_reg(intc, PRU_INTC_SICR, hwirq);
508 		else
509 			generic_handle_irq(virq);
510 	}
511 
512 	chained_irq_exit(chip, desc);
513 }
514 
515 static const char * const irq_names[MAX_NUM_HOST_IRQS] = {
516 	"host_intr0", "host_intr1", "host_intr2", "host_intr3",
517 	"host_intr4", "host_intr5", "host_intr6", "host_intr7",
518 };
519 
pruss_intc_probe(struct platform_device * pdev)520 static int pruss_intc_probe(struct platform_device *pdev)
521 {
522 	const struct pruss_intc_match_data *data;
523 	struct device *dev = &pdev->dev;
524 	struct pruss_intc *intc;
525 	struct pruss_host_irq_data *host_data;
526 	int i, irq, ret;
527 	u8 max_system_events, irqs_reserved = 0;
528 
529 	data = of_device_get_match_data(dev);
530 	if (!data)
531 		return -ENODEV;
532 
533 	max_system_events = data->num_system_events;
534 
535 	intc = devm_kzalloc(dev, sizeof(*intc), GFP_KERNEL);
536 	if (!intc)
537 		return -ENOMEM;
538 
539 	intc->soc_config = data;
540 	intc->dev = dev;
541 	platform_set_drvdata(pdev, intc);
542 
543 	intc->base = devm_platform_ioremap_resource(pdev, 0);
544 	if (IS_ERR(intc->base))
545 		return PTR_ERR(intc->base);
546 
547 	ret = of_property_read_u8(dev->of_node, "ti,irqs-reserved",
548 				  &irqs_reserved);
549 
550 	/*
551 	 * The irqs-reserved is used only for some SoC's therefore not having
552 	 * this property is still valid
553 	 */
554 	if (ret < 0 && ret != -EINVAL)
555 		return ret;
556 
557 	pruss_intc_init(intc);
558 
559 	mutex_init(&intc->lock);
560 
561 	intc->domain = irq_domain_add_linear(dev->of_node, max_system_events,
562 					     &pruss_intc_irq_domain_ops, intc);
563 	if (!intc->domain)
564 		return -ENOMEM;
565 
566 	for (i = 0; i < MAX_NUM_HOST_IRQS; i++) {
567 		if (irqs_reserved & BIT(i))
568 			continue;
569 
570 		irq = platform_get_irq_byname(pdev, irq_names[i]);
571 		if (irq <= 0) {
572 			ret = (irq == 0) ? -EINVAL : irq;
573 			goto fail_irq;
574 		}
575 
576 		intc->irqs[i] = irq;
577 
578 		host_data = devm_kzalloc(dev, sizeof(*host_data), GFP_KERNEL);
579 		if (!host_data) {
580 			ret = -ENOMEM;
581 			goto fail_irq;
582 		}
583 
584 		host_data->intc = intc;
585 		host_data->host_irq = i;
586 
587 		irq_set_handler_data(irq, host_data);
588 		irq_set_chained_handler(irq, pruss_intc_irq_handler);
589 	}
590 
591 	return 0;
592 
593 fail_irq:
594 	while (--i >= 0) {
595 		if (intc->irqs[i])
596 			irq_set_chained_handler_and_data(intc->irqs[i], NULL,
597 							 NULL);
598 	}
599 
600 	irq_domain_remove(intc->domain);
601 
602 	return ret;
603 }
604 
pruss_intc_remove(struct platform_device * pdev)605 static int pruss_intc_remove(struct platform_device *pdev)
606 {
607 	struct pruss_intc *intc = platform_get_drvdata(pdev);
608 	u8 max_system_events = intc->soc_config->num_system_events;
609 	unsigned int hwirq;
610 	int i;
611 
612 	for (i = 0; i < MAX_NUM_HOST_IRQS; i++) {
613 		if (intc->irqs[i])
614 			irq_set_chained_handler_and_data(intc->irqs[i], NULL,
615 							 NULL);
616 	}
617 
618 	for (hwirq = 0; hwirq < max_system_events; hwirq++)
619 		irq_dispose_mapping(irq_find_mapping(intc->domain, hwirq));
620 
621 	irq_domain_remove(intc->domain);
622 
623 	return 0;
624 }
625 
626 static const struct pruss_intc_match_data pruss_intc_data = {
627 	.num_system_events = 64,
628 	.num_host_events = 10,
629 };
630 
631 static const struct pruss_intc_match_data icssg_intc_data = {
632 	.num_system_events = 160,
633 	.num_host_events = 20,
634 };
635 
636 static const struct of_device_id pruss_intc_of_match[] = {
637 	{
638 		.compatible = "ti,pruss-intc",
639 		.data = &pruss_intc_data,
640 	},
641 	{
642 		.compatible = "ti,icssg-intc",
643 		.data = &icssg_intc_data,
644 	},
645 	{ /* sentinel */ },
646 };
647 MODULE_DEVICE_TABLE(of, pruss_intc_of_match);
648 
649 static struct platform_driver pruss_intc_driver = {
650 	.driver = {
651 		.name = "pruss-intc",
652 		.of_match_table = pruss_intc_of_match,
653 		.suppress_bind_attrs = true,
654 	},
655 	.probe  = pruss_intc_probe,
656 	.remove = pruss_intc_remove,
657 };
658 module_platform_driver(pruss_intc_driver);
659 
660 MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
661 MODULE_AUTHOR("Suman Anna <s-anna@ti.com>");
662 MODULE_AUTHOR("Grzegorz Jaszczyk <grzegorz.jaszczyk@linaro.org>");
663 MODULE_DESCRIPTION("TI PRU-ICSS INTC Driver");
664 MODULE_LICENSE("GPL v2");
665