aboutsummaryrefslogtreecommitdiff
path: root/board/w7o/post1.S
blob: a6f46c8746d38f77d28a7254c1d893294818cd9b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
/*
 * (C) Copyright 2001
 * Bill Hunter, Wave 7 Optics, william.hunter@mediaone.net
 *  and
 * Erik Theisen, Wave 7 Optics, etheisen@mindspring.com
 *
 * See file CREDITS for list of people who contributed to this
 * project.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 */
/*
 * Description:
 *	Routine to exercise memory for the bringing up of our boards.
 */
#include <config.h>
#include <ppc4xx.h>

#define _LINUX_CONFIG_H 1       /* avoid reading Linux autoconf.h file  */

#include <ppc_asm.tmpl>
#include <ppc_defs.h>

#include <asm/cache.h>
#include <asm/mmu.h>

#include <watchdog.h>

#include "errors.h"

#define _ASMLANGUAGE

	.globl	test_sdram
	.globl	test_led
	.globl	log_stat
	.globl	log_warn
	.globl	log_err
	.globl  temp_uart_init
	.globl  post_puts
	.globl  disp_hex

/*****************************************************
*******   Text Strings for low level printing   ******
*******          In section got2               *******
*****************************************************/

/*
 * Define the text strings for errors and warnings.
 * Switch to .data section.
 */
	.section ".data"
err_str:	.asciz "*** POST ERROR   = "
warn_str:	.asciz "*** POST WARNING = "
end_str:  .asciz "\r\n"

/*
 * Enter the labels in Global Entry Table (GOT).
 * Switch to .got2 section.
 */
	START_GOT
	GOT_ENTRY(err_str)
	GOT_ENTRY(warn_str)
	GOT_ENTRY(end_str)
	END_GOT

/*
 * Switch  back to .text section.
 */
	.text

/****************************************
 ****************************************
 ********    LED register test   ********
 ****************************************
 ***************************************/
test_led:
	/* save the return info on stack */
	mflr	r0			/* Get link register */
	stwu	r1, -12(r1)		/* Save back chain and move SP */
	stw	r0, +16(r1)		/* Save link register */
	stw	r4, +8(r1)		/* save R4 */

	WATCHDOG_RESET			/* Reset the watchdog */

	addi    r3, 0, ERR_FF		/* first test value is ffff */
	addi	r4, r3, 0		/* save copy of pattern */
	bl	set_led			/* store first test value */
	bl	get_led			/* read it back */
	xor.	r4, r4, r3		/* compare to original */
#if defined(CONFIG_W7OLMC)
	andi.   r4, r4, 0x00ff		/* lmc has 8 bits */
#else
	andi.   r4, r4, 0xffff		/* lmg has 16 bits */
#endif
	beq     LED2			/* next test */
	addi    r3, 0, ERR_LED		/* error code = 1 */
	bl	log_err			/* display error and halt */
LED2:	addi    r3, 0, ERR_00		/* 2nd test value is 0000 */
	addi	r4, r3, 0		/* save copy of pattern */
	bl	set_led			/* store first test value */
	bl	get_led			/* read it back */
	xor.	r4, r4, r3		/* compare to original */
#if defined(CONFIG_W7OLMC)
	andi.   r4, r4, 0x00ff		/* lmc has 8 bits */
#else
	andi.   r4, r4, 0xffff		/* lmg has 16 bits */
#endif
	beq     LED3			/* next test */
	addi    r3, 0, ERR_LED		/* error code = 1 */
	bl	log_err			/* display error and halt */

LED3:	/* restore stack and return */
	lwz	r0, +16(r1)		/* Get saved link register */
	mtlr	r0			/* Restore link register */
	lwz	r4, +8(r1)		/* restore r4 */
	addi	r1, r1, +12		/* Remove frame from stack */
	blr				/* Return to calling function */

/****************************************
 ****************************************
 ********     SDRAM TESTS        ********
 ****************************************
 ***************************************/
