From c115739da801ea1ea20c48e2991ce6761496bef1 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 8 Feb 2013 16:14:59 -0600 Subject: ARM: sched_clock: allow changing to higher frequency counter Allow multiple calls to setup_sched_clock and switch to the new counter if it is higher frequency. Signed-off-by: Rob Herring diff --git a/arch/arm/kernel/sched_clock.c b/arch/arm/kernel/sched_clock.c index bd6f56b..040168e 100644 --- a/arch/arm/kernel/sched_clock.c +++ b/arch/arm/kernel/sched_clock.c @@ -20,6 +20,7 @@ struct clock_data { u64 epoch_ns; u32 epoch_cyc; u32 epoch_cyc_copy; + unsigned long rate; u32 mult; u32 shift; bool suspended; @@ -113,11 +114,14 @@ void __init setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate) u64 res, wrap; char r_unit; + if (cd.rate > rate) + return; + BUG_ON(bits > 32); WARN_ON(!irqs_disabled()); - WARN_ON(read_sched_clock != jiffy_sched_clock_read); read_sched_clock = read; sched_clock_mask = (1 << bits) - 1; + cd.rate = rate; /* calculate the mult/shift to convert counter ticks to ns. */ clocks_calc_mult_shift(&cd.mult, &cd.shift, rate, NSEC_PER_SEC, 0); -- cgit v0.10.2 From 7e48c0b9d9ab07c92cd26f167010cd5a50eb0cec Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 1 Apr 2013 13:53:38 -0500 Subject: ARM: make sched_clock just call a function pointer This converts sched_clock to simply a call to a function pointer in order to allow overriding it. This will allow for use with 64-bit counters where overflow handling is not needed. Signed-off-by: Rob Herring diff --git a/arch/arm/include/asm/sched_clock.h b/arch/arm/include/asm/sched_clock.h index e3f7572..3d520dd 100644 --- a/arch/arm/include/asm/sched_clock.h +++ b/arch/arm/include/asm/sched_clock.h @@ -11,4 +11,6 @@ extern void sched_clock_postinit(void); extern void setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate); +extern unsigned long long (*sched_clock_func)(void); + #endif diff --git a/arch/arm/kernel/sched_clock.c b/arch/arm/kernel/sched_clock.c index 040168e..8805848 100644 --- a/arch/arm/kernel/sched_clock.c +++ b/arch/arm/kernel/sched_clock.c @@ -165,12 +165,19 @@ void __init setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate) pr_debug("Registered %pF as sched_clock source\n", read); } -unsigned long long notrace sched_clock(void) +static unsigned long long notrace sched_clock_32(void) { u32 cyc = read_sched_clock(); return cyc_to_sched_clock(cyc, sched_clock_mask); } +unsigned long long __read_mostly (*sched_clock_func)(void) = sched_clock_32; + +unsigned long long notrace sched_clock(void) +{ + return sched_clock_func(); +} + void __init sched_clock_postinit(void) { /* -- cgit v0.10.2 From 023796b9be3a77481cd5ee0b64a13a55bb0d5df4 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 11 Mar 2013 16:23:46 -0500 Subject: ARM: arch_timer: use full 64-bit counter for sched_clock Only 32-bits of the arch timer were being used and wrapping was needlessly being done in s/w. By using the full counter (56-64 bits), we don't need to deal with wrapping and can simplify the implementation when using arch timer. Signed-off-by: Rob Herring diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c index d957a51..80c458f 100644 --- a/arch/arm/kernel/arch_timer.c +++ b/arch/arm/kernel/arch_timer.c @@ -22,9 +22,11 @@ static unsigned long arch_timer_read_counter_long(void) return arch_timer_read_counter(); } -static u32 arch_timer_read_counter_u32(void) +static u32 sched_clock_mult __read_mostly; + +static unsigned long long notrace arch_timer_sched_clock(void) { - return arch_timer_read_counter(); + return arch_timer_read_counter() * sched_clock_mult; } static struct delay_timer arch_delay_timer; @@ -52,10 +54,16 @@ int __init arch_timer_of_register(void) int __init arch_timer_sched_clock_init(void) { - if (arch_timer_get_rate() == 0) + u32 arch_timer_rate = arch_timer_get_rate(); + + if (arch_timer_rate == 0) return -ENXIO; - setup_sched_clock(arch_timer_read_counter_u32, - 32, arch_timer_get_rate()); + /* Cache the sched_clock multiplier to save a divide in the hot path. */ + sched_clock_mult = NSEC_PER_SEC / arch_timer_rate; + sched_clock_func = arch_timer_sched_clock; + pr_info("sched_clock: ARM arch timer >56 bits at %ukHz, resolution %uns\n", + arch_timer_rate / 1000, sched_clock_mult); + return 0; } -- cgit v0.10.2 From f414f13f2fd0d8bb12a87268a55827cda771d42b Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 25 Mar 2013 11:14:57 -0500 Subject: ARM: make machine_desc->init_time default to clocksource_of_init Originally from a default machine descriptor patch from Arnd, pull out just the default call to clocksource_of_init part. This is needed so that platforms can simply remove .init_time calls as they are converted to use clocksource_of_init. Signed-off-by: Arnd Bergmann Acked-by: Nicolas Pitre Acked-by: Olof Johansson Signed-off-by: Rob Herring 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 #include #include +#include #include #include @@ -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(); } -- cgit v0.10.2 From 0583fe478a7d93be2c814b7e50d6e81c287edfe8 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 10 Apr 2013 18:27:51 -0500 Subject: ARM: convert arm/arm64 arch timer to use CLKSRC_OF init This converts arm and arm64 to use CLKSRC_OF DT based initialization for the arch timer. A new function arch_timer_arch_init is added to allow for arch specific setup. This has a side effect of enabling sched_clock on omap5 and exynos5. There should not be any reason not to use the arch timers for sched_clock. Signed-off-by: Rob Herring Cc: Russell King Cc: Kukjin Kim Cc: Tony Lindgren Cc: Simon Horman Cc: Magnus Damm Cc: Catalin Marinas Cc: Will Deacon Cc: John Stultz Cc: Thomas Gleixner Cc: linux-samsung-soc@vger.kernel.org Cc: linux-omap@vger.kernel.org Cc: linux-sh@vger.kernel.org Acked-by: Santosh Shilimkar diff --git a/arch/arm/include/asm/arch_timer.h b/arch/arm/include/asm/arch_timer.h index 7ade91d..7c1bfc0 100644 --- a/arch/arm/include/asm/arch_timer.h +++ b/arch/arm/include/asm/arch_timer.h @@ -10,8 +10,7 @@ #include #ifdef CONFIG_ARM_ARCH_TIMER -int arch_timer_of_register(void); -int arch_timer_sched_clock_init(void); +int arch_timer_arch_init(void); /* * These register accessors are marked inline so the compiler can @@ -110,16 +109,6 @@ static inline void __cpuinit arch_counter_set_user_access(void) asm volatile("mcr p15, 0, %0, c14, c1, 0" : : "r" (cntkctl)); } -#else -static inline int arch_timer_of_register(void) -{ - return -ENXIO; -} - -static inline int arch_timer_sched_clock_init(void) -{ - return -ENXIO; -} #endif #endif diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c index 80c458f..59dcdce 100644 --- a/arch/arm/kernel/arch_timer.c +++ b/arch/arm/kernel/arch_timer.c @@ -39,26 +39,15 @@ static void __init arch_timer_delay_timer_register(void) register_current_timer_delay(&arch_delay_timer); } -int __init arch_timer_of_register(void) -{ - int ret; - - ret = arch_timer_init(); - if (ret) - return ret; - - arch_timer_delay_timer_register(); - - return 0; -} - -int __init arch_timer_sched_clock_init(void) +int __init arch_timer_arch_init(void) { u32 arch_timer_rate = arch_timer_get_rate(); if (arch_timer_rate == 0) return -ENXIO; + arch_timer_delay_timer_register(); + /* Cache the sched_clock multiplier to save a divide in the hot path. */ sched_clock_mult = NSEC_PER_SEC / arch_timer_rate; sched_clock_func = arch_timer_sched_clock; diff --git a/arch/arm/mach-exynos/mach-exynos5-dt.c b/arch/arm/mach-exynos/mach-exynos5-dt.c index acaeb14..4d97b43 100644 --- a/arch/arm/mach-exynos/mach-exynos5-dt.c +++ b/arch/arm/mach-exynos/mach-exynos5-dt.c @@ -216,7 +216,6 @@ DT_MACHINE_START(EXYNOS5_DT, "SAMSUNG EXYNOS5 (Flattened Device Tree)") .map_io = exynos5_dt_map_io, .init_machine = exynos5_dt_machine_init, .init_late = exynos_init_late, - .init_time = exynos4_timer_init, .dt_compat = exynos5_dt_compat, .restart = exynos5_restart, .reserve = exynos5_reserve, diff --git a/arch/arm/mach-exynos/mct.c b/arch/arm/mach-exynos/mct.c index c9d6650..04aff6a 100644 --- a/arch/arm/mach-exynos/mct.c +++ b/arch/arm/mach-exynos/mct.c @@ -21,7 +21,6 @@ #include #include -#include #include #include @@ -469,11 +468,6 @@ static void __init exynos4_timer_resources(void) void __init exynos4_timer_init(void) { - if (soc_is_exynos5440()) { - arch_timer_of_register(); - return; - } - if ((soc_is_exynos4210()) || (soc_is_exynos5250())) mct_int_type = MCT_INT_SPI; else diff --git a/arch/arm/mach-highbank/highbank.c b/arch/arm/mach-highbank/highbank.c index 76c1170..758150e 100644 --- a/arch/arm/mach-highbank/highbank.c +++ b/arch/arm/mach-highbank/highbank.c @@ -15,6 +15,7 @@ */ #include #include +#include #include #include #include @@ -28,7 +29,6 @@ #include #include -#include #include #include #include @@ -118,9 +118,6 @@ static void __init highbank_timer_init(void) sp804_clocksource_and_sched_clock_init(timer_base + 0x20, "timer1"); sp804_clockevents_init(timer_base, irq, "timer0"); - arch_timer_of_register(); - arch_timer_sched_clock_init(); - clocksource_of_init(); } diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index 4fd8025..7dd6453 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c @@ -46,7 +46,6 @@ #include #include -#include #include "omap_hwmod.h" #include "omap_device.h" #include @@ -624,9 +623,7 @@ void __init omap5_realtime_timer_init(void) omap5_sync32k_timer_init(); realtime_counter_init(); - err = arch_timer_of_register(); - if (err) - pr_err("%s: arch_timer_register failed %d\n", __func__, err); + clocksource_of_init(); } #endif /* CONFIG_SOC_OMAP5 */ diff --git a/arch/arm/mach-shmobile/board-kzm9d.c b/arch/arm/mach-shmobile/board-kzm9d.c index c254782..c016ccd 100644 --- a/arch/arm/mach-shmobile/board-kzm9d.c +++ b/arch/arm/mach-shmobile/board-kzm9d.c @@ -90,6 +90,5 @@ DT_MACHINE_START(KZM9D_DT, "kzm9d") .init_irq = emev2_init_irq, .init_machine = kzm9d_add_standard_devices, .init_late = shmobile_init_late, - .init_time = shmobile_timer_init, .dt_compat = kzm9d_boards_compat_dt, MACHINE_END diff --git a/arch/arm/mach-shmobile/setup-emev2.c b/arch/arm/mach-shmobile/setup-emev2.c index 47662a5..4e38a66 100644 --- a/arch/arm/mach-shmobile/setup-emev2.c +++ b/arch/arm/mach-shmobile/setup-emev2.c @@ -456,7 +456,6 @@ DT_MACHINE_START(EMEV2_DT, "Generic Emma Mobile EV2 (Flattened Device Tree)") .nr_irqs = NR_IRQS_LEGACY, .init_irq = irqchip_init, .init_machine = emev2_add_standard_devices_dt, - .init_time = shmobile_timer_init, .dt_compat = emev2_boards_compat_dt, MACHINE_END diff --git a/arch/arm/mach-shmobile/setup-r8a7740.c b/arch/arm/mach-shmobile/setup-r8a7740.c index 8b85d4d..104b474 100644 --- a/arch/arm/mach-shmobile/setup-r8a7740.c +++ b/arch/arm/mach-shmobile/setup-r8a7740.c @@ -906,7 +906,6 @@ DT_MACHINE_START(R8A7740_DT, "Generic R8A7740 (Flattened Device Tree)") .init_irq = r8a7740_init_irq, .handle_irq = shmobile_handle_irq_intc, .init_machine = r8a7740_add_standard_devices_dt, - .init_time = shmobile_timer_init, .dt_compat = r8a7740_boards_compat_dt, MACHINE_END diff --git a/arch/arm/mach-shmobile/setup-sh7372.c b/arch/arm/mach-shmobile/setup-sh7372.c index 59c7146..5502d62 100644 --- a/arch/arm/mach-shmobile/setup-sh7372.c +++ b/arch/arm/mach-shmobile/setup-sh7372.c @@ -1175,7 +1175,6 @@ DT_MACHINE_START(SH7372_DT, "Generic SH7372 (Flattened Device Tree)") .init_irq = sh7372_init_irq, .handle_irq = shmobile_handle_irq_intc, .init_machine = sh7372_add_standard_devices_dt, - .init_time = shmobile_timer_init, .dt_compat = sh7372_boards_compat_dt, MACHINE_END diff --git a/arch/arm/mach-shmobile/setup-sh73a0.c b/arch/arm/mach-shmobile/setup-sh73a0.c index bdab575..ea66316 100644 --- a/arch/arm/mach-shmobile/setup-sh73a0.c +++ b/arch/arm/mach-shmobile/setup-sh73a0.c @@ -923,7 +923,6 @@ DT_MACHINE_START(SH73A0_DT, "Generic SH73A0 (Flattened Device Tree)") .nr_irqs = NR_IRQS_LEGACY, .init_irq = sh73a0_init_irq_dt, .init_machine = sh73a0_add_standard_devices_dt, - .init_time = shmobile_timer_init, .dt_compat = sh73a0_boards_compat_dt, MACHINE_END #endif /* CONFIG_USE_OF */ diff --git a/arch/arm/mach-shmobile/timer.c b/arch/arm/mach-shmobile/timer.c index 3d16d4d..f321dbe 100644 --- a/arch/arm/mach-shmobile/timer.c +++ b/arch/arm/mach-shmobile/timer.c @@ -19,10 +19,8 @@ * */ #include +#include #include -#include -#include -#include void __init shmobile_setup_delay(unsigned int max_cpu_core_mhz, unsigned int mult, unsigned int div) @@ -63,6 +61,5 @@ void __init shmobile_earlytimer_init(void) void __init shmobile_timer_init(void) { - arch_timer_of_register(); - arch_timer_sched_clock_init(); + clocksource_of_init(); } diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c index d0ad789..6215717 100644 --- a/arch/arm/mach-vexpress/v2m.c +++ b/arch/arm/mach-vexpress/v2m.c @@ -1,6 +1,7 @@ /* * Versatile Express V2M Motherboard Support */ +#include #include #include #include @@ -23,7 +24,6 @@ #include #include -#include #include #include #include @@ -446,10 +446,7 @@ static void __init v2m_dt_timer_init(void) irq_of_parse_and_map(node, 0)); } - arch_timer_of_register(); - - if (arch_timer_sched_clock_init() != 0) - versatile_sched_clock_init(vexpress_get_24mhz_clock_base(), + versatile_sched_clock_init(vexpress_get_24mhz_clock_base(), 24000000); } diff --git a/arch/arm/mach-virt/virt.c b/arch/arm/mach-virt/virt.c index 31666f6..adc0945 100644 --- a/arch/arm/mach-virt/virt.c +++ b/arch/arm/mach-virt/virt.c @@ -23,21 +23,13 @@ #include #include -#include #include -#include static void __init virt_init(void) { of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); } -static void __init virt_timer_init(void) -{ - WARN_ON(arch_timer_of_register() != 0); - WARN_ON(arch_timer_sched_clock_init() != 0); -} - static const char *virt_dt_match[] = { "linux,dummy-virt", NULL @@ -47,7 +39,6 @@ extern struct smp_operations virt_smp_ops; DT_MACHINE_START(VIRT, "Dummy Virtual Machine") .init_irq = irqchip_init, - .init_time = virt_timer_init, .init_machine = virt_init, .smp = smp_ops(virt_smp_ops), .dt_compat = virt_dt_match, diff --git a/arch/arm64/include/asm/arch_timer.h b/arch/arm64/include/asm/arch_timer.h index 91e2a6a..bf6ab242 100644 --- a/arch/arm64/include/asm/arch_timer.h +++ b/arch/arm64/include/asm/arch_timer.h @@ -130,4 +130,9 @@ static inline u64 arch_counter_get_cntvct(void) return cval; } +static inline int arch_timer_arch_init(void) +{ + return 0; +} + #endif diff --git a/arch/arm64/kernel/time.c b/arch/arm64/kernel/time.c index b0ef18d..a551f88 100644 --- a/arch/arm64/kernel/time.c +++ b/arch/arm64/kernel/time.c @@ -32,6 +32,7 @@ #include #include #include +#include #include @@ -77,10 +78,11 @@ void __init time_init(void) { u32 arch_timer_rate; - if (arch_timer_init()) - panic("Unable to initialise architected timer.\n"); + clocksource_of_init(); arch_timer_rate = arch_timer_get_rate(); + if (!arch_timer_rate) + panic("Unable to initialise architected timer.\n"); /* Cache the sched_clock multiplier to save a divide in the hot path. */ sched_clock_mult = NSEC_PER_SEC / arch_timer_rate; diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index e507ab7..d98e7e1 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -62,6 +62,7 @@ config CLKSRC_DBX500_PRCMU_SCHED_CLOCK config ARM_ARCH_TIMER bool + select CLKSRC_OF if OF config CLKSRC_METAG_GENERIC def_bool y if METAG diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index d7ad425..122ff05 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -337,22 +337,14 @@ out: return err; } -static const struct of_device_id arch_timer_of_match[] __initconst = { - { .compatible = "arm,armv7-timer", }, - { .compatible = "arm,armv8-timer", }, - {}, -}; - -int __init arch_timer_init(void) +static void __init arch_timer_init(struct device_node *np) { - struct device_node *np; u32 freq; int i; - np = of_find_matching_node(NULL, arch_timer_of_match); - if (!np) { - pr_err("arch_timer: can't find DT node\n"); - return -ENODEV; + if (arch_timer_get_rate()) { + pr_warn("arch_timer: multiple nodes in dt, skipping\n"); + return; } /* Try to determine the frequency from the device tree or CNTFRQ */ @@ -378,7 +370,7 @@ int __init arch_timer_init(void) if (!arch_timer_ppi[PHYS_SECURE_PPI] || !arch_timer_ppi[PHYS_NONSECURE_PPI]) { pr_warn("arch_timer: No interrupt available, giving up\n"); - return -EINVAL; + return; } } @@ -387,5 +379,8 @@ int __init arch_timer_init(void) else arch_timer_read_counter = arch_counter_get_cntpct; - return arch_timer_register(); + arch_timer_register(); + arch_timer_arch_init(); } +CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_init); +CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_init); diff --git a/include/clocksource/arm_arch_timer.h b/include/clocksource/arm_arch_timer.h index 2603267..e6c9c4c 100644 --- a/include/clocksource/arm_arch_timer.h +++ b/include/clocksource/arm_arch_timer.h @@ -31,18 +31,12 @@ #ifdef CONFIG_ARM_ARCH_TIMER -extern int arch_timer_init(void); extern u32 arch_timer_get_rate(void); extern u64 (*arch_timer_read_counter)(void); extern struct timecounter *arch_timer_get_timecounter(void); #else -static inline int arch_timer_init(void) -{ - return -ENXIO; -} - static inline u32 arch_timer_get_rate(void) { return 0; -- cgit v0.10.2 From d71956960c9dafaafeb19ea010c234abe9d25f10 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 20 Mar 2013 16:56:18 -0500 Subject: OF: add empty of_device_is_available for !OF Add an empty version of of_device_is_available. Signed-off-by: Rob Herring diff --git a/include/linux/of.h b/include/linux/of.h index a0f1292..95c8583 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) -- cgit v0.10.2 From 7a0eca712118862a2ac25413b7ee24deb27808ea Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 25 Mar 2013 11:23:52 -0500 Subject: ARM: timer-sp: convert to use CLKSRC_OF init 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 diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 5bfd584..10e3053 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1173,6 +1173,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..ded926f 100644 --- a/arch/arm/common/timer-sp.c +++ b/arch/arm/common/timer-sp.c @@ -25,33 +25,28 @@ #include #include #include +#include +#include +#include #include #include -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,64 @@ void __init sp804_clockevents_init(void __iomem *base, unsigned int irq, evt->irq = irq; evt->cpumask = cpu_possible_mask; + writel(0, 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; + struct clk *clk1, *clk2; + const char *name = of_get_property(np, "compatible", NULL); + + base = of_iomap(np, 0); + if (WARN_ON(!base)) + return; + + /* Ensure timers are disabled */ + writel(0, base + TIMER_CTRL); + writel(0, base + TIMER_2_BASE + TIMER_CTRL); + + if (initialized || !of_device_is_available(np)) + goto err; + + clk1 = of_clk_get(np, 0); + if (IS_ERR(clk1)) + clk1 = NULL; + + /* Get the 2nd clock if the timer has 2 timer clocks */ + if (of_count_phandle_with_args(np, "clocks", "#clock-cells") == 3) { + clk2 = of_clk_get(np, 1); + if (IS_ERR(clk2)) { + pr_err("sp804: %s clock not found: %d\n", np->name, + (int)PTR_ERR(clk2)); + goto err; + } + } else + clk2 = clk1; + + irq = irq_of_parse_and_map(np, 0); + if (irq <= 0) + goto err; + + of_property_read_u32(np, "arm,sp804-has-irq", &irq_num); + if (irq_num == 2) { + __sp804_clockevents_init(base + TIMER_2_BASE, irq, clk2, name); + __sp804_clocksource_and_sched_clock_init(base, name, clk1, 1); + } else { + __sp804_clockevents_init(base, irq, clk1 , name); + __sp804_clocksource_and_sched_clock_init(base + TIMER_2_BASE, + name, clk2, 1); + } + initialized = true; + + return; +err: + iounmap(base); +} +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); + +} -- cgit v0.10.2 From 5993b3ee98c6b1a86fc0f0a4bed12a1dd9f0eae5 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 21 Jan 2013 14:19:23 -0600 Subject: ARM: highbank: use OF init for sp804 timer Remove the highbank specific setup for the sp804 timer now that clocksource_of_init will do it. Signed-off-by: Rob Herring 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 #include #include -#include -#include #include #include #include @@ -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(); } -- cgit v0.10.2 From dabfd8fb84abfddf526123388b68a50ec14cd380 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 6 Feb 2013 21:18:31 -0600 Subject: ARM: vexpress: remove sp804 OF init Remove the vexpress specific setup for the sp804 timer now that clocksource_of_init will do it. Signed-off-by: Rob Herring Acked-by: Pawel Moll diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c index 6215717..cdc29d8 100644 --- a/arch/arm/mach-vexpress/v2m.c +++ b/arch/arm/mach-vexpress/v2m.c @@ -431,20 +431,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); -- cgit v0.10.2 From 34c2e5feeb0164baef76555141ad5b8dc84394bb Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 6 Feb 2013 21:15:09 -0600 Subject: ARM: dts: vexpress: disable CA9 core tile sp804 timer 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 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 { -- cgit v0.10.2 From b2a93b1d6b0d1af00e4796f3ef1252d2862513e3 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 25 Mar 2013 11:20:36 -0500 Subject: ARM: vexpress: remove extra timer-sp control register clearing The timer-sp initialization code clears the control register before initializing the timers, so every platform doing this is redundant. Signed-off-by: Rob Herring diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c index cdc29d8..09e571d 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"); } -- cgit v0.10.2 From cc8e9ad88487004372cae87718ff593d0a2fdc3a Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 13 Mar 2013 21:31:42 -0500 Subject: ARM: versatile: add versatile dtbs to dtbs target Add the versatile platform dtbs to the dtbs make rule. Signed-off-by: Rob Herring 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 \ -- cgit v0.10.2 From 818270d573674188cfe731992e66455e2e183e64 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 13 Mar 2013 17:07:44 -0500 Subject: ARM: versatile: use OF init for sp804 timer Enable DT based init for the sp804 timers on versatile DT platform. Signed-off-by: Rob Herring 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 25160ae..54bb80b 100644 --- a/arch/arm/mach-versatile/core.c +++ b/arch/arm/mach-versatile/core.c @@ -749,12 +749,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) @@ -785,19 +798,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)); /* * Initialise to a known state (all timers off) 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, -- cgit v0.10.2 From 870e2928cf3368ca9b06bc925d0027b0a56bcd8e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 13 Mar 2013 15:31:12 -0500 Subject: ARM: integrator-cp: convert use CLKSRC_OF for timer init 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 Acked-by: Linus Walleij 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 ded926f..ddc7407 100644 --- a/arch/arm/common/timer-sp.c +++ b/arch/arm/common/timer-sp.c @@ -31,6 +31,7 @@ #include #include +#include static long __init sp804_get_clock_rate(struct clk *clk) { @@ -262,3 +263,37 @@ err: iounmap(base); } 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); + + base = of_iomap(np, 0); + if (WARN_ON(!base)) + return; + + /* Ensure timer is disabled */ + writel(0, base + TIMER_CTRL); + + if (init_count == 2 || !of_device_is_available(np)) + goto err; + + if (!init_count) + sp804_clocksource_init(base, name); + else { + irq = irq_of_parse_and_map(np, 0); + if (irq <= 0) + goto err; + + sp804_clockevents_init(base, irq, name); + } + + init_count++; + return; +err: + iounmap(base); +} +CLOCKSOURCE_OF_DECLARE(intcp, "arm,integrator-cp-timer", integrator_cp_of_init); diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c index 2b0db82..5781f3c 100644 --- a/arch/arm/mach-integrator/integrator_cp.c +++ b/arch/arm/mach-integrator/integrator_cp.c @@ -250,39 +250,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; - writel(0, base + TIMER_CTRL); - 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); - writel(0, base + TIMER_CTRL); - 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 */ } @@ -386,7 +353,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, -- cgit v0.10.2 From 69a517b2471bcd1c5a175aad82647c1e2c24f08b Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Wed, 13 Mar 2013 13:05:34 +0800 Subject: devtree: add binding documentation for sp804 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 Signed-off-by: Rob Herring 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"; + }; -- cgit v0.10.2