aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/arm64/silicon-errata.txt2
-rw-r--r--drivers/clocksource/Kconfig10
-rw-r--r--drivers/clocksource/arm_arch_timer.c55
3 files changed, 67 insertions, 0 deletions
diff --git a/Documentation/arm64/silicon-errata.txt b/Documentation/arm64/silicon-errata.txt
index 1f09d043d086..ddb8ce5333ba 100644
--- a/Documentation/arm64/silicon-errata.txt
+++ b/Documentation/arm64/silicon-errata.txt
@@ -44,6 +44,8 @@ stable kernels.
44 44
45| Implementor | Component | Erratum ID | Kconfig | 45| Implementor | Component | Erratum ID | Kconfig |
46+----------------+-----------------+-----------------+-----------------------------+ 46+----------------+-----------------+-----------------+-----------------------------+
47| Allwinner | A64/R18 | UNKNOWN1 | SUN50I_ERRATUM_UNKNOWN1 |
48| | | | |
47| ARM | Cortex-A53 | #826319 | ARM64_ERRATUM_826319 | 49| ARM | Cortex-A53 | #826319 | ARM64_ERRATUM_826319 |
48| ARM | Cortex-A53 | #827319 | ARM64_ERRATUM_827319 | 50| ARM | Cortex-A53 | #827319 | ARM64_ERRATUM_827319 |
49| ARM | Cortex-A53 | #824069 | ARM64_ERRATUM_824069 | 51| ARM | Cortex-A53 | #824069 | ARM64_ERRATUM_824069 |
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index a9e26f6a81a1..8dfd3bc448d0 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -360,6 +360,16 @@ config ARM64_ERRATUM_858921
360 The workaround will be dynamically enabled when an affected 360 The workaround will be dynamically enabled when an affected
361 core is detected. 361 core is detected.
362 362
363config SUN50I_ERRATUM_UNKNOWN1
364 bool "Workaround for Allwinner A64 erratum UNKNOWN1"
365 default y
366 depends on ARM_ARCH_TIMER && ARM64 && ARCH_SUNXI
367 select ARM_ARCH_TIMER_OOL_WORKAROUND
368 help
369 This option enables a workaround for instability in the timer on
370 the Allwinner A64 SoC. The workaround will only be active if the
371 allwinner,erratum-unknown1 property is found in the timer node.
372
363config ARM_GLOBAL_TIMER 373config ARM_GLOBAL_TIMER
364 bool "Support for the ARM global timer" if COMPILE_TEST 374 bool "Support for the ARM global timer" if COMPILE_TEST
365 select TIMER_OF if OF 375 select TIMER_OF if OF
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 *,