2013-03-20 22:54:30

by Rob Herring

[permalink] [raw]
Subject: [PATCH 00/11] sp804 and integrator timer CLKSRC_OF support

From: Rob Herring <[email protected]>

This series add device-tree support using CLKSRC_OF for initialization
of integrator ap and cp timers and sp804 timers. The timer code for all
of these is moved to drivers/clocksource. The common DT based
initialization of sp804 is supported on highbank, versatile-ab and
vexpress. The DT init support is newly added for versatile-ab.

This series is dependent on my CLKSRC_OF clean-up in arm-soc, my
sched_clock selection series[1], and Arnd's default machine descriptor
patch (for default clocksource_of_init call). The full series is
available here:

git://sources.calxeda.com/kernel/linux.git arm-timers

http://sources.calxeda.com/gitweb/?p=kernel/linux.git;a=shortlog;h=refs/heads/arm-timers

I've tested integrator and versatile on qemu and on highbank h/w.

Rob

[1] http://comments.gmane.org/gmane.linux.ports.arm.kernel/222282

Haojian Zhuang (1):
devtree: add binding documentation for sp804

Rob Herring (10):
OF: add empty of_device_is_available for !OF
ARM: remove extra timer-sp control register clearing
ARM: timer-sp: convert to use CLKSRC_OF init
ARM: highbank: use OF init for sp804 timer
ARM: vexpress: remove sp804 OF init
ARM: dts: vexpress: disable CA9 core tile sp804 timer
ARM: versatile: add versatile dtbs to dtbs target
ARM: versatile: use OF init for sp804 timer
ARM: integrator-cp: convert use CLKSRC_OF for timer init
ARM: move sp804 and integrator timers to drivers/clocksource

.../devicetree/bindings/timer/arm,sp804.txt | 29 +++
arch/arm/Kconfig | 5 -
arch/arm/boot/dts/Makefile | 2 +
arch/arm/boot/dts/integratorcp.dts | 6 +-
arch/arm/boot/dts/versatile-ab.dts | 12 ++
arch/arm/boot/dts/vexpress-v2p-ca9.dts | 1 +
arch/arm/common/Makefile | 1 -
arch/arm/include/asm/hardware/timer-sp.h | 15 --
arch/arm/mach-highbank/highbank.c | 19 --
arch/arm/mach-integrator/Kconfig | 1 +
arch/arm/mach-integrator/integrator_ap.c | 173 +-----------------
arch/arm/mach-integrator/integrator_cp.c | 42 +----
arch/arm/mach-realview/core.c | 12 +-
arch/arm/mach-versatile/core.c | 37 ++--
arch/arm/mach-versatile/versatile_dt.c | 1 -
arch/arm/mach-vexpress/ct-ca9x4.c | 4 +-
arch/arm/mach-vexpress/v2m.c | 17 +-
drivers/clocksource/Kconfig | 12 ++
drivers/clocksource/Makefile | 2 +
.../hardware => drivers/clocksource}/arm_timer.h | 6 +-
drivers/clocksource/integrator_ap_timer.c | 190 ++++++++++++++++++++
.../arm/common => drivers/clocksource}/timer-sp.c | 132 ++++++++++++--
include/clocksource/integrator_ap_timer.h | 7 +
include/clocksource/timer-sp.h | 31 ++++
include/linux/of.h | 5 +
25 files changed, 429 insertions(+), 333 deletions(-)
create mode 100644 Documentation/devicetree/bindings/timer/arm,sp804.txt
delete mode 100644 arch/arm/include/asm/hardware/timer-sp.h
rename {arch/arm/include/asm/hardware => drivers/clocksource}/arm_timer.h (89%)
create mode 100644 drivers/clocksource/integrator_ap_timer.c
rename {arch/arm/common => drivers/clocksource}/timer-sp.c (60%)
create mode 100644 include/clocksource/integrator_ap_timer.h
create mode 100644 include/clocksource/timer-sp.h

--
1.7.10.4


2013-03-20 22:54:33

by Rob Herring

[permalink] [raw]
Subject: [PATCH 01/11] OF: add empty of_device_is_available for !OF

From: Rob Herring <[email protected]>

Add an empty version of of_device_is_available.

Signed-off-by: Rob Herring <[email protected]>
---
include/linux/of.h | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/include/linux/of.h b/include/linux/of.h
index a0f1292..6fe655b 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -379,6 +379,11 @@ static inline int of_device_is_compatible(const struct device_node *device,
return 0;
}

+static inline int of_device_is_available(const struct device_node *device,)
+{
+ return 0;
+}
+
static inline struct property *of_find_property(const struct device_node *np,
const char *name,
int *lenp)
--
1.7.10.4

2013-03-20 22:54:42

by Rob Herring

[permalink] [raw]
Subject: [PATCH 10/11] ARM: move sp804 and integrator timers to drivers/clocksource

From: Rob Herring <[email protected]>

Move timer-sp and integrator-ap timer code to drivers/clocksource and
update timer-sp.h and arm_timer.h includes.

This adds CLKSRC_OF support for the integrator-ap timer and removes the
use of "arm,timer-primary" and "arm,timer-secondary" aliases. The timer
selection should not be important as all 3 timers are equal capability.

Signed-off-by: Rob Herring <[email protected]>
Cc: Russell King <[email protected]>
Cc: John Stultz <[email protected]>
Cc: Thomas Gleixner <[email protected]>
---
arch/arm/Kconfig | 6 -
arch/arm/common/Makefile | 1 -
arch/arm/mach-integrator/Kconfig | 1 +
arch/arm/mach-integrator/integrator_ap.c | 169 +----------------
arch/arm/mach-integrator/integrator_cp.c | 3 +-
arch/arm/mach-realview/core.c | 3 +-
arch/arm/mach-versatile/core.c | 2 +-
arch/arm/mach-vexpress/ct-ca9x4.c | 4 +-
arch/arm/mach-vexpress/v2m.c | 3 +-
drivers/clocksource/Kconfig | 12 ++
drivers/clocksource/Makefile | 2 +
.../hardware => drivers/clocksource}/arm_timer.h | 6 +-
drivers/clocksource/integrator_ap_timer.c | 190 ++++++++++++++++++++
.../arm/common => drivers/clocksource}/timer-sp.c | 9 +-
include/clocksource/integrator_ap_timer.h | 7 +
.../hardware => include/clocksource}/timer-sp.h | 8 +
16 files changed, 232 insertions(+), 194 deletions(-)
rename {arch/arm/include/asm/hardware => drivers/clocksource}/arm_timer.h (89%)
create mode 100644 drivers/clocksource/integrator_ap_timer.c
rename {arch/arm/common => drivers/clocksource}/timer-sp.c (98%)
create mode 100644 include/clocksource/integrator_ap_timer.h
rename {arch/arm/include/asm/hardware => include/clocksource}/timer-sp.h (84%)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 774131a..46970d7 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1169,12 +1169,6 @@ config PLAT_PXA
config PLAT_VERSATILE
bool

-config ARM_TIMER_SP804
- bool
- select CLKSRC_MMIO
- select CLKSRC_OF if OF
- select HAVE_SCHED_CLOCK
-
source arch/arm/mm/Kconfig

config ARM_NR_BANKS
diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile
index dc8dd0d..5a4cc1a 100644
--- a/arch/arm/common/Makefile
+++ b/arch/arm/common/Makefile
@@ -10,4 +10,3 @@ obj-$(CONFIG_SHARP_LOCOMO) += locomo.o
obj-$(CONFIG_SHARP_PARAM) += sharpsl_param.o
obj-$(CONFIG_SHARP_SCOOP) += scoop.o
obj-$(CONFIG_PCI_HOST_ITE8152) += it8152.o
-obj-$(CONFIG_ARM_TIMER_SP804) += timer-sp.o
diff --git a/arch/arm/mach-integrator/Kconfig b/arch/arm/mach-integrator/Kconfig
index abeff25..c5e4ff3 100644
--- a/arch/arm/mach-integrator/Kconfig
+++ b/arch/arm/mach-integrator/Kconfig
@@ -5,6 +5,7 @@ menu "Integrator Options"
config ARCH_INTEGRATOR_AP
bool "Support Integrator/AP and Integrator/PP2 platforms"
select CLKSRC_MMIO
+ select INTEGRATOR_AP_TIMER
select MIGHT_HAVE_PCI
select SERIAL_AMBA_PL010
select SERIAL_AMBA_PL010_CONSOLE
diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c
index 4cb322d..6b5f540 100644
--- a/arch/arm/mach-integrator/integrator_ap.c
+++ b/arch/arm/mach-integrator/integrator_ap.c
@@ -27,8 +27,6 @@
#include <linux/syscore_ops.h>
#include <linux/amba/bus.h>
#include <linux/amba/kmi.h>
-#include <linux/clocksource.h>
-#include <linux/clockchips.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irqchip/versatile-fpga.h>
@@ -41,15 +39,14 @@
#include <linux/stat.h>
#include <linux/sys_soc.h>
#include <linux/termios.h>
+#include <clocksource/integrator_ap_timer.h>
#include <video/vga.h>

#include <mach/hardware.h>
#include <mach/platform.h>
-#include <asm/hardware/arm_timer.h>
#include <asm/setup.h>
#include <asm/param.h> /* HZ */
#include <asm/mach-types.h>
-#include <asm/sched_clock.h>

#include <mach/lm.h>
#include <mach/irqs.h>
@@ -58,7 +55,6 @@
#include <asm/mach/irq.h>
#include <asm/mach/map.h>
#include <asm/mach/pci.h>
-#include <asm/mach/time.h>

#include "common.h"

