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 19DECLARE_GLOBAL_DATA_PTR; 20 21#ifdef CONFIG_SYS_TIMER_RATE 22/* Returns tick rate in ticks per second */ 23ulong notrace get_tbclk(void) 24{ 25 return CONFIG_SYS_TIMER_RATE; 26} 27#endif 28 29#ifdef CONFIG_SYS_TIMER_COUNTER 30unsigned 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 39ulong 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 56extern unsigned long __weak timer_read_counter(void); 57#endif 58 59#ifdef CONFIG_TIMER 60ulong 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 77uint64_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 103uint64_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 */ 117static 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 126int __weak timer_init(void) 127{ 128 return 0; 129} 130 131/* Returns time in milliseconds */ 132ulong __weak get_timer(ulong base) 133{ 134 return tick_to_time(get_ticks()) - base; 135} 136 137unsigned long __weak notrace timer_get_us(void) 138{ 139 return tick_to_time(get_ticks() * 1000); 140} 141 142static 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 150void __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 162void 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