/* 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 _DRV_W2DR2R_H_
#define _DRV_W2DR2R_H_
#include "typedef.h"
#include "x_timer.h"

//-----------------------------------------------------------------------------
// Constant definitions
//-----------------------------------------------------------------------------
#define W2DR2R_HW_SUPPORT_FRAME_CNT 6
#define R2R_CRC_MON_MAX_RECORD 10
#define W2DR2R_VERIFY_R2R_OVERLAP 0

//-----------------------------------------------------------------------------
// Typedef
//-----------------------------------------------------------------------------
typedef enum
{
    W2DR2R_CHANNEL_Y,
    W2DR2R_CHANNEL_C,
    W2DR2R_CHANNEL_MAX
}E_W2DR2R_CHANNEL;

typedef enum
{
    R2R_PATTERN_PURE_COLOR,
    R2R_PATTERN_MOVING_LINE,
    R2R_PATTERN_STATIC_LINE,
    R2R_PATTERN_MAX
}E_R2R_PATTERN_TYPE;

typedef struct _R2R_PATTERN_COLOR
{
    UINT16 u2YLeft;
    UINT16 u2CLeft;
    UINT16 u2YRight;
    UINT16 u2CRight;
}R2R_PATTERN_COLOR;

typedef struct _W2DR2R_TIMING_INFO
{
/*H parameters, should be half of input timing for left and right implement.
   e.g input 8K,set 4K parameters here*/
    UINT32 u4HActive;
    UINT32 u4HTotal;
    UINT32 u4HBP;
    UINT32 u4HSyncWidth;
/*H parameters end*/
    UINT32 u4VActive;
    UINT32 u4VTotal;
    UINT32 u4VBP;
    UINT32 u4VSyncWidth;
    UINT8  u1ColorDepth;
}W2DR2R_TIMING_INFO;

typedef enum
{
    R2R_LOG_EN_ISR_TIME,
    W2D_LOG_EN_ISR_TIME,
    W2DR2R_LOG_ENABLE_MAX
}E_W2DR2R_LOG_ENABLE;

typedef enum
{
    R2R_DBG_EN_ISR_TIME_MON,
    R2R_DBG_EN_CRC_MON,
    W2D_DBG_EN_ISR_TIME_MON,
    W2D_DBG_EN_ADDR_IDX_DIFF_MON,
    R2R_DBG_EN_ADDR_IDX_DIFF_MON,
    W2DR2R_DBG_OPT_MAX
}E_W2DR2R_DBG_OPTION;