@@ -296,174 +292,12 @@ struct amba_pl010_data ap_uart_data = {
#define TIMER1_VA_BASE __io_address(INTEGRATOR_TIMER1_BASE)
#define TIMER2_VA_BASE __io_address(INTEGRATOR_TIMER2_BASE)

-static unsigned long timer_reload;
-
-static u32 notrace integrator_read_sched_clock(void)
-{
- return -readl((void __iomem *) TIMER2_VA_BASE + TIMER_VALUE);
-}
-
-static void integrator_clocksource_init(unsigned long inrate,
- void __iomem *base)
-{
- u32 ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC;
- unsigned long rate = inrate;
-
- if (rate >= 1500000) {
- rate /= 16;
- ctrl |= TIMER_CTRL_DIV16;
- }
-
- writel(0xffff, base + TIMER_LOAD);
- writel(ctrl, base + TIMER_CTRL);
-
- clocksource_mmio_init(base + TIMER_VALUE, "timer2",
- rate, 200, 16, clocksource_mmio_readl_down);
- setup_sched_clock(integrator_read_sched_clock, 16, rate);
-}
-
-static void __iomem * clkevt_base;
-
-/*
- * IRQ handler for the timer
- */
-static irqreturn_t integrator_timer_interrupt(int irq, void *dev_id)
-{
- struct clock_event_device *evt = dev_id;
-
- /* clear the interrupt */
- writel(1, clkevt_base + TIMER_INTCLR);
-
- evt->event_handler(evt);
-
- return IRQ_HANDLED;
-}
-
-static void clkevt_set_mode(enum clock_event_mode mode, struct clock_event_device *evt)
-{
- u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE;
-
- /* Disable timer */
- writel(ctrl, clkevt_base + TIMER_CTRL);
-
- switch (mode) {
- case CLOCK_EVT_MODE_PERIODIC:
- /* Enable the timer and start the periodic tick */
- writel(timer_reload, clkevt_base + TIMER_LOAD);
- ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
- writel(ctrl, clkevt_base + TIMER_CTRL);
- break;
- case CLOCK_EVT_MODE_ONESHOT:
- /* Leave the timer disabled, .set_next_event will enable it */
- ctrl &= ~TIMER_CTRL_PERIODIC;
- writel(ctrl, clkevt_base + TIMER_CTRL);
- break;
- case CLOCK_EVT_MODE_UNUSED:
- case CLOCK_EVT_MODE_SHUTDOWN:
- case CLOCK_EVT_MODE_RESUME:
- default:
- /* Just leave in disabled state */
- break;
- }
-
-}
-
-static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt)
-{
- unsigned long ctrl = readl(clkevt_base + TIMER_CTRL);
-
- writel(ctrl & ~TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL);
- writel(next, clkevt_base + TIMER_LOAD);
- writel(ctrl | TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL);
-
- return 0;
-}
-
-static struct clock_event_device integrator_clockevent = {
- .name = "timer1",
- .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
- .set_mode = clkevt_set_mode,
- .set_next_event = clkevt_set_next_event,
- .rating = 300,
-};
-
-static struct irqaction integrator_timer_irq = {
- .name = "timer",
- .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
- .handler = integrator_timer_interrupt,
- .dev_id = &integrator_clockevent,
-};
-
-static void integrator_clockevent_init(unsigned long inrate,
- void __iomem *base, int irq)
-{
- unsigned long rate = inrate;
- unsigned int ctrl = 0;
-
- clkevt_base = base;
- /* Calculate and program a divisor */
- if (rate > 0x100000 * HZ) {
- rate /= 256;
- ctrl |= TIMER_CTRL_DIV256;
- } else if (rate > 0x10000 * HZ) {
- rate /= 16;
- ctrl |= TIMER_CTRL_DIV16;
- }
- timer_reload = rate / HZ;
- writel(ctrl, clkevt_base + TIMER_CTRL);
-
- setup_irq(irq, &integrator_timer_irq);
- clockevents_config_and_register(&integrator_clockevent,
- rate,
- 1,
- 0xffffU);
-}
-
void __init ap_init_early(void)
{
}

#ifdef CONFIG_OF

-static void __init ap_of_timer_init(void)
-{
- struct device_node *node;
- const char *path;
- void __iomem *base;
- int err;
- int irq;
- struct clk *clk;
- unsigned long rate;
-
- clk = clk_get_sys("ap_timer", NULL);
- BUG_ON(IS_ERR(clk));
- clk_prepare_enable(clk);
- rate = clk_get_rate(clk);
-
- err = of_property_read_string(of_aliases,
- "arm,timer-primary", &path);
- if (WARN_ON(err))
- return;
- node = of_find_node_by_path(path);
- base = of_iomap(node, 0);
- if (WARN_ON(!base))
- return;
- writel(0, base + TIMER_CTRL);
- integrator_clocksource_init(rate, base);
-
- err = of_property_read_string(of_aliases,
- "arm,timer-secondary", &path);
- if (WARN_ON(err))
- return;
- node = of_find_node_by_path(path);
- base = of_iomap(node, 0);
- if (WARN_ON(!base))
- return;
- irq = irq_of_parse_and_map(node, 0);
- writel(0, base + TIMER_CTRL);
- integrator_clockevent_init(rate, base, irq);
-}
-
static const struct of_device_id fpga_irq_of_match[] __initconst = {
{ .compatible = "arm,versatile-fpga-irq", .data = fpga_irq_of_init, },
{ /* Sentinel */ }
@@ -582,7 +416,6 @@ DT_MACHINE_START(INTEGRATOR_AP_DT, "ARM Integrator/AP (Device Tree)")
.init_early = ap_init_early,
.init_irq = ap_init_irq_of,
.handle_irq = fpga_handle_irq,
- .init_time = ap_of_timer_init,
.init_machine = ap_init_of,
.restart = integrator_restart,
.dt_compat = ap_dt_board_compat,
diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c
index 5729c3d..b5c7a7b 100644
--- a/arch/arm/mach-integrator/integrator_cp.c
+++ b/arch/arm/mach-integrator/integrator_cp.c
@@ -28,6 +28,7 @@
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/sys_soc.h>
+#include <clocksource/timer-sp.h>

#include <mach/hardware.h>
#include <mach/platform.h>
@@ -44,8 +45,6 @@
#include <asm/mach/map.h>
#include <asm/mach/time.h>

-#include <asm/hardware/timer-sp.h>
-
#include <plat/clcd.h>
#include <plat/sched_clock.h>

diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c
index 8ce6366..2009f8f 100644
--- a/arch/arm/mach-realview/core.c
+++ b/arch/arm/mach-realview/core.c
@@ -31,6 +31,7 @@
#include <linux/amba/mmci.h>
#include <linux/gfp.h>
#include <linux/mtd/physmap.h>
+#include <clocksource/timer-sp.h>

#include <mach/hardware.h>
#include <asm/irq.h>
@@ -41,10 +42,8 @@
#include <asm/mach/irq.h>
#include <asm/mach/map.h>

-
#include <mach/platform.h>
#include <mach/irqs.h>
-#include <asm/hardware/timer-sp.h>

#include <plat/clcd.h>
#include <plat/sched_clock.h>
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index 5cdfc87..56ec027 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -38,6 +38,7 @@
#include <linux/clkdev.h>
#include <linux/mtd/physmap.h>
#include <linux/bitops.h>
+#include <clocksource/timer-sp.h>

#include <asm/irq.h>
#include <asm/hardware/icst.h>
@@ -49,7 +50,6 @@
#include <asm/mach/map.h>
#include <mach/hardware.h>
#include <mach/platform.h>
-#include <asm/hardware/timer-sp.h>

#include <plat/clcd.h>
#include <plat/sched_clock.h>
diff --git a/arch/arm/mach-vexpress/ct-ca9x4.c b/arch/arm/mach-vexpress/ct-ca9x4.c
index 6f34497..8cce326 100644
--- a/arch/arm/mach-vexpress/ct-ca9x4.c
+++ b/arch/arm/mach-vexpress/ct-ca9x4.c
@@ -11,16 +11,14 @@
#include <linux/clkdev.h>
#include <linux/vexpress.h>
#include <linux/irqchip/arm-gic.h>
+#include <clocksource/timer-sp.h>

-#include <asm/hardware/arm_timer.h>
#include <asm/hardware/cache-l2x0.h>
#include <asm/smp_scu.h>
#include <asm/smp_twd.h>

#include <mach/ct-ca9x4.h>

-#include <asm/hardware/timer-sp.h>
-
#include <asm/mach/map.h>
#include <asm/mach/time.h>

diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c
index 09e571d..fb4cdc6 100644
--- a/arch/arm/mach-vexpress/v2m.c
+++ b/arch/arm/mach-vexpress/v2m.c
@@ -23,15 +23,14 @@
#include <linux/regulator/fixed.h>
#include <linux/regulator/machine.h>
#include <linux/vexpress.h>
+#include <clocksource/timer-sp.h>

#include <asm/mach-types.h>
#include <asm/sizes.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/time.h>
-#include <asm/hardware/arm_timer.h>
#include <asm/hardware/cache-l2x0.h>
-#include <asm/hardware/timer-sp.h>

#include <mach/ct-ca9x4.h>
#include <mach/motherboard.h>
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index d98e7e1..00aa4cd 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -25,6 +25,18 @@ config DW_APB_TIMER_OF
config ARMADA_370_XP_TIMER
bool

+config ARM_TIMER_SP804
+ bool
+ depends on ARM
+ select CLKSRC_MMIO
+ select CLKSRC_OF if OF
+ select HAVE_SCHED_CLOCK
+
+config INTEGRATOR_AP_TIMER
+ bool
+ depends on ARM
+ select CLKSRC_OF if OF
+
config SUNXI_TIMER
bool

diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 4d8283a..9f3b62b 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -14,8 +14,10 @@ obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o
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_ARM_TIMER_SP804) += timer-sp.o
obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o
obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o
+obj-$(CONFIG_INTEGRATOR_AP_TIMER) += integrator_ap_timer.o
obj-$(CONFIG_SUNXI_TIMER) += sunxi_timer.o
obj-$(CONFIG_ARCH_TEGRA) += tegra20_timer.o
obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o
diff --git a/arch/arm/include/asm/hardware/arm_timer.h b/drivers/clocksource/arm_timer.h
similarity index 89%
rename from arch/arm/include/asm/hardware/arm_timer.h
rename to drivers/clocksource/arm_timer.h
index d6030ff..3d3f679 100644
--- a/arch/arm/include/asm/hardware/arm_timer.h
+++ b/drivers/clocksource/arm_timer.h
@@ -1,5 +1,5 @@
-#ifndef __ASM_ARM_HARDWARE_ARM_TIMER_H
-#define __ASM_ARM_HARDWARE_ARM_TIMER_H
+#ifndef __CLOCKSOURCE_ARM_TIMER_H
+#define __CLOCKSOURCE_ARM_TIMER_H

