From 67d06e6efa41c4135cfc4c4c5c9b55d5e3a9b6f7 Mon Sep 17 00:00:00 2001 From: Mesih Kilinc Date: Mon, 11 Feb 2019 12:21:07 +0300 Subject: [PATCH 01/16] dt-bindings: timer: Add Allwinner suniv timer Add compatible string for Allwinner suniv timer which is similar to sun4i timer. Signed-off-by: Mesih Kilinc Acked-by: Maxime Ripard Reviewed-by: Rob Herring Signed-off-by: Daniel Lezcano --- .../devicetree/bindings/timer/allwinner,sun4i-timer.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/timer/allwinner,sun4i-timer.txt b/Documentation/devicetree/bindings/timer/allwinner,sun4i-timer.txt index 5c2e23574ca0..3da9d515c03a 100644 --- a/Documentation/devicetree/bindings/timer/allwinner,sun4i-timer.txt +++ b/Documentation/devicetree/bindings/timer/allwinner,sun4i-timer.txt @@ -2,7 +2,9 @@ Allwinner A1X SoCs Timer Controller Required properties: -- compatible : should be "allwinner,sun4i-a10-timer" +- compatible : should be one of the following: + "allwinner,sun4i-a10-timer" + "allwinner,suniv-f1c100s-timer" - reg : Specifies base physical address and size of the registers. - interrupts : The interrupt of the first timer - clocks: phandle to the source clock (usually a 24 MHz fixed clock) From 0113ab803a8aee00bc136507bcc9b16466f3c3aa Mon Sep 17 00:00:00 2001 From: Mesih Kilinc Date: Mon, 11 Feb 2019 12:21:08 +0300 Subject: [PATCH 02/16] clocksource/drivers/sun4i: Add a compatible for suniv The suniv (new F-series) chip has a timer with less functionality than the A10 timer, e.g. it has only 3 channels. Add a new compatible for it. As we didn't use the extra channels on A10 either now, the code needn't to be changed. The suniv chip is based on ARM926EJ-S CPU, thus it has no architecture timer. Register sun4i_timer as sched_clock on it. Signed-off-by: Mesih Kilinc Acked-by: Maxime Ripard Acked-by: Daniel Lezcano Signed-off-by: Daniel Lezcano --- drivers/clocksource/timer-sun4i.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/clocksource/timer-sun4i.c b/drivers/clocksource/timer-sun4i.c index 6e0180aaf784..65f38f6ca714 100644 --- a/drivers/clocksource/timer-sun4i.c +++ b/drivers/clocksource/timer-sun4i.c @@ -186,7 +186,8 @@ static int __init sun4i_timer_init(struct device_node *node) */ if (of_machine_is_compatible("allwinner,sun4i-a10") || of_machine_is_compatible("allwinner,sun5i-a13") || - of_machine_is_compatible("allwinner,sun5i-a10s")) + of_machine_is_compatible("allwinner,sun5i-a10s") || + of_machine_is_compatible("allwinner,suniv-f1c100s")) sched_clock_register(sun4i_timer_sched_read, 32, timer_of_rate(&to)); @@ -218,3 +219,5 @@ static int __init sun4i_timer_init(struct device_node *node) } TIMER_OF_DECLARE(sun4i, "allwinner,sun4i-a10-timer", sun4i_timer_init); +TIMER_OF_DECLARE(suniv, "allwinner,suniv-f1c100s-timer", + sun4i_timer_init); From dfc82faad72520769ca146f857e65c23632eed5a Mon Sep 17 00:00:00 2001 From: David Abdurachmanov Date: Mon, 8 Apr 2019 10:07:45 +0200 Subject: [PATCH 03/16] clocksource/drivers/sp804: Add COMPILE_TEST to CONFIG_ARM_TIMER_SP804 This is only used on arm and arm64 platforms. Add COMPILE_TEST option. Tested with 5.1-rc3+ on Fedora/RISCV. CONFIG_ARM_TIMER_SP804 no more shows up in riscv config. Signed-off-by: David Abdurachmanov Signed-off-by: Daniel Lezcano --- drivers/clocksource/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 171502a356aa..ede5d20299b9 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -379,7 +379,7 @@ config ARM_GLOBAL_TIMER This options enables support for the ARM global timer unit config ARM_TIMER_SP804 - bool "Support for Dual Timer SP804 module" + bool "Support for Dual Timer SP804 module" if COMPILE_TEST depends on GENERIC_SCHED_CLOCK && CLKDEV_LOOKUP select CLKSRC_MMIO select TIMER_OF if OF From 95170f0708f2f499da2594b29d39ac07ea221d7a Mon Sep 17 00:00:00 2001 From: Joseph Lo Date: Tue, 2 Apr 2019 11:02:34 +0800 Subject: [PATCH 04/16] clocksource/drivers/tegra: Rework for compensation of suspend time Since the clocksource framework has the support for suspend time compensation. Re-work the driver to use that, so we can reduce the duplicate code. Suggested-by: Daniel Lezcano Signed-off-by: Joseph Lo Acked-by: Thierry Reding Signed-off-by: Daniel Lezcano --- drivers/clocksource/timer-tegra20.c | 63 +++++++++-------------------- 1 file changed, 20 insertions(+), 43 deletions(-) diff --git a/drivers/clocksource/timer-tegra20.c b/drivers/clocksource/timer-tegra20.c index fdb3d795a409..919b3568c495 100644 --- a/drivers/clocksource/timer-tegra20.c +++ b/drivers/clocksource/timer-tegra20.c @@ -60,9 +60,6 @@ static u32 usec_config; static void __iomem *timer_reg_base; #ifdef CONFIG_ARM -static void __iomem *rtc_base; -static struct timespec64 persistent_ts; -static u64 persistent_ms, last_persistent_ms; static struct delay_timer tegra_delay_timer; #endif @@ -199,40 +196,30 @@ static unsigned long tegra_delay_timer_read_counter_long(void) return readl(timer_reg_base + TIMERUS_CNTR_1US); } +static struct timer_of suspend_rtc_to = { + .flags = TIMER_OF_BASE | TIMER_OF_CLOCK, +}; + /* * tegra_rtc_read - Reads the Tegra RTC registers * Care must be taken that this funciton is not called while the * tegra_rtc driver could be executing to avoid race conditions * on the RTC shadow register */ -static u64 tegra_rtc_read_ms(void) +static u64 tegra_rtc_read_ms(struct clocksource *cs) { - u32 ms = readl(rtc_base + RTC_MILLISECONDS); - u32 s = readl(rtc_base + RTC_SHADOW_SECONDS); + u32 ms = readl(timer_of_base(&suspend_rtc_to) + RTC_MILLISECONDS); + u32 s = readl(timer_of_base(&suspend_rtc_to) + RTC_SHADOW_SECONDS); return (u64)s * MSEC_PER_SEC + ms; } -/* - * tegra_read_persistent_clock64 - Return time from a persistent clock. - * - * Reads the time from a source which isn't disabled during PM, the - * 32k sync timer. Convert the cycles elapsed since last read into - * nsecs and adds to a monotonically increasing timespec64. - * Care must be taken that this funciton is not called while the - * tegra_rtc driver could be executing to avoid race conditions - * on the RTC shadow register - */ -static void tegra_read_persistent_clock64(struct timespec64 *ts) -{ - u64 delta; - - last_persistent_ms = persistent_ms; - persistent_ms = tegra_rtc_read_ms(); - delta = persistent_ms - last_persistent_ms; - - timespec64_add_ns(&persistent_ts, delta * NSEC_PER_MSEC); - *ts = persistent_ts; -} +static struct clocksource suspend_rtc_clocksource = { + .name = "tegra_suspend_timer", + .rating = 200, + .read = tegra_rtc_read_ms, + .mask = CLOCKSOURCE_MASK(32), + .flags = CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_SUSPEND_NONSTOP, +}; #endif static int tegra_timer_common_init(struct device_node *np, struct timer_of *to) @@ -385,25 +372,15 @@ out: static int __init tegra20_init_rtc(struct device_node *np) { - struct clk *clk; + int ret; - rtc_base = of_iomap(np, 0); - if (!rtc_base) { - pr_err("Can't map RTC registers\n"); - return -ENXIO; - } + ret = timer_of_init(np, &suspend_rtc_to); + if (ret) + return ret; - /* - * rtc registers are used by read_persistent_clock, keep the rtc clock - * enabled - */ - clk = of_clk_get(np, 0); - if (IS_ERR(clk)) - pr_warn("Unable to get rtc-tegra clock\n"); - else - clk_prepare_enable(clk); + clocksource_register_hz(&suspend_rtc_clocksource, 1000); - return register_persistent_clock(tegra_read_persistent_clock64); + return 0; } TIMER_OF_DECLARE(tegra20_rtc, "nvidia,tegra20-rtc", tegra20_init_rtc); #endif From f0b1ca623d8df5dad977f22a1142a81a886b0eb8 Mon Sep 17 00:00:00 2001 From: Sugaya Taichi Date: Fri, 12 Apr 2019 16:36:49 +0900 Subject: [PATCH 05/16] clocksource/drivers/timer-milbeaut: Fix to enable one-shot timer Fix mlb_set_oneshot_state() to enable one-shot timer. The function should stop and start a timer, but "start" statement was dropped. Kick the register to start one-shot timer. Fixes: b58f28f306db ("clocksource/drivers/timer-milbeaut: Introduce timer for Milbeaut SoCs") Signed-off-by: Sugaya Taichi Signed-off-by: Daniel Lezcano --- drivers/clocksource/timer-milbeaut.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clocksource/timer-milbeaut.c b/drivers/clocksource/timer-milbeaut.c index f2019a88e3ee..9fd5d081fac4 100644 --- a/drivers/clocksource/timer-milbeaut.c +++ b/drivers/clocksource/timer-milbeaut.c @@ -79,6 +79,8 @@ static int mlb_set_state_oneshot(struct clock_event_device *clk) struct timer_of *to = to_timer_of(clk); u32 val = MLB_TMR_TMCSR_CSL_DIV2; + writel_relaxed(val, timer_of_base(to) + MLB_TMR_EVT_TMCSR_OFS); + val |= MLB_TMR_TMCSR_CNTE | MLB_TMR_TMCSR_TRG | MLB_TMR_TMCSR_INTE; writel_relaxed(val, timer_of_base(to) + MLB_TMR_EVT_TMCSR_OFS); return 0; } From 95d5dc712634901e6707d3178e6170aa6e0a43ce Mon Sep 17 00:00:00 2001 From: Sugaya Taichi Date: Fri, 12 Apr 2019 16:36:50 +0900 Subject: [PATCH 06/16] clocksource/drivers/timer-milbeaut: Add shutdown function Add a shutdown operation to support shutdown timer. Signed-off-by: Sugaya Taichi Signed-off-by: Daniel Lezcano --- drivers/clocksource/timer-milbeaut.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/clocksource/timer-milbeaut.c b/drivers/clocksource/timer-milbeaut.c index 9fd5d081fac4..f4780619dbaf 100644 --- a/drivers/clocksource/timer-milbeaut.c +++ b/drivers/clocksource/timer-milbeaut.c @@ -85,6 +85,15 @@ static int mlb_set_state_oneshot(struct clock_event_device *clk) return 0; } +static int mlb_set_state_shutdown(struct clock_event_device *clk) +{ + struct timer_of *to = to_timer_of(clk); + u32 val = MLB_TMR_TMCSR_CSL_DIV2; + + writel_relaxed(val, timer_of_base(to) + MLB_TMR_EVT_TMCSR_OFS); + return 0; +} + static int mlb_clkevt_next_event(unsigned long event, struct clock_event_device *clk) { @@ -125,6 +134,7 @@ static struct timer_of to = { .features = CLOCK_EVT_FEAT_DYNIRQ | CLOCK_EVT_FEAT_ONESHOT, .set_state_oneshot = mlb_set_state_oneshot, .set_state_periodic = mlb_set_state_periodic, + .set_state_shutdown = mlb_set_state_shutdown, .set_next_event = mlb_clkevt_next_event, }, From 37dbf65c6a1fb7978ebc818c6fa9a4cf54ded2f9 Mon Sep 17 00:00:00 2001 From: Sugaya Taichi Date: Fri, 12 Apr 2019 16:36:51 +0900 Subject: [PATCH 07/16] clocksource/drivers/timer-milbeaut: Cleanup common register accesses Aggregate common register accesses into shared functions for maintainability. Signed-off-by: Sugaya Taichi Signed-off-by: Daniel Lezcano --- drivers/clocksource/timer-milbeaut.c | 66 +++++++++++++++++----------- 1 file changed, 41 insertions(+), 25 deletions(-) diff --git a/drivers/clocksource/timer-milbeaut.c b/drivers/clocksource/timer-milbeaut.c index f4780619dbaf..fa9fb4eacade 100644 --- a/drivers/clocksource/timer-milbeaut.c +++ b/drivers/clocksource/timer-milbeaut.c @@ -26,8 +26,8 @@ #define MLB_TMR_TMCSR_CSL_DIV2 0 #define MLB_TMR_DIV_CNT 2 -#define MLB_TMR_SRC_CH (1) -#define MLB_TMR_EVT_CH (0) +#define MLB_TMR_SRC_CH 1 +#define MLB_TMR_EVT_CH 0 #define MLB_TMR_SRC_CH_OFS (MLB_TMR_REGSZPCH * MLB_TMR_SRC_CH) #define MLB_TMR_EVT_CH_OFS (MLB_TMR_REGSZPCH * MLB_TMR_EVT_CH) @@ -43,6 +43,8 @@ #define MLB_TMR_EVT_TMRLR2_OFS (MLB_TMR_EVT_CH_OFS + MLB_TMR_TMRLR2_OFS) #define MLB_TIMER_RATING 500 +#define MLB_TIMER_ONESHOT 0 +#define MLB_TIMER_PERIODIC 1 static irqreturn_t mlb_timer_interrupt(int irq, void *dev_id) { @@ -59,38 +61,53 @@ static irqreturn_t mlb_timer_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +static void mlb_evt_timer_start(struct timer_of *to, bool periodic) +{ + u32 val = MLB_TMR_TMCSR_CSL_DIV2; + + val |= MLB_TMR_TMCSR_CNTE | MLB_TMR_TMCSR_TRG | MLB_TMR_TMCSR_INTE; + if (periodic) + val |= MLB_TMR_TMCSR_RELD; + writel_relaxed(val, timer_of_base(to) + MLB_TMR_EVT_TMCSR_OFS); +} + +static void mlb_evt_timer_stop(struct timer_of *to) +{ + u32 val = readl_relaxed(timer_of_base(to) + MLB_TMR_EVT_TMCSR_OFS); + + val &= ~MLB_TMR_TMCSR_CNTE; + writel_relaxed(val, timer_of_base(to) + MLB_TMR_EVT_TMCSR_OFS); +} + +static void mlb_evt_timer_register_count(struct timer_of *to, unsigned long cnt) +{ + writel_relaxed(cnt, timer_of_base(to) + MLB_TMR_EVT_TMRLR1_OFS); +} + static int mlb_set_state_periodic(struct clock_event_device *clk) { struct timer_of *to = to_timer_of(clk); - u32 val = MLB_TMR_TMCSR_CSL_DIV2; - writel_relaxed(val, timer_of_base(to) + MLB_TMR_EVT_TMCSR_OFS); - - writel_relaxed(to->of_clk.period, timer_of_base(to) + - MLB_TMR_EVT_TMRLR1_OFS); - val |= MLB_TMR_TMCSR_RELD | MLB_TMR_TMCSR_CNTE | - MLB_TMR_TMCSR_TRG | MLB_TMR_TMCSR_INTE; - writel_relaxed(val, timer_of_base(to) + MLB_TMR_EVT_TMCSR_OFS); + mlb_evt_timer_stop(to); + mlb_evt_timer_register_count(to, to->of_clk.period); + mlb_evt_timer_start(to, MLB_TIMER_PERIODIC); return 0; } static int mlb_set_state_oneshot(struct clock_event_device *clk) { struct timer_of *to = to_timer_of(clk); - u32 val = MLB_TMR_TMCSR_CSL_DIV2; - writel_relaxed(val, timer_of_base(to) + MLB_TMR_EVT_TMCSR_OFS); - val |= MLB_TMR_TMCSR_CNTE | MLB_TMR_TMCSR_TRG | MLB_TMR_TMCSR_INTE; - writel_relaxed(val, timer_of_base(to) + MLB_TMR_EVT_TMCSR_OFS); + mlb_evt_timer_stop(to); + mlb_evt_timer_start(to, MLB_TIMER_ONESHOT); return 0; } static int mlb_set_state_shutdown(struct clock_event_device *clk) { struct timer_of *to = to_timer_of(clk); - u32 val = MLB_TMR_TMCSR_CSL_DIV2; - writel_relaxed(val, timer_of_base(to) + MLB_TMR_EVT_TMCSR_OFS); + mlb_evt_timer_stop(to); return 0; } @@ -99,22 +116,21 @@ static int mlb_clkevt_next_event(unsigned long event, { struct timer_of *to = to_timer_of(clk); - writel_relaxed(event, timer_of_base(to) + MLB_TMR_EVT_TMRLR1_OFS); - writel_relaxed(MLB_TMR_TMCSR_CSL_DIV2 | - MLB_TMR_TMCSR_CNTE | MLB_TMR_TMCSR_INTE | - MLB_TMR_TMCSR_TRG, timer_of_base(to) + - MLB_TMR_EVT_TMCSR_OFS); + mlb_evt_timer_stop(to); + mlb_evt_timer_register_count(to, event); + mlb_evt_timer_start(to, MLB_TIMER_ONESHOT); return 0; } static int mlb_config_clock_source(struct timer_of *to) { - writel_relaxed(0, timer_of_base(to) + MLB_TMR_SRC_TMCSR_OFS); - writel_relaxed(~0, timer_of_base(to) + MLB_TMR_SRC_TMR_OFS); + u32 val = MLB_TMR_TMCSR_CSL_DIV2; + + writel_relaxed(val, timer_of_base(to) + MLB_TMR_SRC_TMCSR_OFS); writel_relaxed(~0, timer_of_base(to) + MLB_TMR_SRC_TMRLR1_OFS); writel_relaxed(~0, timer_of_base(to) + MLB_TMR_SRC_TMRLR2_OFS); - writel_relaxed(BIT(4) | BIT(1) | BIT(0), timer_of_base(to) + - MLB_TMR_SRC_TMCSR_OFS); + val |= MLB_TMR_TMCSR_RELD | MLB_TMR_TMCSR_CNTE | MLB_TMR_TMCSR_TRG; + writel_relaxed(val, timer_of_base(to) + MLB_TMR_SRC_TMCSR_OFS); return 0; } From c2c9136b7096f0583117d7d0486600feec387865 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 26 Apr 2019 23:47:10 +0200 Subject: [PATCH 08/16] ARM: at91: move SoC specific definitions to SoC folder Move linux/atmel_tc.h to the SoC specific folder include/soc/at91. Signed-off-by: Alexandre Belloni Acked-by: Thierry Reding Acked-by: Arnd Bergmann Signed-off-by: Daniel Lezcano --- drivers/clocksource/tcb_clksrc.c | 2 +- drivers/misc/atmel_tclib.c | 2 +- drivers/pwm/pwm-atmel-tcb.c | 2 +- include/{linux/atmel_tc.h => soc/at91/atmel_tcb.h} | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) rename include/{linux/atmel_tc.h => soc/at91/atmel_tcb.h} (99%) diff --git a/drivers/clocksource/tcb_clksrc.c b/drivers/clocksource/tcb_clksrc.c index 43f4d5c4d6fa..138a12090149 100644 --- a/drivers/clocksource/tcb_clksrc.c +++ b/drivers/clocksource/tcb_clksrc.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include /* diff --git a/drivers/misc/atmel_tclib.c b/drivers/misc/atmel_tclib.c index ac24a4bd63f7..194f774ab3a1 100644 --- a/drivers/misc/atmel_tclib.c +++ b/drivers/misc/atmel_tclib.c @@ -1,4 +1,3 @@ -#include #include #include #include @@ -10,6 +9,7 @@ #include #include #include +#include /* * This is a thin library to solve the problem of how to portably allocate diff --git a/drivers/pwm/pwm-atmel-tcb.c b/drivers/pwm/pwm-atmel-tcb.c index 0d0f8376bc35..7da1fdb4d269 100644 --- a/drivers/pwm/pwm-atmel-tcb.c +++ b/drivers/pwm/pwm-atmel-tcb.c @@ -17,10 +17,10 @@ #include #include #include -#include #include #include #include +#include #define NPWM 6 diff --git a/include/linux/atmel_tc.h b/include/soc/at91/atmel_tcb.h similarity index 99% rename from include/linux/atmel_tc.h rename to include/soc/at91/atmel_tcb.h index 468fdfa643f0..c3c7200ce151 100644 --- a/include/linux/atmel_tc.h +++ b/include/soc/at91/atmel_tcb.h @@ -7,8 +7,8 @@ * (at your option) any later version. */ -#ifndef ATMEL_TC_H -#define ATMEL_TC_H +#ifndef __SOC_ATMEL_TCB_H +#define __SOC_ATMEL_TCB_H #include #include From 86232bfd28d71db4a50562cf81ff88ef58a6d401 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 26 Apr 2019 23:47:11 +0200 Subject: [PATCH 09/16] clocksource/drivers/tcb_clksrc: Stop depending on atmel_tclib atmel_tclib is probed too late in the boot process to be able to use the TCB as the boot clocksource. This is an issue for SoCs without the PIT (sams70, samv70 and samv71 families) as they simply currently can't boot. Get rid of the atmel_tclib dependency and probe everything on our own using the correct device tree binding. This also allows getting rid of ATMEL_TCB_CLKSRC_BLOCK and makes the driver a bit more flexible as the TCB is not hardcoded in the kernel anymore. Signed-off-by: Alexandre Belloni Signed-off-by: Daniel Lezcano --- drivers/clocksource/tcb_clksrc.c | 110 +++++++++++++++++++------------ drivers/misc/Kconfig | 14 +--- 2 files changed, 71 insertions(+), 53 deletions(-) diff --git a/drivers/clocksource/tcb_clksrc.c b/drivers/clocksource/tcb_clksrc.c index 138a12090149..bf68504da94a 100644 --- a/drivers/clocksource/tcb_clksrc.c +++ b/drivers/clocksource/tcb_clksrc.c @@ -9,7 +9,8 @@ #include #include #include -#include +#include +#include #include #include @@ -28,13 +29,6 @@ * source, used in either periodic or oneshot mode. This runs * at 32 KiHZ, and can handle delays of up to two seconds. * - * A boot clocksource and clockevent source are also currently needed, - * unless the relevant platforms (ARM/AT91, AVR32/AT32) are changed so - * this code can be used when init_timers() is called, well before most - * devices are set up. (Some low end AT91 parts, which can run uClinux, - * have only the timers in one TC block... they currently don't support - * the tclib code, because of that initialization issue.) - * * REVISIT behavior during system suspend states... we should disable * all clocks and save the power. Easily done for clockevent devices, * but clocksources won't necessarily get the needed notifications. @@ -112,7 +106,6 @@ void tc_clksrc_resume(struct clocksource *cs) } static struct clocksource clksrc = { - .name = "tcb_clksrc", .rating = 200, .read = tc_get_cycles, .mask = CLOCKSOURCE_MASK(32), @@ -214,7 +207,6 @@ static int tc_next_event(unsigned long delta, struct clock_event_device *d) static struct tc_clkevt_device clkevt = { .clkevt = { - .name = "tc_clkevt", .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, /* Should be lower than at91rm9200's system timer */ @@ -330,39 +322,73 @@ static void __init tcb_setup_single_chan(struct atmel_tc *tc, int mck_divisor_id writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR); } -static int __init tcb_clksrc_init(void) -{ - static char bootinfo[] __initdata - = KERN_DEBUG "%s: tc%d at %d.%03d MHz\n"; +static const u8 atmel_tcb_divisors[5] = { 2, 8, 32, 128, 0, }; - struct platform_device *pdev; - struct atmel_tc *tc; +static const struct of_device_id atmel_tcb_of_match[] = { + { .compatible = "atmel,at91rm9200-tcb", .data = (void *)16, }, + { .compatible = "atmel,at91sam9x5-tcb", .data = (void *)32, }, + { /* sentinel */ } +}; + +static int __init tcb_clksrc_init(struct device_node *node) +{ + struct atmel_tc tc; struct clk *t0_clk; + const struct of_device_id *match; u32 rate, divided_rate = 0; int best_divisor_idx = -1; int clk32k_divisor_idx = -1; + int bits; int i; int ret; - tc = atmel_tc_alloc(CONFIG_ATMEL_TCB_CLKSRC_BLOCK); - if (!tc) { - pr_debug("can't alloc TC for clocksource\n"); - return -ENODEV; - } - tcaddr = tc->regs; - pdev = tc->pdev; + /* Protect against multiple calls */ + if (tcaddr) + return 0; + + tc.regs = of_iomap(node->parent, 0); + if (!tc.regs) + return -ENXIO; + + t0_clk = of_clk_get_by_name(node->parent, "t0_clk"); + if (IS_ERR(t0_clk)) + return PTR_ERR(t0_clk); + + tc.slow_clk = of_clk_get_by_name(node->parent, "slow_clk"); + if (IS_ERR(tc.slow_clk)) + return PTR_ERR(tc.slow_clk); + + tc.clk[0] = t0_clk; + tc.clk[1] = of_clk_get_by_name(node->parent, "t1_clk"); + if (IS_ERR(tc.clk[1])) + tc.clk[1] = t0_clk; + tc.clk[2] = of_clk_get_by_name(node->parent, "t2_clk"); + if (IS_ERR(tc.clk[2])) + tc.clk[2] = t0_clk; + + tc.irq[2] = of_irq_get(node->parent, 2); + if (tc.irq[2] <= 0) { + tc.irq[2] = of_irq_get(node->parent, 0); + if (tc.irq[2] <= 0) + return -EINVAL; + } + + match = of_match_node(atmel_tcb_of_match, node->parent); + bits = (uintptr_t)match->data; + + for (i = 0; i < ARRAY_SIZE(tc.irq); i++) + writel(ATMEL_TC_ALL_IRQ, tc.regs + ATMEL_TC_REG(i, IDR)); - t0_clk = tc->clk[0]; ret = clk_prepare_enable(t0_clk); if (ret) { pr_debug("can't enable T0 clk\n"); - goto err_free_tc; + return ret; } /* How fast will we be counting? Pick something over 5 MHz. */ rate = (u32) clk_get_rate(t0_clk); - for (i = 0; i < 5; i++) { - unsigned divisor = atmel_tc_divisors[i]; + for (i = 0; i < ARRAY_SIZE(atmel_tcb_divisors); i++) { + unsigned divisor = atmel_tcb_divisors[i]; unsigned tmp; /* remember 32 KiHz clock for later */ @@ -381,27 +407,29 @@ static int __init tcb_clksrc_init(void) best_divisor_idx = i; } - - printk(bootinfo, clksrc.name, CONFIG_ATMEL_TCB_CLKSRC_BLOCK, - divided_rate / 1000000, + clksrc.name = kbasename(node->parent->full_name); + clkevt.clkevt.name = kbasename(node->parent->full_name); + pr_debug("%s at %d.%03d MHz\n", clksrc.name, divided_rate / 1000000, ((divided_rate % 1000000) + 500) / 1000); - if (tc->tcb_config && tc->tcb_config->counter_width == 32) { + tcaddr = tc.regs; + + if (bits == 32) { /* use apropriate function to read 32 bit counter */ clksrc.read = tc_get_cycles32; /* setup ony channel 0 */ - tcb_setup_single_chan(tc, best_divisor_idx); + tcb_setup_single_chan(&tc, best_divisor_idx); } else { - /* tclib will give us three clocks no matter what the + /* we have three clocks no matter what the * underlying platform supports. */ - ret = clk_prepare_enable(tc->clk[1]); + ret = clk_prepare_enable(tc.clk[1]); if (ret) { pr_debug("can't enable T1 clk\n"); goto err_disable_t0; } /* setup both channel 0 & 1 */ - tcb_setup_dual_chan(tc, best_divisor_idx); + tcb_setup_dual_chan(&tc, best_divisor_idx); } /* and away we go! */ @@ -410,7 +438,7 @@ static int __init tcb_clksrc_init(void) goto err_disable_t1; /* channel 2: periodic and oneshot timer support */ - ret = setup_clkevents(tc, clk32k_divisor_idx); + ret = setup_clkevents(&tc, clk32k_divisor_idx); if (ret) goto err_unregister_clksrc; @@ -420,14 +448,14 @@ err_unregister_clksrc: clocksource_unregister(&clksrc); err_disable_t1: - if (!tc->tcb_config || tc->tcb_config->counter_width != 32) - clk_disable_unprepare(tc->clk[1]); + if (bits != 32) + clk_disable_unprepare(tc.clk[1]); err_disable_t0: clk_disable_unprepare(t0_clk); -err_free_tc: - atmel_tc_free(tc); + tcaddr = NULL; + return ret; } -arch_initcall(tcb_clksrc_init); +TIMER_OF_DECLARE(atmel_tcb_clksrc, "atmel,tcb-timer", tcb_clksrc_init); diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 42ab8ec92a04..268a01d3d6f3 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -61,7 +61,8 @@ config ATMEL_TCLIB config ATMEL_TCB_CLKSRC bool "TC Block Clocksource" - depends on ATMEL_TCLIB + depends on ARCH_AT91 + select TIMER_OF if OF default y help Select this to get a high precision clocksource based on a @@ -72,17 +73,6 @@ config ATMEL_TCB_CLKSRC may be used as a clock event device supporting oneshot mode (delays of up to two seconds) based on the 32 KiHz clock. -config ATMEL_TCB_CLKSRC_BLOCK - int - depends on ATMEL_TCB_CLKSRC - default 0 - range 0 1 - help - Some chips provide more than one TC block, so you have the - choice of which one to use for the clock framework. The other - TC can be used for other purposes, such as PWM generation and - interval timing. - config DUMMY_IRQ tristate "Dummy IRQ handler" default n From f712a1e8e59e8f42b5a9ec3887a4ad079bb18175 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 26 Apr 2019 23:47:12 +0200 Subject: [PATCH 10/16] clocksource/drivers/tcb_clksrc: Use tcb as sched_clock Now that the driver is registered early enough, use the TCB as the sched_clock which is much more accurate than the jiffies implementation. Signed-off-by: Alexandre Belloni Signed-off-by: Daniel Lezcano --- drivers/clocksource/tcb_clksrc.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/clocksource/tcb_clksrc.c b/drivers/clocksource/tcb_clksrc.c index bf68504da94a..9de8c10ab546 100644 --- a/drivers/clocksource/tcb_clksrc.c +++ b/drivers/clocksource/tcb_clksrc.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -114,6 +115,16 @@ static struct clocksource clksrc = { .resume = tc_clksrc_resume, }; +static u64 notrace tc_sched_clock_read(void) +{ + return tc_get_cycles(&clksrc); +} + +static u64 notrace tc_sched_clock_read32(void) +{ + return tc_get_cycles32(&clksrc); +} + #ifdef CONFIG_GENERIC_CLOCKEVENTS struct tc_clkevt_device { @@ -335,6 +346,7 @@ static int __init tcb_clksrc_init(struct device_node *node) struct atmel_tc tc; struct clk *t0_clk; const struct of_device_id *match; + u64 (*tc_sched_clock)(void); u32 rate, divided_rate = 0; int best_divisor_idx = -1; int clk32k_divisor_idx = -1; @@ -419,6 +431,7 @@ static int __init tcb_clksrc_init(struct device_node *node) clksrc.read = tc_get_cycles32; /* setup ony channel 0 */ tcb_setup_single_chan(&tc, best_divisor_idx); + tc_sched_clock = tc_sched_clock_read32; } else { /* we have three clocks no matter what the * underlying platform supports. @@ -430,6 +443,7 @@ static int __init tcb_clksrc_init(struct device_node *node) } /* setup both channel 0 & 1 */ tcb_setup_dual_chan(&tc, best_divisor_idx); + tc_sched_clock = tc_sched_clock_read; } /* and away we go! */ @@ -442,6 +456,8 @@ static int __init tcb_clksrc_init(struct device_node *node) if (ret) goto err_unregister_clksrc; + sched_clock_register(tc_sched_clock, 32, divided_rate); + return 0; err_unregister_clksrc: From 7803dc865bd2963192c623546fb240d01e3e7aa0 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 26 Apr 2019 23:47:13 +0200 Subject: [PATCH 11/16] ARM: at91: Implement clocksource selection Allow selecting and unselecting the PIT clocksource driver so it doesn't have to be compiled when unused. Signed-off-by: Alexandre Belloni Signed-off-by: Daniel Lezcano --- arch/arm/mach-at91/Kconfig | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig index 903f23c309df..da1d97a06c53 100644 --- a/arch/arm/mach-at91/Kconfig +++ b/arch/arm/mach-at91/Kconfig @@ -107,6 +107,29 @@ config SOC_AT91SAM9 AT91SAM9X35 AT91SAM9XE +comment "Clocksource driver selection" + +config ATMEL_CLOCKSOURCE_PIT + bool "Periodic Interval Timer (PIT) support" + depends on SOC_AT91SAM9 || SOC_SAMA5 + default SOC_AT91SAM9 || SOC_SAMA5 + select ATMEL_PIT + help + Select this to get a clocksource based on the Atmel Periodic Interval + Timer. It has a relatively low resolution and the TC Block clocksource + should be preferred. + +config ATMEL_CLOCKSOURCE_TCB + bool "Timer Counter Blocks (TCB) support" + default SOC_AT91RM9200 || SOC_AT91SAM9 || SOC_SAMA5 + select ATMEL_TCB_CLKSRC + help + Select this to get a high precision clocksource based on a + TC block with a 5+ MHz base clock rate. + On platforms with 16-bit counters, two timer channels are combined + to make a single 32-bit timer. + It can also be used as a clock event device supporting oneshot mode. + config HAVE_AT91_UTMI bool From 6275f4947e2f13a13a509d9fec4e1e5b15152680 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 26 Apr 2019 23:47:14 +0200 Subject: [PATCH 12/16] clocksource/drivers/tcb_clksrc: Move Kconfig option Move the ATMEL_TCB_CLKSRC option to drivers/clocksource and make it silent if COMPILE_TEST is not selected. Cc: Arnd Bergmann Signed-off-by: Alexandre Belloni Signed-off-by: Daniel Lezcano --- drivers/clocksource/Kconfig | 7 +++++++ drivers/misc/Kconfig | 14 -------------- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index ede5d20299b9..eb1560187434 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -410,6 +410,13 @@ config ATMEL_ST help Support for the Atmel ST timer. +config ATMEL_TCB_CLKSRC + bool "Atmel TC Block timer driver" if COMPILE_TEST + depends on HAS_IOMEM + select TIMER_OF if OF + help + Support for Timer Counter Blocks on Atmel SoCs. + config CLKSRC_EXYNOS_MCT bool "Exynos multi core timer driver" if COMPILE_TEST depends on ARM || ARM64 diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 268a01d3d6f3..c84033909395 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -59,20 +59,6 @@ config ATMEL_TCLIB blocks found on many Atmel processors. This facilitates using these blocks by different drivers despite processor differences. -config ATMEL_TCB_CLKSRC - bool "TC Block Clocksource" - depends on ARCH_AT91 - select TIMER_OF if OF - default y - help - Select this to get a high precision clocksource based on a - TC block with a 5+ MHz base clock rate. Two timer channels - are combined to make a single 32-bit timer. - - When GENERIC_CLOCKEVENTS is defined, the third timer channel - may be used as a clock event device supporting oneshot mode - (delays of up to two seconds) based on the 32 KiHz clock. - config DUMMY_IRQ tristate "Dummy IRQ handler" default n From 2f982703bd00245af8455efad491ca45990bc0d8 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 26 Apr 2019 23:47:15 +0200 Subject: [PATCH 13/16] clocksource/drivers/timer-atmel-pit: Rework Kconfig option Allow building the PIT driver when COMPILE_TEST is enabled. Also remove its default value so it can be disabled. Signed-off-by: Alexandre Belloni Signed-off-by: Daniel Lezcano --- drivers/clocksource/Kconfig | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index eb1560187434..2137f672a12f 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -399,8 +399,11 @@ config ARMV7M_SYSTICK This options enables support for the ARMv7M system timer unit config ATMEL_PIT + bool "Atmel PIT support" if COMPILE_TEST + depends on HAS_IOMEM select TIMER_OF if OF - def_bool SOC_AT91SAM9 || SOC_SAMA5 + help + Support for the Periodic Interval Timer found on Atmel SoCs. config ATMEL_ST bool "Atmel ST timer support" if COMPILE_TEST From a7aae768166e1fff342cfe3ab506e657b7ea8044 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 26 Apr 2019 23:47:16 +0200 Subject: [PATCH 14/16] clocksource/drivers/tcb_clksrc: Rename the file for consistency For the sake of consistency, let's rename the file to a name similar to other file names in this directory. Signed-off-by: Alexandre Belloni Signed-off-by: Daniel Lezcano --- drivers/clocksource/Makefile | 2 +- drivers/clocksource/{tcb_clksrc.c => timer-atmel-tcb.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename drivers/clocksource/{tcb_clksrc.c => timer-atmel-tcb.c} (100%) diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index be6e0fbc7489..923b9b60c909 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -3,7 +3,7 @@ obj-$(CONFIG_TIMER_OF) += timer-of.o obj-$(CONFIG_TIMER_PROBE) += timer-probe.o obj-$(CONFIG_ATMEL_PIT) += timer-atmel-pit.o obj-$(CONFIG_ATMEL_ST) += timer-atmel-st.o -obj-$(CONFIG_ATMEL_TCB_CLKSRC) += tcb_clksrc.o +obj-$(CONFIG_ATMEL_TCB_CLKSRC) += timer-atmel-tcb.o obj-$(CONFIG_X86_PM_TIMER) += acpi_pm.o obj-$(CONFIG_SCx200HR_TIMER) += scx200_hrt.o obj-$(CONFIG_CS5535_CLOCK_EVENT_SRC) += timer-cs5535.o diff --git a/drivers/clocksource/tcb_clksrc.c b/drivers/clocksource/timer-atmel-tcb.c similarity index 100% rename from drivers/clocksource/tcb_clksrc.c rename to drivers/clocksource/timer-atmel-tcb.c From 7ebe68100418bd196cd4d638655e60d17c412d56 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Fri, 26 Apr 2019 23:47:17 +0200 Subject: [PATCH 15/16] clocksource/drivers/timer-atmel-tcb: Convert tc_clksrc_suspend|resume() to static Statisticize tc_clksrc_suspend and tc_clksrc_resume. Signed-off-by: kbuild test robot Signed-off-by: Alexandre Belloni Signed-off-by: Daniel Lezcano --- drivers/clocksource/timer-atmel-tcb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clocksource/timer-atmel-tcb.c b/drivers/clocksource/timer-atmel-tcb.c index 9de8c10ab546..6ed31f9def7e 100644 --- a/drivers/clocksource/timer-atmel-tcb.c +++ b/drivers/clocksource/timer-atmel-tcb.c @@ -66,7 +66,7 @@ static u64 tc_get_cycles32(struct clocksource *cs) return readl_relaxed(tcaddr + ATMEL_TC_REG(0, CV)); } -void tc_clksrc_suspend(struct clocksource *cs) +static void tc_clksrc_suspend(struct clocksource *cs) { int i; @@ -81,7 +81,7 @@ void tc_clksrc_suspend(struct clocksource *cs) bmr_cache = readl(tcaddr + ATMEL_TC_BMR); } -void tc_clksrc_resume(struct clocksource *cs) +static void tc_clksrc_resume(struct clocksource *cs) { int i; From 8c9374068ef6dc3fdf244484b4711a6e10c84d1a Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 26 Apr 2019 23:47:18 +0200 Subject: [PATCH 16/16] misc: atmel_tclib: Do not probe already used TCBs The TCBs that have children are using the proper DT bindings and don't need to be handled by tclib. Acked-by: Greg Kroah-Hartman Signed-off-by: Alexandre Belloni Signed-off-by: Daniel Lezcano --- drivers/misc/atmel_tclib.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/misc/atmel_tclib.c b/drivers/misc/atmel_tclib.c index 194f774ab3a1..2c6850ef0e9c 100644 --- a/drivers/misc/atmel_tclib.c +++ b/drivers/misc/atmel_tclib.c @@ -111,6 +111,9 @@ static int __init tc_probe(struct platform_device *pdev) struct resource *r; unsigned int i; + if (of_get_child_count(pdev->dev.of_node)) + return -EBUSY; + irq = platform_get_irq(pdev, 0); if (irq < 0) return -EINVAL;