| /* |
| * 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; |
| } |