/*
* ARM timer implementation, found in Integrator, Versatile and Realview
@@ -12,8 +12,6 @@
*
* Every SP804 contains two identical timers.
*/
-#define TIMER_1_BASE 0x00
-#define TIMER_2_BASE 0x20

#define TIMER_LOAD 0x00 /* ACVR rw */
#define TIMER_VALUE 0x04 /* ACVR ro */
diff --git a/drivers/clocksource/integrator_ap_timer.c b/drivers/clocksource/integrator_ap_timer.c
new file mode 100644
index 0000000..75eb6c9
--- /dev/null
+++ b/drivers/clocksource/integrator_ap_timer.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2000-2003 Deep Blue Solutions Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/clk.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+
+#include <asm/sched_clock.h>
+
+#include "arm_timer.h"
+
+static unsigned long timer_reload;
+static void __iomem *clksrc_base;
+
+static u32 notrace integrator_read_sched_clock(void)
+{
+ return -readl(clksrc_base + TIMER_VALUE);
+}
+
+void __init integrator_clocksource_init(unsigned long inrate,
+ void __iomem *base)
+{
+ u32 ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC;
+ unsigned long rate = inrate;
+
+ clksrc_base = base;
+
+ if (rate >= 1500000) {
+ rate /= 16;
+ ctrl |= TIMER_CTRL_DIV16;
+ }
+
+ writel(0xffff, base + TIMER_LOAD);
+ writel(ctrl, base + TIMER_CTRL);
+
+ clocksource_mmio_init(base + TIMER_VALUE, "timer2",
+ rate, 200, 16, clocksource_mmio_readl_down);
+ setup_sched_clock(integrator_read_sched_clock, 16, rate);
+}
+
+static void __iomem * clkevt_base;
+
+/*
+ * IRQ handler for the timer
+ */
+static irqreturn_t integrator_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = dev_id;
+
+ /* clear the interrupt */
+ writel(1, clkevt_base + TIMER_INTCLR);
+
+ evt->event_handler(evt);
+
+ return IRQ_HANDLED;
+}
+
+static void clkevt_set_mode(enum clock_event_mode mode, struct clock_event_device *evt)
+{
+ u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE;
+
+ /* Disable timer */
+ writel(ctrl, clkevt_base + TIMER_CTRL);
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ /* Enable the timer and start the periodic tick */
+ writel(timer_reload, clkevt_base + TIMER_LOAD);
+ ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
+ writel(ctrl, clkevt_base + TIMER_CTRL);
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ /* Leave the timer disabled, .set_next_event will enable it */
+ ctrl &= ~TIMER_CTRL_PERIODIC;
+ writel(ctrl, clkevt_base + TIMER_CTRL);
+ break;
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ case CLOCK_EVT_MODE_RESUME:
+ default:
+ /* Just leave in disabled state */
+ break;
+ }
+
+}
+
+static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt)
+{
+ unsigned long ctrl = readl(clkevt_base + TIMER_CTRL);
+
+ writel(ctrl & ~TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL);
+ writel(next, clkevt_base + TIMER_LOAD);
+ writel(ctrl | TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL);
+
+ return 0;
+}
+
+static struct clock_event_device integrator_clockevent = {
+ .name = "timer1",
+ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+ .set_mode = clkevt_set_mode,
+ .set_next_event = clkevt_set_next_event,
+ .rating = 300,
+};
+
+static struct irqaction integrator_timer_irq = {
+ .name = "timer",
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+ .handler = integrator_timer_interrupt,
+ .dev_id = &integrator_clockevent,
+};
+
+void __init integrator_clockevent_init(unsigned long inrate,
+ void __iomem *base, int irq)
+{
+ unsigned long rate = inrate;
+ unsigned int ctrl = 0;
+
+ clkevt_base = base;
+ /* Calculate and program a divisor */
+ if (rate > 0x100000 * HZ) {
+ rate /= 256;
+ ctrl |= TIMER_CTRL_DIV256;
+ } else if (rate > 0x10000 * HZ) {
+ rate /= 16;
+ ctrl |= TIMER_CTRL_DIV16;
+ }
+ timer_reload = rate / HZ;
+ writel(ctrl, clkevt_base + TIMER_CTRL);
+
+ setup_irq(irq, &integrator_timer_irq);
+ clockevents_config_and_register(&integrator_clockevent,
+ rate,
+ 1,
+ 0xffffU);
+}
+
+static void __init ap_of_timer_init(struct device_node *node)
+{
+ static int init_cnt = 0;
+ void __iomem *base;
+ int irq;
+ struct clk *clk;
+ unsigned long rate;
+
+ if ((init_cnt == 2) || !of_device_is_available(node))
+ return;
+
+ clk = clk_get_sys("ap_timer", NULL);
+ BUG_ON(IS_ERR(clk));
+ clk_prepare_enable(clk);
+ rate = clk_get_rate(clk);
+
+ base = of_iomap(node, 0);
+ if (WARN_ON(!base))
+ return;
+
+ writel(0, base + TIMER_CTRL);
+
+ if (!init_cnt) {
+ irq = irq_of_parse_and_map(node, 0);
+ integrator_clockevent_init(rate, base, irq);
+ } else
+ integrator_clocksource_init(rate, base);
+
+ init_cnt++;
+}
+CLOCKSOURCE_OF_DECLARE(integrator_ap, "integrator-timer", ap_of_timer_init);
diff --git a/arch/arm/common/timer-sp.c b/drivers/clocksource/timer-sp.c
similarity index 98%
rename from arch/arm/common/timer-sp.c
rename to drivers/clocksource/timer-sp.c
index 203a2b3..91b12e3 100644
--- a/arch/arm/common/timer-sp.c
+++ b/drivers/clocksource/timer-sp.c
@@ -1,6 +1,4 @@
/*
- * linux/arch/arm/common/timer-sp.c
- *
* Copyright (C) 1999 - 2003 ARM Limited
* Copyright (C) 2000 Deep Blue Solutions Ltd
*
@@ -28,10 +26,11 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
+#include <clocksource/timer-sp.h>

#include <asm/sched_clock.h>
-#include <asm/hardware/arm_timer.h>
-#include <asm/hardware/timer-sp.h>
+
+#include "arm_timer.h"

static long __init sp804_get_clock_rate(struct clk *clk)
{
@@ -283,4 +282,4 @@ static void __init integrator_cp_of_init(struct device_node *np)

init_count++;
}
-CLOCKSOURCE_OF_DECLARE(intcp, "arm,integrator-cp-timer", integrator_cp_of_init);
\ No newline at end of file
+CLOCKSOURCE_OF_DECLARE(intcp, "arm,integrator-cp-timer", integrator_cp_of_init);
diff --git a/include/clocksource/integrator_ap_timer.h b/include/clocksource/integrator_ap_timer.h
new file mode 100644
index 0000000..2f585fc
--- /dev/null
+++ b/include/clocksource/integrator_ap_timer.h
@@ -0,0 +1,7 @@
+#ifndef __CLOCKSOURCE_INTEGRATOR_AP_TIMER
+#define __CLOCKSOURCE_INTEGRATOR_AP_TIMER
+
+void integrator_clocksource_init(unsigned long inrate, void __iomem *base);
+void integrator_clockevent_init(unsigned long inrate, void __iomem *base, int irq);
+
+#endif
diff --git a/arch/arm/include/asm/hardware/timer-sp.h b/include/clocksource/timer-sp.h
similarity index 84%
rename from arch/arm/include/asm/hardware/timer-sp.h
rename to include/clocksource/timer-sp.h
index bb28af7..f59dc9c 100644
--- a/arch/arm/include/asm/hardware/timer-sp.h
+++ b/include/clocksource/timer-sp.h
@@ -1,3 +1,9 @@
+#ifndef __CLOCKSOURCE_TIMER_SP
+#define __CLOCKSOURCE_TIMER_SP
+
+#define TIMER_1_BASE 0x00
+#define TIMER_2_BASE 0x20
+
struct clk;

void __sp804_clocksource_and_sched_clock_init(void __iomem *,
@@ -21,3 +27,5 @@ static inline void sp804_clockevents_init(void __iomem *base, unsigned int irq,
__sp804_clockevents_init(base, irq, NULL, name);

}
+
+#endif
--
1.7.10.4

2013-03-20 22:54:56

by Rob Herring

[permalink] [raw]
Subject: [PATCH 11/11] devtree: add binding documentation for sp804

From: Haojian Zhuang <[email protected]>

The sp804 binding is already in use by several platforms. This adds missing
documentation for the binding and also extends the binding to handle some
additional possible interrupt configurations.

Signed-off-by: Haojian Zhuang <[email protected]>
Signed-off-by: Rob Herring <[email protected]>
---
.../devicetree/bindings/timer/arm,sp804.txt | 29 ++++++++++++++++++++
1 file changed, 29 insertions(+)
create mode 100644 Documentation/devicetree/bindings/timer/arm,sp804.txt

diff --git a/Documentation/devicetree/bindings/timer/arm,sp804.txt b/Documentation/devicetree/bindings/timer/arm,sp804.txt
new file mode 100644
index 0000000..5cd8eee
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/arm,sp804.txt
@@ -0,0 +1,29 @@
+ARM sp804 Dual Timers
+---------------------------------------
+
+Required properties:
+- compatible: Should be "arm,sp804" & "arm,primecell"
+- interrupts: Should contain the list of Dual Timer interrupts. This is the
+ interrupt for timer 1 and timer 2. In the case of a single entry, it is
+ the combined interrupt or if "arm,sp804-has-irq" is present that
+ specifies which timer interrupt is connected.
+- reg: Should contain location and length for dual timer register.
+- clocks: clocks driving the dual timer hardware. This list should be 1 or 3
+ clocks. With 3 clocks, the order is timer0 clock, timer1 clock,
+ apb_pclk. A single clock can also be specified if the same clock is
+ used for all clock inputs.
+
+Optional properties:
+- arm,sp804-has-irq = <#>: In the case of only 1 timer irq line connected, this
+ specifies if the irq connection is for timer 1 or timer 2. A value of 1
+ or 2 should be used.
+
+Example:
+
+ timer0: timer@fc800000 {
+ compatible = "arm,sp804", "arm,primecell";
+ reg = <0xfc800000 0x1000>;
+ interrupts = <0 0 4>, <0 1 4>;
+ clocks = <&timclk1 &timclk2 &pclk>;
+ clock-names = "timer1", "timer2", "apb_pclk";
+ };
--
1.7.10.4

2013-03-20 22:54:37

by Rob Herring

[permalink] [raw]
Subject: [PATCH 04/11] ARM: highbank: use OF init for sp804 timer

From: Rob Herring <[email protected]>

Remove the highbank specific setup for the sp804 timer now that
clocksource_of_init will do it.

Signed-off-by: Rob Herring <[email protected]>
---
arch/arm/mach-highbank/highbank.c | 19 -------------------
1 file changed, 19 deletions(-)

diff --git a/arch/arm/mach-highbank/highbank.c b/arch/arm/mach-highbank/highbank.c
index 758150e..e7df2dd 100644
--- a/arch/arm/mach-highbank/highbank.c
+++ b/arch/arm/mach-highbank/highbank.c
@@ -32,8 +32,6 @@
#include <asm/cacheflush.h>
#include <asm/cputype.h>
#include <asm/smp_plat.h>
-#include <asm/hardware/arm_timer.h>
-#include <asm/hardware/timer-sp.h>
#include <asm/hardware/cache-l2x0.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
@@ -90,33 +88,16 @@ static void __init highbank_init_irq(void)
#endif
}

-static struct clk_lookup lookup = {
- .dev_id = "sp804",
- .con_id = NULL,
-};
-
static void __init highbank_timer_init(void)
{
- int irq;
struct device_node *np;
- void __iomem *timer_base;

/* Map system registers */
np = of_find_compatible_node(NULL, NULL, "calxeda,hb-sregs");
sregs_base = of_iomap(np, 0);
WARN_ON(!sregs_base);

