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