1 /* 2 * (C) Copyright 2002 3 * Lineo, Inc. <www.lineo.com> 4 * Bernhard Kuhn <bkuhn@lineo.com> 5 * 6 * (C) Copyright 2002 7 * Sysgo Real-Time Solutions, GmbH <www.elinos.com> 8 * Marius Groeger <mgroeger@sysgo.de> 9 * 10 * (C) Copyright 2002 11 * Sysgo Real-Time Solutions, GmbH <www.elinos.com> 12 * Alex Zuepke <azu@sysgo.de> 13 * 14 * SPDX-License-Identifier: GPL-2.0+ 15 */ 16 17 #include <common.h> 18 19 #include <asm/io.h> 20 #include <asm/arch/hardware.h> 21 #include <asm/arch/at91_tc.h> 22 #include <asm/arch/clk.h> 23 24 DECLARE_GLOBAL_DATA_PTR; 25 26 /* the number of clocks per CONFIG_SYS_HZ */ 27 #define TIMER_LOAD_VAL (CONFIG_SYS_HZ_CLOCK/CONFIG_SYS_HZ) 28 29 int timer_init(void) 30 { 31 at91_tc_t *tc = (at91_tc_t *) ATMEL_BASE_TC; 32 33 at91_periph_clk_enable(ATMEL_ID_TC0); 34 35 writel(0, &tc->bcr); 36 writel(AT91_TC_BMR_TC0XC0S_NONE | AT91_TC_BMR_TC1XC1S_NONE | 37 AT91_TC_BMR_TC2XC2S_NONE , &tc->bmr); 38 39 writel(AT91_TC_CCR_CLKDIS, &tc->tc[0].ccr); 40 /* set to MCLK/2 and restart the timer 41 when the value in TC_RC is reached */ 42 writel(AT91_TC_CMR_TCCLKS_CLOCK1 | AT91_TC_CMR_CPCTRG, &tc->tc[0].cmr); 43 44 writel(0xFFFFFFFF, &tc->tc[0].idr); /* disable interrupts */ 45 writel(TIMER_LOAD_VAL, &tc->tc[0].rc); 46 47 writel(AT91_TC_CCR_SWTRG | AT91_TC_CCR_CLKEN, &tc->tc[0].ccr); 48 gd->arch.lastinc = 0; 49 gd->arch.tbl = 0; 50 51 return 0; 52 } 53 54 /* 55 * timer without interrupts 56 */ 57 ulong get_timer(ulong base) 58 { 59 return get_timer_masked() - base; 60 } 61 62 void __udelay(unsigned long usec) 63 { 64 udelay_masked(usec); 65 } 66 67 ulong get_timer_raw(void) 68 { 69 at91_tc_t *tc = (at91_tc_t *) ATMEL_BASE_TC; 70 u32 now; 71 72 now = readl(&tc->tc[0].cv) & 0x0000ffff; 73 74 if (now >= gd->arch.lastinc) { 75 /* normal mode */ 76 gd->arch.tbl += now - gd->arch.lastinc; 77 } else { 78 /* we have an overflow ... */ 79 gd->arch.tbl += now + TIMER_LOAD_VAL - gd->arch.lastinc; 80 } 81 gd->arch.lastinc = now; 82 83 return gd->arch.tbl; 84 } 85 86 ulong get_timer_masked(void) 87 { 88 return get_timer_raw()/TIMER_LOAD_VAL; 89 } 90 91 void udelay_masked(unsigned long usec) 92 { 93 u32 tmo; 94 u32 endtime; 95 signed long diff; 96 97 tmo = CONFIG_SYS_HZ_CLOCK / 1000; 98 tmo *= usec; 99 tmo /= 1000; 100 101 endtime = get_timer_raw() + tmo; 102 103 do { 104 u32 now = get_timer_raw(); 105 diff = endtime - now; 106 } while (diff >= 0); 107 } 108 109 /* 110 * This function is derived from PowerPC code (read timebase as long long). 111 * On ARM it just returns the timer value. 112 */ 113 unsigned long long get_ticks(void) 114 { 115 return get_timer(0); 116 } 117 118 /* 119 * This function is derived from PowerPC code (timebase clock frequency). 120 * On ARM it returns the number of timer ticks per second. 121 */ 122 ulong get_tbclk(void) 123 { 124 return CONFIG_SYS_HZ; 125 } 126