diff options
| author | Thomas Gleixner <tglx@linutronix.de> | 2019-02-23 11:21:53 -0500 |
|---|---|---|
| committer | Thomas Gleixner <tglx@linutronix.de> | 2019-02-23 11:21:53 -0500 |
| commit | 8dd2eee2f444a7a570599bffc9da330157cca5b5 (patch) | |
| tree | 400b9a2fb19e7ac5bac27750bdac77615eded541 | |
| parent | 75b710af7139768fd4ba2d4e05335d2344796279 (diff) | |
| parent | f40f4fc9506d6b2b786920059b320aac3a831574 (diff) | |
Merge branch 'clockevents/5.1' of https://git.linaro.org/people/daniel.lezcano/linux into timers/core
Pull clockevents updates from Daniel Lezcano:
- Update the binding documentation for the gpt timer (Anson Huang)
- Improve checking and error handling at init time on risc timer (Atish
Patra)
- Update the binding documentation for r8a774c0 cmt and tmu (Biju Das)
- Fail gracefully when clock rate is unavailable on sun5i (Chen-Yu Tsai)
- Rename the tango-xtal, pxa and cs5535 to timer-*.c for consistency
(Daniel Lezcano)
- Add the support for the tegra210 timer and add the platform's Kconfig
selection (Joseph Lo)
- Do a cleanup in the header inclusions and remove the unused ones for the
exynos_mct timer driver (Krzysztof Kozlowski)
- Remove some non-of dead code and fix the error path when initializing
the resources in the exynos_mct timer driver (Marek Szyprowski)
- Update the DT bindings for the MT7629 (Ryder Lee)
- Provide a workaround for the arm arch timer for Allwinner A64 timers
(Samuel Holland)
- Clear the timer interrupt at shutdown time on the exynos_mct timer
driver (Stuart Menefy)
18 files changed, 470 insertions, 148 deletions
diff --git a/Documentation/arm64/silicon-errata.txt b/Documentation/arm64/silicon-errata.txt index 1f09d043d086..ddb8ce5333ba 100644 --- a/Documentation/arm64/silicon-errata.txt +++ b/Documentation/arm64/silicon-errata.txt | |||
| @@ -44,6 +44,8 @@ stable kernels. | |||
| 44 | 44 | ||
| 45 | | Implementor | Component | Erratum ID | Kconfig | | 45 | | Implementor | Component | Erratum ID | Kconfig | |
| 46 | +----------------+-----------------+-----------------+-----------------------------+ | 46 | +----------------+-----------------+-----------------+-----------------------------+ |
| 47 | | Allwinner | A64/R18 | UNKNOWN1 | SUN50I_ERRATUM_UNKNOWN1 | | ||
| 48 | | | | | | | ||
| 47 | | ARM | Cortex-A53 | #826319 | ARM64_ERRATUM_826319 | | 49 | | ARM | Cortex-A53 | #826319 | ARM64_ERRATUM_826319 | |
| 48 | | ARM | Cortex-A53 | #827319 | ARM64_ERRATUM_827319 | | 50 | | ARM | Cortex-A53 | #827319 | ARM64_ERRATUM_827319 | |
| 49 | | ARM | Cortex-A53 | #824069 | ARM64_ERRATUM_824069 | | 51 | | ARM | Cortex-A53 | #824069 | ARM64_ERRATUM_824069 | |
diff --git a/Documentation/devicetree/bindings/timer/fsl,imxgpt.txt b/Documentation/devicetree/bindings/timer/fsl,imxgpt.txt index 9809b11f7180..5d8fd5b52598 100644 --- a/Documentation/devicetree/bindings/timer/fsl,imxgpt.txt +++ b/Documentation/devicetree/bindings/timer/fsl,imxgpt.txt | |||
| @@ -2,17 +2,44 @@ Freescale i.MX General Purpose Timer (GPT) | |||
| 2 | 2 | ||
| 3 | Required properties: | 3 | Required properties: |
| 4 | 4 | ||
| 5 | - compatible : should be "fsl,<soc>-gpt" | 5 | - compatible : should be one of following: |
| 6 | - reg : Specifies base physical address and size of the registers. | 6 | for i.MX1: |
| 7 | - interrupts : A list of 4 interrupts; one per timer channel. | 7 | - "fsl,imx1-gpt"; |
| 8 | - clocks : The clocks provided by the SoC to drive the timer. | 8 | for i.MX21: |
| 9 | - "fsl,imx21-gpt"; | ||
| 10 | for i.MX27: | ||
| 11 | - "fsl,imx27-gpt", "fsl,imx21-gpt"; | ||
| 12 | for i.MX31: | ||
| 13 | - "fsl,imx31-gpt"; | ||
| 14 | for i.MX25: | ||
| 15 | - "fsl,imx25-gpt", "fsl,imx31-gpt"; | ||
| 16 | for i.MX50: | ||
| 17 | - "fsl,imx50-gpt", "fsl,imx31-gpt"; | ||
| 18 | for i.MX51: | ||
| 19 | - "fsl,imx51-gpt", "fsl,imx31-gpt"; | ||
| 20 | for i.MX53: | ||
| 21 | - "fsl,imx53-gpt", "fsl,imx31-gpt"; | ||
| 22 | for i.MX6Q: | ||
| 23 | - "fsl,imx6q-gpt", "fsl,imx31-gpt"; | ||
| 24 | for i.MX6DL: | ||
| 25 | - "fsl,imx6dl-gpt"; | ||
| 26 | for i.MX6SL: | ||
| 27 | - "fsl,imx6sl-gpt", "fsl,imx6dl-gpt"; | ||
| 28 | for i.MX6SX: | ||
| 29 | - "fsl,imx6sx-gpt", "fsl,imx6dl-gpt"; | ||
| 30 | - reg : specifies base physical address and size of the registers. | ||
| 31 | - interrupts : should be the gpt interrupt. | ||
| 32 | - clocks : the clocks provided by the SoC to drive the timer, must contain | ||
| 33 | an entry for each entry in clock-names. | ||
| 34 | - clock-names : must include "ipg" entry first, then "per" entry. | ||
| 9 | 35 | ||
| 10 | Example: | 36 | Example: |
| 11 | 37 | ||
| 12 | gpt1: timer@10003000 { | 38 | gpt1: timer@10003000 { |
| 13 | compatible = "fsl,imx27-gpt", "fsl,imx1-gpt"; | 39 | compatible = "fsl,imx27-gpt", "fsl,imx21-gpt"; |
| 14 | reg = <0x10003000 0x1000>; | 40 | reg = <0x10003000 0x1000>; |
| 15 | interrupts = <26>; | 41 | interrupts = <26>; |
| 16 | clocks = <&clks 46>, <&clks 61>; | 42 | clocks = <&clks IMX27_CLK_GPT1_IPG_GATE>, |
| 43 | <&clks IMX27_CLK_PER1_GATE>; | ||
| 17 | clock-names = "ipg", "per"; | 44 | clock-names = "ipg", "per"; |
| 18 | }; | 45 | }; |
diff --git a/Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt b/Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt index 18d4d0166c76..ff7c567a7972 100644 --- a/Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt +++ b/Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | Mediatek Timers | 1 | MediaTek Timers |
| 2 | --------------- | 2 | --------------- |
| 3 | 3 | ||
| 4 | Mediatek SoCs have two different timers on different platforms, | 4 | MediaTek SoCs have two different timers on different platforms, |
| 5 | - GPT (General Purpose Timer) | 5 | - GPT (General Purpose Timer) |
| 6 | - SYST (System Timer) | 6 | - SYST (System Timer) |
| 7 | 7 | ||
| @@ -9,6 +9,7 @@ The proper timer will be selected automatically by driver. | |||
| 9 | 9 | ||
| 10 | Required properties: | 10 | Required properties: |
| 11 | - compatible should contain: | 11 | - compatible should contain: |
| 12 | For those SoCs that use GPT | ||
| 12 | * "mediatek,mt2701-timer" for MT2701 compatible timers (GPT) | 13 | * "mediatek,mt2701-timer" for MT2701 compatible timers (GPT) |
| 13 | * "mediatek,mt6580-timer" for MT6580 compatible timers (GPT) | 14 | * "mediatek,mt6580-timer" for MT6580 compatible timers (GPT) |
| 14 | * "mediatek,mt6589-timer" for MT6589 compatible timers (GPT) | 15 | * "mediatek,mt6589-timer" for MT6589 compatible timers (GPT) |
| @@ -17,7 +18,11 @@ Required properties: | |||
| 17 | * "mediatek,mt8135-timer" for MT8135 compatible timers (GPT) | 18 | * "mediatek,mt8135-timer" for MT8135 compatible timers (GPT) |
| 18 | * "mediatek,mt8173-timer" for MT8173 compatible timers (GPT) | 19 | * "mediatek,mt8173-timer" for MT8173 compatible timers (GPT) |
| 19 | * "mediatek,mt6577-timer" for MT6577 and all above compatible timers (GPT) | 20 | * "mediatek,mt6577-timer" for MT6577 and all above compatible timers (GPT) |
| 20 | * "mediatek,mt6765-timer" for MT6765 compatible timers (SYST) | 21 | |
| 22 | For those SoCs that use SYST | ||
| 23 | * "mediatek,mt7629-timer" for MT7629 compatible timers (SYST) | ||
| 24 | * "mediatek,mt6765-timer" for MT6765 and all above compatible timers (SYST) | ||
| 25 | |||
| 21 | - reg: Should contain location and length for timer register. | 26 | - reg: Should contain location and length for timer register. |
| 22 | - clocks: Should contain system clock. | 27 | - clocks: Should contain system clock. |
| 23 | 28 | ||
diff --git a/Documentation/devicetree/bindings/timer/nvidia,tegra210-timer.txt b/Documentation/devicetree/bindings/timer/nvidia,tegra210-timer.txt new file mode 100644 index 000000000000..032cda96fe0d --- /dev/null +++ b/Documentation/devicetree/bindings/timer/nvidia,tegra210-timer.txt | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | NVIDIA Tegra210 timer | ||
| 2 | |||
| 3 | The Tegra210 timer provides fourteen 29-bit timer counters and one 32-bit | ||
| 4 | timestamp counter. The TMRs run at either a fixed 1 MHz clock rate derived | ||
| 5 | from the oscillator clock (TMR0-TMR9) or directly at the oscillator clock | ||
| 6 | (TMR10-TMR13). Each TMR can be programmed to generate one-shot, periodic, | ||
| 7 | or watchdog interrupts. | ||
| 8 | |||
| 9 | Required properties: | ||
| 10 | - compatible : "nvidia,tegra210-timer". | ||
| 11 | - reg : Specifies base physical address and size of the registers. | ||
| 12 | - interrupts : A list of 14 interrupts; one per each timer channels 0 through | ||
| 13 | 13. | ||
| 14 | - clocks : Must contain one entry, for the module clock. | ||
| 15 | See ../clocks/clock-bindings.txt for details. | ||
| 16 | |||
| 17 | timer@60005000 { | ||
| 18 | compatible = "nvidia,tegra210-timer"; | ||
| 19 | reg = <0x0 0x60005000 0x0 0x400>; | ||
| 20 | interrupts = <GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH>, | ||
| 21 | <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>, | ||
| 22 | <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>, | ||
| 23 | <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>, | ||
| 24 | <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>, | ||
| 25 | <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>, | ||
| 26 | <GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>, | ||
| 27 | <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>, | ||
| 28 | <GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>, | ||
| 29 | <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>, | ||
| 30 | <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>, | ||
| 31 | <GIC_SPI 177 IRQ_TYPE_LEVEL_HIGH>, | ||
| 32 | <GIC_SPI 178 IRQ_TYPE_LEVEL_HIGH>, | ||
| 33 | <GIC_SPI 179 IRQ_TYPE_LEVEL_HIGH>; | ||
| 34 | clocks = <&tegra_car TEGRA210_CLK_TIMER>; | ||
| 35 | clock-names = "timer"; | ||
| 36 | }; | ||
diff --git a/Documentation/devicetree/bindings/timer/renesas,cmt.txt b/Documentation/devicetree/bindings/timer/renesas,cmt.txt index 862a80f0380a..c0594450e9ef 100644 --- a/Documentation/devicetree/bindings/timer/renesas,cmt.txt +++ b/Documentation/devicetree/bindings/timer/renesas,cmt.txt | |||
| @@ -32,6 +32,8 @@ Required Properties: | |||
| 32 | - "renesas,r8a77470-cmt1" for the 48-bit CMT1 device included in r8a77470. | 32 | - "renesas,r8a77470-cmt1" for the 48-bit CMT1 device included in r8a77470. |
| 33 | - "renesas,r8a774a1-cmt0" for the 32-bit CMT0 device included in r8a774a1. | 33 | - "renesas,r8a774a1-cmt0" for the 32-bit CMT0 device included in r8a774a1. |
| 34 | - "renesas,r8a774a1-cmt1" for the 48-bit CMT1 device included in r8a774a1. | 34 | - "renesas,r8a774a1-cmt1" for the 48-bit CMT1 device included in r8a774a1. |
| 35 | - "renesas,r8a774c0-cmt0" for the 32-bit CMT0 device included in r8a774c0. | ||
| 36 | - "renesas,r8a774c0-cmt1" for the 48-bit CMT1 device included in r8a774c0. | ||
| 35 | - "renesas,r8a7790-cmt0" for the 32-bit CMT0 device included in r8a7790. | 37 | - "renesas,r8a7790-cmt0" for the 32-bit CMT0 device included in r8a7790. |
| 36 | - "renesas,r8a7790-cmt1" for the 48-bit CMT1 device included in r8a7790. | 38 | - "renesas,r8a7790-cmt1" for the 48-bit CMT1 device included in r8a7790. |
| 37 | - "renesas,r8a7791-cmt0" for the 32-bit CMT0 device included in r8a7791. | 39 | - "renesas,r8a7791-cmt0" for the 32-bit CMT0 device included in r8a7791. |
diff --git a/Documentation/devicetree/bindings/timer/renesas,tmu.txt b/Documentation/devicetree/bindings/timer/renesas,tmu.txt index 4ddff85837da..13ad07416bdd 100644 --- a/Documentation/devicetree/bindings/timer/renesas,tmu.txt +++ b/Documentation/devicetree/bindings/timer/renesas,tmu.txt | |||
| @@ -10,6 +10,7 @@ Required Properties: | |||
| 10 | 10 | ||
| 11 | - compatible: must contain one or more of the following: | 11 | - compatible: must contain one or more of the following: |
| 12 | - "renesas,tmu-r8a7740" for the r8a7740 TMU | 12 | - "renesas,tmu-r8a7740" for the r8a7740 TMU |
| 13 | - "renesas,tmu-r8a774c0" for the r8a774C0 TMU | ||
| 13 | - "renesas,tmu-r8a7778" for the r8a7778 TMU | 14 | - "renesas,tmu-r8a7778" for the r8a7778 TMU |
| 14 | - "renesas,tmu-r8a7779" for the r8a7779 TMU | 15 | - "renesas,tmu-r8a7779" for the r8a7779 TMU |
| 15 | - "renesas,tmu-r8a77970" for the r8a77970 TMU | 16 | - "renesas,tmu-r8a77970" for the r8a77970 TMU |
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index a9e26f6a81a1..5d93e580e5dc 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig | |||
| @@ -131,7 +131,8 @@ config SUN5I_HSTIMER | |||
| 131 | config TEGRA_TIMER | 131 | config TEGRA_TIMER |
| 132 | bool "Tegra timer driver" if COMPILE_TEST | 132 | bool "Tegra timer driver" if COMPILE_TEST |
| 133 | select CLKSRC_MMIO | 133 | select CLKSRC_MMIO |
| 134 | depends on ARM | 134 | select TIMER_OF |
| 135 | depends on ARM || ARM64 | ||
| 135 | help | 136 | help |
| 136 | Enables support for the Tegra driver. | 137 | Enables support for the Tegra driver. |
| 137 | 138 | ||
| @@ -360,6 +361,16 @@ config ARM64_ERRATUM_858921 | |||
| 360 | The workaround will be dynamically enabled when an affected | 361 | The workaround will be dynamically enabled when an affected |
| 361 | core is detected. | 362 | core is detected. |
| 362 | 363 | ||
| 364 | config SUN50I_ERRATUM_UNKNOWN1 | ||
| 365 | bool "Workaround for Allwinner A64 erratum UNKNOWN1" | ||
| 366 | default y | ||
| 367 | depends on ARM_ARCH_TIMER && ARM64 && ARCH_SUNXI | ||
| 368 | select ARM_ARCH_TIMER_OOL_WORKAROUND | ||
| 369 | help | ||
| 370 | This option enables a workaround for instability in the timer on | ||
| 371 | the Allwinner A64 SoC. The workaround will only be active if the | ||
| 372 | allwinner,erratum-unknown1 property is found in the timer node. | ||
| 373 | |||
| 363 | config ARM_GLOBAL_TIMER | 374 | config ARM_GLOBAL_TIMER |
| 364 | bool "Support for the ARM global timer" if COMPILE_TEST | 375 | bool "Support for the ARM global timer" if COMPILE_TEST |
| 365 | select TIMER_OF if OF | 376 | select TIMER_OF if OF |
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index cdd210ff89ea..c4a8e9ef932a 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile | |||
| @@ -6,7 +6,7 @@ obj-$(CONFIG_ATMEL_ST) += timer-atmel-st.o | |||
| 6 | obj-$(CONFIG_ATMEL_TCB_CLKSRC) += tcb_clksrc.o | 6 | obj-$(CONFIG_ATMEL_TCB_CLKSRC) += tcb_clksrc.o |
| 7 | obj-$(CONFIG_X86_PM_TIMER) += acpi_pm.o | 7 | obj-$(CONFIG_X86_PM_TIMER) += acpi_pm.o |
| 8 | obj-$(CONFIG_SCx200HR_TIMER) += scx200_hrt.o | 8 | obj-$(CONFIG_SCx200HR_TIMER) += scx200_hrt.o |
| 9 | obj-$(CONFIG_CS5535_CLOCK_EVENT_SRC) += cs5535-clockevt.o | 9 | obj-$(CONFIG_CS5535_CLOCK_EVENT_SRC) += timer-cs5535.o |
| 10 | obj-$(CONFIG_CLKSRC_JCORE_PIT) += jcore-pit.o | 10 | obj-$(CONFIG_CLKSRC_JCORE_PIT) += jcore-pit.o |
| 11 | obj-$(CONFIG_SH_TIMER_CMT) += sh_cmt.o | 11 | obj-$(CONFIG_SH_TIMER_CMT) += sh_cmt.o |
| 12 | obj-$(CONFIG_SH_TIMER_MTU2) += sh_mtu2.o | 12 | obj-$(CONFIG_SH_TIMER_MTU2) += sh_mtu2.o |
| @@ -29,7 +29,7 @@ obj-$(CONFIG_BCM2835_TIMER) += bcm2835_timer.o | |||
| 29 | obj-$(CONFIG_CLPS711X_TIMER) += clps711x-timer.o | 29 | obj-$(CONFIG_CLPS711X_TIMER) += clps711x-timer.o |
| 30 | obj-$(CONFIG_ATLAS7_TIMER) += timer-atlas7.o | 30 | obj-$(CONFIG_ATLAS7_TIMER) += timer-atlas7.o |
| 31 | obj-$(CONFIG_MXS_TIMER) += mxs_timer.o | 31 | obj-$(CONFIG_MXS_TIMER) += mxs_timer.o |
| 32 | obj-$(CONFIG_CLKSRC_PXA) += pxa_timer.o | 32 | obj-$(CONFIG_CLKSRC_PXA) += timer-pxa.o |
| 33 | obj-$(CONFIG_PRIMA2_TIMER) += timer-prima2.o | 33 | obj-$(CONFIG_PRIMA2_TIMER) += timer-prima2.o |
| 34 | obj-$(CONFIG_U300_TIMER) += timer-u300.o | 34 | obj-$(CONFIG_U300_TIMER) += timer-u300.o |
| 35 | obj-$(CONFIG_SUN4I_TIMER) += timer-sun4i.o | 35 | obj-$(CONFIG_SUN4I_TIMER) += timer-sun4i.o |
| @@ -69,7 +69,7 @@ obj-$(CONFIG_KEYSTONE_TIMER) += timer-keystone.o | |||
| 69 | obj-$(CONFIG_INTEGRATOR_AP_TIMER) += timer-integrator-ap.o | 69 | obj-$(CONFIG_INTEGRATOR_AP_TIMER) += timer-integrator-ap.o |
| 70 | obj-$(CONFIG_CLKSRC_VERSATILE) += timer-versatile.o | 70 | obj-$(CONFIG_CLKSRC_VERSATILE) += timer-versatile.o |
| 71 | obj-$(CONFIG_CLKSRC_MIPS_GIC) += mips-gic-timer.o | 71 | obj-$(CONFIG_CLKSRC_MIPS_GIC) += mips-gic-timer.o |
| 72 | obj-$(CONFIG_CLKSRC_TANGO_XTAL) += tango_xtal.o | 72 | obj-$(CONFIG_CLKSRC_TANGO_XTAL) += timer-tango-xtal.o |
| 73 | obj-$(CONFIG_CLKSRC_IMX_GPT) += timer-imx-gpt.o | 73 | obj-$(CONFIG_CLKSRC_IMX_GPT) += timer-imx-gpt.o |
| 74 | obj-$(CONFIG_CLKSRC_IMX_TPM) += timer-imx-tpm.o | 74 | obj-$(CONFIG_CLKSRC_IMX_TPM) += timer-imx-tpm.o |
| 75 | obj-$(CONFIG_ASM9260_TIMER) += asm9260_timer.o | 75 | obj-$(CONFIG_ASM9260_TIMER) += asm9260_timer.o |
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 9a7d4dc00b6e..a8b20b65bd4b 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c | |||
| @@ -326,6 +326,48 @@ static u64 notrace arm64_1188873_read_cntvct_el0(void) | |||
| 326 | } | 326 | } |
| 327 | #endif | 327 | #endif |
| 328 | 328 | ||
| 329 | #ifdef CONFIG_SUN50I_ERRATUM_UNKNOWN1 | ||
| 330 | /* | ||
| 331 | * The low bits of the counter registers are indeterminate while bit 10 or | ||
| 332 | * greater is rolling over. Since the counter value can jump both backward | ||
| 333 | * (7ff -> 000 -> 800) and forward (7ff -> fff -> 800), ignore register values | ||
| 334 | * with all ones or all zeros in the low bits. Bound the loop by the maximum | ||
| 335 | * number of CPU cycles in 3 consecutive 24 MHz counter periods. | ||
| 336 | */ | ||
| 337 | #define __sun50i_a64_read_reg(reg) ({ \ | ||
| 338 | u64 _val; \ | ||
| 339 | int _retries = 150; \ | ||
| 340 | \ | ||
| 341 | do { \ | ||
| 342 | _val = read_sysreg(reg); \ | ||
| 343 | _retries--; \ | ||
| 344 | } while (((_val + 1) & GENMASK(9, 0)) <= 1 && _retries); \ | ||
| 345 | \ | ||
| 346 | WARN_ON_ONCE(!_retries); \ | ||
| 347 | _val; \ | ||
| 348 | }) | ||
| 349 | |||
| 350 | static u64 notrace sun50i_a64_read_cntpct_el0(void) | ||
| 351 | { | ||
| 352 | return __sun50i_a64_read_reg(cntpct_el0); | ||
| 353 | } | ||
| 354 | |||
| 355 | static u64 notrace sun50i_a64_read_cntvct_el0(void) | ||
| 356 | { | ||
| 357 | return __sun50i_a64_read_reg(cntvct_el0); | ||
| 358 | } | ||
| 359 | |||
| 360 | static u32 notrace sun50i_a64_read_cntp_tval_el0(void) | ||
| 361 | { | ||
| 362 | return read_sysreg(cntp_cval_el0) - sun50i_a64_read_cntpct_el0(); | ||
| 363 | } | ||
| 364 | |||
| 365 | static u32 notrace sun50i_a64_read_cntv_tval_el0(void) | ||
| 366 | { | ||
| 367 | return read_sysreg(cntv_cval_el0) - sun50i_a64_read_cntvct_el0(); | ||
| 368 | } | ||
| 369 | #endif | ||
| 370 | |||
| 329 | #ifdef CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND | 371 | #ifdef CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND |
| 330 | DEFINE_PER_CPU(const struct arch_timer_erratum_workaround *, timer_unstable_counter_workaround); | 372 | DEFINE_PER_CPU(const struct arch_timer_erratum_workaround *, timer_unstable_counter_workaround); |
| 331 | EXPORT_SYMBOL_GPL(timer_unstable_counter_workaround); | 373 | EXPORT_SYMBOL_GPL(timer_unstable_counter_workaround); |
| @@ -423,6 +465,19 @@ static const struct arch_timer_erratum_workaround ool_workarounds[] = { | |||
| 423 | .read_cntvct_el0 = arm64_1188873_read_cntvct_el0, | 465 | .read_cntvct_el0 = arm64_1188873_read_cntvct_el0, |
| 424 | }, | 466 | }, |
| 425 | #endif | 467 | #endif |
| 468 | #ifdef CONFIG_SUN50I_ERRATUM_UNKNOWN1 | ||
| 469 | { | ||
| 470 | .match_type = ate_match_dt, | ||
| 471 | .id = "allwinner,erratum-unknown1", | ||
| 472 | .desc = "Allwinner erratum UNKNOWN1", | ||
| 473 | .read_cntp_tval_el0 = sun50i_a64_read_cntp_tval_el0, | ||
| 474 | .read_cntv_tval_el0 = sun50i_a64_read_cntv_tval_el0, | ||
| 475 | .read_cntpct_el0 = sun50i_a64_read_cntpct_el0, | ||
| 476 | .read_cntvct_el0 = sun50i_a64_read_cntvct_el0, | ||
| 477 | .set_next_event_phys = erratum_set_next_event_tval_phys, | ||
| 478 | .set_next_event_virt = erratum_set_next_event_tval_virt, | ||
| 479 | }, | ||
| 480 | #endif | ||
| 426 | }; | 481 | }; |
| 427 | 482 | ||
| 428 | typedef bool (*ate_match_fn_t)(const struct arch_timer_erratum_workaround *, | 483 | typedef bool (*ate_match_fn_t)(const struct arch_timer_erratum_workaround *, |
diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c index 7a244b681876..34bd250d46c6 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c | |||
| @@ -10,14 +10,12 @@ | |||
| 10 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
| 11 | */ | 11 | */ |
| 12 | 12 | ||
| 13 | #include <linux/sched.h> | ||
| 14 | #include <linux/interrupt.h> | 13 | #include <linux/interrupt.h> |
| 15 | #include <linux/irq.h> | 14 | #include <linux/irq.h> |
| 16 | #include <linux/err.h> | 15 | #include <linux/err.h> |
| 17 | #include <linux/clk.h> | 16 | #include <linux/clk.h> |
| 18 | #include <linux/clockchips.h> | 17 | #include <linux/clockchips.h> |
| 19 | #include <linux/cpu.h> | 18 | #include <linux/cpu.h> |
| 20 | #include <linux/platform_device.h> | ||
| 21 | #include <linux/delay.h> | 19 | #include <linux/delay.h> |
| 22 | #include <linux/percpu.h> | 20 | #include <linux/percpu.h> |
| 23 | #include <linux/of.h> | 21 | #include <linux/of.h> |
| @@ -388,6 +386,13 @@ static void exynos4_mct_tick_start(unsigned long cycles, | |||
| 388 | exynos4_mct_write(tmp, mevt->base + MCT_L_TCON_OFFSET); | 386 | exynos4_mct_write(tmp, mevt->base + MCT_L_TCON_OFFSET); |
| 389 | } | 387 | } |
| 390 | 388 | ||
| 389 | static void exynos4_mct_tick_clear(struct mct_clock_event_device *mevt) | ||
| 390 | { | ||
| 391 | /* Clear the MCT tick interrupt */ | ||
| 392 | if (readl_relaxed(reg_base + mevt->base + MCT_L_INT_CSTAT_OFFSET) & 1) | ||
| 393 | exynos4_mct_write(0x1, mevt->base + MCT_L_INT_CSTAT_OFFSET); | ||
| 394 | } | ||
| 395 | |||
| 391 | static int exynos4_tick_set_next_event(unsigned long cycles, | 396 | static int exynos4_tick_set_next_event(unsigned long cycles, |
| 392 | struct clock_event_device *evt) | 397 | struct clock_event_device *evt) |
| 393 | { | 398 | { |
| @@ -404,6 +409,7 @@ static int set_state_shutdown(struct clock_event_device *evt) | |||
| 404 | 409 | ||
| 405 | mevt = container_of(evt, struct mct_clock_event_device, evt); | 410 | mevt = container_of(evt, struct mct_clock_event_device, evt); |
| 406 | exynos4_mct_tick_stop(mevt); | 411 | exynos4_mct_tick_stop(mevt); |
| 412 | exynos4_mct_tick_clear(mevt); | ||
| 407 | return 0; | 413 | return 0; |
| 408 | } | 414 | } |
| 409 | 415 | ||
| @@ -420,8 +426,11 @@ static int set_state_periodic(struct clock_event_device *evt) | |||
| 420 | return 0; | 426 | return 0; |
| 421 | } | 427 | } |
| 422 | 428 | ||
| 423 | static void exynos4_mct_tick_clear(struct mct_clock_event_device *mevt) | 429 | static irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id) |
| 424 | { | 430 | { |
| 431 | struct mct_clock_event_device *mevt = dev_id; | ||
| 432 | struct clock_event_device *evt = &mevt->evt; | ||
| 433 | |||
| 425 | /* | 434 | /* |
| 426 | * This is for supporting oneshot mode. | 435 | * This is for supporting oneshot mode. |
| 427 | * Mct would generate interrupt periodically | 436 | * Mct would generate interrupt periodically |
| @@ -430,16 +439,6 @@ static void exynos4_mct_tick_clear(struct mct_clock_event_device *mevt) | |||
| 430 | if (!clockevent_state_periodic(&mevt->evt)) | 439 | if (!clockevent_state_periodic(&mevt->evt)) |
| 431 | exynos4_mct_tick_stop(mevt); | 440 | exynos4_mct_tick_stop(mevt); |
| 432 | 441 | ||
| 433 | /* Clear the MCT tick interrupt */ | ||
| 434 | if (readl_relaxed(reg_base + mevt->base + MCT_L_INT_CSTAT_OFFSET) & 1) | ||
| 435 | exynos4_mct_write(0x1, mevt->base + MCT_L_INT_CSTAT_OFFSET); | ||
| 436 | } | ||
| 437 | |||
| 438 | static irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id) | ||
| 439 | { | ||
| 440 | struct mct_clock_event_device *mevt = dev_id; | ||
| 441 | struct clock_event_device *evt = &mevt->evt; | ||
| 442 | |||
| 443 | exynos4_mct_tick_clear(mevt); | 442 | exynos4_mct_tick_clear(mevt); |
| 444 | 443 | ||
| 445 | evt->event_handler(evt); | 444 | evt->event_handler(evt); |
| @@ -507,13 +506,12 @@ static int __init exynos4_timer_resources(struct device_node *np, void __iomem * | |||
| 507 | int err, cpu; | 506 | int err, cpu; |
| 508 | struct clk *mct_clk, *tick_clk; | 507 | struct clk *mct_clk, *tick_clk; |
| 509 | 508 | ||
| 510 | tick_clk = np ? of_clk_get_by_name(np, "fin_pll") : | 509 | tick_clk = of_clk_get_by_name(np, "fin_pll"); |
| 511 | clk_get(NULL, "fin_pll"); | ||
| 512 | if (IS_ERR(tick_clk)) | 510 | if (IS_ERR(tick_clk)) |
| 513 | panic("%s: unable to determine tick clock rate\n", __func__); | 511 | panic("%s: unable to determine tick clock rate\n", __func__); |
| 514 | clk_rate = clk_get_rate(tick_clk); | 512 | clk_rate = clk_get_rate(tick_clk); |
| 515 | 513 | ||
| 516 | mct_clk = np ? of_clk_get_by_name(np, "mct") : clk_get(NULL, "mct"); | 514 | mct_clk = of_clk_get_by_name(np, "mct"); |
| 517 | if (IS_ERR(mct_clk)) | 515 | if (IS_ERR(mct_clk)) |
| 518 | panic("%s: unable to retrieve mct clock instance\n", __func__); | 516 | panic("%s: unable to retrieve mct clock instance\n", __func__); |
| 519 | clk_prepare_enable(mct_clk); | 517 | clk_prepare_enable(mct_clk); |
| @@ -562,7 +560,19 @@ static int __init exynos4_timer_resources(struct device_node *np, void __iomem * | |||
| 562 | return 0; | 560 | return 0; |
| 563 | 561 | ||
| 564 | out_irq: | 562 | out_irq: |
| 565 | free_percpu_irq(mct_irqs[MCT_L0_IRQ], &percpu_mct_tick); | 563 | if (mct_int_type == MCT_INT_PPI) { |
| 564 | free_percpu_irq(mct_irqs[MCT_L0_IRQ], &percpu_mct_tick); | ||
| 565 | } else { | ||
| 566 | for_each_possible_cpu(cpu) { | ||
| 567 | struct mct_clock_event_device *pcpu_mevt = | ||
| 568 | per_cpu_ptr(&percpu_mct_tick, cpu); | ||
| 569 | |||
| 570 | if (pcpu_mevt->evt.irq != -1) { | ||
| 571 | free_irq(pcpu_mevt->evt.irq, pcpu_mevt); | ||
| 572 | pcpu_mevt->evt.irq = -1; | ||
| 573 | } | ||
| 574 | } | ||
| 575 | } | ||
| 566 | return err; | 576 | return err; |
| 567 | } | 577 | } |
| 568 | 578 | ||
| @@ -581,11 +591,7 @@ static int __init mct_init_dt(struct device_node *np, unsigned int int_type) | |||
| 581 | * timer irqs are specified after the four global timer | 591 | * timer irqs are specified after the four global timer |
| 582 | * irqs are specified. | 592 | * irqs are specified. |
| 583 | */ | 593 | */ |
| 584 | #ifdef CONFIG_OF | ||
| 585 | nr_irqs = of_irq_count(np); | 594 | nr_irqs = of_irq_count(np); |
| 586 | #else | ||
| 587 | nr_irqs = 0; | ||
| 588 | #endif | ||
| 589 | for (i = MCT_L0_IRQ; i < nr_irqs; i++) | 595 | for (i = MCT_L0_IRQ; i < nr_irqs; i++) |
| 590 | mct_irqs[i] = irq_of_parse_and_map(np, i); | 596 | mct_irqs[i] = irq_of_parse_and_map(np, i); |
| 591 | 597 | ||
diff --git a/drivers/clocksource/cs5535-clockevt.c b/drivers/clocksource/timer-cs5535.c index 1de8cac99a0e..1de8cac99a0e 100644 --- a/drivers/clocksource/cs5535-clockevt.c +++ b/drivers/clocksource/timer-cs5535.c | |||
diff --git a/drivers/clocksource/pxa_timer.c b/drivers/clocksource/timer-pxa.c index 395837938301..395837938301 100644 --- a/drivers/clocksource/pxa_timer.c +++ b/drivers/clocksource/timer-pxa.c | |||
diff --git a/drivers/clocksource/timer-riscv.c b/drivers/clocksource/timer-riscv.c index 431892200a08..e8163693e936 100644 --- a/drivers/clocksource/timer-riscv.c +++ b/drivers/clocksource/timer-riscv.c | |||
| @@ -95,13 +95,30 @@ static int __init riscv_timer_init_dt(struct device_node *n) | |||
| 95 | struct clocksource *cs; | 95 | struct clocksource *cs; |
| 96 | 96 | ||
| 97 | hartid = riscv_of_processor_hartid(n); | 97 | hartid = riscv_of_processor_hartid(n); |
| 98 | if (hartid < 0) { | ||
| 99 | pr_warn("Not valid hartid for node [%pOF] error = [%d]\n", | ||
| 100 | n, hartid); | ||
| 101 | return hartid; | ||
| 102 | } | ||
| 103 | |||
| 98 | cpuid = riscv_hartid_to_cpuid(hartid); | 104 | cpuid = riscv_hartid_to_cpuid(hartid); |
| 105 | if (cpuid < 0) { | ||
| 106 | pr_warn("Invalid cpuid for hartid [%d]\n", hartid); | ||
| 107 | return cpuid; | ||
| 108 | } | ||
| 99 | 109 | ||
| 100 | if (cpuid != smp_processor_id()) | 110 | if (cpuid != smp_processor_id()) |
| 101 | return 0; | 111 | return 0; |
| 102 | 112 | ||
| 113 | pr_info("%s: Registering clocksource cpuid [%d] hartid [%d]\n", | ||
| 114 | __func__, cpuid, hartid); | ||
| 103 | cs = per_cpu_ptr(&riscv_clocksource, cpuid); | 115 | cs = per_cpu_ptr(&riscv_clocksource, cpuid); |
| 104 | clocksource_register_hz(cs, riscv_timebase); | 116 | error = clocksource_register_hz(cs, riscv_timebase); |
| 117 | if (error) { | ||
| 118 | pr_err("RISCV timer register failed [%d] for cpu = [%d]\n", | ||
| 119 | error, cpuid); | ||
| 120 | return error; | ||
| 121 | } | ||
| 105 | 122 | ||
| 106 | sched_clock_register(riscv_sched_clock, | 123 | sched_clock_register(riscv_sched_clock, |
| 107 | BITS_PER_LONG, riscv_timebase); | 124 | BITS_PER_LONG, riscv_timebase); |
| @@ -110,8 +127,8 @@ static int __init riscv_timer_init_dt(struct device_node *n) | |||
| 110 | "clockevents/riscv/timer:starting", | 127 | "clockevents/riscv/timer:starting", |
| 111 | riscv_timer_starting_cpu, riscv_timer_dying_cpu); | 128 | riscv_timer_starting_cpu, riscv_timer_dying_cpu); |
| 112 | if (error) | 129 | if (error) |
| 113 | pr_err("RISCV timer register failed [%d] for cpu = [%d]\n", | 130 | pr_err("cpu hp setup state failed for RISCV timer [%d]\n", |
| 114 | error, cpuid); | 131 | error); |
| 115 | return error; | 132 | return error; |
| 116 | } | 133 | } |
| 117 | 134 | ||
diff --git a/drivers/clocksource/timer-sun5i.c b/drivers/clocksource/timer-sun5i.c index 3b56ea3f52af..552c5254390c 100644 --- a/drivers/clocksource/timer-sun5i.c +++ b/drivers/clocksource/timer-sun5i.c | |||
| @@ -202,6 +202,11 @@ static int __init sun5i_setup_clocksource(struct device_node *node, | |||
| 202 | } | 202 | } |
| 203 | 203 | ||
| 204 | rate = clk_get_rate(clk); | 204 | rate = clk_get_rate(clk); |
| 205 | if (!rate) { | ||
| 206 | pr_err("Couldn't get parent clock rate\n"); | ||
| 207 | ret = -EINVAL; | ||
| 208 | goto err_disable_clk; | ||
| 209 | } | ||
| 205 | 210 | ||
| 206 | cs->timer.base = base; | 211 | cs->timer.base = base; |
| 207 | cs->timer.clk = clk; | 212 | cs->timer.clk = clk; |
| @@ -275,6 +280,11 @@ static int __init sun5i_setup_clockevent(struct device_node *node, void __iomem | |||
| 275 | } | 280 | } |
| 276 | 281 | ||
| 277 | rate = clk_get_rate(clk); | 282 | rate = clk_get_rate(clk); |
| 283 | if (!rate) { | ||
| 284 | pr_err("Couldn't get parent clock rate\n"); | ||
| 285 | ret = -EINVAL; | ||
| 286 | goto err_disable_clk; | ||
| 287 | } | ||
| 278 | 288 | ||
| 279 | ce->timer.base = base; | 289 | ce->timer.base = base; |
| 280 | ce->timer.ticks_per_jiffy = DIV_ROUND_UP(rate, HZ); | 290 | ce->timer.ticks_per_jiffy = DIV_ROUND_UP(rate, HZ); |
diff --git a/drivers/clocksource/tango_xtal.c b/drivers/clocksource/timer-tango-xtal.c index 3f94e454ef99..3f94e454ef99 100644 --- a/drivers/clocksource/tango_xtal.c +++ b/drivers/clocksource/timer-tango-xtal.c | |||
diff --git a/drivers/clocksource/timer-tegra20.c b/drivers/clocksource/timer-tegra20.c index 4293943f4e2b..fdb3d795a409 100644 --- a/drivers/clocksource/timer-tegra20.c +++ b/drivers/clocksource/timer-tegra20.c | |||
| @@ -15,21 +15,24 @@ | |||
| 15 | * | 15 | * |
| 16 | */ | 16 | */ |
| 17 | 17 | ||
| 18 | #include <linux/init.h> | 18 | #include <linux/clk.h> |
| 19 | #include <linux/clockchips.h> | ||
| 20 | #include <linux/cpu.h> | ||
| 21 | #include <linux/cpumask.h> | ||
| 22 | #include <linux/delay.h> | ||
| 19 | #include <linux/err.h> | 23 | #include <linux/err.h> |
| 20 | #include <linux/time.h> | ||
| 21 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
| 22 | #include <linux/irq.h> | ||
| 23 | #include <linux/clockchips.h> | ||
| 24 | #include <linux/clocksource.h> | ||
| 25 | #include <linux/clk.h> | ||
| 26 | #include <linux/io.h> | ||
| 27 | #include <linux/of_address.h> | 25 | #include <linux/of_address.h> |
| 28 | #include <linux/of_irq.h> | 26 | #include <linux/of_irq.h> |
| 27 | #include <linux/percpu.h> | ||
| 29 | #include <linux/sched_clock.h> | 28 | #include <linux/sched_clock.h> |
| 30 | #include <linux/delay.h> | 29 | #include <linux/time.h> |
| 30 | |||
| 31 | #include "timer-of.h" | ||
| 31 | 32 | ||
| 33 | #ifdef CONFIG_ARM | ||
| 32 | #include <asm/mach/time.h> | 34 | #include <asm/mach/time.h> |
| 35 | #endif | ||
| 33 | 36 | ||
| 34 | #define RTC_SECONDS 0x08 | 37 | #define RTC_SECONDS 0x08 |
| 35 | #define RTC_SHADOW_SECONDS 0x0c | 38 | #define RTC_SHADOW_SECONDS 0x0c |
| @@ -39,74 +42,161 @@ | |||
| 39 | #define TIMERUS_USEC_CFG 0x14 | 42 | #define TIMERUS_USEC_CFG 0x14 |
| 40 | #define TIMERUS_CNTR_FREEZE 0x4c | 43 | #define TIMERUS_CNTR_FREEZE 0x4c |
| 41 | 44 | ||
| 42 | #define TIMER1_BASE 0x0 | 45 | #define TIMER_PTV 0x0 |
| 43 | #define TIMER2_BASE 0x8 | 46 | #define TIMER_PTV_EN BIT(31) |
| 44 | #define TIMER3_BASE 0x50 | 47 | #define TIMER_PTV_PER BIT(30) |
| 45 | #define TIMER4_BASE 0x58 | 48 | #define TIMER_PCR 0x4 |
| 46 | 49 | #define TIMER_PCR_INTR_CLR BIT(30) | |
| 47 | #define TIMER_PTV 0x0 | 50 | |
| 48 | #define TIMER_PCR 0x4 | 51 | #ifdef CONFIG_ARM |
| 49 | 52 | #define TIMER_CPU0 0x50 /* TIMER3 */ | |
| 53 | #else | ||
| 54 | #define TIMER_CPU0 0x90 /* TIMER10 */ | ||
| 55 | #define TIMER10_IRQ_IDX 10 | ||
| 56 | #define IRQ_IDX_FOR_CPU(cpu) (TIMER10_IRQ_IDX + cpu) | ||
| 57 | #endif | ||
| 58 | #define TIMER_BASE_FOR_CPU(cpu) (TIMER_CPU0 + (cpu) * 8) | ||
| 59 | |||
| 60 | static u32 usec_config; | ||
| 50 | static void __iomem *timer_reg_base; | 61 | static void __iomem *timer_reg_base; |
| 62 | #ifdef CONFIG_ARM | ||
| 51 | static void __iomem *rtc_base; | 63 | static void __iomem *rtc_base; |
| 52 | |||
| 53 | static struct timespec64 persistent_ts; | 64 | static struct timespec64 persistent_ts; |
| 54 | static u64 persistent_ms, last_persistent_ms; | 65 | static u64 persistent_ms, last_persistent_ms; |
| 55 | |||
| 56 | static struct delay_timer tegra_delay_timer; | 66 | static struct delay_timer tegra_delay_timer; |
| 57 | 67 | #endif | |
| 58 | #define timer_writel(value, reg) \ | ||
| 59 | writel_relaxed(value, timer_reg_base + (reg)) | ||
| 60 | #define timer_readl(reg) \ | ||
| 61 | readl_relaxed(timer_reg_base + (reg)) | ||
| 62 | 68 | ||
| 63 | static int tegra_timer_set_next_event(unsigned long cycles, | 69 | static int tegra_timer_set_next_event(unsigned long cycles, |
| 64 | struct clock_event_device *evt) | 70 | struct clock_event_device *evt) |
| 65 | { | 71 | { |
| 66 | u32 reg; | 72 | void __iomem *reg_base = timer_of_base(to_timer_of(evt)); |
| 67 | 73 | ||
| 68 | reg = 0x80000000 | ((cycles > 1) ? (cycles-1) : 0); | 74 | writel(TIMER_PTV_EN | |
| 69 | timer_writel(reg, TIMER3_BASE + TIMER_PTV); | 75 | ((cycles > 1) ? (cycles - 1) : 0), /* n+1 scheme */ |
| 76 | reg_base + TIMER_PTV); | ||
| 70 | 77 | ||
| 71 | return 0; | 78 | return 0; |
| 72 | } | 79 | } |
| 73 | 80 | ||
| 74 | static inline void timer_shutdown(struct clock_event_device *evt) | 81 | static int tegra_timer_shutdown(struct clock_event_device *evt) |
| 75 | { | 82 | { |
| 76 | timer_writel(0, TIMER3_BASE + TIMER_PTV); | 83 | void __iomem *reg_base = timer_of_base(to_timer_of(evt)); |
| 84 | |||
| 85 | writel(0, reg_base + TIMER_PTV); | ||
| 86 | |||
| 87 | return 0; | ||
| 77 | } | 88 | } |
| 78 | 89 | ||
| 79 | static int tegra_timer_shutdown(struct clock_event_device *evt) | 90 | static int tegra_timer_set_periodic(struct clock_event_device *evt) |
| 80 | { | 91 | { |
| 81 | timer_shutdown(evt); | 92 | void __iomem *reg_base = timer_of_base(to_timer_of(evt)); |
| 93 | |||
| 94 | writel(TIMER_PTV_EN | TIMER_PTV_PER | | ||
| 95 | ((timer_of_rate(to_timer_of(evt)) / HZ) - 1), | ||
| 96 | reg_base + TIMER_PTV); | ||
| 97 | |||
| 82 | return 0; | 98 | return 0; |
| 83 | } | 99 | } |
| 84 | 100 | ||
| 85 | static int tegra_timer_set_periodic(struct clock_event_device *evt) | 101 | static irqreturn_t tegra_timer_isr(int irq, void *dev_id) |
| 102 | { | ||
| 103 | struct clock_event_device *evt = (struct clock_event_device *)dev_id; | ||
| 104 | void __iomem *reg_base = timer_of_base(to_timer_of(evt)); | ||
| 105 | |||
| 106 | writel(TIMER_PCR_INTR_CLR, reg_base + TIMER_PCR); | ||
| 107 | evt->event_handler(evt); | ||
| 108 | |||
| 109 | return IRQ_HANDLED; | ||
| 110 | } | ||
| 111 | |||
| 112 | static void tegra_timer_suspend(struct clock_event_device *evt) | ||
| 113 | { | ||
| 114 | void __iomem *reg_base = timer_of_base(to_timer_of(evt)); | ||
| 115 | |||
| 116 | writel(TIMER_PCR_INTR_CLR, reg_base + TIMER_PCR); | ||
| 117 | } | ||
| 118 | |||
| 119 | static void tegra_timer_resume(struct clock_event_device *evt) | ||
| 120 | { | ||
| 121 | writel(usec_config, timer_reg_base + TIMERUS_USEC_CFG); | ||
| 122 | } | ||
| 123 | |||
| 124 | #ifdef CONFIG_ARM64 | ||
| 125 | static DEFINE_PER_CPU(struct timer_of, tegra_to) = { | ||
| 126 | .flags = TIMER_OF_CLOCK | TIMER_OF_BASE, | ||
| 127 | |||
| 128 | .clkevt = { | ||
| 129 | .name = "tegra_timer", | ||
| 130 | .rating = 460, | ||
| 131 | .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, | ||
| 132 | .set_next_event = tegra_timer_set_next_event, | ||
| 133 | .set_state_shutdown = tegra_timer_shutdown, | ||
| 134 | .set_state_periodic = tegra_timer_set_periodic, | ||
| 135 | .set_state_oneshot = tegra_timer_shutdown, | ||
| 136 | .tick_resume = tegra_timer_shutdown, | ||
| 137 | .suspend = tegra_timer_suspend, | ||
| 138 | .resume = tegra_timer_resume, | ||
| 139 | }, | ||
| 140 | }; | ||
| 141 | |||
| 142 | static int tegra_timer_setup(unsigned int cpu) | ||
| 86 | { | 143 | { |
| 87 | u32 reg = 0xC0000000 | ((1000000 / HZ) - 1); | 144 | struct timer_of *to = per_cpu_ptr(&tegra_to, cpu); |
| 145 | |||
| 146 | irq_force_affinity(to->clkevt.irq, cpumask_of(cpu)); | ||
| 147 | enable_irq(to->clkevt.irq); | ||
| 148 | |||
| 149 | clockevents_config_and_register(&to->clkevt, timer_of_rate(to), | ||
| 150 | 1, /* min */ | ||
| 151 | 0x1fffffff); /* 29 bits */ | ||
| 88 | 152 | ||
| 89 | timer_shutdown(evt); | ||
| 90 | timer_writel(reg, TIMER3_BASE + TIMER_PTV); | ||
| 91 | return 0; | 153 | return 0; |
| 92 | } | 154 | } |
| 93 | 155 | ||
| 94 | static struct clock_event_device tegra_clockevent = { | 156 | static int tegra_timer_stop(unsigned int cpu) |
| 95 | .name = "timer0", | 157 | { |
| 96 | .rating = 300, | 158 | struct timer_of *to = per_cpu_ptr(&tegra_to, cpu); |
| 97 | .features = CLOCK_EVT_FEAT_ONESHOT | | 159 | |
| 98 | CLOCK_EVT_FEAT_PERIODIC | | 160 | to->clkevt.set_state_shutdown(&to->clkevt); |
| 99 | CLOCK_EVT_FEAT_DYNIRQ, | 161 | disable_irq_nosync(to->clkevt.irq); |
| 100 | .set_next_event = tegra_timer_set_next_event, | 162 | |
| 101 | .set_state_shutdown = tegra_timer_shutdown, | 163 | return 0; |
| 102 | .set_state_periodic = tegra_timer_set_periodic, | 164 | } |
| 103 | .set_state_oneshot = tegra_timer_shutdown, | 165 | #else /* CONFIG_ARM */ |
| 104 | .tick_resume = tegra_timer_shutdown, | 166 | static struct timer_of tegra_to = { |
| 167 | .flags = TIMER_OF_CLOCK | TIMER_OF_BASE | TIMER_OF_IRQ, | ||
| 168 | |||
| 169 | .clkevt = { | ||
| 170 | .name = "tegra_timer", | ||
| 171 | .rating = 300, | ||
| 172 | .features = CLOCK_EVT_FEAT_ONESHOT | | ||
| 173 | CLOCK_EVT_FEAT_PERIODIC | | ||
| 174 | CLOCK_EVT_FEAT_DYNIRQ, | ||
| 175 | .set_next_event = tegra_timer_set_next_event, | ||
| 176 | .set_state_shutdown = tegra_timer_shutdown, | ||
| 177 | .set_state_periodic = tegra_timer_set_periodic, | ||
| 178 | .set_state_oneshot = tegra_timer_shutdown, | ||
| 179 | .tick_resume = tegra_timer_shutdown, | ||
| 180 | .suspend = tegra_timer_suspend, | ||
| 181 | .resume = tegra_timer_resume, | ||
| 182 | .cpumask = cpu_possible_mask, | ||
| 183 | }, | ||
| 184 | |||
| 185 | .of_irq = { | ||
| 186 | .index = 2, | ||
| 187 | .flags = IRQF_TIMER | IRQF_TRIGGER_HIGH, | ||
| 188 | .handler = tegra_timer_isr, | ||
| 189 | }, | ||
| 105 | }; | 190 | }; |
| 106 | 191 | ||
| 107 | static u64 notrace tegra_read_sched_clock(void) | 192 | static u64 notrace tegra_read_sched_clock(void) |
| 108 | { | 193 | { |
| 109 | return timer_readl(TIMERUS_CNTR_1US); | 194 | return readl(timer_reg_base + TIMERUS_CNTR_1US); |
| 195 | } | ||
| 196 | |||
| 197 | static unsigned long tegra_delay_timer_read_counter_long(void) | ||
| 198 | { | ||
| 199 | return readl(timer_reg_base + TIMERUS_CNTR_1US); | ||
| 110 | } | 200 | } |
| 111 | 201 | ||
| 112 | /* | 202 | /* |
| @@ -143,100 +233,155 @@ static void tegra_read_persistent_clock64(struct timespec64 *ts) | |||
| 143 | timespec64_add_ns(&persistent_ts, delta * NSEC_PER_MSEC); | 233 | timespec64_add_ns(&persistent_ts, delta * NSEC_PER_MSEC); |
| 144 | *ts = persistent_ts; | 234 | *ts = persistent_ts; |
| 145 | } | 235 | } |
| 236 | #endif | ||
| 146 | 237 | ||
| 147 | static unsigned long tegra_delay_timer_read_counter_long(void) | 238 | static int tegra_timer_common_init(struct device_node *np, struct timer_of *to) |
| 148 | { | ||
| 149 | return readl(timer_reg_base + TIMERUS_CNTR_1US); | ||
| 150 | } | ||
| 151 | |||
| 152 | static irqreturn_t tegra_timer_interrupt(int irq, void *dev_id) | ||
| 153 | { | ||
| 154 | struct clock_event_device *evt = (struct clock_event_device *)dev_id; | ||
| 155 | timer_writel(1<<30, TIMER3_BASE + TIMER_PCR); | ||
| 156 | evt->event_handler(evt); | ||
| 157 | return IRQ_HANDLED; | ||
| 158 | } | ||
| 159 | |||
| 160 | static struct irqaction tegra_timer_irq = { | ||
| 161 | .name = "timer0", | ||
| 162 | .flags = IRQF_TIMER | IRQF_TRIGGER_HIGH, | ||
| 163 | .handler = tegra_timer_interrupt, | ||
| 164 | .dev_id = &tegra_clockevent, | ||
| 165 | }; | ||
| 166 | |||
| 167 | static int __init tegra20_init_timer(struct device_node *np) | ||
| 168 | { | 239 | { |
| 169 | struct clk *clk; | 240 | int ret = 0; |
| 170 | unsigned long rate; | ||
| 171 | int ret; | ||
| 172 | |||
| 173 | timer_reg_base = of_iomap(np, 0); | ||
| 174 | if (!timer_reg_base) { | ||
| 175 | pr_err("Can't map timer registers\n"); | ||
| 176 | return -ENXIO; | ||
| 177 | } | ||
| 178 | 241 | ||
| 179 | tegra_timer_irq.irq = irq_of_parse_and_map(np, 2); | 242 | ret = timer_of_init(np, to); |
| 180 | if (tegra_timer_irq.irq <= 0) { | 243 | if (ret < 0) |
| 181 | pr_err("Failed to map timer IRQ\n"); | 244 | goto out; |
| 182 | return -EINVAL; | ||
| 183 | } | ||
| 184 | 245 | ||
| 185 | clk = of_clk_get(np, 0); | 246 | timer_reg_base = timer_of_base(to); |
| 186 | if (IS_ERR(clk)) { | ||
| 187 | pr_warn("Unable to get timer clock. Assuming 12Mhz input clock.\n"); | ||
| 188 | rate = 12000000; | ||
| 189 | } else { | ||
| 190 | clk_prepare_enable(clk); | ||
| 191 | rate = clk_get_rate(clk); | ||
| 192 | } | ||
| 193 | 247 | ||
| 194 | switch (rate) { | 248 | /* |
| 249 | * Configure microsecond timers to have 1MHz clock | ||
| 250 | * Config register is 0xqqww, where qq is "dividend", ww is "divisor" | ||
| 251 | * Uses n+1 scheme | ||
| 252 | */ | ||
| 253 | switch (timer_of_rate(to)) { | ||
| 195 | case 12000000: | 254 | case 12000000: |
| 196 | timer_writel(0x000b, TIMERUS_USEC_CFG); | 255 | usec_config = 0x000b; /* (11+1)/(0+1) */ |
| 256 | break; | ||
| 257 | case 12800000: | ||
| 258 | usec_config = 0x043f; /* (63+1)/(4+1) */ | ||
| 197 | break; | 259 | break; |
| 198 | case 13000000: | 260 | case 13000000: |
| 199 | timer_writel(0x000c, TIMERUS_USEC_CFG); | 261 | usec_config = 0x000c; /* (12+1)/(0+1) */ |
| 262 | break; | ||
| 263 | case 16800000: | ||
| 264 | usec_config = 0x0453; /* (83+1)/(4+1) */ | ||
| 200 | break; | 265 | break; |
| 201 | case 19200000: | 266 | case 19200000: |
| 202 | timer_writel(0x045f, TIMERUS_USEC_CFG); | 267 | usec_config = 0x045f; /* (95+1)/(4+1) */ |
| 203 | break; | 268 | break; |
| 204 | case 26000000: | 269 | case 26000000: |
| 205 | timer_writel(0x0019, TIMERUS_USEC_CFG); | 270 | usec_config = 0x0019; /* (25+1)/(0+1) */ |
| 271 | break; | ||
| 272 | case 38400000: | ||
| 273 | usec_config = 0x04bf; /* (191+1)/(4+1) */ | ||
| 274 | break; | ||
| 275 | case 48000000: | ||
| 276 | usec_config = 0x002f; /* (47+1)/(0+1) */ | ||
| 206 | break; | 277 | break; |
| 207 | default: | 278 | default: |
| 208 | WARN(1, "Unknown clock rate"); | 279 | ret = -EINVAL; |
| 280 | goto out; | ||
| 281 | } | ||
| 282 | |||
| 283 | writel(usec_config, timer_of_base(to) + TIMERUS_USEC_CFG); | ||
| 284 | |||
| 285 | out: | ||
| 286 | return ret; | ||
| 287 | } | ||
| 288 | |||
| 289 | #ifdef CONFIG_ARM64 | ||
| 290 | static int __init tegra_init_timer(struct device_node *np) | ||
| 291 | { | ||
| 292 | int cpu, ret = 0; | ||
| 293 | struct timer_of *to; | ||
| 294 | |||
| 295 | to = this_cpu_ptr(&tegra_to); | ||
| 296 | ret = tegra_timer_common_init(np, to); | ||
| 297 | if (ret < 0) | ||
| 298 | goto out; | ||
| 299 | |||
| 300 | for_each_possible_cpu(cpu) { | ||
| 301 | struct timer_of *cpu_to; | ||
| 302 | |||
| 303 | cpu_to = per_cpu_ptr(&tegra_to, cpu); | ||
| 304 | cpu_to->of_base.base = timer_reg_base + TIMER_BASE_FOR_CPU(cpu); | ||
| 305 | cpu_to->of_clk.rate = timer_of_rate(to); | ||
| 306 | cpu_to->clkevt.cpumask = cpumask_of(cpu); | ||
| 307 | cpu_to->clkevt.irq = | ||
| 308 | irq_of_parse_and_map(np, IRQ_IDX_FOR_CPU(cpu)); | ||
| 309 | if (!cpu_to->clkevt.irq) { | ||
| 310 | pr_err("%s: can't map IRQ for CPU%d\n", | ||
| 311 | __func__, cpu); | ||
| 312 | ret = -EINVAL; | ||
| 313 | goto out; | ||
| 314 | } | ||
| 315 | |||
| 316 | irq_set_status_flags(cpu_to->clkevt.irq, IRQ_NOAUTOEN); | ||
| 317 | ret = request_irq(cpu_to->clkevt.irq, tegra_timer_isr, | ||
| 318 | IRQF_TIMER | IRQF_NOBALANCING, | ||
| 319 | cpu_to->clkevt.name, &cpu_to->clkevt); | ||
| 320 | if (ret) { | ||
| 321 | pr_err("%s: cannot setup irq %d for CPU%d\n", | ||
| 322 | __func__, cpu_to->clkevt.irq, cpu); | ||
| 323 | ret = -EINVAL; | ||
| 324 | goto out_irq; | ||
| 325 | } | ||
| 326 | } | ||
| 327 | |||
| 328 | cpuhp_setup_state(CPUHP_AP_TEGRA_TIMER_STARTING, | ||
| 329 | "AP_TEGRA_TIMER_STARTING", tegra_timer_setup, | ||
| 330 | tegra_timer_stop); | ||
| 331 | |||
| 332 | return ret; | ||
| 333 | out_irq: | ||
| 334 | for_each_possible_cpu(cpu) { | ||
| 335 | struct timer_of *cpu_to; | ||
| 336 | |||
| 337 | cpu_to = per_cpu_ptr(&tegra_to, cpu); | ||
| 338 | if (cpu_to->clkevt.irq) { | ||
| 339 | free_irq(cpu_to->clkevt.irq, &cpu_to->clkevt); | ||
| 340 | irq_dispose_mapping(cpu_to->clkevt.irq); | ||
| 341 | } | ||
| 209 | } | 342 | } |
| 343 | out: | ||
| 344 | timer_of_cleanup(to); | ||
| 345 | return ret; | ||
| 346 | } | ||
| 347 | #else /* CONFIG_ARM */ | ||
| 348 | static int __init tegra_init_timer(struct device_node *np) | ||
| 349 | { | ||
| 350 | int ret = 0; | ||
| 351 | |||
| 352 | ret = tegra_timer_common_init(np, &tegra_to); | ||
| 353 | if (ret < 0) | ||
| 354 | goto out; | ||
| 210 | 355 | ||
| 211 | sched_clock_register(tegra_read_sched_clock, 32, 1000000); | 356 | tegra_to.of_base.base = timer_reg_base + TIMER_BASE_FOR_CPU(0); |
| 357 | tegra_to.of_clk.rate = 1000000; /* microsecond timer */ | ||
| 212 | 358 | ||
| 359 | sched_clock_register(tegra_read_sched_clock, 32, | ||
| 360 | timer_of_rate(&tegra_to)); | ||
| 213 | ret = clocksource_mmio_init(timer_reg_base + TIMERUS_CNTR_1US, | 361 | ret = clocksource_mmio_init(timer_reg_base + TIMERUS_CNTR_1US, |
| 214 | "timer_us", 1000000, 300, 32, | 362 | "timer_us", timer_of_rate(&tegra_to), |
| 215 | clocksource_mmio_readl_up); | 363 | 300, 32, clocksource_mmio_readl_up); |
| 216 | if (ret) { | 364 | if (ret) { |
| 217 | pr_err("Failed to register clocksource\n"); | 365 | pr_err("Failed to register clocksource\n"); |
| 218 | return ret; | 366 | goto out; |
| 219 | } | 367 | } |
| 220 | 368 | ||
| 221 | tegra_delay_timer.read_current_timer = | 369 | tegra_delay_timer.read_current_timer = |
| 222 | tegra_delay_timer_read_counter_long; | 370 | tegra_delay_timer_read_counter_long; |
| 223 | tegra_delay_timer.freq = 1000000; | 371 | tegra_delay_timer.freq = timer_of_rate(&tegra_to); |
| 224 | register_current_timer_delay(&tegra_delay_timer); | 372 | register_current_timer_delay(&tegra_delay_timer); |
| 225 | 373 | ||
| 226 | ret = setup_irq(tegra_timer_irq.irq, &tegra_timer_irq); | 374 | clockevents_config_and_register(&tegra_to.clkevt, |
| 227 | if (ret) { | 375 | timer_of_rate(&tegra_to), |
| 228 | pr_err("Failed to register timer IRQ: %d\n", ret); | 376 | 0x1, |
| 229 | return ret; | 377 | 0x1fffffff); |
| 230 | } | ||
| 231 | 378 | ||
| 232 | tegra_clockevent.cpumask = cpu_possible_mask; | 379 | return ret; |
| 233 | tegra_clockevent.irq = tegra_timer_irq.irq; | 380 | out: |
| 234 | clockevents_config_and_register(&tegra_clockevent, 1000000, | 381 | timer_of_cleanup(&tegra_to); |
| 235 | 0x1, 0x1fffffff); | ||
| 236 | 382 | ||
| 237 | return 0; | 383 | return ret; |
| 238 | } | 384 | } |
| 239 | TIMER_OF_DECLARE(tegra20_timer, "nvidia,tegra20-timer", tegra20_init_timer); | ||
| 240 | 385 | ||
| 241 | static int __init tegra20_init_rtc(struct device_node *np) | 386 | static int __init tegra20_init_rtc(struct device_node *np) |
| 242 | { | 387 | { |
| @@ -261,3 +406,6 @@ static int __init tegra20_init_rtc(struct device_node *np) | |||
| 261 | return register_persistent_clock(tegra_read_persistent_clock64); | 406 | return register_persistent_clock(tegra_read_persistent_clock64); |
| 262 | } | 407 | } |
| 263 | TIMER_OF_DECLARE(tegra20_rtc, "nvidia,tegra20-rtc", tegra20_init_rtc); | 408 | TIMER_OF_DECLARE(tegra20_rtc, "nvidia,tegra20-rtc", tegra20_init_rtc); |
| 409 | #endif | ||
| 410 | TIMER_OF_DECLARE(tegra210_timer, "nvidia,tegra210-timer", tegra_init_timer); | ||
| 411 | TIMER_OF_DECLARE(tegra20_timer, "nvidia,tegra20-timer", tegra_init_timer); | ||
diff --git a/drivers/soc/tegra/Kconfig b/drivers/soc/tegra/Kconfig index fe4481676da6..a0b03443d8c1 100644 --- a/drivers/soc/tegra/Kconfig +++ b/drivers/soc/tegra/Kconfig | |||
| @@ -76,6 +76,7 @@ config ARCH_TEGRA_210_SOC | |||
| 76 | select PINCTRL_TEGRA210 | 76 | select PINCTRL_TEGRA210 |
| 77 | select SOC_TEGRA_FLOWCTRL | 77 | select SOC_TEGRA_FLOWCTRL |
| 78 | select SOC_TEGRA_PMC | 78 | select SOC_TEGRA_PMC |
| 79 | select TEGRA_TIMER | ||
| 79 | help | 80 | help |
| 80 | Enable support for the NVIDIA Tegra210 SoC. Also known as Tegra X1, | 81 | Enable support for the NVIDIA Tegra210 SoC. Also known as Tegra X1, |
| 81 | the Tegra210 has four Cortex-A57 cores paired with four Cortex-A53 | 82 | the Tegra210 has four Cortex-A57 cores paired with four Cortex-A53 |
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h index fd586d0301e7..e78281d07b70 100644 --- a/include/linux/cpuhotplug.h +++ b/include/linux/cpuhotplug.h | |||
| @@ -121,6 +121,7 @@ enum cpuhp_state { | |||
| 121 | CPUHP_AP_EXYNOS4_MCT_TIMER_STARTING, | 121 | CPUHP_AP_EXYNOS4_MCT_TIMER_STARTING, |
| 122 | CPUHP_AP_ARM_TWD_STARTING, | 122 | CPUHP_AP_ARM_TWD_STARTING, |
| 123 | CPUHP_AP_QCOM_TIMER_STARTING, | 123 | CPUHP_AP_QCOM_TIMER_STARTING, |
| 124 | CPUHP_AP_TEGRA_TIMER_STARTING, | ||
| 124 | CPUHP_AP_ARMADA_TIMER_STARTING, | 125 | CPUHP_AP_ARMADA_TIMER_STARTING, |
| 125 | CPUHP_AP_MARCO_TIMER_STARTING, | 126 | CPUHP_AP_MARCO_TIMER_STARTING, |
| 126 | CPUHP_AP_MIPS_GIC_TIMER_STARTING, | 127 | CPUHP_AP_MIPS_GIC_TIMER_STARTING, |
