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 CFG_POST & CFG_SYS_POST_CPU
32
33extern void cpu_post_exec_22w (ulong *code, ulong *op1, ulong op2, ulong *op3);
34extern void cpu_post_exec_21w (ulong *code, ulong *op1, ulong *op2);
35
36static 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};
158static unsigned int cpu_post_load_size = ARRAY_SIZE(cpu_post_load_table);
159
160int 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