1/**
2 * viddec_mpeg2_workload.c
3 * -----------------------
4 * This file packs the data parsed and stored in the context into workload and
5 * emits it out. The current list of workitems emitter into the workload
6 * include:
7 *
8 * - DMEM - Register Data
9 * - Past and Future picture references
10 * - Quantization matrix data
11 *
12 * Slice data gets appended into the workload in viddec_mpeg2_parse.c
13 *
14 * Also, the frame attributes are updated in the workload.
15 */
16
17#include "viddec_mpeg2.h"
18#include "viddec_fw_item_types.h"
19
20void viddec_mpeg2_append_workitem(void *parent, viddec_workload_item_t *wi, uint8_t next_wl)
21{
22    if (next_wl)
23    {
24        viddec_pm_append_workitem_next(parent, wi);
25    }
26    else
27    {
28        viddec_pm_append_workitem(parent, wi);
29    }
30    return;
31}
32
33viddec_workload_t* viddec_mpeg2_get_header(void *parent, uint8_t next_wl)
34{
35    viddec_workload_t *ret;
36    if (next_wl)
37    {
38        ret = viddec_pm_get_next_header(parent);
39    }
40    else
41    {
42        ret = viddec_pm_get_header(parent);
43    }
44    return ret;
45}
46
47/* viddec_mpeg2_set_seq_ext_defaults() - Sets non-zero default values for    */
48/* sequence extension items in case sequence extension is not present.       */
49static void viddec_mpeg2_set_seq_ext_defaults(struct viddec_mpeg2_parser *parser)
50{
51    parser->info.seq_ext.progressive_sequence = true;
52    parser->info.seq_ext.chroma_format        = MPEG2_CF_420;
53}
54
55/* viddec_mpeg2_set_pic_cod_ext_defaults() - Sets non-zero default values for*/
56/* picture coding extension items in case picture coding extension is not    */
57/* present.                                                                  */
58static void viddec_mpeg2_set_pic_cod_ext_defaults(struct viddec_mpeg2_parser *parser)
59{
60    parser->info.pic_cod_ext.picture_structure    = MPEG2_PIC_STRUCT_FRAME;
61    parser->info.pic_cod_ext.frame_pred_frame_dct = true;
62    parser->info.pic_cod_ext.progressive_frame    = true;
63}
64
65/* viddec_mpeg2_pack_qmat() - Packs the 256 byte quantization matrix data    */
66/* 64 32-bit values.                                                         */
67#ifdef MFDBIGENDIAN
68static void viddec_mpeg2_pack_qmat(struct viddec_mpeg2_parser *parser)
69{
70    /* Quantization Matrix Support */
71    /* Populate Quantization Matrices */
72    uint32_t index = 0;
73    uint32_t *qmat_packed, *qmat_unpacked;
74
75    /* When transferring the quantization matrix data from the parser */
76    /* context into workload items, we are packing four 8 bit         */
77    /* quantization values into one DWORD (32 bits). To do this, the  */
78    /* array of values of type uint8_t, is typecast as uint32 * and   */
79    /* read.                                                          */
80    qmat_packed   = (uint32_t *) parser->wi.qmat;
81    qmat_unpacked = (uint32_t *) &parser->info.qnt_mat;
82
83    for (index=0; index<MPEG2_QUANT_MAT_SIZE; index++)
84    {
85        qmat_packed[index] = qmat_unpacked[index];
86    }
87    return;
88}
89#else
90static void viddec_mpeg2_pack_qmat(struct viddec_mpeg2_parser *parser)
91{
92    /* Quantization Matrix Support */
93    /* Populate Quantization Matrices */
94    uint32_t index = 0;
95    uint32_t *qmat_packed;
96    uint8_t  *qmat_unpacked;
97
98    /* When transferring the quantization matrix data from the parser */
99    /* context into workload items, we are packing four 8 bit         */
100    /* quantization values into one DWORD (32 bits). To do this, the  */
101    /* array of values of type uint8_t, is typecast as uint32 * and   */
102    /* read.                                                          */
103    qmat_packed   = (uint32_t *) parser->wi.qmat;
104    qmat_unpacked = (uint8_t *) &parser->info.qnt_mat;
105
106    for (index=0; index<MPEG2_QUANT_MAT_SIZE; index++)
107    {
108        qmat_packed[index] =
109            (((uint32_t)qmat_unpacked[(index<<2)+0])<< 24) |
110            (((uint32_t)qmat_unpacked[(index<<2)+1])<< 16) |
111            (((uint32_t)qmat_unpacked[(index<<2)+2])<<  8) |
112            (((uint32_t)qmat_unpacked[(index<<2)+3])<<  0) ;
113    }
114    return;
115}
116#endif
117
118/* viddec_mpeg2_trans_metadata_workitems() - Transfers the metadata stored   */
119/* in parser context into workitems by bit masking. These workitems are then */
120/* sent through emitter                                                      */
121static void viddec_mpeg2_trans_metadata_workitems(void *ctxt)
122{
123    struct viddec_mpeg2_parser *parser = (struct viddec_mpeg2_parser *) ctxt;
124
125    /* Reset register values */
126    parser->wi.csi1  = 0x0;
127    parser->wi.csi2  = 0x0;
128    parser->wi.cpi1  = 0x0;
129    parser->wi.cpce1 = 0x0;
130
131    /* Set defaults for missing fields */
132    if (!(parser->mpeg2_curr_seq_headers & MPEG2_HEADER_SEQ_EXT))
133    {
134        viddec_mpeg2_set_seq_ext_defaults(parser);
135    }
136    if (!(parser->mpeg2_curr_frame_headers & MPEG2_HEADER_PIC_COD_EXT))
137    {
138        viddec_mpeg2_set_pic_cod_ext_defaults(parser);
139    }
140
141    /* Populate Core Sequence Info 1 */
142    parser->wi.csi1 |= (parser->mpeg2_stream) <<  1;
143    parser->wi.csi1 |= (parser->info.seq_hdr.constrained_parameters_flag) <<  2;
144    parser->wi.csi1 |= (parser->info.seq_ext.progressive_sequence) <<  3;
145    parser->wi.csi1 |= (parser->info.seq_ext.chroma_format) << 16;
146    parser->wi.csi1 |= (parser->info.qnt_ext.load_intra_quantiser_matrix) << 19;
147    parser->wi.csi1 |= (parser->info.qnt_ext.load_non_intra_quantiser_matrix) << 20;
148    parser->wi.csi1 |= (parser->info.qnt_ext.load_chroma_intra_quantiser_matrix) << 21;
149    parser->wi.csi1 |= (parser->info.qnt_ext.load_chroma_non_intra_quantiser_matrix) << 22;
150    MPEG2_DEB("Core Sequence Info 1: 0x%.8X\n", parser->wi.csi1);
151
152    /* Populate Core Sequence Info 2 */
153    parser->wi.csi2 |= (parser->info.seq_hdr.horizontal_size_value & MPEG2_BIT_MASK_11);
154    parser->wi.csi2 |= (parser->info.seq_hdr.vertical_size_value & MPEG2_BIT_MASK_11) << 14;
155    MPEG2_DEB("Core Sequence Info 2: 0x%.8X\n", parser->wi.csi2);
156
157    /* Populate Core Picture Info */
158    parser->wi.cpi1 |= (parser->info.pic_hdr.full_pel_forward_vect);
159    parser->wi.cpi1 |= (parser->info.pic_hdr.forward_f_code) <<  1;
160    parser->wi.cpi1 |= (parser->info.pic_hdr.full_pel_backward_vect) <<  4;
161    parser->wi.cpi1 |= (parser->info.pic_hdr.backward_f_code) <<  5;
162    parser->wi.cpi1 |= (parser->info.pic_cod_ext.fcode00) <<  8;
163    parser->wi.cpi1 |= (parser->info.pic_cod_ext.fcode01) << 12;
164    parser->wi.cpi1 |= (parser->info.pic_cod_ext.fcode10) << 16;
165    parser->wi.cpi1 |= (parser->info.pic_cod_ext.fcode11) << 20;
166    parser->wi.cpi1 |= (parser->info.pic_cod_ext.intra_dc_precision) << 24;
167    parser->wi.cpi1 |= (parser->info.pic_hdr.picture_coding_type-1) << 26;
168    MPEG2_DEB("Core Picture Info 1: 0x%.8X\n", parser->wi.cpi1);
169
170    /* Populate Core Picture Extension Info */
171    parser->wi.cpce1 |= (parser->info.pic_cod_ext.composite_display_flag);
172    parser->wi.cpce1 |= (parser->info.pic_cod_ext.progressive_frame) <<  1;
173    parser->wi.cpce1 |= (parser->info.pic_cod_ext.chroma_420_type) <<  2;
174    parser->wi.cpce1 |= (parser->info.pic_cod_ext.repeat_first_field) <<  3;
175    parser->wi.cpce1 |= (parser->info.pic_cod_ext.alternate_scan) <<  4;
176    parser->wi.cpce1 |= (parser->info.pic_cod_ext.intra_vlc_format) <<  5;
177    parser->wi.cpce1 |= (parser->info.pic_cod_ext.q_scale_type) <<  6;
178    parser->wi.cpce1 |= (parser->info.pic_cod_ext.concealment_motion_vectors) <<  7;
179    parser->wi.cpce1 |= (parser->info.pic_cod_ext.frame_pred_frame_dct) <<  8;
180    parser->wi.cpce1 |= (parser->info.pic_cod_ext.top_field_first) <<  9;
181    parser->wi.cpce1 |= (parser->info.pic_cod_ext.picture_structure) << 10;
182    MPEG2_DEB("Core Picture Ext Info 1: 0x%.8X\n", parser->wi.cpce1);
183
184    return;
185}
186
187/* mpeg2_emit_display_frame() - Sends the frame id as a workload item.       */
188static inline void mpeg2_emit_frameid(void *parent, int32_t wl_type, uint8_t flag)
189{
190    viddec_workload_item_t wi;
191    wi.vwi_type = wl_type;
192
193    wi.ref_frame.reference_id     = 0;
194    wi.ref_frame.luma_phys_addr   = 0;
195    wi.ref_frame.chroma_phys_addr = 0;
196    viddec_mpeg2_append_workitem( parent, &wi, flag );
197}
198
199/* mpeg2_send_ref_reorder() - Reorders reference frames */
200static inline void mpeg2_send_ref_reorder(void *parent, uint8_t flag)
201{
202    viddec_workload_item_t wi;
203
204    wi.vwi_type = VIDDEC_WORKLOAD_REFERENCE_FRAME_REORDER;
205    wi.ref_reorder.ref_table_offset = 0;
206    /* Reorder index 1 to index 0 only */
207    wi.ref_reorder.ref_reorder_00010203 = 0x01010203;
208    wi.ref_reorder.ref_reorder_04050607 = 0x04050607;
209    viddec_mpeg2_append_workitem( parent, &wi, flag );
210}
211
212/* viddec_mpeg2_manage_ref() - Manages frame references by inserting the     */
213/* past and future references (if any) for every frame inserted in the       */
214/* workload.                                                                 */
215static void viddec_mpeg2_manage_ref(void *parent, void *ctxt)
216{
217    int32_t frame_id = 1;
218    int32_t frame_type;
219
220    /* Get MPEG2 Parser context */
221    struct viddec_mpeg2_parser *parser = (struct viddec_mpeg2_parser *) ctxt;
222    viddec_workload_t *wl = viddec_mpeg2_get_header( parent, parser->mpeg2_use_next_workload );
223    wl->is_reference_frame = 0;
224
225    /* Identify the frame type (I, P or B) */
226    frame_type = parser->info.pic_hdr.picture_coding_type;
227
228    /* Send reference frame information based on whether the picture is a */
229    /* frame picture or field picture. */
230    if ((!parser->mpeg2_picture_interlaced)
231        || ((parser->mpeg2_picture_interlaced) && (parser->mpeg2_first_field)))
232    {
233        /* Check if we need to reorder frame references/send frame for display */
234        /* in case of I or P type */
235        if (frame_type != MPEG2_PC_TYPE_B)
236        {
237            /* Checking reorder */
238            if (parser->mpeg2_ref_table_updated)
239            {
240                mpeg2_send_ref_reorder(parent, parser->mpeg2_use_next_workload);
241            }
242        }
243
244        /* Send reference frame workitems */
245        switch(frame_type)
246        {
247            case MPEG2_PC_TYPE_I:
248            {
249                break;
250            }
251            case MPEG2_PC_TYPE_P:
252            {
253                mpeg2_emit_frameid(parent, VIDDEC_WORKLOAD_MPEG2_REF_PAST, parser->mpeg2_use_next_workload);
254                break;
255            }
256            case MPEG2_PC_TYPE_B:
257            {
258                mpeg2_emit_frameid(parent, VIDDEC_WORKLOAD_MPEG2_REF_PAST, parser->mpeg2_use_next_workload);
259                mpeg2_emit_frameid(parent, VIDDEC_WORKLOAD_MPEG2_REF_FUTURE, parser->mpeg2_use_next_workload);
260            }
261        }
262
263        /* Set reference information updated flag */
264        if (!parser->mpeg2_picture_interlaced)
265        {
266            parser->mpeg2_wl_status |= MPEG2_WL_REF_INFO;
267        }
268    }
269    else
270    {
271        /* Set reference information updated flag for second fiel */
272        parser->mpeg2_wl_status |= MPEG2_WL_REF_INFO;
273    }
274
275    /* Set the reference frame flags for I and P types */
276    if (frame_type != MPEG2_PC_TYPE_B)
277    {
278        wl->is_reference_frame |= WORKLOAD_REFERENCE_FRAME | (frame_id & WORKLOAD_REFERENCE_FRAME_BMASK);
279        parser->mpeg2_ref_table_updated = true;
280    }
281
282    return;
283}
284
285/* viddec_mpeg2_check_unsupported() - Check for unsupported feature in the stream */
286static void viddec_mpeg2_check_unsupported(void *parent, void *ctxt)
287{
288    unsigned int unsupported_feature_found = 0;
289
290    /* Get MPEG2 Parser context */
291    struct viddec_mpeg2_parser *parser = (struct viddec_mpeg2_parser *) ctxt;
292
293    /* Get workload */
294    viddec_workload_t *wl = viddec_mpeg2_get_header( parent, parser->mpeg2_use_next_workload );
295
296    /* Get attributes in workload */
297    viddec_frame_attributes_t *attrs = &wl->attrs;
298
299    /* Check for unsupported content size */
300    unsupported_feature_found |= (attrs->cont_size.height > MPEG2_MAX_CONTENT_HEIGHT);
301    unsupported_feature_found |= (attrs->cont_size.width  > MPEG2_MAX_CONTENT_WIDTH);
302
303    /* Update parser status, if found */
304    if (unsupported_feature_found)
305    {
306        parser->mpeg2_wl_status |= MPEG2_WL_UNSUPPORTED;
307    }
308
309    return;
310}
311
312/* viddec_mpeg2_append_metadata() - Appends meta data from the stream.       */
313void viddec_mpeg2_append_metadata(void *parent, void *ctxt)
314{
315    /* Get MPEG2 Parser context */
316    struct viddec_mpeg2_parser *parser = (struct viddec_mpeg2_parser *) ctxt;
317
318    viddec_workload_item_t  wi;
319
320    /* Append sequence info, if found with current frame */
321    if (parser->mpeg2_curr_frame_headers & MPEG2_HEADER_SEQ)
322    {
323        memset(&wi, 0, sizeof(viddec_workload_item_t));
324        wi.vwi_type = VIDDEC_WORKLOAD_SEQUENCE_INFO;
325
326        viddec_fw_mp2_sh_set_horizontal_size_value       ( &(wi.mp2_sh) , parser->info.seq_hdr.horizontal_size_value);
327        viddec_fw_mp2_sh_set_vertical_size_value         ( &(wi.mp2_sh) , parser->info.seq_hdr.vertical_size_value);
328        viddec_fw_mp2_sh_set_aspect_ratio_information    ( &(wi.mp2_sh) , parser->info.seq_hdr.aspect_ratio_information);
329        viddec_fw_mp2_sh_set_frame_rate_code             ( &(wi.mp2_sh) , parser->info.seq_hdr.frame_rate_code);
330        viddec_fw_mp2_sh_set_bit_rate_value              ( &(wi.mp2_sh) , parser->info.seq_hdr.bit_rate_value);
331        viddec_fw_mp2_sh_set_vbv_buffer_size_value       ( &(wi.mp2_sh) , parser->info.seq_hdr.vbv_buffer_size_value);
332
333        viddec_mpeg2_append_workitem(parent, &wi, parser->mpeg2_use_next_workload);
334    }
335
336    /* Append sequence extension info, if found with current frame */
337    if (parser->mpeg2_curr_frame_headers & MPEG2_HEADER_SEQ_EXT)
338    {
339        memset(&wi, 0, sizeof(viddec_workload_item_t));
340        wi.vwi_type = VIDDEC_WORKLOAD_MPEG2_SEQ_EXT;
341
342        viddec_fw_mp2_se_set_profile_and_level_indication( &(wi.mp2_se) , parser->info.seq_ext.profile_and_level_indication);
343        viddec_fw_mp2_se_set_progressive_sequence        ( &(wi.mp2_se) , parser->info.seq_ext.progressive_sequence);
344        viddec_fw_mp2_se_set_chroma_format               ( &(wi.mp2_se) , parser->info.seq_ext.chroma_format);
345        viddec_fw_mp2_se_set_horizontal_size_extension   ( &(wi.mp2_se) , parser->info.seq_ext.horizontal_size_extension);
346        viddec_fw_mp2_se_set_vertical_size_extension     ( &(wi.mp2_se) , parser->info.seq_ext.vertical_size_extension);
347        viddec_fw_mp2_se_set_bit_rate_extension          ( &(wi.mp2_se) , parser->info.seq_ext.bit_rate_extension);
348        viddec_fw_mp2_se_set_vbv_buffer_size_extension   ( &(wi.mp2_se) , parser->info.seq_ext.vbv_buffer_size_extension);
349        viddec_fw_mp2_se_set_frame_rate_extension_n      ( &(wi.mp2_se) , parser->info.seq_ext.frame_rate_extension_n);
350        viddec_fw_mp2_se_set_frame_rate_extension_d      ( &(wi.mp2_se) , parser->info.seq_ext.frame_rate_extension_d);
351
352        viddec_mpeg2_append_workitem(parent, &wi, parser->mpeg2_use_next_workload);
353    }
354
355    /* Append Display info, if present */
356    if (parser->mpeg2_curr_frame_headers & MPEG2_HEADER_SEQ_DISP_EXT)
357    {
358        memset(&wi, 0, sizeof(viddec_workload_item_t));
359        wi.vwi_type = VIDDEC_WORKLOAD_DISPLAY_INFO;
360
361        viddec_fw_mp2_sde_set_video_format            ( &(wi.mp2_sde) , parser->info.seq_disp_ext.video_format);
362        viddec_fw_mp2_sde_set_color_description       ( &(wi.mp2_sde) , parser->info.seq_disp_ext.colour_description);
363        viddec_fw_mp2_sde_set_color_primaries         ( &(wi.mp2_sde) , parser->info.seq_disp_ext.colour_primaries);
364        viddec_fw_mp2_sde_set_transfer_characteristics( &(wi.mp2_sde) , parser->info.seq_disp_ext.transfer_characteristics);
365        viddec_fw_mp2_sde_set_display_horizontal_size ( &(wi.mp2_sde) , parser->info.seq_disp_ext.display_horizontal_size);
366        viddec_fw_mp2_sde_set_display_vertical_size   ( &(wi.mp2_sde) , parser->info.seq_disp_ext.display_vertical_size);
367
368        viddec_mpeg2_append_workitem(parent, &wi, parser->mpeg2_use_next_workload);
369    }
370
371    /* Append GOP info, if present */
372    if (parser->mpeg2_curr_frame_headers & MPEG2_HEADER_GOP)
373    {
374        memset(&wi, 0, sizeof(viddec_workload_item_t));
375        wi.vwi_type = VIDDEC_WORKLOAD_GOP_INFO;
376
377        viddec_fw_mp2_gop_set_closed_gop ( &(wi.mp2_gop) , parser->info.gop_hdr.closed_gop);
378        viddec_fw_mp2_gop_set_broken_link( &(wi.mp2_gop) , parser->info.gop_hdr.broken_link);
379
380        viddec_mpeg2_append_workitem(parent, &wi, parser->mpeg2_use_next_workload);
381    }
382
383    return;
384}
385
386/* viddec_mpeg2_append_workitems() - Appends decoder specific workitems      */
387/* to the workload starting at the address and length specified.             */
388static void viddec_mpeg2_append_workitems
389(
390    void *parent,
391    uint32_t* address,
392    int workitem_type,
393    int num_items,
394    uint8_t flag
395)
396{
397    int32_t                  index=0;
398    const uint32_t*          initial_address = address;
399    viddec_workload_item_t   wi;
400
401    for (index=0; index < num_items; index++)
402    {
403        wi.vwi_type = workitem_type;
404        wi.data.data_offset = (char *) address - (const char *) initial_address;
405        wi.data.data_payload[0] = address[0];
406        wi.data.data_payload[1] = address[1];
407        address += 2;
408
409        viddec_mpeg2_append_workitem(parent, &wi, flag);
410    }
411
412    return;
413}
414
415/* viddec_mpeg2_emit_workload() - Emits MPEG2 parser generated work load     */
416/* items.                                                                    */
417/* Items include: MPEG2 DMEM Data, Quantization Matrices.                    */
418/* Pixel ES data sent separately whenever parser sees slice data             */
419void viddec_mpeg2_emit_workload(void *parent, void *ctxt)
420{
421    MPEG2_DEB("Emitting workloads.\n");
422
423    /* Get MPEG2 Parser context */
424    struct viddec_mpeg2_parser *parser = (struct viddec_mpeg2_parser *) ctxt;
425
426    /* Append meta data workitems */
427    viddec_mpeg2_append_metadata(parent, ctxt);
428
429    /* Transfer metadata into attributes */
430    viddec_mpeg2_translate_attr(parent, ctxt);
431
432    /* Check for unsupported features in the stream and update parser status */
433    viddec_mpeg2_check_unsupported(parent, ctxt);
434
435    /* Transfer all stored metadata into MPEG2 Hardware Info */
436    viddec_mpeg2_trans_metadata_workitems(parser);
437
438    /* Send MPEG2 DMEM workitems */
439    viddec_mpeg2_append_workitems(parent,
440                                   (uint32_t *) &parser->wi,
441                                   VIDDEC_WORKLOAD_MPEG2_DMEM,
442                                   MPEG2_NUM_DMEM_WL_ITEMS,
443                                   parser->mpeg2_use_next_workload);
444    parser->mpeg2_wl_status |= MPEG2_WL_DMEM_DATA;
445    MPEG2_DEB("Adding %d items as DMEM Data.\n", MPEG2_NUM_DMEM_WL_ITEMS);
446
447    /* Send MPEG2 Quantization Matrix workitems, if updated */
448    viddec_mpeg2_pack_qmat(parser);
449    viddec_mpeg2_append_workitems(parent,
450                                   (uint32_t *) parser->wi.qmat,
451                                   VIDDEC_WORKLOAD_MPEG2_QMAT,
452                                   MPEG2_NUM_QMAT_WL_ITEMS,
453                                   parser->mpeg2_use_next_workload);
454    MPEG2_DEB("Adding %d items as QMAT Data.\n", MPEG2_NUM_QMAT_WL_ITEMS);
455
456    /* Manage reference frames */
457    viddec_mpeg2_manage_ref(parent, ctxt);
458
459    return;
460}
461
462