test_sdram:
	/* called with mem size in r3 */
	/* save the return info on stack */
	mflr	r0			/* Get link register */
	stwu	r1, -16(r1)		/* Save back chain and move SP */
	stw	r0, +20(r1)		/* Save link register */
	stmw	r30, +8(r1)		/* save R30,R31 */
					/* r30 is log2(mem size) */
					/* r31 is mem size */

	/* take log2 of total mem size */
	addi	r31, r3, 0		/* save total mem size */
	addi	r30, 0, 0		/* clear r30 */
l2_loop:
	srwi.	r31, r31, 1		/* shift right 1 */
	addi	r30, r30, 1		/* count shifts */
	bne	l2_loop			/* loop till done */
	addi	r30, r30, -1		/* correct for over count */
	addi	r31, r3, 0		/* save original size */

	/* now kick the dog and test the mem */
	WATCHDOG_RESET			/* Reset the watchdog */
	bl	Data_Buster		/* test crossed/shorted data lines */
	addi	r3, r30, 0		/* get log2(memsize) */
	addi	r4, r31, 0		/* get memsize */
	bl	Ghost_Buster		/* test crossed/shorted addr lines */
	addi	r3, r31, 0		/* get mem size */
	bl	Bit_Buster		/* check for bad internal bits */

	/* restore stack and return */
	lmw	r30, +8(r1)		/* Restore r30, r31 */
	lwz	r0, +20(r1)		/* Get saved link register */
	mtlr	r0			/* Restore link register */
	addi	r1, r1, +16		/* Remove frame from stack */
	blr				/* Return to calling function */


/****************************************
 ********  sdram data bus test   ********
 ***************************************/
Data_Buster:
	/* save the return info on stack */
	mflr	r0			/* Get link register */
	stwu	r1, -24(r1)		/* Save back chain and move SP */
	stw	r0, +28(r1)		/* Save link register */
	stmw	r28, 8(r1)		/* save r28 - r31 on stack */
					/* r31 i/o register */
					/* r30 sdram base address */
					/* r29 5555 syndrom */
					/* r28 aaaa syndrom */

	/* set up led register for this test */
	addi    r3, 0, ERR_RAMG		/* set led code to 1 */
	bl	log_stat		/* store test value */
	/* now test the dram data bus */
	xor	r30, r30, r30		/* load r30 with base addr of sdram */
	addis	r31, 0, 0x5555		/* load r31 with test value */
	ori	r31, r31, 0x5555
	stw	r31,0(r30)		/* sto the value */
	lwz	r29,0(r30)		/* read it back */
	xor	r29,r31,r29		/* compare it to original */
	addis	r31, 0, 0xaaaa		/* load r31 with test value */
	ori	r31, r31, 0xaaaa
	stw	r31,0(r30)		/* sto the value */
	lwz	r28,0(r30)		/* read it back */
	xor	r28,r31,r28		/* compare it to original */
	or	r3,r28,r29		/* or together both error terms */
	/*
	 * Now that we have the error bits,
	 * we have to decide which part they are in.
	 */
	bl	get_idx			/* r5 is now index to error */
	addi	r3, r3, ERR_RAMG
	cmpwi	r3, ERR_RAMG		/* check for errors */
	beq	db_done			/* skip if no errors */
	bl	log_err			/* log the error */

db_done:
	lmw	r28, 8(r1)		/* restore r28 - r31 from stack */
	lwz	r0, +28(r1)		/* Get saved link register */
	addi	r1, r1, +24		/* Remove frame from stack */
	mtlr	r0			/* Restore link register */
	blr				/* Return to calling function */


/****************************************************
 ********  test for address ghosting in dram ********
 ***************************************************/

Ghost_Buster:
	/* save the return info on stack */
	mflr	r0			/* Get link register */
	stwu	r1, -36(r1)		/* Save back chain and move SP */
	stw	r0, +40(r1)		/* Save link register */
	stmw	r25, 8(r1)		/* save r25 - r31 on stack */
					/* r31 = scratch register */
					/* r30 is main referance loop counter,
					   0 to 23 */
					/* r29 is ghost loop count, 0 to 22 */
					/* r28 is referance address */
					/* r27 is ghost address */
					/* r26 is log2 (mem size) =
					     number of byte addr bits */
					/* r25 is mem size */

	/* save the log2(mem size) and mem size */
	addi	r26, r3, 0		/* r26 is number of byte addr bits */
	addi	r25, r4, 0		/* r25 is mem size in bytes */

	/* set the leds for address ghost test */
	addi	r3, 0, ERR_ADDG
	bl	set_led

	/* first fill memory with zeros */
	srwi	r31, r25, 2		/* convert bytes to longs */
	mtctr	r31			/* setup byte counter */
	addi	r28, 0, 0		/* start at address at 0 */
	addi	r31, 0, 0		/* data value = 0 */
