at v2.6.15-rc2 157 lines 3.8 kB view raw
1/* 2 * Common time prototypes and such for all ppc machines. 3 * 4 * Written by Cort Dougan (cort@fsmlabs.com) to merge 5 * Paul Mackerras' version and mine for PReP and Pmac. 6 */ 7 8#ifdef __KERNEL__ 9#ifndef __ASM_TIME_H__ 10#define __ASM_TIME_H__ 11 12#include <linux/config.h> 13#include <linux/types.h> 14#include <linux/rtc.h> 15#include <linux/threads.h> 16 17#include <asm/reg.h> 18 19/* time.c */ 20extern unsigned tb_ticks_per_jiffy; 21extern unsigned tb_to_us; 22extern unsigned tb_last_stamp; 23extern unsigned long disarm_decr[NR_CPUS]; 24 25extern void to_tm(int tim, struct rtc_time * tm); 26extern time_t last_rtc_update; 27 28extern void set_dec_cpu6(unsigned int val); 29 30int via_calibrate_decr(void); 31 32/* Accessor functions for the decrementer register. 33 * The 4xx doesn't even have a decrementer. I tried to use the 34 * generic timer interrupt code, which seems OK, with the 4xx PIT 35 * in auto-reload mode. The problem is PIT stops counting when it 36 * hits zero. If it would wrap, we could use it just like a decrementer. 37 */ 38static __inline__ unsigned int get_dec(void) 39{ 40#if defined(CONFIG_40x) 41 return (mfspr(SPRN_PIT)); 42#else 43 return (mfspr(SPRN_DEC)); 44#endif 45} 46 47static __inline__ void set_dec(unsigned int val) 48{ 49#if defined(CONFIG_40x) 50 return; /* Have to let it auto-reload */ 51#elif defined(CONFIG_8xx_CPU6) 52 set_dec_cpu6(val); 53#else 54 mtspr(SPRN_DEC, val); 55#endif 56} 57 58/* Accessor functions for the timebase (RTC on 601) registers. */ 59/* If one day CONFIG_POWER is added just define __USE_RTC as 1 */ 60#ifdef CONFIG_6xx 61extern __inline__ int __attribute_pure__ __USE_RTC(void) { 62 return (mfspr(SPRN_PVR)>>16) == 1; 63} 64#else 65#define __USE_RTC() 0 66#endif 67 68extern __inline__ unsigned long get_tbl(void) { 69 unsigned long tbl; 70#if defined(CONFIG_403GCX) 71 asm volatile("mfspr %0, 0x3dd" : "=r" (tbl)); 72#else 73 asm volatile("mftb %0" : "=r" (tbl)); 74#endif 75 return tbl; 76} 77 78extern __inline__ unsigned long get_tbu(void) { 79 unsigned long tbl; 80#if defined(CONFIG_403GCX) 81 asm volatile("mfspr %0, 0x3dc" : "=r" (tbl)); 82#else 83 asm volatile("mftbu %0" : "=r" (tbl)); 84#endif 85 return tbl; 86} 87 88extern __inline__ void set_tb(unsigned int upper, unsigned int lower) 89{ 90 mtspr(SPRN_TBWL, 0); 91 mtspr(SPRN_TBWU, upper); 92 mtspr(SPRN_TBWL, lower); 93} 94 95extern __inline__ unsigned long get_rtcl(void) { 96 unsigned long rtcl; 97 asm volatile("mfrtcl %0" : "=r" (rtcl)); 98 return rtcl; 99} 100 101extern __inline__ unsigned long get_rtcu(void) 102{ 103 unsigned long rtcu; 104 asm volatile("mfrtcu %0" : "=r" (rtcu)); 105 return rtcu; 106} 107 108extern __inline__ unsigned get_native_tbl(void) { 109 if (__USE_RTC()) 110 return get_rtcl(); 111 else 112 return get_tbl(); 113} 114 115/* On machines with RTC, this function can only be used safely 116 * after the timestamp and for 1 second. It is only used by gettimeofday 117 * however so it should not matter. 118 */ 119extern __inline__ unsigned tb_ticks_since(unsigned tstamp) { 120 if (__USE_RTC()) { 121 int delta = get_rtcl() - tstamp; 122 return delta<0 ? delta + 1000000000 : delta; 123 } else { 124 return get_tbl() - tstamp; 125 } 126} 127 128#if 0 129extern __inline__ unsigned long get_bin_rtcl(void) { 130 unsigned long rtcl, rtcu1, rtcu2; 131 asm volatile("\ 1321: mfrtcu %0\n\ 133 mfrtcl %1\n\ 134 mfrtcu %2\n\ 135 cmpw %0,%2\n\ 136 bne- 1b\n" 137 : "=r" (rtcu1), "=r" (rtcl), "=r" (rtcu2) 138 : : "cr0"); 139 return rtcu2*1000000000+rtcl; 140} 141 142extern __inline__ unsigned binary_tbl(void) { 143 if (__USE_RTC()) 144 return get_bin_rtcl(); 145 else 146 return get_tbl(); 147} 148#endif 149 150/* Use mulhwu to scale processor timebase to timeval */ 151/* Specifically, this computes (x * y) / 2^32. -- paulus */ 152#define mulhwu(x,y) \ 153({unsigned z; asm ("mulhwu %0,%1,%2" : "=r" (z) : "r" (x), "r" (y)); z;}) 154 155unsigned mulhwu_scale_factor(unsigned, unsigned); 156#endif /* __ASM_TIME_H__ */ 157#endif /* __KERNEL__ */