| /* | 
 |  * (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 | 
 |  * Condition register istructions:	mtcr, mfcr, mcrxr, | 
 |  *					crand, crandc, cror, crorc, crxor, | 
 |  *					crnand, crnor, creqv, mcrf | 
 |  * | 
 |  * The mtcrf/mfcr instructions is tested by loading different | 
 |  * values into the condition register (mtcrf), moving its value | 
 |  * to a general-purpose register (mfcr) and comparing this value | 
 |  * with the expected one. | 
 |  * The mcrxr instruction is tested by loading a fixed value | 
 |  * into the XER register (mtspr), moving XER value to the | 
 |  * condition register (mcrxr), moving it to a general-purpose | 
 |  * register (mfcr) and comparing the value of this register with | 
 |  * the expected one. | 
 |  * The rest of instructions is tested by loading a fixed | 
 |  * value into the condition register (mtcrf), executing each | 
 |  * instruction several times to modify all 4-bit condition | 
 |  * fields, moving the value of the conditional register to a | 
 |  * general-purpose register (mfcr) and comparing it with the | 
 |  * expected one. | 
 |  */ | 
 |  | 
 | #ifdef CONFIG_POST | 
 |  | 
 | #include <post.h> | 
 | #include "cpu_asm.h" | 
 |  | 
 | #if CONFIG_POST & CFG_POST_CPU | 
 |  | 
 | extern void cpu_post_exec_11 (ulong *code, ulong *res, ulong op1); | 
 | extern void cpu_post_exec_21x (ulong *code, ulong *op1, ulong *op2, ulong op3); | 
 |  | 
 | static ulong cpu_post_cr_table1[] = | 
 | { | 
 |     0xaaaaaaaa, | 
 |     0x55555555, | 
 | }; | 
 | static unsigned int cpu_post_cr_size1 = | 
 |     sizeof (cpu_post_cr_table1) / sizeof (ulong); | 
 |  | 
 | static struct cpu_post_cr_s2 { | 
 |     ulong xer; | 
 |     ulong cr; | 
 | } cpu_post_cr_table2[] = | 
 | { | 
 |     { | 
 | 	0xa0000000, | 
 | 	1 | 
 |     }, | 
 |     { | 
 | 	0x40000000, | 
 | 	5 | 
 |     }, | 
 | }; | 
 | static unsigned int cpu_post_cr_size2 = | 
 |     sizeof (cpu_post_cr_table2) / sizeof (struct cpu_post_cr_s2); | 
 |  | 
 | static struct cpu_post_cr_s3 { | 
 |     ulong cr; | 
 |     ulong cs; | 
 |     ulong cd; | 
 |     ulong res; | 
 | } cpu_post_cr_table3[] = | 
 | { | 
 |     { | 
 | 	0x01234567, | 
 | 	0, | 
 | 	4, | 
 | 	0x01230567 | 
 |     }, | 
 |     { | 
 | 	0x01234567, | 
 | 	7, | 
 | 	0, | 
 | 	0x71234567 | 
 |     }, | 
 | }; | 
 | static unsigned int cpu_post_cr_size3 = | 
 |     sizeof (cpu_post_cr_table3) / sizeof (struct cpu_post_cr_s3); | 
 |  | 
 | static struct cpu_post_cr_s4 { | 
 |     ulong cmd; | 
 |     ulong cr; | 
 |     ulong op1; | 
 |     ulong op2; | 
 |     ulong op3; | 
 |     ulong res; | 
 | } cpu_post_cr_table4[] = | 
 | { | 
 |     { | 
 | 	OP_CRAND, | 
 | 	0x0000ffff, | 
 | 	0, | 
 | 	16, | 
 | 	0, | 
 | 	0x0000ffff | 
 |     }, | 
 |     { | 
 | 	OP_CRAND, | 
 | 	0x0000ffff, | 
 | 	16, | 
 | 	17, | 
 | 	0, | 
 | 	0x8000ffff | 
 |     }, | 
 |     { | 
 | 	OP_CRANDC, | 
 | 	0x0000ffff, | 
 | 	0, | 
 | 	16, | 
 | 	0, | 
 | 	0x0000ffff | 
 |     }, | 
 |     { | 
 | 	OP_CRANDC, | 
 | 	0x0000ffff, | 
 | 	16, | 
 | 	0, | 
 | 	0, | 
 | 	0x8000ffff | 
 |     }, | 
 |     { | 
 | 	OP_CROR, | 
 | 	0x0000ffff, | 
 | 	0, | 
 | 	16, | 
 | 	0, | 
 | 	0x8000ffff | 
 |     }, | 
 |     { | 
 | 	OP_CROR, | 
 | 	0x0000ffff, | 
 | 	0, | 
 | 	1, | 
 | 	0, | 
 | 	0x0000ffff | 
 |     }, | 
 |     { | 
 | 	OP_CRORC, | 
 | 	0x0000ffff, | 
 | 	0, | 
 | 	16, | 
 | 	0, | 
 | 	0x0000ffff | 
 |     }, | 
 |     { | 
 | 	OP_CRORC, | 
 | 	0x0000ffff, | 
 | 	0, | 
 | 	0, | 
 | 	0, | 
 | 	0x8000ffff | 
 |     }, | 
 |     { | 
 | 	OP_CRXOR, | 
 | 	0x0000ffff, | 
 | 	0, | 
 | 	0, | 
 | 	0, | 
 | 	0x0000ffff | 
 |     }, | 
 |     { | 
 | 	OP_CRXOR, | 
 | 	0x0000ffff, | 
 | 	0, | 
 | 	16, | 
 | 	0, | 
 | 	0x8000ffff | 
 |     }, | 
 |     { | 
 | 	OP_CRNAND, | 
 | 	0x0000ffff, | 
 | 	0, | 
 | 	16, | 
 | 	0, | 
 | 	0x8000ffff | 
 |     }, | 
 |     { | 
 | 	OP_CRNAND, | 
 | 	0x0000ffff, | 
 | 	16, | 
 | 	17, | 
 | 	0, | 
 | 	0x0000ffff | 
 |     }, | 
 |     { | 
 | 	OP_CRNOR, | 
 | 	0x0000ffff, | 
 | 	0, | 
 | 	16, | 
 | 	0, | 
 | 	0x0000ffff | 
 |     }, | 
 |     { | 
 | 	OP_CRNOR, | 
 | 	0x0000ffff, | 
 | 	0, | 
 | 	1, | 
 | 	0, | 
 | 	0x8000ffff | 
 |     }, | 
 |     { | 
 | 	OP_CREQV, | 
 | 	0x0000ffff, | 
 | 	0, | 
 | 	0, | 
 | 	0, | 
 | 	0x8000ffff | 
 |     }, | 
 |     { | 
 | 	OP_CREQV, | 
 | 	0x0000ffff, | 
 | 	0, | 
 | 	16, | 
 | 	0, | 
 | 	0x0000ffff | 
 |     }, | 
 | }; | 
 | static unsigned int cpu_post_cr_size4 = | 
 |     sizeof (cpu_post_cr_table4) / sizeof (struct cpu_post_cr_s4); | 
 |  | 
 | int cpu_post_test_cr (void) | 
 | { | 
 |     int ret = 0; | 
 |     unsigned int i; | 
 |     unsigned long cr_sav; | 
 |  | 
 |     asm ( "mfcr %0" : "=r" (cr_sav) : ); | 
 |  | 
 |     for (i = 0; i < cpu_post_cr_size1 && ret == 0; i++) | 
 |     { | 
 | 	ulong cr = cpu_post_cr_table1[i]; | 
 | 	ulong res; | 
 |  | 
 | 	unsigned long code[] = | 
 | 	{ | 
 | 	    ASM_MTCR(3), | 
 | 	    ASM_MFCR(3), | 
 | 	    ASM_BLR, | 
 | 	}; | 
 |  | 
 | 	cpu_post_exec_11 (code, &res, cr); | 
 |  | 
 | 	ret = res == cr ? 0 : -1; | 
 |  | 
 | 	if (ret != 0) | 
 | 	{ | 
 | 	    post_log ("Error at cr1 test %d !\n", i); | 
 | 	} | 
 |     } | 
 |  | 
 |     for (i = 0; i < cpu_post_cr_size2 && ret == 0; i++) | 
 |     { | 
 | 	struct cpu_post_cr_s2 *test = cpu_post_cr_table2 + i; | 
 | 	ulong res; | 
 | 	ulong xer; | 
 |  | 
 | 	unsigned long code[] = | 
 | 	{ | 
 | 	    ASM_MTXER(3), | 
 | 	    ASM_MCRXR(test->cr), | 
 | 	    ASM_MFCR(3), | 
 | 	    ASM_MFXER(4), | 
 | 	    ASM_BLR, | 
 | 	}; | 
 |  | 
 | 	cpu_post_exec_21x (code, &res, &xer, test->xer); | 
 |  | 
 | 	ret = xer == 0 && ((res << (4 * test->cr)) & 0xe0000000) == test->xer ? | 
 | 	      0 : -1; | 
 |  | 
 | 	if (ret != 0) | 
 | 	{ | 
 | 	    post_log ("Error at cr2 test %d !\n", i); | 
 | 	} | 
 |     } | 
 |  | 
 |     for (i = 0; i < cpu_post_cr_size3 && ret == 0; i++) | 
 |     { | 
 | 	struct cpu_post_cr_s3 *test = cpu_post_cr_table3 + i; | 
 | 	ulong res; | 
 |  | 
 | 	unsigned long code[] = | 
 | 	{ | 
 | 	    ASM_MTCR(3), | 
 | 	    ASM_MCRF(test->cd, test->cs), | 
 | 	    ASM_MFCR(3), | 
 | 	    ASM_BLR, | 
 | 	}; | 
 |  | 
 | 	cpu_post_exec_11 (code, &res, test->cr); | 
 |  | 
 | 	ret = res == test->res ? 0 : -1; | 
 |  | 
 | 	if (ret != 0) | 
 | 	{ | 
 | 	    post_log ("Error at cr3 test %d !\n", i); | 
 | 	} | 
 |     } | 
 |  | 
 |     for (i = 0; i < cpu_post_cr_size4 && ret == 0; i++) | 
 |     { | 
 | 	struct cpu_post_cr_s4 *test = cpu_post_cr_table4 + i; | 
 | 	ulong res; | 
 |  | 
 | 	unsigned long code[] = | 
 | 	{ | 
 | 	    ASM_MTCR(3), | 
 | 	    ASM_12F(test->cmd, test->op3, test->op1, test->op2), | 
 | 	    ASM_MFCR(3), | 
 | 	    ASM_BLR, | 
 | 	}; | 
 |  | 
 | 	cpu_post_exec_11 (code, &res, test->cr); | 
 |  | 
 | 	ret = res == test->res ? 0 : -1; | 
 |  | 
 | 	if (ret != 0) | 
 | 	{ | 
 | 	    post_log ("Error at cr4 test %d !\n", i); | 
 | 	} | 
 |     } | 
 |  | 
 |     asm ( "mtcr %0" : : "r" (cr_sav)); | 
 |  | 
 |     return ret; | 
 | } | 
 |  | 
 | #endif | 
 | #endif |