Subject: [Patch v5 00/12] microblaze/MIPS/PowerPC: Xilinx intc

Hi,

The MIPS based Xilfpga platform uses the axi interrupt controller
daisy chained to the MIPS microAptiv cpu interrupt controller.
This patch series moves the axi interrupt controller driver out
of arch/microblaze to drivers/irqchip and then cleans it up a bit.
And then remove another implementation of the driver in arch/powerpc.
This makes one common driver usable by mips,microblaze and powerpc.
The rest of the series basically enables drivers and adds dt nodes.

Would make sense for this to go via the MIPS tree.
Hence, ACKs from microblaze, powerpc and irqchip welcome.

Compile tested on microblaze-el.
Tested using qemu-system-ppc using virtix440-ml507

Based on v4.9-rc1

Regards,
ZubairLK

V4 -> V5
Added a new patch that removes the PPC driver
Rebase to v4.9-rc1
Better error handling

V3 -> V4
Better error handling
Some minor fixups

V2 -> V3
Cleanup the interrupt controller driver a bit based on feedback
Rebase to v4.8-rc4

V1 -> V2
Resubmitting without truncating the diff output for file moves
Removed accidental local mac address entry
Individual logs have more detail


Zubair Lutfullah Kakakhel (12):
microblaze: irqchip: Move intc driver to irqchip
irqchip: xilinx: Clean up irqdomain argument and read/write
irqchip: xilinx: Rename get_irq to xintc_get_irq
irqchip: xilinx: Add support for parent intc
irqchip: xilinx: Try to fall back if xlnx,kind-of-intr not provided
powerpc/virtex: Use generic xilinx irqchip driver
MIPS: xilfpga: Use irqchip instead of the legacy way
MIPS: xilfpga: Use Xilinx Interrupt Controller
MIPS: xilfpga: Update DT node and specify uart irq
MIPS: xilfpga: Add DT node for AXI I2C
MIPS: xilfpga: Add DT node for AXI emaclite
MIPS: xilfpga: Update defconfig

arch/microblaze/Kconfig | 1 +
arch/microblaze/include/asm/irq.h | 2 +-
arch/microblaze/kernel/Makefile | 2 +-
arch/microblaze/kernel/intc.c | 196 -----------------------
arch/microblaze/kernel/irq.c | 4 +-
arch/mips/Kconfig | 1 +
arch/mips/boot/dts/xilfpga/nexys4ddr.dts | 63 ++++++++
arch/mips/configs/xilfpga_defconfig | 37 ++++-
arch/mips/xilfpga/intc.c | 7 +-
arch/powerpc/include/asm/xilinx_intc.h | 2 +-
arch/powerpc/platforms/40x/Kconfig | 1 +
arch/powerpc/platforms/40x/virtex.c | 2 +-
arch/powerpc/platforms/44x/Kconfig | 1 +
arch/powerpc/platforms/44x/virtex.c | 2 +-
arch/powerpc/sysdev/xilinx_intc.c | 211 +------------------------
drivers/irqchip/Kconfig | 4 +
drivers/irqchip/Makefile | 1 +
drivers/irqchip/irq-xilinx-intc.c | 258 +++++++++++++++++++++++++++++++
18 files changed, 377 insertions(+), 418 deletions(-)
delete mode 100644 arch/microblaze/kernel/intc.c
create mode 100644 drivers/irqchip/irq-xilinx-intc.c

--
1.9.1


Subject: [Patch v5 01/12] microblaze: irqchip: Move intc driver to irqchip

The Xilinx AXI Interrupt Controller IP block is used by the MIPS
based xilfpga platform and a few PowerPC based platforms.

Move the interrupt controller code out of arch/microblaze so that
it can be used by everyone

Signed-off-by: Zubair Lutfullah Kakakhel <[email protected]>

---
V4 -> V5
Rebase to v4.9-rc1
Renamed back to irq-xilinx-intc.c

V3 -> V4
No change

V2 -> V3
No change here. Cleanup patches follow after this patch.
Its debatable to cleanup before/after move. Decided to place cleanup
after move to put history in new place.

V1 -> V2

Renamed irq-xilinx to irq-axi-intc
Renamed CONFIG_XILINX_INTC to CONFIG_XILINX_AXI_INTC
Patch is now without rename flag so as to facilitate review
---
arch/microblaze/Kconfig | 1 +
arch/microblaze/kernel/Makefile | 2 +-
arch/microblaze/kernel/intc.c | 196 --------------------------------------
drivers/irqchip/Kconfig | 4 +
drivers/irqchip/Makefile | 1 +
drivers/irqchip/irq-xilinx-intc.c | 196 ++++++++++++++++++++++++++++++++++++++
6 files changed, 203 insertions(+), 197 deletions(-)
delete mode 100644 arch/microblaze/kernel/intc.c
create mode 100644 drivers/irqchip/irq-xilinx-intc.c

diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig
index 86f6572..85885a5 100644
--- a/arch/microblaze/Kconfig
+++ b/arch/microblaze/Kconfig
@@ -27,6 +27,7 @@ config MICROBLAZE
select HAVE_MEMBLOCK_NODE_MAP
select HAVE_OPROFILE
select IRQ_DOMAIN
+ select XILINX_INTC
select MODULES_USE_ELF_RELA
select OF
select OF_EARLY_FLATTREE
diff --git a/arch/microblaze/kernel/Makefile b/arch/microblaze/kernel/Makefile
index f08baca..e098381 100644
--- a/arch/microblaze/kernel/Makefile
+++ b/arch/microblaze/kernel/Makefile
@@ -15,7 +15,7 @@ endif
extra-y := head.o vmlinux.lds

obj-y += dma.o exceptions.o \
- hw_exception_handler.o intc.o irq.o \
+ hw_exception_handler.o irq.o \
platform.o process.o prom.o ptrace.o \
reset.o setup.o signal.o sys_microblaze.o timer.o traps.o unwind.o

