1 /* 2 * (C) Copyright 2000-2009 3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 #include <common.h> 9 #include <dm.h> 10 #include <errno.h> 11 #include <timer.h> 12 #include <watchdog.h> 13 #include <div64.h> 14 #include <asm/io.h> 15 16 #ifndef CONFIG_WD_PERIOD 17 # define CONFIG_WD_PERIOD (10 * 1000 * 1000) /* 10 seconds default */ 18 #endif 19 20 DECLARE_GLOBAL_DATA_PTR; 21 22 #ifdef CONFIG_SYS_TIMER_RATE 23 /* Returns tick rate in ticks per second */ 24 ulong notrace get_tbclk(void) 25 { 26 return CONFIG_SYS_TIMER_RATE; 27 } 28 #endif 29 30 #ifdef CONFIG_SYS_TIMER_COUNTER 31 unsigned long notrace timer_read_counter(void) 32 { 33 #ifdef CONFIG_SYS_TIMER_COUNTS_DOWN 34 return ~readl(CONFIG_SYS_TIMER_COUNTER); 35 #else 36 return readl(CONFIG_SYS_TIMER_COUNTER); 37 #endif 38 } 39 40 ulong timer_get_boot_us(void) 41 { 42 ulong count = timer_read_counter(); 43 44 #if CONFIG_SYS_TIMER_RATE == 1000000 45 return count; 46 #elif CONFIG_SYS_TIMER_RATE > 1000000 47 return lldiv(count, CONFIG_SYS_TIMER_RATE / 1000000); 48 #elif defined(CONFIG_SYS_TIMER_RATE) 49 return (unsigned long long)count * 1000000 / CONFIG_SYS_TIMER_RATE; 50 #else 51 /* Assume the counter is in microseconds */ 52 return count; 53 #endif 54 } 55 56 #else 57 extern unsigned long __weak timer_read_counter(void); 58 #endif 59 60 #ifdef CONFIG_TIMER 61 ulong notrace get_tbclk(void) 62 { 63 if (!gd->timer) { 64 #ifdef CONFIG_TIMER_EARLY 65 return timer_early_get_rate(); 66 #else 67 int ret; 68 69 ret = dm_timer_init(); 70 if (ret) 71 return ret; 72 #endif 73 } 74 75 return timer_get_rate(gd->timer); 76 } 77 78 uint64_t notrace get_ticks(void) 79 { 80 u64 count; 81 int ret; 82 83 if (!gd->timer) { 84 #ifdef CONFIG_TIMER_EARLY 85 return timer_early_get_count(); 86 #else 87 int ret; 88 89 ret = dm_timer_init(); 90 if (ret) 91 return ret; 92 #endif 93 } 94 95 ret = timer_get_count(gd->timer, &count); 96 if (ret) 97 return ret; 98 99 return count; 100 } 101 102 #else /* !CONFIG_TIMER */ 103 104 uint64_t __weak notrace get_ticks(void) 105 { 106 unsigned long now = timer_read_counter(); 107 108 /* increment tbu if tbl has rolled over */ 109 if (now < gd->timebase_l) 110 gd->timebase_h++; 111 gd->timebase_l = now; 112 return ((uint64_t)gd->timebase_h << 32) | gd->timebase_l; 113 } 114 115 #endif /* CONFIG_TIMER */ 116 117 /* Returns time in milliseconds */ 118 static uint64_t notrace tick_to_time(uint64_t tick) 119 { 120 ulong div = get_tbclk(); 121 122 tick *= CONFIG_SYS_HZ; 123 do_div(tick, div); 124 return tick; 125 } 126 127 int __weak timer_init(void) 128 { 129 return 0; 130 } 131 132 /* Returns time in milliseconds */ 133 ulong __weak get_timer(ulong base) 134 { 135 return tick_to_time(get_ticks()) - base; 136 } 137 138 unsigned long __weak notrace timer_get_us(void) 139 { 140 return tick_to_time(get_ticks() * 1000); 141 } 142 143 static uint64_t usec_to_tick(unsigned long usec) 144 { 145 uint64_t tick = usec; 146 tick *= get_tbclk(); 147 do_div(tick, 1000000); 148 return tick; 149 } 150 151 void __weak __udelay(unsigned long usec) 152 { 153 uint64_t tmp; 154 155 tmp = get_ticks() + usec_to_tick(usec); /* get current timestamp */ 156 157 while (get_ticks() < tmp+1) /* loop till event */ 158 /*NOP*/; 159 } 160 161 /* ------------------------------------------------------------------------- */ 162 163 void udelay(unsigned long usec) 164 { 165 ulong kv; 166 167 do { 168 WATCHDOG_RESET(); 169 kv = usec > CONFIG_WD_PERIOD ? CONFIG_WD_PERIOD : usec; 170 __udelay (kv); 171 usec -= kv; 172 } while(usec); 173 } 174