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