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
This commit is contained in:
parent
bb312899f6
commit
ef4f69adc0
19 changed files with 1842 additions and 78 deletions
|
@ -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 */
|
|
@ -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 },
|
||||
{},
|
||||
};
|
|
@ -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)
|
||||
{
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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
|
||||
}
|
|
@ -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 */
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue