1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * (C) Copyright 2002 4 * Sysgo Real-Time Solutions, GmbH <www.elinos.com> 5 * Marius Groeger <mgroeger@sysgo.de> 6 * 7 * (C) Copyright 2002 8 * David Mueller, ELSOFT AG, <d.mueller@elsoft.ch> 9 * 10 * (C) Copyright 2003 11 * Texas Instruments, <www.ti.com> 12 * Kshitij Gupta <Kshitij@ti.com> 13 * 14 * (C) Copyright 2004 15 * ARM Ltd. 16 * Philippe Robin, <philippe.robin@arm.com> 17 */ 18 19#include <common.h> 20#include <div64.h> 21#include <time.h> 22#include <linux/delay.h> 23 24#ifdef CONFIG_ARCH_CINTEGRATOR 25#define DIV_CLOCK_INIT 1 26#define TIMER_LOAD_VAL 0xFFFFFFFFL 27#else 28#define DIV_CLOCK_INIT 256 29#define TIMER_LOAD_VAL 0x0000FFFFL 30#endif 31/* The Integrator/CP timer1 is clocked at 1MHz 32 * can be divided by 16 or 256 33 * and can be set up as a 32-bit timer 34 */ 35/* U-Boot expects a 32 bit timer, running at CONFIG_SYS_HZ */ 36/* Keep total timer count to avoid losing decrements < div_timer */ 37static unsigned long long total_count = 0; 38static unsigned long long lastdec; /* Timer reading at last call */ 39/* Divisor applied to timer clock */ 40static unsigned long long div_clock = DIV_CLOCK_INIT; 41static unsigned long long div_timer = 1; /* Divisor to convert timer reading 42 * change to U-Boot ticks 43 */ 44/* CONFIG_SYS_HZ = CONFIG_SYS_HZ_CLOCK/(div_clock * div_timer) */ 45static ulong timestamp; /* U-Boot ticks since startup */ 46 47#define READ_TIMER (*(volatile ulong *)(CONFIG_SYS_TIMERBASE+4)) 48 49/* all function return values in U-Boot ticks i.e. (1/CONFIG_SYS_HZ) sec 50 * - unless otherwise stated 51 */ 52 53/* starts up a counter 54 * - the Integrator/CP timer can be set up to issue an interrupt */ 55int timer_init (void) 56{ 57 /* Load timer with initial value */ 58 *(volatile ulong *)(CONFIG_SYS_TIMERBASE + 0) = TIMER_LOAD_VAL; 59#ifdef CONFIG_ARCH_CINTEGRATOR 60 /* Set timer to be 61 * enabled 1 62 * periodic 1 63 * no interrupts 0 64 * X 0 65 * divider 1 00 == less rounding error 66 * 32 bit 1 67 * wrapping 0 68 */ 69 *(volatile ulong *)(CONFIG_SYS_TIMERBASE + 8) = 0x000000C2; 70#else 71 /* Set timer to be 72 * enabled 1 73 * free-running 0 74 * XX 00 75 * divider 256 10 76 * XX 00 77 */ 78 *(volatile ulong *)(CONFIG_SYS_TIMERBASE + 8) = 0x00000088; 79#endif 80 81 /* init the timestamp */ 82 total_count = 0ULL; 83 /* capure current decrementer value */ 84 lastdec = READ_TIMER; 85 /* start "advancing" time stamp from 0 */ 86 timestamp = 0L; 87 88 div_timer = CONFIG_SYS_HZ_CLOCK; 89 do_div(div_timer, CONFIG_SYS_HZ); 90 do_div(div_timer, div_clock); 91 92 return (0); 93} 94 95/* 96 * timer without interrupts 97 */ 98 99/* converts the timer reading to U-Boot ticks */ 100/* the timestamp is the number of ticks since reset */ 101static ulong get_timer_masked (void) 102{ 103 /* get current count */ 104 unsigned long long now = READ_TIMER; 105 106 if(now > lastdec) { 107 /* Must have wrapped */ 108 total_count += lastdec + TIMER_LOAD_VAL + 1 - now; 109 } else { 110 total_count += lastdec - now; 111 } 112 lastdec = now; 113 114 /* Reuse "now" */ 115 now = total_count; 116 do_div(now, div_timer); 117 timestamp = now; 118 119 return timestamp; 120} 121 122ulong get_timer (ulong base_ticks) 123{ 124 return get_timer_masked () - base_ticks; 125} 126 127/* delay usec useconds */ 128void __udelay(unsigned long usec) 129{ 130 ulong tmo, tmp; 131 132 /* Convert to U-Boot ticks */ 133 tmo = usec * CONFIG_SYS_HZ; 134 tmo /= (1000000L); 135 136 tmp = get_timer_masked(); /* get current timestamp */ 137 tmo += tmp; /* form target timestamp */ 138 139 while (get_timer_masked () < tmo) {/* loop till event */ 140 /*NOP*/; 141 } 142} 143 144/* 145 * This function is derived from PowerPC code (read timebase as long long). 146 * On ARM it just returns the timer value. 147 */ 148unsigned long long get_ticks(void) 149{ 150 return get_timer(0); 151} 152 153/* 154 * Return the timebase clock frequency 155 * i.e. how often the timer decrements 156 */ 157ulong get_tbclk(void) 158{ 159 unsigned long long tmp = CONFIG_SYS_HZ_CLOCK; 160 161 do_div(tmp, div_clock); 162 163 return tmp; 164} 165