diff --git a/arch/microblaze/kernel/intc.c b/arch/microblaze/kernel/intc.c
deleted file mode 100644
index 90bec7d..0000000
--- a/arch/microblaze/kernel/intc.c
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Copyright (C) 2007-2013 Michal Simek <[email protected]>
- * Copyright (C) 2012-2013 Xilinx, Inc.
- * Copyright (C) 2007-2009 PetaLogix
- * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#include <linux/irqdomain.h>
-#include <linux/irq.h>
-#include <linux/irqchip.h>
-#include <linux/of_address.h>
-#include <linux/io.h>
-#include <linux/bug.h>
-
-static void __iomem *intc_baseaddr;
-
-/* No one else should require these constants, so define them locally here. */
-#define ISR 0x00 /* Interrupt Status Register */
-#define IPR 0x04 /* Interrupt Pending Register */
-#define IER 0x08 /* Interrupt Enable Register */
-#define IAR 0x0c /* Interrupt Acknowledge Register */
-#define SIE 0x10 /* Set Interrupt Enable bits */
-#define CIE 0x14 /* Clear Interrupt Enable bits */
-#define IVR 0x18 /* Interrupt Vector Register */
-#define MER 0x1c /* Master Enable Register */
-
-#define MER_ME (1<<0)
-#define MER_HIE (1<<1)
-
-static unsigned int (*read_fn)(void __iomem *);
-static void (*write_fn)(u32, void __iomem *);
-
-static void intc_write32(u32 val, void __iomem *addr)
-{
- iowrite32(val, addr);
-}
-
-static unsigned int intc_read32(void __iomem *addr)
-{
- return ioread32(addr);
-}
-
-static void intc_write32_be(u32 val, void __iomem *addr)
-{
- iowrite32be(val, addr);
-}
-
-static unsigned int intc_read32_be(void __iomem *addr)
-{
- return ioread32be(addr);
-}
-
-static void intc_enable_or_unmask(struct irq_data *d)
-{
- unsigned long mask = 1 << d->hwirq;
-
- pr_debug("enable_or_unmask: %ld\n", d->hwirq);
-
- /* ack level irqs because they can't be acked during
- * ack function since the handle_level_irq function
- * acks the irq before calling the interrupt handler
- */
- if (irqd_is_level_type(d))
- write_fn(mask, intc_baseaddr + IAR);
-
- write_fn(mask, intc_baseaddr + SIE);
-}
-
-static void intc_disable_or_mask(struct irq_data *d)
-{
- pr_debug("disable: %ld\n", d->hwirq);
- write_fn(1 << d->hwirq, intc_baseaddr + CIE);
-}
-
-static void intc_ack(struct irq_data *d)
-{
- pr_debug("ack: %ld\n", d->hwirq);
- write_fn(1 << d->hwirq, intc_baseaddr + IAR);
-}
-
-static void intc_mask_ack(struct irq_data *d)
-{
- unsigned long mask = 1 << d->hwirq;
-
- pr_debug("disable_and_ack: %ld\n", d->hwirq);
- write_fn(mask, intc_baseaddr + CIE);
- write_fn(mask, intc_baseaddr + IAR);
-}
-
-static struct irq_chip intc_dev = {
- .name = "Xilinx INTC",
- .irq_unmask = intc_enable_or_unmask,
- .irq_mask = intc_disable_or_mask,
- .irq_ack = intc_ack,
- .irq_mask_ack = intc_mask_ack,
-};
-
-static struct irq_domain *root_domain;
-
-unsigned int get_irq(void)
-{
- unsigned int hwirq, irq = -1;
-
- hwirq = read_fn(intc_baseaddr + IVR);
- if (hwirq != -1U)
- irq = irq_find_mapping(root_domain, hwirq);
-
- pr_debug("get_irq: hwirq=%d, irq=%d\n", hwirq, irq);
-
- return irq;
-}
-
-static int xintc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
-{
- u32 intr_mask = (u32)d->host_data;
-
- if (intr_mask & (1 << hw)) {
- irq_set_chip_and_handler_name(irq, &intc_dev,
- handle_edge_irq, "edge");
- irq_clear_status_flags(irq, IRQ_LEVEL);
- } else {
- irq_set_chip_and_handler_name(irq, &intc_dev,
- handle_level_irq, "level");
- irq_set_status_flags(irq, IRQ_LEVEL);
- }
- return 0;
-}
-
-static const struct irq_domain_ops xintc_irq_domain_ops = {
- .xlate = irq_domain_xlate_onetwocell,
- .map = xintc_map,
-};
-
-static int __init xilinx_intc_of_init(struct device_node *intc,
- struct device_node *parent)
-{
- u32 nr_irq, intr_mask;
- int ret;
-
- intc_baseaddr = of_iomap(intc, 0);
- BUG_ON(!intc_baseaddr);
-
- ret = of_property_read_u32(intc, "xlnx,num-intr-inputs", &nr_irq);
- if (ret < 0) {
- pr_err("%s: unable to read xlnx,num-intr-inputs\n", __func__);
- return ret;
- }
-
- ret = of_property_read_u32(intc, "xlnx,kind-of-intr", &intr_mask);
- if (ret < 0) {
- pr_err("%s: unable to read xlnx,kind-of-intr\n", __func__);
- return ret;
- }
-
- if (intr_mask >> nr_irq)
- pr_warn("%s: mismatch in kind-of-intr param\n", __func__);
-
- pr_info("%s: num_irq=%d, edge=0x%x\n",
- intc->full_name, nr_irq, intr_mask);
-
- write_fn = intc_write32;
- read_fn = intc_read32;
-
- /*
- * Disable all external interrupts until they are
- * explicity requested.
- */
- write_fn(0, intc_baseaddr + IER);
-
- /* Acknowledge any pending interrupts just in case. */
- write_fn(0xffffffff, intc_baseaddr + IAR);
-
- /* Turn on the Master Enable. */
- write_fn(MER_HIE | MER_ME, intc_baseaddr + MER);
- if (!(read_fn(intc_baseaddr + MER) & (MER_HIE | MER_ME))) {
- write_fn = intc_write32_be;
- read_fn = intc_read32_be;
- write_fn(MER_HIE | MER_ME, intc_baseaddr + MER);
- }
-
- /* Yeah, okay, casting the intr_mask to a void* is butt-ugly, but I'm
- * lazy and Michal can clean it up to something nicer when he tests
- * and commits this patch. ~~gcl */
- root_domain = irq_domain_add_linear(intc, nr_irq, &xintc_irq_domain_ops,
- (void *)intr_mask);
-
- irq_set_default_host(root_domain);
-
- return 0;
-}
-
-IRQCHIP_DECLARE(xilinx_intc, "xlnx,xps-intc-1.00.a", xilinx_intc_of_init);
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 82b0b5d..0842cbc 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -211,6 +211,10 @@ config XTENSA_MX
bool
select IRQ_DOMAIN

+config XILINX_INTC
+ bool
+ select IRQ_DOMAIN
+
config IRQ_CROSSBAR
bool
help
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index e4dbfc8..0e55d94 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -52,6 +52,7 @@ obj-$(CONFIG_TB10X_IRQC) += irq-tb10x.o
obj-$(CONFIG_TS4800_IRQ) += irq-ts4800.o
obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o
obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o
+obj-$(CONFIG_XILINX_INTC) += irq-xilinx-intc.o
obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o
obj-$(CONFIG_SOC_VF610) += irq-vf610-mscm-ir.o
obj-$(CONFIG_BCM6345_L1_IRQ) += irq-bcm6345-l1.o
diff --git a/drivers/irqchip/irq-xilinx-intc.c b/drivers/irqchip/irq-xilinx-intc.c
new file mode 100644
index 0000000..90bec7d
--- /dev/null
+++ b/drivers/irqchip/irq-xilinx-intc.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2007-2013 Michal Simek <[email protected]>
+ * Copyright (C) 2012-2013 Xilinx, Inc.
+ * Copyright (C) 2007-2009 PetaLogix
+ * Copyright (C) 2006 Atmark Techno, Inc.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/irqdomain.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/of_address.h>
+#include <linux/io.h>
+#include <linux/bug.h>
+
+static void __iomem *intc_baseaddr;
+
+/* No one else should require these constants, so define them locally here. */
+#define ISR 0x00 /* Interrupt Status Register */
+#define IPR 0x04 /* Interrupt Pending Register */
+#define IER 0x08 /* Interrupt Enable Register */
+#define IAR 0x0c /* Interrupt Acknowledge Register */
+#define SIE 0x10 /* Set Interrupt Enable bits */
+#define CIE 0x14 /* Clear Interrupt Enable bits */
+#define IVR 0x18 /* Interrupt Vector Register */
+#define MER 0x1c /* Master Enable Register */
+
+#define MER_ME (1<<0)
+#define MER_HIE (1<<1)
+
+static unsigned int (*read_fn)(void __iomem *);
+static void (*write_fn)(u32, void __iomem *);
+
+static void intc_write32(u32 val, void __iomem *addr)
+{
+ iowrite32(val, addr);
+}
+
+static unsigned int intc_read32(void __iomem *addr)
+{
+ return ioread32(addr);
+}
+
+static void intc_write32_be(u32 val, void __iomem *addr)
+{
+ iowrite32be(val, addr);
+}
+
+static unsigned int intc_read32_be(void __iomem *addr)
+{
+ return ioread32be(addr);
+}
+
+static void intc_enable_or_unmask(struct irq_data *d)
+{
+ unsigned long mask = 1 << d->hwirq;
+
+ pr_debug("enable_or_unmask: %ld\n", d->hwirq);
+
+ /* ack level irqs because they can't be acked during
+ * ack function since the handle_level_irq function
+ * acks the irq before calling the interrupt handler
+ */
+ if (irqd_is_level_type(d))
+ write_fn(mask, intc_baseaddr + IAR);
+
+ write_fn(mask, intc_baseaddr + SIE);
+}
+
+static void intc_disable_or_mask(struct irq_data *d)
+{
+ pr_debug("disable: %ld\n", d->hwirq);
+ write_fn(1 << d->hwirq, intc_baseaddr + CIE);
+}
+
+static void intc_ack(struct irq_data *d)
+{
+ pr_debug("ack: %ld\n", d->hwirq);
+ write_fn(1 << d->hwirq, intc_baseaddr + IAR);
+}
+
+static void intc_mask_ack(struct irq_data *d)
+{
+ unsigned long mask = 1 << d->hwirq;
+
+ pr_debug("disable_and_ack: %ld\n", d->hwirq);
+ write_fn(mask, intc_baseaddr + CIE);
+ write_fn(mask, intc_baseaddr + IAR);
+}
+
+static struct irq_chip intc_dev = {
+ .name = "Xilinx INTC",
+ .irq_unmask = intc_enable_or_unmask,
+ .irq_mask = intc_disable_or_mask,
+ .irq_ack = intc_ack,
+ .irq_mask_ack = intc_mask_ack,
+};
+
+static struct irq_domain *root_domain;
+
+unsigned int get_irq(void)
+{
+ unsigned int hwirq, irq = -1;
+
+ hwirq = read_fn(intc_baseaddr + IVR);
+ if (hwirq != -1U)
+ irq = irq_find_mapping(root_domain, hwirq);
+
+ pr_debug("get_irq: hwirq=%d, irq=%d\n", hwirq, irq);
+
+ return irq;
+}
+
+static int xintc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
+{
+ u32 intr_mask = (u32)d->host_data;
+
+ if (intr_mask & (1 << hw)) {
+ irq_set_chip_and_handler_name(irq, &intc_dev,
+ handle_edge_irq, "edge");
+ irq_clear_status_flags(irq, IRQ_LEVEL);
+ } else {
+ irq_set_chip_and_handler_name(irq, &intc_dev,
+ handle_level_irq, "level");
+ irq_set_status_flags(irq, IRQ_LEVEL);
+ }
+ return 0;
+}
+
+static const struct irq_domain_ops xintc_irq_domain_ops = {
+ .xlate = irq_domain_xlate_onetwocell,
+ .map = xintc_map,
+};
+
+static int __init xilinx_intc_of_init(struct device_node *intc,
+ struct device_node *parent)
+{
+ u32 nr_irq, intr_mask;
+ int ret;
+
+ intc_baseaddr = of_iomap(intc, 0);
+ BUG_ON(!intc_baseaddr);
+
+ ret = of_property_read_u32(intc, "xlnx,num-intr-inputs", &nr_irq);
+ if (ret < 0) {
+ pr_err("%s: unable to read xlnx,num-intr-inputs\n", __func__);
+ return ret;
+ }
+
+ ret = of_property_read_u32(intc, "xlnx,kind-of-intr", &intr_mask);
+ if (ret < 0) {
+ pr_err("%s: unable to read xlnx,kind-of-intr\n", __func__);
+ return ret;
+ }
+
+ if (intr_mask >> nr_irq)
+ pr_warn("%s: mismatch in kind-of-intr param\n", __func__);
+
+ pr_info("%s: num_irq=%d, edge=0x%x\n",
+ intc->full_name, nr_irq, intr_mask);
+
+ write_fn = intc_write32;
+ read_fn = intc_read32;
+
+ /*
+ * Disable all external interrupts until they are
+ * explicity requested.
+ */
+ write_fn(0, intc_baseaddr + IER);
+
+ /* Acknowledge any pending interrupts just in case. */
+ write_fn(0xffffffff, intc_baseaddr + IAR);
+
+ /* Turn on the Master Enable. */
+ write_fn(MER_HIE | MER_ME, intc_baseaddr + MER);
+ if (!(read_fn(intc_baseaddr + MER) & (MER_HIE | MER_ME))) {
+ write_fn = intc_write32_be;
+ read_fn = intc_read32_be;
+ write_fn(MER_HIE | MER_ME, intc_baseaddr + MER);
+ }
+
+ /* Yeah, okay, casting the intr_mask to a void* is butt-ugly, but I'm
+ * lazy and Michal can clean it up to something nicer when he tests
+ * and commits this patch. ~~gcl */
+ root_domain = irq_domain_add_linear(intc, nr_irq, &xintc_irq_domain_ops,
+ (void *)intr_mask);
+
+ irq_set_default_host(root_domain);
+
+ return 0;
+}
+
+IRQCHIP_DECLARE(xilinx_intc, "xlnx,xps-intc-1.00.a", xilinx_intc_of_init);
--
1.9.1

