blob: 3817f19d53521e5c96fa7e5a121a031eab83353e [file] [log] [blame]
Jon Loeliger5c8aa972006-04-26 17:58:56 -05001/*
Jon Loeliger11c99582007-08-02 14:42:20 -05002 * Copyright 2004, 2007 Freescale Semiconductor.
Jon Loeliger5c8aa972006-04-26 17:58:56 -05003 * Srikanth Srinivasan <srikanth.srinivaan@freescale.com>
4 *
5 * See file CREDITS for list of people who contributed to this
6 * project.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 */
23
24/* U-Boot - Startup Code for 86xx PowerPC based Embedded Boards
25 *
26 *
27 * The processor starts at 0xfff00100 and the code is executed
28 * from flash. The code is organized to be at an other address
29 * in memory, but as long we don't jump around before relocating.
30 * board_init lies at a quite high address and when the cpu has
31 * jumped there, everything is ok.
32 */
33#include <config.h>
34#include <mpc86xx.h>
Peter Tyser62948502008-11-03 09:30:59 -060035#include <timestamp.h>
Jon Loeliger5c8aa972006-04-26 17:58:56 -050036#include <version.h>
37
38#include <ppc_asm.tmpl>
39#include <ppc_defs.h>
40
41#include <asm/cache.h>
42#include <asm/mmu.h>
Peter Tyser3a1362d2010-10-14 23:33:24 -050043#include <asm/u-boot.h>
Jon Loeliger5c8aa972006-04-26 17:58:56 -050044
Wolfgang Denkd46f6e72006-10-24 15:32:57 +020045#ifndef CONFIG_IDENT_STRING
46#define CONFIG_IDENT_STRING ""
Jon Loeliger5c8aa972006-04-26 17:58:56 -050047#endif
48
Jon Loeliger11c99582007-08-02 14:42:20 -050049/*
50 * Need MSR_DR | MSR_IR enabled to access I/O (printf) in exceptions
51 */
Jon Loeliger5c8aa972006-04-26 17:58:56 -050052
53/*
54 * Set up GOT: Global Offset Table
55 *
Joakim Tjernlund3fbaa4d2010-01-19 14:41:56 +010056 * Use r12 to access the GOT
Jon Loeliger5c8aa972006-04-26 17:58:56 -050057 */
58 START_GOT
59 GOT_ENTRY(_GOT2_TABLE_)
60 GOT_ENTRY(_FIXUP_TABLE_)
61
62 GOT_ENTRY(_start)
63 GOT_ENTRY(_start_of_vectors)
64 GOT_ENTRY(_end_of_vectors)
65 GOT_ENTRY(transfer_to_handler)
66
67 GOT_ENTRY(__init_end)
68 GOT_ENTRY(_end)
69 GOT_ENTRY(__bss_start)
70 END_GOT
71
72/*
73 * r3 - 1st arg to board_init(): IMMP pointer
74 * r4 - 2nd arg to board_init(): boot flag
75 */
76 .text
Jon Loeligera1295442006-08-22 12:06:18 -050077 .long 0x27051956 /* U-Boot Magic Number */
Jon Loeliger5c8aa972006-04-26 17:58:56 -050078 .globl version_string
79version_string:
80 .ascii U_BOOT_VERSION
Peter Tyser62948502008-11-03 09:30:59 -060081 .ascii " (", U_BOOT_DATE, " - ", U_BOOT_TIME, ")"
Jon Loeliger5c8aa972006-04-26 17:58:56 -050082 .ascii CONFIG_IDENT_STRING, "\0"
83
84 . = EXC_OFF_SYS_RESET
85 .globl _start
86_start:
Jon Loeliger5c8aa972006-04-26 17:58:56 -050087 b boot_cold
Jon Loeliger5c8aa972006-04-26 17:58:56 -050088
89 /* the boot code is located below the exception table */
90
91 .globl _start_of_vectors
92_start_of_vectors:
93
94/* Machine check */
95 STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
96
97/* Data Storage exception. */
98 STD_EXCEPTION(0x300, DataStorage, UnknownException)
99
100/* Instruction Storage exception. */
101 STD_EXCEPTION(0x400, InstStorage, UnknownException)
102
103/* External Interrupt exception. */
104 STD_EXCEPTION(0x500, ExtInterrupt, external_interrupt)
105
106/* Alignment exception. */
107 . = 0x600
108Alignment:
Rafal Jaworowski06244e42007-06-22 14:58:04 +0200109 EXCEPTION_PROLOG(SRR0, SRR1)
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500110 mfspr r4,DAR
111 stw r4,_DAR(r21)
112 mfspr r5,DSISR
113 stw r5,_DSISR(r21)
114 addi r3,r1,STACK_FRAME_OVERHEAD
Joakim Tjernlund4ff6bc02010-01-19 14:41:55 +0100115 EXC_XFER_TEMPLATE(Alignment, AlignmentException, MSR_KERNEL, COPY_EE)
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500116
117/* Program check exception */
118 . = 0x700
119ProgramCheck:
Rafal Jaworowski06244e42007-06-22 14:58:04 +0200120 EXCEPTION_PROLOG(SRR0, SRR1)
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500121 addi r3,r1,STACK_FRAME_OVERHEAD
Joakim Tjernlund4ff6bc02010-01-19 14:41:55 +0100122 EXC_XFER_TEMPLATE(ProgramCheck, ProgramCheckException,
123 MSR_KERNEL, COPY_EE)
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500124
125 STD_EXCEPTION(0x800, FPUnavailable, UnknownException)
126
127 /* I guess we could implement decrementer, and may have
128 * to someday for timekeeping.
129 */
130 STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
131 STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
132 STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
133 STD_EXCEPTION(0xc00, SystemCall, UnknownException)
134 STD_EXCEPTION(0xd00, SingleStep, UnknownException)
135 STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
136 STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
137 STD_EXCEPTION(0x1000, SoftEmu, SoftEmuException)
138 STD_EXCEPTION(0x1100, InstructionTLBMiss, UnknownException)
139 STD_EXCEPTION(0x1200, DataTLBMiss, UnknownException)
140 STD_EXCEPTION(0x1300, InstructionTLBError, UnknownException)
141 STD_EXCEPTION(0x1400, DataTLBError, UnknownException)
142 STD_EXCEPTION(0x1500, Reserved5, UnknownException)
143 STD_EXCEPTION(0x1600, Reserved6, UnknownException)
144 STD_EXCEPTION(0x1700, Reserved7, UnknownException)
145 STD_EXCEPTION(0x1800, Reserved8, UnknownException)
146 STD_EXCEPTION(0x1900, Reserved9, UnknownException)
147 STD_EXCEPTION(0x1a00, ReservedA, UnknownException)
148 STD_EXCEPTION(0x1b00, ReservedB, UnknownException)
149 STD_EXCEPTION(0x1c00, DataBreakpoint, UnknownException)
150 STD_EXCEPTION(0x1d00, InstructionBreakpoint, UnknownException)
151 STD_EXCEPTION(0x1e00, PeripheralBreakpoint, UnknownException)
152 STD_EXCEPTION(0x1f00, DevPortBreakpoint, UnknownException)
153
154 .globl _end_of_vectors
155_end_of_vectors:
156
157 . = 0x2000
158
159boot_cold:
Becky Bruced1cb6cb2008-11-03 15:44:01 -0600160 /*
161 * NOTE: Only Cpu 0 will ever come here. Other cores go to an
162 * address specified by the BPTR
163 */
Jon Loeliger11c99582007-08-02 14:42:20 -05001641:
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200165#ifdef CONFIG_SYS_RAMBOOT
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500166 /* disable everything */
Jon Loeliger11c99582007-08-02 14:42:20 -0500167 li r0, 0
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500168 mtspr HID0, r0
169 sync
170 mtmsr 0
Jon Loeliger11c99582007-08-02 14:42:20 -0500171#endif
172
Dave Liu358ab662008-10-28 17:46:12 +0800173 /* Invalidate BATs */
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500174 bl invalidate_bats
175 sync
Dave Liu358ab662008-10-28 17:46:12 +0800176 /* Invalidate all of TLB before MMU turn on */
177 bl clear_tlbs
178 sync
Jon Loeligera1295442006-08-22 12:06:18 -0500179
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200180#ifdef CONFIG_SYS_L2
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500181 /* init the L2 cache */
Jon Loeliger11c99582007-08-02 14:42:20 -0500182 lis r3, L2_INIT@h
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500183 ori r3, r3, L2_INIT@l
Jon Loeligera1295442006-08-22 12:06:18 -0500184 mtspr l2cr, r3
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500185 /* invalidate the L2 cache */
186 bl l2cache_invalidate
187 sync
188#endif
Jon Loeligera1295442006-08-22 12:06:18 -0500189
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500190 /*
191 * Calculate absolute address in FLASH and jump there
192 *------------------------------------------------------*/
Becky Bruce2a978672008-11-05 14:55:35 -0600193 lis r3, CONFIG_SYS_MONITOR_BASE_EARLY@h
194 ori r3, r3, CONFIG_SYS_MONITOR_BASE_EARLY@l
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500195 addi r3, r3, in_flash - _start + EXC_OFF_SYS_RESET
196 mtlr r3
197 blr
198
199in_flash:
200 /* let the C-code set up the rest */
201 /* */
202 /* Be careful to keep code relocatable ! */
203 /*------------------------------------------------------*/
204 /* perform low-level init */
205
206 /* enable extended addressing */
207 bl enable_ext_addr
Jon Loeligera1295442006-08-22 12:06:18 -0500208
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500209 /* setup the bats */
Becky Brucef81ab5b2008-01-23 16:31:00 -0600210 bl early_bats
Jon Loeligera1295442006-08-22 12:06:18 -0500211
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500212 /*
213 * Cache must be enabled here for stack-in-cache trick.
214 * This means we need to enable the BATS.
215 * Cache should be turned on after BATs, since by default
216 * everything is write-through.
217 */
218
219 /* enable address translation */
Becky Bruceaa06c6c2008-11-05 14:55:34 -0600220 mfmsr r5
221 ori r5, r5, (MSR_IR | MSR_DR)
222 lis r3,addr_trans_enabled@h
223 ori r3, r3, addr_trans_enabled@l
224 mtspr SPRN_SRR0,r3
225 mtspr SPRN_SRR1,r5
226 rfi
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500227
Becky Bruceaa06c6c2008-11-05 14:55:34 -0600228addr_trans_enabled:
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500229 /* enable and invalidate the data cache */
230/* bl l1dcache_enable */
Wolfgang Denkd46f6e72006-10-24 15:32:57 +0200231 bl dcache_enable
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500232 sync
233
234#if 1
235 bl icache_enable
236#endif
Jon Loeligera1295442006-08-22 12:06:18 -0500237
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200238#ifdef CONFIG_SYS_INIT_RAM_LOCK
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500239 bl lock_ram_in_cache
240 sync
241#endif
242
Becky Bruce0bd25092008-11-06 17:37:35 -0600243#if (CONFIG_SYS_CCSRBAR_DEFAULT != CONFIG_SYS_CCSRBAR)
244 bl setup_ccsrbar
245#endif
246
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500247 /* set up the stack pointer in our newly created
248 * cache-ram (r1) */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200249 lis r1, (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET)@h
250 ori r1, r1, (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET)@l
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500251
Wolfgang Denkd46f6e72006-10-24 15:32:57 +0200252 li r0, 0 /* Make room for stack frame header and */
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500253 stwu r0, -4(r1) /* clear final stack frame so that */
254 stwu r0, -4(r1) /* stack backtraces terminate cleanly */
255
256 GET_GOT /* initialize GOT access */
257
Wolfgang Denkd46f6e72006-10-24 15:32:57 +0200258 /* run low-level CPU init code (from Flash) */
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500259 bl cpu_init_f
260 sync
261
Wolfgang Denkd46f6e72006-10-24 15:32:57 +0200262#ifdef RUN_DIAG
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500263
Wolfgang Denkd46f6e72006-10-24 15:32:57 +0200264 /* Load PX_AUX register address in r4 */
Becky Bruce8c2ebd02008-11-06 17:36:04 -0600265 lis r4, PIXIS_BASE@h
Wolfgang Denkd46f6e72006-10-24 15:32:57 +0200266 ori r4, r4, 0x6
267 /* Load contents of PX_AUX in r3 bits 24 to 31*/
268 lbz r3, 0(r4)
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500269
Wolfgang Denkd46f6e72006-10-24 15:32:57 +0200270 /* Mask and obtain the bit in r3 */
271 rlwinm. r3, r3, 0, 24, 24
272 /* If not zero, jump and continue with u-boot */
273 bne diag_done
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500274
Wolfgang Denkd46f6e72006-10-24 15:32:57 +0200275 /* Load back contents of PX_AUX in r3 bits 24 to 31 */
276 lbz r3, 0(r4)
277 /* Set the MSB of the register value */
278 ori r3, r3, 0x80
279 /* Write value in r3 back to PX_AUX */
280 stb r3, 0(r4)
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500281
Wolfgang Denkd46f6e72006-10-24 15:32:57 +0200282 /* Get the address to jump to in r3*/
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200283 lis r3, CONFIG_SYS_DIAG_ADDR@h
284 ori r3, r3, CONFIG_SYS_DIAG_ADDR@l
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500285
Wolfgang Denkd46f6e72006-10-24 15:32:57 +0200286 /* Load the LR with the branch address */
287 mtlr r3
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500288
Wolfgang Denkd46f6e72006-10-24 15:32:57 +0200289 /* Branch to diagnostic */
290 blr
Jon Loeligera1295442006-08-22 12:06:18 -0500291
292diag_done:
293#endif
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500294
Wolfgang Denkd46f6e72006-10-24 15:32:57 +0200295/* bl l2cache_enable */
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500296
Wolfgang Denkd46f6e72006-10-24 15:32:57 +0200297 /* run 1st part of board init code (from Flash) */
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500298 bl board_init_f
299 sync
300
Peter Tyser0c44caf2010-09-14 19:13:53 -0500301 /* NOTREACHED - board_init_f() does not return */
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500302
303 .globl invalidate_bats
304invalidate_bats:
Jon Loeligera1295442006-08-22 12:06:18 -0500305
Jon Loeliger11c99582007-08-02 14:42:20 -0500306 li r0, 0
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500307 /* invalidate BATs */
308 mtspr IBAT0U, r0
309 mtspr IBAT1U, r0
310 mtspr IBAT2U, r0
311 mtspr IBAT3U, r0
Wolfgang Denkd46f6e72006-10-24 15:32:57 +0200312 mtspr IBAT4U, r0
313 mtspr IBAT5U, r0
314 mtspr IBAT6U, r0
315 mtspr IBAT7U, r0
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500316
317 isync
318 mtspr DBAT0U, r0
319 mtspr DBAT1U, r0
320 mtspr DBAT2U, r0
321 mtspr DBAT3U, r0
Wolfgang Denkd46f6e72006-10-24 15:32:57 +0200322 mtspr DBAT4U, r0
323 mtspr DBAT5U, r0
324 mtspr DBAT6U, r0
325 mtspr DBAT7U, r0
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500326
327 isync
328 sync
329 blr
Jon Loeligera1295442006-08-22 12:06:18 -0500330
Becky Brucef81ab5b2008-01-23 16:31:00 -0600331/*
332 * early_bats:
333 *
334 * Set up bats needed early on - this is usually the BAT for the
Becky Bruce7e554a32008-11-02 18:19:32 -0600335 * stack-in-cache, the Flash, and CCSR space
Becky Brucef81ab5b2008-01-23 16:31:00 -0600336 */
337 .globl early_bats
338early_bats:
Becky Bruce7e554a32008-11-02 18:19:32 -0600339 /* IBAT 3 */
340 lis r4, CONFIG_SYS_IBAT3L@h
341 ori r4, r4, CONFIG_SYS_IBAT3L@l
342 lis r3, CONFIG_SYS_IBAT3U@h
343 ori r3, r3, CONFIG_SYS_IBAT3U@l
344 mtspr IBAT3L, r4
345 mtspr IBAT3U, r3
346 isync
347
348 /* DBAT 3 */
349 lis r4, CONFIG_SYS_DBAT3L@h
350 ori r4, r4, CONFIG_SYS_DBAT3L@l
351 lis r3, CONFIG_SYS_DBAT3U@h
352 ori r3, r3, CONFIG_SYS_DBAT3U@l
353 mtspr DBAT3L, r4
354 mtspr DBAT3U, r3
355 isync
356
Becky Brucef81ab5b2008-01-23 16:31:00 -0600357 /* IBAT 5 */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200358 lis r4, CONFIG_SYS_IBAT5L@h
359 ori r4, r4, CONFIG_SYS_IBAT5L@l
360 lis r3, CONFIG_SYS_IBAT5U@h
361 ori r3, r3, CONFIG_SYS_IBAT5U@l
Becky Brucef81ab5b2008-01-23 16:31:00 -0600362 mtspr IBAT5L, r4
363 mtspr IBAT5U, r3
364 isync
365
366 /* DBAT 5 */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200367 lis r4, CONFIG_SYS_DBAT5L@h
368 ori r4, r4, CONFIG_SYS_DBAT5L@l
369 lis r3, CONFIG_SYS_DBAT5U@h
370 ori r3, r3, CONFIG_SYS_DBAT5U@l
Becky Brucef81ab5b2008-01-23 16:31:00 -0600371 mtspr DBAT5L, r4
372 mtspr DBAT5U, r3
373 isync
374
375 /* IBAT 6 */
Becky Bruce2a978672008-11-05 14:55:35 -0600376 lis r4, CONFIG_SYS_IBAT6L_EARLY@h
377 ori r4, r4, CONFIG_SYS_IBAT6L_EARLY@l
378 lis r3, CONFIG_SYS_IBAT6U_EARLY@h
379 ori r3, r3, CONFIG_SYS_IBAT6U_EARLY@l
Becky Brucef81ab5b2008-01-23 16:31:00 -0600380 mtspr IBAT6L, r4
381 mtspr IBAT6U, r3
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500382 isync
383
Becky Brucef81ab5b2008-01-23 16:31:00 -0600384 /* DBAT 6 */
Becky Bruce2a978672008-11-05 14:55:35 -0600385 lis r4, CONFIG_SYS_DBAT6L_EARLY@h
386 ori r4, r4, CONFIG_SYS_DBAT6L_EARLY@l
387 lis r3, CONFIG_SYS_DBAT6U_EARLY@h
388 ori r3, r3, CONFIG_SYS_DBAT6U_EARLY@l
Becky Brucef81ab5b2008-01-23 16:31:00 -0600389 mtspr DBAT6L, r4
390 mtspr DBAT6U, r3
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500391 isync
Becky Bruce0bd25092008-11-06 17:37:35 -0600392
393#if(CONFIG_SYS_CCSRBAR_DEFAULT != CONFIG_SYS_CCSRBAR)
394 /* IBAT 7 */
395 lis r4, CONFIG_SYS_CCSR_DEFAULT_IBATL@h
396 ori r4, r4, CONFIG_SYS_CCSR_DEFAULT_IBATL@l
397 lis r3, CONFIG_SYS_CCSR_DEFAULT_IBATU@h
398 ori r3, r3, CONFIG_SYS_CCSR_DEFAULT_IBATU@l
399 mtspr IBAT7L, r4
400 mtspr IBAT7U, r3
401 isync
402
403 /* DBAT 7 */
404 lis r4, CONFIG_SYS_CCSR_DEFAULT_DBATL@h
405 ori r4, r4, CONFIG_SYS_CCSR_DEFAULT_DBATL@l
406 lis r3, CONFIG_SYS_CCSR_DEFAULT_DBATU@h
407 ori r3, r3, CONFIG_SYS_CCSR_DEFAULT_DBATU@l
408 mtspr DBAT7L, r4
409 mtspr DBAT7U, r3
410 isync
411#endif
Becky Brucef81ab5b2008-01-23 16:31:00 -0600412 blr
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500413
Becky Brucef81ab5b2008-01-23 16:31:00 -0600414 .globl clear_tlbs
415clear_tlbs:
416 addis r3, 0, 0x0000
417 addis r5, 0, 0x4
418 isync
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500419tlblp:
Becky Brucef81ab5b2008-01-23 16:31:00 -0600420 tlbie r3
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500421 sync
Becky Brucef81ab5b2008-01-23 16:31:00 -0600422 addi r3, r3, 0x1000
423 cmp 0, 0, r3, r5
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500424 blt tlblp
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500425 blr
426
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500427 .globl disable_addr_trans
428disable_addr_trans:
429 /* disable address translation */
430 mflr r4
431 mfmsr r3
432 andi. r0, r3, (MSR_IR | MSR_DR)
433 beqlr
434 andc r3, r3, r0
435 mtspr SRR0, r4
436 mtspr SRR1, r3
437 rfi
438
439/*
440 * This code finishes saving the registers to the exception frame
441 * and jumps to the appropriate handler for the exception.
442 * Register r21 is pointer into trap frame, r1 has new stack pointer.
443 */
444 .globl transfer_to_handler
445transfer_to_handler:
446 stw r22,_NIP(r21)
447 lis r22,MSR_POW@h
448 andc r23,r23,r22
449 stw r23,_MSR(r21)
450 SAVE_GPR(7, r21)
451 SAVE_4GPRS(8, r21)
452 SAVE_8GPRS(12, r21)
453 SAVE_8GPRS(24, r21)
454 mflr r23
455 andi. r24,r23,0x3f00 /* get vector offset */
456 stw r24,TRAP(r21)
457 li r22,0
458 stw r22,RESULT(r21)
459 mtspr SPRG2,r22 /* r1 is now kernel sp */
460 lwz r24,0(r23) /* virtual address of handler */
461 lwz r23,4(r23) /* where to go when done */
462 mtspr SRR0,r24
463 mtspr SRR1,r20
464 mtlr r23
465 SYNC
466 rfi /* jump to handler, enable MMU */
467
468int_return:
469 mfmsr r28 /* Disable interrupts */
470 li r4,0
471 ori r4,r4,MSR_EE
472 andc r28,r28,r4
473 SYNC /* Some chip revs need this... */
474 mtmsr r28
475 SYNC
476 lwz r2,_CTR(r1)
477 lwz r0,_LINK(r1)
478 mtctr r2
479 mtlr r0
480 lwz r2,_XER(r1)
481 lwz r0,_CCR(r1)
482 mtspr XER,r2
483 mtcrf 0xFF,r0
484 REST_10GPRS(3, r1)
485 REST_10GPRS(13, r1)
486 REST_8GPRS(23, r1)
487 REST_GPR(31, r1)
488 lwz r2,_NIP(r1) /* Restore environment */
489 lwz r0,_MSR(r1)
490 mtspr SRR0,r2
491 mtspr SRR1,r0
492 lwz r0,GPR0(r1)
493 lwz r2,GPR2(r1)
494 lwz r1,GPR1(r1)
495 SYNC
496 rfi
497
498 .globl dc_read
499dc_read:
500 blr
501
502 .globl get_pvr
503get_pvr:
504 mfspr r3, PVR
505 blr
506
507 .globl get_svr
508get_svr:
509 mfspr r3, SVR
510 blr
511
512
Jon Loeligera1295442006-08-22 12:06:18 -0500513/*
Wolfgang Denkd46f6e72006-10-24 15:32:57 +0200514 * Function: in8
515 * Description: Input 8 bits
Jon Loeligera1295442006-08-22 12:06:18 -0500516 */
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500517 .globl in8
518in8:
519 lbz r3,0x0000(r3)
520 blr
521
Jon Loeligera1295442006-08-22 12:06:18 -0500522/*
Wolfgang Denkd46f6e72006-10-24 15:32:57 +0200523 * Function: out8
524 * Description: Output 8 bits
Jon Loeligera1295442006-08-22 12:06:18 -0500525 */
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500526 .globl out8
527out8:
528 stb r4,0x0000(r3)
529 blr
530
Jon Loeligera1295442006-08-22 12:06:18 -0500531/*
Wolfgang Denkd46f6e72006-10-24 15:32:57 +0200532 * Function: out16
533 * Description: Output 16 bits
Jon Loeligera1295442006-08-22 12:06:18 -0500534 */
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500535 .globl out16
536out16:
537 sth r4,0x0000(r3)
538 blr
539
Jon Loeligera1295442006-08-22 12:06:18 -0500540/*
Wolfgang Denkd46f6e72006-10-24 15:32:57 +0200541 * Function: out16r
542 * Description: Byte reverse and output 16 bits
Jon Loeligera1295442006-08-22 12:06:18 -0500543 */
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500544 .globl out16r
545out16r:
546 sthbrx r4,r0,r3
547 blr
548
Jon Loeligera1295442006-08-22 12:06:18 -0500549/*
Wolfgang Denkd46f6e72006-10-24 15:32:57 +0200550 * Function: out32
551 * Description: Output 32 bits
Jon Loeligera1295442006-08-22 12:06:18 -0500552 */
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500553 .globl out32
554out32:
555 stw r4,0x0000(r3)
556 blr
557
Jon Loeligera1295442006-08-22 12:06:18 -0500558/*
Wolfgang Denkd46f6e72006-10-24 15:32:57 +0200559 * Function: out32r
560 * Description: Byte reverse and output 32 bits
Jon Loeligera1295442006-08-22 12:06:18 -0500561 */
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500562 .globl out32r
563out32r:
564 stwbrx r4,r0,r3
565 blr
566
Jon Loeligera1295442006-08-22 12:06:18 -0500567/*
Wolfgang Denkd46f6e72006-10-24 15:32:57 +0200568 * Function: in16
569 * Description: Input 16 bits
Jon Loeligera1295442006-08-22 12:06:18 -0500570 */
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500571 .globl in16
572in16:
573 lhz r3,0x0000(r3)
574 blr
575
Jon Loeligera1295442006-08-22 12:06:18 -0500576/*
Wolfgang Denkd46f6e72006-10-24 15:32:57 +0200577 * Function: in16r
578 * Description: Input 16 bits and byte reverse
Jon Loeligera1295442006-08-22 12:06:18 -0500579 */
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500580 .globl in16r
581in16r:
582 lhbrx r3,r0,r3
583 blr
584
Jon Loeligera1295442006-08-22 12:06:18 -0500585/*
Wolfgang Denkd46f6e72006-10-24 15:32:57 +0200586 * Function: in32
587 * Description: Input 32 bits
Jon Loeligera1295442006-08-22 12:06:18 -0500588 */
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500589 .globl in32
590in32:
591 lwz 3,0x0000(3)
592 blr
593
Jon Loeligera1295442006-08-22 12:06:18 -0500594/*
Wolfgang Denkd46f6e72006-10-24 15:32:57 +0200595 * Function: in32r
596 * Description: Input 32 bits and byte reverse
Jon Loeligera1295442006-08-22 12:06:18 -0500597 */
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500598 .globl in32r
599in32r:
600 lwbrx r3,r0,r3
601 blr
602
Jon Loeligera1295442006-08-22 12:06:18 -0500603/*
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500604 * void relocate_code (addr_sp, gd, addr_moni)
605 *
606 * This "function" does not return, instead it continues in RAM
607 * after relocating the monitor code.
608 *
609 * r3 = dest
610 * r4 = src
611 * r5 = length in bytes
612 * r6 = cachelinesize
613 */
614 .globl relocate_code
615relocate_code:
616
Wolfgang Denkd46f6e72006-10-24 15:32:57 +0200617 mr r1, r3 /* Set new stack pointer */
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500618 mr r9, r4 /* Save copy of Global Data pointer */
619 mr r10, r5 /* Save copy of Destination Address */
Haiying Wang0383df82006-08-15 15:13:15 -0400620
Joakim Tjernlund3fbaa4d2010-01-19 14:41:56 +0100621 GET_GOT
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500622 mr r3, r5 /* Destination Address */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200623 lis r4, CONFIG_SYS_MONITOR_BASE@h /* Source Address */
624 ori r4, r4, CONFIG_SYS_MONITOR_BASE@l
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500625 lwz r5, GOT(__init_end)
626 sub r5, r5, r4
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200627 li r6, CONFIG_SYS_CACHELINE_SIZE /* Cache Line Size */
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500628
629 /*
630 * Fix GOT pointer:
631 *
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200632 * New GOT-PTR = (old GOT-PTR - CONFIG_SYS_MONITOR_BASE) + Destination Address
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500633 *
634 * Offset:
635 */
636 sub r15, r10, r4
637
638 /* First our own GOT */
Joakim Tjernlund3fbaa4d2010-01-19 14:41:56 +0100639 add r12, r12, r15
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500640 /* then the one used by the C code */
641 add r30, r30, r15
642
643 /*
644 * Now relocate code
645 */
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500646 cmplw cr1,r3,r4
647 addi r0,r5,3
648 srwi. r0,r0,2
649 beq cr1,4f /* In place copy is not necessary */
650 beq 7f /* Protect against 0 count */
651 mtctr r0
652 bge cr1,2f
653
654 la r8,-4(r4)
655 la r7,-4(r3)
6561: lwzu r0,4(r8)
657 stwu r0,4(r7)
658 bdnz 1b
659 b 4f
660
6612: slwi r0,r0,2
662 add r8,r4,r0
663 add r7,r3,r0
6643: lwzu r0,-4(r8)
665 stwu r0,-4(r7)
666 bdnz 3b
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500667/*
668 * Now flush the cache: note that we must start from a cache aligned
669 * address. Otherwise we might miss one cache line.
670 */
6714: cmpwi r6,0
672 add r5,r3,r5
673 beq 7f /* Always flush prefetch queue in any case */
674 subi r0,r6,1
675 andc r3,r3,r0
676 mr r4,r3
6775: dcbst 0,r4
678 add r4,r4,r6
679 cmplw r4,r5
680 blt 5b
681 sync /* Wait for all dcbst to complete on bus */
682 mr r4,r3
6836: icbi 0,r4
684 add r4,r4,r6
685 cmplw r4,r5
686 blt 6b
Wolfgang Denkd46f6e72006-10-24 15:32:57 +02006877: sync /* Wait for all icbi to complete on bus */
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500688 isync
689
690/*
691 * We are done. Do not return, instead branch to second part of board
692 * initialization, now running from RAM.
693 */
694 addi r0, r10, in_ram - _start + EXC_OFF_SYS_RESET
695 mtlr r0
696 blr
697
698in_ram:
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500699 /*
Joakim Tjernlund3fbaa4d2010-01-19 14:41:56 +0100700 * Relocation Function, r12 point to got2+0x8000
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500701 *
702 * Adjust got2 pointers, no need to check for 0, this code
703 * already puts a few entries in the table.
704 */
705 li r0,__got2_entries@sectoff@l
706 la r3,GOT(_GOT2_TABLE_)
707 lwz r11,GOT(_GOT2_TABLE_)
708 mtctr r0
709 sub r11,r3,r11
710 addi r3,r3,-4
7111: lwzu r0,4(r3)
Joakim Tjernlund4f2fdac2009-10-08 02:03:51 +0200712 cmpwi r0,0
713 beq- 2f
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500714 add r0,r0,r11
715 stw r0,0(r3)
Joakim Tjernlund4f2fdac2009-10-08 02:03:51 +02007162: bdnz 1b
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500717
718 /*
719 * Now adjust the fixups and the pointers to the fixups
720 * in case we need to move ourselves again.
721 */
Joakim Tjernlund4f2fdac2009-10-08 02:03:51 +0200722 li r0,__fixup_entries@sectoff@l
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500723 lwz r3,GOT(_FIXUP_TABLE_)
724 cmpwi r0,0
725 mtctr r0
726 addi r3,r3,-4
727 beq 4f
7283: lwzu r4,4(r3)
729 lwzux r0,r4,r11
Joakim Tjernlundc61b25a2010-10-14 11:51:44 +0200730 cmpwi r0,0
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500731 add r0,r0,r11
732 stw r10,0(r3)
Joakim Tjernlundc61b25a2010-10-14 11:51:44 +0200733 beq- 5f
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500734 stw r0,0(r4)
Joakim Tjernlundc61b25a2010-10-14 11:51:44 +02007355: bdnz 3b
Jon Loeliger5c8aa972006-04-26 17:58:56 -05007364:
737/* clear_bss: */
738 /*
739 * Now clear BSS segment
740 */
741 lwz r3,GOT(__bss_start)
742 lwz r4,GOT(_end)
743
744 cmplw 0, r3, r4
745 beq 6f
746
747 li r0, 0
7485:
749 stw r0, 0(r3)
750 addi r3, r3, 4
751 cmplw 0, r3, r4
752 bne 5b
7536:
Haiying Wang237c5ad2006-05-10 09:38:06 -0500754 mr r3, r9 /* Init Date pointer */
755 mr r4, r10 /* Destination Address */
756 bl board_init_r
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500757
758 /* not reached - end relocate_code */
759/*-----------------------------------------------------------------------*/
760
761 /*
762 * Copy exception vector code to low memory
763 *
764 * r3: dest_addr
765 * r7: source address, r8: end address, r9: target address
766 */
767 .globl trap_init
768trap_init:
Joakim Tjernlund3fbaa4d2010-01-19 14:41:56 +0100769 mflr r4 /* save link register */
770 GET_GOT
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500771 lwz r7, GOT(_start)
772 lwz r8, GOT(_end_of_vectors)
773
774 li r9, 0x100 /* reset vector always at 0x100 */
775
776 cmplw 0, r7, r8
777 bgelr /* return if r7>=r8 - just in case */
Jon Loeliger5c8aa972006-04-26 17:58:56 -05007781:
779 lwz r0, 0(r7)
780 stw r0, 0(r9)
781 addi r7, r7, 4
782 addi r9, r9, 4
783 cmplw 0, r7, r8
784 bne 1b
785
786 /*
787 * relocate `hdlr' and `int_return' entries
788 */
789 li r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET
790 li r8, Alignment - _start + EXC_OFF_SYS_RESET
7912:
792 bl trap_reloc
793 addi r7, r7, 0x100 /* next exception vector */
794 cmplw 0, r7, r8
795 blt 2b
796
797 li r7, .L_Alignment - _start + EXC_OFF_SYS_RESET
798 bl trap_reloc
799
800 li r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET
801 bl trap_reloc
802
803 li r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET
804 li r8, SystemCall - _start + EXC_OFF_SYS_RESET
8053:
806 bl trap_reloc
807 addi r7, r7, 0x100 /* next exception vector */
808 cmplw 0, r7, r8
809 blt 3b
810
811 li r7, .L_SingleStep - _start + EXC_OFF_SYS_RESET
812 li r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET
8134:
814 bl trap_reloc
815 addi r7, r7, 0x100 /* next exception vector */
816 cmplw 0, r7, r8
817 blt 4b
818
819 /* enable execptions from RAM vectors */
820 mfmsr r7
821 li r8,MSR_IP
822 andc r7,r7,r8
Jon Loeliger11c99582007-08-02 14:42:20 -0500823 ori r7,r7,MSR_ME /* Enable Machine Check */
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500824 mtmsr r7
825
826 mtlr r4 /* restore link register */
827 blr
828
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500829.globl enable_ext_addr
830enable_ext_addr:
831 mfspr r0, HID0
Wolfgang Denkd46f6e72006-10-24 15:32:57 +0200832 lis r0, (HID0_HIGH_BAT_EN | HID0_XBSEN | HID0_XAEN)@h
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500833 ori r0, r0, (HID0_HIGH_BAT_EN | HID0_XBSEN | HID0_XAEN)@l
Wolfgang Denkd46f6e72006-10-24 15:32:57 +0200834 mtspr HID0, r0
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500835 sync
836 isync
837 blr
838
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200839#if (CONFIG_SYS_CCSRBAR_DEFAULT != CONFIG_SYS_CCSRBAR)
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500840.globl setup_ccsrbar
Jon Loeligera1295442006-08-22 12:06:18 -0500841setup_ccsrbar:
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500842 /* Special sequence needed to update CCSRBAR itself */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200843 lis r4, CONFIG_SYS_CCSRBAR_DEFAULT@h
844 ori r4, r4, CONFIG_SYS_CCSRBAR_DEFAULT@l
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500845
Becky Bruce0bd25092008-11-06 17:37:35 -0600846 lis r5, CONFIG_SYS_CCSRBAR_PHYS_LOW@h
847 ori r5, r5, CONFIG_SYS_CCSRBAR_PHYS_LOW@l
848 srwi r5,r5,12
849 li r6, CONFIG_SYS_CCSRBAR_PHYS_HIGH@l
850 rlwimi r5,r6,20,8,11
851 stw r5, 0(r4) /* Store physical value of CCSR */
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500852 isync
853
Wolfgang Denk0708bc62010-10-07 21:51:12 +0200854 lis r5, CONFIG_SYS_TEXT_BASE@h
855 ori r5,r5,CONFIG_SYS_TEXT_BASE@l
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500856 lwz r5, 0(r5)
857 isync
858
Becky Bruce0bd25092008-11-06 17:37:35 -0600859 /* Use VA of CCSR to do read */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200860 lis r3, CONFIG_SYS_CCSRBAR@h
861 lwz r5, CONFIG_SYS_CCSRBAR@l(r3)
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500862 isync
Jon Loeligera1295442006-08-22 12:06:18 -0500863
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500864 blr
865#endif
Jon Loeligera1295442006-08-22 12:06:18 -0500866
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200867#ifdef CONFIG_SYS_INIT_RAM_LOCK
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500868lock_ram_in_cache:
869 /* Allocate Initial RAM in data cache.
870 */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200871 lis r3, (CONFIG_SYS_INIT_RAM_ADDR & ~31)@h
872 ori r3, r3, (CONFIG_SYS_INIT_RAM_ADDR & ~31)@l
873 li r4, ((CONFIG_SYS_INIT_RAM_END & ~31) + \
874 (CONFIG_SYS_INIT_RAM_ADDR & 31) + 31) / 32
Nick Spencee4bfc8b2008-08-28 14:09:15 -0700875 mtctr r4
Jon Loeliger5c8aa972006-04-26 17:58:56 -05008761:
877 dcbz r0, r3
878 addi r3, r3, 32
879 bdnz 1b
880#if 1
881/* Lock the data cache */
882 mfspr r0, HID0
883 ori r0, r0, 0x1000
884 sync
885 mtspr HID0, r0
886 sync
887 blr
888#endif
889#if 0
890 /* Lock the first way of the data cache */
891 mfspr r0, LDSTCR
892 ori r0, r0, 0x0080
893#if defined(CONFIG_ALTIVEC)
894 dssall
895#endif
896 sync
897 mtspr LDSTCR, r0
898 sync
899 isync
900 blr
901#endif
Jon Loeligera1295442006-08-22 12:06:18 -0500902
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500903.globl unlock_ram_in_cache
904unlock_ram_in_cache:
905 /* invalidate the INIT_RAM section */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200906 lis r3, (CONFIG_SYS_INIT_RAM_ADDR & ~31)@h
907 ori r3, r3, (CONFIG_SYS_INIT_RAM_ADDR & ~31)@l
908 li r4, ((CONFIG_SYS_INIT_RAM_END & ~31) + \
909 (CONFIG_SYS_INIT_RAM_ADDR & 31) + 31) / 32
Nick Spencee4bfc8b2008-08-28 14:09:15 -0700910 mtctr r4
Jon Loeliger5c8aa972006-04-26 17:58:56 -05009111: icbi r0, r3
912 addi r3, r3, 32
913 bdnz 1b
Wolfgang Denkd46f6e72006-10-24 15:32:57 +0200914 sync /* Wait for all icbi to complete on bus */
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500915 isync
916#if 1
917/* Unlock the data cache and invalidate it */
Wolfgang Denkd46f6e72006-10-24 15:32:57 +0200918 mfspr r0, HID0
919 li r3,0x1000
920 andc r0,r0,r3
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500921 li r3,0x0400
922 or r0,r0,r3
923 sync
Wolfgang Denkd46f6e72006-10-24 15:32:57 +0200924 mtspr HID0, r0
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500925 sync
926 blr
927#endif
Jon Loeligera1295442006-08-22 12:06:18 -0500928#if 0
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500929 /* Unlock the first way of the data cache */
Wolfgang Denkd46f6e72006-10-24 15:32:57 +0200930 mfspr r0, LDSTCR
931 li r3,0x0080
932 andc r0,r0,r3
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500933#ifdef CONFIG_ALTIVEC
934 dssall
935#endif
936 sync
Wolfgang Denkd46f6e72006-10-24 15:32:57 +0200937 mtspr LDSTCR, r0
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500938 sync
939 isync
940 li r3,0x0400
941 or r0,r0,r3
942 sync
Wolfgang Denkd46f6e72006-10-24 15:32:57 +0200943 mtspr HID0, r0
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500944 sync
945 blr
946#endif
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500947#endif