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
cpu_post_test_load(void)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