summaryrefslogtreecommitdiff
path: root/hifi/xaf/hifi-dpf/audio/xa-class-base.c
blob: ef1110e6fdbbd01b487b91ecd29b4ce8a25706d1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
/*******************************************************************************
* Copyright (C) 2018 Cadence Design Systems, Inc.
* 
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to use this Software with Cadence processor cores only and 
* not with any other processors and platforms, subject to
* the following conditions:
* 
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

******************************************************************************/

/*******************************************************************************
 * xa-class-base.c
 *
 * Generic audio codec task implementation
 *
 ******************************************************************************/

#define MODULE_TAG                      BASE

/*******************************************************************************
 * Includes
 ******************************************************************************/

#include "xf.h"
#include "xa-class-base.h"

/*******************************************************************************
 * Tracing configuration
 ******************************************************************************/

TRACE_TAG(INIT, 1);
TRACE_TAG(WARNING, 1);
TRACE_TAG(SETUP, 1);
TRACE_TAG(EXEC, 1);

/*******************************************************************************
 * Internal functions definitions
 ******************************************************************************/

/* ...codec pre-initialization */
static XA_ERRORCODE xa_base_preinit(XACodecBase *base, u32 core)
{
    WORD32      n;

    /* ...codec must be empty */
    XF_CHK_ERR(base->state == 0, XA_API_FATAL_INVALID_CMD);

    /* ...get API structure size */
    XA_API(base, XA_API_CMD_GET_API_SIZE, 0, &n);

    /* ...allocate memory for codec API structure (4-bytes aligned) */
    XMALLOC(&base->api, n, 4, core);

    /* ...set default config parameters */
    XA_API(base, XA_API_CMD_INIT, XA_CMD_TYPE_INIT_API_PRE_CONFIG_PARAMS, NULL);

    /* ...get memory info tables size */
    if (XA_API(base, XA_API_CMD_GET_MEMTABS_SIZE, 0, &n), n != 0)
    {
        /* ...allocate memory for tables (4-bytes aligned) */
        XMALLOC(&base->mem_tabs, n, 4, core);

        /* ...set pointer for process memory tables */
        XA_API(base, XA_API_CMD_SET_MEMTABS_PTR, 0, base->mem_tabs.addr);
    }
    
    TRACE(INIT, _b("Codec[%p] pre-initialization completed"), base);
    
    return XA_NO_ERROR;
}

/* ...post-initialization setup */
static XA_ERRORCODE xa_base_postinit(XACodecBase *base, u32 core)
{
    WORD32  n, i;
    
    /* ...issue post-config command and determine the buffer requirements */
    XA_API(base, XA_API_CMD_INIT, XA_CMD_TYPE_INIT_API_POST_CONFIG_PARAMS, NULL);

    /* ...get number of memory tables required */
    XA_API(base, XA_API_CMD_GET_N_MEMTABS, 0, &n);

    /* ...set scratch buffer in advance (as codec not necessarily exposes it) */
    base->scratch = XF_CORE_DATA(core)->scratch;

    /* ...allocate memory buffers */
    for (i = 0; i < n; i++)
    {
        WORD32      size, align, type;

        TRACE(1, _b("i = %u (of %u)"), (u32)i, (u32)n);
        
        /* ...get memory type */
        XA_API(base, XA_API_CMD_GET_MEM_INFO_TYPE, i, &type);

        /* ...get memory size of i-th buffer */
        XA_API(base, XA_API_CMD_GET_MEM_INFO_SIZE, i, &size);

        /* ...get alignment */
        XA_API(base, XA_API_CMD_GET_MEM_INFO_ALIGNMENT, i, &align);

        /* ...process individual buffer */
        switch (type)
        {
        case XA_MEMTYPE_SCRATCH:
            /* ...scratch memory is shared among all codecs; check its validity */
            XF_CHK_ERR(size <= XF_CFG_CODEC_SCRATCHMEM_SIZE, XA_API_FATAL_MEM_ALLOC);

            /* ...make sure alignment is valid */
            XF_CHK_ERR((XF_CFG_CODEC_SCRATCHMEM_ALIGN & (align - 1)) == 0, XA_API_FATAL_MEM_ALIGN);

            /* ...set the scratch memory pointer */
            XA_API(base, XA_API_CMD_SET_MEM_PTR, i, base->scratch);

            TRACE(INIT, _b("Mem tab %d: sz=%d al=%d ty=%d Scratch memory (%p)"), i, size, align, type, base->scratch);

            break;

        case XA_MEMTYPE_PERSIST:
            /* ...allocate persistent memory */
            XMALLOC(&base->persist, size, align, core);

            /* ...and set the pointer instantly */
            XA_API(base, XA_API_CMD_SET_MEM_PTR, i, base->persist.addr);

            TRACE(INIT, _b("Mem tab %d: sz=%d al=%d ty=%d Persistent memory (%p)"), i, size, align, type, base->persist.addr);

            break;

        case XA_MEMTYPE_INPUT:
        case XA_MEMTYPE_OUTPUT:
            /* ...input/output buffer specification; pass to codec function */
            CODEC_API(base, memtab, i, type, size, align, core);

            break;

        default:
            /* ...unrecognized memory type */
            TRACE(ERROR, _x("Invalid memory type: [%d]=(%u, %u, %u)"), i, type, size, align);
            return XA_API_FATAL_INVALID_CMD_TYPE;
        }
    }

    TRACE(INIT, _b("Codec[%p] post-initialization completed (api:%p[%u])"), base, base->api.addr, base->api.size);

    return XA_NO_ERROR;
}

