blob: 394fc10ec3ad6b13f9cab9f5bac10b576eef4f80 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Macpaul Lin83dbca72011-10-11 22:33:18 +00002/*
3 * (C) Copyright 2009 Faraday Technology
4 * Po-Yu Chuang <ratbert@faraday-tech.com>
5 *
6 * Copyright (C) 2011 Andes Technology Corporation
7 * Shawn Lin, Andes Technology Corporation <nobuhiro@andestech.com>
8 * Macpaul Lin, Andes Technology Corporation <macpaul@andestech.com>
Macpaul Lin83dbca72011-10-11 22:33:18 +00009 */
rick6d564b82017-05-17 10:59:20 +080010#ifndef CONFIG_TIMER
Macpaul Lin83dbca72011-10-11 22:33:18 +000011#include <common.h>
Simon Glass97589732020-05-10 11:40:02 -060012#include <init.h>
Simon Glass9b61c7c2019-11-14 12:57:41 -070013#include <irq_func.h>
Simon Glass0f2af882020-05-10 11:40:05 -060014#include <log.h>
Simon Glass495a5dc2019-11-14 12:57:30 -070015#include <time.h>
Macpaul Lin83dbca72011-10-11 22:33:18 +000016#include <asm/io.h>
17#include <faraday/fttmr010.h>
Simon Glassdbd79542020-05-10 11:40:11 -060018#include <linux/delay.h>
Macpaul Lin83dbca72011-10-11 22:33:18 +000019
20static ulong timestamp;
21static ulong lastdec;
22
23int timer_init(void)
24{
Macpaul Linf4a7b802011-11-23 13:56:50 +080025 struct fttmr010 *tmr = (struct fttmr010 *)CONFIG_FTTMR010_BASE;
Macpaul Lin83dbca72011-10-11 22:33:18 +000026 unsigned int cr;
27
28 debug("%s()\n", __func__);
29
30 /* disable timers */
31 writel(0, &tmr->cr);
32
33#ifdef CONFIG_FTTMR010_EXT_CLK
34 /* use 32768Hz oscillator for RTC, WDT, TIMER */
35 ftpmu010_32768osc_enable();
36#endif
37
38 /* setup timer */
39 writel(TIMER_LOAD_VAL, &tmr->timer3_load);
40 writel(TIMER_LOAD_VAL, &tmr->timer3_counter);
41 writel(0, &tmr->timer3_match1);
42 writel(0, &tmr->timer3_match2);
43
44 /* we don't want timer to issue interrupts */
45 writel(FTTMR010_TM3_MATCH1 |
46 FTTMR010_TM3_MATCH2 |
47 FTTMR010_TM3_OVERFLOW,
48 &tmr->interrupt_mask);
49
50 cr = readl(&tmr->cr);
51#ifdef CONFIG_FTTMR010_EXT_CLK
52 cr |= FTTMR010_TM3_CLOCK; /* use external clock */
53#endif
54 cr |= FTTMR010_TM3_ENABLE;
55 writel(cr, &tmr->cr);
56
57 /* init the timestamp and lastdec value */
58 reset_timer_masked();
59
60 return 0;
61}
62
63/*
64 * timer without interrupts
65 */
66
67/*
68 * reset time
69 */
70void reset_timer_masked(void)
71{
Macpaul Linf4a7b802011-11-23 13:56:50 +080072 struct fttmr010 *tmr = (struct fttmr010 *)CONFIG_FTTMR010_BASE;
Macpaul Lin83dbca72011-10-11 22:33:18 +000073
74 /* capure current decrementer value time */
75#ifdef CONFIG_FTTMR010_EXT_CLK
76 lastdec = readl(&tmr->timer3_counter) / (TIMER_CLOCK / CONFIG_SYS_HZ);
77#else
Axel Lin55edeb52013-07-08 14:29:52 +080078 lastdec = readl(&tmr->timer3_counter) /
79 (CONFIG_SYS_CLK_FREQ / 2 / CONFIG_SYS_HZ);
Macpaul Lin83dbca72011-10-11 22:33:18 +000080#endif
81 timestamp = 0; /* start "advancing" time stamp from 0 */
82
83 debug("%s(): lastdec = %lx\n", __func__, lastdec);
84}
85
86void reset_timer(void)
87{
88 debug("%s()\n", __func__);
89 reset_timer_masked();
90}
91
92/*
93 * return timer ticks
94 */
95ulong get_timer_masked(void)
96{
Macpaul Linf4a7b802011-11-23 13:56:50 +080097 struct fttmr010 *tmr = (struct fttmr010 *)CONFIG_FTTMR010_BASE;
Macpaul Lin83dbca72011-10-11 22:33:18 +000098
99 /* current tick value */
100#ifdef CONFIG_FTTMR010_EXT_CLK
101 ulong now = readl(&tmr->timer3_counter) / (TIMER_CLOCK / CONFIG_SYS_HZ);
102#else
Axel Lin55edeb52013-07-08 14:29:52 +0800103 ulong now = readl(&tmr->timer3_counter) /
104 (CONFIG_SYS_CLK_FREQ / 2 / CONFIG_SYS_HZ);
Macpaul Lin83dbca72011-10-11 22:33:18 +0000105#endif
106
107 debug("%s(): now = %lx, lastdec = %lx\n", __func__, now, lastdec);
108
109 if (lastdec >= now) {
110 /*
111 * normal mode (non roll)
112 * move stamp fordward with absoulte diff ticks
113 */
114 timestamp += lastdec - now;
115 } else {
116 /*
117 * we have overflow of the count down timer
118 *
119 * nts = ts + ld + (TLV - now)
120 * ts=old stamp, ld=time that passed before passing through -1
121 * (TLV-now) amount of time after passing though -1
122 * nts = new "advancing time stamp"...it could also roll and
123 * cause problems.
124 */
125 timestamp += lastdec + TIMER_LOAD_VAL - now;
126 }
127
128 lastdec = now;
129
130 debug("%s() returns %lx\n", __func__, timestamp);
131
132 return timestamp;
133}
134
135/*
136 * return difference between timer ticks and base
137 */
138ulong get_timer(ulong base)
139{
140 debug("%s(%lx)\n", __func__, base);
141 return get_timer_masked() - base;
142}
143
144void set_timer(ulong t)
145{
146 debug("%s(%lx)\n", __func__, t);
147 timestamp = t;
148}
149
150/* delay x useconds AND preserve advance timestamp value */
151void __udelay(unsigned long usec)
152{
Macpaul Linf4a7b802011-11-23 13:56:50 +0800153 struct fttmr010 *tmr = (struct fttmr010 *)CONFIG_FTTMR010_BASE;
Macpaul Lin83dbca72011-10-11 22:33:18 +0000154
155#ifdef CONFIG_FTTMR010_EXT_CLK
156 long tmo = usec * (TIMER_CLOCK / 1000) / 1000;
157#else
158 long tmo = usec * ((CONFIG_SYS_CLK_FREQ / 2) / 1000) / 1000;
159#endif
160 unsigned long now, last = readl(&tmr->timer3_counter);
161
162 debug("%s(%lu)\n", __func__, usec);
163 while (tmo > 0) {
164 now = readl(&tmr->timer3_counter);
165 if (now > last) /* count down timer overflow */
166 tmo -= TIMER_LOAD_VAL + last - now;
167 else
168 tmo -= last - now;
169 last = now;
170 }
171}
172
173/*
174 * This function is derived from PowerPC code (read timebase as long long).
175 * On ARM it just returns the timer value.
176 */
177unsigned long long get_ticks(void)
178{
179 debug("%s()\n", __func__);
180 return get_timer(0);
181}
182
183/*
184 * This function is derived from PowerPC code (timebase clock frequency).
185 * On ARM it returns the number of timer ticks per second.
186 */
187ulong get_tbclk(void)
188{
189 debug("%s()\n", __func__);
190#ifdef CONFIG_FTTMR010_EXT_CLK
191 return CONFIG_SYS_HZ;
192#else
193 return CONFIG_SYS_CLK_FREQ;
194#endif
195}
rick6d564b82017-05-17 10:59:20 +0800196#endif /* CONFIG_TIMER */