xref: /OK3568_Linux_fs/u-boot/arch/arm/cpu/armv7/s5p-common/timer.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright (C) 2009 Samsung Electronics
3*4882a593Smuzhiyun  * Heungjun Kim <riverful.kim@samsung.com>
4*4882a593Smuzhiyun  * Inki Dae <inki.dae@samsung.com>
5*4882a593Smuzhiyun  * Minkyu Kang <mk7.kang@samsung.com>
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <common.h>
11*4882a593Smuzhiyun #include <div64.h>
12*4882a593Smuzhiyun #include <asm/io.h>
13*4882a593Smuzhiyun #include <asm/arch/pwm.h>
14*4882a593Smuzhiyun #include <asm/arch/clk.h>
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun /* Use the old PWM interface for now */
17*4882a593Smuzhiyun #undef CONFIG_DM_PWM
18*4882a593Smuzhiyun #include <pwm.h>
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun unsigned long get_current_tick(void);
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun /* macro to read the 16 bit timer */
s5p_get_base_timer(void)25*4882a593Smuzhiyun static inline struct s5p_timer *s5p_get_base_timer(void)
26*4882a593Smuzhiyun {
27*4882a593Smuzhiyun 	return (struct s5p_timer *)samsung_get_base_timer();
28*4882a593Smuzhiyun }
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun /**
31*4882a593Smuzhiyun  * Read the countdown timer.
32*4882a593Smuzhiyun  *
33*4882a593Smuzhiyun  * This operates at 1MHz and counts downwards. It will wrap about every
34*4882a593Smuzhiyun  * hour (2^32 microseconds).
35*4882a593Smuzhiyun  *
36*4882a593Smuzhiyun  * @return current value of timer
37*4882a593Smuzhiyun  */
timer_get_us_down(void)38*4882a593Smuzhiyun static unsigned long timer_get_us_down(void)
39*4882a593Smuzhiyun {
40*4882a593Smuzhiyun 	struct s5p_timer *const timer = s5p_get_base_timer();
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun 	return readl(&timer->tcnto4);
43*4882a593Smuzhiyun }
44*4882a593Smuzhiyun 
timer_init(void)45*4882a593Smuzhiyun int timer_init(void)
46*4882a593Smuzhiyun {
47*4882a593Smuzhiyun 	/* PWM Timer 4 */
48*4882a593Smuzhiyun 	pwm_init(4, MUX_DIV_4, 0);
49*4882a593Smuzhiyun 	pwm_config(4, 100000, 100000);
50*4882a593Smuzhiyun 	pwm_enable(4);
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 	/* Use this as the current monotonic time in us */
53*4882a593Smuzhiyun 	gd->arch.timer_reset_value = 0;
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 	/* Use this as the last timer value we saw */
56*4882a593Smuzhiyun 	gd->arch.lastinc = timer_get_us_down();
57*4882a593Smuzhiyun 	reset_timer_masked();
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun 	return 0;
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun /*
63*4882a593Smuzhiyun  * timer without interrupts
64*4882a593Smuzhiyun  */
get_timer(unsigned long base)65*4882a593Smuzhiyun unsigned long get_timer(unsigned long base)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun 	unsigned long long time_ms;
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	ulong now = timer_get_us_down();
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun 	/*
72*4882a593Smuzhiyun 	 * Increment the time by the amount elapsed since the last read.
73*4882a593Smuzhiyun 	 * The timer may have wrapped around, but it makes no difference to
74*4882a593Smuzhiyun 	 * our arithmetic here.
75*4882a593Smuzhiyun 	 */
76*4882a593Smuzhiyun 	gd->arch.timer_reset_value += gd->arch.lastinc - now;
77*4882a593Smuzhiyun 	gd->arch.lastinc = now;
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 	/* Divide by 1000 to convert from us to ms */
80*4882a593Smuzhiyun 	time_ms = gd->arch.timer_reset_value;
81*4882a593Smuzhiyun 	do_div(time_ms, 1000);
82*4882a593Smuzhiyun 	return time_ms - base;
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun 
timer_get_us(void)85*4882a593Smuzhiyun unsigned long __attribute__((no_instrument_function)) timer_get_us(void)
86*4882a593Smuzhiyun {
87*4882a593Smuzhiyun 	static unsigned long base_time_us;
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun 	struct s5p_timer *const timer =
90*4882a593Smuzhiyun 		(struct s5p_timer *)samsung_get_base_timer();
91*4882a593Smuzhiyun 	unsigned long now_downward_us = readl(&timer->tcnto4);
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	if (!base_time_us)
94*4882a593Smuzhiyun 		base_time_us = now_downward_us;
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	/* Note that this timer counts downward. */
97*4882a593Smuzhiyun 	return base_time_us - now_downward_us;
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun /* delay x useconds */
__udelay(unsigned long usec)101*4882a593Smuzhiyun void __udelay(unsigned long usec)
102*4882a593Smuzhiyun {
103*4882a593Smuzhiyun 	unsigned long count_value;
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	count_value = timer_get_us_down();
106*4882a593Smuzhiyun 	while ((int)(count_value - timer_get_us_down()) < (int)usec)
107*4882a593Smuzhiyun 		;
108*4882a593Smuzhiyun }
109*4882a593Smuzhiyun 
reset_timer_masked(void)110*4882a593Smuzhiyun void reset_timer_masked(void)
111*4882a593Smuzhiyun {
112*4882a593Smuzhiyun 	struct s5p_timer *const timer = s5p_get_base_timer();
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	/* reset time */
115*4882a593Smuzhiyun 	gd->arch.lastinc = readl(&timer->tcnto4);
116*4882a593Smuzhiyun 	gd->arch.tbl = 0;
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun /*
120*4882a593Smuzhiyun  * This function is derived from PowerPC code (read timebase as long long).
121*4882a593Smuzhiyun  * On ARM it just returns the timer value.
122*4882a593Smuzhiyun  */
get_ticks(void)123*4882a593Smuzhiyun unsigned long long get_ticks(void)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun 	return get_timer(0);
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun /*
129*4882a593Smuzhiyun  * This function is derived from PowerPC code (timebase clock frequency).
130*4882a593Smuzhiyun  * On ARM it returns the number of timer ticks per second.
131*4882a593Smuzhiyun  */
get_tbclk(void)132*4882a593Smuzhiyun unsigned long get_tbclk(void)
133*4882a593Smuzhiyun {
134*4882a593Smuzhiyun 	return CONFIG_SYS_HZ;
135*4882a593Smuzhiyun }
136