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