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 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__ */ 413