android_kernel_modules_leno.../intel_media/video/decode/psb_msvdx_ec.c

540 lines
16 KiB
C

/**
* file psb_msvdx_ec.c
* MSVDX error concealment I/O operations
*
*/
/**************************************************************************
*
* Copyright (c) 2007 Intel Corporation, Hillsboro, OR, USA
* Copyright (c) Imagination Technologies Limited, UK
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
* Authors:
* Li Zeng <li.zeng@intel.com>
*
**************************************************************************/
#ifdef CONFIG_DRM_VXD_BYT
#include "vxd_drv.h"
#else
#include "psb_drv.h"
#endif
#include "psb_msvdx.h"
#include "psb_msvdx_msg.h"
#include "psb_msvdx_reg.h"
#include "psb_msvdx_ec.h"
#define MAX_SIZE_IN_MB (4096 / 16)
static inline int psb_msvdx_cmd_port_write(struct drm_psb_private *dev_priv,
uint32_t offset, uint32_t value, uint32_t *cmd_space)
{
uint32_t max_attempts = 0xff;
uint32_t attempts = 0;
max_attempts = 0xff;
while (*cmd_space == 0) {
*cmd_space = PSB_RMSVDX32(
MSVDX_CORE_CR_MSVDX_COMMAND_SPACE_OFFSET +
MSVDX_CORE_BASE);
if (*cmd_space)
break;
PSB_UDELAY(2);
attempts++;
if (attempts > max_attempts) {
printk(KERN_ERR "MSVDX: poll cmd space timeout\n");
return -1;
}
}
PSB_WMSVDX32(value, offset + MSVDX_CMDS_BASE);
(*cmd_space)--;
/*
*printk(KERN_DEBUG "MSVDX: poll cmd space attempts %d\n", attempts);
*/
return 0;
}
#define PSB_CMDPORT_WRITE(_dev_priv_, _offset_, _cmd_, _cmd_space_) \
do { \
ret = psb_msvdx_cmd_port_write(_dev_priv_, \
_offset_, _cmd_, &_cmd_space_); \
if (ret) { \
printk(KERN_DEBUG "write cmd fail, abort\n"); \
goto ec_done; \
} \
} while (0);
#define PSB_CMDPORT_WRITE_FAST(_dev_priv_, _offset_, _cmd_, _cmd_space_) \
psb_msvdx_cmd_port_write(_dev_priv_, \
_offset_, _cmd_, &_cmd_space_); \
void psb_msvdx_do_concealment(struct work_struct *work)
{
struct msvdx_private *msvdx_priv =
container_of(work, struct msvdx_private, ec_work);
struct drm_psb_private *dev_priv = NULL;
struct psb_msvdx_ec_ctx *msvdx_ec_ctx = msvdx_priv->cur_msvdx_ec_ctx;
drm_psb_msvdx_decode_status_t *fault_region = NULL;
struct fw_deblock_msg *deblock_msg =
(struct fw_deblock_msg *)(msvdx_ec_ctx->unfenced_cmd +
msvdx_ec_ctx->deblock_cmd_offset);
uint32_t width_in_mb, height_in_mb, cmd;
int conceal_above_row = 0, loop, mb_loop;
uint32_t cmd_space = 0;
int ret = 0;
#ifdef CONFIG_VIDEO_MRFLD
if (!power_island_get(OSPM_VIDEO_DEC_ISLAND)) {
#else
if (!ospm_power_using_video_begin(OSPM_VIDEO_DEC_ISLAND)) {
#endif
printk(KERN_ERR "MSVDX: fail to power on ved for ec\n");
return;
}
dev_priv = msvdx_priv->dev_priv;
fault_region = &msvdx_ec_ctx->decode_status;
/* Concealment should be done in time,
* otherwise panic msg will be signaled in msvdx
*/
preempt_disable();
if (msvdx_ec_ctx->deblock_cmd_offset == PSB_MSVDX_INVALID_OFFSET) {
printk(KERN_ERR "invalid msg offset, abort concealment\n");
goto ec_done;
}
if (fault_region->num_region == 0) {
PSB_DEBUG_MSVDX("no fault region\n");
goto ec_done;
}
width_in_mb = deblock_msg->pic_size.bits.pic_width_mb;
height_in_mb = deblock_msg->pic_size.bits.frame_height_mb;
{
int i;
for (i = 0; i < fault_region->num_region; i++)
PSB_DEBUG_MSVDX("[region %d] is %d to %d\n",
i,
fault_region->mb_regions[i].start,
fault_region->mb_regions[i].end);
PSB_DEBUG_MSVDX("MSVDX: MSGID_DEBLOCK:"
" - fence: %08x"
" - flags: %08x - slice_field_type: %08x"
" - operating_mode: %08x"
" - context: %08x - mmu_ptd: %08x"
" - frame_height_mb: %08x - pic_width_mb: %08x"
" - address_a0: %08x - address_a1: %08x"
" - mb_param_address: %08x"
" - ext_stride_a: %08x"
" - address_b0: %08x - address_b1: %08x"
" - alt_output_flags_b: %08x.\n",
deblock_msg->header.bits.msg_fence,
deblock_msg->flag_type.bits.flags,
deblock_msg->flag_type.bits.slice_field_type,
deblock_msg->operating_mode,
deblock_msg->mmu_context.bits.context,
deblock_msg->mmu_context.bits.mmu_ptd,
deblock_msg->pic_size.bits.frame_height_mb,
deblock_msg->pic_size.bits.pic_width_mb,
deblock_msg->address_a0,
deblock_msg->address_a1,
deblock_msg->mb_param_address,
deblock_msg->ext_stride_a,
deblock_msg->address_b0,
deblock_msg->address_b1,
deblock_msg->alt_output_flags_b);
PSB_DEBUG_MSVDX("deblock addr_c0 is 0x%08x\n",
deblock_msg->address_c0);
PSB_DEBUG_MSVDX("deblock addr_c1 is 0x%08x\n",
deblock_msg->address_c1);
}
if (unlikely(!width_in_mb || !height_in_mb ||
width_in_mb > MAX_SIZE_IN_MB ||
height_in_mb > MAX_SIZE_IN_MB)) {
PSB_DEBUG_MSVDX("wrong pic size\n");
goto ec_done;
}
cmd = 0;
REGIO_WRITE_FIELD_LITE(cmd, MSVDX_CMDS,
DISPLAY_PICTURE_SIZE_DISPLAY_PICTURE_HEIGHT,
(height_in_mb * 16) - 1);
REGIO_WRITE_FIELD_LITE(cmd, MSVDX_CMDS,
DISPLAY_PICTURE_SIZE_DISPLAY_PICTURE_WIDTH,
(width_in_mb * 16) - 1);
PSB_CMDPORT_WRITE(dev_priv,
MSVDX_CMDS_DISPLAY_PICTURE_SIZE_OFFSET,
cmd, cmd_space);
cmd = 0;
REGIO_WRITE_FIELD_LITE(cmd, MSVDX_CMDS,
CODED_PICTURE_SIZE_CODED_PICTURE_HEIGHT,
(height_in_mb * 16) - 1);
REGIO_WRITE_FIELD_LITE(cmd, MSVDX_CMDS,
CODED_PICTURE_SIZE_CODED_PICTURE_WIDTH,
(width_in_mb * 16) - 1);
PSB_CMDPORT_WRITE(dev_priv,
MSVDX_CMDS_CODED_PICTURE_SIZE_OFFSET,
cmd, cmd_space);
cmd = deblock_msg->operating_mode;
REGIO_WRITE_FIELD(cmd, MSVDX_CMDS_OPERATING_MODE,
CHROMA_FORMAT, 1);
REGIO_WRITE_FIELD(cmd, MSVDX_CMDS_OPERATING_MODE,
ASYNC_MODE, 1);
REGIO_WRITE_FIELD(cmd, MSVDX_CMDS_OPERATING_MODE,
CODEC_MODE, 3);
REGIO_WRITE_FIELD(cmd, MSVDX_CMDS_OPERATING_MODE,
CODEC_PROFILE, 1);
PSB_CMDPORT_WRITE(dev_priv,
MSVDX_CMDS_OPERATING_MODE_OFFSET,
cmd, cmd_space);
/* dest frame address */
PSB_CMDPORT_WRITE(dev_priv,
MSVDX_CMDS_LUMA_RECONSTRUCTED_PICTURE_BASE_ADDRESSES_OFFSET,
deblock_msg->address_a0,
cmd_space);
PSB_CMDPORT_WRITE(dev_priv,
MSVDX_CMDS_CHROMA_RECONSTRUCTED_PICTURE_BASE_ADDRESSES_OFFSET,
deblock_msg->address_a1,
cmd_space);
/* conceal frame address */
PSB_CMDPORT_WRITE(dev_priv,
MSVDX_CMDS_REFERENCE_PICTURE_BASE_ADDRESSES_OFFSET,
deblock_msg->address_b0,
cmd_space);
PSB_CMDPORT_WRITE(dev_priv,
MSVDX_CMDS_REFERENCE_PICTURE_BASE_ADDRESSES_OFFSET + 4,
deblock_msg->address_b1,
cmd_space);
cmd = 0;
REGIO_WRITE_FIELD(cmd, MSVDX_CMDS_SLICE_PARAMS, SLICE_FIELD_TYPE, 2);
REGIO_WRITE_FIELD(cmd, MSVDX_CMDS_SLICE_PARAMS, SLICE_CODE_TYPE, 1);
PSB_CMDPORT_WRITE(dev_priv,
MSVDX_CMDS_SLICE_PARAMS_OFFSET,
cmd, cmd_space);
cmd = deblock_msg->alt_output_flags_b;
if ((cmd & 3) != 0) {
PSB_DEBUG_MSVDX("MSVDX: conceal to rotate surface\n");
} else {
PSB_CMDPORT_WRITE(dev_priv,
MSVDX_CMDS_ALTERNATIVE_OUTPUT_PICTURE_ROTATION_OFFSET,
cmd, cmd_space);
PSB_CMDPORT_WRITE(dev_priv,
MSVDX_CMDS_VC1_LUMA_RANGE_MAPPING_BASE_ADDRESS_OFFSET,
0, cmd_space);
PSB_CMDPORT_WRITE(dev_priv,
MSVDX_CMDS_VC1_CHROMA_RANGE_MAPPING_BASE_ADDRESS_OFFSET,
0, cmd_space);
PSB_CMDPORT_WRITE(dev_priv,
MSVDX_CMDS_VC1_RANGE_MAPPING_FLAGS_OFFSET,
0, cmd_space);
}
cmd = deblock_msg->ext_stride_a;
PSB_CMDPORT_WRITE(dev_priv,
MSVDX_CMDS_EXTENDED_ROW_STRIDE_OFFSET,
cmd, cmd_space);
for (loop = 0; loop < fault_region->num_region; loop++) {
uint32_t start = fault_region->mb_regions[loop].start;
uint32_t end = fault_region->mb_regions[loop].end;
uint32_t x, y;
PSB_DEBUG_MSVDX("MSVDX: region(%d) is %d~%d\n",
loop, start, end);
if (conceal_above_row)
start -= width_in_mb;
if (end > (width_in_mb * height_in_mb - 1))
end = (width_in_mb * height_in_mb - 1);
if (start > end)
start = 0;
PSB_DEBUG_MSVDX("MSVDX: modify region(%d) is %d~%d\n",
loop, start, end);
x = start % width_in_mb;
y = start / width_in_mb;
for (mb_loop = start; mb_loop <= end; mb_loop++, x++) {
if (x >= width_in_mb) {
x = 0;
y++;
}
/* PSB_DEBUG_MSVDX("MSVDX: concleament (%d,%d)\n",
x, y); */
if ((x == 0) && (mb_loop != start))
PSB_CMDPORT_WRITE_FAST(dev_priv,
MSVDX_CMDS_END_SLICE_PICTURE_OFFSET,
0, cmd_space);
cmd = 0;
REGIO_WRITE_FIELD_LITE(cmd,
MSVDX_CMDS_MACROBLOCK_NUMBER,
MB_CODE_TYPE, 1);
REGIO_WRITE_FIELD_LITE(cmd,
MSVDX_CMDS_MACROBLOCK_NUMBER,
MB_NO_X, x);
REGIO_WRITE_FIELD_LITE(cmd,
MSVDX_CMDS_MACROBLOCK_NUMBER,
MB_NO_Y, y);
PSB_CMDPORT_WRITE_FAST(dev_priv,
MSVDX_CMDS_MACROBLOCK_NUMBER_OFFSET,
cmd, cmd_space);
PSB_CMDPORT_WRITE_FAST(dev_priv,
MSVDX_CMDS_MACROBLOCK_RESIDUAL_FORMAT_OFFSET,
0, cmd_space);
cmd = 0;
REGIO_WRITE_FIELD_LITE(cmd,
MSVDX_CMDS_INTER_BLOCK_PREDICTION,
REF_INDEX_A_VALID, 1);
REGIO_WRITE_FIELD_LITE(cmd,
MSVDX_CMDS_INTER_BLOCK_PREDICTION,
INTER_PRED_BLOCK_SIZE, 0);
REGIO_WRITE_FIELD_LITE(cmd,
MSVDX_CMDS_INTER_BLOCK_PREDICTION,
REF_INDEX_A, 0);
REGIO_WRITE_FIELD_LITE(cmd,
MSVDX_CMDS_INTER_BLOCK_PREDICTION,
REF_INDEX_B, 0);
PSB_CMDPORT_WRITE_FAST(dev_priv,
MSVDX_CMDS_INTER_BLOCK_PREDICTION_OFFSET,
cmd, cmd_space);
PSB_CMDPORT_WRITE_FAST(dev_priv,
MSVDX_CMDS_MOTION_VECTOR_OFFSET,
0, cmd_space);
}
PSB_CMDPORT_WRITE(dev_priv,
MSVDX_CMDS_END_SLICE_PICTURE_OFFSET,
0, cmd_space);
}
ec_done:
/* try to unblock rendec */
ret = PSB_CMDPORT_WRITE_FAST(dev_priv,
MSVDX_CMDS_END_SLICE_PICTURE_OFFSET,
1, cmd_space);
fault_region->num_region = 0;
preempt_enable();
#ifdef CONFIG_VIDEO_MRFLD
power_island_put(OSPM_VIDEO_DEC_ISLAND);
#else
ospm_power_using_video_end(OSPM_VIDEO_DEC_ISLAND);
#endif
printk(KERN_DEBUG "MSVDX: EC done, unlock msvdx ret %d\n",
ret);
return;
}
struct psb_msvdx_ec_ctx *psb_msvdx_find_ec_ctx(
struct msvdx_private *msvdx_priv,
struct ttm_object_file *tfile,
void *cmd)
{
int i, free_idx;
struct psb_msvdx_ec_ctx *ec_ctx = NULL;
struct fw_deblock_msg *deblock_msg = (struct fw_deblock_msg *)cmd;
free_idx = -1;
for (i = 0; i < PSB_MAX_EC_INSTANCE; i++) {
if (msvdx_priv->msvdx_ec_ctx[i]->tfile == tfile)
break;
else if (free_idx < 0 &&
msvdx_priv->msvdx_ec_ctx[i]->tfile == NULL)
free_idx = i;
}
if (i < PSB_MAX_EC_INSTANCE)
ec_ctx = msvdx_priv->msvdx_ec_ctx[i];
else if (free_idx >= 0 && cmd) {
PSB_DEBUG_MSVDX("acquire ec ctx idx %d for tfile %p\n",
free_idx, tfile);
ec_ctx = msvdx_priv->msvdx_ec_ctx[free_idx];
memset(ec_ctx, 0, sizeof(*ec_ctx));
ec_ctx->tfile = tfile;
ec_ctx->context_id = deblock_msg->mmu_context.bits.context;
} else {
PSB_DEBUG_MSVDX("Available ec ctx is not found\n");
}
return ec_ctx;
}
void psb_msvdx_update_frame_info(struct msvdx_private *msvdx_priv,
struct ttm_object_file *tfile,
void *cmd)
{
int i, free_idx;
drm_psb_msvdx_frame_info_t *frame_info;
struct fw_deblock_msg *deblock_msg = (struct fw_deblock_msg *)cmd;
uint32_t buffer_handle = deblock_msg->mb_param_address;
struct psb_msvdx_ec_ctx *ec_ctx;
PSB_DEBUG_MSVDX(
"update frame info (handle 0x%08x) for error concealment\n",
buffer_handle);
ec_ctx = psb_msvdx_find_ec_ctx(msvdx_priv, tfile, cmd);
if (!ec_ctx)
return;
free_idx = -1;
for (i = 0; i < MAX_DECODE_BUFFERS; i++) {
if (buffer_handle == ec_ctx->frame_info[i].handle)
break;
if (free_idx < 0 && ec_ctx->frame_info[i].handle == 0)
free_idx = i;
}
if (i < MAX_DECODE_BUFFERS)
frame_info = &ec_ctx->frame_info[i];
else if (free_idx >= 0) {
PSB_DEBUG_MSVDX("acquire frame_info solt idx %d\n", free_idx);
frame_info = &ec_ctx->frame_info[free_idx];
} else {
PSB_DEBUG_MSVDX("%d solts occupied, abort update frame_info\n",
MAX_DECODE_BUFFERS);
return;
}
frame_info->fw_status = 0;
frame_info->handle = buffer_handle;
frame_info->fence = (deblock_msg->header.bits.msg_fence & (~0xf));
frame_info->decode_status.num_region = 0;
ec_ctx->cur_frame_info = frame_info;
}
void psb_msvdx_backup_cmd(struct msvdx_private *msvdx_priv,
struct ttm_object_file *tfile,
void *cmd,
uint32_t cmd_size,
uint32_t deblock_cmd_offset)
{
struct fw_deblock_msg *deblock_msg = NULL;
struct psb_msvdx_ec_ctx *ec_ctx;
union msg_header *header;
PSB_DEBUG_MSVDX("backup cmd for ved error concealment\n");
ec_ctx = psb_msvdx_find_ec_ctx(msvdx_priv, tfile, NULL);
if (!ec_ctx) {
PSB_DEBUG_MSVDX("this is not a ec ctx, abort backup cmd\n");
return;
}
if (deblock_cmd_offset != PSB_MSVDX_INVALID_OFFSET)
deblock_msg = (struct fw_deblock_msg *)(cmd + deblock_cmd_offset);
if (deblock_msg &&
ec_ctx->context_id != deblock_msg->mmu_context.bits.context) {
PSB_DEBUG_MSVDX("backup cmd but find mis-match context id\n");
return;
}
ec_ctx->cmd_size = cmd_size;
ec_ctx->deblock_cmd_offset = deblock_cmd_offset;
memcpy(ec_ctx->unfenced_cmd, cmd, cmd_size);
ec_ctx->fence = PSB_MSVDX_INVALID_FENCE;
header = (union msg_header *)ec_ctx->unfenced_cmd;
if (cmd_size)
ec_ctx->fence = header->bits.msg_fence;
ec_ctx->fence &= (~0xf);
PSB_DEBUG_MSVDX("backup cmd for ved: fence 0x%08x, cmd_size %d\n",
ec_ctx->fence, cmd_size);
}
void psb_msvdx_mtx_message_dump(struct drm_device *dev)
{
struct drm_psb_private *dev_priv = psb_priv(dev);
int i, buf_size, buf_offset;
buf_size = PSB_RMSVDX32(MSVDX_COMMS_TO_HOST_BUF_SIZE) & ((1 << 16) - 1);
buf_offset =
(PSB_RMSVDX32(MSVDX_COMMS_TO_HOST_BUF_SIZE) >> 16) + 0x2000;
printk(KERN_DEBUG "Dump to HOST message buffer (offset:size)%04x:%04x\n",
buf_offset, buf_size);
for (i = 0; i < buf_size; i += 4) {
uint32_t reg1, reg2, reg3, reg4;
reg1 = PSB_RMSVDX32(buf_offset + i * 4);
reg2 = PSB_RMSVDX32(buf_offset + i * 4 + 4);
reg3 = PSB_RMSVDX32(buf_offset + i * 4 + 8);
reg4 = PSB_RMSVDX32(buf_offset + i * 4 + 12);
printk(KERN_DEBUG "0x%04x: 0x%08x 0x%08x 0x%08x 0x%08x\n",
(buf_offset + i * 4), reg1, reg2, reg3, reg4);
}
buf_size = PSB_RMSVDX32(MSVDX_COMMS_TO_MTX_BUF_SIZE) & ((1 << 16) - 1);
buf_offset = (PSB_RMSVDX32(MSVDX_COMMS_TO_MTX_BUF_SIZE) >> 16) + 0x2000;
printk(KERN_DEBUG "Dump to MTX message buffer (offset:size)%04x:%04x\n",
buf_offset, buf_size);
for (i = 0; i < buf_size; i += 4) {
uint32_t reg1, reg2, reg3, reg4;
reg1 = PSB_RMSVDX32(buf_offset + i * 4);
reg2 = PSB_RMSVDX32(buf_offset + i * 4 + 4);
reg3 = PSB_RMSVDX32(buf_offset + i * 4 + 8);
reg4 = PSB_RMSVDX32(buf_offset + i * 4 + 12);
printk(KERN_DEBUG "0x%04x: 0x%08x 0x%08x 0x%08x 0x%08x\n",
(buf_offset + i * 4), reg1, reg2, reg3, reg4);
}
buf_size = 12;
buf_offset = 0xFD0 + 0x2000;
printk(KERN_DEBUG "Comm header (offset:size)%04x:%04x\n",
buf_offset, buf_size);
for (i = 0; i < buf_size; i += 4) {
uint32_t reg1, reg2, reg3, reg4;
reg1 = PSB_RMSVDX32(buf_offset + i * 4);
reg2 = PSB_RMSVDX32(buf_offset + i * 4 + 4);
reg3 = PSB_RMSVDX32(buf_offset + i * 4 + 8);
reg4 = PSB_RMSVDX32(buf_offset + i * 4 + 12);
printk(KERN_DEBUG "0x%04x: 0x%08x 0x%08x 0x%08x 0x%08x\n",
(buf_offset + i * 4), reg1, reg2, reg3, reg4);
}
printk(KERN_DEBUG "Error status 0x2cc4: 0x%08x\n",
PSB_RMSVDX32(0x2cc4));
}