uboot/lib/time.c
<<
>>
Prefs
   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