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 #else 40 extern unsigned long __weak timer_read_counter(void); 41 #endif 42 43 #ifdef CONFIG_TIMER 44 static int notrace dm_timer_init(void) 45 { 46 struct udevice *dev; 47 int ret; 48 49 if (!gd->timer) { 50 ret = uclass_first_device(UCLASS_TIMER, &dev); 51 if (ret) 52 return ret; 53 if (!dev) 54 return -ENODEV; 55 gd->timer = dev; 56 } 57 58 return 0; 59 } 60 61 ulong notrace get_tbclk(void) 62 { 63 int ret; 64 65 ret = dm_timer_init(); 66 if (ret) 67 return ret; 68 69 return timer_get_rate(gd->timer); 70 } 71 72 uint64_t notrace get_ticks(void) 73 { 74 u64 count; 75 int ret; 76 77 ret = dm_timer_init(); 78 if (ret) 79 return ret; 80 81 ret = timer_get_count(gd->timer, &count); 82 if (ret) 83 return ret; 84 85 return count; 86 } 87 88 #else /* !CONFIG_TIMER */ 89 90 uint64_t __weak notrace get_ticks(void) 91 { 92 unsigned long now = timer_read_counter(); 93 94 /* increment tbu if tbl has rolled over */ 95 if (now < gd->timebase_l) 96 gd->timebase_h++; 97 gd->timebase_l = now; 98 return ((uint64_t)gd->timebase_h << 32) | gd->timebase_l; 99 } 100 101 #endif /* CONFIG_TIMER */ 102 103 /* Returns time in milliseconds */ 104 static uint64_t notrace tick_to_time(uint64_t tick) 105 { 106 ulong div = get_tbclk(); 107 108 tick *= CONFIG_SYS_HZ; 109 do_div(tick, div); 110 return tick; 111 } 112 113 int __weak timer_init(void) 114 { 115 return 0; 116 } 117 118 /* Returns time in milliseconds */ 119 ulong __weak get_timer(ulong base) 120 { 121 return tick_to_time(get_ticks()) - base; 122 } 123 124 unsigned long __weak notrace timer_get_us(void) 125 { 126 return tick_to_time(get_ticks() * 1000); 127 } 128 129 static uint64_t usec_to_tick(unsigned long usec) 130 { 131 uint64_t tick = usec; 132 tick *= get_tbclk(); 133 do_div(tick, 1000000); 134 return tick; 135 } 136 137 void __weak __udelay(unsigned long usec) 138 { 139 uint64_t tmp; 140 141 tmp = get_ticks() + usec_to_tick(usec); /* get current timestamp */ 142 143 while (get_ticks() < tmp+1) /* loop till event */ 144 /*NOP*/; 145 } 146 147 /* ------------------------------------------------------------------------- */ 148 149 void udelay(unsigned long usec) 150 { 151 ulong kv; 152 153 do { 154 WATCHDOG_RESET(); 155 kv = usec > CONFIG_WD_PERIOD ? CONFIG_WD_PERIOD : usec; 156 __udelay (kv); 157 usec -= kv; 158 } while(usec); 159 } 160 161 void mdelay(unsigned long msec) 162 { 163 while (msec--) 164 udelay(1000); 165 } 166