HACK: ARM64: use only arch timer on Exynos5433
authorMarek Szyprowski <m.szyprowski@samsung.com>
Wed, 25 Apr 2018 10:55:44 +0000 (12:55 +0200)
committerMarek Szyprowski <m.szyprowski@samsung.com>
Thu, 26 Apr 2018 11:33:08 +0000 (13:33 +0200)
Xenomai ARM64 port requires proper ARCH TIMER support, so hack
MCT to enable timers and let Linux kernel to use only ARCH TIMER
as clock source, events and VDSO calls.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
arch/arm64/include/asm/arch_timer.h
arch/arm64/include/asm/ipipe.h
arch/arm64/kernel/vdso/gettimeofday.S
drivers/clocksource/exynos_mct.c

index effff73d6b4f333e8d917469f154c29fdca13e0b..31dd116ea4893bfa09b3628d8bf36e5cb0b57b41 100644 (file)
@@ -134,7 +134,7 @@ static inline u64 arch_counter_get_cntvct(void)
        u64 cval;
 
        isb();
-       asm volatile("mrs %0, cntvct_el0" : "=r" (cval));
+       asm volatile("mrs %0, cntpct_el0" : "=r" (cval));
 
        return cval;
 }
index 7ee43a5beb537210a3e722c74f4f80ef6bbc570c..bba7a68cd5a3bd9d6c724e90afc19a524edeb043 100644 (file)
@@ -82,7 +82,7 @@ static inline void __ipipe_mach_update_tsc(void) {}
 
 static inline notrace unsigned long long __ipipe_mach_get_tsc(void)
 {
-       return arch_counter_get_cntvct();
+       return arch_counter_get_cntpct();
 }
 
 #define __ipipe_tsc_get() __ipipe_mach_get_tsc()
index efa79e8d4196d01318779cd76f2e926c40765ae9..3e7a4f3f5f9e72675d6465a00d834dc6179cc8ed 100644 (file)
@@ -224,7 +224,7 @@ ENTRY(__do_get_tspec)
 
        /* Read the virtual counter. */
        isb
-       mrs     x15, cntvct_el0
+       mrs     x15, cntpct_el0
 
        /* Calculate cycle delta and convert to ns. */
        sub     x10, x15, x10
index 6db3ba02237ff1edbcf2e0cd0b73c3c81e34913c..660f86284383298c3293b3410a942a4fd3f47fb5 100644 (file)
@@ -165,207 +165,9 @@ static void exynos4_mct_frc_start(void)
        exynos4_mct_write(reg, EXYNOS4_MCT_G_TCON);
 }
 
