/* SPDX-License-Identifier: LGPL-2.1-only OR BSD-3-Clause */
/******************************************************************************
 *
 * This file is provided under a dual license.  When you use or
 * distribute this software, you may choose to be licensed under
 * version 2.1 of the GNU Lesser General Public License
 * ("LGPLv2.1 License") or BSD License.
 *
 * LGPLv2.1 License
 *
 * Copyright(C) 2019 MediaTek Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of version 2.1 of the GNU Lesser General Public
 * License as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html for more
 * details.
 *
 * BSD LICENSE
 *
 * Copyright(C) 2019 MediaTek Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *  * Neither the name of the copyright holder nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *****************************************************************************/

#ifndef _VDEC_SHARE_IF_H_
#define _VDEC_SHARE_IF_H_

#include "vdec_val_info.h"

#define VDEC_ALIGN(value, mask)     ((value + mask -1) & (~(mask -1)))
#define VDEC_CLRFLG(flg,index) ((flg) &= ~(1<<(index)))
#define VDEC_SETFLG(flg,index) ((flg) |= (1<<(index)))
#define VDEC_ISSET(flg,index) (((flg)>>(index))&1)
#define VDEC_SETFLG_COND(flg,index,cond) ((cond) ? VDEC_SETFLG(flg,index) : VDEC_CLRFLG(flg,index))


typedef enum {
    // invalid parameter
    VDEC_RET_INVAL = -5,
    // not implemented
    VDEC_RET_NOT_IMPL = -4,
    // out of memory
    VDEC_RET_NO_MEM = -3,
    // no permission
    VDEC_RET_NO_PERM = -2,
    // general fail
    VDEC_RET_FAIL = -1,
    // success
    VDEC_RET_OK,
}VdecRetValue;

typedef enum
{
    //Core
    IC_ES1 = 1,
    IC_ES2,
    IC_ES3,

} VdecSubVersion;

typedef enum
{
    //Core
    VDEC_VLD0 = 0,
    VDEC_VLD1,
    VDEC_VLD2,
    VDEC_CORE_COUNT,

    //LAT
    VDEC_LAT0 = VDEC_CORE_COUNT,
    VDEC_LAT1,
    VDEC_SOC,
    VDEC_HW_COUNT
} VdecCoreId;

typedef struct _VdecHalComParam_ {
    UCHAR mCoreId;
    UCHAR mCoreId2;

	union {
    	BOOL mUfoEnable;
    	// 0 ufo off
    	// 1 ufo on
    	// 2 ufo bypass
    	UCHAR ucUfo;
    };
    BOOL mJumpModeEnable;

    union {
        BOOL bMCore;
        // support single core/mcore/tricore
        UCHAR mMCore;
    };
    union {
		BOOL fgLaxMCore;
        // support single core/mcore/tricore
        UCHAR mLaxMCore;
    };
    BOOL mLatSCore;
    BOOL mMLat;
    BOOL fgBeGCE;
} VdecHalComParam;

typedef struct _VDEC_BS_FIFO_T_
{
    union {
        UPTR u4FifoStart;
        UINT64 u4FifoStartPadding;
    };
    union {
        UPTR u4FifoEnd;
        UINT64 u4FifoEndPadding;
    };
    union {
        UPTR u4VldReadPtr;
        UINT64 u4VldReadPtrPadding;
    };
    union {
        UPTR u4VldReadPtrEnd;
        UINT64 u4VldReadPtrEndPadding;
    };
    union {
        UPTR u4DmxWritePtr;
        UINT64 u4DmxWritePtrPadding;
    };
    BOOL fgAnnexB;   //for av1
    UINT32 u4FrameSize; //for av1
} VDEC_BS_FIFO_T;

static INLINE MAYBE_UNUSED VOID vVDecHalInitBsFifoPtr(VDEC_BS_FIFO_T *prBsFifo, UPTR u4FifoStart, UPTR u4FifoEnd, UPTR u4VldReadPtr, UPTR u4VldReadPtrEnd, UPTR u4DmxWritePtr)
{
    prBsFifo->u4FifoStart = u4FifoStart;
    prBsFifo->u4FifoEnd = u4FifoEnd;
    prBsFifo->u4VldReadPtr = u4VldReadPtr;
    prBsFifo->u4VldReadPtrEnd = u4VldReadPtrEnd;
    prBsFifo->u4DmxWritePtr = u4DmxWritePtr;
}