clr_loop:
	stw	r31, 0(r28)		/* Store zero value */
	addi	r28, r28, 4		/* Increment to next word */
	andi.	r27, r28, 0xffff	/* check for 2^16 loops */
	bne	clr_skip		/* if not there, then skip */
	WATCHDOG_RESET			/* kick the dog every now and then */
clr_skip:
	bdnz	clr_loop		/* Round and round... */

	/* now do main test */
	addi	r30, 0, 0		/* start referance counter at 0 */
outside:
	/*
	 * Calculate the referance address
	 *   the referance address is calculated by setting the (r30-1)
	 *   bit of the base address
	 * when r30=0, the referance address is the base address.
	 * thus the sequence 0,1,2,4,8,..,2^(n-1)
	 * setting the bit is done with the following shift functions.
	 */
	WATCHDOG_RESET			/* Reset the watchdog */

	addi	r31, 0, 1		/* r31 = 1 */
	slw	r28, r31, r30		/* set bit coresponding to loop cnt */
	srwi	r28, r28, 1		/* then shift it right one so  */
					/*   we start at location 0 */
	/* fill referance address with Fs */
	addi	r31, 0, 0x00ff		/* r31 = one byte of set bits */
	stb     r31,0(r28)		/* save ff in referance address */

	/* ghost (inner) loop, now check all posible ghosted addresses */
	addi	r29, 0, 0		/* start ghosted loop counter at 0 */
inside:
	/*
	 * Calculate the ghost address by flipping one
	 *  bit of referance address.  This gives the
	 *  sequence 1,2,4,8,...,2^(n-1)
	 */
	addi	r31, 0, 1		/* r31 = 1 */
	slw     r27, r31, r29		/* set  bit coresponding to loop cnt */
	xor	r27, r28, r27		/* ghost address = ref addr with
					     bit flipped*/

	/* now check for ghosting */
	lbz     r31,0(r27)		/* get content of ghost addr */
	cmpwi   r31, 0			/* compare read value to 0 */
	bne	Casper			/*   we found a ghost! */

	/* now close ghost ( inner ) loop */
	addi	r29, r29, 1		/* increment inner loop counter */
	cmpw	r29, r26		/* check for last inner loop */
	blt		inside		/* do more inner loops */

	/* now close referance ( outer ) loop */
	addi	r31, 0, 0		/* r31 = zero */
	stb	r31, 0(28)		/* zero out the altered address loc. */
	/*
	 * Increment and check for end, count is zero based.
	 * With the ble, this gives us one more loops than
	 * address bits for sequence 0,1,2,4,8,...2^(n-1)
	*/
	addi	r30, r30, 1		/* increment outer loop counter */
	cmpw	r30, r26		/* check for last inner loop */
	ble	outside			/* do more outer loops */

	/* were done, lets go home */
	b	gb_done
Casper:					/* we found a ghost !! */
	addi	r3, 0, ERR_ADDF		/* get indexed error message */
	bl	log_err			/* log error led error code */
gb_done: /*  pack your bags, and go home */
	lmw     r25, 8(r1)              /* restore r25 - r31 from stack */
	lwz     r0, +40(r1)             /* Get saved link register */
	addi    r1, r1, +36             /* Remove frame from stack */
	mtlr    r0                      /* Restore link register */
	blr                             /* Return to calling function */

/****************************************************
 ********      SDRAM data fill tests       **********
 ***************************************************/
