- 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
|
||||
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:
|
||||
- compatible: Should be "atmel,at91rm9200-st", "syscon", "simple-mfd"
|
||||
- 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,r8a774a1-cmt0" for the 32-bit CMT0 device 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-cmt1" for the 48-bit CMT devices included in r8a774c0.
|
||||
- "renesas,r8a7790-cmt0" for the 32-bit CMT0 device included in r8a7790.
|
||||
|
|
|
@ -88,7 +88,7 @@ config ROCKCHIP_TIMER
|
|||
select TIMER_OF
|
||||
select CLKSRC_MMIO
|
||||
help
|
||||
Enables the support for the rockchip timer driver.
|
||||
Enables the support for the Rockchip timer driver.
|
||||
|
||||
config ARMADA_370_XP_TIMER
|
||||
bool "Armada 370 and XP timer driver" if COMPILE_TEST
|
||||
|
@ -162,13 +162,13 @@ config NPCM7XX_TIMER
|
|||
select CLKSRC_MMIO
|
||||
help
|
||||
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
|
||||
bool "Cadence TTC timer driver" if COMPILE_TEST
|
||||
depends on COMMON_CLK
|
||||
help
|
||||
Enables support for the cadence ttc driver.
|
||||
Enables support for the Cadence TTC driver.
|
||||
|
||||
config ASM9260_TIMER
|
||||
bool "ASM9260 timer driver" if COMPILE_TEST
|
||||
|
@ -190,10 +190,10 @@ config CLKSRC_DBX500_PRCMU
|
|||
bool "Clocksource PRCMU Timer" if COMPILE_TEST
|
||||
depends on HAS_IOMEM
|
||||
help
|
||||
Use the always on PRCMU Timer as clocksource
|
||||
Use the always on PRCMU Timer as clocksource.
|
||||
|
||||
config CLPS711X_TIMER
|
||||
bool "Cirrus logic timer driver" if COMPILE_TEST
|
||||
bool "Cirrus Logic timer driver" if COMPILE_TEST
|
||||
select CLKSRC_MMIO
|
||||
help
|
||||
Enables support for the Cirrus Logic PS711 timer.
|
||||
|
@ -205,11 +205,11 @@ config ATLAS7_TIMER
|
|||
Enables support for the Atlas7 timer.
|
||||
|
||||
config MXS_TIMER
|
||||
bool "Mxs timer driver" if COMPILE_TEST
|
||||
bool "MXS timer driver" if COMPILE_TEST
|
||||
select CLKSRC_MMIO
|
||||
select STMP_DEVICE
|
||||
help
|
||||
Enables support for the Mxs timer.
|
||||
Enables support for the MXS timer.
|
||||
|
||||
config PRIMA2_TIMER
|
||||
bool "Prima2 timer driver" if COMPILE_TEST
|
||||
|
@ -238,10 +238,10 @@ config KEYSTONE_TIMER
|
|||
Enables support for the Keystone timer.
|
||||
|
||||
config INTEGRATOR_AP_TIMER
|
||||
bool "Integrator-ap timer driver" if COMPILE_TEST
|
||||
bool "Integrator-AP timer driver" if COMPILE_TEST
|
||||
select CLKSRC_MMIO
|
||||
help
|
||||
Enables support for the Integrator-ap timer.
|
||||
Enables support for the Integrator-AP timer.
|
||||
|
||||
config CLKSRC_EFM32
|
||||
bool "Clocksource for Energy Micro's EFM32 SoCs" if !ARCH_EFM32
|
||||
|
@ -283,8 +283,8 @@ config CLKSRC_NPS
|
|||
select TIMER_OF if OF
|
||||
help
|
||||
NPS400 clocksource support.
|
||||
Got 64 bit counter with update rate up to 1000MHz.
|
||||
This counter is accessed via couple of 32 bit memory mapped registers.
|
||||
It has a 64-bit counter with update rate up to 1000MHz.
|
||||
This counter is accessed via couple of 32-bit memory-mapped registers.
|
||||
|
||||
config CLKSRC_STM32
|
||||
bool "Clocksource for STM32 SoCs" if !ARCH_STM32
|
||||
|
@ -305,14 +305,14 @@ config ARC_TIMERS
|
|||
help
|
||||
These are legacy 32-bit TIMER0 and TIMER1 counters found on all ARC cores
|
||||
(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
|
||||
bool "Support for 64-bit counters in ARC HS38 cores" if COMPILE_TEST
|
||||
depends on ARC_TIMERS
|
||||
select TIMER_OF
|
||||
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
|
||||
ARConnect IP block. Driver automatically picks one of them for clocksource
|
||||
as appropriate.
|
||||
|
@ -390,7 +390,7 @@ config ARM_GLOBAL_TIMER
|
|||
select TIMER_OF if OF
|
||||
depends on ARM
|
||||
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
|
||||
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
|
||||
default y
|
||||
help
|
||||
Use ARM global timer clock source as sched_clock
|
||||
Use ARM global timer clock source as sched_clock.
|
||||
|
||||
config ARMV7M_SYSTICK
|
||||
bool "Support for the ARMv7M system time" if COMPILE_TEST
|
||||
select TIMER_OF if OF
|
||||
select CLKSRC_MMIO
|
||||
help
|
||||
This options enables support for the ARMv7M system timer unit
|
||||
This option enables support for the ARMv7M system timer unit.
|
||||
|
||||
config ATMEL_PIT
|
||||
bool "Atmel PIT support" if COMPILE_TEST
|
||||
|
@ -460,7 +460,7 @@ config VF_PIT_TIMER
|
|||
bool
|
||||
select CLKSRC_MMIO
|
||||
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
|
||||
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.
|
||||
|
||||
config SYS_SUPPORTS_SH_CMT
|
||||
bool
|
||||
bool
|
||||
|
||||
config MTK_TIMER
|
||||
bool "Mediatek timer driver" if COMPILE_TEST
|
||||
|
@ -490,13 +490,13 @@ config SPRD_TIMER
|
|||
Enables support for the Spreadtrum timer driver.
|
||||
|
||||
config SYS_SUPPORTS_SH_MTU2
|
||||
bool
|
||||
bool
|
||||
|
||||
config SYS_SUPPORTS_SH_TMU
|
||||
bool
|
||||
bool
|
||||
|
||||
config SYS_SUPPORTS_EM_STI
|
||||
bool
|
||||
bool
|
||||
|
||||
config CLKSRC_JCORE_PIT
|
||||
bool "J-Core PIT timer driver" if COMPILE_TEST
|
||||
|
@ -523,7 +523,7 @@ config SH_TIMER_MTU2
|
|||
help
|
||||
This enables build of a clockevent driver for the Multi-Function
|
||||
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
|
||||
bool "Renesas OSTM timer driver" if COMPILE_TEST
|
||||
|
@ -580,7 +580,7 @@ config CLKSRC_TANGO_XTAL
|
|||
select TIMER_OF
|
||||
select CLKSRC_MMIO
|
||||
help
|
||||
This enables the clocksource for Tango SoC
|
||||
This enables the clocksource for Tango SoC.
|
||||
|
||||
config CLKSRC_PXA
|
||||
bool "Clocksource for PXA or SA-11x0 platform" if COMPILE_TEST
|
||||
|
@ -591,24 +591,24 @@ config CLKSRC_PXA
|
|||
platforms.
|
||||
|
||||
config H8300_TMR8
|
||||
bool "Clockevent timer for the H8300 platform" if COMPILE_TEST
|
||||
depends on HAS_IOMEM
|
||||
bool "Clockevent timer for the H8300 platform" if COMPILE_TEST
|
||||
depends on HAS_IOMEM
|
||||
help
|
||||
This enables the 8 bits timer for the H8300 platform.
|
||||
|
||||
config H8300_TMR16
|
||||
bool "Clockevent timer for the H83069 platform" if COMPILE_TEST
|
||||
depends on HAS_IOMEM
|
||||
bool "Clockevent timer for the H83069 platform" if COMPILE_TEST
|
||||
depends on HAS_IOMEM
|
||||
help
|
||||
This enables the 16 bits timer for the H8300 platform with the
|
||||
H83069 cpu.
|
||||
H83069 CPU.
|
||||
|
||||
config H8300_TPU
|
||||
bool "Clocksource for the H8300 platform" if COMPILE_TEST
|
||||
depends on HAS_IOMEM
|
||||
bool "Clocksource for the H8300 platform" if COMPILE_TEST
|
||||
depends on HAS_IOMEM
|
||||
help
|
||||
This enables the clocksource for the H8300 platform with the
|
||||
H8S2678 cpu.
|
||||
H8S2678 CPU.
|
||||
|
||||
config CLKSRC_IMX_GPT
|
||||
bool "Clocksource using i.MX GPT" if COMPILE_TEST
|
||||
|
@ -666,8 +666,8 @@ config CSKY_MP_TIMER
|
|||
help
|
||||
Say yes here to enable C-SKY SMP timer driver used for C-SKY SMP
|
||||
system.
|
||||
csky,mptimer is not only used in SMP system, it also could be used
|
||||
single core system. It's not a mmio reg and it use mtcr/mfcr instruction.
|
||||
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 uses mtcr/mfcr instruction.
|
||||
|
||||
config GX6605S_TIMER
|
||||
bool "Gx6605s SOC system timer driver" if COMPILE_TEST
|
||||
|
@ -697,4 +697,14 @@ config INGENIC_TIMER
|
|||
help
|
||||
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
|
||||
|
|
|
@ -88,3 +88,4 @@ obj-$(CONFIG_RISCV_TIMER) += timer-riscv.o
|
|||
obj-$(CONFIG_CSKY_MP_TIMER) += timer-mp-csky.o
|
||||
obj-$(CONFIG_GX6605S_TIMER) += timer-gx6605s.o
|
||||
obj-$(CONFIG_HYPERV_TIMER) += hyperv_timer.o
|
||||
obj-$(CONFIG_MICROCHIP_PIT64B) += timer-microchip-pit64b.o
|
||||
|
|
|
@ -121,7 +121,7 @@ static int __init bcm2835_timer_init(struct device_node *node)
|
|||
ret = setup_irq(irq, &timer->act);
|
||||
if (ret) {
|
||||
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);
|
||||
|
@ -130,6 +130,9 @@ static int __init bcm2835_timer_init(struct device_node *node)
|
|||
|
||||
return 0;
|
||||
|
||||
err_timer_free:
|
||||
kfree(timer);
|
||||
|
||||
err_iounmap:
|
||||
iounmap(base);
|
||||
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)
|
||||
{
|
||||
struct em_sti_priv *p;
|
||||
struct resource *res;
|
||||
int irq;
|
||||
int ret;
|
||||
int irq, ret;
|
||||
|
||||
p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
|
||||
if (p == NULL)
|
||||
|
@ -295,8 +293,7 @@ static int em_sti_probe(struct platform_device *pdev)
|
|||
return irq;
|
||||
|
||||
/* map memory, let base point to the STI instance */
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
p->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
p->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(p->base))
|
||||
return PTR_ERR(p->base);
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
*
|
||||
* EXYNOS4 MCT(Multi-Core Timer) support
|
||||
* Exynos4 MCT(Multi-Core Timer) support
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
|
|
|
@ -66,7 +66,7 @@ static int hv_ce_set_next_event(unsigned long delta,
|
|||
{
|
||||
u64 current_tick;
|
||||
|
||||
current_tick = hyperv_cs->read(NULL);
|
||||
current_tick = hv_read_reference_counter();
|
||||
current_tick += delta;
|
||||
hv_init_timer(0, current_tick);
|
||||
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
|
||||
* TLFS. The MSR version is for compatibility with old versions of
|
||||
* 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;
|
||||
EXPORT_SYMBOL_GPL(hyperv_cs);
|
||||
u64 (*hv_read_reference_counter)(void);
|
||||
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)
|
||||
{
|
||||
return &tsc_pg;
|
||||
return &tsc_pg.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)
|
||||
hv_get_time_ref_count(current_tick);
|
||||
|
@ -325,20 +336,50 @@ static u64 notrace read_hv_clock_tsc(struct clocksource *arg)
|
|||
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)
|
||||
{
|
||||
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 = {
|
||||
.name = "hyperv_clocksource_tsc_page",
|
||||
.rating = 400,
|
||||
.read = read_hv_clock_tsc,
|
||||
.rating = 250,
|
||||
.read = read_hv_clock_tsc_cs,
|
||||
.mask = CLOCKSOURCE_MASK(64),
|
||||
.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;
|
||||
/*
|
||||
|
@ -350,15 +391,20 @@ static u64 notrace read_hv_clock_msr(struct clocksource *arg)
|
|||
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)
|
||||
{
|
||||
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 = {
|
||||
.name = "hyperv_clocksource_msr",
|
||||
.rating = 400,
|
||||
.read = read_hv_clock_msr,
|
||||
.rating = 250,
|
||||
.read = read_hv_clock_msr_cs,
|
||||
.mask = CLOCKSOURCE_MASK(64),
|
||||
.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))
|
||||
return false;
|
||||
|
||||
hyperv_cs = &hyperv_cs_tsc;
|
||||
phys_addr = virt_to_phys(&tsc_pg);
|
||||
hv_read_reference_counter = read_hv_clock_tsc;
|
||||
phys_addr = virt_to_phys(hv_get_tsc_page());
|
||||
|
||||
/*
|
||||
* 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);
|
||||
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);
|
||||
|
||||
return true;
|
||||
|
@ -411,10 +457,10 @@ void __init hv_init_clocksource(void)
|
|||
if (!(ms_hyperv.features & HV_MSR_TIME_REF_COUNT_AVAILABLE))
|
||||
return;
|
||||
|
||||
hyperv_cs = &hyperv_cs_msr;
|
||||
hv_read_reference_counter = read_hv_clock_msr;
|
||||
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);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hv_init_clocksource);
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
#include <linux/of_irq.h>
|
||||
#include <linux/slab.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:
|
||||
|
@ -464,13 +466,7 @@ static int __init ttc_setup_clockevent(struct clk *clk,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
static int __init ttc_timer_probe(struct platform_device *pdev)
|
||||
{
|
||||
unsigned int irq;
|
||||
void __iomem *timer_baseaddr;
|
||||
|
@ -478,6 +474,7 @@ static int __init ttc_timer_init(struct device_node *timer)
|
|||
static int initialized;
|
||||
int clksel, ret;
|
||||
u32 timer_width = 16;
|
||||
struct device_node *timer = pdev->dev.of_node;
|
||||
|
||||
if (initialized)
|
||||
return 0;
|
||||
|
@ -532,4 +529,17 @@ static int __init ttc_timer_init(struct device_node *timer)
|
|||
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;
|
||||
struct omap_dm_timer *timer;
|
||||
struct resource *mem, *irq;
|
||||
struct device *dev = &pdev->dev;
|
||||
const struct dmtimer_platform_data *pdata;
|
||||
int ret;
|
||||
|
@ -796,24 +795,16 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
|
|||
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);
|
||||
if (!timer)
|
||||
return -ENOMEM;
|
||||
|
||||
timer->irq = platform_get_irq(pdev, 0);
|
||||
if (timer->irq < 0)
|
||||
return timer->irq;
|
||||
|
||||
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))
|
||||
return PTR_ERR(timer->io_base);
|
||||
|
||||
|
@ -836,7 +827,6 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
|
|||
if (pdata)
|
||||
timer->errata = pdata->timer_errata;
|
||||
|
||||
timer->irq = irq->start;
|
||||
timer->pdev = pdev;
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
|
|
|
@ -211,7 +211,7 @@ static struct timespec64 hv_get_adj_host_time(void)
|
|||
unsigned long 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);
|
||||
ts = ns_to_timespec64((newtime - WLTIMEDELTA) * 100);
|
||||
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);
|
||||
|
||||
cur_reftime = hyperv_cs->read(hyperv_cs);
|
||||
cur_reftime = hv_read_reference_counter();
|
||||
host_ts.host_time = hosttime;
|
||||
host_ts.ref_time = cur_reftime;
|
||||
|
||||
|
@ -315,7 +315,7 @@ static void timesync_onchannelcallback(void *context)
|
|||
sizeof(struct vmbuspipe_hdr) +
|
||||
sizeof(struct icmsg_hdr)];
|
||||
adj_guesttime(timedatap->parenttime,
|
||||
hyperv_cs->read(hyperv_cs),
|
||||
hv_read_reference_counter(),
|
||||
timedatap->flags);
|
||||
}
|
||||
}
|
||||
|
@ -524,7 +524,7 @@ static struct ptp_clock *hv_ptp_clock;
|
|||
static int hv_timesync_init(struct hv_util_service *srv)
|
||||
{
|
||||
/* TimeSync requires Hyper-V clocksource. */
|
||||
if (!hyperv_cs)
|
||||
if (!hv_read_reference_counter)
|
||||
return -ENODEV;
|
||||
|
||||
spin_lock_init(&host_ts.lock);
|
||||
|
|
|
@ -30,7 +30,7 @@ extern void hv_stimer_global_cleanup(void);
|
|||
extern void hv_stimer0_isr(void);
|
||||
|
||||
#ifdef CONFIG_HYPERV_TIMER
|
||||
extern struct clocksource *hyperv_cs;
|
||||
extern u64 (*hv_read_reference_counter)(void);
|
||||
extern void hv_init_clocksource(void);
|
||||
|
||||
extern struct ms_hyperv_tsc_page *hv_get_tsc_page(void);
|
||||
|
|
Loading…
Reference in New Issue