/*******************************************************************************
 * Commands processing
 ******************************************************************************/

/* ...SET-PARAM processing (enabled in all states) */
XA_ERRORCODE xa_base_set_param(XACodecBase *base, xf_message_t *m)
{
    xf_set_param_msg_t     *cmd = m->buffer;
    xf_set_param_item_t    *param = &cmd->item[0];
    WORD32                  n, i;

    /* ...calculate total amount of parameters */
    n = m->length / sizeof(*param);

    /* ...check the message length is valid */
    XF_CHK_ERR(m->length == XF_SET_PARAM_CMD_LEN(n), XA_API_FATAL_INVALID_CMD_TYPE);

    /* ...apply all parameters; pass to codec-specific function */
    for (i = 0; i < n; i++)
    {
        TRACE(SETUP, _b("set-param[%p]: [%u]=%u"), base, param[i].id, param[i].value);

        if (base->setparam)
        {
            CODEC_API(base, setparam, param[i].id, &param[i].value);
        }
        else
        {
            XA_API(base, XA_API_CMD_SET_CONFIG_PARAM, param[i].id, &param[i].value);
        }
    }

    /* ...check if we need to do post-initialization */
    if ((base->state & XA_BASE_FLAG_POSTINIT) == 0)
    {
        /* ...do post-initialization step */
        XA_CHK(xa_base_postinit(base, XF_MSG_DST_CORE(m->id)));
        
        /* ...mark the codec static configuration is set */
        base->state ^= XA_BASE_FLAG_POSTINIT | XA_BASE_FLAG_RUNTIME_INIT;
    }
    
    /* ...complete message processing; output buffer is empty */
    xf_response_ok(m);

    return XA_NO_ERROR;
}

/* ...GET-PARAM message processing (enabled in all states) */
XA_ERRORCODE xa_base_get_param(XACodecBase *base, xf_message_t *m)
{
    xf_get_param_msg_t *cmd = m->buffer;
    u32                *id = &cmd->c.id[0];
    u32                *value = &cmd->r.value[0];
    u32                 n, i;

    /* ...calculate amount of parameters */
    n = m->length / sizeof(*id);

    /* ...check input parameter length */
    XF_CHK_ERR(XF_GET_PARAM_CMD_LEN(n) == m->length, XA_API_FATAL_INVALID_CMD_TYPE);

    /* ...retrieve the collection of codec  parameters */
    for (i = 0; i < n; i++)
    {
        /* ...place the result into same location */
        if (base->getparam)
        {
            CODEC_API(base, getparam, id[i], &value[i]);
        }
        else
        {
            XA_API(base, XA_API_CMD_GET_CONFIG_PARAM, id[i], &value[i]);
        }
    }

    /* ...complete message specifying output buffer size */
    xf_response_data(m, XF_GET_PARAM_RSP_LEN(n));

    return XA_NO_ERROR;
}

