1 /*
2  * U-boot - interrupts.c Interrupt related routines
3  *
4  * Copyright (c) 2005-2008 Analog Devices Inc.
5  *
6  * This file is based on interrupts.c
7  * Copyright 1996 Roman Zippel
8  * Copyright 1999 D. Jeff Dionne <jeff@uclinux.org>
9  * Copyright 2000-2001 Lineo, Inc. D. Jefff Dionne <jeff@lineo.ca>
10  * Copyright 2002 Arcturus Networks Inc. MaTed <mated@sympatico.ca>
11  * Copyright 2003 Metrowerks/Motorola
12  * Copyright 2003 Bas Vermeulen <bas@buyways.nl>,
13  *			BuyWays B.V. (www.buyways.nl)
14  *
15  * (C) Copyright 2000-2004
16  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
17  *
18  * Licensed under the GPL-2 or later.
19  */
20 
21 #include <common.h>
22 #include <config.h>
23 #include <watchdog.h>
24 #include <asm/blackfin.h>
25 #include "cpu.h"
26 
27 static ulong timestamp;
28 static ulong last_time;
29 static int int_flag;
30 
31 int irq_flags;			/* needed by asm-blackfin/system.h */
32 
33 /* Functions just to satisfy the linker */
34 
35 /*
36  * This function is derived from PowerPC code (read timebase as long long).
37  * On Blackfin it just returns the timer value.
38  */
get_ticks(void)39 unsigned long long get_ticks(void)
40 {
41 	return get_timer(0);
42 }
43 
44 /*
45  * This function is derived from PowerPC code (timebase clock frequency).
46  * On Blackfin it returns the number of timer ticks per second.
47  */
get_tbclk(void)48 ulong get_tbclk(void)
49 {
50 	ulong tbclk;
51 
52 	tbclk = CONFIG_SYS_HZ;
53 	return tbclk;
54 }
55 
enable_interrupts(void)56 void enable_interrupts(void)
57 {
58 	local_irq_restore(int_flag);
59 }
60 
disable_interrupts(void)61 int disable_interrupts(void)
62 {
63 	local_irq_save(int_flag);
64 	return 1;
65 }
66 
__udelay(unsigned long usec)67 void __udelay(unsigned long usec)
68 {
69 	unsigned long delay, start, stop;
70 	unsigned long cclk;
71 	cclk = (CONFIG_CCLK_HZ);
72 
73 	while (usec > 1) {
74 		WATCHDOG_RESET();
75 
76 		/*
77 		 * how many clock ticks to delay?
78 		 *  - request(in useconds) * clock_ticks(Hz) / useconds/second
79 		 */
80 		if (usec < 1000) {
81 			delay = (usec * (cclk / 244)) >> 12;
82 			usec = 0;
83 		} else {
84 			delay = (1000 * (cclk / 244)) >> 12;
85 			usec -= 1000;
86 		}
87 
88 		asm volatile (" %0 = CYCLES;" : "=r" (start));
89 		do {
90 			asm volatile (" %0 = CYCLES; " : "=r" (stop));
91 		} while (stop - start < delay);
92 	}
93 
94 	return;
95 }
96 
97 #define MAX_TIM_LOAD	0xFFFFFFFF
timer_init(void)98 int timer_init(void)
99 {
100 	bfin_write_TCNTL(0x1);
101 	CSYNC();
102 	bfin_write_TSCALE(0x0);
103 	bfin_write_TCOUNT(MAX_TIM_LOAD);
104 	bfin_write_TPERIOD(MAX_TIM_LOAD);
105 	bfin_write_TCNTL(0x7);
106 	CSYNC();
107 
108 	timestamp = 0;
109 	last_time = 0;
110 
111 	return 0;
112 }
113 
114 /*
115  * Any network command or flash
116  * command is started get_timer shall
117  * be called before TCOUNT gets reset,
118  * to implement the accurate timeouts.
119  *
120  * How ever milliconds doesn't return
121  * the number that has been elapsed from
122  * the last reset.
123  *
124  * As get_timer is used in the u-boot
125  * only for timeouts this should be
126  * sufficient
127  */
get_timer(ulong base)128 ulong get_timer(ulong base)
129 {
130 	ulong milisec;
131 
132 	/* Number of clocks elapsed */
133 	ulong clocks = (MAX_TIM_LOAD - bfin_read_TCOUNT());
134 
135 	/*
136 	 * Find if the TCOUNT is reset
137 	 * timestamp gives the number of times
138 	 * TCOUNT got reset
139 	 */
140 	if (clocks < last_time)
141 		timestamp++;
142 	last_time = clocks;
143 
144 	/* Get the number of milliseconds */
145 	milisec = clocks / (CONFIG_CCLK_HZ / 1000);
146 
147 	/*
148 	 * Find the number of millisonds that
149 	 * got elapsed before this TCOUNT cycle
150 	 */
151 	milisec += timestamp * (MAX_TIM_LOAD / (CONFIG_CCLK_HZ / 1000));
152 
153 	return (milisec - base);
154 }
155 
reset_timer(void)156 void reset_timer(void)
157 {
158 	timer_init();
159 }
160