uboot/arch/arm/cpu/armv7/s5p-common/timer.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2009 Samsung Electronics
   3 * Heungjun Kim <riverful.kim@samsung.com>
   4 * Inki Dae <inki.dae@samsung.com>
   5 * Minkyu Kang <mk7.kang@samsung.com>
   6 *
   7 * SPDX-License-Identifier:     GPL-2.0+
   8 */
   9
  10#include <common.h>
  11#include <div64.h>
  12#include <asm/io.h>
  13#include <asm/arch/pwm.h>
  14#include <asm/arch/clk.h>
  15
  16/* Use the old PWM interface for now */
  17#undef CONFIG_DM_PWM
  18#include <pwm.h>
  19
  20DECLARE_GLOBAL_DATA_PTR;
  21
  22unsigned long get_current_tick(void);
  23
  24/* macro to read the 16 bit timer */
  25static inline struct s5p_timer *s5p_get_base_timer(void)
  26{
  27        return (struct s5p_timer *)samsung_get_base_timer();
  28}
  29
  30/**
  31 * Read the countdown timer.
  32 *
  33 * This operates at 1MHz and counts downwards. It will wrap about every
  34 * hour (2^32 microseconds).
  35 *
  36 * @return current value of timer
  37 */
  38static unsigned long timer_get_us_down(void)
  39{
  40        struct s5p_timer *const timer = s5p_get_base_timer();
  41
  42        return readl(&timer->tcnto4);
  43}
  44
  45int timer_init(void)
  46{
  47        /* PWM Timer 4 */
  48        pwm_init(4, MUX_DIV_4, 0);
  49        pwm_config(4, 100000, 100000);
  50        pwm_enable(4);
  51
  52        /* Use this as the current monotonic time in us */
  53        gd->arch.timer_reset_value = 0;
  54
  55        /* Use this as the last timer value we saw */
  56        gd->arch.lastinc = timer_get_us_down();
  57        reset_timer_masked();
  58
  59        return 0;
  60}
  61
  62/*
  63 * timer without interrupts
  64 */
  65unsigned long get_timer(unsigned long base)
  66{
  67        unsigned long long time_ms;
  68
  69        ulong now = timer_get_us_down();
  70
  71        /*
  72         * Increment the time by the amount elapsed since the last read.
  73         * The timer may have wrapped around, but it makes no difference to
  74         * our arithmetic here.
  75         */
  76        gd->arch.timer_reset_value += gd->arch.lastinc - now;
  77        gd->arch.lastinc = now;
  78
  79        /* Divide by 1000 to convert from us to ms */
  80        time_ms = gd->arch.timer_reset_value;
  81        do_div(time_ms, 1000);
  82        return time_ms - base;
  83}
  84
  85unsigned long __attribute__((no_instrument_function)) timer_get_us(void)
  86{
  87        static unsigned long base_time_us;
  88
  89        struct s5p_timer *const timer =
  90                (struct s5p_timer *)samsung_get_base_timer();
  91        unsigned long now_downward_us = readl(&timer->tcnto4);
  92
  93        if (!base_time_us)
  94                base_time_us = now_downward_us;
  95
  96        /* Note that this timer counts downward. */
  97        return base_time_us - now_downward_us;
  98}
  99
 100/* delay x useconds */
 101void __udelay(unsigned long usec)
 102{
 103        unsigned long count_value;
 104
 105        count_value = timer_get_us_down();
 106        while ((int)(count_value - timer_get_us_down()) < (int)usec)
 107                ;
 108}
 109
 110void reset_timer_masked(void)
 111{
 112        struct s5p_timer *const timer = s5p_get_base_timer();
 113
 114        /* reset time */
 115        gd->arch.lastinc = readl(&timer->tcnto4);
 116        gd->arch.tbl = 0;
 117}
 118
 119/*
 120 * This function is derived from PowerPC code (read timebase as long long).
 121 * On ARM it just returns the timer value.
 122 */
 123unsigned long long get_ticks(void)
 124{
 125        return get_timer(0);
 126}
 127
 128/*
 129 * This function is derived from PowerPC code (timebase clock frequency).
 130 * On ARM it returns the number of timer ticks per second.
 131 */
 132unsigned long get_tbclk(void)
 133{
 134        return CONFIG_SYS_HZ;
 135}
 136