]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/blackfin/cpu/interrupts.c
Blackfin: use on-chip reset func with newer parts
[karo-tx-uboot.git] / arch / blackfin / cpu / interrupts.c
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  */
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  */
48 ulong get_tbclk(void)
49 {
50         ulong tbclk;
51
52         tbclk = CONFIG_SYS_HZ;
53         return tbclk;
54 }
55
56 void enable_interrupts(void)
57 {
58         local_irq_restore(int_flag);
59 }
60
61 int disable_interrupts(void)
62 {
63         local_irq_save(int_flag);
64         return 1;
65 }
66
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
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  */
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
156 void reset_timer(void)
157 {
158         timer_init();
159 }