-/**
- * exynos4_read_count_64 - Read all 64-bits of the global counter
- *
- * This will read all 64-bits of the global counter taking care to make sure
- * that the upper and lower half match.  Note that reading the MCT can be quite
- * slow (hundreds of nanoseconds) so you should use the 32-bit (lower half
- * only) version when possible.
- *
- * Returns the number of cycles in the global counter.
- */
-static u64 exynos4_read_count_64(void)
-{
-       unsigned int lo, hi;
-       u32 hi2 = readl_relaxed(reg_base + EXYNOS4_MCT_G_CNT_U);
-
-       do {
-               hi = hi2;
-               lo = readl_relaxed(reg_base + EXYNOS4_MCT_G_CNT_L);
-               hi2 = readl_relaxed(reg_base + EXYNOS4_MCT_G_CNT_U);
-       } while (hi != hi2);
-
-       return ((cycle_t)hi << 32) | lo;
-}
-
-/**
- * exynos4_read_count_32 - Read the lower 32-bits of the global counter
- *
- * This will read just the lower 32-bits of the global counter.  This is marked
- * as notrace so it can be used by the scheduler clock.
- *
- * Returns the number of cycles in the global counter (lower 32 bits).
- */
-static u32 notrace exynos4_read_count_32(void)
-{
-       return readl_relaxed(reg_base + EXYNOS4_MCT_G_CNT_L);
-}
-
-static cycle_t exynos4_frc_read(struct clocksource *cs)
-{
-       return exynos4_read_count_32();
-}
-
-static void exynos4_frc_resume(struct clocksource *cs)
-{
-       exynos4_mct_frc_start();
-}
-
-struct clocksource mct_frc = {
-       .name           = "mct-frc",
-       .rating         = 400,
-       .read           = exynos4_frc_read,
-       .mask           = CLOCKSOURCE_MASK(32),
-       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
-       .resume         = exynos4_frc_resume,
-};
-
-#if defined(CONFIG_IPIPE)
-static struct __ipipe_tscinfo tsc_info = {
-       .type = IPIPE_TSC_TYPE_FREERUNNING,
-       .u = {
-               {
-                       .mask = 0xffffffff,
-               },
-       },
-};
-#endif /* CONFIG_IPIPE */
-
-static u64 notrace exynos4_read_sched_clock(void)
-{
-       return exynos4_read_count_32();
-}
-
-#if defined(CONFIG_ARM)
-static struct delay_timer exynos4_delay_timer;
-
-static cycles_t exynos4_read_current_timer(void)
-{
-       BUILD_BUG_ON_MSG(sizeof(cycles_t) != sizeof(u32),
-                        "cycles_t needs to move to 32-bit for ARM64 usage");
-       return exynos4_read_count_32();
-}
-#endif
-
 static void __init exynos4_clocksource_init(void)
 {
        exynos4_mct_frc_start();
-
-#if defined(CONFIG_ARM)
-       exynos4_delay_timer.read_current_timer = &exynos4_read_current_timer;
-       exynos4_delay_timer.freq = clk_rate;
-       register_current_timer_delay(&exynos4_delay_timer);
-#endif
-
-       if (clocksource_register_hz(&mct_frc, clk_rate))
-               panic("%s: can't register clocksource\n", mct_frc.name);
-
-#if defined(CONFIG_IPIPE)
-       tsc_info.freq = clk_rate;
-       tsc_info.counter_vaddr = (unsigned long)(reg_base + EXYNOS4_MCT_G_CNT_L);
-       tsc_info.u.counter_paddr = phys_base + EXYNOS4_MCT_G_CNT_L;
-       __ipipe_tsc_register(&tsc_info);
-#endif /* CONFIG_IPIPE */
-
-       sched_clock_register(exynos4_read_sched_clock, 32, clk_rate);
-}
-
-static void exynos4_mct_comp0_stop(void)
-{
-       unsigned int tcon;
-
-       tcon = readl_relaxed(reg_base + EXYNOS4_MCT_G_TCON);
-       tcon &= ~(MCT_G_TCON_COMP0_ENABLE | MCT_G_TCON_COMP0_AUTO_INC);
-
-       exynos4_mct_write(tcon, EXYNOS4_MCT_G_TCON);
-       exynos4_mct_write(0, EXYNOS4_MCT_G_INT_ENB);
-}
-
-static void exynos4_mct_comp0_start(enum clock_event_mode mode,
-                                   unsigned long cycles)
-{
-       unsigned int tcon;
-       cycle_t comp_cycle;
-
-       tcon = readl_relaxed(reg_base + EXYNOS4_MCT_G_TCON);
-
-       if (mode == CLOCK_EVT_MODE_PERIODIC) {
-               tcon |= MCT_G_TCON_COMP0_AUTO_INC;
-               exynos4_mct_write(cycles, EXYNOS4_MCT_G_COMP0_ADD_INCR);
-       }
-
-       comp_cycle = exynos4_read_count_64() + cycles;
-       exynos4_mct_write((u32)comp_cycle, EXYNOS4_MCT_G_COMP0_L);
-       exynos4_mct_write((u32)(comp_cycle >> 32), EXYNOS4_MCT_G_COMP0_U);
-
-       exynos4_mct_write(0x1, EXYNOS4_MCT_G_INT_ENB);
-
-       tcon |= MCT_G_TCON_COMP0_ENABLE;
-       exynos4_mct_write(tcon , EXYNOS4_MCT_G_TCON);
-}
-
-static int exynos4_comp_set_next_event(unsigned long cycles,
-                                      struct clock_event_device *evt)
-{
-       exynos4_mct_comp0_start(evt->mode, cycles);
-
-       return 0;
-}
-
-static void exynos4_comp_set_mode(enum clock_event_mode mode,
-                                 struct clock_event_device *evt)
-{
-       unsigned long cycles_per_jiffy;
-       exynos4_mct_comp0_stop();
-
-       switch (mode) {
-       case CLOCK_EVT_MODE_PERIODIC:
-               cycles_per_jiffy =
-                       (((unsigned long long) NSEC_PER_SEC / HZ * evt->mult) >> evt->shift);
-               exynos4_mct_comp0_start(mode, cycles_per_jiffy);
-               break;
-
-       case CLOCK_EVT_MODE_ONESHOT:
-       case CLOCK_EVT_MODE_UNUSED:
-       case CLOCK_EVT_MODE_SHUTDOWN:
-       case CLOCK_EVT_MODE_RESUME:
-               break;
-       }
-}
-
-static struct clock_event_device mct_comp_device = {
-       .name           = "mct-comp",
-       .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
-       .rating         = 250,
-       .set_next_event = exynos4_comp_set_next_event,
-       .set_mode       = exynos4_comp_set_mode,
-};
-
-static irqreturn_t exynos4_mct_comp_isr(int irq, void *dev_id)
-{
-       struct clock_event_device *evt = dev_id;
-
-       exynos4_mct_write(0x1, EXYNOS4_MCT_G_INT_CSTAT);
-
-       evt->event_handler(evt);
-
-       return IRQ_HANDLED;
-}
-
-static struct irqaction mct_comp_event_irq = {
-       .name           = "mct_comp_irq",
-       .flags          = IRQF_TIMER | IRQF_IRQPOLL,
-       .handler        = exynos4_mct_comp_isr,
-       .dev_id         = &mct_comp_device,
-};
-
-static void exynos4_clockevent_init(void)
-{
-       mct_comp_device.cpumask = cpumask_of(0);
-       clockevents_config_and_register(&mct_comp_device, clk_rate,
-                                       0xf, 0xffffffff);
-       setup_irq(mct_irqs[MCT_G0_IRQ], &mct_comp_event_irq);
 }
 
 static DEFINE_PER_CPU(struct mct_clock_event_device, percpu_mct_tick);
