xref: /rk3399_rockchip-uboot/arch/arm/cpu/armv7/iproc-common/timer.c (revision c4b4500910b2dac1dd2e02fb498c059688fb606a)
1*c4b45009SScott Branden /*
2*c4b45009SScott Branden  * Copyright 2014 Broadcom Corporation.
3*c4b45009SScott Branden  *
4*c4b45009SScott Branden  * SPDX-License-Identifier:	GPL-2.0+
5*c4b45009SScott Branden  */
6*c4b45009SScott Branden 
7*c4b45009SScott Branden #include <common.h>
8*c4b45009SScott Branden #include <div64.h>
9*c4b45009SScott Branden #include <asm/io.h>
10*c4b45009SScott Branden #include <asm/iproc-common/timer.h>
11*c4b45009SScott Branden #include <asm/iproc-common/sysmap.h>
12*c4b45009SScott Branden 
timer_global_read(void)13*c4b45009SScott Branden static inline uint64_t timer_global_read(void)
14*c4b45009SScott Branden {
15*c4b45009SScott Branden 	uint64_t cur_tick;
16*c4b45009SScott Branden 	uint32_t count_h;
17*c4b45009SScott Branden 	uint32_t count_l;
18*c4b45009SScott Branden 
19*c4b45009SScott Branden 	do {
20*c4b45009SScott Branden 		count_h = readl(IPROC_PERIPH_GLB_TIM_REG_BASE +
21*c4b45009SScott Branden 				TIMER_GLB_HI_OFFSET);
22*c4b45009SScott Branden 		count_l = readl(IPROC_PERIPH_GLB_TIM_REG_BASE +
23*c4b45009SScott Branden 				TIMER_GLB_LOW_OFFSET);
24*c4b45009SScott Branden 		cur_tick = readl(IPROC_PERIPH_GLB_TIM_REG_BASE +
25*c4b45009SScott Branden 				 TIMER_GLB_HI_OFFSET);
26*c4b45009SScott Branden 	} while (cur_tick != count_h);
27*c4b45009SScott Branden 
28*c4b45009SScott Branden 	return (cur_tick << 32) + count_l;
29*c4b45009SScott Branden }
30*c4b45009SScott Branden 
timer_global_init(void)31*c4b45009SScott Branden void timer_global_init(void)
32*c4b45009SScott Branden {
33*c4b45009SScott Branden 	writel(0, IPROC_PERIPH_GLB_TIM_REG_BASE + TIMER_GLB_CTRL_OFFSET);
34*c4b45009SScott Branden 	writel(0, IPROC_PERIPH_GLB_TIM_REG_BASE + TIMER_GLB_LOW_OFFSET);
35*c4b45009SScott Branden 	writel(0, IPROC_PERIPH_GLB_TIM_REG_BASE + TIMER_GLB_HI_OFFSET);
36*c4b45009SScott Branden 	writel(TIMER_GLB_TIM_CTRL_TIM_EN,
37*c4b45009SScott Branden 	       IPROC_PERIPH_GLB_TIM_REG_BASE + TIMER_GLB_CTRL_OFFSET);
38*c4b45009SScott Branden }
39*c4b45009SScott Branden 
timer_init(void)40*c4b45009SScott Branden int timer_init(void)
41*c4b45009SScott Branden {
42*c4b45009SScott Branden 	timer_global_init();
43*c4b45009SScott Branden 	return 0;
44*c4b45009SScott Branden }
45*c4b45009SScott Branden 
get_timer(unsigned long base)46*c4b45009SScott Branden unsigned long get_timer(unsigned long base)
47*c4b45009SScott Branden {
48*c4b45009SScott Branden 	uint64_t count;
49*c4b45009SScott Branden 	uint64_t ret;
50*c4b45009SScott Branden 	uint64_t tim_clk;
51*c4b45009SScott Branden 	uint64_t periph_clk;
52*c4b45009SScott Branden 
53*c4b45009SScott Branden 	count = timer_global_read();
54*c4b45009SScott Branden 
55*c4b45009SScott Branden 	/* default arm clk is 1GHz, periph_clk=arm_clk/2, tick per msec */
56*c4b45009SScott Branden 	periph_clk = 500000;
57*c4b45009SScott Branden 	tim_clk = lldiv(periph_clk,
58*c4b45009SScott Branden 			(((readl(IPROC_PERIPH_GLB_TIM_REG_BASE +
59*c4b45009SScott Branden 				 TIMER_GLB_CTRL_OFFSET) &
60*c4b45009SScott Branden 			TIMER_GLB_TIM_CTRL_PRESC_MASK) >> 8) + 1));
61*c4b45009SScott Branden 
62*c4b45009SScott Branden 	ret = lldiv(count, (uint32_t)tim_clk);
63*c4b45009SScott Branden 
64*c4b45009SScott Branden 	/* returns msec */
65*c4b45009SScott Branden 	return ret - base;
66*c4b45009SScott Branden }
67*c4b45009SScott Branden 
__udelay(unsigned long usec)68*c4b45009SScott Branden void __udelay(unsigned long usec)
69*c4b45009SScott Branden {
70*c4b45009SScott Branden 	uint64_t cur_tick, end_tick;
71*c4b45009SScott Branden 	uint64_t tim_clk;
72*c4b45009SScott Branden 	uint64_t periph_clk;
73*c4b45009SScott Branden 
74*c4b45009SScott Branden 	/* default arm clk is 1GHz, periph_clk=arm_clk/2, tick per usec */
75*c4b45009SScott Branden 	periph_clk = 500;
76*c4b45009SScott Branden 
77*c4b45009SScott Branden 	tim_clk = lldiv(periph_clk,
78*c4b45009SScott Branden 			(((readl(IPROC_PERIPH_GLB_TIM_REG_BASE +
79*c4b45009SScott Branden 				 TIMER_GLB_CTRL_OFFSET) &
80*c4b45009SScott Branden 			TIMER_GLB_TIM_CTRL_PRESC_MASK) >> 8) + 1));
81*c4b45009SScott Branden 
82*c4b45009SScott Branden 	cur_tick = timer_global_read();
83*c4b45009SScott Branden 
84*c4b45009SScott Branden 	end_tick = tim_clk;
85*c4b45009SScott Branden 	end_tick *= usec;
86*c4b45009SScott Branden 	end_tick += cur_tick;
87*c4b45009SScott Branden 
88*c4b45009SScott Branden 	do {
89*c4b45009SScott Branden 		cur_tick = timer_global_read();
90*c4b45009SScott Branden 
91*c4b45009SScott Branden 	} while (cur_tick < end_tick);
92*c4b45009SScott Branden }
93*c4b45009SScott Branden 
timer_systick_init(uint32_t tick_ms)94*c4b45009SScott Branden void timer_systick_init(uint32_t tick_ms)
95*c4b45009SScott Branden {
96*c4b45009SScott Branden 	/* Disable timer and clear interrupt status*/
97*c4b45009SScott Branden 	writel(0, IPROC_PERIPH_PVT_TIM_REG_BASE + TIMER_PVT_CTRL_OFFSET);
98*c4b45009SScott Branden 	writel(TIMER_PVT_TIM_INT_STATUS_SET,
99*c4b45009SScott Branden 	       IPROC_PERIPH_PVT_TIM_REG_BASE + TIMER_PVT_STATUS_OFFSET);
100*c4b45009SScott Branden 	writel((PLL_AXI_CLK/1000) * tick_ms,
101*c4b45009SScott Branden 	       IPROC_PERIPH_PVT_TIM_REG_BASE + TIMER_PVT_LOAD_OFFSET);
102*c4b45009SScott Branden 	writel(TIMER_PVT_TIM_CTRL_INT_EN |
103*c4b45009SScott Branden 	       TIMER_PVT_TIM_CTRL_AUTO_RELD |
104*c4b45009SScott Branden 	       TIMER_PVT_TIM_CTRL_TIM_EN,
105*c4b45009SScott Branden 	       IPROC_PERIPH_PVT_TIM_REG_BASE + TIMER_PVT_CTRL_OFFSET);
106*c4b45009SScott Branden }
107*c4b45009SScott Branden 
timer_systick_isr(void * data)108*c4b45009SScott Branden void timer_systick_isr(void *data)
109*c4b45009SScott Branden {
110*c4b45009SScott Branden 	writel(TIMER_PVT_TIM_INT_STATUS_SET,
111*c4b45009SScott Branden 	       IPROC_PERIPH_PVT_TIM_REG_BASE + TIMER_PVT_STATUS_OFFSET);
112*c4b45009SScott Branden }
113*c4b45009SScott Branden 
114*c4b45009SScott Branden /*
115*c4b45009SScott Branden  * This function is derived from PowerPC code (read timebase as long long).
116*c4b45009SScott Branden  * On ARM it just returns the timer value in msec.
117*c4b45009SScott Branden  */
get_ticks(void)118*c4b45009SScott Branden unsigned long long get_ticks(void)
119*c4b45009SScott Branden {
120*c4b45009SScott Branden 	return get_timer(0);
121*c4b45009SScott Branden }
122*c4b45009SScott Branden 
123*c4b45009SScott Branden /*
124*c4b45009SScott Branden  * This is used in conjuction with get_ticks, which returns msec as ticks.
125*c4b45009SScott Branden  * Here we just return ticks/sec = msec/sec = 1000
126*c4b45009SScott Branden  */
get_tbclk(void)127*c4b45009SScott Branden ulong get_tbclk(void)
128*c4b45009SScott Branden {
129*c4b45009SScott Branden 	return 1000;
130*c4b45009SScott Branden }
131