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