1537 lines
52 KiB
C
1537 lines
52 KiB
C
/*------------------------------------------------------------------------------
|
|
-- --
|
|
-- This software is confidential and proprietary and may be used --
|
|
-- only as expressly authorized by a licensing agreement from --
|
|
-- --
|
|
-- Hantro Products Oy. --
|
|
-- --
|
|
-- (C) COPYRIGHT 2006 HANTRO PRODUCTS OY --
|
|
-- ALL RIGHTS RESERVED --
|
|
-- --
|
|
-- The entire notice above must be reproduced --
|
|
-- on all copies and should not be removed. --
|
|
-- --
|
|
--------------------------------------------------------------------------------
|
|
--
|
|
-- Description : Hardware interface read/write
|
|
--
|
|
------------------------------------------------------------------------------
|
|
--
|
|
-- Version control information, please leave untouched.
|
|
--
|
|
-- $RCSfile: h264hwd_asic.c,v $
|
|
-- $Revision: 1.48 $
|
|
-- $Date: 2009/11/26 13:32:15 $
|
|
--
|
|
------------------------------------------------------------------------------*/
|
|
|
|
#include "basetype.h"
|
|
#include "h264hwd_regdrv.h"
|
|
#include "h264hwd_asic.h"
|
|
#include "h264hwd_container.h"
|
|
#include "h264hwd_debug.h"
|
|
#include "h264hwd_util.h"
|
|
#include "h264hwd_cabac.h"
|
|
#include "dwl.h"
|
|
#include "refbuffer.h"
|
|
#include "h264_pp_multibuffer.h"
|
|
|
|
#define ASIC_HOR_MV_MASK 0x07FFFU
|
|
#define ASIC_VER_MV_MASK 0x01FFFU
|
|
|
|
#define ASIC_HOR_MV_OFFSET 17U
|
|
#define ASIC_VER_MV_OFFSET 4U
|
|
|
|
static void H264RefreshRegs(decContainer_t * pDecCont);
|
|
static void H264FlushRegs(decContainer_t * pDecCont);
|
|
static void h264StreamPosUpdate(decContainer_t * pDecCont);
|
|
static void H264PrepareCabacInitTables(DecAsicBuffers_t * pAsicBuff);
|
|
|
|
#ifndef TRACE_PP_CTRL
|
|
#define TRACE_PP_CTRL(...) do{}while(0)
|
|
#else
|
|
#undef TRACE_PP_CTRL
|
|
#define TRACE_PP_CTRL(...) printf(__VA_ARGS__)
|
|
#endif
|
|
|
|
const u32 refBase[16] = {
|
|
HWIF_REFER0_BASE, HWIF_REFER1_BASE, HWIF_REFER2_BASE,
|
|
HWIF_REFER3_BASE, HWIF_REFER4_BASE, HWIF_REFER5_BASE,
|
|
HWIF_REFER6_BASE, HWIF_REFER7_BASE, HWIF_REFER8_BASE,
|
|
HWIF_REFER9_BASE, HWIF_REFER10_BASE, HWIF_REFER11_BASE,
|
|
HWIF_REFER12_BASE, HWIF_REFER13_BASE, HWIF_REFER14_BASE,
|
|
HWIF_REFER15_BASE
|
|
};
|
|
|
|
const u32 refFieldMode[16] = {
|
|
HWIF_REFER0_FIELD_E, HWIF_REFER1_FIELD_E, HWIF_REFER2_FIELD_E,
|
|
HWIF_REFER3_FIELD_E, HWIF_REFER4_FIELD_E, HWIF_REFER5_FIELD_E,
|
|
HWIF_REFER6_FIELD_E, HWIF_REFER7_FIELD_E, HWIF_REFER8_FIELD_E,
|
|
HWIF_REFER9_FIELD_E, HWIF_REFER10_FIELD_E, HWIF_REFER11_FIELD_E,
|
|
HWIF_REFER12_FIELD_E, HWIF_REFER13_FIELD_E, HWIF_REFER14_FIELD_E,
|
|
HWIF_REFER15_FIELD_E
|
|
};
|
|
|
|
const u32 refTopc[16] = {
|
|
HWIF_REFER0_TOPC_E, HWIF_REFER1_TOPC_E, HWIF_REFER2_TOPC_E,
|
|
HWIF_REFER3_TOPC_E, HWIF_REFER4_TOPC_E, HWIF_REFER5_TOPC_E,
|
|
HWIF_REFER6_TOPC_E, HWIF_REFER7_TOPC_E, HWIF_REFER8_TOPC_E,
|
|
HWIF_REFER9_TOPC_E, HWIF_REFER10_TOPC_E, HWIF_REFER11_TOPC_E,
|
|
HWIF_REFER12_TOPC_E, HWIF_REFER13_TOPC_E, HWIF_REFER14_TOPC_E,
|
|
HWIF_REFER15_TOPC_E
|
|
};
|
|
|
|
const u32 refPicNum[16] = {
|
|
HWIF_REFER0_NBR, HWIF_REFER1_NBR, HWIF_REFER2_NBR,
|
|
HWIF_REFER3_NBR, HWIF_REFER4_NBR, HWIF_REFER5_NBR,
|
|
HWIF_REFER6_NBR, HWIF_REFER7_NBR, HWIF_REFER8_NBR,
|
|
HWIF_REFER9_NBR, HWIF_REFER10_NBR, HWIF_REFER11_NBR,
|
|
HWIF_REFER12_NBR, HWIF_REFER13_NBR, HWIF_REFER14_NBR,
|
|
HWIF_REFER15_NBR
|
|
};
|
|
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Reference list initialization
|
|
------------------------------------------------------------------------------*/
|
|
#define IS_SHORT_TERM_FRAME(a) ((a).status[0] == SHORT_TERM && \
|
|
(a).status[1] == SHORT_TERM)
|
|
#define IS_SHORT_TERM_FRAME_F(a) ((a).status[0] == SHORT_TERM || \
|
|
(a).status[1] == SHORT_TERM)
|
|
#define IS_LONG_TERM_FRAME(a) ((a).status[0] == LONG_TERM && \
|
|
(a).status[1] == LONG_TERM)
|
|
#define IS_LONG_TERM_FRAME_F(a) ((a).status[0] == LONG_TERM || \
|
|
(a).status[1] == LONG_TERM)
|
|
#define FRAME_POC(a) MIN((a).picOrderCnt[0], (a).picOrderCnt[1])
|
|
#define FIELD_POC(a) MIN(((a).status[0] != EMPTY) ? \
|
|
(a).picOrderCnt[0] : 0x7FFFFFFF,\
|
|
((a).status[1] != EMPTY) ? \
|
|
(a).picOrderCnt[1] : 0x7FFFFFFF)
|
|
|
|
#define INVALID_IDX 0xFFFFFFFF
|
|
#define MIN_POC 0x80000000
|
|
#define MAX_POC 0x7FFFFFFF
|
|
|
|
const u32 refPicList0[16] = {
|
|
HWIF_BINIT_RLIST_F0, HWIF_BINIT_RLIST_F1, HWIF_BINIT_RLIST_F2,
|
|
HWIF_BINIT_RLIST_F3, HWIF_BINIT_RLIST_F4, HWIF_BINIT_RLIST_F5,
|
|
HWIF_BINIT_RLIST_F6, HWIF_BINIT_RLIST_F7, HWIF_BINIT_RLIST_F8,
|
|
HWIF_BINIT_RLIST_F9, HWIF_BINIT_RLIST_F10, HWIF_BINIT_RLIST_F11,
|
|
HWIF_BINIT_RLIST_F12, HWIF_BINIT_RLIST_F13, HWIF_BINIT_RLIST_F14,
|
|
HWIF_BINIT_RLIST_F15
|
|
};
|
|
|
|
const u32 refPicList1[16] = {
|
|
HWIF_BINIT_RLIST_B0, HWIF_BINIT_RLIST_B1, HWIF_BINIT_RLIST_B2,
|
|
HWIF_BINIT_RLIST_B3, HWIF_BINIT_RLIST_B4, HWIF_BINIT_RLIST_B5,
|
|
HWIF_BINIT_RLIST_B6, HWIF_BINIT_RLIST_B7, HWIF_BINIT_RLIST_B8,
|
|
HWIF_BINIT_RLIST_B9, HWIF_BINIT_RLIST_B10, HWIF_BINIT_RLIST_B11,
|
|
HWIF_BINIT_RLIST_B12, HWIF_BINIT_RLIST_B13, HWIF_BINIT_RLIST_B14,
|
|
HWIF_BINIT_RLIST_B15
|
|
};
|
|
|
|
const u32 refPicListP[16] = {
|
|
HWIF_PINIT_RLIST_F0, HWIF_PINIT_RLIST_F1, HWIF_PINIT_RLIST_F2,
|
|
HWIF_PINIT_RLIST_F3, HWIF_PINIT_RLIST_F4, HWIF_PINIT_RLIST_F5,
|
|
HWIF_PINIT_RLIST_F6, HWIF_PINIT_RLIST_F7, HWIF_PINIT_RLIST_F8,
|
|
HWIF_PINIT_RLIST_F9, HWIF_PINIT_RLIST_F10, HWIF_PINIT_RLIST_F11,
|
|
HWIF_PINIT_RLIST_F12, HWIF_PINIT_RLIST_F13, HWIF_PINIT_RLIST_F14,
|
|
HWIF_PINIT_RLIST_F15
|
|
};
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Function name : AllocateAsicBuffers
|
|
Description :
|
|
|
|
Return type : i32
|
|
Argument : DecAsicBuffers_t * asicBuff
|
|
Argument : u32 mbs
|
|
------------------------------------------------------------------------------*/
|
|
u32 AllocateAsicBuffers(decContainer_t * pDecCont, DecAsicBuffers_t * asicBuff,
|
|
u32 mbs)
|
|
{
|
|
i32 ret = 0;
|
|
u32 tmp;
|
|
|
|
if(pDecCont->rlcMode)
|
|
{
|
|
tmp = ASIC_MB_CTRL_BUFFER_SIZE;
|
|
ret = DWLMallocLinear(pDecCont->dwl, mbs * tmp, &asicBuff[0].mbCtrl);
|
|
|
|
tmp = ASIC_MB_MV_BUFFER_SIZE;
|
|
ret |= DWLMallocLinear(pDecCont->dwl, mbs * tmp, &asicBuff[0].mv);
|
|
|
|
tmp = ASIC_MB_I4X4_BUFFER_SIZE;
|
|
ret |=
|
|
DWLMallocLinear(pDecCont->dwl, mbs * tmp, &asicBuff[0].intraPred);
|
|
|
|
tmp = ASIC_MB_RLC_BUFFER_SIZE;
|
|
ret |= DWLMallocLinear(pDecCont->dwl, mbs * tmp, &asicBuff[0].residual);
|
|
}
|
|
|
|
asicBuff[0].buff_status = 0;
|
|
asicBuff[0].picSizeInMbs = mbs;
|
|
|
|
if(pDecCont->h264ProfileSupport != H264_BASELINE_PROFILE)
|
|
{
|
|
tmp = ASIC_CABAC_INIT_BUFFER_SIZE + ASIC_SCALING_LIST_SIZE +
|
|
ASIC_POC_BUFFER_SIZE;
|
|
ret |= DWLMallocLinear(pDecCont->dwl, tmp, &asicBuff[0].cabacInit);
|
|
if(ret == 0)
|
|
{
|
|
H264PrepareCabacInitTables(asicBuff);
|
|
}
|
|
}
|
|
|
|
if(pDecCont->refBufSupport)
|
|
{
|
|
RefbuInit(&pDecCont->refBufferCtrl, DEC_X170_MODE_H264,
|
|
pDecCont->storage.activeSps->picWidthInMbs,
|
|
pDecCont->storage.activeSps->picHeightInMbs,
|
|
pDecCont->refBufSupport);
|
|
}
|
|
|
|
if(ret != 0)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Function name : ReleaseAsicBuffers
|
|
Description :
|
|
|
|
Return type : void
|
|
Argument : DecAsicBuffers_t * asicBuff
|
|
------------------------------------------------------------------------------*/
|
|
void ReleaseAsicBuffers(const void *dwl, DecAsicBuffers_t * asicBuff)
|
|
{
|
|
|
|
if(asicBuff[0].mbCtrl.virtualAddress != NULL)
|
|
{
|
|
DWLFreeLinear(dwl, &asicBuff[0].mbCtrl);
|
|
asicBuff[0].mbCtrl.virtualAddress = NULL;
|
|
}
|
|
if(asicBuff[0].residual.virtualAddress != NULL)
|
|
{
|
|
DWLFreeLinear(dwl, &asicBuff[0].residual);
|
|
asicBuff[0].residual.virtualAddress = NULL;
|
|
}
|
|
|
|
if(asicBuff[0].mv.virtualAddress != NULL)
|
|
{
|
|
DWLFreeLinear(dwl, &asicBuff[0].mv);
|
|
asicBuff[0].mv.virtualAddress = NULL;
|
|
}
|
|
|
|
if(asicBuff[0].intraPred.virtualAddress != NULL)
|
|
{
|
|
DWLFreeLinear(dwl, &asicBuff[0].intraPred);
|
|
asicBuff[0].intraPred.virtualAddress = NULL;
|
|
}
|
|
|
|
if(asicBuff[0].cabacInit.virtualAddress != NULL)
|
|
{
|
|
DWLFreeLinear(dwl, &asicBuff[0].cabacInit);
|
|
asicBuff[0].cabacInit.virtualAddress = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Function name : H264RunAsic
|
|
Description :
|
|
|
|
Return type : hw status
|
|
Argument : DecAsicBuffers_t * pAsicBuff
|
|
------------------------------------------------------------------------------*/
|
|
u32 H264RunAsic(decContainer_t * pDecCont, DecAsicBuffers_t * pAsicBuff)
|
|
{
|
|
const seqParamSet_t *pSps = pDecCont->storage.activeSps;
|
|
const sliceHeader_t *pSliceHeader = pDecCont->storage.sliceHeader;
|
|
const picParamSet_t *pPps = pDecCont->storage.activePps;
|
|
const dpbStorage_t *dpb = pDecCont->storage.dpb;
|
|
|
|
u32 asic_status = 0;
|
|
i32 ret = 0;
|
|
|
|
if(!pDecCont->asicRunning)
|
|
{
|
|
u32 reserveRet = 0;
|
|
u32 i;
|
|
|
|
for(i = 0; i < 16; i++)
|
|
{
|
|
SetDecRegister(pDecCont->h264Regs, refBase[i],
|
|
pAsicBuff->refPicList[i]);
|
|
}
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_FILTERING_DIS,
|
|
pAsicBuff->filterDisable);
|
|
|
|
if(pSliceHeader->fieldPicFlag && pSliceHeader->bottomFieldFlag)
|
|
{
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_DEC_OUT_BASE,
|
|
pAsicBuff->outBuffer->busAddress +
|
|
pSps->picWidthInMbs * 16);
|
|
}
|
|
else
|
|
{
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_DEC_OUT_BASE,
|
|
pAsicBuff->outBuffer->busAddress);
|
|
}
|
|
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_CH_QP_OFFSET,
|
|
pAsicBuff->chromaQpIndexOffset);
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_CH_QP_OFFSET2,
|
|
pAsicBuff->chromaQpIndexOffset2);
|
|
|
|
if(pDecCont->rlcMode)
|
|
{
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_RLC_MODE_E, 1);
|
|
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_MB_CTRL_BASE,
|
|
pAsicBuff->mbCtrl.busAddress);
|
|
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_RLC_VLC_BASE,
|
|
pAsicBuff->residual.busAddress);
|
|
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_REF_FRAMES,
|
|
pSps->numRefFrames);
|
|
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_INTRA_4X4_BASE,
|
|
pAsicBuff->intraPred.busAddress);
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_DIFF_MV_BASE,
|
|
pAsicBuff->mv.busAddress);
|
|
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_STREAM_LEN, 0);
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_STRM_START_BIT, 0);
|
|
}
|
|
else
|
|
{
|
|
/* new 8190 stuff (not used/ignored in 8170) */
|
|
if(pDecCont->h264ProfileSupport == H264_BASELINE_PROFILE)
|
|
{
|
|
goto skipped_high_profile; /* leave high profile stuff disabled */
|
|
}
|
|
|
|
/* direct mv writing not enabled if HW config says that
|
|
* SW_DEC_H264_PROF="10" */
|
|
if(pAsicBuff->enableDmvAndPoc && pDecCont->h264ProfileSupport != 2)
|
|
{
|
|
u32 dirMvOffset;
|
|
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_WRITE_MVS_E,
|
|
pDecCont->storage.prevNalUnit->nalRefIdc != 0);
|
|
|
|
dirMvOffset = dpb->dirMvOffset +
|
|
(pSliceHeader->
|
|
bottomFieldFlag ? (dpb->picSizeInMbs * 32) : 0);
|
|
|
|
/*
|
|
ASSERT(pAsicBuff->outBuffer->busAddress ==
|
|
dpb->buffer[dpb->currentOutPos].data->busAddress);
|
|
*/
|
|
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_DIR_MV_BASE,
|
|
pAsicBuff->outBuffer->busAddress + dirMvOffset);
|
|
}
|
|
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_DIR_8X8_INFER_E,
|
|
pSps->direct8x8InferenceFlag);
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_WEIGHT_PRED_E,
|
|
pPps->weightedPredFlag);
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_WEIGHT_BIPR_IDC,
|
|
pPps->weightedBiPredIdc);
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_REFIDX1_ACTIVE,
|
|
pPps->numRefIdxL1Active);
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_FIELDPIC_FLAG_E,
|
|
!pSps->frameMbsOnlyFlag);
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_PIC_INTERLACE_E,
|
|
!pSps->frameMbsOnlyFlag &&
|
|
(pSps->mbAdaptiveFrameFieldFlag || pSliceHeader->fieldPicFlag));
|
|
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_PIC_FIELDMODE_E,
|
|
pSliceHeader->fieldPicFlag);
|
|
|
|
DEBUG_PRINT(("framembs %d, mbaff %d, fieldpic %d\n",
|
|
pSps->frameMbsOnlyFlag,
|
|
pSps->mbAdaptiveFrameFieldFlag, pSliceHeader->fieldPicFlag));
|
|
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_PIC_TOPFIELD_E,
|
|
!pSliceHeader->bottomFieldFlag);
|
|
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_SEQ_MBAFF_E,
|
|
pSps->mbAdaptiveFrameFieldFlag);
|
|
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_8X8TRANS_FLAG_E,
|
|
pPps->transform8x8Flag);
|
|
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_BLACKWHITE_E,
|
|
pSps->profileIdc >= 100 &&
|
|
pSps->chromaFormatIdc == 0);
|
|
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_TYPE1_QUANT_E,
|
|
pPps->scalingMatrixPresentFlag);
|
|
if(pPps->scalingMatrixPresentFlag)
|
|
{
|
|
u32 j, tmp;
|
|
u32 *p;
|
|
|
|
u8(*scalingList)[64];
|
|
|
|
p = (u32 *) ((u8 *) pDecCont->asicBuff->cabacInit.
|
|
virtualAddress + ASIC_CABAC_INIT_BUFFER_SIZE +
|
|
ASIC_POC_BUFFER_SIZE);
|
|
scalingList = pDecCont->storage.activePps->scalingList;
|
|
for(i = 0; i < 6; i++)
|
|
{
|
|
for(j = 0; j < 4; j++)
|
|
{
|
|
tmp = (scalingList[i][4 * j + 0] << 24) |
|
|
(scalingList[i][4 * j + 1] << 16) |
|
|
(scalingList[i][4 * j + 2] << 8) |
|
|
(scalingList[i][4 * j + 3]);
|
|
*p++ = tmp;
|
|
}
|
|
}
|
|
for(i = 6; i < 8; i++)
|
|
{
|
|
for(j = 0; j < 16; j++)
|
|
{
|
|
tmp = (scalingList[i][4 * j + 0] << 24) |
|
|
(scalingList[i][4 * j + 1] << 16) |
|
|
(scalingList[i][4 * j + 2] << 8) |
|
|
(scalingList[i][4 * j + 3]);
|
|
*p++ = tmp;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/***************************************************************************/
|
|
skipped_high_profile:
|
|
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_DEC_OUT_DIS,
|
|
pAsicBuff->disableOutWriting);
|
|
|
|
/* Setup reference picture buffer */
|
|
if(pDecCont->refBufSupport)
|
|
{
|
|
u32 fieldPicFlag;
|
|
u32 mbaff;
|
|
u32 picId0;
|
|
u32 picId1;
|
|
u32 flags = 0;
|
|
const picParamSet_t *pPps = pDecCont->storage.activePps;
|
|
/* TODO in this */
|
|
fieldPicFlag = pSliceHeader->fieldPicFlag;
|
|
mbaff = pDecCont->storage.activeSps->mbAdaptiveFrameFieldFlag;
|
|
picId0 = pDecCont->storage.dpb[0].list[0];
|
|
picId1 = pDecCont->storage.dpb[0].list[1];
|
|
if( pPps->numRefIdxL0Active > 1 ||
|
|
( IS_B_SLICE(pDecCont->storage.sliceHeader->sliceType) &&
|
|
pPps->numRefIdxL0Active > 1 ) )
|
|
{
|
|
flags |= REFBU_MULTIPLE_REF_FRAMES;
|
|
}
|
|
|
|
RefbuSetup(&pDecCont->refBufferCtrl, pDecCont->h264Regs,
|
|
fieldPicFlag ? REFBU_FIELD : (mbaff ? REFBU_MBAFF : REFBU_FRAME),
|
|
IS_IDR_NAL_UNIT(pDecCont->storage.prevNalUnit),
|
|
IS_B_SLICE(pDecCont->storage.sliceHeader->sliceType),
|
|
picId0, picId1, flags );
|
|
}
|
|
|
|
if (pDecCont->storage.enable2ndChroma &&
|
|
!pDecCont->storage.activeSps->monoChrome)
|
|
{
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_CH_8PIX_ILEAV_E, 1);
|
|
if(pSliceHeader->fieldPicFlag && pSliceHeader->bottomFieldFlag)
|
|
{
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_DEC_CH8PIX_BASE,
|
|
pAsicBuff->outBuffer->busAddress + dpb->ch2Offset+
|
|
pSps->picWidthInMbs * 16);
|
|
}
|
|
else
|
|
{
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_DEC_CH8PIX_BASE,
|
|
pAsicBuff->outBuffer->busAddress + dpb->ch2Offset);
|
|
}
|
|
}
|
|
else
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_CH_8PIX_ILEAV_E, 0);
|
|
|
|
if (!pDecCont->keepHwReserved)
|
|
{
|
|
reserveRet = DWLReserveHw(pDecCont->dwl);
|
|
if(reserveRet != DWL_OK)
|
|
{
|
|
return X170_DEC_HW_RESERVED;
|
|
}
|
|
}
|
|
|
|
pDecCont->asicRunning = 1;
|
|
|
|
if(pDecCont->pp.ppInstance != NULL &&
|
|
pDecCont->pp.ppInfo.multiBuffer == 0 &&
|
|
pDecCont->pp.decPpIf.ppStatus == DECPP_RUNNING)
|
|
{
|
|
/* legacy single buffer mode */
|
|
const storage_t *pStorage = &pDecCont->storage;
|
|
DecPpInterface *decPpIf = &pDecCont->pp.decPpIf;
|
|
|
|
TRACE_PP_CTRL("H264RunAsic: PP Run\n");
|
|
|
|
decPpIf->inwidth = pSps->picWidthInMbs * 16;
|
|
decPpIf->inheight = pSps->picHeightInMbs * 16;
|
|
decPpIf->croppedW = decPpIf->inwidth;
|
|
decPpIf->croppedH = decPpIf->inheight;
|
|
|
|
if(pSps->frameMbsOnlyFlag)
|
|
{
|
|
decPpIf->picStruct = DECPP_PIC_FRAME_OR_TOP_FIELD;
|
|
}
|
|
else
|
|
{
|
|
/* interlaced */
|
|
decPpIf->picStruct = DECPP_PIC_TOP_AND_BOT_FIELD_FRAME;
|
|
/* TODO: missing field? is this OK? */
|
|
}
|
|
|
|
decPpIf->littleEndian =
|
|
GetDecRegister(pDecCont->h264Regs, HWIF_DEC_OUT_ENDIAN);
|
|
decPpIf->wordSwap =
|
|
GetDecRegister(pDecCont->h264Regs, HWIF_DEC_OUTSWAP32_E);
|
|
|
|
if(decPpIf->usePipeline)
|
|
{
|
|
decPpIf->inputBusLuma = pStorage->dpb->currentOut->data->busAddress;
|
|
}
|
|
else
|
|
{
|
|
decPpIf->inputBusLuma =
|
|
pStorage->dpb->outBuf[pStorage->dpb->outIndexR].data->busAddress;
|
|
}
|
|
|
|
decPpIf->inputBusChroma =
|
|
decPpIf->inputBusLuma + decPpIf->inwidth * decPpIf->inheight;
|
|
|
|
if(decPpIf->picStruct != DECPP_PIC_FRAME_OR_TOP_FIELD)
|
|
{
|
|
decPpIf->bottomBusLuma =
|
|
decPpIf->inputBusLuma + decPpIf->inwidth;
|
|
decPpIf->bottomBusChroma =
|
|
decPpIf->inputBusChroma + decPpIf->inwidth;
|
|
}
|
|
else
|
|
{
|
|
decPpIf->bottomBusLuma = (u32) (-1);
|
|
decPpIf->bottomBusChroma = (u32) (-1);
|
|
}
|
|
|
|
pDecCont->pp.PPDecStart(pDecCont->pp.ppInstance, decPpIf);
|
|
}
|
|
|
|
|
|
if(pDecCont->pp.ppInstance != NULL &&
|
|
pDecCont->pp.ppInfo.multiBuffer == 1 &&
|
|
pDecCont->pp.decPpIf.ppStatus == DECPP_RUNNING)
|
|
{
|
|
/* multibuffer mode */
|
|
const storage_t *pStorage = &pDecCont->storage;
|
|
DecPpInterface *decPpIf = &pDecCont->pp.decPpIf;
|
|
|
|
TRACE_PP_CTRL("H264RunAsic: PP Run\n");
|
|
|
|
decPpIf->inwidth = pSps->picWidthInMbs * 16;
|
|
decPpIf->inheight = pSps->picHeightInMbs * 16;
|
|
decPpIf->croppedW = decPpIf->inwidth;
|
|
decPpIf->croppedH = decPpIf->inheight;
|
|
|
|
if(pSps->frameMbsOnlyFlag)
|
|
{
|
|
decPpIf->picStruct = DECPP_PIC_FRAME_OR_TOP_FIELD;
|
|
}
|
|
else
|
|
{
|
|
/* interlaced */
|
|
decPpIf->picStruct = DECPP_PIC_TOP_AND_BOT_FIELD_FRAME;
|
|
}
|
|
|
|
decPpIf->littleEndian =
|
|
GetDecRegister(pDecCont->h264Regs, HWIF_DEC_OUT_ENDIAN);
|
|
decPpIf->wordSwap =
|
|
GetDecRegister(pDecCont->h264Regs, HWIF_DEC_OUTSWAP32_E);
|
|
|
|
if(decPpIf->usePipeline)
|
|
{
|
|
u32 picID;
|
|
decPpIf->inputBusLuma = pStorage->dpb->currentOut->data->busAddress;
|
|
picID = h264PpMultiAddPic(pDecCont, pStorage->dpb->currentOut->data);
|
|
|
|
ASSERT(picID <= pDecCont->pp.multiMaxId);
|
|
TRACE_PP_CTRL("H264RunAsic: PP Multibuffer index = %d\n", picID);
|
|
decPpIf->bufferIndex = picID;
|
|
decPpIf->displayIndex = (u32)(-1);
|
|
|
|
/*pDecCont->pp.queuedPicToPp = NULL;*/ /* no queue */ /* we do not need to forget our queued picture */
|
|
}
|
|
else
|
|
{
|
|
u32 picID;
|
|
/* send queued picture to PP */
|
|
ASSERT(pDecCont->pp.queuedPicToPp != NULL);
|
|
|
|
decPpIf->inputBusLuma = pDecCont->pp.queuedPicToPp->busAddress;
|
|
picID = h264PpMultiAddPic(pDecCont, pDecCont->pp.queuedPicToPp);
|
|
|
|
ASSERT(picID <= pDecCont->pp.multiMaxId);
|
|
TRACE_PP_CTRL("H264RunAsic: PP Multibuffer index = %d\n", picID);
|
|
decPpIf->bufferIndex = picID;
|
|
decPpIf->displayIndex = (u32)(-1);
|
|
|
|
/* queue curent picture for next PP processing */
|
|
if(!pStorage->secondField)
|
|
{
|
|
pDecCont->pp.queuedPicToPp = pStorage->dpb->currentOut->data;
|
|
}
|
|
else
|
|
{
|
|
pDecCont->pp.queuedPicToPp = NULL; /* do not queue first field */
|
|
}
|
|
}
|
|
|
|
decPpIf->inputBusChroma =
|
|
decPpIf->inputBusLuma + decPpIf->inwidth * decPpIf->inheight;
|
|
|
|
if(decPpIf->picStruct != DECPP_PIC_FRAME_OR_TOP_FIELD)
|
|
{
|
|
decPpIf->bottomBusLuma =
|
|
decPpIf->inputBusLuma + decPpIf->inwidth;
|
|
decPpIf->bottomBusChroma =
|
|
decPpIf->inputBusChroma + decPpIf->inwidth;
|
|
}
|
|
else
|
|
{
|
|
decPpIf->bottomBusLuma = (u32) (-1);
|
|
decPpIf->bottomBusChroma = (u32) (-1);
|
|
}
|
|
|
|
pDecCont->pp.PPDecStart(pDecCont->pp.ppInstance, decPpIf);
|
|
}
|
|
|
|
H264FlushRegs(pDecCont);
|
|
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_DEC_E, 1);
|
|
DWLEnableHW(pDecCont->dwl, 4 * 1, pDecCont->h264Regs[1]);
|
|
}
|
|
else /* buffer was empty and now we restart with new stream values */
|
|
{
|
|
h264StreamPosUpdate(pDecCont);
|
|
|
|
DWLWriteReg(pDecCont->dwl, 4 * 5, pDecCont->h264Regs[5]);
|
|
DWLWriteReg(pDecCont->dwl, 4 * 6, pDecCont->h264Regs[6]);
|
|
DWLWriteReg(pDecCont->dwl, 4 * 12, pDecCont->h264Regs[12]);
|
|
|
|
/* start HW by clearing IRQ_BUFFER_EMPTY status bit */
|
|
DWLEnableHW(pDecCont->dwl, 4 * 1, pDecCont->h264Regs[1]);
|
|
}
|
|
|
|
ret = DWLWaitHwReady(pDecCont->dwl, (u32) DEC_X170_TIMEOUT_LENGTH);
|
|
|
|
if(ret != DWL_HW_WAIT_OK)
|
|
{
|
|
ERROR_PRINT("DWLWaitHwReady");
|
|
DEBUG_PRINT(("DWLWaitHwReady returned: %d\n", ret));
|
|
|
|
/* reset HW */
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_DEC_IRQ_STAT, 0);
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_DEC_IRQ, 0);
|
|
|
|
DWLDisableHW(pDecCont->dwl, 4 * 1, pDecCont->h264Regs[1]);
|
|
|
|
/* Wait for PP to end also */
|
|
if(pDecCont->pp.ppInstance != NULL &&
|
|
(pDecCont->pp.decPpIf.ppStatus == DECPP_RUNNING ||
|
|
pDecCont->pp.decPpIf.ppStatus == DECPP_PIC_NOT_FINISHED))
|
|
{
|
|
pDecCont->pp.decPpIf.ppStatus = DECPP_PIC_READY;
|
|
|
|
TRACE_PP_CTRL("H264RunAsic: PP Wait for end\n");
|
|
|
|
pDecCont->pp.PPDecWaitEnd(pDecCont->pp.ppInstance);
|
|
|
|
TRACE_PP_CTRL("H264RunAsic: PP Finished\n");
|
|
}
|
|
|
|
pDecCont->asicRunning = 0;
|
|
pDecCont->keepHwReserved = 0;
|
|
DWLReleaseHw(pDecCont->dwl);
|
|
|
|
return (ret == DWL_HW_WAIT_ERROR) ?
|
|
X170_DEC_SYSTEM_ERROR : X170_DEC_TIMEOUT;
|
|
}
|
|
|
|
H264RefreshRegs(pDecCont);
|
|
|
|
/* React to the HW return value */
|
|
|
|
asic_status = GetDecRegister(pDecCont->h264Regs, HWIF_DEC_IRQ_STAT);
|
|
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_DEC_IRQ_STAT, 0);
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_DEC_IRQ, 0); /* just in case */
|
|
|
|
/* any B stuff detected by HW? (note reg name changed from
|
|
* b_detected to pic_inf) */
|
|
if(GetDecRegister(pDecCont->h264Regs, HWIF_DEC_PIC_INF))
|
|
{
|
|
ASSERT(pDecCont->h264ProfileSupport != H264_BASELINE_PROFILE);
|
|
if((pDecCont->h264ProfileSupport != H264_BASELINE_PROFILE) &&
|
|
(pAsicBuff->enableDmvAndPoc == 0))
|
|
{
|
|
DEBUG_PRINT(("HW Detected B slice in baseline profile stream!!!\n"));
|
|
pAsicBuff->enableDmvAndPoc = 1;
|
|
}
|
|
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_DEC_PIC_INF, 0);
|
|
}
|
|
|
|
if(!(asic_status & DEC_X170_IRQ_BUFFER_EMPTY))
|
|
{
|
|
/* HW done, release it! */
|
|
pDecCont->asicRunning = 0;
|
|
|
|
pDecCont->keepHwReserved = 0;
|
|
/* Wait for PP to end also */
|
|
if(pDecCont->pp.ppInstance != NULL &&
|
|
(pDecCont->pp.decPpIf.ppStatus == DECPP_RUNNING ||
|
|
pDecCont->pp.decPpIf.ppStatus == DECPP_PIC_NOT_FINISHED))
|
|
{
|
|
/* first field of a frame finished -> decode second one before
|
|
* waiting for PP to finish */
|
|
if (pDecCont->storage.secondField &&
|
|
(asic_status & DEC_X170_IRQ_DEC_RDY))
|
|
{
|
|
pDecCont->pp.decPpIf.ppStatus = DECPP_PIC_NOT_FINISHED;
|
|
pDecCont->keepHwReserved = 1;
|
|
}
|
|
else
|
|
{
|
|
pDecCont->pp.decPpIf.ppStatus = DECPP_PIC_READY;
|
|
|
|
TRACE_PP_CTRL("H264RunAsic: PP Wait for end\n");
|
|
|
|
pDecCont->pp.PPDecWaitEnd(pDecCont->pp.ppInstance);
|
|
|
|
TRACE_PP_CTRL("H264RunAsic: PP Finished\n");
|
|
}
|
|
}
|
|
|
|
if (!pDecCont->keepHwReserved)
|
|
DWLReleaseHw(pDecCont->dwl);
|
|
}
|
|
|
|
/* update reference buffer stat */
|
|
if(pDecCont->asicRunning == 0 &&
|
|
(asic_status & DEC_X170_IRQ_DEC_RDY))
|
|
{
|
|
u32 *pMv = pAsicBuff->outBuffer->virtualAddress;
|
|
u32 tmp = dpb->dirMvOffset;
|
|
|
|
if(pSliceHeader->fieldPicFlag && pSliceHeader->bottomFieldFlag)
|
|
{
|
|
tmp += dpb->picSizeInMbs * 32;
|
|
}
|
|
pMv = (u32 *) ((u8*)pMv + tmp);
|
|
|
|
if(pDecCont->refBufSupport &&
|
|
!IS_B_SLICE(pDecCont->storage.sliceHeader->sliceType))
|
|
{
|
|
RefbuMvStatistics(&pDecCont->refBufferCtrl, pDecCont->h264Regs,
|
|
pMv, pAsicBuff->enableDmvAndPoc,
|
|
IS_IDR_NAL_UNIT(pDecCont->storage.prevNalUnit));
|
|
}
|
|
else if ( pDecCont->refBufSupport )
|
|
{
|
|
RefbuMvStatisticsB( &pDecCont->refBufferCtrl, pDecCont->h264Regs );
|
|
}
|
|
}
|
|
|
|
if(!pDecCont->rlcMode)
|
|
{
|
|
u32 last_read_address;
|
|
u32 bytes_processed;
|
|
const u32 start_address =
|
|
pDecCont->hwStreamStartBus & (~DEC_X170_ALIGN_MASK);
|
|
const u32 offset_bytes =
|
|
pDecCont->hwStreamStartBus & DEC_X170_ALIGN_MASK;
|
|
|
|
last_read_address =
|
|
GetDecRegister(pDecCont->h264Regs, HWIF_RLC_VLC_BASE);
|
|
|
|
bytes_processed = last_read_address - start_address;
|
|
|
|
DEBUG_PRINT(("HW updated stream position: %08x\n"
|
|
" processed bytes: %8d\n"
|
|
" of which offset bytes: %8d\n",
|
|
last_read_address, bytes_processed, offset_bytes));
|
|
|
|
if(!(asic_status & DEC_X170_IRQ_ASO))
|
|
{
|
|
/* from start of the buffer add what HW has decoded */
|
|
|
|
/* end - start smaller or equal than maximum */
|
|
if((bytes_processed - offset_bytes) > pDecCont->hwLength)
|
|
{
|
|
|
|
if(!(asic_status & DEC_X170_IRQ_STREAM_ERROR))
|
|
{
|
|
DEBUG_PRINT(("New stream position out of range!\n"));
|
|
ASSERT(0);
|
|
}
|
|
|
|
/* consider all buffer processed */
|
|
pDecCont->pHwStreamStart += pDecCont->hwLength;
|
|
pDecCont->hwStreamStartBus += pDecCont->hwLength;
|
|
pDecCont->hwLength = 0; /* no bytes left */
|
|
}
|
|
else
|
|
{
|
|
pDecCont->hwLength -= (bytes_processed - offset_bytes);
|
|
pDecCont->pHwStreamStart += (bytes_processed - offset_bytes);
|
|
pDecCont->hwStreamStartBus += (bytes_processed - offset_bytes);
|
|
}
|
|
|
|
}
|
|
/* else will continue decoding from the beginning of buffer */
|
|
|
|
pDecCont->streamPosUpdated = 1;
|
|
}
|
|
|
|
return asic_status;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Function name : PrepareMvData
|
|
Description :
|
|
|
|
Return type : void
|
|
Argument : storage_t * pStorage
|
|
Argument : DecAsicBuffers_t * pAsicBuff
|
|
------------------------------------------------------------------------------*/
|
|
void PrepareMvData(storage_t * pStorage, DecAsicBuffers_t * pAsicBuff)
|
|
{
|
|
const mbStorage_t *pMb = pStorage->mb;
|
|
|
|
u32 mbs = pStorage->picSizeInMbs;
|
|
u32 tmp, n;
|
|
u32 *pMvCtrl, *pMvCtrlBase = pAsicBuff->mv.virtualAddress;
|
|
const u32 *pMbCtrl = pAsicBuff->mbCtrl.virtualAddress;
|
|
|
|
if(pAsicBuff->wholePicConcealed != 0)
|
|
{
|
|
if(pMb->mbType_asic == P_Skip)
|
|
{
|
|
tmp = pMb->refID[0];
|
|
|
|
pMvCtrl = pMvCtrlBase;
|
|
|
|
for(n = mbs; n > 0; n--)
|
|
{
|
|
*pMvCtrl = tmp;
|
|
pMvCtrl += (ASIC_MB_MV_BUFFER_SIZE / 4);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
for(n = mbs; n > 0; n--, pMb++, pMvCtrlBase += (ASIC_MB_MV_BUFFER_SIZE / 4),
|
|
pMbCtrl += (ASIC_MB_CTRL_BUFFER_SIZE / 4))
|
|
{
|
|
const mv_t *mv = pMb->mv;
|
|
|
|
pMvCtrl = pMvCtrlBase;
|
|
|
|
switch (pMb->mbType_asic)
|
|
{
|
|
case P_Skip:
|
|
tmp = pMb->refID[0];
|
|
*pMvCtrl++ = tmp;
|
|
break;
|
|
|
|
case P_L0_16x16:
|
|
tmp = ((u32) (mv[0].hor & ASIC_HOR_MV_MASK)) << ASIC_HOR_MV_OFFSET;
|
|
tmp |= ((u32) (mv[0].ver & ASIC_VER_MV_MASK)) << ASIC_VER_MV_OFFSET;
|
|
tmp |= pMb->refID[0];
|
|
*pMvCtrl++ = tmp;
|
|
|
|
break;
|
|
case P_L0_L0_16x8:
|
|
tmp = ((u32) (mv[0].hor & ASIC_HOR_MV_MASK)) << ASIC_HOR_MV_OFFSET;
|
|
tmp |= ((u32) (mv[0].ver & ASIC_VER_MV_MASK)) << ASIC_VER_MV_OFFSET;
|
|
tmp |= pMb->refID[0];
|
|
|
|
*pMvCtrl++ = tmp;
|
|
|
|
tmp = ((u32) (mv[8].hor & ASIC_HOR_MV_MASK)) << ASIC_HOR_MV_OFFSET;
|
|
tmp |= ((u32) (mv[8].ver & ASIC_VER_MV_MASK)) << ASIC_VER_MV_OFFSET;
|
|
tmp |= pMb->refID[1];
|
|
|
|
*pMvCtrl++ = tmp;
|
|
|
|
break;
|
|
case P_L0_L0_8x16:
|
|
tmp = ((u32) (mv[0].hor & ASIC_HOR_MV_MASK)) << ASIC_HOR_MV_OFFSET;
|
|
tmp |= ((u32) (mv[0].ver & ASIC_VER_MV_MASK)) << ASIC_VER_MV_OFFSET;
|
|
tmp |= pMb->refID[0];
|
|
|
|
*pMvCtrl++ = tmp;
|
|
|
|
tmp = ((u32) (mv[4].hor & ASIC_HOR_MV_MASK)) << ASIC_HOR_MV_OFFSET;
|
|
tmp |= ((u32) (mv[4].ver & ASIC_VER_MV_MASK)) << ASIC_VER_MV_OFFSET;
|
|
tmp |= pMb->refID[1];
|
|
|
|
*pMvCtrl++ = tmp;
|
|
|
|
break;
|
|
case P_8x8:
|
|
case P_8x8ref0:
|
|
{
|
|
u32 i;
|
|
u32 subMbType = *pMbCtrl;
|
|
|
|
for(i = 0; i < 4; i++)
|
|
{
|
|
switch ((subMbType >> (u32) (27 - 2 * i)) & 0x03)
|
|
{
|
|
case MB_SP_8x8:
|
|
tmp =
|
|
((u32) ((*mv).hor & ASIC_HOR_MV_MASK)) <<
|
|
ASIC_HOR_MV_OFFSET;
|
|
tmp |=
|
|
((u32) ((*mv).ver & ASIC_VER_MV_MASK)) <<
|
|
ASIC_VER_MV_OFFSET;
|
|
tmp |= pMb->refID[i];
|
|
*pMvCtrl++ = tmp;
|
|
mv += 4;
|
|
break;
|
|
|
|
case MB_SP_8x4:
|
|
tmp =
|
|
((u32) ((*mv).hor & ASIC_HOR_MV_MASK)) <<
|
|
ASIC_HOR_MV_OFFSET;
|
|
tmp |=
|
|
((u32) ((*mv).ver & ASIC_VER_MV_MASK)) <<
|
|
ASIC_VER_MV_OFFSET;
|
|
tmp |= pMb->refID[i];
|
|
*pMvCtrl++ = tmp;
|
|
mv += 2;
|
|
|
|
tmp =
|
|
((u32) ((*mv).hor & ASIC_HOR_MV_MASK)) <<
|
|
ASIC_HOR_MV_OFFSET;
|
|
tmp |=
|
|
((u32) ((*mv).ver & ASIC_VER_MV_MASK)) <<
|
|
ASIC_VER_MV_OFFSET;
|
|
tmp |= pMb->refID[i];
|
|
*pMvCtrl++ = tmp;
|
|
mv += 2;
|
|
break;
|
|
|
|
case MB_SP_4x8:
|
|
tmp =
|
|
((u32) ((*mv).hor & ASIC_HOR_MV_MASK)) <<
|
|
ASIC_HOR_MV_OFFSET;
|
|
tmp |=
|
|
((u32) ((*mv).ver & ASIC_VER_MV_MASK)) <<
|
|
ASIC_VER_MV_OFFSET;
|
|
tmp |= pMb->refID[i];
|
|
*pMvCtrl++ = tmp;
|
|
mv++;
|
|
tmp =
|
|
((u32) ((*mv).hor & ASIC_HOR_MV_MASK)) <<
|
|
ASIC_HOR_MV_OFFSET;
|
|
tmp |=
|
|
((u32) ((*mv).ver & ASIC_VER_MV_MASK)) <<
|
|
ASIC_VER_MV_OFFSET;
|
|
tmp |= pMb->refID[i];
|
|
*pMvCtrl++ = tmp;
|
|
mv += 3;
|
|
|
|
break;
|
|
|
|
case MB_SP_4x4:
|
|
{
|
|
u32 j;
|
|
|
|
for(j = 4; j > 0; j--)
|
|
{
|
|
tmp =
|
|
((u32) ((*mv).hor & ASIC_HOR_MV_MASK)) <<
|
|
ASIC_HOR_MV_OFFSET;
|
|
tmp |=
|
|
((u32) ((*mv).ver & ASIC_VER_MV_MASK)) <<
|
|
ASIC_VER_MV_OFFSET;
|
|
tmp |= pMb->refID[i];
|
|
*pMvCtrl++ = tmp;
|
|
mv++;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
ASSERT(0);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Function name : PrepareIntra4x4ModeData
|
|
Description :
|
|
|
|
Return type : void
|
|
Argument : storage_t * pStorage
|
|
Argument : DecAsicBuffers_t * pAsicBuff
|
|
------------------------------------------------------------------------------*/
|
|
void PrepareIntra4x4ModeData(storage_t * pStorage, DecAsicBuffers_t * pAsicBuff)
|
|
{
|
|
u32 n;
|
|
u32 mbs = pStorage->picSizeInMbs;
|
|
u32 *pIntraPred, *pIntraPredBase = pAsicBuff->intraPred.virtualAddress;
|
|
const mbStorage_t *pMb = pStorage->mb;
|
|
|
|
if(pAsicBuff->wholePicConcealed != 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
/* write out "INTRA4x4 mode" to ASIC */
|
|
for(n = mbs; n > 0;
|
|
n--, pMb++, pIntraPredBase += (ASIC_MB_I4X4_BUFFER_SIZE / 4))
|
|
{
|
|
u32 tmp = 0, block;
|
|
|
|
pIntraPred = pIntraPredBase;
|
|
|
|
if(h264bsdMbPartPredMode(pMb->mbType_asic) != PRED_MODE_INTRA4x4)
|
|
continue;
|
|
|
|
for(block = 0; block < 16; block++)
|
|
{
|
|
u8 mode = pMb->intra4x4PredMode_asic[block];
|
|
|
|
tmp <<= 4;
|
|
tmp |= mode;
|
|
|
|
if(block == 7)
|
|
{
|
|
*pIntraPred++ = tmp;
|
|
tmp = 0;
|
|
}
|
|
}
|
|
*pIntraPred++ = tmp;
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Function name : PrepareRlcCount
|
|
Description :
|
|
Return type : void
|
|
Argument : storage_t * pStorage
|
|
Argument : DecAsicBuffers_t * pAsicBuff
|
|
------------------------------------------------------------------------------*/
|
|
void PrepareRlcCount(storage_t * pStorage, DecAsicBuffers_t * pAsicBuff)
|
|
{
|
|
u32 n;
|
|
u32 mbs = pStorage->picSizeInMbs;
|
|
u32 *pMbCtrl = pAsicBuff->mbCtrl.virtualAddress + 1;
|
|
|
|
if(pAsicBuff->wholePicConcealed != 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for(n = mbs - 1; n > 0; n--, pMbCtrl += (ASIC_MB_CTRL_BUFFER_SIZE / 4))
|
|
{
|
|
u32 tmp = (*(pMbCtrl + (ASIC_MB_CTRL_BUFFER_SIZE / 4))) << 4;
|
|
|
|
(*pMbCtrl) |= (tmp >> 23);
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Function name : H264RefreshRegs
|
|
Description :
|
|
Return type : void
|
|
Argument : decContainer_t * pDecCont
|
|
------------------------------------------------------------------------------*/
|
|
static void H264RefreshRegs(decContainer_t * pDecCont)
|
|
{
|
|
i32 i;
|
|
u32 offset = 0x0;
|
|
|
|
u32 *decRegs = pDecCont->h264Regs;
|
|
|
|
for(i = DEC_X170_REGISTERS; i > 0; --i)
|
|
{
|
|
*decRegs++ = DWLReadReg(pDecCont->dwl, offset);
|
|
offset += 4;
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Function name : H264FlushRegs
|
|
Description :
|
|
Return type : void
|
|
Argument : decContainer_t * pDecCont
|
|
------------------------------------------------------------------------------*/
|
|
static void H264FlushRegs(decContainer_t * pDecCont)
|
|
{
|
|
i32 i;
|
|
u32 offset = 0x04;
|
|
const u32 *decRegs = pDecCont->h264Regs + 1; /* Dont write ID reg */
|
|
|
|
#ifdef TRACE_START_MARKER
|
|
/* write ID register to trigger logic analyzer */
|
|
DWLWriteReg(pDecCont->dwl, 0x00, ~0);
|
|
#endif
|
|
|
|
for(i = DEC_X170_REGISTERS; i > 1; --i)
|
|
{
|
|
DWLWriteReg(pDecCont->dwl, offset, *decRegs);
|
|
decRegs++;
|
|
offset += 4;
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Function name : H264SetupVlcRegs
|
|
Description : set up registers for vlc mode
|
|
|
|
Return type :
|
|
Argument : container
|
|
------------------------------------------------------------------------------*/
|
|
void H264SetupVlcRegs(decContainer_t * pDecCont)
|
|
{
|
|
u32 tmp, i;
|
|
u32 longTermflags = 0;
|
|
u32 validFlags = 0;
|
|
u32 longTermTmp = 0;
|
|
i32 diffPoc, currPoc, itmp;
|
|
|
|
const seqParamSet_t *pSps = pDecCont->storage.activeSps;
|
|
const sliceHeader_t *pSliceHeader = pDecCont->storage.sliceHeader;
|
|
const picParamSet_t *pPps = pDecCont->storage.activePps;
|
|
const dpbStorage_t *pDpb = pDecCont->storage.dpb;
|
|
const storage_t *pStorage = &pDecCont->storage;
|
|
const u32 is8190 = pDecCont->is8190;
|
|
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_DEC_OUT_DIS, 0);
|
|
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_RLC_MODE_E, 0);
|
|
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_INIT_QP, pPps->picInitQp);
|
|
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_REFIDX0_ACTIVE,
|
|
pPps->numRefIdxL0Active);
|
|
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_REF_FRAMES, pSps->numRefFrames);
|
|
|
|
i = 0;
|
|
while(pSps->maxFrameNum >> i)
|
|
{
|
|
i++;
|
|
}
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_FRAMENUM_LEN, i - 1);
|
|
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_FRAMENUM, pSliceHeader->frameNum);
|
|
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_CONST_INTRA_E,
|
|
pPps->constrainedIntraPredFlag);
|
|
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_FILT_CTRL_PRES,
|
|
pPps->deblockingFilterControlPresentFlag);
|
|
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_RDPIC_CNT_PRES,
|
|
pPps->redundantPicCntPresentFlag);
|
|
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_REFPIC_MK_LEN,
|
|
pSliceHeader->decRefPicMarking.strmLen);
|
|
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_IDR_PIC_E,
|
|
IS_IDR_NAL_UNIT(pStorage->prevNalUnit));
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_IDR_PIC_ID, pSliceHeader->idrPicId);
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_PPS_ID, pStorage->activePpsId);
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_POC_LENGTH,
|
|
pSliceHeader->pocLengthHw);
|
|
|
|
/* reference picture flags */
|
|
|
|
/* TODO separate fields */
|
|
if(pSliceHeader->fieldPicFlag)
|
|
{
|
|
ASSERT(pDecCont->h264ProfileSupport != H264_BASELINE_PROFILE);
|
|
|
|
for(i = 0; i < 32; i++)
|
|
{
|
|
longTermTmp = pDpb->buffer[i / 2].status[i & 1] == 3;
|
|
longTermflags = longTermflags << 1 | longTermTmp;
|
|
|
|
tmp = h264bsdGetRefPicDataVlcMode(pDpb, i, 1) != NULL;
|
|
validFlags = validFlags << 1 | tmp;
|
|
}
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_REFER_LTERM_E, longTermflags);
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_REFER_VALID_E, validFlags);
|
|
}
|
|
else
|
|
{
|
|
for(i = 0; i < 16; i++)
|
|
{
|
|
u32 n = is8190 ? i : pStorage->dpb[0].list[i];
|
|
|
|
longTermTmp = pDpb->buffer[n].status[0] == 3 &&
|
|
pDpb->buffer[n].status[1] == 3;
|
|
longTermflags = longTermflags << 1 | longTermTmp;
|
|
|
|
tmp = h264bsdGetRefPicDataVlcMode(pDpb, n, 0) != NULL;
|
|
validFlags = validFlags << 1 | tmp;
|
|
}
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_REFER_LTERM_E,
|
|
longTermflags << 16);
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_REFER_VALID_E,
|
|
validFlags << 16);
|
|
}
|
|
|
|
if(pSliceHeader->fieldPicFlag)
|
|
{
|
|
currPoc = pStorage->poc->picOrderCnt[pSliceHeader->bottomFieldFlag];
|
|
}
|
|
else
|
|
{
|
|
currPoc = MIN(pStorage->poc->picOrderCnt[0],
|
|
pStorage->poc->picOrderCnt[1]);
|
|
}
|
|
for(i = 0; i < 16; i++)
|
|
{
|
|
u32 n = is8190 ? i : pDpb->list[i];
|
|
|
|
if(pDpb->buffer[n].status[0] == 3 || pDpb->buffer[n].status[1] == 3)
|
|
{
|
|
SetDecRegister(pDecCont->h264Regs, refPicNum[i],
|
|
pDpb->buffer[n].picNum);
|
|
}
|
|
else
|
|
{
|
|
SetDecRegister(pDecCont->h264Regs, refPicNum[i],
|
|
pDpb->buffer[n].frameNum);
|
|
}
|
|
diffPoc = ABS(pDpb->buffer[i].picOrderCnt[0] - currPoc);
|
|
itmp = ABS(pDpb->buffer[i].picOrderCnt[1] - currPoc);
|
|
|
|
pDecCont->asicBuff->refPicList[i] |=
|
|
(diffPoc < itmp ? 0x1 : 0) | (pDpb->buffer[i].isFieldPic ? 0x2 : 0);
|
|
|
|
}
|
|
|
|
if(pDecCont->h264ProfileSupport != H264_BASELINE_PROFILE)
|
|
{
|
|
if(pDecCont->asicBuff->enableDmvAndPoc)
|
|
{
|
|
u32 *pocBase;
|
|
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_PICORD_COUNT_E, 1);
|
|
pocBase =
|
|
(u32 *) ((u8 *) pDecCont->asicBuff->cabacInit.virtualAddress +
|
|
ASIC_CABAC_INIT_BUFFER_SIZE);
|
|
for(i = 0; i < 32; i++)
|
|
{
|
|
*pocBase++ = pDpb->buffer[i / 2].picOrderCnt[i & 0x1];
|
|
}
|
|
|
|
if(pSliceHeader[0].fieldPicFlag || !pSps->mbAdaptiveFrameFieldFlag)
|
|
{
|
|
*pocBase++ = currPoc;
|
|
}
|
|
else
|
|
{
|
|
*pocBase++ = pStorage->poc->picOrderCnt[0];
|
|
*pocBase++ = pStorage->poc->picOrderCnt[1];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_PICORD_COUNT_E, 0);
|
|
}
|
|
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_CABAC_E,
|
|
pPps->entropyCodingModeFlag);
|
|
}
|
|
|
|
h264StreamPosUpdate(pDecCont);
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Function name : H264InitRefPicList1
|
|
Description :
|
|
Return type : void
|
|
Argument : decContainer_t *pDecCont
|
|
Argument : u32 *list0
|
|
Argument : u32 *list1
|
|
------------------------------------------------------------------------------*/
|
|
void H264InitRefPicList1(decContainer_t * pDecCont, u32 * list0, u32 * list1)
|
|
{
|
|
u32 tmp, i;
|
|
u32 idx, idx0, idx1, idx2;
|
|
i32 refPoc;
|
|
const storage_t *pStorage = &pDecCont->storage;
|
|
const dpbPicture_t *pic;
|
|
|
|
refPoc = MIN(pStorage->poc->picOrderCnt[0], pStorage->poc->picOrderCnt[1]);
|
|
i = 0;
|
|
|
|
pic = pStorage->dpb->buffer;
|
|
while(IS_SHORT_TERM_FRAME(pic[list0[i]]) &&
|
|
MIN(pic[list0[i]].picOrderCnt[0], pic[list0[i]].picOrderCnt[1]) <
|
|
refPoc)
|
|
i++;
|
|
|
|
idx0 = i;
|
|
|
|
while(IS_SHORT_TERM_FRAME(pic[list0[i]]))
|
|
i++;
|
|
|
|
idx1 = i;
|
|
|
|
while(IS_LONG_TERM_FRAME(pic[list0[i]]))
|
|
i++;
|
|
|
|
idx2 = i;
|
|
|
|
/* list L1 */
|
|
for(i = idx0, idx = 0; i < idx1; i++, idx++)
|
|
list1[idx] = list0[i];
|
|
|
|
for(i = 0; i < idx0; i++, idx++)
|
|
list1[idx] = list0[i];
|
|
|
|
for(i = idx1; idx < 16; idx++, i++)
|
|
list1[idx] = list0[i];
|
|
|
|
if(idx2 > 1)
|
|
{
|
|
tmp = 0;
|
|
for(i = 0; i < idx2; i++)
|
|
{
|
|
tmp += (list0[i] != list1[i]) ? 1 : 0;
|
|
}
|
|
/* lists are equal -> switch list1[0] and list1[1] */
|
|
if(!tmp)
|
|
{
|
|
i = list1[0];
|
|
list1[0] = list1[1];
|
|
list1[1] = i;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Function name : H264InitRefPicList1F
|
|
Description :
|
|
Return type : void
|
|
Argument : decContainer_t *pDecCont
|
|
Argument : u32 *list0
|
|
Argument : u32 *list1
|
|
------------------------------------------------------------------------------*/
|
|
void H264InitRefPicList1F(decContainer_t * pDecCont, u32 * list0, u32 * list1)
|
|
{
|
|
u32 i;
|
|
u32 idx, idx0, idx1;
|
|
i32 refPoc;
|
|
const storage_t *pStorage = &pDecCont->storage;
|
|
const dpbPicture_t *pic;
|
|
|
|
refPoc =
|
|
pStorage->poc->picOrderCnt[pStorage->sliceHeader[0].bottomFieldFlag];
|
|
i = 0;
|
|
|
|
pic = pStorage->dpb->buffer;
|
|
while(IS_SHORT_TERM_FRAME_F(pic[list0[i]]) &&
|
|
FIELD_POC(pic[list0[i]]) <= refPoc)
|
|
i++;
|
|
|
|
idx0 = i;
|
|
|
|
while(IS_SHORT_TERM_FRAME_F(pic[list0[i]]))
|
|
i++;
|
|
|
|
idx1 = i;
|
|
|
|
/* list L1 */
|
|
for(i = idx0, idx = 0; i < idx1; i++, idx++)
|
|
list1[idx] = list0[i];
|
|
|
|
for(i = 0; i < idx0; i++, idx++)
|
|
list1[idx] = list0[i];
|
|
|
|
for(i = idx1; idx < 16; idx++, i++)
|
|
list1[idx] = list0[i];
|
|
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Function name : H264InitRefPicList
|
|
Description :
|
|
Return type : void
|
|
Argument : decContainer_t *pDecCont
|
|
------------------------------------------------------------------------------*/
|
|
void H264InitRefPicList(decContainer_t * pDecCont)
|
|
{
|
|
sliceHeader_t *pSliceHeader = pDecCont->storage.sliceHeader;
|
|
pocStorage_t *poc = pDecCont->storage.poc;
|
|
dpbStorage_t *dpb = pDecCont->storage.dpb;
|
|
u32 i;
|
|
u32 list0[34] =
|
|
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
|
|
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33
|
|
};
|
|
u32 list1[34] =
|
|
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
|
|
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33
|
|
};
|
|
u32 listP[34] =
|
|
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
|
|
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33
|
|
};
|
|
|
|
/* B lists */
|
|
if(!pDecCont->rlcMode)
|
|
{
|
|
if(pSliceHeader->fieldPicFlag)
|
|
{
|
|
/* list 0 */
|
|
ShellSortF(dpb, list0, 1,
|
|
poc->picOrderCnt[pSliceHeader->bottomFieldFlag]);
|
|
/* list 1 */
|
|
H264InitRefPicList1F(pDecCont, list0, list1);
|
|
for(i = 0; i < 16; i++)
|
|
{
|
|
SetDecRegister(pDecCont->h264Regs, refPicList0[i], list0[i]);
|
|
SetDecRegister(pDecCont->h264Regs, refPicList1[i], list1[i]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* list 0 */
|
|
ShellSort(dpb, list0, 1,
|
|
MIN(poc->picOrderCnt[0], poc->picOrderCnt[1]));
|
|
/* list 1 */
|
|
H264InitRefPicList1(pDecCont, list0, list1);
|
|
for(i = 0; i < 16; i++)
|
|
{
|
|
SetDecRegister(pDecCont->h264Regs, refPicList0[i], list0[i]);
|
|
SetDecRegister(pDecCont->h264Regs, refPicList1[i], list1[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* P list */
|
|
if(pSliceHeader->fieldPicFlag)
|
|
{
|
|
if(!pDecCont->rlcMode)
|
|
{
|
|
ShellSortF(dpb, listP, 0, 0);
|
|
for(i = 0; i < 16; i++)
|
|
{
|
|
SetDecRegister(pDecCont->h264Regs, refPicListP[i], listP[i]);
|
|
|
|
/* copy to dpb for error handling purposes */
|
|
dpb[0].list[i] = listP[i];
|
|
dpb[1].list[i] = listP[i];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ShellSort(dpb, listP, 0, 0);
|
|
for(i = 0; i < 16; i++)
|
|
{
|
|
if(!pDecCont->rlcMode)
|
|
SetDecRegister(pDecCont->h264Regs, refPicListP[i], listP[i]);
|
|
/* copy to dpb for error handling purposes */
|
|
dpb[0].list[i] = listP[i];
|
|
dpb[1].list[i] = listP[i];
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Function name : h264StreamPosUpdate
|
|
Description : Set stream base and length related registers
|
|
|
|
Return type :
|
|
Argument : container
|
|
------------------------------------------------------------------------------*/
|
|
void h264StreamPosUpdate(decContainer_t * pDecCont)
|
|
{
|
|
u32 tmp;
|
|
|
|
DEBUG_PRINT(("h264StreamPosUpdate:\n"));
|
|
tmp = 0;
|
|
|
|
/* NAL start prefix in stream start is 0 0 0 or 0 0 1 */
|
|
if(!(*pDecCont->pHwStreamStart + *(pDecCont->pHwStreamStart + 1)))
|
|
{
|
|
if(*(pDecCont->pHwStreamStart + 2) < 2)
|
|
{
|
|
tmp = 1;
|
|
}
|
|
}
|
|
|
|
DEBUG_PRINT(("\tByte stream %8d\n", tmp));
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_START_CODE_E, tmp);
|
|
|
|
/* bit offset if base is unaligned */
|
|
tmp = (pDecCont->hwStreamStartBus & DEC_X170_ALIGN_MASK) * 8;
|
|
|
|
DEBUG_PRINT(("\tStart bit pos %8d\n", tmp));
|
|
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_STRM_START_BIT, tmp);
|
|
|
|
pDecCont->hwBitPos = tmp;
|
|
|
|
tmp = pDecCont->hwStreamStartBus; /* unaligned base */
|
|
tmp &= (~DEC_X170_ALIGN_MASK); /* align the base */
|
|
|
|
DEBUG_PRINT(("\tStream base %08x\n", tmp));
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_RLC_VLC_BASE, tmp);
|
|
|
|
tmp = pDecCont->hwLength; /* unaligned stream */
|
|
tmp += pDecCont->hwBitPos / 8; /* add the alignmet bytes */
|
|
|
|
DEBUG_PRINT(("\tStream length %8d\n", tmp));
|
|
SetDecRegister(pDecCont->h264Regs, HWIF_STREAM_LEN, tmp);
|
|
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Function name : H264PrepareCabacInitTables
|
|
Description : Prepare CABAC initialization tables
|
|
|
|
Return type : void
|
|
Argument : DecAsicBuffers_t * pAsicBuff
|
|
------------------------------------------------------------------------------*/
|
|
void H264PrepareCabacInitTables(DecAsicBuffers_t * pAsicBuff)
|
|
{
|
|
ASSERT(pAsicBuff->cabacInit.virtualAddress != NULL);
|
|
(void) DWLmemcpy(pAsicBuff->cabacInit.virtualAddress,
|
|
cabacInitValues, 4 * 460 * 2);
|
|
}
|