typedef struct VDEC_LAX_BUF_INFO_T
{
    union {
        UPTR upTRSAddr;
        UINT64 upTRSAddrPadding;
    };
    union {
        UPTR upTRSAddrEnd;
        UINT64 upTRSAddrEndPadding;
    };
    union {
        UPTR upUBESa;
        UINT64 upUBESaPadding;
    };
    union {
        UPTR upUBEEa;
        UINT64 upUBEEaPadding;
    };
    union {
        UPTR upWPtrOffset;
        UINT64 upWPtrOffsetPadding;
    };
    union {
        UPTR upRPtrOffset;
        UINT64 upRPtrOffsetPadding;
    };
    union {
        UPTR upTRS1Addr;
        UINT64 upTRS1AddrPadding;
    };
    union {
        UPTR upTRS1AddrEnd;
        UINT64 upTRS1AddrEndPadding;
    };
    union {
        UPTR upUBE1Sa;
        UINT64 upUBE1SaPadding;
    };
    union {
        UPTR upUBE1Ea;
        UINT64 upUBE1EaPadding;
    };
    union {
        UPTR upWPtr1Offset;
        UINT64 upWPtr1OffsetPadding;
    };
    union {
        UPTR upRPtr1Offset;
        UINT64 upRPtr1OffsetPadding;
    };
    union {
        UPTR upSliceHdrAddr;
        UINT64 upSliceHdrAddrPadding;
    };
    union {
        UPTR upErrMapAddr;
        UINT64 upErrMapAddrPadding;
    };
    union {
        UPTR upRowInfoAddr;
        UINT64 upRowInfoAddrPadding;
    };
    union {
        UPTR upColRdMvAddr;
        UINT64 upColRdMvAddrPadding;   //for av1
    };

    UINT32 u4TRSSize;
    UINT32 u4SliceHdrSize;
    UINT32 u4ErrMapSize;
    UINT32 u4RowInfoSize;
    UINT32 u4ColRdSize;

    BOOL fgIsUBEEnable;
} VDEC_LAX_BUF_INFO_T;

typedef struct _RBSP_BitStream_ {
    UCHAR *pStartBuff;
    UCHAR *pEndBuff;
    UINT32 u4Cache;
    UINT32 u4Cache1;
    UINT32 u4BitLeft;
    UINT32 u4BitLeft1;
    UINT32 u4ByteLeft;
    UINT32 u4BitAccumulated;
    UINT32 u4BitTotalBuffBitCount;
    BOOL   bError;
//    FILE *pfLogFile;
} RBSP_BitStream, *pRBSP_BitStream;

struct _VDEC_BARREL_SHIFTER_T_;

typedef struct _BARREL_SHIFTER_OPS_T_
{
    INT32 (*InitFifo)(struct _VDEC_BARREL_SHIFTER_T_ *prBs, VOID *pvStart, VOID *pvEnd, VOID *pvRdPtr);

    INT32 (*WaitBsDone)(struct _VDEC_BARREL_SHIFTER_T_ *prBs);

    UINT32 (*ReadRdPtr)(struct _VDEC_BARREL_SHIFTER_T_ *prBs, UPTR upFifoStart, UINT32 *pu4Bits);
    UINT32 (*ReadInputWindow)(struct _VDEC_BARREL_SHIFTER_T_ *prBs);

    UINT32 (*GetBits)(struct _VDEC_BARREL_SHIFTER_T_ *prBs, UINT32 u4Bit);
    UINT32 (*GetUE)(struct _VDEC_BARREL_SHIFTER_T_ *prBs);
    INT32 (*GetSE)(struct _VDEC_BARREL_SHIFTER_T_ *prBs);

    VOID (*TrailingBits)(struct _VDEC_BARREL_SHIFTER_T_ *prBs);
    VOID (*ByteAlign)(struct _VDEC_BARREL_SHIFTER_T_ *prBs);
    INT32 (*ByteAligned)(struct _VDEC_BARREL_SHIFTER_T_ *prBs);
    BOOL (*IsMoreData)(struct _VDEC_BARREL_SHIFTER_T_ *prBs);

    UINT32 (*ReadErrorType)(struct _VDEC_BARREL_SHIFTER_T_ *prBs);
} BARREL_SHIFTER_OPS_T;

