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