1#include "viddec_pm_utils_list.h"
2#include "viddec_fw_debug.h"
3
4/*
5  Initialize list.
6 */
7void viddec_pm_utils_list_init(viddec_pm_utils_list_t *cxt)
8{
9    cxt->num_items = 0;
10    cxt->start_offset = 0;
11    cxt->end_offset = -1;
12    cxt->total_bytes = 0;
13    cxt->first_scprfx_length = 0;
14}
15
16/*
17  Add a new ES buffer to list. If not succesful returns 0.
18 */
19uint32_t viddec_pm_utils_list_addbuf(viddec_pm_utils_list_t *list, viddec_input_buffer_t *es_buf)
20{
21    uint32_t ret = 0;
22    if((list->num_items + 1) <= MAX_IBUFS_PER_SC)
23    {
24        list->num_items +=1;
25        list->sc_ibuf[list->num_items - 1] = *es_buf;
26        ret = 1;
27    }
28    return ret;
29}
30
31/*
32  We return the index of es buffer and the offset into it for the requested byte offset.
33  EX: if byte=4, and the first es buffer in list is of length 100, we return lis_index=0, offset=3.
34  byte value should range from [1-N].
35 */
36uint32_t viddec_pm_utils_list_getbyte_position(viddec_pm_utils_list_t *list, uint32_t byte, uint32_t *list_index, uint32_t *offset)
37{
38    uint32_t index = 0, accumulated_size=0;
39
40    /* First buffer in list is always special case, since start offset is tied to it */
41    accumulated_size = list->sc_ibuf[index].len - list->start_offset;
42    if( accumulated_size >= byte)
43    {
44        /* we found a match in first buffer itself */
45        *offset = list->start_offset + byte - 1;
46        *list_index = index;
47        return 0;
48    }
49    index++;
50    /* walkthrough the list until we find the byte */
51    while(index < list->num_items)
52    {
53        if((accumulated_size + list->sc_ibuf[index].len) >= byte)
54        {
55            *offset = byte - accumulated_size - 1;
56            *list_index = index;
57            return 0;
58        }
59        accumulated_size += list->sc_ibuf[index].len;
60        index++;
61    }
62    return 1;
63}
64
65/*
66  Since the stream data can span multiple ES buffers on different DDR locations, for our purpose
67  we store start and end position on each ES buffer to make the data look linear.
68  The start represents the linear offset of the first byte in list.
69  end-1 represents linear offset of last byte in list.
70 */
71void viddec_pm_utils_list_updatebytepos(viddec_pm_utils_list_t *list, uint8_t sc_prefix_length)
72{
73    uint32_t items=0;
74    uint32_t start=0, end=0;
75
76    if(list->num_items != 0)
77    {
78        end = list->sc_ibuf[0].len - list->start_offset;
79        if((int32_t)end >= list->total_bytes) end = list->total_bytes;
80        list->data[items].stpos = start;
81        list->data[items].edpos = end;
82        items++;
83        while((int32_t)end < list->total_bytes)
84        {
85            start = end;
86            end += list->sc_ibuf[items].len;
87            if((int32_t)end >= list->total_bytes) end = list->total_bytes;
88            list->data[items].stpos = start;
89            list->data[items].edpos = end;
90            items++;
91        }
92        while(items < list->num_items)
93        {
94            if(sc_prefix_length != 0)
95            {
96                start = end = list->total_bytes+1;
97            }
98            else
99            {
100                start = end = list->total_bytes;
101            }
102            list->data[items].stpos = start;
103            list->data[items].edpos = end;
104            items++;
105        }
106        /* Normal access unit sequence is SC+data+SC. We read SC+data+SC bytes so far.
107           but the current access unit should be SC+data, the Second SC belongs to next access unit.
108           So we subtract SC length to reflect that */
109        list->total_bytes -= sc_prefix_length;
110    }
111}
112
113static inline void viddec_pm_utils_list_emit_slice_tags_append(viddec_emitter_wkld *cur_wkld, viddec_workload_item_t *wi)
114{
115    /*
116      Most of the time len >0. However we can have a condition on EOS where the last buffer can be
117      zero sized in which case we want to make sure that we emit END of SLICE information.
118     */
119    if((wi->es.es_phys_len != 0) || (wi->es.es_flags&VIDDEC_WORKLOAD_FLAGS_ES_END_SLICE))
120    {
121        viddec_emit_append(cur_wkld, wi);
122    }
123}
124
125/*
126  Emit requested tags for data from start to end position. The tags should include end byte too.
127 */
128void viddec_pm_utils_list_emit_slice_tags(viddec_pm_utils_list_t *list, uint32_t start, uint32_t end, viddec_emitter *emitter, uint32_t is_cur_wkld, viddec_workload_item_t *wi)
129{
130    if((list->num_items != 0) && ((int32_t)start < (list->total_bytes)) && ((int32_t)end <= (list->total_bytes)))
131    {
132        uint32_t flags=0, items=0;
133        viddec_emitter_wkld *cur_wkld;
134
135        flags = wi->es.es_flags;
136        cur_wkld = (is_cur_wkld != 0) ? &(emitter->cur):&(emitter->next);
137        /* Seek until we find a ES buffer entry which has the start position */
138        while(start >= list->data[items].edpos) items++;
139
140        if(end < list->data[items].edpos)
141        { /* One ES buffer has both start and end in it. So dump a single entry */
142            wi->es.es_phys_len = end - start + 1;
143            wi->es.es_phys_addr = list->sc_ibuf[items].phys + start - list->data[items].stpos;
144            /* Account for start_offset if its the first buffer in List */
145            if(items == 0) wi->es.es_phys_addr += list->start_offset;
146
147            wi->es.es_flags = flags | VIDDEC_WORKLOAD_FLAGS_ES_START_SLICE | VIDDEC_WORKLOAD_FLAGS_ES_END_SLICE;
148            viddec_pm_utils_list_emit_slice_tags_append(cur_wkld, wi);
149        }
150        else
151        {
152            /* We know that there are at least two buffers for the requested data. Dump the first item */
153            wi->es.es_phys_len = list->data[items].edpos - start;
154            wi->es.es_phys_addr = list->sc_ibuf[items].phys + start - list->data[items].stpos;
155            if(items == 0) wi->es.es_phys_addr += list->start_offset;
156            wi->es.es_flags = flags | VIDDEC_WORKLOAD_FLAGS_ES_START_SLICE;
157            viddec_pm_utils_list_emit_slice_tags_append(cur_wkld, wi);
158            items++;
159            /* Dump everything in between if any until the last buffer */
160            while(end >= list->data[items].edpos)
161            {
162                wi->es.es_phys_len = list->data[items].edpos - list->data[items].stpos;
163                wi->es.es_phys_addr = list->sc_ibuf[items].phys;
164                wi->es.es_flags = flags;
165                viddec_pm_utils_list_emit_slice_tags_append(cur_wkld, wi);
166                items++;
167            }
168            /* Dump ES buffer which has end in it along with end slice flag */
169            wi->es.es_phys_len = end - list->data[items].stpos + 1;
170            wi->es.es_phys_addr = list->sc_ibuf[items].phys;
171            wi->es.es_flags = flags | VIDDEC_WORKLOAD_FLAGS_ES_END_SLICE;
172            viddec_pm_utils_list_emit_slice_tags_append(cur_wkld, wi);
173        }
174    }
175}
176
177/*
178  We delete the consumed buffers in our list. If there are any buffers left over which have more data
179  the get moved to the top of the list array.
180 */
181void viddec_pm_utils_list_remove_used_entries(viddec_pm_utils_list_t *list, uint32_t length)
182{
183    list->end_offset = -1;
184
185    if(list->num_items != 0)
186    {
187        if(length != 0)
188        {
189            uint32_t items = list->num_items-1, byte_pos;
190            uint32_t index=0;
191            viddec_input_buffer_t *es_buf;
192            byte_pos = list->total_bytes;
193            while((list->data[items].edpos > byte_pos) && (list->data[items].stpos > byte_pos))
194            {
195                items--;
196            }
197            if(items != 0)
198            {
199                list->start_offset = byte_pos - list->data[items].stpos;
200                while(items < list->num_items)
201                {
202                    es_buf = &(list->sc_ibuf[items]);
203                    list->sc_ibuf[index] = *es_buf;
204                    index++;
205                    items++;
206                }
207                list->num_items = index;
208            }
209            else
210            {
211                list->start_offset += (byte_pos - list->data[items].stpos);
212            }
213        }
214        else
215        {
216            list->num_items = 0;
217            list->start_offset = 0;
218        }
219        list->total_bytes = length;
220    }
221}
222