Bit_Buster:
	/* called with mem size in r3 */
	/* save the return info on stack */
	mflr	r0			/* Get link register */
	stwu	r1, -16(r1)		/* Save back chain and move SP */
	stw	r0, +20(r1)		/* Save link register */
	stw	r4, +8(r1)		/* save R4 */
	stw	r5, +12(r1)		/* save r5 */

	addis	r5, r3, 0		/* save mem size */

	/* Test 55555555 */
	addi	r3, 0, ERR_R55G		/* set up error code in case we fail */
	bl	log_stat		/* store test value */
	addis	r4, 0, 0x5555
	ori	r4, r4, 0x5555
	bl	fill_test

	/* Test aaaaaaaa  */
	addi	r3, 0, ERR_RAAG		/* set up error code in case we fail */
	bl	log_stat		/* store test value */
	addis	r4, 0, 0xAAAA
	ori	r4, r4, 0xAAAA
	bl	fill_test

	/* Test 00000000  */
	addi	r3, 0, ERR_R00G		/* set up error code in case we fail */
	bl	log_stat		/* store test value */
	addis	r4, 0, 0
	ori	r4, r4, 0
	bl	fill_test

	/* restore stack and return */
	lwz	r5, +12(r1)		/* restore r4 */
	lwz	r4, +8(r1)		/* restore r4 */
	lwz	r0, +20(r1)		/* Get saved link register */
	addi	r1, r1, +16		/* Remove frame from stack */
	mtlr	r0			/* Restore link register */
	blr				/* Return to calling function */


/****************************************************
 ********             fill test              ********
 ***************************************************/
/*	tests memory by filling with value, and reading back */
/*	r5 = Size of memory in bytes */
/*	r4 = Value to write */
/*	r3 = Error code */
fill_test:
	mflr    r0                      /* Get link register */
	stwu    r1, -32(r1)             /* Save back chain and move SP */
	stw     r0, +36(r1)             /* Save link register */
	stmw    r27, 8(r1)              /* save r27 - r31 on stack */
					/* r31 - scratch register */
					/* r30 - memory address */
	mr	r27, r3
	mr	r28, r4
	mr	r29, r5

	WATCHDOG_RESET			/* Reset the watchdog */

	/* first fill memory with Value */
	srawi	r31, r29, 2		/* convert bytes to longs */
	mtctr	r31			/* setup counter */
	addi	r30, 0, 0		/* Make r30 = addr 0 */
ft_0:	stw	r28, 0(r30)		/* Store value */
	addi	r30, r30, 4		/* Increment to next word */
	andi.	r31, r30, 0xffff	/* check for 2^16 loops */
	bne	ft_0a			/* if not there, then skip */
	WATCHDOG_RESET			/* kick the dog every now and then */
ft_0a:	bdnz	ft_0			/* Round and round... */

	WATCHDOG_RESET			/* Reset the watchdog */

	/* Now confirm Value is in memory */
	srawi	r31, r29, 2		/* convert bytes to longs */
	mtctr	r31			/* setup counter */
	addi	r30, 0, 0		/* Make r30 = addr 0 */
ft_1:	lwz	r31, 0(r30)		/* get value from memory */
	xor.	r31, r31, r28		/* Writen = Read ? */
	bne	ft_err			/* If bad, than halt */
	addi	r30, r30, 4		/* Increment to next word */
	andi.	r31, r30, 0xffff	/* check for 2^16 loops*/
	bne	ft_1a			/* if not there, then skip */
	WATCHDOG_RESET			/* kick the dog every now and then */
ft_1a:	bdnz	ft_1			/* Round and round... */

	WATCHDOG_RESET			/* Reset the watchdog */

	b	fill_done		/* restore and return */

ft_err:	addi	r29, r27, 0		/* save current led code */
	addi	r27, r31, 0		/* get pattern in r27 */
	bl	get_idx			/* get index from r27 */
	add	r27, r27, r29		/* add index to old led code */
	bl	log_err			/* output led err code, halt CPU */

fill_done:
	lmw     r27, 8(r1)              /* restore r27 - r31 from stack */
	lwz     r0, +36(r1)             /* Get saved link register */
	addi    r1, r1, +32             /* Remove frame from stack */
	mtlr    r0                      /* Restore link register */
	blr                             /* Return to calling function */


/****************************************************
 *******  get error index from r3 pattern    ********
 ***************************************************/