@@ -438,54 +240,9 @@ static inline void exynos4_tick_set_mode(enum clock_event_mode mode,
        }
 }
 
-static int exynos4_mct_tick_clear(struct mct_clock_event_device *mevt)
-{
-       struct clock_event_device *evt = &mevt->evt;
-
-       /*
-        * This is for supporting oneshot mode.
-        * Mct would generate interrupt periodically
-        * without explicit stopping.
-        */
-       if (evt->mode != CLOCK_EVT_MODE_PERIODIC)
-               exynos4_mct_tick_stop(mevt);
-
-       /* Clear the MCT tick interrupt */
-       if (readl_relaxed(reg_base + mevt->base + MCT_L_INT_CSTAT_OFFSET) & 1) {
-               exynos4_mct_write(0x1, mevt->base + MCT_L_INT_CSTAT_OFFSET);
-               return 1;
-       } else {
-               return 0;
-       }
-}
-
-#if defined(CONFIG_IPIPE)
-static DEFINE_PER_CPU(struct ipipe_timer, mct_itimer);
-
-static void mct_tick_ack(void)
-{
-       struct mct_clock_event_device *mevt = raw_cpu_ptr(&percpu_mct_tick);
-
-       exynos4_mct_tick_clear(mevt);
-}
-#endif /* CONFIG_IPIPE */
-
-static irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id)
-{
-       struct mct_clock_event_device *mevt = dev_id;
-       struct clock_event_device *evt = &mevt->evt;
-
-
-       if (!clockevent_ipipe_stolen(evt))
-               exynos4_mct_tick_clear(mevt);
-
-       evt->event_handler(evt);
-
-       return IRQ_HANDLED;
-}
-
 static int exynos4_local_timer_setup(struct clock_event_device *evt)
 {
+
        struct mct_clock_event_device *mevt;
        unsigned int cpu = ipipe_processor_id();
 
@@ -503,48 +260,12 @@ static int exynos4_local_timer_setup(struct clock_event_device *evt)
 
        exynos4_mct_write(TICK_BASE_CNT, mevt->base + MCT_L_TCNTB_OFFSET);
 
-       if (mct_int_type == MCT_INT_SPI) {
-
-               if (evt->irq == -1)
-                       return -EIO;
-
-               irq_force_affinity(evt->irq, cpumask_of(cpu));
-               enable_irq(evt->irq);
-       } else {
-               enable_percpu_irq(mct_irqs[MCT_L0_IRQ], 0);
-       }
-
-#if defined(CONFIG_IPIPE)
-       evt->ipipe_timer = raw_cpu_ptr(&mct_itimer);
-       if (mct_int_type == MCT_INT_SPI)
-               evt->ipipe_timer->irq = evt->irq;
-       else
-               evt->ipipe_timer->irq = mct_irqs[MCT_L0_IRQ];
-       evt->ipipe_timer->ack = mct_tick_ack;
-#endif
-
-       clockevents_config_and_register(evt, clk_rate / (TICK_BASE_CNT + 1),
-                                       0xf, 0x7fffffff);
-
        return 0;
 }
 
 static void exynos4_local_timer_stop(struct clock_event_device *evt)
 {
        evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
-       if (mct_int_type == MCT_INT_SPI) {
-               if (evt->irq != -1) {
-                       struct mct_clock_event_device *mevt =
-                               container_of(evt, struct mct_clock_event_device,
-                                            evt);
-
-                       disable_irq_nosync(evt->irq);
-                       exynos4_mct_write(0x1, mevt->base +
-                                         MCT_L_INT_CSTAT_OFFSET);
-               }
-       } else {
-               disable_percpu_irq(mct_irqs[MCT_L0_IRQ]);
-       }
 }
 
 static int exynos4_mct_cpu_notify(struct notifier_block *self,
@@ -576,7 +297,7 @@ static struct notifier_block exynos4_mct_cpu_nb = {
 
 static void __init exynos4_timer_resources(struct device_node *np, void __iomem *base)
 {
-       int err, cpu;
+       int err;
        struct mct_clock_event_device *mevt = raw_cpu_ptr(&percpu_mct_tick);
        struct clk *mct_clk, *tick_clk;
 
@@ -595,45 +316,13 @@ static void __init exynos4_timer_resources(struct device_node *np, void __iomem
        if (!reg_base)
                panic("%s: unable to ioremap mct address space\n", __func__);
 
-       if (mct_int_type == MCT_INT_PPI) {
-
-               err = request_percpu_irq(mct_irqs[MCT_L0_IRQ],
-                                        exynos4_mct_tick_isr, "MCT",
-                                        &percpu_mct_tick);
-               WARN(err, "MCT: can't request IRQ %d (%d)\n",
-                    mct_irqs[MCT_L0_IRQ], err);
-       } else {
-               for_each_possible_cpu(cpu) {
-                       int mct_irq = mct_irqs[MCT_L0_IRQ + cpu];
-                       struct mct_clock_event_device *pcpu_mevt =
-                               per_cpu_ptr(&percpu_mct_tick, cpu);
-
-                       pcpu_mevt->evt.irq = -1;
-
-                       irq_set_status_flags(mct_irq, IRQ_NOAUTOEN);
-                       if (request_irq(mct_irq,
-                                       exynos4_mct_tick_isr,
-                                       IRQF_TIMER | IRQF_NOBALANCING,
-                                       pcpu_mevt->name, pcpu_mevt)) {
-                               pr_err("exynos-mct: cannot register IRQ (cpu%d)\n",
-                                                                       cpu);
-
-                               continue;
-                       }
-                       pcpu_mevt->evt.irq = mct_irq;
-               }
-       }
-
        err = register_cpu_notifier(&exynos4_mct_cpu_nb);
        if (err)
-               goto out_irq;
+               return;
 
        /* Immediately configure the timer on the boot CPU */
        exynos4_local_timer_setup(&mevt->evt);
        return;
-
-out_irq:
-       free_percpu_irq(mct_irqs[MCT_L0_IRQ], &percpu_mct_tick);
 }
 
 void __init mct_init(void __iomem *base, int irq_g0, int irq_l0, int irq_l1)
@@ -645,7 +334,6 @@ void __init mct_init(void __iomem *base, int irq_g0, int irq_l0, int irq_l1)
 
        exynos4_timer_resources(NULL, base);
        exynos4_clocksource_init();
-       exynos4_clockevent_init();
 }
 
 static void __init mct_init_dt(struct device_node *np, unsigned int int_type)
@@ -677,10 +365,8 @@ static void __init mct_init_dt(struct device_node *np, unsigned int int_type)
 
        exynos4_timer_resources(np, of_iomap(np, 0));
        exynos4_clocksource_init();
-       exynos4_clockevent_init();
 }
 
-
 static void __init mct_init_spi(struct device_node *np)
 {
        return mct_init_dt(np, MCT_INT_SPI);