blob: de6f5daa35a5a4b061059956f58aae91ea5be955 [file] [log] [blame]
Xiangfu Liu2f46d422011-10-12 12:24:06 +08001/*
2 * Copyright (c) 2006
3 * Ingenic Semiconductor, <jlwei@ingenic.cn>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
18 * MA 02111-1307 USA
19 */
20
21#include <config.h>
22#include <common.h>
23#include <asm/io.h>
24
25#include <asm/jz4740.h>
26
27#define TIMER_CHAN 0
28#define TIMER_FDATA 0xffff /* Timer full data value */
29
30DECLARE_GLOBAL_DATA_PTR;
31
32static struct jz4740_tcu *tcu = (struct jz4740_tcu *)JZ4740_TCU_BASE;
33
34void reset_timer_masked(void)
35{
36 /* reset time */
37 gd->lastinc = readw(&tcu->tcnt0);
38 gd->tbl = 0;
39}
40
41ulong get_timer_masked(void)
42{
43 ulong now = readw(&tcu->tcnt0);
44
45 if (gd->lastinc <= now)
46 gd->tbl += now - gd->lastinc; /* normal mode */
47 else {
48 /* we have an overflow ... */
49 gd->tbl += TIMER_FDATA + now - gd->lastinc;
50 }
51
52 gd->lastinc = now;
53
54 return gd->tbl;
55}
56
57void udelay_masked(unsigned long usec)
58{
59 ulong tmo;
60 ulong endtime;
61 signed long diff;
62
63 /* normalize */
64 if (usec >= 1000) {
65 tmo = usec / 1000;
66 tmo *= CONFIG_SYS_HZ;
67 tmo /= 1000;
68 } else {
69 if (usec > 1) {
70 tmo = usec * CONFIG_SYS_HZ;
71 tmo /= 1000*1000;
72 } else
73 tmo = 1;
74 }
75
76 endtime = get_timer_masked() + tmo;
77
78 do {
79 ulong now = get_timer_masked();
80 diff = endtime - now;
81 } while (diff >= 0);
82}
83
84int timer_init(void)
85{
86 writew(TCU_TCSR_PRESCALE256 | TCU_TCSR_EXT_EN, &tcu->tcsr0);
87
88 writew(0, &tcu->tcnt0);
89 writew(0, &tcu->tdhr0);
90 writew(TIMER_FDATA, &tcu->tdfr0);
91
92 /* mask irqs */
93 writel((1 << TIMER_CHAN) | (1 << (TIMER_CHAN + 16)), &tcu->tmsr);
94 writel(1 << TIMER_CHAN, &tcu->tscr); /* enable timer clock */
95 writeb(1 << TIMER_CHAN, &tcu->tesr); /* start counting up */
96
97 gd->lastinc = 0;
98 gd->tbl = 0;
99
100 return 0;
101}
102
103void reset_timer(void)
104{
105 reset_timer_masked();
106}
107
108ulong get_timer(ulong base)
109{
110 return get_timer_masked() - base;
111}
112
113void set_timer(ulong t)
114{
115 gd->tbl = t;
116}
117
118void __udelay(unsigned long usec)
119{
120 ulong tmo, tmp;
121
122 /* normalize */
123 if (usec >= 1000) {
124 tmo = usec / 1000;
125 tmo *= CONFIG_SYS_HZ;
126 tmo /= 1000;
127 } else {
128 if (usec >= 1) {
129 tmo = usec * CONFIG_SYS_HZ;
130 tmo /= 1000 * 1000;
131 } else
132 tmo = 1;
133 }
134
135 /* check for rollover during this delay */
136 tmp = get_timer(0);
137 if ((tmp + tmo) < tmp)
138 reset_timer_masked(); /* timer would roll over */
139 else
140 tmo += tmp;
141
142 while (get_timer_masked() < tmo)
143 ;
144}
145
146/*
147 * This function is derived from PowerPC code (read timebase as long long).
148 * On MIPS it just returns the timer value.
149 */
150unsigned long long get_ticks(void)
151{
152 return get_timer(0);
153}
154
155/*
156 * This function is derived from PowerPC code (timebase clock frequency).
157 * On MIPS it returns the number of timer ticks per second.
158 */
159ulong get_tbclk(void)
160{
161 return CONFIG_SYS_HZ;
162}