]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | /* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0) |
2 | * | |
3 | * Copyright 2008-2016 Freescale Semiconductor Inc. | |
f67539c2 | 4 | * Copyright 2016,2019 NXP |
11fdf7f2 TL |
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 | */ | |
f67539c2 TL |
49 | static const unsigned int move_src_table_sz[] = {9, 11, 14, 14, 14, 14, 14, 14, |
50 | 14, 14}; | |
11fdf7f2 TL |
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 | |
f67539c2 | 75 | unsigned int move_dst_table_sz[] = {13, 14, 14, 15, 15, 15, 15, 15, 15, 15}; |
11fdf7f2 TL |
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 | |
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 | if ((rta_sec_era < RTA_SEC_ERA_7) && (cmd_type != __MOVE)) { | |
99 | pr_err("MOVE: MOVEB / MOVEDW not supported by SEC Era %d. SEC PC: %d; Instr: %d\n", | |
100 | USER_SEC_ERA(rta_sec_era), program->current_pc, | |
101 | program->current_instruction); | |
102 | goto err; | |
103 | } | |
104 | ||
105 | /* write command type */ | |
106 | if (cmd_type == __MOVEB) { | |
107 | opcode = CMD_MOVEB; | |
108 | } else if (cmd_type == __MOVEDW) { | |
109 | opcode = CMD_MOVEDW; | |
110 | } else if (!(flags & IMMED)) { | |
111 | if (rta_sec_era < RTA_SEC_ERA_3) { | |
112 | pr_err("MOVE: MOVE_LEN not supported by SEC Era %d. SEC PC: %d; Instr: %d\n", | |
113 | USER_SEC_ERA(rta_sec_era), program->current_pc, | |
114 | program->current_instruction); | |
115 | goto err; | |
116 | } | |
117 | ||
118 | if ((length != MATH0) && (length != MATH1) && | |
119 | (length != MATH2) && (length != MATH3)) { | |
120 | pr_err("MOVE: MOVE_LEN length must be MATH[0-3]. SEC PC: %d; Instr: %d\n", | |
121 | program->current_pc, | |
122 | program->current_instruction); | |
123 | goto err; | |
124 | } | |
125 | ||
126 | opcode = CMD_MOVE_LEN; | |
127 | is_move_len_cmd = true; | |
128 | } else { | |
129 | opcode = CMD_MOVE; | |
130 | } | |
131 | ||
132 | /* write offset first, to check for invalid combinations or incorrect | |
133 | * offset values sooner; decide which offset should be here | |
134 | * (src or dst) | |
135 | */ | |
136 | ret = set_move_offset(program, src, src_offset, dst, dst_offset, | |
137 | &offset, &opt); | |
138 | if (ret < 0) | |
139 | goto err; | |
140 | ||
141 | opcode |= (offset << MOVE_OFFSET_SHIFT) & MOVE_OFFSET_MASK; | |
142 | ||
143 | /* set AUX field if required */ | |
144 | if (opt == MOVE_SET_AUX_SRC) { | |
145 | opcode |= ((src_offset / 16) << MOVE_AUX_SHIFT) & MOVE_AUX_MASK; | |
146 | } else if (opt == MOVE_SET_AUX_DST) { | |
147 | opcode |= ((dst_offset / 16) << MOVE_AUX_SHIFT) & MOVE_AUX_MASK; | |
148 | } else if (opt == MOVE_SET_AUX_LS) { | |
149 | opcode |= MOVE_AUX_LS; | |
150 | } else if (opt & MOVE_SET_AUX_MATH) { | |
151 | if (opt & MOVE_SET_AUX_SRC) | |
152 | offset = src_offset; | |
153 | else | |
154 | offset = dst_offset; | |
155 | ||
156 | if (rta_sec_era < RTA_SEC_ERA_6) { | |
157 | if (offset) | |
158 | pr_debug("MOVE: Offset not supported by SEC Era %d. SEC PC: %d; Instr: %d\n", | |
159 | USER_SEC_ERA(rta_sec_era), | |
160 | program->current_pc, | |
161 | program->current_instruction); | |
162 | /* nothing to do for offset = 0 */ | |
163 | } else { | |
164 | ret = math_offset(offset); | |
165 | if (ret < 0) { | |
166 | pr_err("MOVE: Invalid offset in MATH register. SEC PC: %d; Instr: %d\n", | |
167 | program->current_pc, | |
168 | program->current_instruction); | |
169 | goto err; | |
170 | } | |
171 | ||
172 | opcode |= (uint32_t)ret; | |
173 | } | |
174 | } | |
175 | ||
176 | /* write source field */ | |
177 | ret = __rta_map_opcode((uint32_t)src, move_src_table, | |
178 | move_src_table_sz[rta_sec_era], &val); | |
179 | if (ret < 0) { | |
180 | pr_err("MOVE: Invalid SRC. SEC PC: %d; Instr: %d\n", | |
181 | program->current_pc, program->current_instruction); | |
182 | goto err; | |
183 | } | |
184 | opcode |= val; | |
185 | ||
186 | /* write destination field */ | |
187 | ret = __rta_map_opcode((uint32_t)dst, move_dst_table, | |
188 | move_dst_table_sz[rta_sec_era], &val); | |
189 | if (ret < 0) { | |
190 | pr_err("MOVE: Invalid DST. SEC PC: %d; Instr: %d\n", | |
191 | program->current_pc, program->current_instruction); | |
192 | goto err; | |
193 | } | |
194 | opcode |= val; | |
195 | ||
196 | /* write flags */ | |
197 | if (flags & (FLUSH1 | FLUSH2)) | |
198 | opcode |= MOVE_AUX_MS; | |
199 | if (flags & (LAST2 | LAST1)) | |
200 | opcode |= MOVE_AUX_LS; | |
201 | if (flags & WAITCOMP) | |
202 | opcode |= MOVE_WAITCOMP; | |
203 | ||
204 | if (!is_move_len_cmd) { | |
205 | /* write length */ | |
206 | if (opt == MOVE_SET_LEN_16b) | |
207 | opcode |= (length & (MOVE_OFFSET_MASK | MOVE_LEN_MASK)); | |
208 | else | |
209 | opcode |= (length & MOVE_LEN_MASK); | |
210 | } else { | |
211 | /* write mrsel */ | |
212 | switch (length) { | |
213 | case (MATH0): | |
214 | /* | |
215 | * opcode |= MOVELEN_MRSEL_MATH0; | |
216 | * MOVELEN_MRSEL_MATH0 is 0 | |
217 | */ | |
218 | break; | |
219 | case (MATH1): | |
220 | opcode |= MOVELEN_MRSEL_MATH1; | |
221 | break; | |
222 | case (MATH2): | |
223 | opcode |= MOVELEN_MRSEL_MATH2; | |
224 | break; | |
225 | case (MATH3): | |
226 | opcode |= MOVELEN_MRSEL_MATH3; | |
227 | break; | |
228 | } | |
229 | ||
230 | /* write size */ | |
231 | if (rta_sec_era >= RTA_SEC_ERA_7) { | |
232 | if (flags & SIZE_WORD) | |
233 | opcode |= MOVELEN_SIZE_WORD; | |
234 | else if (flags & SIZE_BYTE) | |
235 | opcode |= MOVELEN_SIZE_BYTE; | |
236 | else if (flags & SIZE_DWORD) | |
237 | opcode |= MOVELEN_SIZE_DWORD; | |
238 | } | |
239 | } | |
240 | ||
241 | __rta_out32(program, opcode); | |
242 | program->current_instruction++; | |
243 | ||
244 | return (int)start_pc; | |
245 | ||
246 | err: | |
247 | program->first_error_pc = start_pc; | |
248 | program->current_instruction++; | |
249 | return ret; | |
250 | } | |
251 | ||
252 | static inline int | |
253 | set_move_offset(struct program *program __maybe_unused, | |
254 | uint64_t src, uint16_t src_offset, | |
255 | uint64_t dst, uint16_t dst_offset, | |
256 | uint16_t *offset, uint16_t *opt) | |
257 | { | |
258 | switch (src) { | |
259 | case (CONTEXT1): | |
260 | case (CONTEXT2): | |
261 | if (dst == DESCBUF) { | |
262 | *opt = MOVE_SET_AUX_SRC; | |
263 | *offset = dst_offset; | |
264 | } else if ((dst == KEY1) || (dst == KEY2)) { | |
265 | if ((src_offset) && (dst_offset)) { | |
266 | pr_err("MOVE: Bad offset. SEC PC: %d; Instr: %d\n", | |
267 | program->current_pc, | |
268 | program->current_instruction); | |
269 | goto err; | |
270 | } | |
271 | if (dst_offset) { | |
272 | *opt = MOVE_SET_AUX_LS; | |
273 | *offset = dst_offset; | |
274 | } else { | |
275 | *offset = src_offset; | |
276 | } | |
277 | } else { | |
278 | if ((dst == MATH0) || (dst == MATH1) || | |
279 | (dst == MATH2) || (dst == MATH3)) { | |
280 | *opt = MOVE_SET_AUX_MATH_DST; | |
281 | } else if (((dst == OFIFO) || (dst == ALTSOURCE)) && | |
282 | (src_offset % 4)) { | |
283 | pr_err("MOVE: Bad offset alignment. SEC PC: %d; Instr: %d\n", | |
284 | program->current_pc, | |
285 | program->current_instruction); | |
286 | goto err; | |
287 | } | |
288 | ||
289 | *offset = src_offset; | |
290 | } | |
291 | break; | |
292 | ||
293 | case (OFIFO): | |
294 | if (dst == OFIFO) { | |
295 | pr_err("MOVE: Invalid DST. SEC PC: %d; Instr: %d\n", | |
296 | program->current_pc, | |
297 | program->current_instruction); | |
298 | goto err; | |
299 | } | |
300 | if (((dst == IFIFOAB1) || (dst == IFIFOAB2) || | |
301 | (dst == IFIFO) || (dst == PKA)) && | |
302 | (src_offset || dst_offset)) { | |
303 | pr_err("MOVE: Offset should be zero. SEC PC: %d; Instr: %d\n", | |
304 | program->current_pc, | |
305 | program->current_instruction); | |
306 | goto err; | |
307 | } | |
308 | *offset = dst_offset; | |
309 | break; | |
310 | ||
311 | case (DESCBUF): | |
312 | if ((dst == CONTEXT1) || (dst == CONTEXT2)) { | |
313 | *opt = MOVE_SET_AUX_DST; | |
314 | } else if ((dst == MATH0) || (dst == MATH1) || | |
315 | (dst == MATH2) || (dst == MATH3)) { | |
316 | *opt = MOVE_SET_AUX_MATH_DST; | |
317 | } else if (dst == DESCBUF) { | |
318 | pr_err("MOVE: Invalid DST. SEC PC: %d; Instr: %d\n", | |
319 | program->current_pc, | |
320 | program->current_instruction); | |
321 | goto err; | |
322 | } else if (((dst == OFIFO) || (dst == ALTSOURCE)) && | |
323 | (src_offset % 4)) { | |
324 | pr_err("MOVE: Invalid offset alignment. SEC PC: %d; Instr %d\n", | |
325 | program->current_pc, | |
326 | program->current_instruction); | |
327 | goto err; | |
328 | } | |
329 | ||
330 | *offset = src_offset; | |
331 | break; | |
332 | ||
333 | case (MATH0): | |
334 | case (MATH1): | |
335 | case (MATH2): | |
336 | case (MATH3): | |
337 | if ((dst == OFIFO) || (dst == ALTSOURCE)) { | |
338 | if (src_offset % 4) { | |
339 | pr_err("MOVE: Bad offset alignment. SEC PC: %d; Instr: %d\n", | |
340 | program->current_pc, | |
341 | program->current_instruction); | |
342 | goto err; | |
343 | } | |
344 | *offset = src_offset; | |
345 | } else if ((dst == IFIFOAB1) || (dst == IFIFOAB2) || | |
346 | (dst == IFIFO) || (dst == PKA)) { | |
347 | *offset = src_offset; | |
348 | } else { | |
349 | *offset = dst_offset; | |
350 | ||
351 | /* | |
352 | * This condition is basically the negation of: | |
353 | * dst in { CONTEXT[1-2], MATH[0-3] } | |
354 | */ | |
355 | if ((dst != KEY1) && (dst != KEY2)) | |
356 | *opt = MOVE_SET_AUX_MATH_SRC; | |
357 | } | |
358 | break; | |
359 | ||
360 | case (IFIFOABD): | |
361 | case (IFIFOAB1): | |
362 | case (IFIFOAB2): | |
363 | case (ABD): | |
364 | case (AB1): | |
365 | case (AB2): | |
366 | if ((dst == IFIFOAB1) || (dst == IFIFOAB2) || | |
367 | (dst == IFIFO) || (dst == PKA) || (dst == ALTSOURCE)) { | |
368 | pr_err("MOVE: Bad DST. SEC PC: %d; Instr: %d\n", | |
369 | program->current_pc, | |
370 | program->current_instruction); | |
371 | goto err; | |
372 | } else { | |
373 | if (dst == OFIFO) { | |
374 | *opt = MOVE_SET_LEN_16b; | |
375 | } else { | |
376 | if (dst_offset % 4) { | |
377 | pr_err("MOVE: Bad offset alignment. SEC PC: %d; Instr: %d\n", | |
378 | program->current_pc, | |
379 | program->current_instruction); | |
380 | goto err; | |
381 | } | |
382 | *offset = dst_offset; | |
383 | } | |
384 | } | |
385 | break; | |
386 | default: | |
387 | break; | |
388 | } | |
389 | ||
390 | return 0; | |
391 | err: | |
392 | return -EINVAL; | |
393 | } | |
394 | ||
395 | static inline int | |
396 | math_offset(uint16_t offset) | |
397 | { | |
398 | switch (offset) { | |
399 | case 0: | |
400 | return 0; | |
401 | case 4: | |
402 | return MOVE_AUX_LS; | |
403 | case 6: | |
404 | return MOVE_AUX_MS; | |
405 | case 7: | |
406 | return MOVE_AUX_LS | MOVE_AUX_MS; | |
407 | } | |
408 | ||
409 | return -EINVAL; | |
410 | } | |
411 | ||
412 | #endif /* __RTA_MOVE_CMD_H__ */ |