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