1 /* 2 * Common time prototypes and such for all ppc machines. 3 * 4 * Written by Cort Dougan (cort@cs.nmt.edu) to merge 5 * Paul Mackerras' version and mine for PReP and Pmac. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 10 * 2 of the License, or (at your option) any later version. 11 */ 12 13 #ifndef __POWERPC_TIME_H 14 #define __POWERPC_TIME_H 15 16 #ifdef __KERNEL__ 17 #include <linux/types.h> 18 #include <linux/percpu.h> 19 20 #include <asm/processor.h> 21 22 /* time.c */ 23 extern unsigned long tb_ticks_per_jiffy; 24 extern unsigned long tb_ticks_per_usec; 25 extern unsigned long tb_ticks_per_sec; 26 extern struct clock_event_device decrementer_clockevent; 27 28 struct rtc_time; 29 extern void to_tm(int tim, struct rtc_time * tm); 30 extern void tick_broadcast_ipi_handler(void); 31 32 extern void generic_calibrate_decr(void); 33 34 /* Some sane defaults: 125 MHz timebase, 1GHz processor */ 35 extern unsigned long ppc_proc_freq; 36 #define DEFAULT_PROC_FREQ (DEFAULT_TB_FREQ * 8) 37 extern unsigned long ppc_tb_freq; 38 #define DEFAULT_TB_FREQ 125000000UL 39 40 struct div_result { 41 u64 result_high; 42 u64 result_low; 43 }; 44 45 /* Accessor functions for the timebase (RTC on 601) registers. */ 46 /* If one day CONFIG_POWER is added just define __USE_RTC as 1 */ 47 #ifdef CONFIG_6xx 48 #define __USE_RTC() (!cpu_has_feature(CPU_FTR_USE_TB)) 49 #else 50 #define __USE_RTC() 0 51 #endif 52 53 #ifdef CONFIG_PPC64 54 55 /* For compatibility, get_tbl() is defined as get_tb() on ppc64 */ 56 #define get_tbl get_tb 57 58 #else 59 60 static inline unsigned long get_tbl(void) 61 { 62 #if defined(CONFIG_403GCX) 63 unsigned long tbl; 64 asm volatile("mfspr %0, 0x3dd" : "=r" (tbl)); 65 return tbl; 66 #else 67 return mftbl(); 68 #endif 69 } 70 71 static inline unsigned int get_tbu(void) 72 { 73 #ifdef CONFIG_403GCX 74 unsigned int tbu; 75 asm volatile("mfspr %0, 0x3dc" : "=r" (tbu)); 76 return tbu; 77 #else 78 return mftbu(); 79 #endif 80 } 81 #endif /* !CONFIG_PPC64 */ 82 83 static inline unsigned int get_rtcl(void) 84 { 85 unsigned int rtcl; 86 87 asm volatile("mfrtcl %0" : "=r" (rtcl)); 88 return rtcl; 89 } 90 91 static inline u64 get_rtc(void) 92 { 93 unsigned int hi, lo, hi2; 94 95 do { 96 asm volatile("mfrtcu %0; mfrtcl %1; mfrtcu %2" 97 : "=r" (hi), "=r" (lo), "=r" (hi2)); 98 } while (hi2 != hi); 99 return (u64)hi * 1000000000 + lo; 100 } 101 102 static inline u64 get_vtb(void) 103 { 104 #ifdef CONFIG_PPC_BOOK3S_64 105 if (cpu_has_feature(CPU_FTR_ARCH_207S)) 106 return mfvtb(); 107 #endif 108 return 0; 109 } 110 111 #ifdef CONFIG_PPC64 112 static inline u64 get_tb(void) 113 { 114 return mftb(); 115 } 116 #else /* CONFIG_PPC64 */ 117 static inline u64 get_tb(void) 118 { 119 unsigned int tbhi, tblo, tbhi2; 120 121 do { 122 tbhi = get_tbu(); 123 tblo = get_tbl(); 124 tbhi2 = get_tbu(); 125 } while (tbhi != tbhi2); 126 127 return ((u64)tbhi << 32) | tblo; 128 } 129 #endif /* !CONFIG_PPC64 */ 130 131 static inline u64 get_tb_or_rtc(void) 132 { 133 return __USE_RTC() ? get_rtc() : get_tb(); 134 } 135 136 static inline void set_tb(unsigned int upper, unsigned int lower) 137 { 138 mtspr(SPRN_TBWL, 0); 139 mtspr(SPRN_TBWU, upper); 140 mtspr(SPRN_TBWL, lower); 141 } 142 143 /* Accessor functions for the decrementer register. 144 * The 4xx doesn't even have a decrementer. I tried to use the 145 * generic timer interrupt code, which seems OK, with the 4xx PIT 146 * in auto-reload mode. The problem is PIT stops counting when it 147 * hits zero. If it would wrap, we could use it just like a decrementer. 148 */ 149 static inline u64 get_dec(void) 150 { 151 #if defined(CONFIG_40x) 152 return (mfspr(SPRN_PIT)); 153 #else 154 return (mfspr(SPRN_DEC)); 155 #endif 156 } 157 158 /* 159 * Note: Book E and 4xx processors differ from other PowerPC processors 160 * in when the decrementer generates its interrupt: on the 1 to 0 161 * transition for Book E/4xx, but on the 0 to -1 transition for others. 162 */ 163 static inline void set_dec(u64 val) 164 { 165 #if defined(CONFIG_40x) 166 mtspr(SPRN_PIT, (u32) val); 167 #else 168 #ifndef CONFIG_BOOKE 169 --val; 170 #endif 171 mtspr(SPRN_DEC, val); 172 #endif /* not 40x */ 173 } 174 175 static inline unsigned long tb_ticks_since(unsigned long tstamp) 176 { 177 if (__USE_RTC()) { 178 int delta = get_rtcl() - (unsigned int) tstamp; 179 return delta < 0 ? delta + 1000000000 : delta; 180 } 181 return get_tbl() - tstamp; 182 } 183 184 #define mulhwu(x,y) \ 185 ({unsigned z; asm ("mulhwu %0,%1,%2" : "=r" (z) : "r" (x), "r" (y)); z;}) 186 187 #ifdef CONFIG_PPC64 188 #define mulhdu(x,y) \ 189 ({unsigned long z; asm ("mulhdu %0,%1,%2" : "=r" (z) : "r" (x), "r" (y)); z;}) 190 #else 191 extern u64 mulhdu(u64, u64); 192 #endif 193 194 extern void div128_by_32(u64 dividend_high, u64 dividend_low, 195 unsigned divisor, struct div_result *dr); 196 197 /* Used to store Processor Utilization register (purr) values */ 198 199 struct cpu_usage { 200 u64 current_tb; /* Holds the current purr register values */ 201 }; 202 203 DECLARE_PER_CPU(struct cpu_usage, cpu_usage_array); 204 205 extern void secondary_cpu_time_init(void); 206 207 DECLARE_PER_CPU(u64, decrementers_next_tb); 208 209 /* Convert timebase ticks to nanoseconds */ 210 unsigned long long tb_to_ns(unsigned long long tb_ticks); 211 212 #endif /* __KERNEL__ */ 213 #endif /* __POWERPC_TIME_H */ 214