diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/clocksource/Kconfig | 10 | ||||
-rw-r--r-- | drivers/clocksource/arm_arch_timer.c | 104 |
2 files changed, 114 insertions, 0 deletions
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 567788664723..8a753fd5b79d 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig | |||
@@ -305,6 +305,16 @@ config ARM_ARCH_TIMER_EVTSTREAM | |||
305 | This must be disabled for hardware validation purposes to detect any | 305 | This must be disabled for hardware validation purposes to detect any |
306 | hardware anomalies of missing events. | 306 | hardware anomalies of missing events. |
307 | 307 | ||
308 | config FSL_ERRATUM_A008585 | ||
309 | bool "Workaround for Freescale/NXP Erratum A-008585" | ||
310 | default y | ||
311 | depends on ARM_ARCH_TIMER && ARM64 | ||
312 | help | ||
313 | This option enables a workaround for Freescale/NXP Erratum | ||
314 | A-008585 ("ARM generic timer may contain an erroneous | ||
315 | value"). The workaround will only be active if the | ||
316 | fsl,erratum-a008585 property is found in the timer node. | ||
317 | |||
308 | config ARM_GLOBAL_TIMER | 318 | config ARM_GLOBAL_TIMER |
309 | bool "Support for the ARM global timer" if COMPILE_TEST | 319 | bool "Support for the ARM global timer" if COMPILE_TEST |
310 | select CLKSRC_OF if OF | 320 | select CLKSRC_OF if OF |
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 57700541f951..eb5fb4121ac8 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c | |||
@@ -94,6 +94,43 @@ early_param("clocksource.arm_arch_timer.evtstrm", early_evtstrm_cfg); | |||
94 | * Architected system timer support. | 94 | * Architected system timer support. |
95 | */ | 95 | */ |
96 | 96 | ||
97 | #ifdef CONFIG_FSL_ERRATUM_A008585 | ||
98 | DEFINE_STATIC_KEY_FALSE(arch_timer_read_ool_enabled); | ||
99 | EXPORT_SYMBOL_GPL(arch_timer_read_ool_enabled); | ||
100 | |||
101 | static int fsl_a008585_enable = -1; | ||
102 | |||
103 | static int __init early_fsl_a008585_cfg(char *buf) | ||
104 | { | ||
105 | int ret; | ||
106 | bool val; | ||
107 | |||
108 | ret = strtobool(buf, &val); | ||
109 | if (ret) | ||
110 | return ret; | ||
111 | |||
112 | fsl_a008585_enable = val; | ||
113 | return 0; | ||
114 | } | ||
115 | early_param("clocksource.arm_arch_timer.fsl-a008585", early_fsl_a008585_cfg); | ||
116 | |||
117 | u32 __fsl_a008585_read_cntp_tval_el0(void) | ||
118 | { | ||
119 | return __fsl_a008585_read_reg(cntp_tval_el0); | ||
120 | } | ||
121 | |||
122 | u32 __fsl_a008585_read_cntv_tval_el0(void) | ||
123 | { | ||
124 | return __fsl_a008585_read_reg(cntv_tval_el0); | ||
125 | } | ||
126 | |||
127 | u64 __fsl_a008585_read_cntvct_el0(void) | ||
128 | { | ||
129 | return __fsl_a008585_read_reg(cntvct_el0); | ||
130 | } | ||
131 | EXPORT_SYMBOL(__fsl_a008585_read_cntvct_el0); | ||
132 | #endif /* CONFIG_FSL_ERRATUM_A008585 */ | ||
133 | |||
97 | static __always_inline | 134 | static __always_inline |
98 | void arch_timer_reg_write(int access, enum arch_timer_reg reg, u32 val, | 135 | void arch_timer_reg_write(int access, enum arch_timer_reg reg, u32 val, |
99 | struct clock_event_device *clk) | 136 | struct clock_event_device *clk) |
@@ -243,6 +280,40 @@ static __always_inline void set_next_event(const int access, unsigned long evt, | |||
243 | arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk); | 280 | arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk); |
244 | } | 281 | } |
245 | 282 | ||
283 | #ifdef CONFIG_FSL_ERRATUM_A008585 | ||
284 | static __always_inline void fsl_a008585_set_next_event(const int access, | ||
285 | unsigned long evt, struct clock_event_device *clk) | ||
286 | { | ||
287 | unsigned long ctrl; | ||
288 | u64 cval = evt + arch_counter_get_cntvct(); | ||
289 | |||
290 | ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL, clk); | ||
291 | ctrl |= ARCH_TIMER_CTRL_ENABLE; | ||
292 | ctrl &= ~ARCH_TIMER_CTRL_IT_MASK; | ||
293 | |||
294 | if (access == ARCH_TIMER_PHYS_ACCESS) | ||
295 | write_sysreg(cval, cntp_cval_el0); | ||
296 | else if (access == ARCH_TIMER_VIRT_ACCESS) | ||
297 | write_sysreg(cval, cntv_cval_el0); | ||
298 | |||
299 | arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk); | ||
300 | } | ||
301 | |||
302 | static int fsl_a008585_set_next_event_virt(unsigned long evt, | ||
303 | struct clock_event_device *clk) | ||
304 | { | ||
305 | fsl_a008585_set_next_event(ARCH_TIMER_VIRT_ACCESS, evt, clk); | ||
306 | return 0; | ||
307 | } | ||
308 | |||
309 | static int fsl_a008585_set_next_event_phys(unsigned long evt, | ||
310 | struct clock_event_device *clk) | ||
311 | { | ||
312 | fsl_a008585_set_next_event(ARCH_TIMER_PHYS_ACCESS, evt, clk); | ||
313 | return 0; | ||
314 | } | ||
315 | #endif /* CONFIG_FSL_ERRATUM_A008585 */ | ||
316 | |||
246 | static int arch_timer_set_next_event_virt(unsigned long evt, | 317 | static int arch_timer_set_next_event_virt(unsigned long evt, |
247 | struct clock_event_device *clk) | 318 | struct clock_event_device *clk) |
248 | { | 319 | { |
@@ -271,6 +342,19 @@ static int arch_timer_set_next_event_phys_mem(unsigned long evt, | |||
271 | return 0; | 342 | return 0; |
272 | } | 343 | } |
273 | 344 | ||
345 | static void fsl_a008585_set_sne(struct clock_event_device *clk) | ||
346 | { | ||
347 | #ifdef CONFIG_FSL_ERRATUM_A008585 | ||
348 | if (!static_branch_unlikely(&arch_timer_read_ool_enabled)) | ||
349 | return; | ||
350 | |||
351 | if (arch_timer_uses_ppi == VIRT_PPI) | ||
352 | clk->set_next_event = fsl_a008585_set_next_event_virt; | ||
353 | else | ||
354 | clk->set_next_event = fsl_a008585_set_next_event_phys; | ||
355 | #endif | ||
356 | } | ||
357 | |||
274 | static void __arch_timer_setup(unsigned type, | 358 | static void __arch_timer_setup(unsigned type, |
275 | struct clock_event_device *clk) | 359 | struct clock_event_device *clk) |
276 | { | 360 | { |
@@ -299,6 +383,8 @@ static void __arch_timer_setup(unsigned type, | |||
299 | default: | 383 | default: |
300 | BUG(); | 384 | BUG(); |
301 | } | 385 | } |
386 | |||
387 | fsl_a008585_set_sne(clk); | ||
302 | } else { | 388 | } else { |
303 | clk->features |= CLOCK_EVT_FEAT_DYNIRQ; | 389 | clk->features |= CLOCK_EVT_FEAT_DYNIRQ; |
304 | clk->name = "arch_mem_timer"; | 390 | clk->name = "arch_mem_timer"; |
@@ -515,6 +601,15 @@ static void __init arch_counter_register(unsigned type) | |||
515 | arch_timer_read_counter = arch_counter_get_cntvct; | 601 | arch_timer_read_counter = arch_counter_get_cntvct; |
516 | else | 602 | else |
517 | arch_timer_read_counter = arch_counter_get_cntpct; | 603 | arch_timer_read_counter = arch_counter_get_cntpct; |
604 | |||
605 | #ifdef CONFIG_FSL_ERRATUM_A008585 | ||
606 | /* | ||
607 | * Don't use the vdso fastpath if errata require using | ||
608 | * the out-of-line counter accessor. | ||
609 | */ | ||
610 | if (static_branch_unlikely(&arch_timer_read_ool_enabled)) | ||
611 | clocksource_counter.name = "arch_sys_counter_ool"; | ||
612 | #endif | ||
518 | } else { | 613 | } else { |
519 | arch_timer_read_counter = arch_counter_get_cntvct_mem; | 614 | arch_timer_read_counter = arch_counter_get_cntvct_mem; |
520 | 615 | ||
@@ -800,6 +895,15 @@ static int __init arch_timer_of_init(struct device_node *np) | |||
800 | 895 | ||
801 | arch_timer_c3stop = !of_property_read_bool(np, "always-on"); | 896 | arch_timer_c3stop = !of_property_read_bool(np, "always-on"); |
802 | 897 | ||
898 | #ifdef CONFIG_FSL_ERRATUM_A008585 | ||
899 | if (fsl_a008585_enable < 0) | ||
900 | fsl_a008585_enable = of_property_read_bool(np, "fsl,erratum-a008585"); | ||
901 | if (fsl_a008585_enable) { | ||
902 | static_branch_enable(&arch_timer_read_ool_enabled); | ||
903 | pr_info("Enabling workaround for FSL erratum A-008585\n"); | ||
904 | } | ||
905 | #endif | ||
906 | |||
803 | /* | 907 | /* |
804 | * If we cannot rely on firmware initializing the timer registers then | 908 | * If we cannot rely on firmware initializing the timer registers then |
805 | * we should use the physical timers instead. | 909 | * we should use the physical timers instead. |