From 557804a81d256b15952dcd179280ede92a5bfae1 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 15 Oct 2021 10:29:14 +0200 Subject: [PATCH 01/17] dt-bindings: timer: cadence_ttc: Add power-domains Describe optional power-domain property to fix dts_check warnings. The similar change was done by commit 8c0aa567146b ("dt-bindings: gpio: fsl-imx-gpio: Add power-domains"). Signed-off-by: Michal Simek Acked-by: Rob Herring Link: https://lore.kernel.org/r/cc655a72b20790f6d7408b1aaf81c4bf878aafb4.1634286552.git.michal.simek@xilinx.com Signed-off-by: Daniel Lezcano --- Documentation/devicetree/bindings/timer/cdns,ttc.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/timer/cdns,ttc.yaml b/Documentation/devicetree/bindings/timer/cdns,ttc.yaml index 8615353f69b4..c3386076a98c 100644 --- a/Documentation/devicetree/bindings/timer/cdns,ttc.yaml +++ b/Documentation/devicetree/bindings/timer/cdns,ttc.yaml @@ -25,6 +25,9 @@ properties: clocks: maxItems: 1 + power-domains: + maxItems: 1 + timer-width: $ref: "/schemas/types.yaml#/definitions/uint32" description: | From ad253b3dd79851d926154ef747a69427573233e4 Mon Sep 17 00:00:00 2001 From: Johan Jonker Date: Tue, 24 Aug 2021 11:56:37 +0200 Subject: [PATCH 02/17] dt-bindings: timer: remove rockchip,rk3066-timer compatible string from rockchip,rk-timer.yaml The Rockchip rk3066 timers have a different register layout then rk3288 with only a 32 vs 64 bits timer channel. The timers in rk3066a.dtsi have "snps,dw-apb-timer" as compatible string, so remove the "rockchip,rk3066-timer" from rockchip,rk-timer.yaml Signed-off-by: Johan Jonker Acked-by: Rob Herring Link: https://lore.kernel.org/r/20210824095637.2547-1-jbx6244@gmail.com Signed-off-by: Daniel Lezcano --- Documentation/devicetree/bindings/timer/rockchip,rk-timer.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/devicetree/bindings/timer/rockchip,rk-timer.yaml b/Documentation/devicetree/bindings/timer/rockchip,rk-timer.yaml index e26ecb5893ae..5d157d87dad5 100644 --- a/Documentation/devicetree/bindings/timer/rockchip,rk-timer.yaml +++ b/Documentation/devicetree/bindings/timer/rockchip,rk-timer.yaml @@ -18,7 +18,6 @@ properties: - enum: - rockchip,rv1108-timer - rockchip,rk3036-timer - - rockchip,rk3066-timer - rockchip,rk3188-timer - rockchip,rk3228-timer - rockchip,rk3229-timer From 7cd925a8823d16de5614d3f0aabea9948747accd Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 1 Nov 2021 21:35:30 +0200 Subject: [PATCH 03/17] clocksource/drivers/exynos_mct: Refactor resources allocation Move interrupts allocation from exynos4_timer_resources() into separate function together with the interrupt number parsing code from mct_init_dt(), so the code for managing interrupts is kept together. While touching exynos4_timer_resources() function, move of_iomap() to it. No functional changes. Signed-off-by: Marek Szyprowski Reviewed-by: Chanwoo Choi Tested-by: Chanwoo Choi Reviewed-by: Krzysztof Kozlowski Signed-off-by: Sam Protsenko Link: https://lore.kernel.org/r/20211101193531.15078-2-semen.protsenko@linaro.org Signed-off-by: Daniel Lezcano --- drivers/clocksource/exynos_mct.c | 50 +++++++++++++++++++------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c index 5e3e96d3d1b9..857cf12ebe57 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c @@ -504,11 +504,14 @@ static int exynos4_mct_dying_cpu(unsigned int cpu) return 0; } -static int __init exynos4_timer_resources(struct device_node *np, void __iomem *base) +static int __init exynos4_timer_resources(struct device_node *np) { - int err, cpu; struct clk *mct_clk, *tick_clk; + reg_base = of_iomap(np, 0); + if (!reg_base) + panic("%s: unable to ioremap mct address space\n", __func__); + tick_clk = of_clk_get_by_name(np, "fin_pll"); if (IS_ERR(tick_clk)) panic("%s: unable to determine tick clock rate\n", __func__); @@ -519,9 +522,27 @@ static int __init exynos4_timer_resources(struct device_node *np, void __iomem * panic("%s: unable to retrieve mct clock instance\n", __func__); clk_prepare_enable(mct_clk); - reg_base = base; - if (!reg_base) - panic("%s: unable to ioremap mct address space\n", __func__); + return 0; +} + +static int __init exynos4_timer_interrupts(struct device_node *np, + unsigned int int_type) +{ + int nr_irqs, i, err, cpu; + + mct_int_type = int_type; + + /* This driver uses only one global timer interrupt */ + mct_irqs[MCT_G0_IRQ] = irq_of_parse_and_map(np, MCT_G0_IRQ); + + /* + * Find out the number of local irqs specified. The local + * timer irqs are specified after the four global timer + * irqs are specified. + */ + nr_irqs = of_irq_count(np); + for (i = MCT_L0_IRQ; i < nr_irqs; i++) + mct_irqs[i] = irq_of_parse_and_map(np, i); if (mct_int_type == MCT_INT_PPI) { @@ -581,24 +602,13 @@ out_irq: static int __init mct_init_dt(struct device_node *np, unsigned int int_type) { - u32 nr_irqs, i; int ret; - mct_int_type = int_type; + ret = exynos4_timer_resources(np); + if (ret) + return ret; - /* This driver uses only one global timer interrupt */ - mct_irqs[MCT_G0_IRQ] = irq_of_parse_and_map(np, MCT_G0_IRQ); - - /* - * Find out the number of local irqs specified. The local - * timer irqs are specified after the four global timer - * irqs are specified. - */ - nr_irqs = of_irq_count(np); - for (i = MCT_L0_IRQ; i < nr_irqs; i++) - mct_irqs[i] = irq_of_parse_and_map(np, i); - - ret = exynos4_timer_resources(np, of_iomap(np, 0)); + ret = exynos4_timer_interrupts(np, int_type); if (ret) return ret; From c4f5b30dda01f2f6979a9681142de454991182ee Mon Sep 17 00:00:00 2001 From: Biju Das Date: Fri, 12 Nov 2021 18:44:10 +0000 Subject: [PATCH 04/17] reset: Add of_reset_control_get_optional_exclusive() Add optional variant of of_reset_control_get_exclusive(). If the requested reset is not specified in the device tree, this function returns NULL instead of an error. Suggested-by: Philipp Zabel Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20211112184413.4391-2-biju.das.jz@bp.renesas.com Signed-off-by: Philipp Zabel --- include/linux/reset.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/include/linux/reset.h b/include/linux/reset.h index db0e6115a2f6..8a21b5756c3e 100644 --- a/include/linux/reset.h +++ b/include/linux/reset.h @@ -454,6 +454,26 @@ static inline struct reset_control *of_reset_control_get_exclusive( return __of_reset_control_get(node, id, 0, false, false, true); } +/** + * of_reset_control_get_optional_exclusive - Lookup and obtain an optional exclusive + * reference to a reset controller. + * @node: device to be reset by the controller + * @id: reset line name + * + * Optional variant of of_reset_control_get_exclusive(). If the requested reset + * is not specified in the device tree, this function returns NULL instead of + * an error. + * + * Returns a struct reset_control or IS_ERR() condition containing errno. + * + * Use of id names is optional. + */ +static inline struct reset_control *of_reset_control_get_optional_exclusive( + struct device_node *node, const char *id) +{ + return __of_reset_control_get(node, id, 0, false, true, true); +} + /** * of_reset_control_get_shared - Lookup and obtain a shared reference * to a reset controller. From 453e2cadc97ca52e423852435522eb7d4f4b5b6b Mon Sep 17 00:00:00 2001 From: Jacky Bai Date: Fri, 26 Nov 2021 15:39:58 +0800 Subject: [PATCH 05/17] dt-bindings: timer: tpm-timer: Add imx8ulp compatible string The tpm timer on i.MX8ULP is derived from i.MX7ULP, it use two compatible strings, so update the compatible string for it. Reviewed-by: Dong Aisheng Acked-by: Rob Herring Signed-off-by: Jacky Bai Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/20211126074002.1535696-4-peng.fan@oss.nxp.com Signed-off-by: Daniel Lezcano --- Documentation/devicetree/bindings/timer/nxp,tpm-timer.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/timer/nxp,tpm-timer.yaml b/Documentation/devicetree/bindings/timer/nxp,tpm-timer.yaml index edd9585f6726..f69773a8e4b9 100644 --- a/Documentation/devicetree/bindings/timer/nxp,tpm-timer.yaml +++ b/Documentation/devicetree/bindings/timer/nxp,tpm-timer.yaml @@ -19,7 +19,11 @@ description: | properties: compatible: - const: fsl,imx7ulp-tpm + oneOf: + - const: fsl,imx7ulp-tpm + - items: + - const: fsl,imx8ulp-tpm + - const: fsl,imx7ulp-tpm reg: maxItems: 1 From c86ff8c55b8ae68837b2fa59dc0c203907e9a15f Mon Sep 17 00:00:00 2001 From: Waiman Long Date: Thu, 18 Nov 2021 14:14:36 -0500 Subject: [PATCH 06/17] clocksource: Avoid accidental unstable marking of clocksources Since commit db3a34e17433 ("clocksource: Retry clock read if long delays detected") and commit 2e27e793e280 ("clocksource: Reduce clocksource-skew threshold"), it is found that tsc clocksource fallback to hpet can sometimes happen on both Intel and AMD systems especially when they are running stressful benchmarking workloads. Of the 23 systems tested with a v5.14 kernel, 10 of them have switched to hpet clock source during the test run. The result of falling back to hpet is a drastic reduction of performance when running benchmarks. For example, the fio performance tests can drop up to 70% whereas the iperf3 performance can drop up to 80%. 4 hpet fallbacks happened during bootup. They were: [ 8.749399] clocksource: timekeeping watchdog on CPU13: hpet read-back delay of 263750ns, attempt 4, marking unstable [ 12.044610] clocksource: timekeeping watchdog on CPU19: hpet read-back delay of 186166ns, attempt 4, marking unstable [ 17.336941] clocksource: timekeeping watchdog on CPU28: hpet read-back delay of 182291ns, attempt 4, marking unstable [ 17.518565] clocksource: timekeeping watchdog on CPU34: hpet read-back delay of 252196ns, attempt 4, marking unstable Other fallbacks happen when the systems were running stressful benchmarks. For example: [ 2685.867873] clocksource: timekeeping watchdog on CPU117: hpet read-back delay of 57269ns, attempt 4, marking unstable [46215.471228] clocksource: timekeeping watchdog on CPU8: hpet read-back delay of 61460ns, attempt 4, marking unstable Commit 2e27e793e280 ("clocksource: Reduce clocksource-skew threshold"), changed the skew margin from 100us to 50us. I think this is too small and can easily be exceeded when running some stressful workloads on a thermally stressed system. So it is switched back to 100us. Even a maximum skew margin of 100us may be too small in for some systems when booting up especially if those systems are under thermal stress. To eliminate the case that the large skew is due to the system being too busy slowing down the reading of both the watchdog and the clocksource, an extra consecutive read of watchdog clock is being done to check this. The consecutive watchdog read delay is compared against WATCHDOG_MAX_SKEW/2. If the delay exceeds the limit, we assume that the system is just too busy. A warning will be printed to the console and the clock skew check is skipped for this round. Fixes: db3a34e17433 ("clocksource: Retry clock read if long delays detected") Fixes: 2e27e793e280 ("clocksource: Reduce clocksource-skew threshold") Signed-off-by: Waiman Long Signed-off-by: Paul E. McKenney --- kernel/time/clocksource.c | 50 ++++++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index b8a14d2fb5ba..bcad1a1e5dcf 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c @@ -107,7 +107,7 @@ static u64 suspend_start; * This delay could be due to SMIs, NMIs, or to VCPU preemptions. Used as * a lower bound for cs->uncertainty_margin values when registering clocks. */ -#define WATCHDOG_MAX_SKEW (50 * NSEC_PER_USEC) +#define WATCHDOG_MAX_SKEW (100 * NSEC_PER_USEC) #ifdef CONFIG_CLOCKSOURCE_WATCHDOG static void clocksource_watchdog_work(struct work_struct *work); @@ -205,17 +205,24 @@ EXPORT_SYMBOL_GPL(max_cswd_read_retries); static int verify_n_cpus = 8; module_param(verify_n_cpus, int, 0644); -static bool cs_watchdog_read(struct clocksource *cs, u64 *csnow, u64 *wdnow) +enum wd_read_status { + WD_READ_SUCCESS, + WD_READ_UNSTABLE, + WD_READ_SKIP +}; + +static enum wd_read_status cs_watchdog_read(struct clocksource *cs, u64 *csnow, u64 *wdnow) { unsigned int nretries; - u64 wd_end, wd_delta; - int64_t wd_delay; + u64 wd_end, wd_end2, wd_delta; + int64_t wd_delay, wd_seq_delay; for (nretries = 0; nretries <= max_cswd_read_retries; nretries++) { local_irq_disable(); *wdnow = watchdog->read(watchdog); *csnow = cs->read(cs); wd_end = watchdog->read(watchdog); + wd_end2 = watchdog->read(watchdog); local_irq_enable(); wd_delta = clocksource_delta(wd_end, *wdnow, watchdog->mask); @@ -226,13 +233,34 @@ static bool cs_watchdog_read(struct clocksource *cs, u64 *csnow, u64 *wdnow) pr_warn("timekeeping watchdog on CPU%d: %s retried %d times before success\n", smp_processor_id(), watchdog->name, nretries); } - return true; + return WD_READ_SUCCESS; } + + /* + * Now compute delay in consecutive watchdog read to see if + * there is too much external interferences that cause + * significant delay in reading both clocksource and watchdog. + * + * If consecutive WD read-back delay > WATCHDOG_MAX_SKEW/2, + * report system busy, reinit the watchdog and skip the current + * watchdog test. + */ + wd_delta = clocksource_delta(wd_end2, wd_end, watchdog->mask); + wd_seq_delay = clocksource_cyc2ns(wd_delta, watchdog->mult, watchdog->shift); + if (wd_seq_delay > WATCHDOG_MAX_SKEW/2) + goto skip_test; } pr_warn("timekeeping watchdog on CPU%d: %s read-back delay of %lldns, attempt %d, marking unstable\n", smp_processor_id(), watchdog->name, wd_delay, nretries); - return false; + return WD_READ_UNSTABLE; + +skip_test: + pr_info("timekeeping watchdog on CPU%d: %s wd-wd read-back delay of %lldns\n", + smp_processor_id(), watchdog->name, wd_seq_delay); + pr_info("wd-%s-wd read-back delay of %lldns, clock-skew test skipped!\n", + cs->name, wd_delay); + return WD_READ_SKIP; } static u64 csnow_mid; @@ -356,6 +384,7 @@ static void clocksource_watchdog(struct timer_list *unused) int next_cpu, reset_pending; int64_t wd_nsec, cs_nsec; struct clocksource *cs; + enum wd_read_status read_ret; u32 md; spin_lock(&watchdog_lock); @@ -373,9 +402,12 @@ static void clocksource_watchdog(struct timer_list *unused) continue; } - if (!cs_watchdog_read(cs, &csnow, &wdnow)) { - /* Clock readout unreliable, so give it up. */ - __clocksource_unstable(cs); + read_ret = cs_watchdog_read(cs, &csnow, &wdnow); + + if (read_ret != WD_READ_SUCCESS) { + if (read_ret == WD_READ_UNSTABLE) + /* Clock readout unreliable, so give it up. */ + __clocksource_unstable(cs); continue; } From 1a5620671a1b6fd9cc08761677d050f1702f910c Mon Sep 17 00:00:00 2001 From: Waiman Long Date: Thu, 18 Nov 2021 14:14:37 -0500 Subject: [PATCH 07/17] clocksource: Reduce the default clocksource_watchdog() retries to 2 With the previous patch, there is an extra watchdog read in each retry. Now the total number of clocksource reads is increased to 4 per iteration. In order to avoid increasing the clock skew check overhead, the default maximum number of retries is reduced from 3 to 2 to maintain the same 12 clocksource reads in the worst case. Suggested-by: Paul E. McKenney Signed-off-by: Waiman Long Signed-off-by: Paul E. McKenney --- Documentation/admin-guide/kernel-parameters.txt | 4 ++-- kernel/time/clocksource.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 9725c546a0d4..3ea934b034f7 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -603,8 +603,8 @@ clocksource.max_cswd_read_retries= [KNL] Number of clocksource_watchdog() retries due to external delays before the clock will be marked - unstable. Defaults to three retries, that is, - four attempts to read the clock under test. + unstable. Defaults to two retries, that is, + three attempts to read the clock under test. clocksource.verify_n_cpus= [KNL] Limit the number of CPUs checked for clocksources diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index bcad1a1e5dcf..b7e52a642948 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c @@ -199,7 +199,7 @@ void clocksource_mark_unstable(struct clocksource *cs) spin_unlock_irqrestore(&watchdog_lock, flags); } -ulong max_cswd_read_retries = 3; +ulong max_cswd_read_retries = 2; module_param(max_cswd_read_retries, ulong, 0644); EXPORT_SYMBOL_GPL(max_cswd_read_retries); static int verify_n_cpus = 8; From 410fbda49cc9b2165e80b87880f164d9644b460d Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Wed, 3 Nov 2021 16:48:04 +0000 Subject: [PATCH 08/17] clocksource/drivers/exynos_mct: Fix silly typo resulting in checkpatch warning Commit ae460fd9164b ("clocksource/drivers/exynos_mct: Prioritise Arm arch timer on arm64") changed the rating of the MCT clockevents device to be lower than the Arm architected timer and, in the process, replaced a semicolon with a comma thanks to a silly copy-paste error. Put the semicolon back so that the code looks more idiomatic and resolve the SUSPECT_COMMA_SEMICOLON warning from checkpatch at the same time. Cc: Krzysztof Kozlowski Cc: Daniel Lezcano Signed-off-by: Will Deacon Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20211103164804.30182-1-will@kernel.org Signed-off-by: Daniel Lezcano --- drivers/clocksource/exynos_mct.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c index 857cf12ebe57..6db3d5511b0f 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c @@ -467,7 +467,7 @@ static int exynos4_mct_starting_cpu(unsigned int cpu) evt->tick_resume = set_state_shutdown; evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERCPU; - evt->rating = MCT_CLKEVENTS_RATING, + evt->rating = MCT_CLKEVENTS_RATING; exynos4_mct_write(TICK_BASE_CNT, mevt->base + MCT_L_TCNTB_OFFSET); From 92d06a3f67ad809649d26aa7698e4d42362585a8 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Fri, 12 Nov 2021 18:44:11 +0000 Subject: [PATCH 09/17] dt-bindings: timer: renesas: ostm: Document Renesas RZ/G2L OSTM Document the General Timer Module(a.k.a OSTM) found on the RZ/G2L SoC. Signed-off-by: Biju Das Reviewed-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20211112184413.4391-3-biju.das.jz@bp.renesas.com Signed-off-by: Daniel Lezcano --- .../bindings/timer/renesas,ostm.yaml | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/timer/renesas,ostm.yaml b/Documentation/devicetree/bindings/timer/renesas,ostm.yaml index 600d47ab7d58..7fa7f977b44c 100644 --- a/Documentation/devicetree/bindings/timer/renesas,ostm.yaml +++ b/Documentation/devicetree/bindings/timer/renesas,ostm.yaml @@ -21,9 +21,10 @@ properties: compatible: items: - enum: - - renesas,r7s72100-ostm # RZ/A1H - - renesas,r7s9210-ostm # RZ/A2M - - const: renesas,ostm # Generic + - renesas,r7s72100-ostm # RZ/A1H + - renesas,r7s9210-ostm # RZ/A2M + - renesas,r9a07g044-ostm # RZ/G2{L,LC} + - const: renesas,ostm # Generic reg: maxItems: 1 @@ -37,6 +38,9 @@ properties: power-domains: maxItems: 1 + resets: + maxItems: 1 + required: - compatible - reg @@ -44,6 +48,16 @@ required: - clocks - power-domains +if: + properties: + compatible: + contains: + enum: + - renesas,r9a07g044-ostm +then: + required: + - resets + additionalProperties: false examples: From 3a3e9f23c2cae907677a236fa547610ca747e6fb Mon Sep 17 00:00:00 2001 From: Biju Das Date: Fri, 12 Nov 2021 18:44:12 +0000 Subject: [PATCH 10/17] clocksource/drivers/renesas-ostm: Add RZ/G2L OSTM support RZ/G2L SoC has Generic Timer Module(a.k.a OSTM) which needs to deassert the reset line before accessing any registers. This patch adds an entry point for RZ/G2L so that we can deassert the reset line in probe callback. Signed-off-by: Biju Das Reviewed-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20211112184413.4391-4-biju.das.jz@bp.renesas.com Signed-off-by: Daniel Lezcano --- drivers/clocksource/renesas-ostm.c | 39 +++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/drivers/clocksource/renesas-ostm.c b/drivers/clocksource/renesas-ostm.c index 3d06ba66008c..21d1392637b8 100644 --- a/drivers/clocksource/renesas-ostm.c +++ b/drivers/clocksource/renesas-ostm.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include #include @@ -159,6 +161,7 @@ static int __init ostm_init_clkevt(struct timer_of *to) static int __init ostm_init(struct device_node *np) { + struct reset_control *rstc; struct timer_of *to; int ret; @@ -166,6 +169,14 @@ static int __init ostm_init(struct device_node *np) if (!to) return -ENOMEM; + rstc = of_reset_control_get_optional_exclusive(np, NULL); + if (IS_ERR(rstc)) { + ret = PTR_ERR(rstc); + goto err_free; + } + + reset_control_deassert(rstc); + to->flags = TIMER_OF_BASE | TIMER_OF_CLOCK; if (system_clock) { /* @@ -178,7 +189,7 @@ static int __init ostm_init(struct device_node *np) ret = timer_of_init(np, to); if (ret) - goto err_free; + goto err_reset; /* * First probed device will be used as system clocksource. Any @@ -203,9 +214,35 @@ static int __init ostm_init(struct device_node *np) err_cleanup: timer_of_cleanup(to); +err_reset: + reset_control_assert(rstc); + reset_control_put(rstc); err_free: kfree(to); return ret; } TIMER_OF_DECLARE(ostm, "renesas,ostm", ostm_init); + +#ifdef CONFIG_ARCH_R9A07G044 +static int __init ostm_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + + return ostm_init(dev->of_node); +} + +static const struct of_device_id ostm_of_table[] = { + { .compatible = "renesas,ostm", }, + { /* sentinel */ } +}; + +static struct platform_driver ostm_device_driver = { + .driver = { + .name = "renesas_ostm", + .of_match_table = of_match_ptr(ostm_of_table), + .suppress_bind_attrs = true, + }, +}; +builtin_platform_driver_probe(ostm_device_driver, ostm_probe); +#endif From a2807f657976b943bf0eb81d026398d28aa89863 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Fri, 12 Nov 2021 18:44:13 +0000 Subject: [PATCH 11/17] clocksource/drivers/renesas,ostm: Make RENESAS_OSTM symbol visible As RZ/G2L uses the ARM Architected Timer as system timer, enabling the OSTM is not mandatory. Make RENESAS_OSTM symbol visible, so that user can enable it when needed. Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20211112184413.4391-5-biju.das.jz@bp.renesas.com Signed-off-by: Daniel Lezcano --- drivers/clocksource/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index f65e31bab9ae..821ea4aa5c86 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -510,7 +510,8 @@ config SH_TIMER_MTU2 This hardware comes with 16-bit timer registers. config RENESAS_OSTM - bool "Renesas OSTM timer driver" if COMPILE_TEST + bool "Renesas OSTM timer driver" + depends on ARCH_RENESAS || COMPILE_TEST select CLKSRC_MMIO select TIMER_OF help From f5bd5fc9d478cdb94f89ccc74870dd81d1919b42 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 1 Dec 2021 20:50:29 +0800 Subject: [PATCH 12/17] clocksource/drivers/imx-sysctr: Mark two variable with __ro_after_init The variables 'sys_ctr_base' and 'cmpcr' are not be updated after init, so mark them as __ro_after_init. Cc: Kees Cook Signed-off-by: Peng Fan Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/20211201125030.2307746-1-peng.fan@oss.nxp.com Signed-off-by: Daniel Lezcano --- drivers/clocksource/timer-imx-sysctr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clocksource/timer-imx-sysctr.c b/drivers/clocksource/timer-imx-sysctr.c index 18b90fc56bfc..2b309af11266 100644 --- a/drivers/clocksource/timer-imx-sysctr.c +++ b/drivers/clocksource/timer-imx-sysctr.c @@ -20,8 +20,8 @@ #define SYS_CTR_CLK_DIV 0x3 -static void __iomem *sys_ctr_base; -static u32 cmpcr; +static void __iomem *sys_ctr_base __ro_after_init; +static u32 cmpcr __ro_after_init; static void sysctr_timer_enable(bool enable) { From 0ed9e4ebcebcb36bd1186e68cf2f72b3e0bfbac6 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 1 Dec 2021 20:50:30 +0800 Subject: [PATCH 13/17] clocksource/drivers/timer-imx-sysctr: Set cpumask to cpu_possible_mask The syctr interrupt could set the affinity to any cores in the SoC. However, the default affinity is set to cpu 0. This timer will be used as broadcast timer on all the i.MX SoCs. Because DYNIRQ flag is set, the core time framework will runtime set the interrupt affinity to the cores that needs to wake up and the cpumask will runtime set to the core that will be wake up. So even the sysctr initialization use cpumask 0, there is no issue, the current patch is just use cpu_possible_mask to show the fact that the timer supports routed to all the cpu cores and nothing else. Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/20211201125030.2307746-2-peng.fan@oss.nxp.com Signed-off-by: Daniel Lezcano --- drivers/clocksource/timer-imx-sysctr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clocksource/timer-imx-sysctr.c b/drivers/clocksource/timer-imx-sysctr.c index 2b309af11266..55a8e198d2a1 100644 --- a/drivers/clocksource/timer-imx-sysctr.c +++ b/drivers/clocksource/timer-imx-sysctr.c @@ -119,7 +119,7 @@ static struct timer_of to_sysctr = { static void __init sysctr_clockevent_init(void) { - to_sysctr.clkevt.cpumask = cpumask_of(0); + to_sysctr.clkevt.cpumask = cpu_possible_mask; clockevents_config_and_register(&to_sysctr.clkevt, timer_of_rate(&to_sysctr), From 0642fb4ba68f7158f7a6d92190b3090cf0c7fac6 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Tue, 23 Nov 2021 11:25:24 -0800 Subject: [PATCH 14/17] clocksource/drivers/pistachio: Fix -Wunused-but-set-variable warning Variable 'overflow' set but not used, but this is the intended behavior. The hardware only updates the counter register after the overflow register read. However, the value of overflow is not actually needed. Link: https://lore.kernel.org/lkml/202111200402.afQsussU-lkp@intel.com/ Reported-by: kernel test robot Suggested-by: Daniel Lezcano Signed-off-by: Drew Fustini Link: https://lore.kernel.org/r/20211123192524.1038304-1-dfustini@baylibre.com Signed-off-by: Daniel Lezcano --- drivers/clocksource/timer-pistachio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/clocksource/timer-pistachio.c b/drivers/clocksource/timer-pistachio.c index 6f37181a8c63..69c069e6f0a2 100644 --- a/drivers/clocksource/timer-pistachio.c +++ b/drivers/clocksource/timer-pistachio.c @@ -71,7 +71,8 @@ static u64 notrace pistachio_clocksource_read_cycles(struct clocksource *cs) { struct pistachio_clocksource *pcs = to_pistachio_clocksource(cs); - u32 counter, overflow; + __maybe_unused u32 overflow; + u32 counter; unsigned long flags; /* From 5fc1f93f69989e72be7a84ded6ee867d6415f690 Mon Sep 17 00:00:00 2001 From: Romain Perier Date: Fri, 17 Dec 2021 20:57:22 +0100 Subject: [PATCH 15/17] clocksource/drivers: Add MStar MSC313e timer support The MSC313e-compatible SoCs have 3 timer hardware blocks. All of these are free running 32-bit increasing counters and can generate interrupts. Based onto a maximum value register, each timer can either count from 0 to max, one time then stop (which generates interrupts) or can count from 0 to max and then roll. This commit adds basic support for these timers, the first timer block being used as clocksource/sched_clock and delay, while the others will be used as clockevents. Signed-off-by: Romain Perier Co-developed-by: Daniel Palmer Signed-off-by: Daniel Palmer Link: https://lore.kernel.org/r/20211217195727.8955-2-romain.perier@gmail.com Signed-off-by: Daniel Lezcano --- MAINTAINERS | 1 + drivers/clocksource/Kconfig | 9 + drivers/clocksource/Makefile | 1 + drivers/clocksource/timer-msc313e.c | 244 ++++++++++++++++++++++++++++ 4 files changed, 255 insertions(+) create mode 100644 drivers/clocksource/timer-msc313e.c diff --git a/MAINTAINERS b/MAINTAINERS index 7a2345ce8521..f39a1617bf50 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2282,6 +2282,7 @@ F: Documentation/devicetree/bindings/gpio/mstar,msc313-gpio.yaml F: arch/arm/boot/dts/mstar-* F: arch/arm/mach-mstar/ F: drivers/clk/mstar/ +F: drivers/clocksource/timer-msc313e.c F: drivers/gpio/gpio-msc313.c F: drivers/rtc/rtc-msc313.c F: drivers/watchdog/msc313e_wdt.c diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 821ea4aa5c86..cfb8ea0df3b1 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -672,6 +672,15 @@ config MILBEAUT_TIMER help Enables the support for Milbeaut timer driver. +config MSC313E_TIMER + bool "MSC313E timer driver" if COMPILE_TEST + select TIMER_OF + select CLKSRC_MMIO + help + Enables support for the MStar MSC313E timer driver. + This provides access to multiple interrupt generating + programmable 32-bit free running incrementing counters. + config INGENIC_TIMER bool "Clocksource/timer using the TCU in Ingenic JZ SoCs" default MACH_INGENIC diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index c17ee32a7151..fa5f624eadb6 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -88,3 +88,4 @@ obj-$(CONFIG_CSKY_MP_TIMER) += timer-mp-csky.o obj-$(CONFIG_GX6605S_TIMER) += timer-gx6605s.o obj-$(CONFIG_HYPERV_TIMER) += hyperv_timer.o obj-$(CONFIG_MICROCHIP_PIT64B) += timer-microchip-pit64b.o +obj-$(CONFIG_MSC313E_TIMER) += timer-msc313e.o diff --git a/drivers/clocksource/timer-msc313e.c b/drivers/clocksource/timer-msc313e.c new file mode 100644 index 000000000000..154e73444a0c --- /dev/null +++ b/drivers/clocksource/timer-msc313e.c @@ -0,0 +1,244 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MStar timer driver + * + * Copyright (C) 2021 Daniel Palmer + * Copyright (C) 2021 Romain Perier + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_ARM +#include +#endif + +#include "timer-of.h" + +#define TIMER_NAME "msc313e_timer" + +#define MSC313E_REG_CTRL 0x00 +#define MSC313E_REG_CTRL_TIMER_EN BIT(0) +#define MSC313E_REG_CTRL_TIMER_TRIG BIT(1) +#define MSC313E_REG_CTRL_TIMER_INT_EN BIT(8) +#define MSC313E_REG_TIMER_MAX_LOW 0x08 +#define MSC313E_REG_TIMER_MAX_HIGH 0x0c +#define MSC313E_REG_COUNTER_LOW 0x10 +#define MSC313E_REG_COUNTER_HIGH 0x14 + +#define TIMER_SYNC_TICKS 3 + +#ifdef CONFIG_ARM +struct msc313e_delay { + void __iomem *base; + struct delay_timer delay; +}; +static struct msc313e_delay msc313e_delay; +#endif + +static void __iomem *msc313e_clksrc; + +static void msc313e_timer_stop(void __iomem *base) +{ + writew(0, base + MSC313E_REG_CTRL); +} + +static void msc313e_timer_start(void __iomem *base, bool periodic) +{ + u16 reg; + + reg = readw(base + MSC313E_REG_CTRL); + if (periodic) + reg |= MSC313E_REG_CTRL_TIMER_EN; + else + reg |= MSC313E_REG_CTRL_TIMER_TRIG; + writew(reg | MSC313E_REG_CTRL_TIMER_INT_EN, base + MSC313E_REG_CTRL); +} + +static void msc313e_timer_setup(void __iomem *base, unsigned long delay) +{ + unsigned long flags; + + local_irq_save(flags); + writew(delay >> 16, base + MSC313E_REG_TIMER_MAX_HIGH); + writew(delay & 0xffff, base + MSC313E_REG_TIMER_MAX_LOW); + local_irq_restore(flags); +} + +static unsigned long msc313e_timer_current_value(void __iomem *base) +{ + unsigned long flags; + u16 l, h; + + local_irq_save(flags); + l = readw(base + MSC313E_REG_COUNTER_LOW); + h = readw(base + MSC313E_REG_COUNTER_HIGH); + local_irq_restore(flags); + + return (((u32)h) << 16 | l); +} + +static int msc313e_timer_clkevt_shutdown(struct clock_event_device *evt) +{ + struct timer_of *timer = to_timer_of(evt); + + msc313e_timer_stop(timer_of_base(timer)); + + return 0; +} + +static int msc313e_timer_clkevt_set_oneshot(struct clock_event_device *evt) +{ + struct timer_of *timer = to_timer_of(evt); + + msc313e_timer_stop(timer_of_base(timer)); + msc313e_timer_start(timer_of_base(timer), false); + + return 0; +} + +static int msc313e_timer_clkevt_set_periodic(struct clock_event_device *evt) +{ + struct timer_of *timer = to_timer_of(evt); + + msc313e_timer_stop(timer_of_base(timer)); + msc313e_timer_setup(timer_of_base(timer), timer_of_period(timer)); + msc313e_timer_start(timer_of_base(timer), true); + + return 0; +} + +static int msc313e_timer_clkevt_next_event(unsigned long evt, struct clock_event_device *clkevt) +{ + struct timer_of *timer = to_timer_of(clkevt); + + msc313e_timer_stop(timer_of_base(timer)); + msc313e_timer_setup(timer_of_base(timer), evt); + msc313e_timer_start(timer_of_base(timer), false); + + return 0; +} + +static irqreturn_t msc313e_timer_clkevt_irq(int irq, void *dev_id) +{ + struct clock_event_device *evt = dev_id; + + evt->event_handler(evt); + + return IRQ_HANDLED; +} + +static u64 msc313e_timer_clksrc_read(struct clocksource *cs) +{ + return msc313e_timer_current_value(msc313e_clksrc) & cs->mask; +} + +#ifdef CONFIG_ARM +static unsigned long msc313e_read_delay_timer_read(void) +{ + return msc313e_timer_current_value(msc313e_delay.base); +} +#endif + +static u64 msc313e_timer_sched_clock_read(void) +{ + return msc313e_timer_current_value(msc313e_clksrc); +} + +static struct clock_event_device msc313e_clkevt = { + .name = TIMER_NAME, + .rating = 300, + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .set_state_shutdown = msc313e_timer_clkevt_shutdown, + .set_state_periodic = msc313e_timer_clkevt_set_periodic, + .set_state_oneshot = msc313e_timer_clkevt_set_oneshot, + .tick_resume = msc313e_timer_clkevt_shutdown, + .set_next_event = msc313e_timer_clkevt_next_event, +}; + +static int __init msc313e_clkevt_init(struct device_node *np) +{ + int ret; + struct timer_of *to; + + to = kzalloc(sizeof(*to), GFP_KERNEL); + if (!to) + return -ENOMEM; + + to->flags = TIMER_OF_IRQ | TIMER_OF_CLOCK | TIMER_OF_BASE; + to->of_irq.handler = msc313e_timer_clkevt_irq; + ret = timer_of_init(np, to); + if (ret) + return ret; + + msc313e_clkevt.cpumask = cpu_possible_mask; + msc313e_clkevt.irq = to->of_irq.irq; + to->clkevt = msc313e_clkevt; + + clockevents_config_and_register(&to->clkevt, timer_of_rate(to), + TIMER_SYNC_TICKS, 0xffffffff); + return 0; +} + +static int __init msc313e_clksrc_init(struct device_node *np) +{ + struct timer_of to = { 0 }; + int ret; + u16 reg; + + to.flags = TIMER_OF_BASE | TIMER_OF_CLOCK; + ret = timer_of_init(np, &to); + if (ret) + return ret; + + msc313e_clksrc = timer_of_base(&to); + reg = readw(msc313e_clksrc + MSC313E_REG_CTRL); + reg |= MSC313E_REG_CTRL_TIMER_EN; + writew(reg, msc313e_clksrc + MSC313E_REG_CTRL); + +#ifdef CONFIG_ARM + msc313e_delay.base = timer_of_base(&to); + msc313e_delay.delay.read_current_timer = msc313e_read_delay_timer_read; + msc313e_delay.delay.freq = timer_of_rate(&to); + + register_current_timer_delay(&msc313e_delay.delay); +#endif + + sched_clock_register(msc313e_timer_sched_clock_read, 32, timer_of_rate(&to)); + return clocksource_mmio_init(timer_of_base(&to), TIMER_NAME, timer_of_rate(&to), 300, 32, + msc313e_timer_clksrc_read); +} + +static int __init msc313e_timer_init(struct device_node *np) +{ + int ret = 0; + static int num_called; + + switch (num_called) { + case 0: + ret = msc313e_clksrc_init(np); + if (ret) + return ret; + break; + + default: + ret = msc313e_clkevt_init(np); + if (ret) + return ret; + break; + } + + num_called++; + + return 0; +} + +TIMER_OF_DECLARE(msc313, "mstar,msc313e-timer", msc313e_timer_init); From e64da64f410cf4f9697e25ab76cdfc679f4fb6db Mon Sep 17 00:00:00 2001 From: Romain Perier Date: Fri, 17 Dec 2021 20:57:23 +0100 Subject: [PATCH 16/17] clocksource/drivers/msc313e: Add support for ssd20xd-based platforms On SSD20X family SoCs the timers are connected to a 432MHz clock instead of 12MHz that all the previous chips used. There is no way to reduce or divide these clocks in the clktree yet as we do not know exactly where the 432MHz clock comes from but it is enabled at boot. The SSD20X timers have an input clock divider within the timer itself to configure the frequency. timer0 is preconfigured at power up to run at 12MHz so it is backwards compatible and doesn't need special handling right now. timer1 and timer2 run at 432Mhz at power up so are not backward compatible. This commit adds support for the input clock divider register and sets timer1 and timer2 to run at 48Mhz for clockevents. Signed-off-by: Romain Perier Link: https://lore.kernel.org/r/20211217195727.8955-3-romain.perier@gmail.com Signed-off-by: Daniel Lezcano --- drivers/clocksource/timer-msc313e.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/clocksource/timer-msc313e.c b/drivers/clocksource/timer-msc313e.c index 154e73444a0c..54c54ca7c786 100644 --- a/drivers/clocksource/timer-msc313e.c +++ b/drivers/clocksource/timer-msc313e.c @@ -33,7 +33,9 @@ #define MSC313E_REG_TIMER_MAX_HIGH 0x0c #define MSC313E_REG_COUNTER_LOW 0x10 #define MSC313E_REG_COUNTER_HIGH 0x14 +#define MSC313E_REG_TIMER_DIVIDE 0x18 +#define MSC313E_CLK_DIVIDER 9 #define TIMER_SYNC_TICKS 3 #ifdef CONFIG_ARM @@ -179,6 +181,12 @@ static int __init msc313e_clkevt_init(struct device_node *np) if (ret) return ret; + if (of_device_is_compatible(np, "sstar,ssd20xd-timer")) { + to->of_clk.rate = clk_get_rate(to->of_clk.clk) / MSC313E_CLK_DIVIDER; + to->of_clk.period = DIV_ROUND_UP(to->of_clk.rate, HZ); + writew(MSC313E_CLK_DIVIDER - 1, timer_of_base(to) + MSC313E_REG_TIMER_DIVIDE); + } + msc313e_clkevt.cpumask = cpu_possible_mask; msc313e_clkevt.irq = to->of_irq.irq; to->clkevt = msc313e_clkevt; @@ -242,3 +250,4 @@ static int __init msc313e_timer_init(struct device_node *np) } TIMER_OF_DECLARE(msc313, "mstar,msc313e-timer", msc313e_timer_init); +TIMER_OF_DECLARE(ssd20xd, "sstar,ssd20xd-timer", msc313e_timer_init); From 7647204c2e81b28b4a7c4eec7d539f998d48eaf0 Mon Sep 17 00:00:00 2001 From: Romain Perier Date: Fri, 17 Dec 2021 20:57:25 +0100 Subject: [PATCH 17/17] dt-bindings: timer: Add Mstar MSC313e timer devicetree bindings documentation This adds the documentation for the devicetree bindings of the Mstar MSC313e timer driver, found from MSC313e SoCs and newer. Signed-off-by: Romain Perier Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20211217195727.8955-5-romain.perier@gmail.com Signed-off-by: Daniel Lezcano --- .../bindings/timer/mstar,msc313e-timer.yaml | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 Documentation/devicetree/bindings/timer/mstar,msc313e-timer.yaml diff --git a/Documentation/devicetree/bindings/timer/mstar,msc313e-timer.yaml b/Documentation/devicetree/bindings/timer/mstar,msc313e-timer.yaml new file mode 100644 index 000000000000..03d5dba5d5b3 --- /dev/null +++ b/Documentation/devicetree/bindings/timer/mstar,msc313e-timer.yaml @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/timer/mstar,msc313e-timer.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Mstar MSC313e Timer Device Tree Bindings + +maintainers: + - Daniel Palmer + - Romain Perier + +properties: + compatible: + enum: + - mstar,msc313e-timer + - sstar,ssd20xd-timer + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + - clocks + +additionalProperties: false + +examples: + - | + #include + + timer@6040 { + compatible = "mstar,msc313e-timer"; + reg = <0x6040 0x40>; + clocks = <&xtal_div2>; + interrupts-extended = <&intc_fiq GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>; + }; +...