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