typedef struct _W2DR2R_CONTROL_CONTEXT
{
    UINT8 u1W2D0HDMIPort;
    UINT8 u1W2D1HDMIPort;
    BOOL fgW2DIsR2RFeed;
    BOOL fgW2DIs420Mode;
    BOOL fgR2RIs420Mode;
    BOOL fgW2D420ModeSelEven;
    BOOL fgR2R420ModeSelEven;
    UINT32 u4R2ROverLapPixel;
    BOOL fgW2DDropLine;
    BOOL fgW2DDropLineSelEven;
    UINT32 au4W2DFrameSize[W2DR2R_CHANNEL_MAX];
    UINT32 au4R2RFrameSize[W2DR2R_CHANNEL_MAX];
    BOOL fgW2DLeftRight;
    BOOL fgR2RLeftRight;
    UINT32 u4W2DCutHActive;
    UINT8 u1W2DFrameCnt;
    UINT8 u1R2RFrameCnt;
    UINT8 u1R2RDelayFrameCnt;
    UINT8 u1R2RRepeatFrames;
    W2DR2R_TIMING_INFO tW2DTimingInfo;
    W2DR2R_TIMING_INFO tR2RTimingInfo;
    HAL_TIME_T tW2DR2RSettingTime;
    /*----------------W2DR2R DEBUG--BEGIN-----------------*/
    /*ISR time monitor--BEGIN*/
    HAL_TIME_T tR2RLastIsrTime;
    UINT32 u4MaxR2RIsrDiffTime;
    UINT32 u4MinR2RIsrDiffTime;
    HAL_TIME_T tW2DLastIsrTime;
    UINT32 u4MaxW2DIsrDiffTime;
    UINT32 u4MinW2DIsrDiffTime;
    /*ISR time monitor--END*/
    /*R2R CRC monitor--BEGIN*/
    UINT32 au4R2RCRC[R2R_CRC_MON_MAX_RECORD];
    UINT32 u4R2RCRCMonCount;
    UINT32 u4R2RCRCMonIdx;
    /*R2R CRC monitor--END*/
    /*Addr idx monitor--BEGIN*/
    UINT8 u1W2DLeftAddrIdx;
    UINT8 u1W2DRightAddrIdx;
    UINT8 u1R2RAddrIdx;
    UINT8 u1W2DLeftAddrIdxMaxDiff;
    UINT8 u1W2DLeftAddrIdxMinDiff;
    UINT8 u1W2DRightAddrIdxMaxDiff;
    UINT8 u1W2DRightAddrIdxMinDiff;
    UINT8 u1R2RAddrIdxMaxDiff;
    UINT8 u1R2RAddrIdxMinDiff;
    /*Addr idx monitor--END*/
    BOOL afgLogEnable[W2DR2R_LOG_ENABLE_MAX];
    BOOL afgDbgOpt[W2DR2R_DBG_OPT_MAX];
    /*----------------W2DR2R DEBUG--END-----------------*/
}W2DR2R_CONTROL_CONTEXT;

