1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * (C) Copyright 2002 4 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 5 */ 6 7 #include <common.h> 8 9 /* 10 * CPU test 11 * Load instructions: lbz(x)(u), lhz(x)(u), lha(x)(u), lwz(x)(u) 12 * 13 * All operations are performed on a 16-byte array. The array 14 * is 4-byte aligned. The base register points to offset 8. 15 * The immediate offset (index register) ranges in [-8 ... +7]. 16 * The test cases are composed so that they do not 17 * cause alignment exceptions. 18 * The test contains a pre-built table describing all test cases. 19 * The table entry contains: 20 * the instruction opcode, the array contents, the value of the index 21 * register and the expected value of the destination register. 22 * After executing the instruction, the test verifies the 23 * value of the destination register and the value of the base 24 * register (it must change for "load with update" instructions). 25 */ 26 27 #include <post.h> 28 #include "cpu_asm.h" 29 30 #if CONFIG_POST & CONFIG_SYS_POST_CPU 31 32 extern void cpu_post_exec_22w (ulong *code, ulong *op1, ulong op2, ulong *op3); 33 extern void cpu_post_exec_21w (ulong *code, ulong *op1, ulong *op2); 34 35 static struct cpu_post_load_s 36 { 37 ulong cmd; 38 uint width; 39 int update; 40 int index; 41 ulong offset; 42 } cpu_post_load_table[] = 43 { 44 { 45 OP_LWZ, 46 4, 47 0, 48 0, 49 4 50 }, 51 { 52 OP_LHA, 53 3, 54 0, 55 0, 56 2 57 }, 58 { 59 OP_LHZ, 60 2, 61 0, 62 0, 63 2 64 }, 65 { 66 OP_LBZ, 67 1, 68 0, 69 0, 70 1 71 }, 72 { 73 OP_LWZU, 74 4, 75 1, 76 0, 77 4 78 }, 79 { 80 OP_LHAU, 81 3, 82 1, 83 0, 84 2 85 }, 86 { 87 OP_LHZU, 88 2, 89 1, 90 0, 91 2 92 }, 93 { 94 OP_LBZU, 95 1, 96 1, 97 0, 98 1 99 }, 100 { 101 OP_LWZX, 102 4, 103 0, 104 1, 105 4 106 }, 107 { 108 OP_LHAX, 109 3, 110 0, 111 1, 112 2 113 }, 114 { 115 OP_LHZX, 116 2, 117 0, 118 1, 119 2 120 }, 121 { 122 OP_LBZX, 123 1, 124 0, 125 1, 126 1 127 }, 128 { 129 OP_LWZUX, 130 4, 131 1, 132 1, 133 4 134 }, 135 { 136 OP_LHAUX, 137 3, 138 1, 139 1, 140 2 141 }, 142 { 143 OP_LHZUX, 144 2, 145 1, 146 1, 147 2 148 }, 149 { 150 OP_LBZUX, 151 1, 152 1, 153 1, 154 1 155 }, 156 }; 157 static unsigned int cpu_post_load_size = ARRAY_SIZE(cpu_post_load_table); 158 159 int cpu_post_test_load (void) 160 { 161 int ret = 0; 162 unsigned int i; 163 int flag = disable_interrupts(); 164 165 for (i = 0; i < cpu_post_load_size && ret == 0; i++) 166 { 167 struct cpu_post_load_s *test = cpu_post_load_table + i; 168 uchar data[16] = 169 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; 170 ulong base0 = (ulong) (data + 8); 171 ulong base = base0; 172 ulong value; 173 174 if (test->index) 175 { 176 ulong code[] = 177 { 178 ASM_12(test->cmd, 5, 3, 4), 179 ASM_BLR, 180 }; 181 182 cpu_post_exec_22w (code, &base, test->offset, &value); 183 } 184 else 185 { 186 ulong code[] = 187 { 188 ASM_11I(test->cmd, 4, 3, test->offset), 189 ASM_BLR, 190 }; 191 192 cpu_post_exec_21w (code, &base, &value); 193 } 194 195 if (ret == 0) 196 { 197 if (test->update) 198 ret = base == base0 + test->offset ? 0 : -1; 199 else 200 ret = base == base0 ? 0 : -1; 201 } 202 203 if (ret == 0) 204 { 205 switch (test->width) 206 { 207 case 1: 208 ret = *(uchar *)(base0 + test->offset) == value ? 209 0 : -1; 210 break; 211 case 2: 212 ret = *(ushort *)(base0 + test->offset) == value ? 213 0 : -1; 214 break; 215 case 3: 216 ret = *(short *)(base0 + test->offset) == value ? 217 0 : -1; 218 break; 219 case 4: 220 ret = *(ulong *)(base0 + test->offset) == value ? 221 0 : -1; 222 break; 223 } 224 } 225 226 if (ret != 0) 227 { 228 post_log ("Error at load test %d !\n", i); 229 } 230 } 231 232 if (flag) 233 enable_interrupts(); 234 235 return ret; 236 } 237 238 #endif 239