blob: d6f6adf3188cee410066fec7078320aecfa46c2b [file] [log] [blame]
#include "viddec_pm_utils_list.h"
#include "viddec_fw_debug.h"
/*
Initialize list.
*/
void viddec_pm_utils_list_init(viddec_pm_utils_list_t *cxt)
{
cxt->num_items = 0;
cxt->start_offset = 0;
cxt->end_offset = -1;
cxt->total_bytes = 0;
cxt->first_scprfx_length = 0;
}
/*
Add a new ES buffer to list. If not succesful returns 0.
*/
uint32_t viddec_pm_utils_list_addbuf(viddec_pm_utils_list_t *list, viddec_input_buffer_t *es_buf)
{
uint32_t ret = 0;
if((list->num_items + 1) <= MAX_IBUFS_PER_SC)
{
list->num_items +=1;
list->sc_ibuf[list->num_items - 1] = *es_buf;
ret = 1;
}
return ret;
}
/*
We return the index of es buffer and the offset into it for the requested byte offset.
EX: if byte=4, and the first es buffer in list is of length 100, we return lis_index=0, offset=3.
byte value should range from [1-N].
*/
uint32_t viddec_pm_utils_list_getbyte_position(viddec_pm_utils_list_t *list, uint32_t byte, uint32_t *list_index, uint32_t *offset)
{
uint32_t index = 0, accumulated_size=0;
/* First buffer in list is always special case, since start offset is tied to it */
accumulated_size = list->sc_ibuf[index].len - list->start_offset;
if( accumulated_size >= byte)
{
/* we found a match in first buffer itself */
*offset = list->start_offset + byte - 1;
*list_index = index;
return 0;
}
index++;
/* walkthrough the list until we find the byte */
while(index < list->num_items)
{
if((accumulated_size + list->sc_ibuf[index].len) >= byte)
{
*offset = byte - accumulated_size - 1;
*list_index = index;
return 0;
}
accumulated_size += list->sc_ibuf[index].len;
index++;
}
return 1;
}
/*
Since the stream data can span multiple ES buffers on different DDR locations, for our purpose
we store start and end position on each ES buffer to make the data look linear.
The start represents the linear offset of the first byte in list.
end-1 represents linear offset of last byte in list.
*/
void viddec_pm_utils_list_updatebytepos(viddec_pm_utils_list_t *list, uint8_t sc_prefix_length)
{
uint32_t items=0;
uint32_t start=0, end=0;
if(list->num_items != 0)
{
end = list->sc_ibuf[0].len - list->start_offset;
if((int32_t)end >= list->total_bytes) end = list->total_bytes;
list->data[items].stpos = start;
list->data[items].edpos = end;
items++;
while((int32_t)end < list->total_bytes)
{
start = end;
end += list->sc_ibuf[items].len;
if((int32_t)end >= list->total_bytes) end = list->total_bytes;
list->data[items].stpos = start;
list->data[items].edpos = end;
items++;
}
while(items < list->num_items)
{
if(sc_prefix_length != 0)
{
start = end = list->total_bytes+1;
}
else
{
start = end = list->total_bytes;
}
list->data[items].stpos = start;
list->data[items].edpos = end;
items++;
}
/* Normal access unit sequence is SC+data+SC. We read SC+data+SC bytes so far.
but the current access unit should be SC+data, the Second SC belongs to next access unit.
So we subtract SC length to reflect that */
list->total_bytes -= sc_prefix_length;
}
}
static inline void viddec_pm_utils_list_emit_slice_tags_append(viddec_emitter_wkld *cur_wkld, viddec_workload_item_t *wi)
{
/*
Most of the time len >0. However we can have a condition on EOS where the last buffer can be
zero sized in which case we want to make sure that we emit END of SLICE information.
*/
if((wi->es.es_phys_len != 0) || (wi->es.es_flags&VIDDEC_WORKLOAD_FLAGS_ES_END_SLICE))
{
viddec_emit_append(cur_wkld, wi);
}
}
/*
Emit requested tags for data from start to end position. The tags should include end byte too.
*/
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)
{
if((list->num_items != 0) && ((int32_t)start < (list->total_bytes)) && ((int32_t)end <= (list->total_bytes)))
{
uint32_t flags=0, items=0;
viddec_emitter_wkld *cur_wkld;
flags = wi->es.es_flags;
cur_wkld = (is_cur_wkld != 0) ? &(emitter->cur):&(emitter->next);
/* Seek until we find a ES buffer entry which has the start position */
while(start >= list->data[items].edpos) items++;
if(end < list->data[items].edpos)
{ /* One ES buffer has both start and end in it. So dump a single entry */
wi->es.es_phys_len = end - start + 1;
wi->es.es_phys_addr = list->sc_ibuf[items].phys + start - list->data[items].stpos;
/* Account for start_offset if its the first buffer in List */
if(items == 0) wi->es.es_phys_addr += list->start_offset;
wi->es.es_flags = flags | VIDDEC_WORKLOAD_FLAGS_ES_START_SLICE | VIDDEC_WORKLOAD_FLAGS_ES_END_SLICE;
viddec_pm_utils_list_emit_slice_tags_append(cur_wkld, wi);
}
else
{
/* We know that there are at least two buffers for the requested data. Dump the first item */
wi->es.es_phys_len = list->data[items].edpos - start;
wi->es.es_phys_addr = list->sc_ibuf[items].phys + start - list->data[items].stpos;
if(items == 0) wi->es.es_phys_addr += list->start_offset;
wi->es.es_flags = flags | VIDDEC_WORKLOAD_FLAGS_ES_START_SLICE;
viddec_pm_utils_list_emit_slice_tags_append(cur_wkld, wi);
items++;
/* Dump everything in between if any until the last buffer */
while(end >= list->data[items].edpos)
{
wi->es.es_phys_len = list->data[items].edpos - list->data[items].stpos;
wi->es.es_phys_addr = list->sc_ibuf[items].phys;
wi->es.es_flags = flags;
viddec_pm_utils_list_emit_slice_tags_append(cur_wkld, wi);
items++;
}
/* Dump ES buffer which has end in it along with end slice flag */
wi->es.es_phys_len = end - list->data[items].stpos + 1;
wi->es.es_phys_addr = list->sc_ibuf[items].phys;
wi->es.es_flags = flags | VIDDEC_WORKLOAD_FLAGS_ES_END_SLICE;
viddec_pm_utils_list_emit_slice_tags_append(cur_wkld, wi);
}
}
}
/*
We delete the consumed buffers in our list. If there are any buffers left over which have more data
the get moved to the top of the list array.
*/
void viddec_pm_utils_list_remove_used_entries(viddec_pm_utils_list_t *list, uint32_t length)
{
list->end_offset = -1;
if(list->num_items != 0)
{
if(length != 0)
{
uint32_t items = list->num_items-1, byte_pos;
uint32_t index=0;
viddec_input_buffer_t *es_buf;
byte_pos = list->total_bytes;
while((list->data[items].edpos > byte_pos) && (list->data[items].stpos > byte_pos))
{
items--;
}
if(items != 0)
{
list->start_offset = byte_pos - list->data[items].stpos;
while(items < list->num_items)
{
es_buf = &(list->sc_ibuf[items]);
list->sc_ibuf[index] = *es_buf;
index++;
items++;
}
list->num_items = index;
}
else
{
list->start_offset += (byte_pos - list->data[items].stpos);
}
}
else
{
list->num_items = 0;
list->start_offset = 0;
}
list->total_bytes = length;
}
}