- Add suspend/resume for Hyper-V clocksource (Dexuan Cui)
- Fix Kconfig indentation (Krzysztof Kozlowski) - Add SoC specific bindings for RZ/G2N (r8a774b1) (Biju Das) - Add Microchip PIT64B support (Claudiu Beznea) - Convert the cadence ttc driver to a platform driver to initialize later (Rajan Vaja) - Fix a memory leak when the initialization fails on bcm2835 (Colin Ian King) - Use the combo devm_platform_ioremap_resource() function for em-sti, ti-dm and switch to platform_get_irq (Yangtao Li) - Fix Exynos naming in the driver (Krzysztof Kozlowski) - Fix an uninitialized pointer access in ti-dm timer (Tony Lindgren) - Fix a sparse warning in microchip-pit64b (Claudiu Beznea) - Code reorg without functional changes for Hyper-V clocksource (Andrea Parri) - Decrease the Hyper-V clocksource rating in order to let the stable TSC to be selected instead (Andrea Parri) -----BEGIN PGP SIGNATURE----- iHUEABYIAB0WIQRuKdf4M92Gi9vqihve5qtOL396pgUCXiCm6wAKCRDe5qtOL396 pma2AP9SPecUoUxv7Wf0LtnauNPNbDZlUur/F7syq1CELcmBTAD/cl12kl36SMRh 6hRPgzE/7p6H1Aahk/KK3ycVmbuI+gQ= =DO9a -----END PGP SIGNATURE----- Merge tag 'timers-v5.5-rc6' of https://git.linaro.org/people/daniel.lezcano/linux into timers/core Pull clocksource/events driver updates from Daniel Lezcano - Add suspend/resume for Hyper-V clocksource (Dexuan Cui) - Fix Kconfig indentation (Krzysztof Kozlowski) - Add SoC specific bindings for RZ/G2N (r8a774b1) (Biju Das) - Add Microchip PIT64B support (Claudiu Beznea) - Convert the cadence ttc driver to a platform driver to initialize later (Rajan Vaja) - Fix a memory leak when the initialization fails on bcm2835 (Colin Ian King) - Use the combo devm_platform_ioremap_resource() function for em-sti, ti-dm and switch to platform_get_irq (Yangtao Li) - Fix Exynos naming in the driver (Krzysztof Kozlowski) - Fix an uninitialized pointer access in ti-dm timer (Tony Lindgren) - Fix a sparse warning in microchip-pit64b (Claudiu Beznea) - Code reorg without functional changes for Hyper-V clocksource (Andrea Parri) - Decrease the Hyper-V clocksource rating in order to let the stable TSC to be selected instead (Andrea Parri)
This commit is contained in:
commit
a67ca893ae
|
@ -10,6 +10,12 @@ PIT Timer required properties:
|
||||||
- interrupts: Should contain interrupt for the PIT which is the IRQ line
|
- interrupts: Should contain interrupt for the PIT which is the IRQ line
|
||||||
shared across all System Controller members.
|
shared across all System Controller members.
|
||||||
|
|
||||||
|
PIT64B Timer required properties:
|
||||||
|
- compatible: Should be "microchip,sam9x60-pit64b"
|
||||||
|
- reg: Should contain registers location and length
|
||||||
|
- interrupts: Should contain interrupt for PIT64B timer
|
||||||
|
- clocks: Should contain the available clock sources for PIT64B timer.
|
||||||
|
|
||||||
System Timer (ST) required properties:
|
System Timer (ST) required properties:
|
||||||
- compatible: Should be "atmel,at91rm9200-st", "syscon", "simple-mfd"
|
- compatible: Should be "atmel,at91rm9200-st", "syscon", "simple-mfd"
|
||||||
- reg: Should contain registers location and length
|
- reg: Should contain registers location and length
|
||||||
|
|
|
@ -29,6 +29,8 @@ Required Properties:
|
||||||
- "renesas,r8a77470-cmt1" for the 48-bit CMT1 device included in r8a77470.
|
- "renesas,r8a77470-cmt1" for the 48-bit CMT1 device included in r8a77470.
|
||||||
- "renesas,r8a774a1-cmt0" for the 32-bit CMT0 device included in r8a774a1.
|
- "renesas,r8a774a1-cmt0" for the 32-bit CMT0 device included in r8a774a1.
|
||||||
- "renesas,r8a774a1-cmt1" for the 48-bit CMT devices included in r8a774a1.
|
- "renesas,r8a774a1-cmt1" for the 48-bit CMT devices included in r8a774a1.
|
||||||
|
- "renesas,r8a774b1-cmt0" for the 32-bit CMT0 device included in r8a774b1.
|
||||||
|
- "renesas,r8a774b1-cmt1" for the 48-bit CMT devices included in r8a774b1.
|
||||||
- "renesas,r8a774c0-cmt0" for the 32-bit CMT0 device included in r8a774c0.
|
- "renesas,r8a774c0-cmt0" for the 32-bit CMT0 device included in r8a774c0.
|
||||||
- "renesas,r8a774c0-cmt1" for the 48-bit CMT devices included in r8a774c0.
|
- "renesas,r8a774c0-cmt1" for the 48-bit CMT devices included in r8a774c0.
|
||||||
- "renesas,r8a7790-cmt0" for the 32-bit CMT0 device included in r8a7790.
|
- "renesas,r8a7790-cmt0" for the 32-bit CMT0 device included in r8a7790.
|
||||||
|
|
|
@ -88,7 +88,7 @@ config ROCKCHIP_TIMER
|
||||||
select TIMER_OF
|
select TIMER_OF
|
||||||
select CLKSRC_MMIO
|
select CLKSRC_MMIO
|
||||||
help
|
help
|
||||||
Enables the support for the rockchip timer driver.
|
Enables the support for the Rockchip timer driver.
|
||||||
|
|
||||||
config ARMADA_370_XP_TIMER
|
config ARMADA_370_XP_TIMER
|
||||||
bool "Armada 370 and XP timer driver" if COMPILE_TEST
|
bool "Armada 370 and XP timer driver" if COMPILE_TEST
|
||||||
|
@ -162,13 +162,13 @@ config NPCM7XX_TIMER
|
||||||
select CLKSRC_MMIO
|
select CLKSRC_MMIO
|
||||||
help
|
help
|
||||||
Enable 24-bit TIMER0 and TIMER1 counters in the NPCM7xx architecture,
|
Enable 24-bit TIMER0 and TIMER1 counters in the NPCM7xx architecture,
|
||||||
While TIMER0 serves as clockevent and TIMER1 serves as clocksource.
|
where TIMER0 serves as clockevent and TIMER1 serves as clocksource.
|
||||||
|
|
||||||
config CADENCE_TTC_TIMER
|
config CADENCE_TTC_TIMER
|
||||||
bool "Cadence TTC timer driver" if COMPILE_TEST
|
bool "Cadence TTC timer driver" if COMPILE_TEST
|
||||||
depends on COMMON_CLK
|
depends on COMMON_CLK
|
||||||
help
|
help
|
||||||
Enables support for the cadence ttc driver.
|
Enables support for the Cadence TTC driver.
|
||||||
|
|
||||||
config ASM9260_TIMER
|
config ASM9260_TIMER
|
||||||
bool "ASM9260 timer driver" if COMPILE_TEST
|
bool "ASM9260 timer driver" if COMPILE_TEST
|
||||||
|
@ -190,10 +190,10 @@ config CLKSRC_DBX500_PRCMU
|
||||||
bool "Clocksource PRCMU Timer" if COMPILE_TEST
|
bool "Clocksource PRCMU Timer" if COMPILE_TEST
|
||||||
depends on HAS_IOMEM
|
depends on HAS_IOMEM
|
||||||
help
|
help
|
||||||
Use the always on PRCMU Timer as clocksource
|
Use the always on PRCMU Timer as clocksource.
|
||||||
|
|
||||||
config CLPS711X_TIMER
|
config CLPS711X_TIMER
|
||||||
bool "Cirrus logic timer driver" if COMPILE_TEST
|
bool "Cirrus Logic timer driver" if COMPILE_TEST
|
||||||
select CLKSRC_MMIO
|
select CLKSRC_MMIO
|
||||||
help
|
help
|
||||||
Enables support for the Cirrus Logic PS711 timer.
|
Enables support for the Cirrus Logic PS711 timer.
|
||||||
|
@ -205,11 +205,11 @@ config ATLAS7_TIMER
|
||||||
Enables support for the Atlas7 timer.
|
Enables support for the Atlas7 timer.
|
||||||
|
|
||||||
config MXS_TIMER
|
config MXS_TIMER
|
||||||
bool "Mxs timer driver" if COMPILE_TEST
|
bool "MXS timer driver" if COMPILE_TEST
|
||||||
select CLKSRC_MMIO
|
select CLKSRC_MMIO
|
||||||
select STMP_DEVICE
|
select STMP_DEVICE
|
||||||
help
|
help
|
||||||
Enables support for the Mxs timer.
|
Enables support for the MXS timer.
|
||||||
|
|
||||||
config PRIMA2_TIMER
|
config PRIMA2_TIMER
|
||||||
bool "Prima2 timer driver" if COMPILE_TEST
|
bool "Prima2 timer driver" if COMPILE_TEST
|
||||||
|
@ -238,10 +238,10 @@ config KEYSTONE_TIMER
|
||||||
Enables support for the Keystone timer.
|
Enables support for the Keystone timer.
|
||||||
|
|
||||||
config INTEGRATOR_AP_TIMER
|
config INTEGRATOR_AP_TIMER
|
||||||
bool "Integrator-ap timer driver" if COMPILE_TEST
|
bool "Integrator-AP timer driver" if COMPILE_TEST
|
||||||
select CLKSRC_MMIO
|
select CLKSRC_MMIO
|
||||||
help
|
help
|
||||||
Enables support for the Integrator-ap timer.
|
Enables support for the Integrator-AP timer.
|
||||||
|
|
||||||
config CLKSRC_EFM32
|
config CLKSRC_EFM32
|
||||||
bool "Clocksource for Energy Micro's EFM32 SoCs" if !ARCH_EFM32
|
bool "Clocksource for Energy Micro's EFM32 SoCs" if !ARCH_EFM32
|
||||||
|
@ -283,8 +283,8 @@ config CLKSRC_NPS
|
||||||
select TIMER_OF if OF
|
select TIMER_OF if OF
|
||||||
help
|
help
|
||||||
NPS400 clocksource support.
|
NPS400 clocksource support.
|
||||||
Got 64 bit counter with update rate up to 1000MHz.
|
It has a 64-bit counter with update rate up to 1000MHz.
|
||||||
This counter is accessed via couple of 32 bit memory mapped registers.
|
This counter is accessed via couple of 32-bit memory-mapped registers.
|
||||||
|
|
||||||
config CLKSRC_STM32
|
config CLKSRC_STM32
|
||||||
bool "Clocksource for STM32 SoCs" if !ARCH_STM32
|
bool "Clocksource for STM32 SoCs" if !ARCH_STM32
|
||||||
|
@ -305,14 +305,14 @@ config ARC_TIMERS
|
||||||
help
|
help
|
||||||
These are legacy 32-bit TIMER0 and TIMER1 counters found on all ARC cores
|
These are legacy 32-bit TIMER0 and TIMER1 counters found on all ARC cores
|
||||||
(ARC700 as well as ARC HS38).
|
(ARC700 as well as ARC HS38).
|
||||||
TIMER0 serves as clockevent while TIMER1 provides clocksource
|
TIMER0 serves as clockevent while TIMER1 provides clocksource.
|
||||||
|
|
||||||
config ARC_TIMERS_64BIT
|
config ARC_TIMERS_64BIT
|
||||||
bool "Support for 64-bit counters in ARC HS38 cores" if COMPILE_TEST
|
bool "Support for 64-bit counters in ARC HS38 cores" if COMPILE_TEST
|
||||||
depends on ARC_TIMERS
|
depends on ARC_TIMERS
|
||||||
select TIMER_OF
|
select TIMER_OF
|
||||||
help
|
help
|
||||||
This enables 2 different 64-bit timers: RTC (for UP) and GFRC (for SMP)
|
This enables 2 different 64-bit timers: RTC (for UP) and GFRC (for SMP).
|
||||||
RTC is implemented inside the core, while GFRC sits outside the core in
|
RTC is implemented inside the core, while GFRC sits outside the core in
|
||||||
ARConnect IP block. Driver automatically picks one of them for clocksource
|
ARConnect IP block. Driver automatically picks one of them for clocksource
|
||||||
as appropriate.
|
as appropriate.
|
||||||
|
@ -390,7 +390,7 @@ config ARM_GLOBAL_TIMER
|
||||||
select TIMER_OF if OF
|
select TIMER_OF if OF
|
||||||
depends on ARM
|
depends on ARM
|
||||||
help
|
help
|
||||||
This options enables support for the ARM global timer unit
|
This option enables support for the ARM global timer unit.
|
||||||
|
|
||||||
config ARM_TIMER_SP804
|
config ARM_TIMER_SP804
|
||||||
bool "Support for Dual Timer SP804 module" if COMPILE_TEST
|
bool "Support for Dual Timer SP804 module" if COMPILE_TEST
|
||||||
|
@ -403,14 +403,14 @@ config CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
|
||||||
depends on ARM_GLOBAL_TIMER
|
depends on ARM_GLOBAL_TIMER
|
||||||
default y
|
default y
|
||||||
help
|
help
|
||||||
Use ARM global timer clock source as sched_clock
|
Use ARM global timer clock source as sched_clock.
|
||||||
|
|
||||||
config ARMV7M_SYSTICK
|
config ARMV7M_SYSTICK
|
||||||
bool "Support for the ARMv7M system time" if COMPILE_TEST
|
bool "Support for the ARMv7M system time" if COMPILE_TEST
|
||||||
select TIMER_OF if OF
|
select TIMER_OF if OF
|
||||||
select CLKSRC_MMIO
|
select CLKSRC_MMIO
|
||||||
help
|
help
|
||||||
This options enables support for the ARMv7M system timer unit
|
This option enables support for the ARMv7M system timer unit.
|
||||||
|
|
||||||
config ATMEL_PIT
|
config ATMEL_PIT
|
||||||
bool "Atmel PIT support" if COMPILE_TEST
|
bool "Atmel PIT support" if COMPILE_TEST
|
||||||
|
@ -460,7 +460,7 @@ config VF_PIT_TIMER
|
||||||
bool
|
bool
|
||||||
select CLKSRC_MMIO
|
select CLKSRC_MMIO
|
||||||
help
|
help
|
||||||
Support for Period Interrupt Timer on Freescale Vybrid Family SoCs.
|
Support for Periodic Interrupt Timer on Freescale Vybrid Family SoCs.
|
||||||
|
|
||||||
config OXNAS_RPS_TIMER
|
config OXNAS_RPS_TIMER
|
||||||
bool "Oxford Semiconductor OXNAS RPS Timers driver" if COMPILE_TEST
|
bool "Oxford Semiconductor OXNAS RPS Timers driver" if COMPILE_TEST
|
||||||
|
@ -470,7 +470,7 @@ config OXNAS_RPS_TIMER
|
||||||
This enables support for the Oxford Semiconductor OXNAS RPS timers.
|
This enables support for the Oxford Semiconductor OXNAS RPS timers.
|
||||||
|
|
||||||
config SYS_SUPPORTS_SH_CMT
|
config SYS_SUPPORTS_SH_CMT
|
||||||
bool
|
bool
|
||||||
|
|
||||||
config MTK_TIMER
|
config MTK_TIMER
|
||||||
bool "Mediatek timer driver" if COMPILE_TEST
|
bool "Mediatek timer driver" if COMPILE_TEST
|
||||||
|
@ -490,13 +490,13 @@ config SPRD_TIMER
|
||||||
Enables support for the Spreadtrum timer driver.
|
Enables support for the Spreadtrum timer driver.
|
||||||
|
|
||||||
config SYS_SUPPORTS_SH_MTU2
|
config SYS_SUPPORTS_SH_MTU2
|
||||||
bool
|
bool
|
||||||
|
|
||||||
config SYS_SUPPORTS_SH_TMU
|
config SYS_SUPPORTS_SH_TMU
|
||||||
bool
|
bool
|
||||||
|
|
||||||
config SYS_SUPPORTS_EM_STI
|
config SYS_SUPPORTS_EM_STI
|
||||||
bool
|
bool
|
||||||
|
|
||||||
config CLKSRC_JCORE_PIT
|
config CLKSRC_JCORE_PIT
|
||||||
bool "J-Core PIT timer driver" if COMPILE_TEST
|
bool "J-Core PIT timer driver" if COMPILE_TEST
|
||||||
|
@ -523,7 +523,7 @@ config SH_TIMER_MTU2
|
||||||
help
|
help
|
||||||
This enables build of a clockevent driver for the Multi-Function
|
This enables build of a clockevent driver for the Multi-Function
|
||||||
Timer Pulse Unit 2 (MTU2) hardware available on SoCs from Renesas.
|
Timer Pulse Unit 2 (MTU2) hardware available on SoCs from Renesas.
|
||||||
This hardware comes with 16 bit-timer registers.
|
This hardware comes with 16-bit timer registers.
|
||||||
|
|
||||||
config RENESAS_OSTM
|
config RENESAS_OSTM
|
||||||
bool "Renesas OSTM timer driver" if COMPILE_TEST
|
bool "Renesas OSTM timer driver" if COMPILE_TEST
|
||||||
|
@ -580,7 +580,7 @@ config CLKSRC_TANGO_XTAL
|
||||||
select TIMER_OF
|
select TIMER_OF
|
||||||
select CLKSRC_MMIO
|
select CLKSRC_MMIO
|
||||||
help
|
help
|
||||||
This enables the clocksource for Tango SoC
|
This enables the clocksource for Tango SoC.
|
||||||
|
|
||||||
config CLKSRC_PXA
|
config CLKSRC_PXA
|
||||||
bool "Clocksource for PXA or SA-11x0 platform" if COMPILE_TEST
|
bool "Clocksource for PXA or SA-11x0 platform" if COMPILE_TEST
|
||||||
|
@ -591,24 +591,24 @@ config CLKSRC_PXA
|
||||||
platforms.
|
platforms.
|
||||||
|
|
||||||
config H8300_TMR8
|
config H8300_TMR8
|
||||||
bool "Clockevent timer for the H8300 platform" if COMPILE_TEST
|
bool "Clockevent timer for the H8300 platform" if COMPILE_TEST
|
||||||
depends on HAS_IOMEM
|
depends on HAS_IOMEM
|
||||||
help
|
help
|
||||||
This enables the 8 bits timer for the H8300 platform.
|
This enables the 8 bits timer for the H8300 platform.
|
||||||
|
|
||||||
config H8300_TMR16
|
config H8300_TMR16
|
||||||
bool "Clockevent timer for the H83069 platform" if COMPILE_TEST
|
bool "Clockevent timer for the H83069 platform" if COMPILE_TEST
|
||||||
depends on HAS_IOMEM
|
depends on HAS_IOMEM
|
||||||
help
|
help
|
||||||
This enables the 16 bits timer for the H8300 platform with the
|
This enables the 16 bits timer for the H8300 platform with the
|
||||||
H83069 cpu.
|
H83069 CPU.
|
||||||
|
|
||||||
config H8300_TPU
|
config H8300_TPU
|
||||||
bool "Clocksource for the H8300 platform" if COMPILE_TEST
|
bool "Clocksource for the H8300 platform" if COMPILE_TEST
|
||||||
depends on HAS_IOMEM
|
depends on HAS_IOMEM
|
||||||
help
|
help
|
||||||
This enables the clocksource for the H8300 platform with the
|
This enables the clocksource for the H8300 platform with the
|
||||||
H8S2678 cpu.
|
H8S2678 CPU.
|
||||||
|
|
||||||
config CLKSRC_IMX_GPT
|
config CLKSRC_IMX_GPT
|
||||||
bool "Clocksource using i.MX GPT" if COMPILE_TEST
|
bool "Clocksource using i.MX GPT" if COMPILE_TEST
|
||||||
|
@ -666,8 +666,8 @@ config CSKY_MP_TIMER
|
||||||
help
|
help
|
||||||
Say yes here to enable C-SKY SMP timer driver used for C-SKY SMP
|
Say yes here to enable C-SKY SMP timer driver used for C-SKY SMP
|
||||||
system.
|
system.
|
||||||
csky,mptimer is not only used in SMP system, it also could be used
|
csky,mptimer is not only used in SMP system, it also could be used in
|
||||||
single core system. It's not a mmio reg and it use mtcr/mfcr instruction.
|
single core system. It's not a mmio reg and it uses mtcr/mfcr instruction.
|
||||||
|
|
||||||
config GX6605S_TIMER
|
config GX6605S_TIMER
|
||||||
bool "Gx6605s SOC system timer driver" if COMPILE_TEST
|
bool "Gx6605s SOC system timer driver" if COMPILE_TEST
|
||||||
|
@ -697,4 +697,14 @@ config INGENIC_TIMER
|
||||||
help
|
help
|
||||||
Support for the timer/counter unit of the Ingenic JZ SoCs.
|
Support for the timer/counter unit of the Ingenic JZ SoCs.
|
||||||
|
|
||||||
|
config MICROCHIP_PIT64B
|
||||||
|
bool "Microchip PIT64B support"
|
||||||
|
depends on OF || COMPILE_TEST
|
||||||
|
select CLKSRC_MMIO
|
||||||
|
help
|
||||||
|
This option enables Microchip PIT64B timer for Atmel
|
||||||
|
based system. It supports the oneshot, the periodic
|
||||||
|
modes and high resolution. It is used as a clocksource
|
||||||
|
and a clockevent.
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
|
@ -88,3 +88,4 @@ obj-$(CONFIG_RISCV_TIMER) += timer-riscv.o
|
||||||
obj-$(CONFIG_CSKY_MP_TIMER) += timer-mp-csky.o
|
obj-$(CONFIG_CSKY_MP_TIMER) += timer-mp-csky.o
|
||||||
obj-$(CONFIG_GX6605S_TIMER) += timer-gx6605s.o
|
obj-$(CONFIG_GX6605S_TIMER) += timer-gx6605s.o
|
||||||
obj-$(CONFIG_HYPERV_TIMER) += hyperv_timer.o
|
obj-$(CONFIG_HYPERV_TIMER) += hyperv_timer.o
|
||||||
|
obj-$(CONFIG_MICROCHIP_PIT64B) += timer-microchip-pit64b.o
|
||||||
|
|
|
@ -121,7 +121,7 @@ static int __init bcm2835_timer_init(struct device_node *node)
|
||||||
ret = setup_irq(irq, &timer->act);
|
ret = setup_irq(irq, &timer->act);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("Can't set up timer IRQ\n");
|
pr_err("Can't set up timer IRQ\n");
|
||||||
goto err_iounmap;
|
goto err_timer_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
clockevents_config_and_register(&timer->evt, freq, 0xf, 0xffffffff);
|
clockevents_config_and_register(&timer->evt, freq, 0xf, 0xffffffff);
|
||||||
|
@ -130,6 +130,9 @@ static int __init bcm2835_timer_init(struct device_node *node)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
err_timer_free:
|
||||||
|
kfree(timer);
|
||||||
|
|
||||||
err_iounmap:
|
err_iounmap:
|
||||||
iounmap(base);
|
iounmap(base);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -279,9 +279,7 @@ static void em_sti_register_clockevent(struct em_sti_priv *p)
|
||||||
static int em_sti_probe(struct platform_device *pdev)
|
static int em_sti_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct em_sti_priv *p;
|
struct em_sti_priv *p;
|
||||||
struct resource *res;
|
int irq, ret;
|
||||||
int irq;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
|
p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
|
||||||
if (p == NULL)
|
if (p == NULL)
|
||||||
|
@ -295,8 +293,7 @@ static int em_sti_probe(struct platform_device *pdev)
|
||||||
return irq;
|
return irq;
|
||||||
|
|
||||||
/* map memory, let base point to the STI instance */
|
/* map memory, let base point to the STI instance */
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
p->base = devm_platform_ioremap_resource(pdev, 0);
|
||||||
p->base = devm_ioremap_resource(&pdev->dev, res);
|
|
||||||
if (IS_ERR(p->base))
|
if (IS_ERR(p->base))
|
||||||
return PTR_ERR(p->base);
|
return PTR_ERR(p->base);
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
|
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
|
||||||
* http://www.samsung.com
|
* http://www.samsung.com
|
||||||
*
|
*
|
||||||
* EXYNOS4 MCT(Multi-Core Timer) support
|
* Exynos4 MCT(Multi-Core Timer) support
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
|
|
|
@ -66,7 +66,7 @@ static int hv_ce_set_next_event(unsigned long delta,
|
||||||
{
|
{
|
||||||
u64 current_tick;
|
u64 current_tick;
|
||||||
|
|
||||||
current_tick = hyperv_cs->read(NULL);
|
current_tick = hv_read_reference_counter();
|
||||||
current_tick += delta;
|
current_tick += delta;
|
||||||
hv_init_timer(0, current_tick);
|
hv_init_timer(0, current_tick);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -302,22 +302,33 @@ EXPORT_SYMBOL_GPL(hv_stimer_global_cleanup);
|
||||||
* the other that uses the TSC reference page feature as defined in the
|
* the other that uses the TSC reference page feature as defined in the
|
||||||
* TLFS. The MSR version is for compatibility with old versions of
|
* TLFS. The MSR version is for compatibility with old versions of
|
||||||
* Hyper-V and 32-bit x86. The TSC reference page version is preferred.
|
* Hyper-V and 32-bit x86. The TSC reference page version is preferred.
|
||||||
|
*
|
||||||
|
* The Hyper-V clocksource ratings of 250 are chosen to be below the
|
||||||
|
* TSC clocksource rating of 300. In configurations where Hyper-V offers
|
||||||
|
* an InvariantTSC, the TSC is not marked "unstable", so the TSC clocksource
|
||||||
|
* is available and preferred. With the higher rating, it will be the
|
||||||
|
* default. On older hardware and Hyper-V versions, the TSC is marked
|
||||||
|
* "unstable", so no TSC clocksource is created and the selected Hyper-V
|
||||||
|
* clocksource will be the default.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct clocksource *hyperv_cs;
|
u64 (*hv_read_reference_counter)(void);
|
||||||
EXPORT_SYMBOL_GPL(hyperv_cs);
|
EXPORT_SYMBOL_GPL(hv_read_reference_counter);
|
||||||
|
|
||||||
static struct ms_hyperv_tsc_page tsc_pg __aligned(PAGE_SIZE);
|
static union {
|
||||||
|
struct ms_hyperv_tsc_page page;
|
||||||
|
u8 reserved[PAGE_SIZE];
|
||||||
|
} tsc_pg __aligned(PAGE_SIZE);
|
||||||
|
|
||||||
struct ms_hyperv_tsc_page *hv_get_tsc_page(void)
|
struct ms_hyperv_tsc_page *hv_get_tsc_page(void)
|
||||||
{
|
{
|
||||||
return &tsc_pg;
|
return &tsc_pg.page;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(hv_get_tsc_page);
|
EXPORT_SYMBOL_GPL(hv_get_tsc_page);
|
||||||
|
|
||||||
static u64 notrace read_hv_clock_tsc(struct clocksource *arg)
|
static u64 notrace read_hv_clock_tsc(void)
|
||||||
{
|
{
|
||||||
u64 current_tick = hv_read_tsc_page(&tsc_pg);
|
u64 current_tick = hv_read_tsc_page(hv_get_tsc_page());
|
||||||
|
|
||||||
if (current_tick == U64_MAX)
|
if (current_tick == U64_MAX)
|
||||||
hv_get_time_ref_count(current_tick);
|
hv_get_time_ref_count(current_tick);
|
||||||
|
@ -325,20 +336,50 @@ static u64 notrace read_hv_clock_tsc(struct clocksource *arg)
|
||||||
return current_tick;
|
return current_tick;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u64 notrace read_hv_clock_tsc_cs(struct clocksource *arg)
|
||||||
|
{
|
||||||
|
return read_hv_clock_tsc();
|
||||||
|
}
|
||||||
|
|
||||||
static u64 read_hv_sched_clock_tsc(void)
|
static u64 read_hv_sched_clock_tsc(void)
|
||||||
{
|
{
|
||||||
return read_hv_clock_tsc(NULL) - hv_sched_clock_offset;
|
return read_hv_clock_tsc() - hv_sched_clock_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void suspend_hv_clock_tsc(struct clocksource *arg)
|
||||||
|
{
|
||||||
|
u64 tsc_msr;
|
||||||
|
|
||||||
|
/* Disable the TSC page */
|
||||||
|
hv_get_reference_tsc(tsc_msr);
|
||||||
|
tsc_msr &= ~BIT_ULL(0);
|
||||||
|
hv_set_reference_tsc(tsc_msr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void resume_hv_clock_tsc(struct clocksource *arg)
|
||||||
|
{
|
||||||
|
phys_addr_t phys_addr = virt_to_phys(&tsc_pg);
|
||||||
|
u64 tsc_msr;
|
||||||
|
|
||||||
|
/* Re-enable the TSC page */
|
||||||
|
hv_get_reference_tsc(tsc_msr);
|
||||||
|
tsc_msr &= GENMASK_ULL(11, 0);
|
||||||
|
tsc_msr |= BIT_ULL(0) | (u64)phys_addr;
|
||||||
|
hv_set_reference_tsc(tsc_msr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct clocksource hyperv_cs_tsc = {
|
static struct clocksource hyperv_cs_tsc = {
|
||||||
.name = "hyperv_clocksource_tsc_page",
|
.name = "hyperv_clocksource_tsc_page",
|
||||||
.rating = 400,
|
.rating = 250,
|
||||||
.read = read_hv_clock_tsc,
|
.read = read_hv_clock_tsc_cs,
|
||||||
.mask = CLOCKSOURCE_MASK(64),
|
.mask = CLOCKSOURCE_MASK(64),
|
||||||
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
|
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
|
||||||
|
.suspend= suspend_hv_clock_tsc,
|
||||||
|
.resume = resume_hv_clock_tsc,
|
||||||
};
|
};
|
||||||
|
|
||||||
static u64 notrace read_hv_clock_msr(struct clocksource *arg)
|
static u64 notrace read_hv_clock_msr(void)
|
||||||
{
|
{
|
||||||
u64 current_tick;
|
u64 current_tick;
|
||||||
/*
|
/*
|
||||||
|
@ -350,15 +391,20 @@ static u64 notrace read_hv_clock_msr(struct clocksource *arg)
|
||||||
return current_tick;
|
return current_tick;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u64 notrace read_hv_clock_msr_cs(struct clocksource *arg)
|
||||||
|
{
|
||||||
|
return read_hv_clock_msr();
|
||||||
|
}
|
||||||
|
|
||||||
static u64 read_hv_sched_clock_msr(void)
|
static u64 read_hv_sched_clock_msr(void)
|
||||||
{
|
{
|
||||||
return read_hv_clock_msr(NULL) - hv_sched_clock_offset;
|
return read_hv_clock_msr() - hv_sched_clock_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct clocksource hyperv_cs_msr = {
|
static struct clocksource hyperv_cs_msr = {
|
||||||
.name = "hyperv_clocksource_msr",
|
.name = "hyperv_clocksource_msr",
|
||||||
.rating = 400,
|
.rating = 250,
|
||||||
.read = read_hv_clock_msr,
|
.read = read_hv_clock_msr_cs,
|
||||||
.mask = CLOCKSOURCE_MASK(64),
|
.mask = CLOCKSOURCE_MASK(64),
|
||||||
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
|
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
|
||||||
};
|
};
|
||||||
|
@ -371,8 +417,8 @@ static bool __init hv_init_tsc_clocksource(void)
|
||||||
if (!(ms_hyperv.features & HV_MSR_REFERENCE_TSC_AVAILABLE))
|
if (!(ms_hyperv.features & HV_MSR_REFERENCE_TSC_AVAILABLE))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
hyperv_cs = &hyperv_cs_tsc;
|
hv_read_reference_counter = read_hv_clock_tsc;
|
||||||
phys_addr = virt_to_phys(&tsc_pg);
|
phys_addr = virt_to_phys(hv_get_tsc_page());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The Hyper-V TLFS specifies to preserve the value of reserved
|
* The Hyper-V TLFS specifies to preserve the value of reserved
|
||||||
|
@ -389,7 +435,7 @@ static bool __init hv_init_tsc_clocksource(void)
|
||||||
hv_set_clocksource_vdso(hyperv_cs_tsc);
|
hv_set_clocksource_vdso(hyperv_cs_tsc);
|
||||||
clocksource_register_hz(&hyperv_cs_tsc, NSEC_PER_SEC/100);
|
clocksource_register_hz(&hyperv_cs_tsc, NSEC_PER_SEC/100);
|
||||||
|
|
||||||
hv_sched_clock_offset = hyperv_cs->read(hyperv_cs);
|
hv_sched_clock_offset = hv_read_reference_counter();
|
||||||
hv_setup_sched_clock(read_hv_sched_clock_tsc);
|
hv_setup_sched_clock(read_hv_sched_clock_tsc);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -411,10 +457,10 @@ void __init hv_init_clocksource(void)
|
||||||
if (!(ms_hyperv.features & HV_MSR_TIME_REF_COUNT_AVAILABLE))
|
if (!(ms_hyperv.features & HV_MSR_TIME_REF_COUNT_AVAILABLE))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
hyperv_cs = &hyperv_cs_msr;
|
hv_read_reference_counter = read_hv_clock_msr;
|
||||||
clocksource_register_hz(&hyperv_cs_msr, NSEC_PER_SEC/100);
|
clocksource_register_hz(&hyperv_cs_msr, NSEC_PER_SEC/100);
|
||||||
|
|
||||||
hv_sched_clock_offset = hyperv_cs->read(hyperv_cs);
|
hv_sched_clock_offset = hv_read_reference_counter();
|
||||||
hv_setup_sched_clock(read_hv_sched_clock_msr);
|
hv_setup_sched_clock(read_hv_sched_clock_msr);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(hv_init_clocksource);
|
EXPORT_SYMBOL_GPL(hv_init_clocksource);
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
#include <linux/of_irq.h>
|
#include <linux/of_irq.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/sched_clock.h>
|
#include <linux/sched_clock.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/of_platform.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This driver configures the 2 16/32-bit count-up timers as follows:
|
* This driver configures the 2 16/32-bit count-up timers as follows:
|
||||||
|
@ -464,13 +466,7 @@ static int __init ttc_setup_clockevent(struct clk *clk,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static int __init ttc_timer_probe(struct platform_device *pdev)
|
||||||
* ttc_timer_init - Initialize the timer
|
|
||||||
*
|
|
||||||
* Initializes the timer hardware and register the clock source and clock event
|
|
||||||
* timers with Linux kernal timer framework
|
|
||||||
*/
|
|
||||||
static int __init ttc_timer_init(struct device_node *timer)
|
|
||||||
{
|
{
|
||||||
unsigned int irq;
|
unsigned int irq;
|
||||||
void __iomem *timer_baseaddr;
|
void __iomem *timer_baseaddr;
|
||||||
|
@ -478,6 +474,7 @@ static int __init ttc_timer_init(struct device_node *timer)
|
||||||
static int initialized;
|
static int initialized;
|
||||||
int clksel, ret;
|
int clksel, ret;
|
||||||
u32 timer_width = 16;
|
u32 timer_width = 16;
|
||||||
|
struct device_node *timer = pdev->dev.of_node;
|
||||||
|
|
||||||
if (initialized)
|
if (initialized)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -532,4 +529,17 @@ static int __init ttc_timer_init(struct device_node *timer)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
TIMER_OF_DECLARE(ttc, "cdns,ttc", ttc_timer_init);
|
static const struct of_device_id ttc_timer_of_match[] = {
|
||||||
|
{.compatible = "cdns,ttc"},
|
||||||
|
{},
|
||||||
|
};
|
||||||
|
|
||||||
|
MODULE_DEVICE_TABLE(of, ttc_timer_of_match);
|
||||||
|
|
||||||
|
static struct platform_driver ttc_timer_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "cdns_ttc_timer",
|
||||||
|
.of_match_table = ttc_timer_of_match,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
builtin_platform_driver_probe(ttc_timer_driver, ttc_timer_probe);
|
||||||
|
|
|
@ -0,0 +1,451 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* 64-bit Periodic Interval Timer driver
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 Microchip Technology Inc. and its subsidiaries
|
||||||
|
*
|
||||||
|
* Author: Claudiu Beznea <claudiu.beznea@microchip.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/clk.h>
|
||||||
|
#include <linux/clockchips.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/of_address.h>
|
||||||
|
#include <linux/of_irq.h>
|
||||||
|
#include <linux/sched_clock.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
|
||||||
|
#define MCHP_PIT64B_CR 0x00 /* Control Register */
|
||||||
|
#define MCHP_PIT64B_CR_START BIT(0)
|
||||||
|
#define MCHP_PIT64B_CR_SWRST BIT(8)
|
||||||
|
|
||||||
|
#define MCHP_PIT64B_MR 0x04 /* Mode Register */
|
||||||
|
#define MCHP_PIT64B_MR_CONT BIT(0)
|
||||||
|
#define MCHP_PIT64B_MR_ONE_SHOT (0)
|
||||||
|
#define MCHP_PIT64B_MR_SGCLK BIT(3)
|
||||||
|
#define MCHP_PIT64B_MR_PRES GENMASK(11, 8)
|
||||||
|
|
||||||
|
#define MCHP_PIT64B_LSB_PR 0x08 /* LSB Period Register */
|
||||||
|
|
||||||
|
#define MCHP_PIT64B_MSB_PR 0x0C /* MSB Period Register */
|
||||||
|
|
||||||
|
#define MCHP_PIT64B_IER 0x10 /* Interrupt Enable Register */
|
||||||
|
#define MCHP_PIT64B_IER_PERIOD BIT(0)
|
||||||
|
|
||||||
|
#define MCHP_PIT64B_ISR 0x1C /* Interrupt Status Register */
|
||||||
|
|
||||||
|
#define MCHP_PIT64B_TLSBR 0x20 /* Timer LSB Register */
|
||||||
|
|
||||||
|
#define MCHP_PIT64B_TMSBR 0x24 /* Timer MSB Register */
|
||||||
|
|
||||||
|
#define MCHP_PIT64B_PRES_MAX 0x10
|
||||||
|
#define MCHP_PIT64B_LSBMASK GENMASK_ULL(31, 0)
|
||||||
|
#define MCHP_PIT64B_PRES_TO_MODE(p) (MCHP_PIT64B_MR_PRES & ((p) << 8))
|
||||||
|
#define MCHP_PIT64B_MODE_TO_PRES(m) ((MCHP_PIT64B_MR_PRES & (m)) >> 8)
|
||||||
|
#define MCHP_PIT64B_DEF_CS_FREQ 5000000UL /* 5 MHz */
|
||||||
|
#define MCHP_PIT64B_DEF_CE_FREQ 32768 /* 32 KHz */
|
||||||
|
|
||||||
|
#define MCHP_PIT64B_NAME "pit64b"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct mchp_pit64b_timer - PIT64B timer data structure
|
||||||
|
* @base: base address of PIT64B hardware block
|
||||||
|
* @pclk: PIT64B's peripheral clock
|
||||||
|
* @gclk: PIT64B's generic clock
|
||||||
|
* @mode: precomputed value for mode register
|
||||||
|
*/
|
||||||
|
struct mchp_pit64b_timer {
|
||||||
|
void __iomem *base;
|
||||||
|
struct clk *pclk;
|
||||||
|
struct clk *gclk;
|
||||||
|
u32 mode;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mchp_pit64b_clkevt - PIT64B clockevent data structure
|
||||||
|
* @timer: PIT64B timer
|
||||||
|
* @clkevt: clockevent
|
||||||
|
*/
|
||||||
|
struct mchp_pit64b_clkevt {
|
||||||
|
struct mchp_pit64b_timer timer;
|
||||||
|
struct clock_event_device clkevt;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define to_mchp_pit64b_timer(x) \
|
||||||
|
((struct mchp_pit64b_timer *)container_of(x,\
|
||||||
|
struct mchp_pit64b_clkevt, clkevt))
|
||||||
|
|
||||||
|
/* Base address for clocksource timer. */
|
||||||
|
static void __iomem *mchp_pit64b_cs_base;
|
||||||
|
/* Default cycles for clockevent timer. */
|
||||||
|
static u64 mchp_pit64b_ce_cycles;
|
||||||
|
|
||||||
|
static inline u64 mchp_pit64b_cnt_read(void __iomem *base)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
u32 low, high;
|
||||||
|
|
||||||
|
raw_local_irq_save(flags);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When using a 64 bit period TLSB must be read first, followed by the
|
||||||
|
* read of TMSB. This sequence generates an atomic read of the 64 bit
|
||||||
|
* timer value whatever the lapse of time between the accesses.
|
||||||
|
*/
|
||||||
|
low = readl_relaxed(base + MCHP_PIT64B_TLSBR);
|
||||||
|
high = readl_relaxed(base + MCHP_PIT64B_TMSBR);
|
||||||
|
|
||||||
|
raw_local_irq_restore(flags);
|
||||||
|
|
||||||
|
return (((u64)high << 32) | low);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void mchp_pit64b_reset(struct mchp_pit64b_timer *timer,
|
||||||
|
u64 cycles, u32 mode, u32 irqs)
|
||||||
|
{
|
||||||
|
u32 low, high;
|
||||||
|
|
||||||
|
low = cycles & MCHP_PIT64B_LSBMASK;
|
||||||
|
high = cycles >> 32;
|
||||||
|
|
||||||
|
writel_relaxed(MCHP_PIT64B_CR_SWRST, timer->base + MCHP_PIT64B_CR);
|
||||||
|
writel_relaxed(mode | timer->mode, timer->base + MCHP_PIT64B_MR);
|
||||||
|
writel_relaxed(high, timer->base + MCHP_PIT64B_MSB_PR);
|
||||||
|
writel_relaxed(low, timer->base + MCHP_PIT64B_LSB_PR);
|
||||||
|
writel_relaxed(irqs, timer->base + MCHP_PIT64B_IER);
|
||||||
|
writel_relaxed(MCHP_PIT64B_CR_START, timer->base + MCHP_PIT64B_CR);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u64 mchp_pit64b_clksrc_read(struct clocksource *cs)
|
||||||
|
{
|
||||||
|
return mchp_pit64b_cnt_read(mchp_pit64b_cs_base);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u64 mchp_pit64b_sched_read_clk(void)
|
||||||
|
{
|
||||||
|
return mchp_pit64b_cnt_read(mchp_pit64b_cs_base);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mchp_pit64b_clkevt_shutdown(struct clock_event_device *cedev)
|
||||||
|
{
|
||||||
|
struct mchp_pit64b_timer *timer = to_mchp_pit64b_timer(cedev);
|
||||||
|
|
||||||
|
writel_relaxed(MCHP_PIT64B_CR_SWRST, timer->base + MCHP_PIT64B_CR);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mchp_pit64b_clkevt_set_periodic(struct clock_event_device *cedev)
|
||||||
|
{
|
||||||
|
struct mchp_pit64b_timer *timer = to_mchp_pit64b_timer(cedev);
|
||||||
|
|
||||||
|
mchp_pit64b_reset(timer, mchp_pit64b_ce_cycles, MCHP_PIT64B_MR_CONT,
|
||||||
|
MCHP_PIT64B_IER_PERIOD);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mchp_pit64b_clkevt_set_next_event(unsigned long evt,
|
||||||
|
struct clock_event_device *cedev)
|
||||||
|
{
|
||||||
|
struct mchp_pit64b_timer *timer = to_mchp_pit64b_timer(cedev);
|
||||||
|
|
||||||
|
mchp_pit64b_reset(timer, evt, MCHP_PIT64B_MR_ONE_SHOT,
|
||||||
|
MCHP_PIT64B_IER_PERIOD);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mchp_pit64b_clkevt_suspend(struct clock_event_device *cedev)
|
||||||
|
{
|
||||||
|
struct mchp_pit64b_timer *timer = to_mchp_pit64b_timer(cedev);
|
||||||
|
|
||||||
|
writel_relaxed(MCHP_PIT64B_CR_SWRST, timer->base + MCHP_PIT64B_CR);
|
||||||
|
if (timer->mode & MCHP_PIT64B_MR_SGCLK)
|
||||||
|
clk_disable_unprepare(timer->gclk);
|
||||||
|
clk_disable_unprepare(timer->pclk);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mchp_pit64b_clkevt_resume(struct clock_event_device *cedev)
|
||||||
|
{
|
||||||
|
struct mchp_pit64b_timer *timer = to_mchp_pit64b_timer(cedev);
|
||||||
|
|
||||||
|
clk_prepare_enable(timer->pclk);
|
||||||
|
if (timer->mode & MCHP_PIT64B_MR_SGCLK)
|
||||||
|
clk_prepare_enable(timer->gclk);
|
||||||
|
}
|
||||||
|
|
||||||
|
static irqreturn_t mchp_pit64b_interrupt(int irq, void *dev_id)
|
||||||
|
{
|
||||||
|
struct mchp_pit64b_clkevt *irq_data = dev_id;
|
||||||
|
|
||||||
|
/* Need to clear the interrupt. */
|
||||||
|
readl_relaxed(irq_data->timer.base + MCHP_PIT64B_ISR);
|
||||||
|
|
||||||
|
irq_data->clkevt.event_handler(&irq_data->clkevt);
|
||||||
|
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __init mchp_pit64b_pres_compute(u32 *pres, u32 clk_rate,
|
||||||
|
u32 max_rate)
|
||||||
|
{
|
||||||
|
u32 tmp;
|
||||||
|
|
||||||
|
for (*pres = 0; *pres < MCHP_PIT64B_PRES_MAX; (*pres)++) {
|
||||||
|
tmp = clk_rate / (*pres + 1);
|
||||||
|
if (tmp <= max_rate)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Use the bigest prescaler if we didn't match one. */
|
||||||
|
if (*pres == MCHP_PIT64B_PRES_MAX)
|
||||||
|
*pres = MCHP_PIT64B_PRES_MAX - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mchp_pit64b_init_mode - prepare PIT64B mode register value to be used at
|
||||||
|
* runtime; this includes prescaler and SGCLK bit
|
||||||
|
*
|
||||||
|
* PIT64B timer may be fed by gclk or pclk. When gclk is used its rate has to
|
||||||
|
* be at least 3 times lower that pclk's rate. pclk rate is fixed, gclk rate
|
||||||
|
* could be changed via clock APIs. The chosen clock (pclk or gclk) could be
|
||||||
|
* divided by the internal PIT64B's divider.
|
||||||
|
*
|
||||||
|
* This function, first tries to use GCLK by requesting the desired rate from
|
||||||
|
* PMC and then using the internal PIT64B prescaler, if any, to reach the
|
||||||
|
* requested rate. If PCLK/GCLK < 3 (condition requested by PIT64B hardware)
|
||||||
|
* then the function falls back on using PCLK as clock source for PIT64B timer
|
||||||
|
* choosing the highest prescaler in case it doesn't locate one to match the
|
||||||
|
* requested frequency.
|
||||||
|
*
|
||||||
|
* Below is presented the PIT64B block in relation with PMC:
|
||||||
|
*
|
||||||
|
* PIT64B
|
||||||
|
* PMC +------------------------------------+
|
||||||
|
* +----+ | +-----+ |
|
||||||
|
* | |-->gclk -->|-->| | +---------+ +-----+ |
|
||||||
|
* | | | | MUX |--->| Divider |->|timer| |
|
||||||
|
* | |-->pclk -->|-->| | +---------+ +-----+ |
|
||||||
|
* +----+ | +-----+ |
|
||||||
|
* | ^ |
|
||||||
|
* | sel |
|
||||||
|
* +------------------------------------+
|
||||||
|
*
|
||||||
|
* Where:
|
||||||
|
* - gclk rate <= pclk rate/3
|
||||||
|
* - gclk rate could be requested from PMC
|
||||||
|
* - pclk rate is fixed (cannot be requested from PMC)
|
||||||
|
*/
|
||||||
|
static int __init mchp_pit64b_init_mode(struct mchp_pit64b_timer *timer,
|
||||||
|
unsigned long max_rate)
|
||||||
|
{
|
||||||
|
unsigned long pclk_rate, diff = 0, best_diff = ULONG_MAX;
|
||||||
|
long gclk_round = 0;
|
||||||
|
u32 pres, best_pres = 0;
|
||||||
|
|
||||||
|
pclk_rate = clk_get_rate(timer->pclk);
|
||||||
|
if (!pclk_rate)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
timer->mode = 0;
|
||||||
|
|
||||||
|
/* Try using GCLK. */
|
||||||
|
gclk_round = clk_round_rate(timer->gclk, max_rate);
|
||||||
|
if (gclk_round < 0)
|
||||||
|
goto pclk;
|
||||||
|
|
||||||
|
if (pclk_rate / gclk_round < 3)
|
||||||
|
goto pclk;
|
||||||
|
|
||||||
|
mchp_pit64b_pres_compute(&pres, gclk_round, max_rate);
|
||||||
|
best_diff = abs(gclk_round / (pres + 1) - max_rate);
|
||||||
|
best_pres = pres;
|
||||||
|
|
||||||
|
if (!best_diff) {
|
||||||
|
timer->mode |= MCHP_PIT64B_MR_SGCLK;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
pclk:
|
||||||
|
/* Check if requested rate could be obtained using PCLK. */
|
||||||
|
mchp_pit64b_pres_compute(&pres, pclk_rate, max_rate);
|
||||||
|
diff = abs(pclk_rate / (pres + 1) - max_rate);
|
||||||
|
|
||||||
|
if (best_diff > diff) {
|
||||||
|
/* Use PCLK. */
|
||||||
|
best_pres = pres;
|
||||||
|
} else {
|
||||||
|
/* Use GCLK. */
|
||||||
|
timer->mode |= MCHP_PIT64B_MR_SGCLK;
|
||||||
|
clk_set_rate(timer->gclk, gclk_round);
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
timer->mode |= MCHP_PIT64B_PRES_TO_MODE(best_pres);
|
||||||
|
|
||||||
|
pr_info("PIT64B: using clk=%s with prescaler %u, freq=%lu [Hz]\n",
|
||||||
|
timer->mode & MCHP_PIT64B_MR_SGCLK ? "gclk" : "pclk", best_pres,
|
||||||
|
timer->mode & MCHP_PIT64B_MR_SGCLK ?
|
||||||
|
gclk_round / (best_pres + 1) : pclk_rate / (best_pres + 1));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __init mchp_pit64b_init_clksrc(struct mchp_pit64b_timer *timer,
|
||||||
|
u32 clk_rate)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
mchp_pit64b_reset(timer, ULLONG_MAX, MCHP_PIT64B_MR_CONT, 0);
|
||||||
|
|
||||||
|
mchp_pit64b_cs_base = timer->base;
|
||||||
|
|
||||||
|
ret = clocksource_mmio_init(timer->base, MCHP_PIT64B_NAME, clk_rate,
|
||||||
|
210, 64, mchp_pit64b_clksrc_read);
|
||||||
|
if (ret) {
|
||||||
|
pr_debug("clksrc: Failed to register PIT64B clocksource!\n");
|
||||||
|
|
||||||
|
/* Stop timer. */
|
||||||
|
writel_relaxed(MCHP_PIT64B_CR_SWRST,
|
||||||
|
timer->base + MCHP_PIT64B_CR);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
sched_clock_register(mchp_pit64b_sched_read_clk, 64, clk_rate);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __init mchp_pit64b_init_clkevt(struct mchp_pit64b_timer *timer,
|
||||||
|
u32 clk_rate, u32 irq)
|
||||||
|
{
|
||||||
|
struct mchp_pit64b_clkevt *ce;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ce = kzalloc(sizeof(*ce), GFP_KERNEL);
|
||||||
|
if (!ce)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
mchp_pit64b_ce_cycles = DIV_ROUND_CLOSEST(clk_rate, HZ);
|
||||||
|
|
||||||
|
ce->timer.base = timer->base;
|
||||||
|
ce->timer.pclk = timer->pclk;
|
||||||
|
ce->timer.gclk = timer->gclk;
|
||||||
|
ce->timer.mode = timer->mode;
|
||||||
|
ce->clkevt.name = MCHP_PIT64B_NAME;
|
||||||
|
ce->clkevt.features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC;
|
||||||
|
ce->clkevt.rating = 150;
|
||||||
|
ce->clkevt.set_state_shutdown = mchp_pit64b_clkevt_shutdown;
|
||||||
|
ce->clkevt.set_state_periodic = mchp_pit64b_clkevt_set_periodic;
|
||||||
|
ce->clkevt.set_next_event = mchp_pit64b_clkevt_set_next_event;
|
||||||
|
ce->clkevt.suspend = mchp_pit64b_clkevt_suspend;
|
||||||
|
ce->clkevt.resume = mchp_pit64b_clkevt_resume;
|
||||||
|
ce->clkevt.cpumask = cpumask_of(0);
|
||||||
|
ce->clkevt.irq = irq;
|
||||||
|
|
||||||
|
ret = request_irq(irq, mchp_pit64b_interrupt, IRQF_TIMER,
|
||||||
|
"pit64b_tick", ce);
|
||||||
|
if (ret) {
|
||||||
|
pr_debug("clkevt: Failed to setup PIT64B IRQ\n");
|
||||||
|
kfree(ce);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
clockevents_config_and_register(&ce->clkevt, clk_rate, 1, ULONG_MAX);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __init mchp_pit64b_dt_init_timer(struct device_node *node,
|
||||||
|
bool clkevt)
|
||||||
|
{
|
||||||
|
u32 freq = clkevt ? MCHP_PIT64B_DEF_CE_FREQ : MCHP_PIT64B_DEF_CS_FREQ;
|
||||||
|
struct mchp_pit64b_timer timer;
|
||||||
|
unsigned long clk_rate;
|
||||||
|
u32 irq = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Parse DT node. */
|
||||||
|
timer.pclk = of_clk_get_by_name(node, "pclk");
|
||||||
|
if (IS_ERR(timer.pclk))
|
||||||
|
return PTR_ERR(timer.pclk);
|
||||||
|
|
||||||
|
timer.gclk = of_clk_get_by_name(node, "gclk");
|
||||||
|
if (IS_ERR(timer.gclk))
|
||||||
|
return PTR_ERR(timer.gclk);
|
||||||
|
|
||||||
|
timer.base = of_iomap(node, 0);
|
||||||
|
if (!timer.base)
|
||||||
|
return -ENXIO;
|
||||||
|
|
||||||
|
if (clkevt) {
|
||||||
|
irq = irq_of_parse_and_map(node, 0);
|
||||||
|
if (!irq) {
|
||||||
|
ret = -ENODEV;
|
||||||
|
goto io_unmap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize mode (prescaler + SGCK bit). To be used at runtime. */
|
||||||
|
ret = mchp_pit64b_init_mode(&timer, freq);
|
||||||
|
if (ret)
|
||||||
|
goto irq_unmap;
|
||||||
|
|
||||||
|
ret = clk_prepare_enable(timer.pclk);
|
||||||
|
if (ret)
|
||||||
|
goto irq_unmap;
|
||||||
|
|
||||||
|
if (timer.mode & MCHP_PIT64B_MR_SGCLK) {
|
||||||
|
ret = clk_prepare_enable(timer.gclk);
|
||||||
|
if (ret)
|
||||||
|
goto pclk_unprepare;
|
||||||
|
|
||||||
|
clk_rate = clk_get_rate(timer.gclk);
|
||||||
|
} else {
|
||||||
|
clk_rate = clk_get_rate(timer.pclk);
|
||||||
|
}
|
||||||
|
clk_rate = clk_rate / (MCHP_PIT64B_MODE_TO_PRES(timer.mode) + 1);
|
||||||
|
|
||||||
|
if (clkevt)
|
||||||
|
ret = mchp_pit64b_init_clkevt(&timer, clk_rate, irq);
|
||||||
|
else
|
||||||
|
ret = mchp_pit64b_init_clksrc(&timer, clk_rate);
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
goto gclk_unprepare;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
gclk_unprepare:
|
||||||
|
if (timer.mode & MCHP_PIT64B_MR_SGCLK)
|
||||||
|
clk_disable_unprepare(timer.gclk);
|
||||||
|
pclk_unprepare:
|
||||||
|
clk_disable_unprepare(timer.pclk);
|
||||||
|
irq_unmap:
|
||||||
|
irq_dispose_mapping(irq);
|
||||||
|
io_unmap:
|
||||||
|
iounmap(timer.base);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __init mchp_pit64b_dt_init(struct device_node *node)
|
||||||
|
{
|
||||||
|
static int inits;
|
||||||
|
|
||||||
|
switch (inits++) {
|
||||||
|
case 0:
|
||||||
|
/* 1st request, register clockevent. */
|
||||||
|
return mchp_pit64b_dt_init_timer(node, true);
|
||||||
|
case 1:
|
||||||
|
/* 2nd request, register clocksource. */
|
||||||
|
return mchp_pit64b_dt_init_timer(node, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The rest, don't care. */
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
TIMER_OF_DECLARE(mchp_pit64b, "microchip,sam9x60-pit64b", mchp_pit64b_dt_init);
|
|
@ -780,7 +780,6 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
struct omap_dm_timer *timer;
|
struct omap_dm_timer *timer;
|
||||||
struct resource *mem, *irq;
|
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
const struct dmtimer_platform_data *pdata;
|
const struct dmtimer_platform_data *pdata;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -796,24 +795,16 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
|
||||||
if (unlikely(!irq)) {
|
|
||||||
dev_err(dev, "%s: no IRQ resource.\n", __func__);
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
||||||
if (unlikely(!mem)) {
|
|
||||||
dev_err(dev, "%s: no memory resource.\n", __func__);
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
timer = devm_kzalloc(dev, sizeof(*timer), GFP_KERNEL);
|
timer = devm_kzalloc(dev, sizeof(*timer), GFP_KERNEL);
|
||||||
if (!timer)
|
if (!timer)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
timer->irq = platform_get_irq(pdev, 0);
|
||||||
|
if (timer->irq < 0)
|
||||||
|
return timer->irq;
|
||||||
|
|
||||||
timer->fclk = ERR_PTR(-ENODEV);
|
timer->fclk = ERR_PTR(-ENODEV);
|
||||||
timer->io_base = devm_ioremap_resource(dev, mem);
|
timer->io_base = devm_platform_ioremap_resource(pdev, 0);
|
||||||
if (IS_ERR(timer->io_base))
|
if (IS_ERR(timer->io_base))
|
||||||
return PTR_ERR(timer->io_base);
|
return PTR_ERR(timer->io_base);
|
||||||
|
|
||||||
|
@ -836,7 +827,6 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
|
||||||
if (pdata)
|
if (pdata)
|
||||||
timer->errata = pdata->timer_errata;
|
timer->errata = pdata->timer_errata;
|
||||||
|
|
||||||
timer->irq = irq->start;
|
|
||||||
timer->pdev = pdev;
|
timer->pdev = pdev;
|
||||||
|
|
||||||
pm_runtime_enable(dev);
|
pm_runtime_enable(dev);
|
||||||
|
|
|
@ -211,7 +211,7 @@ static struct timespec64 hv_get_adj_host_time(void)
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock_irqsave(&host_ts.lock, flags);
|
spin_lock_irqsave(&host_ts.lock, flags);
|
||||||
reftime = hyperv_cs->read(hyperv_cs);
|
reftime = hv_read_reference_counter();
|
||||||
newtime = host_ts.host_time + (reftime - host_ts.ref_time);
|
newtime = host_ts.host_time + (reftime - host_ts.ref_time);
|
||||||
ts = ns_to_timespec64((newtime - WLTIMEDELTA) * 100);
|
ts = ns_to_timespec64((newtime - WLTIMEDELTA) * 100);
|
||||||
spin_unlock_irqrestore(&host_ts.lock, flags);
|
spin_unlock_irqrestore(&host_ts.lock, flags);
|
||||||
|
@ -250,7 +250,7 @@ static inline void adj_guesttime(u64 hosttime, u64 reftime, u8 adj_flags)
|
||||||
*/
|
*/
|
||||||
spin_lock_irqsave(&host_ts.lock, flags);
|
spin_lock_irqsave(&host_ts.lock, flags);
|
||||||
|
|
||||||
cur_reftime = hyperv_cs->read(hyperv_cs);
|
cur_reftime = hv_read_reference_counter();
|
||||||
host_ts.host_time = hosttime;
|
host_ts.host_time = hosttime;
|
||||||
host_ts.ref_time = cur_reftime;
|
host_ts.ref_time = cur_reftime;
|
||||||
|
|
||||||
|
@ -315,7 +315,7 @@ static void timesync_onchannelcallback(void *context)
|
||||||
sizeof(struct vmbuspipe_hdr) +
|
sizeof(struct vmbuspipe_hdr) +
|
||||||
sizeof(struct icmsg_hdr)];
|
sizeof(struct icmsg_hdr)];
|
||||||
adj_guesttime(timedatap->parenttime,
|
adj_guesttime(timedatap->parenttime,
|
||||||
hyperv_cs->read(hyperv_cs),
|
hv_read_reference_counter(),
|
||||||
timedatap->flags);
|
timedatap->flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -524,7 +524,7 @@ static struct ptp_clock *hv_ptp_clock;
|
||||||
static int hv_timesync_init(struct hv_util_service *srv)
|
static int hv_timesync_init(struct hv_util_service *srv)
|
||||||
{
|
{
|
||||||
/* TimeSync requires Hyper-V clocksource. */
|
/* TimeSync requires Hyper-V clocksource. */
|
||||||
if (!hyperv_cs)
|
if (!hv_read_reference_counter)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
spin_lock_init(&host_ts.lock);
|
spin_lock_init(&host_ts.lock);
|
||||||
|
|
|
@ -30,7 +30,7 @@ extern void hv_stimer_global_cleanup(void);
|
||||||
extern void hv_stimer0_isr(void);
|
extern void hv_stimer0_isr(void);
|
||||||
|
|
||||||
#ifdef CONFIG_HYPERV_TIMER
|
#ifdef CONFIG_HYPERV_TIMER
|
||||||
extern struct clocksource *hyperv_cs;
|
extern u64 (*hv_read_reference_counter)(void);
|
||||||
extern void hv_init_clocksource(void);
|
extern void hv_init_clocksource(void);
|
||||||
|
|
||||||
extern struct ms_hyperv_tsc_page *hv_get_tsc_page(void);
|
extern struct ms_hyperv_tsc_page *hv_get_tsc_page(void);
|
||||||
|
|
Loading…
Reference in New Issue