CC devicetree for the bindings On Mon, May 26, 2014 at 10:31 PM, Stefan Kristiansson <stefan.kristiansson@xxxxxxxxxxxxx> wrote: > In addition to consolidating the or1k-pic with other interrupt > controllers, this makes OpenRISC less tied to its on-cpu > interrupt controller. > > All or1k-pic specific parts are moved out of irq.c and into > drivers/irqchip/irq-or1k-pic.c > > In that transition, the funtionality have been divided into > three chip variants. > One that handles level triggered interrupts, one that handles edge > triggered interrupts and one that handles the interrupt > controller that is present in the or1200 OpenRISC cpu > implementation. > > Signed-off-by: Stefan Kristiansson <stefan.kristiansson@xxxxxxxxxxxxx> > --- > Changes in v2: > - Move or1k-pic related code into irq-or1k-pic > - Add documentation for device tree bindings > > Changes in v3: > - Split level-, edge-triggered and or1200 implementation into seperate > chip variants. > > Changes in v4: > - Fix typos in documentation > --- > .../interrupt-controller/opencores,or1k-pic.txt | 23 +++ > arch/openrisc/Kconfig | 1 + > arch/openrisc/include/asm/irq.h | 3 + > arch/openrisc/kernel/irq.c | 146 ++--------------- > drivers/irqchip/Kconfig | 4 + > drivers/irqchip/Makefile | 1 + > drivers/irqchip/irq-or1k-pic.c | 182 +++++++++++++++++++++ > 7 files changed, 227 insertions(+), 133 deletions(-) > create mode 100644 Documentation/devicetree/bindings/interrupt-controller/opencores,or1k-pic.txt > create mode 100644 drivers/irqchip/irq-or1k-pic.c > > diff --git a/Documentation/devicetree/bindings/interrupt-controller/opencores,or1k-pic.txt b/Documentation/devicetree/bindings/interrupt-controller/opencores,or1k-pic.txt > new file mode 100644 > index 0000000..55c04fa > --- /dev/null > +++ b/Documentation/devicetree/bindings/interrupt-controller/opencores,or1k-pic.txt > @@ -0,0 +1,23 @@ > +OpenRISC 1000 Programmable Interrupt Controller > + > +Required properties: > + > +- compatible : should be "opencores,or1k-pic-level" for variants with > + level triggered interrupt lines, "opencores,or1k-pic-edge" for variants with > + edge triggered interrupt lines or "opencores,or1200-pic" for machines > + with the non-spec compliant or1200 type implementation. > + > + "opencores,or1k-pic" is also provided as an alias to "opencores,or1200-pic", > + but this is only for backwards compatibility. > + > +- interrupt-controller : Identifies the node as an interrupt controller > +- #interrupt-cells : Specifies the number of cells needed to encode an > + interrupt source. The value shall be 1. > + > +Example: > + > +intc: interrupt-controller { > + compatible = "opencores,or1k-pic-level"; > + interrupt-controller; > + #interrupt-cells = <1>; > +}; > diff --git a/arch/openrisc/Kconfig b/arch/openrisc/Kconfig > index e71d712..88e8336 100644 > --- a/arch/openrisc/Kconfig > +++ b/arch/openrisc/Kconfig > @@ -22,6 +22,7 @@ config OPENRISC > select GENERIC_STRNLEN_USER > select MODULES_USE_ELF_RELA > select HAVE_DEBUG_STACKOVERFLOW > + select OR1K_PIC > > config MMU > def_bool y > diff --git a/arch/openrisc/include/asm/irq.h b/arch/openrisc/include/asm/irq.h > index eb612b1..b84634c 100644 > --- a/arch/openrisc/include/asm/irq.h > +++ b/arch/openrisc/include/asm/irq.h > @@ -24,4 +24,7 @@ > > #define NO_IRQ (-1) > > +void handle_IRQ(unsigned int, struct pt_regs *); > +extern void set_handle_irq(void (*handle_irq)(struct pt_regs *)); > + > #endif /* __ASM_OPENRISC_IRQ_H__ */ > diff --git a/arch/openrisc/kernel/irq.c b/arch/openrisc/kernel/irq.c > index 8ec77bc..967eb14 100644 > --- a/arch/openrisc/kernel/irq.c > +++ b/arch/openrisc/kernel/irq.c > @@ -16,11 +16,10 @@ > > #include <linux/interrupt.h> > #include <linux/init.h> > -#include <linux/of.h> > #include <linux/ftrace.h> > #include <linux/irq.h> > +#include <linux/irqchip.h> > #include <linux/export.h> > -#include <linux/irqdomain.h> > #include <linux/irqflags.h> > > /* read interrupt enabled status */ > @@ -37,150 +36,31 @@ void arch_local_irq_restore(unsigned long flags) > } > EXPORT_SYMBOL(arch_local_irq_restore); > > - > -/* OR1K PIC implementation */ > - > -/* We're a couple of cycles faster than the generic implementations with > - * these 'fast' versions. > - */ > - > -static void or1k_pic_mask(struct irq_data *data) > -{ > - mtspr(SPR_PICMR, mfspr(SPR_PICMR) & ~(1UL << data->hwirq)); > -} > - > -static void or1k_pic_unmask(struct irq_data *data) > -{ > - mtspr(SPR_PICMR, mfspr(SPR_PICMR) | (1UL << data->hwirq)); > -} > - > -static void or1k_pic_ack(struct irq_data *data) > -{ > - /* EDGE-triggered interrupts need to be ack'ed in order to clear > - * the latch. > - * LEVEL-triggered interrupts do not need to be ack'ed; however, > - * ack'ing the interrupt has no ill-effect and is quicker than > - * trying to figure out what type it is... > - */ > - > - /* The OpenRISC 1000 spec says to write a 1 to the bit to ack the > - * interrupt, but the OR1200 does this backwards and requires a 0 > - * to be written... > - */ > - > -#ifdef CONFIG_OR1K_1200 > - /* There are two oddities with the OR1200 PIC implementation: > - * i) LEVEL-triggered interrupts are latched and need to be cleared > - * ii) the interrupt latch is cleared by writing a 0 to the bit, > - * as opposed to a 1 as mandated by the spec > - */ > - > - mtspr(SPR_PICSR, mfspr(SPR_PICSR) & ~(1UL << data->hwirq)); > -#else > - WARN(1, "Interrupt handling possibly broken\n"); > - mtspr(SPR_PICSR, (1UL << data->hwirq)); > -#endif > -} > - > -static void or1k_pic_mask_ack(struct irq_data *data) > -{ > - /* Comments for pic_ack apply here, too */ > - > -#ifdef CONFIG_OR1K_1200 > - mtspr(SPR_PICMR, mfspr(SPR_PICMR) & ~(1UL << data->hwirq)); > - mtspr(SPR_PICSR, mfspr(SPR_PICSR) & ~(1UL << data->hwirq)); > -#else > - WARN(1, "Interrupt handling possibly broken\n"); > - mtspr(SPR_PICMR, (1UL << data->hwirq)); > - mtspr(SPR_PICSR, (1UL << data->hwirq)); > -#endif > -} > - > -#if 0 > -static int or1k_pic_set_type(struct irq_data *data, unsigned int flow_type) > -{ > - /* There's nothing to do in the PIC configuration when changing > - * flow type. Level and edge-triggered interrupts are both > - * supported, but it's PIC-implementation specific which type > - * is handled. */ > - > - return irq_setup_alt_chip(data, flow_type); > -} > -#endif > - > -static struct irq_chip or1k_dev = { > - .name = "or1k-PIC", > - .irq_unmask = or1k_pic_unmask, > - .irq_mask = or1k_pic_mask, > - .irq_ack = or1k_pic_ack, > - .irq_mask_ack = or1k_pic_mask_ack, > -}; > - > -static struct irq_domain *root_domain; > - > -static inline int pic_get_irq(int first) > -{ > - int hwirq; > - > - hwirq = ffs(mfspr(SPR_PICSR) >> first); > - if (!hwirq) > - return NO_IRQ; > - else > - hwirq = hwirq + first -1; > - > - return irq_find_mapping(root_domain, hwirq); > -} > - > - > -static int or1k_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) > +void __init init_IRQ(void) > { > - irq_set_chip_and_handler_name(irq, &or1k_dev, > - handle_level_irq, "level"); > - irq_set_status_flags(irq, IRQ_LEVEL | IRQ_NOPROBE); > - > - return 0; > + irqchip_init(); > } > > -static const struct irq_domain_ops or1k_irq_domain_ops = { > - .xlate = irq_domain_xlate_onecell, > - .map = or1k_map, > -}; > - > -/* > - * This sets up the IRQ domain for the PIC built in to the OpenRISC > - * 1000 CPU. This is the "root" domain as these are the interrupts > - * that directly trigger an exception in the CPU. > - */ > -static void __init or1k_irq_init(void) > -{ > - struct device_node *intc = NULL; > - > - /* The interrupt controller device node is mandatory */ > - intc = of_find_compatible_node(NULL, NULL, "opencores,or1k-pic"); > - BUG_ON(!intc); > - > - /* Disable all interrupts until explicitly requested */ > - mtspr(SPR_PICMR, (0UL)); > - > - root_domain = irq_domain_add_linear(intc, 32, > - &or1k_irq_domain_ops, NULL); > -} > +static void (*handle_arch_irq)(struct pt_regs *); > > -void __init init_IRQ(void) > +void __init set_handle_irq(void (*handle_irq)(struct pt_regs *)) > { > - or1k_irq_init(); > + handle_arch_irq = handle_irq; > } > > -void __irq_entry do_IRQ(struct pt_regs *regs) > +void handle_IRQ(unsigned int irq, struct pt_regs *regs) > { > - int irq = -1; > struct pt_regs *old_regs = set_irq_regs(regs); > > irq_enter(); > > - while ((irq = pic_get_irq(irq + 1)) != NO_IRQ) > - generic_handle_irq(irq); > + generic_handle_irq(irq); > > irq_exit(); > set_irq_regs(old_regs); > } > + > +void __irq_entry do_IRQ(struct pt_regs *regs) > +{ > + handle_arch_irq(regs); > +} > diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig > index d770f74..f06e4c8 100644 > --- a/drivers/irqchip/Kconfig > +++ b/drivers/irqchip/Kconfig > @@ -47,6 +47,10 @@ config CLPS711X_IRQCHIP > select SPARSE_IRQ > default y > > +config OR1K_PIC > + bool > + select IRQ_DOMAIN > + > config ORION_IRQCHIP > bool > select IRQ_DOMAIN > diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile > index f180f8d..4377695 100644 > --- a/drivers/irqchip/Makefile > +++ b/drivers/irqchip/Makefile > @@ -11,6 +11,7 @@ obj-$(CONFIG_METAG) += irq-metag-ext.o > obj-$(CONFIG_METAG_PERFCOUNTER_IRQS) += irq-metag.o > obj-$(CONFIG_ARCH_MOXART) += irq-moxart.o > obj-$(CONFIG_CLPS711X_IRQCHIP) += irq-clps711x.o > +obj-$(CONFIG_OR1K_PIC) += irq-or1k-pic.o > obj-$(CONFIG_ORION_IRQCHIP) += irq-orion.o > obj-$(CONFIG_ARCH_SUNXI) += irq-sun4i.o > obj-$(CONFIG_ARCH_SUNXI) += irq-sunxi-nmi.o > diff --git a/drivers/irqchip/irq-or1k-pic.c b/drivers/irqchip/irq-or1k-pic.c > new file mode 100644 > index 0000000..17ff033 > --- /dev/null > +++ b/drivers/irqchip/irq-or1k-pic.c > @@ -0,0 +1,182 @@ > +/* > + * Copyright (C) 2010-2011 Jonas Bonn <jonas@xxxxxxxxxxxx> > + * Copyright (C) 2014 Stefan Kristansson <stefan.kristiansson@xxxxxxxxxxxxx> > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License > + * as published by the Free Software Foundation; either version > + * 2 of the License, or (at your option) any later version. > + */ > + > +#include <linux/irq.h> > +#include <linux/of.h> > +#include <linux/of_irq.h> > +#include <linux/of_address.h> > + > +#include "irqchip.h" > + > +/* OR1K PIC implementation */ > + > +struct or1k_pic_dev { > + struct irq_chip chip; > + irq_flow_handler_t handle; > + unsigned long flags; > +}; > + > +/* > + * We're a couple of cycles faster than the generic implementations with > + * these 'fast' versions. > + */ > + > +static void or1k_pic_mask(struct irq_data *data) > +{ > + mtspr(SPR_PICMR, mfspr(SPR_PICMR) & ~(1UL << data->hwirq)); > +} > + > +static void or1k_pic_unmask(struct irq_data *data) > +{ > + mtspr(SPR_PICMR, mfspr(SPR_PICMR) | (1UL << data->hwirq)); > +} > + > +static void or1k_pic_ack(struct irq_data *data) > +{ > + mtspr(SPR_PICSR, (1UL << data->hwirq)); > +} > + > +static void or1k_pic_mask_ack(struct irq_data *data) > +{ > + mtspr(SPR_PICMR, mfspr(SPR_PICMR) & ~(1UL << data->hwirq)); > + mtspr(SPR_PICSR, (1UL << data->hwirq)); > +} > + > +/* > + * There are two oddities with the OR1200 PIC implementation: > + * i) LEVEL-triggered interrupts are latched and need to be cleared > + * ii) the interrupt latch is cleared by writing a 0 to the bit, > + * as opposed to a 1 as mandated by the spec > + */ > +static void or1k_pic_or1200_ack(struct irq_data *data) > +{ > + mtspr(SPR_PICSR, mfspr(SPR_PICSR) & ~(1UL << data->hwirq)); > +} > + > +static void or1k_pic_or1200_mask_ack(struct irq_data *data) > +{ > + mtspr(SPR_PICMR, mfspr(SPR_PICMR) & ~(1UL << data->hwirq)); > + mtspr(SPR_PICSR, mfspr(SPR_PICSR) & ~(1UL << data->hwirq)); > +} > + > +static struct or1k_pic_dev or1k_pic_level = { > + .chip = { > + .name = "or1k-PIC-level", > + .irq_unmask = or1k_pic_unmask, > + .irq_mask = or1k_pic_mask, > + .irq_mask_ack = or1k_pic_mask, > + }, > + .handle = handle_level_irq, > + .flags = IRQ_LEVEL | IRQ_NOPROBE, > +}; > + > +static struct or1k_pic_dev or1k_pic_edge = { > + .chip = { > + .name = "or1k-PIC-edge", > + .irq_unmask = or1k_pic_unmask, > + .irq_mask = or1k_pic_mask, > + .irq_ack = or1k_pic_ack, > + .irq_mask_ack = or1k_pic_mask_ack, > + }, > + .handle = handle_edge_irq, > + .flags = IRQ_LEVEL | IRQ_NOPROBE, > +}; > + > +static struct or1k_pic_dev or1k_pic_or1200 = { > + .chip = { > + .name = "or1200-PIC", > + .irq_unmask = or1k_pic_unmask, > + .irq_mask = or1k_pic_mask, > + .irq_ack = or1k_pic_or1200_ack, > + .irq_mask_ack = or1k_pic_or1200_mask_ack, > + }, > + .handle = handle_level_irq, > + .flags = IRQ_LEVEL | IRQ_NOPROBE, > +}; > + > +static struct irq_domain *root_domain; > + > +static inline int pic_get_irq(int first) > +{ > + int hwirq; > + > + hwirq = ffs(mfspr(SPR_PICSR) >> first); > + if (!hwirq) > + return NO_IRQ; > + else > + hwirq = hwirq + first - 1; > + > + return irq_find_mapping(root_domain, hwirq); > +} > + > +static void or1k_pic_handle_irq(struct pt_regs *regs) > +{ > + int irq = -1; > + > + while ((irq = pic_get_irq(irq + 1)) != NO_IRQ) > + handle_IRQ(irq, regs); > +} > + > +static int or1k_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) > +{ > + struct or1k_pic_dev *pic = d->host_data; > + > + irq_set_chip_and_handler(irq, &pic->chip, pic->handle); > + irq_set_status_flags(irq, pic->flags); > + > + return 0; > +} > + > +static const struct irq_domain_ops or1k_irq_domain_ops = { > + .xlate = irq_domain_xlate_onecell, > + .map = or1k_map, > +}; > + > +/* > + * This sets up the IRQ domain for the PIC built in to the OpenRISC > + * 1000 CPU. This is the "root" domain as these are the interrupts > + * that directly trigger an exception in the CPU. > + */ > +static int __init or1k_pic_init(struct device_node *node, > + struct or1k_pic_dev *pic) > +{ > + /* Disable all interrupts until explicitly requested */ > + mtspr(SPR_PICMR, (0UL)); > + > + root_domain = irq_domain_add_linear(node, 32, &or1k_irq_domain_ops, > + pic); > + > + set_handle_irq(or1k_pic_handle_irq); > + > + return 0; > +} > + > +static int __init or1k_pic_or1200_init(struct device_node *node, > + struct device_node *parent) > +{ > + return or1k_pic_init(node, &or1k_pic_or1200); > +} > +IRQCHIP_DECLARE(or1k_pic_or1200, "opencores,or1200-pic", or1k_pic_or1200_init); > +IRQCHIP_DECLARE(or1k_pic, "opencores,or1k-pic", or1k_pic_or1200_init); > + > +static int __init or1k_pic_level_init(struct device_node *node, > + struct device_node *parent) > +{ > + return or1k_pic_init(node, &or1k_pic_level); > +} > +IRQCHIP_DECLARE(or1k_pic_level, "opencores,or1k-pic-level", > + or1k_pic_level_init); > + > +static int __init or1k_pic_edge_init(struct device_node *node, > + struct device_node *parent) > +{ > + return or1k_pic_init(node, &or1k_pic_edge); > +} > +IRQCHIP_DECLARE(or1k_pic_edge, "opencores,or1k-pic-edge", or1k_pic_edge_init); > -- > 1.8.3.2 > -- Gr{oetje,eeting}s, Geert -- Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@xxxxxxxxxxxxxx In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that. -- Linus Torvalds -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html