Pull timer updates from Thomas Gleixner: "Updates for the time(r) subsystem: Core: - Make the clocksource watchdog more robust by better validation checks of the measurement. Drivers: - New drivers for MStar and SSD20xd SOCs - The usual cleanups and improvements all over the place" * tag 'timers-core-2022-01-13' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: dt-bindings: timer: Add Mstar MSC313e timer devicetree bindings documentation clocksource/drivers/msc313e: Add support for ssd20xd-based platforms clocksource/drivers: Add MStar MSC313e timer support clocksource/drivers/pistachio: Fix -Wunused-but-set-variable warning clocksource/drivers/timer-imx-sysctr: Set cpumask to cpu_possible_mask clocksource/drivers/imx-sysctr: Mark two variable with __ro_after_init clocksource/drivers/renesas,ostm: Make RENESAS_OSTM symbol visible clocksource/drivers/renesas-ostm: Add RZ/G2L OSTM support dt-bindings: timer: renesas: ostm: Document Renesas RZ/G2L OSTM clocksource/drivers/exynos_mct: Fix silly typo resulting in checkpatch warning clocksource: Reduce the default clocksource_watchdog() retries to 2 clocksource: Avoid accidental unstable marking of clocksources dt-bindings: timer: tpm-timer: Add imx8ulp compatible string reset: Add of_reset_control_get_optional_exclusive() clocksource/drivers/exynos_mct: Refactor resources allocation dt-bindings: timer: remove rockchip,rk3066-timer compatible string from rockchip,rk-timer.yaml dt-bindings: timer: cadence_ttc: Add power-domains
Unified · Split
| @@ -612,8 +612,8 @@ · 611 unmodified lines | |||
| 612 | clocksource.max_cswd_read_retries= [KNL] | 612 | clocksource.max_cswd_read_retries= [KNL] |
| 613 | Number of clocksource_watchdog() retries due to | 613 | Number of clocksource_watchdog() retries due to |
| 614 | external delays before the clock will be marked | 614 | external delays before the clock will be marked |
| 615 | unstable. Defaults to three retries, that is, | 615 | unstable. Defaults to two retries, that is, |
| 616 | four attempts to read the clock under test. | 616 | three attempts to read the clock under test. |
| 617 | 617 | ||
| 618 | clocksource.verify_n_cpus= [KNL] | 618 | clocksource.verify_n_cpus= [KNL] |
| 619 | Limit the number of CPUs checked for clocksources | 619 | Limit the number of CPUs checked for clocksources |
| @@ -25,6 +25,9 @@ properties: · 24 unmodified lines | |||
| 25 | clocks: | 25 | clocks: |
| 26 | maxItems: 1 | 26 | maxItems: 1 |
| 27 | 27 | ||
| 28 | power-domains: | ||
| 29 | maxItems: 1 | ||
| 30 | |||
| 28 | timer-width: | 31 | timer-width: |
| 29 | $ref: "/schemas/types.yaml#/definitions/uint32" | 32 | $ref: "/schemas/types.yaml#/definitions/uint32" |
| 30 | description: | | 33 | description: | |
| @@ -0,0 +1,46 @@ | |||
| 1 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||
| 2 | %YAML 1.2 | ||
| 3 | --- | ||
| 4 | $id: http://devicetree.org/schemas/timer/mstar,msc313e-timer.yaml# | ||
| 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 6 | |||
| 7 | title: Mstar MSC313e Timer Device Tree Bindings | ||
| 8 | |||
| 9 | maintainers: | ||
| 10 | - Daniel Palmer <daniel@0x0f.com> | ||
| 11 | - Romain Perier <romain.perier@gmail.com> | ||
| 12 | |||
| 13 | properties: | ||
| 14 | compatible: | ||
| 15 | enum: | ||
| 16 | - mstar,msc313e-timer | ||
| 17 | - sstar,ssd20xd-timer | ||
| 18 | |||
| 19 | reg: | ||
| 20 | maxItems: 1 | ||
| 21 | |||
| 22 | interrupts: | ||
| 23 | maxItems: 1 | ||
| 24 | |||
| 25 | clocks: | ||
| 26 | maxItems: 1 | ||
| 27 | |||
| 28 | required: | ||
| 29 | - compatible | ||
| 30 | - reg | ||
| 31 | - interrupts | ||
| 32 | - clocks | ||
| 33 | |||
| 34 | additionalProperties: false | ||
| 35 | |||
| 36 | examples: | ||
| 37 | - | | ||
| 38 | #include <dt-bindings/interrupt-controller/arm-gic.h> | ||
| 39 | |||
| 40 | timer@6040 { | ||
| 41 | compatible = "mstar,msc313e-timer"; | ||
| 42 | reg = <0x6040 0x40>; | ||
| 43 | clocks = <&xtal_div2>; | ||
| 44 | interrupts-extended = <&intc_fiq GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>; | ||
| 45 | }; | ||
| 46 | ... | ||
| @@ -19,7 +19,11 @@ description: | · 18 unmodified lines | |||
| 19 | 19 | ||
| 20 | properties: | 20 | properties: |
| 21 | compatible: | 21 | compatible: |
| 22 | const: fsl,imx7ulp-tpm | 22 | oneOf: |
| 23 | - const: fsl,imx7ulp-tpm | ||
| 24 | - items: | ||
| 25 | - const: fsl,imx8ulp-tpm | ||
| 26 | - const: fsl,imx7ulp-tpm | ||
| 23 | 27 | ||
| 24 | reg: | 28 | reg: |
| 25 | maxItems: 1 | 29 | maxItems: 1 |
| @@ -21,9 +21,10 @@ properties: · 20 unmodified lines | |||
| 21 | compatible: | 21 | compatible: |
| 22 | items: | 22 | items: |
| 23 | - enum: | 23 | - enum: |
| 24 | - renesas,r7s72100-ostm # RZ/A1H | 24 | - renesas,r7s72100-ostm # RZ/A1H |
| 25 | - renesas,r7s9210-ostm # RZ/A2M | 25 | - renesas,r7s9210-ostm # RZ/A2M |
| 26 | - const: renesas,ostm # Generic | 26 | - renesas,r9a07g044-ostm # RZ/G2{L,LC} |
| 27 | - const: renesas,ostm # Generic | ||
| 27 | 28 | ||
| 28 | reg: | 29 | reg: |
| 29 | maxItems: 1 | 30 | maxItems: 1 |
| @@ -37,6 +38,9 @@ properties: · 7 unmodified lines | |||
| 37 | power-domains: | 38 | power-domains: |
| 38 | maxItems: 1 | 39 | maxItems: 1 |
| 39 | 40 | ||
| 41 | resets: | ||
| 42 | maxItems: 1 | ||
| 43 | |||
| 40 | required: | 44 | required: |
| 41 | - compatible | 45 | - compatible |
| 42 | - reg | 46 | - reg |
| @@ -44,6 +48,16 @@ required: · 1 unmodified line | |||
| 44 | - clocks | 48 | - clocks |
| 45 | - power-domains | 49 | - power-domains |
| 46 | 50 | ||
| 51 | if: | ||
| 52 | properties: | ||
| 53 | compatible: | ||
| 54 | contains: | ||
| 55 | enum: | ||
| 56 | - renesas,r9a07g044-ostm | ||
| 57 | then: | ||
| 58 | required: | ||
| 59 | - resets | ||
| 60 | |||
| 47 | additionalProperties: false | 61 | additionalProperties: false |
| 48 | 62 | ||
| 49 | examples: | 63 | examples: |
| @@ -18,7 +18,6 @@ properties: · 17 unmodified lines | |||
| 18 | - enum: | 18 | - enum: |
| 19 | - rockchip,rv1108-timer | 19 | - rockchip,rv1108-timer |
| 20 | - rockchip,rk3036-timer | 20 | - rockchip,rk3036-timer |
| 21 | - rockchip,rk3066-timer | ||
| 22 | - rockchip,rk3188-timer | 21 | - rockchip,rk3188-timer |
| 23 | - rockchip,rk3228-timer | 22 | - rockchip,rk3228-timer |
| 24 | - rockchip,rk3229-timer | 23 | - rockchip,rk3229-timer |
| @@ -2304,6 +2304,7 @@ F: Documentation/devicetree/bindings/gpio/mstar,msc313-gpio.yaml · 2303 unmodified lines | |||
| 2304 | F: arch/arm/boot/dts/mstar-* | 2304 | F: arch/arm/boot/dts/mstar-* |
| 2305 | F: arch/arm/mach-mstar/ | 2305 | F: arch/arm/mach-mstar/ |
| 2306 | F: drivers/clk/mstar/ | 2306 | F: drivers/clk/mstar/ |
| 2307 | F: drivers/clocksource/timer-msc313e.c | ||
| 2307 | F: drivers/gpio/gpio-msc313.c | 2308 | F: drivers/gpio/gpio-msc313.c |
| 2308 | F: drivers/rtc/rtc-msc313.c | 2309 | F: drivers/rtc/rtc-msc313.c |
| 2309 | F: drivers/watchdog/msc313e_wdt.c | 2310 | F: drivers/watchdog/msc313e_wdt.c |
| @@ -510,7 +510,8 @@ config SH_TIMER_MTU2 · 509 unmodified lines | |||
| 510 | This hardware comes with 16-bit timer registers. | 510 | This hardware comes with 16-bit timer registers. |
| 511 | 511 | ||
| 512 | config RENESAS_OSTM | 512 | config RENESAS_OSTM |
| 513 | bool "Renesas OSTM timer driver" if COMPILE_TEST | 513 | bool "Renesas OSTM timer driver" |
| 514 | depends on ARCH_RENESAS || COMPILE_TEST | ||
| 514 | select CLKSRC_MMIO | 515 | select CLKSRC_MMIO |
| 515 | select TIMER_OF | 516 | select TIMER_OF |
| 516 | help | 517 | help |
| @@ -671,6 +672,15 @@ config MILBEAUT_TIMER · 154 unmodified lines | |||
| 671 | help | 672 | help |
| 672 | Enables the support for Milbeaut timer driver. | 673 | Enables the support for Milbeaut timer driver. |
| 673 | 674 | ||
| 675 | config MSC313E_TIMER | ||
| 676 | bool "MSC313E timer driver" if COMPILE_TEST | ||
| 677 | select TIMER_OF | ||
| 678 | select CLKSRC_MMIO | ||
| 679 | help | ||
| 680 | Enables support for the MStar MSC313E timer driver. | ||
| 681 | This provides access to multiple interrupt generating | ||
| 682 | programmable 32-bit free running incrementing counters. | ||
| 683 | |||
| 674 | config INGENIC_TIMER | 684 | config INGENIC_TIMER |
| 675 | bool "Clocksource/timer using the TCU in Ingenic JZ SoCs" | 685 | bool "Clocksource/timer using the TCU in Ingenic JZ SoCs" |
| 676 | default MACH_INGENIC | 686 | default MACH_INGENIC |
| @@ -88,3 +88,4 @@ obj-$(CONFIG_CSKY_MP_TIMER) += timer-mp-csky.o · 87 unmodified lines | |||
| 88 | obj-$(CONFIG_GX6605S_TIMER) += timer-gx6605s.o | 88 | obj-$(CONFIG_GX6605S_TIMER) += timer-gx6605s.o |
| 89 | obj-$(CONFIG_HYPERV_TIMER) += hyperv_timer.o | 89 | obj-$(CONFIG_HYPERV_TIMER) += hyperv_timer.o |
| 90 | obj-$(CONFIG_MICROCHIP_PIT64B) += timer-microchip-pit64b.o | 90 | obj-$(CONFIG_MICROCHIP_PIT64B) += timer-microchip-pit64b.o |
| 91 | obj-$(CONFIG_MSC313E_TIMER) += timer-msc313e.o | ||
| @@ -467,7 +467,7 @@ static int exynos4_mct_starting_cpu(unsigned int cpu) · 466 unmodified lines | |||
| 467 | evt->tick_resume = set_state_shutdown; | 467 | evt->tick_resume = set_state_shutdown; |
| 468 | evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT | | 468 | evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT | |
| 469 | CLOCK_EVT_FEAT_PERCPU; | 469 | CLOCK_EVT_FEAT_PERCPU; |
| 470 | evt->rating = MCT_CLKEVENTS_RATING, | 470 | evt->rating = MCT_CLKEVENTS_RATING; |
| 471 | 471 | ||
| 472 | exynos4_mct_write(TICK_BASE_CNT, mevt->base + MCT_L_TCNTB_OFFSET); | 472 | exynos4_mct_write(TICK_BASE_CNT, mevt->base + MCT_L_TCNTB_OFFSET); |
| 473 | 473 | ||
| @@ -504,11 +504,14 @@ static int exynos4_mct_dying_cpu(unsigned int cpu) · 30 unmodified lines | |||
| 504 | return 0; | 504 | return 0; |
| 505 | } | 505 | } |
| 506 | 506 | ||
| 507 | static int __init exynos4_timer_resources(struct device_node *np, void __iomem *base) | 507 | static int __init exynos4_timer_resources(struct device_node *np) |
| 508 | { | 508 | { |
| 509 | int err, cpu; | ||
| 510 | struct clk *mct_clk, *tick_clk; | 509 | struct clk *mct_clk, *tick_clk; |
| 511 | 510 | ||
| 511 | reg_base = of_iomap(np, 0); | ||
| 512 | if (!reg_base) | ||
| 513 | panic("%s: unable to ioremap mct address space\n", __func__); | ||
| 514 | |||
| 512 | tick_clk = of_clk_get_by_name(np, "fin_pll"); | 515 | tick_clk = of_clk_get_by_name(np, "fin_pll"); |
| 513 | if (IS_ERR(tick_clk)) | 516 | if (IS_ERR(tick_clk)) |
| 514 | panic("%s: unable to determine tick clock rate\n", __func__); | 517 | 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 * · 4 unmodified lines | |||
| 519 | panic("%s: unable to retrieve mct clock instance\n", __func__); | 522 | panic("%s: unable to retrieve mct clock instance\n", __func__); |
| 520 | clk_prepare_enable(mct_clk); | 523 | clk_prepare_enable(mct_clk); |
| 521 | 524 | ||
| 522 | reg_base = base; | 525 | return 0; |
| 523 | if (!reg_base) | 526 | } |
| 524 | panic("%s: unable to ioremap mct address space\n", __func__); | 527 | |
| 528 | static int __init exynos4_timer_interrupts(struct device_node *np, | ||
| 529 | unsigned int int_type) | ||
| 530 | { | ||
| 531 | int nr_irqs, i, err, cpu; | ||
| 532 | |||
| 533 | mct_int_type = int_type; | ||
| 534 | |||
| 535 | /* This driver uses only one global timer interrupt */ | ||
| 536 | mct_irqs[MCT_G0_IRQ] = irq_of_parse_and_map(np, MCT_G0_IRQ); | ||
| 537 | |||
| 538 | /* | ||
| 539 | * Find out the number of local irqs specified. The local | ||
| 540 | * timer irqs are specified after the four global timer | ||
| 541 | * irqs are specified. | ||
| 542 | */ | ||
| 543 | nr_irqs = of_irq_count(np); | ||
| 544 | for (i = MCT_L0_IRQ; i < nr_irqs; i++) | ||
| 545 | mct_irqs[i] = irq_of_parse_and_map(np, i); | ||
| 525 | 546 | ||
| 526 | if (mct_int_type == MCT_INT_PPI) { | 547 | if (mct_int_type == MCT_INT_PPI) { |
| 527 | 548 | ||
| @@ -581,24 +602,13 @@ out_irq: · 53 unmodified lines | |||
| 581 | 602 | ||
| 582 | static int __init mct_init_dt(struct device_node *np, unsigned int int_type) | 603 | static int __init mct_init_dt(struct device_node *np, unsigned int int_type) |
| 583 | { | 604 | { |
| 584 | u32 nr_irqs, i; | ||
| 585 | int ret; | 605 | int ret; |
| 586 | 606 | ||
| 587 | mct_int_type = int_type; | 607 | ret = exynos4_timer_resources(np); |
| 588 | 608 | if (ret) | |
| 589 | /* This driver uses only one global timer interrupt */ | 609 | return ret; |
| 590 | mct_irqs[MCT_G0_IRQ] = irq_of_parse_and_map(np, MCT_G0_IRQ); | ||
| 591 | |||
| 592 | /* | ||
| 593 | * Find out the number of local irqs specified. The local | ||
| 594 | * timer irqs are specified after the four global timer | ||
| 595 | * irqs are specified. | ||
| 596 | */ | ||
| 597 | nr_irqs = of_irq_count(np); | ||
| 598 | for (i = MCT_L0_IRQ; i < nr_irqs; i++) | ||
| 599 | mct_irqs[i] = irq_of_parse_and_map(np, i); | ||
| 600 | 610 | ||
| 601 | ret = exynos4_timer_resources(np, of_iomap(np, 0)); | 611 | ret = exynos4_timer_interrupts(np, int_type); |
| 602 | if (ret) | 612 | if (ret) |
| 603 | return ret; | 613 | return ret; |
| 604 | 614 | ||
| @@ -9,6 +9,8 @@ · 8 unmodified lines | |||
| 9 | #include <linux/clk.h> | 9 | #include <linux/clk.h> |
| 10 | #include <linux/clockchips.h> | 10 | #include <linux/clockchips.h> |
| 11 | #include <linux/interrupt.h> | 11 | #include <linux/interrupt.h> |
| 12 | #include <linux/platform_device.h> | ||
| 13 | #include <linux/reset.h> | ||
| 12 | #include <linux/sched_clock.h> | 14 | #include <linux/sched_clock.h> |
| 13 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
| 14 | 16 | ||
| @@ -159,6 +161,7 @@ static int __init ostm_init_clkevt(struct timer_of *to) · 144 unmodified lines | |||
| 159 | 161 | ||
| 160 | static int __init ostm_init(struct device_node *np) | 162 | static int __init ostm_init(struct device_node *np) |
| 161 | { | 163 | { |
| 164 | struct reset_control *rstc; | ||
| 162 | struct timer_of *to; | 165 | struct timer_of *to; |
| 163 | int ret; | 166 | int ret; |
| 164 | 167 | ||
| @@ -166,6 +169,14 @@ static int __init ostm_init(struct device_node *np) · 1 unmodified line | |||
| 166 | if (!to) | 169 | if (!to) |
| 167 | return -ENOMEM; | 170 | return -ENOMEM; |
| 168 | 171 | ||
| 172 | rstc = of_reset_control_get_optional_exclusive(np, NULL); | ||
| 173 | if (IS_ERR(rstc)) { | ||
| 174 | ret = PTR_ERR(rstc); | ||
| 175 | goto err_free; | ||
| 176 | } | ||
| 177 | |||
| 178 | reset_control_deassert(rstc); | ||
| 179 | |||
| 169 | to->flags = TIMER_OF_BASE | TIMER_OF_CLOCK; | 180 | to->flags = TIMER_OF_BASE | TIMER_OF_CLOCK; |
| 170 | if (system_clock) { | 181 | if (system_clock) { |
| 171 | /* | 182 | /* |
| @@ -178,7 +189,7 @@ static int __init ostm_init(struct device_node *np) · 6 unmodified lines | |||
| 178 | 189 | ||
| 179 | ret = timer_of_init(np, to); | 190 | ret = timer_of_init(np, to); |
| 180 | if (ret) | 191 | if (ret) |
| 181 | goto err_free; | 192 | goto err_reset; |
| 182 | 193 | ||
| 183 | /* | 194 | /* |
| 184 | * First probed device will be used as system clocksource. Any | 195 | * First probed device will be used as system clocksource. Any |
| @@ -203,9 +214,35 @@ static int __init ostm_init(struct device_node *np) · 18 unmodified lines | |||
| 203 | 214 | ||
| 204 | err_cleanup: | 215 | err_cleanup: |
| 205 | timer_of_cleanup(to); | 216 | timer_of_cleanup(to); |
| 217 | err_reset: | ||
| 218 | reset_control_assert(rstc); | ||
| 219 | reset_control_put(rstc); | ||
| 206 | err_free: | 220 | err_free: |
| 207 | kfree(to); | 221 | kfree(to); |
| 208 | return ret; | 222 | return ret; |
| 209 | } | 223 | } |
| 210 | 224 | ||
| 211 | TIMER_OF_DECLARE(ostm, "renesas,ostm", ostm_init); | 225 | TIMER_OF_DECLARE(ostm, "renesas,ostm", ostm_init); |
| 226 | |||
| 227 | #ifdef CONFIG_ARCH_R9A07G044 | ||
| 228 | static int __init ostm_probe(struct platform_device *pdev) | ||
| 229 | { | ||
| 230 | struct device *dev = &pdev->dev; | ||
| 231 | |||
| 232 | return ostm_init(dev->of_node); | ||
| 233 | } | ||
| 234 | |||
| 235 | static const struct of_device_id ostm_of_table[] = { | ||
| 236 | { .compatible = "renesas,ostm", }, | ||
| 237 | { /* sentinel */ } | ||
| 238 | }; | ||
| 239 | |||
| 240 | static struct platform_driver ostm_device_driver = { | ||
| 241 | .driver = { | ||
| 242 | .name = "renesas_ostm", | ||
| 243 | .of_match_table = of_match_ptr(ostm_of_table), | ||
| 244 | .suppress_bind_attrs = true, | ||
| 245 | }, | ||
| 246 | }; | ||
| 247 | builtin_platform_driver_probe(ostm_device_driver, ostm_probe); | ||
| 248 | #endif | ||
| @@ -20,8 +20,8 @@ · 19 unmodified lines | |||
| 20 | 20 | ||
| 21 | #define SYS_CTR_CLK_DIV 0x3 | 21 | #define SYS_CTR_CLK_DIV 0x3 |
| 22 | 22 | ||
| 23 | static void __iomem *sys_ctr_base; | 23 | static void __iomem *sys_ctr_base __ro_after_init; |
| 24 | static u32 cmpcr; | 24 | static u32 cmpcr __ro_after_init; |
| 25 | 25 | ||
| 26 | static void sysctr_timer_enable(bool enable) | 26 | static void sysctr_timer_enable(bool enable) |
| 27 | { | 27 | { |
| @@ -119,7 +119,7 @@ static struct timer_of to_sysctr = { · 91 unmodified lines | |||
| 119 | 119 | ||
| 120 | static void __init sysctr_clockevent_init(void) | 120 | static void __init sysctr_clockevent_init(void) |
| 121 | { | 121 | { |
| 122 | to_sysctr.clkevt.cpumask = cpumask_of(0); | 122 | to_sysctr.clkevt.cpumask = cpu_possible_mask; |
| 123 | 123 | ||
| 124 | clockevents_config_and_register(&to_sysctr.clkevt, | 124 | clockevents_config_and_register(&to_sysctr.clkevt, |
| 125 | timer_of_rate(&to_sysctr), | 125 | timer_of_rate(&to_sysctr), |
| @@ -0,0 +1,253 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * MStar timer driver | ||
| 4 | * | ||
| 5 | * Copyright (C) 2021 Daniel Palmer | ||
| 6 | * Copyright (C) 2021 Romain Perier | ||
| 7 | * | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include <linux/clk.h> | ||
| 11 | #include <linux/clockchips.h> | ||
| 12 | #include <linux/interrupt.h> | ||
| 13 | #include <linux/irq.h> | ||
| 14 | #include <linux/irqreturn.h> | ||
| 15 | #include <linux/sched_clock.h> | ||
| 16 | #include <linux/of.h> | ||
| 17 | #include <linux/of_address.h> | ||
| 18 | #include <linux/of_irq.h> | ||
| 19 | |||
| 20 | #ifdef CONFIG_ARM | ||
| 21 | #include <linux/delay.h> | ||
| 22 | #endif | ||
| 23 | |||
| 24 | #include "timer-of.h" | ||
| 25 | |||
| 26 | #define TIMER_NAME "msc313e_timer" | ||
| 27 | |||
| 28 | #define MSC313E_REG_CTRL 0x00 | ||
| 29 | #define MSC313E_REG_CTRL_TIMER_EN BIT(0) | ||
| 30 | #define MSC313E_REG_CTRL_TIMER_TRIG BIT(1) | ||
| 31 | #define MSC313E_REG_CTRL_TIMER_INT_EN BIT(8) | ||
| 32 | #define MSC313E_REG_TIMER_MAX_LOW 0x08 | ||
| 33 | #define MSC313E_REG_TIMER_MAX_HIGH 0x0c | ||
| 34 | #define MSC313E_REG_COUNTER_LOW 0x10 | ||
| 35 | #define MSC313E_REG_COUNTER_HIGH 0x14 | ||
| 36 | #define MSC313E_REG_TIMER_DIVIDE 0x18 | ||
| 37 | |||
| 38 | #define MSC313E_CLK_DIVIDER 9 | ||
| 39 | #define TIMER_SYNC_TICKS 3 | ||
| 40 | |||
| 41 | #ifdef CONFIG_ARM | ||
| 42 | struct msc313e_delay { | ||
| 43 | void __iomem *base; | ||
| 44 | struct delay_timer delay; | ||
| 45 | }; | ||
| 46 | static struct msc313e_delay msc313e_delay; | ||
| 47 | #endif | ||
| 48 | |||
| 49 | static void __iomem *msc313e_clksrc; | ||
| 50 | |||
| 51 | static void msc313e_timer_stop(void __iomem *base) | ||
| 52 | { | ||
| 53 | writew(0, base + MSC313E_REG_CTRL); | ||
| 54 | } | ||
| 55 | |||
| 56 | static void msc313e_timer_start(void __iomem *base, bool periodic) | ||
| 57 | { | ||
| 58 | u16 reg; | ||
| 59 | |||
| 60 | reg = readw(base + MSC313E_REG_CTRL); | ||
| 61 | if (periodic) | ||
| 62 | reg |= MSC313E_REG_CTRL_TIMER_EN; | ||
| 63 | else | ||
| 64 | reg |= MSC313E_REG_CTRL_TIMER_TRIG; | ||
| 65 | writew(reg | MSC313E_REG_CTRL_TIMER_INT_EN, base + MSC313E_REG_CTRL); | ||
| 66 | } | ||
| 67 | |||
| 68 | static void msc313e_timer_setup(void __iomem *base, unsigned long delay) | ||
| 69 | { | ||
| 70 | unsigned long flags; | ||
| 71 | |||
| 72 | local_irq_save(flags); | ||
| 73 | writew(delay >> 16, base + MSC313E_REG_TIMER_MAX_HIGH); | ||
| 74 | writew(delay & 0xffff, base + MSC313E_REG_TIMER_MAX_LOW); | ||
| 75 | local_irq_restore(flags); | ||
| 76 | } | ||
| 77 | |||
| 78 | static unsigned long msc313e_timer_current_value(void __iomem *base) | ||
| 79 | { | ||
| 80 | unsigned long flags; | ||
| 81 | u16 l, h; | ||
| 82 | |||
| 83 | local_irq_save(flags); | ||
| 84 | l = readw(base + MSC313E_REG_COUNTER_LOW); | ||
| 85 | h = readw(base + MSC313E_REG_COUNTER_HIGH); | ||
| 86 | local_irq_restore(flags); | ||
| 87 | |||
| 88 | return (((u32)h) << 16 | l); | ||
| 89 | } | ||
| 90 | |||
| 91 | static int msc313e_timer_clkevt_shutdown(struct clock_event_device *evt) | ||
| 92 | { | ||
| 93 | struct timer_of *timer = to_timer_of(evt); | ||
| 94 | |||
| 95 | msc313e_timer_stop(timer_of_base(timer)); | ||
| 96 | |||
| 97 | return 0; | ||
| 98 | } | ||
| 99 | |||
| 100 | static int msc313e_timer_clkevt_set_oneshot(struct clock_event_device *evt) | ||
| 101 | { | ||
| 102 | struct timer_of *timer = to_timer_of(evt); | ||
| 103 | |||
| 104 | msc313e_timer_stop(timer_of_base(timer)); | ||
| 105 | msc313e_timer_start(timer_of_base(timer), false); | ||
| 106 | |||
| 107 | return 0; | ||
| 108 | } | ||
| 109 | |||
| 110 | static int msc313e_timer_clkevt_set_periodic(struct clock_event_device *evt) | ||
| 111 | { | ||
| 112 | struct timer_of *timer = to_timer_of(evt); | ||
| 113 | |||
| 114 | msc313e_timer_stop(timer_of_base(timer)); | ||
| 115 | msc313e_timer_setup(timer_of_base(timer), timer_of_period(timer)); | ||
| 116 | msc313e_timer_start(timer_of_base(timer), true); | ||
| 117 | |||
| 118 | return 0; | ||
| 119 | } | ||
| 120 | |||
| 121 | static int msc313e_timer_clkevt_next_event(unsigned long evt, struct clock_event_device *clkevt) | ||
| 122 | { | ||
| 123 | struct timer_of *timer = to_timer_of(clkevt); | ||
| 124 | |||
| 125 | msc313e_timer_stop(timer_of_base(timer)); | ||
| 126 | msc313e_timer_setup(timer_of_base(timer), evt); | ||
| 127 | msc313e_timer_start(timer_of_base(timer), false); | ||
| 128 | |||
| 129 | return 0; | ||
| 130 | } | ||
| 131 | |||
| 132 | static irqreturn_t msc313e_timer_clkevt_irq(int irq, void *dev_id) | ||
| 133 | { | ||
| 134 | struct clock_event_device *evt = dev_id; | ||
| 135 | |||
| 136 | evt->event_handler(evt); | ||
| 137 | |||
| 138 | return IRQ_HANDLED; | ||
| 139 | } | ||
| 140 | |||
| 141 | static u64 msc313e_timer_clksrc_read(struct clocksource *cs) | ||
| 142 | { | ||
| 143 | return msc313e_timer_current_value(msc313e_clksrc) & cs->mask; | ||
| 144 | } | ||
| 145 | |||
| 146 | #ifdef CONFIG_ARM | ||
| 147 | static unsigned long msc313e_read_delay_timer_read(void) | ||
| 148 | { | ||
| 149 | return msc313e_timer_current_value(msc313e_delay.base); | ||
| 150 | } | ||
| 151 | #endif | ||
| 152 | |||
| 153 | static u64 msc313e_timer_sched_clock_read(void) | ||
| 154 | { | ||
| 155 | return msc313e_timer_current_value(msc313e_clksrc); | ||
| 156 | } | ||
| 157 | |||
| 158 | static struct clock_event_device msc313e_clkevt = { | ||
| 159 | .name = TIMER_NAME, | ||
| 160 | .rating = 300, | ||
| 161 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | ||
| 162 | .set_state_shutdown = msc313e_timer_clkevt_shutdown, | ||
| 163 | .set_state_periodic = msc313e_timer_clkevt_set_periodic, | ||
| 164 | .set_state_oneshot = msc313e_timer_clkevt_set_oneshot, | ||
| 165 | .tick_resume = msc313e_timer_clkevt_shutdown, | ||
| 166 | .set_next_event = msc313e_timer_clkevt_next_event, | ||
| 167 | }; | ||
| 168 | |||
| 169 | static int __init msc313e_clkevt_init(struct device_node *np) | ||
| 170 | { | ||
| 171 | int ret; | ||
| 172 | struct timer_of *to; | ||
| 173 | |||
| 174 | to = kzalloc(sizeof(*to), GFP_KERNEL); | ||
| 175 | if (!to) | ||
| 176 | return -ENOMEM; | ||
| 177 | |||
| 178 | to->flags = TIMER_OF_IRQ | TIMER_OF_CLOCK | TIMER_OF_BASE; | ||
| 179 | to->of_irq.handler = msc313e_timer_clkevt_irq; | ||
| 180 | ret = timer_of_init(np, to); | ||
| 181 | if (ret) | ||
| 182 | return ret; | ||
| 183 | |||
| 184 | if (of_device_is_compatible(np, "sstar,ssd20xd-timer")) { | ||
| 185 | to->of_clk.rate = clk_get_rate(to->of_clk.clk) / MSC313E_CLK_DIVIDER; | ||
| 186 | to->of_clk.period = DIV_ROUND_UP(to->of_clk.rate, HZ); | ||
| 187 | writew(MSC313E_CLK_DIVIDER - 1, timer_of_base(to) + MSC313E_REG_TIMER_DIVIDE); | ||
| 188 | } | ||
| 189 | |||
| 190 | msc313e_clkevt.cpumask = cpu_possible_mask; | ||
| 191 | msc313e_clkevt.irq = to->of_irq.irq; | ||
| 192 | to->clkevt = msc313e_clkevt; | ||
| 193 | |||
| 194 | clockevents_config_and_register(&to->clkevt, timer_of_rate(to), | ||
| 195 | TIMER_SYNC_TICKS, 0xffffffff); | ||
| 196 | return 0; | ||
| 197 | } | ||
| 198 | |||
| 199 | static int __init msc313e_clksrc_init(struct device_node *np) | ||
| 200 | { | ||
| 201 | struct timer_of to = { 0 }; | ||
| 202 | int ret; | ||
| 203 | u16 reg; | ||
| 204 | |||
| 205 | to.flags = TIMER_OF_BASE | TIMER_OF_CLOCK; | ||
| 206 | ret = timer_of_init(np, &to); | ||
| 207 | if (ret) | ||
| 208 | return ret; | ||
| 209 | |||
| 210 | msc313e_clksrc = timer_of_base(&to); | ||
| 211 | reg = readw(msc313e_clksrc + MSC313E_REG_CTRL); | ||
| 212 | reg |= MSC313E_REG_CTRL_TIMER_EN; | ||
| 213 | writew(reg, msc313e_clksrc + MSC313E_REG_CTRL); | ||
| 214 | |||
| 215 | #ifdef CONFIG_ARM | ||
| 216 | msc313e_delay.base = timer_of_base(&to); | ||
| 217 | msc313e_delay.delay.read_current_timer = msc313e_read_delay_timer_read; | ||
| 218 | msc313e_delay.delay.freq = timer_of_rate(&to); | ||
| 219 | |||
| 220 | register_current_timer_delay(&msc313e_delay.delay); | ||
| 221 | #endif | ||
| 222 | |||
| 223 | sched_clock_register(msc313e_timer_sched_clock_read, 32, timer_of_rate(&to)); | ||
| 224 | return clocksource_mmio_init(timer_of_base(&to), TIMER_NAME, timer_of_rate(&to), 300, 32, | ||
| 225 | msc313e_timer_clksrc_read); | ||
| 226 | } | ||
| 227 | |||
| 228 | static int __init msc313e_timer_init(struct device_node *np) | ||
| 229 | { | ||
| 230 | int ret = 0; | ||
| 231 | static int num_called; | ||
| 232 | |||
| 233 | switch (num_called) { | ||
| 234 | case 0: | ||
| 235 | ret = msc313e_clksrc_init(np); | ||
| 236 | if (ret) | ||
| 237 | return ret; | ||
| 238 | break; | ||
| 239 | |||
| 240 | default: | ||
| 241 | ret = msc313e_clkevt_init(np); | ||
| 242 | if (ret) | ||
| 243 | return ret; | ||
| 244 | break; | ||
| 245 | } | ||
| 246 | |||
| 247 | num_called++; | ||
| 248 | |||
| 249 | return 0; | ||
| 250 | } | ||
| 251 | |||
| 252 | TIMER_OF_DECLARE(msc313, "mstar,msc313e-timer", msc313e_timer_init); | ||
| 253 | TIMER_OF_DECLARE(ssd20xd, "sstar,ssd20xd-timer", msc313e_timer_init); | ||
| @@ -71,7 +71,8 @@ static u64 notrace · 70 unmodified lines | |||
| 71 | pistachio_clocksource_read_cycles(struct clocksource *cs) | 71 | pistachio_clocksource_read_cycles(struct clocksource *cs) |
| 72 | { | 72 | { |
| 73 | struct pistachio_clocksource *pcs = to_pistachio_clocksource(cs); | 73 | struct pistachio_clocksource *pcs = to_pistachio_clocksource(cs); |
| 74 | u32 counter, overflow; | 74 | __maybe_unused u32 overflow; |
| 75 | u32 counter; | ||
| 75 | unsigned long flags; | 76 | unsigned long flags; |
| 76 | 77 | ||
| 77 | /* | 78 | /* |
| @@ -454,6 +454,26 @@ static inline struct reset_control *of_reset_control_get_exclusive( · 453 unmodified lines | |||
| 454 | return __of_reset_control_get(node, id, 0, false, false, true); | 454 | return __of_reset_control_get(node, id, 0, false, false, true); |
| 455 | } | 455 | } |
| 456 | 456 | ||
| 457 | /** | ||
| 458 | * of_reset_control_get_optional_exclusive - Lookup and obtain an optional exclusive | ||
| 459 | * reference to a reset controller. | ||
| 460 | * @node: device to be reset by the controller | ||
| 461 | * @id: reset line name | ||
| 462 | * | ||
| 463 | * Optional variant of of_reset_control_get_exclusive(). If the requested reset | ||
| 464 | * is not specified in the device tree, this function returns NULL instead of | ||
| 465 | * an error. | ||
| 466 | * | ||
| 467 | * Returns a struct reset_control or IS_ERR() condition containing errno. | ||
| 468 | * | ||
| 469 | * Use of id names is optional. | ||
| 470 | */ | ||
| 471 | static inline struct reset_control *of_reset_control_get_optional_exclusive( | ||
| 472 | struct device_node *node, const char *id) | ||
| 473 | { | ||
| 474 | return __of_reset_control_get(node, id, 0, false, true, true); | ||
| 475 | } | ||
| 476 | |||
| 457 | /** | 477 | /** |
| 458 | * of_reset_control_get_shared - Lookup and obtain a shared reference | 478 | * of_reset_control_get_shared - Lookup and obtain a shared reference |
| 459 | * to a reset controller. | 479 | * to a reset controller. |
| @@ -107,7 +107,7 @@ static u64 suspend_start; · 106 unmodified lines | |||
| 107 | * This delay could be due to SMIs, NMIs, or to VCPU preemptions. Used as | 107 | * This delay could be due to SMIs, NMIs, or to VCPU preemptions. Used as |
| 108 | * a lower bound for cs->uncertainty_margin values when registering clocks. | 108 | * a lower bound for cs->uncertainty_margin values when registering clocks. |
| 109 | */ | 109 | */ |
| 110 | #define WATCHDOG_MAX_SKEW (50 * NSEC_PER_USEC) | 110 | #define WATCHDOG_MAX_SKEW (100 * NSEC_PER_USEC) |
| 111 | 111 | ||
| 112 | #ifdef CONFIG_CLOCKSOURCE_WATCHDOG | 112 | #ifdef CONFIG_CLOCKSOURCE_WATCHDOG |
| 113 | static void clocksource_watchdog_work(struct work_struct *work); | 113 | static void clocksource_watchdog_work(struct work_struct *work); |
| @@ -199,23 +199,30 @@ void clocksource_mark_unstable(struct clocksource *cs) · 85 unmodified lines | |||
| 199 | spin_unlock_irqrestore(&watchdog_lock, flags); | 199 | spin_unlock_irqrestore(&watchdog_lock, flags); |
| 200 | } | 200 | } |
| 201 | 201 | ||
| 202 | ulong max_cswd_read_retries = 3; | 202 | ulong max_cswd_read_retries = 2; |
| 203 | module_param(max_cswd_read_retries, ulong, 0644); | 203 | module_param(max_cswd_read_retries, ulong, 0644); |
| 204 | EXPORT_SYMBOL_GPL(max_cswd_read_retries); | 204 | EXPORT_SYMBOL_GPL(max_cswd_read_retries); |
| 205 | static int verify_n_cpus = 8; | 205 | static int verify_n_cpus = 8; |
| 206 | module_param(verify_n_cpus, int, 0644); | 206 | module_param(verify_n_cpus, int, 0644); |
| 207 | 207 | ||
| 208 | static bool cs_watchdog_read(struct clocksource *cs, u64 *csnow, u64 *wdnow) | 208 | enum wd_read_status { |
| 209 | WD_READ_SUCCESS, | ||
| 210 | WD_READ_UNSTABLE, | ||
| 211 | WD_READ_SKIP | ||
| 212 | }; | ||
| 213 | |||
| 214 | static enum wd_read_status cs_watchdog_read(struct clocksource *cs, u64 *csnow, u64 *wdnow) | ||
| 209 | { | 215 | { |
| 210 | unsigned int nretries; | 216 | unsigned int nretries; |
| 211 | u64 wd_end, wd_delta; | 217 | u64 wd_end, wd_end2, wd_delta; |
| 212 | int64_t wd_delay; | 218 | int64_t wd_delay, wd_seq_delay; |
| 213 | 219 | ||
| 214 | for (nretries = 0; nretries <= max_cswd_read_retries; nretries++) { | 220 | for (nretries = 0; nretries <= max_cswd_read_retries; nretries++) { |
| 215 | local_irq_disable(); | 221 | local_irq_disable(); |
| 216 | *wdnow = watchdog->read(watchdog); | 222 | *wdnow = watchdog->read(watchdog); |
| 217 | *csnow = cs->read(cs); | 223 | *csnow = cs->read(cs); |
| 218 | wd_end = watchdog->read(watchdog); | 224 | wd_end = watchdog->read(watchdog); |
| 225 | wd_end2 = watchdog->read(watchdog); | ||
| 219 | local_irq_enable(); | 226 | local_irq_enable(); |
| 220 | 227 | ||
| 221 | wd_delta = clocksource_delta(wd_end, *wdnow, watchdog->mask); | 228 | 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) · 4 unmodified lines | |||
| 226 | pr_warn("timekeeping watchdog on CPU%d: %s retried %d times before success\n", | 233 | pr_warn("timekeeping watchdog on CPU%d: %s retried %d times before success\n", |
| 227 | smp_processor_id(), watchdog->name, nretries); | 234 | smp_processor_id(), watchdog->name, nretries); |
| 228 | } | 235 | } |
| 229 | return true; | 236 | return WD_READ_SUCCESS; |
| 230 | } | 237 | } |
| 238 | |||
| 239 | /* | ||
| 240 | * Now compute delay in consecutive watchdog read to see if | ||
| 241 | * there is too much external interferences that cause | ||
| 242 | * significant delay in reading both clocksource and watchdog. | ||
| 243 | * | ||
| 244 | * If consecutive WD read-back delay > WATCHDOG_MAX_SKEW/2, | ||
| 245 | * report system busy, reinit the watchdog and skip the current | ||
| 246 | * watchdog test. | ||
| 247 | */ | ||
| 248 | wd_delta = clocksource_delta(wd_end2, wd_end, watchdog->mask); | ||
| 249 | wd_seq_delay = clocksource_cyc2ns(wd_delta, watchdog->mult, watchdog->shift); | ||
| 250 | if (wd_seq_delay > WATCHDOG_MAX_SKEW/2) | ||
| 251 | goto skip_test; | ||
| 231 | } | 252 | } |
| 232 | 253 | ||
| 233 | pr_warn("timekeeping watchdog on CPU%d: %s read-back delay of %lldns, attempt %d, marking unstable\n", | 254 | pr_warn("timekeeping watchdog on CPU%d: %s read-back delay of %lldns, attempt %d, marking unstable\n", |
| 234 | smp_processor_id(), watchdog->name, wd_delay, nretries); | 255 | smp_processor_id(), watchdog->name, wd_delay, nretries); |
| 235 | return false; | 256 | return WD_READ_UNSTABLE; |
| 257 | |||
| 258 | skip_test: | ||
| 259 | pr_info("timekeeping watchdog on CPU%d: %s wd-wd read-back delay of %lldns\n", | ||
| 260 | smp_processor_id(), watchdog->name, wd_seq_delay); | ||
| 261 | pr_info("wd-%s-wd read-back delay of %lldns, clock-skew test skipped!\n", | ||
| 262 | cs->name, wd_delay); | ||
| 263 | return WD_READ_SKIP; | ||
| 236 | } | 264 | } |
| 237 | 265 | ||
| 238 | static u64 csnow_mid; | 266 | static u64 csnow_mid; |
| @@ -356,6 +384,7 @@ static void clocksource_watchdog(struct timer_list *unused) · 117 unmodified lines | |||
| 356 | int next_cpu, reset_pending; | 384 | int next_cpu, reset_pending; |
| 357 | int64_t wd_nsec, cs_nsec; | 385 | int64_t wd_nsec, cs_nsec; |
| 358 | struct clocksource *cs; | 386 | struct clocksource *cs; |
| 387 | enum wd_read_status read_ret; | ||
| 359 | u32 md; | 388 | u32 md; |
| 360 | 389 | ||
| 361 | spin_lock(&watchdog_lock); | 390 | spin_lock(&watchdog_lock); |
| @@ -373,9 +402,12 @@ static void clocksource_watchdog(struct timer_list *unused) · 11 unmodified lines | |||
| 373 | continue; | 402 | continue; |
| 374 | } | 403 | } |
| 375 | 404 | ||
| 376 | if (!cs_watchdog_read(cs, &csnow, &wdnow)) { | 405 | read_ret = cs_watchdog_read(cs, &csnow, &wdnow); |
| 377 | /* Clock readout unreliable, so give it up. */ | 406 | |
| 378 | __clocksource_unstable(cs); | 407 | if (read_ret != WD_READ_SUCCESS) { |
| 408 | if (read_ret == WD_READ_UNSTABLE) | ||
| 409 | /* Clock readout unreliable, so give it up. */ | ||
| 410 | __clocksource_unstable(cs); | ||
| 379 | continue; | 411 | continue; |
| 380 | } | 412 | } |
| 381 | 413 | ||