summaryrefslogtreecommitdiff
path: root/src/psb_cmdbuf.c
diff options
context:
space:
mode:
authorAustin Yuan <shengquan.yuan@gmail.com>2011-08-04 09:53:51 +0800
committerAustin Yuan <shengquan.yuan@gmail.com>2011-09-08 01:38:13 -0400
commit88ea3553ab0ab81352693907ed9e412f343c9ad8 (patch)
treed2a15646632904c0f4e4eb03fd47471a05f91d33 /src/psb_cmdbuf.c
pvr: initial video driver drop for IMG VXD/VXE video engines
The first open source video driver drop for IMG VXD/VXE video engines 1) support IMG VXD375/385 MPEG4/2/H264/VC1 decode HW acceleration 2) support IMG VXE250/285 MPEG4/H264/H263 encode HW accleratoin 3) support post-processing by DC/overlay and GPU 4) support MeeGO and Android It depends on some header files and libraries to build Signed-off-by: Austin Yuan <shengquan.yuan@intel.com>
Diffstat (limited to 'src/psb_cmdbuf.c')
-rw-r--r--src/psb_cmdbuf.c2042
1 files changed, 2042 insertions, 0 deletions
diff --git a/src/psb_cmdbuf.c b/src/psb_cmdbuf.c
new file mode 100644
index 0000000..a4eb6ba
--- /dev/null
+++ b/src/psb_cmdbuf.c
@@ -0,0 +1,2042 @@
+/*
+ * 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_ws_driver.h"
+
+#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 MAX_CMD_COUNT 12
+
+#define MTX_SEG_SIZE (0x0800)
+
+#define PSB_TIMEOUT_USEC 990000
+
+static void psb_cmdbuf_lldma_create_internal(psb_cmdbuf_p cmdbuf,
+ LLDMA_CMD *pLLDMACmd,
+ psb_buffer_p bitstream_buf,
+ uint32_t buffer_offset,
+ uint32_t size,
+ uint32_t dest_offset,
+ LLDMA_TYPE cmd);
+
+/*
+ * 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;
+
+ 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;
+ }
+
+ /* only for RAR buffers */
+ if ((cmdbuf->buffer_refs[item_loc] != buf)
+ && (buf->rar_handle != 0)) {
+ psb_buffer_p tmp = cmdbuf->buffer_refs[item_loc];
+ psb__information_message("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 {
+ psb__information_message("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(((void *)(addr_in_cmdbuf)) >= cmdbuf->cmd_base);
+ ASSERT(((void *)(addr_in_cmdbuf)) < LLDMA_END(cmdbuf));
+ reloc->where = addr_in_cmdbuf - (uint32_t *) cmdbuf->cmd_base; /* Location in DWORDs */
+ } else {
+ ASSERT(((void *)(addr_in_cmdbuf)) >= cmdbuf->MTX_msg);
+ ASSERT(((void *)(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;
+
+#ifdef DEBUG_TRACE
+ //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);
+#endif
+
+ 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(((void *)(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, drm_clip_rect_t * clipRects, int 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) {
+ psb__error_message("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;
+
+ memset(arg, 0, sizeof(*arg));
+ 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;
+ }
+ arg_list[buffer_count-1].d.req.next = 0;
+
+ ca.buffer_list = (uint64_t)((unsigned long)arg_list);
+ ca.clip_rects = (uint64_t)((unsigned long)clipRects);
+ ca.scene_arg = 0;
+ ca.fence_arg = (uint64_t)((unsigned long)fence_arg);
+
+ ca.ta_flags = 0;
+
+ ca.ta_handle = 0;
+ ca.ta_offset = 0;
+ ca.ta_size = 0;
+
+ ca.oom_handle = 0;
+ ca.oom_offset = 0;
+ ca.oom_size = 0;
+
+ 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.damage = damage;
+ ca.fence_flags = fence_flags;
+ ca.engine = engine;
+
+ ca.feedback_ops = 0;
+ ca.feedback_handle = 0;
+ ca.feedback_offset = 0;
+ ca.feedback_breakpoints = 0;
+ ca.feedback_size = 0;
+
+#if 1
+ psb__information_message("PSB submit: buffer_list = %08x\n", ca.buffer_list);
+ psb__information_message("PSB submit: clip_rects = %08x\n", ca.clip_rects);
+ psb__information_message("PSB submit: cmdbuf_handle = %08x\n", ca.cmdbuf_handle);
+ psb__information_message("PSB submit: cmdbuf_offset = %08x\n", ca.cmdbuf_offset);
+ psb__information_message("PSB submit: cmdbuf_size = %08x\n", ca.cmdbuf_size);
+ psb__information_message("PSB submit: reloc_handle = %08x\n", ca.reloc_handle);
+ psb__information_message("PSB submit: reloc_offset = %08x\n", ca.reloc_offset);
+ psb__information_message("PSB submit: num_relocs = %08x\n", ca.num_relocs);
+ psb__information_message("PSB submit: engine = %08x\n", ca.engine);
+ psb__information_message("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)) {
+ psb__error_message("Gettimeofday error.\n");
+ break;
+ }
+
+ have_then = TRUE;
+ }
+ if (gettimeofday(&now, NULL)) {
+ psb__error_message("Gettimeofday error.\n");
+ break;
+ }
+
+ }
+ } while ((ret == EAGAIN) && (psbTimeDiff(&now, &then) < PSB_TIMEOUT_USEC));
+
+ psb__information_message("command write return is %d\n", ret);
+
+ if (ret) {
+ psb__information_message("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;
+
+ 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;
+}
+
+#ifdef DEBUG_TRACE
+
+#define DBH(fmt, arg...) psb__trace_message(fmt, ##arg)
+#define DB(fmt, arg1, arg...) psb__trace_message("[%08x] %08x = " fmt, ((void *) arg1) - cmd_start, *arg1, ##arg)
+
+/* See also MsvdxGpuSim() in msvdxgpu.c */
+static void debug_dump_cmdbuf(uint32_t *cmd_idx, uint32_t cmd_size_in_bytes)
+{
+ uint32_t cmd_size = cmd_size_in_bytes / sizeof(uint32_t);
+ uint32_t *cmd_end = cmd_idx + cmd_size;
+ void *cmd_start = cmd_idx;
+ struct {
+ unsigned int start;
+ unsigned int end;
+ char *name;
+ } msvdx_regs[10] = {{0x04800000, 0x048003FF, "MTX_MTX"},
+ {0x04800400, 0x0480047F, "VDMC_MTX"},
+ {0x04800480, 0x048004FF, "VDEB_MTX"},
+ {0x04800500, 0x048005FF, "DMAC_MTX"},
+ {0x04800600, 0x048006FF, "SYS_MTX"},
+ {0x04800700, 0x048007FF, "VEC_IQRAM_MTX"},
+ {0x04800800, 0x04800FFF, "VEC_MTX"},
+ {0x04801000, 0x04801FFF, "CMD_MTX"},
+ {0x04802000, 0x04802FFF, "VEC_RAM_MTX"},
+ {0x04803000, 0x04804FFF, "VEC_VLC_M"}
+ };
+
+ DBH("CMD BUFFER [%08x] - [%08x], %08x bytes, %08x dwords\n", (uint32_t) cmd_idx, cmd_end, cmd_size_in_bytes, cmd_size);
+ while (cmd_idx < cmd_end) {
+ uint32_t cmd = *cmd_idx;
+ /* What about CMD_MAGIC_BEGIN ?*/
+ switch (cmd & CMD_MASK) {
+ case CMD_NOP: {
+ DB("CMD_NOPE\n", cmd_idx);
+ cmd_idx++;
+ break;
+ }
+
+ case CMD_HEADER: {
+ uint32_t context = cmd & CMD_HEADER_CONTEXT_MASK;
+ DB("CMD_HEADER context = %08x\n", cmd_idx, context);
+ cmd_idx++;
+ DB("StatusBufferAddress\n", cmd_idx);
+ cmd_idx++;
+ DB("PreloadSave\n", cmd_idx);
+ cmd_idx++;
+ DB("PreloadRestore\n", cmd_idx);
+ cmd_idx++;
+ break;
+ }
+ case CMD_REGVALPAIR_WRITE: {
+ uint32_t count = (cmd & CMD_REGVALPAIR_COUNT_MASK) >> CMD_REGVALPAIR_COUNT_SHIFT;
+ DB("CMD_REGVALPAIR_WRITE count = %08x\n", cmd_idx, count);
+ cmd_idx++;
+
+ while (count--) {
+ int i;
+ for (i = 0; i < 10; i++) {
+ if ((*cmd_idx >= msvdx_regs[i].start) &&
+ (*cmd_idx <= msvdx_regs[i].end))
+ break;
+ }
+ DB("%s_%04x\n", cmd_idx, msvdx_regs[i].name, *cmd_idx & 0xffff);
+ cmd_idx++;
+ DB("value\n", cmd_idx);
+ cmd_idx++;
+ }
+ break;
+ }
+ case CMD_RENDEC_WRITE: {
+ uint32_t encoding;
+ uint32_t count = (cmd & CMD_RENDEC_COUNT_MASK) >> CMD_RENDEC_COUNT_SHIFT;
+ DB("CMD_RENDEC_WRITE count = %08x\n", cmd_idx, count);
+ cmd_idx++;
+
+ DB("RENDEC_SL_HDR\n", cmd_idx);
+ cmd_idx++;
+
+ DB("RENDEC_SL_NULL\n", cmd_idx);
+ cmd_idx++;
+
+ do {
+ uint32_t chk_hdr = *cmd_idx;
+ count = 1 + ((chk_hdr & 0x07FF0000) >> 16);
+ uint32_t start_address = (chk_hdr & 0x0000FFF0) >> 4;
+ encoding = (chk_hdr & 0x07);
+ if ((count == 1) && (encoding == 7)) {
+ count = 0;
+ DB("SLICE_SEPARATOR\n", cmd_idx);
+ } else {
+ DB("RENDEC_CK_HDR #symbols = %d address = %08x encoding = %01x\n", cmd_idx, count, start_address, encoding);
+ }
+ cmd_idx++;
+
+ while (count && (count < 0x1000)) {
+ DB("value\n", cmd_idx);
+ cmd_idx++;
+
+ count -= 2;
+ }
+ } while (encoding != 0x07);
+
+ break;
+ }
+ case CMD_COMPLETION: {
+ if (*cmd_idx == PSB_RELOC_MAGIC) {
+ DB("CMD_(S)LLDMA (assumed)\n", cmd_idx);
+ cmd_idx++;
+
+ } else {
+ DB("CMD_COMPLETION\n", cmd_idx);
+ cmd_idx++;
+
+// DB("interrupt\n", cmd_idx);
+// cmd_idx++;
+ }
+ break;
+ }
+ case CMD_LLDMA: {
+ DB("CMD_LLDMA\n", cmd_idx);
+ cmd_idx++;
+ break;
+ }
+ case CMD_SLLDMA: {
+ DB("CMD_SLLDMA\n", cmd_idx);
+ cmd_idx++;
+ break;
+ }
+ case CMD_SR_SETUP: {
+ DB("CMD_SR_SETUP\n", cmd_idx);
+ cmd_idx++;
+ DB("offset in bits\n", cmd_idx);
+ cmd_idx++;
+ DB("size in bytes\n", cmd_idx);
+ cmd_idx++;
+ break;
+ }
+ default:
+ if (*cmd_idx == PSB_RELOC_MAGIC) {
+ DB("CMD_(S)LLDMA (assumed)\n", cmd_idx);
+ cmd_idx++;
+
+ } else {
+ DB("*** Unknown command ***\n", cmd_idx);
+ cmd_idx++;
+ }
+ break;
+ } /* switch */
+ } /* while */
+}
+#endif
+
+
+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) {
+ psb__error_message("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,
+ (void *)fence_rep->handle,
+ 0);
+ if (fence)
+ *status = wsbmFenceFinish(fence, fence_rep->fence_type, 0);
+
+ return fence;
+}
+
+
+#ifdef DEBUG_TRACE
+uint32_t debug_cmd_start[MAX_CMD_COUNT];
+uint32_t debug_cmd_size[MAX_CMD_COUNT];
+uint32_t debug_cmd_count;
+uint32_t debug_lldma_count;
+uint32_t debug_lldma_start;
+
+#define MAX_DUMP_COUNT 20
+const char * debug_dump_name[MAX_DUMP_COUNT];
+psb_buffer_p debug_dump_buf[MAX_DUMP_COUNT];
+uint32_t debug_dump_offset[MAX_DUMP_COUNT];
+uint32_t debug_dump_size[MAX_DUMP_COUNT];
+uint32_t debug_dump_count = 0;
+#endif
+
+#ifdef DEBUG_TRACE
+#define DW(wd, sym, to, from) psb__debug_w(((uint32_t *)pasDmaList)[wd], "LLDMA: " #sym " = %d\n", to, from);
+#define DWH(wd, sym, to, from) psb__debug_w(((uint32_t *)pasDmaList)[wd], "LLDMA: " #sym " = %08x\n", to, from);
+static void psb__debug_w(uint32_t val, char *fmt, uint32_t bit_to, uint32_t bit_from)
+{
+ if (bit_to < 31) {
+ val &= ~(0xffffffff << (bit_to + 1));
+ }
+ val = val >> bit_from;
+ psb__trace_message(fmt, val);
+}
+
+static uint32_t g_hexdump_offset = 0;
+
+static void psb__hexdump2(unsigned char *p, int offset, int size)
+{
+ if (offset + size > 8)
+ size = 8 - offset;
+ psb__trace_message("[%04x]", g_hexdump_offset);
+ g_hexdump_offset += offset;
+ g_hexdump_offset += size;
+ while (offset-- > 0) {
+ psb__trace_message(" --");
+ }
+ while (size-- > 0) {
+ psb__trace_message(" %02x", *p++);
+ }
+ psb__trace_message("\n");
+}
+
+static void psb__hexdump(void *addr, int size)
+{
+ unsigned char *p = (unsigned char *) addr;
+
+ int offset = g_hexdump_offset % 8;
+ g_hexdump_offset -= offset;
+ if (offset) {
+ psb__hexdump2(p, offset, size);
+ size -= 8 - offset;
+ p += 8 - offset;
+ }
+
+ while (1) {
+ if (size < 8) {
+ if (size > 0) {
+ psb__hexdump2(p, 0, size);
+ }
+ return;
+ }
+ psb__trace_message("[%04x] %02x %02x %02x %02x %02x %02x %02x %02x\n", g_hexdump_offset, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
+ p += 8;
+ size -= 8;
+ g_hexdump_offset += 8;
+ }
+}
+
+void psb__debug_schedule_hexdump(const char *name, psb_buffer_p buf, uint32_t offset, uint32_t size)
+{
+ ASSERT(debug_dump_count < MAX_DUMP_COUNT);
+ debug_dump_name[debug_dump_count] = name;
+ debug_dump_buf[debug_dump_count] = buf;
+ debug_dump_offset[debug_dump_count] = offset;
+ debug_dump_size[debug_dump_count] = size;
+ debug_dump_count++;
+}
+
+#endif
+
+
+/*
+ * Closes the last segment
+ */
+static void psb_cmdbuf_close_segment(psb_cmdbuf_p cmdbuf)
+{
+ uint32_t bytes_used = ((void *) cmdbuf->cmd_idx - cmdbuf->cmd_start) % MTX_SEG_SIZE;
+ void *segment_start = (void *) 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;
+}
+
+int psb_context_submit_deblock(object_context_p obj_context)
+{
+ psb_cmdbuf_p cmdbuf = obj_context->cmdbuf;
+ uint32_t msg_size = FW_VA_DEBLOCK_SIZE;
+ uint32_t *msg = cmdbuf->MTX_msg;
+ DEBLOCKPARAMS* pdbParams;
+
+ psb__information_message("Send two pass deblock cmd\n");
+ if (cmdbuf->cmd_count) {
+ psb__information_message("two pass deblock cmdbuf has render msg!\n");
+ return 1;
+ }
+
+ cmdbuf->deblock_count++;
+ memset(msg, 0, msg_size);
+
+ MEMIO_WRITE_FIELD(msg, FWRK_GENMSG_SIZE, 16); /* Deblock message size is 16 bytes */
+ MEMIO_WRITE_FIELD(msg, FWRK_GENMSG_ID, VA_MSGID_DEBLOCK);
+
+ MEMIO_WRITE_FIELD(msg, FW_VA_DEBLOCK_CONTEXT, obj_context->msvdx_context);
+ MEMIO_WRITE_FIELD(msg, FW_VA_DEBLOCK_FLAGS, FW_VA_RENDER_HOST_INT);
+
+ pdbParams = (DEBLOCKPARAMS*)(msg + 16 / sizeof(uint32_t));
+
+ pdbParams->handle = wsbmKBufHandle(wsbmKBuf(cmdbuf->regio_buf.drm_buf));
+ /* printf("regio buffer size is 0x%x\n", cmdbuf->regio_size); */
+ pdbParams->buffer_size = cmdbuf->regio_size;
+ pdbParams->ctxid = (obj_context->msvdx_context & 0xfff);
+
+ return 0;
+}
+
+/* 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; /* Size of a render/deocde msg */
+ FW_VA_DEBLOCK_MSG *deblock_msg;
+
+ if (IS_MFLD(driver_data))
+ item_size = FW_DEVA_DECODE_SIZE;
+ else
+ item_size = FW_VA_RENDER_SIZE;
+
+ uint32_t *msg = 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 = msg_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;
+ 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;
+}
+
+int psb_context_submit_oold(object_context_p obj_context,
+ psb_buffer_p src_buf,
+ psb_buffer_p dst_buf,
+ psb_buffer_p colocate_buffer,
+ uint32_t picture_width_in_mb,
+ uint32_t frame_height_in_mb,
+ uint32_t field_type,
+ uint32_t chroma_offset)
+{
+ psb_cmdbuf_p cmdbuf = obj_context->cmdbuf;
+ uint32_t msg_size = FW_VA_OOLD_SIZE;
+ uint32_t *msg = cmdbuf->MTX_msg + cmdbuf->cmd_count * FW_VA_RENDER_SIZE;
+ FW_VA_OOLD_MSG *oold_msg;
+
+ if (NULL == src_buf || NULL == dst_buf || NULL == colocate_buffer) {
+ psb__error_message("%s L%d Invalide src_buf, dst_buf or colocate_buffer\n",
+ __FUNCTION__, __LINE__);
+ return VA_STATUS_ERROR_INVALID_BUFFER;
+ }
+
+ psb__information_message("Send out of loop deblock cmd\n");
+
+ cmdbuf->oold_count++;
+ memset(msg, 0, msg_size);
+ oold_msg = (FW_VA_OOLD_MSG *) msg;
+
+ MEMIO_WRITE_FIELD(msg, FWRK_GENMSG_SIZE, FW_VA_OOLD_SIZE);
+ MEMIO_WRITE_FIELD(msg, FWRK_GENMSG_ID, VA_MSGID_OOLD);
+ MEMIO_WRITE_FIELD(msg, FW_VA_DEBLOCK_CONTEXT, obj_context->msvdx_context);
+
+ MEMIO_WRITE_FIELD(msg, FW_VA_OOLD_OPERATING_MODE, obj_context->operating_mode);
+ MEMIO_WRITE_FIELD(msg, FW_VA_OOLD_FRAME_HEIGHT_MBS, frame_height_in_mb);
+ MEMIO_WRITE_FIELD(msg, FW_VA_OOLD_PIC_WIDTH_MBS, picture_width_in_mb);
+
+ RELOC_MSG(oold_msg->SOURCE_LUMA_BUFFER_ADDRESS, src_buf->buffer_ofs, src_buf);
+ RELOC_MSG(oold_msg->SOURCE_CHROMA_BUFFER_ADDRESS, src_buf->buffer_ofs + chroma_offset, src_buf);
+ RELOC_MSG(oold_msg->TARGET_LUMA_BUFFER_ADDRESS, dst_buf->buffer_ofs, dst_buf);
+ RELOC_MSG(oold_msg->TARGET_CHROMA_BUFFER_ADDRESS, dst_buf->buffer_ofs + chroma_offset, dst_buf);
+
+ RELOC_MSG(oold_msg->SOURCE_MB_PARAM_ADDRESS, colocate_buffer->buffer_ofs, colocate_buffer);
+
+ MEMIO_WRITE_FIELD(msg, FW_VA_OOLD_SLICE_FIELD_TYPE, field_type);
+
+ return 0;
+}
+
+int psb_context_submit_host_be_opp(object_context_p obj_context, psb_buffer_p dst_buf,
+ uint32_t stride, uint32_t size,
+ uint32_t picture_width_mb,
+ uint32_t size_mb)
+{
+ psb_cmdbuf_p cmdbuf = obj_context->cmdbuf;
+ uint32_t msg_size = FW_VA_HOST_BE_OPP_SIZE;
+
+ if ((NULL == cmdbuf) || ((0 == cmdbuf->cmd_count) && (0 == cmdbuf->host_be_opp_count) &&
+ (0 == cmdbuf->deblock_count) || (0 == cmdbuf->frame_info_count))) {
+ psb_context_get_next_cmdbuf(obj_context);
+ cmdbuf = obj_context->cmdbuf;
+ }
+ uint32_t *msg = cmdbuf->MTX_msg + cmdbuf->cmd_count * FW_VA_RENDER_SIZE +
+ cmdbuf->oold_count * FW_VA_OOLD_SIZE + cmdbuf->frame_info_count * FW_VA_FRAME_INFO_SIZE;
+
+ psb__information_message("Send host be opp cmd\n");
+
+ cmdbuf->host_be_opp_count++;
+ memset(msg, 0, msg_size);
+
+ MEMIO_WRITE_FIELD(msg, FWRK_GENMSG_SIZE, 16); /* Deblock message size is 16 bytes */
+ MEMIO_WRITE_FIELD(msg, FWRK_GENMSG_ID, DAVA_MSGID_HOST_BE_OPP);
+
+ MEMIO_WRITE_FIELD(msg, FW_VA_HOST_BE_OPP_CONTEXT, ((obj_context->msvdx_context >> 8) | 0x1));
+ MEMIO_WRITE_FIELD(msg, FW_VA_HOST_BE_OPP_FLAGS, FW_VA_RENDER_HOST_INT | FW_ERROR_DETECTION_AND_RECOVERY);
+
+ return 0;
+}
+
+int psb_context_submit_frame_info(object_context_p obj_context, psb_buffer_p dst_buf,
+ uint32_t stride, uint32_t size,
+ uint32_t picture_width_mb,
+ uint32_t size_mb)
+{
+ FRAME_INFO_PARAMS* frame_info;
+ psb_cmdbuf_p cmdbuf = obj_context->cmdbuf;
+ uint32_t msg_size = FW_VA_FRAME_INFO_SIZE;
+
+ uint32_t *msg = cmdbuf->MTX_msg;
+
+ psb__information_message("Send frame info cmd\n");
+
+ cmdbuf->frame_info_count++;
+ memset(msg, 0, msg_size);
+ /*first word is used to store message id and message size*/
+ MEMIO_WRITE_FIELD(msg, FWRK_GENMSG_SIZE, FW_VA_FRAME_INFO_SIZE); /* Deblock message size is 16 bytes */
+ MEMIO_WRITE_FIELD(msg, FWRK_GENMSG_ID, VA_MSGID_FRAME_INFO);
+
+ frame_info = (FRAME_INFO_PARAMS*)(msg + 4 / sizeof(uint32_t));
+
+ frame_info->handle = wsbmKBufHandle(wsbmKBuf(dst_buf->drm_buf));
+ frame_info->buffer_size = size;
+ frame_info->buffer_stride = stride;
+ frame_info->picture_width_mb = picture_width_mb;
+ frame_info->size_mb = size_mb;
+ return 0;
+}
+
+/*
+ * 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; /* Size of a render/deocde msg */
+
+ if (IS_MFLD(driver_data))
+ item_size = FW_DEVA_DECODE_SIZE;
+ else
+ item_size = FW_VA_RENDER_SIZE;
+
+ uint32_t cmdbuffer_size = (void *) 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 = cmdbuf->MTX_msg + cmdbuf->cmd_count * msg_size + cmdbuf->frame_info_count * FW_VA_FRAME_INFO_SIZE;
+
+#ifdef DEBUG_TRACE
+ debug_cmd_start[cmdbuf->cmd_count] = cmdbuf->cmd_start - cmdbuf->cmd_base;
+ debug_cmd_size[cmdbuf->cmd_count] = (void *) cmdbuf->cmd_idx - cmdbuf->cmd_start;
+ debug_cmd_count = cmdbuf->cmd_count + 1;
+#endif
+
+#define DUMP_CMDBUF 0
+
+#if DUMP_CMDBUF
+ 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);
+#endif
+
+ 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((void *) 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);
+
+ if (!IS_MFLD(driver_data)) {
+ /* TODO: Need to make context more unique */
+ if (driver_data->ec_enabled) { /* ec firmware hw issue, unknown reason */
+ MEMIO_WRITE_FIELD(msg, FW_VA_RENDER_CONTEXT, ((obj_context->msvdx_context >> 8) | 0x1));
+ } else {
+ MEMIO_WRITE_FIELD(msg, FW_VA_RENDER_CONTEXT, obj_context->msvdx_context);
+ }
+
+ /* Point to CMDBUFFER */
+ uint32_t lldma_record_offset = psb_cmdbuf_lldma_create(cmdbuf,
+ &(cmdbuf->buf), (cmdbuf->cmd_start - cmdbuf->cmd_base) /* offset */,
+ cmdbuffer_size,
+ 0 /* destination offset */,
+ (obj_context->video_op == psb_video_vld) ? LLDMA_TYPE_RENDER_BUFF_VLD : LLDMA_TYPE_RENDER_BUFF_MC);
+ /* This is the last relocation */
+ RELOC_MSG(*(msg + (FW_VA_RENDER_LLDMA_ADDRESS_OFFSET / sizeof(uint32_t))),
+ lldma_record_offset, &(cmdbuf->buf));
+
+ MEMIO_WRITE_FIELD(msg, FW_VA_RENDER_BUFFER_SIZE, cmdbuffer_size); // In bytes
+ MEMIO_WRITE_FIELD(msg, FW_VA_RENDER_OPERATING_MODE, obj_context->operating_mode);
+ MEMIO_WRITE_FIELD(msg, FW_VA_RENDER_LAST_MB_IN_FRAME, obj_context->last_mb);
+ MEMIO_WRITE_FIELD(msg, FW_VA_RENDER_FIRST_MB_IN_SLICE, obj_context->first_mb);
+ MEMIO_WRITE_FIELD(msg, FW_VA_RENDER_FLAGS, obj_context->flags);
+ } else {
+ MEMIO_WRITE_FIELD(msg, FW_DEVA_DECODE_CONTEXT, (obj_context->msvdx_context)); /* context is 8 bits */
+
+ /* Point to CMDBUFFER */
+ uint32_t lldma_record_offset = psb_cmdbuf_lldma_create(cmdbuf,
+ &(cmdbuf->buf), (cmdbuf->cmd_start - cmdbuf->cmd_base) /* offset */,
+ cmdbuffer_size,
+ 0 /* destination offset */,
+ (obj_context->video_op == psb_video_vld) ? LLDMA_TYPE_RENDER_BUFF_VLD : LLDMA_TYPE_RENDER_BUFF_MC);
+ /* This is the last relocation */
+ RELOC_MSG(*(msg + (FW_DEVA_DECODE_LLDMA_ADDRESS_OFFSET / sizeof(uint32_t))),
+ lldma_record_offset, &(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);
+ }
+#ifdef DEBUG_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;
+#endif
+
+ cmdbuf->cmd_start = cmdbuf->cmd_idx;
+
+#ifdef DEBUG_TRACE
+ return psb_context_flush_cmdbuf(obj_context);
+#else
+ if ((cmdbuf->cmd_count >= MAX_CMD_COUNT) ||
+ (MTXMSG_END(cmdbuf) - (void *) msg < MTXMSG_MARGIN) ||
+ (CMD_END(cmdbuf) - (void *) cmdbuf->cmd_idx < CMD_MARGIN) ||
+ (LLDMA_END(cmdbuf) - cmdbuf->lldma_idx < LLDMA_MARGIN) ||
+ (RELOC_END(cmdbuf) - (void *) cmdbuf->reloc_idx < RELOC_MARGIN)) {
+ return psb_context_flush_cmdbuf(obj_context);
+ }
+#endif
+ 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; /* Size of a render/deocde msg */
+
+ if (IS_MFLD(driver_data))
+ item_size = FW_DEVA_DECODE_SIZE;
+ else
+ item_size = FW_VA_RENDER_SIZE;
+
+ if ((NULL == cmdbuf) ||
+ (0 == (cmdbuf->cmd_count + cmdbuf->deblock_count + cmdbuf->host_be_opp_count + cmdbuf->frame_info_count))) {
+ return 0; // Nothing to do
+ }
+
+ uint32_t msg_size = 0;
+ uint32_t *msg = cmdbuf->MTX_msg;
+ int i;
+
+ /* 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;
+
+ if (IS_MFLD(driver_data))
+ flags = MEMIO_READ_FIELD(msg, FW_DEVA_DECODE_FLAGS);
+ else
+ flags = MEMIO_READ_FIELD(msg, FW_VA_RENDER_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) |
+ (obj_context->video_op == psb_video_vld ? FW_VA_RENDER_IS_VLD_NOT_MC : 0);
+
+ if (driver_data->ec_enabled && IS_MRST(driver_data))
+ flags |= FW_ERROR_DETECTION_AND_RECOVERY;
+
+ if (IS_MFLD(driver_data)) {
+ flags &= ~FW_VA_RENDER_IS_VLD_NOT_MC;
+ MEMIO_WRITE_FIELD(msg, FW_DEVA_DECODE_FLAGS, flags);
+ } else {
+ MEMIO_WRITE_FIELD(msg, FW_VA_RENDER_FLAGS, flags);
+ }
+
+#ifdef DEBUG_TRACE
+ if (!IS_MFLD(driver_data)) {
+ psb__trace_message("MSG BUFFER_SIZE = %08x\n", MEMIO_READ_FIELD(msg, FW_VA_RENDER_BUFFER_SIZE));
+ psb__trace_message("MSG OPERATING_MODE = %08x\n", MEMIO_READ_FIELD(msg, FW_VA_RENDER_OPERATING_MODE));
+ psb__trace_message("MSG LAST_MB_IN_FRAME = %08x\n", MEMIO_READ_FIELD(msg, FW_VA_RENDER_LAST_MB_IN_FRAME));
+ psb__trace_message("MSG FIRST_MB_IN_SLICE = %08x\n", MEMIO_READ_FIELD(msg, FW_VA_RENDER_FIRST_MB_IN_SLICE));
+ psb__trace_message("MSG FLAGS = %08x\n", MEMIO_READ_FIELD(msg, FW_VA_RENDER_FLAGS));
+
+ psb__information_message("MSG BUFFER_SIZE = %08x\n", MEMIO_READ_FIELD(msg, FW_VA_RENDER_BUFFER_SIZE));
+ psb__information_message("MSG OPERATING_MODE = %08x\n", MEMIO_READ_FIELD(msg, FW_VA_RENDER_OPERATING_MODE));
+ psb__information_message("MSG LAST_MB_IN_FRAME = %08x\n", MEMIO_READ_FIELD(msg, FW_VA_RENDER_LAST_MB_IN_FRAME));
+ psb__information_message("MSG FIRST_MB_IN_SLICE = %08x\n", MEMIO_READ_FIELD(msg, FW_VA_RENDER_FIRST_MB_IN_SLICE));
+ psb__information_message("MSG FLAGS = %08x\n", MEMIO_READ_FIELD(msg, FW_VA_RENDER_FLAGS));
+ } else {
+ 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));
+
+ psb__information_message("MSG BUFFER_SIZE = %08x\n", MEMIO_READ_FIELD(msg, FW_DEVA_DECODE_BUFFER_SIZE));
+ psb__information_message("MSG OPERATING_MODE = %08x\n", MEMIO_READ_FIELD(msg, FW_DEVA_DECODE_OPERATING_MODE));
+ psb__information_message("MSG FLAGS = %08x\n", MEMIO_READ_FIELD(msg, FW_DEVA_DECODE_FLAGS));
+ }
+#endif
+
+#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++) {
+ if (!IS_MFLD(driver_data))
+ msg_size += FW_VA_DEBLOCK_SIZE;
+ else
+ msg_size += FW_DEVA_DEBLOCK_SIZE;
+ }
+
+ for (i = 1; i <= cmdbuf->oold_count; i++) {
+ msg_size += FW_VA_OOLD_SIZE;
+ }
+
+ for (i = 1; i <= cmdbuf->host_be_opp_count; i++) {
+ msg_size += FW_VA_HOST_BE_OPP_SIZE;
+ }
+
+ /* Now calculate the total number of relocations */
+ reloc_offset = cmdbuf->reloc_base - cmdbuf->MTX_msg;
+ num_relocs = (((void *) cmdbuf->reloc_idx) - cmdbuf->reloc_base) / sizeof(struct drm_psb_reloc);
+
+#ifdef DEBUG_TRACE
+ psb__information_message("Cmdbuf MTXMSG size = %08x [%08x]\n", msg_size, MTXMSG_SIZE);
+ psb__information_message("Cmdbuf CMD size = %08x - %d[%08x]\n", (void *) cmdbuf->cmd_idx - cmdbuf->cmd_base, cmdbuf->cmd_count, CMD_SIZE);
+ psb__information_message("Cmdbuf LLDMA size = %08x [%08x]\n", cmdbuf->lldma_idx - cmdbuf->lldma_base, LLDMA_SIZE);
+ psb__information_message("Cmdbuf RELOC size = %08x [%08x]\n", num_relocs * sizeof(struct drm_psb_reloc), RELOC_SIZE);
+#endif
+
+ psb_cmdbuf_unmap(cmdbuf);
+
+#ifdef DEBUG_TRACE
+ psb__trace_message(NULL); /* Flush trace */
+#endif
+
+ ASSERT(NULL == cmdbuf->MTX_msg);
+ ASSERT(NULL == cmdbuf->reloc_base);
+
+#ifdef DEBUG_TRACE
+ fence_flags = 0;
+#else
+ fence_flags = DRM_PSB_FENCE_NO_USER;
+#endif
+
+ /* cmdbuf will be validated as part of the buffer list */
+ /* Submit */
+#if 1
+ 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 /* clipRects */, 0, PSB_ENGINE_VIDEO, fence_flags, &fence_rep);
+ wsbmWriteUnlockKernelBO();
+ UNLOCK_HARDWARE(driver_data);
+#else
+ ret = 1;
+#endif
+ if (ret) {
+ obj_context->cmdbuf = NULL;
+ obj_context->slice_count++;
+
+ DEBUG_FAILURE_RET;
+ return ret;
+ }
+
+
+#ifdef DEBUG_TRACE
+ static int error_count = 0;
+ int status = 0;
+ struct _WsbmFenceObject *fence = NULL;
+#if 0
+ fence = psb_fence_wait(driver_data, &fence_rep, &status);
+ psb__information_message("psb_fence_wait returns: %d (fence=0x%08x)\n", status, fence);
+#endif
+
+ psb_buffer_map(&cmdbuf->buf, &cmdbuf->cmd_base);
+ psb_buffer_map(&cmdbuf->reloc_buf, &cmdbuf->MTX_msg);
+
+ if (getenv("PSB_VIDEO_TRACE_LLDMA")) {
+ psb__trace_message("lldma_count = %d, vitual=0x%08x\n",
+ debug_lldma_count, wsbmBOOffsetHint(cmdbuf->buf.drm_buf) + CMD_SIZE);
+ for (i = 0; i < debug_lldma_count; i++) {
+ DMA_sLinkedList* pasDmaList = (DMA_sLinkedList*)(cmdbuf->cmd_base + debug_lldma_start);
+ pasDmaList += i;
+
+ psb__trace_message("\nLLDMA record at offset %08x\n", ((void*)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)
+ }
+ }
+
+
+
+ psb__trace_message("debug_dump_count = %d\n", debug_dump_count);
+ for (i = 0; i < debug_dump_count; i++) {
+ void *buf_addr;
+ psb__trace_message("Buffer %d = '%s' offset = %08x size = %08x\n", i, debug_dump_name[i], debug_dump_offset[i], debug_dump_size[i]);
+ if (debug_dump_buf[i]->rar_handle
+ || (psb_buffer_map(debug_dump_buf[i], &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[i], debug_dump_size[i]);
+ psb_buffer_unmap(debug_dump_buf[i]);
+ }
+ debug_dump_count = 0;
+
+ psb__trace_message("cmd_count = %d, virtual=0x%08x\n",
+ debug_cmd_count, wsbmBOOffsetHint(cmdbuf->buf.drm_buf));
+ for (i = 0; i < debug_cmd_count; i++) {
+ uint32_t *msg = cmdbuf->MTX_msg + i * item_size;
+ int j;
+ psb__information_message("start = %08x size = %08x\n", debug_cmd_start[i], debug_cmd_size[i]);
+ debug_dump_cmdbuf((uint32_t *)(cmdbuf->cmd_base + debug_cmd_start[i]), debug_cmd_size[i]);
+
+ 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;
+ }
+ }
+ }
+ psb_buffer_unmap(&cmdbuf->buf);
+ psb_buffer_unmap(&cmdbuf->reloc_buf);
+
+ cmdbuf->cmd_base = NULL;
+
+ if (status) {
+ psb__error_message("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_lldma_write_cmdbuf(psb_cmdbuf_p cmdbuf,
+ psb_buffer_p bitstream_buf,
+ uint32_t buffer_offset,
+ uint32_t size,
+ uint32_t dest_offset,
+ LLDMA_TYPE cmd)
+{
+ LLDMA_CMD *pLLDMACmd = (LLDMA_CMD*) cmdbuf->cmd_idx++;
+ psb_cmdbuf_lldma_create_internal(cmdbuf, pLLDMACmd, bitstream_buf, buffer_offset, size,
+ dest_offset, cmd);
+}
+
+uint32_t psb_cmdbuf_lldma_create(psb_cmdbuf_p cmdbuf,
+ psb_buffer_p bitstream_buf,
+ uint32_t buffer_offset,
+ uint32_t size,
+ uint32_t dest_offset,
+ LLDMA_TYPE cmd)
+{
+ uint32_t lldma_record_offset = (((void*)cmdbuf->lldma_idx) - ((void *) cmdbuf->cmd_base));
+ psb_cmdbuf_lldma_create_internal(cmdbuf, 0, bitstream_buf, buffer_offset, size,
+ dest_offset, cmd);
+ return lldma_record_offset;
+}
+
+/*
+ * Write a CMD_SR_SETUP referencing a bitstream buffer to the command buffer
+ */
+void psb_cmdbuf_lldma_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;
+
+ psb_cmdbuf_lldma_write_cmdbuf(cmdbuf, bitstream_buf, buffer_offset,
+ size_in_bytes, 0, LLDMA_TYPE_BITSTREAM);
+
+#ifdef DEBUG_TRACE
+ //psb__debug_schedule_hexdump("Bitstream", bitstream_buf, buffer_offset, size_in_bytes);
+#endif
+}
+
+/*
+ * Chain a LLDMA bitstream command to the previous one
+ */
+void psb_cmdbuf_lldma_write_bitstream_chained(psb_cmdbuf_p cmdbuf,
+ psb_buffer_p bitstream_buf,
+ uint32_t size_in_bytes)
+{
+ DMA_sLinkedList* pasDmaList = (DMA_sLinkedList*) cmdbuf->lldma_last;
+ uint32_t lldma_record_offset = psb_cmdbuf_lldma_create(cmdbuf, bitstream_buf, bitstream_buf->buffer_ofs,
+ size_in_bytes, 0, LLDMA_TYPE_BITSTREAM);
+ /* Update WD7 of last LLDMA record to point to this one */
+ RELOC_SHIFT4(pasDmaList->ui32Word_7, lldma_record_offset, 0, &(cmdbuf->buf));
+ /* This touches WD1 */
+ MEMIO_WRITE_FIELD(pasDmaList, DMAC_LL_LIST_FIN, 0);
+
+#ifdef DEBUG_TRACE
+ //psb__debug_schedule_hexdump("Bitstream (chained)", bitstream_buf, 0, size_in_bytes);
+#endif
+
+ *(cmdbuf->cmd_bitstream_size) += size_in_bytes;
+}
+
+static void psb_cmdbuf_lldma_create_internal(psb_cmdbuf_p cmdbuf,
+ LLDMA_CMD *pLLDMACmd,
+ psb_buffer_p bitstream_buf,
+ uint32_t buffer_offset,
+ uint32_t size,
+ uint32_t dest_offset,
+ LLDMA_TYPE cmd)
+{
+ const DMA_DETAIL_LOOKUP* pDmaDetail;
+ IMG_UINT32 ui32DMACount, ui32LLDMA_Offset, ui32DMADestAddr, ui32Cmd;
+ DMA_sLinkedList* pasDmaList;
+ static IMG_UINT32 lu[] = {4, 2, 1};
+
+ /* See if we will fit */
+ ASSERT(cmdbuf->lldma_idx + sizeof(DMA_sLinkedList) < LLDMA_END(cmdbuf));
+
+ pDmaDetail = &DmaDetailLookUp[cmd];
+
+ ui32DMACount = size / lu[pDmaDetail->ePeripheralWidth];
+
+ /* DMA list must be 16byte alligned if it is done in Hw */
+ pasDmaList = (DMA_sLinkedList*)(cmdbuf->lldma_idx) ;
+ // psaDmaList = (DMA_sLinkedList*) ((( cmdbuf->lldma_idx )+0x0f) & ~0x0f );
+
+ /* Offset of LLDMA record in cmdbuf */
+ ui32LLDMA_Offset = (IMG_UINT32)(((IMG_UINT8*)pasDmaList) - ((IMG_UINT8*) cmdbuf->cmd_base));
+
+ ASSERT(0 == (ui32LLDMA_Offset & 0xf));
+
+ ui32DMADestAddr = pDmaDetail->ui32DevDestAddr + dest_offset;
+
+ /* Write the header */
+ if (pLLDMACmd) {
+ ui32Cmd = ((pDmaDetail->bSynchronous) ? CMD_SLLDMA : CMD_LLDMA);
+ RELOC_SHIFT4(pLLDMACmd->ui32CmdAndDevLinAddr, ui32LLDMA_Offset, ui32Cmd, &(cmdbuf->buf));
+ }
+
+ while (ui32DMACount) {
+ memset(pasDmaList , 0 , sizeof(DMA_sLinkedList));
+
+ DMA_LL_SET_WD2(pasDmaList, ui32DMADestAddr);
+
+ /* DMA_LL_SET_WD6 with relocation */
+ ASSERT(DMAC_LL_SA_SHIFT == 0);
+
+ RELOC(pasDmaList->ui32Word_6, buffer_offset, bitstream_buf);
+
+ if (ui32DMACount > MAX_DMA_LEN) {
+ ui32LLDMA_Offset += sizeof(DMA_sLinkedList);
+
+ /* DMA_LL_SET_WD7 with relocation */
+ ASSERT(DMAC_LL_LISTPTR_SHIFT == 0);
+ RELOC_SHIFT4(pasDmaList->ui32Word_7, ui32LLDMA_Offset, 0, &(cmdbuf->buf));
+ /* This touches WD1 */
+ MEMIO_WRITE_FIELD(pasDmaList, DMAC_LL_LIST_FIN, 0);
+
+ DMA_LL_SET_WD1(pasDmaList, pDmaDetail->ePeriphIncr, pDmaDetail->ePeriphIncrSize, MAX_DMA_LEN); /* size */
+
+ ui32DMACount -= MAX_DMA_LEN;
+
+ if (pDmaDetail->ePeriphIncr == DMA_PERIPH_INCR_ON) {
+ /* Update Destination pointers */
+ ui32DMADestAddr += ((MAX_DMA_LEN) * lu[pDmaDetail->ePeriphIncrSize]);
+ }
+
+ /* Update Source Pointer */
+ buffer_offset += ((MAX_DMA_LEN) * lu[pDmaDetail->ePeripheralWidth]);
+ } else {
+ /* This also set LIST_FIN in WD1 to 1*/
+ DMA_LL_SET_WD7(pasDmaList, IMG_NULL); // next linked list
+ DMA_LL_SET_WD1(pasDmaList, pDmaDetail->ePeriphIncr, pDmaDetail->ePeriphIncrSize, ui32DMACount); /* size */
+
+ ui32DMACount = 0;
+ }
+
+ /* Keep pointer in case we need to chain another LLDMA command */
+ cmdbuf->lldma_last = (void *) pasDmaList;
+
+ DMA_LL_SET_WD0(pasDmaList, DMA_BSWAP_NO_SWAP,
+ (pDmaDetail->eDMADir == HOST_TO_MSVDX) ? DMA_DIR_MEM_TO_PERIPH : DMA_DIR_PERIPH_TO_MEM ,
+ pDmaDetail->ePeripheralWidth);
+
+ DMA_LL_SET_WD3(pasDmaList, DMA_ACC_DEL_0, pDmaDetail->eDMA_eBurst, pDmaDetail->eMMUGroup);
+ DMA_LL_SET_WD4(pasDmaList, DMA_MODE_2D_OFF, 0); // 2d
+ DMA_LL_SET_WD5(pasDmaList, 0, 0); // 2d
+
+
+ pasDmaList++;
+ }
+
+ /* there can be up to 3 Bytes of padding after header */
+ cmdbuf->lldma_idx = (void *)pasDmaList;
+}
+
+
+/*
+ * Create a command to set registers
+ */
+void psb_cmdbuf_reg_start_block(psb_cmdbuf_p cmdbuf)
+{
+ ASSERT(NULL == cmdbuf->rendec_block_start); /* Can't have both */
+
+ cmdbuf->reg_start = cmdbuf->cmd_idx++;
+ *cmdbuf->reg_start = 0;
+}
+
+void psb_cmdbuf_reg_start_block_flag(psb_cmdbuf_p cmdbuf, uint32_t flags)
+{
+ ASSERT(NULL == cmdbuf->rendec_block_start); /* Can't have both */
+
+ cmdbuf->reg_start = cmdbuf->cmd_idx++;
+ *cmdbuf->reg_start = flags;
+}
+
+void psb_cmdbuf_reg_set_address(psb_cmdbuf_p cmdbuf,
+ uint32_t reg,
+ psb_buffer_p buffer,
+ uint32_t buffer_offset)
+{
+ *cmdbuf->cmd_idx++ = reg;
+ RELOC(*cmdbuf->cmd_idx++, buffer_offset, buffer);
+}
+
+/*
+ * Finish a command to set registers
+ */
+void psb_cmdbuf_reg_end_block(psb_cmdbuf_p cmdbuf)
+{
+ uint32_t reg_count = ((cmdbuf->cmd_idx - cmdbuf->reg_start) - 1) / 2;
+
+ *cmdbuf->reg_start |= CMD_REGVALPAIR_WRITE | reg_count;
+ cmdbuf->reg_start = NULL;
+}
+
+typedef enum {
+ MTX_CTRL_HEADER = 0,
+ RENDEC_SL_HDR,
+ RENDEC_SL_NULL,
+ RENDEC_CK_HDR,
+} RENDEC_CHUNK_OFFSETS;
+
+/*
+ * Create a RENDEC command block
+ */
+void psb_cmdbuf_rendec_start_block(psb_cmdbuf_p cmdbuf)
+{
+ ASSERT(NULL == cmdbuf->rendec_block_start); /* Can't have both */
+ cmdbuf->rendec_block_start = cmdbuf->cmd_idx;
+
+ cmdbuf->rendec_block_start[RENDEC_SL_HDR] = 0;
+ REGIO_WRITE_FIELD_LITE(cmdbuf->rendec_block_start[RENDEC_SL_HDR], RENDEC_SLICE_INFO, SL_HDR_CK_START, SL_ROUTING_INFO, 1);
+ REGIO_WRITE_FIELD_LITE(cmdbuf->rendec_block_start[RENDEC_SL_HDR], RENDEC_SLICE_INFO, SL_HDR_CK_START, SL_ENCODING_METHOD, 3);
+ REGIO_WRITE_FIELD_LITE(cmdbuf->rendec_block_start[RENDEC_SL_HDR], RENDEC_SLICE_INFO, SL_HDR_CK_START, SL_NUM_SYMBOLS_LESS1, 1);
+
+ cmdbuf->rendec_block_start[RENDEC_SL_NULL] = 0; /* empty */
+
+ cmdbuf->cmd_idx += RENDEC_CK_HDR;
+}
+
+/*
+ * Start a new chunk in a RENDEC command block
+ */
+void psb_cmdbuf_rendec_start_chunk(psb_cmdbuf_p cmdbuf, uint32_t dest_address)
+{
+ ASSERT(NULL != cmdbuf->rendec_block_start); /* Must have a RENDEC block open */
+ cmdbuf->rendec_chunk_start = cmdbuf->cmd_idx++;
+
+ *cmdbuf->rendec_chunk_start = 0;
+ REGIO_WRITE_FIELD_LITE(*cmdbuf->rendec_chunk_start, RENDEC_SLICE_INFO, CK_HDR, CK_ENCODING_METHOD, 3);
+ REGIO_WRITE_FIELD_LITE(*cmdbuf->rendec_chunk_start, RENDEC_SLICE_INFO, CK_HDR, CK_START_ADDRESS, (dest_address >> 2));
+}
+
+/*
+ * 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 >> 2) << 4);
+}
+
+void psb_cmdbuf_rendec_write_block(psb_cmdbuf_p cmdbuf,
+ unsigned char *block,
+ uint32_t size)
+{
+ ASSERT((size & 0x3) == 0);
+ 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 chunk
+ */
+void psb_cmdbuf_rendec_end_chunk(psb_cmdbuf_p cmdbuf)
+{
+ ASSERT(NULL != cmdbuf->rendec_block_start); /* Must have an open RENDEC block */
+ ASSERT(NULL != cmdbuf->rendec_chunk_start); /* Must have an open RENDEC chunk */
+ uint32_t dword_count = (cmdbuf->cmd_idx - cmdbuf->rendec_chunk_start) - 1;
+
+ REGIO_WRITE_FIELD_LITE(*cmdbuf->rendec_chunk_start,
+ RENDEC_SLICE_INFO,
+ CK_HDR,
+ CK_NUM_SYMBOLS_LESS1,
+ (2 * dword_count) - 1); /* Number of 16-bit symbols, minus 1.*/
+
+ cmdbuf->rendec_chunk_start = NULL;
+}
+
+/*
+ * 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;
+}
+
+/*
+ * Finish a RENDEC block
+ */
+void psb_cmdbuf_rendec_end_block(psb_cmdbuf_p cmdbuf)
+{
+ ASSERT(NULL != cmdbuf->rendec_block_start); /* Must have an open RENDEC block */
+ ASSERT(NULL == cmdbuf->rendec_chunk_start); /* All chunks must be closed */
+
+ uint32_t block_size = cmdbuf->cmd_idx - cmdbuf->rendec_block_start; /* Include separator but not mtx block header*/
+
+ /* Write separator (footer-type thing) */
+ *cmdbuf->cmd_idx = 0;
+ REGIO_WRITE_FIELD(*cmdbuf->cmd_idx, RENDEC_SLICE_INFO, SLICE_SEPARATOR, SL_SEP_SUFFIX, 7);
+ cmdbuf->cmd_idx++;
+
+ /* Write CMD Header */
+ cmdbuf->rendec_block_start[MTX_CTRL_HEADER] = CMD_RENDEC_WRITE | block_size;
+
+ cmdbuf->rendec_block_start = NULL;
+}
+
+/*
+ * Returns the number of words left in the current segment
+ */
+uint32_t psb_cmdbuf_segment_space(psb_cmdbuf_p cmdbuf)
+{
+ uint32_t bytes_used = (void *) cmdbuf->cmd_idx - cmdbuf->cmd_start;
+ return (MTX_SEG_SIZE - (bytes_used % MTX_SEG_SIZE)) / sizeof(uint32_t);
+}
+
+/*
+ * Forwards the command buffer index to the next segment
+ */
+void psb_cmdbuf_next_segment(psb_cmdbuf_p cmdbuf)
+{
+ uint32_t *next_segment_cmd = cmdbuf->cmd_idx;
+ cmdbuf->cmd_idx += 2;
+ uint32_t words_free = psb_cmdbuf_segment_space(cmdbuf);
+
+ if (cmdbuf->last_next_segment_cmd) {
+ psb_cmdbuf_close_segment(cmdbuf);
+ } else {
+ cmdbuf->first_segment_size = (void *) cmdbuf->cmd_idx - cmdbuf->cmd_start;
+ }
+
+ cmdbuf->cmd_idx += words_free; /* move pui32CmdBuffer to start of next segment */
+
+ cmdbuf->last_next_segment_cmd = next_segment_cmd;
+}
+
+/*
+ * 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;
+}