diff options
Diffstat (limited to 'post/lib_powerpc/cr.c')
-rw-r--r-- | post/lib_powerpc/cr.c | 357 |
1 files changed, 357 insertions, 0 deletions
diff --git a/post/lib_powerpc/cr.c b/post/lib_powerpc/cr.c new file mode 100644 index 0000000..fbee6d5 --- /dev/null +++ b/post/lib_powerpc/cr.c @@ -0,0 +1,357 @@ +/* + * (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 & CONFIG_SYS_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; + int flag = disable_interrupts(); + + 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)); + + if (flag) + enable_interrupts(); + + return ret; +} + +#endif |