// VDEC barrel shifter
typedef struct _VDEC_BARREL_SHIFTER_T_
{
    // for custom barrel shifter, maybe software barrel shifter
    BARREL_SHIFTER_OPS_T *mOps;

    // barrel shifter's context
    VOID *mContext;

    // backup hal's core
    //UCHAR ucCoreId;
    //UCHAR ucCoreId2;
    //BOOL fgMCore;

    // software context
    //RBSP_BitStream rRBSPBitStream;
} VDEC_BARREL_SHIFTER_T;

typedef struct _RbspBs_ {
    struct _VDEC_BARREL_SHIFTER_T_ mBs;
    RBSP_BitStream mRbsp;
} RbspBs;

#define GCE_MAP_EVENT(CoreId, Event) ((Event))

#define VDEC_GCE_THREAD_MAX   (3)
#define VDEC_GCE_SUBSYS_MAX   (4)
#define VDEC_GCE_EVENT_MAX    (16)


enum vdec_gce_subsys_id{
    VDEC_SUBSYS_SOC,
    VDEC_SUBSYS_LAT,
    VDEC_SUBSYS_CORE0,
    VDEC_SUBSYS_CORE1,
    VDEC_SUBSYS_CORE2,
};

typedef enum _vdec_gce_submodule_{
    CMDQ_VDEC_VLD,
    CMDQ_VDEC_HEVC_VLD,
    CMDQ_VDEC_AVC_VLD,
    CMDQ_VDEC_VP9_VLD,
    CMDQ_VDEC_AV1_VLD,
    CMDQ_VDEC_BS2,
    CMDQ_VDEC_VLD_TOP,
    CMDQ_VDEC_PP,
    CMDQ_VDEC_MC,
    CMDQ_VDEC_MV,
    CMDQ_VDEC_MISC,
    CMDQ_VDEC_MCORE_TOP,
    CMDQ_VDEC_MCORE_UFO_ENC,
    CMDQ_VDEC_GLOBAL_CON,
    CMDQ_VDEC_LAT_TOP,
    CMDQ_VDEC_LAT_WDMA,
    CMDQ_VDEC_VP6,
    CMDQ_VDEC_AVS,
    CMDQ_VDEC_VP8,
    CMDQ_VDEC_MBIST,
    CMDQ_VDEC_WRAP_TOP,
}VDEC_SUBMODULE;

struct _VDEC_HW_OPS_T_;
typedef struct _VDEC_HW_OPS_T_ VDEC_HW_OPS_T;
struct _VDEC_VIRT_HW_T_;
typedef struct _VDEC_VIRT_HW_T_ VDEC_VIRT_HW_T;

struct _VDEC_HW_OPS_T_ {
    // only for risc
    UINT32 (*Read)(VDEC_VIRT_HW_T *prHw, UINT32 u4CoreId, UINT32 u4SubModule,  UINT32 u4Reg, UINT32 u4Addr);

    INT32 (*Write)(VDEC_VIRT_HW_T *prHw, UINT32 u4CoreId, UINT32 u4SubModule,  UINT32 u4Reg, UINT32 u4Addr, UINT32 u4Val);
    INT32 (*WriteMask)(VDEC_VIRT_HW_T *prHw, UINT32 u4CoreId, UINT32 u4SubModule,  UINT32 u4Reg, UINT32 u4Addr, UINT32 u4Val, UINT32 u4Mask);

    // take care of virtual and physical address ...
    // take care of 32/64 bit address
    INT32 (*Load)(VDEC_VIRT_HW_T *prHw, UINT32 u4CoreId, UINT32 u4SubModule,  UINT32 u4Reg, UINT32 u4Addr, UINT32 *pu4Val);
    INT32 (*LoadMask)(VDEC_VIRT_HW_T *prHw, UINT32 u4CoreId, UINT32 u4SubModule,  UINT32 u4Reg, UINT32 u4Addr, UINT32 *pu4Val, UINT32 u4Mask);

    //INT32 (*EnableEvent)(UINT32 u4CoreId);
    //INT32 (*DisableEvent)(UINT32 u4CoreId);
    INT32 (*ClearEvent)(VDEC_VIRT_HW_T *prHw, UINT32 u4CoreId, UINT32 u4Event);
    INT32 (*Wfe)(VDEC_VIRT_HW_T *prHw, UCHAR ucBSID, UCHAR ucHwId, UINT32 u4Event, UINT32 u4SubCategory);
    //INT32 (*WfeSramStable)(VDEC_VIRT_HW_T *prHw, UINT32 u4CoreId);
    // risc implementation has virtual hw event
    // gce and dram implementations have real hw event
    //INT32 (*VirtualEvent)(UINT32 u4CoreId, VDEC_VIRT_HW_T *prHw);
};

