|
|
@@ -32,6 +32,7 @@
|
|
|
#include <linux/interrupt.h>
|
|
|
#include <linux/io.h>
|
|
|
#include <linux/mtd/physmap.h>
|
|
|
+#include <linux/clk.h>
|
|
|
#include <video/vga.h>
|
|
|
|
|
|
#include <mach/hardware.h>
|
|
|
@@ -322,27 +323,16 @@ static void __init ap_init(void)
|
|
|
#define TIMER1_VA_BASE IO_ADDRESS(INTEGRATOR_TIMER1_BASE)
|
|
|
#define TIMER2_VA_BASE IO_ADDRESS(INTEGRATOR_TIMER2_BASE)
|
|
|
|
|
|
-/*
|
|
|
- * How long is the timer interval?
|
|
|
- */
|
|
|
-#define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10)
|
|
|
-#if TIMER_INTERVAL >= 0x100000
|
|
|
-#define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC)
|
|
|
-#elif TIMER_INTERVAL >= 0x10000
|
|
|
-#define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC)
|
|
|
-#else
|
|
|
-#define TICKS2USECS(x) ((x) / TICKS_PER_uSEC)
|
|
|
-#endif
|
|
|
-
|
|
|
static unsigned long timer_reload;
|
|
|
|
|
|
-static void integrator_clocksource_init(u32 khz)
|
|
|
+static void integrator_clocksource_init(unsigned long inrate)
|
|
|
{
|
|
|
void __iomem *base = (void __iomem *)TIMER2_VA_BASE;
|
|
|
u32 ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC;
|
|
|
+ unsigned long rate = inrate;
|
|
|
|
|
|
- if (khz >= 1500) {
|
|
|
- khz /= 16;
|
|
|
+ if (rate >= 1500000) {
|
|
|
+ rate /= 16;
|
|
|
ctrl |= TIMER_CTRL_DIV16;
|
|
|
}
|
|
|
|
|
|
@@ -350,7 +340,7 @@ static void integrator_clocksource_init(u32 khz)
|
|
|
writel(ctrl, base + TIMER_CTRL);
|
|
|
|
|
|
clocksource_mmio_init(base + TIMER_VALUE, "timer2",
|
|
|
- khz * 1000, 200, 16, clocksource_mmio_readl_down);
|
|
|
+ rate, 200, 16, clocksource_mmio_readl_down);
|
|
|
}
|
|
|
|
|
|
static void __iomem * const clkevt_base = (void __iomem *)TIMER1_VA_BASE;
|
|
|
@@ -374,15 +364,29 @@ static void clkevt_set_mode(enum clock_event_mode mode, struct clock_event_devic
|
|
|
{
|
|
|
u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE;
|
|
|
|
|
|
- BUG_ON(mode == CLOCK_EVT_MODE_ONESHOT);
|
|
|
+ /* Disable timer */
|
|
|
+ writel(ctrl, clkevt_base + TIMER_CTRL);
|
|
|
|
|
|
- if (mode == CLOCK_EVT_MODE_PERIODIC) {
|
|
|
- writel(ctrl, clkevt_base + TIMER_CTRL);
|
|
|
+ switch (mode) {
|
|
|
+ case CLOCK_EVT_MODE_PERIODIC:
|
|
|
+ /* Enable the timer and start the periodic tick */
|
|
|
writel(timer_reload, clkevt_base + TIMER_LOAD);
|
|
|
ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
|
|
|
+ writel(ctrl, clkevt_base + TIMER_CTRL);
|
|
|
+ break;
|
|
|
+ case CLOCK_EVT_MODE_ONESHOT:
|
|
|
+ /* Leave the timer disabled, .set_next_event will enable it */
|
|
|
+ ctrl &= ~TIMER_CTRL_PERIODIC;
|
|
|
+ writel(ctrl, clkevt_base + TIMER_CTRL);
|
|
|
+ break;
|
|
|
+ case CLOCK_EVT_MODE_UNUSED:
|
|
|
+ case CLOCK_EVT_MODE_SHUTDOWN:
|
|
|
+ case CLOCK_EVT_MODE_RESUME:
|
|
|
+ default:
|
|
|
+ /* Just leave in disabled state */
|
|
|
+ break;
|
|
|
}
|
|
|
|
|
|
- writel(ctrl, clkevt_base + TIMER_CTRL);
|
|
|
}
|
|
|
|
|
|
static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt)
|
|
|
@@ -398,12 +402,10 @@ static int clkevt_set_next_event(unsigned long next, struct clock_event_device *
|
|
|
|
|
|
static struct clock_event_device integrator_clockevent = {
|
|
|
.name = "timer1",
|
|
|
- .shift = 34,
|
|
|
- .features = CLOCK_EVT_FEAT_PERIODIC,
|
|
|
+ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
|
|
|
.set_mode = clkevt_set_mode,
|
|
|
.set_next_event = clkevt_set_next_event,
|
|
|
.rating = 300,
|
|
|
- .cpumask = cpu_all_mask,
|
|
|
};
|
|
|
|
|
|
static struct irqaction integrator_timer_irq = {
|
|
|
@@ -413,29 +415,27 @@ static struct irqaction integrator_timer_irq = {
|
|
|
.dev_id = &integrator_clockevent,
|
|
|
};
|
|
|
|
|
|
-static void integrator_clockevent_init(u32 khz)
|
|
|
+static void integrator_clockevent_init(unsigned long inrate)
|
|
|
{
|
|
|
- struct clock_event_device *evt = &integrator_clockevent;
|
|
|
+ unsigned long rate = inrate;
|
|
|
unsigned int ctrl = 0;
|
|
|
|
|
|
- if (khz * 1000 > 0x100000 * HZ) {
|
|
|
- khz /= 256;
|
|
|
+ /* Calculate and program a divisor */
|
|
|
+ if (rate > 0x100000 * HZ) {
|
|
|
+ rate /= 256;
|
|
|
ctrl |= TIMER_CTRL_DIV256;
|
|
|
- } else if (khz * 1000 > 0x10000 * HZ) {
|
|
|
- khz /= 16;
|
|
|
+ } else if (rate > 0x10000 * HZ) {
|
|
|
+ rate /= 16;
|
|
|
ctrl |= TIMER_CTRL_DIV16;
|
|
|
}
|
|
|
-
|
|
|
- timer_reload = khz * 1000 / HZ;
|
|
|
+ timer_reload = rate / HZ;
|
|
|
writel(ctrl, clkevt_base + TIMER_CTRL);
|
|
|
|
|
|
- evt->irq = IRQ_TIMERINT1;
|
|
|
- evt->mult = div_sc(khz, NSEC_PER_MSEC, evt->shift);
|
|
|
- evt->max_delta_ns = clockevent_delta2ns(0xffff, evt);
|
|
|
- evt->min_delta_ns = clockevent_delta2ns(0xf, evt);
|
|
|
-
|
|
|
setup_irq(IRQ_TIMERINT1, &integrator_timer_irq);
|
|
|
- clockevents_register_device(evt);
|
|
|
+ clockevents_config_and_register(&integrator_clockevent,
|
|
|
+ rate,
|
|
|
+ 1,
|
|
|
+ 0xffffU);
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
@@ -443,14 +443,20 @@ static void integrator_clockevent_init(u32 khz)
|
|
|
*/
|
|
|
static void __init ap_init_timer(void)
|
|
|
{
|
|
|
- u32 khz = TICKS_PER_uSEC * 1000;
|
|
|
+ struct clk *clk;
|
|
|
+ unsigned long rate;
|
|
|
+
|
|
|
+ clk = clk_get_sys("ap_timer", NULL);
|
|
|
+ BUG_ON(IS_ERR(clk));
|
|
|
+ clk_enable(clk);
|
|
|
+ rate = clk_get_rate(clk);
|
|
|
|
|
|
writel(0, TIMER0_VA_BASE + TIMER_CTRL);
|
|
|
writel(0, TIMER1_VA_BASE + TIMER_CTRL);
|
|
|
writel(0, TIMER2_VA_BASE + TIMER_CTRL);
|
|
|
|
|
|
- integrator_clocksource_init(khz);
|
|
|
- integrator_clockevent_init(khz);
|
|
|
+ integrator_clocksource_init(rate);
|
|
|
+ integrator_clockevent_init(rate);
|
|
|
}
|
|
|
|
|
|
static struct sys_timer ap_timer = {
|