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 */
xa_base_preinit(XACodecBase * base,u32 core)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 */
xa_base_postinit(XACodecBase * base,u32 core)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) */
xa_base_set_param(XACodecBase * base,xf_message_t * m)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, &param[i].value);
186         }
187         else
188         {
189             XA_API(base, XA_API_CMD_SET_CONFIG_PARAM, param[i].id, &param[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) */
xa_base_get_param(XACodecBase * base,xf_message_t * m)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) */
xa_base_set_param_ext(XACodecBase * base,xf_message_t * m)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) */
xa_base_get_param_ext(XACodecBase * base,xf_message_t * m)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 */
xa_base_process(XACodecBase * base)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) */
xa_base_command(xf_component_t * component,xf_message_t * m)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 */
xa_base_schedule(XACodecBase * base,u32 dts)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 */
xa_base_cancel(XACodecBase * base)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 */
xa_base_destroy(XACodecBase * base,u32 size,u32 core)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 */
xa_base_factory(u32 core,u32 size,xa_codec_func_t process)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