Skip to content

Commit

Permalink
ARM: Realview/Versatile: separate out common SP804 timer code
Browse files Browse the repository at this point in the history
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
  • Loading branch information
Russell King committed May 2, 2010
1 parent f4b8b31 commit e388771
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 268 deletions.
5 changes: 5 additions & 0 deletions arch/arm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ config ARCH_REALVIEW
select GENERIC_CLOCKEVENTS
select ARCH_WANT_OPTIONAL_GPIOLIB
select PLAT_VERSATILE
select ARM_TIMER_SP804
help
This enables support for ARM Ltd RealView boards.

Expand All @@ -271,6 +272,7 @@ config ARCH_VERSATILE
select GENERIC_CLOCKEVENTS
select ARCH_WANT_OPTIONAL_GPIOLIB
select PLAT_VERSATILE
select ARM_TIMER_SP804
help
This enables support for ARM Ltd Versatile board.

Expand Down Expand Up @@ -944,6 +946,9 @@ config PLAT_PXA
config PLAT_VERSATILE
bool

config ARM_TIMER_SP804
bool

source arch/arm/mm/Kconfig

config IWMMXT
Expand Down
139 changes: 3 additions & 136 deletions arch/arm/mach-realview/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@
#include <linux/interrupt.h>
#include <linux/amba/bus.h>
#include <linux/amba/clcd.h>
#include <linux/clocksource.h>
#include <linux/clockchips.h>
#include <linux/io.h>
#include <linux/smsc911x.h>
#include <linux/ata_platform.h>
Expand All @@ -51,6 +49,7 @@
#include <mach/clkdev.h>
#include <mach/platform.h>
#include <mach/irqs.h>
#include <plat/timer-sp.h>

#include "core.h"

Expand Down Expand Up @@ -645,133 +644,6 @@ void __iomem *timer1_va_base;
void __iomem *timer2_va_base;
void __iomem *timer3_va_base;

/*
* How long is the timer interval?
*/
#define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10)
#if TIMER_INTERVAL >= 0x100000
#define TIMER_RELOAD (TIMER_INTERVAL >> 8)
#define TIMER_DIVISOR (TIMER_CTRL_DIV256)
#define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC)
#elif TIMER_INTERVAL >= 0x10000
#define TIMER_RELOAD (TIMER_INTERVAL >> 4) /* Divide by 16 */
#define TIMER_DIVISOR (TIMER_CTRL_DIV16)
#define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC)
#else
#define TIMER_RELOAD (TIMER_INTERVAL)
#define TIMER_DIVISOR (TIMER_CTRL_DIV1)
#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,
.cpumask = cpu_all_mask,
};

static void __init realview_clockevents_init(unsigned int timer_irq)
{
timer0_clockevent.irq = timer_irq;
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)
{
struct clock_event_device *evt = &timer0_clockevent;

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

evt->event_handler(evt);

return IRQ_HANDLED;
}

static struct irqaction realview_timer_irq = {
.name = "RealView Timer Tick",
.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.handler = realview_timer_interrupt,
};

static cycle_t realview_get_cycles(struct clocksource *cs)
{
return ~readl(timer3_va_base + TIMER_VALUE);
}

static struct clocksource clocksource_realview = {
.name = "timer3",
.rating = 200,
.read = realview_get_cycles,
.mask = CLOCKSOURCE_MASK(32),
.shift = 20,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};

static void __init realview_clocksource_init(void)
{
/* setup timer 0 as free-running clocksource */
writel(0, timer3_va_base + TIMER_CTRL);
writel(0xffffffff, timer3_va_base + TIMER_LOAD);
writel(0xffffffff, timer3_va_base + TIMER_VALUE);
writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC,
timer3_va_base + TIMER_CTRL);

clocksource_realview.mult =
clocksource_khz2mult(1000, clocksource_realview.shift);
clocksource_register(&clocksource_realview);
}

/*
* Set up the clock source and clock events devices
*/
Expand Down Expand Up @@ -799,13 +671,8 @@ void __init realview_timer_init(unsigned int timer_irq)
writel(0, timer2_va_base + TIMER_CTRL);
writel(0, timer3_va_base + TIMER_CTRL);

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

realview_clocksource_init();
realview_clockevents_init(timer_irq);
sp804_clocksource_init(timer3_va_base);
sp804_clockevents_init(timer0_va_base, timer_irq);
}