- np = of_find_compatible_node(NULL, NULL, "arm,sp804");
- timer_base = of_iomap(np, 0);
- WARN_ON(!timer_base);
- irq = irq_of_parse_and_map(np, 0);
-
of_clk_init(NULL);
- lookup.clk = of_clk_get(np, 0);
- clkdev_add(&lookup);
-
- sp804_clocksource_and_sched_clock_init(timer_base + 0x20, "timer1");
- sp804_clockevents_init(timer_base, irq, "timer0");

clocksource_of_init();
}
--
1.7.10.4

2013-03-20 22:55:40

by Rob Herring

[permalink] [raw]
Subject: [PATCH 08/11] ARM: versatile: use OF init for sp804 timer

From: Rob Herring <[email protected]>

Enable DT based init for the sp804 timers on versatile DT platform.

Signed-off-by: Rob Herring <[email protected]>
---
arch/arm/boot/dts/versatile-ab.dts | 12 ++++++++++++
arch/arm/mach-versatile/core.c | 26 +++++++++++++-------------
arch/arm/mach-versatile/versatile_dt.c | 1 -
3 files changed, 25 insertions(+), 14 deletions(-)

diff --git a/arch/arm/boot/dts/versatile-ab.dts b/arch/arm/boot/dts/versatile-ab.dts
index e2fe319..dde75ae 100644
--- a/arch/arm/boot/dts/versatile-ab.dts
+++ b/arch/arm/boot/dts/versatile-ab.dts
@@ -121,6 +121,18 @@
interrupts = <0>;
};

