]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - cpu/arm925t/interrupts.c
Add support for Siemens SX1 mobile phone;
[karo-tx-uboot.git] / cpu / arm925t / interrupts.c
1 /*
2  * (C) Copyright 2003
3  * Texas Instruments, <www.ti.com>
4  *
5  * (C) Copyright 2002
6  * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
7  * Marius Groeger <mgroeger@sysgo.de>
8  *
9  * (C) Copyright 2002
10  * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
11  * Alex Zuepke <azu@sysgo.de>
12  *
13  * (C) Copyright 2002
14  * Gary Jennejohn, DENX Software Engineering, <gj@denx.de>
15  *
16  * See file CREDITS for list of people who contributed to this
17  * project.
18  *
19  * This program is free software; you can redistribute it and/or
20  * modify it under the terms of the GNU General Public License as
21  * published by the Free Software Foundation; either version 2 of
22  * the License, or (at your option) any later version.
23  *
24  * This program is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27  * GNU General Public License for more details.
28  *
29  * You should have received a copy of the GNU General Public License
30  * along with this program; if not, write to the Free Software
31  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
32  * MA 02111-1307 USA
33  */
34
35 #include <common.h>
36 #include <arm925t.h>
37 #include <configs/omap1510.h>
38
39 #include <asm/proc-armv/ptrace.h>
40
41 extern void reset_cpu(ulong addr);
42 #define TIMER_LOAD_VAL 0xffffffff
43
44 /* macro to read the 32 bit timer */
45 #define READ_TIMER (*(volatile ulong *)(CFG_TIMERBASE+8))
46
47 #ifdef CONFIG_USE_IRQ
48 /* enable IRQ interrupts */
49 void enable_interrupts (void)
50 {
51         unsigned long temp;
52         __asm__ __volatile__("mrs %0, cpsr\n"
53                              "bic %0, %0, #0x80\n"
54                              "msr cpsr_c, %0"
55                              : "=r" (temp)
56                              :
57                              : "memory");
58 }
59
60
61 /*
62  * disable IRQ/FIQ interrupts
63  * returns true if interrupts had been enabled before we disabled them
64  */
65 int disable_interrupts (void)
66 {
67         unsigned long old,temp;
68         __asm__ __volatile__("mrs %0, cpsr\n"
69                              "orr %1, %0, #0xc0\n"
70                              "msr cpsr_c, %1"
71                              : "=r" (old), "=r" (temp)
72                              :
73                              : "memory");
74         return (old & 0x80) == 0;
75 }
76 #else
77 void enable_interrupts (void)
78 {
79         return;
80 }
81 int disable_interrupts (void)
82 {
83         return 0;
84 }
85 #endif
86
87
88 void bad_mode (void)
89 {
90         panic ("Resetting CPU ...\n");
91         reset_cpu (0);
92 }
93
94 void show_regs (struct pt_regs *regs)
95 {
96         unsigned long flags;
97         const char *processor_modes[] = {
98         "USER_26",      "FIQ_26",       "IRQ_26",       "SVC_26",
99         "UK4_26",       "UK5_26",       "UK6_26",       "UK7_26",
100         "UK8_26",       "UK9_26",       "UK10_26",      "UK11_26",
101         "UK12_26",      "UK13_26",      "UK14_26",      "UK15_26",
102         "USER_32",      "FIQ_32",       "IRQ_32",       "SVC_32",
103         "UK4_32",       "UK5_32",       "UK6_32",       "ABT_32",
104         "UK8_32",       "UK9_32",       "UK10_32",      "UND_32",
105         "UK12_32",      "UK13_32",      "UK14_32",      "SYS_32",
106         };
107
108         flags = condition_codes (regs);
109
110         printf ("pc : [<%08lx>]    lr : [<%08lx>]\n"
111                 "sp : %08lx  ip : %08lx  fp : %08lx\n",
112                 instruction_pointer (regs),
113                 regs->ARM_lr, regs->ARM_sp, regs->ARM_ip, regs->ARM_fp);
114         printf ("r10: %08lx  r9 : %08lx  r8 : %08lx\n",
115                 regs->ARM_r10, regs->ARM_r9, regs->ARM_r8);
116         printf ("r7 : %08lx  r6 : %08lx  r5 : %08lx  r4 : %08lx\n",
117                 regs->ARM_r7, regs->ARM_r6, regs->ARM_r5, regs->ARM_r4);
118         printf ("r3 : %08lx  r2 : %08lx  r1 : %08lx  r0 : %08lx\n",
119                 regs->ARM_r3, regs->ARM_r2, regs->ARM_r1, regs->ARM_r0);
120         printf ("Flags: %c%c%c%c",
121                 flags & CC_N_BIT ? 'N' : 'n',
122                 flags & CC_Z_BIT ? 'Z' : 'z',
123                 flags & CC_C_BIT ? 'C' : 'c', flags & CC_V_BIT ? 'V' : 'v');
124         printf ("  IRQs %s  FIQs %s  Mode %s%s\n",
125                 interrupts_enabled (regs) ? "on" : "off",
126                 fast_interrupts_enabled (regs) ? "on" : "off",
127                 processor_modes[processor_mode (regs)],
128                 thumb_mode (regs) ? " (T)" : "");
129 }
130
131 void do_undefined_instruction (struct pt_regs *pt_regs)
132 {
133         printf ("undefined instruction\n");
134         show_regs (pt_regs);
135         bad_mode ();
136 }
137
138 void do_software_interrupt (struct pt_regs *pt_regs)
139 {
140         printf ("software interrupt\n");
141         show_regs (pt_regs);
142         bad_mode ();
143 }
144
145 void do_prefetch_abort (struct pt_regs *pt_regs)
146 {
147         printf ("prefetch abort\n");
148         show_regs (pt_regs);
149         bad_mode ();
150 }
151
152 void do_data_abort (struct pt_regs *pt_regs)
153 {
154         printf ("data abort\n");
155         show_regs (pt_regs);
156         bad_mode ();
157 }
158
159 void do_not_used (struct pt_regs *pt_regs)
160 {
161         printf ("not used\n");
162         show_regs (pt_regs);
163         bad_mode ();
164 }
165
166 void do_fiq (struct pt_regs *pt_regs)
167 {
168         printf ("fast interrupt request\n");
169         show_regs (pt_regs);
170         bad_mode ();
171 }
172
173 void do_irq (struct pt_regs *pt_regs)
174 {
175         printf ("interrupt request\n");
176         show_regs (pt_regs);
177         bad_mode ();
178 }
179
180 static ulong timestamp;
181 static ulong lastdec;
182
183 /* nothing really to do with interrupts, just starts up a counter. */
184 int interrupt_init (void)
185 {
186         int32_t val;
187
188         /* Start the decrementer ticking down from 0xffffffff */
189         *((int32_t *) (CFG_TIMERBASE + LOAD_TIM)) = TIMER_LOAD_VAL;
190         val = MPUTIM_ST | MPUTIM_AR | MPUTIM_CLOCK_ENABLE | (CFG_PVT << MPUTIM_PTV_BIT);
191         *((int32_t *) (CFG_TIMERBASE + CNTL_TIMER)) = val;
192
193         /* init the timestamp and lastdec value */
194         reset_timer_masked();
195
196         return (0);
197 }
198
199 /*
200  * timer without interrupts
201  */
202
203 void reset_timer (void)
204 {
205         reset_timer_masked ();
206 }
207
208 ulong get_timer (ulong base)
209 {
210         return get_timer_masked () - base;
211 }
212
213 void set_timer (ulong t)
214 {
215         timestamp = t;
216 }
217
218 /* delay x useconds AND perserve advance timstamp value */
219 void udelay (unsigned long usec)
220 {
221 #ifdef CONFIG_INNOVATOROMAP1510
222 #define LOOPS_PER_MSEC 60               /* tuned on omap1510 */
223         volatile int i, time_remaining = LOOPS_PER_MSEC * usec;
224
225         for (i = time_remaining; i > 0; i--) {
226         }
227 #else
228         ulong tmo, tmp;
229
230         if(usec >= 1000){               /* if "big" number, spread normalization to seconds */
231                 tmo = usec / 1000;      /* start to normalize for usec to ticks per sec */
232                 tmo *= CFG_HZ;          /* find number of "ticks" to wait to achieve target */
233                 tmo /= 1000;            /* finish normalize. */
234         }else{                          /* else small number, don't kill it prior to HZ multiply */
235                 tmo = usec * CFG_HZ;
236                 tmo /= (1000*1000);
237         }
238
239         tmp = get_timer (0);            /* get current timestamp */
240         if( (tmo + tmp + 1) < tmp )     /* if setting this fordward will roll time stamp */
241                 reset_timer_masked ();  /* reset "advancing" timestamp to 0, set lastdec value */
242         else
243                 tmo += tmp;             /* else, set advancing stamp wake up time */
244
245         while (get_timer_masked () < tmo)/* loop till event */
246                 /*NOP*/;
247 #endif
248 }
249
250 void reset_timer_masked (void)
251 {
252         /* reset time */
253         lastdec = READ_TIMER;  /* capure current decrementer value time */
254         timestamp = 0;         /* start "advancing" time stamp from 0 */
255 }
256
257 ulong get_timer_masked (void)
258 {
259         ulong now = READ_TIMER;         /* current tick value */
260
261         if (lastdec >= now) {           /* normal mode (non roll) */
262                 /* normal mode */
263                 timestamp += lastdec - now; /* move stamp fordward with absoulte diff ticks */
264         } else {                        /* we have overflow of the count down timer */
265                 /* nts = ts + ld + (TLV - now)
266                  * ts=old stamp, ld=time that passed before passing through -1
267                  * (TLV-now) amount of time after passing though -1
268                  * nts = new "advancing time stamp"...it could also roll and cause problems.
269                  */
270                 timestamp += lastdec + TIMER_LOAD_VAL - now;
271         }
272         lastdec = now;
273
274         return timestamp;
275 }
276
277 /* waits specified delay value and resets timestamp */
278 void udelay_masked (unsigned long usec)
279 {
280 #ifdef CONFIG_INNOVATOROMAP1510
281         #define LOOPS_PER_MSEC 60 /* tuned on omap1510 */
282         volatile int i, time_remaining = LOOPS_PER_MSEC*usec;
283     for (i=time_remaining; i>0; i--) { }
284 #else
285
286         ulong tmo;
287
288         if(usec >= 1000){               /* if "big" number, spread normalization to seconds */
289                 tmo = usec / 1000;      /* start to normalize for usec to ticks per sec */
290                 tmo *= CFG_HZ;          /* find number of "ticks" to wait to achieve target */
291                 tmo /= 1000;            /* finish normalize. */
292         }else{                          /* else small number, don't kill it prior to HZ multiply */
293                 tmo = usec * CFG_HZ;
294                 tmo /= (1000*1000);
295         }
296
297         reset_timer_masked ();  /* set "advancing" timestamp to 0, set lastdec vaule */
298
299         while (get_timer_masked () < tmo) /* wait for time stamp to overtake tick number.*/
300                 /*NOP*/;
301 #endif
302 }
303
304 /*
305  * This function is derived from PowerPC code (read timebase as long long).
306  * On ARM it just returns the timer value.
307  */
308 unsigned long long get_ticks(void)
309 {
310         return get_timer(0);
311 }
312
313 /*
314  * This function is derived from PowerPC code (timebase clock frequency).
315  * On ARM it returns the number of timer ticks per second.
316  */
317 ulong get_tbclk (void)
318 {
319         ulong tbclk;
320
321         tbclk = CFG_HZ;
322         return tbclk;
323 }