1 /* Some utility functions around the free running clock on ARM. The clock is 2 * 32-bits wide, but we provide 64-bit wrapper functions to make it look 3 * similar to the read_tsc functions. On hardware we could actually make use 4 * of the timer overflow counter, but emulator doesn't emulate it. */ 5 6 #include <minix/minlib.h> 7 #include <minix/sysutil.h> 8 #include <minix/type.h> 9 #include <sys/errno.h> 10 #include <sys/types.h> 11 #include <assert.h> 12 13 #define MICROHZ 1000000ULL /* number of micros per second */ 14 #define MICROSPERTICK(h) (MICROHZ/(h)) /* number of micros per HZ tick */ 15 16 static u64_t Hz; 17 18 extern struct minix_kerninfo *_minix_kerninfo; 19 20 int 21 micro_delay(u32_t micros) 22 { 23 u64_t start, delta, delta_end; 24 25 Hz = sys_hz(); 26 27 /* Start of delay. */ 28 read_frclock_64(&start); 29 assert(_minix_kerninfo->minix_arm_frclock_hz); 30 delta_end = (_minix_kerninfo->minix_arm_frclock_hz * micros) / MICROHZ; 31 32 /* If we have to wait for at least one HZ tick, use the regular 33 * tickdelay first. Round downwards on purpose, so the average 34 * half-tick we wait short (depending on where in the current tick 35 * we call tickdelay). We can correct for both overhead of tickdelay 36 * itself and the short wait in the busywait later. 37 */ 38 if (micros >= MICROSPERTICK(Hz)) 39 tickdelay(micros*Hz/MICROHZ); 40 41 /* Wait (the rest) of the delay time using busywait. */ 42 do { 43 read_frclock_64(&delta); 44 } while (delta_frclock_64(start, delta) < delta_end); 45 46 47 return 0; 48 } 49 50 u32_t frclock_64_to_micros(u64_t tsc) 51 { 52 return (u32_t) (tsc / (_minix_kerninfo->minix_arm_frclock_hz / MICROHZ)); 53 } 54 55 void 56 read_frclock(u32_t *frclk) 57 { 58 assert(frclk); 59 assert(_minix_kerninfo->minix_frclock_tcrr); 60 assert(_minix_kerninfo->minix_arm_frclock_hz); 61 *frclk = *(volatile u32_t *)((u8_t *) _minix_kerninfo->minix_frclock_tcrr); 62 } 63 64 u32_t 65 delta_frclock(u32_t base, u32_t cur) 66 { 67 u32_t delta; 68 69 if (cur < base) { 70 /* We have wrapped around, so delta is base to wrapping point 71 * plus starting point (0) to cur. This supports wrapping once 72 * only. */ 73 delta = (UINT_MAX - base) + cur; 74 } else { 75 delta = cur - base; 76 } 77 78 return delta; 79 } 80 81 void 82 read_frclock_64(u64_t *frclk) 83 { 84 read_frclock((u32_t *) frclk); 85 } 86 87 u64_t 88 delta_frclock_64(u64_t base, u64_t cur) 89 { 90 return (u64_t) delta_frclock((u32_t) base, (u32_t) cur); 91 } 92 93