+ timer@101e2000 {
+ compatible = "arm,sp804", "arm,primecell";
+ reg = <0x101e2000 0x1000>;
+ interrupts = <4>;
+ };
+
+ timer@101e3000 {
+ compatible = "arm,sp804", "arm,primecell";
+ reg = <0x101e3000 0x1000>;
+ interrupts = <5>;
+ };
+
gpio0: gpio@101e4000 {
compatible = "arm,pl061", "arm,primecell";
reg = <0x101e4000 0x1000>;
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index 286303a..5cdfc87 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -748,12 +748,25 @@ void versatile_restart(char mode, const char *cmd)
/* Early initializations */
void __init versatile_init_early(void)
{
+ u32 val;
void __iomem *sys = __io_address(VERSATILE_SYS_BASE);

osc4_clk.vcoreg = sys + VERSATILE_SYS_OSCCLCD_OFFSET;
clkdev_add_table(lookups, ARRAY_SIZE(lookups));

versatile_sched_clock_init(sys + VERSATILE_SYS_24MHz_OFFSET, 24000000);
+
+ /*
+ * set clock frequency:
+ * VERSATILE_REFCLK is 32KHz
+ * VERSATILE_TIMCLK is 1MHz
+ */
+ val = readl(__io_address(VERSATILE_SCTL_BASE));
+ writel((VERSATILE_TIMCLK << VERSATILE_TIMER1_EnSel) |
+ (VERSATILE_TIMCLK << VERSATILE_TIMER2_EnSel) |
+ (VERSATILE_TIMCLK << VERSATILE_TIMER3_EnSel) |
+ (VERSATILE_TIMCLK << VERSATILE_TIMER4_EnSel) | val,
+ __io_address(VERSATILE_SCTL_BASE));
}

void __init versatile_init(void)
@@ -784,19 +797,6 @@ void __init versatile_init(void)
*/
void __init versatile_timer_init(void)
{
- u32 val;
-
- /*
- * set clock frequency:
- * VERSATILE_REFCLK is 32KHz
- * VERSATILE_TIMCLK is 1MHz
- */
- val = readl(__io_address(VERSATILE_SCTL_BASE));
- writel((VERSATILE_TIMCLK << VERSATILE_TIMER1_EnSel) |
- (VERSATILE_TIMCLK << VERSATILE_TIMER2_EnSel) |
- (VERSATILE_TIMCLK << VERSATILE_TIMER3_EnSel) |
- (VERSATILE_TIMCLK << VERSATILE_TIMER4_EnSel) | val,
- __io_address(VERSATILE_SCTL_BASE));

sp804_clocksource_init(TIMER3_VA_BASE, "timer3");
sp804_clockevents_init(TIMER0_VA_BASE, IRQ_TIMERINT0_1, "timer0");
diff --git a/arch/arm/mach-versatile/versatile_dt.c b/arch/arm/mach-versatile/versatile_dt.c
index 2558f2e..3621b00 100644
--- a/arch/arm/mach-versatile/versatile_dt.c
+++ b/arch/arm/mach-versatile/versatile_dt.c
@@ -45,7 +45,6 @@ DT_MACHINE_START(VERSATILE_PB, "ARM-Versatile (Device Tree Support)")
.map_io = versatile_map_io,
.init_early = versatile_init_early,
.init_irq = versatile_init_irq,
- .init_time = versatile_timer_init,
.init_machine = versatile_dt_init,
.dt_compat = versatile_dt_match,
.restart = versatile_restart,
--
1.7.10.4

2013-03-20 22:55:37

by Rob Herring

[permalink] [raw]
Subject: [PATCH 09/11] ARM: integrator-cp: convert use CLKSRC_OF for timer init

From: Rob Herring <[email protected]>

Move the integrator-cp timer init to timer-sp.c and use CLKSRC_OF. There is
no reason to use the aliases, so drop them from the init code.

The integrator-cp timers are mistakenly called sp804 timers in the dts, but
in fact they are not sp804 dual timers, but single timers with the same
programming model. Fix the dts to reflect this.

Signed-off-by: Rob Herring <[email protected]>
---
arch/arm/boot/dts/integratorcp.dts | 6 +++---
arch/arm/common/timer-sp.c | 29 +++++++++++++++++++++++++++
arch/arm/mach-integrator/integrator_cp.c | 32 ------------------------------
3 files changed, 32 insertions(+), 35 deletions(-)

diff --git a/arch/arm/boot/dts/integratorcp.dts b/arch/arm/boot/dts/integratorcp.dts
index 8b11939..ff1aea0 100644
--- a/arch/arm/boot/dts/integratorcp.dts
+++ b/arch/arm/boot/dts/integratorcp.dts
@@ -24,15 +24,15 @@
};

timer0: timer@13000000 {
- compatible = "arm,sp804", "arm,primecell";
+ compatible = "arm,integrator-cp-timer";
};

timer1: timer@13000100 {
- compatible = "arm,sp804", "arm,primecell";
+ compatible = "arm,integrator-cp-timer";
};

timer2: timer@13000200 {
- compatible = "arm,sp804", "arm,primecell";
+ compatible = "arm,integrator-cp-timer";
};

pic: pic@14000000 {
diff --git a/arch/arm/common/timer-sp.c b/arch/arm/common/timer-sp.c
index 3e86835..203a2b3 100644
--- a/arch/arm/common/timer-sp.c
+++ b/arch/arm/common/timer-sp.c
@@ -31,6 +31,7 @@

#include <asm/sched_clock.h>
#include <asm/hardware/arm_timer.h>
+#include <asm/hardware/timer-sp.h>

static long __init sp804_get_clock_rate(struct clk *clk)
{
@@ -255,3 +256,31 @@ static void __init sp804_of_init(struct device_node *np)
initialized = true;
}
CLOCKSOURCE_OF_DECLARE(sp804, "arm,sp804", sp804_of_init);
+
+static void __init integrator_cp_of_init(struct device_node *np)
+{
+ static int init_count = 0;
+ void __iomem *base;
+ int irq;
+ const char *name = of_get_property(np, "compatible", NULL);
+
+ if (init_count == 2 || !of_device_is_available(np))
+ return;
+
+ base = of_iomap(np, 0);
+ if (WARN_ON(!base))
+ return;
+
+ if (!init_count)
+ sp804_clocksource_init(base, name);
+ else {
+ irq = irq_of_parse_and_map(np, 0);
+ if (irq <= 0)
+ return;
+
+ sp804_clockevents_init(base, irq, name);
+ }
+
+ init_count++;
+}
+CLOCKSOURCE_OF_DECLARE(intcp, "arm,integrator-cp-timer", integrator_cp_of_init);
\ No newline at end of file
diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c
index c68e7d8..5729c3d 100644
--- a/arch/arm/mach-integrator/integrator_cp.c
+++ b/arch/arm/mach-integrator/integrator_cp.c
@@ -249,37 +249,6 @@ static void __init intcp_init_early(void)
}

#ifdef CONFIG_OF
-
-static void __init cp_of_timer_init(void)
-{
- struct device_node *node;
- const char *path;
- void __iomem *base;
- int err;
- int irq;
-
- err = of_property_read_string(of_aliases,
- "arm,timer-primary", &path);
- if (WARN_ON(err))
- return;
- node = of_find_node_by_path(path);
- base = of_iomap(node, 0);
- if (WARN_ON(!base))
- return;
- sp804_clocksource_init(base, node->name);
-
- err = of_property_read_string(of_aliases,
- "arm,timer-secondary", &path);
- if (WARN_ON(err))
- return;
- node = of_find_node_by_path(path);
- base = of_iomap(node, 0);
- if (WARN_ON(!base))
- return;
- irq = irq_of_parse_and_map(node, 0);
- sp804_clockevents_init(base, irq, node->name);
-}
-
static const struct of_device_id fpga_irq_of_match[] __initconst = {
{ .compatible = "arm,versatile-fpga-irq", .data = fpga_irq_of_init, },
{ /* Sentinel */ }
@@ -383,7 +352,6 @@ DT_MACHINE_START(INTEGRATOR_CP_DT, "ARM Integrator/CP (Device Tree)")
.init_early = intcp_init_early,
.init_irq = intcp_init_irq_of,
.handle_irq = fpga_handle_irq,
- .init_time = cp_of_timer_init,
.init_machine = intcp_init_of,
.restart = integrator_restart,
.dt_compat = intcp_dt_board_compat,
--
1.7.10.4

2013-03-20 22:56:18

by Rob Herring

[permalink] [raw]
Subject: [PATCH 07/11] ARM: versatile: add versatile dtbs to dtbs target

From: Rob Herring <[email protected]>

Add the versatile platform dtbs to the dtbs make rule.

Signed-off-by: Rob Herring <[email protected]>
---
arch/arm/boot/dts/Makefile | 2 ++
1 file changed, 2 insertions(+)

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 9c62558..08d298d 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -165,6 +165,8 @@ dtb-$(CONFIG_ARCH_TEGRA) += tegra20-harmony.dtb \
tegra30-cardhu-a04.dtb \
tegra114-dalmore.dtb \
tegra114-pluto.dtb
+dtb-$(CONFIG_ARCH_VERSATILE) += versatile-ab.dtb \
+ versatile-pb.dtb
dtb-$(CONFIG_ARCH_VEXPRESS) += vexpress-v2p-ca5s.dtb \
vexpress-v2p-ca9.dtb \
vexpress-v2p-ca15-tc1.dtb \
--
1.7.10.4

2013-03-20 22:56:36

by Rob Herring

[permalink] [raw]
Subject: [PATCH 05/11] ARM: vexpress: remove sp804 OF init

From: Rob Herring <[email protected]>

Remove the vexpress specific setup for the sp804 timer now that
clocksource_of_init will do it.

Signed-off-by: Rob Herring <[email protected]>
---
arch/arm/mach-vexpress/v2m.c | 11 -----------
1 file changed, 11 deletions(-)

diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c
index 9fbfbe4..09e571d 100644
--- a/arch/arm/mach-vexpress/v2m.c
+++ b/arch/arm/mach-vexpress/v2m.c
@@ -428,20 +428,9 @@ void __init v2m_dt_init_early(void)

static void __init v2m_dt_timer_init(void)
{
- struct device_node *node = NULL;
-
vexpress_clk_of_init();

clocksource_of_init();
- do {
- node = of_find_compatible_node(node, NULL, "arm,sp804");
- } while (node && vexpress_get_site_by_node(node) != VEXPRESS_SITE_MB);
- if (node) {
- pr_info("Using SP804 '%s' as a clock & events source\n",
- node->full_name);
- v2m_sp804_init(of_iomap(node, 0),
- irq_of_parse_and_map(node, 0));
- }

versatile_sched_clock_init(vexpress_get_24mhz_clock_base(),
24000000);
--
1.7.10.4

2013-03-20 22:56:34

by Rob Herring

[permalink] [raw]
Subject: [PATCH 06/11] ARM: dts: vexpress: disable CA9 core tile sp804 timer

From: Rob Herring <[email protected]>

The motherboard sp804 timer is used, but core tile sp804 timer is not.
According to Russell King, the clock configuration is undocumented and
defaults to 32kHz which is not desireable. So mark core tile sp804 timer
as disabled.

Signed-off-by: Rob Herring <[email protected]>
---
arch/arm/boot/dts/vexpress-v2p-ca9.dts | 1 +
1 file changed, 1 insertion(+)

diff --git a/arch/arm/boot/dts/vexpress-v2p-ca9.dts b/arch/arm/boot/dts/vexpress-v2p-ca9.dts
index 1420bb1..62d9b22 100644
--- a/arch/arm/boot/dts/vexpress-v2p-ca9.dts
+++ b/arch/arm/boot/dts/vexpress-v2p-ca9.dts
@@ -98,6 +98,7 @@
<0 49 4>;
clocks = <&oscclk2>, <&oscclk2>;
clock-names = "timclk", "apb_pclk";
+ status = "disabled";
};

watchdog@100e5000 {
--
1.7.10.4

2013-03-20 22:57:32

by Rob Herring

[permalink] [raw]
Subject: [PATCH 02/11] ARM: remove extra timer-sp control register clearing

From: Rob Herring <[email protected]>

The timer-sp initialization code clears the control register before
initializing the timers, so every platform doing this is redundant.

For unused timers, we should not care what state they are in.

Signed-off-by: Rob Herring <[email protected]>
---
arch/arm/mach-integrator/integrator_ap.c | 4 ----
arch/arm/mach-integrator/integrator_cp.c | 7 -------
arch/arm/mach-realview/core.c | 9 ---------
arch/arm/mach-versatile/core.c | 9 ---------
arch/arm/mach-vexpress/v2m.c | 3 ---
5 files changed, 32 deletions(-)

diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c
index ea96144..4cb322d 100644
--- a/arch/arm/mach-integrator/integrator_ap.c
+++ b/arch/arm/mach-integrator/integrator_ap.c
@@ -643,10 +643,6 @@ static void __init ap_timer_init(void)
clk_prepare_enable(clk);
rate = clk_get_rate(clk);

- writel(0, TIMER0_VA_BASE + TIMER_CTRL);
- writel(0, TIMER1_VA_BASE + TIMER_CTRL);
- writel(0, TIMER2_VA_BASE + TIMER_CTRL);
-
integrator_clocksource_init(rate, (void __iomem *)TIMER2_VA_BASE);
integrator_clockevent_init(rate, (void __iomem *)TIMER1_VA_BASE,
IRQ_TIMERINT1);
diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c
index 2b0db82..c68e7d8 100644
--- a/arch/arm/mach-integrator/integrator_cp.c
+++ b/arch/arm/mach-integrator/integrator_cp.c
@@ -33,7 +33,6 @@
#include <mach/platform.h>
#include <asm/setup.h>
#include <asm/mach-types.h>
-#include <asm/hardware/arm_timer.h>
#include <asm/hardware/icst.h>

#include <mach/cm.h>
@@ -267,7 +266,6 @@ static void __init cp_of_timer_init(void)
base = of_iomap(node, 0);
if (WARN_ON(!base))
return;
- writel(0, base + TIMER_CTRL);
sp804_clocksource_init(base, node->name);

err = of_property_read_string(of_aliases,
@@ -279,7 +277,6 @@ static void __init cp_of_timer_init(void)
if (WARN_ON(!base))
return;
irq = irq_of_parse_and_map(node, 0);
- writel(0, base + TIMER_CTRL);
sp804_clockevents_init(base, irq, node->name);
}

@@ -510,10 +507,6 @@ static void __init intcp_init_irq(void)

static void __init cp_timer_init(void)
{
- writel(0, TIMER0_VA_BASE + TIMER_CTRL);
- writel(0, TIMER1_VA_BASE + TIMER_CTRL);
- writel(0, TIMER2_VA_BASE + TIMER_CTRL);
-
sp804_clocksource_init(TIMER2_VA_BASE, "timer2");
sp804_clockevents_init(TIMER1_VA_BASE, IRQ_TIMERINT1, "timer1");
}
diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c
index 1d5ee5c..8ce6366 100644
--- a/arch/arm/mach-realview/core.c
+++ b/arch/arm/mach-realview/core.c
@@ -35,7 +35,6 @@
#include <mach/hardware.h>
#include <asm/irq.h>
#include <asm/mach-types.h>
-#include <asm/hardware/arm_timer.h>
#include <asm/hardware/icst.h>

#include <asm/mach/arch.h>
@@ -355,14 +354,6 @@ void __init realview_timer_init(unsigned int timer_irq)
(REALVIEW_TIMCLK << REALVIEW_TIMER4_EnSel) | val,
__io_address(REALVIEW_SCTL_BASE));

- /*
- * Initialise to a known state (all timers off)
- */
- writel(0, timer0_va_base + TIMER_CTRL);
- writel(0, timer1_va_base + TIMER_CTRL);
- writel(0, timer2_va_base + TIMER_CTRL);
- writel(0, timer3_va_base + TIMER_CTRL);
-
sp804_clocksource_init(timer3_va_base, "timer3");
sp804_clockevents_init(timer0_va_base, timer_irq, "timer0");
}
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index 25160ae..286303a 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -40,7 +40,6 @@
#include <linux/bitops.h>

#include <asm/irq.h>
-#include <asm/hardware/arm_timer.h>
#include <asm/hardware/icst.h>
#include <asm/mach-types.h>

@@ -799,14 +798,6 @@ void __init versatile_timer_init(void)
(VERSATILE_TIMCLK << VERSATILE_TIMER4_EnSel) | val,
__io_address(VERSATILE_SCTL_BASE));

