hc
2023-05-26 a23f51ed7a39e452c1037343a84d7db1ca2c5bd7
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/*
 * Cirrus Logic EP93xx timer support.
 *
 * Copyright (C) 2009, 2010 Matthias Kaehlcke <matthias@kaehlcke.net>
 *
 * Copyright (C) 2004, 2005
 * Cory T. Tusar, Videon Central, Inc., <ctusar@videon-central.com>
 *
 * Based on the original intr.c Cirrus Logic EP93xx Rev D. interrupt support,
 * author unknown.
 *
 * SPDX-License-Identifier:    GPL-2.0+
 */
 
#include <common.h>
#include <linux/types.h>
#include <asm/arch/ep93xx.h>
#include <asm/io.h>
#include <div64.h>
 
#define TIMER_CLKSEL    (1 << 3)
#define TIMER_ENABLE    (1 << 7)
 
#define TIMER_FREQ            508469        /* ticks / second */
#define TIMER_MAX_VAL            0xFFFFFFFF
 
static struct ep93xx_timer
{
   unsigned long long ticks;
   unsigned long last_read;
} timer;
 
static inline unsigned long long usecs_to_ticks(unsigned long usecs)
{
   unsigned long long ticks = (unsigned long long)usecs * TIMER_FREQ;
   do_div(ticks, 1000 * 1000);
 
   return ticks;
}
 
static inline void read_timer(void)
{
   struct timer_regs *timer_regs = (struct timer_regs *)TIMER_BASE;
   const unsigned long now = TIMER_MAX_VAL - readl(&timer_regs->timer3.value);
 
   if (now >= timer.last_read)
       timer.ticks += now - timer.last_read;
   else
       /* an overflow occurred */
       timer.ticks += TIMER_MAX_VAL - timer.last_read + now;
 
   timer.last_read = now;
}
 
/*
 * Get the number of ticks (in CONFIG_SYS_HZ resolution)
 */
unsigned long long get_ticks(void)
{
   unsigned long long sys_ticks;
 
   read_timer();
 
   sys_ticks = timer.ticks * CONFIG_SYS_HZ;
   do_div(sys_ticks, TIMER_FREQ);
 
   return sys_ticks;
}
 
unsigned long get_timer_masked(void)
{
   return get_ticks();
}
 
unsigned long get_timer(unsigned long base)
{
   return get_timer_masked() - base;
}
 
void __udelay(unsigned long usec)
{
   unsigned long long target;
 
   read_timer();
 
   target = timer.ticks + usecs_to_ticks(usec);
 
   while (timer.ticks < target)
       read_timer();
}
 
int timer_init(void)
{
   struct timer_regs *timer_regs = (struct timer_regs *)TIMER_BASE;
 
   /* use timer 3 with 508KHz and free running, not enabled now */
   writel(TIMER_CLKSEL, &timer_regs->timer3.control);
 
   /* set initial timer value */
   writel(TIMER_MAX_VAL, &timer_regs->timer3.load);
 
   /* Enable the timer */
   writel(TIMER_ENABLE | TIMER_CLKSEL,
       &timer_regs->timer3.control);
 
   /* Reset the timer */
   read_timer();
   timer.ticks = 0;
 
   return 0;
}
 
/*
 * This function is derived from PowerPC code (timebase clock frequency).
 * On ARM it returns the number of timer ticks per second.
 */
unsigned long get_tbclk(void)
{
   return CONFIG_SYS_HZ;
}