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