get_idx:				/* r3 = (MSW(r3) !=0)*2 +
					    (LSW(r3) !=0) */
	/* save the return info on stack */
	mflr	r0			/* Get link register */
	stwu	r1, -12(r1)		/* Save back chain and move SP */
	stw	r0, +16(r1)		/* Save link register */
	stw	r4, +8(r1)		/* save R4 */

	andi.	r4, r3, 0xffff		/* check for lower bits */
	beq	gi2			/* skip if no bits set */
	andis.	r4, r3, 0xffff		/* check for upper bits */
	beq	gi3			/* skip if no bits set */
	addi	r3, 0, 3		/* both upper and lower bits set */
	b	gi_done
gi2:	andis.	r4, r3, 0xffff		/* check for upper bits*/
	beq	gi4			/* skip if no bits set */
	addi	r3, 0, 2		/* only upper bits set */
	b	gi_done
gi3:	addi	r3, 0, 1		/* only lower bits set */
	b	gi_done
gi4:	addi	r3, 0, 0		/* no bits set */
gi_done:
	/* restore stack and return */
	lwz	r0, +16(r1)		/* Get saved link register */
	mtlr	r0			/* Restore link register */
	lwz	r4, +8(r1)		/* restore r4 */
	addi	r1, r1, +12		/* Remove frame from stack */
	blr				/* Return to calling function */

/****************************************************
 ********       set LED to R5 and hang       ********
 ***************************************************/
log_stat:				/* output a led code and continue */
set_led:
	/* save the return info on stack */
	mflr	r0			/* Get link register */
	stwu	r1, -12(r1)		/* Save back chain and move SP */
	stw	r0, +16(r1)		/* Save link register */
	stw	r4, +8(r1)		/* save R4 */

	addis	r4, 0, 0xfe00		/* LED buffer is at 0xfe000000 */
#if defined(CONFIG_W7OLMG)		/* only on gateway, invert outputs */
	xori	r3,r3, 0xffff		/* complement led code, active low */
	sth	r3, 0(r4)		/* store first test value */
	xori	r3,r3, 0xffff		/* complement led code, active low */
#else					/* if not gateway, then don't invert */
	sth	r3, 0(r4)		/* store first test value */
#endif

	/* restore stack and return */
	lwz	r0, +16(r1)		/* Get saved link register */
	mtlr	r0			/* Restore link register */
	lwz	r4, +8(r1)		/* restore r4 */
	addi	r1, r1, +12		/* Remove frame from stack */
	blr				/* Return to calling function */

get_led:
	/* save the return info on stack */
	mflr	r0			/* Get link register */
	stwu	r1, -12(r1)		/* Save back chain and move SP */
	stw	r0, +16(r1)		/* Save link register */
	stw	r4, +8(r1)		/* save R4 */

	addis	r4, 0, 0xfe00		/* LED buffer is at 0xfe000000 */
	lhz	r3, 0(r4)		/* store first test value */
#if defined(CONFIG_W7OLMG)		/* only on gateway, invert inputs */
	xori	r3,r3, 0xffff		/* complement led code, active low */
#endif

	/* restore stack and return */
	lwz	r0, +16(r1)		/* Get saved link register */
	mtlr	r0			/* Restore link register */
	lwz	r4, +8(r1)		/* restore r4 */
	addi	r1, r1, +12		/* Remove frame from stack */
	blr				/* Return to calling function */

log_err:	/* output the error and hang the board ( for now ) */
	/* save the return info on stack */
	mflr	r0			/* Get link register */
	stwu	r1, -12(r1)		/* Save back chain and move SP */
	stw	r0, +16(r1)		/* Save link register */
	stw	r3, +8(r1)		/* save a copy of error code */
	bl	set_led			/* set the led pattern */
	GET_GOT				/* get GOT address in r14 */
	lwz	r3,GOT(err_str)		/* get address of string */
	bl	post_puts		/* output the warning string */
	lwz	r3, +8(r1)		/* get error code */
	addi	r4, 0, 2		/* set disp length to 2 nibbles */
	bl	disp_hex		/* output the error code */
	lwz	r3,GOT(end_str)		/* get address of string */
	bl	post_puts		/* output the warning string */
halt:
	b	halt			/* hang */

	/* restore stack and return */
	lwz	r0, +16(r1)		/* Get saved link register */
	mtlr	r0			/* Restore link register */
	addi	r1, r1, +12		/* Remove frame from stack */
	blr				/* Return to calling function */

