1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (C) 2010 Albert ARIBAUD <albert.u.boot@aribaud.net> 4 * 5 * Based on original Kirkwood support which is 6 * Copyright (C) Marvell International Ltd. and its affiliates 7 * Written-by: Prafulla Wadaskar <prafulla@marvell.com> 8 */ 9 10#include <common.h> 11#include <init.h> 12#include <time.h> 13#include <asm/global_data.h> 14#include <asm/io.h> 15#include <linux/delay.h> 16 17#define UBOOT_CNTR 0 /* counter to use for uboot timer */ 18 19/* Timer reload and current value registers */ 20struct orion5x_tmr_val { 21 u32 reload; /* Timer reload reg */ 22 u32 val; /* Timer value reg */ 23}; 24 25/* Timer registers */ 26struct orion5x_tmr_registers { 27 u32 ctrl; /* Timer control reg */ 28 u32 pad[3]; 29 struct orion5x_tmr_val tmr[2]; 30 u32 wdt_reload; 31 u32 wdt_val; 32}; 33 34struct orion5x_tmr_registers *orion5x_tmr_regs = 35 (struct orion5x_tmr_registers *)ORION5X_TIMER_BASE; 36 37/* 38 * ARM Timers Registers Map 39 */ 40#define CNTMR_CTRL_REG (&orion5x_tmr_regs->ctrl) 41#define CNTMR_RELOAD_REG(tmrnum) (&orion5x_tmr_regs->tmr[tmrnum].reload) 42#define CNTMR_VAL_REG(tmrnum) (&orion5x_tmr_regs->tmr[tmrnum].val) 43 44/* 45 * ARM Timers Control Register 46 * CPU_TIMERS_CTRL_REG (CTCR) 47 */ 48#define CTCR_ARM_TIMER_EN_OFFS(cntr) (cntr * 2) 49#define CTCR_ARM_TIMER_EN_MASK(cntr) (1 << CTCR_ARM_TIMER_EN_OFFS) 50#define CTCR_ARM_TIMER_EN(cntr) (1 << CTCR_ARM_TIMER_EN_OFFS(cntr)) 51#define CTCR_ARM_TIMER_DIS(cntr) (0 << CTCR_ARM_TIMER_EN_OFFS(cntr)) 52 53#define CTCR_ARM_TIMER_AUTO_OFFS(cntr) ((cntr * 2) + 1) 54#define CTCR_ARM_TIMER_AUTO_MASK(cntr) (1 << 1) 55#define CTCR_ARM_TIMER_AUTO_EN(cntr) (1 << CTCR_ARM_TIMER_AUTO_OFFS(cntr)) 56#define CTCR_ARM_TIMER_AUTO_DIS(cntr) (0 << CTCR_ARM_TIMER_AUTO_OFFS(cntr)) 57 58/* 59 * ARM Timer\Watchdog Reload Register 60 * CNTMR_RELOAD_REG (TRR) 61 */ 62#define TRG_ARM_TIMER_REL_OFFS 0 63#define TRG_ARM_TIMER_REL_MASK 0xffffffff 64 65/* 66 * ARM Timer\Watchdog Register 67 * CNTMR_VAL_REG (TVRG) 68 */ 69#define TVR_ARM_TIMER_OFFS 0 70#define TVR_ARM_TIMER_MASK 0xffffffff 71#define TVR_ARM_TIMER_MAX 0xffffffff 72#define TIMER_LOAD_VAL 0xffffffff 73 74static inline ulong read_timer(void) 75{ 76 return readl(CNTMR_VAL_REG(UBOOT_CNTR)) 77 / (CONFIG_SYS_TCLK / 1000); 78} 79 80DECLARE_GLOBAL_DATA_PTR; 81 82#define timestamp gd->arch.tbl 83#define lastdec gd->arch.lastinc 84 85static ulong get_timer_masked(void) 86{ 87 ulong now = read_timer(); 88 89 if (lastdec >= now) { 90 /* normal mode */ 91 timestamp += lastdec - now; 92 } else { 93 /* we have an overflow ... */ 94 timestamp += lastdec + 95 (TIMER_LOAD_VAL / (CONFIG_SYS_TCLK / 1000)) - now; 96 } 97 lastdec = now; 98 99 return timestamp; 100} 101 102ulong get_timer(ulong base) 103{ 104 return get_timer_masked() - base; 105} 106 107static inline ulong uboot_cntr_val(void) 108{ 109 return readl(CNTMR_VAL_REG(UBOOT_CNTR)); 110} 111 112void __udelay(unsigned long usec) 113{ 114 uint current; 115 ulong delayticks; 116 117 current = uboot_cntr_val(); 118 delayticks = (usec * (CONFIG_SYS_TCLK / 1000000)); 119 120 if (current < delayticks) { 121 delayticks -= current; 122 while (uboot_cntr_val() < current) 123 ; 124 while ((TIMER_LOAD_VAL - delayticks) < uboot_cntr_val()) 125 ; 126 } else { 127 while (uboot_cntr_val() > (current - delayticks)) 128 ; 129 } 130} 131 132/* 133 * init the counter 134 */ 135int timer_init(void) 136{ 137 unsigned int cntmrctrl; 138 139 /* load value into timer */ 140 writel(TIMER_LOAD_VAL, CNTMR_RELOAD_REG(UBOOT_CNTR)); 141 writel(TIMER_LOAD_VAL, CNTMR_VAL_REG(UBOOT_CNTR)); 142 143 /* enable timer in auto reload mode */ 144 cntmrctrl = readl(CNTMR_CTRL_REG); 145 cntmrctrl |= CTCR_ARM_TIMER_EN(UBOOT_CNTR); 146 cntmrctrl |= CTCR_ARM_TIMER_AUTO_EN(UBOOT_CNTR); 147 writel(cntmrctrl, CNTMR_CTRL_REG); 148 return 0; 149} 150 151void timer_init_r(void) 152{ 153 /* init the timestamp and lastdec value */ 154 lastdec = read_timer(); 155 timestamp = 0; 156} 157 158/* 159 * This function is derived from PowerPC code (read timebase as long long). 160 * On ARM it just returns the timer value. 161 */ 162unsigned long long get_ticks(void) 163{ 164 return get_timer(0); 165} 166 167/* 168 * This function is derived from PowerPC code (timebase clock frequency). 169 * On ARM it returns the number of timer ticks per second. 170 */ 171ulong get_tbclk(void) 172{ 173 return (ulong)CONFIG_SYS_HZ; 174} 175