xref: /openbmc/linux/drivers/irqchip/irq-or1k-pic.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
24db8e6d2SStefan Kristiansson /*
34db8e6d2SStefan Kristiansson  * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
44db8e6d2SStefan Kristiansson  * Copyright (C) 2014 Stefan Kristansson <stefan.kristiansson@saunalahti.fi>
54db8e6d2SStefan Kristiansson  */
64db8e6d2SStefan Kristiansson 
74db8e6d2SStefan Kristiansson #include <linux/irq.h>
841a83e06SJoel Porquet #include <linux/irqchip.h>
94db8e6d2SStefan Kristiansson #include <linux/of.h>
104db8e6d2SStefan Kristiansson #include <linux/of_irq.h>
114db8e6d2SStefan Kristiansson #include <linux/of_address.h>
124db8e6d2SStefan Kristiansson 
134db8e6d2SStefan Kristiansson /* OR1K PIC implementation */
144db8e6d2SStefan Kristiansson 
154db8e6d2SStefan Kristiansson struct or1k_pic_dev {
164db8e6d2SStefan Kristiansson 	struct irq_chip chip;
174db8e6d2SStefan Kristiansson 	irq_flow_handler_t handle;
184db8e6d2SStefan Kristiansson 	unsigned long flags;
194db8e6d2SStefan Kristiansson };
204db8e6d2SStefan Kristiansson 
214db8e6d2SStefan Kristiansson /*
224db8e6d2SStefan Kristiansson  * We're a couple of cycles faster than the generic implementations with
234db8e6d2SStefan Kristiansson  * these 'fast' versions.
244db8e6d2SStefan Kristiansson  */
254db8e6d2SStefan Kristiansson 
or1k_pic_mask(struct irq_data * data)264db8e6d2SStefan Kristiansson static void or1k_pic_mask(struct irq_data *data)
274db8e6d2SStefan Kristiansson {
284db8e6d2SStefan Kristiansson 	mtspr(SPR_PICMR, mfspr(SPR_PICMR) & ~(1UL << data->hwirq));
294db8e6d2SStefan Kristiansson }
304db8e6d2SStefan Kristiansson 
or1k_pic_unmask(struct irq_data * data)314db8e6d2SStefan Kristiansson static void or1k_pic_unmask(struct irq_data *data)
324db8e6d2SStefan Kristiansson {
334db8e6d2SStefan Kristiansson 	mtspr(SPR_PICMR, mfspr(SPR_PICMR) | (1UL << data->hwirq));
344db8e6d2SStefan Kristiansson }
354db8e6d2SStefan Kristiansson 
or1k_pic_ack(struct irq_data * data)364db8e6d2SStefan Kristiansson static void or1k_pic_ack(struct irq_data *data)
374db8e6d2SStefan Kristiansson {
384db8e6d2SStefan Kristiansson 	mtspr(SPR_PICSR, (1UL << data->hwirq));
394db8e6d2SStefan Kristiansson }
404db8e6d2SStefan Kristiansson 
or1k_pic_mask_ack(struct irq_data * data)414db8e6d2SStefan Kristiansson static void or1k_pic_mask_ack(struct irq_data *data)
424db8e6d2SStefan Kristiansson {
434db8e6d2SStefan Kristiansson 	mtspr(SPR_PICMR, mfspr(SPR_PICMR) & ~(1UL << data->hwirq));
444db8e6d2SStefan Kristiansson 	mtspr(SPR_PICSR, (1UL << data->hwirq));
454db8e6d2SStefan Kristiansson }
464db8e6d2SStefan Kristiansson 
474db8e6d2SStefan Kristiansson /*
484db8e6d2SStefan Kristiansson  * There are two oddities with the OR1200 PIC implementation:
494db8e6d2SStefan Kristiansson  * i)  LEVEL-triggered interrupts are latched and need to be cleared
504db8e6d2SStefan Kristiansson  * ii) the interrupt latch is cleared by writing a 0 to the bit,
514db8e6d2SStefan Kristiansson  *     as opposed to a 1 as mandated by the spec
524db8e6d2SStefan Kristiansson  */
or1k_pic_or1200_ack(struct irq_data * data)534db8e6d2SStefan Kristiansson static void or1k_pic_or1200_ack(struct irq_data *data)
544db8e6d2SStefan Kristiansson {
554db8e6d2SStefan Kristiansson 	mtspr(SPR_PICSR, mfspr(SPR_PICSR) & ~(1UL << data->hwirq));
564db8e6d2SStefan Kristiansson }
574db8e6d2SStefan Kristiansson 
or1k_pic_or1200_mask_ack(struct irq_data * data)584db8e6d2SStefan Kristiansson static void or1k_pic_or1200_mask_ack(struct irq_data *data)
594db8e6d2SStefan Kristiansson {
604db8e6d2SStefan Kristiansson 	mtspr(SPR_PICMR, mfspr(SPR_PICMR) & ~(1UL << data->hwirq));
614db8e6d2SStefan Kristiansson 	mtspr(SPR_PICSR, mfspr(SPR_PICSR) & ~(1UL << data->hwirq));
624db8e6d2SStefan Kristiansson }
634db8e6d2SStefan Kristiansson 
644db8e6d2SStefan Kristiansson static struct or1k_pic_dev or1k_pic_level = {
654db8e6d2SStefan Kristiansson 	.chip = {
664db8e6d2SStefan Kristiansson 		.name = "or1k-PIC-level",
674db8e6d2SStefan Kristiansson 		.irq_unmask = or1k_pic_unmask,
684db8e6d2SStefan Kristiansson 		.irq_mask = or1k_pic_mask,
694db8e6d2SStefan Kristiansson 	},
704db8e6d2SStefan Kristiansson 	.handle = handle_level_irq,
714db8e6d2SStefan Kristiansson 	.flags = IRQ_LEVEL | IRQ_NOPROBE,
724db8e6d2SStefan Kristiansson };
734db8e6d2SStefan Kristiansson 
744db8e6d2SStefan Kristiansson static struct or1k_pic_dev or1k_pic_edge = {
754db8e6d2SStefan Kristiansson 	.chip = {
764db8e6d2SStefan Kristiansson 		.name = "or1k-PIC-edge",
774db8e6d2SStefan Kristiansson 		.irq_unmask = or1k_pic_unmask,
784db8e6d2SStefan Kristiansson 		.irq_mask = or1k_pic_mask,
794db8e6d2SStefan Kristiansson 		.irq_ack = or1k_pic_ack,
804db8e6d2SStefan Kristiansson 		.irq_mask_ack = or1k_pic_mask_ack,
814db8e6d2SStefan Kristiansson 	},
824db8e6d2SStefan Kristiansson 	.handle = handle_edge_irq,
834db8e6d2SStefan Kristiansson 	.flags = IRQ_LEVEL | IRQ_NOPROBE,
844db8e6d2SStefan Kristiansson };
854db8e6d2SStefan Kristiansson 
864db8e6d2SStefan Kristiansson static struct or1k_pic_dev or1k_pic_or1200 = {
874db8e6d2SStefan Kristiansson 	.chip = {
884db8e6d2SStefan Kristiansson 		.name = "or1200-PIC",
894db8e6d2SStefan Kristiansson 		.irq_unmask = or1k_pic_unmask,
904db8e6d2SStefan Kristiansson 		.irq_mask = or1k_pic_mask,
914db8e6d2SStefan Kristiansson 		.irq_ack = or1k_pic_or1200_ack,
924db8e6d2SStefan Kristiansson 		.irq_mask_ack = or1k_pic_or1200_mask_ack,
934db8e6d2SStefan Kristiansson 	},
944db8e6d2SStefan Kristiansson 	.handle = handle_level_irq,
954db8e6d2SStefan Kristiansson 	.flags = IRQ_LEVEL | IRQ_NOPROBE,
964db8e6d2SStefan Kristiansson };
974db8e6d2SStefan Kristiansson 
984db8e6d2SStefan Kristiansson static struct irq_domain *root_domain;
994db8e6d2SStefan Kristiansson 
pic_get_irq(int first)1004db8e6d2SStefan Kristiansson static inline int pic_get_irq(int first)
1014db8e6d2SStefan Kristiansson {
1024db8e6d2SStefan Kristiansson 	int hwirq;
1034db8e6d2SStefan Kristiansson 
1044db8e6d2SStefan Kristiansson 	hwirq = ffs(mfspr(SPR_PICSR) >> first);
1054db8e6d2SStefan Kristiansson 	if (!hwirq)
1064db8e6d2SStefan Kristiansson 		return NO_IRQ;
1074db8e6d2SStefan Kristiansson 	else
1084db8e6d2SStefan Kristiansson 		hwirq = hwirq + first - 1;
1094db8e6d2SStefan Kristiansson 
110b0fee1dcSMarc Zyngier 	return hwirq;
1114db8e6d2SStefan Kristiansson }
1124db8e6d2SStefan Kristiansson 
or1k_pic_handle_irq(struct pt_regs * regs)1134db8e6d2SStefan Kristiansson static void or1k_pic_handle_irq(struct pt_regs *regs)
1144db8e6d2SStefan Kristiansson {
1154db8e6d2SStefan Kristiansson 	int irq = -1;
1164db8e6d2SStefan Kristiansson 
1174db8e6d2SStefan Kristiansson 	while ((irq = pic_get_irq(irq + 1)) != NO_IRQ)
118*0953fb26SMark Rutland 		generic_handle_domain_irq(root_domain, irq);
1194db8e6d2SStefan Kristiansson }
1204db8e6d2SStefan Kristiansson 
or1k_map(struct irq_domain * d,unsigned int irq,irq_hw_number_t hw)1214db8e6d2SStefan Kristiansson static int or1k_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
1224db8e6d2SStefan Kristiansson {
1234db8e6d2SStefan Kristiansson 	struct or1k_pic_dev *pic = d->host_data;
1244db8e6d2SStefan Kristiansson 
1254db8e6d2SStefan Kristiansson 	irq_set_chip_and_handler(irq, &pic->chip, pic->handle);
1264db8e6d2SStefan Kristiansson 	irq_set_status_flags(irq, pic->flags);
1274db8e6d2SStefan Kristiansson 
1284db8e6d2SStefan Kristiansson 	return 0;
1294db8e6d2SStefan Kristiansson }
1304db8e6d2SStefan Kristiansson 
1314db8e6d2SStefan Kristiansson static const struct irq_domain_ops or1k_irq_domain_ops = {
1324db8e6d2SStefan Kristiansson 	.xlate = irq_domain_xlate_onecell,
1334db8e6d2SStefan Kristiansson 	.map = or1k_map,
1344db8e6d2SStefan Kristiansson };
1354db8e6d2SStefan Kristiansson 
1364db8e6d2SStefan Kristiansson /*
1374db8e6d2SStefan Kristiansson  * This sets up the IRQ domain for the PIC built in to the OpenRISC
1384db8e6d2SStefan Kristiansson  * 1000 CPU.  This is the "root" domain as these are the interrupts
1394db8e6d2SStefan Kristiansson  * that directly trigger an exception in the CPU.
1404db8e6d2SStefan Kristiansson  */
or1k_pic_init(struct device_node * node,struct or1k_pic_dev * pic)1414db8e6d2SStefan Kristiansson static int __init or1k_pic_init(struct device_node *node,
1424db8e6d2SStefan Kristiansson 				 struct or1k_pic_dev *pic)
1434db8e6d2SStefan Kristiansson {
1444db8e6d2SStefan Kristiansson 	/* Disable all interrupts until explicitly requested */
1454db8e6d2SStefan Kristiansson 	mtspr(SPR_PICMR, (0UL));
1464db8e6d2SStefan Kristiansson 
1474db8e6d2SStefan Kristiansson 	root_domain = irq_domain_add_linear(node, 32, &or1k_irq_domain_ops,
1484db8e6d2SStefan Kristiansson 					    pic);
1494db8e6d2SStefan Kristiansson 
1504db8e6d2SStefan Kristiansson 	set_handle_irq(or1k_pic_handle_irq);
1514db8e6d2SStefan Kristiansson 
1524db8e6d2SStefan Kristiansson 	return 0;
1534db8e6d2SStefan Kristiansson }
1544db8e6d2SStefan Kristiansson 
or1k_pic_or1200_init(struct device_node * node,struct device_node * parent)1554db8e6d2SStefan Kristiansson static int __init or1k_pic_or1200_init(struct device_node *node,
1564db8e6d2SStefan Kristiansson 				       struct device_node *parent)
1574db8e6d2SStefan Kristiansson {
1584db8e6d2SStefan Kristiansson 	return or1k_pic_init(node, &or1k_pic_or1200);
1594db8e6d2SStefan Kristiansson }
1604db8e6d2SStefan Kristiansson IRQCHIP_DECLARE(or1k_pic_or1200, "opencores,or1200-pic", or1k_pic_or1200_init);
1614db8e6d2SStefan Kristiansson IRQCHIP_DECLARE(or1k_pic, "opencores,or1k-pic", or1k_pic_or1200_init);
1624db8e6d2SStefan Kristiansson 
or1k_pic_level_init(struct device_node * node,struct device_node * parent)1634db8e6d2SStefan Kristiansson static int __init or1k_pic_level_init(struct device_node *node,
1644db8e6d2SStefan Kristiansson 				      struct device_node *parent)
1654db8e6d2SStefan Kristiansson {
1664db8e6d2SStefan Kristiansson 	return or1k_pic_init(node, &or1k_pic_level);
1674db8e6d2SStefan Kristiansson }
1684db8e6d2SStefan Kristiansson IRQCHIP_DECLARE(or1k_pic_level, "opencores,or1k-pic-level",
1694db8e6d2SStefan Kristiansson 		or1k_pic_level_init);
1704db8e6d2SStefan Kristiansson 
or1k_pic_edge_init(struct device_node * node,struct device_node * parent)1714db8e6d2SStefan Kristiansson static int __init or1k_pic_edge_init(struct device_node *node,
1724db8e6d2SStefan Kristiansson 				     struct device_node *parent)
1734db8e6d2SStefan Kristiansson {
1744db8e6d2SStefan Kristiansson 	return or1k_pic_init(node, &or1k_pic_edge);
1754db8e6d2SStefan Kristiansson }
1764db8e6d2SStefan Kristiansson IRQCHIP_DECLARE(or1k_pic_edge, "opencores,or1k-pic-edge", or1k_pic_edge_init);
177