1 /******************************************************************************* 2 * Copyright (C) 2018 Cadence Design Systems, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining 5 * a copy of this software and associated documentation files (the 6 * "Software"), to use this Software with Cadence processor cores only and 7 * not with any other processors and platforms, subject to 8 * the following conditions: 9 * 10 * The above copyright notice and this permission notice shall be included 11 * in all copies or substantial portions of the Software. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 14 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 15 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 16 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 17 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 18 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 21 ******************************************************************************/ 22 23 /******************************************************************************* 24 * xa-class-base.c 25 * 26 * Generic audio codec task implementation 27 * 28 ******************************************************************************/ 29 30 #define MODULE_TAG BASE 31 32 /******************************************************************************* 33 * Includes 34 ******************************************************************************/ 35 36 #include "xf.h" 37 #include "xa-class-base.h" 38 39 /******************************************************************************* 40 * Tracing configuration 41 ******************************************************************************/ 42 43 TRACE_TAG(INIT, 1); 44 TRACE_TAG(WARNING, 1); 45 TRACE_TAG(SETUP, 1); 46 TRACE_TAG(EXEC, 1); 47 48 /******************************************************************************* 49 * Internal functions definitions 50 ******************************************************************************/ 51 52 /* ...codec pre-initialization */ 53 static XA_ERRORCODE xa_base_preinit(XACodecBase *base, u32 core) 54 { 55 WORD32 n; 56 57 /* ...codec must be empty */ 58 XF_CHK_ERR(base->state == 0, XA_API_FATAL_INVALID_CMD); 59 60 /* ...get API structure size */ 61 XA_API(base, XA_API_CMD_GET_API_SIZE, 0, &n); 62 63 /* ...allocate memory for codec API structure (4-bytes aligned) */ 64 XMALLOC(&base->api, n, 4, core); 65 66 /* ...set default config parameters */ 67 XA_API(base, XA_API_CMD_INIT, XA_CMD_TYPE_INIT_API_PRE_CONFIG_PARAMS, NULL); 68 69 /* ...get memory info tables size */ 70 if (XA_API(base, XA_API_CMD_GET_MEMTABS_SIZE, 0, &n), n != 0) 71 { 72 /* ...allocate memory for tables (4-bytes aligned) */ 73 XMALLOC(&base->mem_tabs, n, 4, core); 74 75 /* ...set pointer for process memory tables */ 76 XA_API(base, XA_API_CMD_SET_MEMTABS_PTR, 0, base->mem_tabs.addr); 77 } 78 79 TRACE(INIT, _b("Codec[%p] pre-initialization completed"), base); 80 81 return XA_NO_ERROR; 82 } 83 84 /* ...post-initialization setup */ 85 static XA_ERRORCODE xa_base_postinit(XACodecBase *base, u32 core) 86 { 87 WORD32 n, i; 88 89 /* ...issue post-config command and determine the buffer requirements */ 90 XA_API(base, XA_API_CMD_INIT, XA_CMD_TYPE_INIT_API_POST_CONFIG_PARAMS, NULL); 91 92 /* ...get number of memory tables required */ 93 XA_API(base, XA_API_CMD_GET_N_MEMTABS, 0, &n); 94 95 /* ...set scratch buffer in advance (as codec not necessarily exposes it) */ 96 base->scratch = XF_CORE_DATA(core)->scratch; 97 98 /* ...allocate memory buffers */ 99 for (i = 0; i < n; i++) 100 { 101 WORD32 size, align, type; 102 103 TRACE(1, _b("i = %u (of %u)"), (u32)i, (u32)n); 104 105 /* ...get memory type */ 106 XA_API(base, XA_API_CMD_GET_MEM_INFO_TYPE, i, &type); 107 108 /* ...get memory size of i-th buffer */ 109 XA_API(base, XA_API_CMD_GET_MEM_INFO_SIZE, i, &size); 110 111 /* ...get alignment */ 112 XA_API(base, XA_API_CMD_GET_MEM_INFO_ALIGNMENT, i, &align); 113 114 /* ...process individual buffer */ 115 switch (type) 116 { 117 case XA_MEMTYPE_SCRATCH: 118 /* ...scratch memory is shared among all codecs; check its validity */ 119 XF_CHK_ERR(size <= XF_CFG_CODEC_SCRATCHMEM_SIZE, XA_API_FATAL_MEM_ALLOC); 120 121 /* ...make sure alignment is valid */ 122 XF_CHK_ERR((XF_CFG_CODEC_SCRATCHMEM_ALIGN & (align - 1)) == 0, XA_API_FATAL_MEM_ALIGN); 123 124 /* ...set the scratch memory pointer */ 125 XA_API(base, XA_API_CMD_SET_MEM_PTR, i, base->scratch); 126 127 TRACE(INIT, _b("Mem tab %d: sz=%d al=%d ty=%d Scratch memory (%p)"), i, size, align, type, base->scratch); 128 129 break; 130 131 case XA_MEMTYPE_PERSIST: 132 /* ...allocate persistent memory */ 133 XMALLOC(&base->persist, size, align, core); 134 135 /* ...and set the pointer instantly */ 136 XA_API(base, XA_API_CMD_SET_MEM_PTR, i, base->persist.addr); 137 138 TRACE(INIT, _b("Mem tab %d: sz=%d al=%d ty=%d Persistent memory (%p)"), i, size, align, type, base->persist.addr); 139 140 break; 141 142 case XA_MEMTYPE_INPUT: 143 case XA_MEMTYPE_OUTPUT: 144 /* ...input/output buffer specification; pass to codec function */ 145 CODEC_API(base, memtab, i, type, size, align, core); 146 147 break; 148 149 default: 150 /* ...unrecognized memory type */ 151 TRACE(ERROR, _x("Invalid memory type: [%d]=(%u, %u, %u)"), i, type, size, align); 152 return XA_API_FATAL_INVALID_CMD_TYPE; 153 } 154 } 155 156 TRACE(INIT, _b("Codec[%p] post-initialization completed (api:%p[%u])"), base, base->api.addr, base->api.size); 157 158 return XA_NO_ERROR; 159 } 160 161 /******************************************************************************* 162 * Commands processing 163 ******************************************************************************/ 164 165 /* ...SET-PARAM processing (enabled in all states) */ 166 XA_ERRORCODE xa_base_set_param(XACodecBase *base, xf_message_t *m) 167 { 168 xf_set_param_msg_t *cmd = m->buffer; 169 xf_set_param_item_t *param = &cmd->item[0]; 170 WORD32 n, i; 171 172 /* ...calculate total amount of parameters */ 173 n = m->length / sizeof(*param); 174 175 /* ...check the message length is valid */ 176 XF_CHK_ERR(m->length == XF_SET_PARAM_CMD_LEN(n), XA_API_FATAL_INVALID_CMD_TYPE); 177 178 /* ...apply all parameters; pass to codec-specific function */ 179 for (i = 0; i < n; i++) 180 { 181 TRACE(SETUP, _b("set-param[%p]: [%u]=%u"), base, param[i].id, param[i].value); 182 183 if (base->setparam) 184 { 185 CODEC_API(base, setparam, param[i].id, ¶m[i].value); 186 } 187 else 188 { 189 XA_API(base, XA_API_CMD_SET_CONFIG_PARAM, param[i].id, ¶m[i].value); 190 } 191 } 192 193 /* ...check if we need to do post-initialization */ 194 if ((base->state & XA_BASE_FLAG_POSTINIT) == 0) 195 { 196 /* ...do post-initialization step */ 197 XA_CHK(xa_base_postinit(base, XF_MSG_DST_CORE(m->id))); 198 199 /* ...mark the codec static configuration is set */ 200 base->state ^= XA_BASE_FLAG_POSTINIT | XA_BASE_FLAG_RUNTIME_INIT; 201 } 202 203 /* ...complete message processing; output buffer is empty */ 204 xf_response_ok(m); 205 206 return XA_NO_ERROR; 207 } 208 209 /* ...GET-PARAM message processing (enabled in all states) */ 210 XA_ERRORCODE xa_base_get_param(XACodecBase *base, xf_message_t *m) 211 { 212 xf_get_param_msg_t *cmd = m->buffer; 213 u32 *id = &cmd->c.id[0]; 214 u32 *value = &cmd->r.value[0]; 215 u32 n, i; 216 217 /* ...calculate amount of parameters */ 218 n = m->length / sizeof(*id); 219 220 /* ...check input parameter length */ 221 XF_CHK_ERR(XF_GET_PARAM_CMD_LEN(n) == m->length, XA_API_FATAL_INVALID_CMD_TYPE); 222 223 /* ...retrieve the collection of codec parameters */ 224 for (i = 0; i < n; i++) 225 { 226 /* ...place the result into same location */ 227 if (base->getparam) 228 { 229 CODEC_API(base, getparam, id[i], &value[i]); 230 } 231 else 232 { 233 XA_API(base, XA_API_CMD_GET_CONFIG_PARAM, id[i], &value[i]); 234 } 235 } 236 237 /* ...complete message specifying output buffer size */ 238 xf_response_data(m, XF_GET_PARAM_RSP_LEN(n)); 239 240 return XA_NO_ERROR; 241 } 242 243 /* ...SET-PARAM-EXT processing (enabled in all states) */ 244 XA_ERRORCODE xa_base_set_param_ext(XACodecBase *base, xf_message_t *m) 245 { 246 xf_ext_param_msg_t *cmd = m->buffer; 247 u16 length = m->length; 248 u16 remaining = (length + 3) & ~3; 249 u16 i; 250 251 for (i = 0; TRACE_CFG(SETUP) && i < remaining; i += 16) 252 { 253 TRACE(SETUP, _b("[%03x]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X"), 254 i, 255 ((u8 *)m->buffer)[i + 0], ((u8 *)m->buffer)[i + 1], 256 ((u8 *)m->buffer)[i + 2], ((u8 *)m->buffer)[i + 3], 257 ((u8 *)m->buffer)[i + 4], ((u8 *)m->buffer)[i + 5], 258 ((u8 *)m->buffer)[i + 6], ((u8 *)m->buffer)[i + 7], 259 ((u8 *)m->buffer)[i + 8], ((u8 *)m->buffer)[i + 9], 260 ((u8 *)m->buffer)[i + 10], ((u8 *)m->buffer)[i + 11], 261 ((u8 *)m->buffer)[i + 12], ((u8 *)m->buffer)[i + 13], 262 ((u8 *)m->buffer)[i + 14], ((u8 *)m->buffer)[i + 15]); 263 } 264 265 /* ...process all parameters encapsulated in buffer */ 266 while (remaining >= sizeof(*cmd)) 267 { 268 u16 id = cmd->desc.id; 269 u16 dlen = cmd->desc.length; 270 u16 dsize = (dlen + 3) & ~3; 271 u16 pad = dlen & 3; 272 273 /* ...cut-off descriptor header */ 274 remaining -= sizeof(*cmd); 275 276 TRACE(SETUP, _b("remaining:%u, desc_size:%u"), (u32)remaining, (u32)dsize); 277 278 /* ...make sure length is sufficient */ 279 XF_CHK_ERR(remaining >= dsize, XA_API_FATAL_INVALID_CMD_TYPE); 280 281 /* ...pad remaining bytes with zeroes */ 282 (pad ? memset(cmd->data + dlen, 0, 4 - pad) : 0); 283 284 TRACE(SETUP, _b("set-ext-param[%p]: [%u]:%u - [%02X:%02X:%02X:%02X:...]"), base, id, dsize, cmd->data[0], cmd->data[1], cmd->data[2], cmd->data[3]); 285 286 /* ...apply parameter */ 287 XA_API(base, XA_API_CMD_SET_CONFIG_PARAM, id, cmd->data); 288 289 /* ...move to next item (keep 4-bytes alignment for descriptor) */ 290 cmd = (xf_ext_param_msg_t *)(&cmd->data[0] + dsize), remaining -= dsize; 291 } 292 293 /* ...check the message is fully processed */ 294 XF_CHK_ERR(remaining == 0, XA_API_FATAL_INVALID_CMD_TYPE); 295 296 /* ...complete message processing; output buffer is empty */ 297 //xf_response_ok(m); 298 299 /* ...unfortunately, it looks like a bug of the library that updates the memory 300 * and leaves it in a dirty state causing subsequent cache inconsistency - tbd 301 */ 302 xf_response_data(m, length); 303 304 return XA_NO_ERROR; 305 } 306 307 /* ...GET-PARAM-EXT message processing (enabled in all states) */ 308 XA_ERRORCODE xa_base_get_param_ext(XACodecBase *base, xf_message_t *m) 309 { 310 xf_ext_param_msg_t *cmd = m->buffer; 311 u32 length = m->length; 312 u32 remaining = (length + 3) & ~3; 313 int i; 314 315 for (i = 0; TRACE_CFG(SETUP) && i < remaining; i += 16) 316 { 317 TRACE(SETUP, _b("[%03x]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X"), 318 i, 319 ((u8 *)m->buffer)[i + 0], ((u8 *)m->buffer)[i + 1], 320 ((u8 *)m->buffer)[i + 2], ((u8 *)m->buffer)[i + 3], 321 ((u8 *)m->buffer)[i + 4], ((u8 *)m->buffer)[i + 5], 322 ((u8 *)m->buffer)[i + 6], ((u8 *)m->buffer)[i + 7], 323 ((u8 *)m->buffer)[i + 8], ((u8 *)m->buffer)[i + 9], 324 ((u8 *)m->buffer)[i + 10], ((u8 *)m->buffer)[i + 11], 325 ((u8 *)m->buffer)[i + 12], ((u8 *)m->buffer)[i + 13], 326 ((u8 *)m->buffer)[i + 14], ((u8 *)m->buffer)[i + 15]); 327 } 328 329 /* ...process all parameters encapsulated in buffer */ 330 while (remaining >= sizeof(*cmd)) 331 { 332 u16 id = cmd->desc.id; 333 u16 len = cmd->desc.length; 334 u16 size = (len + 3) & ~3; 335 u8 pad = len & 3; 336 337 /* ...cut-off command header */ 338 remaining -= sizeof(*cmd); 339 340 /* ...make sure data buffer has sufficient length */ 341 XF_CHK_ERR(remaining >= size, XA_API_FATAL_INVALID_CMD_TYPE); 342 343 /* ...retrieve parameter from buffer (care about alignment? - tbd) */ 344 XA_API(base, XA_API_CMD_GET_CONFIG_PARAM, id, cmd->data); 345 346 /* ...pad remaininig bytes with zeroes */ 347 (pad ? memset(cmd->data + len, 0, 4 - pad) : 0); 348 349 TRACE(SETUP, _b("get-ext-param[%p]: [%u]:%u - [%02X:%02X:%02X:%02X:...]"), base, id, size, cmd->data[0], cmd->data[1], cmd->data[2], cmd->data[3]); 350 351 /* ...move to next item (alignment issues? - tbd) */ 352 cmd = (xf_ext_param_msg_t *)(&cmd->data[0] + size), remaining -= size; 353 } 354 355 /* ...check the message is fully processed */ 356 XF_CHK_ERR(remaining == 0, XA_API_FATAL_INVALID_CMD_TYPE); 357 358 /* ...complete message processing; output buffer has the same length */ 359 xf_response_data(m, length); 360 361 return XA_NO_ERROR; 362 } 363 364 /******************************************************************************* 365 * Command/data processing functions 366 ******************************************************************************/ 367 368 /* ...generic codec data processing */ 369 static XA_ERRORCODE xa_base_process(XACodecBase *base) 370 { 371 XA_ERRORCODE error; 372 WORD32 done; 373 374 /* ...clear internal scheduling flag */ 375 base->state &= ~XA_BASE_FLAG_SCHEDULE; 376 377 /* ...codec-specific preprocessing (buffer maintenance) */ 378 if ((error = CODEC_API(base, preprocess)) != XA_NO_ERROR) 379 { 380 /* ...return non-fatal codec error */ 381 return error; 382 } 383 384 /* ...execution step */ 385 if (base->state & XA_BASE_FLAG_RUNTIME_INIT) 386 { 387 /* ...kick initialization process */ 388 XA_API(base, XA_API_CMD_INIT, XA_CMD_TYPE_INIT_PROCESS, NULL); 389 390 /* ...check if initialization is completed */ 391 XA_API(base, XA_API_CMD_INIT, XA_CMD_TYPE_INIT_DONE_QUERY, &done); 392 393 TRACE(EXEC, _b("Initialization result: %d"), done); 394 395 /* ...switch to execution state if required */ 396 (done ? base->state ^= XA_BASE_FLAG_RUNTIME_INIT | XA_BASE_FLAG_EXECUTION : 0); 397 } 398 else if (base->state & XA_BASE_FLAG_EXECUTION) 399 { 400 TRACE(1, _b("do exec")); 401 402 /* ...execute decoding process */ 403 XA_API(base, XA_API_CMD_EXECUTE, XA_CMD_TYPE_DO_EXECUTE, NULL); 404 405 /* ...check for end-of-stream condition */ 406 XA_API(base, XA_API_CMD_EXECUTE, XA_CMD_TYPE_DONE_QUERY, &done); 407 408 TRACE(EXEC, _b("Execution result: %d"), done); 409 410 /* ...mark the output path is done to release all queued buffers */ 411 (done ? base->state ^= XA_BASE_FLAG_EXECUTION | XA_BASE_FLAG_COMPLETED : 0); 412 } 413 414 /* ...codec-specific buffer post-processing */ 415 return CODEC_API(base, postprocess, done); 416 } 417 418 /* ...message-processing function (component entry point) */ 419 static int xa_base_command(xf_component_t *component, xf_message_t *m) 420 { 421 XACodecBase *base = (XACodecBase *) component; 422 u32 cmd; 423 424 /* ...invoke data-processing function if message is null */ 425 if (m == NULL) 426 { 427 XF_CHK_ERR(!XA_ERROR_SEVERITY(xa_base_process(base)), -EPIPE); 428 return 0; 429 } 430 431 /* ...process the command */ 432 TRACE(EXEC, _b("[%p]:state[%X]:(%X, %d, %p)"), base, base->state, m->opcode, m->length, m->buffer); 433 434 /* ...bail out if this is forced termination command (I do have a map; maybe I'd better have a hook? - tbd) */ 435 if ((cmd = XF_OPCODE_TYPE(m->opcode)) == XF_OPCODE_TYPE(XF_UNREGISTER)) 436 { 437 TRACE(INIT, _b("force component[%p] termination"), base); 438 return -1; 439 } 440 441 /* ...check opcode is valid */ 442 XF_CHK_ERR(cmd < base->command_num, -EINVAL); 443 444 /* ...and has a hook */ 445 XF_CHK_ERR(base->command[cmd] != NULL, -EINVAL); 446 447 /* ...pass control to specific command */ 448 XF_CHK_ERR(!XA_ERROR_SEVERITY(base->command[cmd](base, m)), -EPIPE); 449 450 /* ...execution completed successfully */ 451 return 0; 452 } 453 454 /******************************************************************************* 455 * Base codec API 456 ******************************************************************************/ 457 458 /* ...data processing scheduling */ 459 void xa_base_schedule(XACodecBase *base, u32 dts) 460 { 461 if ((base->state & XA_BASE_FLAG_SCHEDULE) == 0) 462 { 463 /* ...schedule component task execution */ 464 xf_component_schedule(&base->component, dts); 465 466 /* ...and put scheduling flag */ 467 base->state ^= XA_BASE_FLAG_SCHEDULE; 468 } 469 else 470 { 471 TRACE(EXEC, _b("codec[%p] processing pending"), base); 472 } 473 } 474 475 /* ...cancel data processing */ 476 void xa_base_cancel(XACodecBase *base) 477 { 478 if (base->state & XA_BASE_FLAG_SCHEDULE) 479 { 480 /* ...cancel scheduled codec task */ 481 xf_component_cancel(&base->component); 482 483 /* ...and clear scheduling flag */ 484 base->state ^= XA_BASE_FLAG_SCHEDULE; 485 486 TRACE(EXEC, _b("codec[%p] processing cancelled"), base); 487 } 488 } 489 490 /* ...base codec destructor */ 491 void xa_base_destroy(XACodecBase *base, u32 size, u32 core) 492 { 493 /* ...deallocate all resources */ 494 xf_mm_free_buffer(&base->persist, core); 495 xf_mm_free_buffer(&base->mem_tabs, core); 496 xf_mm_free_buffer(&base->api, core); 497 498 /* ...destroy codec structure (and task) itself */ 499 xf_mem_free(base, size, core, 0); 500 501 TRACE(INIT, _b("codec[%p]:%u destroyed"), base, core); 502 } 503 504 /* ...generic codec initialization routine */ 505 XACodecBase * xa_base_factory(u32 core, u32 size, xa_codec_func_t process) 506 { 507 XACodecBase *base; 508 509 /* ...make sure the size is valid */ 510 XF_CHK_ERR(size >= sizeof(XACodecBase), NULL); 511 512 /* ...allocate local memory for codec structure */ 513 XF_CHK_ERR(base = xf_mem_alloc(size, 0, core, 0), NULL); 514 515 /* ...reset codec memory */ 516 memset(base, 0, size); 517 518 /* ...set low-level codec API function */ 519 base->process = process; 520 521 /* ...set message processing function */ 522 base->component.entry = xa_base_command; 523 524 /* ...do basic initialization */ 525 if (xa_base_preinit(base, core) != XA_NO_ERROR) 526 { 527 /* ...initialization failed for some reason; do cleanup */ 528 xa_base_destroy(base, size, core); 529 530 return NULL; 531 } 532 533 /* ...initialization completed successfully */ 534 TRACE(INIT, _b("Codec[%p]:%u initialized"), base, core); 535 536 return base; 537 } 538