log_warn:	/* output a warning, then continue with operations */
	/* save the return info on stack */
	mflr	r0			/* Get link register */
	stwu	r1, -16(r1)		/* Save back chain and move SP */
	stw	r0, +20(r1)		/* Save link register */
	stw	r3, +8(r1)		/* save a copy of error code */
	stw	r14, +12(r1)		/* save a copy of r14 (used by GOT) */

	bl	set_led			/* set the led pattern */
	GET_GOT				/* get GOT address in r14 */
	lwz	r3,GOT(warn_str)	/* get address of string */
	bl	post_puts		/* output the warning string */
	lwz	r3, +8(r1)		/* get error code */
	addi	r4, 0, 2		/* set disp length to 2 nibbles */
	bl	disp_hex		/* output the error code */
	lwz	r3,GOT(end_str)		/* get address of string */
	bl	post_puts		/* output the warning string */

	addis	r3, 0, 64		/* has a long delay */
	mtctr	r3
log_2:
	WATCHDOG_RESET			/* this keeps dog from barking, */
					/*   and takes time */
	bdnz	log_2			/* loop till time expires */

	/* restore stack and return */
	lwz	r0, +20(r1)		/* Get saved link register */
	lwz	r14, +12(r1)		/* restore r14 */
	mtlr	r0			/* Restore link register */
	addi	r1, r1, +16		/* Remove frame from stack */
	blr				/* Return to calling function */

/*******************************************************************
 *	temp_uart_init
 *	Temporary UART initialization routine
 *	Sets up UART0 to run at 9600N81 off of the internal clock.
 *	R3-R4 are used.
 ******************************************************************/
temp_uart_init:
	/* save the return info on stack */
	mflr	r0			/* Get link register */
	stwu	r1, -8(r1)		/* Save back chain and move SP */
	stw	r0, +12(r1)		/* Save link register */

	addis   r3, 0, 0xef60
	ori     r3, r3, 0x0303          /* r3 = UART0_LCR */
	addi    r4, 0, 0x83             /* n81 format, divisor regs enabled */
	stb     r4, 0(r3)

	/* set baud rate to use internal clock,
	   baud = (200e6/16)/31/42 = 9600 */

	addis   r3, 0, 0xef60		/* Address of baud divisor reg */
	ori     r3, r3, 0x0300		/*   UART0_DLM */
	addi    r4, 0, +42		/* uart baud divisor LSB = 93 */
	stb     r4, 0(r3)               /* baud = (200 /16)/14/93 */

	addi    r3, r3, 0x0001		/* uart baud divisor addr */
	addi    r4, 0, 0
	stb     r4, 0(r3)               /* Divisor Latch MSB = 0 */

	addis   r3, 0, 0xef60
	ori     r3, r3, 0x0303          /* r3 = UART0_LCR */
	addi    r4, 0, 0x03             /* n81 format, tx/rx regs enabled */
	stb     r4, 0(r3)

	/* output a few line feeds */
	addi	r3, 0, '\n'		/* load line feed */
	bl	post_putc		/* output the char */
	addi	r3, 0, '\n'		/* load line feed */
	bl	post_putc		/* output the char */

	/* restore stack and return */
	lwz	r0, +12(r1)		/* Get saved link register */
	mtlr	r0			/* Restore link register */
	addi	r1, r1, +8		/* Remove frame from stack */
	blr				/* Return to calling function */

/**********************************************************************
 **	post_putc
 **	outputs charactor in R3
 **	r3 returns the error code ( -1 if there is an error )
 *********************************************************************/

post_putc:

	/* save the return info on stack */
	mflr	r0			/* Get link register */
	stwu	r1, -20(r1)		/* Save back chain and move SP */
	stw	r0, +24(r1)		/* Save link register */
	stmw	r29, 8(r1)		/* save	r29 - r31 on stack
					   r31 - uart base address
					   r30 - delay counter
					   r29 - scratch reg */

     addis   r31, 0, 0xef60		/* Point to uart base */
     ori     r31, r31, 0x0300
     addis   r30, 0, 152		/* Load about 10,000,000 ticks. */
