diff options
Diffstat (limited to 'drivers/clocksource/arm_arch_timer.c')
-rw-r--r-- | drivers/clocksource/arm_arch_timer.c | 55 |
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 | |||
350 | static u64 notrace sun50i_a64_read_cntpct_el0(void) | ||
351 | { | ||
352 | return __sun50i_a64_read_reg(cntpct_el0); | ||
353 | } | ||
354 | |||
355 | static u64 notrace sun50i_a64_read_cntvct_el0(void) | ||
356 | { | ||
357 | return __sun50i_a64_read_reg(cntvct_el0); | ||
358 | } | ||
359 | |||
360 | static u32 notrace sun50i_a64_read_cntp_tval_el0(void) | ||
361 | { | ||
362 | return read_sysreg(cntp_cval_el0) - sun50i_a64_read_cntpct_el0(); | ||
363 | } | ||
364 | |||
365 | static 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 |
330 | DEFINE_PER_CPU(const struct arch_timer_erratum_workaround *, timer_unstable_counter_workaround); | 372 | DEFINE_PER_CPU(const struct arch_timer_erratum_workaround *, timer_unstable_counter_workaround); |
331 | EXPORT_SYMBOL_GPL(timer_unstable_counter_workaround); | 373 | EXPORT_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 | ||
428 | typedef bool (*ate_match_fn_t)(const struct arch_timer_erratum_workaround *, | 483 | typedef bool (*ate_match_fn_t)(const struct arch_timer_erratum_workaround *, |