|
@@ -132,7 +132,6 @@ static int __init bfin_cs_gptimer0_init(void)
|
|
# define bfin_cs_gptimer0_init()
|
|
# define bfin_cs_gptimer0_init()
|
|
#endif
|
|
#endif
|
|
|
|
|
|
-
|
|
|
|
#if defined(CONFIG_GPTMR0_CLOCKSOURCE) || defined(CONFIG_CYCLES_CLOCKSOURCE)
|
|
#if defined(CONFIG_GPTMR0_CLOCKSOURCE) || defined(CONFIG_CYCLES_CLOCKSOURCE)
|
|
/* prefer to use cycles since it has higher rating */
|
|
/* prefer to use cycles since it has higher rating */
|
|
notrace unsigned long long sched_clock(void)
|
|
notrace unsigned long long sched_clock(void)
|
|
@@ -145,47 +144,8 @@ notrace unsigned long long sched_clock(void)
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
|
|
-#ifdef CONFIG_CORE_TIMER_IRQ_L1
|
|
|
|
-__attribute__((l1_text))
|
|
|
|
-#endif
|
|
|
|
-irqreturn_t timer_interrupt(int irq, void *dev_id);
|
|
|
|
-
|
|
|
|
-static int bfin_timer_set_next_event(unsigned long, \
|
|
|
|
- struct clock_event_device *);
|
|
|
|
-
|
|
|
|
-static void bfin_timer_set_mode(enum clock_event_mode, \
|
|
|
|
- struct clock_event_device *);
|
|
|
|
-
|
|
|
|
-static struct clock_event_device clockevent_bfin = {
|
|
|
|
-#if defined(CONFIG_TICKSOURCE_GPTMR0)
|
|
|
|
- .name = "bfin_gptimer0",
|
|
|
|
- .rating = 300,
|
|
|
|
- .irq = IRQ_TIMER0,
|
|
|
|
-#else
|
|
|
|
- .name = "bfin_core_timer",
|
|
|
|
- .rating = 350,
|
|
|
|
- .irq = IRQ_CORETMR,
|
|
|
|
-#endif
|
|
|
|
- .shift = 32,
|
|
|
|
- .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
|
|
|
|
- .set_next_event = bfin_timer_set_next_event,
|
|
|
|
- .set_mode = bfin_timer_set_mode,
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-static struct irqaction bfin_timer_irq = {
|
|
|
|
-#if defined(CONFIG_TICKSOURCE_GPTMR0)
|
|
|
|
- .name = "Blackfin GPTimer0",
|
|
|
|
-#else
|
|
|
|
- .name = "Blackfin CoreTimer",
|
|
|
|
-#endif
|
|
|
|
- .flags = IRQF_DISABLED | IRQF_TIMER | \
|
|
|
|
- IRQF_IRQPOLL | IRQF_PERCPU,
|
|
|
|
- .handler = timer_interrupt,
|
|
|
|
- .dev_id = &clockevent_bfin,
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
#if defined(CONFIG_TICKSOURCE_GPTMR0)
|
|
#if defined(CONFIG_TICKSOURCE_GPTMR0)
|
|
-static int bfin_timer_set_next_event(unsigned long cycles,
|
|
|
|
|
|
+static int bfin_gptmr0_set_next_event(unsigned long cycles,
|
|
struct clock_event_device *evt)
|
|
struct clock_event_device *evt)
|
|
{
|
|
{
|
|
disable_gptimers(TIMER0bit);
|
|
disable_gptimers(TIMER0bit);
|
|
@@ -196,7 +156,7 @@ static int bfin_timer_set_next_event(unsigned long cycles,
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-static void bfin_timer_set_mode(enum clock_event_mode mode,
|
|
|
|
|
|
+static void bfin_gptmr0_set_mode(enum clock_event_mode mode,
|
|
struct clock_event_device *evt)
|
|
struct clock_event_device *evt)
|
|
{
|
|
{
|
|
switch (mode) {
|
|
switch (mode) {
|
|
@@ -224,25 +184,65 @@ static void bfin_timer_set_mode(enum clock_event_mode mode,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-static void bfin_timer_ack(void)
|
|
|
|
|
|
+static void bfin_gptmr0_ack(void)
|
|
{
|
|
{
|
|
set_gptimer_status(TIMER_GROUP1, TIMER_STATUS_TIMIL0);
|
|
set_gptimer_status(TIMER_GROUP1, TIMER_STATUS_TIMIL0);
|
|
}
|
|
}
|
|
|
|
|
|
-static void __init bfin_timer_init(void)
|
|
|
|
|
|
+static void __init bfin_gptmr0_init(void)
|
|
{
|
|
{
|
|
disable_gptimers(TIMER0bit);
|
|
disable_gptimers(TIMER0bit);
|
|
}
|
|
}
|
|
|
|
|
|
-static unsigned long __init bfin_clockevent_check(void)
|
|
|
|
|
|
+#ifdef CONFIG_CORE_TIMER_IRQ_L1
|
|
|
|
+__attribute__((l1_text))
|
|
|
|
+#endif
|
|
|
|
+irqreturn_t bfin_gptmr0_interrupt(int irq, void *dev_id)
|
|
{
|
|
{
|
|
- setup_irq(IRQ_TIMER0, &bfin_timer_irq);
|
|
|
|
- return get_sclk();
|
|
|
|
|
|
+ struct clock_event_device *evt = dev_id;
|
|
|
|
+ smp_mb();
|
|
|
|
+ evt->event_handler(evt);
|
|
|
|
+ bfin_gptmr0_ack();
|
|
|
|
+ return IRQ_HANDLED;
|
|
}
|
|
}
|
|
|
|
|
|
-#else /* CONFIG_TICKSOURCE_CORETMR */
|
|
|
|
|
|
+static struct irqaction gptmr0_irq = {
|
|
|
|
+ .name = "Blackfin GPTimer0",
|
|
|
|
+ .flags = IRQF_DISABLED | IRQF_TIMER | \
|
|
|
|
+ IRQF_IRQPOLL | IRQF_PERCPU,
|
|
|
|
+ .handler = bfin_gptmr0_interrupt,
|
|
|
|
+};
|
|
|
|
|
|
-static int bfin_timer_set_next_event(unsigned long cycles,
|
|
|
|
|
|
+static struct clock_event_device clockevent_gptmr0 = {
|
|
|
|
+ .name = "bfin_gptimer0",
|
|
|
|
+ .rating = 300,
|
|
|
|
+ .irq = IRQ_TIMER0,
|
|
|
|
+ .shift = 32,
|
|
|
|
+ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
|
|
|
|
+ .set_next_event = bfin_gptmr0_set_next_event,
|
|
|
|
+ .set_mode = bfin_gptmr0_set_mode,
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static void __init bfin_gptmr0_clockevent_init(struct clock_event_device *evt)
|
|
|
|
+{
|
|
|
|
+ unsigned long clock_tick;
|
|
|
|
+
|
|
|
|
+ clock_tick = get_sclk();
|
|
|
|
+ evt->mult = div_sc(clock_tick, NSEC_PER_SEC, evt->shift);
|
|
|
|
+ evt->max_delta_ns = clockevent_delta2ns(-1, evt);
|
|
|
|
+ evt->min_delta_ns = clockevent_delta2ns(100, evt);
|
|
|
|
+
|
|
|
|
+ evt->cpumask = cpumask_of(0);
|
|
|
|
+
|
|
|
|
+ clockevents_register_device(evt);
|
|
|
|
+}
|
|
|
|
+#endif /* CONFIG_TICKSOURCE_GPTMR0 */
|
|
|
|
+
|
|
|
|
+#if defined(CONFIG_TICKSOURCE_CORETMR)
|
|
|
|
+/* per-cpu local core timer */
|
|
|
|
+static DEFINE_PER_CPU(struct clock_event_device, coretmr_events);
|
|
|
|
+
|
|
|
|
+static int bfin_coretmr_set_next_event(unsigned long cycles,
|
|
struct clock_event_device *evt)
|
|
struct clock_event_device *evt)
|
|
{
|
|
{
|
|
bfin_write_TCNTL(TMPWR);
|
|
bfin_write_TCNTL(TMPWR);
|
|
@@ -253,7 +253,7 @@ static int bfin_timer_set_next_event(unsigned long cycles,
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-static void bfin_timer_set_mode(enum clock_event_mode mode,
|
|
|
|
|
|
+static void bfin_coretmr_set_mode(enum clock_event_mode mode,
|
|
struct clock_event_device *evt)
|
|
struct clock_event_device *evt)
|
|
{
|
|
{
|
|
switch (mode) {
|
|
switch (mode) {
|
|
@@ -285,19 +285,13 @@ static void bfin_timer_set_mode(enum clock_event_mode mode,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-static void bfin_timer_ack(void)
|
|
|
|
-{
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void __init bfin_timer_init(void)
|
|
|
|
|
|
+void bfin_coretmr_init(void)
|
|
{
|
|
{
|
|
/* power up the timer, but don't enable it just yet */
|
|
/* power up the timer, but don't enable it just yet */
|
|
bfin_write_TCNTL(TMPWR);
|
|
bfin_write_TCNTL(TMPWR);
|
|
CSYNC();
|
|
CSYNC();
|
|
|
|
|
|
- /*
|
|
|
|
- * the TSCALE prescaler counter.
|
|
|
|
- */
|
|
|
|
|
|
+ /* the TSCALE prescaler counter. */
|
|
bfin_write_TSCALE(TIME_SCALE - 1);
|
|
bfin_write_TSCALE(TIME_SCALE - 1);
|
|
bfin_write_TPERIOD(0);
|
|
bfin_write_TPERIOD(0);
|
|
bfin_write_TCOUNT(0);
|
|
bfin_write_TCOUNT(0);
|
|
@@ -305,48 +299,51 @@ static void __init bfin_timer_init(void)
|
|
CSYNC();
|
|
CSYNC();
|
|
}
|
|
}
|
|
|
|
|
|
-static unsigned long __init bfin_clockevent_check(void)
|
|
|
|
-{
|
|
|
|
- setup_irq(IRQ_CORETMR, &bfin_timer_irq);
|
|
|
|
- return get_cclk() / TIME_SCALE;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-void __init setup_core_timer(void)
|
|
|
|
|
|
+#ifdef CONFIG_CORE_TIMER_IRQ_L1
|
|
|
|
+__attribute__((l1_text))
|
|
|
|
+#endif
|
|
|
|
+irqreturn_t bfin_coretmr_interrupt(int irq, void *dev_id)
|
|
{
|
|
{
|
|
- bfin_timer_init();
|
|
|
|
- bfin_timer_set_mode(CLOCK_EVT_MODE_PERIODIC, NULL);
|
|
|
|
-}
|
|
|
|
-#endif /* CONFIG_TICKSOURCE_GPTMR0 */
|
|
|
|
|
|
+ int cpu = smp_processor_id();
|
|
|
|
+ struct clock_event_device *evt = &per_cpu(coretmr_events, cpu);
|
|
|
|
|
|
-/*
|
|
|
|
- * timer_interrupt() needs to keep up the real-time clock,
|
|
|
|
- * as well as call the "do_timer()" routine every clocktick
|
|
|
|
- */
|
|
|
|
-irqreturn_t timer_interrupt(int irq, void *dev_id)
|
|
|
|
-{
|
|
|
|
- struct clock_event_device *evt = dev_id;
|
|
|
|
smp_mb();
|
|
smp_mb();
|
|
evt->event_handler(evt);
|
|
evt->event_handler(evt);
|
|
- bfin_timer_ack();
|
|
|
|
return IRQ_HANDLED;
|
|
return IRQ_HANDLED;
|
|
}
|
|
}
|
|
|
|
|
|
-static int __init bfin_clockevent_init(void)
|
|
|
|
-{
|
|
|
|
- unsigned long timer_clk;
|
|
|
|
-
|
|
|
|
- timer_clk = bfin_clockevent_check();
|
|
|
|
-
|
|
|
|
- bfin_timer_init();
|
|
|
|
-
|
|
|
|
- clockevent_bfin.mult = div_sc(timer_clk, NSEC_PER_SEC, clockevent_bfin.shift);
|
|
|
|
- clockevent_bfin.max_delta_ns = clockevent_delta2ns(-1, &clockevent_bfin);
|
|
|
|
- clockevent_bfin.min_delta_ns = clockevent_delta2ns(100, &clockevent_bfin);
|
|
|
|
- clockevent_bfin.cpumask = cpumask_of(0);
|
|
|
|
- clockevents_register_device(&clockevent_bfin);
|
|
|
|
|
|
+static struct irqaction coretmr_irq = {
|
|
|
|
+ .name = "Blackfin CoreTimer",
|
|
|
|
+ .flags = IRQF_DISABLED | IRQF_TIMER | \
|
|
|
|
+ IRQF_IRQPOLL | IRQF_PERCPU,
|
|
|
|
+ .handler = bfin_coretmr_interrupt,
|
|
|
|
+};
|
|
|
|
|
|
- return 0;
|
|
|
|
|
|
+void bfin_coretmr_clockevent_init(void)
|
|
|
|
+{
|
|
|
|
+ unsigned long clock_tick;
|
|
|
|
+ unsigned int cpu = smp_processor_id();
|
|
|
|
+ struct clock_event_device *evt = &per_cpu(coretmr_events, cpu);
|
|
|
|
+
|
|
|
|
+ evt->name = "bfin_core_timer";
|
|
|
|
+ evt->rating = 350;
|
|
|
|
+ evt->irq = -1;
|
|
|
|
+ evt->shift = 32;
|
|
|
|
+ evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
|
|
|
|
+ evt->set_next_event = bfin_coretmr_set_next_event;
|
|
|
|
+ evt->set_mode = bfin_coretmr_set_mode;
|
|
|
|
+
|
|
|
|
+ clock_tick = get_cclk() / TIME_SCALE;
|
|
|
|
+ evt->mult = div_sc(clock_tick, NSEC_PER_SEC, evt->shift);
|
|
|
|
+ evt->max_delta_ns = clockevent_delta2ns(-1, evt);
|
|
|
|
+ evt->min_delta_ns = clockevent_delta2ns(100, evt);
|
|
|
|
+
|
|
|
|
+ evt->cpumask = cpumask_of(cpu);
|
|
|
|
+
|
|
|
|
+ clockevents_register_device(evt);
|
|
}
|
|
}
|
|
|
|
+#endif /* CONFIG_TICKSOURCE_CORETMR */
|
|
|
|
+
|
|
|
|
|
|
void __init time_init(void)
|
|
void __init time_init(void)
|
|
{
|
|
{
|
|
@@ -370,5 +367,21 @@ void __init time_init(void)
|
|
|
|
|
|
bfin_cs_cycles_init();
|
|
bfin_cs_cycles_init();
|
|
bfin_cs_gptimer0_init();
|
|
bfin_cs_gptimer0_init();
|
|
- bfin_clockevent_init();
|
|
|
|
|
|
+
|
|
|
|
+#if defined(CONFIG_TICKSOURCE_CORETMR)
|
|
|
|
+ bfin_coretmr_init();
|
|
|
|
+ setup_irq(IRQ_CORETMR, &coretmr_irq);
|
|
|
|
+ bfin_coretmr_clockevent_init();
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+#if defined(CONFIG_TICKSOURCE_GPTMR0)
|
|
|
|
+ bfin_gptmr0_init();
|
|
|
|
+ setup_irq(IRQ_TIMER0, &gptmr0_irq);
|
|
|
|
+ gptmr0_irq.dev_id = &clockevent_gptmr0;
|
|
|
|
+ bfin_gptmr0_clockevent_init(&clockevent_gptmr0);
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+#if !defined(CONFIG_TICKSOURCE_CORETMR) && !defined(CONFIG_TICKSOURCE_GPTMR0)
|
|
|
|
+# error at least one clock event device is required
|
|
|
|
+#endif
|
|
}
|
|
}
|