1 /* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0)
2 *
3 * Copyright 2008-2016 Freescale Semiconductor Inc.
4 * Copyright 2016,2019 NXP
5 */
6
7 #ifndef __RTA_MOVE_CMD_H__
8 #define __RTA_MOVE_CMD_H__
9
10 #define MOVE_SET_AUX_SRC 0x01
11 #define MOVE_SET_AUX_DST 0x02
12 #define MOVE_SET_AUX_LS 0x03
13 #define MOVE_SET_LEN_16b 0x04
14
15 #define MOVE_SET_AUX_MATH 0x10
16 #define MOVE_SET_AUX_MATH_SRC (MOVE_SET_AUX_SRC | MOVE_SET_AUX_MATH)
17 #define MOVE_SET_AUX_MATH_DST (MOVE_SET_AUX_DST | MOVE_SET_AUX_MATH)
18
19 #define MASK_16b 0xFF
20
21 /* MOVE command type */
22 #define __MOVE 1
23 #define __MOVEB 2
24 #define __MOVEDW 3
25
26 extern enum rta_sec_era rta_sec_era;
27
28 static const uint32_t move_src_table[][2] = {
29 /*1*/ { CONTEXT1, MOVE_SRC_CLASS1CTX },
30 { CONTEXT2, MOVE_SRC_CLASS2CTX },
31 { OFIFO, MOVE_SRC_OUTFIFO },
32 { DESCBUF, MOVE_SRC_DESCBUF },
33 { MATH0, MOVE_SRC_MATH0 },
34 { MATH1, MOVE_SRC_MATH1 },
35 { MATH2, MOVE_SRC_MATH2 },
36 { MATH3, MOVE_SRC_MATH3 },
37 /*9*/ { IFIFOABD, MOVE_SRC_INFIFO },
38 { IFIFOAB1, MOVE_SRC_INFIFO_CL | MOVE_AUX_LS },
39 { IFIFOAB2, MOVE_SRC_INFIFO_CL },
40 /*12*/ { ABD, MOVE_SRC_INFIFO_NO_NFIFO },
41 { AB1, MOVE_SRC_INFIFO_NO_NFIFO | MOVE_AUX_LS },
42 { AB2, MOVE_SRC_INFIFO_NO_NFIFO | MOVE_AUX_MS }
43 };
44
45 /* Allowed MOVE / MOVE_LEN sources for each SEC Era.
46 * Values represent the number of entries from move_src_table[] that are
47 * supported.
48 */
49 static const unsigned int move_src_table_sz[] = {9, 11, 14, 14, 14, 14, 14, 14,
50 14, 14};
51
52 static const uint32_t move_dst_table[][2] = {
53 /*1*/ { CONTEXT1, MOVE_DEST_CLASS1CTX },
54 { CONTEXT2, MOVE_DEST_CLASS2CTX },
55 { OFIFO, MOVE_DEST_OUTFIFO },
56 { DESCBUF, MOVE_DEST_DESCBUF },
57 { MATH0, MOVE_DEST_MATH0 },
58 { MATH1, MOVE_DEST_MATH1 },
59 { MATH2, MOVE_DEST_MATH2 },
60 { MATH3, MOVE_DEST_MATH3 },
61 { IFIFOAB1, MOVE_DEST_CLASS1INFIFO },
62 { IFIFOAB2, MOVE_DEST_CLASS2INFIFO },
63 { PKA, MOVE_DEST_PK_A },
64 { KEY1, MOVE_DEST_CLASS1KEY },
65 { KEY2, MOVE_DEST_CLASS2KEY },
66 /*14*/ { IFIFO, MOVE_DEST_INFIFO },
67 /*15*/ { ALTSOURCE, MOVE_DEST_ALTSOURCE}
68 };
69
70 /* Allowed MOVE / MOVE_LEN destinations for each SEC Era.
71 * Values represent the number of entries from move_dst_table[] that are
72 * supported.
73 */
74 static const
75 unsigned int move_dst_table_sz[] = {13, 14, 14, 15, 15, 15, 15, 15, 15, 15};
76
77 static inline int
78 set_move_offset(struct program *program __maybe_unused,
79 uint64_t src, uint16_t src_offset,
80 uint64_t dst, uint16_t dst_offset,
81 uint16_t *offset, uint16_t *opt);
82
83 static inline int
84 math_offset(uint16_t offset);
85
86 static inline int
rta_move(struct program * program,int cmd_type,uint64_t src,uint16_t src_offset,uint64_t dst,uint16_t dst_offset,uint32_t length,uint32_t flags)87 rta_move(struct program *program, int cmd_type, uint64_t src,
88 uint16_t src_offset, uint64_t dst,
89 uint16_t dst_offset, uint32_t length, uint32_t flags)
90 {
91 uint32_t opcode = 0;
92 uint16_t offset = 0, opt = 0;
93 uint32_t val = 0;
94 int ret = -EINVAL;
95 bool is_move_len_cmd = false;
96 unsigned int start_pc = program->current_pc;
97
98 /* write command type */
99 if (cmd_type == __MOVEB) {
100 opcode = CMD_MOVEB;
101 } else if (cmd_type == __MOVEDW) {
102 opcode = CMD_MOVEDW;
103 } else if (!(flags & IMMED)) {
104 if ((length != MATH0) && (length != MATH1) &&
105 (length != MATH2) && (length != MATH3)) {
106 pr_err("MOVE: MOVE_LEN length must be MATH[0-3]. SEC PC: %d; Instr: %d\n",
107 program->current_pc,
108 program->current_instruction);
109 goto err;
110 }
111
112 opcode = CMD_MOVE_LEN;
113 is_move_len_cmd = true;
114 } else {
115 opcode = CMD_MOVE;
116 }
117
118 /* write offset first, to check for invalid combinations or incorrect
119 * offset values sooner; decide which offset should be here
120 * (src or dst)
121 */
122 ret = set_move_offset(program, src, src_offset, dst, dst_offset,
123 &offset, &opt);
124 if (ret < 0)
125 goto err;
126
127 opcode |= (offset << MOVE_OFFSET_SHIFT) & MOVE_OFFSET_MASK;
128
129 /* set AUX field if required */
130 if (opt == MOVE_SET_AUX_SRC) {
131 opcode |= ((src_offset / 16) << MOVE_AUX_SHIFT) & MOVE_AUX_MASK;
132 } else if (opt == MOVE_SET_AUX_DST) {
133 opcode |= ((dst_offset / 16) << MOVE_AUX_SHIFT) & MOVE_AUX_MASK;
134 } else if (opt == MOVE_SET_AUX_LS) {
135 opcode |= MOVE_AUX_LS;
136 } else if (opt & MOVE_SET_AUX_MATH) {
137 if (opt & MOVE_SET_AUX_SRC)
138 offset = src_offset;
139 else
140 offset = dst_offset;
141
142 ret = math_offset(offset);
143 if (ret < 0) {
144 pr_err("MOVE: Invalid offset in MATH register. SEC PC: %d; Instr: %d\n",
145 program->current_pc,
146 program->current_instruction);
147 goto err;
148 }
149
150 opcode |= (uint32_t)ret;
151 }
152
153 /* write source field */
154 ret = __rta_map_opcode((uint32_t)src, move_src_table,
155 move_src_table_sz[rta_sec_era], &val);
156 if (ret < 0) {
157 pr_err("MOVE: Invalid SRC. SEC PC: %d; Instr: %d\n",
158 program->current_pc, program->current_instruction);
159 goto err;
160 }
161 opcode |= val;
162
163 /* write destination field */
164 ret = __rta_map_opcode((uint32_t)dst, move_dst_table,
165 move_dst_table_sz[rta_sec_era], &val);
166 if (ret < 0) {
167 pr_err("MOVE: Invalid DST. SEC PC: %d; Instr: %d\n",
168 program->current_pc, program->current_instruction);
169 goto err;
170 }
171 opcode |= val;
172
173 /* write flags */
174 if (flags & (FLUSH1 | FLUSH2))
175 opcode |= MOVE_AUX_MS;
176 if (flags & (LAST2 | LAST1))
177 opcode |= MOVE_AUX_LS;
178 if (flags & WAITCOMP)
179 opcode |= MOVE_WAITCOMP;
180
181 if (!is_move_len_cmd) {
182 /* write length */
183 if (opt == MOVE_SET_LEN_16b)
184 opcode |= (length & (MOVE_OFFSET_MASK | MOVE_LEN_MASK));
185 else
186 opcode |= (length & MOVE_LEN_MASK);
187 } else {
188 /* write mrsel */
189 switch (length) {
190 case (MATH0):
191 /*
192 * opcode |= MOVELEN_MRSEL_MATH0;
193 * MOVELEN_MRSEL_MATH0 is 0
194 */
195 break;
196 case (MATH1):
197 opcode |= MOVELEN_MRSEL_MATH1;
198 break;
199 case (MATH2):
200 opcode |= MOVELEN_MRSEL_MATH2;
201 break;
202 case (MATH3):
203 opcode |= MOVELEN_MRSEL_MATH3;
204 break;
205 }
206
207 /* write size */
208 if (rta_sec_era >= RTA_SEC_ERA_7) {
209 if (flags & SIZE_WORD)
210 opcode |= MOVELEN_SIZE_WORD;
211 else if (flags & SIZE_BYTE)
212 opcode |= MOVELEN_SIZE_BYTE;
213 else if (flags & SIZE_DWORD)
214 opcode |= MOVELEN_SIZE_DWORD;
215 }
216 }
217
218 __rta_out32(program, opcode);
219 program->current_instruction++;
220
221 return (int)start_pc;
222
223 err:
224 program->first_error_pc = start_pc;
225 program->current_instruction++;
226 return ret;
227 }
228
229 static inline int
set_move_offset(struct program * program __maybe_unused,uint64_t src,uint16_t src_offset,uint64_t dst,uint16_t dst_offset,uint16_t * offset,uint16_t * opt)230 set_move_offset(struct program *program __maybe_unused,
231 uint64_t src, uint16_t src_offset,
232 uint64_t dst, uint16_t dst_offset,
233 uint16_t *offset, uint16_t *opt)
234 {
235 switch (src) {
236 case (CONTEXT1):
237 case (CONTEXT2):
238 if (dst == DESCBUF) {
239 *opt = MOVE_SET_AUX_SRC;
240 *offset = dst_offset;
241 } else if ((dst == KEY1) || (dst == KEY2)) {
242 if ((src_offset) && (dst_offset)) {
243 pr_err("MOVE: Bad offset. SEC PC: %d; Instr: %d\n",
244 program->current_pc,
245 program->current_instruction);
246 goto err;
247 }
248 if (dst_offset) {
249 *opt = MOVE_SET_AUX_LS;
250 *offset = dst_offset;
251 } else {
252 *offset = src_offset;
253 }
254 } else {
255 if ((dst == MATH0) || (dst == MATH1) ||
256 (dst == MATH2) || (dst == MATH3)) {
257 *opt = MOVE_SET_AUX_MATH_DST;
258 } else if (((dst == OFIFO) || (dst == ALTSOURCE)) &&
259 (src_offset % 4)) {
260 pr_err("MOVE: Bad offset alignment. SEC PC: %d; Instr: %d\n",
261 program->current_pc,
262 program->current_instruction);
263 goto err;
264 }
265
266 *offset = src_offset;
267 }
268 break;
269
270 case (OFIFO):
271 if (dst == OFIFO) {
272 pr_err("MOVE: Invalid DST. SEC PC: %d; Instr: %d\n",
273 program->current_pc,
274 program->current_instruction);
275 goto err;
276 }
277 if (((dst == IFIFOAB1) || (dst == IFIFOAB2) ||
278 (dst == IFIFO) || (dst == PKA)) &&
279 (src_offset || dst_offset)) {
280 pr_err("MOVE: Offset should be zero. SEC PC: %d; Instr: %d\n",
281 program->current_pc,
282 program->current_instruction);
283 goto err;
284 }
285 *offset = dst_offset;
286 break;
287
288 case (DESCBUF):
289 if ((dst == CONTEXT1) || (dst == CONTEXT2)) {
290 *opt = MOVE_SET_AUX_DST;
291 } else if ((dst == MATH0) || (dst == MATH1) ||
292 (dst == MATH2) || (dst == MATH3)) {
293 *opt = MOVE_SET_AUX_MATH_DST;
294 } else if (dst == DESCBUF) {
295 pr_err("MOVE: Invalid DST. SEC PC: %d; Instr: %d\n",
296 program->current_pc,
297 program->current_instruction);
298 goto err;
299 } else if (((dst == OFIFO) || (dst == ALTSOURCE)) &&
300 (src_offset % 4)) {
301 pr_err("MOVE: Invalid offset alignment. SEC PC: %d; Instr %d\n",
302 program->current_pc,
303 program->current_instruction);
304 goto err;
305 }
306
307 *offset = src_offset;
308 break;
309
310 case (MATH0):
311 case (MATH1):
312 case (MATH2):
313 case (MATH3):
314 if ((dst == OFIFO) || (dst == ALTSOURCE)) {
315 if (src_offset % 4) {
316 pr_err("MOVE: Bad offset alignment. SEC PC: %d; Instr: %d\n",
317 program->current_pc,
318 program->current_instruction);
319 goto err;
320 }
321 *offset = src_offset;
322 } else if ((dst == IFIFOAB1) || (dst == IFIFOAB2) ||
323 (dst == IFIFO) || (dst == PKA)) {
324 *offset = src_offset;
325 } else {
326 *offset = dst_offset;
327
328 /*
329 * This condition is basically the negation of:
330 * dst in { CONTEXT[1-2], MATH[0-3] }
331 */
332 if ((dst != KEY1) && (dst != KEY2))
333 *opt = MOVE_SET_AUX_MATH_SRC;
334 }
335 break;
336
337 case (IFIFOABD):
338 case (IFIFOAB1):
339 case (IFIFOAB2):
340 case (ABD):
341 case (AB1):
342 case (AB2):
343 if ((dst == IFIFOAB1) || (dst == IFIFOAB2) ||
344 (dst == IFIFO) || (dst == PKA) || (dst == ALTSOURCE)) {
345 pr_err("MOVE: Bad DST. SEC PC: %d; Instr: %d\n",
346 program->current_pc,
347 program->current_instruction);
348 goto err;
349 } else {
350 if (dst == OFIFO) {
351 *opt = MOVE_SET_LEN_16b;
352 } else {
353 if (dst_offset % 4) {
354 pr_err("MOVE: Bad offset alignment. SEC PC: %d; Instr: %d\n",
355 program->current_pc,
356 program->current_instruction);
357 goto err;
358 }
359 *offset = dst_offset;
360 }
361 }
362 break;
363 default:
364 break;
365 }
366
367 return 0;
368 err:
369 return -EINVAL;
370 }
371
372 static inline int
math_offset(uint16_t offset)373 math_offset(uint16_t offset)
374 {
375 switch (offset) {
376 case 0:
377 return 0;
378 case 4:
379 return MOVE_AUX_LS;
380 case 6:
381 return MOVE_AUX_MS;
382 case 7:
383 return MOVE_AUX_LS | MOVE_AUX_MS;
384 }
385
386 return -EINVAL;
387 }
388
389 #endif /* __RTA_MOVE_CMD_H__ */
390