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