aboutsummaryrefslogtreecommitdiffstats
path: root/arch/blackfin/kernel/time.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/blackfin/kernel/time.c')
-rw-r--r--arch/blackfin/kernel/time.c114
1 files changed, 79 insertions, 35 deletions
diff --git a/arch/blackfin/kernel/time.c b/arch/blackfin/kernel/time.c
index eb2352320454..06de2ce67a9e 100644
--- a/arch/blackfin/kernel/time.c
+++ b/arch/blackfin/kernel/time.c
@@ -34,9 +34,11 @@
34#include <linux/interrupt.h> 34#include <linux/interrupt.h>
35#include <linux/time.h> 35#include <linux/time.h>
36#include <linux/irq.h> 36#include <linux/irq.h>
37#include <linux/delay.h>
37 38
38#include <asm/blackfin.h> 39#include <asm/blackfin.h>
39#include <asm/time.h> 40#include <asm/time.h>
41#include <asm/gptimers.h>
40 42
41/* This is an NTP setting */ 43/* This is an NTP setting */
42#define TICK_SIZE (tick_nsec / 1000) 44#define TICK_SIZE (tick_nsec / 1000)
@@ -46,11 +48,14 @@ static unsigned long gettimeoffset(void);
46 48
47static struct irqaction bfin_timer_irq = { 49static struct irqaction bfin_timer_irq = {
48 .name = "BFIN Timer Tick", 50 .name = "BFIN Timer Tick",
51#ifdef CONFIG_IRQ_PER_CPU
52 .flags = IRQF_DISABLED | IRQF_PERCPU,
53#else
49 .flags = IRQF_DISABLED 54 .flags = IRQF_DISABLED
55#endif
50}; 56};
51 57
52static void 58void setup_core_timer(void)
53time_sched_init(irq_handler_t timer_routine)
54{ 59{
55 u32 tcount; 60 u32 tcount;
56 61
@@ -71,12 +76,41 @@ time_sched_init(irq_handler_t timer_routine)
71 CSYNC(); 76 CSYNC();
72 77
73 bfin_write_TCNTL(7); 78 bfin_write_TCNTL(7);
79}
80
81#ifdef CONFIG_TICK_SOURCE_SYSTMR0
82void setup_system_timer0(void)
83{
84 /* Power down the core timer, just to play safe. */
85 bfin_write_TCNTL(0);
86
87 disable_gptimers(TIMER0bit);
88 set_gptimer_status(0, TIMER_STATUS_TRUN0);
89 while (get_gptimer_status(0) & TIMER_STATUS_TRUN0)
90 udelay(10);
91
92 set_gptimer_config(0, 0x59); /* IRQ enable, periodic, PWM_OUT, SCLKed, OUT PAD disabled */
93 set_gptimer_period(TIMER0_id, get_sclk() / HZ);
94 set_gptimer_pwidth(TIMER0_id, 1);
95 SSYNC();
96 enable_gptimers(TIMER0bit);
97}
98#endif
74 99
100static void
101time_sched_init(irqreturn_t(*timer_routine) (int, void *))
102{
103#ifdef CONFIG_TICK_SOURCE_SYSTMR0
104 setup_system_timer0();
105#else
106 setup_core_timer();
107#endif
75 bfin_timer_irq.handler = (irq_handler_t)timer_routine; 108 bfin_timer_irq.handler = (irq_handler_t)timer_routine;
76 /* call setup_irq instead of request_irq because request_irq calls 109#ifdef CONFIG_TICK_SOURCE_SYSTMR0
77 * kmalloc which has not been initialized yet 110 setup_irq(IRQ_TIMER0, &bfin_timer_irq);
78 */ 111#else
79 setup_irq(IRQ_CORETMR, &bfin_timer_irq); 112 setup_irq(IRQ_CORETMR, &bfin_timer_irq);
113#endif
80} 114}
81 115
82/* 116/*
@@ -87,17 +121,23 @@ static unsigned long gettimeoffset(void)
87 unsigned long offset; 121 unsigned long offset;
88 unsigned long clocks_per_jiffy; 122 unsigned long clocks_per_jiffy;
89 123
124#ifdef CONFIG_TICK_SOURCE_SYSTMR0
125 clocks_per_jiffy = bfin_read_TIMER0_PERIOD();
126 offset = bfin_read_TIMER0_COUNTER() / \
127 (((clocks_per_jiffy + 1) * HZ) / USEC_PER_SEC);
128
129 if ((get_gptimer_status(0) & TIMER_STATUS_TIMIL0) && offset < (100000 / HZ / 2))
130 offset += (USEC_PER_SEC / HZ);
131#else
90 clocks_per_jiffy = bfin_read_TPERIOD(); 132 clocks_per_jiffy = bfin_read_TPERIOD();
91 offset = 133 offset = (clocks_per_jiffy - bfin_read_TCOUNT()) / \
92 (clocks_per_jiffy - 134 (((clocks_per_jiffy + 1) * HZ) / USEC_PER_SEC);
93 bfin_read_TCOUNT()) / (((clocks_per_jiffy + 1) * HZ) /
94 USEC_PER_SEC);
95 135
96 /* Check if we just wrapped the counters and maybe missed a tick */ 136 /* Check if we just wrapped the counters and maybe missed a tick */
97 if ((bfin_read_ILAT() & (1 << IRQ_CORETMR)) 137 if ((bfin_read_ILAT() & (1 << IRQ_CORETMR))
98 && (offset < (100000 / HZ / 2))) 138 && (offset < (100000 / HZ / 2)))
99 offset += (USEC_PER_SEC / HZ); 139 offset += (USEC_PER_SEC / HZ);
100 140#endif
101 return offset; 141 return offset;
102} 142}
103 143
@@ -120,34 +160,38 @@ irqreturn_t timer_interrupt(int irq, void *dummy)
120 static long last_rtc_update; 160 static long last_rtc_update;
121 161
122 write_seqlock(&xtime_lock); 162 write_seqlock(&xtime_lock);
123 163#ifdef CONFIG_TICK_SOURCE_SYSTMR0
124 do_timer(1); 164 if (get_gptimer_status(0) & TIMER_STATUS_TIMIL0) {
125 165#endif
126 profile_tick(CPU_PROFILING); 166 do_timer(1);
127 167
128 /* 168
129 * If we have an externally synchronized Linux clock, then update 169 /*
130 * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be 170 * If we have an externally synchronized Linux clock, then update
131 * called as close as possible to 500 ms before the new second starts. 171 * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
132 */ 172 * called as close as possible to 500 ms before the new second starts.
133 173 */
134 if (ntp_synced() && 174
135 xtime.tv_sec > last_rtc_update + 660 && 175 if (ntp_synced() &&
136 (xtime.tv_nsec / NSEC_PER_USEC) >= 176 xtime.tv_sec > last_rtc_update + 660 &&
137 500000 - ((unsigned)TICK_SIZE) / 2 177 (xtime.tv_nsec / NSEC_PER_USEC) >=
138 && (xtime.tv_nsec / NSEC_PER_USEC) <= 178 500000 - ((unsigned)TICK_SIZE) / 2
139 500000 + ((unsigned)TICK_SIZE) / 2) { 179 && (xtime.tv_nsec / NSEC_PER_USEC) <=
140 if (set_rtc_mmss(xtime.tv_sec) == 0) 180 500000 + ((unsigned)TICK_SIZE) / 2) {
141 last_rtc_update = xtime.tv_sec; 181 if (set_rtc_mmss(xtime.tv_sec) == 0)
142 else 182 last_rtc_update = xtime.tv_sec;
143 /* Do it again in 60s. */ 183 else
144 last_rtc_update = xtime.tv_sec - 600; 184 /* Do it again in 60s. */
185 last_rtc_update = xtime.tv_sec - 600;
186 }
187#ifdef CONFIG_TICK_SOURCE_SYSTMR0
188 set_gptimer_status(0, TIMER_STATUS_TIMIL0);
145 } 189 }
190#endif
146 write_sequnlock(&xtime_lock); 191 write_sequnlock(&xtime_lock);
147 192
148#ifndef CONFIG_SMP
149 update_process_times(user_mode(get_irq_regs())); 193 update_process_times(user_mode(get_irq_regs()));
150#endif 194 profile_tick(CPU_PROFILING);
151 195
152 return IRQ_HANDLED; 196 return IRQ_HANDLED;
153} 197}