diff options
author | Atsushi Nemoto <anemo@mba.ocn.ne.jp> | 2006-10-23 11:21:27 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2006-10-31 15:13:23 -0500 |
commit | 16b7b2ac0148e839da86af8747b6fa4aad43a9b7 (patch) | |
tree | 93912ae2e9c64f71a8cca028677fd918b9edf0fa /arch | |
parent | 70e46f48cb5933119712ee27945309a4bfc98282 (diff) |
[MIPS] Fixup migration to GENERIC_TIME
Since we already moved to GENERIC_TIME, we should implement alternatives
of old do_gettimeoffset routines to get sub-jiffies resolution from
gettimeofday(). This patch includes:
* MIPS clocksource support (based on works by Manish Lachwani).
* remove unused gettimeoffset routines and related codes.
* remove unised 64bit do_div64_32().
* simplify mips_hpt_init. (no argument needed, __init tag)
* simplify c0_hpt_timer_init. (no need to write to c0_count)
* remove some hpt_init routines.
* mips_hpt_mask variable to specify bitmask of hpt value.
* convert jmr3927_do_gettimeoffset to jmr3927_hpt_read.
* convert ip27_do_gettimeoffset to ip27_hpt_read.
* convert bcm1480_do_gettimeoffset to bcm1480_hpt_read.
* simplify sb1250 hpt functions. (no need to subtract and shift)
Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/mips/au1000/common/time.c | 98 | ||||
-rw-r--r-- | arch/mips/dec/time.c | 9 | ||||
-rw-r--r-- | arch/mips/jmr3927/rbhma3100/setup.c | 40 | ||||
-rw-r--r-- | arch/mips/kernel/time.c | 319 | ||||
-rw-r--r-- | arch/mips/philips/pnx8550/common/time.c | 4 | ||||
-rw-r--r-- | arch/mips/pmc-sierra/yosemite/smp.c | 6 | ||||
-rw-r--r-- | arch/mips/sgi-ip27/ip27-timer.c | 16 | ||||
-rw-r--r-- | arch/mips/sibyte/bcm1480/time.c | 33 | ||||
-rw-r--r-- | arch/mips/sibyte/sb1250/time.c | 28 |
9 files changed, 92 insertions, 461 deletions
diff --git a/arch/mips/au1000/common/time.c b/arch/mips/au1000/common/time.c index 6768638883ea..fa1c62f05515 100644 --- a/arch/mips/au1000/common/time.c +++ b/arch/mips/au1000/common/time.c | |||
@@ -53,9 +53,6 @@ static unsigned long r4k_cur; /* What counter should be at next timer irq */ | |||
53 | int no_au1xxx_32khz; | 53 | int no_au1xxx_32khz; |
54 | extern int allow_au1k_wait; /* default off for CP0 Counter */ | 54 | extern int allow_au1k_wait; /* default off for CP0 Counter */ |
55 | 55 | ||
56 | /* Cycle counter value at the previous timer interrupt.. */ | ||
57 | static unsigned int timerhi = 0, timerlo = 0; | ||
58 | |||
59 | #ifdef CONFIG_PM | 56 | #ifdef CONFIG_PM |
60 | #if HZ < 100 || HZ > 1000 | 57 | #if HZ < 100 || HZ > 1000 |
61 | #error "unsupported HZ value! Must be in [100,1000]" | 58 | #error "unsupported HZ value! Must be in [100,1000]" |
@@ -90,10 +87,6 @@ void mips_timer_interrupt(void) | |||
90 | goto null; | 87 | goto null; |
91 | 88 | ||
92 | do { | 89 | do { |
93 | count = read_c0_count(); | ||
94 | timerhi += (count < timerlo); /* Wrap around */ | ||
95 | timerlo = count; | ||
96 | |||
97 | kstat_this_cpu.irqs[irq]++; | 90 | kstat_this_cpu.irqs[irq]++; |
98 | do_timer(1); | 91 | do_timer(1); |
99 | #ifndef CONFIG_SMP | 92 | #ifndef CONFIG_SMP |
@@ -297,88 +290,6 @@ unsigned long cal_r4koff(void) | |||
297 | return (cpu_speed / HZ); | 290 | return (cpu_speed / HZ); |
298 | } | 291 | } |
299 | 292 | ||
300 | /* This is for machines which generate the exact clock. */ | ||
301 | #define USECS_PER_JIFFY (1000000/HZ) | ||
302 | #define USECS_PER_JIFFY_FRAC (0x100000000LL*1000000/HZ&0xffffffff) | ||
303 | |||
304 | static unsigned long | ||
305 | div64_32(unsigned long v1, unsigned long v2, unsigned long v3) | ||
306 | { | ||
307 | unsigned long r0; | ||
308 | do_div64_32(r0, v1, v2, v3); | ||
309 | return r0; | ||
310 | } | ||
311 | |||
312 | static unsigned long do_fast_cp0_gettimeoffset(void) | ||
313 | { | ||
314 | u32 count; | ||
315 | unsigned long res, tmp; | ||
316 | unsigned long r0; | ||
317 | |||
318 | /* Last jiffy when do_fast_gettimeoffset() was called. */ | ||
319 | static unsigned long last_jiffies=0; | ||
320 | unsigned long quotient; | ||
321 | |||
322 | /* | ||
323 | * Cached "1/(clocks per usec)*2^32" value. | ||
324 | * It has to be recalculated once each jiffy. | ||
325 | */ | ||
326 | static unsigned long cached_quotient=0; | ||
327 | |||
328 | tmp = jiffies; | ||
329 | |||
330 | quotient = cached_quotient; | ||
331 | |||
332 | if (tmp && last_jiffies != tmp) { | ||
333 | last_jiffies = tmp; | ||
334 | if (last_jiffies != 0) { | ||
335 | r0 = div64_32(timerhi, timerlo, tmp); | ||
336 | quotient = div64_32(USECS_PER_JIFFY, USECS_PER_JIFFY_FRAC, r0); | ||
337 | cached_quotient = quotient; | ||
338 | } | ||
339 | } | ||
340 | |||
341 | /* Get last timer tick in absolute kernel time */ | ||
342 | count = read_c0_count(); | ||
343 | |||
344 | /* .. relative to previous jiffy (32 bits is enough) */ | ||
345 | count -= timerlo; | ||
346 | |||
347 | __asm__("multu\t%1,%2\n\t" | ||
348 | "mfhi\t%0" | ||
349 | : "=r" (res) | ||
350 | : "r" (count), "r" (quotient) | ||
351 | : "hi", "lo", GCC_REG_ACCUM); | ||
352 | |||
353 | /* | ||
354 | * Due to possible jiffies inconsistencies, we need to check | ||
355 | * the result so that we'll get a timer that is monotonic. | ||
356 | */ | ||
357 | if (res >= USECS_PER_JIFFY) | ||
358 | res = USECS_PER_JIFFY-1; | ||
359 | |||
360 | return res; | ||
361 | } | ||
362 | |||
363 | #ifdef CONFIG_PM | ||
364 | static unsigned long do_fast_pm_gettimeoffset(void) | ||
365 | { | ||
366 | unsigned long pc0; | ||
367 | unsigned long offset; | ||
368 | |||
369 | pc0 = au_readl(SYS_TOYREAD); | ||
370 | au_sync(); | ||
371 | offset = pc0 - last_pc0; | ||
372 | if (offset > 2*MATCH20_INC) { | ||
373 | printk("huge offset %x, last_pc0 %x last_match20 %x pc0 %x\n", | ||
374 | (unsigned)offset, (unsigned)last_pc0, | ||
375 | (unsigned)last_match20, (unsigned)pc0); | ||
376 | } | ||
377 | offset = (unsigned long)((offset * 305) / 10); | ||
378 | return offset; | ||
379 | } | ||
380 | #endif | ||
381 | |||
382 | void __init plat_timer_setup(struct irqaction *irq) | 293 | void __init plat_timer_setup(struct irqaction *irq) |
383 | { | 294 | { |
384 | unsigned int est_freq; | 295 | unsigned int est_freq; |
@@ -416,7 +327,6 @@ void __init plat_timer_setup(struct irqaction *irq) | |||
416 | unsigned int c0_status; | 327 | unsigned int c0_status; |
417 | 328 | ||
418 | printk("WARNING: no 32KHz clock found.\n"); | 329 | printk("WARNING: no 32KHz clock found.\n"); |
419 | do_gettimeoffset = do_fast_cp0_gettimeoffset; | ||
420 | 330 | ||
421 | /* Ensure we get CPO_COUNTER interrupts. | 331 | /* Ensure we get CPO_COUNTER interrupts. |
422 | */ | 332 | */ |
@@ -441,19 +351,11 @@ void __init plat_timer_setup(struct irqaction *irq) | |||
441 | while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20); | 351 | while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20); |
442 | startup_match20_interrupt(counter0_irq); | 352 | startup_match20_interrupt(counter0_irq); |
443 | 353 | ||
444 | do_gettimeoffset = do_fast_pm_gettimeoffset; | ||
445 | |||
446 | /* We can use the real 'wait' instruction. | 354 | /* We can use the real 'wait' instruction. |
447 | */ | 355 | */ |
448 | allow_au1k_wait = 1; | 356 | allow_au1k_wait = 1; |
449 | } | 357 | } |
450 | 358 | ||
451 | #else | ||
452 | /* We have to do this here instead of in timer_init because | ||
453 | * the generic code in arch/mips/kernel/time.c will write | ||
454 | * over our function pointer. | ||
455 | */ | ||
456 | do_gettimeoffset = do_fast_cp0_gettimeoffset; | ||
457 | #endif | 359 | #endif |
458 | } | 360 | } |
459 | 361 | ||
diff --git a/arch/mips/dec/time.c b/arch/mips/dec/time.c index 4cf0c06e2414..69e424e9ab6f 100644 --- a/arch/mips/dec/time.c +++ b/arch/mips/dec/time.c | |||
@@ -160,11 +160,6 @@ static unsigned int dec_ioasic_hpt_read(void) | |||
160 | return ioasic_read(IO_REG_FCTR); | 160 | return ioasic_read(IO_REG_FCTR); |
161 | } | 161 | } |
162 | 162 | ||
163 | static void dec_ioasic_hpt_init(unsigned int count) | ||
164 | { | ||
165 | ioasic_write(IO_REG_FCTR, ioasic_read(IO_REG_FCTR) - count); | ||
166 | } | ||
167 | |||
168 | 163 | ||
169 | void __init dec_time_init(void) | 164 | void __init dec_time_init(void) |
170 | { | 165 | { |
@@ -174,11 +169,9 @@ void __init dec_time_init(void) | |||
174 | mips_timer_state = dec_timer_state; | 169 | mips_timer_state = dec_timer_state; |
175 | mips_timer_ack = dec_timer_ack; | 170 | mips_timer_ack = dec_timer_ack; |
176 | 171 | ||
177 | if (!cpu_has_counter && IOASIC) { | 172 | if (!cpu_has_counter && IOASIC) |
178 | /* For pre-R4k systems we use the I/O ASIC's counter. */ | 173 | /* For pre-R4k systems we use the I/O ASIC's counter. */ |
179 | mips_hpt_read = dec_ioasic_hpt_read; | 174 | mips_hpt_read = dec_ioasic_hpt_read; |
180 | mips_hpt_init = dec_ioasic_hpt_init; | ||
181 | } | ||
182 | 175 | ||
183 | /* Set up the rate of periodic DS1287 interrupts. */ | 176 | /* Set up the rate of periodic DS1287 interrupts. */ |
184 | CMOS_WRITE(RTC_REF_CLCK_32KHZ | (16 - __ffs(HZ)), RTC_REG_A); | 177 | CMOS_WRITE(RTC_REF_CLCK_32KHZ | (16 - __ffs(HZ)), RTC_REG_A); |
diff --git a/arch/mips/jmr3927/rbhma3100/setup.c b/arch/mips/jmr3927/rbhma3100/setup.c index 025434054ed0..16e5dfe7aa8a 100644 --- a/arch/mips/jmr3927/rbhma3100/setup.c +++ b/arch/mips/jmr3927/rbhma3100/setup.c | |||
@@ -170,12 +170,20 @@ static void jmr3927_machine_power_off(void) | |||
170 | while (1); | 170 | while (1); |
171 | } | 171 | } |
172 | 172 | ||
173 | static unsigned int jmr3927_hpt_read(void) | ||
174 | { | ||
175 | /* We assume this function is called xtime_lock held. */ | ||
176 | return jiffies * (JMR3927_TIMER_CLK / HZ) + jmr3927_tmrptr->trr; | ||
177 | } | ||
178 | |||
173 | #define USE_RTC_DS1742 | 179 | #define USE_RTC_DS1742 |
174 | #ifdef USE_RTC_DS1742 | 180 | #ifdef USE_RTC_DS1742 |
175 | extern void rtc_ds1742_init(unsigned long base); | 181 | extern void rtc_ds1742_init(unsigned long base); |
176 | #endif | 182 | #endif |
177 | static void __init jmr3927_time_init(void) | 183 | static void __init jmr3927_time_init(void) |
178 | { | 184 | { |
185 | mips_hpt_read = jmr3927_hpt_read; | ||
186 | mips_hpt_frequency = JMR3927_TIMER_CLK; | ||
179 | #ifdef USE_RTC_DS1742 | 187 | #ifdef USE_RTC_DS1742 |
180 | if (jmr3927_have_nvram()) { | 188 | if (jmr3927_have_nvram()) { |
181 | rtc_ds1742_init(JMR3927_IOC_NVRAMB_ADDR); | 189 | rtc_ds1742_init(JMR3927_IOC_NVRAMB_ADDR); |
@@ -183,12 +191,8 @@ static void __init jmr3927_time_init(void) | |||
183 | #endif | 191 | #endif |
184 | } | 192 | } |
185 | 193 | ||
186 | unsigned long jmr3927_do_gettimeoffset(void); | ||
187 | |||
188 | void __init plat_timer_setup(struct irqaction *irq) | 194 | void __init plat_timer_setup(struct irqaction *irq) |
189 | { | 195 | { |
190 | do_gettimeoffset = jmr3927_do_gettimeoffset; | ||
191 | |||
192 | jmr3927_tmrptr->cpra = JMR3927_TIMER_CLK / HZ; | 196 | jmr3927_tmrptr->cpra = JMR3927_TIMER_CLK / HZ; |
193 | jmr3927_tmrptr->itmr = TXx927_TMTITMR_TIIE | TXx927_TMTITMR_TZCE; | 197 | jmr3927_tmrptr->itmr = TXx927_TMTITMR_TIIE | TXx927_TMTITMR_TZCE; |
194 | jmr3927_tmrptr->ccdr = JMR3927_TIMER_CCD; | 198 | jmr3927_tmrptr->ccdr = JMR3927_TIMER_CCD; |
@@ -200,34 +204,6 @@ void __init plat_timer_setup(struct irqaction *irq) | |||
200 | 204 | ||
201 | #define USECS_PER_JIFFY (1000000/HZ) | 205 | #define USECS_PER_JIFFY (1000000/HZ) |
202 | 206 | ||
203 | unsigned long jmr3927_do_gettimeoffset(void) | ||
204 | { | ||
205 | unsigned long count; | ||
206 | unsigned long res = 0; | ||
207 | |||
208 | /* MUST read TRR before TISR. */ | ||
209 | count = jmr3927_tmrptr->trr; | ||
210 | |||
211 | if (jmr3927_tmrptr->tisr & TXx927_TMTISR_TIIS) { | ||
212 | /* timer interrupt is pending. use Max value. */ | ||
213 | res = USECS_PER_JIFFY - 1; | ||
214 | } else { | ||
215 | /* convert to usec */ | ||
216 | /* res = count / (JMR3927_TIMER_CLK / 1000000); */ | ||
217 | res = (count << 7) / ((JMR3927_TIMER_CLK << 7) / 1000000); | ||
218 | |||
219 | /* | ||
220 | * Due to possible jiffies inconsistencies, we need to check | ||
221 | * the result so that we'll get a timer that is monotonic. | ||
222 | */ | ||
223 | if (res >= USECS_PER_JIFFY) | ||
224 | res = USECS_PER_JIFFY-1; | ||
225 | } | ||
226 | |||
227 | return res; | ||
228 | } | ||
229 | |||
230 | |||
231 | //#undef DO_WRITE_THROUGH | 207 | //#undef DO_WRITE_THROUGH |
232 | #define DO_WRITE_THROUGH | 208 | #define DO_WRITE_THROUGH |
233 | #define DO_ENABLE_CACHE | 209 | #define DO_ENABLE_CACHE |
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index debe86c2f691..e535f86efa2f 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c | |||
@@ -11,6 +11,7 @@ | |||
11 | * Free Software Foundation; either version 2 of the License, or (at your | 11 | * Free Software Foundation; either version 2 of the License, or (at your |
12 | * option) any later version. | 12 | * option) any later version. |
13 | */ | 13 | */ |
14 | #include <linux/clocksource.h> | ||
14 | #include <linux/types.h> | 15 | #include <linux/types.h> |
15 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
16 | #include <linux/init.h> | 17 | #include <linux/init.h> |
@@ -67,15 +68,9 @@ int (*rtc_mips_set_time)(unsigned long) = null_rtc_set_time; | |||
67 | int (*rtc_mips_set_mmss)(unsigned long); | 68 | int (*rtc_mips_set_mmss)(unsigned long); |
68 | 69 | ||
69 | 70 | ||
70 | /* usecs per counter cycle, shifted to left by 32 bits */ | ||
71 | static unsigned int sll32_usecs_per_cycle; | ||
72 | |||
73 | /* how many counter cycles in a jiffy */ | 71 | /* how many counter cycles in a jiffy */ |
74 | static unsigned long cycles_per_jiffy __read_mostly; | 72 | static unsigned long cycles_per_jiffy __read_mostly; |
75 | 73 | ||
76 | /* Cycle counter value at the previous timer interrupt.. */ | ||
77 | static unsigned int timerhi, timerlo; | ||
78 | |||
79 | /* expirelo is the count value for next CPU timer interrupt */ | 74 | /* expirelo is the count value for next CPU timer interrupt */ |
80 | static unsigned int expirelo; | 75 | static unsigned int expirelo; |
81 | 76 | ||
@@ -93,7 +88,7 @@ static unsigned int null_hpt_read(void) | |||
93 | return 0; | 88 | return 0; |
94 | } | 89 | } |
95 | 90 | ||
96 | static void null_hpt_init(unsigned int count) | 91 | static void __init null_hpt_init(void) |
97 | { | 92 | { |
98 | /* nothing */ | 93 | /* nothing */ |
99 | } | 94 | } |
@@ -128,186 +123,18 @@ static unsigned int c0_hpt_read(void) | |||
128 | return read_c0_count(); | 123 | return read_c0_count(); |
129 | } | 124 | } |
130 | 125 | ||
131 | /* For use solely as a high precision timer. */ | ||
132 | static void c0_hpt_init(unsigned int count) | ||
133 | { | ||
134 | write_c0_count(read_c0_count() - count); | ||
135 | } | ||
136 | |||
137 | /* For use both as a high precision timer and an interrupt source. */ | 126 | /* For use both as a high precision timer and an interrupt source. */ |
138 | static void c0_hpt_timer_init(unsigned int count) | 127 | static void __init c0_hpt_timer_init(void) |
139 | { | 128 | { |
140 | count = read_c0_count() - count; | 129 | expirelo = read_c0_count() + cycles_per_jiffy; |
141 | expirelo = (count / cycles_per_jiffy + 1) * cycles_per_jiffy; | ||
142 | write_c0_count(expirelo - cycles_per_jiffy); | ||
143 | write_c0_compare(expirelo); | 130 | write_c0_compare(expirelo); |
144 | write_c0_count(count); | ||
145 | } | 131 | } |
146 | 132 | ||
147 | int (*mips_timer_state)(void); | 133 | int (*mips_timer_state)(void); |
148 | void (*mips_timer_ack)(void); | 134 | void (*mips_timer_ack)(void); |
149 | unsigned int (*mips_hpt_read)(void); | 135 | unsigned int (*mips_hpt_read)(void); |
150 | void (*mips_hpt_init)(unsigned int); | 136 | void (*mips_hpt_init)(void) __initdata = null_hpt_init; |
151 | 137 | unsigned int mips_hpt_mask = 0xffffffff; | |
152 | /* | ||
153 | * Gettimeoffset routines. These routines returns the time duration | ||
154 | * since last timer interrupt in usecs. | ||
155 | * | ||
156 | * If the exact CPU counter frequency is known, use fixed_rate_gettimeoffset. | ||
157 | * Otherwise use calibrate_gettimeoffset() | ||
158 | * | ||
159 | * If the CPU does not have the counter register, you can either supply | ||
160 | * your own gettimeoffset() routine, or use null_gettimeoffset(), which | ||
161 | * gives the same resolution as HZ. | ||
162 | */ | ||
163 | |||
164 | static unsigned long null_gettimeoffset(void) | ||
165 | { | ||
166 | return 0; | ||
167 | } | ||
168 | |||
169 | |||
170 | /* The function pointer to one of the gettimeoffset funcs. */ | ||
171 | unsigned long (*do_gettimeoffset)(void) = null_gettimeoffset; | ||
172 | |||
173 | |||
174 | static unsigned long fixed_rate_gettimeoffset(void) | ||
175 | { | ||
176 | u32 count; | ||
177 | unsigned long res; | ||
178 | |||
179 | /* Get last timer tick in absolute kernel time */ | ||
180 | count = mips_hpt_read(); | ||
181 | |||
182 | /* .. relative to previous jiffy (32 bits is enough) */ | ||
183 | count -= timerlo; | ||
184 | |||
185 | __asm__("multu %1,%2" | ||
186 | : "=h" (res) | ||
187 | : "r" (count), "r" (sll32_usecs_per_cycle) | ||
188 | : "lo", GCC_REG_ACCUM); | ||
189 | |||
190 | /* | ||
191 | * Due to possible jiffies inconsistencies, we need to check | ||
192 | * the result so that we'll get a timer that is monotonic. | ||
193 | */ | ||
194 | if (res >= USECS_PER_JIFFY) | ||
195 | res = USECS_PER_JIFFY - 1; | ||
196 | |||
197 | return res; | ||
198 | } | ||
199 | |||
200 | |||
201 | /* | ||
202 | * Cached "1/(clocks per usec) * 2^32" value. | ||
203 | * It has to be recalculated once each jiffy. | ||
204 | */ | ||
205 | static unsigned long cached_quotient; | ||
206 | |||
207 | /* Last jiffy when calibrate_divXX_gettimeoffset() was called. */ | ||
208 | static unsigned long last_jiffies; | ||
209 | |||
210 | /* | ||
211 | * This is moved from dec/time.c:do_ioasic_gettimeoffset() by Maciej. | ||
212 | */ | ||
213 | static unsigned long calibrate_div32_gettimeoffset(void) | ||
214 | { | ||
215 | u32 count; | ||
216 | unsigned long res, tmp; | ||
217 | unsigned long quotient; | ||
218 | |||
219 | tmp = jiffies; | ||
220 | |||
221 | quotient = cached_quotient; | ||
222 | |||
223 | if (last_jiffies != tmp) { | ||
224 | last_jiffies = tmp; | ||
225 | if (last_jiffies != 0) { | ||
226 | unsigned long r0; | ||
227 | do_div64_32(r0, timerhi, timerlo, tmp); | ||
228 | do_div64_32(quotient, USECS_PER_JIFFY, | ||
229 | USECS_PER_JIFFY_FRAC, r0); | ||
230 | cached_quotient = quotient; | ||
231 | } | ||
232 | } | ||
233 | |||
234 | /* Get last timer tick in absolute kernel time */ | ||
235 | count = mips_hpt_read(); | ||
236 | |||
237 | /* .. relative to previous jiffy (32 bits is enough) */ | ||
238 | count -= timerlo; | ||
239 | |||
240 | __asm__("multu %1,%2" | ||
241 | : "=h" (res) | ||
242 | : "r" (count), "r" (quotient) | ||
243 | : "lo", GCC_REG_ACCUM); | ||
244 | |||
245 | /* | ||
246 | * Due to possible jiffies inconsistencies, we need to check | ||
247 | * the result so that we'll get a timer that is monotonic. | ||
248 | */ | ||
249 | if (res >= USECS_PER_JIFFY) | ||
250 | res = USECS_PER_JIFFY - 1; | ||
251 | |||
252 | return res; | ||
253 | } | ||
254 | |||
255 | static unsigned long calibrate_div64_gettimeoffset(void) | ||
256 | { | ||
257 | u32 count; | ||
258 | unsigned long res, tmp; | ||
259 | unsigned long quotient; | ||
260 | |||
261 | tmp = jiffies; | ||
262 | |||
263 | quotient = cached_quotient; | ||
264 | |||
265 | if (last_jiffies != tmp) { | ||
266 | last_jiffies = tmp; | ||
267 | if (last_jiffies) { | ||
268 | unsigned long r0; | ||
269 | __asm__(".set push\n\t" | ||
270 | ".set mips3\n\t" | ||
271 | "lwu %0,%3\n\t" | ||
272 | "dsll32 %1,%2,0\n\t" | ||
273 | "or %1,%1,%0\n\t" | ||
274 | "ddivu $0,%1,%4\n\t" | ||
275 | "mflo %1\n\t" | ||
276 | "dsll32 %0,%5,0\n\t" | ||
277 | "or %0,%0,%6\n\t" | ||
278 | "ddivu $0,%0,%1\n\t" | ||
279 | "mflo %0\n\t" | ||
280 | ".set pop" | ||
281 | : "=&r" (quotient), "=&r" (r0) | ||
282 | : "r" (timerhi), "m" (timerlo), | ||
283 | "r" (tmp), "r" (USECS_PER_JIFFY), | ||
284 | "r" (USECS_PER_JIFFY_FRAC) | ||
285 | : "hi", "lo", GCC_REG_ACCUM); | ||
286 | cached_quotient = quotient; | ||
287 | } | ||
288 | } | ||
289 | |||
290 | /* Get last timer tick in absolute kernel time */ | ||
291 | count = mips_hpt_read(); | ||
292 | |||
293 | /* .. relative to previous jiffy (32 bits is enough) */ | ||
294 | count -= timerlo; | ||
295 | |||
296 | __asm__("multu %1,%2" | ||
297 | : "=h" (res) | ||
298 | : "r" (count), "r" (quotient) | ||
299 | : "lo", GCC_REG_ACCUM); | ||
300 | |||
301 | /* | ||
302 | * Due to possible jiffies inconsistencies, we need to check | ||
303 | * the result so that we'll get a timer that is monotonic. | ||
304 | */ | ||
305 | if (res >= USECS_PER_JIFFY) | ||
306 | res = USECS_PER_JIFFY - 1; | ||
307 | |||
308 | return res; | ||
309 | } | ||
310 | |||
311 | 138 | ||
312 | /* last time when xtime and rtc are sync'ed up */ | 139 | /* last time when xtime and rtc are sync'ed up */ |
313 | static long last_rtc_update; | 140 | static long last_rtc_update; |
@@ -334,18 +161,10 @@ void local_timer_interrupt(int irq, void *dev_id) | |||
334 | */ | 161 | */ |
335 | irqreturn_t timer_interrupt(int irq, void *dev_id) | 162 | irqreturn_t timer_interrupt(int irq, void *dev_id) |
336 | { | 163 | { |
337 | unsigned long j; | ||
338 | unsigned int count; | ||
339 | |||
340 | write_seqlock(&xtime_lock); | 164 | write_seqlock(&xtime_lock); |
341 | 165 | ||
342 | count = mips_hpt_read(); | ||
343 | mips_timer_ack(); | 166 | mips_timer_ack(); |
344 | 167 | ||
345 | /* Update timerhi/timerlo for intra-jiffy calibration. */ | ||
346 | timerhi += count < timerlo; /* Wrap around */ | ||
347 | timerlo = count; | ||
348 | |||
349 | /* | 168 | /* |
350 | * call the generic timer interrupt handling | 169 | * call the generic timer interrupt handling |
351 | */ | 170 | */ |
@@ -368,47 +187,6 @@ irqreturn_t timer_interrupt(int irq, void *dev_id) | |||
368 | } | 187 | } |
369 | } | 188 | } |
370 | 189 | ||
371 | /* | ||
372 | * If jiffies has overflown in this timer_interrupt, we must | ||
373 | * update the timer[hi]/[lo] to make fast gettimeoffset funcs | ||
374 | * quotient calc still valid. -arca | ||
375 | * | ||
376 | * The first timer interrupt comes late as interrupts are | ||
377 | * enabled long after timers are initialized. Therefore the | ||
378 | * high precision timer is fast, leading to wrong gettimeoffset() | ||
379 | * calculations. We deal with it by setting it based on the | ||
380 | * number of its ticks between the second and the third interrupt. | ||
381 | * That is still somewhat imprecise, but it's a good estimate. | ||
382 | * --macro | ||
383 | */ | ||
384 | j = jiffies; | ||
385 | if (j < 4) { | ||
386 | static unsigned int prev_count; | ||
387 | static int hpt_initialized; | ||
388 | |||
389 | switch (j) { | ||
390 | case 0: | ||
391 | timerhi = timerlo = 0; | ||
392 | mips_hpt_init(count); | ||
393 | break; | ||
394 | case 2: | ||
395 | prev_count = count; | ||
396 | break; | ||
397 | case 3: | ||
398 | if (!hpt_initialized) { | ||
399 | unsigned int c3 = 3 * (count - prev_count); | ||
400 | |||
401 | timerhi = 0; | ||
402 | timerlo = c3; | ||
403 | mips_hpt_init(count - c3); | ||
404 | hpt_initialized = 1; | ||
405 | } | ||
406 | break; | ||
407 | default: | ||
408 | break; | ||
409 | } | ||
410 | } | ||
411 | |||
412 | write_sequnlock(&xtime_lock); | 190 | write_sequnlock(&xtime_lock); |
413 | 191 | ||
414 | /* | 192 | /* |
@@ -476,12 +254,11 @@ asmlinkage void ll_local_timer_interrupt(int irq) | |||
476 | * 1) board_time_init() - | 254 | * 1) board_time_init() - |
477 | * a) (optional) set up RTC routines, | 255 | * a) (optional) set up RTC routines, |
478 | * b) (optional) calibrate and set the mips_hpt_frequency | 256 | * b) (optional) calibrate and set the mips_hpt_frequency |
479 | * (only needed if you intended to use fixed_rate_gettimeoffset | 257 | * (only needed if you intended to use cpu counter as timer interrupt |
480 | * or use cpu counter as timer interrupt source) | 258 | * source) |
481 | * 2) setup xtime based on rtc_mips_get_time(). | 259 | * 2) setup xtime based on rtc_mips_get_time(). |
482 | * 3) choose a appropriate gettimeoffset routine. | 260 | * 3) calculate a couple of cached variables for later usage |
483 | * 4) calculate a couple of cached variables for later usage | 261 | * 4) plat_timer_setup() - |
484 | * 5) plat_timer_setup() - | ||
485 | * a) (optional) over-write any choices made above by time_init(). | 262 | * a) (optional) over-write any choices made above by time_init(). |
486 | * b) machine specific code should setup the timer irqaction. | 263 | * b) machine specific code should setup the timer irqaction. |
487 | * c) enable the timer interrupt | 264 | * c) enable the timer interrupt |
@@ -533,13 +310,48 @@ static unsigned int __init calibrate_hpt(void) | |||
533 | } while (--i); | 310 | } while (--i); |
534 | hpt_end = mips_hpt_read(); | 311 | hpt_end = mips_hpt_read(); |
535 | 312 | ||
536 | hpt_count = hpt_end - hpt_start; | 313 | hpt_count = (hpt_end - hpt_start) & mips_hpt_mask; |
537 | hz = HZ; | 314 | hz = HZ; |
538 | frequency = (u64)hpt_count * (u64)hz; | 315 | frequency = (u64)hpt_count * (u64)hz; |
539 | 316 | ||
540 | return frequency >> log_2_loops; | 317 | return frequency >> log_2_loops; |
541 | } | 318 | } |
542 | 319 | ||
320 | static cycle_t read_mips_hpt(void) | ||
321 | { | ||
322 | return (cycle_t)mips_hpt_read(); | ||
323 | } | ||
324 | |||
325 | static struct clocksource clocksource_mips = { | ||
326 | .name = "MIPS", | ||
327 | .read = read_mips_hpt, | ||
328 | .is_continuous = 1, | ||
329 | }; | ||
330 | |||
331 | static void __init init_mips_clocksource(void) | ||
332 | { | ||
333 | u64 temp; | ||
334 | u32 shift; | ||
335 | |||
336 | if (!mips_hpt_frequency || mips_hpt_read == null_hpt_read) | ||
337 | return; | ||
338 | |||
339 | /* Calclate a somewhat reasonable rating value */ | ||
340 | clocksource_mips.rating = 200 + mips_hpt_frequency / 10000000; | ||
341 | /* Find a shift value */ | ||
342 | for (shift = 32; shift > 0; shift--) { | ||
343 | temp = (u64) NSEC_PER_SEC << shift; | ||
344 | do_div(temp, mips_hpt_frequency); | ||
345 | if ((temp >> 32) == 0) | ||
346 | break; | ||
347 | } | ||
348 | clocksource_mips.shift = shift; | ||
349 | clocksource_mips.mult = (u32)temp; | ||
350 | clocksource_mips.mask = mips_hpt_mask; | ||
351 | |||
352 | clocksource_register(&clocksource_mips); | ||
353 | } | ||
354 | |||
543 | void __init time_init(void) | 355 | void __init time_init(void) |
544 | { | 356 | { |
545 | if (board_time_init) | 357 | if (board_time_init) |
@@ -555,41 +367,21 @@ void __init time_init(void) | |||
555 | -xtime.tv_sec, -xtime.tv_nsec); | 367 | -xtime.tv_sec, -xtime.tv_nsec); |
556 | 368 | ||
557 | /* Choose appropriate high precision timer routines. */ | 369 | /* Choose appropriate high precision timer routines. */ |
558 | if (!cpu_has_counter && !mips_hpt_read) { | 370 | if (!cpu_has_counter && !mips_hpt_read) |
559 | /* No high precision timer -- sorry. */ | 371 | /* No high precision timer -- sorry. */ |
560 | mips_hpt_read = null_hpt_read; | 372 | mips_hpt_read = null_hpt_read; |
561 | mips_hpt_init = null_hpt_init; | 373 | else if (!mips_hpt_frequency && !mips_timer_state) { |
562 | } else if (!mips_hpt_frequency && !mips_timer_state) { | ||
563 | /* A high precision timer of unknown frequency. */ | 374 | /* A high precision timer of unknown frequency. */ |
564 | if (!mips_hpt_read) { | 375 | if (!mips_hpt_read) |
565 | /* No external high precision timer -- use R4k. */ | 376 | /* No external high precision timer -- use R4k. */ |
566 | mips_hpt_read = c0_hpt_read; | 377 | mips_hpt_read = c0_hpt_read; |
567 | mips_hpt_init = c0_hpt_init; | ||
568 | } | ||
569 | |||
570 | if (cpu_has_mips32r1 || cpu_has_mips32r2 || | ||
571 | (current_cpu_data.isa_level == MIPS_CPU_ISA_I) || | ||
572 | (current_cpu_data.isa_level == MIPS_CPU_ISA_II)) | ||
573 | /* | ||
574 | * We need to calibrate the counter but we don't have | ||
575 | * 64-bit division. | ||
576 | */ | ||
577 | do_gettimeoffset = calibrate_div32_gettimeoffset; | ||
578 | else | ||
579 | /* | ||
580 | * We need to calibrate the counter but we *do* have | ||
581 | * 64-bit division. | ||
582 | */ | ||
583 | do_gettimeoffset = calibrate_div64_gettimeoffset; | ||
584 | } else { | 378 | } else { |
585 | /* We know counter frequency. Or we can get it. */ | 379 | /* We know counter frequency. Or we can get it. */ |
586 | if (!mips_hpt_read) { | 380 | if (!mips_hpt_read) { |
587 | /* No external high precision timer -- use R4k. */ | 381 | /* No external high precision timer -- use R4k. */ |
588 | mips_hpt_read = c0_hpt_read; | 382 | mips_hpt_read = c0_hpt_read; |
589 | 383 | ||
590 | if (mips_timer_state) | 384 | if (!mips_timer_state) { |
591 | mips_hpt_init = c0_hpt_init; | ||
592 | else { | ||
593 | /* No external timer interrupt -- use R4k. */ | 385 | /* No external timer interrupt -- use R4k. */ |
594 | mips_hpt_init = c0_hpt_timer_init; | 386 | mips_hpt_init = c0_hpt_timer_init; |
595 | mips_timer_ack = c0_timer_ack; | 387 | mips_timer_ack = c0_timer_ack; |
@@ -598,16 +390,9 @@ void __init time_init(void) | |||
598 | if (!mips_hpt_frequency) | 390 | if (!mips_hpt_frequency) |
599 | mips_hpt_frequency = calibrate_hpt(); | 391 | mips_hpt_frequency = calibrate_hpt(); |
600 | 392 | ||
601 | do_gettimeoffset = fixed_rate_gettimeoffset; | ||
602 | |||
603 | /* Calculate cache parameters. */ | 393 | /* Calculate cache parameters. */ |
604 | cycles_per_jiffy = (mips_hpt_frequency + HZ / 2) / HZ; | 394 | cycles_per_jiffy = (mips_hpt_frequency + HZ / 2) / HZ; |
605 | 395 | ||
606 | /* sll32_usecs_per_cycle = 10^6 * 2^32 / mips_counter_freq */ | ||
607 | do_div64_32(sll32_usecs_per_cycle, | ||
608 | 1000000, mips_hpt_frequency / 2, | ||
609 | mips_hpt_frequency); | ||
610 | |||
611 | /* Report the high precision timer rate for a reference. */ | 396 | /* Report the high precision timer rate for a reference. */ |
612 | printk("Using %u.%03u MHz high precision timer.\n", | 397 | printk("Using %u.%03u MHz high precision timer.\n", |
613 | ((mips_hpt_frequency + 500) / 1000) / 1000, | 398 | ((mips_hpt_frequency + 500) / 1000) / 1000, |
@@ -619,7 +404,7 @@ void __init time_init(void) | |||
619 | mips_timer_ack = null_timer_ack; | 404 | mips_timer_ack = null_timer_ack; |
620 | 405 | ||
621 | /* This sets up the high precision timer for the first interrupt. */ | 406 | /* This sets up the high precision timer for the first interrupt. */ |
622 | mips_hpt_init(mips_hpt_read()); | 407 | mips_hpt_init(); |
623 | 408 | ||
624 | /* | 409 | /* |
625 | * Call board specific timer interrupt setup. | 410 | * Call board specific timer interrupt setup. |
@@ -633,6 +418,8 @@ void __init time_init(void) | |||
633 | * is not invoked accidentally. | 418 | * is not invoked accidentally. |
634 | */ | 419 | */ |
635 | plat_timer_setup(&timer_irqaction); | 420 | plat_timer_setup(&timer_irqaction); |
421 | |||
422 | init_mips_clocksource(); | ||
636 | } | 423 | } |
637 | 424 | ||
638 | #define FEBRUARY 2 | 425 | #define FEBRUARY 2 |
diff --git a/arch/mips/philips/pnx8550/common/time.c b/arch/mips/philips/pnx8550/common/time.c index 0af655b1f330..65c440e8480b 100644 --- a/arch/mips/philips/pnx8550/common/time.c +++ b/arch/mips/philips/pnx8550/common/time.c | |||
@@ -41,8 +41,8 @@ extern unsigned int mips_hpt_frequency; | |||
41 | * 1) board_time_init() - | 41 | * 1) board_time_init() - |
42 | * a) (optional) set up RTC routines, | 42 | * a) (optional) set up RTC routines, |
43 | * b) (optional) calibrate and set the mips_hpt_frequency | 43 | * b) (optional) calibrate and set the mips_hpt_frequency |
44 | * (only needed if you intended to use fixed_rate_gettimeoffset | 44 | * (only needed if you intended to use cpu counter as timer interrupt |
45 | * or use cpu counter as timer interrupt source) | 45 | * source) |
46 | */ | 46 | */ |
47 | 47 | ||
48 | void pnx8550_time_init(void) | 48 | void pnx8550_time_init(void) |
diff --git a/arch/mips/pmc-sierra/yosemite/smp.c b/arch/mips/pmc-sierra/yosemite/smp.c index 65fa3a23ea5e..3cc0436db6cf 100644 --- a/arch/mips/pmc-sierra/yosemite/smp.c +++ b/arch/mips/pmc-sierra/yosemite/smp.c | |||
@@ -3,9 +3,7 @@ | |||
3 | 3 | ||
4 | #include <asm/pmon.h> | 4 | #include <asm/pmon.h> |
5 | #include <asm/titan_dep.h> | 5 | #include <asm/titan_dep.h> |
6 | 6 | #include <asm/time.h> | |
7 | extern unsigned int (*mips_hpt_read)(void); | ||
8 | extern void (*mips_hpt_init)(unsigned int); | ||
9 | 7 | ||
10 | #define LAUNCHSTACK_SIZE 256 | 8 | #define LAUNCHSTACK_SIZE 256 |
11 | 9 | ||
@@ -101,7 +99,7 @@ void prom_cpus_done(void) | |||
101 | */ | 99 | */ |
102 | void prom_init_secondary(void) | 100 | void prom_init_secondary(void) |
103 | { | 101 | { |
104 | mips_hpt_init(mips_hpt_read()); | 102 | mips_hpt_init(); |
105 | 103 | ||
106 | set_c0_status(ST0_CO | ST0_IE | ST0_IM); | 104 | set_c0_status(ST0_CO | ST0_IE | ST0_IM); |
107 | } | 105 | } |
diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c index 4e870fc4469b..c965705f3427 100644 --- a/arch/mips/sgi-ip27/ip27-timer.c +++ b/arch/mips/sgi-ip27/ip27-timer.c | |||
@@ -134,13 +134,6 @@ again: | |||
134 | irq_exit(); | 134 | irq_exit(); |
135 | } | 135 | } |
136 | 136 | ||
137 | unsigned long ip27_do_gettimeoffset(void) | ||
138 | { | ||
139 | unsigned long ct_cur1; | ||
140 | ct_cur1 = REMOTE_HUB_L(cputonasid(0), PI_RT_COUNT) + CYCLES_PER_JIFFY; | ||
141 | return (ct_cur1 - ct_cur[0]) * NSEC_PER_CYCLE / 1000; | ||
142 | } | ||
143 | |||
144 | /* Includes for ioc3_init(). */ | 137 | /* Includes for ioc3_init(). */ |
145 | #include <asm/sn/types.h> | 138 | #include <asm/sn/types.h> |
146 | #include <asm/sn/sn0/addrs.h> | 139 | #include <asm/sn/sn0/addrs.h> |
@@ -248,12 +241,17 @@ void __init plat_timer_setup(struct irqaction *irq) | |||
248 | setup_irq(irqno, &rt_irqaction); | 241 | setup_irq(irqno, &rt_irqaction); |
249 | } | 242 | } |
250 | 243 | ||
244 | static unsigned int ip27_hpt_read(void) | ||
245 | { | ||
246 | return REMOTE_HUB_L(cputonasid(0), PI_RT_COUNT); | ||
247 | } | ||
248 | |||
251 | void __init ip27_time_init(void) | 249 | void __init ip27_time_init(void) |
252 | { | 250 | { |
251 | mips_hpt_read = ip27_hpt_read; | ||
252 | mips_hpt_frequency = CYCLES_PER_SEC; | ||
253 | xtime.tv_sec = get_m48t35_time(); | 253 | xtime.tv_sec = get_m48t35_time(); |
254 | xtime.tv_nsec = 0; | 254 | xtime.tv_nsec = 0; |
255 | |||
256 | do_gettimeoffset = ip27_do_gettimeoffset; | ||
257 | } | 255 | } |
258 | 256 | ||
259 | void __init cpu_time_init(void) | 257 | void __init cpu_time_init(void) |
diff --git a/arch/mips/sibyte/bcm1480/time.c b/arch/mips/sibyte/bcm1480/time.c index bf12af46132e..e136bde5248e 100644 --- a/arch/mips/sibyte/bcm1480/time.c +++ b/arch/mips/sibyte/bcm1480/time.c | |||
@@ -47,6 +47,12 @@ | |||
47 | #define IMR_IP3_VAL K_BCM1480_INT_MAP_I1 | 47 | #define IMR_IP3_VAL K_BCM1480_INT_MAP_I1 |
48 | #define IMR_IP4_VAL K_BCM1480_INT_MAP_I2 | 48 | #define IMR_IP4_VAL K_BCM1480_INT_MAP_I2 |
49 | 49 | ||
50 | #ifdef CONFIG_SIMULATION | ||
51 | #define BCM1480_HPT_VALUE 50000 | ||
52 | #else | ||
53 | #define BCM1480_HPT_VALUE 1000000 | ||
54 | #endif | ||
55 | |||
50 | extern int bcm1480_steal_irq(int irq); | 56 | extern int bcm1480_steal_irq(int irq); |
51 | 57 | ||
52 | void bcm1480_time_init(void) | 58 | void bcm1480_time_init(void) |
@@ -59,11 +65,6 @@ void bcm1480_time_init(void) | |||
59 | BUG(); | 65 | BUG(); |
60 | } | 66 | } |
61 | 67 | ||
62 | if (!cpu) { | ||
63 | /* Use our own gettimeoffset() routine */ | ||
64 | do_gettimeoffset = bcm1480_gettimeoffset; | ||
65 | } | ||
66 | |||
67 | bcm1480_mask_irq(cpu, irq); | 68 | bcm1480_mask_irq(cpu, irq); |
68 | 69 | ||
69 | /* Map the timer interrupt to ip[4] of this cpu */ | 70 | /* Map the timer interrupt to ip[4] of this cpu */ |
@@ -74,11 +75,7 @@ void bcm1480_time_init(void) | |||
74 | /* Disable the timer and set up the count */ | 75 | /* Disable the timer and set up the count */ |
75 | __raw_writeq(0, IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG))); | 76 | __raw_writeq(0, IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG))); |
76 | __raw_writeq( | 77 | __raw_writeq( |
77 | #ifndef CONFIG_SIMULATION | 78 | BCM1480_HPT_VALUE/HZ |
78 | 1000000/HZ | ||
79 | #else | ||
80 | 50000/HZ | ||
81 | #endif | ||
82 | , IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT))); | 79 | , IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT))); |
83 | 80 | ||
84 | /* Set the timer running */ | 81 | /* Set the timer running */ |
@@ -122,16 +119,16 @@ void bcm1480_timer_interrupt(void) | |||
122 | } | 119 | } |
123 | } | 120 | } |
124 | 121 | ||
125 | /* | 122 | static unsigned int bcm1480_hpt_read(void) |
126 | * We use our own do_gettimeoffset() instead of the generic one, | ||
127 | * because the generic one does not work for SMP case. | ||
128 | * In addition, since we use general timer 0 for system time, | ||
129 | * we can get accurate intra-jiffy offset without calibration. | ||
130 | */ | ||
131 | unsigned long bcm1480_gettimeoffset(void) | ||
132 | { | 123 | { |
124 | /* We assume this function is called xtime_lock held. */ | ||
133 | unsigned long count = | 125 | unsigned long count = |
134 | __raw_readq(IOADDR(A_SCD_TIMER_REGISTER(0, R_SCD_TIMER_CNT))); | 126 | __raw_readq(IOADDR(A_SCD_TIMER_REGISTER(0, R_SCD_TIMER_CNT))); |
127 | return (jiffies + 1) * (BCM1480_HPT_VALUE / HZ) - count; | ||
128 | } | ||
135 | 129 | ||
136 | return 1000000/HZ - count; | 130 | void __init bcm1480_hpt_setup(void) |
131 | { | ||
132 | mips_hpt_read = bcm1480_hpt_read; | ||
133 | mips_hpt_frequency = BCM1480_HPT_VALUE; | ||
137 | } | 134 | } |
diff --git a/arch/mips/sibyte/sb1250/time.c b/arch/mips/sibyte/sb1250/time.c index 0ccf1796dd78..bcb74f2c1948 100644 --- a/arch/mips/sibyte/sb1250/time.c +++ b/arch/mips/sibyte/sb1250/time.c | |||
@@ -47,15 +47,11 @@ | |||
47 | 47 | ||
48 | #define SB1250_HPT_NUM 3 | 48 | #define SB1250_HPT_NUM 3 |
49 | #define SB1250_HPT_VALUE M_SCD_TIMER_CNT /* max value */ | 49 | #define SB1250_HPT_VALUE M_SCD_TIMER_CNT /* max value */ |
50 | #define SB1250_HPT_SHIFT ((sizeof(unsigned int)*8)-V_SCD_TIMER_WIDTH) | ||
51 | 50 | ||
52 | 51 | ||
53 | extern int sb1250_steal_irq(int irq); | 52 | extern int sb1250_steal_irq(int irq); |
54 | 53 | ||
55 | static unsigned int sb1250_hpt_read(void); | 54 | static unsigned int sb1250_hpt_read(void); |
56 | static void sb1250_hpt_init(unsigned int); | ||
57 | |||
58 | static unsigned int hpt_offset; | ||
59 | 55 | ||
60 | void __init sb1250_hpt_setup(void) | 56 | void __init sb1250_hpt_setup(void) |
61 | { | 57 | { |
@@ -69,13 +65,9 @@ void __init sb1250_hpt_setup(void) | |||
69 | __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, | 65 | __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, |
70 | IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_CFG))); | 66 | IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_CFG))); |
71 | 67 | ||
72 | /* | 68 | mips_hpt_frequency = V_SCD_TIMER_FREQ; |
73 | * we need to fill 32 bits, so just use the upper 23 bits and pretend | ||
74 | * the timer is going 512Mhz instead of 1Mhz | ||
75 | */ | ||
76 | mips_hpt_frequency = V_SCD_TIMER_FREQ << SB1250_HPT_SHIFT; | ||
77 | mips_hpt_init = sb1250_hpt_init; | ||
78 | mips_hpt_read = sb1250_hpt_read; | 69 | mips_hpt_read = sb1250_hpt_read; |
70 | mips_hpt_mask = M_SCD_TIMER_INIT; | ||
79 | } | 71 | } |
80 | } | 72 | } |
81 | 73 | ||
@@ -149,11 +141,7 @@ void sb1250_timer_interrupt(void) | |||
149 | 141 | ||
150 | /* | 142 | /* |
151 | * The HPT is free running from SB1250_HPT_VALUE down to 0 then starts over | 143 | * The HPT is free running from SB1250_HPT_VALUE down to 0 then starts over |
152 | * again. There's no easy way to set to a specific value so store init value | 144 | * again. |
153 | * in hpt_offset and subtract each time. | ||
154 | * | ||
155 | * Note: Timer isn't full 32bits so shift it into the upper part making | ||
156 | * it appear to run at a higher frequency. | ||
157 | */ | 145 | */ |
158 | static unsigned int sb1250_hpt_read(void) | 146 | static unsigned int sb1250_hpt_read(void) |
159 | { | 147 | { |
@@ -161,13 +149,5 @@ static unsigned int sb1250_hpt_read(void) | |||
161 | 149 | ||
162 | count = G_SCD_TIMER_CNT(__raw_readq(IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_CNT)))); | 150 | count = G_SCD_TIMER_CNT(__raw_readq(IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_CNT)))); |
163 | 151 | ||
164 | count = (SB1250_HPT_VALUE - count) << SB1250_HPT_SHIFT; | 152 | return SB1250_HPT_VALUE - count; |
165 | |||
166 | return count - hpt_offset; | ||
167 | } | ||
168 | |||
169 | static void sb1250_hpt_init(unsigned int count) | ||
170 | { | ||
171 | hpt_offset = count; | ||
172 | return; | ||
173 | } | 153 | } |