blob: 2039106e4074ef5d5a21f13f67a74627b30463a1 [file] [log] [blame]
Marek Vasutc140e982011-11-08 23:18:08 +00001/*
2 * Freescale i.MX28 timer driver
3 *
4 * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
5 * on behalf of DENX Software Engineering GmbH
6 *
7 * Based on code from LTIB:
8 * (C) Copyright 2009-2010 Freescale Semiconductor, Inc.
9 *
10 * See file CREDITS for list of people who contributed to this
11 * project.
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License as
15 * published by the Free Software Foundation; either version 2 of
16 * the License, or (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
26 * MA 02111-1307 USA
27 */
28
29#include <common.h>
30#include <asm/io.h>
31#include <asm/arch/imx-regs.h>
32#include <asm/arch/sys_proto.h>
33
34/* Maximum fixed count */
Fadil Berishad608f6e2013-02-27 17:00:07 +000035#if defined(CONFIG_MX23)
36#define TIMER_LOAD_VAL 0xffff
37#elif defined(CONFIG_MX28)
38#define TIMER_LOAD_VAL 0xffffffff
39#endif
Marek Vasutc140e982011-11-08 23:18:08 +000040
41DECLARE_GLOBAL_DATA_PTR;
42
Simon Glass2655ee12012-12-13 20:48:34 +000043#define timestamp (gd->arch.tbl)
Simon Glassa848da52012-12-13 20:48:35 +000044#define lastdec (gd->arch.lastinc)
Marek Vasutc140e982011-11-08 23:18:08 +000045
46/*
47 * This driver uses 1kHz clock source.
48 */
Fadil Berisha69d8ce02013-02-28 10:03:26 -050049#define MXS_INCREMENTER_HZ 1000
Marek Vasutc140e982011-11-08 23:18:08 +000050
51static inline unsigned long tick_to_time(unsigned long tick)
52{
Fadil Berisha69d8ce02013-02-28 10:03:26 -050053 return tick / (MXS_INCREMENTER_HZ / CONFIG_SYS_HZ);
Marek Vasutc140e982011-11-08 23:18:08 +000054}
55
56static inline unsigned long time_to_tick(unsigned long time)
57{
Fadil Berisha69d8ce02013-02-28 10:03:26 -050058 return time * (MXS_INCREMENTER_HZ / CONFIG_SYS_HZ);
Marek Vasutc140e982011-11-08 23:18:08 +000059}
60
61/* Calculate how many ticks happen in "us" microseconds */
62static inline unsigned long us_to_tick(unsigned long us)
63{
Fadil Berisha69d8ce02013-02-28 10:03:26 -050064 return (us * MXS_INCREMENTER_HZ) / 1000000;
Marek Vasutc140e982011-11-08 23:18:08 +000065}
66
67int timer_init(void)
68{
Otavio Salvador22f4ff92012-08-05 09:05:31 +000069 struct mxs_timrot_regs *timrot_regs =
70 (struct mxs_timrot_regs *)MXS_TIMROT_BASE;
Marek Vasutc140e982011-11-08 23:18:08 +000071
72 /* Reset Timers and Rotary Encoder module */
Otavio Salvadorcbf0bf22012-08-13 09:53:12 +000073 mxs_reset_block(&timrot_regs->hw_timrot_rotctrl_reg);
Marek Vasutc140e982011-11-08 23:18:08 +000074
75 /* Set fixed_count to 0 */
Fadil Berishad608f6e2013-02-27 17:00:07 +000076#if defined(CONFIG_MX23)
77 writel(0, &timrot_regs->hw_timrot_timcount0);
78#elif defined(CONFIG_MX28)
Marek Vasutc140e982011-11-08 23:18:08 +000079 writel(0, &timrot_regs->hw_timrot_fixed_count0);
Fadil Berishad608f6e2013-02-27 17:00:07 +000080#endif
Marek Vasutc140e982011-11-08 23:18:08 +000081
82 /* Set UPDATE bit and 1Khz frequency */
83 writel(TIMROT_TIMCTRLn_UPDATE | TIMROT_TIMCTRLn_RELOAD |
84 TIMROT_TIMCTRLn_SELECT_1KHZ_XTAL,
85 &timrot_regs->hw_timrot_timctrl0);
86
87 /* Set fixed_count to maximal value */
Fadil Berishad608f6e2013-02-27 17:00:07 +000088#if defined(CONFIG_MX23)
89 writel(TIMER_LOAD_VAL - 1, &timrot_regs->hw_timrot_timcount0);
90#elif defined(CONFIG_MX28)
Marek Vasutc140e982011-11-08 23:18:08 +000091 writel(TIMER_LOAD_VAL, &timrot_regs->hw_timrot_fixed_count0);
Fadil Berishad608f6e2013-02-27 17:00:07 +000092#endif
Marek Vasutc140e982011-11-08 23:18:08 +000093
94 return 0;
95}
96
Marek Vasutc142b672012-02-07 06:47:31 +000097unsigned long long get_ticks(void)
Marek Vasutc140e982011-11-08 23:18:08 +000098{
Otavio Salvador22f4ff92012-08-05 09:05:31 +000099 struct mxs_timrot_regs *timrot_regs =
100 (struct mxs_timrot_regs *)MXS_TIMROT_BASE;
Fadil Berishad608f6e2013-02-27 17:00:07 +0000101 uint32_t now;
Marek Vasutc140e982011-11-08 23:18:08 +0000102
103 /* Current tick value */
Fadil Berishad608f6e2013-02-27 17:00:07 +0000104#if defined(CONFIG_MX23)
105 /* Upper bits are the valid ones. */
106 now = readl(&timrot_regs->hw_timrot_timcount0) >>
107 TIMROT_RUNNING_COUNTn_RUNNING_COUNT_OFFSET;
108#elif defined(CONFIG_MX28)
109 now = readl(&timrot_regs->hw_timrot_running_count0);
110#endif
Marek Vasutc140e982011-11-08 23:18:08 +0000111
112 if (lastdec >= now) {
113 /*
114 * normal mode (non roll)
115 * move stamp forward with absolut diff ticks
116 */
117 timestamp += (lastdec - now);
118 } else {
119 /* we have rollover of decrementer */
120 timestamp += (TIMER_LOAD_VAL - now) + lastdec;
121
122 }
123 lastdec = now;
124
Marek Vasutc142b672012-02-07 06:47:31 +0000125 return timestamp;
126}
127
128ulong get_timer_masked(void)
129{
130 return tick_to_time(get_ticks());
Marek Vasutc140e982011-11-08 23:18:08 +0000131}
132
Marek Vasutc142b672012-02-07 06:47:31 +0000133ulong get_timer(ulong base)
134{
135 return get_timer_masked() - base;
136}
137
Marek Vasutc140e982011-11-08 23:18:08 +0000138/* We use the HW_DIGCTL_MICROSECONDS register for sub-millisecond timer. */
Fadil Berisha69d8ce02013-02-28 10:03:26 -0500139#define MXS_HW_DIGCTL_MICROSECONDS 0x8001c0c0
Marek Vasutc140e982011-11-08 23:18:08 +0000140
141void __udelay(unsigned long usec)
142{
143 uint32_t old, new, incr;
144 uint32_t counter = 0;
145
Fadil Berisha69d8ce02013-02-28 10:03:26 -0500146 old = readl(MXS_HW_DIGCTL_MICROSECONDS);
Marek Vasutc140e982011-11-08 23:18:08 +0000147
148 while (counter < usec) {
Fadil Berisha69d8ce02013-02-28 10:03:26 -0500149 new = readl(MXS_HW_DIGCTL_MICROSECONDS);
Marek Vasutc140e982011-11-08 23:18:08 +0000150
151 /* Check if the timer wrapped. */
152 if (new < old) {
153 incr = 0xffffffff - old;
154 incr += new;
155 } else {
156 incr = new - old;
157 }
158
159 /*
160 * Check if we are close to the maximum time and the counter
161 * would wrap if incremented. If that's the case, break out
162 * from the loop as the requested delay time passed.
163 */
164 if (counter + incr < counter)
165 break;
166
167 counter += incr;
168 old = new;
169 }
170}
Marek Vasutc142b672012-02-07 06:47:31 +0000171
172ulong get_tbclk(void)
173{
Fadil Berisha69d8ce02013-02-28 10:03:26 -0500174 return MXS_INCREMENTER_HZ;
Marek Vasutc142b672012-02-07 06:47:31 +0000175}