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