162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/drivers/clocksource/arm_arch_timer.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2011 ARM Ltd. 662306a36Sopenharmony_ci * All Rights Reserved 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#define pr_fmt(fmt) "arch_timer: " fmt 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/init.h> 1262306a36Sopenharmony_ci#include <linux/kernel.h> 1362306a36Sopenharmony_ci#include <linux/device.h> 1462306a36Sopenharmony_ci#include <linux/smp.h> 1562306a36Sopenharmony_ci#include <linux/cpu.h> 1662306a36Sopenharmony_ci#include <linux/cpu_pm.h> 1762306a36Sopenharmony_ci#include <linux/clockchips.h> 1862306a36Sopenharmony_ci#include <linux/clocksource.h> 1962306a36Sopenharmony_ci#include <linux/clocksource_ids.h> 2062306a36Sopenharmony_ci#include <linux/interrupt.h> 2162306a36Sopenharmony_ci#include <linux/kstrtox.h> 2262306a36Sopenharmony_ci#include <linux/of_irq.h> 2362306a36Sopenharmony_ci#include <linux/of_address.h> 2462306a36Sopenharmony_ci#include <linux/io.h> 2562306a36Sopenharmony_ci#include <linux/slab.h> 2662306a36Sopenharmony_ci#include <linux/sched/clock.h> 2762306a36Sopenharmony_ci#include <linux/sched_clock.h> 2862306a36Sopenharmony_ci#include <linux/acpi.h> 2962306a36Sopenharmony_ci#include <linux/arm-smccc.h> 3062306a36Sopenharmony_ci#include <linux/ptp_kvm.h> 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#include <asm/arch_timer.h> 3362306a36Sopenharmony_ci#include <asm/virt.h> 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#include <clocksource/arm_arch_timer.h> 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#define CNTTIDR 0x08 3862306a36Sopenharmony_ci#define CNTTIDR_VIRT(n) (BIT(1) << ((n) * 4)) 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#define CNTACR(n) (0x40 + ((n) * 4)) 4162306a36Sopenharmony_ci#define CNTACR_RPCT BIT(0) 4262306a36Sopenharmony_ci#define CNTACR_RVCT BIT(1) 4362306a36Sopenharmony_ci#define CNTACR_RFRQ BIT(2) 4462306a36Sopenharmony_ci#define CNTACR_RVOFF BIT(3) 4562306a36Sopenharmony_ci#define CNTACR_RWVT BIT(4) 4662306a36Sopenharmony_ci#define CNTACR_RWPT BIT(5) 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#define CNTPCT_LO 0x00 4962306a36Sopenharmony_ci#define CNTVCT_LO 0x08 5062306a36Sopenharmony_ci#define CNTFRQ 0x10 5162306a36Sopenharmony_ci#define CNTP_CVAL_LO 0x20 5262306a36Sopenharmony_ci#define CNTP_CTL 0x2c 5362306a36Sopenharmony_ci#define CNTV_CVAL_LO 0x30 5462306a36Sopenharmony_ci#define CNTV_CTL 0x3c 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/* 5762306a36Sopenharmony_ci * The minimum amount of time a generic counter is guaranteed to not roll over 5862306a36Sopenharmony_ci * (40 years) 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_ci#define MIN_ROLLOVER_SECS (40ULL * 365 * 24 * 3600) 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic unsigned arch_timers_present __initdata; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistruct arch_timer { 6562306a36Sopenharmony_ci void __iomem *base; 6662306a36Sopenharmony_ci struct clock_event_device evt; 6762306a36Sopenharmony_ci}; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic struct arch_timer *arch_timer_mem __ro_after_init; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci#define to_arch_timer(e) container_of(e, struct arch_timer, evt) 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic u32 arch_timer_rate __ro_after_init; 7462306a36Sopenharmony_cistatic int arch_timer_ppi[ARCH_TIMER_MAX_TIMER_PPI] __ro_after_init; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic const char *arch_timer_ppi_names[ARCH_TIMER_MAX_TIMER_PPI] = { 7762306a36Sopenharmony_ci [ARCH_TIMER_PHYS_SECURE_PPI] = "sec-phys", 7862306a36Sopenharmony_ci [ARCH_TIMER_PHYS_NONSECURE_PPI] = "phys", 7962306a36Sopenharmony_ci [ARCH_TIMER_VIRT_PPI] = "virt", 8062306a36Sopenharmony_ci [ARCH_TIMER_HYP_PPI] = "hyp-phys", 8162306a36Sopenharmony_ci [ARCH_TIMER_HYP_VIRT_PPI] = "hyp-virt", 8262306a36Sopenharmony_ci}; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic struct clock_event_device __percpu *arch_timer_evt; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistatic enum arch_timer_ppi_nr arch_timer_uses_ppi __ro_after_init = ARCH_TIMER_VIRT_PPI; 8762306a36Sopenharmony_cistatic bool arch_timer_c3stop __ro_after_init; 8862306a36Sopenharmony_cistatic bool arch_timer_mem_use_virtual __ro_after_init; 8962306a36Sopenharmony_cistatic bool arch_counter_suspend_stop __ro_after_init; 9062306a36Sopenharmony_ci#ifdef CONFIG_GENERIC_GETTIMEOFDAY 9162306a36Sopenharmony_cistatic enum vdso_clock_mode vdso_default = VDSO_CLOCKMODE_ARCHTIMER; 9262306a36Sopenharmony_ci#else 9362306a36Sopenharmony_cistatic enum vdso_clock_mode vdso_default = VDSO_CLOCKMODE_NONE; 9462306a36Sopenharmony_ci#endif /* CONFIG_GENERIC_GETTIMEOFDAY */ 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cistatic cpumask_t evtstrm_available = CPU_MASK_NONE; 9762306a36Sopenharmony_cistatic bool evtstrm_enable __ro_after_init = IS_ENABLED(CONFIG_ARM_ARCH_TIMER_EVTSTREAM); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic int __init early_evtstrm_cfg(char *buf) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci return kstrtobool(buf, &evtstrm_enable); 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ciearly_param("clocksource.arm_arch_timer.evtstrm", early_evtstrm_cfg); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci/* 10662306a36Sopenharmony_ci * Makes an educated guess at a valid counter width based on the Generic Timer 10762306a36Sopenharmony_ci * specification. Of note: 10862306a36Sopenharmony_ci * 1) the system counter is at least 56 bits wide 10962306a36Sopenharmony_ci * 2) a roll-over time of not less than 40 years 11062306a36Sopenharmony_ci * 11162306a36Sopenharmony_ci * See 'ARM DDI 0487G.a D11.1.2 ("The system counter")' for more details. 11262306a36Sopenharmony_ci */ 11362306a36Sopenharmony_cistatic int arch_counter_get_width(void) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci u64 min_cycles = MIN_ROLLOVER_SECS * arch_timer_rate; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci /* guarantee the returned width is within the valid range */ 11862306a36Sopenharmony_ci return clamp_val(ilog2(min_cycles - 1) + 1, 56, 64); 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci/* 12262306a36Sopenharmony_ci * Architected system timer support. 12362306a36Sopenharmony_ci */ 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic __always_inline 12662306a36Sopenharmony_civoid arch_timer_reg_write(int access, enum arch_timer_reg reg, u64 val, 12762306a36Sopenharmony_ci struct clock_event_device *clk) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci if (access == ARCH_TIMER_MEM_PHYS_ACCESS) { 13062306a36Sopenharmony_ci struct arch_timer *timer = to_arch_timer(clk); 13162306a36Sopenharmony_ci switch (reg) { 13262306a36Sopenharmony_ci case ARCH_TIMER_REG_CTRL: 13362306a36Sopenharmony_ci writel_relaxed((u32)val, timer->base + CNTP_CTL); 13462306a36Sopenharmony_ci break; 13562306a36Sopenharmony_ci case ARCH_TIMER_REG_CVAL: 13662306a36Sopenharmony_ci /* 13762306a36Sopenharmony_ci * Not guaranteed to be atomic, so the timer 13862306a36Sopenharmony_ci * must be disabled at this point. 13962306a36Sopenharmony_ci */ 14062306a36Sopenharmony_ci writeq_relaxed(val, timer->base + CNTP_CVAL_LO); 14162306a36Sopenharmony_ci break; 14262306a36Sopenharmony_ci default: 14362306a36Sopenharmony_ci BUILD_BUG(); 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci } else if (access == ARCH_TIMER_MEM_VIRT_ACCESS) { 14662306a36Sopenharmony_ci struct arch_timer *timer = to_arch_timer(clk); 14762306a36Sopenharmony_ci switch (reg) { 14862306a36Sopenharmony_ci case ARCH_TIMER_REG_CTRL: 14962306a36Sopenharmony_ci writel_relaxed((u32)val, timer->base + CNTV_CTL); 15062306a36Sopenharmony_ci break; 15162306a36Sopenharmony_ci case ARCH_TIMER_REG_CVAL: 15262306a36Sopenharmony_ci /* Same restriction as above */ 15362306a36Sopenharmony_ci writeq_relaxed(val, timer->base + CNTV_CVAL_LO); 15462306a36Sopenharmony_ci break; 15562306a36Sopenharmony_ci default: 15662306a36Sopenharmony_ci BUILD_BUG(); 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci } else { 15962306a36Sopenharmony_ci arch_timer_reg_write_cp15(access, reg, val); 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci} 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_cistatic __always_inline 16462306a36Sopenharmony_ciu32 arch_timer_reg_read(int access, enum arch_timer_reg reg, 16562306a36Sopenharmony_ci struct clock_event_device *clk) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci u32 val; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci if (access == ARCH_TIMER_MEM_PHYS_ACCESS) { 17062306a36Sopenharmony_ci struct arch_timer *timer = to_arch_timer(clk); 17162306a36Sopenharmony_ci switch (reg) { 17262306a36Sopenharmony_ci case ARCH_TIMER_REG_CTRL: 17362306a36Sopenharmony_ci val = readl_relaxed(timer->base + CNTP_CTL); 17462306a36Sopenharmony_ci break; 17562306a36Sopenharmony_ci default: 17662306a36Sopenharmony_ci BUILD_BUG(); 17762306a36Sopenharmony_ci } 17862306a36Sopenharmony_ci } else if (access == ARCH_TIMER_MEM_VIRT_ACCESS) { 17962306a36Sopenharmony_ci struct arch_timer *timer = to_arch_timer(clk); 18062306a36Sopenharmony_ci switch (reg) { 18162306a36Sopenharmony_ci case ARCH_TIMER_REG_CTRL: 18262306a36Sopenharmony_ci val = readl_relaxed(timer->base + CNTV_CTL); 18362306a36Sopenharmony_ci break; 18462306a36Sopenharmony_ci default: 18562306a36Sopenharmony_ci BUILD_BUG(); 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci } else { 18862306a36Sopenharmony_ci val = arch_timer_reg_read_cp15(access, reg); 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci return val; 19262306a36Sopenharmony_ci} 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic noinstr u64 raw_counter_get_cntpct_stable(void) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci return __arch_counter_get_cntpct_stable(); 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic notrace u64 arch_counter_get_cntpct_stable(void) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci u64 val; 20262306a36Sopenharmony_ci preempt_disable_notrace(); 20362306a36Sopenharmony_ci val = __arch_counter_get_cntpct_stable(); 20462306a36Sopenharmony_ci preempt_enable_notrace(); 20562306a36Sopenharmony_ci return val; 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cistatic noinstr u64 arch_counter_get_cntpct(void) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci return __arch_counter_get_cntpct(); 21162306a36Sopenharmony_ci} 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_cistatic noinstr u64 raw_counter_get_cntvct_stable(void) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci return __arch_counter_get_cntvct_stable(); 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cistatic notrace u64 arch_counter_get_cntvct_stable(void) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci u64 val; 22162306a36Sopenharmony_ci preempt_disable_notrace(); 22262306a36Sopenharmony_ci val = __arch_counter_get_cntvct_stable(); 22362306a36Sopenharmony_ci preempt_enable_notrace(); 22462306a36Sopenharmony_ci return val; 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistatic noinstr u64 arch_counter_get_cntvct(void) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci return __arch_counter_get_cntvct(); 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci/* 23362306a36Sopenharmony_ci * Default to cp15 based access because arm64 uses this function for 23462306a36Sopenharmony_ci * sched_clock() before DT is probed and the cp15 method is guaranteed 23562306a36Sopenharmony_ci * to exist on arm64. arm doesn't use this before DT is probed so even 23662306a36Sopenharmony_ci * if we don't have the cp15 accessors we won't have a problem. 23762306a36Sopenharmony_ci */ 23862306a36Sopenharmony_ciu64 (*arch_timer_read_counter)(void) __ro_after_init = arch_counter_get_cntvct; 23962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(arch_timer_read_counter); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic u64 arch_counter_read(struct clocksource *cs) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci return arch_timer_read_counter(); 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistatic u64 arch_counter_read_cc(const struct cyclecounter *cc) 24762306a36Sopenharmony_ci{ 24862306a36Sopenharmony_ci return arch_timer_read_counter(); 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic struct clocksource clocksource_counter = { 25262306a36Sopenharmony_ci .name = "arch_sys_counter", 25362306a36Sopenharmony_ci .id = CSID_ARM_ARCH_COUNTER, 25462306a36Sopenharmony_ci .rating = 400, 25562306a36Sopenharmony_ci .read = arch_counter_read, 25662306a36Sopenharmony_ci .flags = CLOCK_SOURCE_IS_CONTINUOUS, 25762306a36Sopenharmony_ci}; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistatic struct cyclecounter cyclecounter __ro_after_init = { 26062306a36Sopenharmony_ci .read = arch_counter_read_cc, 26162306a36Sopenharmony_ci}; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_cistruct ate_acpi_oem_info { 26462306a36Sopenharmony_ci char oem_id[ACPI_OEM_ID_SIZE + 1]; 26562306a36Sopenharmony_ci char oem_table_id[ACPI_OEM_TABLE_ID_SIZE + 1]; 26662306a36Sopenharmony_ci u32 oem_revision; 26762306a36Sopenharmony_ci}; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci#ifdef CONFIG_FSL_ERRATUM_A008585 27062306a36Sopenharmony_ci/* 27162306a36Sopenharmony_ci * The number of retries is an arbitrary value well beyond the highest number 27262306a36Sopenharmony_ci * of iterations the loop has been observed to take. 27362306a36Sopenharmony_ci */ 27462306a36Sopenharmony_ci#define __fsl_a008585_read_reg(reg) ({ \ 27562306a36Sopenharmony_ci u64 _old, _new; \ 27662306a36Sopenharmony_ci int _retries = 200; \ 27762306a36Sopenharmony_ci \ 27862306a36Sopenharmony_ci do { \ 27962306a36Sopenharmony_ci _old = read_sysreg(reg); \ 28062306a36Sopenharmony_ci _new = read_sysreg(reg); \ 28162306a36Sopenharmony_ci _retries--; \ 28262306a36Sopenharmony_ci } while (unlikely(_old != _new) && _retries); \ 28362306a36Sopenharmony_ci \ 28462306a36Sopenharmony_ci WARN_ON_ONCE(!_retries); \ 28562306a36Sopenharmony_ci _new; \ 28662306a36Sopenharmony_ci}) 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_cistatic u64 notrace fsl_a008585_read_cntpct_el0(void) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci return __fsl_a008585_read_reg(cntpct_el0); 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic u64 notrace fsl_a008585_read_cntvct_el0(void) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci return __fsl_a008585_read_reg(cntvct_el0); 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ci#endif 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci#ifdef CONFIG_HISILICON_ERRATUM_161010101 30062306a36Sopenharmony_ci/* 30162306a36Sopenharmony_ci * Verify whether the value of the second read is larger than the first by 30262306a36Sopenharmony_ci * less than 32 is the only way to confirm the value is correct, so clear the 30362306a36Sopenharmony_ci * lower 5 bits to check whether the difference is greater than 32 or not. 30462306a36Sopenharmony_ci * Theoretically the erratum should not occur more than twice in succession 30562306a36Sopenharmony_ci * when reading the system counter, but it is possible that some interrupts 30662306a36Sopenharmony_ci * may lead to more than twice read errors, triggering the warning, so setting 30762306a36Sopenharmony_ci * the number of retries far beyond the number of iterations the loop has been 30862306a36Sopenharmony_ci * observed to take. 30962306a36Sopenharmony_ci */ 31062306a36Sopenharmony_ci#define __hisi_161010101_read_reg(reg) ({ \ 31162306a36Sopenharmony_ci u64 _old, _new; \ 31262306a36Sopenharmony_ci int _retries = 50; \ 31362306a36Sopenharmony_ci \ 31462306a36Sopenharmony_ci do { \ 31562306a36Sopenharmony_ci _old = read_sysreg(reg); \ 31662306a36Sopenharmony_ci _new = read_sysreg(reg); \ 31762306a36Sopenharmony_ci _retries--; \ 31862306a36Sopenharmony_ci } while (unlikely((_new - _old) >> 5) && _retries); \ 31962306a36Sopenharmony_ci \ 32062306a36Sopenharmony_ci WARN_ON_ONCE(!_retries); \ 32162306a36Sopenharmony_ci _new; \ 32262306a36Sopenharmony_ci}) 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_cistatic u64 notrace hisi_161010101_read_cntpct_el0(void) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci return __hisi_161010101_read_reg(cntpct_el0); 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_cistatic u64 notrace hisi_161010101_read_cntvct_el0(void) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci return __hisi_161010101_read_reg(cntvct_el0); 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistatic struct ate_acpi_oem_info hisi_161010101_oem_info[] = { 33562306a36Sopenharmony_ci /* 33662306a36Sopenharmony_ci * Note that trailing spaces are required to properly match 33762306a36Sopenharmony_ci * the OEM table information. 33862306a36Sopenharmony_ci */ 33962306a36Sopenharmony_ci { 34062306a36Sopenharmony_ci .oem_id = "HISI ", 34162306a36Sopenharmony_ci .oem_table_id = "HIP05 ", 34262306a36Sopenharmony_ci .oem_revision = 0, 34362306a36Sopenharmony_ci }, 34462306a36Sopenharmony_ci { 34562306a36Sopenharmony_ci .oem_id = "HISI ", 34662306a36Sopenharmony_ci .oem_table_id = "HIP06 ", 34762306a36Sopenharmony_ci .oem_revision = 0, 34862306a36Sopenharmony_ci }, 34962306a36Sopenharmony_ci { 35062306a36Sopenharmony_ci .oem_id = "HISI ", 35162306a36Sopenharmony_ci .oem_table_id = "HIP07 ", 35262306a36Sopenharmony_ci .oem_revision = 0, 35362306a36Sopenharmony_ci }, 35462306a36Sopenharmony_ci { /* Sentinel indicating the end of the OEM array */ }, 35562306a36Sopenharmony_ci}; 35662306a36Sopenharmony_ci#endif 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci#ifdef CONFIG_ARM64_ERRATUM_858921 35962306a36Sopenharmony_cistatic u64 notrace arm64_858921_read_cntpct_el0(void) 36062306a36Sopenharmony_ci{ 36162306a36Sopenharmony_ci u64 old, new; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci old = read_sysreg(cntpct_el0); 36462306a36Sopenharmony_ci new = read_sysreg(cntpct_el0); 36562306a36Sopenharmony_ci return (((old ^ new) >> 32) & 1) ? old : new; 36662306a36Sopenharmony_ci} 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_cistatic u64 notrace arm64_858921_read_cntvct_el0(void) 36962306a36Sopenharmony_ci{ 37062306a36Sopenharmony_ci u64 old, new; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci old = read_sysreg(cntvct_el0); 37362306a36Sopenharmony_ci new = read_sysreg(cntvct_el0); 37462306a36Sopenharmony_ci return (((old ^ new) >> 32) & 1) ? old : new; 37562306a36Sopenharmony_ci} 37662306a36Sopenharmony_ci#endif 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci#ifdef CONFIG_SUN50I_ERRATUM_UNKNOWN1 37962306a36Sopenharmony_ci/* 38062306a36Sopenharmony_ci * The low bits of the counter registers are indeterminate while bit 10 or 38162306a36Sopenharmony_ci * greater is rolling over. Since the counter value can jump both backward 38262306a36Sopenharmony_ci * (7ff -> 000 -> 800) and forward (7ff -> fff -> 800), ignore register values 38362306a36Sopenharmony_ci * with all ones or all zeros in the low bits. Bound the loop by the maximum 38462306a36Sopenharmony_ci * number of CPU cycles in 3 consecutive 24 MHz counter periods. 38562306a36Sopenharmony_ci */ 38662306a36Sopenharmony_ci#define __sun50i_a64_read_reg(reg) ({ \ 38762306a36Sopenharmony_ci u64 _val; \ 38862306a36Sopenharmony_ci int _retries = 150; \ 38962306a36Sopenharmony_ci \ 39062306a36Sopenharmony_ci do { \ 39162306a36Sopenharmony_ci _val = read_sysreg(reg); \ 39262306a36Sopenharmony_ci _retries--; \ 39362306a36Sopenharmony_ci } while (((_val + 1) & GENMASK(8, 0)) <= 1 && _retries); \ 39462306a36Sopenharmony_ci \ 39562306a36Sopenharmony_ci WARN_ON_ONCE(!_retries); \ 39662306a36Sopenharmony_ci _val; \ 39762306a36Sopenharmony_ci}) 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_cistatic u64 notrace sun50i_a64_read_cntpct_el0(void) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci return __sun50i_a64_read_reg(cntpct_el0); 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_cistatic u64 notrace sun50i_a64_read_cntvct_el0(void) 40562306a36Sopenharmony_ci{ 40662306a36Sopenharmony_ci return __sun50i_a64_read_reg(cntvct_el0); 40762306a36Sopenharmony_ci} 40862306a36Sopenharmony_ci#endif 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci#ifdef CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND 41162306a36Sopenharmony_ciDEFINE_PER_CPU(const struct arch_timer_erratum_workaround *, timer_unstable_counter_workaround); 41262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(timer_unstable_counter_workaround); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_cistatic atomic_t timer_unstable_counter_workaround_in_use = ATOMIC_INIT(0); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci/* 41762306a36Sopenharmony_ci * Force the inlining of this function so that the register accesses 41862306a36Sopenharmony_ci * can be themselves correctly inlined. 41962306a36Sopenharmony_ci */ 42062306a36Sopenharmony_cistatic __always_inline 42162306a36Sopenharmony_civoid erratum_set_next_event_generic(const int access, unsigned long evt, 42262306a36Sopenharmony_ci struct clock_event_device *clk) 42362306a36Sopenharmony_ci{ 42462306a36Sopenharmony_ci unsigned long ctrl; 42562306a36Sopenharmony_ci u64 cval; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL, clk); 42862306a36Sopenharmony_ci ctrl |= ARCH_TIMER_CTRL_ENABLE; 42962306a36Sopenharmony_ci ctrl &= ~ARCH_TIMER_CTRL_IT_MASK; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci if (access == ARCH_TIMER_PHYS_ACCESS) { 43262306a36Sopenharmony_ci cval = evt + arch_counter_get_cntpct_stable(); 43362306a36Sopenharmony_ci write_sysreg(cval, cntp_cval_el0); 43462306a36Sopenharmony_ci } else { 43562306a36Sopenharmony_ci cval = evt + arch_counter_get_cntvct_stable(); 43662306a36Sopenharmony_ci write_sysreg(cval, cntv_cval_el0); 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk); 44062306a36Sopenharmony_ci} 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_cistatic __maybe_unused int erratum_set_next_event_virt(unsigned long evt, 44362306a36Sopenharmony_ci struct clock_event_device *clk) 44462306a36Sopenharmony_ci{ 44562306a36Sopenharmony_ci erratum_set_next_event_generic(ARCH_TIMER_VIRT_ACCESS, evt, clk); 44662306a36Sopenharmony_ci return 0; 44762306a36Sopenharmony_ci} 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_cistatic __maybe_unused int erratum_set_next_event_phys(unsigned long evt, 45062306a36Sopenharmony_ci struct clock_event_device *clk) 45162306a36Sopenharmony_ci{ 45262306a36Sopenharmony_ci erratum_set_next_event_generic(ARCH_TIMER_PHYS_ACCESS, evt, clk); 45362306a36Sopenharmony_ci return 0; 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_cistatic const struct arch_timer_erratum_workaround ool_workarounds[] = { 45762306a36Sopenharmony_ci#ifdef CONFIG_FSL_ERRATUM_A008585 45862306a36Sopenharmony_ci { 45962306a36Sopenharmony_ci .match_type = ate_match_dt, 46062306a36Sopenharmony_ci .id = "fsl,erratum-a008585", 46162306a36Sopenharmony_ci .desc = "Freescale erratum a005858", 46262306a36Sopenharmony_ci .read_cntpct_el0 = fsl_a008585_read_cntpct_el0, 46362306a36Sopenharmony_ci .read_cntvct_el0 = fsl_a008585_read_cntvct_el0, 46462306a36Sopenharmony_ci .set_next_event_phys = erratum_set_next_event_phys, 46562306a36Sopenharmony_ci .set_next_event_virt = erratum_set_next_event_virt, 46662306a36Sopenharmony_ci }, 46762306a36Sopenharmony_ci#endif 46862306a36Sopenharmony_ci#ifdef CONFIG_HISILICON_ERRATUM_161010101 46962306a36Sopenharmony_ci { 47062306a36Sopenharmony_ci .match_type = ate_match_dt, 47162306a36Sopenharmony_ci .id = "hisilicon,erratum-161010101", 47262306a36Sopenharmony_ci .desc = "HiSilicon erratum 161010101", 47362306a36Sopenharmony_ci .read_cntpct_el0 = hisi_161010101_read_cntpct_el0, 47462306a36Sopenharmony_ci .read_cntvct_el0 = hisi_161010101_read_cntvct_el0, 47562306a36Sopenharmony_ci .set_next_event_phys = erratum_set_next_event_phys, 47662306a36Sopenharmony_ci .set_next_event_virt = erratum_set_next_event_virt, 47762306a36Sopenharmony_ci }, 47862306a36Sopenharmony_ci { 47962306a36Sopenharmony_ci .match_type = ate_match_acpi_oem_info, 48062306a36Sopenharmony_ci .id = hisi_161010101_oem_info, 48162306a36Sopenharmony_ci .desc = "HiSilicon erratum 161010101", 48262306a36Sopenharmony_ci .read_cntpct_el0 = hisi_161010101_read_cntpct_el0, 48362306a36Sopenharmony_ci .read_cntvct_el0 = hisi_161010101_read_cntvct_el0, 48462306a36Sopenharmony_ci .set_next_event_phys = erratum_set_next_event_phys, 48562306a36Sopenharmony_ci .set_next_event_virt = erratum_set_next_event_virt, 48662306a36Sopenharmony_ci }, 48762306a36Sopenharmony_ci#endif 48862306a36Sopenharmony_ci#ifdef CONFIG_ARM64_ERRATUM_858921 48962306a36Sopenharmony_ci { 49062306a36Sopenharmony_ci .match_type = ate_match_local_cap_id, 49162306a36Sopenharmony_ci .id = (void *)ARM64_WORKAROUND_858921, 49262306a36Sopenharmony_ci .desc = "ARM erratum 858921", 49362306a36Sopenharmony_ci .read_cntpct_el0 = arm64_858921_read_cntpct_el0, 49462306a36Sopenharmony_ci .read_cntvct_el0 = arm64_858921_read_cntvct_el0, 49562306a36Sopenharmony_ci .set_next_event_phys = erratum_set_next_event_phys, 49662306a36Sopenharmony_ci .set_next_event_virt = erratum_set_next_event_virt, 49762306a36Sopenharmony_ci }, 49862306a36Sopenharmony_ci#endif 49962306a36Sopenharmony_ci#ifdef CONFIG_SUN50I_ERRATUM_UNKNOWN1 50062306a36Sopenharmony_ci { 50162306a36Sopenharmony_ci .match_type = ate_match_dt, 50262306a36Sopenharmony_ci .id = "allwinner,erratum-unknown1", 50362306a36Sopenharmony_ci .desc = "Allwinner erratum UNKNOWN1", 50462306a36Sopenharmony_ci .read_cntpct_el0 = sun50i_a64_read_cntpct_el0, 50562306a36Sopenharmony_ci .read_cntvct_el0 = sun50i_a64_read_cntvct_el0, 50662306a36Sopenharmony_ci .set_next_event_phys = erratum_set_next_event_phys, 50762306a36Sopenharmony_ci .set_next_event_virt = erratum_set_next_event_virt, 50862306a36Sopenharmony_ci }, 50962306a36Sopenharmony_ci#endif 51062306a36Sopenharmony_ci#ifdef CONFIG_ARM64_ERRATUM_1418040 51162306a36Sopenharmony_ci { 51262306a36Sopenharmony_ci .match_type = ate_match_local_cap_id, 51362306a36Sopenharmony_ci .id = (void *)ARM64_WORKAROUND_1418040, 51462306a36Sopenharmony_ci .desc = "ARM erratum 1418040", 51562306a36Sopenharmony_ci .disable_compat_vdso = true, 51662306a36Sopenharmony_ci }, 51762306a36Sopenharmony_ci#endif 51862306a36Sopenharmony_ci}; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_citypedef bool (*ate_match_fn_t)(const struct arch_timer_erratum_workaround *, 52162306a36Sopenharmony_ci const void *); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_cistatic 52462306a36Sopenharmony_cibool arch_timer_check_dt_erratum(const struct arch_timer_erratum_workaround *wa, 52562306a36Sopenharmony_ci const void *arg) 52662306a36Sopenharmony_ci{ 52762306a36Sopenharmony_ci const struct device_node *np = arg; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci return of_property_read_bool(np, wa->id); 53062306a36Sopenharmony_ci} 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_cistatic 53362306a36Sopenharmony_cibool arch_timer_check_local_cap_erratum(const struct arch_timer_erratum_workaround *wa, 53462306a36Sopenharmony_ci const void *arg) 53562306a36Sopenharmony_ci{ 53662306a36Sopenharmony_ci return this_cpu_has_cap((uintptr_t)wa->id); 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_cistatic 54162306a36Sopenharmony_cibool arch_timer_check_acpi_oem_erratum(const struct arch_timer_erratum_workaround *wa, 54262306a36Sopenharmony_ci const void *arg) 54362306a36Sopenharmony_ci{ 54462306a36Sopenharmony_ci static const struct ate_acpi_oem_info empty_oem_info = {}; 54562306a36Sopenharmony_ci const struct ate_acpi_oem_info *info = wa->id; 54662306a36Sopenharmony_ci const struct acpi_table_header *table = arg; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci /* Iterate over the ACPI OEM info array, looking for a match */ 54962306a36Sopenharmony_ci while (memcmp(info, &empty_oem_info, sizeof(*info))) { 55062306a36Sopenharmony_ci if (!memcmp(info->oem_id, table->oem_id, ACPI_OEM_ID_SIZE) && 55162306a36Sopenharmony_ci !memcmp(info->oem_table_id, table->oem_table_id, ACPI_OEM_TABLE_ID_SIZE) && 55262306a36Sopenharmony_ci info->oem_revision == table->oem_revision) 55362306a36Sopenharmony_ci return true; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci info++; 55662306a36Sopenharmony_ci } 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci return false; 55962306a36Sopenharmony_ci} 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_cistatic const struct arch_timer_erratum_workaround * 56262306a36Sopenharmony_ciarch_timer_iterate_errata(enum arch_timer_erratum_match_type type, 56362306a36Sopenharmony_ci ate_match_fn_t match_fn, 56462306a36Sopenharmony_ci void *arg) 56562306a36Sopenharmony_ci{ 56662306a36Sopenharmony_ci int i; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ool_workarounds); i++) { 56962306a36Sopenharmony_ci if (ool_workarounds[i].match_type != type) 57062306a36Sopenharmony_ci continue; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci if (match_fn(&ool_workarounds[i], arg)) 57362306a36Sopenharmony_ci return &ool_workarounds[i]; 57462306a36Sopenharmony_ci } 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci return NULL; 57762306a36Sopenharmony_ci} 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_cistatic 58062306a36Sopenharmony_civoid arch_timer_enable_workaround(const struct arch_timer_erratum_workaround *wa, 58162306a36Sopenharmony_ci bool local) 58262306a36Sopenharmony_ci{ 58362306a36Sopenharmony_ci int i; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci if (local) { 58662306a36Sopenharmony_ci __this_cpu_write(timer_unstable_counter_workaround, wa); 58762306a36Sopenharmony_ci } else { 58862306a36Sopenharmony_ci for_each_possible_cpu(i) 58962306a36Sopenharmony_ci per_cpu(timer_unstable_counter_workaround, i) = wa; 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci if (wa->read_cntvct_el0 || wa->read_cntpct_el0) 59362306a36Sopenharmony_ci atomic_set(&timer_unstable_counter_workaround_in_use, 1); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci /* 59662306a36Sopenharmony_ci * Don't use the vdso fastpath if errata require using the 59762306a36Sopenharmony_ci * out-of-line counter accessor. We may change our mind pretty 59862306a36Sopenharmony_ci * late in the game (with a per-CPU erratum, for example), so 59962306a36Sopenharmony_ci * change both the default value and the vdso itself. 60062306a36Sopenharmony_ci */ 60162306a36Sopenharmony_ci if (wa->read_cntvct_el0) { 60262306a36Sopenharmony_ci clocksource_counter.vdso_clock_mode = VDSO_CLOCKMODE_NONE; 60362306a36Sopenharmony_ci vdso_default = VDSO_CLOCKMODE_NONE; 60462306a36Sopenharmony_ci } else if (wa->disable_compat_vdso && vdso_default != VDSO_CLOCKMODE_NONE) { 60562306a36Sopenharmony_ci vdso_default = VDSO_CLOCKMODE_ARCHTIMER_NOCOMPAT; 60662306a36Sopenharmony_ci clocksource_counter.vdso_clock_mode = vdso_default; 60762306a36Sopenharmony_ci } 60862306a36Sopenharmony_ci} 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_cistatic void arch_timer_check_ool_workaround(enum arch_timer_erratum_match_type type, 61162306a36Sopenharmony_ci void *arg) 61262306a36Sopenharmony_ci{ 61362306a36Sopenharmony_ci const struct arch_timer_erratum_workaround *wa, *__wa; 61462306a36Sopenharmony_ci ate_match_fn_t match_fn = NULL; 61562306a36Sopenharmony_ci bool local = false; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci switch (type) { 61862306a36Sopenharmony_ci case ate_match_dt: 61962306a36Sopenharmony_ci match_fn = arch_timer_check_dt_erratum; 62062306a36Sopenharmony_ci break; 62162306a36Sopenharmony_ci case ate_match_local_cap_id: 62262306a36Sopenharmony_ci match_fn = arch_timer_check_local_cap_erratum; 62362306a36Sopenharmony_ci local = true; 62462306a36Sopenharmony_ci break; 62562306a36Sopenharmony_ci case ate_match_acpi_oem_info: 62662306a36Sopenharmony_ci match_fn = arch_timer_check_acpi_oem_erratum; 62762306a36Sopenharmony_ci break; 62862306a36Sopenharmony_ci default: 62962306a36Sopenharmony_ci WARN_ON(1); 63062306a36Sopenharmony_ci return; 63162306a36Sopenharmony_ci } 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci wa = arch_timer_iterate_errata(type, match_fn, arg); 63462306a36Sopenharmony_ci if (!wa) 63562306a36Sopenharmony_ci return; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci __wa = __this_cpu_read(timer_unstable_counter_workaround); 63862306a36Sopenharmony_ci if (__wa && wa != __wa) 63962306a36Sopenharmony_ci pr_warn("Can't enable workaround for %s (clashes with %s\n)", 64062306a36Sopenharmony_ci wa->desc, __wa->desc); 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci if (__wa) 64362306a36Sopenharmony_ci return; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci arch_timer_enable_workaround(wa, local); 64662306a36Sopenharmony_ci pr_info("Enabling %s workaround for %s\n", 64762306a36Sopenharmony_ci local ? "local" : "global", wa->desc); 64862306a36Sopenharmony_ci} 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_cistatic bool arch_timer_this_cpu_has_cntvct_wa(void) 65162306a36Sopenharmony_ci{ 65262306a36Sopenharmony_ci return has_erratum_handler(read_cntvct_el0); 65362306a36Sopenharmony_ci} 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_cistatic bool arch_timer_counter_has_wa(void) 65662306a36Sopenharmony_ci{ 65762306a36Sopenharmony_ci return atomic_read(&timer_unstable_counter_workaround_in_use); 65862306a36Sopenharmony_ci} 65962306a36Sopenharmony_ci#else 66062306a36Sopenharmony_ci#define arch_timer_check_ool_workaround(t,a) do { } while(0) 66162306a36Sopenharmony_ci#define arch_timer_this_cpu_has_cntvct_wa() ({false;}) 66262306a36Sopenharmony_ci#define arch_timer_counter_has_wa() ({false;}) 66362306a36Sopenharmony_ci#endif /* CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND */ 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_cistatic __always_inline irqreturn_t timer_handler(const int access, 66662306a36Sopenharmony_ci struct clock_event_device *evt) 66762306a36Sopenharmony_ci{ 66862306a36Sopenharmony_ci unsigned long ctrl; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL, evt); 67162306a36Sopenharmony_ci if (ctrl & ARCH_TIMER_CTRL_IT_STAT) { 67262306a36Sopenharmony_ci ctrl |= ARCH_TIMER_CTRL_IT_MASK; 67362306a36Sopenharmony_ci arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, evt); 67462306a36Sopenharmony_ci evt->event_handler(evt); 67562306a36Sopenharmony_ci return IRQ_HANDLED; 67662306a36Sopenharmony_ci } 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci return IRQ_NONE; 67962306a36Sopenharmony_ci} 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_cistatic irqreturn_t arch_timer_handler_virt(int irq, void *dev_id) 68262306a36Sopenharmony_ci{ 68362306a36Sopenharmony_ci struct clock_event_device *evt = dev_id; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci return timer_handler(ARCH_TIMER_VIRT_ACCESS, evt); 68662306a36Sopenharmony_ci} 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_cistatic irqreturn_t arch_timer_handler_phys(int irq, void *dev_id) 68962306a36Sopenharmony_ci{ 69062306a36Sopenharmony_ci struct clock_event_device *evt = dev_id; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci return timer_handler(ARCH_TIMER_PHYS_ACCESS, evt); 69362306a36Sopenharmony_ci} 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_cistatic irqreturn_t arch_timer_handler_phys_mem(int irq, void *dev_id) 69662306a36Sopenharmony_ci{ 69762306a36Sopenharmony_ci struct clock_event_device *evt = dev_id; 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci return timer_handler(ARCH_TIMER_MEM_PHYS_ACCESS, evt); 70062306a36Sopenharmony_ci} 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_cistatic irqreturn_t arch_timer_handler_virt_mem(int irq, void *dev_id) 70362306a36Sopenharmony_ci{ 70462306a36Sopenharmony_ci struct clock_event_device *evt = dev_id; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci return timer_handler(ARCH_TIMER_MEM_VIRT_ACCESS, evt); 70762306a36Sopenharmony_ci} 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_cistatic __always_inline int arch_timer_shutdown(const int access, 71062306a36Sopenharmony_ci struct clock_event_device *clk) 71162306a36Sopenharmony_ci{ 71262306a36Sopenharmony_ci unsigned long ctrl; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL, clk); 71562306a36Sopenharmony_ci ctrl &= ~ARCH_TIMER_CTRL_ENABLE; 71662306a36Sopenharmony_ci arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk); 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci return 0; 71962306a36Sopenharmony_ci} 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_cistatic int arch_timer_shutdown_virt(struct clock_event_device *clk) 72262306a36Sopenharmony_ci{ 72362306a36Sopenharmony_ci return arch_timer_shutdown(ARCH_TIMER_VIRT_ACCESS, clk); 72462306a36Sopenharmony_ci} 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_cistatic int arch_timer_shutdown_phys(struct clock_event_device *clk) 72762306a36Sopenharmony_ci{ 72862306a36Sopenharmony_ci return arch_timer_shutdown(ARCH_TIMER_PHYS_ACCESS, clk); 72962306a36Sopenharmony_ci} 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_cistatic int arch_timer_shutdown_virt_mem(struct clock_event_device *clk) 73262306a36Sopenharmony_ci{ 73362306a36Sopenharmony_ci return arch_timer_shutdown(ARCH_TIMER_MEM_VIRT_ACCESS, clk); 73462306a36Sopenharmony_ci} 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_cistatic int arch_timer_shutdown_phys_mem(struct clock_event_device *clk) 73762306a36Sopenharmony_ci{ 73862306a36Sopenharmony_ci return arch_timer_shutdown(ARCH_TIMER_MEM_PHYS_ACCESS, clk); 73962306a36Sopenharmony_ci} 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_cistatic __always_inline void set_next_event(const int access, unsigned long evt, 74262306a36Sopenharmony_ci struct clock_event_device *clk) 74362306a36Sopenharmony_ci{ 74462306a36Sopenharmony_ci unsigned long ctrl; 74562306a36Sopenharmony_ci u64 cnt; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL, clk); 74862306a36Sopenharmony_ci ctrl |= ARCH_TIMER_CTRL_ENABLE; 74962306a36Sopenharmony_ci ctrl &= ~ARCH_TIMER_CTRL_IT_MASK; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci if (access == ARCH_TIMER_PHYS_ACCESS) 75262306a36Sopenharmony_ci cnt = __arch_counter_get_cntpct(); 75362306a36Sopenharmony_ci else 75462306a36Sopenharmony_ci cnt = __arch_counter_get_cntvct(); 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci arch_timer_reg_write(access, ARCH_TIMER_REG_CVAL, evt + cnt, clk); 75762306a36Sopenharmony_ci arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk); 75862306a36Sopenharmony_ci} 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_cistatic int arch_timer_set_next_event_virt(unsigned long evt, 76162306a36Sopenharmony_ci struct clock_event_device *clk) 76262306a36Sopenharmony_ci{ 76362306a36Sopenharmony_ci set_next_event(ARCH_TIMER_VIRT_ACCESS, evt, clk); 76462306a36Sopenharmony_ci return 0; 76562306a36Sopenharmony_ci} 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_cistatic int arch_timer_set_next_event_phys(unsigned long evt, 76862306a36Sopenharmony_ci struct clock_event_device *clk) 76962306a36Sopenharmony_ci{ 77062306a36Sopenharmony_ci set_next_event(ARCH_TIMER_PHYS_ACCESS, evt, clk); 77162306a36Sopenharmony_ci return 0; 77262306a36Sopenharmony_ci} 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_cistatic noinstr u64 arch_counter_get_cnt_mem(struct arch_timer *t, int offset_lo) 77562306a36Sopenharmony_ci{ 77662306a36Sopenharmony_ci u32 cnt_lo, cnt_hi, tmp_hi; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci do { 77962306a36Sopenharmony_ci cnt_hi = __le32_to_cpu((__le32 __force)__raw_readl(t->base + offset_lo + 4)); 78062306a36Sopenharmony_ci cnt_lo = __le32_to_cpu((__le32 __force)__raw_readl(t->base + offset_lo)); 78162306a36Sopenharmony_ci tmp_hi = __le32_to_cpu((__le32 __force)__raw_readl(t->base + offset_lo + 4)); 78262306a36Sopenharmony_ci } while (cnt_hi != tmp_hi); 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci return ((u64) cnt_hi << 32) | cnt_lo; 78562306a36Sopenharmony_ci} 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_cistatic __always_inline void set_next_event_mem(const int access, unsigned long evt, 78862306a36Sopenharmony_ci struct clock_event_device *clk) 78962306a36Sopenharmony_ci{ 79062306a36Sopenharmony_ci struct arch_timer *timer = to_arch_timer(clk); 79162306a36Sopenharmony_ci unsigned long ctrl; 79262306a36Sopenharmony_ci u64 cnt; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL, clk); 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci /* Timer must be disabled before programming CVAL */ 79762306a36Sopenharmony_ci if (ctrl & ARCH_TIMER_CTRL_ENABLE) { 79862306a36Sopenharmony_ci ctrl &= ~ARCH_TIMER_CTRL_ENABLE; 79962306a36Sopenharmony_ci arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk); 80062306a36Sopenharmony_ci } 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci ctrl |= ARCH_TIMER_CTRL_ENABLE; 80362306a36Sopenharmony_ci ctrl &= ~ARCH_TIMER_CTRL_IT_MASK; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci if (access == ARCH_TIMER_MEM_VIRT_ACCESS) 80662306a36Sopenharmony_ci cnt = arch_counter_get_cnt_mem(timer, CNTVCT_LO); 80762306a36Sopenharmony_ci else 80862306a36Sopenharmony_ci cnt = arch_counter_get_cnt_mem(timer, CNTPCT_LO); 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci arch_timer_reg_write(access, ARCH_TIMER_REG_CVAL, evt + cnt, clk); 81162306a36Sopenharmony_ci arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk); 81262306a36Sopenharmony_ci} 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_cistatic int arch_timer_set_next_event_virt_mem(unsigned long evt, 81562306a36Sopenharmony_ci struct clock_event_device *clk) 81662306a36Sopenharmony_ci{ 81762306a36Sopenharmony_ci set_next_event_mem(ARCH_TIMER_MEM_VIRT_ACCESS, evt, clk); 81862306a36Sopenharmony_ci return 0; 81962306a36Sopenharmony_ci} 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_cistatic int arch_timer_set_next_event_phys_mem(unsigned long evt, 82262306a36Sopenharmony_ci struct clock_event_device *clk) 82362306a36Sopenharmony_ci{ 82462306a36Sopenharmony_ci set_next_event_mem(ARCH_TIMER_MEM_PHYS_ACCESS, evt, clk); 82562306a36Sopenharmony_ci return 0; 82662306a36Sopenharmony_ci} 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_cistatic u64 __arch_timer_check_delta(void) 82962306a36Sopenharmony_ci{ 83062306a36Sopenharmony_ci#ifdef CONFIG_ARM64 83162306a36Sopenharmony_ci const struct midr_range broken_cval_midrs[] = { 83262306a36Sopenharmony_ci /* 83362306a36Sopenharmony_ci * XGene-1 implements CVAL in terms of TVAL, meaning 83462306a36Sopenharmony_ci * that the maximum timer range is 32bit. Shame on them. 83562306a36Sopenharmony_ci * 83662306a36Sopenharmony_ci * Note that TVAL is signed, thus has only 31 of its 83762306a36Sopenharmony_ci * 32 bits to express magnitude. 83862306a36Sopenharmony_ci */ 83962306a36Sopenharmony_ci MIDR_REV_RANGE(MIDR_CPU_MODEL(ARM_CPU_IMP_APM, 84062306a36Sopenharmony_ci APM_CPU_PART_XGENE), 84162306a36Sopenharmony_ci APM_CPU_VAR_POTENZA, 0x0, 0xf), 84262306a36Sopenharmony_ci {}, 84362306a36Sopenharmony_ci }; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci if (is_midr_in_range_list(read_cpuid_id(), broken_cval_midrs)) { 84662306a36Sopenharmony_ci pr_warn_once("Broken CNTx_CVAL_EL1, using 31 bit TVAL instead.\n"); 84762306a36Sopenharmony_ci return CLOCKSOURCE_MASK(31); 84862306a36Sopenharmony_ci } 84962306a36Sopenharmony_ci#endif 85062306a36Sopenharmony_ci return CLOCKSOURCE_MASK(arch_counter_get_width()); 85162306a36Sopenharmony_ci} 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_cistatic void __arch_timer_setup(unsigned type, 85462306a36Sopenharmony_ci struct clock_event_device *clk) 85562306a36Sopenharmony_ci{ 85662306a36Sopenharmony_ci u64 max_delta; 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci clk->features = CLOCK_EVT_FEAT_ONESHOT; 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci if (type == ARCH_TIMER_TYPE_CP15) { 86162306a36Sopenharmony_ci typeof(clk->set_next_event) sne; 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci arch_timer_check_ool_workaround(ate_match_local_cap_id, NULL); 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci if (arch_timer_c3stop) 86662306a36Sopenharmony_ci clk->features |= CLOCK_EVT_FEAT_C3STOP; 86762306a36Sopenharmony_ci clk->name = "arch_sys_timer"; 86862306a36Sopenharmony_ci clk->rating = 450; 86962306a36Sopenharmony_ci clk->cpumask = cpumask_of(smp_processor_id()); 87062306a36Sopenharmony_ci clk->irq = arch_timer_ppi[arch_timer_uses_ppi]; 87162306a36Sopenharmony_ci switch (arch_timer_uses_ppi) { 87262306a36Sopenharmony_ci case ARCH_TIMER_VIRT_PPI: 87362306a36Sopenharmony_ci clk->set_state_shutdown = arch_timer_shutdown_virt; 87462306a36Sopenharmony_ci clk->set_state_oneshot_stopped = arch_timer_shutdown_virt; 87562306a36Sopenharmony_ci sne = erratum_handler(set_next_event_virt); 87662306a36Sopenharmony_ci break; 87762306a36Sopenharmony_ci case ARCH_TIMER_PHYS_SECURE_PPI: 87862306a36Sopenharmony_ci case ARCH_TIMER_PHYS_NONSECURE_PPI: 87962306a36Sopenharmony_ci case ARCH_TIMER_HYP_PPI: 88062306a36Sopenharmony_ci clk->set_state_shutdown = arch_timer_shutdown_phys; 88162306a36Sopenharmony_ci clk->set_state_oneshot_stopped = arch_timer_shutdown_phys; 88262306a36Sopenharmony_ci sne = erratum_handler(set_next_event_phys); 88362306a36Sopenharmony_ci break; 88462306a36Sopenharmony_ci default: 88562306a36Sopenharmony_ci BUG(); 88662306a36Sopenharmony_ci } 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci clk->set_next_event = sne; 88962306a36Sopenharmony_ci max_delta = __arch_timer_check_delta(); 89062306a36Sopenharmony_ci } else { 89162306a36Sopenharmony_ci clk->features |= CLOCK_EVT_FEAT_DYNIRQ; 89262306a36Sopenharmony_ci clk->name = "arch_mem_timer"; 89362306a36Sopenharmony_ci clk->rating = 400; 89462306a36Sopenharmony_ci clk->cpumask = cpu_possible_mask; 89562306a36Sopenharmony_ci if (arch_timer_mem_use_virtual) { 89662306a36Sopenharmony_ci clk->set_state_shutdown = arch_timer_shutdown_virt_mem; 89762306a36Sopenharmony_ci clk->set_state_oneshot_stopped = arch_timer_shutdown_virt_mem; 89862306a36Sopenharmony_ci clk->set_next_event = 89962306a36Sopenharmony_ci arch_timer_set_next_event_virt_mem; 90062306a36Sopenharmony_ci } else { 90162306a36Sopenharmony_ci clk->set_state_shutdown = arch_timer_shutdown_phys_mem; 90262306a36Sopenharmony_ci clk->set_state_oneshot_stopped = arch_timer_shutdown_phys_mem; 90362306a36Sopenharmony_ci clk->set_next_event = 90462306a36Sopenharmony_ci arch_timer_set_next_event_phys_mem; 90562306a36Sopenharmony_ci } 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci max_delta = CLOCKSOURCE_MASK(56); 90862306a36Sopenharmony_ci } 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci clk->set_state_shutdown(clk); 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci clockevents_config_and_register(clk, arch_timer_rate, 0xf, max_delta); 91362306a36Sopenharmony_ci} 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_cistatic void arch_timer_evtstrm_enable(unsigned int divider) 91662306a36Sopenharmony_ci{ 91762306a36Sopenharmony_ci u32 cntkctl = arch_timer_get_cntkctl(); 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci#ifdef CONFIG_ARM64 92062306a36Sopenharmony_ci /* ECV is likely to require a large divider. Use the EVNTIS flag. */ 92162306a36Sopenharmony_ci if (cpus_have_const_cap(ARM64_HAS_ECV) && divider > 15) { 92262306a36Sopenharmony_ci cntkctl |= ARCH_TIMER_EVT_INTERVAL_SCALE; 92362306a36Sopenharmony_ci divider -= 8; 92462306a36Sopenharmony_ci } 92562306a36Sopenharmony_ci#endif 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci divider = min(divider, 15U); 92862306a36Sopenharmony_ci cntkctl &= ~ARCH_TIMER_EVT_TRIGGER_MASK; 92962306a36Sopenharmony_ci /* Set the divider and enable virtual event stream */ 93062306a36Sopenharmony_ci cntkctl |= (divider << ARCH_TIMER_EVT_TRIGGER_SHIFT) 93162306a36Sopenharmony_ci | ARCH_TIMER_VIRT_EVT_EN; 93262306a36Sopenharmony_ci arch_timer_set_cntkctl(cntkctl); 93362306a36Sopenharmony_ci arch_timer_set_evtstrm_feature(); 93462306a36Sopenharmony_ci cpumask_set_cpu(smp_processor_id(), &evtstrm_available); 93562306a36Sopenharmony_ci} 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_cistatic void arch_timer_configure_evtstream(void) 93862306a36Sopenharmony_ci{ 93962306a36Sopenharmony_ci int evt_stream_div, lsb; 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci /* 94262306a36Sopenharmony_ci * As the event stream can at most be generated at half the frequency 94362306a36Sopenharmony_ci * of the counter, use half the frequency when computing the divider. 94462306a36Sopenharmony_ci */ 94562306a36Sopenharmony_ci evt_stream_div = arch_timer_rate / ARCH_TIMER_EVT_STREAM_FREQ / 2; 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci /* 94862306a36Sopenharmony_ci * Find the closest power of two to the divisor. If the adjacent bit 94962306a36Sopenharmony_ci * of lsb (last set bit, starts from 0) is set, then we use (lsb + 1). 95062306a36Sopenharmony_ci */ 95162306a36Sopenharmony_ci lsb = fls(evt_stream_div) - 1; 95262306a36Sopenharmony_ci if (lsb > 0 && (evt_stream_div & BIT(lsb - 1))) 95362306a36Sopenharmony_ci lsb++; 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci /* enable event stream */ 95662306a36Sopenharmony_ci arch_timer_evtstrm_enable(max(0, lsb)); 95762306a36Sopenharmony_ci} 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_cistatic void arch_counter_set_user_access(void) 96062306a36Sopenharmony_ci{ 96162306a36Sopenharmony_ci u32 cntkctl = arch_timer_get_cntkctl(); 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci /* Disable user access to the timers and both counters */ 96462306a36Sopenharmony_ci /* Also disable virtual event stream */ 96562306a36Sopenharmony_ci cntkctl &= ~(ARCH_TIMER_USR_PT_ACCESS_EN 96662306a36Sopenharmony_ci | ARCH_TIMER_USR_VT_ACCESS_EN 96762306a36Sopenharmony_ci | ARCH_TIMER_USR_VCT_ACCESS_EN 96862306a36Sopenharmony_ci | ARCH_TIMER_VIRT_EVT_EN 96962306a36Sopenharmony_ci | ARCH_TIMER_USR_PCT_ACCESS_EN); 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci /* 97262306a36Sopenharmony_ci * Enable user access to the virtual counter if it doesn't 97362306a36Sopenharmony_ci * need to be workaround. The vdso may have been already 97462306a36Sopenharmony_ci * disabled though. 97562306a36Sopenharmony_ci */ 97662306a36Sopenharmony_ci if (arch_timer_this_cpu_has_cntvct_wa()) 97762306a36Sopenharmony_ci pr_info("CPU%d: Trapping CNTVCT access\n", smp_processor_id()); 97862306a36Sopenharmony_ci else 97962306a36Sopenharmony_ci cntkctl |= ARCH_TIMER_USR_VCT_ACCESS_EN; 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci arch_timer_set_cntkctl(cntkctl); 98262306a36Sopenharmony_ci} 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_cistatic bool arch_timer_has_nonsecure_ppi(void) 98562306a36Sopenharmony_ci{ 98662306a36Sopenharmony_ci return (arch_timer_uses_ppi == ARCH_TIMER_PHYS_SECURE_PPI && 98762306a36Sopenharmony_ci arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI]); 98862306a36Sopenharmony_ci} 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_cistatic u32 check_ppi_trigger(int irq) 99162306a36Sopenharmony_ci{ 99262306a36Sopenharmony_ci u32 flags = irq_get_trigger_type(irq); 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci if (flags != IRQF_TRIGGER_HIGH && flags != IRQF_TRIGGER_LOW) { 99562306a36Sopenharmony_ci pr_warn("WARNING: Invalid trigger for IRQ%d, assuming level low\n", irq); 99662306a36Sopenharmony_ci pr_warn("WARNING: Please fix your firmware\n"); 99762306a36Sopenharmony_ci flags = IRQF_TRIGGER_LOW; 99862306a36Sopenharmony_ci } 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci return flags; 100162306a36Sopenharmony_ci} 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_cistatic int arch_timer_starting_cpu(unsigned int cpu) 100462306a36Sopenharmony_ci{ 100562306a36Sopenharmony_ci struct clock_event_device *clk = this_cpu_ptr(arch_timer_evt); 100662306a36Sopenharmony_ci u32 flags; 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci __arch_timer_setup(ARCH_TIMER_TYPE_CP15, clk); 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci flags = check_ppi_trigger(arch_timer_ppi[arch_timer_uses_ppi]); 101162306a36Sopenharmony_ci enable_percpu_irq(arch_timer_ppi[arch_timer_uses_ppi], flags); 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci if (arch_timer_has_nonsecure_ppi()) { 101462306a36Sopenharmony_ci flags = check_ppi_trigger(arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI]); 101562306a36Sopenharmony_ci enable_percpu_irq(arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI], 101662306a36Sopenharmony_ci flags); 101762306a36Sopenharmony_ci } 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci arch_counter_set_user_access(); 102062306a36Sopenharmony_ci if (evtstrm_enable) 102162306a36Sopenharmony_ci arch_timer_configure_evtstream(); 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci return 0; 102462306a36Sopenharmony_ci} 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_cistatic int validate_timer_rate(void) 102762306a36Sopenharmony_ci{ 102862306a36Sopenharmony_ci if (!arch_timer_rate) 102962306a36Sopenharmony_ci return -EINVAL; 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci /* Arch timer frequency < 1MHz can cause trouble */ 103262306a36Sopenharmony_ci WARN_ON(arch_timer_rate < 1000000); 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci return 0; 103562306a36Sopenharmony_ci} 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci/* 103862306a36Sopenharmony_ci * For historical reasons, when probing with DT we use whichever (non-zero) 103962306a36Sopenharmony_ci * rate was probed first, and don't verify that others match. If the first node 104062306a36Sopenharmony_ci * probed has a clock-frequency property, this overrides the HW register. 104162306a36Sopenharmony_ci */ 104262306a36Sopenharmony_cistatic void __init arch_timer_of_configure_rate(u32 rate, struct device_node *np) 104362306a36Sopenharmony_ci{ 104462306a36Sopenharmony_ci /* Who has more than one independent system counter? */ 104562306a36Sopenharmony_ci if (arch_timer_rate) 104662306a36Sopenharmony_ci return; 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci if (of_property_read_u32(np, "clock-frequency", &arch_timer_rate)) 104962306a36Sopenharmony_ci arch_timer_rate = rate; 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci /* Check the timer frequency. */ 105262306a36Sopenharmony_ci if (validate_timer_rate()) 105362306a36Sopenharmony_ci pr_warn("frequency not available\n"); 105462306a36Sopenharmony_ci} 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_cistatic void __init arch_timer_banner(unsigned type) 105762306a36Sopenharmony_ci{ 105862306a36Sopenharmony_ci pr_info("%s%s%s timer(s) running at %lu.%02luMHz (%s%s%s).\n", 105962306a36Sopenharmony_ci type & ARCH_TIMER_TYPE_CP15 ? "cp15" : "", 106062306a36Sopenharmony_ci type == (ARCH_TIMER_TYPE_CP15 | ARCH_TIMER_TYPE_MEM) ? 106162306a36Sopenharmony_ci " and " : "", 106262306a36Sopenharmony_ci type & ARCH_TIMER_TYPE_MEM ? "mmio" : "", 106362306a36Sopenharmony_ci (unsigned long)arch_timer_rate / 1000000, 106462306a36Sopenharmony_ci (unsigned long)(arch_timer_rate / 10000) % 100, 106562306a36Sopenharmony_ci type & ARCH_TIMER_TYPE_CP15 ? 106662306a36Sopenharmony_ci (arch_timer_uses_ppi == ARCH_TIMER_VIRT_PPI) ? "virt" : "phys" : 106762306a36Sopenharmony_ci "", 106862306a36Sopenharmony_ci type == (ARCH_TIMER_TYPE_CP15 | ARCH_TIMER_TYPE_MEM) ? "/" : "", 106962306a36Sopenharmony_ci type & ARCH_TIMER_TYPE_MEM ? 107062306a36Sopenharmony_ci arch_timer_mem_use_virtual ? "virt" : "phys" : 107162306a36Sopenharmony_ci ""); 107262306a36Sopenharmony_ci} 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ciu32 arch_timer_get_rate(void) 107562306a36Sopenharmony_ci{ 107662306a36Sopenharmony_ci return arch_timer_rate; 107762306a36Sopenharmony_ci} 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_cibool arch_timer_evtstrm_available(void) 108062306a36Sopenharmony_ci{ 108162306a36Sopenharmony_ci /* 108262306a36Sopenharmony_ci * We might get called from a preemptible context. This is fine 108362306a36Sopenharmony_ci * because availability of the event stream should be always the same 108462306a36Sopenharmony_ci * for a preemptible context and context where we might resume a task. 108562306a36Sopenharmony_ci */ 108662306a36Sopenharmony_ci return cpumask_test_cpu(raw_smp_processor_id(), &evtstrm_available); 108762306a36Sopenharmony_ci} 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_cistatic noinstr u64 arch_counter_get_cntvct_mem(void) 109062306a36Sopenharmony_ci{ 109162306a36Sopenharmony_ci return arch_counter_get_cnt_mem(arch_timer_mem, CNTVCT_LO); 109262306a36Sopenharmony_ci} 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_cistatic struct arch_timer_kvm_info arch_timer_kvm_info; 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_cistruct arch_timer_kvm_info *arch_timer_get_kvm_info(void) 109762306a36Sopenharmony_ci{ 109862306a36Sopenharmony_ci return &arch_timer_kvm_info; 109962306a36Sopenharmony_ci} 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_cistatic void __init arch_counter_register(unsigned type) 110262306a36Sopenharmony_ci{ 110362306a36Sopenharmony_ci u64 (*scr)(void); 110462306a36Sopenharmony_ci u64 start_count; 110562306a36Sopenharmony_ci int width; 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci /* Register the CP15 based counter if we have one */ 110862306a36Sopenharmony_ci if (type & ARCH_TIMER_TYPE_CP15) { 110962306a36Sopenharmony_ci u64 (*rd)(void); 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci if ((IS_ENABLED(CONFIG_ARM64) && !is_hyp_mode_available()) || 111262306a36Sopenharmony_ci arch_timer_uses_ppi == ARCH_TIMER_VIRT_PPI) { 111362306a36Sopenharmony_ci if (arch_timer_counter_has_wa()) { 111462306a36Sopenharmony_ci rd = arch_counter_get_cntvct_stable; 111562306a36Sopenharmony_ci scr = raw_counter_get_cntvct_stable; 111662306a36Sopenharmony_ci } else { 111762306a36Sopenharmony_ci rd = arch_counter_get_cntvct; 111862306a36Sopenharmony_ci scr = arch_counter_get_cntvct; 111962306a36Sopenharmony_ci } 112062306a36Sopenharmony_ci } else { 112162306a36Sopenharmony_ci if (arch_timer_counter_has_wa()) { 112262306a36Sopenharmony_ci rd = arch_counter_get_cntpct_stable; 112362306a36Sopenharmony_ci scr = raw_counter_get_cntpct_stable; 112462306a36Sopenharmony_ci } else { 112562306a36Sopenharmony_ci rd = arch_counter_get_cntpct; 112662306a36Sopenharmony_ci scr = arch_counter_get_cntpct; 112762306a36Sopenharmony_ci } 112862306a36Sopenharmony_ci } 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci arch_timer_read_counter = rd; 113162306a36Sopenharmony_ci clocksource_counter.vdso_clock_mode = vdso_default; 113262306a36Sopenharmony_ci } else { 113362306a36Sopenharmony_ci arch_timer_read_counter = arch_counter_get_cntvct_mem; 113462306a36Sopenharmony_ci scr = arch_counter_get_cntvct_mem; 113562306a36Sopenharmony_ci } 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci width = arch_counter_get_width(); 113862306a36Sopenharmony_ci clocksource_counter.mask = CLOCKSOURCE_MASK(width); 113962306a36Sopenharmony_ci cyclecounter.mask = CLOCKSOURCE_MASK(width); 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci if (!arch_counter_suspend_stop) 114262306a36Sopenharmony_ci clocksource_counter.flags |= CLOCK_SOURCE_SUSPEND_NONSTOP; 114362306a36Sopenharmony_ci start_count = arch_timer_read_counter(); 114462306a36Sopenharmony_ci clocksource_register_hz(&clocksource_counter, arch_timer_rate); 114562306a36Sopenharmony_ci cyclecounter.mult = clocksource_counter.mult; 114662306a36Sopenharmony_ci cyclecounter.shift = clocksource_counter.shift; 114762306a36Sopenharmony_ci timecounter_init(&arch_timer_kvm_info.timecounter, 114862306a36Sopenharmony_ci &cyclecounter, start_count); 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci sched_clock_register(scr, width, arch_timer_rate); 115162306a36Sopenharmony_ci} 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_cistatic void arch_timer_stop(struct clock_event_device *clk) 115462306a36Sopenharmony_ci{ 115562306a36Sopenharmony_ci pr_debug("disable IRQ%d cpu #%d\n", clk->irq, smp_processor_id()); 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci disable_percpu_irq(arch_timer_ppi[arch_timer_uses_ppi]); 115862306a36Sopenharmony_ci if (arch_timer_has_nonsecure_ppi()) 115962306a36Sopenharmony_ci disable_percpu_irq(arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI]); 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci clk->set_state_shutdown(clk); 116262306a36Sopenharmony_ci} 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_cistatic int arch_timer_dying_cpu(unsigned int cpu) 116562306a36Sopenharmony_ci{ 116662306a36Sopenharmony_ci struct clock_event_device *clk = this_cpu_ptr(arch_timer_evt); 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci cpumask_clear_cpu(smp_processor_id(), &evtstrm_available); 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci arch_timer_stop(clk); 117162306a36Sopenharmony_ci return 0; 117262306a36Sopenharmony_ci} 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci#ifdef CONFIG_CPU_PM 117562306a36Sopenharmony_cistatic DEFINE_PER_CPU(unsigned long, saved_cntkctl); 117662306a36Sopenharmony_cistatic int arch_timer_cpu_pm_notify(struct notifier_block *self, 117762306a36Sopenharmony_ci unsigned long action, void *hcpu) 117862306a36Sopenharmony_ci{ 117962306a36Sopenharmony_ci if (action == CPU_PM_ENTER) { 118062306a36Sopenharmony_ci __this_cpu_write(saved_cntkctl, arch_timer_get_cntkctl()); 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci cpumask_clear_cpu(smp_processor_id(), &evtstrm_available); 118362306a36Sopenharmony_ci } else if (action == CPU_PM_ENTER_FAILED || action == CPU_PM_EXIT) { 118462306a36Sopenharmony_ci arch_timer_set_cntkctl(__this_cpu_read(saved_cntkctl)); 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci if (arch_timer_have_evtstrm_feature()) 118762306a36Sopenharmony_ci cpumask_set_cpu(smp_processor_id(), &evtstrm_available); 118862306a36Sopenharmony_ci } 118962306a36Sopenharmony_ci return NOTIFY_OK; 119062306a36Sopenharmony_ci} 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_cistatic struct notifier_block arch_timer_cpu_pm_notifier = { 119362306a36Sopenharmony_ci .notifier_call = arch_timer_cpu_pm_notify, 119462306a36Sopenharmony_ci}; 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_cistatic int __init arch_timer_cpu_pm_init(void) 119762306a36Sopenharmony_ci{ 119862306a36Sopenharmony_ci return cpu_pm_register_notifier(&arch_timer_cpu_pm_notifier); 119962306a36Sopenharmony_ci} 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_cistatic void __init arch_timer_cpu_pm_deinit(void) 120262306a36Sopenharmony_ci{ 120362306a36Sopenharmony_ci WARN_ON(cpu_pm_unregister_notifier(&arch_timer_cpu_pm_notifier)); 120462306a36Sopenharmony_ci} 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci#else 120762306a36Sopenharmony_cistatic int __init arch_timer_cpu_pm_init(void) 120862306a36Sopenharmony_ci{ 120962306a36Sopenharmony_ci return 0; 121062306a36Sopenharmony_ci} 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_cistatic void __init arch_timer_cpu_pm_deinit(void) 121362306a36Sopenharmony_ci{ 121462306a36Sopenharmony_ci} 121562306a36Sopenharmony_ci#endif 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_cistatic int __init arch_timer_register(void) 121862306a36Sopenharmony_ci{ 121962306a36Sopenharmony_ci int err; 122062306a36Sopenharmony_ci int ppi; 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci arch_timer_evt = alloc_percpu(struct clock_event_device); 122362306a36Sopenharmony_ci if (!arch_timer_evt) { 122462306a36Sopenharmony_ci err = -ENOMEM; 122562306a36Sopenharmony_ci goto out; 122662306a36Sopenharmony_ci } 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci ppi = arch_timer_ppi[arch_timer_uses_ppi]; 122962306a36Sopenharmony_ci switch (arch_timer_uses_ppi) { 123062306a36Sopenharmony_ci case ARCH_TIMER_VIRT_PPI: 123162306a36Sopenharmony_ci err = request_percpu_irq(ppi, arch_timer_handler_virt, 123262306a36Sopenharmony_ci "arch_timer", arch_timer_evt); 123362306a36Sopenharmony_ci break; 123462306a36Sopenharmony_ci case ARCH_TIMER_PHYS_SECURE_PPI: 123562306a36Sopenharmony_ci case ARCH_TIMER_PHYS_NONSECURE_PPI: 123662306a36Sopenharmony_ci err = request_percpu_irq(ppi, arch_timer_handler_phys, 123762306a36Sopenharmony_ci "arch_timer", arch_timer_evt); 123862306a36Sopenharmony_ci if (!err && arch_timer_has_nonsecure_ppi()) { 123962306a36Sopenharmony_ci ppi = arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI]; 124062306a36Sopenharmony_ci err = request_percpu_irq(ppi, arch_timer_handler_phys, 124162306a36Sopenharmony_ci "arch_timer", arch_timer_evt); 124262306a36Sopenharmony_ci if (err) 124362306a36Sopenharmony_ci free_percpu_irq(arch_timer_ppi[ARCH_TIMER_PHYS_SECURE_PPI], 124462306a36Sopenharmony_ci arch_timer_evt); 124562306a36Sopenharmony_ci } 124662306a36Sopenharmony_ci break; 124762306a36Sopenharmony_ci case ARCH_TIMER_HYP_PPI: 124862306a36Sopenharmony_ci err = request_percpu_irq(ppi, arch_timer_handler_phys, 124962306a36Sopenharmony_ci "arch_timer", arch_timer_evt); 125062306a36Sopenharmony_ci break; 125162306a36Sopenharmony_ci default: 125262306a36Sopenharmony_ci BUG(); 125362306a36Sopenharmony_ci } 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci if (err) { 125662306a36Sopenharmony_ci pr_err("can't register interrupt %d (%d)\n", ppi, err); 125762306a36Sopenharmony_ci goto out_free; 125862306a36Sopenharmony_ci } 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci err = arch_timer_cpu_pm_init(); 126162306a36Sopenharmony_ci if (err) 126262306a36Sopenharmony_ci goto out_unreg_notify; 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci /* Register and immediately configure the timer on the boot CPU */ 126562306a36Sopenharmony_ci err = cpuhp_setup_state(CPUHP_AP_ARM_ARCH_TIMER_STARTING, 126662306a36Sopenharmony_ci "clockevents/arm/arch_timer:starting", 126762306a36Sopenharmony_ci arch_timer_starting_cpu, arch_timer_dying_cpu); 126862306a36Sopenharmony_ci if (err) 126962306a36Sopenharmony_ci goto out_unreg_cpupm; 127062306a36Sopenharmony_ci return 0; 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ciout_unreg_cpupm: 127362306a36Sopenharmony_ci arch_timer_cpu_pm_deinit(); 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ciout_unreg_notify: 127662306a36Sopenharmony_ci free_percpu_irq(arch_timer_ppi[arch_timer_uses_ppi], arch_timer_evt); 127762306a36Sopenharmony_ci if (arch_timer_has_nonsecure_ppi()) 127862306a36Sopenharmony_ci free_percpu_irq(arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI], 127962306a36Sopenharmony_ci arch_timer_evt); 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ciout_free: 128262306a36Sopenharmony_ci free_percpu(arch_timer_evt); 128362306a36Sopenharmony_ciout: 128462306a36Sopenharmony_ci return err; 128562306a36Sopenharmony_ci} 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_cistatic int __init arch_timer_mem_register(void __iomem *base, unsigned int irq) 128862306a36Sopenharmony_ci{ 128962306a36Sopenharmony_ci int ret; 129062306a36Sopenharmony_ci irq_handler_t func; 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci arch_timer_mem = kzalloc(sizeof(*arch_timer_mem), GFP_KERNEL); 129362306a36Sopenharmony_ci if (!arch_timer_mem) 129462306a36Sopenharmony_ci return -ENOMEM; 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci arch_timer_mem->base = base; 129762306a36Sopenharmony_ci arch_timer_mem->evt.irq = irq; 129862306a36Sopenharmony_ci __arch_timer_setup(ARCH_TIMER_TYPE_MEM, &arch_timer_mem->evt); 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci if (arch_timer_mem_use_virtual) 130162306a36Sopenharmony_ci func = arch_timer_handler_virt_mem; 130262306a36Sopenharmony_ci else 130362306a36Sopenharmony_ci func = arch_timer_handler_phys_mem; 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci ret = request_irq(irq, func, IRQF_TIMER, "arch_mem_timer", &arch_timer_mem->evt); 130662306a36Sopenharmony_ci if (ret) { 130762306a36Sopenharmony_ci pr_err("Failed to request mem timer irq\n"); 130862306a36Sopenharmony_ci kfree(arch_timer_mem); 130962306a36Sopenharmony_ci arch_timer_mem = NULL; 131062306a36Sopenharmony_ci } 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci return ret; 131362306a36Sopenharmony_ci} 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_cistatic const struct of_device_id arch_timer_of_match[] __initconst = { 131662306a36Sopenharmony_ci { .compatible = "arm,armv7-timer", }, 131762306a36Sopenharmony_ci { .compatible = "arm,armv8-timer", }, 131862306a36Sopenharmony_ci {}, 131962306a36Sopenharmony_ci}; 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_cistatic const struct of_device_id arch_timer_mem_of_match[] __initconst = { 132262306a36Sopenharmony_ci { .compatible = "arm,armv7-timer-mem", }, 132362306a36Sopenharmony_ci {}, 132462306a36Sopenharmony_ci}; 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_cistatic bool __init arch_timer_needs_of_probing(void) 132762306a36Sopenharmony_ci{ 132862306a36Sopenharmony_ci struct device_node *dn; 132962306a36Sopenharmony_ci bool needs_probing = false; 133062306a36Sopenharmony_ci unsigned int mask = ARCH_TIMER_TYPE_CP15 | ARCH_TIMER_TYPE_MEM; 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci /* We have two timers, and both device-tree nodes are probed. */ 133362306a36Sopenharmony_ci if ((arch_timers_present & mask) == mask) 133462306a36Sopenharmony_ci return false; 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci /* 133762306a36Sopenharmony_ci * Only one type of timer is probed, 133862306a36Sopenharmony_ci * check if we have another type of timer node in device-tree. 133962306a36Sopenharmony_ci */ 134062306a36Sopenharmony_ci if (arch_timers_present & ARCH_TIMER_TYPE_CP15) 134162306a36Sopenharmony_ci dn = of_find_matching_node(NULL, arch_timer_mem_of_match); 134262306a36Sopenharmony_ci else 134362306a36Sopenharmony_ci dn = of_find_matching_node(NULL, arch_timer_of_match); 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci if (dn && of_device_is_available(dn)) 134662306a36Sopenharmony_ci needs_probing = true; 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci of_node_put(dn); 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci return needs_probing; 135162306a36Sopenharmony_ci} 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_cistatic int __init arch_timer_common_init(void) 135462306a36Sopenharmony_ci{ 135562306a36Sopenharmony_ci arch_timer_banner(arch_timers_present); 135662306a36Sopenharmony_ci arch_counter_register(arch_timers_present); 135762306a36Sopenharmony_ci return arch_timer_arch_init(); 135862306a36Sopenharmony_ci} 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci/** 136162306a36Sopenharmony_ci * arch_timer_select_ppi() - Select suitable PPI for the current system. 136262306a36Sopenharmony_ci * 136362306a36Sopenharmony_ci * If HYP mode is available, we know that the physical timer 136462306a36Sopenharmony_ci * has been configured to be accessible from PL1. Use it, so 136562306a36Sopenharmony_ci * that a guest can use the virtual timer instead. 136662306a36Sopenharmony_ci * 136762306a36Sopenharmony_ci * On ARMv8.1 with VH extensions, the kernel runs in HYP. VHE 136862306a36Sopenharmony_ci * accesses to CNTP_*_EL1 registers are silently redirected to 136962306a36Sopenharmony_ci * their CNTHP_*_EL2 counterparts, and use a different PPI 137062306a36Sopenharmony_ci * number. 137162306a36Sopenharmony_ci * 137262306a36Sopenharmony_ci * If no interrupt provided for virtual timer, we'll have to 137362306a36Sopenharmony_ci * stick to the physical timer. It'd better be accessible... 137462306a36Sopenharmony_ci * For arm64 we never use the secure interrupt. 137562306a36Sopenharmony_ci * 137662306a36Sopenharmony_ci * Return: a suitable PPI type for the current system. 137762306a36Sopenharmony_ci */ 137862306a36Sopenharmony_cistatic enum arch_timer_ppi_nr __init arch_timer_select_ppi(void) 137962306a36Sopenharmony_ci{ 138062306a36Sopenharmony_ci if (is_kernel_in_hyp_mode()) 138162306a36Sopenharmony_ci return ARCH_TIMER_HYP_PPI; 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci if (!is_hyp_mode_available() && arch_timer_ppi[ARCH_TIMER_VIRT_PPI]) 138462306a36Sopenharmony_ci return ARCH_TIMER_VIRT_PPI; 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_ARM64)) 138762306a36Sopenharmony_ci return ARCH_TIMER_PHYS_NONSECURE_PPI; 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_ci return ARCH_TIMER_PHYS_SECURE_PPI; 139062306a36Sopenharmony_ci} 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_cistatic void __init arch_timer_populate_kvm_info(void) 139362306a36Sopenharmony_ci{ 139462306a36Sopenharmony_ci arch_timer_kvm_info.virtual_irq = arch_timer_ppi[ARCH_TIMER_VIRT_PPI]; 139562306a36Sopenharmony_ci if (is_kernel_in_hyp_mode()) 139662306a36Sopenharmony_ci arch_timer_kvm_info.physical_irq = arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI]; 139762306a36Sopenharmony_ci} 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_cistatic int __init arch_timer_of_init(struct device_node *np) 140062306a36Sopenharmony_ci{ 140162306a36Sopenharmony_ci int i, irq, ret; 140262306a36Sopenharmony_ci u32 rate; 140362306a36Sopenharmony_ci bool has_names; 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci if (arch_timers_present & ARCH_TIMER_TYPE_CP15) { 140662306a36Sopenharmony_ci pr_warn("multiple nodes in dt, skipping\n"); 140762306a36Sopenharmony_ci return 0; 140862306a36Sopenharmony_ci } 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci arch_timers_present |= ARCH_TIMER_TYPE_CP15; 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci has_names = of_property_read_bool(np, "interrupt-names"); 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci for (i = ARCH_TIMER_PHYS_SECURE_PPI; i < ARCH_TIMER_MAX_TIMER_PPI; i++) { 141562306a36Sopenharmony_ci if (has_names) 141662306a36Sopenharmony_ci irq = of_irq_get_byname(np, arch_timer_ppi_names[i]); 141762306a36Sopenharmony_ci else 141862306a36Sopenharmony_ci irq = of_irq_get(np, i); 141962306a36Sopenharmony_ci if (irq > 0) 142062306a36Sopenharmony_ci arch_timer_ppi[i] = irq; 142162306a36Sopenharmony_ci } 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci arch_timer_populate_kvm_info(); 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci rate = arch_timer_get_cntfrq(); 142662306a36Sopenharmony_ci arch_timer_of_configure_rate(rate, np); 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci arch_timer_c3stop = !of_property_read_bool(np, "always-on"); 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci /* Check for globally applicable workarounds */ 143162306a36Sopenharmony_ci arch_timer_check_ool_workaround(ate_match_dt, np); 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci /* 143462306a36Sopenharmony_ci * If we cannot rely on firmware initializing the timer registers then 143562306a36Sopenharmony_ci * we should use the physical timers instead. 143662306a36Sopenharmony_ci */ 143762306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_ARM) && 143862306a36Sopenharmony_ci of_property_read_bool(np, "arm,cpu-registers-not-fw-configured")) 143962306a36Sopenharmony_ci arch_timer_uses_ppi = ARCH_TIMER_PHYS_SECURE_PPI; 144062306a36Sopenharmony_ci else 144162306a36Sopenharmony_ci arch_timer_uses_ppi = arch_timer_select_ppi(); 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_ci if (!arch_timer_ppi[arch_timer_uses_ppi]) { 144462306a36Sopenharmony_ci pr_err("No interrupt available, giving up\n"); 144562306a36Sopenharmony_ci return -EINVAL; 144662306a36Sopenharmony_ci } 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci /* On some systems, the counter stops ticking when in suspend. */ 144962306a36Sopenharmony_ci arch_counter_suspend_stop = of_property_read_bool(np, 145062306a36Sopenharmony_ci "arm,no-tick-in-suspend"); 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci ret = arch_timer_register(); 145362306a36Sopenharmony_ci if (ret) 145462306a36Sopenharmony_ci return ret; 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci if (arch_timer_needs_of_probing()) 145762306a36Sopenharmony_ci return 0; 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_ci return arch_timer_common_init(); 146062306a36Sopenharmony_ci} 146162306a36Sopenharmony_ciTIMER_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_of_init); 146262306a36Sopenharmony_ciTIMER_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_of_init); 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_cistatic u32 __init 146562306a36Sopenharmony_ciarch_timer_mem_frame_get_cntfrq(struct arch_timer_mem_frame *frame) 146662306a36Sopenharmony_ci{ 146762306a36Sopenharmony_ci void __iomem *base; 146862306a36Sopenharmony_ci u32 rate; 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci base = ioremap(frame->cntbase, frame->size); 147162306a36Sopenharmony_ci if (!base) { 147262306a36Sopenharmony_ci pr_err("Unable to map frame @ %pa\n", &frame->cntbase); 147362306a36Sopenharmony_ci return 0; 147462306a36Sopenharmony_ci } 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_ci rate = readl_relaxed(base + CNTFRQ); 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci iounmap(base); 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci return rate; 148162306a36Sopenharmony_ci} 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_cistatic struct arch_timer_mem_frame * __init 148462306a36Sopenharmony_ciarch_timer_mem_find_best_frame(struct arch_timer_mem *timer_mem) 148562306a36Sopenharmony_ci{ 148662306a36Sopenharmony_ci struct arch_timer_mem_frame *frame, *best_frame = NULL; 148762306a36Sopenharmony_ci void __iomem *cntctlbase; 148862306a36Sopenharmony_ci u32 cnttidr; 148962306a36Sopenharmony_ci int i; 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_ci cntctlbase = ioremap(timer_mem->cntctlbase, timer_mem->size); 149262306a36Sopenharmony_ci if (!cntctlbase) { 149362306a36Sopenharmony_ci pr_err("Can't map CNTCTLBase @ %pa\n", 149462306a36Sopenharmony_ci &timer_mem->cntctlbase); 149562306a36Sopenharmony_ci return NULL; 149662306a36Sopenharmony_ci } 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci cnttidr = readl_relaxed(cntctlbase + CNTTIDR); 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_ci /* 150162306a36Sopenharmony_ci * Try to find a virtual capable frame. Otherwise fall back to a 150262306a36Sopenharmony_ci * physical capable frame. 150362306a36Sopenharmony_ci */ 150462306a36Sopenharmony_ci for (i = 0; i < ARCH_TIMER_MEM_MAX_FRAMES; i++) { 150562306a36Sopenharmony_ci u32 cntacr = CNTACR_RFRQ | CNTACR_RWPT | CNTACR_RPCT | 150662306a36Sopenharmony_ci CNTACR_RWVT | CNTACR_RVOFF | CNTACR_RVCT; 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci frame = &timer_mem->frame[i]; 150962306a36Sopenharmony_ci if (!frame->valid) 151062306a36Sopenharmony_ci continue; 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci /* Try enabling everything, and see what sticks */ 151362306a36Sopenharmony_ci writel_relaxed(cntacr, cntctlbase + CNTACR(i)); 151462306a36Sopenharmony_ci cntacr = readl_relaxed(cntctlbase + CNTACR(i)); 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_ci if ((cnttidr & CNTTIDR_VIRT(i)) && 151762306a36Sopenharmony_ci !(~cntacr & (CNTACR_RWVT | CNTACR_RVCT))) { 151862306a36Sopenharmony_ci best_frame = frame; 151962306a36Sopenharmony_ci arch_timer_mem_use_virtual = true; 152062306a36Sopenharmony_ci break; 152162306a36Sopenharmony_ci } 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci if (~cntacr & (CNTACR_RWPT | CNTACR_RPCT)) 152462306a36Sopenharmony_ci continue; 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_ci best_frame = frame; 152762306a36Sopenharmony_ci } 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ci iounmap(cntctlbase); 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci return best_frame; 153262306a36Sopenharmony_ci} 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_cistatic int __init 153562306a36Sopenharmony_ciarch_timer_mem_frame_register(struct arch_timer_mem_frame *frame) 153662306a36Sopenharmony_ci{ 153762306a36Sopenharmony_ci void __iomem *base; 153862306a36Sopenharmony_ci int ret, irq = 0; 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci if (arch_timer_mem_use_virtual) 154162306a36Sopenharmony_ci irq = frame->virt_irq; 154262306a36Sopenharmony_ci else 154362306a36Sopenharmony_ci irq = frame->phys_irq; 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci if (!irq) { 154662306a36Sopenharmony_ci pr_err("Frame missing %s irq.\n", 154762306a36Sopenharmony_ci arch_timer_mem_use_virtual ? "virt" : "phys"); 154862306a36Sopenharmony_ci return -EINVAL; 154962306a36Sopenharmony_ci } 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci if (!request_mem_region(frame->cntbase, frame->size, 155262306a36Sopenharmony_ci "arch_mem_timer")) 155362306a36Sopenharmony_ci return -EBUSY; 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ci base = ioremap(frame->cntbase, frame->size); 155662306a36Sopenharmony_ci if (!base) { 155762306a36Sopenharmony_ci pr_err("Can't map frame's registers\n"); 155862306a36Sopenharmony_ci return -ENXIO; 155962306a36Sopenharmony_ci } 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_ci ret = arch_timer_mem_register(base, irq); 156262306a36Sopenharmony_ci if (ret) { 156362306a36Sopenharmony_ci iounmap(base); 156462306a36Sopenharmony_ci return ret; 156562306a36Sopenharmony_ci } 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci arch_timers_present |= ARCH_TIMER_TYPE_MEM; 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_ci return 0; 157062306a36Sopenharmony_ci} 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_cistatic int __init arch_timer_mem_of_init(struct device_node *np) 157362306a36Sopenharmony_ci{ 157462306a36Sopenharmony_ci struct arch_timer_mem *timer_mem; 157562306a36Sopenharmony_ci struct arch_timer_mem_frame *frame; 157662306a36Sopenharmony_ci struct device_node *frame_node; 157762306a36Sopenharmony_ci struct resource res; 157862306a36Sopenharmony_ci int ret = -EINVAL; 157962306a36Sopenharmony_ci u32 rate; 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_ci timer_mem = kzalloc(sizeof(*timer_mem), GFP_KERNEL); 158262306a36Sopenharmony_ci if (!timer_mem) 158362306a36Sopenharmony_ci return -ENOMEM; 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci if (of_address_to_resource(np, 0, &res)) 158662306a36Sopenharmony_ci goto out; 158762306a36Sopenharmony_ci timer_mem->cntctlbase = res.start; 158862306a36Sopenharmony_ci timer_mem->size = resource_size(&res); 158962306a36Sopenharmony_ci 159062306a36Sopenharmony_ci for_each_available_child_of_node(np, frame_node) { 159162306a36Sopenharmony_ci u32 n; 159262306a36Sopenharmony_ci struct arch_timer_mem_frame *frame; 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_ci if (of_property_read_u32(frame_node, "frame-number", &n)) { 159562306a36Sopenharmony_ci pr_err(FW_BUG "Missing frame-number.\n"); 159662306a36Sopenharmony_ci of_node_put(frame_node); 159762306a36Sopenharmony_ci goto out; 159862306a36Sopenharmony_ci } 159962306a36Sopenharmony_ci if (n >= ARCH_TIMER_MEM_MAX_FRAMES) { 160062306a36Sopenharmony_ci pr_err(FW_BUG "Wrong frame-number, only 0-%u are permitted.\n", 160162306a36Sopenharmony_ci ARCH_TIMER_MEM_MAX_FRAMES - 1); 160262306a36Sopenharmony_ci of_node_put(frame_node); 160362306a36Sopenharmony_ci goto out; 160462306a36Sopenharmony_ci } 160562306a36Sopenharmony_ci frame = &timer_mem->frame[n]; 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ci if (frame->valid) { 160862306a36Sopenharmony_ci pr_err(FW_BUG "Duplicated frame-number.\n"); 160962306a36Sopenharmony_ci of_node_put(frame_node); 161062306a36Sopenharmony_ci goto out; 161162306a36Sopenharmony_ci } 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci if (of_address_to_resource(frame_node, 0, &res)) { 161462306a36Sopenharmony_ci of_node_put(frame_node); 161562306a36Sopenharmony_ci goto out; 161662306a36Sopenharmony_ci } 161762306a36Sopenharmony_ci frame->cntbase = res.start; 161862306a36Sopenharmony_ci frame->size = resource_size(&res); 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_ci frame->virt_irq = irq_of_parse_and_map(frame_node, 162162306a36Sopenharmony_ci ARCH_TIMER_VIRT_SPI); 162262306a36Sopenharmony_ci frame->phys_irq = irq_of_parse_and_map(frame_node, 162362306a36Sopenharmony_ci ARCH_TIMER_PHYS_SPI); 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_ci frame->valid = true; 162662306a36Sopenharmony_ci } 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_ci frame = arch_timer_mem_find_best_frame(timer_mem); 162962306a36Sopenharmony_ci if (!frame) { 163062306a36Sopenharmony_ci pr_err("Unable to find a suitable frame in timer @ %pa\n", 163162306a36Sopenharmony_ci &timer_mem->cntctlbase); 163262306a36Sopenharmony_ci ret = -EINVAL; 163362306a36Sopenharmony_ci goto out; 163462306a36Sopenharmony_ci } 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ci rate = arch_timer_mem_frame_get_cntfrq(frame); 163762306a36Sopenharmony_ci arch_timer_of_configure_rate(rate, np); 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_ci ret = arch_timer_mem_frame_register(frame); 164062306a36Sopenharmony_ci if (!ret && !arch_timer_needs_of_probing()) 164162306a36Sopenharmony_ci ret = arch_timer_common_init(); 164262306a36Sopenharmony_ciout: 164362306a36Sopenharmony_ci kfree(timer_mem); 164462306a36Sopenharmony_ci return ret; 164562306a36Sopenharmony_ci} 164662306a36Sopenharmony_ciTIMER_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem", 164762306a36Sopenharmony_ci arch_timer_mem_of_init); 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_ci#ifdef CONFIG_ACPI_GTDT 165062306a36Sopenharmony_cistatic int __init 165162306a36Sopenharmony_ciarch_timer_mem_verify_cntfrq(struct arch_timer_mem *timer_mem) 165262306a36Sopenharmony_ci{ 165362306a36Sopenharmony_ci struct arch_timer_mem_frame *frame; 165462306a36Sopenharmony_ci u32 rate; 165562306a36Sopenharmony_ci int i; 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci for (i = 0; i < ARCH_TIMER_MEM_MAX_FRAMES; i++) { 165862306a36Sopenharmony_ci frame = &timer_mem->frame[i]; 165962306a36Sopenharmony_ci 166062306a36Sopenharmony_ci if (!frame->valid) 166162306a36Sopenharmony_ci continue; 166262306a36Sopenharmony_ci 166362306a36Sopenharmony_ci rate = arch_timer_mem_frame_get_cntfrq(frame); 166462306a36Sopenharmony_ci if (rate == arch_timer_rate) 166562306a36Sopenharmony_ci continue; 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci pr_err(FW_BUG "CNTFRQ mismatch: frame @ %pa: (0x%08lx), CPU: (0x%08lx)\n", 166862306a36Sopenharmony_ci &frame->cntbase, 166962306a36Sopenharmony_ci (unsigned long)rate, (unsigned long)arch_timer_rate); 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_ci return -EINVAL; 167262306a36Sopenharmony_ci } 167362306a36Sopenharmony_ci 167462306a36Sopenharmony_ci return 0; 167562306a36Sopenharmony_ci} 167662306a36Sopenharmony_ci 167762306a36Sopenharmony_cistatic int __init arch_timer_mem_acpi_init(int platform_timer_count) 167862306a36Sopenharmony_ci{ 167962306a36Sopenharmony_ci struct arch_timer_mem *timers, *timer; 168062306a36Sopenharmony_ci struct arch_timer_mem_frame *frame, *best_frame = NULL; 168162306a36Sopenharmony_ci int timer_count, i, ret = 0; 168262306a36Sopenharmony_ci 168362306a36Sopenharmony_ci timers = kcalloc(platform_timer_count, sizeof(*timers), 168462306a36Sopenharmony_ci GFP_KERNEL); 168562306a36Sopenharmony_ci if (!timers) 168662306a36Sopenharmony_ci return -ENOMEM; 168762306a36Sopenharmony_ci 168862306a36Sopenharmony_ci ret = acpi_arch_timer_mem_init(timers, &timer_count); 168962306a36Sopenharmony_ci if (ret || !timer_count) 169062306a36Sopenharmony_ci goto out; 169162306a36Sopenharmony_ci 169262306a36Sopenharmony_ci /* 169362306a36Sopenharmony_ci * While unlikely, it's theoretically possible that none of the frames 169462306a36Sopenharmony_ci * in a timer expose the combination of feature we want. 169562306a36Sopenharmony_ci */ 169662306a36Sopenharmony_ci for (i = 0; i < timer_count; i++) { 169762306a36Sopenharmony_ci timer = &timers[i]; 169862306a36Sopenharmony_ci 169962306a36Sopenharmony_ci frame = arch_timer_mem_find_best_frame(timer); 170062306a36Sopenharmony_ci if (!best_frame) 170162306a36Sopenharmony_ci best_frame = frame; 170262306a36Sopenharmony_ci 170362306a36Sopenharmony_ci ret = arch_timer_mem_verify_cntfrq(timer); 170462306a36Sopenharmony_ci if (ret) { 170562306a36Sopenharmony_ci pr_err("Disabling MMIO timers due to CNTFRQ mismatch\n"); 170662306a36Sopenharmony_ci goto out; 170762306a36Sopenharmony_ci } 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ci if (!best_frame) /* implies !frame */ 171062306a36Sopenharmony_ci /* 171162306a36Sopenharmony_ci * Only complain about missing suitable frames if we 171262306a36Sopenharmony_ci * haven't already found one in a previous iteration. 171362306a36Sopenharmony_ci */ 171462306a36Sopenharmony_ci pr_err("Unable to find a suitable frame in timer @ %pa\n", 171562306a36Sopenharmony_ci &timer->cntctlbase); 171662306a36Sopenharmony_ci } 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_ci if (best_frame) 171962306a36Sopenharmony_ci ret = arch_timer_mem_frame_register(best_frame); 172062306a36Sopenharmony_ciout: 172162306a36Sopenharmony_ci kfree(timers); 172262306a36Sopenharmony_ci return ret; 172362306a36Sopenharmony_ci} 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_ci/* Initialize per-processor generic timer and memory-mapped timer(if present) */ 172662306a36Sopenharmony_cistatic int __init arch_timer_acpi_init(struct acpi_table_header *table) 172762306a36Sopenharmony_ci{ 172862306a36Sopenharmony_ci int ret, platform_timer_count; 172962306a36Sopenharmony_ci 173062306a36Sopenharmony_ci if (arch_timers_present & ARCH_TIMER_TYPE_CP15) { 173162306a36Sopenharmony_ci pr_warn("already initialized, skipping\n"); 173262306a36Sopenharmony_ci return -EINVAL; 173362306a36Sopenharmony_ci } 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_ci arch_timers_present |= ARCH_TIMER_TYPE_CP15; 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ci ret = acpi_gtdt_init(table, &platform_timer_count); 173862306a36Sopenharmony_ci if (ret) 173962306a36Sopenharmony_ci return ret; 174062306a36Sopenharmony_ci 174162306a36Sopenharmony_ci arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI] = 174262306a36Sopenharmony_ci acpi_gtdt_map_ppi(ARCH_TIMER_PHYS_NONSECURE_PPI); 174362306a36Sopenharmony_ci 174462306a36Sopenharmony_ci arch_timer_ppi[ARCH_TIMER_VIRT_PPI] = 174562306a36Sopenharmony_ci acpi_gtdt_map_ppi(ARCH_TIMER_VIRT_PPI); 174662306a36Sopenharmony_ci 174762306a36Sopenharmony_ci arch_timer_ppi[ARCH_TIMER_HYP_PPI] = 174862306a36Sopenharmony_ci acpi_gtdt_map_ppi(ARCH_TIMER_HYP_PPI); 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ci arch_timer_populate_kvm_info(); 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_ci /* 175362306a36Sopenharmony_ci * When probing via ACPI, we have no mechanism to override the sysreg 175462306a36Sopenharmony_ci * CNTFRQ value. This *must* be correct. 175562306a36Sopenharmony_ci */ 175662306a36Sopenharmony_ci arch_timer_rate = arch_timer_get_cntfrq(); 175762306a36Sopenharmony_ci ret = validate_timer_rate(); 175862306a36Sopenharmony_ci if (ret) { 175962306a36Sopenharmony_ci pr_err(FW_BUG "frequency not available.\n"); 176062306a36Sopenharmony_ci return ret; 176162306a36Sopenharmony_ci } 176262306a36Sopenharmony_ci 176362306a36Sopenharmony_ci arch_timer_uses_ppi = arch_timer_select_ppi(); 176462306a36Sopenharmony_ci if (!arch_timer_ppi[arch_timer_uses_ppi]) { 176562306a36Sopenharmony_ci pr_err("No interrupt available, giving up\n"); 176662306a36Sopenharmony_ci return -EINVAL; 176762306a36Sopenharmony_ci } 176862306a36Sopenharmony_ci 176962306a36Sopenharmony_ci /* Always-on capability */ 177062306a36Sopenharmony_ci arch_timer_c3stop = acpi_gtdt_c3stop(arch_timer_uses_ppi); 177162306a36Sopenharmony_ci 177262306a36Sopenharmony_ci /* Check for globally applicable workarounds */ 177362306a36Sopenharmony_ci arch_timer_check_ool_workaround(ate_match_acpi_oem_info, table); 177462306a36Sopenharmony_ci 177562306a36Sopenharmony_ci ret = arch_timer_register(); 177662306a36Sopenharmony_ci if (ret) 177762306a36Sopenharmony_ci return ret; 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_ci if (platform_timer_count && 178062306a36Sopenharmony_ci arch_timer_mem_acpi_init(platform_timer_count)) 178162306a36Sopenharmony_ci pr_err("Failed to initialize memory-mapped timer.\n"); 178262306a36Sopenharmony_ci 178362306a36Sopenharmony_ci return arch_timer_common_init(); 178462306a36Sopenharmony_ci} 178562306a36Sopenharmony_ciTIMER_ACPI_DECLARE(arch_timer, ACPI_SIG_GTDT, arch_timer_acpi_init); 178662306a36Sopenharmony_ci#endif 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_ciint kvm_arch_ptp_get_crosststamp(u64 *cycle, struct timespec64 *ts, 178962306a36Sopenharmony_ci struct clocksource **cs) 179062306a36Sopenharmony_ci{ 179162306a36Sopenharmony_ci struct arm_smccc_res hvc_res; 179262306a36Sopenharmony_ci u32 ptp_counter; 179362306a36Sopenharmony_ci ktime_t ktime; 179462306a36Sopenharmony_ci 179562306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_HAVE_ARM_SMCCC_DISCOVERY)) 179662306a36Sopenharmony_ci return -EOPNOTSUPP; 179762306a36Sopenharmony_ci 179862306a36Sopenharmony_ci if (arch_timer_uses_ppi == ARCH_TIMER_VIRT_PPI) 179962306a36Sopenharmony_ci ptp_counter = KVM_PTP_VIRT_COUNTER; 180062306a36Sopenharmony_ci else 180162306a36Sopenharmony_ci ptp_counter = KVM_PTP_PHYS_COUNTER; 180262306a36Sopenharmony_ci 180362306a36Sopenharmony_ci arm_smccc_1_1_invoke(ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID, 180462306a36Sopenharmony_ci ptp_counter, &hvc_res); 180562306a36Sopenharmony_ci 180662306a36Sopenharmony_ci if ((int)(hvc_res.a0) < 0) 180762306a36Sopenharmony_ci return -EOPNOTSUPP; 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_ci ktime = (u64)hvc_res.a0 << 32 | hvc_res.a1; 181062306a36Sopenharmony_ci *ts = ktime_to_timespec64(ktime); 181162306a36Sopenharmony_ci if (cycle) 181262306a36Sopenharmony_ci *cycle = (u64)hvc_res.a2 << 32 | hvc_res.a3; 181362306a36Sopenharmony_ci if (cs) 181462306a36Sopenharmony_ci *cs = &clocksource_counter; 181562306a36Sopenharmony_ci 181662306a36Sopenharmony_ci return 0; 181762306a36Sopenharmony_ci} 181862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kvm_arch_ptp_get_crosststamp); 1819