struct _VDEC_VIRT_HW_T_ {
    VDEC_HW_OPS_T *prOps;
    VOID *pvData;
    INT32 i4TriggerEvent;
    INT32 i4ImmediateMode;
    INT32 i4Resv;
};

#define HW_CMD_OP_CODE_MASK 0x1
#define HW_CMD_OP_CODE_READ 0x2
#define HW_CMD_OP_CODE_WRITE 0x3
#define HW_CMD_OP_CODE_WRITE_MASK 0x4
#define HW_CMD_OP_CODE_LOAD 0x5
#define HW_CMD_OP_CODE_LOAD_MASK 0x6
#define HW_CMD_OP_CODE_WFE 0x7
#define HW_CMD_OP_CODE_CLEAR_EVENT 0x8
#define HW_CMD_OP_CODE_ADDR 0x9

typedef struct _VDEC_HW_CMD_BUF_T_ {
    // command count
    UINT32 u4Cnt;
    UCHAR *pucCmdStart;
    UCHAR *pucCmdPtr;
    UCHAR *pucCmdEnd;
} VDEC_HW_CMD_BUF_T;


INT32 i4VDecInitBsFifo(VDEC_BARREL_SHIFTER_T *prBs, VOID *pvStart, VOID *pvEnd, VOID *pvRdPtr);
INT32 i4VDecWaitBsDone(VDEC_BARREL_SHIFTER_T *prBs);
UINT32 u4VDecReadRdPtr(VDEC_BARREL_SHIFTER_T *prBs, UPTR upFifoStart, UINT32 *pu4Bits);
UINT32 u4VDecReadInputWindow(VDEC_BARREL_SHIFTER_T *prBs);
UINT32 u4VDecGetBits(VDEC_BARREL_SHIFTER_T *prBs, UINT32 u4Bits);
UINT32 u4VDecGetUE(VDEC_BARREL_SHIFTER_T *prBs);
INT32 i4VDecGetSE(VDEC_BARREL_SHIFTER_T *prBs);
VOID vVDecTrailingBits(VDEC_BARREL_SHIFTER_T *prBs);
VOID vVDecByteAlign(VDEC_BARREL_SHIFTER_T *prBs);
INT32 i4VDecByteAligned(VDEC_BARREL_SHIFTER_T *prBs);
BOOL fgVDecMoreData(VDEC_BARREL_SHIFTER_T *prBs);

UINT32 u4VDecReadErrorType(VDEC_BARREL_SHIFTER_T *prBs);

VOID vVDecHalInitBs(VDEC_BARREL_SHIFTER_T *bs, BARREL_SHIFTER_OPS_T *ops, VOID *context);
VOID vVDecHalInitRbspBs(RbspBs *rbspBs);
VDEC_BARREL_SHIFTER_T *vdecGetRbspBs(RbspBs *rbspBs);

static INLINE MAYBE_UNUSED UPTR upVDecGetStartcodePtr(UPTR upFifoStart, UPTR upFifoEnd, UPTR upReadPtr, INT32 upOffset)
{
    UPTR upStartcodePtr = 0;

    // move backward @upOffset bytes to -> 00 00 01 26
    upStartcodePtr = upReadPtr - upOffset;

    // ring case
    if (upStartcodePtr < upFifoStart) {
        if((upFifoEnd <= upFifoStart) || (upFifoEnd <= upFifoStart + upOffset))
        {
            LOG(0,"---receive address 0x%lx, 0x%lx,0x%lx,0x%x\n---",upFifoStart, upFifoEnd, upStartcodePtr, upOffset);
        }
        upStartcodePtr += (upFifoEnd - upFifoStart);
    } else if (upStartcodePtr >= upFifoEnd) {
        if(upFifoEnd <= upFifoStart)
        {
            LOG(0,"---!!!receive address 0x%lx, 0x%lx,0x%lx,0x%x\n!!!---",upFifoStart, upFifoEnd, upStartcodePtr, upOffset);
        }
        upStartcodePtr -= (upFifoEnd - upFifoStart);
    }

    return upStartcodePtr;
}

#endif
