1/* 2 * (C) Copyright 2002 3 * Sysgo Real-Time Solutions, GmbH <www.elinos.com> 4 * Marius Groeger <mgroeger@sysgo.de> 5 * 6 * (C) Copyright 2002 7 * Sysgo Real-Time Solutions, GmbH <www.elinos.com> 8 * Alex Zuepke <azu@sysgo.de> 9 * 10 * (C) Copyright 2002 11 * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de> 12 * 13 * SPDX-License-Identifier: GPL-2.0+ 14 */ 15 16#include <common.h> 17#ifdef CONFIG_S3C24X0 18 19#include <asm/io.h> 20#include <asm/arch/s3c24x0_cpu.h> 21 22DECLARE_GLOBAL_DATA_PTR; 23 24int timer_init(void) 25{ 26 struct s3c24x0_timers *timers = s3c24x0_get_base_timers(); 27 ulong tmr; 28 29 /* use PWM Timer 4 because it has no output */ 30 /* prescaler for Timer 4 is 16 */ 31 writel(0x0f00, &timers->tcfg0); 32 if (gd->arch.tbu == 0) { 33 /* 34 * for 10 ms clock period @ PCLK with 4 bit divider = 1/2 35 * (default) and prescaler = 16. Should be 10390 36 * @33.25MHz and 15625 @ 50 MHz 37 */ 38 gd->arch.tbu = get_PCLK() / (2 * 16 * 100); 39 gd->arch.timer_rate_hz = get_PCLK() / (2 * 16); 40 } 41 /* load value for 10 ms timeout */ 42 writel(gd->arch.tbu, &timers->tcntb4); 43 /* auto load, manual update of timer 4 */ 44 tmr = (readl(&timers->tcon) & ~0x0700000) | 0x0600000; 45 writel(tmr, &timers->tcon); 46 /* auto load, start timer 4 */ 47 tmr = (tmr & ~0x0700000) | 0x0500000; 48 writel(tmr, &timers->tcon); 49 gd->arch.lastinc = 0; 50 gd->arch.tbl = 0; 51 52 return 0; 53} 54 55/* 56 * timer without interrupts 57 */ 58ulong get_timer(ulong base) 59{ 60 return get_timer_masked() - base; 61} 62 63void __udelay (unsigned long usec) 64{ 65 ulong tmo; 66 ulong start = get_ticks(); 67 68 tmo = usec / 1000; 69 tmo *= (gd->arch.tbu * 100); 70 tmo /= 1000; 71 72 while ((ulong) (get_ticks() - start) < tmo) 73 /*NOP*/; 74} 75 76ulong get_timer_masked(void) 77{ 78 ulong tmr = get_ticks(); 79 80 return tmr / (gd->arch.timer_rate_hz / CONFIG_SYS_HZ); 81} 82 83void udelay_masked(unsigned long usec) 84{ 85 ulong tmo; 86 ulong endtime; 87 signed long diff; 88 89 if (usec >= 1000) { 90 tmo = usec / 1000; 91 tmo *= (gd->arch.tbu * 100); 92 tmo /= 1000; 93 } else { 94 tmo = usec * (gd->arch.tbu * 100); 95 tmo /= (1000 * 1000); 96 } 97 98 endtime = get_ticks() + tmo; 99 100 do { 101 ulong now = get_ticks(); 102 diff = endtime - now; 103 } while (diff >= 0); 104} 105 106/* 107 * This function is derived from PowerPC code (read timebase as long long). 108 * On ARM it just returns the timer value. 109 */ 110unsigned long long get_ticks(void) 111{ 112 struct s3c24x0_timers *timers = s3c24x0_get_base_timers(); 113 ulong now = readl(&timers->tcnto4) & 0xffff; 114 115 if (gd->arch.lastinc >= now) { 116 /* normal mode */ 117 gd->arch.tbl += gd->arch.lastinc - now; 118 } else { 119 /* we have an overflow ... */ 120 gd->arch.tbl += gd->arch.lastinc + gd->arch.tbu - now; 121 } 122 gd->arch.lastinc = now; 123 124 return gd->arch.tbl; 125} 126 127/* 128 * This function is derived from PowerPC code (timebase clock frequency). 129 * On ARM it returns the number of timer ticks per second. 130 */ 131ulong get_tbclk(void) 132{ 133 return CONFIG_SYS_HZ; 134} 135 136/* 137 * reset the cpu by setting up the watchdog timer and let him time out 138 */ 139void reset_cpu(ulong ignored) 140{ 141 struct s3c24x0_watchdog *watchdog; 142 143 watchdog = s3c24x0_get_base_watchdog(); 144 145 /* Disable watchdog */ 146 writel(0x0000, &watchdog->wtcon); 147 148 /* Initialize watchdog timer count register */ 149 writel(0x0001, &watchdog->wtcnt); 150 151 /* Enable watchdog timer; assert reset at timer timeout */ 152 writel(0x0021, &watchdog->wtcon); 153 154 while (1) 155 /* loop forever and wait for reset to happen */; 156 157 /*NOTREACHED*/ 158} 159 160#endif /* CONFIG_S3C24X0 */ 161