From c4b4500910b2dac1dd2e02fb498c059688fb606a Mon Sep 17 00:00:00 2001 From: Scott Branden Date: Mon, 11 Aug 2014 13:58:22 -0700 Subject: arm: iproc: Initial commit of iproc architecture code The iproc architecture code is present in several Broadcom chip architectures, including Cygnus and NSP. Signed-off-by: Scott Branden Signed-off-by: Steve Rae --- arch/arm/cpu/armv7/iproc-common/timer.c | 130 ++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 arch/arm/cpu/armv7/iproc-common/timer.c (limited to 'arch/arm/cpu/armv7/iproc-common/timer.c') diff --git a/arch/arm/cpu/armv7/iproc-common/timer.c b/arch/arm/cpu/armv7/iproc-common/timer.c new file mode 100644 index 0000000000..373d8ec251 --- /dev/null +++ b/arch/arm/cpu/armv7/iproc-common/timer.c @@ -0,0 +1,130 @@ +/* + * Copyright 2014 Broadcom Corporation. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +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; +} -- cgit v1.2.1