/*
* Copyright (c) 2011 Intel Corporation. All Rights Reserved.
* Copyright (c) Imagination Technologies Limited, UK
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Authors:
* Waldo Bastian <waldo.bastian@intel.com>
*
*/
#include "psb_cmdbuf.h"
#include <unistd.h>
#include <stdio.h>
#include "hwdefs/mem_io.h"
#include "hwdefs/msvdx_offsets.h"
#include "hwdefs/dma_api.h"
#include "hwdefs/reg_io2.h"
#include "hwdefs/msvdx_vec_reg_io2.h"
#include "hwdefs/msvdx_vdmc_reg_io2.h"
#include "hwdefs/msvdx_mtx_reg_io2.h"
#include "hwdefs/msvdx_dmac_linked_list.h"
#include "hwdefs/msvdx_rendec_mtx_slice_cntrl_reg_io2.h"
#include "hwdefs/dxva_cmdseq_msg.h"
#include "hwdefs/dxva_fw_ctrl.h"
#include "hwdefs/fwrk_msg_mem_io.h"
#include "hwdefs/dxva_msg.h"
#include "hwdefs/msvdx_cmds_io2.h"
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/time.h>
#include "psb_def.h"
#include "psb_drv_debug.h"
#ifndef BAYTRAIL
#include "psb_ws_driver.h"
#endif
#include <wsbm/wsbm_pool.h>
#include <wsbm/wsbm_manager.h>
#include <wsbm/wsbm_util.h>
#include <wsbm/wsbm_fencemgr.h>
/*
* Buffer layout:
* cmd_base <= cmd_idx < CMD_END() == lldma_base
* lldma_base <= lldma_idx < LLDMA_END() == (cmd_base + size)
*
* Reloc buffer layout:
* MTX_msg < reloc_base == MTX_msg + MTXMSG_SIZE
* reloc_base <= reloc_idx < RELOC_END() == (MTX_msg + reloc_size)
*/
#define MTXMSG_END(cmdbuf) (cmdbuf->reloc_base)
#define RELOC_END(cmdbuf) (cmdbuf->MTX_msg + cmdbuf->reloc_size)
#define CMD_END(cmdbuf) (cmdbuf->lldma_base)
#define LLDMA_END(cmdbuf) (cmdbuf->cmd_base + cmdbuf->size)
#define MTXMSG_SIZE (0x1000)
#define RELOC_SIZE (0x3000)
#define CMD_SIZE (0x3000)
#define LLDMA_SIZE (0x2000)
#define MTXMSG_MARGIN (0x0040)
#define RELOC_MARGIN (0x0800)
#define CMD_MARGIN (0x0400)
#define LLDMA_MARGIN (0x0400)
#define PSB_SLICE_EXTRACT_UPDATE (0x2)
/*
* Create command buffer
*/
VAStatus psb_cmdbuf_create(object_context_p obj_context, psb_driver_data_p driver_data,
psb_cmdbuf_p cmdbuf
)
{
VAStatus vaStatus = VA_STATUS_SUCCESS;
unsigned int size = CMD_SIZE + LLDMA_SIZE;
unsigned int reloc_size = MTXMSG_SIZE + RELOC_SIZE;
unsigned int regio_size = (obj_context->picture_width >> 4) * (obj_context->picture_height >> 4) * 172;
cmdbuf->size = 0;
cmdbuf->reloc_size = 0;
cmdbuf->regio_size = 0;
cmdbuf->MTX_msg = NULL;
cmdbuf->cmd_base = NULL;
cmdbuf->regio_base = NULL;
cmdbuf->cmd_idx = NULL;
cmdbuf->regio_idx = NULL;
cmdbuf->cmd_bitstream_size = NULL;
cmdbuf->lldma_base = NULL;
cmdbuf->lldma_idx = NULL;
cmdbuf->reloc_base = NULL;
cmdbuf->reloc_idx = NULL;
cmdbuf->reg_start = NULL;
cmdbuf->rendec_block_start = NULL;
cmdbuf->rendec_chunk_start = NULL;
cmdbuf->skip_block_start = NULL;
cmdbuf->last_next_segment_cmd = NULL;
cmdbuf->buffer_refs_count = 0;
cmdbuf->buffer_refs_allocated = 10;
cmdbuf->buffer_refs = (psb_buffer_p *) calloc(1, sizeof(psb_buffer_p) * cmdbuf->buffer_refs_allocated);
if (NULL == cmdbuf->buffer_refs) {
cmdbuf->buffer_refs_allocated = 0;
vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
}
if (VA_STATUS_SUCCESS == vaStatus) {
vaStatus = psb_buffer_create(driver_data, size, psb_bt_cpu_vpu, &cmdbuf->buf);
cmdbuf->size = size;
}
if (VA_STATUS_SUCCESS == vaStatus) {
vaStatus = psb_buffer_create(driver_data, reloc_size, psb_bt_cpu_only, &cmdbuf->reloc_buf);
cmdbuf->reloc_size = reloc_size;
}
if (VA_STATUS_SUCCESS == vaStatus) {
vaStatus = psb_buffer_create(driver_data, regio_size, psb_bt_cpu_only, &cmdbuf->regio_buf);
cmdbuf->regio_size = regio_size;
}
if (VA_STATUS_SUCCESS != vaStatus) {
psb_cmdbuf_destroy(cmdbuf);
}
return vaStatus;
}
/*
* Destroy buffer
*/
void psb_cmdbuf_destroy(psb_cmdbuf_p cmdbuf)
{
if (cmdbuf->size) {
psb_buffer_destroy(&cmdbuf->buf);
cmdbuf->size = 0;
}
if (cmdbuf->reloc_size) {
psb_buffer_destroy(&cmdbuf->reloc_buf);
cmdbuf->reloc_size = 0;
}
if (cmdbuf->regio_size) {
psb_buffer_destroy(&cmdbuf->regio_buf);
cmdbuf->regio_size = 0;
}
if (cmdbuf->buffer_refs_allocated) {
free(cmdbuf->buffer_refs);
cmdbuf->buffer_refs = NULL;
cmdbuf->buffer_refs_allocated = 0;
}
}
/*
* Reset buffer & map
*
* Returns 0 on success
*/
int psb_cmdbuf_reset(psb_cmdbuf_p cmdbuf)
{
int ret;
cmdbuf->MTX_msg = NULL;
cmdbuf->cmd_base = NULL;
cmdbuf->cmd_idx = NULL;
cmdbuf->cmd_bitstream_size = NULL;
cmdbuf->lldma_base = NULL;
cmdbuf->lldma_idx = NULL;
cmdbuf->reloc_base = NULL;
cmdbuf->reloc_idx = NULL;
cmdbuf->last_next_segment_cmd = NULL;
cmdbuf->buffer_refs_count = 0;
cmdbuf->cmd_count = 0;
cmdbuf->deblock_count = 0;
cmdbuf->oold_count = 0;
cmdbuf->host_be_opp_count = 0;
cmdbuf->frame_info_count = 0;
#ifdef SLICE_HEADER_PARSING
cmdbuf->parse_count = 0;
#endif
ret = psb_buffer_map(&cmdbuf->buf, &cmdbuf->cmd_base);
if (ret) {
return ret;
}
ret = psb_buffer_map(&cmdbuf->reloc_buf, &cmdbuf->MTX_msg);
if (ret) {
psb_buffer_unmap(&cmdbuf->buf);
return ret;
}
cmdbuf->cmd_start = cmdbuf->cmd_base;
cmdbuf->cmd_idx = (uint32_t *) cmdbuf->cmd_base;
cmdbuf->cmd_bitstream_size = NULL;
cmdbuf->lldma_base = cmdbuf->cmd_base + CMD_SIZE;
cmdbuf->lldma_idx = cmdbuf->lldma_base;
cmdbuf->reloc_base = cmdbuf->MTX_msg + MTXMSG_SIZE;
cmdbuf->reloc_idx = (struct drm_psb_reloc *) cmdbuf->reloc_base;
/* Add ourselves to the buffer list */
psb_cmdbuf_buffer_ref(cmdbuf, &cmdbuf->reloc_buf); /* reloc buf == 0 */
psb_cmdbuf_buffer_ref(cmdbuf, &cmdbuf->buf); /* cmd buf == 1 */
return ret;
}
/*
* Unmap buffer
*
* Returns 0 on success
*/
int psb_cmdbuf_unmap(psb_cmdbuf_p cmdbuf)
{
cmdbuf->MTX_msg = NULL;
cmdbuf->cmd_base = NULL;
cmdbuf->cmd_start = NULL;
cmdbuf->cmd_idx = NULL;
cmdbuf->cmd_bitstream_size = NULL;
cmdbuf->lldma_base = NULL;
cmdbuf->lldma_idx = NULL;
cmdbuf->reloc_base = NULL;
cmdbuf->reloc_idx = NULL;
cmdbuf->cmd_count = 0;
psb_buffer_unmap(&cmdbuf->buf);
psb_buffer_unmap(&cmdbuf->reloc_buf);
return 0;
}
/*
* Reference an addtional buffer "buf" in the command stream
* Returns a reference index that can be used to refer to "buf" in
* relocation records, -1 on error
*/
int psb_cmdbuf_buffer_ref(psb_cmdbuf_p cmdbuf, psb_buffer_p buf)
{
int item_loc = 0;
// buf->next = NULL; /* buf->next only used for buffer list validation */
while ((item_loc < cmdbuf->buffer_refs_count)
&& (wsbmKBufHandle(wsbmKBuf(cmdbuf->buffer_refs[item_loc]->drm_buf))
!= wsbmKBufHandle(wsbmKBuf(buf->drm_buf)))) {
item_loc++;
}
if (item_loc == cmdbuf->buffer_refs_count) {
/* Add new entry */
if (item_loc >= cmdbuf->buffer_refs_allocated) {
/* Allocate more entries */
int new_size = cmdbuf->buffer_refs_allocated + 10;
psb_buffer_p *new_array;
new_array = (psb_buffer_p *) calloc(1, sizeof(psb_buffer_p) * new_size);
if (NULL == new_array) {
return -1; /* Allocation failure */
}
memcpy(new_array, cmdbuf->buffer_refs, sizeof(psb_buffer_p) * cmdbuf->buffer_refs_allocated);
free(cmdbuf->buffer_refs);
cmdbuf->buffer_refs_allocated = new_size;
cmdbuf->buffer_refs = new_array;
}
cmdbuf->buffer_refs[item_loc] = buf;
cmdbuf->buffer_refs_count++;
buf->status = psb_bs_queued;
buf->next = NULL;
buf->unfence_flag = 0;
}
/* only for RAR buffers */
if ((cmdbuf->buffer_refs[item_loc] != buf)
&& (buf->rar_handle != 0)) {
psb_buffer_p tmp = cmdbuf->buffer_refs[item_loc];
drv_debug_msg(VIDEO_DEBUG_GENERAL, "RAR: found same drm buffer with different psb buffer, link them\n",
tmp, buf);
while ((tmp->next != NULL)) {
tmp = tmp->next;
if (tmp == buf) /* found same buffer */
break;
}
if (tmp != buf) {
tmp->next = buf; /* link it */
buf->status = psb_bs_queued;
buf->next = NULL;
} else {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "RAR: buffer aleady in the list, skip\n",
tmp, buf);
}
}
return item_loc;
}
/* Creates a relocation record for a DWORD in the mapped "cmdbuf" at address
* "addr_in_cmdbuf"
* The relocation is based on the device virtual address of "ref_buffer"
* "buf_offset" is be added to the device virtual address, and the sum is then
* right shifted with "align_shift".
* "mask" determines which bits of the target DWORD will be updated with the so
* constructed address. The remaining bits will be filled with bits from "background".
*/
void psb_cmdbuf_add_relocation(psb_cmdbuf_p cmdbuf,
uint32_t *addr_in_cmdbuf,
psb_buffer_p ref_buffer,
uint32_t buf_offset,
uint32_t mask,
uint32_t background,
uint32_t align_shift,
uint32_t dst_buffer) /* 0 = reloc buf, 1 = cmdbuf, 2 = for host reloc */
{
struct drm_psb_reloc *reloc = cmdbuf->reloc_idx;
uint64_t presumed_offset = wsbmBOOffsetHint(ref_buffer->drm_buf);
/* Check that address is within buffer range */
if (dst_buffer) {
ASSERT(((unsigned char *)(addr_in_cmdbuf)) >= cmdbuf->cmd_base);
ASSERT(((unsigned char *)(addr_in_cmdbuf)) < LLDMA_END(cmdbuf));
reloc->where = addr_in_cmdbuf - (uint32_t *) cmdbuf->cmd_base; /* Location in DWORDs */
} else {
ASSERT(((unsigned char *)(addr_in_cmdbuf)) >= cmdbuf->MTX_msg);
ASSERT(((unsigned char *)(addr_in_cmdbuf)) < MTXMSG_END(cmdbuf));
reloc->where = addr_in_cmdbuf - (uint32_t *) cmdbuf->MTX_msg; /* Location in DWORDs */
}
reloc->buffer = psb_cmdbuf_buffer_ref(cmdbuf, ref_buffer);
ASSERT(reloc->buffer != -1);
reloc->reloc_op = PSB_RELOC_OP_OFFSET;
psb__trace_message("[RE] Reloc at offset %08x (%08x), offset = %08x background = %08x buffer = %d (%08x)\n",
reloc->where, reloc->where << 2, buf_offset, background, reloc->buffer, presumed_offset);
if (presumed_offset) {
uint32_t new_val = presumed_offset + buf_offset;
new_val = ((new_val >> align_shift) << (align_shift << PSB_RELOC_ALSHIFT_SHIFT));
new_val = (background & ~mask) | (new_val & mask);
*addr_in_cmdbuf = new_val;
} else {
*addr_in_cmdbuf = PSB_RELOC_MAGIC;
}
reloc->mask = mask;
reloc->shift = align_shift << PSB_RELOC_ALSHIFT_SHIFT;
reloc->pre_add = buf_offset;
reloc->background = background;
reloc->dst_buffer = dst_buffer;
cmdbuf->reloc_idx++;
ASSERT(((unsigned char *)(cmdbuf->reloc_idx)) < RELOC_END(cmdbuf));
}
/*
* Advances "obj_context" to the next cmdbuf
*
* Returns 0 on success
*/
int psb_context_get_next_cmdbuf(object_context_p obj_context)
{
psb_cmdbuf_p cmdbuf;
int ret;
if (obj_context->cmdbuf) {
return 0;
}
obj_context->cmdbuf_current++;
if (obj_context->cmdbuf_current >= PSB_MAX_CMDBUFS) {
obj_context->cmdbuf_current = 0;
}
cmdbuf = obj_context->cmdbuf_list[obj_context->cmdbuf_current];
ret = psb_cmdbuf_reset(cmdbuf);
if (!ret) {
/* Success */
obj_context->cmdbuf = cmdbuf;
}
return ret;
}
static unsigned
psbTimeDiff(struct timeval *now, struct timeval *then)
{
long long val;
val = now->tv_sec - then->tv_sec;
val *= 1000000LL;
val += now->tv_usec;
val -= then->tv_usec;
if (val < 1LL)
val = 1LL;
return (unsigned) val;
}
/*
* This is the user-space do-it-all interface to the drm cmdbuf ioctl.
* It allows different buffers as command- and reloc buffer. A list of
* cliprects to apply and whether to copy the clipRect content to all
* scanout buffers (damage = 1).
*/
/*
* Don't add debug statements in this function, it gets called with the
* DRM lock held and output to an X terminal can cause X to deadlock
*/
static int
psbDRMCmdBuf(int fd, int ioctl_offset, psb_buffer_p *buffer_list, int buffer_count, unsigned cmdBufHandle,
unsigned cmdBufOffset, unsigned cmdBufSize,
unsigned relocBufHandle, unsigned relocBufOffset,
unsigned numRelocs, int __maybe_unused damage,
unsigned engine, unsigned fence_flags, struct psb_ttm_fence_rep *fence_arg)
{
drm_psb_cmdbuf_arg_t ca;
struct psb_validate_arg *arg_list;
int i;
int ret;
struct timeval then, now;
Bool have_then = FALSE;
uint64_t mask = PSB_GPU_ACCESS_MASK;
arg_list = (struct psb_validate_arg *) calloc(1, sizeof(struct psb_validate_arg) * buffer_count);
if (arg_list == NULL) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "Malloc failed \n");
return -ENOMEM;
}
for (i = 0; i < buffer_count; i++) {
struct psb_validate_arg *arg = &(arg_list[i]);
struct psb_validate_req *req = &arg->d.req;
req->next = (unsigned long) & (arg_list[i+1]);
req->buffer_handle = wsbmKBufHandle(wsbmKBuf(buffer_list[i]->drm_buf));
//req->group = 0;
req->set_flags = (PSB_GPU_ACCESS_READ | PSB_GPU_ACCESS_WRITE) & mask;
req->clear_flags = (~(PSB_GPU_ACCESS_READ | PSB_GPU_ACCESS_WRITE)) & mask;
req->presumed_gpu_offset = (uint64_t)wsbmBOOffsetHint(buffer_list[i]->drm_buf);
req->presumed_flags = PSB_USE_PRESUMED;
req->pad64 = (uint32_t)buffer_list[i]->pl_flags;
#ifndef BAYTRAIL
req->unfence_flag = buffer_list[i]->unfence_flag;
#endif
}
arg_list[buffer_count-1].d.req.next = 0;
ca.buffer_list = (uint64_t)((unsigned long)arg_list);
ca.fence_arg = (uint64_t)((unsigned long)fence_arg);
ca.cmdbuf_handle = cmdBufHandle;
ca.cmdbuf_offset = cmdBufOffset;
ca.cmdbuf_size = cmdBufSize;
ca.reloc_handle = relocBufHandle;
ca.reloc_offset = relocBufOffset;
ca.num_relocs = numRelocs;
ca.fence_flags = fence_flags;
ca.engine = engine;
#if 0
drv_debug_msg(VIDEO_DEBUG_GENERAL, "PSB submit: buffer_list = %08x\n", ca.buffer_list);
drv_debug_msg(VIDEO_DEBUG_GENERAL, "PSB submit: clip_rects = %08x\n", ca.clip_rects);
drv_debug_msg(VIDEO_DEBUG_GENERAL, "PSB submit: cmdbuf_handle = %08x\n", ca.cmdbuf_handle);
drv_debug_msg(VIDEO_DEBUG_GENERAL, "PSB submit: cmdbuf_offset = %08x\n", ca.cmdbuf_offset);
drv_debug_msg(VIDEO_DEBUG_GENERAL, "PSB submit: cmdbuf_size = %08x\n", ca.cmdbuf_size);
drv_debug_msg(VIDEO_DEBUG_GENERAL, "PSB submit: reloc_handle = %08x\n", ca.reloc_handle);
drv_debug_msg(VIDEO_DEBUG_GENERAL, "PSB submit: reloc_offset = %08x\n", ca.reloc_offset);
drv_debug_msg(VIDEO_DEBUG_GENERAL, "PSB submit: num_relocs = %08x\n", ca.num_relocs);
drv_debug_msg(VIDEO_DEBUG_GENERAL, "PSB submit: engine = %08x\n", ca.engine);
drv_debug_msg(VIDEO_DEBUG_GENERAL, "PSB submit: fence_flags = %08x\n", ca.fence_flags);
#endif
/*
* X server Signals will clobber the kernel time out mechanism.
* we need a user-space timeout as well.
*/
do {
ret = drmCommandWrite(fd, ioctl_offset, &ca, sizeof(ca));
if (ret == EAGAIN) {
if (!have_then) {
if (gettimeofday(&then, NULL)) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "Gettimeofday error.\n");
break;
}
have_then = TRUE;
}
if (gettimeofday(&now, NULL)) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "Gettimeofday error.\n");
break;
}
}
} while ((ret == EAGAIN) && (psbTimeDiff(&now, &then) < PSB_TIMEOUT_USEC));
if (ret) {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "command write return is %d\n", ret);
goto out;
}
for (i = 0; i < buffer_count; i++) {
struct psb_validate_arg *arg = &(arg_list[i]);
struct psb_validate_rep *rep = &arg->d.rep;
#ifndef BAYTRAIL
if (arg->d.req.unfence_flag)
continue;
#endif
if (!arg->handled) {
ret = -EFAULT;
goto out;
}
if (arg->ret != 0) {
ret = arg->ret;
goto out;
}
wsbmUpdateKBuf(wsbmKBuf(buffer_list[i]->drm_buf),
rep->gpu_offset, rep->placement, rep->fence_type_mask);
}
out:
free(arg_list);
for (i = 0; i < buffer_count; i++) {
/*
* Buffer no longer queued in userspace
*/
psb_buffer_p tmp = buffer_list[i];
/*
* RAR slice buffer/surface buffer are share one BO, and then only one in
* buffer_list, but they are linked in psb_cmdbuf_buffer_ref
*/
if (buffer_list[i]->rar_handle == 0)
tmp->next = NULL; /* don't loop for non RAR buffer, "next" may be not initialized */
do {
psb_buffer_p p = tmp;
tmp = tmp->next;
switch (p->status) {
case psb_bs_queued:
p->status = psb_bs_ready;
break;
case psb_bs_abandoned:
psb_buffer_destroy(p);
free(p);
break;
default:
/* Not supposed to happen */
ASSERT(0);
}
} while (tmp);
}
return ret;
}
#if 0
int psb_fence_destroy(struct _WsbmFenceObject *pFence)
{
wsbmFenceUnreference(&pFence);
return 0;
}
struct _WsbmFenceObject *
psb_fence_wait(psb_driver_data_p driver_data,
struct psb_ttm_fence_rep *fence_rep, int *status)
{
struct _WsbmFenceObject *fence = NULL;
int ret = -1;
/* copy fence information */
if (fence_rep->error != 0) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "drm failed to create a fence"
" and has idled the HW\n");
DEBUG_FAILURE_RET;
return NULL;
}
fence = wsbmFenceCreate(driver_data->fence_mgr, fence_rep->fence_class,
fence_rep->fence_type,
(unsigned char *)fence_rep->handle,
0);
if (fence)
*status = wsbmFenceFinish(fence, fence_rep->fence_type, 0);
return fence;
}
#endif
/*
* Closes the last segment
*/
static void psb_cmdbuf_close_segment(psb_cmdbuf_p __maybe_unused cmdbuf)
{
#if 0
uint32_t bytes_used = ((unsigned char *) cmdbuf->cmd_idx - cmdbuf->cmd_start) % MTX_SEG_SIZE;
unsigned char *segment_start = (unsigned char *) cmdbuf->cmd_idx - bytes_used;
uint32_t lldma_record_offset = psb_cmdbuf_lldma_create(cmdbuf,
&(cmdbuf->buf), (segment_start - cmdbuf->cmd_base) /* offset */,
bytes_used,
0 /* destination offset */,
LLDMA_TYPE_RENDER_BUFF_MC);
uint32_t cmd = CMD_NEXT_SEG;
RELOC_SHIFT4(*cmdbuf->last_next_segment_cmd, lldma_record_offset, cmd, &(cmdbuf->buf));
*(cmdbuf->last_next_segment_cmd + 1) = bytes_used;
#endif
}
/* Issue deblock cmd, HW will do deblock instead of host */
int psb_context_submit_hw_deblock(object_context_p obj_context,
psb_buffer_p buf_a,
psb_buffer_p buf_b,
psb_buffer_p colocate_buffer,
uint32_t picture_widht_mb,
uint32_t frame_height_mb,
uint32_t rotation_flags,
uint32_t field_type,
uint32_t ext_stride_a,
uint32_t chroma_offset_a,
uint32_t chroma_offset_b,
uint32_t is_oold)
{
psb_cmdbuf_p cmdbuf = obj_context->cmdbuf;
psb_driver_data_p driver_data = obj_context->driver_data;
uint32_t msg_size = FW_DEVA_DEBLOCK_SIZE;
unsigned int item_size = FW_DEVA_DECODE_SIZE; /* Size of a render/deocde msg */
FW_VA_DEBLOCK_MSG *deblock_msg;
uint32_t *msg = (uint32_t *)(cmdbuf->MTX_msg + item_size * cmdbuf->cmd_count);
memset(msg, 0, sizeof(FW_VA_DEBLOCK_MSG));
deblock_msg = (FW_VA_DEBLOCK_MSG *)msg;
deblock_msg->header.bits.msg_size = FW_DEVA_DEBLOCK_SIZE;
if (is_oold)
deblock_msg->header.bits.msg_type = VA_MSGID_OOLD_MFLD;
else
deblock_msg->header.bits.msg_type = VA_MSGID_DEBLOCK_MFLD;
deblock_msg->flags.bits.flags = FW_VA_RENDER_HOST_INT | FW_VA_RENDER_IS_LAST_SLICE | FW_DEVA_DEBLOCK_ENABLE;
deblock_msg->flags.bits.slice_type = field_type;
deblock_msg->operating_mode = obj_context->operating_mode;
deblock_msg->mmu_context.bits.context = (uint8_t)(obj_context->msvdx_context);
deblock_msg->pic_size.bits.frame_height_mb = (uint16_t)frame_height_mb;
deblock_msg->pic_size.bits.pic_width_mb = (uint16_t)picture_widht_mb;
deblock_msg->ext_stride_a = ext_stride_a;
deblock_msg->rotation_flags = rotation_flags;
RELOC_MSG(deblock_msg->address_a0, buf_a->buffer_ofs, buf_a);
RELOC_MSG(deblock_msg->address_a1, buf_a->buffer_ofs + chroma_offset_a, buf_a);
if (buf_b) {
RELOC_MSG(deblock_msg->address_b0, buf_b->buffer_ofs, buf_b);
RELOC_MSG(deblock_msg->address_b1, buf_b->buffer_ofs + chroma_offset_b, buf_b);
}
RELOC_MSG(deblock_msg->mb_param_address, colocate_buffer->buffer_ofs, colocate_buffer);
cmdbuf->deblock_count++;
return 0;
}
#ifdef PSBVIDEO_MSVDX_EC
int psb_context_submit_host_be_opp(object_context_p obj_context,
psb_buffer_p buf_a,
psb_buffer_p buf_b,
psb_buffer_p __maybe_unused buf_c,
uint32_t picture_widht_mb,
uint32_t frame_height_mb,
uint32_t rotation_flags,
uint32_t field_type,
uint32_t ext_stride_a,
uint32_t chroma_offset_a,
uint32_t chroma_offset_b)
{
psb_cmdbuf_p cmdbuf = obj_context->cmdbuf;
psb_driver_data_p driver_data = obj_context->driver_data;
uint32_t msg_size = sizeof(FW_VA_DEBLOCK_MSG);
unsigned int item_size = FW_DEVA_DECODE_SIZE; /* Size of a render/deocde msg */
FW_VA_DEBLOCK_MSG *deblock_msg;
uint32_t *msg = (uint32_t *)(cmdbuf->MTX_msg + item_size * cmdbuf->cmd_count + cmdbuf->deblock_count * msg_size);
memset(msg, 0, sizeof(FW_VA_DEBLOCK_MSG));
deblock_msg = (FW_VA_DEBLOCK_MSG *)msg;
deblock_msg->header.bits.msg_size = FW_DEVA_DEBLOCK_SIZE;
deblock_msg->header.bits.msg_type = VA_MSGID_HOST_BE_OPP_MFLD;
deblock_msg->flags.bits.flags = FW_VA_RENDER_HOST_INT | FW_ERROR_DETECTION_AND_RECOVERY;
deblock_msg->flags.bits.slice_type = field_type;
deblock_msg->operating_mode = obj_context->operating_mode;
deblock_msg->mmu_context.bits.context = (uint8_t)(obj_context->msvdx_context);
deblock_msg->pic_size.bits.frame_height_mb = (uint16_t)frame_height_mb;
deblock_msg->pic_size.bits.pic_width_mb = (uint16_t)picture_widht_mb;
deblock_msg->ext_stride_a = ext_stride_a;
deblock_msg->rotation_flags = rotation_flags;
RELOC_MSG(deblock_msg->address_a0, buf_a->buffer_ofs, buf_a);
RELOC_MSG(deblock_msg->address_a1, buf_a->buffer_ofs + chroma_offset_a, buf_a);
RELOC_MSG(deblock_msg->address_b0, buf_b->buffer_ofs, buf_b);
RELOC_MSG(deblock_msg->address_b1, buf_b->buffer_ofs + chroma_offset_b, buf_b);
deblock_msg->mb_param_address = wsbmKBufHandle(wsbmKBuf(buf_a->drm_buf));
cmdbuf->deblock_count++;
return 0;
}
#endif
/*
* Submits the current cmdbuf
*
* Returns 0 on success
*/
int psb_context_submit_cmdbuf(object_context_p obj_context)
{
psb_cmdbuf_p cmdbuf = obj_context->cmdbuf;
psb_driver_data_p driver_data = obj_context->driver_data;
unsigned int item_size = FW_DEVA_DECODE_SIZE; /* Size of a render/deocde msg */
int ret;
uint32_t cmdbuffer_size = (unsigned char *) cmdbuf->cmd_idx - cmdbuf->cmd_start; // In bytes
if (cmdbuf->last_next_segment_cmd) {
cmdbuffer_size = cmdbuf->first_segment_size;
psb_cmdbuf_close_segment(cmdbuf);
}
uint32_t msg_size = item_size;
uint32_t *msg = (uint32_t *)(cmdbuf->MTX_msg + cmdbuf->cmd_count * msg_size + cmdbuf->frame_info_count * FW_VA_FRAME_INFO_SIZE);
if (psb_video_trace_fp && (psb_video_trace_level & CMDMSG_TRACE)) {
debug_cmd_start[cmdbuf->cmd_count] = cmdbuf->cmd_start - cmdbuf->cmd_base;
debug_cmd_size[cmdbuf->cmd_count] = (unsigned char *) cmdbuf->cmd_idx - cmdbuf->cmd_start;
debug_cmd_count = cmdbuf->cmd_count + 1;
}
/*
static int c = 0;
static char pFileName[30];
sprintf(pFileName , "cmdbuf%i.txt", c++);
FILE* pF = fopen(pFileName, "w");
fwrite(cmdbuf->cmd_start, 1, cmdbuffer_size, pF);
fclose(pF);
*/
ret = psb_cmdbuf_dump((unsigned int *)cmdbuf->cmd_start, cmdbuffer_size);
if(ret)
drv_debug_msg(VIDEO_DEBUG_GENERAL, "psb_cmdbuf: dump cmdbuf fail\n");
cmdbuf->cmd_count++;
memset(msg, 0, msg_size);
*cmdbuf->cmd_idx = 0; // Add a trailing 0 just in case.
ASSERT(cmdbuffer_size < CMD_SIZE);
ASSERT((unsigned char *) cmdbuf->cmd_idx < CMD_END(cmdbuf));
MEMIO_WRITE_FIELD(msg, FWRK_GENMSG_SIZE, msg_size);
MEMIO_WRITE_FIELD(msg, FWRK_GENMSG_ID, VA_MSGID_RENDER);
MEMIO_WRITE_FIELD(msg, FW_DEVA_DECODE_CONTEXT, (obj_context->msvdx_context)); /* context is 8 bits */
/* Point to CMDBUFFER */
RELOC_MSG(*(msg + (FW_DEVA_DECODE_LLDMA_ADDRESS_OFFSET / sizeof(uint32_t))),
(cmdbuf->cmd_start - cmdbuf->cmd_base), &(cmdbuf->buf));
MEMIO_WRITE_FIELD(msg, FW_DEVA_DECODE_BUFFER_SIZE, cmdbuffer_size / 4); // In dwords
MEMIO_WRITE_FIELD(msg, FW_DEVA_DECODE_OPERATING_MODE, obj_context->operating_mode);
MEMIO_WRITE_FIELD(msg, FW_DEVA_DECODE_FLAGS, obj_context->flags);
if (psb_video_trace_fp && (psb_video_trace_level & LLDMA_TRACE)) {
debug_lldma_count = (cmdbuf->lldma_idx - cmdbuf->lldma_base) / sizeof(DMA_sLinkedList);
debug_lldma_start = cmdbuf->lldma_base - cmdbuf->cmd_base;
/* Indicate last LLDMA record (for debugging) */
((uint32_t *)cmdbuf->lldma_idx)[1] = 0;
}
cmdbuf->cmd_start = (unsigned char *)cmdbuf->cmd_idx;
if (psb_video_trace_fp) {
return psb_context_flush_cmdbuf(obj_context);
} else {
if ((cmdbuf->cmd_count >= MAX_CMD_COUNT) ||
(MTXMSG_END(cmdbuf) - (unsigned char *) msg < MTXMSG_MARGIN) ||
(CMD_END(cmdbuf) - (unsigned char *) cmdbuf->cmd_idx < CMD_MARGIN) ||
(LLDMA_END(cmdbuf) - cmdbuf->lldma_idx < LLDMA_MARGIN) ||
(RELOC_END(cmdbuf) - (unsigned char *) cmdbuf->reloc_idx < RELOC_MARGIN)) {
return psb_context_flush_cmdbuf(obj_context);
}
}
return 0;
}
/*
* Flushes all cmdbufs
*/
int psb_context_flush_cmdbuf(object_context_p obj_context)
{
psb_cmdbuf_p cmdbuf = obj_context->cmdbuf;
psb_driver_data_p driver_data = obj_context->driver_data;
unsigned int fence_flags;
/* unsigned int fence_handle = 0; */
struct psb_ttm_fence_rep fence_rep;
unsigned int reloc_offset;
unsigned int num_relocs;
int ret;
unsigned int item_size = FW_DEVA_DECODE_SIZE; /* Size of a render/deocde msg */
#ifdef SLICE_HEADER_PARSING
if ((NULL == cmdbuf) ||
(0 == (cmdbuf->cmd_count + cmdbuf->deblock_count + cmdbuf->host_be_opp_count +
cmdbuf->frame_info_count + cmdbuf->parse_count))) {
return 0; // Nothing to do
}
#else
if ((NULL == cmdbuf) ||
(0 == (cmdbuf->cmd_count + cmdbuf->deblock_count + cmdbuf->host_be_opp_count + cmdbuf->frame_info_count))) {
return 0; // Nothing to do
}
#endif
uint32_t msg_size = 0;
uint32_t *msg = (uint32_t *)cmdbuf->MTX_msg;
int32_t i;
uint32_t index;
/* LOCK */
ret = LOCK_HARDWARE(driver_data);
if (ret) {
UNLOCK_HARDWARE(driver_data);
DEBUG_FAILURE_RET;
return ret;
}
for (i = 1; i <= cmdbuf->frame_info_count; i++) {
msg_size += FW_VA_FRAME_INFO_SIZE;
msg += FW_VA_FRAME_INFO_SIZE / sizeof(uint32_t);
}
for (i = 1; i <= cmdbuf->cmd_count; i++) {
uint32_t flags;
flags = MEMIO_READ_FIELD(msg, FW_DEVA_DECODE_FLAGS);
/* Update flags */
int bBatchEnd = (i == (cmdbuf->cmd_count + cmdbuf->deblock_count + cmdbuf->oold_count
+ cmdbuf->host_be_opp_count));
flags |=
(bBatchEnd ? FW_VA_RENDER_HOST_INT : FW_VA_RENDER_NO_RESPONCE_MSG);
#ifdef PSBVIDEO_MSVDX_EC
if (driver_data->ec_enabled)
flags |= FW_ERROR_DETECTION_AND_RECOVERY;
#endif
MEMIO_WRITE_FIELD(msg, FW_DEVA_DECODE_FLAGS, flags);
psb__trace_message("MSG BUFFER_SIZE = %08x\n", MEMIO_READ_FIELD(msg, FW_DEVA_DECODE_BUFFER_SIZE));
psb__trace_message("MSG OPERATING_MODE = %08x\n", MEMIO_READ_FIELD(msg, FW_DEVA_DECODE_OPERATING_MODE));
psb__trace_message("MSG FLAGS = %08x\n", MEMIO_READ_FIELD(msg, FW_DEVA_DECODE_FLAGS));
drv_debug_msg(VIDEO_DEBUG_GENERAL, "MSG BUFFER_SIZE = %08x\n", MEMIO_READ_FIELD(msg, FW_DEVA_DECODE_BUFFER_SIZE));
drv_debug_msg(VIDEO_DEBUG_GENERAL, "MSG OPERATING_MODE = %08x\n", MEMIO_READ_FIELD(msg, FW_DEVA_DECODE_OPERATING_MODE));
drv_debug_msg(VIDEO_DEBUG_GENERAL, "MSG FLAGS = %08x\n", MEMIO_READ_FIELD(msg, FW_DEVA_DECODE_FLAGS));
#if 0 /* todo */
/* Update SAREA */
driver_data->psb_sarea->msvdx_context = obj_context->msvdx_context;
#endif
msg += item_size / sizeof(uint32_t);
msg_size += item_size;
}
/* Assume deblock message is following render messages and no more render message behand deblock message */
for (i = 1; i <= cmdbuf->deblock_count; i++) {
msg_size += sizeof(FW_VA_DEBLOCK_MSG);
}
for (i = 1; i <= cmdbuf->oold_count; i++) {
msg_size += sizeof(FW_VA_DEBLOCK_MSG);
}
for (i = 1; i <= cmdbuf->host_be_opp_count; i++) {
msg_size += FW_VA_HOST_BE_OPP_SIZE;
}
#ifdef SLICE_HEADER_PARSING
for (i = 1; i <= cmdbuf->parse_count; i++) {
msg_size += sizeof(struct fw_slice_header_extract_msg);
}
#endif
/* Now calculate the total number of relocations */
reloc_offset = cmdbuf->reloc_base - cmdbuf->MTX_msg;
num_relocs = (((unsigned char *) cmdbuf->reloc_idx) - cmdbuf->reloc_base) / sizeof(struct drm_psb_reloc);
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Cmdbuf MTXMSG size = %08x [%08x]\n", msg_size, MTXMSG_SIZE);
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Cmdbuf CMD size = %08x - %d[%08x]\n", (unsigned char *) cmdbuf->cmd_idx - cmdbuf->cmd_base, cmdbuf->cmd_count, CMD_SIZE);
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Cmdbuf LLDMA size = %08x [%08x]\n", cmdbuf->lldma_idx - cmdbuf->lldma_base, LLDMA_SIZE);
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Cmdbuf RELOC size = %08x [%08x]\n", num_relocs * sizeof(struct drm_psb_reloc), RELOC_SIZE);
psb_cmdbuf_unmap(cmdbuf);
psb__trace_message(NULL); /* Flush trace */
ASSERT(NULL == cmdbuf->MTX_msg);
ASSERT(NULL == cmdbuf->reloc_base);
if (psb_video_trace_fp)
fence_flags = 0;
else
fence_flags = DRM_PSB_FENCE_NO_USER;
#ifdef SLICE_HEADER_PARSING
if (obj_context->msvdx_frame_end)
fence_flags |= PSB_SLICE_EXTRACT_UPDATE;
#endif
/* cmdbuf will be validated as part of the buffer list */
/* Submit */
wsbmWriteLockKernelBO();
ret = psbDRMCmdBuf(driver_data->drm_fd, driver_data->execIoctlOffset, cmdbuf->buffer_refs,
cmdbuf->buffer_refs_count,
wsbmKBufHandle(wsbmKBuf(cmdbuf->reloc_buf.drm_buf)),
0, msg_size,
wsbmKBufHandle(wsbmKBuf(cmdbuf->reloc_buf.drm_buf)),
reloc_offset, num_relocs,
0, PSB_ENGINE_DECODE, fence_flags, &fence_rep);
wsbmWriteUnlockKernelBO();
UNLOCK_HARDWARE(driver_data);
if (ret) {
obj_context->cmdbuf = NULL;
obj_context->slice_count++;
DEBUG_FAILURE_RET;
return ret;
}
if (psb_video_trace_fp) {
#if 0
static int error_count = 0;
int status = 0;
struct _WsbmFenceObject *fence = NULL;
fence = psb_fence_wait(driver_data, &fence_rep, &status);
drv_debug_msg(VIDEO_DEBUG_GENERAL, "psb_fence_wait returns: %d (fence=0x%08x)\n", status, fence);
#endif
psb_buffer_map(&cmdbuf->buf, &cmdbuf->cmd_base);
int ret;
ret = psb_buffer_map(&cmdbuf->reloc_buf, &cmdbuf->MTX_msg);
if(ret) {
psb_buffer_unmap(&cmdbuf->buf);
return ret;
}
if (psb_video_trace_level & LLDMA_TRACE) {
psb__trace_message("lldma_count = %d, vitual=0x%08x\n",
debug_lldma_count, wsbmBOOffsetHint(cmdbuf->buf.drm_buf) + CMD_SIZE);
for (index = 0; index < debug_lldma_count; index++) {
DMA_sLinkedList* pasDmaList = (DMA_sLinkedList*)(cmdbuf->cmd_base + debug_lldma_start);
pasDmaList += index;
psb__trace_message("\nLLDMA record at offset %08x\n", ((unsigned char*)pasDmaList) - cmdbuf->cmd_base);
DW(0, BSWAP, 31, 31)
DW(0, DIR, 30, 30)
DW(0, PW, 29, 28)
DW(1, List_FIN, 31, 31)
DW(1, List_INT, 30, 30)
DW(1, PI, 18, 17)
DW(1, INCR, 16, 16)
DW(1, LEN, 15, 0)
DWH(2, ADDR, 22, 0)
DW(3, ACC_DEL, 31, 29)
DW(3, BURST, 28, 26)
DWH(3, EXT_SA, 3, 0)
DW(4, 2D_MODE, 16, 16)
DW(4, REP_COUNT, 10, 0)
DWH(5, LINE_ADD_OFF, 25, 16)
DW(5, ROW_LENGTH, 9, 0)
DWH(6, SA, 31, 0)
DWH(7, LISTPTR, 27, 0)
}
}
if (psb_video_trace_level & AUXBUF_TRACE) {
psb__trace_message("debug_dump_count = %d\n", debug_dump_count);
for (index = 0; index < debug_dump_count; index++) {
unsigned char *buf_addr;
psb__trace_message("Buffer %d = '%s' offset = %08x size = %08x\n", index, debug_dump_name[index], debug_dump_offset[index], debug_dump_size[index]);
if (debug_dump_buf[index]->rar_handle
|| (psb_buffer_map(debug_dump_buf[index], &buf_addr) != 0)) {
psb__trace_message("Unmappable buffer,e.g. RAR buffer\n");
continue;
}
g_hexdump_offset = 0;
psb__hexdump(buf_addr + debug_dump_offset[index], debug_dump_size[index]);
psb_buffer_unmap(debug_dump_buf[index]);
}
debug_dump_count = 0;
}
if (psb_video_trace_level & CMDMSG_TRACE) {
psb__trace_message("cmd_count = %d, virtual=0x%08x\n",
debug_cmd_count, wsbmBOOffsetHint(cmdbuf->buf.drm_buf));
for (index = 0; index < debug_cmd_count; index++) {
uint32_t *msg = (uint32_t *)(cmdbuf->MTX_msg + index * item_size);
uint32_t j;
drv_debug_msg(VIDEO_DEBUG_GENERAL, "start = %08x size = %08x\n", debug_cmd_start[index], debug_cmd_size[index]);
debug_dump_cmdbuf((uint32_t *)(cmdbuf->cmd_base + debug_cmd_start[index]), debug_cmd_size[index]);
for (j = 0; j < item_size / 4; j++) {
psb__trace_message("MTX msg[%d] = 0x%08x", j, *(msg + j));
switch (j) {
case 0:
psb__trace_message("[BufferSize|ID|MSG_SIZE]\n");
break;
case 1:
psb__trace_message("[MMUPTD]\n");
break;
case 2:
psb__trace_message("[LLDMA_address]\n");
break;
case 3:
psb__trace_message("[Context]\n");
break;
case 4:
psb__trace_message("[Fence_Value]\n");
break;
case 5:
psb__trace_message("[Operating_Mode]\n");
break;
case 6:
psb__trace_message("[LastMB|FirstMB]\n");
break;
case 7:
psb__trace_message("[Flags]\n");
break;
default:
psb__trace_message("[overflow]\n");
break;
}
}
}
debug_cmd_count = 0;
}
psb_buffer_unmap(&cmdbuf->buf);
psb_buffer_unmap(&cmdbuf->reloc_buf);
cmdbuf->cmd_base = NULL;
#if 0
if (status) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "RENDERING ERROR FRAME=%03d SLICE=%02d status=%d\n", obj_context->frame_count, obj_context->slice_count, status);
error_count++;
ASSERT(status != 2);
ASSERT(error_count < 40); /* Exit on 40 errors */
}
if (fence)
psb_fence_destroy(fence);
#endif
}
obj_context->cmdbuf = NULL;
obj_context->slice_count++;
return 0;
}
typedef enum {
MMU_GROUP0 = 0,
MMU_GROUP1 = 1,
} MMU_GROUP;
typedef enum {
HOST_TO_MSVDX = 0,
MSXDX_TO_HOST = 1,
} DMA_DIRECTION;
typedef struct {
IMG_UINT32 ui32DevDestAddr ; /* destination address */
DMA_ePW ePeripheralWidth;
DMA_ePeriphIncrSize ePeriphIncrSize;
DMA_ePeriphIncr ePeriphIncr;
IMG_BOOL bSynchronous;
MMU_GROUP eMMUGroup;
DMA_DIRECTION eDMADir;
DMA_eBurst eDMA_eBurst;
} DMA_DETAIL_LOOKUP;
static const DMA_DETAIL_LOOKUP DmaDetailLookUp[] = {
/* LLDMA_TYPE_VLC_TABLE */ {
REG_MSVDX_VEC_VLC_OFFSET ,
DMA_PWIDTH_16_BIT, /* 16 bit wide data*/
DMA_PERIPH_INCR_4, /* Incrament the dest by 32 bits */
DMA_PERIPH_INCR_ON,
IMG_TRUE,
MMU_GROUP0,
HOST_TO_MSVDX,
DMA_BURST_2
},
/* LLDMA_TYPE_BITSTREAM */ {
(REG_MSVDX_VEC_OFFSET + MSVDX_VEC_CR_VEC_SHIFTREG_STREAMIN_OFFSET),
DMA_PWIDTH_8_BIT,
DMA_PERIPH_INCR_1,
DMA_PERIPH_INCR_OFF,
IMG_FALSE,
MMU_GROUP0,
HOST_TO_MSVDX,
DMA_BURST_4
},
/*LLDMA_TYPE_RESIDUAL*/ {
(REG_MSVDX_VDMC_OFFSET + MSVDX_VDMC_CR_VDMC_RESIDUAL_DIRECT_INSERT_DATA_OFFSET),
DMA_PWIDTH_32_BIT,
DMA_PERIPH_INCR_1,
DMA_PERIPH_INCR_OFF,
IMG_FALSE,
MMU_GROUP1,
HOST_TO_MSVDX,
DMA_BURST_4
},
/*LLDMA_TYPE_RENDER_BUFF_MC*/{
(REG_MSVDX_MTX_OFFSET + MTX_CORE_CR_MTX_SYSC_CDMAT_OFFSET),
DMA_PWIDTH_32_BIT,
DMA_PERIPH_INCR_1,
DMA_PERIPH_INCR_OFF,
IMG_TRUE,
MMU_GROUP1,
HOST_TO_MSVDX,
DMA_BURST_1 /* Into MTX */
},
/*LLDMA_TYPE_RENDER_BUFF_VLD*/{
(REG_MSVDX_MTX_OFFSET + MTX_CORE_CR_MTX_SYSC_CDMAT_OFFSET),
DMA_PWIDTH_32_BIT,
DMA_PERIPH_INCR_1,
DMA_PERIPH_INCR_OFF,
IMG_TRUE,
MMU_GROUP0,
HOST_TO_MSVDX,
DMA_BURST_1 /* Into MTX */
},
/*LLDMA_TYPE_MPEG4_FESTATE_SAVE*/{
(REG_MSVDX_VEC_RAM_OFFSET + 0xB90),
DMA_PWIDTH_32_BIT,
DMA_PERIPH_INCR_4,
DMA_PERIPH_INCR_ON,
IMG_TRUE,
MMU_GROUP0,
MSXDX_TO_HOST,
DMA_BURST_2 /* From VLR */
},
/*LLDMA_TYPE_MPEG4_FESTATE_RESTORE*/{
(REG_MSVDX_VEC_RAM_OFFSET + 0xB90),
DMA_PWIDTH_32_BIT,
DMA_PERIPH_INCR_4,
DMA_PERIPH_INCR_ON,
IMG_TRUE,
MMU_GROUP0,
HOST_TO_MSVDX,
DMA_BURST_2 /* Into VLR */
},
/*LLDMA_TYPE_H264_PRELOAD_SAVE*/{
(REG_MSVDX_MTX_OFFSET + MTX_CORE_CR_MTX_SYSC_CDMAT_OFFSET),
DMA_PWIDTH_32_BIT,
DMA_PERIPH_INCR_1,
DMA_PERIPH_INCR_OFF,
IMG_TRUE, /* na */
MMU_GROUP1,
MSXDX_TO_HOST,
DMA_BURST_1 /* From MTX */
},
/*LLDMA_TYPE_H264_PRELOAD_RESTORE*/{
(REG_MSVDX_MTX_OFFSET + MTX_CORE_CR_MTX_SYSC_CDMAT_OFFSET),
DMA_PWIDTH_32_BIT,
DMA_PERIPH_INCR_1,
DMA_PERIPH_INCR_OFF,
IMG_TRUE, /* na */
MMU_GROUP1,
HOST_TO_MSVDX,
DMA_BURST_1 /* Into MTX */
},
/*LLDMA_TYPE_VC1_PRELOAD_SAVE*/{
(REG_MSVDX_MTX_OFFSET + MTX_CORE_CR_MTX_SYSC_CDMAT_OFFSET),
DMA_PWIDTH_32_BIT,
DMA_PERIPH_INCR_1,
DMA_PERIPH_INCR_OFF,
IMG_TRUE, /* na */
MMU_GROUP0,
MSXDX_TO_HOST,
DMA_BURST_1 //2 /* From MTX */
},
/*LLDMA_TYPE_VC1_PRELOAD_RESTORE*/{
(REG_MSVDX_MTX_OFFSET + MTX_CORE_CR_MTX_SYSC_CDMAT_OFFSET),
DMA_PWIDTH_32_BIT,
DMA_PERIPH_INCR_1,
DMA_PERIPH_INCR_OFF,
IMG_TRUE, /* na */
MMU_GROUP0,
HOST_TO_MSVDX,
DMA_BURST_1 /* Into MTX */
},
/*LLDMA_TYPE_MEM_SET */{
(REG_MSVDX_VEC_RAM_OFFSET + 0xCC0),
DMA_PWIDTH_32_BIT,
DMA_PERIPH_INCR_4,
DMA_PERIPH_INCR_OFF,
IMG_TRUE, /* na */
MMU_GROUP0,
MSXDX_TO_HOST,
DMA_BURST_4 /* From VLR */
},
};
#define MAX_DMA_LEN ( 0xffff )
void *psb_cmdbuf_alloc_space(psb_cmdbuf_p cmdbuf, uint32_t byte_size)
{
void *pos = (void *)cmdbuf->cmd_idx;
ASSERT(!(byte_size % 4));
cmdbuf->cmd_idx += (byte_size / 4);
return pos;
}
void psb_cmdbuf_dma_write_cmdbuf(psb_cmdbuf_p cmdbuf,
psb_buffer_p bitstream_buf,
uint32_t buffer_offset,
uint32_t size,
uint32_t dest_offset,
DMA_TYPE type)
{
ASSERT(size < 0xFFFF);
ASSERT(buffer_offset < 0xFFFF);
DMA_CMD_WITH_OFFSET* dma_cmd;
if(dest_offset==0)
{
dma_cmd = (DMA_CMD_WITH_OFFSET*)psb_cmdbuf_alloc_space(cmdbuf, sizeof(DMA_CMD));
dma_cmd->ui32Cmd = 0;
}
else
{
dma_cmd = (DMA_CMD_WITH_OFFSET*)psb_cmdbuf_alloc_space(cmdbuf, sizeof(DMA_CMD_WITH_OFFSET));
dma_cmd->ui32Cmd = CMD_DMA_OFFSET_FLAG; // Set flag indicating that offset is deffined
dma_cmd->ui32ByteOffset = dest_offset;
}
dma_cmd->ui32Cmd |= CMD_DMA;
dma_cmd->ui32Cmd |= (IMG_UINT32)type;
dma_cmd->ui32Cmd |= size;
/* dma_cmd->ui32DevVirtAdd = ui32DevVirtAddress; */
RELOC(dma_cmd->ui32DevVirtAdd, buffer_offset, bitstream_buf);
}
/*
* Write a CMD_SR_SETUP referencing a bitstream buffer to the command buffer
*/
void psb_cmdbuf_dma_write_bitstream(psb_cmdbuf_p cmdbuf,
psb_buffer_p bitstream_buf,
uint32_t buffer_offset,
uint32_t size_in_bytes,
uint32_t offset_in_bits,
uint32_t flags)
{
/*
* We use byte alignment instead of 32bit alignment.
* The third frame of sa10164.vc1 results in the following bitstream
* patttern:
* [0000] 00 00 03 01 76 dc 04 8d
* with offset_in_bits = 0x1e
* This causes an ENTDEC failure because 00 00 03 is a start code
* By byte aligning the datastream the start code will be eliminated.
*/
//don't need to change the offset_in_bits, size_in_bytes and buffer_offset
#if 0
#define ALIGNMENT sizeof(uint8_t)
uint32_t bs_offset_in_dwords = ((offset_in_bits / 8) / ALIGNMENT);
size_in_bytes -= bs_offset_in_dwords * ALIGNMENT;
offset_in_bits -= bs_offset_in_dwords * 8 * ALIGNMENT;
buffer_offset += bs_offset_in_dwords * ALIGNMENT;
#endif
*cmdbuf->cmd_idx++ = CMD_SR_SETUP | flags;
*cmdbuf->cmd_idx++ = offset_in_bits;
cmdbuf->cmd_bitstream_size = cmdbuf->cmd_idx;
*cmdbuf->cmd_idx++ = size_in_bytes;
*cmdbuf->cmd_idx++ = (CMD_BITSTREAM_DMA | size_in_bytes);
RELOC(*cmdbuf->cmd_idx++, buffer_offset, bitstream_buf);
}
#ifdef SLICE_HEADER_PARSING
/*
* Write a CMD_SR_SETUP referencing a bitstream buffer to the command buffer
*/
void psb_cmdbuf_dma_write_key(psb_cmdbuf_p cmdbuf,
uint32_t flags,
uint32_t key)
{
drv_debug_msg(VIDEO_DEBUG_GENERAL, "pass key, flags is 0x%x, key is 0x%x.\n", flags, key);
*cmdbuf->cmd_idx++ = CMD_SR_SETUP | flags;
*cmdbuf->cmd_idx++ = key;
}
#endif
/*
* Chain a LLDMA bitstream command to the previous one
*/
void psb_cmdbuf_dma_write_bitstream_chained(psb_cmdbuf_p cmdbuf,
psb_buffer_p bitstream_buf,
uint32_t size_in_bytes)
{
*cmdbuf->cmd_idx++ = (CMD_BITSTREAM_DMA | size_in_bytes);
RELOC(*cmdbuf->cmd_idx++, bitstream_buf->buffer_ofs, bitstream_buf);
*(cmdbuf->cmd_bitstream_size) += size_in_bytes;
}
void psb_cmdbuf_reg_start_block(psb_cmdbuf_p cmdbuf, uint32_t flags)
{
ASSERT(NULL == cmdbuf->reg_start); /* Can't have both */
cmdbuf->reg_wt_p = cmdbuf->cmd_idx;
cmdbuf->reg_next = 0;
cmdbuf->reg_flags = (flags << 4); /* flags are diff between DE2 & DE3 */
cmdbuf->reg_start = NULL;
}
void psb_cmdbuf_reg_set(psb_cmdbuf_p cmdbuf, uint32_t reg, uint32_t val)
{
if(cmdbuf->reg_start && (reg == cmdbuf->reg_next))
{
/* Incrament header size */
*cmdbuf->reg_start += (0x1 << 16);
}
else
{
cmdbuf->reg_start = cmdbuf->reg_wt_p++;
*cmdbuf->reg_start = CMD_REGVALPAIR_WRITE | cmdbuf->reg_flags | 0x10000 | (reg & 0xfffff); /* We want host reg addr */
}
*cmdbuf->reg_wt_p++ = val;
cmdbuf->reg_next = reg + 4;
}
void psb_cmdbuf_reg_set_address(psb_cmdbuf_p cmdbuf,
uint32_t reg,
psb_buffer_p buffer,
uint32_t buffer_offset)
{
if(cmdbuf->reg_start && (reg == cmdbuf->reg_next))
{
/* Incrament header size */
*cmdbuf->reg_start += (0x1 << 16);
}
else
{
cmdbuf->reg_start = cmdbuf->reg_wt_p++;
*cmdbuf->reg_start = CMD_REGVALPAIR_WRITE | cmdbuf->reg_flags | 0x10000 | (reg & 0xfffff); /* We want host reg addr */
}
RELOC(*cmdbuf->reg_wt_p++, buffer_offset, buffer);
cmdbuf->reg_next = reg + 4;
}
void psb_cmdbuf_reg_end_block(psb_cmdbuf_p cmdbuf)
{
cmdbuf->cmd_idx = cmdbuf->reg_wt_p;
cmdbuf->reg_start = NULL;
}
typedef enum {
MTX_CTRL_HEADER = 0,
RENDEC_SL_HDR,
RENDEC_SL_NULL,
RENDEC_CK_HDR,
} RENDEC_CHUNK_OFFSETS;
/*
* Start a new rendec block of another format
*/
void psb_cmdbuf_rendec_start(psb_cmdbuf_p cmdbuf, uint32_t dest_address)
{
ASSERT(((dest_address >> 2)& ~0xfff) == 0);
cmdbuf->rendec_chunk_start = cmdbuf->cmd_idx++;
*cmdbuf->rendec_chunk_start = CMD_RENDEC_BLOCK | dest_address;
}
void psb_cmdbuf_rendec_write_block(psb_cmdbuf_p cmdbuf,
unsigned char *block,
uint32_t size)
{
ASSERT((size & 0x3) == 0);
unsigned int i;
for (i = 0; i < size; i += 4) {
uint32_t val = block[i] | (block[i+1] << 8) | (block[i+2] << 16) | (block[i+3] << 24);
psb_cmdbuf_rendec_write(cmdbuf, val);
}
}
void psb_cmdbuf_rendec_write_address(psb_cmdbuf_p cmdbuf,
psb_buffer_p buffer,
uint32_t buffer_offset)
{
RELOC(*cmdbuf->cmd_idx++, buffer_offset, buffer);
}
/*
* Finish a RENDEC block
*/
void psb_cmdbuf_rendec_end(psb_cmdbuf_p cmdbuf)
{
ASSERT(NULL != cmdbuf->rendec_chunk_start); /* Must have an open RENDEC chunk */
uint32_t dword_count = cmdbuf->cmd_idx - cmdbuf->rendec_chunk_start;
ASSERT((dword_count - 1) <= 0xff);
*cmdbuf->rendec_chunk_start += ((dword_count - 1) << 16);
cmdbuf->rendec_chunk_start = NULL;
}
/*
* Create a conditional SKIP block
*/
void psb_cmdbuf_skip_start_block(psb_cmdbuf_p cmdbuf, uint32_t skip_condition)
{
ASSERT(NULL == cmdbuf->rendec_block_start); /* Can't be inside a rendec block */
ASSERT(NULL == cmdbuf->reg_start); /* Can't be inside a reg block */
ASSERT(NULL == cmdbuf->skip_block_start); /* Can't be inside another skip block (limitation of current sw design)*/
cmdbuf->skip_condition = skip_condition;
cmdbuf->skip_block_start = cmdbuf->cmd_idx++;
}
/*
* Terminate a conditional SKIP block
*/
void psb_cmdbuf_skip_end_block(psb_cmdbuf_p cmdbuf)
{
ASSERT(NULL == cmdbuf->rendec_block_start); /* Rendec block must be closed */
ASSERT(NULL == cmdbuf->reg_start); /* Reg block must be closed */
ASSERT(NULL != cmdbuf->skip_block_start); /* Skip block must still be open */
uint32_t block_size = cmdbuf->cmd_idx - (cmdbuf->skip_block_start + 1);
*cmdbuf->skip_block_start = CMD_CONDITIONAL_SKIP | (cmdbuf->skip_condition << 20) | block_size;
cmdbuf->skip_block_start = NULL;
}