Subject: [Patch v5 03/12] irqchip: xilinx: Rename get_irq to xintc_get_irq

Now that the driver is generic and used by multiple archs,
get_irq is too generic.

Rename get_irq to xintc_get_irq to avoid any conflicts

Signed-off-by: Zubair Lutfullah Kakakhel <[email protected]>

---
V4 -> V5
Rebased to v4.9-rc1
Use __func__ in pr_err

V3 -> V4
New patch.
---
arch/microblaze/include/asm/irq.h | 2 +-
arch/microblaze/kernel/irq.c | 4 ++--
drivers/irqchip/irq-xilinx-intc.c | 4 ++--
3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/arch/microblaze/include/asm/irq.h b/arch/microblaze/include/asm/irq.h
index bab3b13..d785def 100644
--- a/arch/microblaze/include/asm/irq.h
+++ b/arch/microblaze/include/asm/irq.h
@@ -16,6 +16,6 @@
extern void do_IRQ(struct pt_regs *regs);

/* should be defined in each interrupt controller driver */
-extern unsigned int get_irq(void);
+extern unsigned int xintc_get_irq(void);

#endif /* _ASM_MICROBLAZE_IRQ_H */
diff --git a/arch/microblaze/kernel/irq.c b/arch/microblaze/kernel/irq.c
index 11e24de..903dad8 100644
--- a/arch/microblaze/kernel/irq.c
+++ b/arch/microblaze/kernel/irq.c
@@ -29,12 +29,12 @@ void __irq_entry do_IRQ(struct pt_regs *regs)
trace_hardirqs_off();

irq_enter();
- irq = get_irq();
+ irq = xintc_get_irq();
next_irq:
BUG_ON(!irq);
generic_handle_irq(irq);

- irq = get_irq();
+ irq = xintc_get_irq();
if (irq != -1U) {
pr_debug("next irq: %d\n", irq);
++concurrent_irq;
diff --git a/drivers/irqchip/irq-xilinx-intc.c b/drivers/irqchip/irq-xilinx-intc.c
index fe533e1..45e5154 100644
--- a/drivers/irqchip/irq-xilinx-intc.c
+++ b/drivers/irqchip/irq-xilinx-intc.c
@@ -119,7 +119,7 @@ static void intc_mask_ack(struct irq_data *d)

static struct irq_domain *root_domain;

-unsigned int get_irq(void)
+unsigned int xintc_get_irq(void)
{
unsigned int hwirq, irq = -1;

@@ -127,7 +127,7 @@ unsigned int get_irq(void)
if (hwirq != -1U)
irq = irq_find_mapping(root_domain, hwirq);

- pr_debug("get_irq: hwirq=%d, irq=%d\n", hwirq, irq);
+ pr_debug("%s: hwirq=%d, irq=%d\n", __func__, hwirq, irq);

return irq;
}
--
1.9.1

Subject: [Patch v5 02/12] irqchip: xilinx: Clean up irqdomain argument and read/write

The drivers read/write function handling is a bit quirky.
And the irqmask is passed directly to the handler.

Add a new irqchip struct to pass to the handler and
cleanup read/write handling.

Signed-off-by: Zubair Lutfullah Kakakhel <[email protected]>

---
V4 -> V5
Rebased to v4.9-rc1
Better error handling

V3 -> V4
Better error handling for kzalloc
Erroring out if the axi intc is probed twice as that isn't
supported

V2 -> V3
New patch. Cleans up driver structure
---
drivers/irqchip/irq-xilinx-intc.c | 105 ++++++++++++++++++++++++++------------
1 file changed, 72 insertions(+), 33 deletions(-)

diff --git a/drivers/irqchip/irq-xilinx-intc.c b/drivers/irqchip/irq-xilinx-intc.c
index 90bec7d..fe533e1 100644
--- a/drivers/irqchip/irq-xilinx-intc.c
+++ b/drivers/irqchip/irq-xilinx-intc.c
@@ -16,8 +16,6 @@
#include <linux/io.h>
#include <linux/bug.h>

-static void __iomem *intc_baseaddr;
-
/* No one else should require these constants, so define them locally here. */
#define ISR 0x00 /* Interrupt Status Register */
#define IPR 0x04 /* Interrupt Pending Register */
@@ -31,8 +29,16 @@
#define MER_ME (1<<0)
#define MER_HIE (1<<1)

-static unsigned int (*read_fn)(void __iomem *);
-static void (*write_fn)(u32, void __iomem *);
+struct xintc_irq_chip {
+ void __iomem *base;
+ struct irq_domain *domain;
+ struct irq_chip chip;
+ u32 intr_mask;
+ unsigned int (*read)(void __iomem *iomem);
+ void (*write)(u32 data, void __iomem *iomem);
+};
+
+static struct xintc_irq_chip *xintc_irqc;

static void intc_write32(u32 val, void __iomem *addr)
{
@@ -54,6 +60,18 @@ static unsigned int intc_read32_be(void __iomem *addr)
return ioread32be(addr);
}

+static inline unsigned int xintc_read(struct xintc_irq_chip *xintc_irqc,
+ int reg)
+{
+ return xintc_irqc->read(xintc_irqc->base + reg);
+}
+
+static inline void xintc_write(struct xintc_irq_chip *xintc_irqc,
+ int reg, u32 data)
+{
+ xintc_irqc->write(data, xintc_irqc->base + reg);
+}
+
static void intc_enable_or_unmask(struct irq_data *d)
{
unsigned long mask = 1 << d->hwirq;
@@ -65,21 +83,21 @@ static void intc_enable_or_unmask(struct irq_data *d)
* acks the irq before calling the interrupt handler
*/
if (irqd_is_level_type(d))
- write_fn(mask, intc_baseaddr + IAR);
+ xintc_write(xintc_irqc, IAR, mask);

- write_fn(mask, intc_baseaddr + SIE);
+ xintc_write(xintc_irqc, SIE, mask);
}

static void intc_disable_or_mask(struct irq_data *d)
{
pr_debug("disable: %ld\n", d->hwirq);
- write_fn(1 << d->hwirq, intc_baseaddr + CIE);
+ xintc_write(xintc_irqc, CIE, 1 << d->hwirq);
}

static void intc_ack(struct irq_data *d)
{
pr_debug("ack: %ld\n", d->hwirq);
- write_fn(1 << d->hwirq, intc_baseaddr + IAR);
+ xintc_write(xintc_irqc, IAR, 1 << d->hwirq);
}

static void intc_mask_ack(struct irq_data *d)
@@ -87,8 +105,8 @@ static void intc_mask_ack(struct irq_data *d)
unsigned long mask = 1 << d->hwirq;

pr_debug("disable_and_ack: %ld\n", d->hwirq);
- write_fn(mask, intc_baseaddr + CIE);
- write_fn(mask, intc_baseaddr + IAR);
+ xintc_write(xintc_irqc, CIE, mask);
+ xintc_write(xintc_irqc, IAR, mask);
}

