1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2016 Nexell
4  * Hyunseok, Jung <hsjung@nexell.co.kr>
5  */
6 
7 #include <common.h>
8 #include <log.h>
9 
10 #include <asm/io.h>
11 #include <asm/arch/nexell.h>
12 #include <asm/arch/clk.h>
13 #if defined(CONFIG_ARCH_S5P4418)
14 #include <asm/arch/reset.h>
15 #endif
16 
17 #if (CONFIG_TIMER_SYS_TICK_CH > 3)
18 #error Not support timer channel. Please use "0~3" channels.
19 #endif
20 
21 /* global variables to save timer count
22  *
23  * Section ".data" must be used because BSS is not available before relocation,
24  * in board_init_f(), respectively! I.e. global variables can not be used!
25  */
26 static unsigned long timestamp __section(".data");
27 static unsigned long lastdec __section(".data");
28 static int	timerinit __section(".data");
29 
30 /* macro to hw timer tick config */
31 static long	TIMER_FREQ  = 1000000;
32 static long	TIMER_HZ    = 1000000 / CONFIG_SYS_HZ;
33 static long	TIMER_COUNT = 0xFFFFFFFF;
34 
35 #define	REG_TCFG0			(0x00)
36 #define	REG_TCFG1			(0x04)
37 #define	REG_TCON			(0x08)
38 #define	REG_TCNTB0			(0x0C)
39 #define	REG_TCMPB0			(0x10)
40 #define	REG_TCNT0			(0x14)
41 #define	REG_CSTAT			(0x44)
42 
43 #define	TCON_BIT_AUTO			(1 << 3)
44 #define	TCON_BIT_INVT			(1 << 2)
45 #define	TCON_BIT_UP			(1 << 1)
46 #define	TCON_BIT_RUN			(1 << 0)
47 #define TCFG0_BIT_CH(ch)		((ch) == 0 || (ch) == 1 ? 0 : 8)
48 #define TCFG1_BIT_CH(ch)		((ch) * 4)
49 #define TCON_BIT_CH(ch)			((ch) ? (ch) * 4  + 4 : 0)
50 #define TINT_CH(ch)			(ch)
51 #define TINT_CSTAT_BIT_CH(ch)		((ch) + 5)
52 #define	TINT_CSTAT_MASK			(0x1F)
53 #define TIMER_TCNT_OFFS			(0xC)
54 
55 void reset_timer_masked(void);
56 unsigned long get_timer_masked(void);
57 
58 /*
59  * Timer HW
60  */
timer_clock(void __iomem * base,int ch,int mux,int scl)61 static inline void timer_clock(void __iomem *base, int ch, int mux, int scl)
62 {
63 	u32 val = readl(base + REG_TCFG0) & ~(0xFF << TCFG0_BIT_CH(ch));
64 
65 	writel(val | ((scl - 1) << TCFG0_BIT_CH(ch)), base + REG_TCFG0);
66 	val = readl(base + REG_TCFG1) & ~(0xF << TCFG1_BIT_CH(ch));
67 	writel(val | (mux << TCFG1_BIT_CH(ch)), base + REG_TCFG1);
68 }
69 
timer_count(void __iomem * base,int ch,unsigned int cnt)70 static inline void timer_count(void __iomem *base, int ch, unsigned int cnt)
71 {
72 	writel((cnt - 1), base + REG_TCNTB0 + (TIMER_TCNT_OFFS * ch));
73 	writel((cnt - 1), base + REG_TCMPB0 + (TIMER_TCNT_OFFS * ch));
74 }
75 
timer_start(void __iomem * base,int ch)76 static inline void timer_start(void __iomem *base, int ch)
77 {
78 	int on = 0;
79 	u32 val = readl(base + REG_CSTAT) & ~(TINT_CSTAT_MASK << 5 | 0x1 << ch);
80 
81 	writel(val | (0x1 << TINT_CSTAT_BIT_CH(ch) | on << ch),
82 	       base + REG_CSTAT);
83 	val = readl(base + REG_TCON) & ~(0xE << TCON_BIT_CH(ch));
84 	writel(val | (TCON_BIT_UP << TCON_BIT_CH(ch)), base + REG_TCON);
85 
86 	val &= ~(TCON_BIT_UP << TCON_BIT_CH(ch));
87 	val |= ((TCON_BIT_AUTO | TCON_BIT_RUN) << TCON_BIT_CH(ch));
88 	writel(val, base + REG_TCON);
89 	dmb();
90 }
91 
timer_stop(void __iomem * base,int ch)92 static inline void timer_stop(void __iomem *base, int ch)
93 {
94 	int on = 0;
95 	u32 val = readl(base + REG_CSTAT) & ~(TINT_CSTAT_MASK << 5 | 0x1 << ch);
96 
97 	writel(val | (0x1 << TINT_CSTAT_BIT_CH(ch) | on << ch),
98 	       base + REG_CSTAT);
99 	val = readl(base + REG_TCON) & ~(TCON_BIT_RUN << TCON_BIT_CH(ch));
100 	writel(val, base + REG_TCON);
101 }
102 
timer_read(void __iomem * base,int ch)103 static inline unsigned long timer_read(void __iomem *base, int ch)
104 {
105 	unsigned long ret;
106 
107 	ret = TIMER_COUNT - readl(base + REG_TCNT0 + (TIMER_TCNT_OFFS * ch));
108 	return ret;
109 }
110 
timer_init(void)111 int timer_init(void)
112 {
113 	struct clk *clk = NULL;
114 	char name[16] = "pclk";
115 	int ch = CONFIG_TIMER_SYS_TICK_CH;
116 	unsigned long rate, tclk = 0;
117 	unsigned long mout, thz, cmp = -1UL;
118 	int tcnt, tscl = 0, tmux = 0;
119 	int mux = 0, scl = 0;
120 	void __iomem *base = (void __iomem *)PHY_BASEADDR_TIMER;
121 
122 	if (timerinit)
123 		return 0;
124 
125 	/* get with PCLK */
126 	clk  = clk_get(name);
127 	rate = clk_get_rate(clk);
128 	for (mux = 0; mux < 5; mux++) {
129 		mout = rate / (1 << mux), scl = mout / TIMER_FREQ,
130 		thz = mout / scl;
131 		if (!(mout % TIMER_FREQ) && 256 > scl) {
132 			tclk = thz, tmux = mux, tscl = scl;
133 			break;
134 		}
135 		if (scl > 256)
136 			continue;
137 		if (abs(thz - TIMER_FREQ) >= cmp)
138 			continue;
139 		tclk = thz, tmux = mux, tscl = scl;
140 		cmp = abs(thz - TIMER_FREQ);
141 	}
142 	tcnt = tclk;	/* Timer Count := 1 Mhz counting */
143 
144 	TIMER_FREQ = tcnt;	/* Timer Count := 1 Mhz counting */
145 	TIMER_HZ = TIMER_FREQ / CONFIG_SYS_HZ;
146 	tcnt = TIMER_COUNT == 0xFFFFFFFF ? TIMER_COUNT + 1 : tcnt;
147 
148 	timer_stop(base, ch);
149 	timer_clock(base, ch, tmux, tscl);
150 	timer_count(base, ch, tcnt);
151 	timer_start(base, ch);
152 
153 	reset_timer_masked();
154 	timerinit = 1;
155 
156 	return 0;
157 }
158 
reset_timer(void)159 void reset_timer(void)
160 {
161 	reset_timer_masked();
162 }
163 
get_timer(unsigned long base)164 unsigned long get_timer(unsigned long base)
165 {
166 	long ret;
167 	unsigned long time = get_timer_masked();
168 	unsigned long hz = TIMER_HZ;
169 
170 	ret = time / hz - base;
171 	return ret;
172 }
173 
set_timer(unsigned long t)174 void set_timer(unsigned long t)
175 {
176 	timestamp = (unsigned long)t;
177 }
178 
reset_timer_masked(void)179 void reset_timer_masked(void)
180 {
181 	void __iomem *base = (void __iomem *)PHY_BASEADDR_TIMER;
182 	int ch = CONFIG_TIMER_SYS_TICK_CH;
183 
184 	/* reset time */
185 	/* capure current decrementer value time */
186 	lastdec = timer_read(base, ch);
187 	/* start "advancing" time stamp from 0 */
188 	timestamp = 0;
189 }
190 
get_timer_masked(void)191 unsigned long get_timer_masked(void)
192 {
193 	void __iomem *base = (void __iomem *)PHY_BASEADDR_TIMER;
194 	int ch = CONFIG_TIMER_SYS_TICK_CH;
195 
196 	unsigned long now = timer_read(base, ch); /* current tick value */
197 
198 	if (now >= lastdec) {			  /* normal mode (non roll) */
199 		/* move stamp fordward with absolute diff ticks */
200 		timestamp += now - lastdec;
201 	} else {
202 		/* we have overflow of the count down timer */
203 		/* nts = ts + ld + (TLV - now)
204 		 * ts=old stamp, ld=time that passed before passing through -1
205 		 * (TLV-now) amount of time after passing though -1
206 		 * nts = new "advancing time stamp"...
207 		 * it could also roll and cause problems.
208 		 */
209 		timestamp += now + TIMER_COUNT - lastdec;
210 	}
211 	/* save last */
212 	lastdec = now;
213 
214 	debug("now=%lu, last=%lu, timestamp=%lu\n", now, lastdec, timestamp);
215 	return (unsigned long)timestamp;
216 }
217 
__udelay(unsigned long usec)218 void __udelay(unsigned long usec)
219 {
220 	unsigned long tmo, tmp;
221 
222 	debug("+udelay=%ld\n", usec);
223 
224 	if (!timerinit)
225 		timer_init();
226 
227 	/* if "big" number, spread normalization to seconds */
228 	if (usec >= 1000) {
229 		/* start to normalize for usec to ticks per sec */
230 		tmo  = usec / 1000;
231 		/* find number of "ticks" to wait to achieve target */
232 		tmo *= TIMER_FREQ;
233 		/* finish normalize. */
234 		tmo /= 1000;
235 	/* else small number, don't kill it prior to HZ multiply */
236 	} else {
237 		tmo = usec * TIMER_FREQ;
238 		tmo /= (1000 * 1000);
239 	}
240 
241 	tmp = get_timer_masked();	/* get current timestamp */
242 	debug("A. tmo=%ld, tmp=%ld\n", tmo, tmp);
243 
244 	/* if setting this fordward will roll time stamp */
245 	if (tmp > (tmo + tmp + 1))
246 		/* reset "advancing" timestamp to 0, set lastdec value */
247 		reset_timer_masked();
248 	else
249 		/* set advancing stamp wake up time */
250 		tmo += tmp;
251 
252 	debug("B. tmo=%ld, tmp=%ld\n", tmo, tmp);
253 
254 	/* loop till event */
255 	do {
256 		tmp = get_timer_masked();
257 	} while (tmo > tmp);
258 	debug("-udelay=%ld\n", usec);
259 }
260 
udelay_masked(unsigned long usec)261 void udelay_masked(unsigned long usec)
262 {
263 	unsigned long tmo, endtime;
264 	signed long diff;
265 
266 	/* if "big" number, spread normalization to seconds */
267 	if (usec >= 1000) {
268 		/* start to normalize for usec to ticks per sec */
269 		tmo = usec / 1000;
270 		/* find number of "ticks" to wait to achieve target */
271 		tmo *= TIMER_FREQ;
272 		/* finish normalize. */
273 		tmo /= 1000;
274 	} else { /* else small number, don't kill it prior to HZ multiply */
275 		tmo = usec * TIMER_FREQ;
276 		tmo /= (1000 * 1000);
277 	}
278 
279 	endtime = get_timer_masked() + tmo;
280 
281 	do {
282 		unsigned long now = get_timer_masked();
283 
284 		diff = endtime - now;
285 	} while (diff >= 0);
286 }
287 
get_ticks(void)288 unsigned long long get_ticks(void)
289 {
290 	return get_timer_masked();
291 }
292 
293 #if defined(CONFIG_ARCH_S5P4418)
get_tbclk(void)294 ulong get_tbclk(void)
295 {
296 	ulong  tbclk = TIMER_FREQ;
297 	return tbclk;
298 }
299 #endif
300