1 #include "viddec_pm_utils_list.h"
2 #include "viddec_fw_debug.h"
3 
4 /*
5   Initialize list.
6  */
viddec_pm_utils_list_init(viddec_pm_utils_list_t * cxt)7 void 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  */
viddec_pm_utils_list_addbuf(viddec_pm_utils_list_t * list,viddec_input_buffer_t * es_buf)19 uint32_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  */
viddec_pm_utils_list_getbyte_position(viddec_pm_utils_list_t * list,uint32_t byte,uint32_t * list_index,uint32_t * offset)36 uint32_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  */
viddec_pm_utils_list_updatebytepos(viddec_pm_utils_list_t * list,uint8_t sc_prefix_length)71 void 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 
viddec_pm_utils_list_emit_slice_tags_append(viddec_emitter_wkld * cur_wkld,viddec_workload_item_t * wi)113 static 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  */
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)128 void 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  */
viddec_pm_utils_list_remove_used_entries(viddec_pm_utils_list_t * list,uint32_t length)181 void 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