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