Merge branch 'master' of git://git.denx.de/u-boot-arm
[oweals/u-boot.git] / post / lib_powerpc / three.c
1 /*
2  * (C) Copyright 2002
3  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4  *
5  * SPDX-License-Identifier:     GPL-2.0+
6  */
7
8 #include <common.h>
9
10 /*
11  * CPU test
12  * Ternary instructions         instr rD,rA,rB
13  *
14  * Arithmetic instructions:     add, addc, adde, subf, subfc, subfe,
15  *                              mullw, mulhw, mulhwu, divw, divwu
16  *
17  * The test contains a pre-built table of instructions, operands and
18  * expected results. For each table entry, the test will cyclically use
19  * different sets of operand registers and result registers.
20  */
21
22 #include <post.h>
23 #include "cpu_asm.h"
24
25 #if CONFIG_POST & CONFIG_SYS_POST_CPU
26
27 extern void cpu_post_exec_22 (ulong *code, ulong *cr, ulong *res, ulong op1,
28     ulong op2);
29 extern ulong cpu_post_makecr (long v);
30
31 static struct cpu_post_three_s
32 {
33     ulong cmd;
34     ulong op1;
35     ulong op2;
36     ulong res;
37 } cpu_post_three_table[] =
38 {
39     {
40         OP_ADD,
41         100,
42         200,
43         300
44     },
45     {
46         OP_ADD,
47         100,
48         -200,
49         -100
50     },
51     {
52         OP_ADDC,
53         100,
54         200,
55         300
56     },
57     {
58         OP_ADDC,
59         100,
60         -200,
61         -100
62     },
63     {
64         OP_ADDE,
65         100,
66         200,
67         300
68     },
69     {
70         OP_ADDE,
71         100,
72         -200,
73         -100
74     },
75     {
76         OP_SUBF,
77         100,
78         200,
79         100
80     },
81     {
82         OP_SUBF,
83         300,
84         200,
85         -100
86     },
87     {
88         OP_SUBFC,
89         100,
90         200,
91         100
92     },
93     {
94         OP_SUBFC,
95         300,
96         200,
97         -100
98     },
99     {
100         OP_SUBFE,
101         100,
102         200,
103         200 + ~100
104     },
105     {
106         OP_SUBFE,
107         300,
108         200,
109         200 + ~300
110     },
111     {
112         OP_MULLW,
113         200,
114         300,
115         200 * 300
116     },
117     {
118         OP_MULHW,
119         0x10000000,
120         0x10000000,
121         0x1000000
122     },
123     {
124         OP_MULHWU,
125         0x80000000,
126         0x80000000,
127         0x40000000
128     },
129     {
130         OP_DIVW,
131         -20,
132         5,
133         -4
134     },
135     {
136         OP_DIVWU,
137         0x8000,
138         0x200,
139         0x40
140     },
141 };
142 static unsigned int cpu_post_three_size = ARRAY_SIZE(cpu_post_three_table);
143
144 int cpu_post_test_three (void)
145 {
146     int ret = 0;
147     unsigned int i, reg;
148     int flag = disable_interrupts();
149
150     for (i = 0; i < cpu_post_three_size && ret == 0; i++)
151     {
152         struct cpu_post_three_s *test = cpu_post_three_table + i;
153
154         for (reg = 0; reg < 32 && ret == 0; reg++)
155         {
156             unsigned int reg0 = (reg + 0) % 32;
157             unsigned int reg1 = (reg + 1) % 32;
158             unsigned int reg2 = (reg + 2) % 32;
159             unsigned int stk = reg < 16 ? 31 : 15;
160             unsigned long code[] =
161             {
162                 ASM_STW(stk, 1, -4),
163                 ASM_ADDI(stk, 1, -24),
164                 ASM_STW(3, stk, 12),
165                 ASM_STW(4, stk, 16),
166                 ASM_STW(reg0, stk, 8),
167                 ASM_STW(reg1, stk, 4),
168                 ASM_STW(reg2, stk, 0),
169                 ASM_LWZ(reg1, stk, 12),
170                 ASM_LWZ(reg0, stk, 16),
171                 ASM_12(test->cmd, reg2, reg1, reg0),
172                 ASM_STW(reg2, stk, 12),
173                 ASM_LWZ(reg2, stk, 0),
174                 ASM_LWZ(reg1, stk, 4),
175                 ASM_LWZ(reg0, stk, 8),
176                 ASM_LWZ(3, stk, 12),
177                 ASM_ADDI(1, stk, 24),
178                 ASM_LWZ(stk, 1, -4),
179                 ASM_BLR,
180             };
181             unsigned long codecr[] =
182             {
183                 ASM_STW(stk, 1, -4),
184                 ASM_ADDI(stk, 1, -24),
185                 ASM_STW(3, stk, 12),
186                 ASM_STW(4, stk, 16),
187                 ASM_STW(reg0, stk, 8),
188                 ASM_STW(reg1, stk, 4),
189                 ASM_STW(reg2, stk, 0),
190                 ASM_LWZ(reg1, stk, 12),
191                 ASM_LWZ(reg0, stk, 16),
192                 ASM_12(test->cmd, reg2, reg1, reg0) | BIT_C,
193                 ASM_STW(reg2, stk, 12),
194                 ASM_LWZ(reg2, stk, 0),
195                 ASM_LWZ(reg1, stk, 4),
196                 ASM_LWZ(reg0, stk, 8),
197                 ASM_LWZ(3, stk, 12),
198                 ASM_ADDI(1, stk, 24),
199                 ASM_LWZ(stk, 1, -4),
200                 ASM_BLR,
201             };
202             ulong res;
203             ulong cr;
204
205             if (ret == 0)
206             {
207                 cr = 0;
208                 cpu_post_exec_22 (code, & cr, & res, test->op1, test->op2);
209
210                 ret = res == test->res && cr == 0 ? 0 : -1;
211
212                 if (ret != 0)
213                 {
214                     post_log ("Error at three test %d !\n", i);
215                 }
216             }
217
218             if (ret == 0)
219             {
220                 cpu_post_exec_22 (codecr, & cr, & res, test->op1, test->op2);
221
222                 ret = res == test->res &&
223                       (cr & 0xe0000000) == cpu_post_makecr (res) ? 0 : -1;
224
225                 if (ret != 0)
226                 {
227                     post_log ("Error at three test %d !\n", i);
228                 }
229             }
230         }
231     }
232
233     if (flag)
234         enable_interrupts();
235
236     return ret;
237 }
238
239 #endif