brcm63xx: convert to irq domain

Add irq-domain aware irqchip drivers for the irq controllers of bcm63xx
and switch to use them.

Signed-off-by: Jonas Gorski <jogo@openwrt.org>

SVN-Revision: 43454
lede-17.01
Jonas Gorski 2014-12-01 00:51:51 +00:00
parent bb312899f6
commit ef4f69adc0
19 changed files with 1842 additions and 78 deletions

View File

@ -0,0 +1,98 @@
From 0f84c305351c993e4307e1e8c128d44760314e31 Mon Sep 17 00:00:00 2001
From: Andrew Bresticker <abrestic@chromium.org>
Date: Thu, 18 Sep 2014 14:47:07 -0700
Subject: [PATCH 1/3] MIPS: Always use IRQ domains for CPU IRQs
Use an IRQ domain for the 8 CPU IRQs in both the DT and non-DT cases.
Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
Reviewed-by: Qais Yousef <qais.yousef@imgtec.com>
Tested-by: Qais Yousef <qais.yousef@imgtec.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Andrew Bresticker <abrestic@chromium.org>
Cc: Jeffrey Deans <jeffrey.deans@imgtec.com>
Cc: Markos Chandras <markos.chandras@imgtec.com>
Cc: Paul Burton <paul.burton@imgtec.com>
Cc: Qais Yousef <qais.yousef@imgtec.com>
Cc: Jonas Gorski <jogo@openwrt.org>
Cc: John Crispin <blogic@openwrt.org>
Cc: David Daney <ddaney.cavm@gmail.com>
Cc: linux-mips@linux-mips.org
Cc: linux-kernel@vger.kernel.org
Patchwork: https://patchwork.linux-mips.org/patch/7799/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
---
arch/mips/Kconfig | 1 +
arch/mips/kernel/irq_cpu.c | 36 +++++++++++-------------------------
2 files changed, 12 insertions(+), 25 deletions(-)
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -1025,6 +1025,7 @@ config MIPS_HUGE_TLB_SUPPORT
config IRQ_CPU
bool
+ select IRQ_DOMAIN
config IRQ_CPU_RM7K
bool
--- a/arch/mips/kernel/irq_cpu.c
+++ b/arch/mips/kernel/irq_cpu.c
@@ -94,28 +94,6 @@ static struct irq_chip mips_mt_cpu_irq_c
.irq_eoi = unmask_mips_irq,
};
-void __init mips_cpu_irq_init(void)
-{
- int irq_base = MIPS_CPU_IRQ_BASE;
- int i;
-
- /* Mask interrupts. */
- clear_c0_status(ST0_IM);
- clear_c0_cause(CAUSEF_IP);
-
- /* Software interrupts are used for MT/CMT IPI */
- for (i = irq_base; i < irq_base + 2; i++)
- irq_set_chip_and_handler(i, cpu_has_mipsmt ?
- &mips_mt_cpu_irq_controller :
- &mips_cpu_irq_controller,
- handle_percpu_irq);
-
- for (i = irq_base + 2; i < irq_base + 8; i++)
- irq_set_chip_and_handler(i, &mips_cpu_irq_controller,
- handle_percpu_irq);
-}
-
-#ifdef CONFIG_IRQ_DOMAIN
static int mips_cpu_intc_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hw)
{
@@ -138,8 +116,7 @@ static const struct irq_domain_ops mips_
.xlate = irq_domain_xlate_onecell,
};
-int __init mips_cpu_intc_init(struct device_node *of_node,
- struct device_node *parent)
+static void __init __mips_cpu_irq_init(struct device_node *of_node)
{
struct irq_domain *domain;
@@ -151,7 +128,16 @@ int __init mips_cpu_intc_init(struct dev
&mips_cpu_intc_irq_domain_ops, NULL);
if (!domain)
panic("Failed to add irqdomain for MIPS CPU");
+}
+void __init mips_cpu_irq_init(void)
+{
+ __mips_cpu_irq_init(NULL);
+}
+
+int __init mips_cpu_intc_init(struct device_node *of_node,
+ struct device_node *parent)
+{
+ __mips_cpu_irq_init(of_node);
return 0;
}
-#endif /* CONFIG_IRQ_DOMAIN */

View File