- /*
- * Initialise to a known state (all timers off)
- */
- writel(0, TIMER0_VA_BASE + TIMER_CTRL);
- writel(0, TIMER1_VA_BASE + TIMER_CTRL);
- writel(0, TIMER2_VA_BASE + TIMER_CTRL);
- writel(0, TIMER3_VA_BASE + TIMER_CTRL);
-
sp804_clocksource_init(TIMER3_VA_BASE, "timer3");
sp804_clockevents_init(TIMER0_VA_BASE, IRQ_TIMERINT0_1, "timer0");
}
diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c
index 6215717..9fbfbe4 100644
--- a/arch/arm/mach-vexpress/v2m.c
+++ b/arch/arm/mach-vexpress/v2m.c
@@ -61,9 +61,6 @@ static void __init v2m_sp804_init(void __iomem *base, unsigned int irq)
if (WARN_ON(!base || irq == NO_IRQ))
return;

- writel(0, base + TIMER_1_BASE + TIMER_CTRL);
- writel(0, base + TIMER_2_BASE + TIMER_CTRL);
-
sp804_clocksource_init(base + TIMER_2_BASE, "v2m-timer1");
sp804_clockevents_init(base + TIMER_1_BASE, irq, "v2m-timer0");
}
--
1.7.10.4

2013-03-20 22:57:31

by Rob Herring

[permalink] [raw]
Subject: [PATCH 03/11] ARM: timer-sp: convert to use CLKSRC_OF init

From: Rob Herring <[email protected]>

This adds CLKSRC_OF based init for sp804 timer. The clock initialization is
refactored to support retrieving the clock(s) from the DT.

Signed-off-by: Rob Herring <[email protected]>
---
arch/arm/Kconfig | 1 +
arch/arm/common/timer-sp.c | 98 +++++++++++++++++++++++++-----
arch/arm/include/asm/hardware/timer-sp.h | 16 +++--
3 files changed, 95 insertions(+), 20 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index f0f90f0..774131a 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1172,6 +1172,7 @@ config PLAT_VERSATILE
config ARM_TIMER_SP804
bool
select CLKSRC_MMIO
+ select CLKSRC_OF if OF
select HAVE_SCHED_CLOCK

source arch/arm/mm/Kconfig
diff --git a/arch/arm/common/timer-sp.c b/arch/arm/common/timer-sp.c
index 9d2d3ba..3e86835 100644
--- a/arch/arm/common/timer-sp.c
+++ b/arch/arm/common/timer-sp.c
@@ -25,33 +25,28 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>

#include <asm/sched_clock.h>
#include <asm/hardware/arm_timer.h>