static struct irq_chip intc_dev = {
@@ -105,7 +123,7 @@ unsigned int get_irq(void)
{
unsigned int hwirq, irq = -1;

- hwirq = read_fn(intc_baseaddr + IVR);
+ hwirq = xintc_read(xintc_irqc, IVR);
if (hwirq != -1U)
irq = irq_find_mapping(root_domain, hwirq);

@@ -116,7 +134,8 @@ unsigned int get_irq(void)

static int xintc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
{
- u32 intr_mask = (u32)d->host_data;
+ struct xintc_irq_chip *irqc = d->host_data;
+ u32 intr_mask = irqc->intr_mask;

if (intr_mask & (1 << hw)) {
irq_set_chip_and_handler_name(irq, &intc_dev,
@@ -138,59 +157,79 @@ static int xintc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
static int __init xilinx_intc_of_init(struct device_node *intc,
struct device_node *parent)
{
- u32 nr_irq, intr_mask;
+ u32 nr_irq;
int ret;
+ struct xintc_irq_chip *irqc;
+
+ if (xintc_irqc) {
+ pr_err("%s: Multiple instances of xilinx_intc aren't supported\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ irqc = kzalloc(sizeof(*irqc), GFP_KERNEL);
+ if (!irqc)
+ return -ENOMEM;

- intc_baseaddr = of_iomap(intc, 0);
- BUG_ON(!intc_baseaddr);
+ xintc_irqc = irqc;
+
+ irqc->base = of_iomap(intc, 0);
+ BUG_ON(!irqc->base);

ret = of_property_read_u32(intc, "xlnx,num-intr-inputs", &nr_irq);
if (ret < 0) {
pr_err("%s: unable to read xlnx,num-intr-inputs\n", __func__);
- return ret;
+ goto err_alloc;
}

- ret = of_property_read_u32(intc, "xlnx,kind-of-intr", &intr_mask);
+ ret = of_property_read_u32(intc, "xlnx,kind-of-intr", &irqc->intr_mask);
if (ret < 0) {
pr_err("%s: unable to read xlnx,kind-of-intr\n", __func__);
- return ret;
+ goto err_alloc;
}

- if (intr_mask >> nr_irq)
+ if (irqc->intr_mask >> nr_irq)
pr_warn("%s: mismatch in kind-of-intr param\n", __func__);

pr_info("%s: num_irq=%d, edge=0x%x\n",
- intc->full_name, nr_irq, intr_mask);
+ intc->full_name, nr_irq, irqc->intr_mask);

- write_fn = intc_write32;
- read_fn = intc_read32;
+ irqc->read = intc_read32;
+ irqc->write = intc_write32;

/*
* Disable all external interrupts until they are
* explicity requested.
*/
- write_fn(0, intc_baseaddr + IER);
+ xintc_write(irqc, IER, 0);

/* Acknowledge any pending interrupts just in case. */
- write_fn(0xffffffff, intc_baseaddr + IAR);
+ xintc_write(irqc, IAR, 0xffffffff);

/* Turn on the Master Enable. */
- write_fn(MER_HIE | MER_ME, intc_baseaddr + MER);
- if (!(read_fn(intc_baseaddr + MER) & (MER_HIE | MER_ME))) {
- write_fn = intc_write32_be;
- read_fn = intc_read32_be;
- write_fn(MER_HIE | MER_ME, intc_baseaddr + MER);
+ xintc_write(irqc, MER, MER_HIE | MER_ME);
+ if (!(xintc_read(irqc, MER) & (MER_HIE | MER_ME))) {
+ irqc->read = intc_read32_be;
+ irqc->write = intc_write32_be;
+ xintc_write(irqc, MER, MER_HIE | MER_ME);
}

- /* Yeah, okay, casting the intr_mask to a void* is butt-ugly, but I'm
- * lazy and Michal can clean it up to something nicer when he tests
- * and commits this patch. ~~gcl */
root_domain = irq_domain_add_linear(intc, nr_irq, &xintc_irq_domain_ops,
- (void *)intr_mask);
+ irqc);
+ if (!root_domain) {
+ pr_err("%s: Unable to create IRQ domain\n", __func__);
+ goto err_alloc;
+ }

irq_set_default_host(root_domain);

return 0;
+
+err_alloc:
+ xintc_irqc = NULL;
+ kfree(irqc);
+ return ret;
+
}

IRQCHIP_DECLARE(xilinx_intc, "xlnx,xps-intc-1.00.a", xilinx_intc_of_init);
--
1.9.1

Subject: [Patch v5 12/12] MIPS: xilfpga: Update defconfig

Update defconfig to enable emaclite, i2c, temp sensor found on the
xilfpga platform

Signed-off-by: Zubair Lutfullah Kakakhel <[email protected]>

---
V3 -> V4
No change

V2 -> V3
No change

V1 -> V2
No change
---
arch/mips/configs/xilfpga_defconfig | 37 ++++++++++++++++++++++++++++++++++++-
1 file changed, 36 insertions(+), 1 deletion(-)

diff --git a/arch/mips/configs/xilfpga_defconfig b/arch/mips/configs/xilfpga_defconfig
index ed1dce3..829c637 100644
--- a/arch/mips/configs/xilfpga_defconfig
+++ b/arch/mips/configs/xilfpga_defconfig
@@ -7,6 +7,12 @@ CONFIG_EMBEDDED=y
CONFIG_SLAB=y
# CONFIG_BLOCK is not set
# CONFIG_SUSPEND is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
# CONFIG_UEVENT_HELPER is not set
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
@@ -14,6 +20,30 @@ CONFIG_DEVTMPFS_MOUNT=y
# CONFIG_PREVENT_FIRMWARE_BUILD is not set
# CONFIG_FW_LOADER is not set
# CONFIG_ALLOW_DEV_COREDUMP is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NET_CORE is not set
+# CONFIG_NET_VENDOR_ARC is not set
+# CONFIG_NET_CADENCE is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_EZCHIP is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_NETRONOME is not set
+# CONFIG_NET_VENDOR_QUALCOMM is not set
+# CONFIG_NET_VENDOR_RENESAS is not set
+# CONFIG_NET_VENDOR_ROCKER is not set
+# CONFIG_NET_VENDOR_SAMSUNG is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_NET_VENDOR_SYNOPSYS is not set
+# CONFIG_NET_VENDOR_VIA is not set
+# CONFIG_NET_VENDOR_WIZNET is not set
+CONFIG_XILINX_EMACLITE=y
+CONFIG_SMSC_PHY=y
+# CONFIG_WLAN is not set
# CONFIG_INPUT_MOUSEDEV is not set
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
@@ -25,13 +55,18 @@ CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_OF_PLATFORM=y
# CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_HELPER_AUTO is not set
+CONFIG_I2C_XILINX=y
CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_XILINX=y
-# CONFIG_HWMON is not set
+CONFIG_SENSORS_ADT7410=y
# CONFIG_USB_SUPPORT is not set
# CONFIG_MIPS_PLATFORM_DEVICES is not set
# CONFIG_IOMMU_SUPPORT is not set
# CONFIG_PROC_PAGE_MONITOR is not set
+CONFIG_TMPFS=y
# CONFIG_MISC_FILESYSTEMS is not set
CONFIG_PANIC_ON_OOPS=y
# CONFIG_SCHED_DEBUG is not set
--
1.9.1

Subject: [Patch v5 09/12] MIPS: xilfpga: Update DT node and specify uart irq

Update the DT node with the UART irq

Signed-off-by: Zubair Lutfullah Kakakhel <[email protected]>

---
V3 -> V4
No change

V2 -> V3
No change

V1 -> V2

No change
---
arch/mips/boot/dts/xilfpga/nexys4ddr.dts | 3 +++
1 file changed, 3 insertions(+)

diff --git a/arch/mips/boot/dts/xilfpga/nexys4ddr.dts b/arch/mips/boot/dts/xilfpga/nexys4ddr.dts
index 8db660b..d285c8d 100644
--- a/arch/mips/boot/dts/xilfpga/nexys4ddr.dts
+++ b/arch/mips/boot/dts/xilfpga/nexys4ddr.dts
@@ -50,6 +50,9 @@
reg-offset = <0x1000>;

clocks = <&ext>;
+
+ interrupt-parent = <&axi_intc>;
+ interrupts = <0>;
};
};

--
1.9.1

Subject: [Patch v5 06/12] powerpc/virtex: Use generic xilinx irqchip driver

The Xilinx interrupt controller driver is now available in drivers/irqchip.
Switch to using that driver.

Signed-off-by: Zubair Lutfullah Kakakhel <[email protected]>

---
V5 New patch

Tested on virtex440-ml507 using qemu
---
arch/powerpc/include/asm/xilinx_intc.h | 2 +-
arch/powerpc/platforms/40x/Kconfig | 1 +
arch/powerpc/platforms/40x/virtex.c | 2 +-
arch/powerpc/platforms/44x/Kconfig | 1 +
arch/powerpc/platforms/44x/virtex.c | 2 +-
arch/powerpc/sysdev/xilinx_intc.c | 211 +--------------------------------
drivers/irqchip/irq-xilinx-intc.c | 3 +-
7 files changed, 9 insertions(+), 213 deletions(-)

diff --git a/arch/powerpc/include/asm/xilinx_intc.h b/arch/powerpc/include/asm/xilinx_intc.h
index 343612f..3192d7f 100644
--- a/arch/powerpc/include/asm/xilinx_intc.h
+++ b/arch/powerpc/include/asm/xilinx_intc.h
@@ -14,7 +14,7 @@
#ifdef __KERNEL__

extern void __init xilinx_intc_init_tree(void);
-extern unsigned int xilinx_intc_get_irq(void);
+extern unsigned int xintc_get_irq(void);

#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_XILINX_INTC_H */
diff --git a/arch/powerpc/platforms/40x/Kconfig b/arch/powerpc/platforms/40x/Kconfig
index e3257f2..1d7c1b1 100644
--- a/arch/powerpc/platforms/40x/Kconfig
+++ b/arch/powerpc/platforms/40x/Kconfig
@@ -64,6 +64,7 @@ config XILINX_VIRTEX_GENERIC_BOARD
default n
select XILINX_VIRTEX_II_PRO
select XILINX_VIRTEX_4_FX
+ select XILINX_INTC
help
This option enables generic support for Xilinx Virtex based boards.

diff --git a/arch/powerpc/platforms/40x/virtex.c b/arch/powerpc/platforms/40x/virtex.c
index 91a08ea..e3d5e09 100644
--- a/arch/powerpc/platforms/40x/virtex.c
+++ b/arch/powerpc/platforms/40x/virtex.c
@@ -48,7 +48,7 @@ static int __init virtex_probe(void)
.probe = virtex_probe,
.setup_arch = xilinx_pci_init,
.init_IRQ = xilinx_intc_init_tree,
- .get_irq = xilinx_intc_get_irq,
+ .get_irq = xintc_get_irq,
.restart = ppc4xx_reset_system,
.calibrate_decr = generic_calibrate_decr,
};
diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig
index 48fc180..25b8d64 100644
--- a/arch/powerpc/platforms/44x/Kconfig
+++ b/arch/powerpc/platforms/44x/Kconfig
@@ -241,6 +241,7 @@ config XILINX_VIRTEX440_GENERIC_BOARD
depends on 44x
default n
select XILINX_VIRTEX_5_FXT
+ select XILINX_INTC
help
This option enables generic support for Xilinx Virtex based boards
that use a 440 based processor in the Virtex 5 FXT FPGA architecture.
diff --git a/arch/powerpc/platforms/44x/virtex.c b/arch/powerpc/platforms/44x/virtex.c
index a7e0802..3eb13ed 100644
--- a/arch/powerpc/platforms/44x/virtex.c
+++ b/arch/powerpc/platforms/44x/virtex.c
@@ -54,7 +54,7 @@ static int __init virtex_probe(void)
.probe = virtex_probe,
.setup_arch = xilinx_pci_init,
.init_IRQ = xilinx_intc_init_tree,
- .get_irq = xilinx_intc_get_irq,
+ .get_irq = xintc_get_irq,
.calibrate_decr = generic_calibrate_decr,
.restart = ppc4xx_reset_system,
};
diff --git a/arch/powerpc/sysdev/xilinx_intc.c b/arch/powerpc/sysdev/xilinx_intc.c
index 0f52d79..4a86dcf 100644
--- a/arch/powerpc/sysdev/xilinx_intc.c
+++ b/arch/powerpc/sysdev/xilinx_intc.c
@@ -29,194 +29,7 @@
#include <asm/processor.h>
#include <asm/i8259.h>
#include <asm/irq.h>
-
-/*
- * INTC Registers
- */
-#define XINTC_ISR 0 /* Interrupt Status */
-#define XINTC_IPR 4 /* Interrupt Pending */
-#define XINTC_IER 8 /* Interrupt Enable */
-#define XINTC_IAR 12 /* Interrupt Acknowledge */
-#define XINTC_SIE 16 /* Set Interrupt Enable bits */
-#define XINTC_CIE 20 /* Clear Interrupt Enable bits */
-#define XINTC_IVR 24 /* Interrupt Vector */
-#define XINTC_MER 28 /* Master Enable */
-
-static struct irq_domain *master_irqhost;
-
-#define XILINX_INTC_MAXIRQS (32)
-
-/* The following table allows the interrupt type, edge or level,
- * to be cached after being read from the device tree until the interrupt
- * is mapped
- */
-static int xilinx_intc_typetable[XILINX_INTC_MAXIRQS];
-
-/* Map the interrupt type from the device tree to the interrupt types
- * used by the interrupt subsystem
- */
-static unsigned char xilinx_intc_map_senses[] = {
- IRQ_TYPE_EDGE_RISING,
- IRQ_TYPE_EDGE_FALLING,
- IRQ_TYPE_LEVEL_HIGH,
- IRQ_TYPE_LEVEL_LOW,
-};
-
-/*
- * The interrupt controller is setup such that it doesn't work well with
- * the level interrupt handler in the kernel because the handler acks the
- * interrupt before calling the application interrupt handler. To deal with
- * that, we use 2 different irq chips so that different functions can be
- * used for level and edge type interrupts.
- *
- * IRQ Chip common (across level and edge) operations
- */
-static void xilinx_intc_mask(struct irq_data *d)
-{
- int irq = irqd_to_hwirq(d);
- void * regs = irq_data_get_irq_chip_data(d);
- pr_debug("mask: %d\n", irq);
- out_be32(regs + XINTC_CIE, 1 << irq);
-}
-
-static int xilinx_intc_set_type(struct irq_data *d, unsigned int flow_type)
-{
- return 0;
-}
-
-/*
- * IRQ Chip level operations
- */
-static void xilinx_intc_level_unmask(struct irq_data *d)
-{
- int irq = irqd_to_hwirq(d);
- void * regs = irq_data_get_irq_chip_data(d);
- pr_debug("unmask: %d\n", irq);
- out_be32(regs + XINTC_SIE, 1 << irq);
-
- /* ack level irqs because they can't be acked during
- * ack function since the handle_level_irq function
- * acks the irq before calling the inerrupt handler
- */
- out_be32(regs + XINTC_IAR, 1 << irq);
-}
-
-static struct irq_chip xilinx_intc_level_irqchip = {
- .name = "Xilinx Level INTC",
- .irq_mask = xilinx_intc_mask,
- .irq_mask_ack = xilinx_intc_mask,
- .irq_unmask = xilinx_intc_level_unmask,
- .irq_set_type = xilinx_intc_set_type,
-};
-
-/*
- * IRQ Chip edge operations
- */
-static void xilinx_intc_edge_unmask(struct irq_data *d)
-{
- int irq = irqd_to_hwirq(d);
- void *regs = irq_data_get_irq_chip_data(d);
- pr_debug("unmask: %d\n", irq);
- out_be32(regs + XINTC_SIE, 1 << irq);
-}
-
-static void xilinx_intc_edge_ack(struct irq_data *d)
-{
- int irq = irqd_to_hwirq(d);
- void * regs = irq_data_get_irq_chip_data(d);
- pr_debug("ack: %d\n", irq);
- out_be32(regs + XINTC_IAR, 1 << irq);
-}
-
-static struct irq_chip xilinx_intc_edge_irqchip = {
- .name = "Xilinx Edge INTC",
- .irq_mask = xilinx_intc_mask,
- .irq_unmask = xilinx_intc_edge_unmask,
- .irq_ack = xilinx_intc_edge_ack,
- .irq_set_type = xilinx_intc_set_type,
-};
-
-/*
- * IRQ Host operations
- */
-
-/**
- * xilinx_intc_xlate - translate virq# from device tree interrupts property
- */
-static int xilinx_intc_xlate(struct irq_domain *h, struct device_node *ct,
- const u32 *intspec, unsigned int intsize,
- irq_hw_number_t *out_hwirq,
- unsigned int *out_flags)
-{
- if ((intsize < 2) || (intspec[0] >= XILINX_INTC_MAXIRQS))
- return -EINVAL;
-
- /* keep a copy of the interrupt type til the interrupt is mapped
- */
- xilinx_intc_typetable[intspec[0]] = xilinx_intc_map_senses[intspec[1]];
-
- /* Xilinx uses 2 interrupt entries, the 1st being the h/w
- * interrupt number, the 2nd being the interrupt type, edge or level
- */
- *out_hwirq = intspec[0];
- *out_flags = xilinx_intc_map_senses[intspec[1]];
-
- return 0;
-}
-static int xilinx_intc_map(struct irq_domain *h, unsigned int virq,
- irq_hw_number_t irq)
-{
- irq_set_chip_data(virq, h->host_data);
-
- if (xilinx_intc_typetable[irq] == IRQ_TYPE_LEVEL_HIGH ||
- xilinx_intc_typetable[irq] == IRQ_TYPE_LEVEL_LOW) {
- irq_set_chip_and_handler(virq, &xilinx_intc_level_irqchip,
- handle_level_irq);
- } else {
- irq_set_chip_and_handler(virq, &xilinx_intc_edge_irqchip,
- handle_edge_irq);
- }
- return 0;
-}
-
-static const struct irq_domain_ops xilinx_intc_ops = {
- .map = xilinx_intc_map,
- .xlate = xilinx_intc_xlate,
-};
-
-struct irq_domain * __init
-xilinx_intc_init(struct device_node *np)
-{
- struct irq_domain * irq;
- void * regs;
-
- /* Find and map the intc registers */
- regs = of_iomap(np, 0);
- if (!regs) {
- pr_err("xilinx_intc: could not map registers\n");
- return NULL;
- }
-
- /* Setup interrupt controller */
- out_be32(regs + XINTC_IER, 0); /* disable all irqs */
- out_be32(regs + XINTC_IAR, ~(u32) 0); /* Acknowledge pending irqs */
- out_be32(regs + XINTC_MER, 0x3UL); /* Turn on the Master Enable. */
-
- /* Allocate and initialize an irq_domain structure. */
- irq = irq_domain_add_linear(np, XILINX_INTC_MAXIRQS, &xilinx_intc_ops,
- regs);
- if (!irq)
- panic(__FILE__ ": Cannot allocate IRQ host\n");
-
- return irq;
-}
-
-int xilinx_intc_get_irq(void)
-{
- void * regs = master_irqhost->host_data;
- pr_debug("get_irq:\n");
- return irq_linear_revmap(master_irqhost, in_be32(regs + XINTC_IVR));
-}
+#include <linux/irqchip.h>

#if defined(CONFIG_PPC_I8259)
/*
@@ -265,31 +78,11 @@ static void __init xilinx_i8259_setup_cascade(void)
static inline void xilinx_i8259_setup_cascade(void) { return; }
#endif /* defined(CONFIG_PPC_I8259) */

-static const struct of_device_id xilinx_intc_match[] __initconst = {
- { .compatible = "xlnx,opb-intc-1.00.c", },
- { .compatible = "xlnx,xps-intc-1.00.a", },
- {}
-};
-
/*
* Initialize master Xilinx interrupt controller
*/
void __init xilinx_intc_init_tree(void)
{
- struct device_node *np;
-
- /* find top level interrupt controller */
- for_each_matching_node(np, xilinx_intc_match) {
- if (!of_get_property(np, "interrupts", NULL))
- break;
- }
- BUG_ON(!np);
-
- master_irqhost = xilinx_intc_init(np);
- BUG_ON(!master_irqhost);
-
- irq_set_default_host(master_irqhost);
- of_node_put(np);
-
+ irqchip_init();
xilinx_i8259_setup_cascade();
}
diff --git a/drivers/irqchip/irq-xilinx-intc.c b/drivers/irqchip/irq-xilinx-intc.c
index 485fb11..dd372d7 100644
--- a/drivers/irqchip/irq-xilinx-intc.c
+++ b/drivers/irqchip/irq-xilinx-intc.c
@@ -254,4 +254,5 @@ static int __init xilinx_intc_of_init(struct device_node *intc,

}

-IRQCHIP_DECLARE(xilinx_intc, "xlnx,xps-intc-1.00.a", xilinx_intc_of_init);
+IRQCHIP_DECLARE(xilinx_intc_xps, "xlnx,xps-intc-1.00.a", xilinx_intc_of_init);
+IRQCHIP_DECLARE(xilinx_intc_opb, "xlnx,opb-intc-1.00.c", xilinx_intc_of_init);
--
1.9.1

Subject: [Patch v5 08/12] MIPS: xilfpga: Use Xilinx Interrupt Controller

IRQs from peripherals such as i2c/uart/ethernet come via
the AXI Interrupt controller.

Select it in Kconfig for xilfpga and add the DT node

Signed-off-by: Zubair Lutfullah Kakakhel <[email protected]>

---
V4 -> V5
Rebase to v4.9-rc1
Renamed XILINX_AXI_INTC to XILINX_INTC

V3 -> V4
No change

V2 -> V3
No change

V1 -> V2
Renamed select XILINX_INTC to select XILINX_AXI_INTC
---
arch/mips/Kconfig | 1 +
arch/mips/boot/dts/xilfpga/nexys4ddr.dts | 12 ++++++++++++
2 files changed, 13 insertions(+)

diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index b3c5bde..3d681c6 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -478,6 +478,7 @@ config MACH_XILFPGA
select SYS_SUPPORTS_ZBOOT_UART16550
select USE_OF
select USE_GENERIC_EARLY_PRINTK_8250
+ select XILINX_INTC
help
This enables support for the IMG University Program MIPSfpga platform.

diff --git a/arch/mips/boot/dts/xilfpga/nexys4ddr.dts b/arch/mips/boot/dts/xilfpga/nexys4ddr.dts
index 48d2112..8db660b 100644
--- a/arch/mips/boot/dts/xilfpga/nexys4ddr.dts
+++ b/arch/mips/boot/dts/xilfpga/nexys4ddr.dts
@@ -17,6 +17,18 @@
compatible = "mti,cpu-interrupt-controller";
};

+ axi_intc: interrupt-controller@10200000 {
+ #interrupt-cells = <1>;
+ compatible = "xlnx,xps-intc-1.00.a";
+ interrupt-controller;
+ reg = <0x10200000 0x10000>;
+ xlnx,kind-of-intr = <0x0>;
+ xlnx,num-intr-inputs = <0x6>;
+
+ interrupt-parent = <&cpuintc>;
+ interrupts = <6>;
+ };
+
axi_gpio: gpio@10600000 {
#gpio-cells = <1>;
compatible = "xlnx,xps-gpio-1.00.a";
--
1.9.1

Subject: [Patch v5 10/12] MIPS: xilfpga: Add DT node for AXI I2C

The xilfpga platform has an AXI I2C Bus master with a temperature
sensor connected to it.

Add the device tree node to use them.

Signed-off-by: Zubair Lutfullah Kakakhel <[email protected]>

---
V3 -> V4
changed compatible string from "adt7420" to "adi,adt7420"

V2 -> V3
No change

V1 -> V2

No change
---
arch/mips/boot/dts/xilfpga/nexys4ddr.dts | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)

diff --git a/arch/mips/boot/dts/xilfpga/nexys4ddr.dts b/arch/mips/boot/dts/xilfpga/nexys4ddr.dts
index d285c8d..f5ebab8 100644
--- a/arch/mips/boot/dts/xilfpga/nexys4ddr.dts
+++ b/arch/mips/boot/dts/xilfpga/nexys4ddr.dts
@@ -54,6 +54,28 @@
interrupt-parent = <&axi_intc>;
interrupts = <0>;
};
+
+ axi_i2c: i2c@10A00000 {
+ compatible = "xlnx,xps-iic-2.00.a";
+ interrupt-parent = <&axi_intc>;
+ interrupts = <4>;
+ reg = < 0x10A00000 0x10000 >;
+ clocks = <&ext>;
+ xlnx,clk-freq = <0x5f5e100>;
+ xlnx,family = "Artix7";
+ xlnx,gpo-width = <0x1>;
+ xlnx,iic-freq = <0x186a0>;
+ xlnx,scl-inertial-delay = <0x0>;
+ xlnx,sda-inertial-delay = <0x0>;
+ xlnx,ten-bit-adr = <0x0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ad7420@4B {
+ compatible = "adi,adt7420";
+ reg = <0x4B>;
+ };
+ } ;
};