/* ...SET-PARAM-EXT processing (enabled in all states) */
XA_ERRORCODE xa_base_set_param_ext(XACodecBase *base, xf_message_t *m)
{
    xf_ext_param_msg_t *cmd = m->buffer;
    u16                 length = m->length;
    u16                 remaining = (length + 3) & ~3;
    u16                 i;
    
    for (i = 0; TRACE_CFG(SETUP) && i < remaining; i += 16)
    {
        TRACE(SETUP, _b("[%03x]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X"),
              i, 
              ((u8 *)m->buffer)[i + 0], ((u8 *)m->buffer)[i + 1],
              ((u8 *)m->buffer)[i + 2], ((u8 *)m->buffer)[i + 3],
              ((u8 *)m->buffer)[i + 4], ((u8 *)m->buffer)[i + 5],
              ((u8 *)m->buffer)[i + 6], ((u8 *)m->buffer)[i + 7],
              ((u8 *)m->buffer)[i + 8], ((u8 *)m->buffer)[i + 9],
              ((u8 *)m->buffer)[i + 10], ((u8 *)m->buffer)[i + 11],
              ((u8 *)m->buffer)[i + 12], ((u8 *)m->buffer)[i + 13],
              ((u8 *)m->buffer)[i + 14], ((u8 *)m->buffer)[i + 15]);
    }    

    /* ...process all parameters encapsulated in buffer */
    while (remaining >= sizeof(*cmd))
    {
        u16     id = cmd->desc.id;
        u16     dlen = cmd->desc.length;
        u16     dsize = (dlen + 3) & ~3;
        u16     pad = dlen & 3;

        /* ...cut-off descriptor header */
        remaining -= sizeof(*cmd);

        TRACE(SETUP, _b("remaining:%u, desc_size:%u"), (u32)remaining, (u32)dsize);
        
        /* ...make sure length is sufficient */        
        XF_CHK_ERR(remaining >= dsize, XA_API_FATAL_INVALID_CMD_TYPE);
        
        /* ...pad remaining bytes with zeroes */
        (pad ? memset(cmd->data + dlen, 0, 4 - pad) : 0);

        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]);

        /* ...apply parameter */
        XA_API(base, XA_API_CMD_SET_CONFIG_PARAM, id, cmd->data);

        /* ...move to next item (keep 4-bytes alignment for descriptor) */
        cmd = (xf_ext_param_msg_t *)(&cmd->data[0] + dsize), remaining -= dsize;
    }
    
    /* ...check the message is fully processed */
    XF_CHK_ERR(remaining == 0, XA_API_FATAL_INVALID_CMD_TYPE);

    /* ...complete message processing; output buffer is empty */
    //xf_response_ok(m);

    /* ...unfortunately, it looks like a bug of the library that updates the memory
     * and leaves it in a dirty state causing subsequent cache inconsistency - tbd
     */
    xf_response_data(m, length);

    return XA_NO_ERROR;
}