@ -0,0 +1,89 @@
From afe8dc254711b72ba8144295f4a8fcc66d30572d Mon Sep 17 00:00:00 2001
From: Andrew Bresticker <abrestic@chromium.org>
Date: Thu, 18 Sep 2014 14:47:08 -0700
Subject: [PATCH 2/3] MIPS: Rename mips_cpu_intc_init() ->
mips_cpu_irq_of_init()
mips_cpu_intc_init() is used for DT-based initialization of the CPU
IRQ domain. Give it a more appropriate name.
Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
Reviewed-by: Qais Yousef <qais.yousef@imgtec.com>
Tested-by: Qais Yousef <qais.yousef@imgtec.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Andrew Bresticker <abrestic@chromium.org>
Cc: Jeffrey Deans <jeffrey.deans@imgtec.com>
Cc: Markos Chandras <markos.chandras@imgtec.com>
Cc: Paul Burton <paul.burton@imgtec.com>
Cc: Qais Yousef <qais.yousef@imgtec.com>
Cc: Jonas Gorski <jogo@openwrt.org>
Cc: John Crispin <blogic@openwrt.org>
Cc: David Daney <ddaney.cavm@gmail.com>
Cc: linux-mips@linux-mips.org
Cc: linux-kernel@vger.kernel.org
Patchwork: https://patchwork.linux-mips.org/patch/7800/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
---
Documentation/devicetree/bindings/mips/cpu_irq.txt | 4 ++--
arch/mips/include/asm/irq_cpu.h | 4 ++--
arch/mips/kernel/irq_cpu.c | 4 ++--
arch/mips/ralink/irq.c | 2 +-
4 files changed, 7 insertions(+), 7 deletions(-)
--- a/Documentation/devicetree/bindings/mips/cpu_irq.txt
+++ b/Documentation/devicetree/bindings/mips/cpu_irq.txt
@@ -1,6 +1,6 @@
MIPS CPU interrupt controller
-On MIPS the mips_cpu_intc_init() helper can be used to initialize the 8 CPU
+On MIPS the mips_cpu_irq_of_init() helper can be used to initialize the 8 CPU
IRQs from a devicetree file and create a irq_domain for IRQ controller.
With the irq_domain in place we can describe how the 8 IRQs are wired to the
@@ -36,7 +36,7 @@ Example devicetree:
Example platform irq.c:
static struct of_device_id __initdata of_irq_ids[] = {
- { .compatible = "mti,cpu-interrupt-controller", .data = mips_cpu_intc_init },
+ { .compatible = "mti,cpu-interrupt-controller", .data = mips_cpu_irq_of_init },
{ .compatible = "ralink,rt2880-intc", .data = intc_of_init },
{},
};
--- a/arch/mips/include/asm/irq_cpu.h
+++ b/arch/mips/include/asm/irq_cpu.h
@@ -19,8 +19,8 @@ extern void rm9k_cpu_irq_init(void);
#ifdef CONFIG_IRQ_DOMAIN
struct device_node;
-extern int mips_cpu_intc_init(struct device_node *of_node,
- struct device_node *parent);
+extern int mips_cpu_irq_of_init(struct device_node *of_node,
+ struct device_node *parent);
#endif
#endif /* _ASM_IRQ_CPU_H */
--- a/arch/mips/kernel/irq_cpu.c
+++ b/arch/mips/kernel/irq_cpu.c
@@ -135,8 +135,8 @@ void __init mips_cpu_irq_init(void)
__mips_cpu_irq_init(NULL);
}
-int __init mips_cpu_intc_init(struct device_node *of_node,
- struct device_node *parent)
+int __init mips_cpu_irq_of_init(struct device_node *of_node,
+ struct device_node *parent)
{
__mips_cpu_irq_init(of_node);
return 0;
--- a/arch/mips/ralink/irq.c
+++ b/arch/mips/ralink/irq.c
@@ -173,7 +173,7 @@ static int __init intc_of_init(struct de
}
static struct of_device_id __initdata of_irq_ids[] = {
- { .compatible = "mti,cpu-interrupt-controller", .data = mips_cpu_intc_init },
+ { .compatible = "mti,cpu-interrupt-controller", .data = mips_cpu_irq_of_init },
{ .compatible = "ralink,rt2880-intc", .data = intc_of_init },
{},
};

View File

@ -0,0 +1,58 @@
From 85f7cdacbb81db8c4cc8e474837eab1f0e4ff77b Mon Sep 17 00:00:00 2001
From: Andrew Bresticker <abrestic@chromium.org>
Date: Thu, 18 Sep 2014 14:47:09 -0700
Subject: [PATCH 3/3] MIPS: Provide a generic plat_irq_dispatch
For platforms which boot with device-tree or have correctly chained
all external interrupt controllers, a generic plat_irq_dispatch() can
be used. Implement a plat_irq_dispatch() which simply handles all the
pending interrupts as reported by C0_Cause.
Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
Reviewed-by: Qais Yousef <qais.yousef@imgtec.com>
Tested-by: Qais Yousef <qais.yousef@imgtec.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Andrew Bresticker <abrestic@chromium.org>
Cc: Jeffrey Deans <jeffrey.deans@imgtec.com>
Cc: Markos Chandras <markos.chandras@imgtec.com>
Cc: Paul Burton <paul.burton@imgtec.com>
Cc: Qais Yousef <qais.yousef@imgtec.com>
Cc: Jonas Gorski <jogo@openwrt.org>
Cc: John Crispin <blogic@openwrt.org>
Cc: David Daney <ddaney.cavm@gmail.com>
Cc: linux-mips@linux-mips.org
Cc: linux-kernel@vger.kernel.org
Patchwork: https://patchwork.linux-mips.org/patch/7801/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
---
arch/mips/kernel/irq_cpu.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
--- a/arch/mips/kernel/irq_cpu.c
+++ b/arch/mips/kernel/irq_cpu.c
@@ -94,6 +94,24 @@ static struct irq_chip mips_mt_cpu_irq_c
.irq_eoi = unmask_mips_irq,
};
+asmlinkage void __weak plat_irq_dispatch(void)
+{
+ unsigned long pending = read_c0_cause() & read_c0_status() & ST0_IM;
+ int irq;
+
+ if (!pending) {
+ spurious_interrupt();
+ return;
+ }
+
+ pending >>= CAUSEB_IP;
+ while (pending) {
+ irq = fls(pending) - 1;
+ do_IRQ(MIPS_CPU_IRQ_BASE + irq);
+ pending &= ~BIT(irq);
+ }
+}
+
static int mips_cpu_intc_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hw)
{

View File

@ -0,0 +1,411 @@
From 4d3886359d6f6ac475e143d5f3e3b389542a0510 Mon Sep 17 00:00:00 2001
From: Jonas Gorski <jogo@openwrt.org>
Date: Sun, 30 Nov 2014 14:53:12 +0100
Subject: [PATCH 17/20] irqchip: add support for bcm6345-style l2 irq
controller
Signed-off-by: Jonas Gorski <jogo@openwrt.org>
---
.../interrupt-controller/brcm,bcm6345-l2-intc.txt | 25 ++
drivers/irqchip/Kconfig | 4 +
drivers/irqchip/Makefile | 1 +
drivers/irqchip/irq-bcm6345-l2.c | 320 ++++++++++++++++++++
include/linux/irqchip/irq-bcm6345-l2-intc.h | 16 +
5 files changed, 366 insertions(+)
create mode 100644 Documentation/devicetree/bindings/interrupt-controller/brcm,bcm6345-l2-intc.txt
create mode 100644 drivers/irqchip/irq-bcm6345-l2.c
create mode 100644 include/linux/irqchip/irq-bcm6345-l2-intc.h
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm6345-l2-intc.txt
@@ -0,0 +1,25 @@
+Broadcom BCM6345 Level 2 interrupt controller
+
+Required properties:
+
+- compatible: should be "brcm,bcm6345-l2-intc"
+- reg: specifies the base physical address and size of the registers;
+ multiple regs may be specified, and must match the amount of parent interrupts
+- interrupt-controller: identifies the node as an interrupt controller
+- #interrupt-cells: specifies the number of cells needed to encode an interrupt
+ source, should be 1
+- interrupt-parent: specifies the phandle to the parent interrupt controller
+ this one is cascaded from
+- interrupts: specifies the interrupt line(s) in the interrupt-parent controller
+ node, valid values depend on the type of parent interrupt controller
+
+Example:
+
+periph_intc: interrupt-controller@f0406800 {
+ compatible = "brcm,bcm6345-l2-intc";
+ interrupt-parent = <&mips_intc>;
+ #interrupt-cells = <1>;
+ reg = <0x10000020 0x10> <0x10000030 0x10>;
+ interrupt-controller;
+ interrupts = <2>, <3>;
+};
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -30,6 +30,10 @@ config ARM_VIC_NR
The maximum number of VICs available in the system, for
power management.
+config BCM6345_L2_IRQ
+ bool
+ select IRQ_DOMAIN
+
config DW_APB_ICTL
bool
select IRQ_DOMAIN
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_ARCH_MMP) += irq-mmp.o
obj-$(CONFIG_ARCH_MVEBU) += irq-armada-370-xp.o
obj-$(CONFIG_ARCH_MXS) += irq-mxs.o
obj-$(CONFIG_ARCH_S3C24XX) += irq-s3c24xx.o
+obj-$(CONFIG_BCM6345_L2_IRQ) += irq-bcm6345-l2.o
obj-$(CONFIG_DW_APB_ICTL) += irq-dw-apb-ictl.o
obj-$(CONFIG_METAG) += irq-metag-ext.o
obj-$(CONFIG_METAG_PERFCOUNTER_IRQS) += irq-metag.o
--- /dev/null
+++ b/drivers/irqchip/irq-bcm6345-l2.c
@@ -0,0 +1,320 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2014 Jonas Gorski <jogo@openwrt.org>
+ */
+
+#include <linux/ioport.h>
+#include <linux/irq.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqchip/irq-bcm6345-l2-intc.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#ifdef CONFIG_BCM63XX
+#include <asm/mach-bcm63xx/bcm63xx_irq.h>
+
+#define VIRQ_BASE IRQ_INTERNAL_BASE
+#else
+#define VIRQ_BASE 0
+#endif
+
+#include "irqchip.h"
+
+#define MAX_WORDS 4
+#define MAX_PARENT_IRQS 2
+#define IRQS_PER_WORD 32
+
+struct intc_block {
+ int parent_irq;
+ void __iomem *base;
+ void __iomem *en_reg[MAX_WORDS];
+ void __iomem *status_reg[MAX_WORDS];
+ u32 mask_cache[MAX_WORDS];
+};
+
+struct intc_data {
+ struct irq_chip chip;
+ struct intc_block block[MAX_PARENT_IRQS];
+
+ int num_words;
+
+ struct irq_domain *domain;
+ spinlock_t lock;
+};
+
+static void bcm6345_l2_intc_irq_handle(unsigned int irq, struct irq_desc *desc)
+{
+ struct intc_data *data = irq_desc_get_handler_data(desc);
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ struct intc_block *block;
+ unsigned int idx;
+
+ chained_irq_enter(chip, desc);
+
+ for (idx = 0; idx < MAX_PARENT_IRQS; idx++)
+ if (irq == data->block[idx].parent_irq)
+ block = &data->block[idx];
+
+ for (idx = 0; idx < data->num_words; idx++) {
+ int base = idx * IRQS_PER_WORD;
+ unsigned long pending;
+ int hw_irq;
+
+ raw_spin_lock(data->lock);
+ pending = __raw_readl(block->en_reg[idx]) &
+ __raw_readl(block->status_reg[idx]);
+ raw_spin_unlock(data->lock);
+
+ for_each_set_bit(hw_irq, &pending, IRQS_PER_WORD) {
+ generic_handle_irq(irq_find_mapping(data->domain, base + hw_irq));
+ }
+ }
+
+ chained_irq_exit(chip, desc);
+}
+
+static void bcm6345_l2_intc_irq_mask(struct irq_data *data)
+{
+ unsigned int i, reg, bit;
+ struct intc_data *priv = data->domain->host_data;
+ irq_hw_number_t hwirq = irqd_to_hwirq(data);
+
+ reg = hwirq / IRQS_PER_WORD;
+ bit = hwirq % IRQS_PER_WORD;
+
+ raw_spin_lock(priv->lock);
+ for (i = 0; i < MAX_PARENT_IRQS; i++) {
+ struct intc_block *block = &priv->block[i];
+ u32 val;
+
+ if (!block->parent_irq)
+ break;
+
+ val = __raw_readl(block->en_reg[reg]);
+ __raw_writel(val & ~BIT(bit), block->en_reg[reg]);
+ }
+ raw_spin_unlock(priv->lock);
+}
+
+static void bcm6345_l2_intc_irq_unmask(struct irq_data *data)
+{
+ unsigned int i, reg, bit;
+ struct intc_data *priv = data->domain->host_data;
+ irq_hw_number_t hwirq = irqd_to_hwirq(data);
+
+ reg = hwirq / IRQS_PER_WORD;
+ bit = hwirq % IRQS_PER_WORD;
+
+ raw_spin_lock(priv->lock);
+ for (i = 0; i < MAX_PARENT_IRQS; i++) {
+ struct intc_block *block = &priv->block[i];
+ u32 val;
+
+ if (!block->parent_irq)
+ break;
+
+ val = __raw_readl(block->en_reg[reg]);
+
+ if (block->mask_cache[reg] & BIT(bit))
+ val |= BIT(bit);
+ else
+ val &= ~BIT(bit);
+
+ __raw_writel(val, block->en_reg[reg]);
+
+ }
+ raw_spin_unlock(priv->lock);
+}
+
+#ifdef CONFIG_SMP
+static int bcm6345_l2_intc_set_affinity(struct irq_data *data,
+ const struct cpumask *mask,
+ bool force)
+{
+ irq_hw_number_t hwirq = irqd_to_hwirq(data);
+ struct intc_data *priv = data->domain->host_data;
+ unsigned int i, reg, bit;
+ int cpu;
+
+ reg = hwirq / IRQS_PER_WORD;
+ bit = hwirq % IRQS_PER_WORD;
+
+ /* we could route to more than one cpu, but performance
+ suffers, so fix it to one.
+ */
+ cpu = cpumask_any_and(mask, cpu_online_mask);
+ if (cpu >= nr_cpu_ids)
+ return -EINVAL;
+
+ if (cpu >= MAX_PARENT_IRQS)
+ return -EINVAL;
+
+ if (!priv->block[cpu].parent_irq)
+ return -EINVAL;
+
+ raw_spin_lock(priv->lock);
+ for (i = 0; i < MAX_PARENT_IRQS; i++) {
+ if (i == cpu)
+ priv->block[i].mask_cache[reg] |= BIT(bit);
+ else
+ priv->block[i].mask_cache[reg] &= ~BIT(bit);
+ }
+ raw_spin_unlock(priv->lock);
+
+ return 0;
+}
+#endif
+
+static int bcm6345_l2_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hw)
+{
+ struct intc_data *priv = d->host_data;
+
+ irq_set_chip_and_handler(irq, &priv->chip, handle_level_irq);
+
+ return 0;
+}
+
+static const struct irq_domain_ops bcm6345_l2_domain_ops = {
+ .xlate = irq_domain_xlate_onecell,
+ .map = bcm6345_l2_map,
+};
+
+static int __init __bcm6345_l2_intc_init(struct device_node *node,
+ int num_blocks, int *irq,
+ void __iomem **base, int num_words)
+{
+ struct intc_data *data;
+ unsigned int i, w, status_offset;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ status_offset = num_words * sizeof(u32);
+
+ for (i = 0; i < num_blocks; i++) {
+ struct intc_block *block = &data->block[i];
+
+ block->parent_irq = irq[i];
+ block->base = base[i];
+
+ for (w = 0; w < num_words; w++) {
+ int word_offset = sizeof(u32) * ((num_words - w) - 1);
+
+ block->en_reg[w] = base[i] + word_offset;
+ block->status_reg[w] = base[i] + status_offset;
+ block->status_reg[w] += word_offset;
+
+ /* route all interrups to line 0 by default */
+ if (i == 0)
+ block->mask_cache[w] = 0xffffffff;
+ }
+
+ irq_set_handler_data(block->parent_irq, data);
+ irq_set_chained_handler(block->parent_irq,
+ bcm6345_l2_intc_irq_handle);
+ }
+
+ data->num_words = num_words;
+
+ data->chip.name = "bcm6345-l2-intc";
+ data->chip.irq_mask = bcm6345_l2_intc_irq_mask;
+ data->chip.irq_unmask = bcm6345_l2_intc_irq_unmask;
+
+#ifdef CONFIG_SMP
+ if (num_blocks > 1)
+ data->chip.set_affinity = bcm6345_l2_intc_set_affinity;
+#endif
+
+ data->domain = irq_domain_add_simple(node, IRQS_PER_WORD * num_words,
+ VIRQ_BASE, &bcm6345_l2_domain_ops,
+ data);
+ if (!data->domain) {
+ kfree(data);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+void __init bcm6345_l2_intc_init(int num_blocks, int *irq, void __iomem **base,
+ int num_words)
+{
+ __bcm6345_l2_intc_init(NULL, num_blocks, irq, base, num_words);
+}
+
+#ifdef CONFIG_OF
+static int __init bcm6345_l2_intc_of_init(struct device_node *node,
+ struct device_node *parent)
+{
+ struct resource res;
+ int num_irqs, ret = -EINVAL;
+ int irqs[MAX_PARENT_IRQS] = { 0 };
+ void __iomem *bases[MAX_PARENT_IRQS] = { NULL };
+ int words = 0;
+ int i;
+
+ num_irqs = of_irq_count(node);
+
+ if (num_irqs < 1 || num_irqs > MAX_PARENT_IRQS)
+ return -EINVAL;
+
+ for (i = 0; i < num_irqs; i++) {
+ resource_size_t size;
+
+ irqs[i] = irq_of_parse_and_map(node, i);
+ if (!irqs[i])
+ goto out_unmap;
+
+ if (of_address_to_resource(node, i, &res)) {
+ goto out_unmap;
+ }
+
+ size = resource_size(&res);
+ switch (size) {
+ case 8:
+ case 16:
+ case 32:
+ size = size / 8;
+ break;
+ default:
+ goto out_unmap;
+ }
+
+ if (words && words != size) {
+ ret = -EINVAL;
+ goto out_unmap;
+ }
+ words = size;
+
+ bases[i] = of_iomap(node, i);
+ if (!bases[i]) {
+ ret = -ENOMEM;
+ goto out_unmap;
+ }
+ }
+
+ ret = __bcm6345_l2_intc_init(node, num_irqs, irqs, bases, words);
+ if (!ret)
+ return 0;
+
+out_unmap:
+ for (i = 0; i < num_irqs; i++) {
+ iounmap(bases[i]);
+ irq_dispose_mapping(irqs[i]);
+ }
+
+ return ret;
+}
+
+IRQCHIP_DECLARE(bcm6345_l2_intc, "brcm,bcm6345-l2-intc",
+ bcm6345_l2_intc_of_init);
+#endif
--- /dev/null
+++ b/include/linux/irqchip/irq-bcm6345-l2-intc.h
@@ -0,0 +1,16 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
+ * Copyright (C) 2008 Nicolas Schichan <nschichan@freebox.fr>
+ */
+
+#ifndef __INCLUDE_LINUX_IRQCHIP_IRQ_BCM6345_L2_INTC_H
+#define __INCLUDE_LINUX_IRQCHIP_IRQ_BCM6345_L2_INTC_H
+
+void bcm6345_l2_intc_init(int num_blocks, int *irq, void __iomem **base,
+ int num_words);
+
+#endif /* __INCLUDE_LINUX_IRQCHIP_IRQ_BCM6345_L2_INTC_H */

View File

@ -0,0 +1,384 @@
From 6896b5f0538a7a7cfb7fac2d9ed3c6841c72ed40 Mon Sep 17 00:00:00 2001
From: Jonas Gorski <jogo@openwrt.org>
Date: Sun, 30 Nov 2014 14:54:27 +0100
Subject: [PATCH 18/20] irqchip: add support for bcm6345-style external
interrupt controller
Signed-off-by: Jonas Gorski <jogo@openwrt.org>
---
.../interrupt-controller/brcm,bcm6345-ext-intc.txt | 24 ++
drivers/irqchip/Kconfig | 4 +
drivers/irqchip/Makefile | 1 +
drivers/irqchip/irq-bcm6345-ext.c | 296 ++++++++++++++++++++
include/linux/irqchip/irq-bcm6345-ext-intc.h | 14 +
5 files changed, 339 insertions(+)
create mode 100644 Documentation/devicetree/bindings/interrupt-controller/brcm,bcm6345-ext-intc.txt
create mode 100644 drivers/irqchip/irq-bcm6345-ext.c
create mode 100644 include/linux/irqchip/irq-bcm6345-ext-intc.h
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm6345-ext-intc.txt
@@ -0,0 +1,24 @@
+Broadcom BCM6345-style external interrupt controller
+
+Required properties:
+
+- compatible: should be "brcm,bcm6345-l2-intc" or "brcm,bcm6345-l2-intc"
+- reg: specifies the base physical addresses and size of the registers.
+- interrupt-controller: identifies the node as an interrupt controller
+- #interrupt-cells: specifies the number of cells needed to encode an interrupt
+ source, should be 2
+- interrupt-parent: specifies the phandle to the parent interrupt controller
+ this one is cascaded from
+- interrupts: specifies the interrupt line(s) in the interrupt-parent controller
+ node, valid values depend on the type of parent interrupt controller
+
+Example:
+
+ext_intc: interrupt-controller@10000018 {
+ compatible = "brcm,bcm6345-l2-intc";
+ interrupt-parent = <&periph_intc>;
+ #interrupt-cells = <2>;
+ reg = <0x10000018 0x4>;
+ interrupt-controller;
+ interrupts = <24>, <25>, <26>, <27>;
+};
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -30,6 +30,10 @@ config ARM_VIC_NR
The maximum number of VICs available in the system, for
power management.
+config BCM6345_EXT_IRQ
+ bool
+ select IRQ_DOMAIN
+
config BCM6345_L2_IRQ
bool
select IRQ_DOMAIN
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_ARCH_MMP) += irq-mmp.o
obj-$(CONFIG_ARCH_MVEBU) += irq-armada-370-xp.o
obj-$(CONFIG_ARCH_MXS) += irq-mxs.o
obj-$(CONFIG_ARCH_S3C24XX) += irq-s3c24xx.o
+obj-$(CONFIG_BCM6345_EXT_IRQ) += irq-bcm6345-ext.o
obj-$(CONFIG_BCM6345_L2_IRQ) += irq-bcm6345-l2.o
obj-$(CONFIG_DW_APB_ICTL) += irq-dw-apb-ictl.o
obj-$(CONFIG_METAG) += irq-metag-ext.o
--- /dev/null
+++ b/drivers/irqchip/irq-bcm6345-ext.c
@@ -0,0 +1,296 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2014 Jonas Gorski <jogo@openwrt.org>
+i */
+
+#include <linux/ioport.h>
+#include <linux/irq.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqchip/irq-bcm6345-ext-intc.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include "irqchip.h"
+
+#ifdef CONFIG_BCM63XX
+#include <asm/mach-bcm63xx/bcm63xx_irq.h>
+
+#define VIRQ_BASE IRQ_EXTERNAL_BASE
+#else
+#define VIRQ_BASE 0
+#endif
+
+#define MAX_IRQS 4
+
+#define EXTIRQ_CFG_SENSE 0
+#define EXTIRQ_CFG_STAT 1
+#define EXTIRQ_CFG_CLEAR 2
+#define EXTIRQ_CFG_MASK 3
+#define EXTIRQ_CFG_BOTHEDGE 4
+#define EXTIRQ_CFG_LEVELSENSE 5
+
+struct intc_data {
+ struct irq_chip chip;
+ struct irq_domain *domain;
+ spinlock_t lock;
+
+ int parent_irq[MAX_IRQS];
+ void __iomem *reg;
+ int shift;
+};
+
+static void bcm6345_ext_intc_irq_handle(unsigned int irq, struct irq_desc *desc)
+{
+ struct intc_data *data = irq_desc_get_handler_data(desc);
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ unsigned int idx;
+
+ chained_irq_enter(chip, desc);
+
+ for (idx = 0; idx < MAX_IRQS; idx++) {
+ if (data->parent_irq[idx] != irq)
+ continue;
+
+ generic_handle_irq(irq_find_mapping(data->domain, idx));
+ }
+
+ chained_irq_exit(chip, desc);
+}
+
+static void bcm6345_ext_intc_irq_ack(struct irq_data *data)
+{
+ struct intc_data *priv = data->domain->host_data;
+ irq_hw_number_t hwirq = irqd_to_hwirq(data);
+ u32 reg;
+
+ raw_spin_lock(priv->lock);
+ reg = __raw_readl(priv->reg);
+ reg |= hwirq << (EXTIRQ_CFG_CLEAR * priv->shift);
+ __raw_writel(reg, priv->reg);
+ raw_spin_unlock(priv->lock);
+}
+
+static void bcm6345_ext_intc_irq_mask(struct irq_data *data)
+{
+ struct intc_data *priv = data->domain->host_data;
+ irq_hw_number_t hwirq = irqd_to_hwirq(data);
+ u32 reg;
+
+ raw_spin_lock(priv->lock);
+ reg = __raw_readl(priv->reg);
+ reg &= ~(hwirq << (EXTIRQ_CFG_MASK * priv->shift));
+ __raw_writel(reg, priv->reg);
+ raw_spin_unlock(priv->lock);
+}
+
+static void bcm6345_ext_intc_irq_unmask(struct irq_data *data)
+{
+ struct intc_data *priv = data->domain->host_data;
+ irq_hw_number_t hwirq = irqd_to_hwirq(data);
+ u32 reg;
+
+ raw_spin_lock(priv->lock);
+ reg = __raw_readl(priv->reg);
+ reg |= hwirq << (EXTIRQ_CFG_MASK * priv->shift);
+ __raw_writel(reg, priv->reg);
+ raw_spin_unlock(priv->lock);
+}
+
+static int bcm6345_ext_intc_set_type(struct irq_data *data,
+ unsigned int flow_type)
+{
+ struct intc_data *priv = data->domain->host_data;
+ irq_hw_number_t hwirq = irqd_to_hwirq(data);
+ bool levelsense = 0, sense = 0, bothedge = 0;
+ u32 reg;
+
+ flow_type &= IRQ_TYPE_SENSE_MASK;
+
+ if (flow_type == IRQ_TYPE_NONE)
+ flow_type = IRQ_TYPE_LEVEL_LOW;
+
+ switch (flow_type) {
+ case IRQ_TYPE_EDGE_BOTH:
+ bothedge = 1;
+ break;
+
+ case IRQ_TYPE_EDGE_RISING:
+ break;
+
+ case IRQ_TYPE_EDGE_FALLING:
+ sense = 1;
+ break;
+
+ case IRQ_TYPE_LEVEL_HIGH:
+ levelsense = 1;
+ sense = 1;
+ break;
+
+ case IRQ_TYPE_LEVEL_LOW:
+ levelsense = 1;
+ break;
+
+ default:
+ pr_err("bogus flow type combination given!\n");
+ return -EINVAL;
+ }
+
+ raw_spin_lock(priv->lock);
+ reg = __raw_readl(priv->reg);
+
+ if (levelsense)
+ reg |= hwirq << (EXTIRQ_CFG_LEVELSENSE * priv->shift);
+ else
+ reg &= ~(hwirq << (EXTIRQ_CFG_LEVELSENSE * priv->shift));
+ if (sense)
+ reg |= hwirq << (EXTIRQ_CFG_SENSE * priv->shift);
+ else
+ reg &= ~(hwirq << (EXTIRQ_CFG_SENSE * priv->shift));
+ if (bothedge)
+ reg |= hwirq << (EXTIRQ_CFG_BOTHEDGE * priv->shift);
+ else
+ reg &= ~(hwirq << (EXTIRQ_CFG_BOTHEDGE * priv->shift));
+
+ __raw_writel(reg, priv->reg);
+ raw_spin_unlock(priv->lock);
+
+ irqd_set_trigger_type(data, flow_type);
+ if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
+ __irq_set_handler_locked(data->irq, handle_level_irq);
+ else
+ __irq_set_handler_locked(data->irq, handle_edge_irq);
+
+ return 0;
+}
+
+static int bcm6345_ext_intc_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hw)
+{
+ struct intc_data *priv = d->host_data;
+
+ irq_set_chip_and_handler(irq, &priv->chip, handle_level_irq);
+
+ return 0;
+}
+
+
+static const struct irq_domain_ops bcm6345_ext_domain_ops = {
+ .xlate = irq_domain_xlate_twocell,
+ .map = bcm6345_ext_intc_map,
+};
+
+static int __init __bcm6345_ext_intc_init(struct device_node *node,
+ int num_irqs, int *irqs,
+ void __iomem *reg, int shift)
+{
+ struct intc_data *data;
+ unsigned int i;
+ int start = VIRQ_BASE;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ for (i = 0; i < num_irqs; i++) {
+ data->parent_irq[i] = irqs[i];
+
+ irq_set_handler_data(irqs[i], data);
+ irq_set_chained_handler(irqs[i], bcm6345_ext_intc_irq_handle);
+ }
+
+ data->reg = reg;
+
+ data->chip.name = "bcm6345-ext-intc";
+ data->chip.irq_ack = bcm6345_ext_intc_irq_ack;
+ data->chip.irq_mask = bcm6345_ext_intc_irq_mask;
+ data->chip.irq_unmask = bcm6345_ext_intc_irq_unmask;
+ data->chip.irq_set_type = bcm6345_ext_intc_set_type;
+
+ /*
+ * If we have less than 4 irqs, this is the second controller on
+ * bcm63xx. So increase the VIRQ start to not overlap with the first
+ * one, but only do so if we actually use a non-zero start.
+ *
+ * This can be removed when bcm63xx has no legacy users anymore.
+ */
+ if (start && num_irqs < 4)
+ start += 4;
+
+ data->domain = irq_domain_add_simple(node, num_irqs, start,
+ &bcm6345_ext_domain_ops, data);
+ if (!data->domain) {
+ kfree(data);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+void __init bcm6345_ext_intc_init(int num_irqs, int *irqs, void __iomem *reg,
+ int shift)
+{
+ __bcm6345_ext_intc_init(NULL, num_irqs, irqs, reg, shift);
+}
+
+#ifdef CONFIG_OF
+static int __init bcm63xx_ext_intc_of_init(struct device_node *node,
+ struct device_node *parent,
+ int shift)
+{
+ int num_irqs, ret = -EINVAL;
+ unsigned i;
+ void __iomem *base;
+ int irqs[MAX_IRQS] = { 0 };
+
+ num_irqs = of_irq_count(node);
+
+ if (!num_irqs || num_irqs > MAX_IRQS)
+ return -EINVAL;
+
+ for (i = 0; i < num_irqs; i++) {
+ irqs[i] = irq_of_parse_and_map(node, i);
+ if (!irqs[i]) {
+ ret = -ENOMEM;
+ goto out_unmap;
+ }
+ }
+
+ base = of_iomap(node, 0);
+ if (!base)
+ goto out_unmap;
+
+ ret = __bcm6345_ext_intc_init(node, num_irqs, irqs, base, shift);
+ if (!ret)
+ return 0;
+out_unmap:
+ iounmap(base);
+
+ for (i = 0; i < num_irqs; i++)
+ irq_dispose_mapping(irqs[i]);
+
+ return ret;
+}
+
+static int __init bcm6345_ext_intc_of_init(struct device_node *node,
+ struct device_node *parent)
+{
+ return bcm63xx_ext_intc_of_init(node, parent, 4);
+}
+static int __init bcm6348_ext_intc_of_init(struct device_node *node,
+ struct device_node *parent)
+{
+ return bcm63xx_ext_intc_of_init(node, parent, 5);
+}
+
+IRQCHIP_DECLARE(bcm6345_ext_intc, "brcm,bcm6345-ext-intc",
+ bcm6345_ext_intc_of_init);
+IRQCHIP_DECLARE(bcm6348_ext_intc, "brcm,bcm6348-ext-intc",
+ bcm6348_ext_intc_of_init);
+#endif
--- /dev/null
+++ b/include/linux/irqchip/irq-bcm6345-ext-intc.h
@@ -0,0 +1,14 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2014 Jonas Gorski <jogo@openwrt.org>
+ */
+
+#ifndef __INCLUDE_LINUX_IRQCHIP_IRQ_BCM6345_EXT_INTC_H
+#define __INCLUDE_LINUX_IRQCHIP_IRQ_BCM6345_EXT_INTC_H
+
+void bcm6345_ext_intc_init(int n_irqs, int *irqs, void __iomem *reg, int shift);
+
+#endif /* __INCLUDE_LINUX_IRQCHIP_IRQ_BCM6345_EXT_INTC_H */

View File

@ -0,0 +1,694 @@
From d93661c9e164ccc41820eeb4f1881e59a34a9e5c Mon Sep 17 00:00:00 2001
From: Jonas Gorski <jogo@openwrt.org>
Date: Sun, 30 Nov 2014 14:55:02 +0100
Subject: [PATCH 19/20] MIPS: BCM63XX: switch to IRQ_DOMAIN
Now that we have working IRQ_DOMAIN drivers for both interrupt controllers,
switch to using them.
Signed-off-by: Jonas Gorski <jogo@openwrt.org>
---
arch/mips/Kconfig | 3 +
arch/mips/bcm63xx/irq.c | 608 ++++++++---------------------------------------
2 files changed, 108 insertions(+), 503 deletions(-)
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -135,6 +135,9 @@ config BCM63XX
select SYNC_R4K
select DMA_NONCOHERENT
select IRQ_CPU
+ select BCM6345_EXT_IRQ
+ select BCM6345_L2_IRQ
+ select IRQ_DOMAIN
select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_BIG_ENDIAN
select SYS_HAS_EARLY_PRINTK
--- a/arch/mips/bcm63xx/irq.c
+++ b/arch/mips/bcm63xx/irq.c
@@ -12,7 +12,9 @@
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/irq.h>
-#include <linux/spinlock.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/irq-bcm6345-ext-intc.h>
+#include <linux/irqchip/irq-bcm6345-l2-intc.h>
#include <asm/irq_cpu.h>
#include <asm/mipsregs.h>
#include <bcm63xx_cpu.h>
@@ -20,544 +22,144 @@
#include <bcm63xx_io.h>
#include <bcm63xx_irq.h>
-
-static DEFINE_SPINLOCK(ipic_lock);
-static DEFINE_SPINLOCK(epic_lock);
-
-static u32 irq_stat_addr[2];
-static u32 irq_mask_addr[2];
-static void (*dispatch_internal)(int cpu);
-static int is_ext_irq_cascaded;
-static unsigned int ext_irq_count;
-static unsigned int ext_irq_start, ext_irq_end;
-static unsigned int ext_irq_cfg_reg1, ext_irq_cfg_reg2;
-static void (*internal_irq_mask)(struct irq_data *d);
-static void (*internal_irq_unmask)(struct irq_data *d, const struct cpumask *m);
-
-
-static inline u32 get_ext_irq_perf_reg(int irq)
-{
- if (irq < 4)
- return ext_irq_cfg_reg1;
- return ext_irq_cfg_reg2;
-}
-
-static inline void handle_internal(int intbit)
-{
- if (is_ext_irq_cascaded &&
- intbit >= ext_irq_start && intbit <= ext_irq_end)
- do_IRQ(intbit - ext_irq_start + IRQ_EXTERNAL_BASE);
- else
- do_IRQ(intbit + IRQ_INTERNAL_BASE);
-}
-
-static inline int enable_irq_for_cpu(int cpu, struct irq_data *d,
- const struct cpumask *m)
-{
- bool enable = cpu_online(cpu);
-
-#ifdef CONFIG_SMP
- if (m)
- enable &= cpu_isset(cpu, *m);
- else if (irqd_affinity_was_set(d))
- enable &= cpu_isset(cpu, *d->affinity);
-#endif
- return enable;
-}
-
-/*
- * dispatch internal devices IRQ (uart, enet, watchdog, ...). do not
- * prioritize any interrupt relatively to another. the static counter
- * will resume the loop where it ended the last time we left this
- * function.
- */
-
-#define BUILD_IPIC_INTERNAL(width) \
-void __dispatch_internal_##width(int cpu) \
-{ \
- u32 pending[width / 32]; \
- unsigned int src, tgt; \
- bool irqs_pending = false; \
- static unsigned int i[2]; \
- unsigned int *next = &i[cpu]; \
- unsigned long flags; \
- \
- /* read registers in reverse order */ \
- spin_lock_irqsave(&ipic_lock, flags); \
- for (src = 0, tgt = (width / 32); src < (width / 32); src++) { \
- u32 val; \
- \
- val = bcm_readl(irq_stat_addr[cpu] + src * sizeof(u32)); \
- val &= bcm_readl(irq_mask_addr[cpu] + src * sizeof(u32)); \
- pending[--tgt] = val; \
- \
- if (val) \
- irqs_pending = true; \
- } \
- spin_unlock_irqrestore(&ipic_lock, flags); \
- \
- if (!irqs_pending) \
- return; \
- \
- while (1) { \
- unsigned int to_call = *next; \
- \
- *next = (*next + 1) & (width - 1); \
- if (pending[to_call / 32] & (1 << (to_call & 0x1f))) { \
- handle_internal(to_call); \
- break; \
- } \
- } \
-} \
- \
-static void __internal_irq_mask_##width(struct irq_data *d) \
-{ \
- u32 val; \
- unsigned irq = d->irq - IRQ_INTERNAL_BASE; \
- unsigned reg = (irq / 32) ^ (width/32 - 1); \
- unsigned bit = irq & 0x1f; \
- unsigned long flags; \
- int cpu; \
- \
- spin_lock_irqsave(&ipic_lock, flags); \
- for_each_present_cpu(cpu) { \
- if (!irq_mask_addr[cpu]) \
- break; \
- \
- val = bcm_readl(irq_mask_addr[cpu] + reg * sizeof(u32));\
- val &= ~(1 << bit); \
- bcm_writel(val, irq_mask_addr[cpu] + reg * sizeof(u32));\
- } \
- spin_unlock_irqrestore(&ipic_lock, flags); \
-} \
- \
-static void __internal_irq_unmask_##width(struct irq_data *d, \
- const struct cpumask *m) \
-{ \
- u32 val; \
- unsigned irq = d->irq - IRQ_INTERNAL_BASE; \
- unsigned reg = (irq / 32) ^ (width/32 - 1); \
- unsigned bit = irq & 0x1f; \
- unsigned long flags; \
- int cpu; \
- \
- spin_lock_irqsave(&ipic_lock, flags); \
- for_each_present_cpu(cpu) { \
- if (!irq_mask_addr[cpu]) \
- break; \
- \
- val = bcm_readl(irq_mask_addr[cpu] + reg * sizeof(u32));\
- if (enable_irq_for_cpu(cpu, d, m)) \
- val |= (1 << bit); \
- else \
- val &= ~(1 << bit); \
- bcm_writel(val, irq_mask_addr[cpu] + reg * sizeof(u32));\
- } \
- spin_unlock_irqrestore(&ipic_lock, flags); \
-}
-
-BUILD_IPIC_INTERNAL(32);
-BUILD_IPIC_INTERNAL(64);
-
-asmlinkage void plat_irq_dispatch(void)
-{
- u32 cause;
-
- do {
- cause = read_c0_cause() & read_c0_status() & ST0_IM;
-
- if (!cause)
- break;
-
- if (cause & CAUSEF_IP7)
- do_IRQ(7);
- if (cause & CAUSEF_IP0)
- do_IRQ(0);
- if (cause & CAUSEF_IP1)
- do_IRQ(1);
- if (cause & CAUSEF_IP2)
- dispatch_internal(0);
- if (is_ext_irq_cascaded) {
- if (cause & CAUSEF_IP3)
- dispatch_internal(1);
- } else {
- if (cause & CAUSEF_IP3)
- do_IRQ(IRQ_EXT_0);
- if (cause & CAUSEF_IP4)
- do_IRQ(IRQ_EXT_1);
- if (cause & CAUSEF_IP5)
- do_IRQ(IRQ_EXT_2);
- if (cause & CAUSEF_IP6)
- do_IRQ(IRQ_EXT_3);
- }
- } while (1);
-}
-
-/*
- * internal IRQs operations: only mask/unmask on PERF irq mask
- * register.
- */
-static void bcm63xx_internal_irq_mask(struct irq_data *d)
-{
- internal_irq_mask(d);
-}
-
-static void bcm63xx_internal_irq_unmask(struct irq_data *d)
-{
- internal_irq_unmask(d, NULL);
-}
-
-/*
- * external IRQs operations: mask/unmask and clear on PERF external
- * irq control register.
- */
-static void bcm63xx_external_irq_mask(struct irq_data *d)
-{
- unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
- u32 reg, regaddr;
- unsigned long flags;
-
- regaddr = get_ext_irq_perf_reg(irq);
- spin_lock_irqsave(&epic_lock, flags);
- reg = bcm_perf_readl(regaddr);
-
- if (BCMCPU_IS_6348())
- reg &= ~EXTIRQ_CFG_MASK_6348(irq % 4);
- else
- reg &= ~EXTIRQ_CFG_MASK(irq % 4);
-
- bcm_perf_writel(reg, regaddr);
- spin_unlock_irqrestore(&epic_lock, flags);
-
- if (is_ext_irq_cascaded)
- internal_irq_mask(irq_get_irq_data(irq + ext_irq_start));
-}
-
-static void bcm63xx_external_irq_unmask(struct irq_data *d)
-{
- unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
- u32 reg, regaddr;
- unsigned long flags;
-
- regaddr = get_ext_irq_perf_reg(irq);
- spin_lock_irqsave(&epic_lock, flags);
- reg = bcm_perf_readl(regaddr);
-
- if (BCMCPU_IS_6348())
- reg |= EXTIRQ_CFG_MASK_6348(irq % 4);
- else
- reg |= EXTIRQ_CFG_MASK(irq % 4);
-
- bcm_perf_writel(reg, regaddr);
- spin_unlock_irqrestore(&epic_lock, flags);
-
- if (is_ext_irq_cascaded)
- internal_irq_unmask(irq_get_irq_data(irq + ext_irq_start),
- NULL);
-}
-
-static void bcm63xx_external_irq_clear(struct irq_data *d)
-{
- unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
- u32 reg, regaddr;
- unsigned long flags;
-
- regaddr = get_ext_irq_perf_reg(irq);
- spin_lock_irqsave(&epic_lock, flags);
- reg = bcm_perf_readl(regaddr);
-
- if (BCMCPU_IS_6348())
- reg |= EXTIRQ_CFG_CLEAR_6348(irq % 4);
- else
- reg |= EXTIRQ_CFG_CLEAR(irq % 4);
-
- bcm_perf_writel(reg, regaddr);
- spin_unlock_irqrestore(&epic_lock, flags);
-}
-
-static int bcm63xx_external_irq_set_type(struct irq_data *d,
- unsigned int flow_type)
-{
- unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
- u32 reg, regaddr;
- int levelsense, sense, bothedge;
- unsigned long flags;
-
- flow_type &= IRQ_TYPE_SENSE_MASK;
-
- if (flow_type == IRQ_TYPE_NONE)
- flow_type = IRQ_TYPE_LEVEL_LOW;
-
- levelsense = sense = bothedge = 0;
- switch (flow_type) {
- case IRQ_TYPE_EDGE_BOTH:
- bothedge = 1;
- break;
-
- case IRQ_TYPE_EDGE_RISING:
- sense = 1;
- break;
-
- case IRQ_TYPE_EDGE_FALLING:
- break;
-
- case IRQ_TYPE_LEVEL_HIGH:
- levelsense = 1;
- sense = 1;
- break;
-
- case IRQ_TYPE_LEVEL_LOW:
- levelsense = 1;
- break;
-
- default:
- printk(KERN_ERR "bogus flow type combination given !\n");
- return -EINVAL;
- }
-
- regaddr = get_ext_irq_perf_reg(irq);
- spin_lock_irqsave(&epic_lock, flags);
- reg = bcm_perf_readl(regaddr);
- irq %= 4;
-
- switch (bcm63xx_get_cpu_id()) {
- case BCM6348_CPU_ID:
- if (levelsense)
- reg |= EXTIRQ_CFG_LEVELSENSE_6348(irq);
- else
- reg &= ~EXTIRQ_CFG_LEVELSENSE_6348(irq);
- if (sense)
- reg |= EXTIRQ_CFG_SENSE_6348(irq);
- else
- reg &= ~EXTIRQ_CFG_SENSE_6348(irq);
- if (bothedge)
- reg |= EXTIRQ_CFG_BOTHEDGE_6348(irq);
- else
- reg &= ~EXTIRQ_CFG_BOTHEDGE_6348(irq);
- break;
-
- case BCM3368_CPU_ID:
- case BCM6328_CPU_ID:
- case BCM6338_CPU_ID:
- case BCM6345_CPU_ID:
- case BCM6358_CPU_ID:
- case BCM6362_CPU_ID:
- case BCM6368_CPU_ID:
- if (levelsense)
- reg |= EXTIRQ_CFG_LEVELSENSE(irq);
- else
- reg &= ~EXTIRQ_CFG_LEVELSENSE(irq);
- if (sense)
- reg |= EXTIRQ_CFG_SENSE(irq);
- else
- reg &= ~EXTIRQ_CFG_SENSE(irq);
- if (bothedge)
- reg |= EXTIRQ_CFG_BOTHEDGE(irq);
- else
- reg &= ~EXTIRQ_CFG_BOTHEDGE(irq);
- break;
- default:
- BUG();
- }
-
- bcm_perf_writel(reg, regaddr);
- spin_unlock_irqrestore(&epic_lock, flags);
-
- irqd_set_trigger_type(d, flow_type);
- if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
- __irq_set_handler_locked(d->irq, handle_level_irq);
- else
- __irq_set_handler_locked(d->irq, handle_edge_irq);
-
- return IRQ_SET_MASK_OK_NOCOPY;
-}
-
-#ifdef CONFIG_SMP
-static int bcm63xx_internal_set_affinity(struct irq_data *data,
- const struct cpumask *dest,
- bool force)
-{
- if (!irqd_irq_disabled(data))
- internal_irq_unmask(data, dest);
-
- return 0;
-}
-#endif
-
-static struct irq_chip bcm63xx_internal_irq_chip = {
- .name = "bcm63xx_ipic",
- .irq_mask = bcm63xx_internal_irq_mask,
- .irq_unmask = bcm63xx_internal_irq_unmask,
-};
-
-static struct irq_chip bcm63xx_external_irq_chip = {
- .name = "bcm63xx_epic",
- .irq_ack = bcm63xx_external_irq_clear,
-
- .irq_mask = bcm63xx_external_irq_mask,
- .irq_unmask = bcm63xx_external_irq_unmask,
-
- .irq_set_type = bcm63xx_external_irq_set_type,
-};
-
-static struct irqaction cpu_ip2_cascade_action = {
- .handler = no_action,
- .name = "cascade_ip2",
- .flags = IRQF_NO_THREAD,
-};
-
-#ifdef CONFIG_SMP
-static struct irqaction cpu_ip3_cascade_action = {
- .handler = no_action,
- .name = "cascade_ip3",
- .flags = IRQF_NO_THREAD,
-};
-#endif
-
-static struct irqaction cpu_ext_cascade_action = {
- .handler = no_action,
- .name = "cascade_extirq",
- .flags = IRQF_NO_THREAD,
-};
-
static void bcm63xx_init_irq(void)
{
- int irq_bits;
-
- irq_stat_addr[0] = bcm63xx_regset_address(RSET_PERF);
- irq_mask_addr[0] = bcm63xx_regset_address(RSET_PERF);
- irq_stat_addr[1] = bcm63xx_regset_address(RSET_PERF);
- irq_mask_addr[1] = bcm63xx_regset_address(RSET_PERF);
+ void __iomem *l2_intc_bases[2];
+ void __iomem *ext_intc_bases[2];
+ int l2_irq_count, l2_width, ext_irq_count, ext_shift;
+ int l2_irqs[2] = { 2, 3 };
+ int ext_irqs[6];
+
+ l2_intc_bases[0] = (void __iomem *)bcm63xx_regset_address(RSET_PERF);
+ l2_intc_bases[1] = (void __iomem *)bcm63xx_regset_address(RSET_PERF);
+ ext_intc_bases[0] = (void __iomem *)bcm63xx_regset_address(RSET_PERF);
+ ext_intc_bases[1] = (void __iomem *)bcm63xx_regset_address(RSET_PERF);
switch (bcm63xx_get_cpu_id()) {
case BCM3368_CPU_ID:
- irq_stat_addr[0] += PERF_IRQSTAT_3368_REG;
- irq_mask_addr[0] += PERF_IRQMASK_3368_REG;
- irq_stat_addr[1] = 0;
- irq_stat_addr[1] = 0;
- irq_bits = 32;
- ext_irq_count = 4;
- ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_3368;
+ l2_intc_bases[0] += PERF_IRQMASK_3368_REG;
+ l2_irq_count = 1;
+ l2_width = 1;
+
+ ext_intc_bases[0] += PERF_EXTIRQ_CFG_REG_3368;
+ ext_irq_count = 4;
+ ext_irqs[0] = BCM_3368_EXT_IRQ0;
+ ext_irqs[1] = BCM_3368_EXT_IRQ1;
+ ext_irqs[2] = BCM_3368_EXT_IRQ2;
+ ext_irqs[3] = BCM_3368_EXT_IRQ3;
+ ext_shift = 4;
break;
case BCM6328_CPU_ID:
- irq_stat_addr[0] += PERF_IRQSTAT_6328_REG(0);
- irq_mask_addr[0] += PERF_IRQMASK_6328_REG(0);
- irq_stat_addr[1] += PERF_IRQSTAT_6328_REG(1);
- irq_stat_addr[1] += PERF_IRQMASK_6328_REG(1);
- irq_bits = 64;
- ext_irq_count = 4;
- is_ext_irq_cascaded = 1;
- ext_irq_start = BCM_6328_EXT_IRQ0 - IRQ_INTERNAL_BASE;
- ext_irq_end = BCM_6328_EXT_IRQ3 - IRQ_INTERNAL_BASE;
- ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6328;
+ l2_intc_bases[0] += PERF_IRQMASK_6328_REG(0);
+ l2_intc_bases[1] += PERF_IRQMASK_6328_REG(1);
+ l2_irq_count = 2;
+ l2_width = 2;
+
+ ext_intc_bases[0] += PERF_EXTIRQ_CFG_REG_6328;
+ ext_irq_count = 4;
+ ext_irqs[0] = BCM_6328_EXT_IRQ0;
+ ext_irqs[1] = BCM_6328_EXT_IRQ1;
+ ext_irqs[2] = BCM_6328_EXT_IRQ2;
+ ext_irqs[3] = BCM_6328_EXT_IRQ3;
+ ext_shift = 4;
break;
case BCM6338_CPU_ID:
- irq_stat_addr[0] += PERF_IRQSTAT_6338_REG;
- irq_mask_addr[0] += PERF_IRQMASK_6338_REG;
- irq_stat_addr[1] = 0;
- irq_mask_addr[1] = 0;
- irq_bits = 32;
- ext_irq_count = 4;
- ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6338;
+ l2_intc_bases[0] += PERF_IRQMASK_6338_REG;
+ l2_irq_count = 1;
+ l2_width = 1;
+
+ ext_intc_bases[0] += PERF_EXTIRQ_CFG_REG_6338;
+ ext_irq_count = 4;
+ ext_irqs[0] = 3;
+ ext_irqs[1] = 4;
+ ext_irqs[2] = 5;
+ ext_irqs[3] = 6;
+ ext_shift = 4;
break;
case BCM6345_CPU_ID:
- irq_stat_addr[0] += PERF_IRQSTAT_6345_REG;
- irq_mask_addr[0] += PERF_IRQMASK_6345_REG;
- irq_stat_addr[1] = 0;
- irq_mask_addr[1] = 0;
- irq_bits = 32;
- ext_irq_count = 4;
- ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6345;
+ l2_intc_bases[0] += PERF_IRQMASK_6345_REG;
+ l2_irq_count = 1;
+ l2_width = 1;
+
+ ext_intc_bases[0] += PERF_EXTIRQ_CFG_REG_6345;
+ ext_irq_count = 4;
+ ext_irqs[0] = 3;
+ ext_irqs[1] = 4;
+ ext_irqs[2] = 5;
+ ext_irqs[3] = 6;
+ ext_shift = 4;
break;
case BCM6348_CPU_ID:
- irq_stat_addr[0] += PERF_IRQSTAT_6348_REG;
- irq_mask_addr[0] += PERF_IRQMASK_6348_REG;
- irq_stat_addr[1] = 0;
- irq_mask_addr[1] = 0;
- irq_bits = 32;
- ext_irq_count = 4;
- ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6348;
+ l2_intc_bases[0] += PERF_IRQMASK_6348_REG;
+ l2_irq_count = 1;
+ l2_width = 1;
+
+ ext_intc_bases[0] += PERF_EXTIRQ_CFG_REG_6348;
+ ext_irq_count = 4;
+ ext_irqs[0] = 3;
+ ext_irqs[1] = 4;
+ ext_irqs[2] = 5;
+ ext_irqs[3] = 6;
+ ext_shift = 5;
break;
case BCM6358_CPU_ID:
- irq_stat_addr[0] += PERF_IRQSTAT_6358_REG(0);
- irq_mask_addr[0] += PERF_IRQMASK_6358_REG(0);
- irq_stat_addr[1] += PERF_IRQSTAT_6358_REG(1);
- irq_mask_addr[1] += PERF_IRQMASK_6358_REG(1);
- irq_bits = 32;
- ext_irq_count = 4;
- is_ext_irq_cascaded = 1;
- ext_irq_start = BCM_6358_EXT_IRQ0 - IRQ_INTERNAL_BASE;
- ext_irq_end = BCM_6358_EXT_IRQ3 - IRQ_INTERNAL_BASE;
- ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6358;
+ l2_intc_bases[0] += PERF_IRQMASK_6358_REG(0);
+ l2_intc_bases[1] += PERF_IRQMASK_6358_REG(1);
+ l2_irq_count = 2;
+ l2_width = 1;
+
+ ext_intc_bases[0] += PERF_EXTIRQ_CFG_REG_6358;
+ ext_irq_count = 4;
+ ext_irqs[0] = BCM_6358_EXT_IRQ0;
+ ext_irqs[1] = BCM_6358_EXT_IRQ1;
+ ext_irqs[2] = BCM_6358_EXT_IRQ2;
+ ext_irqs[3] = BCM_6358_EXT_IRQ3;
+ ext_shift = 4;
break;
case BCM6362_CPU_ID:
- irq_stat_addr[0] += PERF_IRQSTAT_6362_REG(0);
- irq_mask_addr[0] += PERF_IRQMASK_6362_REG(0);
- irq_stat_addr[1] += PERF_IRQSTAT_6362_REG(1);
- irq_mask_addr[1] += PERF_IRQMASK_6362_REG(1);
- irq_bits = 64;
- ext_irq_count = 4;
- is_ext_irq_cascaded = 1;
- ext_irq_start = BCM_6362_EXT_IRQ0 - IRQ_INTERNAL_BASE;
- ext_irq_end = BCM_6362_EXT_IRQ3 - IRQ_INTERNAL_BASE;
- ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6362;
+ l2_intc_bases[0] += PERF_IRQMASK_6362_REG(0);
+ l2_intc_bases[1] += PERF_IRQMASK_6362_REG(1);
+ l2_irq_count = 2;
+ l2_width = 2;
+
+ ext_intc_bases[0] += PERF_EXTIRQ_CFG_REG_6362;
+ ext_irq_count = 4;
+ ext_irqs[0] = BCM_6362_EXT_IRQ0;
+ ext_irqs[1] = BCM_6362_EXT_IRQ1;
+ ext_irqs[2] = BCM_6362_EXT_IRQ2;
+ ext_irqs[3] = BCM_6362_EXT_IRQ3;
+ ext_shift = 4;
break;
case BCM6368_CPU_ID:
- irq_stat_addr[0] += PERF_IRQSTAT_6368_REG(0);
- irq_mask_addr[0] += PERF_IRQMASK_6368_REG(0);
- irq_stat_addr[1] += PERF_IRQSTAT_6368_REG(1);
- irq_mask_addr[1] += PERF_IRQMASK_6368_REG(1);
- irq_bits = 64;
+ l2_intc_bases[0] += PERF_IRQMASK_6368_REG(0);
+ l2_intc_bases[1] += PERF_IRQMASK_6368_REG(1);
+ l2_irq_count = 2;
+ l2_width = 2;
+
+ ext_intc_bases[0] += PERF_EXTIRQ_CFG_REG_6368;
+ ext_intc_bases[1] += PERF_EXTIRQ_CFG_REG2_6368;
ext_irq_count = 6;
- is_ext_irq_cascaded = 1;
- ext_irq_start = BCM_6368_EXT_IRQ0 - IRQ_INTERNAL_BASE;
- ext_irq_end = BCM_6368_EXT_IRQ5 - IRQ_INTERNAL_BASE;
- ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6368;
- ext_irq_cfg_reg2 = PERF_EXTIRQ_CFG_REG2_6368;
+ ext_irqs[0] = BCM_6368_EXT_IRQ0;
+ ext_irqs[1] = BCM_6368_EXT_IRQ1;
+ ext_irqs[2] = BCM_6368_EXT_IRQ2;
+ ext_irqs[3] = BCM_6368_EXT_IRQ3;
+ ext_irqs[4] = BCM_6368_EXT_IRQ4;
+ ext_irqs[5] = BCM_6368_EXT_IRQ5;
+ ext_shift = 4;
break;
default:
BUG();
}
- if (irq_bits == 32) {
- dispatch_internal = __dispatch_internal_32;
- internal_irq_mask = __internal_irq_mask_32;
- internal_irq_unmask = __internal_irq_unmask_32;
- } else {
- dispatch_internal = __dispatch_internal_64;
- internal_irq_mask = __internal_irq_mask_64;
- internal_irq_unmask = __internal_irq_unmask_64;
- }
+ mips_cpu_irq_init();
+ bcm6345_l2_intc_init(l2_irq_count, l2_irqs, l2_intc_bases, l2_width);
+ bcm6345_ext_intc_init(4, ext_irqs, ext_intc_bases[0], ext_shift);
+ if (ext_irq_count > 4)
+ bcm6345_ext_intc_init(2, &ext_irqs[4], ext_intc_bases[1],
+ ext_shift);
}
void __init arch_init_irq(void)
{
- int i;
-
bcm63xx_init_irq();
- mips_cpu_irq_init();
- for (i = IRQ_INTERNAL_BASE; i < NR_IRQS; ++i)
- irq_set_chip_and_handler(i, &bcm63xx_internal_irq_chip,
- handle_level_irq);
-
- for (i = IRQ_EXTERNAL_BASE; i < IRQ_EXTERNAL_BASE + ext_irq_count; ++i)
- irq_set_chip_and_handler(i, &bcm63xx_external_irq_chip,
- handle_edge_irq);
-
- if (!is_ext_irq_cascaded) {
- for (i = 3; i < 3 + ext_irq_count; ++i)
- setup_irq(MIPS_CPU_IRQ_BASE + i, &cpu_ext_cascade_action);
- }
-
- setup_irq(MIPS_CPU_IRQ_BASE + 2, &cpu_ip2_cascade_action);
-#ifdef CONFIG_SMP
- if (is_ext_irq_cascaded) {
- setup_irq(MIPS_CPU_IRQ_BASE + 3, &cpu_ip3_cascade_action);
- bcm63xx_internal_irq_chip.irq_set_affinity =
- bcm63xx_internal_set_affinity;
-
- cpumask_clear(irq_default_affinity);
- cpumask_set_cpu(smp_processor_id(), irq_default_affinity);
- }
-#endif
}

View File

@ -0,0 +1,57 @@
From e3c68bbba30b212326fb69bf64b2220750dead3e Mon Sep 17 00:00:00 2001
From: Jonas Gorski <jogo@openwrt.org>
Date: Sun, 30 Nov 2014 20:20:30 +0100
Subject: [PATCH 20/20] MIPS: BCM63XX: wire up BCM6358's external interrupts 4
and 5
Due to the external interrupts being non consecutive, the previous
implementation did not support them. Now that we treat both registers
as separate irq controllers, there is no such limitation anymore and
we can expose them for drivers to use.
Signed-off-by: Jonas Gorski <jogo@openwrt.org>
---
arch/mips/bcm63xx/irq.c | 5 ++++-
arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h | 2 ++
arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h | 1 +
3 files changed, 7 insertions(+), 1 deletion(-)
--- a/arch/mips/bcm63xx/irq.c
+++ b/arch/mips/bcm63xx/irq.c
@@ -109,11 +109,14 @@ static void bcm63xx_init_irq(void)
l2_width = 1;
ext_intc_bases[0] += PERF_EXTIRQ_CFG_REG_6358;
- ext_irq_count = 4;
+ ext_intc_bases[1] += PERF_EXTIRQ_CFG_REG2_6358;
+ ext_irq_count = 6;
ext_irqs[0] = BCM_6358_EXT_IRQ0;
ext_irqs[1] = BCM_6358_EXT_IRQ1;
ext_irqs[2] = BCM_6358_EXT_IRQ2;
ext_irqs[3] = BCM_6358_EXT_IRQ3;
+ ext_irqs[4] = BCM_6358_EXT_IRQ4;
+ ext_irqs[5] = BCM_6358_EXT_IRQ5;
ext_shift = 4;
break;
case BCM6362_CPU_ID:
--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
@@ -940,6 +940,8 @@ enum bcm63xx_irq {
#define BCM_6358_EXT_IRQ1 (IRQ_INTERNAL_BASE + 26)
#define BCM_6358_EXT_IRQ2 (IRQ_INTERNAL_BASE + 27)
#define BCM_6358_EXT_IRQ3 (IRQ_INTERNAL_BASE + 28)
+#define BCM_6358_EXT_IRQ4 (IRQ_INTERNAL_BASE + 20)
+#define BCM_6358_EXT_IRQ5 (IRQ_INTERNAL_BASE + 21)
/*
* 6362 irqs
--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
@@ -243,6 +243,7 @@
#define PERF_EXTIRQ_CFG_REG_6362 0x18
#define PERF_EXTIRQ_CFG_REG_6368 0x18
+#define PERF_EXTIRQ_CFG_REG2_6358 0x1c
#define PERF_EXTIRQ_CFG_REG2_6368 0x1c
/* for 6348 only */

View File

@ -284,57 +284,27 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
spi_pdata.msg_type_shift = SPI_6358_MSG_TYPE_SHIFT;
--- a/arch/mips/bcm63xx/irq.c
+++ b/arch/mips/bcm63xx/irq.c
@@ -158,6 +158,7 @@ static void __internal_irq_unmask_##widt
BUILD_IPIC_INTERNAL(32);
BUILD_IPIC_INTERNAL(64);
+BUILD_IPIC_INTERNAL(128);
asmlinkage void plat_irq_dispatch(void)
{
@@ -343,6 +344,7 @@ static int bcm63xx_external_irq_set_type
case BCM6358_CPU_ID:
case BCM6362_CPU_ID:
case BCM6368_CPU_ID:
+ case BCM63268_CPU_ID:
if (levelsense)
reg |= EXTIRQ_CFG_LEVELSENSE(irq);
else
@@ -515,6 +517,18 @@ static void bcm63xx_init_irq(void)
ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6368;
ext_irq_cfg_reg2 = PERF_EXTIRQ_CFG_REG2_6368;
@@ -150,6 +150,20 @@ static void bcm63xx_init_irq(void)
ext_irqs[5] = BCM_6368_EXT_IRQ5;
ext_shift = 4;
break;
+ case BCM63268_CPU_ID:
+ irq_stat_addr[0] += PERF_IRQSTAT_63268_REG(0);
+ irq_mask_addr[0] += PERF_IRQMASK_63268_REG(0);
+ irq_stat_addr[1] += PERF_IRQSTAT_63268_REG(1);
+ irq_mask_addr[1] += PERF_IRQMASK_63268_REG(1);
+ irq_bits = 128;
+ l2_intc_bases[0] += PERF_IRQSTAT_63268_REG(0);
+ l2_intc_bases[1] += PERF_IRQSTAT_63268_REG(1);
+ l2_irq_count = 2;
+ l2_width = 4;
+
+ ext_intc_bases[0] += PERF_EXTIRQ_CFG_REG_63268;
+ ext_irq_count = 4;
+ is_ext_irq_cascaded = 1;
+ ext_irq_start = BCM_63268_EXT_IRQ0 - IRQ_INTERNAL_BASE;
+ ext_irq_end = BCM_63268_EXT_IRQ3 - IRQ_INTERNAL_BASE;
+ ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_63268;
+ ext_irqs[0] = BCM_63268_EXT_IRQ0;
+ ext_irqs[1] = BCM_63268_EXT_IRQ1;
+ ext_irqs[2] = BCM_63268_EXT_IRQ2;
+ ext_irqs[3] = BCM_63268_EXT_IRQ3;
+ ext_shift = 4;
+ break;
default:
BUG();
}
@@ -523,10 +537,14 @@ static void bcm63xx_init_irq(void)
dispatch_internal = __dispatch_internal_32;
internal_irq_mask = __internal_irq_mask_32;
internal_irq_unmask = __internal_irq_unmask_32;
- } else {
+ } else if (irq_bits == 64) {
dispatch_internal = __dispatch_internal_64;
internal_irq_mask = __internal_irq_mask_64;
internal_irq_unmask = __internal_irq_unmask_64;
+ } else {
+ dispatch_internal = __dispatch_internal_128;
+ internal_irq_mask = __internal_irq_mask_128;
+ internal_irq_unmask = __internal_irq_unmask_128;
}
}
--- a/arch/mips/bcm63xx/reset.c
+++ b/arch/mips/bcm63xx/reset.c
@@ -125,6 +125,20 @@
@ -479,7 +449,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
extern const unsigned long *bcm63xx_regs_base;
@@ -1084,6 +1147,73 @@ enum bcm63xx_irq {
@@ -1086,6 +1149,73 @@ enum bcm63xx_irq {
#define BCM_6368_EXT_IRQ4 (IRQ_INTERNAL_BASE + 24)
#define BCM_6368_EXT_IRQ5 (IRQ_INTERNAL_BASE + 25)
@ -650,9 +620,9 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
#define PERF_EXTIRQ_CFG_REG_6368 0x18
+#define PERF_EXTIRQ_CFG_REG_63268 0x18
#define PERF_EXTIRQ_CFG_REG2_6358 0x1c
#define PERF_EXTIRQ_CFG_REG2_6368 0x1c
@@ -273,6 +324,7 @@
@@ -274,6 +325,7 @@
#define PERF_SOFTRESET_6358_REG 0x34
#define PERF_SOFTRESET_6362_REG 0x10
#define PERF_SOFTRESET_6368_REG 0x10
@ -660,7 +630,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
#define SOFTRESET_3368_SPI_MASK (1 << 0)
#define SOFTRESET_3368_ENET_MASK (1 << 2)
@@ -366,6 +418,26 @@
@@ -367,6 +419,26 @@
#define SOFTRESET_6368_USBH_MASK (1 << 12)
#define SOFTRESET_6368_PCM_MASK (1 << 13)
@ -687,7 +657,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
/* MIPS PLL control register */
#define PERF_MIPSPLLCTL_REG 0x34
#define MIPSPLLCTL_N1_SHIFT 20
@@ -1379,6 +1451,13 @@
@@ -1380,6 +1452,13 @@
#define STRAPBUS_6362_BOOT_SEL_SERIAL (1 << 15)
#define STRAPBUS_6362_BOOT_SEL_NAND (0 << 15)

View File

@ -194,23 +194,26 @@ Subject: [PATCH 51/53] MIPS: BCM63XX: add support for BCM6318
spi_resources[0].start = bcm63xx_regset_address(RSET_SPI);
--- a/arch/mips/bcm63xx/irq.c
+++ b/arch/mips/bcm63xx/irq.c
@@ -441,6 +441,16 @@ static void bcm63xx_init_irq(void)
ext_irq_count = 4;
ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_3368;
@@ -49,6 +49,19 @@ static void bcm63xx_init_irq(void)
ext_irqs[3] = BCM_3368_EXT_IRQ3;
ext_shift = 4;
break;
+ case BCM6318_CPU_ID:
+ irq_stat_addr[0] += PERF_IRQSTAT_6318_REG;
+ irq_mask_addr[0] += PERF_IRQMASK_6318_REG;
+ irq_bits = 128;
+ l2_intc_bases[0] += PERF_IRQMASK_6318_REG;
+ l2_irq_count = 1;
+ l2_width = 4;
+
+ ext_intc_bases[0] += PERF_EXTIRQ_CFG_REG_6318;
+ ext_irq_count = 4;
+ is_ext_irq_cascaded = 1;
+ ext_irq_start = BCM_6318_EXT_IRQ0 - IRQ_INTERNAL_BASE;
+ ext_irq_end = BCM_6318_EXT_IRQ3 - IRQ_INTERNAL_BASE;
+ ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6318;
+ ext_irqs[0] = BCM_6318_EXT_IRQ0;
+ ext_irqs[1] = BCM_6318_EXT_IRQ0;
+ ext_irqs[2] = BCM_6318_EXT_IRQ0;
+ ext_irqs[3] = BCM_6318_EXT_IRQ0;
+ ext_shift = 4;
+ break;
case BCM6328_CPU_ID:
irq_stat_addr[0] += PERF_IRQSTAT_6328_REG(0);
irq_mask_addr[0] += PERF_IRQMASK_6328_REG(0);
l2_intc_bases[0] += PERF_IRQMASK_6328_REG(0);
l2_intc_bases[1] += PERF_IRQMASK_6328_REG(1);
--- a/arch/mips/bcm63xx/prom.c
+++ b/arch/mips/bcm63xx/prom.c
@@ -72,7 +72,7 @@ void __init prom_init(void)
@ -527,7 +530,7 @@ Subject: [PATCH 51/53] MIPS: BCM63XX: add support for BCM6318
#define PERF_EXTIRQ_CFG_REG_6328 0x18
#define PERF_EXTIRQ_CFG_REG_6338 0x14
#define PERF_EXTIRQ_CFG_REG_6345 0x14
@@ -320,6 +370,7 @@
@@ -321,6 +371,7 @@
/* Soft Reset register */
#define PERF_SOFTRESET_REG 0x28
@ -535,7 +538,7 @@ Subject: [PATCH 51/53] MIPS: BCM63XX: add support for BCM6318
#define PERF_SOFTRESET_6328_REG 0x10
#define PERF_SOFTRESET_6358_REG 0x34
#define PERF_SOFTRESET_6362_REG 0x10
@@ -333,6 +384,18 @@
@@ -334,6 +385,18 @@
#define SOFTRESET_3368_USBS_MASK (1 << 11)
#define SOFTRESET_3368_PCM_MASK (1 << 13)
@ -554,7 +557,7 @@ Subject: [PATCH 51/53] MIPS: BCM63XX: add support for BCM6318
#define SOFTRESET_6328_SPI_MASK (1 << 0)
#define SOFTRESET_6328_EPHY_MASK (1 << 1)
#define SOFTRESET_6328_SAR_MASK (1 << 2)
@@ -504,8 +567,17 @@
@@ -505,8 +568,17 @@
#define TIMER_IRQSTAT_TIMER1_IR_EN (1 << 9)
#define TIMER_IRQSTAT_TIMER2_IR_EN (1 << 10)
@ -572,7 +575,7 @@ Subject: [PATCH 51/53] MIPS: BCM63XX: add support for BCM6318
#define TIMER_CTL0_REG 0x4
#define TIMER_CTL1_REG 0x8
#define TIMER_CTL2_REG 0xC
@@ -1252,6 +1324,8 @@
@@ -1253,6 +1325,8 @@
#define SDRAM_CFG_32B_MASK (1 << SDRAM_CFG_32B_SHIFT)
#define SDRAM_CFG_BANK_SHIFT 13
#define SDRAM_CFG_BANK_MASK (1 << SDRAM_CFG_BANK_SHIFT)

View File

@ -79,7 +79,7 @@ Subject: [PATCH 53/53] MIPS: BCM63XX: add PCIe support for BCM6318
#define BCM_PCIE_MEM_END_PA_6328 (BCM_PCIE_MEM_BASE_PA_6328 + \
--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
@@ -1542,6 +1542,17 @@
@@ -1543,6 +1543,17 @@
* _REG relative to RSET_PCIE
*************************************************************************/
@ -97,7 +97,7 @@ Subject: [PATCH 53/53] MIPS: BCM63XX: add PCIe support for BCM6318
#define PCIE_CONFIG2_REG 0x408
#define CONFIG2_BAR1_SIZE_EN 1
#define CONFIG2_BAR1_SIZE_MASK 0xf
@@ -1587,7 +1598,54 @@
@@ -1588,7 +1599,54 @@
#define PCIE_RC_INT_C (1 << 2)
#define PCIE_RC_INT_D (1 << 3)

View File

@ -58,7 +58,7 @@
spin_unlock_irqrestore(&usb_priv_reg_lock, flags);
--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
@@ -680,6 +680,12 @@
@@ -681,6 +681,12 @@
#define GPIO_MODE_6368_SPI_SSN4 (1 << 30)
#define GPIO_MODE_6368_SPI_SSN5 (1 << 31)
@ -71,7 +71,7 @@
#define GPIO_PINMUX_OTHR_REG 0x24
#define GPIO_PINMUX_OTHR_6328_USB_SHIFT 12
@@ -998,6 +1004,7 @@
@@ -999,6 +1005,7 @@
#define USBH_PRIV_SWAP_6358_REG 0x0
#define USBH_PRIV_SWAP_6368_REG 0x1c
@ -79,7 +79,7 @@
#define USBH_PRIV_SWAP_USBD_SHIFT 6
#define USBH_PRIV_SWAP_USBD_MASK (1 << USBH_PRIV_SWAP_USBD_SHIFT)
@@ -1023,6 +1030,13 @@
@@ -1024,6 +1031,13 @@
#define USBH_PRIV_SETUP_IOC_SHIFT 4
#define USBH_PRIV_SETUP_IOC_MASK (1 << USBH_PRIV_SETUP_IOC_SHIFT)

View File

@ -1,6 +1,6 @@
--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
@@ -585,6 +585,9 @@
@@ -586,6 +586,9 @@
#define TIMER_CTL_MONOTONIC_MASK (1 << 30)
#define TIMER_CTL_ENABLE_MASK (1 << 31)
@ -10,7 +10,7 @@
/*************************************************************************
* _REG relative to RSET_WDT
@@ -1546,6 +1549,11 @@
@@ -1547,6 +1550,11 @@
#define STRAPBUS_63268_FCVO_SHIFT 21
#define STRAPBUS_63268_FCVO_MASK (0xf << STRAPBUS_63268_FCVO_SHIFT)

View File

@ -1,6 +1,6 @@
--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
@@ -1032,11 +1032,18 @@
@@ -1033,11 +1033,18 @@
#define USBH_PRIV_SETUP_6368_REG 0x28
#define USBH_PRIV_SETUP_IOC_SHIFT 4
#define USBH_PRIV_SETUP_IOC_MASK (1 << USBH_PRIV_SETUP_IOC_SHIFT)

View File

@ -43,7 +43,7 @@ Completely untested on anything except MIPS32 / big endian.
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -2519,6 +2519,24 @@ config RAPIDIO
@@ -2523,6 +2523,24 @@ config RAPIDIO
source "drivers/rapidio/Kconfig"

View File

@ -11,7 +11,7 @@
bcm_gpio_writel(val, GPIO_MODE_REG);
--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
@@ -650,6 +650,8 @@
@@ -651,6 +651,8 @@
#define GPIO_MODE_6358_EXTRA_SPI_SS (1 << 7)
#define GPIO_MODE_6358_SERIAL_LED (1 << 10)
#define GPIO_MODE_6358_UTOPIA (1 << 12)

View File

@ -10,7 +10,7 @@ Subject: [PATCH 54/81] bcm63xx_enet: enable rgmii clock on external ports
--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
@@ -966,6 +966,19 @@
@@ -967,6 +967,19 @@
#define ENETSW_PORTOV_FDX_MASK (1 << 1)
#define ENETSW_PORTOV_LINKUP_MASK (1 << 0)

View File

@ -115,7 +115,7 @@ Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com>
return -ENODEV;
--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
@@ -707,6 +707,7 @@
@@ -708,6 +708,7 @@
#define GPIO_STRAPBUS_REG 0x40
#define STRAPBUS_6358_BOOT_SEL_PARALLEL (1 << 1)
#define STRAPBUS_6358_BOOT_SEL_SERIAL (0 << 1)
@ -123,7 +123,7 @@ Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com>
#define STRAPBUS_6368_BOOT_SEL_MASK 0x3
#define STRAPBUS_6368_BOOT_SEL_NAND 0
#define STRAPBUS_6368_BOOT_SEL_SERIAL 1
@@ -1577,6 +1578,7 @@
@@ -1578,6 +1579,7 @@
#define IDDQ_CTRL_63268_USBH (1 << 4)
#define MISC_STRAPBUS_6328_REG 0x240