summaryrefslogtreecommitdiff
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.c64
1 files changed, 58 insertions, 6 deletions
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 5163ec13429d..43005d4d3348 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -299,6 +299,21 @@ static void __arch_timer_setup(unsigned type,
clockevents_config_and_register(clk, arch_timer_rate, 0xf, 0x7fffffff);
}
+static void arch_timer_evtstrm_enable(int divider)
+{
+ u32 cntkctl = arch_timer_get_cntkctl();
+
+ cntkctl &= ~ARCH_TIMER_EVT_TRIGGER_MASK;
+ /* Set the divider and enable virtual event stream */
+ cntkctl |= (divider << ARCH_TIMER_EVT_TRIGGER_SHIFT)
+ | ARCH_TIMER_VIRT_EVT_EN;
+ arch_timer_set_cntkctl(cntkctl);
+ elf_hwcap |= HWCAP_EVTSTRM;
+#ifdef CONFIG_COMPAT
+ compat_elf_hwcap |= COMPAT_HWCAP_EVTSTRM;
+#endif
+}
+
static void arch_timer_configure_evtstream(void)
{
int evt_stream_div, pos;
@@ -312,6 +327,23 @@ static void arch_timer_configure_evtstream(void)
arch_timer_evtstrm_enable(min(pos, 15));
}
+static void arch_counter_set_user_access(void)
+{
+ u32 cntkctl = arch_timer_get_cntkctl();
+
+ /* Disable user access to the timers and the physical counter */
+ /* Also disable virtual event stream */
+ cntkctl &= ~(ARCH_TIMER_USR_PT_ACCESS_EN
+ | ARCH_TIMER_USR_VT_ACCESS_EN
+ | ARCH_TIMER_VIRT_EVT_EN
+ | ARCH_TIMER_USR_PCT_ACCESS_EN);
+
+ /* Enable user access to the virtual counter */
+ cntkctl |= ARCH_TIMER_USR_VCT_ACCESS_EN;
+
+ arch_timer_set_cntkctl(cntkctl);
+}
+
static int arch_timer_setup(struct clock_event_device *clk)
{
__arch_timer_setup(ARCH_CP15_TIMER, clk);
@@ -429,11 +461,19 @@ static void __init arch_counter_register(unsigned type)
u64 start_count;
/* Register the CP15 based counter if we have one */
- if (type & ARCH_CP15_TIMER)
+ if (type & ARCH_CP15_TIMER) {
arch_timer_read_counter = arch_counter_get_cntvct;
- else
+ } else {
arch_timer_read_counter = arch_counter_get_cntvct_mem;
+ /* If the clocksource name is "arch_sys_counter" the
+ * VDSO will attempt to read the CP15-based counter.
+ * Ensure this does not happen when CP15-based
+ * counter is not available.
+ */
+ clocksource_counter.name = "arch_mem_counter";
+ }
+
start_count = arch_timer_read_counter();
clocksource_register_hz(&clocksource_counter, arch_timer_rate);
cyclecounter.mult = clocksource_counter.mult;
@@ -616,17 +656,29 @@ static const struct of_device_id arch_timer_mem_of_match[] __initconst = {
{},
};
+static bool __init
+arch_timer_probed(int type, const struct of_device_id *matches)
+{
+ struct device_node *dn;
+ bool probed = true;
+
+ dn = of_find_matching_node(NULL, matches);
+ if (dn && of_device_is_available(dn) && !(arch_timers_present & type))
+ probed = false;
+ of_node_put(dn);
+
+ return probed;
+}
+
static void __init arch_timer_common_init(void)
{
unsigned mask = ARCH_CP15_TIMER | ARCH_MEM_TIMER;
/* Wait until both nodes are probed if we have two timers */
if ((arch_timers_present & mask) != mask) {
- if (of_find_matching_node(NULL, arch_timer_mem_of_match) &&
- !(arch_timers_present & ARCH_MEM_TIMER))
+ if (!arch_timer_probed(ARCH_MEM_TIMER, arch_timer_mem_of_match))
return;
- if (of_find_matching_node(NULL, arch_timer_of_match) &&
- !(arch_timers_present & ARCH_CP15_TIMER))
+ if (!arch_timer_probed(ARCH_CP15_TIMER, arch_timer_of_match))
return;
}