wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 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" |
Wolfgang Denk | a1be476 | 2008-05-20 16:00:29 +0200 | [diff] [blame] | 65 | err_str: .asciz "*** POST ERROR = " |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 66 | warn_str: .asciz "*** POST WARNING = " |
| 67 | end_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 | ***************************************/ |
| 89 | test_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 | |
Wolfgang Denk | a1be476 | 2008-05-20 16:00:29 +0200 | [diff] [blame] | 96 | WATCHDOG_RESET /* Reset the watchdog */ |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 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 */ |
| 111 | LED2: 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 | |
| 125 | LED3: /* 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 | ***************************************/ |
| 137 | test_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 */ |
| 150 | l2_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 */ |
Wolfgang Denk | a1be476 | 2008-05-20 16:00:29 +0200 | [diff] [blame] | 158 | WATCHDOG_RESET /* Reset the watchdog */ |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 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 | ***************************************/ |
| 177 | Data_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 | |
| 214 | db_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 | |
| 226 | Ghost_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 */ |
| 255 | clr_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 */ |
Wolfgang Denk | a1be476 | 2008-05-20 16:00:29 +0200 | [diff] [blame] | 260 | WATCHDOG_RESET /* kick the dog every now and then */ |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 261 | clr_skip: |
| 262 | bdnz clr_loop /* Round and round... */ |
| 263 | |
| 264 | /* now do main test */ |
| 265 | addi r30, 0, 0 /* start referance counter at 0 */ |
| 266 | outside: |
| 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 | */ |
Wolfgang Denk | a1be476 | 2008-05-20 16:00:29 +0200 | [diff] [blame] | 275 | WATCHDOG_RESET /* Reset the watchdog */ |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 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 | |
wdenk | 57b2d80 | 2003-06-27 21:31:46 +0000 | [diff] [blame] | 285 | /* ghost (inner) loop, now check all posible ghosted addresses */ |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 286 | addi r29, 0, 0 /* start ghosted loop counter at 0 */ |
| 287 | inside: |
| 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 */ |
Wolfgang Denk | a1be476 | 2008-05-20 16:00:29 +0200 | [diff] [blame] | 304 | addi r29, r29, 1 /* increment inner loop counter */ |
| 305 | cmpw r29, r26 /* check for last inner loop */ |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 306 | blt inside /* do more inner loops */ |
| 307 | |
| 308 | /* now close referance ( outer ) loop */ |
Wolfgang Denk | a1be476 | 2008-05-20 16:00:29 +0200 | [diff] [blame] | 309 | addi r31, 0, 0 /* r31 = zero */ |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 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 | */ |
Wolfgang Denk | a1be476 | 2008-05-20 16:00:29 +0200 | [diff] [blame] | 316 | addi r30, r30, 1 /* increment outer loop counter */ |
| 317 | cmpw r30, r26 /* check for last inner loop */ |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 318 | ble outside /* do more outer loops */ |
| 319 | |
| 320 | /* were done, lets go home */ |
| 321 | b gb_done |
| 322 | Casper: /* we found a ghost !! */ |
| 323 | addi r3, 0, ERR_ADDF /* get indexed error message */ |
| 324 | bl log_err /* log error led error code */ |
| 325 | gb_done: /* pack your bags, and go home */ |
wdenk | 57b2d80 | 2003-06-27 21:31:46 +0000 | [diff] [blame] | 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 */ |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 331 | |
| 332 | /**************************************************** |
| 333 | ******** SDRAM data fill tests ********** |
| 334 | ***************************************************/ |
| 335 | Bit_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 | |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 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 */ |
| 383 | fill_test: |
wdenk | 57b2d80 | 2003-06-27 21:31:46 +0000 | [diff] [blame] | 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 */ |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 390 | mr r27, r3 |
| 391 | mr r28, r4 |
| 392 | mr r29, r5 |
| 393 | |
Wolfgang Denk | a1be476 | 2008-05-20 16:00:29 +0200 | [diff] [blame] | 394 | WATCHDOG_RESET /* Reset the watchdog */ |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 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 */ |
| 400 | ft_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 */ |
Wolfgang Denk | a1be476 | 2008-05-20 16:00:29 +0200 | [diff] [blame] | 404 | WATCHDOG_RESET /* kick the dog every now and then */ |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 405 | ft_0a: bdnz ft_0 /* Round and round... */ |
| 406 | |
Wolfgang Denk | a1be476 | 2008-05-20 16:00:29 +0200 | [diff] [blame] | 407 | WATCHDOG_RESET /* Reset the watchdog */ |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 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 */ |
| 413 | ft_1: lwz r31, 0(r30) /* get value from memory */ |
wdenk | 57b2d80 | 2003-06-27 21:31:46 +0000 | [diff] [blame] | 414 | xor. r31, r31, r28 /* Writen = Read ? */ |
| 415 | bne ft_err /* If bad, than halt */ |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 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 */ |
| 420 | ft_1a: bdnz ft_1 /* Round and round... */ |
| 421 | |
Wolfgang Denk | a1be476 | 2008-05-20 16:00:29 +0200 | [diff] [blame] | 422 | WATCHDOG_RESET /* Reset the watchdog */ |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 423 | |
| 424 | b fill_done /* restore and return */ |
| 425 | |
| 426 | ft_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 | |
| 432 | fill_done: |
wdenk | 57b2d80 | 2003-06-27 21:31:46 +0000 | [diff] [blame] | 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 */ |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 438 | |
| 439 | |
| 440 | /**************************************************** |
| 441 | ******* get error index from r3 pattern ******** |
| 442 | ***************************************************/ |
| 443 | get_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 |
| 457 | gi2: 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 |
| 461 | gi3: addi r3, 0, 1 /* only lower bits set */ |
| 462 | b gi_done |
| 463 | gi4: addi r3, 0, 0 /* no bits set */ |
| 464 | gi_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 | ***************************************************/ |
| 475 | log_stat: /* output a led code and continue */ |
| 476 | set_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 | |
| 499 | get_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 | |
| 519 | log_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 */ |
| 534 | halt: |
| 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 | |
| 543 | log_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 |
| 563 | log_2: |
| 564 | WATCHDOG_RESET /* this keeps dog from barking, */ |
wdenk | 57b2d80 | 2003-06-27 21:31:46 +0000 | [diff] [blame] | 565 | /* and takes time */ |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 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 | ******************************************************************/ |
| 581 | temp_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 | |
wdenk | 57b2d80 | 2003-06-27 21:31:46 +0000 | [diff] [blame] | 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) |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 591 | |
| 592 | /* set baud rate to use internal clock, |
| 593 | baud = (200e6/16)/31/42 = 9600 */ |
| 594 | |
wdenk | 57b2d80 | 2003-06-27 21:31:46 +0000 | [diff] [blame] | 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 */ |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 599 | |
wdenk | 57b2d80 | 2003-06-27 21:31:46 +0000 | [diff] [blame] | 600 | addi r3, r3, 0x0001 /* uart baud divisor addr */ |
| 601 | addi r4, 0, 0 |
| 602 | stb r4, 0(r3) /* Divisor Latch MSB = 0 */ |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 603 | |
wdenk | 57b2d80 | 2003-06-27 21:31:46 +0000 | [diff] [blame] | 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) |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 608 | |
| 609 | /* output a few line feeds */ |
| 610 | addi r3, 0, '\n' /* load line feed */ |
Wolfgang Denk | a1be476 | 2008-05-20 16:00:29 +0200 | [diff] [blame] | 611 | bl post_putc /* output the char */ |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 612 | addi r3, 0, '\n' /* load line feed */ |
Wolfgang Denk | a1be476 | 2008-05-20 16:00:29 +0200 | [diff] [blame] | 613 | bl post_putc /* output the char */ |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 614 | |
wdenk | 57b2d80 | 2003-06-27 21:31:46 +0000 | [diff] [blame] | 615 | /* restore stack and return */ |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 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 | |
| 627 | post_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 |
wdenk | 57b2d80 | 2003-06-27 21:31:46 +0000 | [diff] [blame] | 635 | r30 - delay counter |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 636 | r29 - scratch reg */ |
| 637 | |
| 638 | addis r31, 0, 0xef60 /* Point to uart base */ |
| 639 | ori r31, r31, 0x0300 |
Wolfgang Denk | a1be476 | 2008-05-20 16:00:29 +0200 | [diff] [blame] | 640 | addis r30, 0, 152 /* Load about 10,000,000 ticks. */ |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 641 | pputc_lp: |
Wolfgang Denk | a1be476 | 2008-05-20 16:00:29 +0200 | [diff] [blame] | 642 | lbz r29, 5(r31) /* Read Line Status Register */ |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 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 */ |
Wolfgang Denk | a1be476 | 2008-05-20 16:00:29 +0200 | [diff] [blame] | 648 | b pputc_done /* Bail out with error code set */ |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 649 | thre_set: |
| 650 | stb r3, 0(r31) /* Store character to UART */ |
| 651 | addi r3, 0, 0 /* clear error code */ |
| 652 | pputc_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 | *****************************************************************/ |
| 666 | post_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 | |
Wolfgang Denk | a1be476 | 2008-05-20 16:00:29 +0200 | [diff] [blame] | 674 | addi r31, r3, 0 /* move pointer to R31 */ |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 675 | pputs_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 |
Wolfgang Denk | a1be476 | 2008-05-20 16:00:29 +0200 | [diff] [blame] | 682 | addi r31, r31, 1 /* point to next char */ |
| 683 | b pputs_nxt /* loop till term */ |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 684 | pputs_err: |
Wolfgang Denk | a1be476 | 2008-05-20 16:00:29 +0200 | [diff] [blame] | 685 | addi r3, 0, -1 /* set error code */ |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 686 | b pputs_end /* were outa here */ |
| 687 | pputs_term: |
Wolfgang Denk | a1be476 | 2008-05-20 16:00:29 +0200 | [diff] [blame] | 688 | addi r3, 0, 1 /* set success code */ |
wdenk | 57b2d80 | 2003-06-27 21:31:46 +0000 | [diff] [blame] | 689 | /* restore stack and return */ |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 690 | pputs_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 | |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 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 | *******************************************************************/ |
| 706 | disp_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 */ |
Wolfgang Denk | a1be476 | 2008-05-20 16:00:29 +0200 | [diff] [blame] | 714 | addi r30, 0, 8 /* Go through 8 nibbles. */ |
| 715 | addi r31, r3, 0 |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 716 | pputh_nxt: |
| 717 | rlwinm r31, r31, 4, 0, 31 /* Rotate next nibble into position */ |
Wolfgang Denk | a1be476 | 2008-05-20 16:00:29 +0200 | [diff] [blame] | 718 | andi. r3, r31, 0x0f /* Get nibble. */ |
| 719 | addi r3, r3, 0x30 /* Add zero's ASCII code. */ |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 720 | cmpwi r3, 0x03a |
| 721 | blt pputh_out |
Wolfgang Denk | a1be476 | 2008-05-20 16:00:29 +0200 | [diff] [blame] | 722 | addi r3, r3, 0x07 /* 0x27 for lower case. */ |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 723 | pputh_out: |
Wolfgang Denk | a1be476 | 2008-05-20 16:00:29 +0200 | [diff] [blame] | 724 | cmpw r30, r4 |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 725 | bgt pputh_skip |
| 726 | bl post_putc |
Wolfgang Denk | a1be476 | 2008-05-20 16:00:29 +0200 | [diff] [blame] | 727 | addic. r3, r3, 0 /* check for error */ |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 728 | bne pputh_err |
| 729 | pputh_skip: |
| 730 | addic. r30, r30, -1 |
| 731 | bne pputh_nxt |
| 732 | xor r3, r3, r3 /* Clear error code */ |
| 733 | b pputh_done |
| 734 | pputh_err: |
Wolfgang Denk | a1be476 | 2008-05-20 16:00:29 +0200 | [diff] [blame] | 735 | addi r3, 0, -1 /* set error code */ |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 736 | pputh_done: |
wdenk | 57b2d80 | 2003-06-27 21:31:46 +0000 | [diff] [blame] | 737 | /* restore stack and return */ |
wdenk | c609719 | 2002-11-03 00:24:07 +0000 | [diff] [blame] | 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 */ |