This patch set introduces DT-aware irqchip and clocksource drivers for
Marvell Orion SoCs (Kirkwood, Dove, Orion5x, MV78x00) and corresponding
patches for Dove and Kirkwood to enable them for DT-boards.
The irqchip driver, of course, depends on Thomas Gleixner's work on
irqdomain support for generic chip (tip irq/core).
The ARM part of this patch set has a quite ridiculuous dependency havoc
of mv643xx_eth DT support (current net-next) that will add to both irqchip
and clocksource branches respectively. Therefore, I suggest that irq
and clocksource maintainers take in the mere drivers (Patches 1+2) and
Jason Cooper handles the remaining patches when all three drivers have
surfaced on mainline linux.
I prepared a branch for anyone to test on Kirkwood and Dove which takes
care of the above dependencies based on v3.10-rc4 plus tip irq/core,
net-next, and arm-soc for-next (I know it is unstable but contains latest
mvebu related patches already). When Thomas, John, and Jason agree the
dependencies will vanish and only Jason has to take care of ARM patches
for enabling DT-based mv643xx_eth, irqchip, and clocksource.
The branch can be found at
git://github.com/shesselba/linux-dove.git orion-irqchip-for-v3.11
and has been tested on Dove/CuBox and compile tested for Kirkwood.
Sebastian Hesselbarth (6):
irqchip: add support for Marvell Orion SoCs
clocksource: add Marvell Orion SoC timer
ARM: dove: move device tree nodes to DT irqchip and clocksource
ARM: kirkwood: move device tree nodes to DT irqchip and clocksource
ARM: dove: convert to DT irqchip and clocksource
ARM: kirkwood: convert to DT irqchip and clocksource
.../interrupt-controller/marvell,orion-intc.txt | 48 +++++
.../bindings/timer/marvell,orion-timer.txt | 17 ++
arch/arm/boot/dts/dove.dtsi | 21 ++-
arch/arm/boot/dts/kirkwood.dtsi | 35 +++-
arch/arm/mach-dove/Kconfig | 2 +
arch/arm/mach-dove/Makefile | 4 +-
arch/arm/mach-dove/board-dt.c | 23 ++-
arch/arm/mach-kirkwood/Kconfig | 24 +++
arch/arm/mach-kirkwood/Makefile | 4 +-
arch/arm/mach-kirkwood/board-dt.c | 28 ++-
drivers/clocksource/Kconfig | 5 +
drivers/clocksource/Makefile | 1 +
drivers/clocksource/time-orion.c | 143 +++++++++++++++
drivers/irqchip/Kconfig | 5 +
drivers/irqchip/Makefile | 1 +
drivers/irqchip/irq-orion.c | 193 ++++++++++++++++++++
16 files changed, 522 insertions(+), 32 deletions(-)
create mode 100644 Documentation/devicetree/bindings/interrupt-controller/marvell,orion-intc.txt
create mode 100644 Documentation/devicetree/bindings/timer/marvell,orion-timer.txt
create mode 100644 drivers/clocksource/time-orion.c
create mode 100644 drivers/irqchip/irq-orion.c
---
Cc: Grant Likely <[email protected]>
Cc: Rob Herring <[email protected]>
Cc: Rob Landley <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: John Stultz <[email protected]>
Cc: Russell King <[email protected]>
Cc: Jason Cooper <[email protected]>
Cc: Andrew Lunn <[email protected]>
Cc: Thomas Petazzoni <[email protected]>
Cc: Gregory Clement <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
--
1.7.2.5
With recent support for true irqchip and clocksource drivers for Orion
SoCs, now make use of it on DT enabled Dove boards.
Signed-off-by: Sebastian Hesselbarth <[email protected]>
---
Cc: Grant Likely <[email protected]>
Cc: Rob Herring <[email protected]>
Cc: Rob Landley <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: John Stultz <[email protected]>
Cc: Russell King <[email protected]>
Cc: Jason Cooper <[email protected]>
Cc: Andrew Lunn <[email protected]>
Cc: Thomas Petazzoni <[email protected]>
Cc: Gregory Clement <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
---
arch/arm/boot/dts/dove.dtsi | 21 +++++++++++++++++++--
1 files changed, 19 insertions(+), 2 deletions(-)
diff --git a/arch/arm/boot/dts/dove.dtsi b/arch/arm/boot/dts/dove.dtsi
index 8612658..8d5be1e8 100644
--- a/arch/arm/boot/dts/dove.dtsi
+++ b/arch/arm/boot/dts/dove.dtsi
@@ -30,11 +30,28 @@
marvell,tauros2-cache-features = <0>;
};
- intc: interrupt-controller {
+ timer: timer@20300 {
+ compatible = "marvell,orion-timer";
+ reg = <0x20300 0x20>;
+ interrupt-parent = <&bridge_intc>;
+ interrupts = <1>, <2>;
+ clocks = <&core_clk 0>;
+ };
+
+ intc: main-interrupt-ctrl@20200 {
compatible = "marvell,orion-intc";
interrupt-controller;
#interrupt-cells = <1>;
- reg = <0x20204 0x04>, <0x20214 0x04>;
+ reg = <0x20200 0x10>, <0x20210 0x10>;
+ };
+
+ bridge_intc: bridge-interrupt-ctrl@20110 {
+ compatible = "marvell,orion-bridge-intc";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0x20110 0x8>;
+ interrupts = <0>;
+ marvell,#interrupts = <5>;
};
core_clk: core-clocks@d0214 {
--
1.7.2.5
With recent support for true irqchip and clocksource drivers for Orion
SoCs, now make use of it on DT enabled Kirkwood boards.
This also introduces a new Kconfig option for legacy (non-DT) Kirkwood
where old code is moved out to and polishes DT board file a little bit.
Signed-off-by: Sebastian Hesselbarth <[email protected]>
---
Cc: Grant Likely <[email protected]>
Cc: Rob Herring <[email protected]>
Cc: Rob Landley <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: John Stultz <[email protected]>
Cc: Russell King <[email protected]>
Cc: Jason Cooper <[email protected]>
Cc: Andrew Lunn <[email protected]>
Cc: Thomas Petazzoni <[email protected]>
Cc: Gregory Clement <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
---
arch/arm/mach-kirkwood/Kconfig | 24 ++++++++++++++++++++++++
arch/arm/mach-kirkwood/Makefile | 4 ++--
arch/arm/mach-kirkwood/board-dt.c | 28 +++++++++++++++++-----------
3 files changed, 43 insertions(+), 13 deletions(-)
diff --git a/arch/arm/mach-kirkwood/Kconfig b/arch/arm/mach-kirkwood/Kconfig
index 2c95623..f14914f 100644
--- a/arch/arm/mach-kirkwood/Kconfig
+++ b/arch/arm/mach-kirkwood/Kconfig
@@ -2,62 +2,75 @@ if ARCH_KIRKWOOD
menu "Marvell Kirkwood Implementations"
+config KIRKWOOD_LEGACY
+ bool
+
config MACH_D2NET_V2
bool "LaCie d2 Network v2 NAS Board"
+ select KIRKWOOD_LEGACY
help
Say 'Y' here if you want your kernel to support the
LaCie d2 Network v2 NAS.
config MACH_DOCKSTAR
bool "Seagate FreeAgent DockStar"
+ select KIRKWOOD_LEGACY
help
Say 'Y' here if you want your kernel to support the
Seagate FreeAgent DockStar.
config MACH_ESATA_SHEEVAPLUG
bool "Marvell eSATA SheevaPlug Reference Board"
+ select KIRKWOOD_LEGACY
help
Say 'Y' here if you want your kernel to support the
Marvell eSATA SheevaPlug Reference Board.
config MACH_GURUPLUG
bool "Marvell GuruPlug Reference Board"
+ select KIRKWOOD_LEGACY
help
Say 'Y' here if you want your kernel to support the
Marvell GuruPlug Reference Board.
config MACH_INETSPACE_V2
bool "LaCie Internet Space v2 NAS Board"
+ select KIRKWOOD_LEGACY
help
Say 'Y' here if you want your kernel to support the
LaCie Internet Space v2 NAS.
config MACH_MV88F6281GTW_GE
bool "Marvell 88F6281 GTW GE Board"
+ select KIRKWOOD_LEGACY
help
Say 'Y' here if you want your kernel to support the
Marvell 88F6281 GTW GE Board.
config MACH_NET2BIG_V2
bool "LaCie 2Big Network v2 NAS Board"
+ select KIRKWOOD_LEGACY
help
Say 'Y' here if you want your kernel to support the
LaCie 2Big Network v2 NAS.
config MACH_NET5BIG_V2
bool "LaCie 5Big Network v2 NAS Board"
+ select KIRKWOOD_LEGACY
help
Say 'Y' here if you want your kernel to support the
LaCie 5Big Network v2 NAS.
config MACH_NETSPACE_MAX_V2
bool "LaCie Network Space Max v2 NAS Board"
+ select KIRKWOOD_LEGACY
help
Say 'Y' here if you want your kernel to support the
LaCie Network Space Max v2 NAS.
config MACH_NETSPACE_V2
bool "LaCie Network Space v2 NAS Board"
+ select KIRKWOOD_LEGACY
help
Say 'Y' here if you want your kernel to support the
LaCie Network Space v2 NAS.
@@ -67,6 +80,7 @@ config MACH_OPENRD
config MACH_OPENRD_BASE
bool "Marvell OpenRD Base Board"
+ select KIRKWOOD_LEGACY
select MACH_OPENRD
help
Say 'Y' here if you want your kernel to support the
@@ -74,6 +88,7 @@ config MACH_OPENRD_BASE
config MACH_OPENRD_CLIENT
bool "Marvell OpenRD Client Board"
+ select KIRKWOOD_LEGACY
select MACH_OPENRD
help
Say 'Y' here if you want your kernel to support the
@@ -81,6 +96,7 @@ config MACH_OPENRD_CLIENT
config MACH_OPENRD_ULTIMATE
bool "Marvell OpenRD Ultimate Board"
+ select KIRKWOOD_LEGACY
select MACH_OPENRD
help
Say 'Y' here if you want your kernel to support the
@@ -88,30 +104,35 @@ config MACH_OPENRD_ULTIMATE
config MACH_RD88F6192_NAS
bool "Marvell RD-88F6192-NAS Reference Board"
+ select KIRKWOOD_LEGACY
help
Say 'Y' here if you want your kernel to support the
Marvell RD-88F6192-NAS Reference Board.
config MACH_RD88F6281
bool "Marvell RD-88F6281 Reference Board"
+ select KIRKWOOD_LEGACY
help
Say 'Y' here if you want your kernel to support the
Marvell RD-88F6281 Reference Board.
config MACH_SHEEVAPLUG
bool "Marvell SheevaPlug Reference Board"
+ select KIRKWOOD_LEGACY
help
Say 'Y' here if you want your kernel to support the
Marvell SheevaPlug Reference Board.
config MACH_T5325
bool "HP t5325 Thin Client"
+ select KIRKWOOD_LEGACY
help
Say 'Y' here if you want your kernel to support the
HP t5325 Thin Client.
config MACH_TS219
bool "QNAP TS-110, TS-119, TS-119P+, TS-210, TS-219, TS-219P and TS-219P+ Turbo NAS"
+ select KIRKWOOD_LEGACY
help
Say 'Y' here if you want your kernel to support the
QNAP TS-110, TS-119, TS-119P+, TS-210, TS-219, TS-219P and
@@ -119,6 +140,7 @@ config MACH_TS219
config MACH_TS41X
bool "QNAP TS-410, TS-410U, TS-419P, TS-419P+ and TS-419U Turbo NAS"
+ select KIRKWOOD_LEGACY
help
Say 'Y' here if you want your kernel to support the
QNAP TS-410, TS-410U, TS-419P, TS-419P+ and TS-419U Turbo
@@ -129,6 +151,8 @@ comment "Device tree entries"
config ARCH_KIRKWOOD_DT
bool "Marvell Kirkwood Flattened Device Tree"
select KIRKWOOD_CLK
+ select ORION_IRQCHIP
+ select ORION_TIMER
select POWER_SUPPLY
select POWER_RESET
select POWER_RESET_GPIO
diff --git a/arch/arm/mach-kirkwood/Makefile b/arch/arm/mach-kirkwood/Makefile
index 53caf14..91be973 100644
--- a/arch/arm/mach-kirkwood/Makefile
+++ b/arch/arm/mach-kirkwood/Makefile
@@ -1,5 +1,5 @@
-obj-y += common.o irq.o pcie.o mpp.o
-
+obj-y += common.o pcie.o
+obj-$(CONFIG_KIRKWOOD_LEGACY) += irq.o mpp.o
obj-$(CONFIG_MACH_D2NET_V2) += d2net_v2-setup.o lacie_v2-common.o
obj-$(CONFIG_MACH_DOCKSTAR) += dockstar-setup.o
obj-$(CONFIG_MACH_ESATA_SHEEVAPLUG) += sheevaplug-setup.o
diff --git a/arch/arm/mach-kirkwood/board-dt.c b/arch/arm/mach-kirkwood/board-dt.c
index 1e4eac3..cec736b 100644
--- a/arch/arm/mach-kirkwood/board-dt.c
+++ b/arch/arm/mach-kirkwood/board-dt.c
@@ -15,6 +15,9 @@
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/clk-provider.h>
+#include <linux/clocksource.h>
+#include <linux/dma-mapping.h>
+#include <linux/irqchip.h>
#include <linux/kexec.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
@@ -49,10 +52,6 @@ static void __init kirkwood_legacy_clk_init(void)
orion_clkdev_add("1", "pcie",
of_clk_get_from_provider(&clkspec));
- clkspec.args[0] = CGC_BIT_SDIO;
- orion_clkdev_add(NULL, "mvsdio",
- of_clk_get_from_provider(&clkspec));
-
/*
* The ethernet interfaces forget the MAC address assigned by
* u-boot if the clocks are turned off. Until proper DT support
@@ -67,10 +66,18 @@ static void __init kirkwood_legacy_clk_init(void)
clk_prepare_enable(clk);
}
-static void __init kirkwood_of_clk_init(void)
+static void __init kirkwood_dt_time_init(void)
{
of_clk_init(NULL);
- kirkwood_legacy_clk_init();
+ clocksource_of_init();
+}
+
+static void __init kirkwood_dt_init_early(void)
+{
+ init_dma_coherent_pool_size(SZ_1M);
+ mvebu_mbus_init("marvell,kirkwood-mbus",
+ BRIDGE_WINS_BASE, BRIDGE_WINS_SZ,
+ DDR_WINDOW_CPU_BASE, DDR_WINDOW_CPU_SZ);
}
static void __init kirkwood_dt_init(void)
@@ -91,8 +98,8 @@ static void __init kirkwood_dt_init(void)
kirkwood_cpufreq_init();
- /* Setup root of clk tree */
- kirkwood_of_clk_init();
+ /* setup clocks for legacy devices */
+ kirkwood_legacy_clk_init();
kirkwood_cpuidle_init();
@@ -117,9 +124,8 @@ static const char * const kirkwood_dt_board_compat[] = {
DT_MACHINE_START(KIRKWOOD_DT, "Marvell Kirkwood (Flattened Device Tree)")
/* Maintainer: Jason Cooper <[email protected]> */
.map_io = kirkwood_map_io,
- .init_early = kirkwood_init_early,
- .init_irq = orion_dt_init_irq,
- .init_time = kirkwood_timer_init,
+ .init_early = kirkwood_dt_init_early,
+ .init_time = kirkwood_dt_time_init,
.init_machine = kirkwood_dt_init,
.restart = kirkwood_restart,
.dt_compat = kirkwood_dt_board_compat,
--
1.7.2.5
This patch adds an irqchip driver for the main interrupt controller found
on Marvell Orion SoCs (Kirkwood, Dove, Orion5x, Discovery Innovation).
Corresponding device tree documentation is also added.
Signed-off-by: Sebastian Hesselbarth <[email protected]>
---
Cc: Grant Likely <[email protected]>
Cc: Rob Herring <[email protected]>
Cc: Rob Landley <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: John Stultz <[email protected]>
Cc: Russell King <[email protected]>
Cc: Jason Cooper <[email protected]>
Cc: Andrew Lunn <[email protected]>
Cc: Thomas Petazzoni <[email protected]>
Cc: Gregory Clement <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
---
.../interrupt-controller/marvell,orion-intc.txt | 48 +++++
drivers/irqchip/Kconfig | 5 +
drivers/irqchip/Makefile | 1 +
drivers/irqchip/irq-orion.c | 193 ++++++++++++++++++++
4 files changed, 247 insertions(+), 0 deletions(-)
create mode 100644 Documentation/devicetree/bindings/interrupt-controller/marvell,orion-intc.txt
create mode 100644 drivers/irqchip/irq-orion.c
diff --git a/Documentation/devicetree/bindings/interrupt-controller/marvell,orion-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/marvell,orion-intc.txt
new file mode 100644
index 0000000..2c11ac7
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/marvell,orion-intc.txt
@@ -0,0 +1,48 @@
+Marvell Orion SoC interrupt controllers
+
+* Main interrupt controller
+
+Required properties:
+- compatible: shall be "marvell,orion-intc"
+- reg: base address(es) of interrupt registers starting with CAUSE register
+- interrupt-controller: identifies the node as an interrupt controller
+- #interrupt-cells: number of cells to encode an interrupt source, shall be 1
+
+The interrupt sources map to the corresponding bits in the interrupt
+registers, i.e.
+- 0 maps to bit 0 of first base address,
+- 1 maps to bit 1 of first base address,
+- 32 maps to bit 0 of second base address, and so on.
+
+Example:
+ intc: interrupt-controller {
+ compatible = "marvell,orion-intc";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ /* Dove has 64 first level interrupts */
+ reg = <0x20200 0x10>, <0x20210 0x10>;
+ };
+
+* Bridge interrupt controller
+
+Required properties:
+- compatible: shall be "marvell,orion-bridge-intc"
+- reg: base address of bridge interrupt registers starting with CAUSE register
+- interrupts: bridge interrupt of the main interrupt controller
+- interrupt-controller: identifies the node as an interrupt controller
+- #interrupt-cells: number of cells to encode an interrupt source, shall be 1
+
+Optional properties:
+- marvell,#interrupts: number of interrupts provided by bridge interrupt
+ controller, defaults to 32 if not set
+
+Example:
+ bridge_intc: interrupt-controller {
+ compatible = "marvell,orion-bridge-intc";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0x20110 0x8>;
+ interrupts = <0>;
+ /* Dove bridge provides 5 interrupts */
+ marvell,#interrupts = <5>;
+ };
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 4a33351..68c3107 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -25,6 +25,11 @@ config ARM_VIC_NR
The maximum number of VICs available in the system, for
power management.
+config ORION_IRQCHIP
+ bool
+ select IRQ_DOMAIN
+ select MULTI_IRQ_HANDLER
+
config RENESAS_INTC_IRQPIN
bool
select IRQ_DOMAIN
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index cda4cb5..55df3bd 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_ARCH_MXS) += irq-mxs.o
obj-$(CONFIG_ARCH_S3C24XX) += irq-s3c24xx.o
obj-$(CONFIG_METAG) += irq-metag-ext.o
obj-$(CONFIG_METAG_PERFCOUNTER_IRQS) += irq-metag.o
+obj-$(CONFIG_ORION_IRQCHIP) += irq-orion.o
obj-$(CONFIG_ARCH_SUNXI) += irq-sun4i.o
obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o
obj-$(CONFIG_ARM_GIC) += irq-gic.o
diff --git a/drivers/irqchip/irq-orion.c b/drivers/irqchip/irq-orion.c
new file mode 100644
index 0000000..693ea20
--- /dev/null
+++ b/drivers/irqchip/irq-orion.c
@@ -0,0 +1,193 @@
+/*
+ * Marvell Orion SoCs IRQ chip driver.
+ *
+ * Sebastian Hesselbarth <[email protected]>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <asm/exception.h>
+#include <asm/mach/irq.h>
+
+#include "irqchip.h"
+
+/*
+ * Orion SoC main interrupt controller
+ */
+
+#define ORION_IRQS_PER_CHIP 32
+
+#define ORION_IRQ_CAUSE 0x00
+#define ORION_IRQ_MASK 0x04
+#define ORION_IRQ_FIQ_MASK 0x08
+#define ORION_IRQ_ENDP_MASK 0x0c
+
+static struct irq_domain *orion_irq_domain;
+
+static asmlinkage void __exception_irq_entry orion_handle_irq(
+ struct pt_regs *regs)
+{
+ struct irq_domain_chip_generic *dgc = orion_irq_domain->gc;
+ int n, base = 0;
+
+ for (n = 0; n < dgc->num_chips; n++, base += ORION_IRQS_PER_CHIP) {
+ struct irq_chip_generic *gc =
+ irq_get_domain_generic_chip(orion_irq_domain, base);
+ u32 stat = readl_relaxed(gc->reg_base + ORION_IRQ_CAUSE) &
+ gc->mask_cache;
+ while (stat) {
+ u32 hwirq = ffs(stat) - 1;
+ u32 irq = irq_find_mapping(orion_irq_domain,
+ gc->irq_base + hwirq);
+ handle_IRQ(irq, regs);
+ stat &= ~(1 << hwirq);
+ }
+ }
+}
+
+static int __init orion_irq_init(struct device_node *np,
+ struct device_node *parent)
+{
+ unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
+ struct resource r;
+ int n, ret, base, num_chips = 0;
+
+ /* count number of irq chips by valid reg addresses */
+ while (of_address_to_resource(np, num_chips, &r) == 0)
+ num_chips++;
+
+ orion_irq_domain = irq_domain_add_linear(np,
+ num_chips * ORION_IRQS_PER_CHIP,
+ &irq_generic_chip_ops, NULL);
+ if (!orion_irq_domain)
+ panic("%s: unable to add irq domain\n", np->name);
+
+ ret = irq_alloc_domain_generic_chips(orion_irq_domain,
+ ORION_IRQS_PER_CHIP, 1, np->name,
+ handle_level_irq, clr, 0,
+ IRQ_GC_INIT_MASK_CACHE);
+ if (ret)
+ panic("%s: unable to alloc irq domain gc\n", np->name);
+
+ for (n = 0, base = 0; n < num_chips; n++, base += ORION_IRQS_PER_CHIP) {
+ struct irq_chip_generic *gc =
+ irq_get_domain_generic_chip(orion_irq_domain, base);
+
+ of_address_to_resource(np, n, &r);
+
+ if (!request_mem_region(r.start, resource_size(&r), np->name))
+ panic("%s: unable to request mem region %d",
+ np->name, n);
+
+ gc->reg_base = ioremap(r.start, resource_size(&r));
+ if (!gc->reg_base)
+ panic("%s: unable to map resource %d", np->name, n);
+
+ gc->chip_types[0].regs.mask = ORION_IRQ_MASK;
+ gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
+ gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
+
+ /* mask all interrupts */
+ writel(0, gc->reg_base + ORION_IRQ_MASK);
+ }
+
+ set_handle_irq(orion_handle_irq);
+
+ return 0;
+}
+IRQCHIP_DECLARE(orion_intc, "marvell,orion-intc", orion_irq_init);
+
+/*
+ * Orion SoC bridge interrupt controller
+ */
+
+#define ORION_BRIDGE_IRQ_CAUSE 0x00
+#define ORION_BRIDGE_IRQ_MASK 0x04
+
+static void orion_bridge_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+ struct irq_domain *d = irq_get_handler_data(irq);
+ struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, irq);
+ u32 stat = readl_relaxed(gc->reg_base + ORION_BRIDGE_IRQ_CAUSE) &
+ gc->mask_cache;
+
+ while (stat) {
+ u32 hwirq = ffs(stat) - 1;
+ generic_handle_irq(irq_find_mapping(d, gc->irq_base + hwirq));
+ stat &= ~(1 << hwirq);
+ }
+}
+
+static int __init orion_bridge_irq_init(struct device_node *np,
+ struct device_node *parent)
+{
+ unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
+ struct resource r;
+ struct irq_domain *domain;
+ struct irq_chip_generic *gc;
+ int ret, irq, nrirqs = 32;
+
+ /* get optional number of interrupts provided */
+ of_property_read_u32(np, "marvell,#interrupts", &nrirqs);
+
+ domain = irq_domain_add_linear(np, nrirqs,
+ &irq_generic_chip_ops, NULL);
+ if (!domain) {
+ pr_err("%s: unable to add irq domain\n", np->name);
+ return -ENOMEM;
+ }
+
+ ret = irq_alloc_domain_generic_chips(domain, nrirqs, 1, np->name,
+ handle_level_irq, clr, 0, IRQ_GC_INIT_MASK_CACHE);
+ if (ret) {
+ pr_err("%s: unable to alloc irq domain gc\n", np->name);
+ return ret;
+ }
+
+ ret = of_address_to_resource(np, 0, &r);
+ if (ret) {
+ pr_err("%s: unable to get resource\n", np->name);
+ return ret;
+ }
+
+ if (!request_mem_region(r.start, resource_size(&r), np->name)) {
+ pr_err("%s: unable to request mem region\n", np->name);
+ return -ENOMEM;
+ }
+
+ irq = irq_of_parse_and_map(np, 0);
+ if (irq <= 0) {
+ pr_err("%s: unable to parse irq\n", np->name);
+ return -EINVAL;
+ }
+
+ gc = irq_get_domain_generic_chip(domain, 0);
+ gc->reg_base = ioremap(r.start, resource_size(&r));
+ if (!gc->reg_base) {
+ pr_err("%s: unable to map resource\n", np->name);
+ return -ENOMEM;
+ }
+
+ gc->chip_types[0].regs.ack = ORION_BRIDGE_IRQ_CAUSE;
+ gc->chip_types[0].regs.mask = ORION_BRIDGE_IRQ_MASK;
+ gc->chip_types[0].chip.irq_ack = irq_gc_ack_clr_bit;
+ gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
+ gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
+
+ /* mask all interrupts */
+ writel(0, gc->reg_base + ORION_BRIDGE_IRQ_MASK);
+
+ irq_set_handler_data(irq, domain);
+ irq_set_chained_handler(irq, orion_bridge_irq_handler);
+
+ return 0;
+}
+IRQCHIP_DECLARE(orion_bridge_intc,
+ "marvell,orion-bridge-intc", orion_bridge_irq_init);
--
1.7.2.5
With recent support for true irqchip and clocksource drivers for Orion
SoCs, now make use of it on DT enabled Dove boards.
Signed-off-by: Sebastian Hesselbarth <[email protected]>
---
Cc: Grant Likely <[email protected]>
Cc: Rob Herring <[email protected]>
Cc: Rob Landley <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: John Stultz <[email protected]>
Cc: Russell King <[email protected]>
Cc: Jason Cooper <[email protected]>
Cc: Andrew Lunn <[email protected]>
Cc: Thomas Petazzoni <[email protected]>
Cc: Gregory Clement <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
---
arch/arm/mach-dove/Kconfig | 2 ++
arch/arm/mach-dove/Makefile | 4 ++--
arch/arm/mach-dove/board-dt.c | 23 ++++++++++++++++-------
3 files changed, 20 insertions(+), 9 deletions(-)
diff --git a/arch/arm/mach-dove/Kconfig b/arch/arm/mach-dove/Kconfig
index dff7b2f..0bc7cdf 100644
--- a/arch/arm/mach-dove/Kconfig
+++ b/arch/arm/mach-dove/Kconfig
@@ -23,6 +23,8 @@ config MACH_CM_A510
config MACH_DOVE_DT
bool "Marvell Dove Flattened Device Tree"
select DOVE_CLK
+ select ORION_IRQCHIP
+ select ORION_TIMER
select REGULATOR
select REGULATOR_FIXED_VOLTAGE
select USE_OF
diff --git a/arch/arm/mach-dove/Makefile b/arch/arm/mach-dove/Makefile
index 4d9d2ff..cbc5c06 100644
--- a/arch/arm/mach-dove/Makefile
+++ b/arch/arm/mach-dove/Makefile
@@ -1,5 +1,5 @@
-obj-y += common.o irq.o
-obj-$(CONFIG_DOVE_LEGACY) += mpp.o
+obj-y += common.o
+obj-$(CONFIG_DOVE_LEGACY) += irq.o mpp.o
obj-$(CONFIG_PCI) += pcie.o
obj-$(CONFIG_MACH_DOVE_DB) += dove-db-setup.o
obj-$(CONFIG_MACH_DOVE_DT) += board-dt.o
diff --git a/arch/arm/mach-dove/board-dt.c b/arch/arm/mach-dove/board-dt.c
index b3d65e8..b4ed3da 100644
--- a/arch/arm/mach-dove/board-dt.c
+++ b/arch/arm/mach-dove/board-dt.c
@@ -10,10 +10,13 @@
#include <linux/init.h>
#include <linux/clk-provider.h>
+#include <linux/clocksource.h>
+#include <linux/irqchip.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <asm/hardware/cache-tauros2.h>
#include <asm/mach/arch.h>
+#include <mach/dove.h>
#include <mach/pm.h>
#include <plat/common.h>
#include <plat/irq.h>
@@ -41,10 +44,17 @@ static void __init dove_legacy_clk_init(void)
of_clk_get_from_provider(&clkspec));
}
-static void __init dove_of_clk_init(void)
+static void __init dove_dt_time_init(void)
{
of_clk_init(NULL);
- dove_legacy_clk_init();
+ clocksource_of_init();
+}
+
+static void __init dove_dt_init_early(void)
+{
+ mvebu_mbus_init("marvell,dove-mbus",
+ BRIDGE_WINS_BASE, BRIDGE_WINS_SZ,
+ DOVE_MC_WINS_BASE, DOVE_MC_WINS_SZ);
}
static void __init dove_dt_init(void)
@@ -56,8 +66,8 @@ static void __init dove_dt_init(void)
#endif
dove_setup_cpu_wins();
- /* Setup root of clk tree */
- dove_of_clk_init();
+ /* setup clocks for legacy devices */
+ dove_legacy_clk_init();
/* Internal devices not ported to DT yet */
dove_pcie_init(1, 1);
@@ -72,9 +82,8 @@ static const char * const dove_dt_board_compat[] = {
DT_MACHINE_START(DOVE_DT, "Marvell Dove (Flattened Device Tree)")
.map_io = dove_map_io,
- .init_early = dove_init_early,
- .init_irq = orion_dt_init_irq,
- .init_time = dove_timer_init,
+ .init_early = dove_dt_init_early,
+ .init_time = dove_dt_time_init,
.init_machine = dove_dt_init,
.restart = dove_restart,
.dt_compat = dove_dt_board_compat,
--
1.7.2.5
With recent support for true irqchip and clocksource drivers for Orion
SoCs, now make use of it on DT enabled Kirkwood boards.
Signed-off-by: Sebastian Hesselbarth <[email protected]>
---
Cc: Grant Likely <[email protected]>
Cc: Rob Herring <[email protected]>
Cc: Rob Landley <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: John Stultz <[email protected]>
Cc: Russell King <[email protected]>
Cc: Jason Cooper <[email protected]>
Cc: Andrew Lunn <[email protected]>
Cc: Thomas Petazzoni <[email protected]>
Cc: Gregory Clement <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
---
arch/arm/boot/dts/kirkwood.dtsi | 35 +++++++++++++++++++++++++++--------
1 files changed, 27 insertions(+), 8 deletions(-)
diff --git a/arch/arm/boot/dts/kirkwood.dtsi b/arch/arm/boot/dts/kirkwood.dtsi
index c0c4811..ca296c3 100644
--- a/arch/arm/boot/dts/kirkwood.dtsi
+++ b/arch/arm/boot/dts/kirkwood.dtsi
@@ -8,13 +8,6 @@
gpio0 = &gpio0;
gpio1 = &gpio1;
};
- intc: interrupt-controller {
- compatible = "marvell,orion-intc", "marvell,intc";
- interrupt-controller;
- #interrupt-cells = <1>;
- reg = <0xf1020204 0x04>,
- <0xf1020214 0x04>;
- };
ocp@f1000000 {
compatible = "simple-bus";
@@ -24,6 +17,30 @@
#address-cells = <1>;
#size-cells = <1>;
+ timer: timer@20300 {
+ compatible = "marvell,orion-timer";
+ reg = <0x20300 0x20>;
+ interrupt-parent = <&bridge_intc>;
+ interrupts = <1>, <2>;
+ clocks = <&core_clk 0>;
+ };
+
+ intc: main-interrupt-ctrl@20200 {
+ compatible = "marvell,orion-intc";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0x20200 0x10>, <0x20210 0x10>;
+ };
+
+ bridge_intc: bridge-interrupt-ctrl@20110 {
+ compatible = "marvell,orion-bridge-intc";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0x20110 0x8>;
+ interrupts = <1>;
+ marvell,#interrupts = <6>;
+ };
+
core_clk: core-clocks@10030 {
compatible = "marvell,kirkwood-core-clock";
reg = <0x10030 0x4>;
@@ -97,9 +114,11 @@
#clock-cells = <1>;
};
- wdt@20300 {
+ wdt: watchdog-timer@20300 {
compatible = "marvell,orion-wdt";
reg = <0x20300 0x28>;
+ interrupt-parent = <&bridge_intc>;
+ interrupts = <3>;
clocks = <&gate_clk 7>;
status = "okay";
};
--
1.7.2.5
This patch add a DT enabled driver for timers found on Marvell Orion SoCs
(Kirkwood, Dove, Orion5x, and Discovery Innovation). It installs a free-
running clocksource on timer0 and a clockevent source on timer1.
Corresponding device tree documentation is also added.
Signed-off-by: Sebastian Hesselbarth <[email protected]>
---
Cc: Grant Likely <[email protected]>
Cc: Rob Herring <[email protected]>
Cc: Rob Landley <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: John Stultz <[email protected]>
Cc: Russell King <[email protected]>
Cc: Jason Cooper <[email protected]>
Cc: Andrew Lunn <[email protected]>
Cc: Thomas Petazzoni <[email protected]>
Cc: Gregory Clement <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
---
.../bindings/timer/marvell,orion-timer.txt | 17 +++
drivers/clocksource/Kconfig | 5 +
drivers/clocksource/Makefile | 1 +
drivers/clocksource/time-orion.c | 143 ++++++++++++++++++++
4 files changed, 166 insertions(+), 0 deletions(-)
create mode 100644 Documentation/devicetree/bindings/timer/marvell,orion-timer.txt
create mode 100644 drivers/clocksource/time-orion.c
diff --git a/Documentation/devicetree/bindings/timer/marvell,orion-timer.txt b/Documentation/devicetree/bindings/timer/marvell,orion-timer.txt
new file mode 100644
index 0000000..62bb826
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/marvell,orion-timer.txt
@@ -0,0 +1,17 @@
+Marvell Orion SoC timer
+
+Required properties:
+- compatible: shall be "marvell,orion-timer"
+- reg: base address of the timer register starting with TIMERS CONTROL register
+- interrupt-parent: phandle of the bridge interrupt controller
+- interrupts: should contain the interrupts for Timer0 and Timer1
+- clocks: phandle of timer reference clock (tclk)
+
+Example:
+ timer: timer {
+ compatible = "marvell,orion-timer";
+ reg = <0x20300 0x20>;
+ interrupt-parent = <&bridge_intc>;
+ interrupts = <1>, <2>;
+ clocks = <&core_clk 0>;
+ };
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index f151c6c..2404869 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -25,6 +25,11 @@ config DW_APB_TIMER_OF
config ARMADA_370_XP_TIMER
bool
+config ORION_TIMER
+ select CLKSRC_OF
+ select CLKSRC_MMIO
+ bool
+
config SUN4I_TIMER
bool
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 8d979c7..d1e8d68 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_DW_APB_TIMER_OF) += dw_apb_timer_of.o
obj-$(CONFIG_CLKSRC_NOMADIK_MTU) += nomadik-mtu.o
obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o
obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o
+obj-$(CONFIG_ORION_TIMER) += time-orion.o
obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o
obj-$(CONFIG_ARCH_MARCO) += timer-marco.o
obj-$(CONFIG_ARCH_MXS) += mxs_timer.o
diff --git a/drivers/clocksource/time-orion.c b/drivers/clocksource/time-orion.c
new file mode 100644
index 0000000..4ecb2f8
--- /dev/null
+++ b/drivers/clocksource/time-orion.c
@@ -0,0 +1,143 @@
+/*
+ * Marvell Orion SoC timer handling.
+ *
+ * Sebastian Hesselbarth <[email protected]>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ *
+ * Timer 0 is used as free-running clocksource, while timer 1 is
+ * used as clock_event_device.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/interrupt.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <asm/sched_clock.h>
+
+#define TIMER_CTRL 0x00
+#define TIMER0_EN BIT(0)
+#define TIMER0_RELOAD_EN BIT(1)
+#define TIMER1_EN BIT(2)
+#define TIMER1_RELOAD_EN BIT(3)
+#define TIMER0_RELOAD 0x10
+#define TIMER0_VAL 0x14
+#define TIMER1_RELOAD 0x18
+#define TIMER1_VAL 0x1c
+
+#define ORION_ONESHOT_MIN 1
+#define ORION_ONESHOT_MAX 0xfffffffe
+
+static void __iomem *timer_base;
+
+/*
+ * Free-running clocksource handling.
+ */
+static u32 notrace orion_read_sched_clock(void)
+{
+ return ~readl(timer_base + TIMER0_VAL);
+}
+
+/*
+ * Clockevent handling.
+ */
+static u32 ticks_per_jiffy;
+
+static int orion_clkevt_next_event(unsigned long delta,
+ struct clock_event_device *dev)
+{
+ u32 u;
+
+ /* setup and enable one-shot timer */
+ writel(delta, timer_base + TIMER1_VAL);
+ u = readl(timer_base + TIMER_CTRL) & ~TIMER1_RELOAD_EN;
+ writel(u | TIMER1_EN, timer_base + TIMER_CTRL);
+
+ return 0;
+}
+
+static void orion_clkevt_mode(enum clock_event_mode mode,
+ struct clock_event_device *dev)
+{
+ u32 u;
+
+ if (mode == CLOCK_EVT_MODE_PERIODIC) {
+ /* setup and enable periodic timer at 1/HZ intervals */
+ writel(ticks_per_jiffy - 1, timer_base + TIMER1_RELOAD);
+ writel(ticks_per_jiffy - 1, timer_base + TIMER1_VAL);
+ u = readl(timer_base + TIMER_CTRL);
+ writel(u | TIMER1_EN | TIMER1_RELOAD_EN,
+ timer_base + TIMER_CTRL);
+ } else {
+ /* disable timer */
+ u = readl(timer_base + TIMER_CTRL) & ~TIMER1_EN;
+ writel(u, timer_base + TIMER_CTRL);
+ }
+}
+
+static struct clock_event_device orion_clkevt = {
+ .name = "orion_event",
+ .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
+ .shift = 32,
+ .rating = 300,
+ .set_next_event = orion_clkevt_next_event,
+ .set_mode = orion_clkevt_mode,
+};
+
+static irqreturn_t orion_clkevt_irq_handler(int irq, void *dev_id)
+{
+ orion_clkevt.event_handler(&orion_clkevt);
+ return IRQ_HANDLED;
+}
+
+static struct irqaction orion_clkevt_irq = {
+ .name = "orion_event",
+ .flags = IRQF_DISABLED | IRQF_TIMER,
+ .handler = orion_clkevt_irq_handler,
+};
+
+static void __init orion_timer_init(struct device_node *np)
+{
+ struct clk *clk;
+ int irq;
+
+ /* timer registers are shared with watchdog timer */
+ timer_base = of_iomap(np, 0);
+ if (!timer_base)
+ panic("%s: unable to map resource\n", np->name);
+
+ clk = of_clk_get(np, 0);
+ if (IS_ERR(clk))
+ panic("%s: unable to get clk\n", np->name);
+ clk_prepare_enable(clk);
+
+ /* we are only interested in timer1 irq */
+ irq = irq_of_parse_and_map(np, 1);
+ if (irq <= 0)
+ panic("%s: unable to parse timer1 irq\n", np->name);
+
+ /* setup timer0 as free-running clocksource */
+ writel(~0, timer_base + TIMER0_VAL);
+ writel(~0, timer_base + TIMER0_RELOAD);
+ writel(readl(timer_base + TIMER_CTRL) | TIMER0_EN | TIMER0_RELOAD_EN,
+ timer_base + TIMER_CTRL);
+ clocksource_mmio_init(timer_base + TIMER0_VAL, "orion_clocksource",
+ clk_get_rate(clk), 300, 32,
+ clocksource_mmio_readl_down);
+ setup_sched_clock(orion_read_sched_clock, 32, clk_get_rate(clk));
+
+ /* setup timer1 as clockevent timer */
+ if (setup_irq(irq, &orion_clkevt_irq))
+ panic("%s: unable to setup irq\n", np->name);
+
+ ticks_per_jiffy = (clk_get_rate(clk) + HZ/2) / HZ;
+ orion_clkevt.cpumask = cpumask_of(0);
+ clockevents_config_and_register(&orion_clkevt, clk_get_rate(clk),
+ ORION_ONESHOT_MIN, ORION_ONESHOT_MAX);
+}
+CLOCKSOURCE_OF_DECLARE(orion_timer, "marvell,orion-timer", orion_timer_init);
--
1.7.2.5
On Thu, Jun 06, 2013 at 06:27:08PM +0200, Sebastian Hesselbarth wrote:
> This patch set introduces DT-aware irqchip and clocksource drivers for
> Marvell Orion SoCs (Kirkwood, Dove, Orion5x, MV78x00) and corresponding
> patches for Dove and Kirkwood to enable them for DT-boards.
Looks broadly good to me, based on a quick read through all the
patches.
Regards,
Jason
On Thu, Jun 06, 2013 at 06:27:08PM +0200, Sebastian Hesselbarth wrote:
> This patch set introduces DT-aware irqchip and clocksource drivers for
> Marvell Orion SoCs (Kirkwood, Dove, Orion5x, MV78x00) and corresponding
> patches for Dove and Kirkwood to enable them for DT-boards.
>
> The irqchip driver, of course, depends on Thomas Gleixner's work on
> irqdomain support for generic chip (tip irq/core).
Ah, this is why I wanted to look at the diffstat. The dependencies
aren't nearly as complicated as I imagined. :-)
> The ARM part of this patch set has a quite ridiculuous dependency havoc
> of mv643xx_eth DT support (current net-next) that will add to both irqchip
> and clocksource branches respectively. Therefore, I suggest that irq
> and clocksource maintainers take in the mere drivers (Patches 1+2) and
> Jason Cooper handles the remaining patches when all three drivers have
> surfaced on mainline linux.
The suggested approach is correct, but it should be pretty easy to apply
#3-6 once v3.11-rc1 drops.
thx,
Jason.
Dear Sebastian Hesselbarth,
On Thu, 6 Jun 2013 18:27:12 +0200, Sebastian Hesselbarth wrote:
> - wdt@20300 {
> + wdt: watchdog-timer@20300 {
> compatible = "marvell,orion-wdt";
> reg = <0x20300 0x28>;
> + interrupt-parent = <&bridge_intc>;
> + interrupts = <3>;
> clocks = <&gate_clk 7>;
> status = "okay";
> };
The watchdog driver is mapping the same registers as the timer driver
(0x20300) and is poking into the same TIMER_CTRL register that controls
both the timers and the watchdog.
In addition to this, the watchdog driver also pokes into some other
registers, such as BRIDGE_CAUSE and RSTOUTn_MASK.
As we want to bring watchdog support for Armada 370/XP, I'm wondering
if we should fix those problems, and if yes, how:
(1) The timer driver is also responsible for handling the watchdog
(probably the easiest solution)
(2) Have some sort of 'common code' between the timer driver and the
watchdog driver to control the access to the shared TIMER_CTRL
register.
(3) Something else.
And this still does not solve the access to BRIDGE_CAUSE and
RSTOUTn_MASK.
Ideas?
Thomas
--
Thomas Petazzoni, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
On 06/07/13 10:30, Thomas Petazzoni wrote:
> On Thu, 6 Jun 2013 18:27:12 +0200, Sebastian Hesselbarth wrote:
>> - wdt@20300 {
>> + wdt: watchdog-timer@20300 {
>> compatible = "marvell,orion-wdt";
>> reg = <0x20300 0x28>;
>> + interrupt-parent = <&bridge_intc>;
>> + interrupts = <3>;
>> clocks = <&gate_clk 7>;
>> status = "okay";
>> };
>
> The watchdog driver is mapping the same registers as the timer driver
> (0x20300) and is poking into the same TIMER_CTRL register that controls
> both the timers and the watchdog.
Thomas,
you are right. I must admit that I forgot to take care of watchdog
driver.
> In addition to this, the watchdog driver also pokes into some other
> registers, such as BRIDGE_CAUSE and RSTOUTn_MASK.
As you can see above, watchdog should depend on chained interrupts but
current implementation doesn't but clears itself in BRIDGE_CAUSE.
Current non-DT timer also does (thread unsafe).
DT timer depends on the chained irq handler introduced with this patch
set. So for the interrupt, watchdog should also depend on the chained
irq handler to clear wdt irq.
Access to TIMER_CTRL should be made thread safe. I suggest to put that
common code into orion clocksource as it will be always compiled in
while wdt is optional.
> As we want to bring watchdog support for Armada 370/XP, I'm wondering
> if we should fix those problems, and if yes, how:
>
> (1) The timer driver is also responsible for handling the watchdog
> (probably the easiest solution)
Well, there is drivers/watchdog where current (Orion) wdt is located.
I guess it should stay there. For Armada 370/XP I guess it will need
to clear the watchdog events in common timer registers as for the timer
events? That is why I didn't merge Orion clocksource into Armada 370/XP
clocksource because we would have to check for Orion/Armada 370/XP on
every timer event.
> (2) Have some sort of 'common code' between the timer driver and the
> watchdog driver to control the access to the shared TIMER_CTRL
> register.
Yes. Both should call a common thread-safe timer_en(num) at least.
> (3) Something else.
>
> And this still does not solve the access to BRIDGE_CAUSE and
> RSTOUTn_MASK.
BRIDGE_CAUSE is taken care of by making wdt depend on chained irq
handler.. RSTOUTn_MASK is only used by current common code on reset,
maybe there is an API for that I have missed yet. But both reset and
watchdog will ultimately cause a reset - maybe we can accept that for
now.
Sebastian
On 06/07/13 10:30, Thomas Petazzoni wrote:
> On Thu, 6 Jun 2013 18:27:12 +0200, Sebastian Hesselbarth wrote:
>
>> - wdt@20300 {
>> + wdt: watchdog-timer@20300 {
>> compatible = "marvell,orion-wdt";
>> reg = <0x20300 0x28>;
>> + interrupt-parent = <&bridge_intc>;
>> + interrupts = <3>;
>> clocks = <&gate_clk 7>;
>> status = "okay";
>> };
>
> The watchdog driver is mapping the same registers as the timer driver
> (0x20300) and is poking into the same TIMER_CTRL register that controls
> both the timers and the watchdog.
Thomas,
I didn't comment on the base address above: with issue (b) solved the
actual reg property of wdt should be <0x20320 0x8> while timer's reg
property is <0x20300 0x20>.
I had a closer look at orion-wdt. Actually, I don't want to poke into it
too much, but DT irqchip introduces that chained irq handler for bridge
registers. While clocksource allows us to have separate drivers for DT
and non-DT, current watchdog does not.
This introduces some issues to take care of when dealing with kernels
where you have both non-DT and DT compiled in.
(a) non-DT timer and DT/non-DT watchdog poke BRIDGE_CAUSE
Convert non-DT irq to install chained irq and remove it from non-DT
timer and DT/non-DT watchdog.
(b) non-DT timer, DT timer, and DT/non-DT watchdog poke TIMER_CTRL
Have non-DT timer and DT timer export an orion_timer_ctrl_clrset()
function that spin_locks access to TIMER_CTRL register. Make non-DT
timer, DT timer, and DT/non-DT watchdog use that exported function.
One thing we need to workaround here: You cannot have the same function
name exported from both non-DT and DT timer. For a temporary "fix" this
function could sit in arch/arm/plat-orion/temporary.c until we get rid
of non-DT completely. Maybe we also want some place there to
subsequently split-off code from common.c when we switch to other APIs
for DT kernels (Reset API).
(c) common plat-orion reset and watchdog poke RSTOUTn_MASK
Leave it.
*OR* (d) implement a DT-only version of watchdog
From what I can see from current orion wdt I prefer forking the whole
driver and remove of_device_id from the old one. Or just have non-DT
and DT callbacks where required. That will safe us from messing with
non-DT core drivers just for getting orion wdt to behave on DT kernels.
And just for the record, we fork off new drivers for DT all the time
but watchdog already sits in drivers/ while the rest moves from arch/arm
to drivers/.
Sebastian
On 06/06/2013 06:27 PM, Sebastian Hesselbarth wrote:
> This patch add a DT enabled driver for timers found on Marvell Orion SoCs
> (Kirkwood, Dove, Orion5x, and Discovery Innovation). It installs a free-
> running clocksource on timer0 and a clockevent source on timer1.
> Corresponding device tree documentation is also added.
>
> Signed-off-by: Sebastian Hesselbarth <[email protected]>
> ---
> Cc: Grant Likely <[email protected]>
> Cc: Rob Herring <[email protected]>
> Cc: Rob Landley <[email protected]>
> Cc: Thomas Gleixner <[email protected]>
> Cc: John Stultz <[email protected]>
> Cc: Russell King <[email protected]>
> Cc: Jason Cooper <[email protected]>
> Cc: Andrew Lunn <[email protected]>
> Cc: Thomas Petazzoni <[email protected]>
> Cc: Gregory Clement <[email protected]>
> Cc: [email protected]
> Cc: [email protected]
> Cc: [email protected]
> Cc: [email protected]
> ---
> .../bindings/timer/marvell,orion-timer.txt | 17 +++
> drivers/clocksource/Kconfig | 5 +
> drivers/clocksource/Makefile | 1 +
> drivers/clocksource/time-orion.c | 143 ++++++++++++++++++++
> 4 files changed, 166 insertions(+), 0 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/timer/marvell,orion-timer.txt
> create mode 100644 drivers/clocksource/time-orion.c
>
> diff --git a/Documentation/devicetree/bindings/timer/marvell,orion-timer.txt b/Documentation/devicetree/bindings/timer/marvell,orion-timer.txt
> new file mode 100644
> index 0000000..62bb826
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/timer/marvell,orion-timer.txt
> @@ -0,0 +1,17 @@
> +Marvell Orion SoC timer
> +
> +Required properties:
> +- compatible: shall be "marvell,orion-timer"
> +- reg: base address of the timer register starting with TIMERS CONTROL register
> +- interrupt-parent: phandle of the bridge interrupt controller
> +- interrupts: should contain the interrupts for Timer0 and Timer1
> +- clocks: phandle of timer reference clock (tclk)
> +
> +Example:
> + timer: timer {
> + compatible = "marvell,orion-timer";
> + reg = <0x20300 0x20>;
> + interrupt-parent = <&bridge_intc>;
> + interrupts = <1>, <2>;
> + clocks = <&core_clk 0>;
> + };
> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
> index f151c6c..2404869 100644
> --- a/drivers/clocksource/Kconfig
> +++ b/drivers/clocksource/Kconfig
> @@ -25,6 +25,11 @@ config DW_APB_TIMER_OF
> config ARMADA_370_XP_TIMER
> bool
>
> +config ORION_TIMER
> + select CLKSRC_OF
> + select CLKSRC_MMIO
> + bool
> +
> config SUN4I_TIMER
> bool
[ ... ]
> +
> +static irqreturn_t orion_clkevt_irq_handler(int irq, void *dev_id)
> +{
> + orion_clkevt.event_handler(&orion_clkevt);
> + return IRQ_HANDLED;
> +}
> +
> +static struct irqaction orion_clkevt_irq = {
> + .name = "orion_event",
> + .flags = IRQF_DISABLED | IRQF_TIMER,
IRQF_DISABLED is deprecated, it is a noop, you shall remove it.
> + .handler = orion_clkevt_irq_handler,
> +};
> +
> +static void __init orion_timer_init(struct device_node *np)
> +{
[ ... ]
> + /* setup timer1 as clockevent timer */
> + if (setup_irq(irq, &orion_clkevt_irq))
> + panic("%s: unable to setup irq\n", np->name);
> +
> + ticks_per_jiffy = (clk_get_rate(clk) + HZ/2) / HZ;
> + orion_clkevt.cpumask = cpumask_of(0);
orion_clkevt.irq = irq;
> + clockevents_config_and_register(&orion_clkevt, clk_get_rate(clk),
> + ORION_ONESHOT_MIN, ORION_ONESHOT_MAX);
> +}
> +CLOCKSOURCE_OF_DECLARE(orion_timer, "marvell,orion-timer", orion_timer_init);
>
--
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs
Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
This patch add a DT enabled driver for timers found on Marvell Orion SoCs
(Kirkwood, Dove, Orion5x, and Discovery Innovation). It installs a free-
running clocksource on timer0 and a clockevent source on timer1.
Corresponding device tree documentation is also added.
Signed-off-by: Sebastian Hesselbarth <[email protected]>
---
Changelog:
v3->v4:
- export thread-safe access to TIMER_CTRL register to use with watchdog
- remove IRQF_DISABLED and add .irq to clock event (Suggested by Daniel Lezcano)
Notes:
- This is only an update to clocksource driver, the remaining patches are
not resent as they have not been changed.
- I will not rework orion watchdog driver for this patch set. It is written
Kirkwood/Orion5x specific although it will also work on Dove and it is messing
with shared registers. It has done it before, so I consider it broken anyway.
I (or somebody else) will take care of proper watchdog later.
- An updated branch can be found on
git://github.com/shesselba/linux-dove.git orion-irqchip-for-v3.11_v4
Cc: Grant Likely <[email protected]>
Cc: Rob Herring <[email protected]>
Cc: Rob Landley <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: John Stultz <[email protected]>
Cc: Russell King <[email protected]>
Cc: Jason Cooper <[email protected]>
Cc: Andrew Lunn <[email protected]>
Cc: Thomas Petazzoni <[email protected]>
Cc: Gregory Clement <[email protected]>
Cc: Daniel Lezcano <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
---
.../bindings/timer/marvell,orion-timer.txt | 17 +++
drivers/clocksource/Kconfig | 5 +
drivers/clocksource/Makefile | 1 +
drivers/clocksource/time-orion.c | 150 ++++++++++++++++++++
4 files changed, 173 insertions(+), 0 deletions(-)
create mode 100644 Documentation/devicetree/bindings/timer/marvell,orion-timer.txt
create mode 100644 drivers/clocksource/time-orion.c
diff --git a/Documentation/devicetree/bindings/timer/marvell,orion-timer.txt b/Documentation/devicetree/bindings/timer/marvell,orion-timer.txt
new file mode 100644
index 0000000..62bb826
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/marvell,orion-timer.txt
@@ -0,0 +1,17 @@
+Marvell Orion SoC timer
+
+Required properties:
+- compatible: shall be "marvell,orion-timer"
+- reg: base address of the timer register starting with TIMERS CONTROL register
+- interrupt-parent: phandle of the bridge interrupt controller
+- interrupts: should contain the interrupts for Timer0 and Timer1
+- clocks: phandle of timer reference clock (tclk)
+
+Example:
+ timer: timer {
+ compatible = "marvell,orion-timer";
+ reg = <0x20300 0x20>;
+ interrupt-parent = <&bridge_intc>;
+ interrupts = <1>, <2>;
+ clocks = <&core_clk 0>;
+ };
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index f151c6c..2404869 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -25,6 +25,11 @@ config DW_APB_TIMER_OF
config ARMADA_370_XP_TIMER
bool
+config ORION_TIMER
+ select CLKSRC_OF
+ select CLKSRC_MMIO
+ bool
+
config SUN4I_TIMER
bool
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 8d979c7..d1e8d68 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_DW_APB_TIMER_OF) += dw_apb_timer_of.o
obj-$(CONFIG_CLKSRC_NOMADIK_MTU) += nomadik-mtu.o
obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o
obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o
+obj-$(CONFIG_ORION_TIMER) += time-orion.o
obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o
obj-$(CONFIG_ARCH_MARCO) += timer-marco.o
obj-$(CONFIG_ARCH_MXS) += mxs_timer.o
diff --git a/drivers/clocksource/time-orion.c b/drivers/clocksource/time-orion.c
new file mode 100644
index 0000000..ad7df17
--- /dev/null
+++ b/drivers/clocksource/time-orion.c
@@ -0,0 +1,150 @@
+/*
+ * Marvell Orion SoC timer handling.
+ *
+ * Sebastian Hesselbarth <[email protected]>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ *
+ * Timer 0 is used as free-running clocksource, while timer 1 is
+ * used as clock_event_device.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/interrupt.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/spinlock.h>
+#include <asm/sched_clock.h>
+
+#define TIMER_CTRL 0x00
+#define TIMER0_EN BIT(0)
+#define TIMER0_RELOAD_EN BIT(1)
+#define TIMER1_EN BIT(2)
+#define TIMER1_RELOAD_EN BIT(3)
+#define TIMER0_RELOAD 0x10
+#define TIMER0_VAL 0x14
+#define TIMER1_RELOAD 0x18
+#define TIMER1_VAL 0x1c
+
+#define ORION_ONESHOT_MIN 1
+#define ORION_ONESHOT_MAX 0xfffffffe
+
+static void __iomem *timer_base;
+static DEFINE_SPINLOCK(timer_ctrl_lock);
+
+/*
+ * Thread-safe access to TIMER_CTRL register
+ * (shared with watchdog timer)
+ */
+void orion_timer_ctrl_clrset(u32 clr, u32 set)
+{
+ spin_lock(&timer_ctrl_lock);
+ writel((readl(timer_base + TIMER_CTRL) & ~clr) | set,
+ timer_base + TIMER_CTRL);
+ spin_unlock(&timer_ctrl_lock);
+}
+EXPORT_SYMBOL(orion_timer_ctrl_clrset);
+
+/*
+ * Free-running clocksource handling.
+ */
+static u32 notrace orion_read_sched_clock(void)
+{
+ return ~readl(timer_base + TIMER0_VAL);
+}
+
+/*
+ * Clockevent handling.
+ */
+static u32 ticks_per_jiffy;
+
+static int orion_clkevt_next_event(unsigned long delta,
+ struct clock_event_device *dev)
+{
+ /* setup and enable one-shot timer */
+ writel(delta, timer_base + TIMER1_VAL);
+ orion_timer_ctrl_clrset(TIMER1_RELOAD_EN, TIMER1_EN);
+
+ return 0;
+}
+
+static void orion_clkevt_mode(enum clock_event_mode mode,
+ struct clock_event_device *dev)
+{
+ if (mode == CLOCK_EVT_MODE_PERIODIC) {
+ /* setup and enable periodic timer at 1/HZ intervals */
+ writel(ticks_per_jiffy - 1, timer_base + TIMER1_RELOAD);
+ writel(ticks_per_jiffy - 1, timer_base + TIMER1_VAL);
+ orion_timer_ctrl_clrset(0, TIMER1_RELOAD_EN | TIMER1_EN);
+ } else {
+ /* disable timer */
+ orion_timer_ctrl_clrset(TIMER1_RELOAD_EN | TIMER1_EN, 0);
+ }
+}
+
+static struct clock_event_device orion_clkevt = {
+ .name = "orion_event",
+ .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
+ .shift = 32,
+ .rating = 300,
+ .set_next_event = orion_clkevt_next_event,
+ .set_mode = orion_clkevt_mode,
+};
+
+static irqreturn_t orion_clkevt_irq_handler(int irq, void *dev_id)
+{
+ orion_clkevt.event_handler(&orion_clkevt);
+ return IRQ_HANDLED;
+}
+
+static struct irqaction orion_clkevt_irq = {
+ .name = "orion_event",
+ .flags = IRQF_TIMER,
+ .handler = orion_clkevt_irq_handler,
+};
+
+static void __init orion_timer_init(struct device_node *np)
+{
+ struct clk *clk;
+ int irq;
+
+ /* timer registers are shared with watchdog timer */
+ timer_base = of_iomap(np, 0);
+ if (!timer_base)
+ panic("%s: unable to map resource\n", np->name);
+
+ clk = of_clk_get(np, 0);
+ if (IS_ERR(clk))
+ panic("%s: unable to get clk\n", np->name);
+ clk_prepare_enable(clk);
+
+ /* we are only interested in timer1 irq */
+ irq = irq_of_parse_and_map(np, 1);
+ if (irq <= 0)
+ panic("%s: unable to parse timer1 irq\n", np->name);
+
+ /* setup timer0 as free-running clocksource */
+ writel(~0, timer_base + TIMER0_VAL);
+ writel(~0, timer_base + TIMER0_RELOAD);
+ orion_timer_ctrl_clrset(0, TIMER0_RELOAD_EN | TIMER0_EN);
+ clocksource_mmio_init(timer_base + TIMER0_VAL, "orion_clocksource",
+ clk_get_rate(clk), 300, 32,
+ clocksource_mmio_readl_down);
+ setup_sched_clock(orion_read_sched_clock, 32, clk_get_rate(clk));
+
+ /* setup timer1 as clockevent timer */
+ if (setup_irq(irq, &orion_clkevt_irq))
+ panic("%s: unable to setup irq\n", np->name);
+
+ ticks_per_jiffy = (clk_get_rate(clk) + HZ/2) / HZ;
+ orion_clkevt.cpumask = cpumask_of(0);
+ orion_clkevt.irq = irq;
+ clockevents_config_and_register(&orion_clkevt, clk_get_rate(clk),
+ ORION_ONESHOT_MIN, ORION_ONESHOT_MAX);
+}
+CLOCKSOURCE_OF_DECLARE(orion_timer, "marvell,orion-timer", orion_timer_init);
--
1.7.2.5
On 06/10/2013 11:35 AM, Sebastian Hesselbarth wrote:
> This patch add a DT enabled driver for timers found on Marvell Orion SoCs
> (Kirkwood, Dove, Orion5x, and Discovery Innovation). It installs a free-
> running clocksource on timer0 and a clockevent source on timer1.
> Corresponding device tree documentation is also added.
>
> Signed-off-by: Sebastian Hesselbarth <[email protected]>
It looks good for me.
Sebastian,
shall I take it through my tree (it will go to Thomas's tree) ?
Thanks
-- Daniel
> ---
> Changelog:
> v3->v4:
> - export thread-safe access to TIMER_CTRL register to use with watchdog
> - remove IRQF_DISABLED and add .irq to clock event (Suggested by Daniel Lezcano)
>
> Notes:
> - This is only an update to clocksource driver, the remaining patches are
> not resent as they have not been changed.
> - I will not rework orion watchdog driver for this patch set. It is written
> Kirkwood/Orion5x specific although it will also work on Dove and it is messing
> with shared registers. It has done it before, so I consider it broken anyway.
> I (or somebody else) will take care of proper watchdog later.
> - An updated branch can be found on
> git://github.com/shesselba/linux-dove.git orion-irqchip-for-v3.11_v4
>
> Cc: Grant Likely <[email protected]>
> Cc: Rob Herring <[email protected]>
> Cc: Rob Landley <[email protected]>
> Cc: Thomas Gleixner <[email protected]>
> Cc: John Stultz <[email protected]>
> Cc: Russell King <[email protected]>
> Cc: Jason Cooper <[email protected]>
> Cc: Andrew Lunn <[email protected]>
> Cc: Thomas Petazzoni <[email protected]>
> Cc: Gregory Clement <[email protected]>
> Cc: Daniel Lezcano <[email protected]>
> Cc: [email protected]
> Cc: [email protected]
> Cc: [email protected]
> Cc: [email protected]
> ---
> .../bindings/timer/marvell,orion-timer.txt | 17 +++
> drivers/clocksource/Kconfig | 5 +
> drivers/clocksource/Makefile | 1 +
> drivers/clocksource/time-orion.c | 150 ++++++++++++++++++++
> 4 files changed, 173 insertions(+), 0 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/timer/marvell,orion-timer.txt
> create mode 100644 drivers/clocksource/time-orion.c
>
> diff --git a/Documentation/devicetree/bindings/timer/marvell,orion-timer.txt b/Documentation/devicetree/bindings/timer/marvell,orion-timer.txt
> new file mode 100644
> index 0000000..62bb826
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/timer/marvell,orion-timer.txt
> @@ -0,0 +1,17 @@
> +Marvell Orion SoC timer
> +
> +Required properties:
> +- compatible: shall be "marvell,orion-timer"
> +- reg: base address of the timer register starting with TIMERS CONTROL register
> +- interrupt-parent: phandle of the bridge interrupt controller
> +- interrupts: should contain the interrupts for Timer0 and Timer1
> +- clocks: phandle of timer reference clock (tclk)
> +
> +Example:
> + timer: timer {
> + compatible = "marvell,orion-timer";
> + reg = <0x20300 0x20>;
> + interrupt-parent = <&bridge_intc>;
> + interrupts = <1>, <2>;
> + clocks = <&core_clk 0>;
> + };
> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
> index f151c6c..2404869 100644
> --- a/drivers/clocksource/Kconfig
> +++ b/drivers/clocksource/Kconfig
> @@ -25,6 +25,11 @@ config DW_APB_TIMER_OF
> config ARMADA_370_XP_TIMER
> bool
>
> +config ORION_TIMER
> + select CLKSRC_OF
> + select CLKSRC_MMIO
> + bool
> +
> config SUN4I_TIMER
> bool
>
> diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
> index 8d979c7..d1e8d68 100644
> --- a/drivers/clocksource/Makefile
> +++ b/drivers/clocksource/Makefile
> @@ -15,6 +15,7 @@ obj-$(CONFIG_DW_APB_TIMER_OF) += dw_apb_timer_of.o
> obj-$(CONFIG_CLKSRC_NOMADIK_MTU) += nomadik-mtu.o
> obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o
> obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o
> +obj-$(CONFIG_ORION_TIMER) += time-orion.o
> obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o
> obj-$(CONFIG_ARCH_MARCO) += timer-marco.o
> obj-$(CONFIG_ARCH_MXS) += mxs_timer.o
> diff --git a/drivers/clocksource/time-orion.c b/drivers/clocksource/time-orion.c
> new file mode 100644
> index 0000000..ad7df17
> --- /dev/null
> +++ b/drivers/clocksource/time-orion.c
> @@ -0,0 +1,150 @@
> +/*
> + * Marvell Orion SoC timer handling.
> + *
> + * Sebastian Hesselbarth <[email protected]>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2. This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + *
> + * Timer 0 is used as free-running clocksource, while timer 1 is
> + * used as clock_event_device.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/bitops.h>
> +#include <linux/clk.h>
> +#include <linux/clockchips.h>
> +#include <linux/interrupt.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/spinlock.h>
> +#include <asm/sched_clock.h>
> +
> +#define TIMER_CTRL 0x00
> +#define TIMER0_EN BIT(0)
> +#define TIMER0_RELOAD_EN BIT(1)
> +#define TIMER1_EN BIT(2)
> +#define TIMER1_RELOAD_EN BIT(3)
> +#define TIMER0_RELOAD 0x10
> +#define TIMER0_VAL 0x14
> +#define TIMER1_RELOAD 0x18
> +#define TIMER1_VAL 0x1c
> +
> +#define ORION_ONESHOT_MIN 1
> +#define ORION_ONESHOT_MAX 0xfffffffe
> +
> +static void __iomem *timer_base;
> +static DEFINE_SPINLOCK(timer_ctrl_lock);
> +
> +/*
> + * Thread-safe access to TIMER_CTRL register
> + * (shared with watchdog timer)
> + */
> +void orion_timer_ctrl_clrset(u32 clr, u32 set)
> +{
> + spin_lock(&timer_ctrl_lock);
> + writel((readl(timer_base + TIMER_CTRL) & ~clr) | set,
> + timer_base + TIMER_CTRL);
> + spin_unlock(&timer_ctrl_lock);
> +}
> +EXPORT_SYMBOL(orion_timer_ctrl_clrset);
> +
> +/*
> + * Free-running clocksource handling.
> + */
> +static u32 notrace orion_read_sched_clock(void)
> +{
> + return ~readl(timer_base + TIMER0_VAL);
> +}
> +
> +/*
> + * Clockevent handling.
> + */
> +static u32 ticks_per_jiffy;
> +
> +static int orion_clkevt_next_event(unsigned long delta,
> + struct clock_event_device *dev)
> +{
> + /* setup and enable one-shot timer */
> + writel(delta, timer_base + TIMER1_VAL);
> + orion_timer_ctrl_clrset(TIMER1_RELOAD_EN, TIMER1_EN);
> +
> + return 0;
> +}
> +
> +static void orion_clkevt_mode(enum clock_event_mode mode,
> + struct clock_event_device *dev)
> +{
> + if (mode == CLOCK_EVT_MODE_PERIODIC) {
> + /* setup and enable periodic timer at 1/HZ intervals */
> + writel(ticks_per_jiffy - 1, timer_base + TIMER1_RELOAD);
> + writel(ticks_per_jiffy - 1, timer_base + TIMER1_VAL);
> + orion_timer_ctrl_clrset(0, TIMER1_RELOAD_EN | TIMER1_EN);
> + } else {
> + /* disable timer */
> + orion_timer_ctrl_clrset(TIMER1_RELOAD_EN | TIMER1_EN, 0);
> + }
> +}
> +
> +static struct clock_event_device orion_clkevt = {
> + .name = "orion_event",
> + .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
> + .shift = 32,
> + .rating = 300,
> + .set_next_event = orion_clkevt_next_event,
> + .set_mode = orion_clkevt_mode,
> +};
> +
> +static irqreturn_t orion_clkevt_irq_handler(int irq, void *dev_id)
> +{
> + orion_clkevt.event_handler(&orion_clkevt);
> + return IRQ_HANDLED;
> +}
> +
> +static struct irqaction orion_clkevt_irq = {
> + .name = "orion_event",
> + .flags = IRQF_TIMER,
> + .handler = orion_clkevt_irq_handler,
> +};
> +
> +static void __init orion_timer_init(struct device_node *np)
> +{
> + struct clk *clk;
> + int irq;
> +
> + /* timer registers are shared with watchdog timer */
> + timer_base = of_iomap(np, 0);
> + if (!timer_base)
> + panic("%s: unable to map resource\n", np->name);
> +
> + clk = of_clk_get(np, 0);
> + if (IS_ERR(clk))
> + panic("%s: unable to get clk\n", np->name);
> + clk_prepare_enable(clk);
> +
> + /* we are only interested in timer1 irq */
> + irq = irq_of_parse_and_map(np, 1);
> + if (irq <= 0)
> + panic("%s: unable to parse timer1 irq\n", np->name);
> +
> + /* setup timer0 as free-running clocksource */
> + writel(~0, timer_base + TIMER0_VAL);
> + writel(~0, timer_base + TIMER0_RELOAD);
> + orion_timer_ctrl_clrset(0, TIMER0_RELOAD_EN | TIMER0_EN);
> + clocksource_mmio_init(timer_base + TIMER0_VAL, "orion_clocksource",
> + clk_get_rate(clk), 300, 32,
> + clocksource_mmio_readl_down);
> + setup_sched_clock(orion_read_sched_clock, 32, clk_get_rate(clk));
> +
> + /* setup timer1 as clockevent timer */
> + if (setup_irq(irq, &orion_clkevt_irq))
> + panic("%s: unable to setup irq\n", np->name);
> +
> + ticks_per_jiffy = (clk_get_rate(clk) + HZ/2) / HZ;
> + orion_clkevt.cpumask = cpumask_of(0);
> + orion_clkevt.irq = irq;
> + clockevents_config_and_register(&orion_clkevt, clk_get_rate(clk),
> + ORION_ONESHOT_MIN, ORION_ONESHOT_MAX);
> +}
> +CLOCKSOURCE_OF_DECLARE(orion_timer, "marvell,orion-timer", orion_timer_init);
>
--
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs
Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
On 06/10/13 18:04, Daniel Lezcano wrote:
> On 06/10/2013 11:35 AM, Sebastian Hesselbarth wrote:
>> This patch add a DT enabled driver for timers found on Marvell Orion SoCs
>> (Kirkwood, Dove, Orion5x, and Discovery Innovation). It installs a free-
>> running clocksource on timer0 and a clockevent source on timer1.
>> Corresponding device tree documentation is also added.
>>
>> Signed-off-by: Sebastian Hesselbarth <[email protected]>
>
> It looks good for me.
>
> Sebastian,
>
> shall I take it through my tree (it will go to Thomas's tree) ?
Daniel,
I checked MAINTAINERS and thought clocksource, i.e. patch 2/6, would go
through Thomas' or John's tree? If you want to take it, I am fine with
it but guess I am not the one to choose here ;)
Sebastian
On 06/10/2013 06:31 PM, Sebastian Hesselbarth wrote:
> On 06/10/13 18:04, Daniel Lezcano wrote:
>> On 06/10/2013 11:35 AM, Sebastian Hesselbarth wrote:
>>> This patch add a DT enabled driver for timers found on Marvell Orion
>>> SoCs
>>> (Kirkwood, Dove, Orion5x, and Discovery Innovation). It installs a free-
>>> running clocksource on timer0 and a clockevent source on timer1.
>>> Corresponding device tree documentation is also added.
>>>
>>> Signed-off-by: Sebastian Hesselbarth <[email protected]>
>>
>> It looks good for me.
>>
>> Sebastian,
>>
>> shall I take it through my tree (it will go to Thomas's tree) ?
>
> Daniel,
>
> I checked MAINTAINERS and thought clocksource, i.e. patch 2/6, would go
> through Thomas' or John's tree? If you want to take it, I am fine with
> it but guess I am not the one to choose here ;)
Actually, I am giving a hand to John and Thomas. I take the patches for
clockevents (and also for clocksource if both are mixed and John did not
pick it yet) and Thomas pulls from my tree [1].
If there is no dependency with any other patches of your patchset, which
seems to be the case, I will queue it for 3.11.
-- Daniel
[1]
https://git.kernel.org/cgit/linux/kernel/git/tip/tip.git/commit/?h=timers/core&id=762cf9695d714d312ef7369bed1b9f9467c9e64e
--
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs
Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
On 06/10/13 18:44, Daniel Lezcano wrote:
> On 06/10/2013 06:31 PM, Sebastian Hesselbarth wrote:
>> On 06/10/13 18:04, Daniel Lezcano wrote:
>>> On 06/10/2013 11:35 AM, Sebastian Hesselbarth wrote:
>>>> This patch add a DT enabled driver for timers found on Marvell Orion
>>>> SoCs
>>>> (Kirkwood, Dove, Orion5x, and Discovery Innovation). It installs a free-
>>>> running clocksource on timer0 and a clockevent source on timer1.
>>>> Corresponding device tree documentation is also added.
>>>>
>>>> Signed-off-by: Sebastian Hesselbarth <[email protected]>
>>>
>>> It looks good for me.
>>>
>>> Sebastian,
>>>
>>> shall I take it through my tree (it will go to Thomas's tree) ?
>>
>> Daniel,
>>
>> I checked MAINTAINERS and thought clocksource, i.e. patch 2/6, would go
>> through Thomas' or John's tree? If you want to take it, I am fine with
>> it but guess I am not the one to choose here ;)
>
> Actually, I am giving a hand to John and Thomas. I take the patches for
> clockevents (and also for clocksource if both are mixed and John did not
> pick it yet) and Thomas pulls from my tree [1].
>
> If there is no dependency with any other patches of your patchset, which
> seems to be the case, I will queue it for 3.11.
Ok, thanks!
Sebastian
On 06/10/2013 06:47 PM, Sebastian Hesselbarth wrote:
> On 06/10/13 18:44, Daniel Lezcano wrote:
>> On 06/10/2013 06:31 PM, Sebastian Hesselbarth wrote:
>>> On 06/10/13 18:04, Daniel Lezcano wrote:
>>>> On 06/10/2013 11:35 AM, Sebastian Hesselbarth wrote:
>>>>> This patch add a DT enabled driver for timers found on Marvell Orion
>>>>> SoCs
>>>>> (Kirkwood, Dove, Orion5x, and Discovery Innovation). It installs a
>>>>> free-
>>>>> running clocksource on timer0 and a clockevent source on timer1.
>>>>> Corresponding device tree documentation is also added.
>>>>>
>>>>> Signed-off-by: Sebastian Hesselbarth <[email protected]>
>>>>
>>>> It looks good for me.
>>>>
>>>> Sebastian,
>>>>
>>>> shall I take it through my tree (it will go to Thomas's tree) ?
>>>
>>> Daniel,
>>>
>>> I checked MAINTAINERS and thought clocksource, i.e. patch 2/6, would go
>>> through Thomas' or John's tree? If you want to take it, I am fine with
>>> it but guess I am not the one to choose here ;)
>>
>> Actually, I am giving a hand to John and Thomas. I take the patches for
>> clockevents (and also for clocksource if both are mixed and John did not
>> pick it yet) and Thomas pulls from my tree [1].
>>
>> If there is no dependency with any other patches of your patchset, which
>> seems to be the case, I will queue it for 3.11.
>
> Ok, thanks!
I have a lot of ^M in the patch ... dos2unix removed them but I am
wondering how they get there ?
--
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs
Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
On Mon, Jun 10, 2013 at 07:06:38PM +0200, Daniel Lezcano wrote:
> On 06/10/2013 06:47 PM, Sebastian Hesselbarth wrote:
> > On 06/10/13 18:44, Daniel Lezcano wrote:
> >> On 06/10/2013 06:31 PM, Sebastian Hesselbarth wrote:
> >>> On 06/10/13 18:04, Daniel Lezcano wrote:
> >>>> On 06/10/2013 11:35 AM, Sebastian Hesselbarth wrote:
> >>>>> This patch add a DT enabled driver for timers found on Marvell Orion
> >>>>> SoCs
> >>>>> (Kirkwood, Dove, Orion5x, and Discovery Innovation). It installs a
> >>>>> free-
> >>>>> running clocksource on timer0 and a clockevent source on timer1.
> >>>>> Corresponding device tree documentation is also added.
> >>>>>
> >>>>> Signed-off-by: Sebastian Hesselbarth <[email protected]>
> >>>>
> >>>> It looks good for me.
> >>>>
> >>>> Sebastian,
> >>>>
> >>>> shall I take it through my tree (it will go to Thomas's tree) ?
> >>>
> >>> Daniel,
> >>>
> >>> I checked MAINTAINERS and thought clocksource, i.e. patch 2/6, would go
> >>> through Thomas' or John's tree? If you want to take it, I am fine with
> >>> it but guess I am not the one to choose here ;)
> >>
> >> Actually, I am giving a hand to John and Thomas. I take the patches for
> >> clockevents (and also for clocksource if both are mixed and John did not
> >> pick it yet) and Thomas pulls from my tree [1].
> >>
> >> If there is no dependency with any other patches of your patchset, which
> >> seems to be the case, I will queue it for 3.11.
> >
> > Ok, thanks!
>
> I have a lot of ^M in the patch ... dos2unix removed them but I am
> wondering how they get there ?
He sent it with git-send-mail, how are you extracting it from
Thunderbird?
thx,
Jason.
On 06/10/2013 07:09 PM, Jason Cooper wrote:
> On Mon, Jun 10, 2013 at 07:06:38PM +0200, Daniel Lezcano wrote:
>> On 06/10/2013 06:47 PM, Sebastian Hesselbarth wrote:
>>> On 06/10/13 18:44, Daniel Lezcano wrote:
>>>> On 06/10/2013 06:31 PM, Sebastian Hesselbarth wrote:
>>>>> On 06/10/13 18:04, Daniel Lezcano wrote:
>>>>>> On 06/10/2013 11:35 AM, Sebastian Hesselbarth wrote:
>>>>>>> This patch add a DT enabled driver for timers found on Marvell Orion
>>>>>>> SoCs
>>>>>>> (Kirkwood, Dove, Orion5x, and Discovery Innovation). It installs a
>>>>>>> free-
>>>>>>> running clocksource on timer0 and a clockevent source on timer1.
>>>>>>> Corresponding device tree documentation is also added.
>>>>>>>
>>>>>>> Signed-off-by: Sebastian Hesselbarth <[email protected]>
>>>>>>
>>>>>> It looks good for me.
>>>>>>
>>>>>> Sebastian,
>>>>>>
>>>>>> shall I take it through my tree (it will go to Thomas's tree) ?
>>>>>
>>>>> Daniel,
>>>>>
>>>>> I checked MAINTAINERS and thought clocksource, i.e. patch 2/6, would go
>>>>> through Thomas' or John's tree? If you want to take it, I am fine with
>>>>> it but guess I am not the one to choose here ;)
>>>>
>>>> Actually, I am giving a hand to John and Thomas. I take the patches for
>>>> clockevents (and also for clocksource if both are mixed and John did not
>>>> pick it yet) and Thomas pulls from my tree [1].
>>>>
>>>> If there is no dependency with any other patches of your patchset, which
>>>> seems to be the case, I will queue it for 3.11.
>>>
>>> Ok, thanks!
>>
>> I have a lot of ^M in the patch ... dos2unix removed them but I am
>> wondering how they get there ?
>
> He sent it with git-send-mail, how are you extracting it from
> Thunderbird?
I use a script to extract the patch from my mailbox. I am using it for
years now I did not face these spurious characters before.
Anyway, it seems not related to the patch itself, I will handle that.
Thanks
-- Daniel
--
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs
Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
On Mon, Jun 10, 2013 at 11:35:55AM +0200, Sebastian Hesselbarth wrote:
> This patch add a DT enabled driver for timers found on Marvell Orion SoCs
> (Kirkwood, Dove, Orion5x, and Discovery Innovation). It installs a free-
> running clocksource on timer0 and a clockevent source on timer1.
> Corresponding device tree documentation is also added.
>
> Signed-off-by: Sebastian Hesselbarth <[email protected]>
> ---
> Changelog:
> v3->v4:
> - export thread-safe access to TIMER_CTRL register to use with watchdog
> - remove IRQF_DISABLED and add .irq to clock event (Suggested by Daniel Lezcano)
>
> Notes:
> - This is only an update to clocksource driver, the remaining patches are
> not resent as they have not been changed.
> - I will not rework orion watchdog driver for this patch set. It is written
> Kirkwood/Orion5x specific although it will also work on Dove and it is messing
> with shared registers. It has done it before, so I consider it broken anyway.
> I (or somebody else) will take care of proper watchdog later.
> - An updated branch can be found on
> git://github.com/shesselba/linux-dove.git orion-irqchip-for-v3.11_v4
Hi Sebastian
You can add a
Tested-by: Andrew Lunn <[email protected]>
I tested on my kirkwood QNAP.
CPU0
2: 6062 bridge-interrupt-ctrl orion_event
9: 0 f1010140.gpio Reset
15: 0 f1010140.gpio USB Copy
24: 106 main-interrupt-ctrl ehci_hcd:usb1
25: 2463 main-interrupt-ctrl sata_mv
26: 0 main-interrupt-ctrl f1030000.crypto
27: 2 main-interrupt-ctrl f1060800.xor
28: 2 main-interrupt-ctrl f1060800.xor
29: 71 main-interrupt-ctrl mv64xxx_i2c
30: 2 main-interrupt-ctrl f1060900.xor
31: 2 main-interrupt-ctrl f1060900.xor
32: 41 main-interrupt-ctrl eth0
33: 1317 main-interrupt-ctrl serial
75: 745 main-interrupt-ctrl f1072004.mdio-bus
Err: 0
Andrew
On Thu, 6 Jun 2013, Sebastian Hesselbarth wrote:
> This patch set introduces DT-aware irqchip and clocksource drivers for
> Marvell Orion SoCs (Kirkwood, Dove, Orion5x, MV78x00) and corresponding
> patches for Dove and Kirkwood to enable them for DT-boards.
>
> The irqchip driver, of course, depends on Thomas Gleixner's work on
> irqdomain support for generic chip (tip irq/core).
>
> The ARM part of this patch set has a quite ridiculuous dependency havoc
> of mv643xx_eth DT support (current net-next) that will add to both irqchip
> and clocksource branches respectively. Therefore, I suggest that irq
> and clocksource maintainers take in the mere drivers (Patches 1+2) and
> Jason Cooper handles the remaining patches when all three drivers have
> surfaced on mainline linux.
I provided a tip branch irq/for-arm, which contains only these changes
and can be pulled by SoC/subarch maintainers so we don't end up with a
dependency nightmare. Just mention that you pulled it from me when
sending the pull request to Linus.
Thanks,
tglx
On Thu, 6 Jun 2013, Sebastian Hesselbarth wrote:
> This patch adds an irqchip driver for the main interrupt controller found
> on Marvell Orion SoCs (Kirkwood, Dove, Orion5x, Discovery Innovation).
> Corresponding device tree documentation is also added.
>
> Signed-off-by: Sebastian Hesselbarth <[email protected]>
Reviewed-by: Thomas Gleixner <[email protected]>
Hi Sebastian,
On Thu, Jun 06, 2013 at 06:27:08PM +0200, Sebastian Hesselbarth wrote:
> This patch set introduces DT-aware irqchip and clocksource drivers for
> Marvell Orion SoCs (Kirkwood, Dove, Orion5x, MV78x00) and corresponding
> patches for Dove and Kirkwood to enable them for DT-boards.
>
> The irqchip driver, of course, depends on Thomas Gleixner's work on
> irqdomain support for generic chip (tip irq/core).
>
> The ARM part of this patch set has a quite ridiculuous dependency havoc
> of mv643xx_eth DT support (current net-next) that will add to both irqchip
> and clocksource branches respectively. Therefore, I suggest that irq
> and clocksource maintainers take in the mere drivers (Patches 1+2) and
> Jason Cooper handles the remaining patches when all three drivers have
> surfaced on mainline linux.
>
> I prepared a branch for anyone to test on Kirkwood and Dove which takes
> care of the above dependencies based on v3.10-rc4 plus tip irq/core,
> net-next, and arm-soc for-next (I know it is unstable but contains latest
> mvebu related patches already). When Thomas, John, and Jason agree the
> dependencies will vanish and only Jason has to take care of ARM patches
> for enabling DT-based mv643xx_eth, irqchip, and clocksource.
>
> The branch can be found at
>
> git://github.com/shesselba/linux-dove.git orion-irqchip-for-v3.11
>
> and has been tested on Dove/CuBox and compile tested for Kirkwood.
>
> Sebastian Hesselbarth (6):
> irqchip: add support for Marvell Orion SoCs
> clocksource: add Marvell Orion SoC timer
> ARM: dove: move device tree nodes to DT irqchip and clocksource
> ARM: kirkwood: move device tree nodes to DT irqchip and clocksource
> ARM: dove: convert to DT irqchip and clocksource
> ARM: kirkwood: convert to DT irqchip and clocksource
>
I've done some tests on my Kirkwood Openblocks A6 using the latest
branch orion-irqchip-for-v3.11-v4. Everything works fine so:
Tested-by: Ezequiel Garcia <[email protected]>
For patches 3 to 6 I'm wondering if there's any reason why the irqchip and
clocksource changes are not separated. I'm probably being too picky but,
unless you have a good reason for having them together,
I think they should go separated, i.e. patches for irqchip on one side,
and patches for clocksource on the other.
Aside from that, the series looks good. Nice job!
Thanks,
--
Ezequiel GarcĂa, Free Electrons
Embedded Linux, Kernel and Android Engineering
http://free-electrons.com
On 06/11/13 14:35, Ezequiel Garcia wrote:
> On Thu, Jun 06, 2013 at 06:27:08PM +0200, Sebastian Hesselbarth wrote:
>> This patch set introduces DT-aware irqchip and clocksource drivers for
>> Marvell Orion SoCs (Kirkwood, Dove, Orion5x, MV78x00) and corresponding
>> patches for Dove and Kirkwood to enable them for DT-boards.
>>
>> The irqchip driver, of course, depends on Thomas Gleixner's work on
>> irqdomain support for generic chip (tip irq/core).
>>
>> The ARM part of this patch set has a quite ridiculuous dependency havoc
>> of mv643xx_eth DT support (current net-next) that will add to both irqchip
>> and clocksource branches respectively. Therefore, I suggest that irq
>> and clocksource maintainers take in the mere drivers (Patches 1+2) and
>> Jason Cooper handles the remaining patches when all three drivers have
>> surfaced on mainline linux.
>>
[...]
>> Sebastian Hesselbarth (6):
>> irqchip: add support for Marvell Orion SoCs
>> clocksource: add Marvell Orion SoC timer
>> ARM: dove: move device tree nodes to DT irqchip and clocksource
>> ARM: kirkwood: move device tree nodes to DT irqchip and clocksource
>> ARM: dove: convert to DT irqchip and clocksource
>> ARM: kirkwood: convert to DT irqchip and clocksource
>>
>
> I've done some tests on my Kirkwood Openblocks A6 using the latest
> branch orion-irqchip-for-v3.11-v4. Everything works fine so:
>
> Tested-by: Ezequiel Garcia <[email protected]>
Ezequiel, thanks for testing!
> For patches 3 to 6 I'm wondering if there's any reason why the irqchip and
> clocksource changes are not separated. I'm probably being too picky but,
> unless you have a good reason for having them together,
> I think they should go separated, i.e. patches for irqchip on one side,
> and patches for clocksource on the other.
The only reason is that when switching from current non-irqdomain irq
controller to irqdomain-based above, there is no 1:1 mapping between
irq numbers and hwirqs anymore. But you are right, for the ARM part
patches that will be merged first thing when v3.11-rc1 is out, the
correct order is mv643xx_eth, clocksource, irqchip.
I will prepare new, rebased patches for Jason Cooper then anyway.
With Thomas Gleixner's Review now only somebody has to take the irqchip
patch then all three drivers are queued for next release.
Sebastian
On Tue, 11 Jun 2013, Sebastian Hesselbarth wrote:
> On 06/11/13 14:35, Ezequiel Garcia wrote:
> With Thomas Gleixner's Review now only somebody has to take the irqchip
> patch then all three drivers are queued for next release.
I can take it through tip if nobody else wants it :)
On 06/11/13 15:13, Thomas Gleixner wrote:
> On Tue, 11 Jun 2013, Sebastian Hesselbarth wrote:
>> On 06/11/13 14:35, Ezequiel Garcia wrote:
>> With Thomas Gleixner's Review now only somebody has to take the irqchip
>> patch then all three drivers are queued for next release.
>
> I can take it through tip if nobody else wants it :)
Thomas,
I'd appreciate that! Thanks for taking it.
Sebastian
On Tue, 11 Jun 2013, Thomas Gleixner wrote:
> On Thu, 6 Jun 2013, Sebastian Hesselbarth wrote:
>
> > This patch adds an irqchip driver for the main interrupt controller found
> > on Marvell Orion SoCs (Kirkwood, Dove, Orion5x, Discovery Innovation).
> > Corresponding device tree documentation is also added.
> >
> > Signed-off-by: Sebastian Hesselbarth <[email protected]>
>
> Reviewed-by: Thomas Gleixner <[email protected]>
Second thoughts:
>+static void orion_bridge_irq_handler(unsigned int irq, struct irq_desc *desc)
>+{
>+ struct irq_domain *d = irq_get_handler_data(irq);
>+ struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, irq);
>+ u32 stat = readl_relaxed(gc->reg_base + ORION_BRIDGE_IRQ_CAUSE) &
>+ gc->mask_cache;
In init you map the first irq of that chip and install the chain
handler for it. Now if that first irq fires, isn't that set in the
cause register as well? And what acks that first irq?
Thanks,
tglx
On 06/11/13 15:30, Thomas Gleixner wrote:
> On Tue, 11 Jun 2013, Thomas Gleixner wrote:
>
>> On Thu, 6 Jun 2013, Sebastian Hesselbarth wrote:
>>
>>> This patch adds an irqchip driver for the main interrupt controller found
>>> on Marvell Orion SoCs (Kirkwood, Dove, Orion5x, Discovery Innovation).
>>> Corresponding device tree documentation is also added.
>>>
>>> Signed-off-by: Sebastian Hesselbarth <[email protected]>
>>
>> Reviewed-by: Thomas Gleixner <[email protected]>
>
> Second thoughts:
>
>> +static void orion_bridge_irq_handler(unsigned int irq, struct irq_desc *desc)
>> +{
>> + struct irq_domain *d = irq_get_handler_data(irq);
>> + struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, irq);
>> + u32 stat = readl_relaxed(gc->reg_base + ORION_BRIDGE_IRQ_CAUSE) &
>> + gc->mask_cache;
>
> In init you map the first irq of that chip and install the chain
> handler for it. Now if that first irq fires, isn't that set in the
> cause register as well? And what acks that first irq?
It is "acked" by acking all unmasked bridge irqs.
Sebastian
On Tue, 11 Jun 2013, Sebastian Hesselbarth wrote:
> On 06/11/13 15:30, Thomas Gleixner wrote:
> > On Tue, 11 Jun 2013, Thomas Gleixner wrote:
> >
> > > On Thu, 6 Jun 2013, Sebastian Hesselbarth wrote:
> > >
> > > > This patch adds an irqchip driver for the main interrupt controller
> > > > found
> > > > on Marvell Orion SoCs (Kirkwood, Dove, Orion5x, Discovery Innovation).
> > > > Corresponding device tree documentation is also added.
> > > >
> > > > Signed-off-by: Sebastian Hesselbarth <[email protected]>
> > >
> > > Reviewed-by: Thomas Gleixner <[email protected]>
> >
> > Second thoughts:
> >
> > > +static void orion_bridge_irq_handler(unsigned int irq, struct irq_desc
> > > *desc)
> > > +{
> > > + struct irq_domain *d = irq_get_handler_data(irq);
> > > + struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, irq);
> > > + u32 stat = readl_relaxed(gc->reg_base + ORION_BRIDGE_IRQ_CAUSE) &
> > > + gc->mask_cache;
> >
> > In init you map the first irq of that chip and install the chain
> > handler for it. Now if that first irq fires, isn't that set in the
> > cause register as well? And what acks that first irq?
>
> It is "acked" by acking all unmasked bridge irqs.
Ok. A comment would be nice.
But what about the bit in of that first irq in the cause register? If
it's set on entry you call generic_handle_irq() for that as well. So
if it's set you need to mask it in stat. If not, then it wants a
comment.
Thanks,
tglx
On Thu, 6 Jun 2013 18:27:09 +0200, Sebastian Hesselbarth <[email protected]> wrote:
> This patch adds an irqchip driver for the main interrupt controller found
> on Marvell Orion SoCs (Kirkwood, Dove, Orion5x, Discovery Innovation).
> Corresponding device tree documentation is also added.
>
> Signed-off-by: Sebastian Hesselbarth <[email protected]>
Looks reasonable to me.
Acked-by: Grant Likely <[email protected]>
> ---
> Cc: Grant Likely <[email protected]>
> Cc: Rob Herring <[email protected]>
> Cc: Rob Landley <[email protected]>
> Cc: Thomas Gleixner <[email protected]>
> Cc: John Stultz <[email protected]>
> Cc: Russell King <[email protected]>
> Cc: Jason Cooper <[email protected]>
> Cc: Andrew Lunn <[email protected]>
> Cc: Thomas Petazzoni <[email protected]>
> Cc: Gregory Clement <[email protected]>
> Cc: [email protected]
> Cc: [email protected]
> Cc: [email protected]
> Cc: [email protected]
> ---
> .../interrupt-controller/marvell,orion-intc.txt | 48 +++++
> drivers/irqchip/Kconfig | 5 +
> drivers/irqchip/Makefile | 1 +
> drivers/irqchip/irq-orion.c | 193 ++++++++++++++++++++
> 4 files changed, 247 insertions(+), 0 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/interrupt-controller/marvell,orion-intc.txt
> create mode 100644 drivers/irqchip/irq-orion.c
>
> diff --git a/Documentation/devicetree/bindings/interrupt-controller/marvell,orion-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/marvell,orion-intc.txt
> new file mode 100644
> index 0000000..2c11ac7
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/interrupt-controller/marvell,orion-intc.txt
> @@ -0,0 +1,48 @@
> +Marvell Orion SoC interrupt controllers
> +
> +* Main interrupt controller
> +
> +Required properties:
> +- compatible: shall be "marvell,orion-intc"
> +- reg: base address(es) of interrupt registers starting with CAUSE register
> +- interrupt-controller: identifies the node as an interrupt controller
> +- #interrupt-cells: number of cells to encode an interrupt source, shall be 1
> +
> +The interrupt sources map to the corresponding bits in the interrupt
> +registers, i.e.
> +- 0 maps to bit 0 of first base address,
> +- 1 maps to bit 1 of first base address,
> +- 32 maps to bit 0 of second base address, and so on.
> +
> +Example:
> + intc: interrupt-controller {
> + compatible = "marvell,orion-intc";
> + interrupt-controller;
> + #interrupt-cells = <1>;
> + /* Dove has 64 first level interrupts */
> + reg = <0x20200 0x10>, <0x20210 0x10>;
> + };
> +
> +* Bridge interrupt controller
> +
> +Required properties:
> +- compatible: shall be "marvell,orion-bridge-intc"
> +- reg: base address of bridge interrupt registers starting with CAUSE register
> +- interrupts: bridge interrupt of the main interrupt controller
> +- interrupt-controller: identifies the node as an interrupt controller
> +- #interrupt-cells: number of cells to encode an interrupt source, shall be 1
> +
> +Optional properties:
> +- marvell,#interrupts: number of interrupts provided by bridge interrupt
> + controller, defaults to 32 if not set
> +
> +Example:
> + bridge_intc: interrupt-controller {
> + compatible = "marvell,orion-bridge-intc";
> + interrupt-controller;
> + #interrupt-cells = <1>;
> + reg = <0x20110 0x8>;
> + interrupts = <0>;
> + /* Dove bridge provides 5 interrupts */
> + marvell,#interrupts = <5>;
> + };
> diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
> index 4a33351..68c3107 100644
> --- a/drivers/irqchip/Kconfig
> +++ b/drivers/irqchip/Kconfig
> @@ -25,6 +25,11 @@ config ARM_VIC_NR
> The maximum number of VICs available in the system, for
> power management.
>
> +config ORION_IRQCHIP
> + bool
> + select IRQ_DOMAIN
> + select MULTI_IRQ_HANDLER
> +
> config RENESAS_INTC_IRQPIN
> bool
> select IRQ_DOMAIN
> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
> index cda4cb5..55df3bd 100644
> --- a/drivers/irqchip/Makefile
> +++ b/drivers/irqchip/Makefile
> @@ -7,6 +7,7 @@ obj-$(CONFIG_ARCH_MXS) += irq-mxs.o
> obj-$(CONFIG_ARCH_S3C24XX) += irq-s3c24xx.o
> obj-$(CONFIG_METAG) += irq-metag-ext.o
> obj-$(CONFIG_METAG_PERFCOUNTER_IRQS) += irq-metag.o
> +obj-$(CONFIG_ORION_IRQCHIP) += irq-orion.o
> obj-$(CONFIG_ARCH_SUNXI) += irq-sun4i.o
> obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o
> obj-$(CONFIG_ARM_GIC) += irq-gic.o
> diff --git a/drivers/irqchip/irq-orion.c b/drivers/irqchip/irq-orion.c
> new file mode 100644
> index 0000000..693ea20
> --- /dev/null
> +++ b/drivers/irqchip/irq-orion.c
> @@ -0,0 +1,193 @@
> +/*
> + * Marvell Orion SoCs IRQ chip driver.
> + *
> + * Sebastian Hesselbarth <[email protected]>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2. This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#include <linux/io.h>
> +#include <linux/irq.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <asm/exception.h>
> +#include <asm/mach/irq.h>
> +
> +#include "irqchip.h"
> +
> +/*
> + * Orion SoC main interrupt controller
> + */
> +
> +#define ORION_IRQS_PER_CHIP 32
> +
> +#define ORION_IRQ_CAUSE 0x00
> +#define ORION_IRQ_MASK 0x04
> +#define ORION_IRQ_FIQ_MASK 0x08
> +#define ORION_IRQ_ENDP_MASK 0x0c
> +
> +static struct irq_domain *orion_irq_domain;
> +
> +static asmlinkage void __exception_irq_entry orion_handle_irq(
> + struct pt_regs *regs)
> +{
> + struct irq_domain_chip_generic *dgc = orion_irq_domain->gc;
> + int n, base = 0;
> +
> + for (n = 0; n < dgc->num_chips; n++, base += ORION_IRQS_PER_CHIP) {
> + struct irq_chip_generic *gc =
> + irq_get_domain_generic_chip(orion_irq_domain, base);
> + u32 stat = readl_relaxed(gc->reg_base + ORION_IRQ_CAUSE) &
> + gc->mask_cache;
> + while (stat) {
> + u32 hwirq = ffs(stat) - 1;
> + u32 irq = irq_find_mapping(orion_irq_domain,
> + gc->irq_base + hwirq);
> + handle_IRQ(irq, regs);
> + stat &= ~(1 << hwirq);
> + }
> + }
> +}
> +
> +static int __init orion_irq_init(struct device_node *np,
> + struct device_node *parent)
> +{
> + unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
> + struct resource r;
> + int n, ret, base, num_chips = 0;
> +
> + /* count number of irq chips by valid reg addresses */
> + while (of_address_to_resource(np, num_chips, &r) == 0)
> + num_chips++;
> +
> + orion_irq_domain = irq_domain_add_linear(np,
> + num_chips * ORION_IRQS_PER_CHIP,
> + &irq_generic_chip_ops, NULL);
> + if (!orion_irq_domain)
> + panic("%s: unable to add irq domain\n", np->name);
> +
> + ret = irq_alloc_domain_generic_chips(orion_irq_domain,
> + ORION_IRQS_PER_CHIP, 1, np->name,
> + handle_level_irq, clr, 0,
> + IRQ_GC_INIT_MASK_CACHE);
> + if (ret)
> + panic("%s: unable to alloc irq domain gc\n", np->name);
> +
> + for (n = 0, base = 0; n < num_chips; n++, base += ORION_IRQS_PER_CHIP) {
> + struct irq_chip_generic *gc =
> + irq_get_domain_generic_chip(orion_irq_domain, base);
> +
> + of_address_to_resource(np, n, &r);
> +
> + if (!request_mem_region(r.start, resource_size(&r), np->name))
> + panic("%s: unable to request mem region %d",
> + np->name, n);
> +
> + gc->reg_base = ioremap(r.start, resource_size(&r));
> + if (!gc->reg_base)
> + panic("%s: unable to map resource %d", np->name, n);
> +
> + gc->chip_types[0].regs.mask = ORION_IRQ_MASK;
> + gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
> + gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
> +
> + /* mask all interrupts */
> + writel(0, gc->reg_base + ORION_IRQ_MASK);
> + }
> +
> + set_handle_irq(orion_handle_irq);
> +
> + return 0;
> +}
> +IRQCHIP_DECLARE(orion_intc, "marvell,orion-intc", orion_irq_init);
> +
> +/*
> + * Orion SoC bridge interrupt controller
> + */
> +
> +#define ORION_BRIDGE_IRQ_CAUSE 0x00
> +#define ORION_BRIDGE_IRQ_MASK 0x04
> +
> +static void orion_bridge_irq_handler(unsigned int irq, struct irq_desc *desc)
> +{
> + struct irq_domain *d = irq_get_handler_data(irq);
> + struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, irq);
> + u32 stat = readl_relaxed(gc->reg_base + ORION_BRIDGE_IRQ_CAUSE) &
> + gc->mask_cache;
> +
> + while (stat) {
> + u32 hwirq = ffs(stat) - 1;
> + generic_handle_irq(irq_find_mapping(d, gc->irq_base + hwirq));
> + stat &= ~(1 << hwirq);
> + }
> +}
> +
> +static int __init orion_bridge_irq_init(struct device_node *np,
> + struct device_node *parent)
> +{
> + unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
> + struct resource r;
> + struct irq_domain *domain;
> + struct irq_chip_generic *gc;
> + int ret, irq, nrirqs = 32;
> +
> + /* get optional number of interrupts provided */
> + of_property_read_u32(np, "marvell,#interrupts", &nrirqs);
> +
> + domain = irq_domain_add_linear(np, nrirqs,
> + &irq_generic_chip_ops, NULL);
> + if (!domain) {
> + pr_err("%s: unable to add irq domain\n", np->name);
> + return -ENOMEM;
> + }
> +
> + ret = irq_alloc_domain_generic_chips(domain, nrirqs, 1, np->name,
> + handle_level_irq, clr, 0, IRQ_GC_INIT_MASK_CACHE);
> + if (ret) {
> + pr_err("%s: unable to alloc irq domain gc\n", np->name);
> + return ret;
> + }
> +
> + ret = of_address_to_resource(np, 0, &r);
> + if (ret) {
> + pr_err("%s: unable to get resource\n", np->name);
> + return ret;
> + }
> +
> + if (!request_mem_region(r.start, resource_size(&r), np->name)) {
> + pr_err("%s: unable to request mem region\n", np->name);
> + return -ENOMEM;
> + }
> +
> + irq = irq_of_parse_and_map(np, 0);
> + if (irq <= 0) {
> + pr_err("%s: unable to parse irq\n", np->name);
> + return -EINVAL;
> + }
> +
> + gc = irq_get_domain_generic_chip(domain, 0);
> + gc->reg_base = ioremap(r.start, resource_size(&r));
> + if (!gc->reg_base) {
> + pr_err("%s: unable to map resource\n", np->name);
> + return -ENOMEM;
> + }
> +
> + gc->chip_types[0].regs.ack = ORION_BRIDGE_IRQ_CAUSE;
> + gc->chip_types[0].regs.mask = ORION_BRIDGE_IRQ_MASK;
> + gc->chip_types[0].chip.irq_ack = irq_gc_ack_clr_bit;
> + gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
> + gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
> +
> + /* mask all interrupts */
> + writel(0, gc->reg_base + ORION_BRIDGE_IRQ_MASK);
> +
> + irq_set_handler_data(irq, domain);
> + irq_set_chained_handler(irq, orion_bridge_irq_handler);
> +
> + return 0;
> +}
> +IRQCHIP_DECLARE(orion_bridge_intc,
> + "marvell,orion-bridge-intc", orion_bridge_irq_init);
> --
> 1.7.2.5
>
--
Grant Likely, B.Sc, P.Eng.
Secret Lab Technologies, Ltd.
On 06/11/13 15:45, Thomas Gleixner wrote:
> On Tue, 11 Jun 2013, Sebastian Hesselbarth wrote:
>> On 06/11/13 15:30, Thomas Gleixner wrote:
>>> On Tue, 11 Jun 2013, Thomas Gleixner wrote:
>>>> On Thu, 6 Jun 2013, Sebastian Hesselbarth wrote:
>>>>> This patch adds an irqchip driver for the main interrupt controller
>>>>> found
>>>>> on Marvell Orion SoCs (Kirkwood, Dove, Orion5x, Discovery Innovation).
>>>>> Corresponding device tree documentation is also added.
>>>>>
>>>>> Signed-off-by: Sebastian Hesselbarth <[email protected]>
>>>>
>>>> Reviewed-by: Thomas Gleixner <[email protected]>
>>>
>>> Second thoughts:
>>>
>>>> +static void orion_bridge_irq_handler(unsigned int irq, struct irq_desc
>>>> *desc)
>>>> +{
>>>> + struct irq_domain *d = irq_get_handler_data(irq);
>>>> + struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, irq);
>>>> + u32 stat = readl_relaxed(gc->reg_base + ORION_BRIDGE_IRQ_CAUSE) &
>>>> + gc->mask_cache;
>>>
>>> In init you map the first irq of that chip and install the chain
>>> handler for it. Now if that first irq fires, isn't that set in the
>>> cause register as well? And what acks that first irq?
>>
>> It is "acked" by acking all unmasked bridge irqs.
>
> Ok. A comment would be nice.
>
> But what about the bit in of that first irq in the cause register? If
> it's set on entry you call generic_handle_irq() for that as well. So
> if it's set you need to mask it in stat. If not, then it wants a
> comment.
I am not sure I can follow. orion_bridge_irq_init() maps the first
parent irq, i.e. hwirq 0 of orion_irq. The parent irq controller
clears that irq cause when all corresponding chained irqs are
cleared. The chained (bridge) irqs are cleared by
orion_bridge_irq_handler above.
I can put a note to the parent irqchip in orion_irq_init() that we
don't need to clear its cause register, if it is that what you mean?
Sebastian
On Tue, 11 Jun 2013, Sebastian Hesselbarth wrote:
> On 06/11/13 15:45, Thomas Gleixner wrote:
> > But what about the bit in of that first irq in the cause register? If
> > it's set on entry you call generic_handle_irq() for that as well. So
> > if it's set you need to mask it in stat. If not, then it wants a
> > comment.
>
> I am not sure I can follow. orion_bridge_irq_init() maps the first
> parent irq, i.e. hwirq 0 of orion_irq. The parent irq controller
> clears that irq cause when all corresponding chained irqs are
> cleared. The chained (bridge) irqs are cleared by
> orion_bridge_irq_handler above.
That makes sense. I got confused by:
irq = irq_of_parse_and_map(np, 0);
but now I see that it's mapping irq 0 of the parent interrupt
controller. I'll add a comment before merging it.
Thanks,
tglx
On 06/11/13 16:13, Thomas Gleixner wrote:
> On Tue, 11 Jun 2013, Sebastian Hesselbarth wrote:
>> On 06/11/13 15:45, Thomas Gleixner wrote:
>>> But what about the bit in of that first irq in the cause register? If
>>> it's set on entry you call generic_handle_irq() for that as well. So
>>> if it's set you need to mask it in stat. If not, then it wants a
>>> comment.
>>
>> I am not sure I can follow. orion_bridge_irq_init() maps the first
>> parent irq, i.e. hwirq 0 of orion_irq. The parent irq controller
>> clears that irq cause when all corresponding chained irqs are
>> cleared. The chained (bridge) irqs are cleared by
>> orion_bridge_irq_handler above.
>
> That makes sense. I got confused by:
>
> irq = irq_of_parse_and_map(np, 0);
>
> but now I see that it's mapping irq 0 of the parent interrupt
> controller. I'll add a comment before merging it.
Great! Just to be sure: Please make that comment refer to just
"parent interrupt" but not specifically "parent interrupt 0".
It is 0 only for Dove, and irq_of_parse_and_map(np, 0) maps the
first passed irq.
Sebastian
On Tue, Jun 11, 2013 at 03:13:16PM +0200, Thomas Gleixner wrote:
> On Tue, 11 Jun 2013, Sebastian Hesselbarth wrote:
> > On 06/11/13 14:35, Ezequiel Garcia wrote:
> > With Thomas Gleixner's Review now only somebody has to take the irqchip
> > patch then all three drivers are queued for next release.
>
> I can take it through tip if nobody else wants it :)
Great! I'll queue up 3-6 for the next merge window. That way we avoid
all branch dependencies. :)
thx,
Jason.
Commit-ID: 9dbd90f17e4f380593ec5194c2a4d5e52c5f72d1
Gitweb: http://git.kernel.org/tip/9dbd90f17e4f380593ec5194c2a4d5e52c5f72d1
Author: Sebastian Hesselbarth <[email protected]>
AuthorDate: Thu, 6 Jun 2013 18:27:09 +0200
Committer: Thomas Gleixner <[email protected]>
CommitDate: Tue, 11 Jun 2013 16:18:50 +0200
irqchip: Add support for Marvell Orion SoCs
This patch adds an irqchip driver for the main interrupt controller found
on Marvell Orion SoCs (Kirkwood, Dove, Orion5x, Discovery Innovation).
Corresponding device tree documentation is also added.
Signed-off-by: Sebastian Hesselbarth <[email protected]>
Acked-by: Grant Likely <[email protected]>
Cc: Rob Herring <[email protected]>
Cc: Rob Landley <[email protected]>
Cc: John Stultz <[email protected]>
Cc: Russell King <[email protected]>
Cc: Jason Cooper <[email protected]>
Cc: Andrew Lunn <[email protected]>
Cc: Thomas Petazzoni <[email protected]>
Cc: Gregory Clement <[email protected]>
Cc: [email protected]
Cc: [email protected]
Link: http://lkml.kernel.org/r/1370536034-23956-2-git-send-email-sebastian.hesselbarth@gmail.com
Signed-off-by: Thomas Gleixner <[email protected]>
---
.../interrupt-controller/marvell,orion-intc.txt | 48 ++++++
drivers/irqchip/Kconfig | 5 +
drivers/irqchip/Makefile | 1 +
drivers/irqchip/irq-orion.c | 192 +++++++++++++++++++++
4 files changed, 246 insertions(+)
diff --git a/Documentation/devicetree/bindings/interrupt-controller/marvell,orion-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/marvell,orion-intc.txt
new file mode 100644
index 0000000..2c11ac7
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/marvell,orion-intc.txt
@@ -0,0 +1,48 @@
+Marvell Orion SoC interrupt controllers
+
+* Main interrupt controller
+
+Required properties:
+- compatible: shall be "marvell,orion-intc"
+- reg: base address(es) of interrupt registers starting with CAUSE register
+- interrupt-controller: identifies the node as an interrupt controller
+- #interrupt-cells: number of cells to encode an interrupt source, shall be 1
+
+The interrupt sources map to the corresponding bits in the interrupt
+registers, i.e.
+- 0 maps to bit 0 of first base address,
+- 1 maps to bit 1 of first base address,
+- 32 maps to bit 0 of second base address, and so on.
+
+Example:
+ intc: interrupt-controller {
+ compatible = "marvell,orion-intc";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ /* Dove has 64 first level interrupts */
+ reg = <0x20200 0x10>, <0x20210 0x10>;
+ };
+
+* Bridge interrupt controller
+
+Required properties:
+- compatible: shall be "marvell,orion-bridge-intc"
+- reg: base address of bridge interrupt registers starting with CAUSE register
+- interrupts: bridge interrupt of the main interrupt controller
+- interrupt-controller: identifies the node as an interrupt controller
+- #interrupt-cells: number of cells to encode an interrupt source, shall be 1
+
+Optional properties:
+- marvell,#interrupts: number of interrupts provided by bridge interrupt
+ controller, defaults to 32 if not set
+
+Example:
+ bridge_intc: interrupt-controller {
+ compatible = "marvell,orion-bridge-intc";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0x20110 0x8>;
+ interrupts = <0>;
+ /* Dove bridge provides 5 interrupts */
+ marvell,#interrupts = <5>;
+ };
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 4a33351..68c3107 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -25,6 +25,11 @@ config ARM_VIC_NR
The maximum number of VICs available in the system, for
power management.
+config ORION_IRQCHIP
+ bool
+ select IRQ_DOMAIN
+ select MULTI_IRQ_HANDLER
+
config RENESAS_INTC_IRQPIN
bool
select IRQ_DOMAIN
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index cda4cb5..55df3bd 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_ARCH_MXS) += irq-mxs.o
obj-$(CONFIG_ARCH_S3C24XX) += irq-s3c24xx.o
obj-$(CONFIG_METAG) += irq-metag-ext.o
obj-$(CONFIG_METAG_PERFCOUNTER_IRQS) += irq-metag.o
+obj-$(CONFIG_ORION_IRQCHIP) += irq-orion.o
obj-$(CONFIG_ARCH_SUNXI) += irq-sun4i.o
obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o
obj-$(CONFIG_ARM_GIC) += irq-gic.o
diff --git a/drivers/irqchip/irq-orion.c b/drivers/irqchip/irq-orion.c
new file mode 100644
index 0000000..e51d400
--- /dev/null
+++ b/drivers/irqchip/irq-orion.c
@@ -0,0 +1,192 @@
+/*
+ * Marvell Orion SoCs IRQ chip driver.
+ *
+ * Sebastian Hesselbarth <[email protected]>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <asm/exception.h>
+#include <asm/mach/irq.h>
+
+#include "irqchip.h"
+
+/*
+ * Orion SoC main interrupt controller
+ */
+#define ORION_IRQS_PER_CHIP 32
+
+#define ORION_IRQ_CAUSE 0x00
+#define ORION_IRQ_MASK 0x04
+#define ORION_IRQ_FIQ_MASK 0x08
+#define ORION_IRQ_ENDP_MASK 0x0c
+
+static struct irq_domain *orion_irq_domain;
+
+static asmlinkage void
+__exception_irq_entry orion_handle_irq(struct pt_regs *regs)
+{
+ struct irq_domain_chip_generic *dgc = orion_irq_domain->gc;
+ int n, base = 0;
+
+ for (n = 0; n < dgc->num_chips; n++, base += ORION_IRQS_PER_CHIP) {
+ struct irq_chip_generic *gc =
+ irq_get_domain_generic_chip(orion_irq_domain, base);
+ u32 stat = readl_relaxed(gc->reg_base + ORION_IRQ_CAUSE) &
+ gc->mask_cache;
+ while (stat) {
+ u32 hwirq = ffs(stat) - 1;
+ u32 irq = irq_find_mapping(orion_irq_domain,
+ gc->irq_base + hwirq);
+ handle_IRQ(irq, regs);
+ stat &= ~(1 << hwirq);
+ }
+ }
+}
+
+static int __init orion_irq_init(struct device_node *np,
+ struct device_node *parent)
+{
+ unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
+ int n, ret, base, num_chips = 0;
+ struct resource r;
+
+ /* count number of irq chips by valid reg addresses */
+ while (of_address_to_resource(np, num_chips, &r) == 0)
+ num_chips++;
+
+ orion_irq_domain = irq_domain_add_linear(np,
+ num_chips * ORION_IRQS_PER_CHIP,
+ &irq_generic_chip_ops, NULL);
+ if (!orion_irq_domain)
+ panic("%s: unable to add irq domain\n", np->name);
+
+ ret = irq_alloc_domain_generic_chips(orion_irq_domain,
+ ORION_IRQS_PER_CHIP, 1, np->name,
+ handle_level_irq, clr, 0,
+ IRQ_GC_INIT_MASK_CACHE);
+ if (ret)
+ panic("%s: unable to alloc irq domain gc\n", np->name);
+
+ for (n = 0, base = 0; n < num_chips; n++, base += ORION_IRQS_PER_CHIP) {
+ struct irq_chip_generic *gc =
+ irq_get_domain_generic_chip(orion_irq_domain, base);
+
+ of_address_to_resource(np, n, &r);
+
+ if (!request_mem_region(r.start, resource_size(&r), np->name))
+ panic("%s: unable to request mem region %d",
+ np->name, n);
+
+ gc->reg_base = ioremap(r.start, resource_size(&r));
+ if (!gc->reg_base)
+ panic("%s: unable to map resource %d", np->name, n);
+
+ gc->chip_types[0].regs.mask = ORION_IRQ_MASK;
+ gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
+ gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
+
+ /* mask all interrupts */
+ writel(0, gc->reg_base + ORION_IRQ_MASK);
+ }
+
+ set_handle_irq(orion_handle_irq);
+ return 0;
+}
+IRQCHIP_DECLARE(orion_intc, "marvell,orion-intc", orion_irq_init);
+
+/*
+ * Orion SoC bridge interrupt controller
+ */
+#define ORION_BRIDGE_IRQ_CAUSE 0x00
+#define ORION_BRIDGE_IRQ_MASK 0x04
+
+static void orion_bridge_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+ struct irq_domain *d = irq_get_handler_data(irq);
+ struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, irq);
+ u32 stat = readl_relaxed(gc->reg_base + ORION_BRIDGE_IRQ_CAUSE) &
+ gc->mask_cache;
+
+ while (stat) {
+ u32 hwirq = ffs(stat) - 1;
+
+ generic_handle_irq(irq_find_mapping(d, gc->irq_base + hwirq));
+ stat &= ~(1 << hwirq);
+ }
+}
+
+static int __init orion_bridge_irq_init(struct device_node *np,
+ struct device_node *parent)
+{
+ unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
+ struct resource r;
+ struct irq_domain *domain;
+ struct irq_chip_generic *gc;
+ int ret, irq, nrirqs = 32;
+
+ /* get optional number of interrupts provided */
+ of_property_read_u32(np, "marvell,#interrupts", &nrirqs);
+
+ domain = irq_domain_add_linear(np, nrirqs,
+ &irq_generic_chip_ops, NULL);
+ if (!domain) {
+ pr_err("%s: unable to add irq domain\n", np->name);
+ return -ENOMEM;
+ }
+
+ ret = irq_alloc_domain_generic_chips(domain, nrirqs, 1, np->name,
+ handle_level_irq, clr, 0, IRQ_GC_INIT_MASK_CACHE);
+ if (ret) {
+ pr_err("%s: unable to alloc irq domain gc\n", np->name);
+ return ret;
+ }
+
+ ret = of_address_to_resource(np, 0, &r);
+ if (ret) {
+ pr_err("%s: unable to get resource\n", np->name);
+ return ret;
+ }
+
+ if (!request_mem_region(r.start, resource_size(&r), np->name)) {
+ pr_err("%s: unable to request mem region\n", np->name);
+ return -ENOMEM;
+ }
+
+ /* Map the parent interrupt for the chained handler */
+ irq = irq_of_parse_and_map(np, 0);
+ if (irq <= 0) {
+ pr_err("%s: unable to parse irq\n", np->name);
+ return -EINVAL;
+ }
+
+ gc = irq_get_domain_generic_chip(domain, 0);
+ gc->reg_base = ioremap(r.start, resource_size(&r));
+ if (!gc->reg_base) {
+ pr_err("%s: unable to map resource\n", np->name);
+ return -ENOMEM;
+ }
+
+ gc->chip_types[0].regs.ack = ORION_BRIDGE_IRQ_CAUSE;
+ gc->chip_types[0].regs.mask = ORION_BRIDGE_IRQ_MASK;
+ gc->chip_types[0].chip.irq_ack = irq_gc_ack_clr_bit;
+ gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
+ gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
+
+ /* mask all interrupts */
+ writel(0, gc->reg_base + ORION_BRIDGE_IRQ_MASK);
+
+ irq_set_handler_data(irq, domain);
+ irq_set_chained_handler(irq, orion_bridge_irq_handler);
+
+ return 0;
+}
+IRQCHIP_DECLARE(orion_bridge_intc,
+ "marvell,orion-bridge-intc", orion_bridge_irq_init);