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