|
|
@@ -319,6 +319,48 @@ static u64 notrace arm64_858921_read_cntvct_el0(void)
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
+#ifdef CONFIG_SUN50I_ERRATUM_UNKNOWN1
|
|
|
+/*
|
|
|
+ * The low bits of the counter registers are indeterminate while bit 10 or
|
|
|
+ * greater is rolling over. Since the counter value can jump both backward
|
|
|
+ * (7ff -> 000 -> 800) and forward (7ff -> fff -> 800), ignore register values
|
|
|
+ * with all ones or all zeros in the low bits. Bound the loop by the maximum
|
|
|
+ * number of CPU cycles in 3 consecutive 24 MHz counter periods.
|
|
|
+ */
|
|
|
+#define __sun50i_a64_read_reg(reg) ({ \
|
|
|
+ u64 _val; \
|
|
|
+ int _retries = 150; \
|
|
|
+ \
|
|
|
+ do { \
|
|
|
+ _val = read_sysreg(reg); \
|
|
|
+ _retries--; \
|
|
|
+ } while (((_val + 1) & GENMASK(9, 0)) <= 1 && _retries); \
|
|
|
+ \
|
|
|
+ WARN_ON_ONCE(!_retries); \
|
|
|
+ _val; \
|
|
|
+})
|
|
|
+
|
|
|
+static u64 notrace sun50i_a64_read_cntpct_el0(void)
|
|
|
+{
|
|
|
+ return __sun50i_a64_read_reg(cntpct_el0);
|
|
|
+}
|
|
|
+
|
|
|
+static u64 notrace sun50i_a64_read_cntvct_el0(void)
|
|
|
+{
|
|
|
+ return __sun50i_a64_read_reg(cntvct_el0);
|
|
|
+}
|
|
|
+
|
|
|
+static u32 notrace sun50i_a64_read_cntp_tval_el0(void)
|
|
|
+{
|
|
|
+ return read_sysreg(cntp_cval_el0) - sun50i_a64_read_cntpct_el0();
|
|
|
+}
|
|
|
+
|
|
|
+static u32 notrace sun50i_a64_read_cntv_tval_el0(void)
|
|
|
+{
|
|
|
+ return read_sysreg(cntv_cval_el0) - sun50i_a64_read_cntvct_el0();
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
#ifdef CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND
|
|
|
DEFINE_PER_CPU(const struct arch_timer_erratum_workaround *, timer_unstable_counter_workaround);
|
|
|
EXPORT_SYMBOL_GPL(timer_unstable_counter_workaround);
|
|
|
@@ -408,6 +450,19 @@ static const struct arch_timer_erratum_workaround ool_workarounds[] = {
|
|
|
.read_cntvct_el0 = arm64_858921_read_cntvct_el0,
|
|
|
},
|
|
|
#endif
|
|
|
+#ifdef CONFIG_SUN50I_ERRATUM_UNKNOWN1
|
|
|
+ {
|
|
|
+ .match_type = ate_match_dt,
|
|
|
+ .id = "allwinner,erratum-unknown1",
|
|
|
+ .desc = "Allwinner erratum UNKNOWN1",
|
|
|
+ .read_cntp_tval_el0 = sun50i_a64_read_cntp_tval_el0,
|
|
|
+ .read_cntv_tval_el0 = sun50i_a64_read_cntv_tval_el0,
|
|
|
+ .read_cntpct_el0 = sun50i_a64_read_cntpct_el0,
|
|
|
+ .read_cntvct_el0 = sun50i_a64_read_cntvct_el0,
|
|
|
+ .set_next_event_phys = erratum_set_next_event_tval_phys,
|
|
|
+ .set_next_event_virt = erratum_set_next_event_tval_virt,
|
|
|
+ },
|
|
|
+#endif
|
|
|
};
|
|
|
|
|
|
typedef bool (*ate_match_fn_t)(const struct arch_timer_erratum_workaround *,
|