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