&ext {
--
1.9.1

Subject: [Patch v5 11/12] MIPS: xilfpga: Add DT node for AXI emaclite

The xilfpga platform has a Xilinx AXI emaclite block.

Add the DT node to use it.

Signed-off-by: Zubair Lutfullah Kakakhel <[email protected]>

---
V3 -> V4
No change

V2 -> V3
No change

V1 -> V2
Removed accidental local-mac-address entry
---
arch/mips/boot/dts/xilfpga/nexys4ddr.dts | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)

diff --git a/arch/mips/boot/dts/xilfpga/nexys4ddr.dts b/arch/mips/boot/dts/xilfpga/nexys4ddr.dts
index f5ebab8..09a62f2 100644
--- a/arch/mips/boot/dts/xilfpga/nexys4ddr.dts
+++ b/arch/mips/boot/dts/xilfpga/nexys4ddr.dts
@@ -42,6 +42,32 @@
xlnx,tri-default = <0xffffffff>;
} ;

+ axi_ethernetlite: ethernet@10e00000 {
+ compatible = "xlnx,xps-ethernetlite-3.00.a";
+ device_type = "network";
+ interrupt-parent = <&axi_intc>;
+ interrupts = <1>;
+ phy-handle = <&phy0>;
+ reg = <0x10e00000 0x10000>;
+ xlnx,duplex = <0x1>;
+ xlnx,include-global-buffers = <0x1>;
+ xlnx,include-internal-loopback = <0x0>;
+ xlnx,include-mdio = <0x1>;
+ xlnx,instance = "axi_ethernetlite_inst";
+ xlnx,rx-ping-pong = <0x1>;
+ xlnx,s-axi-id-width = <0x1>;
+ xlnx,tx-ping-pong = <0x1>;
+ xlnx,use-internal = <0x0>;
+ mdio {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ phy0: phy@1 {
+ device_type = "ethernet-phy";
+ reg = <1>;
+ };
+ };
+ };
+
axi_uart16550: serial@10400000 {
compatible = "ns16550a";
reg = <0x10400000 0x10000>;
--
1.9.1

Subject: [Patch v5 07/12] MIPS: xilfpga: Use irqchip instead of the legacy way

This prepares the code use the Xilinx Interrupt Controller
driver now available in drivers/irqchip

Signed-off-by: Zubair Lutfullah Kakakhel <[email protected]>
---
V4 -> V5
Better commit message

V3 -> V4
Corrected commit message. Was irq-xilinx.c. Now irq-axi-intc.c

V2 -> V3
No change

V1 -> V2
No change
---
arch/mips/xilfpga/intc.c | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/arch/mips/xilfpga/intc.c b/arch/mips/xilfpga/intc.c
index c4d1a71..a127cca 100644
--- a/arch/mips/xilfpga/intc.c
+++ b/arch/mips/xilfpga/intc.c
@@ -11,15 +11,12 @@

#include <linux/of.h>
#include <linux/of_irq.h>
+#include <linux/irqchip.h>

#include <asm/irq_cpu.h>

-static struct of_device_id of_irq_ids[] __initdata = {
- { .compatible = "mti,cpu-interrupt-controller", .data = mips_cpu_irq_of_init },
- {},
-};

void __init arch_init_irq(void)
{
- of_irq_init(of_irq_ids);
+ irqchip_init();
}
--
1.9.1

Subject: [Patch v5 05/12] irqchip: xilinx: Try to fall back if xlnx,kind-of-intr not provided

The powerpc dts file upstream does not have the xlnx,kind-of-intr
property. Instead of erroring out, give a warning instead.
And attempt to continue to probe the interrupt controller while
assuming kind-of-intr is 0x0 as a fall back.

Signed-off-by: Zubair Lutfullah Kakakhel <[email protected]>

---
V5 new patch
---
drivers/irqchip/irq-xilinx-intc.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/irqchip/irq-xilinx-intc.c b/drivers/irqchip/irq-xilinx-intc.c
index dbf8b0c..485fb11 100644
--- a/drivers/irqchip/irq-xilinx-intc.c
+++ b/drivers/irqchip/irq-xilinx-intc.c
@@ -197,8 +197,8 @@ static int __init xilinx_intc_of_init(struct device_node *intc,

ret = of_property_read_u32(intc, "xlnx,kind-of-intr", &irqc->intr_mask);
if (ret < 0) {
- pr_err("%s: unable to read xlnx,kind-of-intr\n", __func__);
- goto err_alloc;
+ pr_warn("%s: unable to read xlnx,kind-of-intr\n", __func__);
+ irqc->intr_mask = 0;
}

if (irqc->intr_mask >> nr_irq)
--
1.9.1

Subject: [Patch v5 04/12] irqchip: xilinx: Add support for parent intc

The MIPS based xilfpga platform has the following IRQ structure

Peripherals --> xilinx_intcontroller -> mips_cpu_int controller

Add support for the driver to chain the irq handler

Signed-off-by: Zubair Lutfullah Kakakhel <[email protected]>

---
V4 -> V5
Rebased to v4.9-rc1
Missing curly braces

V3 -> V4
Clean up if/else when a parent is found
Pass irqchip structure to handler as data

V2 -> V3
Reused existing parent node instead of finding again.
Cleanup up handler based on review

V1 -> V2

No change
---
drivers/irqchip/irq-xilinx-intc.c | 26 ++++++++++++++++++++++++--
1 file changed, 24 insertions(+), 2 deletions(-)

diff --git a/drivers/irqchip/irq-xilinx-intc.c b/drivers/irqchip/irq-xilinx-intc.c
index 45e5154..dbf8b0c 100644
--- a/drivers/irqchip/irq-xilinx-intc.c
+++ b/drivers/irqchip/irq-xilinx-intc.c
@@ -15,6 +15,7 @@
#include <linux/of_address.h>
#include <linux/io.h>
#include <linux/bug.h>
+#include <linux/of_irq.h>

/* No one else should require these constants, so define them locally here. */
#define ISR 0x00 /* Interrupt Status Register */
@@ -154,11 +155,23 @@ static int xintc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
.map = xintc_map,
};

+static void xil_intc_irq_handler(struct irq_desc *desc)
+{
+ u32 pending;
+
+ do {
+ pending = xintc_get_irq();
+ if (pending == -1U)
+ break;
+ generic_handle_irq(pending);
+ } while (true);
+}
+
static int __init xilinx_intc_of_init(struct device_node *intc,
struct device_node *parent)
{
u32 nr_irq;
- int ret;
+ int ret, irq;
struct xintc_irq_chip *irqc;

if (xintc_irqc) {
@@ -221,7 +234,16 @@ static int __init xilinx_intc_of_init(struct device_node *intc,
goto err_alloc;
}

- irq_set_default_host(root_domain);
+ if (parent) {
+ irq = irq_of_parse_and_map(intc, 0);
+ if (irq)
+ irq_set_chained_handler_and_data(irq,
+ xil_intc_irq_handler,
+ irqc);
+
+ } else {
+ irq_set_default_host(root_domain);
+ }

return 0;

--
1.9.1

2016-10-19 14:21:26

by Michael Ellerman

[permalink] [raw]
Subject: Re: [Patch v5 06/12] powerpc/virtex: Use generic xilinx irqchip driver

Zubair Lutfullah Kakakhel <[email protected]> writes:

> The Xilinx interrupt controller driver is now available in drivers/irqchip.
> Switch to using that driver.
>
> Signed-off-by: Zubair Lutfullah Kakakhel <[email protected]>
>
> ---
> V5 New patch
>
> Tested on virtex440-ml507 using qemu

I don't have one of these to test on, and the patch looks sane, so
that's good enough for me.

Acked-by: Michael Ellerman <[email protected]> (powerpc)

cheers

2016-10-21 09:48:22

by Marc Zyngier

[permalink] [raw]
Subject: Re: [Patch v5 04/12] irqchip: xilinx: Add support for parent intc

On 17/10/16 17:52, Zubair Lutfullah Kakakhel wrote:
> The MIPS based xilfpga platform has the following IRQ structure
>
> Peripherals --> xilinx_intcontroller -> mips_cpu_int controller
>
> Add support for the driver to chain the irq handler
>
> Signed-off-by: Zubair Lutfullah Kakakhel <[email protected]>
>
> ---
> V4 -> V5
> Rebased to v4.9-rc1
> Missing curly braces
>
> V3 -> V4
> Clean up if/else when a parent is found
> Pass irqchip structure to handler as data
>
> V2 -> V3
> Reused existing parent node instead of finding again.
> Cleanup up handler based on review
>
> V1 -> V2
>
> No change
> ---
> drivers/irqchip/irq-xilinx-intc.c | 26 ++++++++++++++++++++++++--
> 1 file changed, 24 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/irqchip/irq-xilinx-intc.c b/drivers/irqchip/irq-xilinx-intc.c
> index 45e5154..dbf8b0c 100644
> --- a/drivers/irqchip/irq-xilinx-intc.c
> +++ b/drivers/irqchip/irq-xilinx-intc.c
> @@ -15,6 +15,7 @@
> #include <linux/of_address.h>
> #include <linux/io.h>
> #include <linux/bug.h>
> +#include <linux/of_irq.h>
>
> /* No one else should require these constants, so define them locally here. */
> #define ISR 0x00 /* Interrupt Status Register */
> @@ -154,11 +155,23 @@ static int xintc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
> .map = xintc_map,
> };
>
> +static void xil_intc_irq_handler(struct irq_desc *desc)
> +{
> + u32 pending;
> +
> + do {
> + pending = xintc_get_irq();
> + if (pending == -1U)
> + break;
> + generic_handle_irq(pending);
> + } while (true);

This is missing the chained_irq_enter()/exit() calls, which will lead to
races or lockups on the root irqchip.

> +}
> +
> static int __init xilinx_intc_of_init(struct device_node *intc,
> struct device_node *parent)
> {
> u32 nr_irq;
> - int ret;
> + int ret, irq;
> struct xintc_irq_chip *irqc;
>
> if (xintc_irqc) {
> @@ -221,7 +234,16 @@ static int __init xilinx_intc_of_init(struct device_node *intc,
> goto err_alloc;
> }
>
> - irq_set_default_host(root_domain);
> + if (parent) {
> + irq = irq_of_parse_and_map(intc, 0);
> + if (irq)
> + irq_set_chained_handler_and_data(irq,
> + xil_intc_irq_handler,
> + irqc);
> +

Shouldn't you return an error if irq is zero?

> + } else {
> + irq_set_default_host(root_domain);
> + }
>
> return 0;
>
>

Thanks,

M.
--
Jazz is not dead. It just smells funny...

Subject: Re: [Patch v5 04/12] irqchip: xilinx: Add support for parent intc

Hi,

Thanks for the review.
Some comments in-line.

On 10/21/2016 10:48 AM, Marc Zyngier wrote:
> On 17/10/16 17:52, Zubair Lutfullah Kakakhel wrote:
>> The MIPS based xilfpga platform has the following IRQ structure
>>
>> Peripherals --> xilinx_intcontroller -> mips_cpu_int controller
>>
>> Add support for the driver to chain the irq handler
>>
>> Signed-off-by: Zubair Lutfullah Kakakhel <[email protected]>
>>
>> ---
>> V4 -> V5
>> Rebased to v4.9-rc1
>> Missing curly braces
>>
>> V3 -> V4
>> Clean up if/else when a parent is found
>> Pass irqchip structure to handler as data
>>
>> V2 -> V3
>> Reused existing parent node instead of finding again.
>> Cleanup up handler based on review
>>
>> V1 -> V2
>>
>> No change
>> ---
>> drivers/irqchip/irq-xilinx-intc.c | 26 ++++++++++++++++++++++++--
>> 1 file changed, 24 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/irqchip/irq-xilinx-intc.c b/drivers/irqchip/irq-xilinx-intc.c
>> index 45e5154..dbf8b0c 100644
>> --- a/drivers/irqchip/irq-xilinx-intc.c
>> +++ b/drivers/irqchip/irq-xilinx-intc.c
>> @@ -15,6 +15,7 @@
>> #include <linux/of_address.h>
>> #include <linux/io.h>
>> #include <linux/bug.h>
>> +#include <linux/of_irq.h>
>>
>> /* No one else should require these constants, so define them locally here. */
>> #define ISR 0x00 /* Interrupt Status Register */
>> @@ -154,11 +155,23 @@ static int xintc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
>> .map = xintc_map,
>> };
>>
>> +static void xil_intc_irq_handler(struct irq_desc *desc)
>> +{
>> + u32 pending;
>> +
>> + do {
>> + pending = xintc_get_irq();
>> + if (pending == -1U)
>> + break;
>> + generic_handle_irq(pending);
>> + } while (true);
>
> This is missing the chained_irq_enter()/exit() calls, which will lead to
> races or lockups on the root irqchip.
>

I 'll fix it up in the next series.

>> +}
>> +
>> static int __init xilinx_intc_of_init(struct device_node *intc,
>> struct device_node *parent)
>> {
>> u32 nr_irq;
>> - int ret;
>> + int ret, irq;
>> struct xintc_irq_chip *irqc;
>>
>> if (xintc_irqc) {
>> @@ -221,7 +234,16 @@ static int __init xilinx_intc_of_init(struct device_node *intc,
>> goto err_alloc;
>> }
>>
>> - irq_set_default_host(root_domain);
>> + if (parent) {
>> + irq = irq_of_parse_and_map(intc, 0);
>> + if (irq)
>> + irq_set_chained_handler_and_data(irq,
>> + xil_intc_irq_handler,
>> + irqc);
>> +
>
> Shouldn't you return an error if irq is zero?
>

I'll add the following for the error case

pr_err("%s: Parent exists but interrupts property not defined\n" , __func__);
goto err_alloc;

Thanks
ZubairLK

>> + } else {
>> + irq_set_default_host(root_domain);
>> + }
>>
>> return 0;
>>
>>
>
> Thanks,
>
> M.
>

2016-10-25 10:52:13

by Thomas Gleixner

[permalink] [raw]
Subject: Re: [Patch v5 04/12] irqchip: xilinx: Add support for parent intc

On Tue, 25 Oct 2016, Zubair Lutfullah Kakakhel wrote:
> On 10/21/2016 10:48 AM, Marc Zyngier wrote:
> > Shouldn't you return an error if irq is zero?
> >
>
> I'll add the following for the error case
>
> pr_err("%s: Parent exists but interrupts property not defined\n" ,
> __func__);

Please do not use this silly __func__ stuff. It's not giving any value to
the printout.

Set a proper prefix for your pr_* stuff, so the string is prefixed with
'irq-xilinx:' or whatever you think is appropriate. Then the string itself
is good enough to find from which place this printk comes.

Thanks,

tglx

2016-10-25 14:52:31

by Marc Zyngier

[permalink] [raw]
Subject: Re: [Patch v5 04/12] irqchip: xilinx: Add support for parent intc

On 25/10/16 15:44, Sören Brinkmann wrote:
> On Tue, 2016-10-25 at 12:49:33 +0200, Thomas Gleixner wrote:
>> On Tue, 25 Oct 2016, Zubair Lutfullah Kakakhel wrote:
>>> On 10/21/2016 10:48 AM, Marc Zyngier wrote:
>>>> Shouldn't you return an error if irq is zero?
>>>>
>>>
>>> I'll add the following for the error case
>>>
>>> pr_err("%s: Parent exists but interrupts property not defined\n" ,
>>> __func__);
>>
>> Please do not use this silly __func__ stuff. It's not giving any value to
>> the printout.
>>
>> Set a proper prefix for your pr_* stuff, so the string is prefixed with
>> 'irq-xilinx:' or whatever you think is appropriate. Then the string itself
>> is good enough to find from which place this printk comes.
>
> Haven't looked at the real code, but is there probably a way to get a
> struct device pointer and use dev_err?

You wish. Interrupt controllers (and timers) are brought up way before
the device model is available, hence no struct device.

I've started untangling that mess a couple of times, and always ran out
of available time (you start pulling the VFS, then the scheduler, the
creation of the first thread, and then things lock up because you need
to context switch and no timer is ready yet).

I may try to spend some time on it again while travelling to LPC...

M.
--
Jazz is not dead. It just smells funny...

2016-10-25 15:00:23

by Soren Brinkmann

[permalink] [raw]
Subject: Re: [Patch v5 04/12] irqchip: xilinx: Add support for parent intc

On Tue, 2016-10-25 at 12:49:33 +0200, Thomas Gleixner wrote:
> On Tue, 25 Oct 2016, Zubair Lutfullah Kakakhel wrote:
> > On 10/21/2016 10:48 AM, Marc Zyngier wrote:
> > > Shouldn't you return an error if irq is zero?
> > >
> >
> > I'll add the following for the error case
> >
> > pr_err("%s: Parent exists but interrupts property not defined\n" ,
> > __func__);
>
> Please do not use this silly __func__ stuff. It's not giving any value to
> the printout.
>
> Set a proper prefix for your pr_* stuff, so the string is prefixed with
> 'irq-xilinx:' or whatever you think is appropriate. Then the string itself
> is good enough to find from which place this printk comes.

Haven't looked at the real code, but is there probably a way to get a
struct device pointer and use dev_err?

Sören