diff options
Diffstat (limited to 'drivers/clocksource')
58 files changed, 2405 insertions, 1079 deletions
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 487c85259967..d1a33a231a44 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -73,6 +73,14 @@ config DW_APB_TIMER_OF select DW_APB_TIMER select TIMER_OF +config ECONET_EN751221_TIMER + bool "EcoNet EN751221 High Precision Timer" if COMPILE_TEST + depends on HAS_IOMEM + select CLKSRC_MMIO + select TIMER_OF + help + Support for CPU timer found on EcoNet MIPS based SoCs. + config FTTMR010_TIMER bool "Faraday Technology timer driver" if COMPILE_TEST depends on HAS_IOMEM @@ -246,6 +254,7 @@ config KEYSTONE_TIMER config INTEGRATOR_AP_TIMER bool "Integrator-AP timer driver" if COMPILE_TEST + depends on OF select CLKSRC_MMIO help Enables support for the Integrator-AP timer. @@ -387,8 +396,7 @@ config ARM_GLOBAL_TIMER config ARM_GT_INITIAL_PRESCALER_VAL int "ARM global timer initial prescaler value" - default 2 if ARCH_ZYNQ - default 1 + default 0 depends on ARM_GLOBAL_TIMER help When the ARM global timer initializes, its current rate is declared @@ -398,6 +406,7 @@ config ARM_GT_INITIAL_PRESCALER_VAL bounds about how much the parent clock is allowed to decrease or increase wrt the initial clock value. This affects CPU_FREQ max delta from the initial frequency. + Use 0 to use auto-detection in the driver. config ARM_TIMER_SP804 bool "Support for Dual Timer SP804 module" @@ -437,8 +446,8 @@ config ATMEL_ST config ATMEL_TCB_CLKSRC bool "Atmel TC Block timer driver" if COMPILE_TEST - depends on ARM && HAS_IOMEM - select TIMER_OF if OF + depends on ARM && OF && HAS_IOMEM + select TIMER_OF help Support for Timer Counter Blocks on Atmel SoCs. @@ -466,11 +475,14 @@ config FSL_FTM_TIMER help Support for Freescale FlexTimer Module (FTM) timer. -config VF_PIT_TIMER - bool +config NXP_PIT_TIMER + bool "NXP Periodic Interrupt Timer" if COMPILE_TEST select CLKSRC_MMIO help - Support for Periodic Interrupt Timer on Freescale Vybrid Family SoCs. + Support for Periodic Interrupt Timer on Freescale / NXP + SoCs. This periodic timer is found on the Vybrid Family and + the Automotive S32G2/3 platforms. It contains 4 channels + where two can be coupled to form a 64 bits channel. config SYS_SUPPORTS_SH_CMT bool @@ -584,7 +596,6 @@ config CLKSRC_VERSATILE config CLKSRC_MIPS_GIC bool depends on MIPS_GIC - select CLOCKSOURCE_WATCHDOG select TIMER_OF config CLKSRC_PXA @@ -763,4 +774,23 @@ config RALINK_TIMER Enables support for system tick counter present on Ralink SoCs RT3352 and MT7620. +config NXP_STM_TIMER + bool "NXP System Timer Module driver" + depends on ARCH_S32 || COMPILE_TEST + select CLKSRC_MMIO + help + Enables the support for NXP System Timer Module found in the + s32g NXP platform series. + +config RTK_SYSTIMER + bool "Realtek SYSTIMER support" + depends on ARM || ARM64 + depends on ARCH_REALTEK || COMPILE_TEST + select TIMER_OF + help + This option enables the driver that registers the global 1 MHz hardware + counter as a clock event device on Realtek SoCs. Make sure to enable + this option only when building for a Realtek platform or for compilation + testing. + endmenu diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 43ef16a4efa6..b46376af6b49 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_CLKBLD_I8253) += i8253.o obj-$(CONFIG_CLKSRC_MMIO) += mmio.o obj-$(CONFIG_DAVINCI_TIMER) += timer-davinci.o obj-$(CONFIG_DIGICOLOR_TIMER) += timer-digicolor.o +obj-$(CONFIG_ECONET_EN751221_TIMER) += timer-econet-en751221.o obj-$(CONFIG_OMAP_DM_TIMER) += timer-ti-dm.o obj-$(CONFIG_OMAP_DM_SYSTIMER) += timer-ti-dm-systimer.o obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o @@ -48,7 +49,7 @@ obj-$(CONFIG_CLKSRC_LPC32XX) += timer-lpc32xx.o obj-$(CONFIG_CLKSRC_MPS2) += mps2-timer.o obj-$(CONFIG_CLKSRC_SAMSUNG_PWM) += samsung_pwm_timer.o obj-$(CONFIG_FSL_FTM_TIMER) += timer-fsl-ftm.o -obj-$(CONFIG_VF_PIT_TIMER) += timer-vf-pit.o +obj-$(CONFIG_NXP_PIT_TIMER) += timer-nxp-pit.o obj-$(CONFIG_CLKSRC_QCOM) += timer-qcom.o obj-$(CONFIG_MTK_TIMER) += timer-mediatek.o obj-$(CONFIG_MTK_CPUX_TIMER) += timer-mediatek-cpux.o @@ -63,6 +64,7 @@ obj-$(CONFIG_REALTEK_OTTO_TIMER) += timer-rtl-otto.o obj-$(CONFIG_ARC_TIMERS) += arc_timer.o obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o +obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer_mmio.o obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o obj-$(CONFIG_ARMV7M_SYSTICK) += armv7m_systick.o obj-$(CONFIG_ARM_TIMER_SP804) += timer-sp804.o @@ -92,3 +94,5 @@ obj-$(CONFIG_GXP_TIMER) += timer-gxp.o obj-$(CONFIG_CLKSRC_LOONGSON1_PWM) += timer-loongson1-pwm.o obj-$(CONFIG_EP93XX_TIMER) += timer-ep93xx.o obj-$(CONFIG_RALINK_TIMER) += timer-ralink.o +obj-$(CONFIG_NXP_STM_TIMER) += timer-nxp-stm.o +obj-$(CONFIG_RTK_SYSTIMER) += timer-realtek.o diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c index b4330a01a566..67792937242f 100644 --- a/drivers/clocksource/acpi_pm.c +++ b/drivers/clocksource/acpi_pm.c @@ -98,7 +98,7 @@ static struct clocksource clocksource_acpi_pm = { .rating = 200, .read = acpi_pm_read, .mask = (u64)ACPI_PM_MASK, - .flags = CLOCK_SOURCE_IS_CONTINUOUS, + .flags = CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_CALIBRATED, .suspend = acpi_pm_suspend, .resume = acpi_pm_resume, }; @@ -243,8 +243,6 @@ static int __init init_acpi_pm_clocksource(void) return -ENODEV; } - if (tsc_clocksource_watchdog_disabled()) - clocksource_acpi_pm.flags |= CLOCK_SOURCE_MUST_VERIFY; return clocksource_register_hz(&clocksource_acpi_pm, PMTMR_TICKS_PER_SEC); } diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 808f259781fd..90aeff44a276 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -34,42 +34,12 @@ #include <clocksource/arm_arch_timer.h> -#define CNTTIDR 0x08 -#define CNTTIDR_VIRT(n) (BIT(1) << ((n) * 4)) - -#define CNTACR(n) (0x40 + ((n) * 4)) -#define CNTACR_RPCT BIT(0) -#define CNTACR_RVCT BIT(1) -#define CNTACR_RFRQ BIT(2) -#define CNTACR_RVOFF BIT(3) -#define CNTACR_RWVT BIT(4) -#define CNTACR_RWPT BIT(5) - -#define CNTPCT_LO 0x00 -#define CNTVCT_LO 0x08 -#define CNTFRQ 0x10 -#define CNTP_CVAL_LO 0x20 -#define CNTP_CTL 0x2c -#define CNTV_CVAL_LO 0x30 -#define CNTV_CTL 0x3c - /* * The minimum amount of time a generic counter is guaranteed to not roll over * (40 years) */ #define MIN_ROLLOVER_SECS (40ULL * 365 * 24 * 3600) -static unsigned arch_timers_present __initdata; - -struct arch_timer { - void __iomem *base; - struct clock_event_device evt; -}; - -static struct arch_timer *arch_timer_mem __ro_after_init; - -#define to_arch_timer(e) container_of(e, struct arch_timer, evt) - static u32 arch_timer_rate __ro_after_init; static int arch_timer_ppi[ARCH_TIMER_MAX_TIMER_PPI] __ro_after_init; @@ -85,7 +55,6 @@ static struct clock_event_device __percpu *arch_timer_evt; static enum arch_timer_ppi_nr arch_timer_uses_ppi __ro_after_init = ARCH_TIMER_VIRT_PPI; static bool arch_timer_c3stop __ro_after_init; -static bool arch_timer_mem_use_virtual __ro_after_init; static bool arch_counter_suspend_stop __ro_after_init; #ifdef CONFIG_GENERIC_GETTIMEOFDAY static enum vdso_clock_mode vdso_default = VDSO_CLOCKMODE_ARCHTIMER; @@ -121,76 +90,6 @@ static int arch_counter_get_width(void) /* * Architected system timer support. */ - -static __always_inline -void arch_timer_reg_write(int access, enum arch_timer_reg reg, u64 val, - struct clock_event_device *clk) -{ - if (access == ARCH_TIMER_MEM_PHYS_ACCESS) { - struct arch_timer *timer = to_arch_timer(clk); - switch (reg) { - case ARCH_TIMER_REG_CTRL: - writel_relaxed((u32)val, timer->base + CNTP_CTL); - break; - case ARCH_TIMER_REG_CVAL: - /* - * Not guaranteed to be atomic, so the timer - * must be disabled at this point. - */ - writeq_relaxed(val, timer->base + CNTP_CVAL_LO); - break; - default: - BUILD_BUG(); - } - } else if (access == ARCH_TIMER_MEM_VIRT_ACCESS) { - struct arch_timer *timer = to_arch_timer(clk); - switch (reg) { - case ARCH_TIMER_REG_CTRL: - writel_relaxed((u32)val, timer->base + CNTV_CTL); - break; - case ARCH_TIMER_REG_CVAL: - /* Same restriction as above */ - writeq_relaxed(val, timer->base + CNTV_CVAL_LO); - break; - default: - BUILD_BUG(); - } - } else { - arch_timer_reg_write_cp15(access, reg, val); - } -} - -static __always_inline -u32 arch_timer_reg_read(int access, enum arch_timer_reg reg, - struct clock_event_device *clk) -{ - u32 val; - - if (access == ARCH_TIMER_MEM_PHYS_ACCESS) { - struct arch_timer *timer = to_arch_timer(clk); - switch (reg) { - case ARCH_TIMER_REG_CTRL: - val = readl_relaxed(timer->base + CNTP_CTL); - break; - default: - BUILD_BUG(); - } - } else if (access == ARCH_TIMER_MEM_VIRT_ACCESS) { - struct arch_timer *timer = to_arch_timer(clk); - switch (reg) { - case ARCH_TIMER_REG_CTRL: - val = readl_relaxed(timer->base + CNTV_CTL); - break; - default: - BUILD_BUG(); - } - } else { - val = arch_timer_reg_read_cp15(access, reg); - } - - return val; -} - static noinstr u64 raw_counter_get_cntpct_stable(void) { return __arch_counter_get_cntpct_stable(); @@ -243,7 +142,7 @@ static u64 arch_counter_read(struct clocksource *cs) return arch_timer_read_counter(); } -static u64 arch_counter_read_cc(const struct cyclecounter *cc) +static u64 arch_counter_read_cc(struct cyclecounter *cc) { return arch_timer_read_counter(); } @@ -424,7 +323,7 @@ void erratum_set_next_event_generic(const int access, unsigned long evt, unsigned long ctrl; u64 cval; - ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL, clk); + ctrl = arch_timer_reg_read_cp15(access, ARCH_TIMER_REG_CTRL); ctrl |= ARCH_TIMER_CTRL_ENABLE; ctrl &= ~ARCH_TIMER_CTRL_IT_MASK; @@ -436,7 +335,7 @@ void erratum_set_next_event_generic(const int access, unsigned long evt, write_sysreg(cval, cntv_cval_el0); } - arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk); + arch_timer_reg_write_cp15(access, ARCH_TIMER_REG_CTRL, ctrl); } static __maybe_unused int erratum_set_next_event_virt(unsigned long evt, @@ -667,10 +566,10 @@ static __always_inline irqreturn_t timer_handler(const int access, { unsigned long ctrl; - ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL, evt); + ctrl = arch_timer_reg_read_cp15(access, ARCH_TIMER_REG_CTRL); if (ctrl & ARCH_TIMER_CTRL_IT_STAT) { ctrl |= ARCH_TIMER_CTRL_IT_MASK; - arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, evt); + arch_timer_reg_write_cp15(access, ARCH_TIMER_REG_CTRL, ctrl); evt->event_handler(evt); return IRQ_HANDLED; } @@ -692,28 +591,14 @@ static irqreturn_t arch_timer_handler_phys(int irq, void *dev_id) return timer_handler(ARCH_TIMER_PHYS_ACCESS, evt); } -static irqreturn_t arch_timer_handler_phys_mem(int irq, void *dev_id) -{ - struct clock_event_device *evt = dev_id; - - return timer_handler(ARCH_TIMER_MEM_PHYS_ACCESS, evt); -} - -static irqreturn_t arch_timer_handler_virt_mem(int irq, void *dev_id) -{ - struct clock_event_device *evt = dev_id; - - return timer_handler(ARCH_TIMER_MEM_VIRT_ACCESS, evt); -} - static __always_inline int arch_timer_shutdown(const int access, struct clock_event_device *clk) { unsigned long ctrl; - ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL, clk); + ctrl = arch_timer_reg_read_cp15(access, ARCH_TIMER_REG_CTRL); ctrl &= ~ARCH_TIMER_CTRL_ENABLE; - arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk); + arch_timer_reg_write_cp15(access, ARCH_TIMER_REG_CTRL, ctrl); return 0; } @@ -728,23 +613,13 @@ static int arch_timer_shutdown_phys(struct clock_event_device *clk) return arch_timer_shutdown(ARCH_TIMER_PHYS_ACCESS, clk); } -static int arch_timer_shutdown_virt_mem(struct clock_event_device *clk) -{ - return arch_timer_shutdown(ARCH_TIMER_MEM_VIRT_ACCESS, clk); -} - -static int arch_timer_shutdown_phys_mem(struct clock_event_device *clk) -{ - return arch_timer_shutdown(ARCH_TIMER_MEM_PHYS_ACCESS, clk); -} - static __always_inline void set_next_event(const int access, unsigned long evt, struct clock_event_device *clk) { unsigned long ctrl; u64 cnt; - ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL, clk); + ctrl = arch_timer_reg_read_cp15(access, ARCH_TIMER_REG_CTRL); ctrl |= ARCH_TIMER_CTRL_ENABLE; ctrl &= ~ARCH_TIMER_CTRL_IT_MASK; @@ -753,8 +628,8 @@ static __always_inline void set_next_event(const int access, unsigned long evt, else cnt = __arch_counter_get_cntvct(); - arch_timer_reg_write(access, ARCH_TIMER_REG_CVAL, evt + cnt, clk); - arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk); + arch_timer_reg_write_cp15(access, ARCH_TIMER_REG_CVAL, evt + cnt); + arch_timer_reg_write_cp15(access, ARCH_TIMER_REG_CTRL, ctrl); } static int arch_timer_set_next_event_virt(unsigned long evt, @@ -771,60 +646,6 @@ static int arch_timer_set_next_event_phys(unsigned long evt, return 0; } -static noinstr u64 arch_counter_get_cnt_mem(struct arch_timer *t, int offset_lo) -{ - u32 cnt_lo, cnt_hi, tmp_hi; - - do { - cnt_hi = __le32_to_cpu((__le32 __force)__raw_readl(t->base + offset_lo + 4)); - cnt_lo = __le32_to_cpu((__le32 __force)__raw_readl(t->base + offset_lo)); - tmp_hi = __le32_to_cpu((__le32 __force)__raw_readl(t->base + offset_lo + 4)); - } while (cnt_hi != tmp_hi); - - return ((u64) cnt_hi << 32) | cnt_lo; -} - -static __always_inline void set_next_event_mem(const int access, unsigned long evt, - struct clock_event_device *clk) -{ - struct arch_timer *timer = to_arch_timer(clk); - unsigned long ctrl; - u64 cnt; - - ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL, clk); - - /* Timer must be disabled before programming CVAL */ - if (ctrl & ARCH_TIMER_CTRL_ENABLE) { - ctrl &= ~ARCH_TIMER_CTRL_ENABLE; - arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk); - } - - ctrl |= ARCH_TIMER_CTRL_ENABLE; - ctrl &= ~ARCH_TIMER_CTRL_IT_MASK; - - if (access == ARCH_TIMER_MEM_VIRT_ACCESS) - cnt = arch_counter_get_cnt_mem(timer, CNTVCT_LO); - else - cnt = arch_counter_get_cnt_mem(timer, CNTPCT_LO); - - arch_timer_reg_write(access, ARCH_TIMER_REG_CVAL, evt + cnt, clk); - arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk); -} - -static int arch_timer_set_next_event_virt_mem(unsigned long evt, - struct clock_event_device *clk) -{ - set_next_event_mem(ARCH_TIMER_MEM_VIRT_ACCESS, evt, clk); - return 0; -} - -static int arch_timer_set_next_event_phys_mem(unsigned long evt, - struct clock_event_device *clk) -{ - set_next_event_mem(ARCH_TIMER_MEM_PHYS_ACCESS, evt, clk); - return 0; -} - static u64 __arch_timer_check_delta(void) { #ifdef CONFIG_ARM64 @@ -842,7 +663,7 @@ static u64 __arch_timer_check_delta(void) {}, }; - if (is_midr_in_range_list(read_cpuid_id(), broken_cval_midrs)) { + if (is_midr_in_range_list(broken_cval_midrs)) { pr_warn_once("Broken CNTx_CVAL_EL1, using 31 bit TVAL instead.\n"); return CLOCKSOURCE_MASK(31); } @@ -850,63 +671,41 @@ static u64 __arch_timer_check_delta(void) return CLOCKSOURCE_MASK(arch_counter_get_width()); } -static void __arch_timer_setup(unsigned type, - struct clock_event_device *clk) +static void __arch_timer_setup(struct clock_event_device *clk) { + typeof(clk->set_next_event) sne; u64 max_delta; clk->features = CLOCK_EVT_FEAT_ONESHOT; - if (type == ARCH_TIMER_TYPE_CP15) { - typeof(clk->set_next_event) sne; - - arch_timer_check_ool_workaround(ate_match_local_cap_id, NULL); - - if (arch_timer_c3stop) - clk->features |= CLOCK_EVT_FEAT_C3STOP; - clk->name = "arch_sys_timer"; - clk->rating = 450; - clk->cpumask = cpumask_of(smp_processor_id()); - clk->irq = arch_timer_ppi[arch_timer_uses_ppi]; - switch (arch_timer_uses_ppi) { - case ARCH_TIMER_VIRT_PPI: - clk->set_state_shutdown = arch_timer_shutdown_virt; - clk->set_state_oneshot_stopped = arch_timer_shutdown_virt; - sne = erratum_handler(set_next_event_virt); - break; - case ARCH_TIMER_PHYS_SECURE_PPI: - case ARCH_TIMER_PHYS_NONSECURE_PPI: - case ARCH_TIMER_HYP_PPI: - clk->set_state_shutdown = arch_timer_shutdown_phys; - clk->set_state_oneshot_stopped = arch_timer_shutdown_phys; - sne = erratum_handler(set_next_event_phys); - break; - default: - BUG(); - } + arch_timer_check_ool_workaround(ate_match_local_cap_id, NULL); - clk->set_next_event = sne; - max_delta = __arch_timer_check_delta(); - } else { - clk->features |= CLOCK_EVT_FEAT_DYNIRQ; - clk->name = "arch_mem_timer"; - clk->rating = 400; - clk->cpumask = cpu_possible_mask; - if (arch_timer_mem_use_virtual) { - clk->set_state_shutdown = arch_timer_shutdown_virt_mem; - clk->set_state_oneshot_stopped = arch_timer_shutdown_virt_mem; - clk->set_next_event = - arch_timer_set_next_event_virt_mem; - } else { - clk->set_state_shutdown = arch_timer_shutdown_phys_mem; - clk->set_state_oneshot_stopped = arch_timer_shutdown_phys_mem; - clk->set_next_event = - arch_timer_set_next_event_phys_mem; - } - - max_delta = CLOCKSOURCE_MASK(56); + if (arch_timer_c3stop) + clk->features |= CLOCK_EVT_FEAT_C3STOP; + clk->name = "arch_sys_timer"; + clk->rating = 450; + clk->cpumask = cpumask_of(smp_processor_id()); + clk->irq = arch_timer_ppi[arch_timer_uses_ppi]; + switch (arch_timer_uses_ppi) { + case ARCH_TIMER_VIRT_PPI: + clk->set_state_shutdown = arch_timer_shutdown_virt; + clk->set_state_oneshot_stopped = arch_timer_shutdown_virt; + sne = erratum_handler(set_next_event_virt); + break; + case ARCH_TIMER_PHYS_SECURE_PPI: + case ARCH_TIMER_PHYS_NONSECURE_PPI: + case ARCH_TIMER_HYP_PPI: + clk->set_state_shutdown = arch_timer_shutdown_phys; + clk->set_state_oneshot_stopped = arch_timer_shutdown_phys; + sne = erratum_handler(set_next_event_phys); + break; + default: + BUG(); } + clk->set_next_event = sne; + max_delta = __arch_timer_check_delta(); + clk->set_state_shutdown(clk); clockevents_config_and_register(clk, arch_timer_rate, 0xf, max_delta); @@ -1029,7 +828,7 @@ static int arch_timer_starting_cpu(unsigned int cpu) struct clock_event_device *clk = this_cpu_ptr(arch_timer_evt); u32 flags; - __arch_timer_setup(ARCH_TIMER_TYPE_CP15, clk); + __arch_timer_setup(clk); flags = check_ppi_trigger(arch_timer_ppi[arch_timer_uses_ppi]); enable_percpu_irq(arch_timer_ppi[arch_timer_uses_ppi], flags); @@ -1075,22 +874,12 @@ static void __init arch_timer_of_configure_rate(u32 rate, struct device_node *np pr_warn("frequency not available\n"); } -static void __init arch_timer_banner(unsigned type) +static void __init arch_timer_banner(void) { - pr_info("%s%s%s timer(s) running at %lu.%02luMHz (%s%s%s).\n", - type & ARCH_TIMER_TYPE_CP15 ? "cp15" : "", - type == (ARCH_TIMER_TYPE_CP15 | ARCH_TIMER_TYPE_MEM) ? - " and " : "", - type & ARCH_TIMER_TYPE_MEM ? "mmio" : "", + pr_info("cp15 timer running at %lu.%02luMHz (%s).\n", (unsigned long)arch_timer_rate / 1000000, (unsigned long)(arch_timer_rate / 10000) % 100, - type & ARCH_TIMER_TYPE_CP15 ? - (arch_timer_uses_ppi == ARCH_TIMER_VIRT_PPI) ? "virt" : "phys" : - "", - type == (ARCH_TIMER_TYPE_CP15 | ARCH_TIMER_TYPE_MEM) ? "/" : "", - type & ARCH_TIMER_TYPE_MEM ? - arch_timer_mem_use_virtual ? "virt" : "phys" : - ""); + (arch_timer_uses_ppi == ARCH_TIMER_VIRT_PPI) ? "virt" : "phys"); } u32 arch_timer_get_rate(void) @@ -1108,11 +897,6 @@ bool arch_timer_evtstrm_available(void) return cpumask_test_cpu(raw_smp_processor_id(), &evtstrm_available); } -static noinstr u64 arch_counter_get_cntvct_mem(void) -{ - return arch_counter_get_cnt_mem(arch_timer_mem, CNTVCT_LO); -} - static struct arch_timer_kvm_info arch_timer_kvm_info; struct arch_timer_kvm_info *arch_timer_get_kvm_info(void) @@ -1120,42 +904,35 @@ struct arch_timer_kvm_info *arch_timer_get_kvm_info(void) return &arch_timer_kvm_info; } -static void __init arch_counter_register(unsigned type) +static void __init arch_counter_register(void) { u64 (*scr)(void); + u64 (*rd)(void); u64 start_count; int width; - /* Register the CP15 based counter if we have one */ - if (type & ARCH_TIMER_TYPE_CP15) { - u64 (*rd)(void); - - if ((IS_ENABLED(CONFIG_ARM64) && !is_hyp_mode_available()) || - arch_timer_uses_ppi == ARCH_TIMER_VIRT_PPI) { - if (arch_timer_counter_has_wa()) { - rd = arch_counter_get_cntvct_stable; - scr = raw_counter_get_cntvct_stable; - } else { - rd = arch_counter_get_cntvct; - scr = arch_counter_get_cntvct; - } + if ((IS_ENABLED(CONFIG_ARM64) && !is_hyp_mode_available()) || + arch_timer_uses_ppi == ARCH_TIMER_VIRT_PPI) { + if (arch_timer_counter_has_wa()) { + rd = arch_counter_get_cntvct_stable; + scr = raw_counter_get_cntvct_stable; } else { - if (arch_timer_counter_has_wa()) { - rd = arch_counter_get_cntpct_stable; - scr = raw_counter_get_cntpct_stable; - } else { - rd = arch_counter_get_cntpct; - scr = arch_counter_get_cntpct; - } + rd = arch_counter_get_cntvct; + scr = arch_counter_get_cntvct; } - - arch_timer_read_counter = rd; - clocksource_counter.vdso_clock_mode = vdso_default; } else { - arch_timer_read_counter = arch_counter_get_cntvct_mem; - scr = arch_counter_get_cntvct_mem; + if (arch_timer_counter_has_wa()) { + rd = arch_counter_get_cntpct_stable; + scr = raw_counter_get_cntpct_stable; + } else { + rd = arch_counter_get_cntpct; + scr = arch_counter_get_cntpct; + } } + arch_timer_read_counter = rd; + clocksource_counter.vdso_clock_mode = vdso_default; + width = arch_counter_get_width(); clocksource_counter.mask = CLOCKSOURCE_MASK(width); cyclecounter.mask = CLOCKSOURCE_MASK(width); @@ -1303,76 +1080,10 @@ out: return err; } -static int __init arch_timer_mem_register(void __iomem *base, unsigned int irq) -{ - int ret; - irq_handler_t func; - - arch_timer_mem = kzalloc(sizeof(*arch_timer_mem), GFP_KERNEL); - if (!arch_timer_mem) - return -ENOMEM; - - arch_timer_mem->base = base; - arch_timer_mem->evt.irq = irq; - __arch_timer_setup(ARCH_TIMER_TYPE_MEM, &arch_timer_mem->evt); - - if (arch_timer_mem_use_virtual) - func = arch_timer_handler_virt_mem; - else - func = arch_timer_handler_phys_mem; - - ret = request_irq(irq, func, IRQF_TIMER, "arch_mem_timer", &arch_timer_mem->evt); - if (ret) { - pr_err("Failed to request mem timer irq\n"); - kfree(arch_timer_mem); - arch_timer_mem = NULL; - } - - return ret; -} - -static const struct of_device_id arch_timer_of_match[] __initconst = { - { .compatible = "arm,armv7-timer", }, - { .compatible = "arm,armv8-timer", }, - {}, -}; - -static const struct of_device_id arch_timer_mem_of_match[] __initconst = { - { .compatible = "arm,armv7-timer-mem", }, - {}, -}; - -static bool __init arch_timer_needs_of_probing(void) -{ - struct device_node *dn; - bool needs_probing = false; - unsigned int mask = ARCH_TIMER_TYPE_CP15 | ARCH_TIMER_TYPE_MEM; - - /* We have two timers, and both device-tree nodes are probed. */ - if ((arch_timers_present & mask) == mask) - return false; - - /* - * Only one type of timer is probed, - * check if we have another type of timer node in device-tree. - */ - if (arch_timers_present & ARCH_TIMER_TYPE_CP15) - dn = of_find_matching_node(NULL, arch_timer_mem_of_match); - else - dn = of_find_matching_node(NULL, arch_timer_of_match); - - if (dn && of_device_is_available(dn)) - needs_probing = true; - - of_node_put(dn); - - return needs_probing; -} - static int __init arch_timer_common_init(void) { - arch_timer_banner(arch_timers_present); - arch_counter_register(arch_timers_present); + arch_timer_banner(); + arch_counter_register(); return arch_timer_arch_init(); } @@ -1421,13 +1132,11 @@ static int __init arch_timer_of_init(struct device_node *np) u32 rate; bool has_names; - if (arch_timers_present & ARCH_TIMER_TYPE_CP15) { + if (arch_timer_evt) { pr_warn("multiple nodes in dt, skipping\n"); return 0; } - arch_timers_present |= ARCH_TIMER_TYPE_CP15; - has_names = of_property_present(np, "interrupt-names"); for (i = ARCH_TIMER_PHYS_SECURE_PPI; i < ARCH_TIMER_MAX_TIMER_PPI; i++) { @@ -1472,283 +1181,22 @@ static int __init arch_timer_of_init(struct device_node *np) if (ret) return ret; - if (arch_timer_needs_of_probing()) - return 0; - return arch_timer_common_init(); } TIMER_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_of_init); TIMER_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_of_init); -static u32 __init -arch_timer_mem_frame_get_cntfrq(struct arch_timer_mem_frame *frame) -{ - void __iomem *base; - u32 rate; - - base = ioremap(frame->cntbase, frame->size); - if (!base) { - pr_err("Unable to map frame @ %pa\n", &frame->cntbase); - return 0; - } - - rate = readl_relaxed(base + CNTFRQ); - - iounmap(base); - - return rate; -} - -static struct arch_timer_mem_frame * __init -arch_timer_mem_find_best_frame(struct arch_timer_mem *timer_mem) -{ - struct arch_timer_mem_frame *frame, *best_frame = NULL; - void __iomem *cntctlbase; - u32 cnttidr; - int i; - - cntctlbase = ioremap(timer_mem->cntctlbase, timer_mem->size); - if (!cntctlbase) { - pr_err("Can't map CNTCTLBase @ %pa\n", - &timer_mem->cntctlbase); - return NULL; - } - - cnttidr = readl_relaxed(cntctlbase + CNTTIDR); - - /* - * Try to find a virtual capable frame. Otherwise fall back to a - * physical capable frame. - */ - for (i = 0; i < ARCH_TIMER_MEM_MAX_FRAMES; i++) { - u32 cntacr = CNTACR_RFRQ | CNTACR_RWPT | CNTACR_RPCT | - CNTACR_RWVT | CNTACR_RVOFF | CNTACR_RVCT; - - frame = &timer_mem->frame[i]; - if (!frame->valid) - continue; - - /* Try enabling everything, and see what sticks */ - writel_relaxed(cntacr, cntctlbase + CNTACR(i)); - cntacr = readl_relaxed(cntctlbase + CNTACR(i)); - - if ((cnttidr & CNTTIDR_VIRT(i)) && - !(~cntacr & (CNTACR_RWVT | CNTACR_RVCT))) { - best_frame = frame; - arch_timer_mem_use_virtual = true; - break; - } - - if (~cntacr & (CNTACR_RWPT | CNTACR_RPCT)) - continue; - - best_frame = frame; - } - - iounmap(cntctlbase); - - return best_frame; -} - -static int __init -arch_timer_mem_frame_register(struct arch_timer_mem_frame *frame) -{ - void __iomem *base; - int ret, irq; - - if (arch_timer_mem_use_virtual) - irq = frame->virt_irq; - else - irq = frame->phys_irq; - - if (!irq) { - pr_err("Frame missing %s irq.\n", - arch_timer_mem_use_virtual ? "virt" : "phys"); - return -EINVAL; - } - - if (!request_mem_region(frame->cntbase, frame->size, - "arch_mem_timer")) - return -EBUSY; - - base = ioremap(frame->cntbase, frame->size); - if (!base) { - pr_err("Can't map frame's registers\n"); - return -ENXIO; - } - - ret = arch_timer_mem_register(base, irq); - if (ret) { - iounmap(base); - return ret; - } - - arch_timers_present |= ARCH_TIMER_TYPE_MEM; - - return 0; -} - -static int __init arch_timer_mem_of_init(struct device_node *np) -{ - struct arch_timer_mem *timer_mem; - struct arch_timer_mem_frame *frame; - struct resource res; - int ret = -EINVAL; - u32 rate; - - timer_mem = kzalloc(sizeof(*timer_mem), GFP_KERNEL); - if (!timer_mem) - return -ENOMEM; - - if (of_address_to_resource(np, 0, &res)) - goto out; - timer_mem->cntctlbase = res.start; - timer_mem->size = resource_size(&res); - - for_each_available_child_of_node_scoped(np, frame_node) { - u32 n; - struct arch_timer_mem_frame *frame; - - if (of_property_read_u32(frame_node, "frame-number", &n)) { - pr_err(FW_BUG "Missing frame-number.\n"); - goto out; - } - if (n >= ARCH_TIMER_MEM_MAX_FRAMES) { - pr_err(FW_BUG "Wrong frame-number, only 0-%u are permitted.\n", - ARCH_TIMER_MEM_MAX_FRAMES - 1); - goto out; - } - frame = &timer_mem->frame[n]; - - if (frame->valid) { - pr_err(FW_BUG "Duplicated frame-number.\n"); - goto out; - } - - if (of_address_to_resource(frame_node, 0, &res)) - goto out; - - frame->cntbase = res.start; - frame->size = resource_size(&res); - - frame->virt_irq = irq_of_parse_and_map(frame_node, - ARCH_TIMER_VIRT_SPI); - frame->phys_irq = irq_of_parse_and_map(frame_node, - ARCH_TIMER_PHYS_SPI); - - frame->valid = true; - } - - frame = arch_timer_mem_find_best_frame(timer_mem); - if (!frame) { - pr_err("Unable to find a suitable frame in timer @ %pa\n", - &timer_mem->cntctlbase); - ret = -EINVAL; - goto out; - } - - rate = arch_timer_mem_frame_get_cntfrq(frame); - arch_timer_of_configure_rate(rate, np); - - ret = arch_timer_mem_frame_register(frame); - if (!ret && !arch_timer_needs_of_probing()) - ret = arch_timer_common_init(); -out: - kfree(timer_mem); - return ret; -} -TIMER_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem", - arch_timer_mem_of_init); - #ifdef CONFIG_ACPI_GTDT -static int __init -arch_timer_mem_verify_cntfrq(struct arch_timer_mem *timer_mem) -{ - struct arch_timer_mem_frame *frame; - u32 rate; - int i; - - for (i = 0; i < ARCH_TIMER_MEM_MAX_FRAMES; i++) { - frame = &timer_mem->frame[i]; - - if (!frame->valid) - continue; - - rate = arch_timer_mem_frame_get_cntfrq(frame); - if (rate == arch_timer_rate) - continue; - - pr_err(FW_BUG "CNTFRQ mismatch: frame @ %pa: (0x%08lx), CPU: (0x%08lx)\n", - &frame->cntbase, - (unsigned long)rate, (unsigned long)arch_timer_rate); - - return -EINVAL; - } - - return 0; -} - -static int __init arch_timer_mem_acpi_init(int platform_timer_count) -{ - struct arch_timer_mem *timers, *timer; - struct arch_timer_mem_frame *frame, *best_frame = NULL; - int timer_count, i, ret = 0; - - timers = kcalloc(platform_timer_count, sizeof(*timers), - GFP_KERNEL); - if (!timers) - return -ENOMEM; - - ret = acpi_arch_timer_mem_init(timers, &timer_count); - if (ret || !timer_count) - goto out; - - /* - * While unlikely, it's theoretically possible that none of the frames - * in a timer expose the combination of feature we want. - */ - for (i = 0; i < timer_count; i++) { - timer = &timers[i]; - - frame = arch_timer_mem_find_best_frame(timer); - if (!best_frame) - best_frame = frame; - - ret = arch_timer_mem_verify_cntfrq(timer); - if (ret) { - pr_err("Disabling MMIO timers due to CNTFRQ mismatch\n"); - goto out; - } - - if (!best_frame) /* implies !frame */ - /* - * Only complain about missing suitable frames if we - * haven't already found one in a previous iteration. - */ - pr_err("Unable to find a suitable frame in timer @ %pa\n", - &timer->cntctlbase); - } - - if (best_frame) - ret = arch_timer_mem_frame_register(best_frame); -out: - kfree(timers); - return ret; -} - -/* Initialize per-processor generic timer and memory-mapped timer(if present) */ static int __init arch_timer_acpi_init(struct acpi_table_header *table) { - int ret, platform_timer_count; + int ret; - if (arch_timers_present & ARCH_TIMER_TYPE_CP15) { + if (arch_timer_evt) { pr_warn("already initialized, skipping\n"); return -EINVAL; } - arch_timers_present |= ARCH_TIMER_TYPE_CP15; - - ret = acpi_gtdt_init(table, &platform_timer_count); + ret = acpi_gtdt_init(table, NULL); if (ret) return ret; @@ -1790,10 +1238,6 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table) if (ret) return ret; - if (platform_timer_count && - arch_timer_mem_acpi_init(platform_timer_count)) - pr_err("Failed to initialize memory-mapped timer.\n"); - return arch_timer_common_init(); } TIMER_ACPI_DECLARE(arch_timer, ACPI_SIG_GTDT, arch_timer_acpi_init); diff --git a/drivers/clocksource/arm_arch_timer_mmio.c b/drivers/clocksource/arm_arch_timer_mmio.c new file mode 100644 index 000000000000..d10362692fdd --- /dev/null +++ b/drivers/clocksource/arm_arch_timer_mmio.c @@ -0,0 +1,442 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ARM Generic Memory Mapped Timer support + * + * Split from drivers/clocksource/arm_arch_timer.c + * + * Copyright (C) 2011 ARM Ltd. + * All Rights Reserved + */ + +#define pr_fmt(fmt) "arch_timer_mmio: " fmt + +#include <linux/clockchips.h> +#include <linux/interrupt.h> +#include <linux/io-64-nonatomic-lo-hi.h> +#include <linux/of_irq.h> +#include <linux/of_address.h> +#include <linux/platform_device.h> + +#include <clocksource/arm_arch_timer.h> + +#define CNTTIDR 0x08 +#define CNTTIDR_VIRT(n) (BIT(1) << ((n) * 4)) + +#define CNTACR(n) (0x40 + ((n) * 4)) +#define CNTACR_RPCT BIT(0) +#define CNTACR_RVCT BIT(1) +#define CNTACR_RFRQ BIT(2) +#define CNTACR_RVOFF BIT(3) +#define CNTACR_RWVT BIT(4) +#define CNTACR_RWPT BIT(5) + +#define CNTPCT_LO 0x00 +#define CNTVCT_LO 0x08 +#define CNTFRQ 0x10 +#define CNTP_CVAL_LO 0x20 +#define CNTP_CTL 0x2c +#define CNTV_CVAL_LO 0x30 +#define CNTV_CTL 0x3c + +enum arch_timer_access { + PHYS_ACCESS, + VIRT_ACCESS, +}; + +struct arch_timer { + struct clock_event_device evt; + struct clocksource cs; + struct arch_timer_mem *gt_block; + void __iomem *base; + enum arch_timer_access access; + u32 rate; +}; + +#define evt_to_arch_timer(e) container_of(e, struct arch_timer, evt) +#define cs_to_arch_timer(c) container_of(c, struct arch_timer, cs) + +static void arch_timer_mmio_write(struct arch_timer *timer, + enum arch_timer_reg reg, u64 val) +{ + switch (timer->access) { + case PHYS_ACCESS: + switch (reg) { + case ARCH_TIMER_REG_CTRL: + writel_relaxed((u32)val, timer->base + CNTP_CTL); + return; + case ARCH_TIMER_REG_CVAL: + /* + * Not guaranteed to be atomic, so the timer + * must be disabled at this point. + */ + writeq_relaxed(val, timer->base + CNTP_CVAL_LO); + return; + } + break; + case VIRT_ACCESS: + switch (reg) { + case ARCH_TIMER_REG_CTRL: + writel_relaxed((u32)val, timer->base + CNTV_CTL); + return; + case ARCH_TIMER_REG_CVAL: + /* Same restriction as above */ + writeq_relaxed(val, timer->base + CNTV_CVAL_LO); + return; + } + break; + } + + /* Should never be here */ + WARN_ON_ONCE(1); +} + +static u32 arch_timer_mmio_read(struct arch_timer *timer, enum arch_timer_reg reg) +{ + switch (timer->access) { + case PHYS_ACCESS: + switch (reg) { + case ARCH_TIMER_REG_CTRL: + return readl_relaxed(timer->base + CNTP_CTL); + default: + break; + } + break; + case VIRT_ACCESS: + switch (reg) { + case ARCH_TIMER_REG_CTRL: + return readl_relaxed(timer->base + CNTV_CTL); + default: + break; + } + break; + } + + /* Should never be here */ + WARN_ON_ONCE(1); + return 0; +} + +static noinstr u64 arch_counter_mmio_get_cnt(struct arch_timer *t) +{ + int offset_lo = t->access == VIRT_ACCESS ? CNTVCT_LO : CNTPCT_LO; + u32 cnt_lo, cnt_hi, tmp_hi; + + do { + cnt_hi = __le32_to_cpu((__le32 __force)__raw_readl(t->base + offset_lo + 4)); + cnt_lo = __le32_to_cpu((__le32 __force)__raw_readl(t->base + offset_lo)); + tmp_hi = __le32_to_cpu((__le32 __force)__raw_readl(t->base + offset_lo + 4)); + } while (cnt_hi != tmp_hi); + + return ((u64) cnt_hi << 32) | cnt_lo; +} + +static u64 arch_mmio_counter_read(struct clocksource *cs) +{ + struct arch_timer *at = cs_to_arch_timer(cs); + + return arch_counter_mmio_get_cnt(at); +} + +static int arch_timer_mmio_shutdown(struct clock_event_device *clk) +{ + struct arch_timer *at = evt_to_arch_timer(clk); + unsigned long ctrl; + + ctrl = arch_timer_mmio_read(at, ARCH_TIMER_REG_CTRL); + ctrl &= ~ARCH_TIMER_CTRL_ENABLE; + arch_timer_mmio_write(at, ARCH_TIMER_REG_CTRL, ctrl); + + return 0; +} + +static int arch_timer_mmio_set_next_event(unsigned long evt, + struct clock_event_device *clk) +{ + struct arch_timer *timer = evt_to_arch_timer(clk); + unsigned long ctrl; + u64 cnt; + + ctrl = arch_timer_mmio_read(timer, ARCH_TIMER_REG_CTRL); + + /* Timer must be disabled before programming CVAL */ + if (ctrl & ARCH_TIMER_CTRL_ENABLE) { + ctrl &= ~ARCH_TIMER_CTRL_ENABLE; + arch_timer_mmio_write(timer, ARCH_TIMER_REG_CTRL, ctrl); + } + + ctrl |= ARCH_TIMER_CTRL_ENABLE; + ctrl &= ~ARCH_TIMER_CTRL_IT_MASK; + + cnt = arch_counter_mmio_get_cnt(timer); + + arch_timer_mmio_write(timer, ARCH_TIMER_REG_CVAL, evt + cnt); + arch_timer_mmio_write(timer, ARCH_TIMER_REG_CTRL, ctrl); + return 0; +} + +static irqreturn_t arch_timer_mmio_handler(int irq, void *dev_id) +{ + struct clock_event_device *evt = dev_id; + struct arch_timer *at = evt_to_arch_timer(evt); + unsigned long ctrl; + + ctrl = arch_timer_mmio_read(at, ARCH_TIMER_REG_CTRL); + if (ctrl & ARCH_TIMER_CTRL_IT_STAT) { + ctrl |= ARCH_TIMER_CTRL_IT_MASK; + arch_timer_mmio_write(at, ARCH_TIMER_REG_CTRL, ctrl); + evt->event_handler(evt); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static struct arch_timer_mem_frame *find_best_frame(struct platform_device *pdev) +{ + struct arch_timer_mem_frame *frame, *best_frame = NULL; + struct arch_timer *at = platform_get_drvdata(pdev); + void __iomem *cntctlbase; + u32 cnttidr; + + cntctlbase = ioremap(at->gt_block->cntctlbase, at->gt_block->size); + if (!cntctlbase) { + dev_err(&pdev->dev, "Can't map CNTCTLBase @ %pa\n", + &at->gt_block->cntctlbase); + return NULL; + } + + cnttidr = readl_relaxed(cntctlbase + CNTTIDR); + + /* + * Try to find a virtual capable frame. Otherwise fall back to a + * physical capable frame. + */ + for (int i = 0; i < ARCH_TIMER_MEM_MAX_FRAMES; i++) { + u32 cntacr = CNTACR_RFRQ | CNTACR_RWPT | CNTACR_RPCT | + CNTACR_RWVT | CNTACR_RVOFF | CNTACR_RVCT; + + frame = &at->gt_block->frame[i]; + if (!frame->valid) + continue; + + /* Try enabling everything, and see what sticks */ + writel_relaxed(cntacr, cntctlbase + CNTACR(i)); + cntacr = readl_relaxed(cntctlbase + CNTACR(i)); + + /* Pick a suitable frame for which we have an IRQ */ + if ((cnttidr & CNTTIDR_VIRT(i)) && + !(~cntacr & (CNTACR_RWVT | CNTACR_RVCT)) && + frame->virt_irq) { + best_frame = frame; + at->access = VIRT_ACCESS; + break; + } + + if ((~cntacr & (CNTACR_RWPT | CNTACR_RPCT)) || + !frame->phys_irq) + continue; + + at->access = PHYS_ACCESS; + best_frame = frame; + } + + iounmap(cntctlbase); + + return best_frame; +} + +static void arch_timer_mmio_setup(struct arch_timer *at, int irq) +{ + at->evt = (struct clock_event_device) { + .features = (CLOCK_EVT_FEAT_ONESHOT | + CLOCK_EVT_FEAT_DYNIRQ), + .name = "arch_mem_timer", + .rating = 400, + .cpumask = cpu_possible_mask, + .irq = irq, + .set_next_event = arch_timer_mmio_set_next_event, + .set_state_oneshot_stopped = arch_timer_mmio_shutdown, + .set_state_shutdown = arch_timer_mmio_shutdown, + }; + + at->evt.set_state_shutdown(&at->evt); + + clockevents_config_and_register(&at->evt, at->rate, 0xf, + (unsigned long)CLOCKSOURCE_MASK(56)); + + enable_irq(at->evt.irq); + + at->cs = (struct clocksource) { + .name = "arch_mmio_counter", + .rating = 300, + .read = arch_mmio_counter_read, + .mask = CLOCKSOURCE_MASK(56), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, + }; + + clocksource_register_hz(&at->cs, at->rate); +} + +static int arch_timer_mmio_frame_register(struct platform_device *pdev, + struct arch_timer_mem_frame *frame) +{ + struct arch_timer *at = platform_get_drvdata(pdev); + struct device_node *np = pdev->dev.of_node; + int ret, irq; + u32 rate; + + if (!devm_request_mem_region(&pdev->dev, frame->cntbase, frame->size, + "arch_mem_timer")) + return -EBUSY; + + at->base = devm_ioremap(&pdev->dev, frame->cntbase, frame->size); + if (!at->base) { + dev_err(&pdev->dev, "Can't map frame's registers\n"); + return -ENXIO; + } + + /* + * Allow "clock-frequency" to override the probed rate. If neither + * lead to something useful, use the CPU timer frequency as the + * fallback. The nice thing about that last point is that we woudn't + * made it here if we didn't have a valid frequency. + */ + rate = readl_relaxed(at->base + CNTFRQ); + + if (!np || of_property_read_u32(np, "clock-frequency", &at->rate)) + at->rate = rate; + + if (!at->rate) + at->rate = arch_timer_get_rate(); + + irq = at->access == VIRT_ACCESS ? frame->virt_irq : frame->phys_irq; + ret = devm_request_irq(&pdev->dev, irq, arch_timer_mmio_handler, + IRQF_TIMER | IRQF_NO_AUTOEN, "arch_mem_timer", + &at->evt); + if (ret) { + dev_err(&pdev->dev, "Failed to request mem timer irq\n"); + return ret; + } + + /* Afer this point, we're not allowed to fail anymore */ + arch_timer_mmio_setup(at, irq); + return 0; +} + +static int of_populate_gt_block(struct platform_device *pdev, + struct arch_timer *at) +{ + struct resource res; + + if (of_address_to_resource(pdev->dev.of_node, 0, &res)) + return -EINVAL; + + at->gt_block->cntctlbase = res.start; + at->gt_block->size = resource_size(&res); + + for_each_available_child_of_node_scoped(pdev->dev.of_node, frame_node) { + struct arch_timer_mem_frame *frame; + u32 n; + + if (of_property_read_u32(frame_node, "frame-number", &n)) { + dev_err(&pdev->dev, FW_BUG "Missing frame-number\n"); + return -EINVAL; + } + if (n >= ARCH_TIMER_MEM_MAX_FRAMES) { + dev_err(&pdev->dev, + FW_BUG "Wrong frame-number, only 0-%u are permitted\n", + ARCH_TIMER_MEM_MAX_FRAMES - 1); + return -EINVAL; + } + + frame = &at->gt_block->frame[n]; + + if (frame->valid) { + dev_err(&pdev->dev, FW_BUG "Duplicated frame-number\n"); + return -EINVAL; + } + + if (of_address_to_resource(frame_node, 0, &res)) + return -EINVAL; + + frame->cntbase = res.start; + frame->size = resource_size(&res); + + frame->phys_irq = irq_of_parse_and_map(frame_node, 0); + frame->virt_irq = irq_of_parse_and_map(frame_node, 1); + + frame->valid = true; + } + + return 0; +} + +static int arch_timer_mmio_probe(struct platform_device *pdev) +{ + struct arch_timer_mem_frame *frame; + struct arch_timer *at; + struct device_node *np; + int ret; + + np = pdev->dev.of_node; + + at = devm_kmalloc(&pdev->dev, sizeof(*at), GFP_KERNEL | __GFP_ZERO); + if (!at) + return -ENOMEM; + + if (np) { + at->gt_block = devm_kmalloc(&pdev->dev, sizeof(*at->gt_block), + GFP_KERNEL | __GFP_ZERO); + if (!at->gt_block) + return -ENOMEM; + ret = of_populate_gt_block(pdev, at); + if (ret) + return ret; + } else { + at->gt_block = dev_get_platdata(&pdev->dev); + } + + platform_set_drvdata(pdev, at); + + frame = find_best_frame(pdev); + if (!frame) { + dev_err(&pdev->dev, + "Unable to find a suitable frame in timer @ %pa\n", + &at->gt_block->cntctlbase); + return -EINVAL; + } + + ret = arch_timer_mmio_frame_register(pdev, frame); + if (!ret) + dev_info(&pdev->dev, + "mmio timer running at %lu.%02luMHz (%s)\n", + (unsigned long)at->rate / 1000000, + (unsigned long)(at->rate / 10000) % 100, + at->access == VIRT_ACCESS ? "virt" : "phys"); + + return ret; +} + +static const struct of_device_id arch_timer_mmio_of_table[] = { + { .compatible = "arm,armv7-timer-mem", }, + {} +}; + +static struct platform_driver arch_timer_mmio_drv = { + .driver = { + .name = "arch-timer-mmio", + .of_match_table = arch_timer_mmio_of_table, + .suppress_bind_attrs = true, + }, + .probe = arch_timer_mmio_probe, +}; +builtin_platform_driver(arch_timer_mmio_drv); + +static struct platform_driver arch_timer_mmio_acpi_drv = { + .driver = { + .name = "gtdt-arm-mmio-timer", + .suppress_bind_attrs = true, + }, + .probe = arch_timer_mmio_probe, +}; +builtin_platform_driver(arch_timer_mmio_acpi_drv); diff --git a/drivers/clocksource/arm_global_timer.c b/drivers/clocksource/arm_global_timer.c index 2d86bbc2764a..5e3d6bb7e437 100644 --- a/drivers/clocksource/arm_global_timer.c +++ b/drivers/clocksource/arm_global_timer.c @@ -263,14 +263,13 @@ static void __init gt_delay_timer_init(void) register_current_timer_delay(>_delay_timer); } -static int __init gt_clocksource_init(void) +static int __init gt_clocksource_init(unsigned int psv) { writel(0, gt_base + GT_CONTROL); writel(0, gt_base + GT_COUNTER0); writel(0, gt_base + GT_COUNTER1); /* set prescaler and enable timer on all the cores */ - writel(FIELD_PREP(GT_CONTROL_PRESCALER_MASK, - CONFIG_ARM_GT_INITIAL_PRESCALER_VAL - 1) | + writel(FIELD_PREP(GT_CONTROL_PRESCALER_MASK, psv - 1) | GT_CONTROL_TIMER_ENABLE, gt_base + GT_CONTROL); #ifdef CONFIG_CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK @@ -338,11 +337,45 @@ static int gt_clk_rate_change_cb(struct notifier_block *nb, return NOTIFY_DONE; } +struct gt_prescaler_config { + const char *compatible; + unsigned long prescaler; +}; + +static const struct gt_prescaler_config gt_prescaler_configs[] = { + /* + * On am43 the global timer clock is a child of the clock used for CPU + * OPPs, so the initial prescaler has to be compatible with all OPPs + * which are 300, 600, 720, 800 and 1000 with a fixed divider of 2, this + * gives us a GCD of 10. Initial frequency is 1000, so the prescaler is + * 50. + */ + { .compatible = "ti,am43", .prescaler = 50 }, + { .compatible = "xlnx,zynq-7000", .prescaler = 2 }, + { .compatible = NULL } +}; + +static unsigned long gt_get_initial_prescaler_value(struct device_node *np) +{ + const struct gt_prescaler_config *config; + + if (CONFIG_ARM_GT_INITIAL_PRESCALER_VAL != 0) + return CONFIG_ARM_GT_INITIAL_PRESCALER_VAL; + + for (config = gt_prescaler_configs; config->compatible; config++) { + if (of_machine_is_compatible(config->compatible)) + return config->prescaler; + } + + return 1; +} + static int __init global_timer_of_register(struct device_node *np) { struct clk *gt_clk; static unsigned long gt_clk_rate; int err; + unsigned long psv; /* * In A9 r2p0 the comparators for each processor with the global timer @@ -378,8 +411,9 @@ static int __init global_timer_of_register(struct device_node *np) goto out_unmap; } + psv = gt_get_initial_prescaler_value(np); gt_clk_rate = clk_get_rate(gt_clk); - gt_target_rate = gt_clk_rate / CONFIG_ARM_GT_INITIAL_PRESCALER_VAL; + gt_target_rate = gt_clk_rate / psv; gt_clk_rate_change_nb.notifier_call = gt_clk_rate_change_cb; err = clk_notifier_register(gt_clk, >_clk_rate_change_nb); @@ -404,7 +438,7 @@ static int __init global_timer_of_register(struct device_node *np) } /* Register and immediately configure the timer on the boot CPU */ - err = gt_clocksource_init(); + err = gt_clocksource_init(psv); if (err) goto out_irq; diff --git a/drivers/clocksource/bcm2835_timer.c b/drivers/clocksource/bcm2835_timer.c index 319c0c780a15..d7662301bf0e 100644 --- a/drivers/clocksource/bcm2835_timer.c +++ b/drivers/clocksource/bcm2835_timer.c @@ -98,7 +98,7 @@ static int __init bcm2835_timer_init(struct device_node *node) goto err_iounmap; } - timer = kzalloc(sizeof(*timer), GFP_KERNEL); + timer = kzalloc_obj(*timer); if (!timer) { ret = -ENOMEM; goto err_iounmap; diff --git a/drivers/clocksource/clps711x-timer.c b/drivers/clocksource/clps711x-timer.c index e95fdc49c226..bb0a44adaf28 100644 --- a/drivers/clocksource/clps711x-timer.c +++ b/drivers/clocksource/clps711x-timer.c @@ -54,7 +54,7 @@ static int __init _clps711x_clkevt_init(struct clk *clock, void __iomem *base, struct clock_event_device *clkevt; unsigned long rate; - clkevt = kzalloc(sizeof(*clkevt), GFP_KERNEL); + clkevt = kzalloc_obj(*clkevt); if (!clkevt) return -ENOMEM; @@ -78,24 +78,33 @@ static int __init clps711x_timer_init(struct device_node *np) unsigned int irq = irq_of_parse_and_map(np, 0); struct clk *clock = of_clk_get(np, 0); void __iomem *base = of_iomap(np, 0); + int ret = 0; if (!base) return -ENOMEM; - if (!irq) - return -EINVAL; - if (IS_ERR(clock)) - return PTR_ERR(clock); + if (!irq) { + ret = -EINVAL; + goto unmap_io; + } + if (IS_ERR(clock)) { + ret = PTR_ERR(clock); + goto unmap_io; + } switch (of_alias_get_id(np, "timer")) { case CLPS711X_CLKSRC_CLOCKSOURCE: clps711x_clksrc_init(clock, base); break; case CLPS711X_CLKSRC_CLOCKEVENT: - return _clps711x_clkevt_init(clock, base, irq); + ret = _clps711x_clkevt_init(clock, base, irq); + break; default: - return -EINVAL; + ret = -EINVAL; + break; } - return 0; +unmap_io: + iounmap(base); + return ret; } TIMER_OF_DECLARE(clps711x, "cirrus,ep7209-timer", clps711x_timer_init); diff --git a/drivers/clocksource/dw_apb_timer.c b/drivers/clocksource/dw_apb_timer.c index 3a55ae5fe225..501980303ddf 100644 --- a/drivers/clocksource/dw_apb_timer.c +++ b/drivers/clocksource/dw_apb_timer.c @@ -222,8 +222,7 @@ struct dw_apb_clock_event_device * dw_apb_clockevent_init(int cpu, const char *name, unsigned rating, void __iomem *base, int irq, unsigned long freq) { - struct dw_apb_clock_event_device *dw_ced = - kzalloc(sizeof(*dw_ced), GFP_KERNEL); + struct dw_apb_clock_event_device *dw_ced = kzalloc_obj(*dw_ced); int err; if (!dw_ced) @@ -340,7 +339,7 @@ struct dw_apb_clocksource * dw_apb_clocksource_init(unsigned rating, const char *name, void __iomem *base, unsigned long freq) { - struct dw_apb_clocksource *dw_cs = kzalloc(sizeof(*dw_cs), GFP_KERNEL); + struct dw_apb_clocksource *dw_cs = kzalloc_obj(*dw_cs); if (!dw_cs) return NULL; diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c index e6a02e351d77..da09f467a6bb 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c @@ -238,7 +238,7 @@ static cycles_t exynos4_read_current_timer(void) static int __init exynos4_clocksource_init(bool frc_shared) { /* - * When the frc is shared, the main processer should have already + * When the frc is shared, the main processor should have already * turned it on and we shouldn't be writing to TCON. */ if (frc_shared) diff --git a/drivers/clocksource/hyperv_timer.c b/drivers/clocksource/hyperv_timer.c index 99177835cade..e9f5034a1bc8 100644 --- a/drivers/clocksource/hyperv_timer.c +++ b/drivers/clocksource/hyperv_timer.c @@ -22,12 +22,14 @@ #include <linux/irq.h> #include <linux/acpi.h> #include <linux/hyperv.h> +#include <linux/export.h> #include <clocksource/hyperv_timer.h> -#include <asm/hyperv-tlfs.h> +#include <hyperv/hvhdk.h> #include <asm/mshyperv.h> static struct clock_event_device __percpu *hv_clock_event; -static u64 hv_sched_clock_offset __ro_after_init; +/* Note: offset can hold negative values after hibernation. */ +static u64 hv_sched_clock_offset __read_mostly; /* * If false, we're using the old mechanism for stimer0 interrupts @@ -470,6 +472,17 @@ static void resume_hv_clock_tsc(struct clocksource *arg) hv_set_msr(HV_MSR_REFERENCE_TSC, tsc_msr.as_uint64); } +/* + * Called during resume from hibernation, from overridden + * x86_platform.restore_sched_clock_state routine. This is to adjust offsets + * used to calculate time for hv tsc page based sched_clock, to account for + * time spent before hibernation. + */ +void hv_adj_sched_clock_offset(u64 offset) +{ + hv_sched_clock_offset -= offset; +} + #ifdef HAVE_VDSO_CLOCKMODE_HVCLOCK static int hv_cs_enable(struct clocksource *cs) { @@ -522,6 +535,8 @@ static __always_inline void hv_setup_sched_clock(void *sched_clock) sched_clock_register(sched_clock, 64, NSEC_PER_SEC); } #elif defined CONFIG_PARAVIRT +#include <asm/timer.h> + static __always_inline void hv_setup_sched_clock(void *sched_clock) { /* We're on x86/x64 *and* using PV ops */ @@ -536,14 +551,22 @@ static void __init hv_init_tsc_clocksource(void) union hv_reference_tsc_msr tsc_msr; /* + * When running as a guest partition: + * * If Hyper-V offers TSC_INVARIANT, then the virtualized TSC correctly * handles frequency and offset changes due to live migration, * pause/resume, and other VM management operations. So lower the * Hyper-V Reference TSC rating, causing the generic TSC to be used. * TSC_INVARIANT is not offered on ARM64, so the Hyper-V Reference * TSC will be preferred over the virtualized ARM64 arch counter. + * + * When running as the root partition: + * + * There is no HV_ACCESS_TSC_INVARIANT feature. Always lower the rating + * of the Hyper-V Reference TSC. */ - if (ms_hyperv.features & HV_ACCESS_TSC_INVARIANT) { + if ((ms_hyperv.features & HV_ACCESS_TSC_INVARIANT) || + hv_root_partition()) { hyperv_cs_tsc.rating = 250; hyperv_cs_msr.rating = 245; } @@ -570,7 +593,7 @@ static void __init hv_init_tsc_clocksource(void) * mapped. */ tsc_msr.as_uint64 = hv_get_msr(HV_MSR_REFERENCE_TSC); - if (hv_root_partition) + if (hv_root_partition()) tsc_pfn = tsc_msr.pfn; else tsc_pfn = HVPFN_DOWN(virt_to_phys(tsc_page)); @@ -615,7 +638,7 @@ void __init hv_remap_tsc_clocksource(void) if (!(ms_hyperv.features & HV_MSR_REFERENCE_TSC_AVAILABLE)) return; - if (!hv_root_partition) { + if (!hv_root_partition()) { WARN(1, "%s: attempt to remap TSC page in guest partition\n", __func__); return; diff --git a/drivers/clocksource/i8253.c b/drivers/clocksource/i8253.c index 39f7c2d736d1..b603c25f3dfa 100644 --- a/drivers/clocksource/i8253.c +++ b/drivers/clocksource/i8253.c @@ -103,7 +103,7 @@ int __init clocksource_i8253_init(void) #ifdef CONFIG_CLKEVT_I8253 void clockevent_i8253_disable(void) { - raw_spin_lock(&i8253_lock); + guard(raw_spinlock_irqsave)(&i8253_lock); /* * Writing the MODE register should stop the counter, according to @@ -132,8 +132,6 @@ void clockevent_i8253_disable(void) outb_p(0, PIT_CH0); outb_p(0x30, PIT_MODE); - - raw_spin_unlock(&i8253_lock); } static int pit_shutdown(struct clock_event_device *evt) diff --git a/drivers/clocksource/ingenic-sysost.c b/drivers/clocksource/ingenic-sysost.c index cb6fc2f152d4..026615bbe921 100644 --- a/drivers/clocksource/ingenic-sysost.c +++ b/drivers/clocksource/ingenic-sysost.c @@ -127,18 +127,23 @@ static u8 ingenic_ost_get_prescale(unsigned long rate, unsigned long req_rate) return 2; /* /16 divider */ } -static long ingenic_ost_round_rate(struct clk_hw *hw, unsigned long req_rate, - unsigned long *parent_rate) +static int ingenic_ost_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { - unsigned long rate = *parent_rate; + unsigned long rate = req->best_parent_rate; u8 prescale; - if (req_rate > rate) - return rate; + if (req->rate > rate) { + req->rate = rate; - prescale = ingenic_ost_get_prescale(rate, req_rate); + return 0; + } + + prescale = ingenic_ost_get_prescale(rate, req->rate); - return rate >> (prescale * 2); + req->rate = rate >> (prescale * 2); + + return 0; } static int ingenic_ost_percpu_timer_set_rate(struct clk_hw *hw, unsigned long req_rate, @@ -175,14 +180,14 @@ static int ingenic_ost_global_timer_set_rate(struct clk_hw *hw, unsigned long re static const struct clk_ops ingenic_ost_percpu_timer_ops = { .recalc_rate = ingenic_ost_percpu_timer_recalc_rate, - .round_rate = ingenic_ost_round_rate, - .set_rate = ingenic_ost_percpu_timer_set_rate, + .determine_rate = ingenic_ost_determine_rate, + .set_rate = ingenic_ost_percpu_timer_set_rate, }; static const struct clk_ops ingenic_ost_global_timer_ops = { .recalc_rate = ingenic_ost_global_timer_recalc_rate, - .round_rate = ingenic_ost_round_rate, - .set_rate = ingenic_ost_global_timer_set_rate, + .determine_rate = ingenic_ost_determine_rate, + .set_rate = ingenic_ost_global_timer_set_rate, }; static const char * const ingenic_ost_clk_parents[] = { "ext" }; @@ -274,7 +279,7 @@ static int __init ingenic_ost_register_clock(struct ingenic_ost *ost, struct ingenic_ost_clk *ost_clk; int val, err; - ost_clk = kzalloc(sizeof(*ost_clk), GFP_KERNEL); + ost_clk = kzalloc_obj(*ost_clk); if (!ost_clk) return -ENOMEM; @@ -427,7 +432,7 @@ static int __init ingenic_ost_probe(struct device_node *np) unsigned int i; int ret; - ost = kzalloc(sizeof(*ost), GFP_KERNEL); + ost = kzalloc_obj(*ost); if (!ost) return -ENOMEM; @@ -453,8 +458,8 @@ static int __init ingenic_ost_probe(struct device_node *np) ost->soc_info = id->data; - ost->clocks = kzalloc(struct_size(ost->clocks, hws, ost->soc_info->num_channels), - GFP_KERNEL); + ost->clocks = kzalloc_flex(*ost->clocks, hws, + ost->soc_info->num_channels); if (!ost->clocks) { ret = -ENOMEM; goto err_clk_disable; diff --git a/drivers/clocksource/ingenic-timer.c b/drivers/clocksource/ingenic-timer.c index 154ee5f7954a..54bb56005dfd 100644 --- a/drivers/clocksource/ingenic-timer.c +++ b/drivers/clocksource/ingenic-timer.c @@ -286,8 +286,7 @@ static int __init ingenic_tcu_init(struct device_node *np) if (IS_ERR(map)) return PTR_ERR(map); - tcu = kzalloc(struct_size(tcu, timers, num_possible_cpus()), - GFP_KERNEL); + tcu = kzalloc_flex(*tcu, timers, num_possible_cpus()); if (!tcu) return -ENOMEM; diff --git a/drivers/clocksource/jcore-pit.c b/drivers/clocksource/jcore-pit.c index a3fe98cd3838..82815428f8f9 100644 --- a/drivers/clocksource/jcore-pit.c +++ b/drivers/clocksource/jcore-pit.c @@ -114,6 +114,18 @@ static int jcore_pit_local_init(unsigned cpu) pit->periodic_delta = DIV_ROUND_CLOSEST(NSEC_PER_SEC, HZ * buspd); clockevents_config_and_register(&pit->ced, freq, 1, ULONG_MAX); + enable_percpu_irq(pit->ced.irq, IRQ_TYPE_NONE); + + return 0; +} + +static int jcore_pit_local_teardown(unsigned cpu) +{ + struct jcore_pit *pit = this_cpu_ptr(jcore_pit_percpu); + + pr_info("Local J-Core PIT teardown on cpu %u\n", cpu); + + disable_percpu_irq(pit->ced.irq); return 0; } @@ -168,6 +180,7 @@ static int __init jcore_pit_init(struct device_node *node) return -ENOMEM; } + irq_set_percpu_devid(pit_irq); err = request_percpu_irq(pit_irq, jcore_timer_interrupt, "jcore_pit", jcore_pit_percpu); if (err) { @@ -237,7 +250,7 @@ static int __init jcore_pit_init(struct device_node *node) cpuhp_setup_state(CPUHP_AP_JCORE_TIMER_STARTING, "clockevents/jcore:starting", - jcore_pit_local_init, NULL); + jcore_pit_local_init, jcore_pit_local_teardown); return 0; } diff --git a/drivers/clocksource/mips-gic-timer.c b/drivers/clocksource/mips-gic-timer.c index 7907b740497a..1501c7db9a8e 100644 --- a/drivers/clocksource/mips-gic-timer.c +++ b/drivers/clocksource/mips-gic-timer.c @@ -77,13 +77,6 @@ static irqreturn_t gic_compare_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static struct irqaction gic_compare_irqaction = { - .handler = gic_compare_interrupt, - .percpu_dev_id = &gic_clockevent_device, - .flags = IRQF_PERCPU | IRQF_TIMER, - .name = "timer", -}; - static void gic_clockevent_cpu_init(unsigned int cpu, struct clock_event_device *cd) { @@ -115,6 +108,9 @@ static void gic_update_frequency(void *data) static int gic_starting_cpu(unsigned int cpu) { + /* Ensure the GIC counter is running */ + clear_gic_config(GIC_CONFIG_COUNTSTOP); + gic_clockevent_cpu_init(cpu, this_cpu_ptr(&gic_clockevent_device)); return 0; } @@ -149,7 +145,8 @@ static int gic_clockevent_init(void) if (!gic_frequency) return -ENXIO; - ret = setup_percpu_irq(gic_timer_irq, &gic_compare_irqaction); + ret = request_percpu_irq(gic_timer_irq, gic_compare_interrupt, + "timer", &gic_clockevent_device); if (ret < 0) { pr_err("IRQ %d setup failed (%d)\n", gic_timer_irq, ret); return ret; @@ -288,9 +285,6 @@ static int __init gic_clocksource_of_init(struct device_node *node) pr_warn("Unable to register clock notifier\n"); } - /* And finally start the counter */ - clear_gic_config(GIC_CONFIG_COUNTSTOP); - /* * It's safe to use the MIPS GIC timer as a sched clock source only if * its ticks are stable, which is true on either the platforms with diff --git a/drivers/clocksource/mmio.c b/drivers/clocksource/mmio.c index 9de751531831..cd5fbf49ac29 100644 --- a/drivers/clocksource/mmio.c +++ b/drivers/clocksource/mmio.c @@ -55,7 +55,7 @@ int __init clocksource_mmio_init(void __iomem *base, const char *name, if (bits > 64 || bits < 16) return -EINVAL; - cs = kzalloc(sizeof(struct clocksource_mmio), GFP_KERNEL); + cs = kzalloc_obj(struct clocksource_mmio); if (!cs) return -ENOMEM; diff --git a/drivers/clocksource/mps2-timer.c b/drivers/clocksource/mps2-timer.c index efe8cad8f2a5..ebca55d8cfed 100644 --- a/drivers/clocksource/mps2-timer.c +++ b/drivers/clocksource/mps2-timer.c @@ -136,7 +136,7 @@ static int __init mps2_clockevent_init(struct device_node *np) goto out_iounmap; } - ce = kzalloc(sizeof(*ce), GFP_KERNEL); + ce = kzalloc_obj(*ce); if (!ce) { ret = -ENOMEM; goto out_iounmap; diff --git a/drivers/clocksource/renesas-ostm.c b/drivers/clocksource/renesas-ostm.c index 3fcbd02b2483..9404ccb1bda9 100644 --- a/drivers/clocksource/renesas-ostm.c +++ b/drivers/clocksource/renesas-ostm.c @@ -165,7 +165,7 @@ static int __init ostm_init(struct device_node *np) struct timer_of *to; int ret; - to = kzalloc(sizeof(*to), GFP_KERNEL); + to = kzalloc_obj(*to); if (!to) return -ENOMEM; @@ -225,7 +225,6 @@ err_free: TIMER_OF_DECLARE(ostm, "renesas,ostm", ostm_init); -#if defined(CONFIG_ARCH_RZG2L) || defined(CONFIG_ARCH_R9A09G057) static int __init ostm_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -233,7 +232,7 @@ static int __init ostm_probe(struct platform_device *pdev) return ostm_init(dev->of_node); } -static const struct of_device_id ostm_of_table[] = { +static const struct of_device_id __maybe_unused ostm_of_table[] = { { .compatible = "renesas,ostm", }, { /* sentinel */ } }; @@ -246,4 +245,3 @@ static struct platform_driver ostm_device_driver = { }, }; builtin_platform_driver_probe(ostm_device_driver, ostm_probe); -#endif diff --git a/drivers/clocksource/scx200_hrt.c b/drivers/clocksource/scx200_hrt.c index c3536fffbe9a..5a99801a1657 100644 --- a/drivers/clocksource/scx200_hrt.c +++ b/drivers/clocksource/scx200_hrt.c @@ -52,6 +52,7 @@ static struct clocksource cs_hrt = { .mask = CLOCKSOURCE_MASK(32), .flags = CLOCK_SOURCE_IS_CONTINUOUS, /* mult, shift are set based on mhz27 flag */ + .owner = THIS_MODULE, }; static int __init init_hrt_clocksource(void) diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index b72b36e0abed..cf057f531a58 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c @@ -355,14 +355,6 @@ static int sh_cmt_enable(struct sh_cmt_channel *ch) dev_pm_syscore_device(&ch->cmt->pdev->dev, true); - /* enable clock */ - ret = clk_enable(ch->cmt->clk); - if (ret) { - dev_err(&ch->cmt->pdev->dev, "ch%u: cannot enable clock\n", - ch->index); - goto err0; - } - /* make sure channel is disabled */ sh_cmt_start_stop_ch(ch, 0); @@ -384,19 +376,12 @@ static int sh_cmt_enable(struct sh_cmt_channel *ch) if (ret || sh_cmt_read_cmcnt(ch)) { dev_err(&ch->cmt->pdev->dev, "ch%u: cannot clear CMCNT\n", ch->index); - ret = -ETIMEDOUT; - goto err1; + return -ETIMEDOUT; } /* enable channel */ sh_cmt_start_stop_ch(ch, 1); return 0; - err1: - /* stop clock */ - clk_disable(ch->cmt->clk); - - err0: - return ret; } static void sh_cmt_disable(struct sh_cmt_channel *ch) @@ -407,9 +392,6 @@ static void sh_cmt_disable(struct sh_cmt_channel *ch) /* disable interrupts in CMT block */ sh_cmt_write_cmcsr(ch, 0); - /* stop clock */ - clk_disable(ch->cmt->clk); - dev_pm_syscore_device(&ch->cmt->pdev->dev, false); } @@ -578,37 +560,68 @@ static irqreturn_t sh_cmt_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static int sh_cmt_start(struct sh_cmt_channel *ch, unsigned long flag) +static int sh_cmt_start_clocksource(struct sh_cmt_channel *ch) { int ret = 0; unsigned long flags; - if (flag & FLAG_CLOCKSOURCE) - pm_runtime_get_sync(&ch->cmt->pdev->dev); - raw_spin_lock_irqsave(&ch->lock, flags); - if (!(ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE))) { - if (flag & FLAG_CLOCKEVENT) - pm_runtime_get_sync(&ch->cmt->pdev->dev); + if (!(ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE))) ret = sh_cmt_enable(ch); - } if (ret) goto out; - ch->flags |= flag; + + ch->flags |= FLAG_CLOCKSOURCE; /* setup timeout if no clockevent */ - if (ch->cmt->num_channels == 1 && - flag == FLAG_CLOCKSOURCE && (!(ch->flags & FLAG_CLOCKEVENT))) + if (ch->cmt->num_channels == 1 && !(ch->flags & FLAG_CLOCKEVENT)) __sh_cmt_set_next(ch, ch->max_match_value); +out: + raw_spin_unlock_irqrestore(&ch->lock, flags); + + return ret; +} + +static void sh_cmt_stop_clocksource(struct sh_cmt_channel *ch) +{ + unsigned long flags; + unsigned long f; + + raw_spin_lock_irqsave(&ch->lock, flags); + + f = ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE); + + ch->flags &= ~FLAG_CLOCKSOURCE; + + if (f && !(ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE))) + sh_cmt_disable(ch); + + raw_spin_unlock_irqrestore(&ch->lock, flags); +} + +static int sh_cmt_start_clockevent(struct sh_cmt_channel *ch) +{ + int ret = 0; + unsigned long flags; + + raw_spin_lock_irqsave(&ch->lock, flags); + + if (!(ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE))) + ret = sh_cmt_enable(ch); + + if (ret) + goto out; + + ch->flags |= FLAG_CLOCKEVENT; out: raw_spin_unlock_irqrestore(&ch->lock, flags); return ret; } -static void sh_cmt_stop(struct sh_cmt_channel *ch, unsigned long flag) +static void sh_cmt_stop_clockevent(struct sh_cmt_channel *ch) { unsigned long flags; unsigned long f; @@ -616,22 +629,17 @@ static void sh_cmt_stop(struct sh_cmt_channel *ch, unsigned long flag) raw_spin_lock_irqsave(&ch->lock, flags); f = ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE); - ch->flags &= ~flag; - if (f && !(ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE))) { + ch->flags &= ~FLAG_CLOCKEVENT; + + if (f && !(ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE))) sh_cmt_disable(ch); - if (flag & FLAG_CLOCKEVENT) - pm_runtime_put(&ch->cmt->pdev->dev); - } /* adjust the timeout to maximum if only clocksource left */ - if ((flag == FLAG_CLOCKEVENT) && (ch->flags & FLAG_CLOCKSOURCE)) + if (ch->flags & FLAG_CLOCKSOURCE) __sh_cmt_set_next(ch, ch->max_match_value); raw_spin_unlock_irqrestore(&ch->lock, flags); - - if (flag & FLAG_CLOCKSOURCE) - pm_runtime_put(&ch->cmt->pdev->dev); } static struct sh_cmt_channel *cs_to_sh_cmt(struct clocksource *cs) @@ -672,7 +680,7 @@ static int sh_cmt_clocksource_enable(struct clocksource *cs) ch->total_cycles = 0; - ret = sh_cmt_start(ch, FLAG_CLOCKSOURCE); + ret = sh_cmt_start_clocksource(ch); if (!ret) ch->cs_enabled = true; @@ -685,7 +693,7 @@ static void sh_cmt_clocksource_disable(struct clocksource *cs) WARN_ON(!ch->cs_enabled); - sh_cmt_stop(ch, FLAG_CLOCKSOURCE); + sh_cmt_stop_clocksource(ch); ch->cs_enabled = false; } @@ -696,7 +704,7 @@ static void sh_cmt_clocksource_suspend(struct clocksource *cs) if (!ch->cs_enabled) return; - sh_cmt_stop(ch, FLAG_CLOCKSOURCE); + sh_cmt_stop_clocksource(ch); dev_pm_genpd_suspend(&ch->cmt->pdev->dev); } @@ -708,7 +716,7 @@ static void sh_cmt_clocksource_resume(struct clocksource *cs) return; dev_pm_genpd_resume(&ch->cmt->pdev->dev); - sh_cmt_start(ch, FLAG_CLOCKSOURCE); + sh_cmt_start_clocksource(ch); } static int sh_cmt_register_clocksource(struct sh_cmt_channel *ch, @@ -740,7 +748,7 @@ static struct sh_cmt_channel *ced_to_sh_cmt(struct clock_event_device *ced) static void sh_cmt_clock_event_start(struct sh_cmt_channel *ch, int periodic) { - sh_cmt_start(ch, FLAG_CLOCKEVENT); + sh_cmt_start_clockevent(ch); if (periodic) sh_cmt_set_next(ch, ((ch->cmt->rate + HZ/2) / HZ) - 1); @@ -752,7 +760,7 @@ static int sh_cmt_clock_event_shutdown(struct clock_event_device *ced) { struct sh_cmt_channel *ch = ced_to_sh_cmt(ced); - sh_cmt_stop(ch, FLAG_CLOCKEVENT); + sh_cmt_stop_clockevent(ch); return 0; } @@ -763,7 +771,7 @@ static int sh_cmt_clock_event_set_state(struct clock_event_device *ced, /* deal with old setting first */ if (clockevent_state_oneshot(ced) || clockevent_state_periodic(ced)) - sh_cmt_stop(ch, FLAG_CLOCKEVENT); + sh_cmt_stop_clockevent(ch); dev_info(&ch->cmt->pdev->dev, "ch%u: used for %s clock events\n", ch->index, periodic ? "periodic" : "oneshot"); @@ -1076,8 +1084,7 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev) /* Allocate and setup the channels. */ cmt->num_channels = hweight8(cmt->hw_channels); - cmt->channels = kcalloc(cmt->num_channels, sizeof(*cmt->channels), - GFP_KERNEL); + cmt->channels = kzalloc_objs(*cmt->channels, cmt->num_channels); if (cmt->channels == NULL) { ret = -ENOMEM; goto err_unmap; @@ -1100,8 +1107,6 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev) mask &= ~(1 << hwidx); } - clk_disable(cmt->clk); - platform_set_drvdata(pdev, cmt); return 0; @@ -1133,7 +1138,7 @@ static int sh_cmt_probe(struct platform_device *pdev) goto out; } - cmt = kzalloc(sizeof(*cmt), GFP_KERNEL); + cmt = kzalloc_obj(*cmt); if (cmt == NULL) return -ENOMEM; @@ -1149,8 +1154,6 @@ static int sh_cmt_probe(struct platform_device *pdev) out: if (cmt->has_clockevent || cmt->has_clocksource) pm_runtime_irq_safe(&pdev->dev); - else - pm_runtime_idle(&pdev->dev); return 0; } diff --git a/drivers/clocksource/sh_mtu2.c b/drivers/clocksource/sh_mtu2.c index 34872df5458a..1997639b113e 100644 --- a/drivers/clocksource/sh_mtu2.c +++ b/drivers/clocksource/sh_mtu2.c @@ -420,8 +420,7 @@ static int sh_mtu2_setup(struct sh_mtu2_device *mtu, mtu->num_channels = min_t(unsigned int, ret, ARRAY_SIZE(sh_mtu2_channel_offsets)); - mtu->channels = kcalloc(mtu->num_channels, sizeof(*mtu->channels), - GFP_KERNEL); + mtu->channels = kzalloc_objs(*mtu->channels, mtu->num_channels); if (mtu->channels == NULL) { ret = -ENOMEM; goto err_unmap; @@ -462,7 +461,7 @@ static int sh_mtu2_probe(struct platform_device *pdev) goto out; } - mtu = kzalloc(sizeof(*mtu), GFP_KERNEL); + mtu = kzalloc_obj(*mtu); if (mtu == NULL) return -ENOMEM; diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c index beffff81c00f..8d6a9e279f73 100644 --- a/drivers/clocksource/sh_tmu.c +++ b/drivers/clocksource/sh_tmu.c @@ -143,16 +143,6 @@ static void sh_tmu_start_stop_ch(struct sh_tmu_channel *ch, int start) static int __sh_tmu_enable(struct sh_tmu_channel *ch) { - int ret; - - /* enable clock */ - ret = clk_enable(ch->tmu->clk); - if (ret) { - dev_err(&ch->tmu->pdev->dev, "ch%u: cannot enable clock\n", - ch->index); - return ret; - } - /* make sure channel is disabled */ sh_tmu_start_stop_ch(ch, 0); @@ -174,7 +164,6 @@ static int sh_tmu_enable(struct sh_tmu_channel *ch) if (ch->enable_count++ > 0) return 0; - pm_runtime_get_sync(&ch->tmu->pdev->dev); dev_pm_syscore_device(&ch->tmu->pdev->dev, true); return __sh_tmu_enable(ch); @@ -187,9 +176,6 @@ static void __sh_tmu_disable(struct sh_tmu_channel *ch) /* disable interrupts in TMU block */ sh_tmu_write(ch, TCR, TCR_TPSC_CLK4); - - /* stop clock */ - clk_disable(ch->tmu->clk); } static void sh_tmu_disable(struct sh_tmu_channel *ch) @@ -203,7 +189,6 @@ static void sh_tmu_disable(struct sh_tmu_channel *ch) __sh_tmu_disable(ch); dev_pm_syscore_device(&ch->tmu->pdev->dev, false); - pm_runtime_put(&ch->tmu->pdev->dev); } static void sh_tmu_set_next(struct sh_tmu_channel *ch, unsigned long delta, @@ -552,7 +537,6 @@ static int sh_tmu_setup(struct sh_tmu_device *tmu, struct platform_device *pdev) goto err_clk_unprepare; tmu->rate = clk_get_rate(tmu->clk) / 4; - clk_disable(tmu->clk); /* Map the memory resource. */ ret = sh_tmu_map_memory(tmu); @@ -562,8 +546,7 @@ static int sh_tmu_setup(struct sh_tmu_device *tmu, struct platform_device *pdev) } /* Allocate and setup the channels. */ - tmu->channels = kcalloc(tmu->num_channels, sizeof(*tmu->channels), - GFP_KERNEL); + tmu->channels = kzalloc_objs(*tmu->channels, tmu->num_channels); if (tmu->channels == NULL) { ret = -ENOMEM; goto err_unmap; @@ -609,7 +592,7 @@ static int sh_tmu_probe(struct platform_device *pdev) goto out; } - tmu = kzalloc(sizeof(*tmu), GFP_KERNEL); + tmu = kzalloc_obj(*tmu); if (tmu == NULL) return -ENOMEM; @@ -626,8 +609,6 @@ static int sh_tmu_probe(struct platform_device *pdev) out: if (tmu->has_clockevent || tmu->has_clocksource) pm_runtime_irq_safe(&pdev->dev); - else - pm_runtime_idle(&pdev->dev); return 0; } diff --git a/drivers/clocksource/timer-armada-370-xp.c b/drivers/clocksource/timer-armada-370-xp.c index 54284c1c0651..a405a084cf72 100644 --- a/drivers/clocksource/timer-armada-370-xp.c +++ b/drivers/clocksource/timer-armada-370-xp.c @@ -22,7 +22,7 @@ * doing otherwise leads to using a clocksource whose frequency varies * when doing cpufreq frequency changes. * - * See Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt + * See Documentation/devicetree/bindings/timer/marvell,armada-370-timer.yaml */ #include <linux/init.h> @@ -207,14 +207,14 @@ static int armada_370_xp_timer_dying_cpu(unsigned int cpu) static u32 timer0_ctrl_reg, timer0_local_ctrl_reg; -static int armada_370_xp_timer_suspend(void) +static int armada_370_xp_timer_suspend(void *data) { timer0_ctrl_reg = readl(timer_base + TIMER_CTRL_OFF); timer0_local_ctrl_reg = readl(local_base + TIMER_CTRL_OFF); return 0; } -static void armada_370_xp_timer_resume(void) +static void armada_370_xp_timer_resume(void *data) { writel(0xffffffff, timer_base + TIMER0_VAL_OFF); writel(0xffffffff, timer_base + TIMER0_RELOAD_OFF); @@ -222,11 +222,15 @@ static void armada_370_xp_timer_resume(void) writel(timer0_local_ctrl_reg, local_base + TIMER_CTRL_OFF); } -static struct syscore_ops armada_370_xp_timer_syscore_ops = { +static const struct syscore_ops armada_370_xp_timer_syscore_ops = { .suspend = armada_370_xp_timer_suspend, .resume = armada_370_xp_timer_resume, }; +static struct syscore armada_370_xp_timer_syscore = { + .ops = &armada_370_xp_timer_syscore_ops, +}; + static unsigned long armada_370_delay_timer_read(void) { return ~readl(timer_base + TIMER0_VAL_OFF); @@ -324,7 +328,7 @@ static int __init armada_370_xp_timer_common_init(struct device_node *np) return res; } - register_syscore_ops(&armada_370_xp_timer_syscore_ops); + register_syscore(&armada_370_xp_timer_syscore); return 0; } diff --git a/drivers/clocksource/timer-atmel-pit.c b/drivers/clocksource/timer-atmel-pit.c index b4f264ed1937..888b06731e54 100644 --- a/drivers/clocksource/timer-atmel-pit.c +++ b/drivers/clocksource/timer-atmel-pit.c @@ -170,7 +170,7 @@ static int __init at91sam926x_pit_dt_init(struct device_node *node) int ret; struct pit_data *data; - data = kzalloc(sizeof(*data), GFP_KERNEL); + data = kzalloc_obj(*data); if (!data) return -ENOMEM; diff --git a/drivers/clocksource/timer-cadence-ttc.c b/drivers/clocksource/timer-cadence-ttc.c index b8a1cf59b9d6..3c50d6892849 100644 --- a/drivers/clocksource/timer-cadence-ttc.c +++ b/drivers/clocksource/timer-cadence-ttc.c @@ -334,7 +334,7 @@ static int __init ttc_setup_clocksource(struct clk *clk, void __iomem *base, struct ttc_timer_clocksource *ttccs; int err; - ttccs = kzalloc(sizeof(*ttccs), GFP_KERNEL); + ttccs = kzalloc_obj(*ttccs); if (!ttccs) return -ENOMEM; @@ -417,7 +417,7 @@ static int __init ttc_setup_clockevent(struct clk *clk, struct ttc_timer_clockevent *ttcce; int err; - ttcce = kzalloc(sizeof(*ttcce), GFP_KERNEL); + ttcce = kzalloc_obj(*ttcce); if (!ttcce) return -ENOMEM; diff --git a/drivers/clocksource/timer-cs5535.c b/drivers/clocksource/timer-cs5535.c index d47acfe848ae..8af666c39890 100644 --- a/drivers/clocksource/timer-cs5535.c +++ b/drivers/clocksource/timer-cs5535.c @@ -101,6 +101,7 @@ static struct clock_event_device cs5535_clockevent = { .tick_resume = mfgpt_shutdown, .set_next_event = mfgpt_next_event, .rating = 250, + .owner = THIS_MODULE, }; static irqreturn_t mfgpt_tick(int irq, void *dev_id) diff --git a/drivers/clocksource/timer-davinci.c b/drivers/clocksource/timer-davinci.c index b1c248498be4..16ee0687ef31 100644 --- a/drivers/clocksource/timer-davinci.c +++ b/drivers/clocksource/timer-davinci.c @@ -271,7 +271,7 @@ int __init davinci_timer_register(struct clk *clk, davinci_timer_init(base); tick_rate = clk_get_rate(clk); - clockevent = kzalloc(sizeof(*clockevent), GFP_KERNEL); + clockevent = kzalloc_obj(*clockevent); if (!clockevent) { rv = -ENOMEM; goto exit_iounmap_base; diff --git a/drivers/clocksource/timer-econet-en751221.c b/drivers/clocksource/timer-econet-en751221.c new file mode 100644 index 000000000000..4008076b1a21 --- /dev/null +++ b/drivers/clocksource/timer-econet-en751221.c @@ -0,0 +1,216 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Timer present on EcoNet EN75xx MIPS based SoCs. + * + * Copyright (C) 2025 by Caleb James DeLisle <cjd@cjdns.fr> + */ + +#include <linux/io.h> +#include <linux/cpumask.h> +#include <linux/interrupt.h> +#include <linux/clockchips.h> +#include <linux/sched_clock.h> +#include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/of_address.h> +#include <linux/cpuhotplug.h> +#include <linux/clk.h> + +#define ECONET_BITS 32 +#define ECONET_MIN_DELTA 0x00001000 +#define ECONET_MAX_DELTA GENMASK(ECONET_BITS - 2, 0) +/* 34Kc hardware has 1 block and 1004Kc has 2. */ +#define ECONET_NUM_BLOCKS DIV_ROUND_UP(NR_CPUS, 2) + +static struct { + void __iomem *membase[ECONET_NUM_BLOCKS]; + u32 freq_hz; +} econet_timer __ro_after_init; + +static DEFINE_PER_CPU(struct clock_event_device, econet_timer_pcpu); + +/* Each memory block has 2 timers, the order of registers is: + * CTL, CMR0, CNT0, CMR1, CNT1 + */ +static inline void __iomem *reg_ctl(u32 timer_n) +{ + return econet_timer.membase[timer_n >> 1]; +} + +static inline void __iomem *reg_compare(u32 timer_n) +{ + return econet_timer.membase[timer_n >> 1] + (timer_n & 1) * 0x08 + 0x04; +} + +static inline void __iomem *reg_count(u32 timer_n) +{ + return econet_timer.membase[timer_n >> 1] + (timer_n & 1) * 0x08 + 0x08; +} + +static inline u32 ctl_bit_enabled(u32 timer_n) +{ + return 1U << (timer_n & 1); +} + +static inline u32 ctl_bit_pending(u32 timer_n) +{ + return 1U << ((timer_n & 1) + 16); +} + +static bool cevt_is_pending(int cpu_id) +{ + return ioread32(reg_ctl(cpu_id)) & ctl_bit_pending(cpu_id); +} + +static irqreturn_t cevt_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *dev = this_cpu_ptr(&econet_timer_pcpu); + int cpu = cpumask_first(dev->cpumask); + + /* Each VPE has its own events, + * so this will only happen on spurious interrupt. + */ + if (!cevt_is_pending(cpu)) + return IRQ_NONE; + + iowrite32(ioread32(reg_count(cpu)), reg_compare(cpu)); + dev->event_handler(dev); + return IRQ_HANDLED; +} + +static int cevt_set_next_event(ulong delta, struct clock_event_device *dev) +{ + u32 next; + int cpu; + + cpu = cpumask_first(dev->cpumask); + next = ioread32(reg_count(cpu)) + delta; + iowrite32(next, reg_compare(cpu)); + + if ((s32)(next - ioread32(reg_count(cpu))) < ECONET_MIN_DELTA / 2) + return -ETIME; + + return 0; +} + +static int cevt_init_cpu(uint cpu) +{ + struct clock_event_device *cd = &per_cpu(econet_timer_pcpu, cpu); + u32 reg; + + pr_debug("%s: Setting up clockevent for CPU %d\n", cd->name, cpu); + + reg = ioread32(reg_ctl(cpu)) | ctl_bit_enabled(cpu); + iowrite32(reg, reg_ctl(cpu)); + + enable_percpu_irq(cd->irq, IRQ_TYPE_NONE); + + /* Do this last because it synchronously configures the timer */ + clockevents_config_and_register(cd, econet_timer.freq_hz, + ECONET_MIN_DELTA, ECONET_MAX_DELTA); + + return 0; +} + +static u64 notrace sched_clock_read(void) +{ + /* Always read from clock zero no matter the CPU */ + return (u64)ioread32(reg_count(0)); +} + +/* Init */ + +static void __init cevt_dev_init(uint cpu) +{ + iowrite32(0, reg_count(cpu)); + iowrite32(U32_MAX, reg_compare(cpu)); +} + +static int __init cevt_init(struct device_node *np) +{ + int i, irq, ret; + + irq = irq_of_parse_and_map(np, 0); + if (irq <= 0) { + pr_err("%pOFn: irq_of_parse_and_map failed", np); + return -EINVAL; + } + + ret = request_percpu_irq(irq, cevt_interrupt, np->name, &econet_timer_pcpu); + + if (ret < 0) { + pr_err("%pOFn: IRQ %d setup failed (%d)\n", np, irq, ret); + goto err_unmap_irq; + } + + for_each_possible_cpu(i) { + struct clock_event_device *cd = &per_cpu(econet_timer_pcpu, i); + + cd->rating = 310; + cd->features = CLOCK_EVT_FEAT_ONESHOT | + CLOCK_EVT_FEAT_C3STOP | + CLOCK_EVT_FEAT_PERCPU; + cd->set_next_event = cevt_set_next_event; + cd->irq = irq; + cd->cpumask = cpumask_of(i); + cd->name = np->name; + + cevt_dev_init(i); + } + + cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, + "clockevents/econet/timer:starting", + cevt_init_cpu, NULL); + return 0; + +err_unmap_irq: + irq_dispose_mapping(irq); + return ret; +} + +static int __init timer_init(struct device_node *np) +{ + int num_blocks = DIV_ROUND_UP(num_possible_cpus(), 2); + struct clk *clk; + int ret; + + clk = of_clk_get(np, 0); + if (IS_ERR(clk)) { + pr_err("%pOFn: Failed to get CPU clock from DT %ld\n", np, PTR_ERR(clk)); + return PTR_ERR(clk); + } + + econet_timer.freq_hz = clk_get_rate(clk); + + for (int i = 0; i < num_blocks; i++) { + econet_timer.membase[i] = of_iomap(np, i); + if (!econet_timer.membase[i]) { + pr_err("%pOFn: failed to map register [%d]\n", np, i); + return -ENXIO; + } + } + + /* For clocksource purposes always read clock zero, whatever the CPU */ + ret = clocksource_mmio_init(reg_count(0), np->name, + econet_timer.freq_hz, 301, ECONET_BITS, + clocksource_mmio_readl_up); + if (ret) { + pr_err("%pOFn: clocksource_mmio_init failed: %d", np, ret); + return ret; + } + + ret = cevt_init(np); + if (ret < 0) + return ret; + + sched_clock_register(sched_clock_read, ECONET_BITS, + econet_timer.freq_hz); + + pr_info("%pOFn: using %u.%03u MHz high precision timer\n", np, + econet_timer.freq_hz / 1000000, + (econet_timer.freq_hz / 1000) % 1000); + + return 0; +} + +TIMER_OF_DECLARE(econet_timer_hpt, "econet,en751221-timer", timer_init); diff --git a/drivers/clocksource/timer-ep93xx.c b/drivers/clocksource/timer-ep93xx.c index 6981ff3ac8a9..1b719282c07f 100644 --- a/drivers/clocksource/timer-ep93xx.c +++ b/drivers/clocksource/timer-ep93xx.c @@ -141,7 +141,7 @@ static int __init ep93xx_timer_of_init(struct device_node *np) struct ep93xx_tcu *tcu; int ret; - tcu = kzalloc(sizeof(*tcu), GFP_KERNEL); + tcu = kzalloc_obj(*tcu); if (!tcu) return -ENOMEM; diff --git a/drivers/clocksource/timer-fsl-ftm.c b/drivers/clocksource/timer-fsl-ftm.c index 93f336ec875a..4eed6cb46132 100644 --- a/drivers/clocksource/timer-fsl-ftm.c +++ b/drivers/clocksource/timer-fsl-ftm.c @@ -300,7 +300,7 @@ static int __init ftm_timer_init(struct device_node *np) unsigned long freq; int ret, irq; - priv = kzalloc(sizeof(*priv), GFP_KERNEL); + priv = kzalloc_obj(*priv); if (!priv) return -ENOMEM; diff --git a/drivers/clocksource/timer-fttmr010.c b/drivers/clocksource/timer-fttmr010.c index 126fb1f259b2..308f94bfbaed 100644 --- a/drivers/clocksource/timer-fttmr010.c +++ b/drivers/clocksource/timer-fttmr010.c @@ -295,7 +295,7 @@ static int __init fttmr010_common_init(struct device_node *np, return ret; } - fttmr010 = kzalloc(sizeof(*fttmr010), GFP_KERNEL); + fttmr010 = kzalloc_obj(*fttmr010); if (!fttmr010) { ret = -ENOMEM; goto out_disable_clock; diff --git a/drivers/clocksource/timer-goldfish.c b/drivers/clocksource/timer-goldfish.c index 0512d5eabc82..3fe12c7ee7b7 100644 --- a/drivers/clocksource/timer-goldfish.c +++ b/drivers/clocksource/timer-goldfish.c @@ -102,7 +102,7 @@ int __init goldfish_timer_init(int irq, void __iomem *base) struct goldfish_timer *timerdrv; int ret; - timerdrv = kzalloc(sizeof(*timerdrv), GFP_KERNEL); + timerdrv = kzalloc_obj(*timerdrv); if (!timerdrv) return -ENOMEM; diff --git a/drivers/clocksource/timer-gxp.c b/drivers/clocksource/timer-gxp.c index 48a73c101eb8..1becc943339d 100644 --- a/drivers/clocksource/timer-gxp.c +++ b/drivers/clocksource/timer-gxp.c @@ -76,7 +76,7 @@ static int __init gxp_timer_init(struct device_node *node) u32 freq; int ret, irq; - gxp_timer = kzalloc(sizeof(*gxp_timer), GFP_KERNEL); + gxp_timer = kzalloc_obj(*gxp_timer); if (!gxp_timer) { ret = -ENOMEM; pr_err("Can't allocate gxp_timer"); diff --git a/drivers/clocksource/timer-imx-gpt.c b/drivers/clocksource/timer-imx-gpt.c index 489e69169ed4..8335bd7f8c6c 100644 --- a/drivers/clocksource/timer-imx-gpt.c +++ b/drivers/clocksource/timer-imx-gpt.c @@ -428,7 +428,7 @@ static int __init mxc_timer_init_dt(struct device_node *np, enum imx_gpt_type t if (initialized) return 0; - imxtm = kzalloc(sizeof(*imxtm), GFP_KERNEL); + imxtm = kzalloc_obj(*imxtm); if (!imxtm) return -ENOMEM; diff --git a/drivers/clocksource/timer-imx-sysctr.c b/drivers/clocksource/timer-imx-sysctr.c index 44525813be1e..dfbd77950e02 100644 --- a/drivers/clocksource/timer-imx-sysctr.c +++ b/drivers/clocksource/timer-imx-sysctr.c @@ -139,7 +139,7 @@ static int __init __sysctr_timer_init(struct device_node *np) void __iomem *base; int ret; - priv = kzalloc(sizeof(struct sysctr_private), GFP_KERNEL); + priv = kzalloc_obj(struct sysctr_private); if (!priv) return -ENOMEM; diff --git a/drivers/clocksource/timer-ixp4xx.c b/drivers/clocksource/timer-ixp4xx.c index 720ed70a2964..4238a004fdef 100644 --- a/drivers/clocksource/timer-ixp4xx.c +++ b/drivers/clocksource/timer-ixp4xx.c @@ -166,7 +166,7 @@ static __init int ixp4xx_timer_register(void __iomem *base, struct ixp4xx_timer *tmr; int ret; - tmr = kzalloc(sizeof(*tmr), GFP_KERNEL); + tmr = kzalloc_obj(*tmr); if (!tmr) return -ENOMEM; tmr->base = base; diff --git a/drivers/clocksource/timer-microchip-pit64b.c b/drivers/clocksource/timer-microchip-pit64b.c index 57209bb38c70..7439bff42233 100644 --- a/drivers/clocksource/timer-microchip-pit64b.c +++ b/drivers/clocksource/timer-microchip-pit64b.c @@ -350,7 +350,7 @@ static int __init mchp_pit64b_init_clksrc(struct mchp_pit64b_timer *timer, struct mchp_pit64b_clksrc *cs; int ret; - cs = kzalloc(sizeof(*cs), GFP_KERNEL); + cs = kzalloc_obj(*cs); if (!cs) return -ENOMEM; @@ -397,7 +397,7 @@ static int __init mchp_pit64b_init_clkevt(struct mchp_pit64b_timer *timer, struct mchp_pit64b_clkevt *ce; int ret; - ce = kzalloc(sizeof(*ce), GFP_KERNEL); + ce = kzalloc_obj(*ce); if (!ce) return -ENOMEM; diff --git a/drivers/clocksource/timer-msc313e.c b/drivers/clocksource/timer-msc313e.c index 54c54ca7c786..e4b9e3f161bb 100644 --- a/drivers/clocksource/timer-msc313e.c +++ b/drivers/clocksource/timer-msc313e.c @@ -171,7 +171,7 @@ static int __init msc313e_clkevt_init(struct device_node *np) int ret; struct timer_of *to; - to = kzalloc(sizeof(*to), GFP_KERNEL); + to = kzalloc_obj(*to); if (!to) return -ENOMEM; diff --git a/drivers/clocksource/timer-nxp-pit.c b/drivers/clocksource/timer-nxp-pit.c new file mode 100644 index 000000000000..bc5157e2ba57 --- /dev/null +++ b/drivers/clocksource/timer-nxp-pit.c @@ -0,0 +1,383 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright 2012-2013 Freescale Semiconductor, Inc. + * Copyright 2018,2021-2025 NXP + */ +#include <linux/interrupt.h> +#include <linux/clockchips.h> +#include <linux/cpuhotplug.h> +#include <linux/clk.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/sched_clock.h> +#include <linux/platform_device.h> + +/* + * Each pit takes 0x10 Bytes register space + */ +#define PIT0_OFFSET 0x100 +#define PIT_CH(n) (PIT0_OFFSET + 0x10 * (n)) + +#define PITMCR(__base) (__base) + +#define PITMCR_FRZ BIT(0) +#define PITMCR_MDIS BIT(1) + +#define PITLDVAL(__base) (__base) +#define PITTCTRL(__base) ((__base) + 0x08) + +#define PITCVAL_OFFSET 0x04 +#define PITCVAL(__base) ((__base) + 0x04) + +#define PITTCTRL_TEN BIT(0) +#define PITTCTRL_TIE BIT(1) + +#define PITTFLG(__base) ((__base) + 0x0c) + +#define PITTFLG_TIF BIT(0) + +struct pit_timer { + void __iomem *clksrc_base; + void __iomem *clkevt_base; + struct clock_event_device ced; + struct clocksource cs; + int rate; +}; + +struct pit_timer_data { + int max_pit_instances; +}; + +static DEFINE_PER_CPU(struct pit_timer *, pit_timers); + +/* + * Global structure for multiple PITs initialization + */ +static int pit_instances; +static int max_pit_instances = 1; + +static void __iomem *sched_clock_base; + +static inline struct pit_timer *ced_to_pit(struct clock_event_device *ced) +{ + return container_of(ced, struct pit_timer, ced); +} + +static inline struct pit_timer *cs_to_pit(struct clocksource *cs) +{ + return container_of(cs, struct pit_timer, cs); +} + +static inline void pit_module_enable(void __iomem *base) +{ + writel(0, PITMCR(base)); +} + +static inline void pit_module_disable(void __iomem *base) +{ + writel(PITMCR_MDIS, PITMCR(base)); +} + +static inline void pit_timer_enable(void __iomem *base, bool tie) +{ + u32 val = PITTCTRL_TEN | (tie ? PITTCTRL_TIE : 0); + + writel(val, PITTCTRL(base)); +} + +static inline void pit_timer_disable(void __iomem *base) +{ + writel(0, PITTCTRL(base)); +} + +static inline void pit_timer_set_counter(void __iomem *base, unsigned int cnt) +{ + writel(cnt, PITLDVAL(base)); +} + +static inline void pit_timer_irqack(struct pit_timer *pit) +{ + writel(PITTFLG_TIF, PITTFLG(pit->clkevt_base)); +} + +static u64 notrace pit_read_sched_clock(void) +{ + return ~readl(sched_clock_base); +} + +static u64 pit_timer_clocksource_read(struct clocksource *cs) +{ + struct pit_timer *pit = cs_to_pit(cs); + + return (u64)~readl(PITCVAL(pit->clksrc_base)); +} + +static int pit_clocksource_init(struct pit_timer *pit, const char *name, + void __iomem *base, unsigned long rate) +{ + /* + * The channels 0 and 1 can be chained to build a 64-bit + * timer. Let's use the channel 2 as a clocksource and leave + * the channels 0 and 1 unused for anyone else who needs them + */ + pit->clksrc_base = base + PIT_CH(2); + pit->cs.name = name; + pit->cs.rating = 300; + pit->cs.read = pit_timer_clocksource_read; + pit->cs.mask = CLOCKSOURCE_MASK(32); + pit->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS; + + /* set the max load value and start the clock source counter */ + pit_timer_disable(pit->clksrc_base); + pit_timer_set_counter(pit->clksrc_base, ~0); + pit_timer_enable(pit->clksrc_base, 0); + + sched_clock_base = pit->clksrc_base + PITCVAL_OFFSET; + sched_clock_register(pit_read_sched_clock, 32, rate); + + return clocksource_register_hz(&pit->cs, rate); +} + +static int pit_set_next_event(unsigned long delta, struct clock_event_device *ced) +{ + struct pit_timer *pit = ced_to_pit(ced); + + /* + * set a new value to PITLDVAL register will not restart the timer, + * to abort the current cycle and start a timer period with the new + * value, the timer must be disabled and enabled again. + * and the PITLAVAL should be set to delta minus one according to pit + * hardware requirement. + */ + pit_timer_disable(pit->clkevt_base); + pit_timer_set_counter(pit->clkevt_base, delta - 1); + pit_timer_enable(pit->clkevt_base, true); + + return 0; +} + +static int pit_shutdown(struct clock_event_device *ced) +{ + struct pit_timer *pit = ced_to_pit(ced); + + pit_timer_disable(pit->clkevt_base); + + return 0; +} + +static int pit_set_periodic(struct clock_event_device *ced) +{ + struct pit_timer *pit = ced_to_pit(ced); + + pit_set_next_event(pit->rate / HZ, ced); + + return 0; +} + +static irqreturn_t pit_timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *ced = dev_id; + struct pit_timer *pit = ced_to_pit(ced); + + pit_timer_irqack(pit); + + /* + * pit hardware doesn't support oneshot, it will generate an interrupt + * and reload the counter value from PITLDVAL when PITCVAL reach zero, + * and start the counter again. So software need to disable the timer + * to stop the counter loop in ONESHOT mode. + */ + if (likely(clockevent_state_oneshot(ced))) + pit_timer_disable(pit->clkevt_base); + + ced->event_handler(ced); + + return IRQ_HANDLED; +} + +static int pit_clockevent_per_cpu_init(struct pit_timer *pit, const char *name, + void __iomem *base, unsigned long rate, + int irq, unsigned int cpu) +{ + int ret; + + /* + * The channels 0 and 1 can be chained to build a 64-bit + * timer. Let's use the channel 3 as a clockevent and leave + * the channels 0 and 1 unused for anyone else who needs them + */ + pit->clkevt_base = base + PIT_CH(3); + pit->rate = rate; + + pit_timer_disable(pit->clkevt_base); + + pit_timer_irqack(pit); + + ret = request_irq(irq, pit_timer_interrupt, IRQF_TIMER | IRQF_NOBALANCING, + name, &pit->ced); + if (ret) + return ret; + + pit->ced.cpumask = cpumask_of(cpu); + pit->ced.irq = irq; + + pit->ced.name = name; + pit->ced.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; + pit->ced.set_state_shutdown = pit_shutdown; + pit->ced.set_state_periodic = pit_set_periodic; + pit->ced.set_next_event = pit_set_next_event; + pit->ced.rating = 300; + + per_cpu(pit_timers, cpu) = pit; + + return 0; +} + +static void pit_clockevent_per_cpu_exit(struct pit_timer *pit, unsigned int cpu) +{ + pit_timer_disable(pit->clkevt_base); + free_irq(pit->ced.irq, &pit->ced); + per_cpu(pit_timers, cpu) = NULL; +} + +static int pit_clockevent_starting_cpu(unsigned int cpu) +{ + struct pit_timer *pit = per_cpu(pit_timers, cpu); + int ret; + + if (!pit) + return 0; + + ret = irq_force_affinity(pit->ced.irq, cpumask_of(cpu)); + if (ret) { + pit_clockevent_per_cpu_exit(pit, cpu); + return ret; + } + + /* + * The value for the LDVAL register trigger is calculated as: + * LDVAL trigger = (period / clock period) - 1 + * The pit is a 32-bit down count timer, when the counter value + * reaches 0, it will generate an interrupt, thus the minimal + * LDVAL trigger value is 1. And then the min_delta is + * minimal LDVAL trigger value + 1, and the max_delta is full 32-bit. + */ + clockevents_config_and_register(&pit->ced, pit->rate, 2, 0xffffffff); + + return 0; +} + +static int pit_timer_init(struct device_node *np) +{ + struct pit_timer *pit; + struct clk *pit_clk; + void __iomem *timer_base; + const char *name = of_node_full_name(np); + unsigned long clk_rate; + int irq, ret; + + pit = kzalloc_obj(*pit); + if (!pit) + return -ENOMEM; + + ret = -ENXIO; + timer_base = of_iomap(np, 0); + if (!timer_base) { + pr_err("Failed to iomap\n"); + goto out_kfree; + } + + ret = -EINVAL; + irq = irq_of_parse_and_map(np, 0); + if (irq <= 0) { + pr_err("Failed to irq_of_parse_and_map\n"); + goto out_iounmap; + } + + pit_clk = of_clk_get(np, 0); + if (IS_ERR(pit_clk)) { + ret = PTR_ERR(pit_clk); + goto out_irq_dispose_mapping; + } + + ret = clk_prepare_enable(pit_clk); + if (ret) + goto out_clk_put; + + clk_rate = clk_get_rate(pit_clk); + + pit_module_disable(timer_base); + + ret = pit_clocksource_init(pit, name, timer_base, clk_rate); + if (ret) { + pr_err("Failed to initialize clocksource '%pOF'\n", np); + goto out_pit_module_disable; + } + + ret = pit_clockevent_per_cpu_init(pit, name, timer_base, clk_rate, irq, pit_instances); + if (ret) { + pr_err("Failed to initialize clockevent '%pOF'\n", np); + goto out_pit_clocksource_unregister; + } + + /* enable the pit module */ + pit_module_enable(timer_base); + + pit_instances++; + + if (pit_instances == max_pit_instances) { + ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "PIT timer:starting", + pit_clockevent_starting_cpu, NULL); + if (ret < 0) + goto out_pit_clocksource_unregister; + } + + return 0; + +out_pit_clocksource_unregister: + clocksource_unregister(&pit->cs); +out_pit_module_disable: + pit_module_disable(timer_base); + clk_disable_unprepare(pit_clk); +out_clk_put: + clk_put(pit_clk); +out_irq_dispose_mapping: + irq_dispose_mapping(irq); +out_iounmap: + iounmap(timer_base); +out_kfree: + kfree(pit); + + return ret; +} + +static int pit_timer_probe(struct platform_device *pdev) +{ + const struct pit_timer_data *pit_timer_data; + + pit_timer_data = of_device_get_match_data(&pdev->dev); + if (pit_timer_data) + max_pit_instances = pit_timer_data->max_pit_instances; + + return pit_timer_init(pdev->dev.of_node); +} + +static struct pit_timer_data s32g2_data = { .max_pit_instances = 2 }; + +static const struct of_device_id pit_timer_of_match[] = { + { .compatible = "nxp,s32g2-pit", .data = &s32g2_data }, + { } +}; +MODULE_DEVICE_TABLE(of, pit_timer_of_match); + +static struct platform_driver nxp_pit_driver = { + .driver = { + .name = "nxp-pit", + .of_match_table = pit_timer_of_match, + .suppress_bind_attrs = true, + }, + .probe = pit_timer_probe, +}; +builtin_platform_driver(nxp_pit_driver); + +TIMER_OF_DECLARE(vf610, "fsl,vf610-pit", pit_timer_init); diff --git a/drivers/clocksource/timer-nxp-stm.c b/drivers/clocksource/timer-nxp-stm.c new file mode 100644 index 000000000000..1ab907233f48 --- /dev/null +++ b/drivers/clocksource/timer-nxp-stm.c @@ -0,0 +1,496 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright 2016 Freescale Semiconductor, Inc. + * Copyright 2018,2021-2025 NXP + * + * NXP System Timer Module: + * + * STM supports commonly required system and application software + * timing functions. STM includes a 32-bit count-up timer and four + * 32-bit compare channels with a separate interrupt source for each + * channel. The timer is driven by the STM module clock divided by an + * 8-bit prescale value (1 to 256). It has ability to stop the timer + * in Debug mode + */ +#include <linux/clk.h> +#include <linux/clockchips.h> +#include <linux/cpuhotplug.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/of_irq.h> +#include <linux/platform_device.h> +#include <linux/sched_clock.h> +#include <linux/units.h> + +#define STM_CR(__base) (__base) + +#define STM_CR_TEN BIT(0) +#define STM_CR_FRZ BIT(1) +#define STM_CR_CPS_OFFSET 8u +#define STM_CR_CPS_MASK GENMASK(15, STM_CR_CPS_OFFSET) + +#define STM_CNT(__base) ((__base) + 0x04) + +#define STM_CCR0(__base) ((__base) + 0x10) +#define STM_CCR1(__base) ((__base) + 0x20) +#define STM_CCR2(__base) ((__base) + 0x30) +#define STM_CCR3(__base) ((__base) + 0x40) + +#define STM_CCR_CEN BIT(0) + +#define STM_CIR0(__base) ((__base) + 0x14) +#define STM_CIR1(__base) ((__base) + 0x24) +#define STM_CIR2(__base) ((__base) + 0x34) +#define STM_CIR3(__base) ((__base) + 0x44) + +#define STM_CIR_CIF BIT(0) + +#define STM_CMP0(__base) ((__base) + 0x18) +#define STM_CMP1(__base) ((__base) + 0x28) +#define STM_CMP2(__base) ((__base) + 0x38) +#define STM_CMP3(__base) ((__base) + 0x48) + +#define STM_ENABLE_MASK (STM_CR_FRZ | STM_CR_TEN) + +struct stm_timer { + void __iomem *base; + unsigned long rate; + unsigned long delta; + unsigned long counter; + struct clock_event_device ced; + struct clocksource cs; + atomic_t refcnt; +}; + +static DEFINE_PER_CPU(struct stm_timer *, stm_timers); + +static struct stm_timer *stm_sched_clock; + +/* + * Global structure for multiple STMs initialization + */ +static int stm_instances; + +/* + * This global lock is used to prevent race conditions with the + * stm_instances in case the driver is using the ASYNC option + */ +static DEFINE_MUTEX(stm_instances_lock); + +DEFINE_GUARD(stm_instances, struct mutex *, mutex_lock(_T), mutex_unlock(_T)) + +static struct stm_timer *cs_to_stm(struct clocksource *cs) +{ + return container_of(cs, struct stm_timer, cs); +} + +static struct stm_timer *ced_to_stm(struct clock_event_device *ced) +{ + return container_of(ced, struct stm_timer, ced); +} + +static u64 notrace nxp_stm_read_sched_clock(void) +{ + return readl(STM_CNT(stm_sched_clock->base)); +} + +static u32 nxp_stm_clocksource_getcnt(struct stm_timer *stm_timer) +{ + return readl(STM_CNT(stm_timer->base)); +} + +static void nxp_stm_clocksource_setcnt(struct stm_timer *stm_timer, u32 cnt) +{ + writel(cnt, STM_CNT(stm_timer->base)); +} + +static u64 nxp_stm_clocksource_read(struct clocksource *cs) +{ + struct stm_timer *stm_timer = cs_to_stm(cs); + + return (u64)nxp_stm_clocksource_getcnt(stm_timer); +} + +static void nxp_stm_module_enable(struct stm_timer *stm_timer) +{ + u32 reg; + + reg = readl(STM_CR(stm_timer->base)); + + reg |= STM_ENABLE_MASK; + + writel(reg, STM_CR(stm_timer->base)); +} + +static void nxp_stm_module_disable(struct stm_timer *stm_timer) +{ + u32 reg; + + reg = readl(STM_CR(stm_timer->base)); + + reg &= ~STM_ENABLE_MASK; + + writel(reg, STM_CR(stm_timer->base)); +} + +static void nxp_stm_module_put(struct stm_timer *stm_timer) +{ + if (atomic_dec_and_test(&stm_timer->refcnt)) + nxp_stm_module_disable(stm_timer); +} + +static void nxp_stm_module_get(struct stm_timer *stm_timer) +{ + if (atomic_inc_return(&stm_timer->refcnt) == 1) + nxp_stm_module_enable(stm_timer); +} + +static int nxp_stm_clocksource_enable(struct clocksource *cs) +{ + struct stm_timer *stm_timer = cs_to_stm(cs); + + nxp_stm_module_get(stm_timer); + + return 0; +} + +static void nxp_stm_clocksource_disable(struct clocksource *cs) +{ + struct stm_timer *stm_timer = cs_to_stm(cs); + + nxp_stm_module_put(stm_timer); +} + +static void nxp_stm_clocksource_suspend(struct clocksource *cs) +{ + struct stm_timer *stm_timer = cs_to_stm(cs); + + nxp_stm_clocksource_disable(cs); + stm_timer->counter = nxp_stm_clocksource_getcnt(stm_timer); +} + +static void nxp_stm_clocksource_resume(struct clocksource *cs) +{ + struct stm_timer *stm_timer = cs_to_stm(cs); + + nxp_stm_clocksource_setcnt(stm_timer, stm_timer->counter); + nxp_stm_clocksource_enable(cs); +} + +static void devm_clocksource_unregister(void *data) +{ + struct stm_timer *stm_timer = data; + + clocksource_unregister(&stm_timer->cs); +} + +static int nxp_stm_clocksource_init(struct device *dev, struct stm_timer *stm_timer, + const char *name, void __iomem *base, struct clk *clk) +{ + int ret; + + stm_timer->base = base; + stm_timer->rate = clk_get_rate(clk); + + stm_timer->cs.name = name; + stm_timer->cs.rating = 460; + stm_timer->cs.read = nxp_stm_clocksource_read; + stm_timer->cs.enable = nxp_stm_clocksource_enable; + stm_timer->cs.disable = nxp_stm_clocksource_disable; + stm_timer->cs.suspend = nxp_stm_clocksource_suspend; + stm_timer->cs.resume = nxp_stm_clocksource_resume; + stm_timer->cs.mask = CLOCKSOURCE_MASK(32); + stm_timer->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS; + stm_timer->cs.owner = THIS_MODULE; + + ret = clocksource_register_hz(&stm_timer->cs, stm_timer->rate); + if (ret) + return ret; + + ret = devm_add_action_or_reset(dev, devm_clocksource_unregister, stm_timer); + if (ret) + return ret; + + stm_sched_clock = stm_timer; + + sched_clock_register(nxp_stm_read_sched_clock, 32, stm_timer->rate); + + dev_dbg(dev, "Registered clocksource %s\n", name); + + return 0; +} + +static int nxp_stm_clockevent_read_counter(struct stm_timer *stm_timer) +{ + return readl(STM_CNT(stm_timer->base)); +} + +static void nxp_stm_clockevent_disable(struct stm_timer *stm_timer) +{ + writel(0, STM_CCR0(stm_timer->base)); +} + +static void nxp_stm_clockevent_enable(struct stm_timer *stm_timer) +{ + writel(STM_CCR_CEN, STM_CCR0(stm_timer->base)); +} + +static int nxp_stm_clockevent_shutdown(struct clock_event_device *ced) +{ + struct stm_timer *stm_timer = ced_to_stm(ced); + + nxp_stm_clockevent_disable(stm_timer); + + return 0; +} + +static int nxp_stm_clockevent_set_next_event(unsigned long delta, struct clock_event_device *ced) +{ + struct stm_timer *stm_timer = ced_to_stm(ced); + u32 val; + + nxp_stm_clockevent_disable(stm_timer); + + stm_timer->delta = delta; + + val = nxp_stm_clockevent_read_counter(stm_timer) + delta; + + writel(val, STM_CMP0(stm_timer->base)); + + /* + * The counter is shared across the channels and can not be + * stopped while we are setting the next event. If the delta + * is very small it is possible the counter increases above + * the computed 'val'. The min_delta value specified when + * registering the clockevent will prevent that. The second + * case is if the counter wraps while we compute the 'val' and + * before writing the comparator register. We read the counter, + * check if we are back in time and abort the timer with -ETIME. + */ + if (val > nxp_stm_clockevent_read_counter(stm_timer) + delta) + return -ETIME; + + nxp_stm_clockevent_enable(stm_timer); + + return 0; +} + +static int nxp_stm_clockevent_set_periodic(struct clock_event_device *ced) +{ + struct stm_timer *stm_timer = ced_to_stm(ced); + + return nxp_stm_clockevent_set_next_event(stm_timer->rate, ced); +} + +static void nxp_stm_clockevent_suspend(struct clock_event_device *ced) +{ + struct stm_timer *stm_timer = ced_to_stm(ced); + + nxp_stm_module_put(stm_timer); +} + +static void nxp_stm_clockevent_resume(struct clock_event_device *ced) +{ + struct stm_timer *stm_timer = ced_to_stm(ced); + + nxp_stm_module_get(stm_timer); +} + +static int nxp_stm_clockevent_per_cpu_init(struct device *dev, struct stm_timer *stm_timer, + const char *name, void __iomem *base, int irq, + struct clk *clk, int cpu) +{ + stm_timer->base = base; + stm_timer->rate = clk_get_rate(clk); + + stm_timer->ced.name = name; + stm_timer->ced.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; + stm_timer->ced.set_state_shutdown = nxp_stm_clockevent_shutdown; + stm_timer->ced.set_state_periodic = nxp_stm_clockevent_set_periodic; + stm_timer->ced.set_next_event = nxp_stm_clockevent_set_next_event; + stm_timer->ced.suspend = nxp_stm_clockevent_suspend; + stm_timer->ced.resume = nxp_stm_clockevent_resume; + stm_timer->ced.cpumask = cpumask_of(cpu); + stm_timer->ced.rating = 460; + stm_timer->ced.irq = irq; + stm_timer->ced.owner = THIS_MODULE; + + per_cpu(stm_timers, cpu) = stm_timer; + + nxp_stm_module_get(stm_timer); + + dev_dbg(dev, "Initialized per cpu clockevent name=%s, irq=%d, cpu=%d\n", name, irq, cpu); + + return 0; +} + +static int nxp_stm_clockevent_starting_cpu(unsigned int cpu) +{ + struct stm_timer *stm_timer = per_cpu(stm_timers, cpu); + int ret; + + if (WARN_ON(!stm_timer)) + return -EFAULT; + + ret = irq_force_affinity(stm_timer->ced.irq, cpumask_of(cpu)); + if (ret) + return ret; + + /* + * The timings measurement show reading the counter register + * and writing to the comparator register takes as a maximum + * value 1100 ns at 133MHz rate frequency. The timer must be + * set above this value and to be secure we set the minimum + * value equal to 2000ns, so 2us. + * + * minimum ticks = (rate / MICRO) * 2 + */ + clockevents_config_and_register(&stm_timer->ced, stm_timer->rate, + (stm_timer->rate / MICRO) * 2, ULONG_MAX); + + return 0; +} + +static irqreturn_t nxp_stm_module_interrupt(int irq, void *dev_id) +{ + struct stm_timer *stm_timer = dev_id; + struct clock_event_device *ced = &stm_timer->ced; + u32 val; + + /* + * The interrupt is shared across the channels in the + * module. But this one is configured to run only one channel, + * consequently it is pointless to test the interrupt flags + * before and we can directly reset the channel 0 irq flag + * register. + */ + writel(STM_CIR_CIF, STM_CIR0(stm_timer->base)); + + /* + * Update STM_CMP value using the counter value + */ + val = nxp_stm_clockevent_read_counter(stm_timer) + stm_timer->delta; + + writel(val, STM_CMP0(stm_timer->base)); + + /* + * stm hardware doesn't support oneshot, it will generate an + * interrupt and start the counter again so software needs to + * disable the timer to stop the counter loop in ONESHOT mode. + */ + if (likely(clockevent_state_oneshot(ced))) + nxp_stm_clockevent_disable(stm_timer); + + ced->event_handler(ced); + + return IRQ_HANDLED; +} + +static int nxp_stm_timer_probe(struct platform_device *pdev) +{ + struct stm_timer *stm_timer; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + const char *name = of_node_full_name(np); + struct clk *clk; + void __iomem *base; + int irq, ret; + + /* + * The device tree can have multiple STM nodes described, so + * it makes this driver a good candidate for the async probe. + * It is still unclear if the time framework correctly handles + * parallel loading of the timers but at least this driver is + * ready to support the option. + */ + guard(stm_instances)(&stm_instances_lock); + + /* + * The S32Gx are SoCs featuring a diverse set of cores. Linux + * is expected to run on Cortex-A53 cores, while other + * software stacks will operate on Cortex-M cores. The number + * of STM instances has been sized to include at most one + * instance per core. + * + * As we need a clocksource and a clockevent per cpu, we + * simply initialize a clocksource per cpu along with the + * clockevent which makes the resulting code simpler. + * + * However if the device tree is describing more STM instances + * than the number of cores, then we ignore them. + */ + if (stm_instances >= num_possible_cpus()) + return 0; + + base = devm_of_iomap(dev, np, 0, NULL); + if (IS_ERR(base)) + return dev_err_probe(dev, PTR_ERR(base), "Failed to iomap %pOFn\n", np); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return dev_err_probe(dev, irq, "Failed to get IRQ\n"); + + clk = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), "Clock not found\n"); + + stm_timer = devm_kzalloc(dev, sizeof(*stm_timer), GFP_KERNEL); + if (!stm_timer) + return -ENOMEM; + + ret = devm_request_irq(dev, irq, nxp_stm_module_interrupt, + IRQF_TIMER | IRQF_NOBALANCING, name, stm_timer); + if (ret) + return dev_err_probe(dev, ret, "Unable to allocate interrupt line\n"); + + ret = nxp_stm_clocksource_init(dev, stm_timer, name, base, clk); + if (ret) + return ret; + + /* + * Next probed STM will be a per CPU clockevent, until we + * probe as many as we have CPUs available on the system, we + * do a partial initialization + */ + ret = nxp_stm_clockevent_per_cpu_init(dev, stm_timer, name, + base, irq, clk, + stm_instances); + if (ret) + return ret; + + stm_instances++; + + /* + * The number of probed STMs for per CPU clockevent is + * equal to the number of available CPUs on the + * system. We install the cpu hotplug to finish the + * initialization by registering the clockevents + */ + if (stm_instances == num_possible_cpus()) { + ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "STM timer:starting", + nxp_stm_clockevent_starting_cpu, NULL); + if (ret < 0) + return ret; + } + + return 0; +} + +static const struct of_device_id nxp_stm_of_match[] = { + { .compatible = "nxp,s32g2-stm" }, + { } +}; +MODULE_DEVICE_TABLE(of, nxp_stm_of_match); + +static struct platform_driver nxp_stm_driver = { + .probe = nxp_stm_timer_probe, + .driver = { + .name = "nxp-stm", + .of_match_table = nxp_stm_of_match, + .suppress_bind_attrs = true, + }, +}; +builtin_platform_driver(nxp_stm_driver); + +MODULE_DESCRIPTION("NXP System Timer Module driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clocksource/timer-orion.c b/drivers/clocksource/timer-orion.c index 49e86cb70a7a..61f1e27fc41e 100644 --- a/drivers/clocksource/timer-orion.c +++ b/drivers/clocksource/timer-orion.c @@ -43,7 +43,7 @@ static struct delay_timer orion_delay_timer = { .read_current_timer = orion_read_timer, }; -static void orion_delay_timer_init(unsigned long rate) +static void __init orion_delay_timer_init(unsigned long rate) { orion_delay_timer.freq = rate; register_current_timer_delay(&orion_delay_timer); diff --git a/drivers/clocksource/timer-ralink.c b/drivers/clocksource/timer-ralink.c index 6ecdb4228f76..68434d9ed910 100644 --- a/drivers/clocksource/timer-ralink.c +++ b/drivers/clocksource/timer-ralink.c @@ -130,14 +130,15 @@ static int __init ralink_systick_init(struct device_node *np) systick.dev.irq = irq_of_parse_and_map(np, 0); if (!systick.dev.irq) { pr_err("%pOFn: request_irq failed", np); - return -EINVAL; + ret = -EINVAL; + goto err_iounmap; } ret = clocksource_mmio_init(systick.membase + SYSTICK_COUNT, np->name, SYSTICK_FREQ, 301, 16, clocksource_mmio_readl_up); if (ret) - return ret; + goto err_free_irq; clockevents_register_device(&systick.dev); @@ -145,6 +146,12 @@ static int __init ralink_systick_init(struct device_node *np) np, systick.dev.mult, systick.dev.shift); return 0; + +err_free_irq: + irq_dispose_mapping(systick.dev.irq); +err_iounmap: + iounmap(systick.membase); + return ret; } TIMER_OF_DECLARE(systick, "ralink,cevt-systick", ralink_systick_init); diff --git a/drivers/clocksource/timer-rda.c b/drivers/clocksource/timer-rda.c index fd1199c189bf..0be8e05970e2 100644 --- a/drivers/clocksource/timer-rda.c +++ b/drivers/clocksource/timer-rda.c @@ -13,6 +13,7 @@ #include <linux/init.h> #include <linux/interrupt.h> +#include <linux/sched_clock.h> #include "timer-of.h" @@ -153,7 +154,7 @@ static struct timer_of rda_ostimer_of = { }, }; -static u64 rda_hwtimer_read(struct clocksource *cs) +static u64 rda_hwtimer_clocksource_read(void) { void __iomem *base = timer_of_base(&rda_ostimer_of); u32 lo, hi; @@ -167,6 +168,11 @@ static u64 rda_hwtimer_read(struct clocksource *cs) return ((u64)hi << 32) | lo; } +static u64 rda_hwtimer_read(struct clocksource *cs) +{ + return rda_hwtimer_clocksource_read(); +} + static struct clocksource rda_hwtimer_clocksource = { .name = "rda-timer", .rating = 400, @@ -185,6 +191,7 @@ static int __init rda_timer_init(struct device_node *np) return ret; clocksource_register_hz(&rda_hwtimer_clocksource, rate); + sched_clock_register(rda_hwtimer_clocksource_read, 64, rate); clockevents_config_and_register(&rda_ostimer_of.clkevt, rate, 0x2, UINT_MAX); diff --git a/drivers/clocksource/timer-realtek.c b/drivers/clocksource/timer-realtek.c new file mode 100644 index 000000000000..4f0439de9939 --- /dev/null +++ b/drivers/clocksource/timer-realtek.c @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2025 Realtek Semiconductor Corp. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/irqflags.h> +#include <linux/interrupt.h> +#include "timer-of.h" + +#define ENBL 1 +#define DSBL 0 + +#define SYSTIMER_RATE 1000000 +#define SYSTIMER_MIN_DELTA 0x64 +#define SYSTIMER_MAX_DELTA ULONG_MAX + +/* SYSTIMER Register Offset (RTK Internal Use) */ +#define TS_LW_OFST 0x0 +#define TS_HW_OFST 0x4 +#define TS_CMP_VAL_LW_OFST 0x8 +#define TS_CMP_VAL_HW_OFST 0xC +#define TS_CMP_CTRL_OFST 0x10 +#define TS_CMP_STAT_OFST 0x14 + +/* SYSTIMER CMP CTRL REG Mask */ +#define TS_CMP_EN_MASK 0x1 +#define TS_WR_EN0_MASK 0x2 + +static void __iomem *systimer_base; + +static u64 rtk_ts64_read(void) +{ + u32 low, high; + u64 ts; + + /* Caution: Read LSB word (TS_LW_OFST) first then MSB (TS_HW_OFST) */ + low = readl(systimer_base + TS_LW_OFST); + high = readl(systimer_base + TS_HW_OFST); + ts = ((u64)high << 32) | low; + + return ts; +} + +static void rtk_cmp_value_write(u64 value) +{ + u32 high, low; + + low = value & 0xFFFFFFFF; + high = value >> 32; + + writel(high, systimer_base + TS_CMP_VAL_HW_OFST); + writel(low, systimer_base + TS_CMP_VAL_LW_OFST); +} + +static inline void rtk_cmp_en_write(bool cmp_en) +{ + u32 val; + + val = TS_WR_EN0_MASK; + if (cmp_en == ENBL) + val |= TS_CMP_EN_MASK; + + writel(val, systimer_base + TS_CMP_CTRL_OFST); +} + +static int rtk_syst_clkevt_next_event(unsigned long cycles, struct clock_event_device *clkevt) +{ + u64 cmp_val; + + rtk_cmp_en_write(DSBL); + cmp_val = rtk_ts64_read(); + + /* Set CMP value to current timestamp plus delta_us */ + rtk_cmp_value_write(cmp_val + cycles); + rtk_cmp_en_write(ENBL); + return 0; +} + +static irqreturn_t rtk_ts_match_intr_handler(int irq, void *dev_id) +{ + struct clock_event_device *clkevt = dev_id; + void __iomem *reg_base; + u32 val; + + /* Disable TS CMP Match */ + rtk_cmp_en_write(DSBL); + + /* Clear TS CMP INTR */ + reg_base = systimer_base + TS_CMP_STAT_OFST; + val = readl(reg_base) & TS_CMP_EN_MASK; + writel(val | TS_CMP_EN_MASK, reg_base); + clkevt->event_handler(clkevt); + + return IRQ_HANDLED; +} + +static int rtk_syst_shutdown(struct clock_event_device *clkevt) +{ + void __iomem *reg_base; + u64 cmp_val = 0; + + /* Disable TS CMP Match */ + rtk_cmp_en_write(DSBL); + /* Set compare value to 0 */ + rtk_cmp_value_write(cmp_val); + + /* Clear TS CMP INTR */ + reg_base = systimer_base + TS_CMP_STAT_OFST; + writel(TS_CMP_EN_MASK, reg_base); + return 0; +} + +static struct timer_of rtk_timer_to = { + .flags = TIMER_OF_IRQ | TIMER_OF_BASE, + + .clkevt = { + .name = "rtk-clkevt", + .rating = 300, + .cpumask = cpu_possible_mask, + .features = CLOCK_EVT_FEAT_DYNIRQ | + CLOCK_EVT_FEAT_ONESHOT, + .set_next_event = rtk_syst_clkevt_next_event, + .set_state_oneshot = rtk_syst_shutdown, + .set_state_shutdown = rtk_syst_shutdown, + }, + + .of_irq = { + .flags = IRQF_TIMER | IRQF_IRQPOLL, + .handler = rtk_ts_match_intr_handler, + }, +}; + +static int __init rtk_systimer_init(struct device_node *node) +{ + int ret; + + ret = timer_of_init(node, &rtk_timer_to); + if (ret) + return ret; + + systimer_base = timer_of_base(&rtk_timer_to); + clockevents_config_and_register(&rtk_timer_to.clkevt, SYSTIMER_RATE, + SYSTIMER_MIN_DELTA, SYSTIMER_MAX_DELTA); + + return 0; +} + +TIMER_OF_DECLARE(rtk_systimer, "realtek,rtd1625-systimer", rtk_systimer_init); diff --git a/drivers/clocksource/timer-riscv.c b/drivers/clocksource/timer-riscv.c index 48ce50c5f5e6..cfc4d83c42c0 100644 --- a/drivers/clocksource/timer-riscv.c +++ b/drivers/clocksource/timer-riscv.c @@ -50,8 +50,9 @@ static int riscv_clock_next_event(unsigned long delta, if (static_branch_likely(&riscv_sstc_available)) { #if defined(CONFIG_32BIT) - csr_write(CSR_STIMECMP, next_tval & 0xFFFFFFFF); + csr_write(CSR_STIMECMP, ULONG_MAX); csr_write(CSR_STIMECMPH, next_tval >> 32); + csr_write(CSR_STIMECMP, next_tval & 0xFFFFFFFF); #else csr_write(CSR_STIMECMP, next_tval); #endif @@ -126,7 +127,13 @@ static int riscv_timer_starting_cpu(unsigned int cpu) static int riscv_timer_dying_cpu(unsigned int cpu) { + /* + * Stop the timer when the cpu is going to be offline otherwise + * the timer interrupt may be pending while performing power-down. + */ + riscv_clock_event_stop(); disable_percpu_irq(riscv_clock_event_irq); + return 0; } diff --git a/drivers/clocksource/timer-rockchip.c b/drivers/clocksource/timer-rockchip.c index 1f95d0aca08f..540a16667145 100644 --- a/drivers/clocksource/timer-rockchip.c +++ b/drivers/clocksource/timer-rockchip.c @@ -207,7 +207,7 @@ static int __init rk_clkevt_init(struct device_node *np) struct clock_event_device *ce; int ret = -EINVAL; - rk_clkevt = kzalloc(sizeof(struct rk_clkevt), GFP_KERNEL); + rk_clkevt = kzalloc_obj(struct rk_clkevt); if (!rk_clkevt) { ret = -ENOMEM; goto out; @@ -254,7 +254,7 @@ static int __init rk_clksrc_init(struct device_node *np) { int ret = -EINVAL; - rk_clksrc = kzalloc(sizeof(struct rk_timer), GFP_KERNEL); + rk_clksrc = kzalloc_obj(struct rk_timer); if (!rk_clksrc) { ret = -ENOMEM; goto out; diff --git a/drivers/clocksource/timer-rtl-otto.c b/drivers/clocksource/timer-rtl-otto.c index 8a3068b36e75..6113d2fdd4de 100644 --- a/drivers/clocksource/timer-rtl-otto.c +++ b/drivers/clocksource/timer-rtl-otto.c @@ -38,14 +38,13 @@ #define RTTM_BIT_COUNT 28 #define RTTM_MIN_DELTA 8 #define RTTM_MAX_DELTA CLOCKSOURCE_MASK(28) +#define RTTM_MAX_DIVISOR GENMASK(15, 0) /* - * Timers are derived from the LXB clock frequency. Usually this is a fixed - * multiple of the 25 MHz oscillator. The 930X SOC is an exception from that. - * Its LXB clock has only dividers and uses the switch PLL of 2.45 GHz as its - * base. The only meaningful frequencies we can achieve from that are 175.000 - * MHz and 153.125 MHz. The greatest common divisor of all explained possible - * speeds is 3125000. Pin the timers to this 3.125 MHz reference frequency. + * Timers are derived from the lexra bus (LXB) clock frequency. This is 175 MHz + * on RTL930x and 200 MHz on the other platforms. With 3.125 MHz choose a common + * divisor to have enough range and detail. This provides comparability between + * the different platforms. */ #define RTTM_TICKS_PER_SEC 3125000 @@ -55,11 +54,6 @@ struct rttm_cs { }; /* Simple internal register functions */ -static inline void rttm_set_counter(void __iomem *base, unsigned int counter) -{ - iowrite32(counter, base + RTTM_CNT); -} - static inline unsigned int rttm_get_counter(void __iomem *base) { return ioread32(base + RTTM_CNT); @@ -112,6 +106,22 @@ static irqreturn_t rttm_timer_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +static void rttm_bounce_timer(void __iomem *base, u32 mode) +{ + /* + * When a running timer has less than ~5us left, a stop/start sequence + * might fail. While the details are unknown the most evident effect is + * that the subsequent interrupt will not be fired. + * + * As a workaround issue an intermediate restart with a very slow + * frequency of ~3kHz keeping the target counter (>=8). So the follow + * up restart will always be issued outside the critical window. + */ + + rttm_disable_timer(base); + rttm_enable_timer(base, mode, RTTM_MAX_DIVISOR); +} + static void rttm_stop_timer(void __iomem *base) { rttm_disable_timer(base); @@ -120,7 +130,6 @@ static void rttm_stop_timer(void __iomem *base) static void rttm_start_timer(struct timer_of *to, u32 mode) { - rttm_set_counter(to->of_base.base, 0); rttm_enable_timer(to->of_base.base, mode, to->of_clk.rate / RTTM_TICKS_PER_SEC); } @@ -129,7 +138,8 @@ static int rttm_next_event(unsigned long delta, struct clock_event_device *clkev struct timer_of *to = to_timer_of(clkevt); RTTM_DEBUG(to->of_base.base); - rttm_stop_timer(to->of_base.base); + rttm_bounce_timer(to->of_base.base, RTTM_CTRL_COUNTER); + rttm_disable_timer(to->of_base.base); rttm_set_period(to->of_base.base, delta); rttm_start_timer(to, RTTM_CTRL_COUNTER); @@ -141,7 +151,8 @@ static int rttm_state_oneshot(struct clock_event_device *clkevt) struct timer_of *to = to_timer_of(clkevt); RTTM_DEBUG(to->of_base.base); - rttm_stop_timer(to->of_base.base); + rttm_bounce_timer(to->of_base.base, RTTM_CTRL_COUNTER); + rttm_disable_timer(to->of_base.base); rttm_set_period(to->of_base.base, RTTM_TICKS_PER_SEC / HZ); rttm_start_timer(to, RTTM_CTRL_COUNTER); @@ -153,7 +164,8 @@ static int rttm_state_periodic(struct clock_event_device *clkevt) struct timer_of *to = to_timer_of(clkevt); RTTM_DEBUG(to->of_base.base); - rttm_stop_timer(to->of_base.base); + rttm_bounce_timer(to->of_base.base, RTTM_CTRL_TIMER); + rttm_disable_timer(to->of_base.base); rttm_set_period(to->of_base.base, RTTM_TICKS_PER_SEC / HZ); rttm_start_timer(to, RTTM_CTRL_TIMER); diff --git a/drivers/clocksource/timer-sp804.c b/drivers/clocksource/timer-sp804.c index cd1916c05325..d69858427359 100644 --- a/drivers/clocksource/timer-sp804.c +++ b/drivers/clocksource/timer-sp804.c @@ -21,6 +21,10 @@ #include <linux/of_irq.h> #include <linux/sched_clock.h> +#ifdef CONFIG_ARM +#include <linux/delay.h> +#endif + #include "timer-sp.h" /* Hisilicon 64-bit timer(a variant of ARM SP804) */ @@ -102,6 +106,27 @@ static u64 notrace sp804_read(void) return ~readl_relaxed(sched_clkevt->value); } +/* Register delay timer backed by the hardware counter */ +#ifdef CONFIG_ARM +static struct delay_timer delay; +static struct sp804_clkevt *delay_clkevt; + +static unsigned long sp804_read_delay_timer_read(void) +{ + return ~readl_relaxed(delay_clkevt->value); +} + +static void sp804_register_delay_timer(struct sp804_clkevt *clk, int freq) +{ + delay_clkevt = clk; + delay.freq = freq; + delay.read_current_timer = sp804_read_delay_timer_read; + register_current_timer_delay(&delay); +} +#else +static inline void sp804_register_delay_timer(struct sp804_clkevt *clk, int freq) {} +#endif + static int __init sp804_clocksource_and_sched_clock_init(void __iomem *base, const char *name, struct clk *clk, @@ -129,6 +154,8 @@ static int __init sp804_clocksource_and_sched_clock_init(void __iomem *base, clocksource_mmio_init(clkevt->value, name, rate, 200, 32, clocksource_mmio_readl_down); + sp804_register_delay_timer(clkevt, rate); + if (use_sched_clock) { sched_clkevt = clkevt; sched_clock_register(sp804_read, 32, rate); @@ -318,6 +345,7 @@ static int __init sp804_of_init(struct device_node *np, struct sp804_timer *time if (ret) goto err; } + initialized = true; return 0; diff --git a/drivers/clocksource/timer-sprd.c b/drivers/clocksource/timer-sprd.c index 430cb99d8d79..2c07dd2af760 100644 --- a/drivers/clocksource/timer-sprd.c +++ b/drivers/clocksource/timer-sprd.c @@ -30,6 +30,7 @@ #define TIMER_VALUE_SHDW_HI 0x1c #define TIMER_VALUE_LO_MASK GENMASK(31, 0) +#define TIMER_VALUE_HI_MASK GENMASK(31, 0) static void sprd_timer_enable(void __iomem *base, u32 flag) { @@ -162,15 +163,26 @@ static struct timer_of suspend_to = { static u64 sprd_suspend_timer_read(struct clocksource *cs) { - return ~(u64)readl_relaxed(timer_of_base(&suspend_to) + - TIMER_VALUE_SHDW_LO) & cs->mask; + u32 lo, hi; + + do { + hi = readl_relaxed(timer_of_base(&suspend_to) + + TIMER_VALUE_SHDW_HI); + lo = readl_relaxed(timer_of_base(&suspend_to) + + TIMER_VALUE_SHDW_LO); + } while (hi != readl_relaxed(timer_of_base(&suspend_to) + TIMER_VALUE_SHDW_HI)); + + return ~(((u64)hi << 32) | lo); } static int sprd_suspend_timer_enable(struct clocksource *cs) { - sprd_timer_update_counter(timer_of_base(&suspend_to), - TIMER_VALUE_LO_MASK); - sprd_timer_enable(timer_of_base(&suspend_to), TIMER_CTL_PERIOD_MODE); + writel_relaxed(TIMER_VALUE_LO_MASK, + timer_of_base(&suspend_to) + TIMER_LOAD_LO); + writel_relaxed(TIMER_VALUE_HI_MASK, + timer_of_base(&suspend_to) + TIMER_LOAD_HI); + sprd_timer_enable(timer_of_base(&suspend_to), + TIMER_CTL_PERIOD_MODE|TIMER_CTL_64BIT_WIDTH); return 0; } @@ -186,7 +198,7 @@ static struct clocksource suspend_clocksource = { .read = sprd_suspend_timer_read, .enable = sprd_suspend_timer_enable, .disable = sprd_suspend_timer_disable, - .mask = CLOCKSOURCE_MASK(32), + .mask = CLOCKSOURCE_MASK(64), .flags = CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_SUSPEND_NONSTOP, }; diff --git a/drivers/clocksource/timer-stm32-lp.c b/drivers/clocksource/timer-stm32-lp.c index a4c95161cb22..3d804128c765 100644 --- a/drivers/clocksource/timer-stm32-lp.c +++ b/drivers/clocksource/timer-stm32-lp.c @@ -5,6 +5,7 @@ * Pascal Paillet <p.paillet@st.com> for STMicroelectronics. */ +#include <linux/bitfield.h> #include <linux/clk.h> #include <linux/clockchips.h> #include <linux/interrupt.h> @@ -24,7 +25,10 @@ struct stm32_lp_private { struct regmap *reg; struct clock_event_device clkevt; unsigned long period; + u32 psc; struct device *dev; + struct clk *clk; + u32 version; }; static struct stm32_lp_private* @@ -45,12 +49,46 @@ static int stm32_clkevent_lp_shutdown(struct clock_event_device *clkevt) return 0; } -static int stm32_clkevent_lp_set_timer(unsigned long evt, - struct clock_event_device *clkevt, - int is_periodic) +static int stm32mp25_clkevent_lp_set_evt(struct stm32_lp_private *priv, unsigned long evt) { - struct stm32_lp_private *priv = to_priv(clkevt); + int ret; + u32 val; + + regmap_read(priv->reg, STM32_LPTIM_CR, &val); + if (!FIELD_GET(STM32_LPTIM_ENABLE, val)) { + /* Enable LPTIMER to be able to write into IER and ARR registers */ + regmap_write(priv->reg, STM32_LPTIM_CR, STM32_LPTIM_ENABLE); + /* + * After setting the ENABLE bit, a delay of two counter clock cycles is needed + * before the LPTIM is actually enabled. For 32KHz rate, this makes approximately + * 62.5 micro-seconds, round it up. + */ + udelay(63); + } + /* set next event counter */ + regmap_write(priv->reg, STM32_LPTIM_ARR, evt); + /* enable ARR interrupt */ + regmap_write(priv->reg, STM32_LPTIM_IER, STM32_LPTIM_ARRMIE); + + /* Poll DIEROK and ARROK to ensure register access has completed */ + ret = regmap_read_poll_timeout_atomic(priv->reg, STM32_LPTIM_ISR, val, + (val & STM32_LPTIM_DIEROK_ARROK) == + STM32_LPTIM_DIEROK_ARROK, + 10, 500); + if (ret) { + dev_err(priv->dev, "access to LPTIM timed out\n"); + /* Disable LPTIMER */ + regmap_write(priv->reg, STM32_LPTIM_CR, 0); + return ret; + } + /* Clear DIEROK and ARROK flags */ + regmap_write(priv->reg, STM32_LPTIM_ICR, STM32_LPTIM_DIEROKCF_ARROKCF); + return 0; +} + +static void stm32_clkevent_lp_set_evt(struct stm32_lp_private *priv, unsigned long evt) +{ /* disable LPTIMER to be able to write into IER register*/ regmap_write(priv->reg, STM32_LPTIM_CR, 0); /* enable ARR interrupt */ @@ -59,6 +97,22 @@ static int stm32_clkevent_lp_set_timer(unsigned long evt, regmap_write(priv->reg, STM32_LPTIM_CR, STM32_LPTIM_ENABLE); /* set next event counter */ regmap_write(priv->reg, STM32_LPTIM_ARR, evt); +} + +static int stm32_clkevent_lp_set_timer(unsigned long evt, + struct clock_event_device *clkevt, + int is_periodic) +{ + struct stm32_lp_private *priv = to_priv(clkevt); + int ret; + + if (priv->version == STM32_LPTIM_VERR_23) { + ret = stm32mp25_clkevent_lp_set_evt(priv, evt); + if (ret) + return ret; + } else { + stm32_clkevent_lp_set_evt(priv, evt); + } /* start counter */ if (is_periodic) @@ -120,6 +174,27 @@ static void stm32_clkevent_lp_set_prescaler(struct stm32_lp_private *priv, /* Adjust rate and period given the prescaler value */ *rate = DIV_ROUND_CLOSEST(*rate, (1 << i)); priv->period = DIV_ROUND_UP(*rate, HZ); + priv->psc = i; +} + +static void stm32_clkevent_lp_suspend(struct clock_event_device *clkevt) +{ + struct stm32_lp_private *priv = to_priv(clkevt); + + stm32_clkevent_lp_shutdown(clkevt); + + /* balance clk_prepare_enable() from the probe */ + clk_disable_unprepare(priv->clk); +} + +static void stm32_clkevent_lp_resume(struct clock_event_device *clkevt) +{ + struct stm32_lp_private *priv = to_priv(clkevt); + + clk_prepare_enable(priv->clk); + + /* restore prescaler */ + regmap_write(priv->reg, STM32_LPTIM_CFGR, priv->psc << CFGR_PSC_OFFSET); } static void stm32_clkevent_lp_init(struct stm32_lp_private *priv, @@ -134,6 +209,9 @@ static void stm32_clkevent_lp_init(struct stm32_lp_private *priv, priv->clkevt.set_state_oneshot = stm32_clkevent_lp_set_oneshot; priv->clkevt.set_next_event = stm32_clkevent_lp_set_next_event; priv->clkevt.rating = STM32_LP_RATING; + priv->clkevt.suspend = stm32_clkevent_lp_suspend; + priv->clkevt.resume = stm32_clkevent_lp_resume; + priv->clkevt.owner = THIS_MODULE; clockevents_config_and_register(&priv->clkevt, rate, 0x1, STM32_LPTIM_MAX_ARR); @@ -151,11 +229,13 @@ static int stm32_clkevent_lp_probe(struct platform_device *pdev) return -ENOMEM; priv->reg = ddata->regmap; - ret = clk_prepare_enable(ddata->clk); + priv->version = ddata->version; + priv->clk = ddata->clk; + ret = clk_prepare_enable(priv->clk); if (ret) return -EINVAL; - rate = clk_get_rate(ddata->clk); + rate = clk_get_rate(priv->clk); if (!rate) { ret = -EINVAL; goto out_clk_disable; @@ -168,9 +248,7 @@ static int stm32_clkevent_lp_probe(struct platform_device *pdev) } if (of_property_read_bool(pdev->dev.parent->of_node, "wakeup-source")) { - ret = device_init_wakeup(&pdev->dev, true); - if (ret) - goto out_clk_disable; + device_set_wakeup_capable(&pdev->dev, true); ret = dev_pm_set_wake_irq(&pdev->dev, irq); if (ret) @@ -191,7 +269,7 @@ static int stm32_clkevent_lp_probe(struct platform_device *pdev) return 0; out_clk_disable: - clk_disable_unprepare(ddata->clk); + clk_disable_unprepare(priv->clk); return ret; } @@ -211,5 +289,4 @@ static struct platform_driver stm32_clkevent_lp_driver = { }; module_platform_driver(stm32_clkevent_lp_driver); -MODULE_ALIAS("platform:stm32-lptimer-timer"); MODULE_DESCRIPTION("STMicroelectronics STM32 clockevent low power driver"); diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c index 0a4ea3288bfb..fee65914f99a 100644 --- a/drivers/clocksource/timer-stm32.c +++ b/drivers/clocksource/timer-stm32.c @@ -291,7 +291,7 @@ static int __init stm32_timer_init(struct device_node *node) struct timer_of *to; int ret; - to = kzalloc(sizeof(*to), GFP_KERNEL); + to = kzalloc_obj(*to); if (!to) return -ENOMEM; @@ -302,8 +302,7 @@ static int __init stm32_timer_init(struct device_node *node) if (ret) goto err; - to->private_data = kzalloc(sizeof(struct stm32_timer_private), - GFP_KERNEL); + to->private_data = kzalloc_obj(struct stm32_timer_private); if (!to->private_data) { ret = -ENOMEM; goto deinit; diff --git a/drivers/clocksource/timer-sun5i.c b/drivers/clocksource/timer-sun5i.c index 6b48a9006444..f827d3f98f60 100644 --- a/drivers/clocksource/timer-sun5i.c +++ b/drivers/clocksource/timer-sun5i.c @@ -185,6 +185,7 @@ static int sun5i_setup_clocksource(struct platform_device *pdev, cs->clksrc.read = sun5i_clksrc_read; cs->clksrc.mask = CLOCKSOURCE_MASK(32); cs->clksrc.flags = CLOCK_SOURCE_IS_CONTINUOUS; + cs->clksrc.owner = THIS_MODULE; ret = clocksource_register_hz(&cs->clksrc, rate); if (ret) { @@ -214,6 +215,7 @@ static int sun5i_setup_clockevent(struct platform_device *pdev, ce->clkevt.rating = 340; ce->clkevt.irq = irq; ce->clkevt.cpumask = cpu_possible_mask; + ce->clkevt.owner = THIS_MODULE; /* Enable timer0 interrupt */ val = readl(base + TIMER_IRQ_EN_REG); diff --git a/drivers/clocksource/timer-tegra186.c b/drivers/clocksource/timer-tegra186.c index 5d4cf5237a11..355558893e5f 100644 --- a/drivers/clocksource/timer-tegra186.c +++ b/drivers/clocksource/timer-tegra186.c @@ -1,8 +1,9 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2019-2020 NVIDIA Corporation. All rights reserved. + * Copyright (c) 2019-2025 NVIDIA Corporation. All rights reserved. */ +#include <linux/bitfield.h> #include <linux/clocksource.h> #include <linux/module.h> #include <linux/interrupt.h> @@ -29,6 +30,7 @@ #define TMRSR 0x004 #define TMRSR_INTR_CLR BIT(30) +#define TMRSR_PCV GENMASK(28, 0) #define TMRCSSR 0x008 #define TMRCSSR_SRC_USEC (0 << 0) @@ -45,6 +47,9 @@ #define WDTCR_TIMER_SOURCE_MASK 0xf #define WDTCR_TIMER_SOURCE(x) ((x) & 0xf) +#define WDTSR 0x004 +#define WDTSR_CURRENT_EXPIRATION_COUNT GENMASK(14, 12) + #define WDTCMDR 0x008 #define WDTCMDR_DISABLE_COUNTER BIT(1) #define WDTCMDR_START_COUNTER BIT(0) @@ -154,7 +159,7 @@ static void tegra186_wdt_enable(struct tegra186_wdt *wdt) tmr_writel(wdt->tmr, TMRCSSR_SRC_USEC, TMRCSSR); /* configure timer (system reset happens on the fifth expiration) */ - value = TMRCR_PTV(wdt->base.timeout * USEC_PER_SEC / 5) | + value = TMRCR_PTV(wdt->base.timeout * (USEC_PER_SEC / 5)) | TMRCR_PERIODIC | TMRCR_ENABLE; tmr_writel(wdt->tmr, value, TMRCR); @@ -169,18 +174,6 @@ static void tegra186_wdt_enable(struct tegra186_wdt *wdt) value &= ~WDTCR_PERIOD_MASK; value |= WDTCR_PERIOD(1); - /* enable local interrupt for WDT petting */ - value |= WDTCR_LOCAL_INT_ENABLE; - - /* enable local FIQ and remote interrupt for debug dump */ - if (0) - value |= WDTCR_REMOTE_INT_ENABLE | - WDTCR_LOCAL_FIQ_ENABLE; - - /* enable system debug reset (doesn't properly reboot) */ - if (0) - value |= WDTCR_SYSTEM_DEBUG_RESET_ENABLE; - /* enable system POR reset */ value |= WDTCR_SYSTEM_POR_RESET_ENABLE; @@ -234,12 +227,74 @@ static int tegra186_wdt_set_timeout(struct watchdog_device *wdd, return 0; } +static unsigned int tegra186_wdt_get_timeleft(struct watchdog_device *wdd) +{ + struct tegra186_wdt *wdt = to_tegra186_wdt(wdd); + u32 expiration, val; + u32 timeleft; + + if (!watchdog_active(&wdt->base)) { + /* return zero if the watchdog timer is not activated. */ + return 0; + } + + /* + * Reset occurs on the fifth expiration of the + * watchdog timer and so when the watchdog timer is configured, + * the actual value programmed into the counter is 1/5 of the + * timeout value. Once the counter reaches 0, expiration count + * will be increased by 1 and the down counter restarts. + * Hence to get the time left before system reset we must + * combine 2 parts: + * 1. value of the current down counter + * 2. (number of counter expirations remaining) * (timeout/5) + */ + + /* Get the current number of counter expirations. Should be a + * value between 0 and 4 + */ + val = readl_relaxed(wdt->regs + WDTSR); + expiration = FIELD_GET(WDTSR_CURRENT_EXPIRATION_COUNT, val); + if (WARN_ON_ONCE(expiration > 4)) + return 0; + + /* Get the current counter value in microsecond. */ + val = readl_relaxed(wdt->tmr->regs + TMRSR); + timeleft = FIELD_GET(TMRSR_PCV, val); + + /* + * Calculate the time remaining by adding the time for the + * counter value to the time of the counter expirations that + * remain. + * Note: Since wdt->base.timeout is bound to 255, the maximum + * value added to timeleft is + * 255 * (1,000,000 / 5) * 4 + * = 255 * 200,000 * 4 + * = 204,000,000 + * TMRSR_PCV is a 29-bit field. + * Its maximum value is 0x1fffffff = 536,870,911. + * 204,000,000 + 536,870,911 = 740,870,911 = 0x2C28CAFF. + * timeleft can therefore not overflow, and 64-bit calculations + * are not necessary. + */ + timeleft += (wdt->base.timeout * (USEC_PER_SEC / 5)) * (4 - expiration); + + /* + * Convert the current counter value to seconds, + * rounding to the nearest second. + */ + timeleft = DIV_ROUND_CLOSEST(timeleft, USEC_PER_SEC); + + return timeleft; +} + static const struct watchdog_ops tegra186_wdt_ops = { .owner = THIS_MODULE, .start = tegra186_wdt_start, .stop = tegra186_wdt_stop, .ping = tegra186_wdt_ping, .set_timeout = tegra186_wdt_set_timeout, + .get_timeleft = tegra186_wdt_get_timeleft, }; static struct tegra186_wdt *tegra186_wdt_create(struct tegra186_timer *tegra, @@ -278,16 +333,12 @@ static struct tegra186_wdt *tegra186_wdt_create(struct tegra186_timer *tegra, wdt->base.parent = tegra->dev; err = watchdog_init_timeout(&wdt->base, 5, tegra->dev); - if (err < 0) { - dev_err(tegra->dev, "failed to initialize timeout: %d\n", err); + if (err < 0) return ERR_PTR(err); - } err = devm_watchdog_register_device(tegra->dev, &wdt->base); - if (err < 0) { - dev_err(tegra->dev, "failed to register WDT: %d\n", err); + if (err < 0) return ERR_PTR(err); - } return wdt; } @@ -323,6 +374,7 @@ static int tegra186_timer_tsc_init(struct tegra186_timer *tegra) tegra->tsc.read = tegra186_timer_tsc_read; tegra->tsc.mask = CLOCKSOURCE_MASK(56); tegra->tsc.flags = CLOCK_SOURCE_IS_CONTINUOUS; + tegra->tsc.owner = THIS_MODULE; return clocksource_register_hz(&tegra->tsc, 31250000); } @@ -342,6 +394,7 @@ static int tegra186_timer_osc_init(struct tegra186_timer *tegra) tegra->osc.read = tegra186_timer_osc_read; tegra->osc.mask = CLOCKSOURCE_MASK(32); tegra->osc.flags = CLOCK_SOURCE_IS_CONTINUOUS; + tegra->osc.owner = THIS_MODULE; return clocksource_register_hz(&tegra->osc, 38400000); } @@ -361,27 +414,15 @@ static int tegra186_timer_usec_init(struct tegra186_timer *tegra) tegra->usec.read = tegra186_timer_usec_read; tegra->usec.mask = CLOCKSOURCE_MASK(32); tegra->usec.flags = CLOCK_SOURCE_IS_CONTINUOUS; + tegra->usec.owner = THIS_MODULE; return clocksource_register_hz(&tegra->usec, USEC_PER_SEC); } -static irqreturn_t tegra186_timer_irq(int irq, void *data) -{ - struct tegra186_timer *tegra = data; - - if (watchdog_active(&tegra->wdt->base)) { - tegra186_wdt_disable(tegra->wdt); - tegra186_wdt_enable(tegra->wdt); - } - - return IRQ_HANDLED; -} - static int tegra186_timer_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct tegra186_timer *tegra; - unsigned int irq; int err; tegra = devm_kzalloc(dev, sizeof(*tegra), GFP_KERNEL); @@ -400,8 +441,6 @@ static int tegra186_timer_probe(struct platform_device *pdev) if (err < 0) return err; - irq = err; - /* create a watchdog using a preconfigured timer */ tegra->wdt = tegra186_wdt_create(tegra, 0); if (IS_ERR(tegra->wdt)) { @@ -428,17 +467,8 @@ static int tegra186_timer_probe(struct platform_device *pdev) goto unregister_osc; } - err = devm_request_irq(dev, irq, tegra186_timer_irq, 0, - "tegra186-timer", tegra); - if (err < 0) { - dev_err(dev, "failed to request IRQ#%u: %d\n", irq, err); - goto unregister_usec; - } - return 0; -unregister_usec: - clocksource_unregister(&tegra->usec); unregister_osc: clocksource_unregister(&tegra->osc); unregister_tsc: diff --git a/drivers/clocksource/timer-ti-dm-systimer.c b/drivers/clocksource/timer-ti-dm-systimer.c index 985a6d08512b..eb0dfe4b9b7c 100644 --- a/drivers/clocksource/timer-ti-dm-systimer.c +++ b/drivers/clocksource/timer-ti-dm-systimer.c @@ -600,7 +600,7 @@ static int __init dmtimer_clockevent_init(struct device_node *np) struct dmtimer_clockevent *clkevt; int error; - clkevt = kzalloc(sizeof(*clkevt), GFP_KERNEL); + clkevt = kzalloc_obj(*clkevt); if (!clkevt) return -ENOMEM; @@ -757,7 +757,7 @@ static int __init dmtimer_clocksource_init(struct device_node *np) struct clocksource *dev; int error; - clksrc = kzalloc(sizeof(*clksrc), GFP_KERNEL); + clksrc = kzalloc_obj(*clksrc); if (!clksrc) return -ENOMEM; diff --git a/drivers/clocksource/timer-ti-dm.c b/drivers/clocksource/timer-ti-dm.c index e9e32df6b566..793e7cdcb1b1 100644 --- a/drivers/clocksource/timer-ti-dm.c +++ b/drivers/clocksource/timer-ti-dm.c @@ -31,6 +31,7 @@ #include <linux/platform_data/dmtimer-omap.h> #include <clocksource/timer-ti-dm.h> +#include <linux/delay.h> /* * timer errata flags @@ -836,6 +837,48 @@ static int omap_dm_timer_set_match(struct omap_dm_timer *cookie, int enable, return 0; } +static int omap_dm_timer_set_cap(struct omap_dm_timer *cookie, + int autoreload, bool config_period) +{ + struct dmtimer *timer; + struct device *dev; + int rc; + u32 l; + + timer = to_dmtimer(cookie); + if (unlikely(!timer)) + return -EINVAL; + + dev = &timer->pdev->dev; + rc = pm_runtime_resume_and_get(dev); + if (rc) + return rc; + /* + * 1. Select autoreload mode. TIMER_TCLR[1] AR bit. + * 2. TIMER_TCLR[14]: Sets the functionality of the TIMER IO pin. + * 3. TIMER_TCLR[13] : Capture mode select bit. + * 3. TIMER_TCLR[9-8] : Select transition capture mode. + */ + + l = dmtimer_read(timer, OMAP_TIMER_CTRL_REG); + + if (autoreload) + l |= OMAP_TIMER_CTRL_AR; + + l |= OMAP_TIMER_CTRL_CAPTMODE | OMAP_TIMER_CTRL_GPOCFG; + + if (config_period == true) + l |= OMAP_TIMER_CTRL_TCM_LOWTOHIGH; /* Time Period config */ + else + l |= OMAP_TIMER_CTRL_TCM_BOTHEDGES; /* Duty Cycle config */ + + dmtimer_write(timer, OMAP_TIMER_CTRL_REG, l); + + pm_runtime_put_sync(dev); + + return 0; +} + static int omap_dm_timer_set_pwm(struct omap_dm_timer *cookie, int def_on, int toggle, int trigger, int autoreload) { @@ -1023,23 +1066,92 @@ static unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *cookie) return __omap_dm_timer_read_counter(timer); } +static inline unsigned int __omap_dm_timer_cap(struct dmtimer *timer, int idx) +{ + return idx == 0 ? dmtimer_read(timer, OMAP_TIMER_CAPTURE_REG) : + dmtimer_read(timer, OMAP_TIMER_CAPTURE2_REG); +} + static int omap_dm_timer_write_counter(struct omap_dm_timer *cookie, unsigned int value) { struct dmtimer *timer; + struct device *dev; timer = to_dmtimer(cookie); - if (unlikely(!timer || !atomic_read(&timer->enabled))) { - pr_err("%s: timer not available or enabled.\n", __func__); + if (unlikely(!timer)) { + pr_err("%s: timer not available.\n", __func__); return -EINVAL; } + dev = &timer->pdev->dev; + + pm_runtime_resume_and_get(dev); dmtimer_write(timer, OMAP_TIMER_COUNTER_REG, value); + pm_runtime_put_sync(dev); /* Save the context */ timer->context.tcrr = value; return 0; } +/** + * omap_dm_timer_cap_counter() - Calculate the high count or period count depending on the + * configuration. + * @cookie:Pointer to OMAP DM timer + * @is_period:Whether to configure timer in period or duty cycle mode + * + * Return high count or period count if timer is enabled else appropriate error. + */ +static unsigned int omap_dm_timer_cap_counter(struct omap_dm_timer *cookie, bool is_period) +{ + struct dmtimer *timer; + unsigned int cap1 = 0; + unsigned int cap2 = 0; + u32 l, ret; + + timer = to_dmtimer(cookie); + if (unlikely(!timer || !atomic_read(&timer->enabled))) { + pr_err("%s:timer is not available or enabled.%p\n", __func__, (void *)timer); + return -EINVAL; + } + + /* Stop the timer */ + omap_dm_timer_stop(cookie); + + /* Clear the timer counter value to 0 */ + ret = omap_dm_timer_write_counter(cookie, 0); + if (ret) + return ret; + + /* Sets the timer capture configuration for period/duty cycle calculation */ + ret = omap_dm_timer_set_cap(cookie, true, is_period); + if (ret) { + pr_err("%s: Failed to set timer capture configuration.\n", __func__); + return ret; + } + /* Start the timer */ + omap_dm_timer_start(cookie); + + /* + * 1 sec delay is given so as to provide + * enough time to capture low frequency signals. + */ + msleep(1000); + + cap1 = __omap_dm_timer_cap(timer, 0); + cap2 = __omap_dm_timer_cap(timer, 1); + + /* + * Clears the TCLR configuration. + * The start bit must be set to 1 as the timer is already in start mode. + */ + l = dmtimer_read(timer, OMAP_TIMER_CTRL_REG); + l &= ~(0xffff) | 0x1; + dmtimer_write(timer, OMAP_TIMER_CTRL_REG, l); + + return (cap2-cap1); +} + static int __maybe_unused omap_dm_timer_runtime_suspend(struct device *dev) { struct dmtimer *timer = dev_get_drvdata(dev); @@ -1246,6 +1358,9 @@ static const struct omap_dm_timer_ops dmtimer_ops = { .write_counter = omap_dm_timer_write_counter, .read_status = omap_dm_timer_read_status, .write_status = omap_dm_timer_write_status, + .set_cap = omap_dm_timer_set_cap, + .get_cap_status = omap_dm_timer_get_pwm_status, + .read_cap = omap_dm_timer_cap_counter, }; static const struct dmtimer_platform_data omap3plus_pdata = { diff --git a/drivers/clocksource/timer-vf-pit.c b/drivers/clocksource/timer-vf-pit.c deleted file mode 100644 index 911c92146eca..000000000000 --- a/drivers/clocksource/timer-vf-pit.c +++ /dev/null @@ -1,194 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright 2012-2013 Freescale Semiconductor, Inc. - */ - -#include <linux/interrupt.h> -#include <linux/clockchips.h> -#include <linux/clk.h> -#include <linux/of_address.h> -#include <linux/of_irq.h> -#include <linux/sched_clock.h> - -/* - * Each pit takes 0x10 Bytes register space - */ -#define PITMCR 0x00 -#define PIT0_OFFSET 0x100 -#define PITn_OFFSET(n) (PIT0_OFFSET + 0x10 * (n)) -#define PITLDVAL 0x00 -#define PITCVAL 0x04 -#define PITTCTRL 0x08 -#define PITTFLG 0x0c - -#define PITMCR_MDIS (0x1 << 1) - -#define PITTCTRL_TEN (0x1 << 0) -#define PITTCTRL_TIE (0x1 << 1) -#define PITCTRL_CHN (0x1 << 2) - -#define PITTFLG_TIF 0x1 - -static void __iomem *clksrc_base; -static void __iomem *clkevt_base; -static unsigned long cycle_per_jiffy; - -static inline void pit_timer_enable(void) -{ - __raw_writel(PITTCTRL_TEN | PITTCTRL_TIE, clkevt_base + PITTCTRL); -} - -static inline void pit_timer_disable(void) -{ - __raw_writel(0, clkevt_base + PITTCTRL); -} - -static inline void pit_irq_acknowledge(void) -{ - __raw_writel(PITTFLG_TIF, clkevt_base + PITTFLG); -} - -static u64 notrace pit_read_sched_clock(void) -{ - return ~__raw_readl(clksrc_base + PITCVAL); -} - -static int __init pit_clocksource_init(unsigned long rate) -{ - /* set the max load value and start the clock source counter */ - __raw_writel(0, clksrc_base + PITTCTRL); - __raw_writel(~0UL, clksrc_base + PITLDVAL); - __raw_writel(PITTCTRL_TEN, clksrc_base + PITTCTRL); - - sched_clock_register(pit_read_sched_clock, 32, rate); - return clocksource_mmio_init(clksrc_base + PITCVAL, "vf-pit", rate, - 300, 32, clocksource_mmio_readl_down); -} - -static int pit_set_next_event(unsigned long delta, - struct clock_event_device *unused) -{ - /* - * set a new value to PITLDVAL register will not restart the timer, - * to abort the current cycle and start a timer period with the new - * value, the timer must be disabled and enabled again. - * and the PITLAVAL should be set to delta minus one according to pit - * hardware requirement. - */ - pit_timer_disable(); - __raw_writel(delta - 1, clkevt_base + PITLDVAL); - pit_timer_enable(); - - return 0; -} - -static int pit_shutdown(struct clock_event_device *evt) -{ - pit_timer_disable(); - return 0; -} - -static int pit_set_periodic(struct clock_event_device *evt) -{ - pit_set_next_event(cycle_per_jiffy, evt); - return 0; -} - -static irqreturn_t pit_timer_interrupt(int irq, void *dev_id) -{ - struct clock_event_device *evt = dev_id; - - pit_irq_acknowledge(); - - /* - * pit hardware doesn't support oneshot, it will generate an interrupt - * and reload the counter value from PITLDVAL when PITCVAL reach zero, - * and start the counter again. So software need to disable the timer - * to stop the counter loop in ONESHOT mode. - */ - if (likely(clockevent_state_oneshot(evt))) - pit_timer_disable(); - - evt->event_handler(evt); - - return IRQ_HANDLED; -} - -static struct clock_event_device clockevent_pit = { - .name = "VF pit timer", - .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .set_state_shutdown = pit_shutdown, - .set_state_periodic = pit_set_periodic, - .set_next_event = pit_set_next_event, - .rating = 300, -}; - -static int __init pit_clockevent_init(unsigned long rate, int irq) -{ - __raw_writel(0, clkevt_base + PITTCTRL); - __raw_writel(PITTFLG_TIF, clkevt_base + PITTFLG); - - BUG_ON(request_irq(irq, pit_timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL, - "VF pit timer", &clockevent_pit)); - - clockevent_pit.cpumask = cpumask_of(0); - clockevent_pit.irq = irq; - /* - * The value for the LDVAL register trigger is calculated as: - * LDVAL trigger = (period / clock period) - 1 - * The pit is a 32-bit down count timer, when the counter value - * reaches 0, it will generate an interrupt, thus the minimal - * LDVAL trigger value is 1. And then the min_delta is - * minimal LDVAL trigger value + 1, and the max_delta is full 32-bit. - */ - clockevents_config_and_register(&clockevent_pit, rate, 2, 0xffffffff); - - return 0; -} - -static int __init pit_timer_init(struct device_node *np) -{ - struct clk *pit_clk; - void __iomem *timer_base; - unsigned long clk_rate; - int irq, ret; - - timer_base = of_iomap(np, 0); - if (!timer_base) { - pr_err("Failed to iomap\n"); - return -ENXIO; - } - - /* - * PIT0 and PIT1 can be chained to build a 64-bit timer, - * so choose PIT2 as clocksource, PIT3 as clockevent device, - * and leave PIT0 and PIT1 unused for anyone else who needs them. - */ - clksrc_base = timer_base + PITn_OFFSET(2); - clkevt_base = timer_base + PITn_OFFSET(3); - - irq = irq_of_parse_and_map(np, 0); - if (irq <= 0) - return -EINVAL; - - pit_clk = of_clk_get(np, 0); - if (IS_ERR(pit_clk)) - return PTR_ERR(pit_clk); - - ret = clk_prepare_enable(pit_clk); - if (ret) - return ret; - - clk_rate = clk_get_rate(pit_clk); - cycle_per_jiffy = clk_rate / (HZ); - - /* enable the pit module */ - __raw_writel(~PITMCR_MDIS, timer_base + PITMCR); - - ret = pit_clocksource_init(clk_rate); - if (ret) - return ret; - - return pit_clockevent_init(clk_rate, irq); -} -TIMER_OF_DECLARE(vf610, "fsl,vf610-pit", pit_timer_init); diff --git a/drivers/clocksource/timer-zevio.c b/drivers/clocksource/timer-zevio.c index ecaa3568841c..9a67b84b3e4c 100644 --- a/drivers/clocksource/timer-zevio.c +++ b/drivers/clocksource/timer-zevio.c @@ -119,7 +119,7 @@ static int __init zevio_timer_add(struct device_node *node) struct resource res; int irqnr, ret; - timer = kzalloc(sizeof(*timer), GFP_KERNEL); + timer = kzalloc_obj(*timer); if (!timer) return -ENOMEM; |
