blob: c88e962a3db81a2c1fe989ca8fdb0b6a8de8f85e [file] [log] [blame]
Vipin KUMAR81c0ebf2010-01-15 19:15:43 +05301/*
2 * (C) Copyright 2009
3 * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
4 *
Wolfgang Denk1a459662013-07-08 09:37:19 +02005 * SPDX-License-Identifier: GPL-2.0+
Vipin KUMAR81c0ebf2010-01-15 19:15:43 +05306 */
7
8#include <common.h>
9#include <asm/io.h>
10#include <asm/arch/hardware.h>
11#include <asm/arch/spr_gpt.h>
12#include <asm/arch/spr_misc.h>
13
14#define GPT_RESOLUTION (CONFIG_SPEAR_HZ_CLOCK / CONFIG_SPEAR_HZ)
15#define READ_TIMER() (readl(&gpt_regs_p->count) & GPT_FREE_RUNNING)
16
17static struct gpt_regs *const gpt_regs_p =
18 (struct gpt_regs *)CONFIG_SPEAR_TIMERBASE;
19
20static struct misc_regs *const misc_regs_p =
21 (struct misc_regs *)CONFIG_SPEAR_MISCBASE;
22
Heiko Schocherc9ac3ba2011-01-20 22:56:39 +000023DECLARE_GLOBAL_DATA_PTR;
24
Simon Glass66ee6922012-12-13 20:48:34 +000025#define timestamp gd->arch.tbl
Simon Glass582601d2012-12-13 20:48:35 +000026#define lastdec gd->arch.lastinc
Vipin KUMAR81c0ebf2010-01-15 19:15:43 +053027
28int timer_init(void)
29{
30 u32 synth;
31
32 /* Prescaler setting */
33#if defined(CONFIG_SPEAR3XX)
34 writel(MISC_PRSC_CFG, &misc_regs_p->prsc2_clk_cfg);
35 synth = MISC_GPT4SYNTH;
36#elif defined(CONFIG_SPEAR600)
37 writel(MISC_PRSC_CFG, &misc_regs_p->prsc1_clk_cfg);
38 synth = MISC_GPT3SYNTH;
39#else
40# error Incorrect config. Can only be spear{600|300|310|320}
41#endif
42
43 writel(readl(&misc_regs_p->periph_clk_cfg) | synth,
44 &misc_regs_p->periph_clk_cfg);
45
46 /* disable timers */
47 writel(GPT_PRESCALER_1 | GPT_MODE_AUTO_RELOAD, &gpt_regs_p->control);
48
49 /* load value for free running */
50 writel(GPT_FREE_RUNNING, &gpt_regs_p->compare);
51
52 /* auto reload, start timer */
53 writel(readl(&gpt_regs_p->control) | GPT_ENABLE, &gpt_regs_p->control);
54
Graeme Russ17659d72011-07-15 02:21:14 +000055 /* Reset the timer */
56 lastdec = READ_TIMER();
57 timestamp = 0;
Vipin KUMAR81c0ebf2010-01-15 19:15:43 +053058
59 return 0;
60}
61
62/*
63 * timer without interrupts
64 */
Vipin KUMAR81c0ebf2010-01-15 19:15:43 +053065ulong get_timer(ulong base)
66{
67 return (get_timer_masked() / GPT_RESOLUTION) - base;
68}
69
Vipin KUMAR81c0ebf2010-01-15 19:15:43 +053070void __udelay(unsigned long usec)
71{
72 ulong tmo;
73 ulong start = get_timer_masked();
74 ulong tenudelcnt = CONFIG_SPEAR_HZ_CLOCK / (1000 * 100);
75 ulong rndoff;
76
77 rndoff = (usec % 10) ? 1 : 0;
78
79 /* tenudelcnt timer tick gives 10 microsecconds delay */
80 tmo = ((usec / 10) + rndoff) * tenudelcnt;
81
82 while ((ulong) (get_timer_masked() - start) < tmo)
83 ;
84}
85
Vipin KUMAR81c0ebf2010-01-15 19:15:43 +053086ulong get_timer_masked(void)
87{
88 ulong now = READ_TIMER();
89
90 if (now >= lastdec) {
91 /* normal mode */
92 timestamp += now - lastdec;
93 } else {
94 /* we have an overflow ... */
95 timestamp += now + GPT_FREE_RUNNING - lastdec;
96 }
97 lastdec = now;
98
99 return timestamp;
100}
101
102void udelay_masked(unsigned long usec)
103{
104 return udelay(usec);
105}
106
107/*
108 * This function is derived from PowerPC code (read timebase as long long).
109 * On ARM it just returns the timer value.
110 */
111unsigned long long get_ticks(void)
112{
113 return get_timer(0);
114}
115
116/*
117 * This function is derived from PowerPC code (timebase clock frequency).
118 * On ARM it returns the number of timer ticks per second.
119 */
120ulong get_tbclk(void)
121{
122 return CONFIG_SPEAR_HZ;
123}