diff options
Diffstat (limited to 'post/lib_powerpc/b.c')
-rw-r--r-- | post/lib_powerpc/b.c | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/post/lib_powerpc/b.c b/post/lib_powerpc/b.c new file mode 100644 index 0000000000..492fba4c53 --- /dev/null +++ b/post/lib_powerpc/b.c @@ -0,0 +1,198 @@ +/* + * (C) Copyright 2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * 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 + */ + +#include <common.h> + +/* + * CPU test + * Branch instructions: b, bl, bc + * + * The first 2 instructions (b, bl) are verified by jumping + * to a fixed address and checking whether control was transfered + * to that very point. For the bl instruction the value of the + * link register is checked as well (using mfspr). + * To verify the bc instruction various combinations of the BI/BO + * fields, the CTR and the condition register values are + * checked. The list of such combinations is pre-built and + * linked in U-Boot at build time. + */ + +#include <post.h> +#include "cpu_asm.h" + +#if CONFIG_POST & CONFIG_SYS_POST_CPU + +extern void cpu_post_exec_11 (ulong *code, ulong *res, ulong op1); +extern void cpu_post_exec_31 (ulong *code, ulong *ctr, ulong *lr, ulong *jump, + ulong cr); + +static int cpu_post_test_bc (ulong cmd, ulong bo, ulong bi, + int pjump, int decr, int link, ulong pctr, ulong cr) +{ + int ret = 0; + ulong lr = 0; + ulong ctr = pctr; + ulong jump; + + unsigned long code[] = + { + ASM_MTCR(6), + ASM_MFLR(6), + ASM_MTCTR(3), + ASM_MTLR(4), + ASM_LI(5, 1), + ASM_3O(cmd, bo, bi, 8), + ASM_LI(5, 0), + ASM_MFCTR(3), + ASM_MFLR(4), + ASM_MTLR(6), + ASM_BLR, + }; + + cpu_post_exec_31 (code, &ctr, &lr, &jump, cr); + + if (ret == 0) + ret = pjump == jump ? 0 : -1; + if (ret == 0) + { + if (decr) + ret = pctr == ctr + 1 ? 0 : -1; + else + ret = pctr == ctr ? 0 : -1; + } + if (ret == 0) + { + if (link) + ret = lr == (ulong) code + 24 ? 0 : -1; + else + ret = lr == 0 ? 0 : -1; + } + + return ret; +} + +int cpu_post_test_b (void) +{ + int ret = 0; + unsigned int i; + int flag = disable_interrupts(); + + if (ret == 0) + { + ulong code[] = + { + ASM_MFLR(4), + ASM_MTLR(3), + ASM_B(4), + ASM_MFLR(3), + ASM_MTLR(4), + ASM_BLR, + }; + ulong res; + + cpu_post_exec_11 (code, &res, 0); + + ret = res == 0 ? 0 : -1; + + if (ret != 0) + { + post_log ("Error at b1 test !\n"); + } + } + + if (ret == 0) + { + ulong code[] = + { + ASM_MFLR(4), + ASM_MTLR(3), + ASM_BL(4), + ASM_MFLR(3), + ASM_MTLR(4), + ASM_BLR, + }; + ulong res; + + cpu_post_exec_11 (code, &res, 0); + + ret = res == (ulong)code + 12 ? 0 : -1; + + if (ret != 0) + { + post_log ("Error at b2 test !\n"); + } + } + + if (ret == 0) + { + ulong cc, cd; + int cond; + ulong ctr; + int link; + + i = 0; + + for (cc = 0; cc < 4 && ret == 0; cc++) + { + for (cd = 0; cd < 4 && ret == 0; cd++) + { + for (link = 0; link <= 1 && ret == 0; link++) + { + for (cond = 0; cond <= 1 && ret == 0; cond++) + { + for (ctr = 1; ctr <= 2 && ret == 0; ctr++) + { + int decr = cd < 2; + int cr = cond ? 0x80000000 : 0x00000000; + int jumpc = cc >= 2 || + (cc == 0 && !cond) || + (cc == 1 && cond); + int jumpd = cd >= 2 || + (cd == 0 && ctr != 1) || + (cd == 1 && ctr == 1); + int jump = jumpc && jumpd; + + ret = cpu_post_test_bc (link ? OP_BCL : OP_BC, + (cc << 3) + (cd << 1), 0, jump, decr, link, + ctr, cr); + + if (ret != 0) + { + post_log ("Error at b3 test %d !\n", i); + } + + i++; + } + } + } + } + } + } + + if (flag) + enable_interrupts(); + + return ret; +} + +#endif |