pputc_lp:
	lbz     r29, 5(r31)		/* Read Line Status Register */
	andi.   r29, r29, 0x20		/* Check THRE status */
	bne     thre_set		/* Branch if FIFO empty */
	addic.  r30, r30, -1		/* Decrement and check if empty. */
	bne     pputc_lp		/* Try, try again */
	addi    r3, 0, -1		/* Load error code for timeout */
	b       pputc_done		/* Bail out with error code set */
thre_set:
	stb     r3, 0(r31)		/* Store character to UART */
	addi	r3, 0, 0		/* clear error code */
pputc_done:
	lmw	r29, 8(r1)		/*restore r29 - r31 from stack */
	lwz	r0, +24(r1)		/* Get saved link register */
	addi	r1, r1, +20		/* Remove frame from stack */
	mtlr	r0			/* Restore link register */
	blr				/* Return to calling function */


/****************************************************************
    post_puts
    Accepts a null-terminated string pointed to by R3
    Outputs to the serial port until 0x00 is found.
    r3 returns the error code ( -1 if there is an error )
*****************************************************************/
post_puts:

	/* save the return info on stack */
	mflr	r0			/* Get link register */
	stwu	r1, -12(r1)		/* Save back chain and move SP */
	stw	r0, +16(r1)		/* Save link register */
	stw	r31, 8(r1)		/* save r31 - char pointer */

	addi	r31, r3, 0              /* move pointer to R31 */
pputs_nxt:
	lbz	r3, 0(r31)		/* Get next character */
	addic.  r3, r3, 0		/* Check for zero */
	beq	pputs_term		/* bail out if zero */
	bl	post_putc		/* output the char */
	addic.	r3, r3, 0		/* check for error */
	bne	pputs_err
	addi	r31, r31, 1		/* point to next char */
	b	pputs_nxt		/* loop till term */
pputs_err:
	addi	r3, 0, -1		/* set error code */
	b	pputs_end		/* were outa here */
pputs_term:
	addi	r3, 0, 1		/* set success code */
	/* restore stack and return */
pputs_end:
	lwz	r31, 8(r1)		/* restore r27 - r31 from stack */
	lwz	r0, +16(r1)		/* Get saved link register */
	addi	r1, r1, +12		/* Remove frame from stack */
	mtlr	r0			/* Restore link register */
	blr				/* Return to calling function */


/********************************************************************
 *****	disp_hex
 *****	Routine to display a hex value from a register.
 *****	R3 is value to display
 *****	R4 is number of nibbles to display ie 2 for byte 8 for (long)word
 *****	Returns -1 in R3 if there is an error ( ie serial port hangs )
 *****	Returns 0 in R3 if no error
 *******************************************************************/
disp_hex:
	/* save the return info on stack */
	mflr	r0			/* Get link register */
	stwu	r1, -16(r1)		/* Save back chain and move SP */
	stw	r0, +20(r1)		/* Save link register */
	stmw	r30, 8(r1)		/* save r30 - r31 on stack */
					/* r31 output char */
					/* r30 uart base address */
	addi	r30, 0, 8               /* Go through 8 nibbles. */
	addi	r31, r3, 0
pputh_nxt:
	rlwinm	r31, r31, 4, 0, 31	/* Rotate next nibble into position */
	andi.	r3, r31, 0x0f		/* Get nibble. */
	addi	r3, r3, 0x30		/* Add zero's ASCII code. */
	cmpwi	r3, 0x03a
	blt	pputh_out
	addi	r3, r3, 0x07            /* 0x27 for lower case. */
pputh_out:
	cmpw	r30, r4
	bgt	pputh_skip
	bl	post_putc
	addic.	r3, r3, 0		/* check for error */
	bne	pputh_err
pputh_skip:
	addic.	r30, r30, -1
	bne	pputh_nxt
	xor	r3, r3, r3		/* Clear error code */
	b	pputh_done
pputh_err:
	addi	r3, 0, -1		/* set error code */
pputh_done:
	/* restore stack and return */
	lmw	r30, 8(r1)		/*  restore r30 - r31 from stack */
	lwz	r0, +20(r1)		/* Get saved link register */
	addi	r1, r1, +16		/* Remove frame from stack */
	mtlr	r0			/* Restore link register */
	blr				/* Return to calling function */