1/* 2 * (C) Copyright 2001 3 * Bill Hunter, Wave 7 Optics, william.hunter@mediaone.net 4 * and 5 * Erik Theisen, Wave 7 Optics, etheisen@mindspring.com 6 * 7 * See file CREDITS for list of people who contributed to this 8 * project. 9 * 10 * This program is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU General Public License as 12 * published by the Free Software Foundation; either version 2 of 13 * the License, or (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 23 * MA 02111-1307 USA 24 */ 25/* 26 * Description: 27 * Routine to exercise memory for the bringing up of our boards. 28 */ 29#include <config.h> 30#include <ppc4xx.h> 31 32#define _LINUX_CONFIG_H 1 /* avoid reading Linux autoconf.h file */ 33 34#include <ppc_asm.tmpl> 35#include <ppc_defs.h> 36 37#include <asm/cache.h> 38#include <asm/mmu.h> 39 40#include <watchdog.h> 41 42#include "errors.h" 43 44#define _ASMLANGUAGE 45 46 .globl test_sdram 47 .globl test_led 48 .globl log_stat 49 .globl log_warn 50 .globl log_err 51 .globl temp_uart_init 52 .globl post_puts 53 .globl disp_hex 54 55/***************************************************** 56******* Text Strings for low level printing ****** 57******* In section got2 ******* 58*****************************************************/ 59 60/* 61 * Define the text strings for errors and warnings. 62 * Switch to .data section. 63 */ 64 .section ".data" 65err_str: .asciz "*** POST ERROR = " 66warn_str: .asciz "*** POST WARNING = " 67end_str: .asciz "\r\n" 68 69/* 70 * Enter the labels in Global Entry Table (GOT). 71 * Switch to .got2 section. 72 */ 73 START_GOT 74 GOT_ENTRY(err_str) 75 GOT_ENTRY(warn_str) 76 GOT_ENTRY(end_str) 77 END_GOT 78 79/* 80 * Switch back to .text section. 81 */ 82 .text 83 84/**************************************** 85 **************************************** 86 ******** LED register test ******** 87 **************************************** 88 ***************************************/ 89test_led: 90 /* save the return info on stack */ 91 mflr r0 /* Get link register */ 92 stwu r1, -12(r1) /* Save back chain and move SP */ 93 stw r0, +16(r1) /* Save link register */ 94 stw r4, +8(r1) /* save R4 */ 95 96 WATCHDOG_RESET /* Reset the watchdog */ 97 98 addi r3, 0, ERR_FF /* first test value is ffff */ 99 addi r4, r3, 0 /* save copy of pattern */ 100 bl set_led /* store first test value */ 101 bl get_led /* read it back */ 102 xor. r4, r4, r3 /* compare to original */ 103#if defined(CONFIG_W7OLMC) 104 andi. r4, r4, 0x00ff /* lmc has 8 bits */ 105#else 106 andi. r4, r4, 0xffff /* lmg has 16 bits */ 107#endif 108 beq LED2 /* next test */ 109 addi r3, 0, ERR_LED /* error code = 1 */ 110 bl log_err /* display error and halt */ 111LED2: addi r3, 0, ERR_00 /* 2nd test value is 0000 */ 112 addi r4, r3, 0 /* save copy of pattern */ 113 bl set_led /* store first test value */ 114 bl get_led /* read it back */ 115 xor. r4, r4, r3 /* compare to original */ 116#if defined(CONFIG_W7OLMC) 117 andi. r4, r4, 0x00ff /* lmc has 8 bits */ 118#else 119 andi. r4, r4, 0xffff /* lmg has 16 bits */ 120#endif 121 beq LED3 /* next test */ 122 addi r3, 0, ERR_LED /* error code = 1 */ 123 bl log_err /* display error and halt */ 124 125LED3: /* restore stack and return */ 126 lwz r0, +16(r1) /* Get saved link register */ 127 mtlr r0 /* Restore link register */ 128 lwz r4, +8(r1) /* restore r4 */ 129 addi r1, r1, +12 /* Remove frame from stack */ 130 blr /* Return to calling function */ 131 132/**************************************** 133 **************************************** 134 ******** SDRAM TESTS ******** 135 **************************************** 136 ***************************************/ 137test_sdram: 138 /* called with mem size in r3 */ 139 /* save the return info on stack */ 140 mflr r0 /* Get link register */ 141 stwu r1, -16(r1) /* Save back chain and move SP */ 142 stw r0, +20(r1) /* Save link register */ 143 stmw r30, +8(r1) /* save R30,R31 */ 144 /* r30 is log2(mem size) */ 145 /* r31 is mem size */ 146 147 /* take log2 of total mem size */ 148 addi r31, r3, 0 /* save total mem size */ 149 addi r30, 0, 0 /* clear r30 */ 150l2_loop: 151 srwi. r31, r31, 1 /* shift right 1 */ 152 addi r30, r30, 1 /* count shifts */ 153 bne l2_loop /* loop till done */ 154 addi r30, r30, -1 /* correct for over count */ 155 addi r31, r3, 0 /* save original size */ 156 157 /* now kick the dog and test the mem */ 158 WATCHDOG_RESET /* Reset the watchdog */ 159 bl Data_Buster /* test crossed/shorted data lines */ 160 addi r3, r30, 0 /* get log2(memsize) */ 161 addi r4, r31, 0 /* get memsize */ 162 bl Ghost_Buster /* test crossed/shorted addr lines */ 163 addi r3, r31, 0 /* get mem size */ 164 bl Bit_Buster /* check for bad internal bits */ 165 166 /* restore stack and return */ 167 lmw r30, +8(r1) /* Restore r30, r31 */ 168 lwz r0, +20(r1) /* Get saved link register */ 169 mtlr r0 /* Restore link register */ 170 addi r1, r1, +16 /* Remove frame from stack */ 171 blr /* Return to calling function */ 172 173 174/**************************************** 175 ******** sdram data bus test ******** 176 ***************************************/ 177Data_Buster: 178 /* save the return info on stack */ 179 mflr r0 /* Get link register */ 180 stwu r1, -24(r1) /* Save back chain and move SP */ 181 stw r0, +28(r1) /* Save link register */ 182 stmw r28, 8(r1) /* save r28 - r31 on stack */ 183 /* r31 i/o register */ 184 /* r30 sdram base address */ 185 /* r29 5555 syndrom */ 186 /* r28 aaaa syndrom */ 187 188 /* set up led register for this test */ 189 addi r3, 0, ERR_RAMG /* set led code to 1 */ 190 bl log_stat /* store test value */ 191 /* now test the dram data bus */ 192 xor r30, r30, r30 /* load r30 with base addr of sdram */ 193 addis r31, 0, 0x5555 /* load r31 with test value */ 194 ori r31, r31, 0x5555 195 stw r31,0(r30) /* sto the value */ 196 lwz r29,0(r30) /* read it back */ 197 xor r29,r31,r29 /* compare it to original */ 198 addis r31, 0, 0xaaaa /* load r31 with test value */ 199 ori r31, r31, 0xaaaa 200 stw r31,0(r30) /* sto the value */ 201 lwz r28,0(r30) /* read it back */ 202 xor r28,r31,r28 /* compare it to original */ 203 or r3,r28,r29 /* or together both error terms */ 204 /* 205 * Now that we have the error bits, 206 * we have to decide which part they are in. 207 */ 208 bl get_idx /* r5 is now index to error */ 209 addi r3, r3, ERR_RAMG 210 cmpwi r3, ERR_RAMG /* check for errors */ 211 beq db_done /* skip if no errors */ 212 bl log_err /* log the error */ 213 214db_done: 215 lmw r28, 8(r1) /* restore r28 - r31 from stack */ 216 lwz r0, +28(r1) /* Get saved link register */ 217 addi r1, r1, +24 /* Remove frame from stack */ 218 mtlr r0 /* Restore link register */ 219 blr /* Return to calling function */ 220 221 222/**************************************************** 223 ******** test for address ghosting in dram ******** 224 ***************************************************/ 225 226Ghost_Buster: 227 /* save the return info on stack */ 228 mflr r0 /* Get link register */ 229 stwu r1, -36(r1) /* Save back chain and move SP */ 230 stw r0, +40(r1) /* Save link register */ 231 stmw r25, 8(r1) /* save r25 - r31 on stack */ 232 /* r31 = scratch register */ 233 /* r30 is main referance loop counter, 234 0 to 23 */ 235 /* r29 is ghost loop count, 0 to 22 */ 236 /* r28 is referance address */ 237 /* r27 is ghost address */ 238 /* r26 is log2 (mem size) = 239 number of byte addr bits */ 240 /* r25 is mem size */ 241 242 /* save the log2(mem size) and mem size */ 243 addi r26, r3, 0 /* r26 is number of byte addr bits */ 244 addi r25, r4, 0 /* r25 is mem size in bytes */ 245 246 /* set the leds for address ghost test */ 247 addi r3, 0, ERR_ADDG 248 bl set_led 249 250 /* first fill memory with zeros */ 251 srwi r31, r25, 2 /* convert bytes to longs */ 252 mtctr r31 /* setup byte counter */ 253 addi r28, 0, 0 /* start at address at 0 */ 254 addi r31, 0, 0 /* data value = 0 */ 255clr_loop: 256 stw r31, 0(r28) /* Store zero value */ 257 addi r28, r28, 4 /* Increment to next word */ 258 andi. r27, r28, 0xffff /* check for 2^16 loops */ 259 bne clr_skip /* if not there, then skip */ 260 WATCHDOG_RESET /* kick the dog every now and then */ 261clr_skip: 262 bdnz clr_loop /* Round and round... */ 263 264 /* now do main test */ 265 addi r30, 0, 0 /* start referance counter at 0 */ 266outside: 267 /* 268 * Calculate the referance address 269 * the referance address is calculated by setting the (r30-1) 270 * bit of the base address 271 * when r30=0, the referance address is the base address. 272 * thus the sequence 0,1,2,4,8,..,2^(n-1) 273 * setting the bit is done with the following shift functions. 274 */ 275 WATCHDOG_RESET /* Reset the watchdog */ 276 277 addi r31, 0, 1 /* r31 = 1 */ 278 slw r28, r31, r30 /* set bit coresponding to loop cnt */ 279 srwi r28, r28, 1 /* then shift it right one so */ 280 /* we start at location 0 */ 281 /* fill referance address with Fs */ 282 addi r31, 0, 0x00ff /* r31 = one byte of set bits */ 283 stb r31,0(r28) /* save ff in referance address */ 284 285 /* ghost (inner) loop, now check all posible ghosted addresses */ 286 addi r29, 0, 0 /* start ghosted loop counter at 0 */ 287inside: 288 /* 289 * Calculate the ghost address by flipping one 290 * bit of referance address. This gives the 291 * sequence 1,2,4,8,...,2^(n-1) 292 */ 293 addi r31, 0, 1 /* r31 = 1 */ 294 slw r27, r31, r29 /* set bit coresponding to loop cnt */ 295 xor r27, r28, r27 /* ghost address = ref addr with 296 bit flipped*/ 297 298 /* now check for ghosting */ 299 lbz r31,0(r27) /* get content of ghost addr */ 300 cmpwi r31, 0 /* compare read value to 0 */ 301 bne Casper /* we found a ghost! */ 302 303 /* now close ghost ( inner ) loop */ 304 addi r29, r29, 1 /* increment inner loop counter */ 305 cmpw r29, r26 /* check for last inner loop */ 306 blt inside /* do more inner loops */ 307 308 /* now close referance ( outer ) loop */ 309 addi r31, 0, 0 /* r31 = zero */ 310 stb r31, 0(28) /* zero out the altered address loc. */ 311 /* 312 * Increment and check for end, count is zero based. 313 * With the ble, this gives us one more loops than 314 * address bits for sequence 0,1,2,4,8,...2^(n-1) 315 */ 316 addi r30, r30, 1 /* increment outer loop counter */ 317 cmpw r30, r26 /* check for last inner loop */ 318 ble outside /* do more outer loops */ 319 320 /* were done, lets go home */ 321 b gb_done 322Casper: /* we found a ghost !! */ 323 addi r3, 0, ERR_ADDF /* get indexed error message */ 324 bl log_err /* log error led error code */ 325gb_done: /* pack your bags, and go home */ 326 lmw r25, 8(r1) /* restore r25 - r31 from stack */ 327 lwz r0, +40(r1) /* Get saved link register */ 328 addi r1, r1, +36 /* Remove frame from stack */ 329 mtlr r0 /* Restore link register */ 330 blr /* Return to calling function */ 331 332/**************************************************** 333 ******** SDRAM data fill tests ********** 334 ***************************************************/ 335Bit_Buster: 336 /* called with mem size in r3 */ 337 /* save the return info on stack */ 338 mflr r0 /* Get link register */ 339 stwu r1, -16(r1) /* Save back chain and move SP */ 340 stw r0, +20(r1) /* Save link register */ 341 stw r4, +8(r1) /* save R4 */ 342 stw r5, +12(r1) /* save r5 */ 343 344 addis r5, r3, 0 /* save mem size */ 345 346 /* Test 55555555 */ 347 addi r3, 0, ERR_R55G /* set up error code in case we fail */ 348 bl log_stat /* store test value */ 349 addis r4, 0, 0x5555 350 ori r4, r4, 0x5555 351 bl fill_test 352 353 /* Test aaaaaaaa */ 354 addi r3, 0, ERR_RAAG /* set up error code in case we fail */ 355 bl log_stat /* store test value */ 356 addis r4, 0, 0xAAAA 357 ori r4, r4, 0xAAAA 358 bl fill_test 359 360 /* Test 00000000 */ 361 addi r3, 0, ERR_R00G /* set up error code in case we fail */ 362 bl log_stat /* store test value */ 363 addis r4, 0, 0 364 ori r4, r4, 0 365 bl fill_test 366 367 /* restore stack and return */ 368 lwz r5, +12(r1) /* restore r4 */ 369 lwz r4, +8(r1) /* restore r4 */ 370 lwz r0, +20(r1) /* Get saved link register */ 371 addi r1, r1, +16 /* Remove frame from stack */ 372 mtlr r0 /* Restore link register */ 373 blr /* Return to calling function */ 374 375 376/**************************************************** 377 ******** fill test ******** 378 ***************************************************/ 379/* tests memory by filling with value, and reading back */ 380/* r5 = Size of memory in bytes */ 381/* r4 = Value to write */ 382/* r3 = Error code */ 383fill_test: 384 mflr r0 /* Get link register */ 385 stwu r1, -32(r1) /* Save back chain and move SP */ 386 stw r0, +36(r1) /* Save link register */ 387 stmw r27, 8(r1) /* save r27 - r31 on stack */ 388 /* r31 - scratch register */ 389 /* r30 - memory address */ 390 mr r27, r3 391 mr r28, r4 392 mr r29, r5 393 394 WATCHDOG_RESET /* Reset the watchdog */ 395 396 /* first fill memory with Value */ 397 srawi r31, r29, 2 /* convert bytes to longs */ 398 mtctr r31 /* setup counter */ 399 addi r30, 0, 0 /* Make r30 = addr 0 */ 400ft_0: stw r28, 0(r30) /* Store value */ 401 addi r30, r30, 4 /* Increment to next word */ 402 andi. r31, r30, 0xffff /* check for 2^16 loops */ 403 bne ft_0a /* if not there, then skip */ 404 WATCHDOG_RESET /* kick the dog every now and then */ 405ft_0a: bdnz ft_0 /* Round and round... */ 406 407 WATCHDOG_RESET /* Reset the watchdog */ 408 409 /* Now confirm Value is in memory */ 410 srawi r31, r29, 2 /* convert bytes to longs */ 411 mtctr r31 /* setup counter */ 412 addi r30, 0, 0 /* Make r30 = addr 0 */ 413ft_1: lwz r31, 0(r30) /* get value from memory */ 414 xor. r31, r31, r28 /* Writen = Read ? */ 415 bne ft_err /* If bad, than halt */ 416 addi r30, r30, 4 /* Increment to next word */ 417 andi. r31, r30, 0xffff /* check for 2^16 loops*/ 418 bne ft_1a /* if not there, then skip */ 419 WATCHDOG_RESET /* kick the dog every now and then */ 420ft_1a: bdnz ft_1 /* Round and round... */ 421 422 WATCHDOG_RESET /* Reset the watchdog */ 423 424 b fill_done /* restore and return */ 425 426ft_err: addi r29, r27, 0 /* save current led code */ 427 addi r27, r31, 0 /* get pattern in r27 */ 428 bl get_idx /* get index from r27 */ 429 add r27, r27, r29 /* add index to old led code */ 430 bl log_err /* output led err code, halt CPU */ 431 432fill_done: 433 lmw r27, 8(r1) /* restore r27 - r31 from stack */ 434 lwz r0, +36(r1) /* Get saved link register */ 435 addi r1, r1, +32 /* Remove frame from stack */ 436 mtlr r0 /* Restore link register */ 437 blr /* Return to calling function */ 438 439 440/**************************************************** 441 ******* get error index from r3 pattern ******** 442 ***************************************************/ 443get_idx: /* r3 = (MSW(r3) !=0)*2 + 444 (LSW(r3) !=0) */ 445 /* save the return info on stack */ 446 mflr r0 /* Get link register */ 447 stwu r1, -12(r1) /* Save back chain and move SP */ 448 stw r0, +16(r1) /* Save link register */ 449 stw r4, +8(r1) /* save R4 */ 450 451 andi. r4, r3, 0xffff /* check for lower bits */ 452 beq gi2 /* skip if no bits set */ 453 andis. r4, r3, 0xffff /* check for upper bits */ 454 beq gi3 /* skip if no bits set */ 455 addi r3, 0, 3 /* both upper and lower bits set */ 456 b gi_done 457gi2: andis. r4, r3, 0xffff /* check for upper bits*/ 458 beq gi4 /* skip if no bits set */ 459 addi r3, 0, 2 /* only upper bits set */ 460 b gi_done 461gi3: addi r3, 0, 1 /* only lower bits set */ 462 b gi_done 463gi4: addi r3, 0, 0 /* no bits set */ 464gi_done: 465 /* restore stack and return */ 466 lwz r0, +16(r1) /* Get saved link register */ 467 mtlr r0 /* Restore link register */ 468 lwz r4, +8(r1) /* restore r4 */ 469 addi r1, r1, +12 /* Remove frame from stack */ 470 blr /* Return to calling function */ 471 472/**************************************************** 473 ******** set LED to R5 and hang ******** 474 ***************************************************/ 475log_stat: /* output a led code and continue */ 476set_led: 477 /* save the return info on stack */ 478 mflr r0 /* Get link register */ 479 stwu r1, -12(r1) /* Save back chain and move SP */ 480 stw r0, +16(r1) /* Save link register */ 481 stw r4, +8(r1) /* save R4 */ 482 483 addis r4, 0, 0xfe00 /* LED buffer is at 0xfe000000 */ 484#if defined(CONFIG_W7OLMG) /* only on gateway, invert outputs */ 485 xori r3,r3, 0xffff /* complement led code, active low */ 486 sth r3, 0(r4) /* store first test value */ 487 xori r3,r3, 0xffff /* complement led code, active low */ 488#else /* if not gateway, then don't invert */ 489 sth r3, 0(r4) /* store first test value */ 490#endif 491 492 /* restore stack and return */ 493 lwz r0, +16(r1) /* Get saved link register */ 494 mtlr r0 /* Restore link register */ 495 lwz r4, +8(r1) /* restore r4 */ 496 addi r1, r1, +12 /* Remove frame from stack */ 497 blr /* Return to calling function */ 498 499get_led: 500 /* save the return info on stack */ 501 mflr r0 /* Get link register */ 502 stwu r1, -12(r1) /* Save back chain and move SP */ 503 stw r0, +16(r1) /* Save link register */ 504 stw r4, +8(r1) /* save R4 */ 505 506 addis r4, 0, 0xfe00 /* LED buffer is at 0xfe000000 */ 507 lhz r3, 0(r4) /* store first test value */ 508#if defined(CONFIG_W7OLMG) /* only on gateway, invert inputs */ 509 xori r3,r3, 0xffff /* complement led code, active low */ 510#endif 511 512 /* restore stack and return */ 513 lwz r0, +16(r1) /* Get saved link register */ 514 mtlr r0 /* Restore link register */ 515 lwz r4, +8(r1) /* restore r4 */ 516 addi r1, r1, +12 /* Remove frame from stack */ 517 blr /* Return to calling function */ 518 519log_err: /* output the error and hang the board ( for now ) */ 520 /* save the return info on stack */ 521 mflr r0 /* Get link register */ 522 stwu r1, -12(r1) /* Save back chain and move SP */ 523 stw r0, +16(r1) /* Save link register */ 524 stw r3, +8(r1) /* save a copy of error code */ 525 bl set_led /* set the led pattern */ 526 GET_GOT /* get GOT address in r14 */ 527 lwz r3,GOT(err_str) /* get address of string */ 528 bl post_puts /* output the warning string */ 529 lwz r3, +8(r1) /* get error code */ 530 addi r4, 0, 2 /* set disp length to 2 nibbles */ 531 bl disp_hex /* output the error code */ 532 lwz r3,GOT(end_str) /* get address of string */ 533 bl post_puts /* output the warning string */ 534halt: 535 b halt /* hang */ 536 537 /* restore stack and return */ 538 lwz r0, +16(r1) /* Get saved link register */ 539 mtlr r0 /* Restore link register */ 540 addi r1, r1, +12 /* Remove frame from stack */ 541 blr /* Return to calling function */ 542 543log_warn: /* output a warning, then continue with operations */ 544 /* save the return info on stack */ 545 mflr r0 /* Get link register */ 546 stwu r1, -16(r1) /* Save back chain and move SP */ 547 stw r0, +20(r1) /* Save link register */ 548 stw r3, +8(r1) /* save a copy of error code */ 549 stw r14, +12(r1) /* save a copy of r14 (used by GOT) */ 550 551 bl set_led /* set the led pattern */ 552 GET_GOT /* get GOT address in r14 */ 553 lwz r3,GOT(warn_str) /* get address of string */ 554 bl post_puts /* output the warning string */ 555 lwz r3, +8(r1) /* get error code */ 556 addi r4, 0, 2 /* set disp length to 2 nibbles */ 557 bl disp_hex /* output the error code */ 558 lwz r3,GOT(end_str) /* get address of string */ 559 bl post_puts /* output the warning string */ 560 561 addis r3, 0, 64 /* has a long delay */ 562 mtctr r3 563log_2: 564 WATCHDOG_RESET /* this keeps dog from barking, */ 565 /* and takes time */ 566 bdnz log_2 /* loop till time expires */ 567 568 /* restore stack and return */ 569 lwz r0, +20(r1) /* Get saved link register */ 570 lwz r14, +12(r1) /* restore r14 */ 571 mtlr r0 /* Restore link register */ 572 addi r1, r1, +16 /* Remove frame from stack */ 573 blr /* Return to calling function */ 574 575/******************************************************************* 576 * temp_uart_init 577 * Temporary UART initialization routine 578 * Sets up UART0 to run at 9600N81 off of the internal clock. 579 * R3-R4 are used. 580 ******************************************************************/ 581temp_uart_init: 582 /* save the return info on stack */ 583 mflr r0 /* Get link register */ 584 stwu r1, -8(r1) /* Save back chain and move SP */ 585 stw r0, +12(r1) /* Save link register */ 586 587 addis r3, 0, 0xef60 588 ori r3, r3, 0x0303 /* r3 = UART0_LCR */ 589 addi r4, 0, 0x83 /* n81 format, divisor regs enabled */ 590 stb r4, 0(r3) 591 592 /* set baud rate to use internal clock, 593 baud = (200e6/16)/31/42 = 9600 */ 594 595 addis r3, 0, 0xef60 /* Address of baud divisor reg */ 596 ori r3, r3, 0x0300 /* UART0_DLM */ 597 addi r4, 0, +42 /* uart baud divisor LSB = 93 */ 598 stb r4, 0(r3) /* baud = (200 /16)/14/93 */ 599 600 addi r3, r3, 0x0001 /* uart baud divisor addr */ 601 addi r4, 0, 0 602 stb r4, 0(r3) /* Divisor Latch MSB = 0 */ 603 604 addis r3, 0, 0xef60 605 ori r3, r3, 0x0303 /* r3 = UART0_LCR */ 606 addi r4, 0, 0x03 /* n81 format, tx/rx regs enabled */ 607 stb r4, 0(r3) 608 609 /* output a few line feeds */ 610 addi r3, 0, '\n' /* load line feed */ 611 bl post_putc /* output the char */ 612 addi r3, 0, '\n' /* load line feed */ 613 bl post_putc /* output the char */ 614 615 /* restore stack and return */ 616 lwz r0, +12(r1) /* Get saved link register */ 617 mtlr r0 /* Restore link register */ 618 addi r1, r1, +8 /* Remove frame from stack */ 619 blr /* Return to calling function */ 620 621/********************************************************************** 622 ** post_putc 623 ** outputs charactor in R3 624 ** r3 returns the error code ( -1 if there is an error ) 625 *********************************************************************/ 626 627post_putc: 628 629 /* save the return info on stack */ 630 mflr r0 /* Get link register */ 631 stwu r1, -20(r1) /* Save back chain and move SP */ 632 stw r0, +24(r1) /* Save link register */ 633 stmw r29, 8(r1) /* save r29 - r31 on stack 634 r31 - uart base address 635 r30 - delay counter 636 r29 - scratch reg */ 637 638 addis r31, 0, 0xef60 /* Point to uart base */ 639 ori r31, r31, 0x0300 640 addis r30, 0, 152 /* Load about 10,000,000 ticks. */ 641pputc_lp: 642 lbz r29, 5(r31) /* Read Line Status Register */ 643 andi. r29, r29, 0x20 /* Check THRE status */ 644 bne thre_set /* Branch if FIFO empty */ 645 addic. r30, r30, -1 /* Decrement and check if empty. */ 646 bne pputc_lp /* Try, try again */ 647 addi r3, 0, -1 /* Load error code for timeout */ 648 b pputc_done /* Bail out with error code set */ 649thre_set: 650 stb r3, 0(r31) /* Store character to UART */ 651 addi r3, 0, 0 /* clear error code */ 652pputc_done: 653 lmw r29, 8(r1) /*restore r29 - r31 from stack */ 654 lwz r0, +24(r1) /* Get saved link register */ 655 addi r1, r1, +20 /* Remove frame from stack */ 656 mtlr r0 /* Restore link register */ 657 blr /* Return to calling function */ 658 659 660/**************************************************************** 661 post_puts 662 Accepts a null-terminated string pointed to by R3 663 Outputs to the serial port until 0x00 is found. 664 r3 returns the error code ( -1 if there is an error ) 665*****************************************************************/ 666post_puts: 667 668 /* save the return info on stack */ 669 mflr r0 /* Get link register */ 670 stwu r1, -12(r1) /* Save back chain and move SP */ 671 stw r0, +16(r1) /* Save link register */ 672 stw r31, 8(r1) /* save r31 - char pointer */ 673 674 addi r31, r3, 0 /* move pointer to R31 */ 675pputs_nxt: 676 lbz r3, 0(r31) /* Get next character */ 677 addic. r3, r3, 0 /* Check for zero */ 678 beq pputs_term /* bail out if zero */ 679 bl post_putc /* output the char */ 680 addic. r3, r3, 0 /* check for error */ 681 bne pputs_err 682 addi r31, r31, 1 /* point to next char */ 683 b pputs_nxt /* loop till term */ 684pputs_err: 685 addi r3, 0, -1 /* set error code */ 686 b pputs_end /* were outa here */ 687pputs_term: 688 addi r3, 0, 1 /* set success code */ 689 /* restore stack and return */ 690pputs_end: 691 lwz r31, 8(r1) /* restore r27 - r31 from stack */ 692 lwz r0, +16(r1) /* Get saved link register */ 693 addi r1, r1, +12 /* Remove frame from stack */ 694 mtlr r0 /* Restore link register */ 695 blr /* Return to calling function */ 696 697 698/******************************************************************** 699 ***** disp_hex 700 ***** Routine to display a hex value from a register. 701 ***** R3 is value to display 702 ***** R4 is number of nibbles to display ie 2 for byte 8 for (long)word 703 ***** Returns -1 in R3 if there is an error ( ie serial port hangs ) 704 ***** Returns 0 in R3 if no error 705 *******************************************************************/ 706disp_hex: 707 /* save the return info on stack */ 708 mflr r0 /* Get link register */ 709 stwu r1, -16(r1) /* Save back chain and move SP */ 710 stw r0, +20(r1) /* Save link register */ 711 stmw r30, 8(r1) /* save r30 - r31 on stack */ 712 /* r31 output char */ 713 /* r30 uart base address */ 714 addi r30, 0, 8 /* Go through 8 nibbles. */ 715 addi r31, r3, 0 716pputh_nxt: 717 rlwinm r31, r31, 4, 0, 31 /* Rotate next nibble into position */ 718 andi. r3, r31, 0x0f /* Get nibble. */ 719 addi r3, r3, 0x30 /* Add zero's ASCII code. */ 720 cmpwi r3, 0x03a 721 blt pputh_out 722 addi r3, r3, 0x07 /* 0x27 for lower case. */ 723pputh_out: 724 cmpw r30, r4 725 bgt pputh_skip 726 bl post_putc 727 addic. r3, r3, 0 /* check for error */ 728 bne pputh_err 729pputh_skip: 730 addic. r30, r30, -1 731 bne pputh_nxt 732 xor r3, r3, r3 /* Clear error code */ 733 b pputh_done 734pputh_err: 735 addi r3, 0, -1 /* set error code */ 736pputh_done: 737 /* restore stack and return */ 738 lmw r30, 8(r1) /* restore r30 - r31 from stack */ 739 lwz r0, +20(r1) /* Get saved link register */ 740 addi r1, r1, +16 /* Remove frame from stack */ 741 mtlr r0 /* Restore link register */ 742 blr /* Return to calling function */ 743