static void kw_clkevt_mode(enum clock_event_mode mode, struct clock_event_device *dev) { unsigned long flags; local_irq_save(flags); if (mode == CLOCK_EVT_MODE_PERIODIC) { /* * Setup latch cycles in timer and enable reload interrupt. */ MV_REG_WRITE(CNTMR_RELOAD_REG(CLOCKEVENT), ((mvBoardTclkGet() + HZ/2) / HZ)); MV_REG_WRITE(CNTMR_VAL_REG(CLOCKEVENT), ((mvBoardTclkGet() + HZ/2) / HZ)); MV_REG_BIT_SET(BRIDGE_INT_MASK_REG, BRIDGE_INT_TIMER(CLOCKEVENT)); MV_REG_BIT_SET(CNTMR_CTRL_REG, TIMER_RELOAD_EN(CLOCKEVENT) | TIMER_EN(CLOCKEVENT)); } else { /* * Disable timer and interrupt */ MV_REG_BIT_RESET(BRIDGE_INT_MASK_REG, BRIDGE_INT_TIMER(CLOCKEVENT)); MV_REG_WRITE(BRIDGE_INT_CAUSE_REG, ~BRIDGE_INT_TIMER(CLOCKEVENT)); MV_REG_BIT_RESET(CNTMR_CTRL_REG, TIMER_RELOAD_EN(CLOCKEVENT) | TIMER_EN(CLOCKEVENT)); } local_irq_restore(flags); }
static int kw_clkevt_next_event(unsigned long delta, struct clock_event_device *dev) { unsigned long flags; if (delta == 0) return -ETIME; local_irq_save(flags); /* * Clear and enable timer interrupt bit */ MV_REG_WRITE(BRIDGE_INT_CAUSE_REG, ~BRIDGE_INT_TIMER(CLOCKEVENT)); MV_REG_BIT_SET(BRIDGE_INT_MASK_REG, BRIDGE_INT_TIMER(CLOCKEVENT)); /* * Setup new timer value */ MV_REG_WRITE(CNTMR_VAL_REG(CLOCKEVENT), delta); /* * Disable auto reload and kickoff the timer */ MV_REG_BIT_RESET(CNTMR_CTRL_REG, TIMER_RELOAD_EN(CLOCKEVENT)); MV_REG_BIT_SET(CNTMR_CTRL_REG, TIMER_EN(CLOCKEVENT)); local_irq_restore(flags); return 0; }
int mv_enable_fc_events(void *fc_event_handler, unsigned long period_ns) { unsigned long flags; uint64_t clock_ticks = period_ns; if (fc_event_handler == 0) return -1; local_irq_save(flags); mv_fc_event_handler = fc_event_handler; clock_ticks *= kw_clkevt.mult; clock_ticks >>= kw_clkevt.shift; /* Setup timer value */ MV_REG_WRITE(CNTMR_RELOAD_REG(FCTRLEVENT), (unsigned long)clock_ticks); MV_REG_WRITE(CNTMR_VAL_REG(FCTRLEVENT), (unsigned long)clock_ticks); /* Enable periodic timer and timer interrupt */ MV_REG_BIT_SET(BRIDGE_INT_MASK_REG, BRIDGE_INT_TIMER(FCTRLEVENT)); MV_REG_BIT_SET(CNTMR_CTRL_REG, TIMER_RELOAD_EN(FCTRLEVENT) | TIMER_EN(FCTRLEVENT)); fc_disabled = 0; local_irq_restore(flags); return 0; }
void mv_disable_fc_events(void) { unsigned long flags; local_irq_save(flags); /* Disable timer */ MV_REG_BIT_RESET(CNTMR_CTRL_REG, TIMER_EN(FCTRLEVENT)); MV_REG_BIT_RESET(CNTMR_CTRL_REG, TIMER_RELOAD_EN(FCTRLEVENT)); /* Clear and disable interrupt */ MV_REG_WRITE(BRIDGE_INT_CAUSE_REG, ~BRIDGE_INT_TIMER(FCTRLEVENT)); MV_REG_BIT_RESET(BRIDGE_INT_MASK_REG, BRIDGE_INT_TIMER(FCTRLEVENT)); fc_disabled = 1; local_irq_restore(flags); }
static void mv_init_timer(void) { /* * Setup clocksource free running timer (no interrupt on reload) */ MV_REG_WRITE(CNTMR_VAL_REG(CLOCKSOURCE), 0xffffffff); MV_REG_WRITE(CNTMR_RELOAD_REG(CLOCKSOURCE), 0xffffffff); MV_REG_BIT_RESET(BRIDGE_INT_MASK_REG, BRIDGE_INT_TIMER(CLOCKSOURCE)); MV_REG_BIT_SET(CNTMR_CTRL_REG, TIMER_RELOAD_EN(CLOCKSOURCE) | TIMER_EN(CLOCKSOURCE)); kw_clkevt.cpumask = cpumask_of(0); /* * Register clocksource */ kw_clksrc.mult = clocksource_hz2mult(mvBoardTclkGet(), kw_clksrc.shift); clocksource_register(&kw_clksrc); /* * Connect and enable tick handler */ setup_irq(IRQ_BRIDGE, &kw_timer_irq); /* * Register clockevent */ kw_clkevt.mult = div_sc(mvBoardTclkGet(), NSEC_PER_SEC, kw_clkevt.shift); kw_clkevt.max_delta_ns = clockevent_delta2ns(0xfffffffe, &kw_clkevt); kw_clkevt.min_delta_ns = clockevent_delta2ns(1, &kw_clkevt); /* * Setup clockevent timer (interrupt-driven.) */ clockevents_register_device(&kw_clkevt); }