Skip to content

Commit

Permalink
[ARM] 4812/1: RealView: clockevents support for the RealView platforms
Browse files Browse the repository at this point in the history
The patch updates the RealView code to the clockevents infrastructure.
The SMP support is implemented in subsequent patches. Based on the
Versatile implementation by Kevin Hilman.

Signed-off-by: Catalin Marinas <[email protected]>
Signed-off-by: Russell King <[email protected]>
  • Loading branch information
ctmarinas authored and Russell King committed Feb 4, 2008
1 parent 85802af commit ae30cea
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 12 deletions.
1 change: 1 addition & 0 deletions arch/arm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ config ARCH_REALVIEW
select ARM_AMBA
select ICST307
select GENERIC_TIME
select GENERIC_CLOCKEVENTS
help
This enables support for ARM Ltd RealView boards.

Expand Down
78 changes: 66 additions & 12 deletions arch/arm/mach-realview/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <linux/amba/bus.h>
#include <linux/amba/clcd.h>
#include <linux/clocksource.h>
#include <linux/clockchips.h>

#include <asm/system.h>
#include <asm/hardware.h>
Expand Down Expand Up @@ -485,20 +486,77 @@ void realview_leds_event(led_event_t ledevt)
#define TICKS2USECS(x) ((x) / TICKS_PER_uSEC)
#endif

static void timer_set_mode(enum clock_event_mode mode,
struct clock_event_device *clk)
{
unsigned long ctrl;

switch(mode) {
case CLOCK_EVT_MODE_PERIODIC:
writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_LOAD);

ctrl = TIMER_CTRL_PERIODIC;
ctrl |= TIMER_CTRL_32BIT | TIMER_CTRL_IE | TIMER_CTRL_ENABLE;
break;
case CLOCK_EVT_MODE_ONESHOT:
/* period set, and timer enabled in 'next_event' hook */
ctrl = TIMER_CTRL_ONESHOT;
ctrl |= TIMER_CTRL_32BIT | TIMER_CTRL_IE;
break;
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
default:
ctrl = 0;
}

writel(ctrl, TIMER0_VA_BASE + TIMER_CTRL);
}

static int timer_set_next_event(unsigned long evt,
struct clock_event_device *unused)
{
unsigned long ctrl = readl(TIMER0_VA_BASE + TIMER_CTRL);

writel(evt, TIMER0_VA_BASE + TIMER_LOAD);
writel(ctrl | TIMER_CTRL_ENABLE, TIMER0_VA_BASE + TIMER_CTRL);

return 0;
}

static struct clock_event_device timer0_clockevent = {
.name = "timer0",
.shift = 32,
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
.set_mode = timer_set_mode,
.set_next_event = timer_set_next_event,
.rating = 300,
.irq = IRQ_TIMERINT0_1,
.cpumask = CPU_MASK_ALL,
};

static void __init realview_clockevents_init(void)
{
timer0_clockevent.mult =
div_sc(1000000, NSEC_PER_SEC, timer0_clockevent.shift);
timer0_clockevent.max_delta_ns =
clockevent_delta2ns(0xffffffff, &timer0_clockevent);
timer0_clockevent.min_delta_ns =
clockevent_delta2ns(0xf, &timer0_clockevent);

clockevents_register_device(&timer0_clockevent);
}

/*
* IRQ handler for the timer
*/
static irqreturn_t realview_timer_interrupt(int irq, void *dev_id)
{
// ...clear the interrupt
writel(1, TIMER0_VA_BASE + TIMER_INTCLR);
struct clock_event_device *evt = &timer0_clockevent;

timer_tick();
/* clear the interrupt */
writel(1, TIMER0_VA_BASE + TIMER_INTCLR);

#if defined(CONFIG_SMP) && !defined(CONFIG_LOCAL_TIMERS)
smp_send_timer();
update_process_times(user_mode(get_irq_regs()));
#endif
evt->event_handler(evt);

return IRQ_HANDLED;
}
Expand Down Expand Up @@ -564,17 +622,13 @@ static void __init realview_timer_init(void)
writel(0, TIMER2_VA_BASE + TIMER_CTRL);
writel(0, TIMER3_VA_BASE + TIMER_CTRL);

writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_LOAD);
writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_VALUE);
writel(TIMER_DIVISOR | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC |
TIMER_CTRL_IE, TIMER0_VA_BASE + TIMER_CTRL);

/*
* Make irqs happen for the system timer
*/
setup_irq(IRQ_TIMERINT0_1, &realview_timer_irq);

realview_clocksource_init();
realview_clockevents_init();
}

struct sys_timer realview_timer = {
Expand Down

0 comments on commit ae30cea

Please sign in to comment.