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