-static long __init sp804_get_clock_rate(const char *name)
+static long __init sp804_get_clock_rate(struct clk *clk)
{
- struct clk *clk;
long rate;
int err;

- clk = clk_get_sys("sp804", name);
- if (IS_ERR(clk)) {
- pr_err("sp804: %s clock not found: %d\n", name,
- (int)PTR_ERR(clk));
- return PTR_ERR(clk);
- }
-
err = clk_prepare(clk);
if (err) {
- pr_err("sp804: %s clock failed to prepare: %d\n", name, err);
+ pr_err("sp804: clock failed to prepare: %d\n", err);
clk_put(clk);
return err;
}

err = clk_enable(clk);
if (err) {
- pr_err("sp804: %s clock failed to enable: %d\n", name, err);
+ pr_err("sp804: clock failed to enable: %d\n", err);
clk_unprepare(clk);
clk_put(clk);
return err;
@@ -59,7 +54,7 @@ static long __init sp804_get_clock_rate(const char *name)

rate = clk_get_rate(clk);
if (rate < 0) {
- pr_err("sp804: %s clock failed to get rate: %ld\n", name, rate);
+ pr_err("sp804: clock failed to get rate: %ld\n", rate);
clk_disable(clk);
clk_unprepare(clk);
clk_put(clk);
@@ -77,9 +72,21 @@ static u32 sp804_read(void)

void __init __sp804_clocksource_and_sched_clock_init(void __iomem *base,
const char *name,
+ struct clk *clk,
int use_sched_clock)
{
- long rate = sp804_get_clock_rate(name);
+ long rate;
+
+ if (!clk) {
+ clk = clk_get_sys("sp804", name);
+ if (IS_ERR(clk)) {
+ pr_err("sp804: clock not found: %d\n",
+ (int)PTR_ERR(clk));
+ return;
+ }
+ }
+
+ rate = sp804_get_clock_rate(clk);

if (rate < 0)
return;
@@ -171,12 +178,20 @@ static struct irqaction sp804_timer_irq = {
.dev_id = &sp804_clockevent,
};

-void __init sp804_clockevents_init(void __iomem *base, unsigned int irq,
- const char *name)
+void __init __sp804_clockevents_init(void __iomem *base, unsigned int irq, struct clk *clk, const char *name)
{
struct clock_event_device *evt = &sp804_clockevent;
- long rate = sp804_get_clock_rate(name);
+ long rate;
+
+ if (!clk)
+ clk = clk_get_sys("sp804", name);
+ if (IS_ERR(clk)) {
+ pr_err("sp804: %s clock not found: %d\n", name,
+ (int)PTR_ERR(clk));
+ return;
+ }

+ rate = sp804_get_clock_rate(clk);
if (rate < 0)
return;

@@ -186,6 +201,57 @@ void __init sp804_clockevents_init(void __iomem *base, unsigned int irq,
evt->irq = irq;
evt->cpumask = cpu_possible_mask;

+ writel(0, clkevt_base + TIMER_CTRL);
+
setup_irq(irq, &sp804_timer_irq);
clockevents_config_and_register(evt, rate, 0xf, 0xffffffff);
}
+
+static void __init sp804_of_init(struct device_node *np)
+{
+ static bool initialized = false;
+ void __iomem *base;
+ int irq;
+ u32 irq_num = 0;
+ bool tmr2_evt = false;
+ struct clk *clk0, *clk1;
+ const char *name = of_get_property(np, "compatible", NULL);
+
+ if (initialized || !of_device_is_available(np))
+ return;
+
+ base = of_iomap(np, 0);
+ if (WARN_ON(!base))
+ return;
+
+ clk0 = of_clk_get(np, 0);
+ if (IS_ERR(clk0))
+ clk0 = NULL;
+
+ /* Get the 2nd clock if the timer has 2 timer clocks */
+ if (of_count_phandle_with_args(np, "clocks", "#clock-cells") == 3) {
+ clk1 = of_clk_get(np, 1);
+ if (IS_ERR(clk1)) {
+ pr_err("sp804: %s clock not found: %d\n", np->name,
+ (int)PTR_ERR(clk1));
+ return;
+ }
+ } else
+ clk1 = clk0;
+
+ irq = irq_of_parse_and_map(np, 0);
+ if (irq <= 0)
+ return;
+
+ of_property_read_u32(np, "arm,sp804-has-irq", &irq_num);
+ if (irq_num == 2)
+ tmr2_evt = true;
+
+ __sp804_clockevents_init(base + (tmr2_evt ? TIMER_2_BASE : 0),
+ irq, tmr2_evt ? clk1 : clk0, name);
+ __sp804_clocksource_and_sched_clock_init(base + (tmr2_evt ? 0 : TIMER_2_BASE),
+ name, tmr2_evt ? clk0 : clk1, 1);
+
+ initialized = true;
+}
+CLOCKSOURCE_OF_DECLARE(sp804, "arm,sp804", sp804_of_init);
diff --git a/arch/arm/include/asm/hardware/timer-sp.h b/arch/arm/include/asm/hardware/timer-sp.h
index 2dd9d3f..bb28af7 100644
--- a/arch/arm/include/asm/hardware/timer-sp.h
+++ b/arch/arm/include/asm/hardware/timer-sp.h
@@ -1,15 +1,23 @@
+struct clk;
+
void __sp804_clocksource_and_sched_clock_init(void __iomem *,
- const char *, int);
+ const char *, struct clk *, int);
+void __sp804_clockevents_init(void __iomem *, unsigned int,
+ struct clk *, const char *);

static inline void sp804_clocksource_init(void __iomem *base, const char *name)
{
- __sp804_clocksource_and_sched_clock_init(base, name, 0);
+ __sp804_clocksource_and_sched_clock_init(base, name, NULL, 0);
}

static inline void sp804_clocksource_and_sched_clock_init(void __iomem *base,
const char *name)
{
- __sp804_clocksource_and_sched_clock_init(base, name, 1);
+ __sp804_clocksource_and_sched_clock_init(base, name, NULL, 1);
}

-void sp804_clockevents_init(void __iomem *, unsigned int, const char *);
+static inline void sp804_clockevents_init(void __iomem *base, unsigned int irq, const char *name)
+{
+ __sp804_clockevents_init(base, irq, NULL, name);
+
+}
--
1.7.10.4

2013-03-21 13:25:09

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH 00/11] sp804 and integrator timer CLKSRC_OF support

On Wednesday 20 March 2013, Rob Herring wrote:
> This series is dependent on my CLKSRC_OF clean-up in arm-soc, my
> sched_clock selection series[1], and Arnd's default machine descriptor
> patch (for default clocksource_of_init call). The full series is
> available here:

All your patches look good to me, but I'd suggest you don't depend on
my default machine descriptor patch yet, that just makes the dependencies
harder to track, and we can easily remove all the calls once they
are obsoletely.

Arnd

2013-03-21 14:06:31

by Rob Herring

[permalink] [raw]
Subject: Re: [PATCH 00/11] sp804 and integrator timer CLKSRC_OF support

On 03/21/2013 08:24 AM, Arnd Bergmann wrote:
> On Wednesday 20 March 2013, Rob Herring wrote:
>> This series is dependent on my CLKSRC_OF clean-up in arm-soc, my
>> sched_clock selection series[1], and Arnd's default machine descriptor
>> patch (for default clocksource_of_init call). The full series is
>> available here:
>
> All your patches look good to me, but I'd suggest you don't depend on
> my default machine descriptor patch yet, that just makes the dependencies
> harder to track, and we can easily remove all the calls once they
> are obsoletely.
>

I really only need the hunk that calls clocksource_of_init which is
really somewhat unrelated to a default machine desc. So what if I just
pull out this hunk to a separate patch:

diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
index 955d92d..abff4e9 100644
--- a/arch/arm/kernel/time.c
+++ b/arch/arm/kernel/time.c
@@ -22,6 +22,7 @@
#include <linux/errno.h>
#include <linux/profile.h>
#include <linux/timer.h>
+#include <linux/clocksource.h>
#include <linux/irq.h>

#include <asm/thread_info.h>
@@ -115,6 +116,10 @@ int __init
register_persistent_clock(clock_access_fn read_boot,

void __init time_init(void)
{
- machine_desc->init_time();
+ if (machine_desc->init_time)
+ machine_desc->init_time();
+ else
+ clocksource_of_init();
+
sched_clock_postinit();
}

2013-03-21 14:18:44

by Mark Rutland

[permalink] [raw]
Subject: Re: [PATCH 01/11] OF: add empty of_device_is_available for !OF

On Wed, Mar 20, 2013 at 10:54:01PM +0000, Rob Herring wrote:
> From: Rob Herring <[email protected]>
>
> Add an empty version of of_device_is_available.
>
> Signed-off-by: Rob Herring <[email protected]>
> ---
> include/linux/of.h | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/include/linux/of.h b/include/linux/of.h
> index a0f1292..6fe655b 100644
> --- a/include/linux/of.h
> +++ b/include/linux/of.h
> @@ -379,6 +379,11 @@ static inline int of_device_is_compatible(const struct device_node *device,
> return 0;
> }
>
> +static inline int of_device_is_available(const struct device_node *device,)

I assume that comma shouldn't be there? ^

Mark.

2013-03-21 14:26:49

by Rob Herring

[permalink] [raw]
Subject: Re: [PATCH 01/11] OF: add empty of_device_is_available for !OF

On 03/21/2013 09:18 AM, Mark Rutland wrote:
> On Wed, Mar 20, 2013 at 10:54:01PM +0000, Rob Herring wrote:
>> From: Rob Herring <[email protected]>
>>
>> Add an empty version of of_device_is_available.
>>
>> Signed-off-by: Rob Herring <[email protected]>
>> ---
>> include/linux/of.h | 5 +++++
>> 1 file changed, 5 insertions(+)
>>
>> diff --git a/include/linux/of.h b/include/linux/of.h
>> index a0f1292..6fe655b 100644
>> --- a/include/linux/of.h
>> +++ b/include/linux/of.h
>> @@ -379,6 +379,11 @@ static inline int of_device_is_compatible(const struct device_node *device,
>> return 0;
>> }
>>
>> +static inline int of_device_is_available(const struct device_node *device,)
>
> I assume that comma shouldn't be there? ^

Right. I've fixed that up in my git tree.

Rob

2013-03-21 17:58:11

by Linus Walleij

[permalink] [raw]
Subject: Re: [PATCH 02/11] ARM: remove extra timer-sp control register clearing

On Wed, Mar 20, 2013 at 11:54 PM, Rob Herring <[email protected]> wrote:

> From: Rob Herring <[email protected]>
>
> The timer-sp initialization code clears the control register before
> initializing the timers, so every platform doing this is redundant.
>
> For unused timers, we should not care what state they are in.
>
> Signed-off-by: Rob Herring <[email protected]>
(...)
> diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c
> index ea96144..4cb322d 100644
> --- a/arch/arm/mach-integrator/integrator_ap.c
> +++ b/arch/arm/mach-integrator/integrator_ap.c
> @@ -643,10 +643,6 @@ static void __init ap_timer_init(void)
> clk_prepare_enable(clk);
> rate = clk_get_rate(clk);
>
> - writel(0, TIMER0_VA_BASE + TIMER_CTRL);
> - writel(0, TIMER1_VA_BASE + TIMER_CTRL);
> - writel(0, TIMER2_VA_BASE + TIMER_CTRL);
> -

As noted this is not an init function for timer-sp.c so please drop this
hunk of the patch. Maybe this zeroing is pointless but that would
be a separate patch that I can test.

> diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c
> index 2b0db82..c68e7d8 100644
> --- a/arch/arm/mach-integrator/integrator_cp.c
> +++ b/arch/arm/mach-integrator/integrator_cp.c
> @@ -33,7 +33,6 @@
> #include <mach/platform.h>
> #include <asm/setup.h>
> #include <asm/mach-types.h>
> -#include <asm/hardware/arm_timer.h>

What doe this change has to do with $SUBJECT?

> #include <asm/hardware/icst.h>
>
> #include <mach/cm.h>
> @@ -267,7 +266,6 @@ static void __init cp_of_timer_init(void)
> base = of_iomap(node, 0);
> if (WARN_ON(!base))
> return;
> - writel(0, base + TIMER_CTRL);
> sp804_clocksource_init(base, node->name);
>
> err = of_property_read_string(of_aliases,
> @@ -279,7 +277,6 @@ static void __init cp_of_timer_init(void)
> if (WARN_ON(!base))
> return;
> irq = irq_of_parse_and_map(node, 0);
> - writel(0, base + TIMER_CTRL);
> sp804_clockevents_init(base, irq, node->name);
> }
>
> @@ -510,10 +507,6 @@ static void __init intcp_init_irq(void)
>
> static void __init cp_timer_init(void)
> {
> - writel(0, TIMER0_VA_BASE + TIMER_CTRL);
> - writel(0, TIMER1_VA_BASE + TIMER_CTRL);
> - writel(0, TIMER2_VA_BASE + TIMER_CTRL);
> -
> sp804_clocksource_init(TIMER2_VA_BASE, "timer2");
> sp804_clockevents_init(TIMER1_VA_BASE, IRQ_TIMERINT1, "timer1");
> }

The rest of the changes to integrator_cp.c looks OK...

Yours,
Linus Walleij

2013-03-21 18:03:00

by Linus Walleij

[permalink] [raw]
Subject: Re: [PATCH 03/11] ARM: timer-sp: convert to use CLKSRC_OF init

On Wed, Mar 20, 2013 at 11:54 PM, Rob Herring <[email protected]> wrote:

> From: Rob Herring <[email protected]>
>
> This adds CLKSRC_OF based init for sp804 timer. The clock initialization is
> refactored to support retrieving the clock(s) from the DT.
>
> Signed-off-by: Rob Herring <[email protected]>
(...)
> @@ -186,6 +201,57 @@ void __init sp804_clockevents_init(void __iomem *base, unsigned int irq,
> evt->irq = irq;
> evt->cpumask = cpu_possible_mask;
>
> + writel(0, clkevt_base + TIMER_CTRL);
> +

Wait, patch 1/11 depends on this being done first, right?

So patch 1/11 has to be moved after this one in the series
to avoid bisectability problems?

Apart from that:
Acked-by: Linus Walleij <[email protected]>

Yours,
Linus Walleij

2013-03-21 18:04:05

by Rob Herring

[permalink] [raw]
Subject: Re: [PATCH 02/11] ARM: remove extra timer-sp control register clearing

On 03/21/2013 12:58 PM, Linus Walleij wrote:
> On Wed, Mar 20, 2013 at 11:54 PM, Rob Herring <[email protected]> wrote:
>
>> From: Rob Herring <[email protected]>
>>
>> The timer-sp initialization code clears the control register before
>> initializing the timers, so every platform doing this is redundant.
>>
>> For unused timers, we should not care what state they are in.
>>
>> Signed-off-by: Rob Herring <[email protected]>
> (...)
>> diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c
>> index ea96144..4cb322d 100644
>> --- a/arch/arm/mach-integrator/integrator_ap.c
>> +++ b/arch/arm/mach-integrator/integrator_ap.c
>> @@ -643,10 +643,6 @@ static void __init ap_timer_init(void)
>> clk_prepare_enable(clk);
>> rate = clk_get_rate(clk);
>>
>> - writel(0, TIMER0_VA_BASE + TIMER_CTRL);
>> - writel(0, TIMER1_VA_BASE + TIMER_CTRL);
>> - writel(0, TIMER2_VA_BASE + TIMER_CTRL);
>> -
>
> As noted this is not an init function for timer-sp.c so please drop this
> hunk of the patch. Maybe this zeroing is pointless but that would
> be a separate patch that I can test.

Okay. I'll split this out.

>
>> diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c
>> index 2b0db82..c68e7d8 100644
>> --- a/arch/arm/mach-integrator/integrator_cp.c
>> +++ b/arch/arm/mach-integrator/integrator_cp.c
>> @@ -33,7 +33,6 @@
>> #include <mach/platform.h>
>> #include <asm/setup.h>
>> #include <asm/mach-types.h>
>> -#include <asm/hardware/arm_timer.h>
>
> What doe this change has to do with $SUBJECT?

If I remove TIMER_CTRL use, then I don't need the header that defines it
any more.

Rob

2013-03-21 18:07:30

by Linus Walleij

[permalink] [raw]
Subject: Re: [PATCH 09/11] ARM: integrator-cp: convert use CLKSRC_OF for timer init

On Wed, Mar 20, 2013 at 11:54 PM, Rob Herring <[email protected]> wrote:

> From: Rob Herring <[email protected]>
>
> Move the integrator-cp timer init to timer-sp.c and use CLKSRC_OF. There is
> no reason to use the aliases, so drop them from the init code.
>
> The integrator-cp timers are mistakenly called sp804 timers in the dts, but
> in fact they are not sp804 dual timers, but single timers with the same
> programming model. Fix the dts to reflect this.
>
> Signed-off-by: Rob Herring <[email protected]>

Looks correct to me. Throw it into linux-next and I'll
test if it works too! :-)
Acked-by: Linus Walleij <[email protected]>

Yours,
Linus Walleij

2013-03-21 18:15:44

by Linus Walleij

[permalink] [raw]
Subject: Re: [PATCH 10/11] ARM: move sp804 and integrator timers to drivers/clocksource

On Wed, Mar 20, 2013 at 11:54 PM, Rob Herring <[email protected]> wrote:

> From: Rob Herring <[email protected]>
>
> Move timer-sp and integrator-ap timer code to drivers/clocksource and
> update timer-sp.h and arm_timer.h includes.
>
> This adds CLKSRC_OF support for the integrator-ap timer and removes the
> use of "arm,timer-primary" and "arm,timer-secondary" aliases. The timer
> selection should not be important as all 3 timers are equal capability.
>
> Signed-off-by: Rob Herring <[email protected]>
> Cc: Russell King <[email protected]>
> Cc: John Stultz <[email protected]>
> Cc: Thomas Gleixner <[email protected]>

Nice!

This looks like it'll work.

Acked-by: Linus Walleij <[email protected]>

Yours,
Linus Walleij

2013-03-21 20:09:54

by Russell King - ARM Linux

[permalink] [raw]
Subject: Re: [PATCH 03/11] ARM: timer-sp: convert to use CLKSRC_OF init

On Wed, Mar 20, 2013 at 05:54:03PM -0500, Rob Herring wrote:
> + clk0 = of_clk_get(np, 0);
> + if (IS_ERR(clk0))
> + clk0 = NULL;
> +
> + /* Get the 2nd clock if the timer has 2 timer clocks */
> + if (of_count_phandle_with_args(np, "clocks", "#clock-cells") == 3) {
> + clk1 = of_clk_get(np, 1);
> + if (IS_ERR(clk1)) {
> + pr_err("sp804: %s clock not found: %d\n", np->name,
> + (int)PTR_ERR(clk1));
> + return;
> + }
> + } else
> + clk1 = clk0;
> +
> + irq = irq_of_parse_and_map(np, 0);
> + if (irq <= 0)
> + return;
> +
> + of_property_read_u32(np, "arm,sp804-has-irq", &irq_num);
> + if (irq_num == 2)
> + tmr2_evt = true;
> +
> + __sp804_clockevents_init(base + (tmr2_evt ? TIMER_2_BASE : 0),
> + irq, tmr2_evt ? clk1 : clk0, name);
> + __sp804_clocksource_and_sched_clock_init(base + (tmr2_evt ? 0 : TIMER_2_BASE),
> + name, tmr2_evt ? clk0 : clk1, 1);

This just looks totally screwed to me.

A SP804 cell has two timers, and has one clock input and two clock
enable inputs. The clock input is common to both timers. The timers
only count on the rising edge of the clock input when the enable
input is high. (the APB PCLK also matters too...)

Now, the clock enable inputs are controlled by the SP810 system
controller to achieve different clock rates for each. So, we *can*
view an SP804 as having two clock inputs.

However, the two clock inputs do not depend on whether one or the
other has an IRQ or not. Timer 1 is always clocked by TIMCLK &
TIMCLKEN1. Timer 2 is always clocked by TIMCLK & TIMCLKEN2.

Using the logic above, the clocks depend on how the IRQs are wired
up... really? Can you see from my description above why that is
screwed? What bearing does the IRQ have on the wiring of the
clock inputs?

And, by doing this aren't you embedding into the DT description
something specific to the Linux implementation for this device -
namely the decision by you that the IRQs determine how the clocks
get used?

So... NAK.

2013-03-21 20:13:11

by Russell King - ARM Linux

[permalink] [raw]
Subject: Re: [PATCH 02/11] ARM: remove extra timer-sp control register clearing

On Wed, Mar 20, 2013 at 05:54:02PM -0500, Rob Herring wrote:
> From: Rob Herring <[email protected]>
>
> The timer-sp initialization code clears the control register before
> initializing the timers, so every platform doing this is redundant.
>
> For unused timers, we should not care what state they are in.

NAK. We do care what state they're in. What if they have their interrupt
enable bit set, and IRQ is shared with the clock event timer?

No, this patch is just wrong.

2013-03-21 20:13:33

by Russell King - ARM Linux

[permalink] [raw]
Subject: Re: [PATCH 11/11] devtree: add binding documentation for sp804

On Wed, Mar 20, 2013 at 05:54:11PM -0500, Rob Herring wrote:
> +Optional properties:
> +- arm,sp804-has-irq = <#>: In the case of only 1 timer irq line connected, this
> + specifies if the irq connection is for timer 1 or timer 2. A value of 1
> + or 2 should be used.

This fails to mention that it has any bearing on the clocks.

2013-03-22 02:31:06

by Rob Herring

[permalink] [raw]
Subject: Re: [PATCH 03/11] ARM: timer-sp: convert to use CLKSRC_OF init

On 03/21/2013 02:35 PM, Russell King - ARM Linux wrote:
> On Wed, Mar 20, 2013 at 05:54:03PM -0500, Rob Herring wrote:
>> + clk0 = of_clk_get(np, 0);
>> + if (IS_ERR(clk0))
>> + clk0 = NULL;
>> +
>> + /* Get the 2nd clock if the timer has 2 timer clocks */
>> + if (of_count_phandle_with_args(np, "clocks", "#clock-cells") == 3) {
>> + clk1 = of_clk_get(np, 1);
>> + if (IS_ERR(clk1)) {
>> + pr_err("sp804: %s clock not found: %d\n", np->name,
>> + (int)PTR_ERR(clk1));
>> + return;
>> + }
>> + } else
>> + clk1 = clk0;
>> +
>> + irq = irq_of_parse_and_map(np, 0);
>> + if (irq <= 0)
>> + return;
>> +
>> + of_property_read_u32(np, "arm,sp804-has-irq", &irq_num);
>> + if (irq_num == 2)
>> + tmr2_evt = true;
>> +
>> + __sp804_clockevents_init(base + (tmr2_evt ? TIMER_2_BASE : 0),
>> + irq, tmr2_evt ? clk1 : clk0, name);
>> + __sp804_clocksource_and_sched_clock_init(base + (tmr2_evt ? 0 : TIMER_2_BASE),
>> + name, tmr2_evt ? clk0 : clk1, 1);
>
> This just looks totally screwed to me.
>
> A SP804 cell has two timers, and has one clock input and two clock
> enable inputs. The clock input is common to both timers. The timers
> only count on the rising edge of the clock input when the enable
> input is high. (the APB PCLK also matters too...)
>
> Now, the clock enable inputs are controlled by the SP810 system
> controller to achieve different clock rates for each. So, we *can*
> view an SP804 as having two clock inputs.

Exactly. Effectively, the TIMCLKENx are just dividers of the clock input.

> However, the two clock inputs do not depend on whether one or the
> other has an IRQ or not. Timer 1 is always clocked by TIMCLK &
> TIMCLKEN1. Timer 2 is always clocked by TIMCLK & TIMCLKEN2.
>
> Using the logic above, the clocks depend on how the IRQs are wired
> up... really? Can you see from my description above why that is
> screwed? What bearing does the IRQ have on the wiring of the
> clock inputs?

No. I'm simply swapping which timer is used for clksrc vs. clkevt based
on the irq connection DT describes. If only timer 2's irq being hooked
up, then timer 2 is the clkevt. Otherwise I always use timer 1 for the
clkevt because I either have a combined interrupt or timer 1 interrupt
hooked up.

Perhaps re-writing it like this would be more clear:

if (irq_num == 2){
__sp804_clockevents_init(base + TIMER_2_BASE, irq, clk1, name);
__sp804_clocksource_and_sched_clock_init(base, name, clk0, 1);
} else {
__sp804_clockevents_init(base, irq, clk0, name);
__sp804_clocksource_and_sched_clock_init(base + TIMER_2_BASE,
name, clk1, 1);
}


Rob

2013-03-22 02:36:20

by Rob Herring

[permalink] [raw]
Subject: Re: [PATCH 02/11] ARM: remove extra timer-sp control register clearing

On 03/21/2013 02:23 PM, Russell King - ARM Linux wrote:
> On Wed, Mar 20, 2013 at 05:54:02PM -0500, Rob Herring wrote:
>> From: Rob Herring <[email protected]>
>>
>> The timer-sp initialization code clears the control register before
>> initializing the timers, so every platform doing this is redundant.
>>
>> For unused timers, we should not care what state they are in.
>
> NAK. We do care what state they're in. What if they have their interrupt
> enable bit set, and IRQ is shared with the clock event timer?
>
> No, this patch is just wrong.

Okay, I can have the timer init function clear the register in the case
that even when the timer is unused.

Rob

2013-03-22 11:49:58

by Russell King - ARM Linux

[permalink] [raw]
Subject: Re: [PATCH 03/11] ARM: timer-sp: convert to use CLKSRC_OF init

On Thu, Mar 21, 2013 at 09:31:01PM -0500, Rob Herring wrote:
> Perhaps re-writing it like this would be more clear:
>
> if (irq_num == 2){
> __sp804_clockevents_init(base + TIMER_2_BASE, irq, clk1, name);
> __sp804_clocksource_and_sched_clock_init(base, name, clk0, 1);
> } else {
> __sp804_clockevents_init(base, irq, clk0, name);
> __sp804_clocksource_and_sched_clock_init(base + TIMER_2_BASE,
> name, clk1, 1);
> }

Yes, that is definitely much clearer than the original patch.