| /* |
| * (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 */ |
| |