/* ...GET-PARAM-EXT message processing (enabled in all states) */
XA_ERRORCODE xa_base_get_param_ext(XACodecBase *base, xf_message_t *m)
{
    xf_ext_param_msg_t *cmd = m->buffer;
    u32                 length = m->length;
    u32                 remaining = (length + 3) & ~3;
    int                 i;

    for (i = 0; TRACE_CFG(SETUP) && i < remaining; i += 16)
    {
        TRACE(SETUP, _b("[%03x]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X"),
              i, 
              ((u8 *)m->buffer)[i + 0], ((u8 *)m->buffer)[i + 1],
              ((u8 *)m->buffer)[i + 2], ((u8 *)m->buffer)[i + 3],
              ((u8 *)m->buffer)[i + 4], ((u8 *)m->buffer)[i + 5],
              ((u8 *)m->buffer)[i + 6], ((u8 *)m->buffer)[i + 7],
              ((u8 *)m->buffer)[i + 8], ((u8 *)m->buffer)[i + 9],
              ((u8 *)m->buffer)[i + 10], ((u8 *)m->buffer)[i + 11],
              ((u8 *)m->buffer)[i + 12], ((u8 *)m->buffer)[i + 13],
              ((u8 *)m->buffer)[i + 14], ((u8 *)m->buffer)[i + 15]);
    }
    
    /* ...process all parameters encapsulated in buffer */
    while (remaining >= sizeof(*cmd))
    {
        u16     id = cmd->desc.id;
        u16     len = cmd->desc.length;
        u16     size = (len + 3) & ~3;
        u8      pad = len & 3;

        /* ...cut-off command header */
        remaining -= sizeof(*cmd);

        /* ...make sure data buffer has sufficient length */
        XF_CHK_ERR(remaining >= size, XA_API_FATAL_INVALID_CMD_TYPE);
        
        /* ...retrieve parameter from buffer (care about alignment? - tbd) */
        XA_API(base, XA_API_CMD_GET_CONFIG_PARAM, id, cmd->data);

        /* ...pad remaininig bytes with zeroes */
        (pad ? memset(cmd->data + len, 0, 4 - pad) : 0);

        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]);
        
        /* ...move to next item (alignment issues? - tbd) */
        cmd = (xf_ext_param_msg_t *)(&cmd->data[0] + size), remaining -= size;
    }
    
    /* ...check the message is fully processed */
    XF_CHK_ERR(remaining == 0, XA_API_FATAL_INVALID_CMD_TYPE);

    /* ...complete message processing; output buffer has the same length */
    xf_response_data(m, length);

    return XA_NO_ERROR;
}

/*******************************************************************************
 * Command/data processing functions
 ******************************************************************************/

/* ...generic codec data processing */
static XA_ERRORCODE xa_base_process(XACodecBase *base)
{
    XA_ERRORCODE    error;
    WORD32          done;

    /* ...clear internal scheduling flag */
    base->state &= ~XA_BASE_FLAG_SCHEDULE;
        
    /* ...codec-specific preprocessing (buffer maintenance) */
    if ((error = CODEC_API(base, preprocess)) != XA_NO_ERROR)
    {
        /* ...return non-fatal codec error */
        return error;
    }

    /* ...execution step */
    if (base->state & XA_BASE_FLAG_RUNTIME_INIT)
    {
        /* ...kick initialization process */
        XA_API(base, XA_API_CMD_INIT, XA_CMD_TYPE_INIT_PROCESS, NULL);

        /* ...check if initialization is completed */
        XA_API(base, XA_API_CMD_INIT, XA_CMD_TYPE_INIT_DONE_QUERY, &done);

        TRACE(EXEC, _b("Initialization result: %d"), done);

        /* ...switch to execution state if required */
        (done ? base->state ^= XA_BASE_FLAG_RUNTIME_INIT | XA_BASE_FLAG_EXECUTION : 0);
    }
    else if (base->state & XA_BASE_FLAG_EXECUTION)
    {
        TRACE(1, _b("do exec"));
        
        /* ...execute decoding process */
        XA_API(base, XA_API_CMD_EXECUTE, XA_CMD_TYPE_DO_EXECUTE, NULL);

        /* ...check for end-of-stream condition */
        XA_API(base, XA_API_CMD_EXECUTE, XA_CMD_TYPE_DONE_QUERY, &done);

        TRACE(EXEC, _b("Execution result: %d"), done);

        /* ...mark the output path is done to release all queued buffers */
        (done ? base->state ^= XA_BASE_FLAG_EXECUTION | XA_BASE_FLAG_COMPLETED : 0);
    }

    /* ...codec-specific buffer post-processing */
    return CODEC_API(base, postprocess, done);
}
                              
