From 280e12ab67d2b2f3337823334f08cf308a97c11a Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E9=BB=84=E6=B6=9B?= Date: Mon, 14 Jun 2010 07:22:53 +0000 Subject: [PATCH] TIMER: clock source use timer3, clock event use timer2 --- arch/arm/mach-rk2818/timer.c | 249 +++++++++++++++++------------------ 1 file changed, 118 insertions(+), 131 deletions(-) diff --git a/arch/arm/mach-rk2818/timer.c b/arch/arm/mach-rk2818/timer.c index 1a9ad50a2e6b..2caa74d4c90e 100644 --- a/arch/arm/mach-rk2818/timer.c +++ b/arch/arm/mach-rk2818/timer.c @@ -19,8 +19,8 @@ #include #include #include -#include #include +#include #include #include @@ -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 CSR_PROTECTION 0x0020 -#define CSR_PROTECTION_EN 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; + +#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_DISABLE 4 +#define TIMER_ENABLE 3 +#define TIMER_ENABLE_FREE_RUNNING 1 + +static struct clk *timer_clk; +static volatile unsigned long timer_mult; + +static int rk2818_timer_set_next_event(unsigned long cycles, struct clock_event_device *evt) +{ + 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); + + return 0; +} + +static void rk2818_timer_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) +{ + switch (mode) { + case CLOCK_EVT_MODE_RESUME: + case CLOCK_EVT_MODE_PERIODIC: + case CLOCK_EVT_MODE_ONESHOT: + break; + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + writel(TIMER_DISABLE, RK2818_TIMER2_BASE + TIMER_CONTROL_REG); + break; + } +} + +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_timer_interrupt(int irq, void *dev_id) +static irqreturn_t rk2818_timer2_interrupt(int irq, void *dev_id) { 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; + + readl(RK2818_TIMER2_BASE + TIMER_EOI); + writel(TIMER_DISABLE, RK2818_TIMER2_BASE + TIMER_CONTROL_REG); + evt->event_handler(evt); + return IRQ_HANDLED; } -static cycle_t rk2818_timer_read(struct clocksource *cs) +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; + } - unsigned int elapsed; - unsigned int t; + return 0; +} - t = readl(RK2818_TIMER3_BASE + TIMER_LOAD_COUNT); +static struct notifier_block rk2818_timer_cpufreq_notifier_block = { + .notifier_call = rk2818_timer_cpufreq_notifier, + .priority = 0x7ffffff, +}; - elapsed = __raw_readl(RK2818_TIMER3_BASE + TIMER_CUR_VALUE); - - elapsed = t - elapsed; - elapsed += pit_cnt; - return elapsed; +static __init int rk2818_timer_init_cpufreq(void) +{ + cpufreq_register_notifier(&rk2818_timer_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); + return 0; } -static int rk2818_timer_set_next_event(unsigned long cycles, - struct clock_event_device *evt) +arch_initcall_sync(rk2818_timer_init_cpufreq); + +static __init int rk2818_timer_init_clockevent(void) { - - struct rk2818_clock *clock = container_of(evt, struct rk2818_clock, clockevent); + 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); - 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 cycle_t rk2818_timer3_read(struct clocksource *cs) { - 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); - break; - } + return ~readl(RK2818_TIMER3_BASE + TIMER_CUR_VALUE); } -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 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 }; + -- 2.34.1