//-----------------------------------------------------------------------------
// Function declaration
//-----------------------------------------------------------------------------
/**
 * @brief Set input timing info for W2D
 * @param prW2DTimingInfo Pointer to timing info
*/
extern void vW2DSetTimingInfo(W2DR2R_TIMING_INFO *prW2DTimingInfo);
/**
 * @brief Get current W2D timing info
 * @param prW2DTimingInfo Pointer to timing info
*/
extern void vW2DGetCurrentTimingInfo(W2DR2R_TIMING_INFO *prW2DTimingInfo);
/**
 * @brief Set output timing info for R2R
 * @param prR2RTimingInfo Pointer to timing info
*/
extern void vR2RSetTimingInfo(W2DR2R_TIMING_INFO *prR2RTimingInfo);
/**
 * @brief Get current R2R timing info
 * @param prR2RTimingInfo Pointer to timing info
*/
extern void vR2RGetCurrentTimingInfo(W2DR2R_TIMING_INFO *prR2RTimingInfo);
/**
 * @brief Set W2D left and right flag
 * @param fgLeftRight TRUE for W2D use left and right both, FALSE for W2D use left only
*/
extern void vW2DSetLeftRight(BOOL fgLeftRight);
/**
 * @brief Get W2D left and right flag
 * @retval TRUE for W2D use left and right both, FALSE for W2D use left only
*/
extern BOOL fgW2DLeftRight(void);
/**
 * @brief Set R2R left and right flag
 * @param fgLeftRight TRUE for R2R use left and right both, FALSE for R2R use left only
*/
extern void vR2RSetLeftRight(BOOL fgLeftRight);
/**
 * @brief Get R2R left and right flag
 * @retval TRUE for R2R use left and right both, FALSE for R2R use left only
*/
extern BOOL fgR2RLeftRight(void);
/**
 * @brief Set W2D cut H-Active
 * @param u4CutHActive The pixels count to cut
*/
extern void vW2DSetCutHActive(UINT32 u4CutHActive);
/**
 * @brief Get 128bit unit count for x pixels with y color depth
 * @param u4Pixels Pixels to count
 * @param u1ColorDepth Color depth,currently only 8bit and 10bit supported
 * @retval 128bit unit count
*/
extern UINT32 u4W2DR2RGet128bitUnit(UINT32 u4Pixels,UINT8 u1ColorDepth);
/**
 * @brief Get W2D left and right merged line size
 * @retval Line size in byte
*/
extern UINT32 u4W2DGetMergedLineSize(void);
/**
 * @brief Get R2R left and right merged line size
 * @retval Line size in byte
*/
extern UINT32 u4R2RGetMergedLineSize(void);
/**
 * @brief Set W2D frame size
 * @param eChannel YC channel
 * @param u4FrameSize Frame size in Byte
*/
extern void vW2DSetFrameSize(E_W2DR2R_CHANNEL eChannel,UINT32 u4FrameSize);
/**
 * @brief Get W2D frame size
 * @param eChannel YC channel
 * @retval Frame size in Byte
*/
extern UINT32 u4W2DGetFrameSize(E_W2DR2R_CHANNEL eChannel);
/**
 * @brief Set R2R frame size
 * @param eChannel YC channel
 * @param u4FrameSize Frame size in Byte
*/
extern void vR2RSetFrameSize(E_W2DR2R_CHANNEL eChannel,UINT32 u4FrameSize);
/**
 * @brief Get R2R frame size
 * @param eChannel YC channel
 * @retval Frame size in Byte
*/
extern UINT32 u4R2RGetFrameSize(E_W2DR2R_CHANNEL eChannel);
/**
 * @brief Set W2D frame count
 * @param u1FrameCnt Frame count
*/
extern void vW2DSetFrameCnt(UINT8 u1FrameCnt);
/**
 * @brief Get W2D frame count
 * @retval Frame count
*/
extern UINT8 u1W2DGetFrameCnt(void);
/**
 * @brief Set R2R frame count
 * @param u1FrameCnt Frame count
*/
extern void vR2RSetFrameCnt(UINT8 u1FrameCnt);
/**
 * @brief Get R2R frame count
 * @retval Frame count
*/
extern UINT8 u1R2RGetFrameCnt(void);
/**
 * @brief Set R2R repeat frames
              The repeat frames is made for case frame rate transfer from low to high, e.g W2D input 30Hz, but R2R output 60Hz
 * @param u1RepeatFrames Repeat frames to set
*/
extern void vR2RSetRepeatFrames(UINT8 u1RepeatFrames);
/**
 * @brief Set R2R delay frames
              The delay frame count the delay in W2D frame's view, in R2R frame's view, the delay frame = (delay here/repeat frames)
 * @param u1DelayFrames Delay frames to set
*/
extern void vR2RSetDelayFrames(UINT8 u1DelayFrames);
/**
 * @brief Set W2D frame size caculated for current timing
*/
extern void vW2DSetTimingDefaultFrameSize(void);
/**
 * @brief Set R2R frame size caculated for current timing
*/
extern void vR2RSetTimingDefaultFrameSize(void);
/**
 * @brief Set default cut H-Active
*/
extern void vW2DSetDefaultCutHActive(void);
/**
 * @brief Set frame start address for W2D
 * @param u4W2DYAddr W2D Y channel address
 * @param u4W2DCAddr W2D C channel address
*/
extern void vW2DSetFrameAddr(UINT32 u4W2DYAddr,UINT32 u4W2DCAddr);
/**
 * @brief Get frame address for W2D
 * @param u1FrameIdx The frame index to get
 * @param pu4W2DYAddr Pointer to W2D Y channel address
 * @param pu4W2DCAddr Pointer to W2D C channel address
*/
extern void vW2DGetFrameAddr(UINT8 u1FrameIdx,UINT32 *pu4W2DYAddr,UINT32 *pu4W2DCAddr);
/**
 * @brief Set frame start address for R2R
 * @param u4R2RYAddr R2R Y channel address
 * @param u4R2RCAddr R2R C channel address
*/
extern void vR2RSetFrameAddr(UINT32 u4R2RYAddr,UINT32 u4R2RCAddr);
/**
 * @brief Get frame address for R2R
 * @param u1FrameIdx The frame index to get
 * @param pu4R2RYAddr Pointer to R2R Y channel address
 * @param pu4R2RCAddr Pointer to R2R C channel address
*/
extern void vR2RGetFrameAddr(UINT8 u1FrameIdx,UINT32 *pu4R2RYAddr,UINT32 *pu4R2RCAddr);
/**
 * @brief Set W2D 420 mode
 * @param fg420Mode Enable(TRUE)/Disable(FALSE) 420 mode
 * @param fgSelEven Use even(TRUE) or odd(FALSE) lines
*/
extern void vW2DSet420Mode(BOOL fg420Mode,BOOL fgSelEven);
/**
 * @brief Set R2R 420 mode
 * @param fg420Mode Enable(TRUE)/Disable(FALSE) 420 mode
 * @param fgSelEven Use even(TRUE) or odd(FALSE) lines
*/
extern void vR2RSet420Mode(BOOL fg420Mode,BOOL fgSelEven);
/**
 * @brief Get R2R 420 mode or not
 * @retval TRUE for R2R is 420 mode, FALSE for not 420 mode
*/
extern BOOL fgR2RIs420Mode(void);
/**
 * @brief Set R2R read overlap pixels
 * @param u4R2ROverLapPixel Overlap pixels, the overlap pixels should meet below request
 *             For 8 bit mode, pixels should be n*16 which n is integer
 *             For 10bit mode, pixels should be n*12 which n is integer
*/
extern void vR2RSetOverlapPixels(UINT32 u4R2ROverLapPixel);
/**
 * @brief Get R2R read overlap pixels
 * @retval R2R overlap pixels
*/
extern UINT32 u4R2RGetOverlapPixels(void);
/**
 * @brief Set W2D auto address
 * @param fgEnable Enable(TRUE)/Disable(FALSE) auto address
 * @param u1AutoAddrCnt Address count to do auto address
 * @param u1W2DIdx W2D index(0(left) or 1(right))
*/
extern void vW2DSetAutoAddress(BOOL fgEnable,UINT8 u1AutoAddrCnt,UINT8 u1W2DIdx);
/**
 * @brief Set R2R auto address
 * @param fgEnable Enable(TRUE)/Disable(FALSE) auto address
 * @param u1AutoAddrCnt Address count to do auto address
*/
extern void vR2RSetAutoAddress(BOOL fgEnable,UINT8 u1AutoAddrCnt);
/**
 * @brief Set W2D drop line(2 line to 1 line)
 * @param fgEnable Enable(TRUE)/Disable(FALSE) drop line
 * @param fgSelEven Use even(TRUE) or odd(FALSE) lines
*/
extern void vW2DSetDropLine(BOOL fgEnable,BOOL fgSelEven);
/**
 * @brief Set HDMI down scaler(2 line to 1 line, average method)
 * @param fgEnable Enable(TRUE)/Disable(FALSE) down scaler
*/
extern void vW2DSetHDMIDownScaler(BOOL fgEnable);
/**
 * @brief Set W2D source
 * @param fgIsR2RFeed TRUE for R2R feed, FALE for HDMI input
*/
extern void vW2DSelSource(BOOL fgIsR2RFeed);
/**
 * @brief Set R2R slave sync mode
 * @param fgEnable TRUE for slave sync mode, FALE for not
*/
extern void vR2RSetSlaveSyncMode(BOOL fgEnable);
/**
 * @brief Set W2D HDMI port
 * @param u1HDMIPort HDMI port ID
 * @param u1W2DIdx W2D ID
*/
extern void vW2DSetHDMIPort(UINT8 u1HDMIPort,UINT8 u1W2DIdx);
/**
 * @brief Get W2D HDMI port
 * @param u1W2DIdx W2D ID
 * @retval HDMI port ID
*/
extern UINT8 u1W2DGetHDMIPort(UINT8 u1W2DIdx);
/**
 * @brief Enable W2D interrupt
 * @param fgEnable TRUE for enable, FALE for disable
*/
extern void vW2DEnableInterrupt(BOOL fgEnable);
/**
 * @brief W2D interrupt handler
*/
extern void vW2DIntHandler(void);
/**
 * @brief Init W2D hardware
*/
extern void vW2DHwInit(void);
/**
 * @brief Init R2R hardware
*/
extern void vR2RHwInit(void);
/**
 * @brief Init W2DR2R module
*/
extern void vW2DR2RInit(void);
/**
 * @brief Enable W2D
 * @param fgEnable Enable(TRUE)/Disable(FALSE) W2D
 * @param u1W2DIdx W2D index(0(left) or 1(right))
*/
extern void vW2DEnable(BOOL fgEnable, UINT8 u1W2DIdx);
/**
 * @brief Enable R2R dram request
 * @param fgEnable Enable(TRUE)/Disable(FALSE) dram request
 * @param u1R2RIdx R2R index(0(left) or 1(right))
*/
extern void vR2RDramReqEnable(BOOL fgEnable, UINT8 u1R2RIdx);
/**
 * @brief Enable R2R timing gen
 * @param fgEnable Enable(TRUE)/Disable(FALSE) R2R timing gen
*/
extern void vR2REnable(BOOL fgEnable);
/**
 * @brief Set W2D timing related setting
*/
extern void vW2DSetTimingRelated(void);
/**
 * @brief Set R2R timing related setting
*/
extern void vR2RSetTimingRelated(void);
/**
 * @brief Enter point for W2DR2R setting, call this API to set W2DR2R when input timing is stable
 * @param prW2DTiming Pointer to W2D input timing info
 * @param prR2RTiming Pointer to R2R output timing info
 * @param fgW2DLR W2D left and right flag
 * @param fgR2RLR R2R left and right flag
*/
extern void vW2DR2RSetting(W2DR2R_TIMING_INFO *prW2DTiming,W2DR2R_TIMING_INFO *prR2RTiming,BOOL fgW2DLR,BOOL fgR2RLR);
/**
 * @brief Disable W2D and R2R module
*/
extern void vW2DR2RDisable(void);
/**
 * @brief Enable W2D and R2R module
*/
extern void vW2DR2REnable(void);
/**
 * @brief Enable/disable log for debug purpose
 * @param eLogEnable Log type, enum value of E_W2DR2R_LOG_ENABLE
 * @param fgEnable Enable(TRUE)/Disable(FALSE)
*/
extern void vW2DR2REnableLog(E_W2DR2R_LOG_ENABLE eLogEnable,BOOL fgEnable);
/**
 * @brief Enable/disable debug options
 * @param eDbgOpt Debug option, enum value of E_W2DR2R_DBG_OPTION
 * @param fgEnable Enable(TRUE)/Disable(FALSE)
*/
extern void vW2DR2RDbgOption(E_W2DR2R_DBG_OPTION eDbgOpt,BOOL fgEnable);
/**
 * @brief Enable/disable all debug option
 * @param fgEnable Enable(TRUE)/Disable(FALSE)
*/
extern void vW2DR2REnableDbgOptionAll(BOOL fgEnable);
/**
 * @brief Log current W2DR2R status
*/
extern void vLogW2DR2RStatus(void);
/**
 * @brief R2R pattern
 * @param ePatternType R2R pattern type,refer to ENUM E_R2R_PATTERN_TYPE
 * @param fgEnable Enable(TRUE)/Disable(FALSE)
 * @param prPatternColor Pointer to color parameter, refer to STRUCT R2R_PATTERN_COLOR
*/
extern void vR2RPatternEn(E_R2R_PATTERN_TYPE ePatternType,BOOL fgEnable,R2R_PATTERN_COLOR *prPatternColor);
#endif