/* ...message-processing function (component entry point) */
static int xa_base_command(xf_component_t *component, xf_message_t *m)
{
    XACodecBase    *base = (XACodecBase *) component;
    u32             cmd;
    
    /* ...invoke data-processing function if message is null */
    if (m == NULL)
    {
        XF_CHK_ERR(!XA_ERROR_SEVERITY(xa_base_process(base)), -EPIPE);
        return 0;
    }

    /* ...process the command */
    TRACE(EXEC, _b("[%p]:state[%X]:(%X, %d, %p)"), base, base->state, m->opcode, m->length, m->buffer);

    /* ...bail out if this is forced termination command (I do have a map; maybe I'd better have a hook? - tbd) */
    if ((cmd = XF_OPCODE_TYPE(m->opcode)) == XF_OPCODE_TYPE(XF_UNREGISTER))
    {
        TRACE(INIT, _b("force component[%p] termination"), base);
        return -1;    
    }
    
    /* ...check opcode is valid */
    XF_CHK_ERR(cmd < base->command_num, -EINVAL);

    /* ...and has a hook */
    XF_CHK_ERR(base->command[cmd] != NULL, -EINVAL);
    
    /* ...pass control to specific command */
    XF_CHK_ERR(!XA_ERROR_SEVERITY(base->command[cmd](base, m)), -EPIPE);

    /* ...execution completed successfully */
    return 0;
}

/*******************************************************************************
 * Base codec API
 ******************************************************************************/

/* ...data processing scheduling */
void xa_base_schedule(XACodecBase *base, u32 dts)
{
    if ((base->state & XA_BASE_FLAG_SCHEDULE) == 0)
    {
        /* ...schedule component task execution */
        xf_component_schedule(&base->component, dts);

        /* ...and put scheduling flag */
        base->state ^= XA_BASE_FLAG_SCHEDULE;
    }
    else
    {
        TRACE(EXEC, _b("codec[%p] processing pending"), base);
    }
}

/* ...cancel data processing */
void xa_base_cancel(XACodecBase *base)
{
    if (base->state & XA_BASE_FLAG_SCHEDULE)
    {
        /* ...cancel scheduled codec task */
        xf_component_cancel(&base->component);

        /* ...and clear scheduling flag */
        base->state ^= XA_BASE_FLAG_SCHEDULE;

        TRACE(EXEC, _b("codec[%p] processing cancelled"), base);
    }
}

/* ...base codec destructor */
void xa_base_destroy(XACodecBase *base, u32 size, u32 core)
{
    /* ...deallocate all resources */
    xf_mm_free_buffer(&base->persist, core);
    xf_mm_free_buffer(&base->mem_tabs, core);
    xf_mm_free_buffer(&base->api, core);

    /* ...destroy codec structure (and task) itself */
    xf_mem_free(base, size, core, 0);

    TRACE(INIT, _b("codec[%p]:%u destroyed"), base, core);
}

/* ...generic codec initialization routine */
XACodecBase * xa_base_factory(u32 core, u32 size, xa_codec_func_t process)
{
    XACodecBase    *base;

    /* ...make sure the size is valid */
    XF_CHK_ERR(size >= sizeof(XACodecBase), NULL);
    
    /* ...allocate local memory for codec structure */
    XF_CHK_ERR(base = xf_mem_alloc(size, 0, core, 0), NULL);
 
    /* ...reset codec memory */
    memset(base, 0, size);

    /* ...set low-level codec API function */
    base->process = process;

    /* ...set message processing function */
    base->component.entry = xa_base_command;

    /* ...do basic initialization */
    if (xa_base_preinit(base, core) != XA_NO_ERROR)
    {
        /* ...initialization failed for some reason; do cleanup */
        xa_base_destroy(base, size, core);

        return NULL;
    }   

    /* ...initialization completed successfully */
    TRACE(INIT, _b("Codec[%p]:%u initialized"), base, core);
    
    return base;
}