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 000000000..492fba4c5 --- /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 |