|
@@ -187,3 +187,88 @@ static inline void timer_set_mode(const int access, int mode)
|
|
|
break;
|
|
|
default:
|
|
|
break;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void arch_timer_set_mode_virt(enum clock_event_mode mode,
|
|
|
+ struct clock_event_device *clk)
|
|
|
+{
|
|
|
+ timer_set_mode(ARCH_TIMER_VIRT_ACCESS, mode);
|
|
|
+}
|
|
|
+
|
|
|
+static void arch_timer_set_mode_phys(enum clock_event_mode mode,
|
|
|
+ struct clock_event_device *clk)
|
|
|
+{
|
|
|
+ timer_set_mode(ARCH_TIMER_PHYS_ACCESS, mode);
|
|
|
+}
|
|
|
+
|
|
|
+static inline void set_next_event(const int access, unsigned long evt)
|
|
|
+{
|
|
|
+ unsigned long ctrl;
|
|
|
+ ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL);
|
|
|
+ ctrl |= ARCH_TIMER_CTRL_ENABLE;
|
|
|
+ ctrl &= ~ARCH_TIMER_CTRL_IT_MASK;
|
|
|
+ arch_timer_reg_write(access, ARCH_TIMER_REG_TVAL, evt);
|
|
|
+ arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl);
|
|
|
+}
|
|
|
+
|
|
|
+static int arch_timer_set_next_event_virt(unsigned long evt,
|
|
|
+ struct clock_event_device *unused)
|
|
|
+{
|
|
|
+ set_next_event(ARCH_TIMER_VIRT_ACCESS, evt);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int arch_timer_set_next_event_phys(unsigned long evt,
|
|
|
+ struct clock_event_device *unused)
|
|
|
+{
|
|
|
+ set_next_event(ARCH_TIMER_PHYS_ACCESS, evt);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int __cpuinit arch_timer_setup(struct clock_event_device *clk)
|
|
|
+{
|
|
|
+ clk->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_C3STOP;
|
|
|
+ clk->name = "arch_sys_timer";
|
|
|
+ clk->rating = 450;
|
|
|
+ if (arch_timer_use_virtual) {
|
|
|
+ clk->irq = arch_timer_ppi[VIRT_PPI];
|
|
|
+ clk->set_mode = arch_timer_set_mode_virt;
|
|
|
+ clk->set_next_event = arch_timer_set_next_event_virt;
|
|
|
+ } else {
|
|
|
+ clk->irq = arch_timer_ppi[PHYS_SECURE_PPI];
|
|
|
+ clk->set_mode = arch_timer_set_mode_phys;
|
|
|
+ clk->set_next_event = arch_timer_set_next_event_phys;
|
|
|
+ }
|
|
|
+
|
|
|
+ clk->set_mode(CLOCK_EVT_MODE_SHUTDOWN, NULL);
|
|
|
+
|
|
|
+ clockevents_config_and_register(clk, arch_timer_rate,
|
|
|
+ 0xf, 0x7fffffff);
|
|
|
+
|
|
|
+ *__this_cpu_ptr(arch_timer_evt) = clk;
|
|
|
+
|
|
|
+ if (arch_timer_use_virtual)
|
|
|
+ enable_percpu_irq(arch_timer_ppi[VIRT_PPI], 0);
|
|
|
+ else {
|
|
|
+ enable_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI], 0);
|
|
|
+ if (arch_timer_ppi[PHYS_NONSECURE_PPI])
|
|
|
+ enable_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI], 0);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/* Is the optional system timer available? */
|
|
|
+static int local_timer_is_architected(void)
|
|
|
+{
|
|
|
+ return (cpu_architecture() >= CPU_ARCH_ARMv7) &&
|
|
|
+ ((read_cpuid_ext(CPUID_EXT_PFR1) >> 16) & 0xf) == 1;
|
|
|
+}
|
|
|
+
|
|
|
+static int arch_timer_available(void)
|
|
|
+{
|
|
|
+ unsigned long freq;
|
|
|
+
|
|
|
+ if (!local_timer_is_architected())
|
|
|
+ return -ENXIO;
|