aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clocksource/arm_arch_timer.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clocksource/arm_arch_timer.c')
-rw-r--r--drivers/clocksource/arm_arch_timer.c55
1 files changed, 55 insertions, 0 deletions
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 9a7d4dc00b6e..a8b20b65bd4b 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -326,6 +326,48 @@ static u64 notrace arm64_1188873_read_cntvct_el0(void)
326} 326}
327#endif 327#endif
328 328
329#ifdef CONFIG_SUN50I_ERRATUM_UNKNOWN1
330/*
331 * The low bits of the counter registers are indeterminate while bit 10 or
332 * greater is rolling over. Since the counter value can jump both backward
333 * (7ff -> 000 -> 800) and forward (7ff -> fff -> 800), ignore register values
334 * with all ones or all zeros in the low bits. Bound the loop by the maximum
335 * number of CPU cycles in 3 consecutive 24 MHz counter periods.
336 */
337#define __sun50i_a64_read_reg(reg) ({ \
338 u64 _val; \
339 int _retries = 150; \
340 \
341 do { \
342 _val = read_sysreg(reg); \
343 _retries--; \
344 } while (((_val + 1) & GENMASK(9, 0)) <= 1 && _retries); \
345 \
346 WARN_ON_ONCE(!_retries); \
347 _val; \
348})
349
350static u64 notrace sun50i_a64_read_cntpct_el0(void)
351{
352 return __sun50i_a64_read_reg(cntpct_el0);
353}
354
355static u64 notrace sun50i_a64_read_cntvct_el0(void)
356{
357 return __sun50i_a64_read_reg(cntvct_el0);
358}
359
360static u32 notrace sun50i_a64_read_cntp_tval_el0(void)
361{
362 return read_sysreg(cntp_cval_el0) - sun50i_a64_read_cntpct_el0();
363}
364
365static u32 notrace sun50i_a64_read_cntv_tval_el0(void)
366{
367 return read_sysreg(cntv_cval_el0) - sun50i_a64_read_cntvct_el0();
368}
369#endif
370
329#ifdef CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND 371#ifdef CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND
330DEFINE_PER_CPU(const struct arch_timer_erratum_workaround *, timer_unstable_counter_workaround); 372DEFINE_PER_CPU(const struct arch_timer_erratum_workaround *, timer_unstable_counter_workaround);
331EXPORT_SYMBOL_GPL(timer_unstable_counter_workaround); 373EXPORT_SYMBOL_GPL(timer_unstable_counter_workaround);
@@ -423,6 +465,19 @@ static const struct arch_timer_erratum_workaround ool_workarounds[] = {
423 .read_cntvct_el0 = arm64_1188873_read_cntvct_el0, 465 .read_cntvct_el0 = arm64_1188873_read_cntvct_el0,
424 }, 466 },
425#endif 467#endif
468#ifdef CONFIG_SUN50I_ERRATUM_UNKNOWN1
469 {
470 .match_type = ate_match_dt,
471 .id = "allwinner,erratum-unknown1",
472 .desc = "Allwinner erratum UNKNOWN1",
473 .read_cntp_tval_el0 = sun50i_a64_read_cntp_tval_el0,
474 .read_cntv_tval_el0 = sun50i_a64_read_cntv_tval_el0,
475 .read_cntpct_el0 = sun50i_a64_read_cntpct_el0,
476 .read_cntvct_el0 = sun50i_a64_read_cntvct_el0,
477 .set_next_event_phys = erratum_set_next_event_tval_phys,
478 .set_next_event_virt = erratum_set_next_event_tval_virt,
479 },
480#endif
426}; 481};
427 482
428typedef bool (*ate_match_fn_t)(const struct arch_timer_erratum_workaround *, 483typedef bool (*ate_match_fn_t)(const struct arch_timer_erratum_workaround *,