/*
Expand Down
135 changes: 3 additions & 132 deletions arch/arm/mach-versatile/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@
#include <linux/amba/clcd.h>
#include <linux/amba/pl061.h>
#include <linux/amba/mmci.h>
#include <linux/clocksource.h>
#include <linux/clockchips.h>
#include <linux/cnt32_to_63.h>
#include <linux/io.h>

Expand All @@ -50,6 +48,7 @@
#include <mach/clkdev.h>
#include <mach/hardware.h>
#include <mach/platform.h>
#include <plat/timer-sp.h>

#include "core.h"

Expand Down Expand Up @@ -877,120 +876,6 @@ void __init versatile_init(void)
#define TIMER1_VA_BASE (__io_address(VERSATILE_TIMER0_1_BASE) + 0x20)
#define TIMER2_VA_BASE __io_address(VERSATILE_TIMER2_3_BASE)
#define TIMER3_VA_BASE (__io_address(VERSATILE_TIMER2_3_BASE) + 0x20)
#define VA_IC_BASE __io_address(VERSATILE_VIC_BASE)

/*
* How long is the timer interval?
*/
#define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10)
#if TIMER_INTERVAL >= 0x100000
#define TIMER_RELOAD (TIMER_INTERVAL >> 8)
#define TIMER_DIVISOR (TIMER_CTRL_DIV256)
#define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC)
#elif TIMER_INTERVAL >= 0x10000
#define TIMER_RELOAD (TIMER_INTERVAL >> 4) /* Divide by 16 */
#define TIMER_DIVISOR (TIMER_CTRL_DIV16)
#define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC)
#else
#define TIMER_RELOAD (TIMER_INTERVAL)
#define TIMER_DIVISOR (TIMER_CTRL_DIV1)
#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,
};

/*
* IRQ handler for the timer
*/
static irqreturn_t versatile_timer_interrupt(int irq, void *dev_id)
{
struct clock_event_device *evt = &timer0_clockevent;

writel(1, TIMER0_VA_BASE + TIMER_INTCLR);

evt->event_handler(evt);

return IRQ_HANDLED;
}

static struct irqaction versatile_timer_irq = {
.name = "Versatile Timer Tick",
.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.handler = versatile_timer_interrupt,
};

static cycle_t versatile_get_cycles(struct clocksource *cs)
{
return ~readl(TIMER3_VA_BASE + TIMER_VALUE);
}

static struct clocksource clocksource_versatile = {
.name = "timer3",
.rating = 200,
.read = versatile_get_cycles,
.mask = CLOCKSOURCE_MASK(32),
.shift = 20,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};

static int __init versatile_clocksource_init(void)
{
/* setup timer3 as free-running clocksource */
writel(0, TIMER3_VA_BASE + TIMER_CTRL);
writel(0xffffffff, TIMER3_VA_BASE + TIMER_LOAD);
writel(0xffffffff, TIMER3_VA_BASE + TIMER_VALUE);
writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC,
TIMER3_VA_BASE + TIMER_CTRL);

clocksource_versatile.mult =
clocksource_khz2mult(1000, clocksource_versatile.shift);
clocksource_register(&clocksource_versatile);

return 0;
}

/*
* Set up timer interrupt, and return the current time in seconds.
Expand Down Expand Up @@ -1019,22 +904,8 @@ static void __init versatile_timer_init(void)
writel(0, TIMER2_VA_BASE + TIMER_CTRL);
writel(0, TIMER3_VA_BASE + TIMER_CTRL);

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

versatile_clocksource_init();

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);

timer0_clockevent.cpumask = cpumask_of(0);
clockevents_register_device(&timer0_clockevent);
sp804_clocksource_init(TIMER3_VA_BASE);
sp804_clockevents_init(TIMER0_VA_BASE, IRQ_TIMERINT0_1);
}

struct sys_timer versatile_timer = {
Expand Down
1 change: 1 addition & 0 deletions arch/arm/plat-versatile/Makefile
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
obj-y := clock.o
obj-$(CONFIG_ARM_TIMER_SP804) += timer-sp.o
2 changes: 2 additions & 0 deletions arch/arm/plat-versatile/include/plat/timer-sp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
void sp804_clocksource_init(void __iomem *);
void sp804_clockevents_init(void __iomem *, unsigned int);
Loading

0 comments on commit e388771

Please sign in to comment.