TIMER: clock source use timer3, clock event use timer2

This commit is contained in:
黄涛
2010-06-14 07:22:53 +00:00
parent 31053020ed
commit 280e12ab67

View File

@@ -19,8 +19,8 @@
#include <linux/irq.h>
#include <linux/clk.h>
#include <linux/clockchips.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/cpufreq.h>
#include <asm/mach/time.h>
#include <mach/rk2818_iomap.h>
@@ -28,164 +28,151 @@
#define RK2818_TIMER1_BASE RK2818_TIMER_BASE
#define RK2818_TIMER2_BASE RK2818_TIMER_BASE + 0x14
#define RK2818_TIMER3_BASE RK2818_TIMER_BASE + 0x28
#define TIMER_LOAD_COUNT 0x0000
#define TIMER_CUR_VALUE 0x0004
#define TIMER_CONTROL_REG 0x0008
#define TIMER_EOI 0x000C
#define TIMER_INT_STATUS 0x0010
#define TIMER_MATCH_VAL 0x0000
#define TIMER_COUNT_VAL 0x0004
#define TIMER_ENABLE 0x0008
#define TIMER_ENABLE_CLR_ON_MATCH_EN 2
#define TIMER_ENABLE_EN 3
#define TIMER_CLEAR 0x000C
#define TIMER_LOAD_COUNT 0x0000
#define TIMER_CUR_VALUE 0x0004
#define TIMER_CONTROL_REG 0x0008
#define TIMER_EOI 0x000C
#define TIMER_INT_STATUS 0x0010
#define CSR_PROTECTION 0x0020
#define CSR_PROTECTION_EN 1
#define TIMER_DISABLE 4
#define TIMER_ENABLE 3
#define TIMER_ENABLE_FREE_RUNNING 1
#define TIMER_HZ 24000000
#define timer_cycle (TIMER_HZ+HZ/2)/HZ
uint32_t tcount;
uint32_t mycycles = 0;
static int pit_cnt=0;
struct rk2818_clock {
struct clock_event_device clockevent;
struct clocksource clocksource;
struct irqaction irq;
uint32_t regbase;
uint32_t freq;
uint32_t shift;
};
static struct clk *timer_clk;
static volatile unsigned long timer_mult;
static irqreturn_t rk2818_timer_interrupt(int irq, void *dev_id)
static int rk2818_timer_set_next_event(unsigned long cycles, struct clock_event_device *evt)
{
struct clock_event_device *evt = dev_id;
struct rk2818_clock *clock = container_of(evt, struct rk2818_clock, clockevent);
readl(clock->regbase + TIMER_EOI);
pit_cnt +=mycycles;
evt->event_handler(evt);
return IRQ_HANDLED;
}
writel(TIMER_DISABLE, RK2818_TIMER2_BASE + TIMER_CONTROL_REG);
writel(cycles * timer_mult, RK2818_TIMER2_BASE + TIMER_LOAD_COUNT);
writel(TIMER_ENABLE, RK2818_TIMER2_BASE + TIMER_CONTROL_REG);
static cycle_t rk2818_timer_read(struct clocksource *cs)
{
unsigned int elapsed;
unsigned int t;
t = readl(RK2818_TIMER3_BASE + TIMER_LOAD_COUNT);
elapsed = __raw_readl(RK2818_TIMER3_BASE + TIMER_CUR_VALUE);
elapsed = t - elapsed;
elapsed += pit_cnt;
return elapsed;
}
static int rk2818_timer_set_next_event(unsigned long cycles,
struct clock_event_device *evt)
{
struct rk2818_clock *clock = container_of(evt, struct rk2818_clock, clockevent);
writel(4, clock->regbase + TIMER_CONTROL_REG);
mycycles = cycles;
writel(cycles, clock->regbase + TIMER_LOAD_COUNT);
writel(TIMER_ENABLE_EN, clock->regbase + TIMER_CONTROL_REG);
return 0;
}
static void rk2818_timer_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
static void rk2818_timer_set_mode(enum clock_event_mode mode, struct clock_event_device *evt)
{
struct rk2818_clock *clock = container_of(evt, struct rk2818_clock, clockevent);
printk("%s::Enter--mode is %d\n",__FUNCTION__,mode);
switch (mode) {
case CLOCK_EVT_MODE_RESUME:
case CLOCK_EVT_MODE_PERIODIC:
break;
case CLOCK_EVT_MODE_ONESHOT:
readl(clock->regbase+TIMER_EOI);
writel((TIMER_HZ+ HZ/2) / HZ,clock->regbase+TIMER_LOAD_COUNT);
writel(TIMER_ENABLE_EN, clock->regbase + TIMER_CONTROL_REG);
break;
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
writel(4, clock->regbase + TIMER_CONTROL_REG);
writel(TIMER_DISABLE, RK2818_TIMER2_BASE + TIMER_CONTROL_REG);
break;
}
}
static struct rk2818_clock rk2818_system_clocks[] = {
{
.clockevent = {
.name = "timer",
.features = CLOCK_EVT_FEAT_ONESHOT,
.shift = 32,
.rating = 200,
.set_next_event = rk2818_timer_set_next_event,
.set_mode = rk2818_timer_set_mode,
},
.clocksource = {
.name = "timer",
.rating = 200,
.read = rk2818_timer_read,
.mask = CLOCKSOURCE_MASK(24),
.shift = 26,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
},
.irq = {
.name = "timer",
.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_TRIGGER_RISING,
.handler = rk2818_timer_interrupt,
.dev_id = &rk2818_system_clocks[0].clockevent,
.irq = IRQ_NR_TIMER3
},
.regbase = RK2818_TIMER3_BASE,
.freq = TIMER_HZ
},
static struct clock_event_device clockenent_timer2 = {
.name = "timer2",
.features = CLOCK_EVT_FEAT_ONESHOT,
.shift = 32,
.rating = 200,
.set_next_event = rk2818_timer_set_next_event,
.set_mode = rk2818_timer_set_mode,
};
static irqreturn_t rk2818_timer2_interrupt(int irq, void *dev_id)
{
struct clock_event_device *evt = dev_id;
readl(RK2818_TIMER2_BASE + TIMER_EOI);
writel(TIMER_DISABLE, RK2818_TIMER2_BASE + TIMER_CONTROL_REG);
evt->event_handler(evt);
return IRQ_HANDLED;
}
static struct irqaction rk2818_timer2_irq = {
.name = "timer2",
.flags = IRQF_DISABLED | IRQF_TIMER,
.handler = rk2818_timer2_interrupt,
.irq = IRQ_NR_TIMER2,
.dev_id = &clockenent_timer2,
};
static int rk2818_timer_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data)
{
if (val == CPUFREQ_POSTCHANGE) {
timer_mult = clk_get_rate(timer_clk) / 1000000;
}
return 0;
}
static struct notifier_block rk2818_timer_cpufreq_notifier_block = {
.notifier_call = rk2818_timer_cpufreq_notifier,
.priority = 0x7ffffff,
};
static __init int rk2818_timer_init_cpufreq(void)
{
cpufreq_register_notifier(&rk2818_timer_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
return 0;
}
arch_initcall_sync(rk2818_timer_init_cpufreq);
static __init int rk2818_timer_init_clockevent(void)
{
struct clock_event_device *ce = &clockenent_timer2;
timer_clk = clk_get(NULL, "timer");
timer_mult = clk_get_rate(timer_clk) / 1000000;
writel(TIMER_DISABLE, RK2818_TIMER2_BASE + TIMER_CONTROL_REG);
setup_irq(rk2818_timer2_irq.irq, &rk2818_timer2_irq);
ce->mult = div_sc(1000000, NSEC_PER_SEC, ce->shift);
ce->max_delta_ns = clockevent_delta2ns(0xFFFFFFFFUL / 256, ce); // max pclk < 256MHz
ce->min_delta_ns = clockevent_delta2ns(1, ce);
ce->cpumask = cpumask_of(0);
clockevents_register_device(ce);
return 0;
}
static cycle_t rk2818_timer3_read(struct clocksource *cs)
{
return ~readl(RK2818_TIMER3_BASE + TIMER_CUR_VALUE);
}
static struct clocksource clocksource_timer3 = {
.name = "timer3",
.rating = 200,
.read = rk2818_timer3_read,
.mask = CLOCKSOURCE_MASK(32),
.shift = 26,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
static void __init rk2818_timer_init_clocksource(void)
{
static char err[] __initdata = KERN_ERR "%s: can't register clocksource!\n";
struct clocksource *cs = &clocksource_timer3;
writel(TIMER_DISABLE, RK2818_TIMER3_BASE + TIMER_CONTROL_REG);
writel(0xFFFFFFFF, RK2818_TIMER3_BASE + TIMER_LOAD_COUNT);
writel(TIMER_ENABLE_FREE_RUNNING, RK2818_TIMER3_BASE + TIMER_CONTROL_REG);
cs->mult = clocksource_hz2mult(24000000, cs->shift);
if (clocksource_register(cs))
printk(err, cs->name);
}
static void __init rk2818_timer_init(void)
{
int i;
int res;
for (i = 0; i < ARRAY_SIZE(rk2818_system_clocks); i++) {
struct rk2818_clock *clock = &rk2818_system_clocks[i];
struct clock_event_device *ce = &clock->clockevent;
struct clocksource *cs = &clock->clocksource;
printk("%s::Enter %d\n",__FUNCTION__,i+1);
writel((TIMER_HZ+ HZ/2) / HZ,clock->regbase+TIMER_LOAD_COUNT);
writel(0x04, clock->regbase + TIMER_CONTROL_REG);
ce->mult = div_sc(clock->freq, NSEC_PER_SEC, ce->shift);
/* allow at least 10 seconds to notice that the timer wrapped */
ce->max_delta_ns =
clockevent_delta2ns(0xf0000000 >> clock->shift, ce);
/* 4 gets rounded down to 3 */
ce->min_delta_ns = clockevent_delta2ns(4, ce);
ce->cpumask = cpumask_of(0);
cs->mult = clocksource_hz2mult(clock->freq, cs->shift);
printk("mult is %x\n",cs->mult);
res = clocksource_register(cs);
if (res)
printk(KERN_ERR "rk2818_timer_init: clocksource_register "
"failed for %s\n", cs->name);
printk("%s::irq is %d\n",__FUNCTION__,clock->irq.irq);
res = setup_irq(clock->irq.irq, &clock->irq);
if (res)
printk(KERN_ERR "rk2818_timer_init: setup_irq "
"failed for %s\n", cs->name);
clockevents_register_device(ce);
}
rk2818_timer_init_clocksource();
rk2818_timer_init_clockevent();
}
struct sys_timer rk2818_timer = {
.init = rk2818_timer_init
};