/**
 * @file hv_drv_OsdInterrupt.c
 * @brief Osd Driver interrupt handling c file.
 * @details This file provides the following functions: \n
 *          (1) interrupt enable/disable functions \n
 *          (2) interrupt handle functions \n
 *
 * @author HiView SoC Software Team
 * @version 1.0.0
 * @date 2022-08-31
 * @copyright Copyright(c),2022-8, Hiview Software. All rights reserved.
 * @par History:
 * <table>
 * <tr><th>Author         <th>Date        <th>Change Description
 * <tr><td>OSD Group      <td>2022-08-31   <td>create
 * </table>
*/

#include "hv_drv_Osd.h"
#include "hv_cal_Osd.h"
#include "hv_mw_SystemManager.h"
#include "hv_mw_OsdInterrupt.h"

#ifdef HV_SCALER_DEBUG_VERSION
UINT32 g_uiDMACount = 0;
UINT32 g_uiRegenClrCount = 0;
UINT32 g_uiIrqCount = 0;
#endif

static BOOL s_bSendSyncFlag = HV_TRUE;
static UCHAR8 s_ucSyncFrameDelay = 0;

VOID Hv_Mw_OsdInterrupt_SetSyncFlag(BOOL bSyncEnable)
{
    s_bSendSyncFlag = bSyncEnable;
}

VOID Hv_Mw_OsdInterrupt_SetSyncFrameDelay(UCHAR8 ucFrameDelay)
{
    s_ucSyncFrameDelay = ucFrameDelay;
}

static VOID Hv_Mw_OsdInterrupt_ClearDMADone(USHORT16 usBit)
{
    HV_R32_DECL_VAR();

    Hv_Cal_OsdInnerDMA_ClearDoneFlag();

    HV_W32_FIELD(OSD_KV_DMA_CTRL_A0, rdma_int_rel, OSD_INT_DMA_READ_DONE_BIT);
    HV_W32_FIELD(OSD_KV_DMA_CTRL_A0, rdma_int_rel, 0);
}

static VOID Hv_Mw_OsdInterrupt_ClearCommon(USHORT16 usBit)
{
    HV_R32_DECL_VAR();

    HV_W32_FIELD(OSD_KV_DMA_CTRL_A0, rdma_int_rel, usBit);
    HV_W32_FIELD(OSD_KV_DMA_CTRL_A0, rdma_int_rel, 0);
}

VOID Hv_Mw_OsdInterrupt_DebugInit(VOID)
{
#ifdef HV_SCALER_DEBUG_VERSION
    g_uiIrqCount = 0;
    g_uiDMACount = 0;
    g_uiRegenClrCount = 0;
#endif
}

VOID Hv_Mw_OsdInterrupt_DebugPrint(BOOL bResult)
{
#ifdef HV_SCALER_DEBUG_VERSION
    HV_LOG_RAW(" result: %s\n", bResult ? "Success" : "Failed");
    HV_LOG_RAW("Total interrupt entrance count: %u\n", g_uiIrqCount);
    HV_LOG_RAW("DMA read done interrupt count: %u\n", g_uiDMACount);
    HV_LOG_RAW("Reg_en clear interrupt count: %u\n", g_uiRegenClrCount);
#endif
}

static VOID Hv_Mw_OsdInterrupt_Clear(USHORT16 usBits)
{
    if (usBits & OSD_INT_DMA_READ_DONE_BIT)
    {
        Hv_Mw_OsdInterrupt_ClearDMADone(usBits);
    }
    if (usBits & OSD_INT_REGEN_CLR_BIT)
    {
        Hv_Mw_OsdInterrupt_ClearCommon(usBits);
    }
}

static VOID Hv_Mw_OsdInterrupt_SetTriggerType(OsdInterruptTrigType enTrigType)
{
    UCHAR8 ucShift = 0;
    UINT32 uiData = 0;

    for (ucShift = 0; ucShift < 10; ++ucShift)
    {
        uiData |= (enTrigType << (ucShift * 3));
    }
    HV_W32_FIELD(OSD_KV_DMA_CTRL_A4, RDMA_INTR_TRIGGER_MODE, uiData);
}

static HV_VOS_ISR_RESULT_E Hv_Mw_Osd_ISRHandler(UINT32 irqNum, VOID *arg)
{
    USHORT16 usFlags = 0;
    HV_R32_DECL_VAR();

#ifdef HV_SCALER_DEBUG_VERSION
    ++g_uiIrqCount;
#endif

    usFlags = HV_R32_FIELD(OSD_KV_DMA_CTRL_A0, rdma_int_sta);

    if (usFlags & OSD_INT_DMA_READ_DONE_BIT)
    {
#ifdef HV_SCALER_DEBUG_VERSION
        ++g_uiDMACount;
#endif
        Hv_Drv_OsdDMA_TransferFinish();
        Hv_Mw_OsdInterrupt_Clear(OSD_INT_DMA_READ_DONE_BIT);

        Hv_Cal_OsdInnerDMA_ClearStart();
    }

    if (usFlags & OSD_INT_REGEN_CLR_BIT)
    {
#ifdef HV_SCALER_DEBUG_VERSION
        ++g_uiRegenClrCount;
#endif
        Hv_Mw_OsdInterrupt_Clear(OSD_INT_REGEN_CLR_BIT);
        if (s_bSendSyncFlag)
        {
            if (s_ucSyncFrameDelay == 0)
            {
                HV_VOS_QUEUE_S *pstQueue = Hv_Mw_System_GetOsdQueue();
                OsdEvent stEventMsg = {OSD_EVENT_SYNC, 0};
                if (NULL != pstQueue)
                {
                    Hv_Vos_QueueSendFromISR(pstQueue, &stEventMsg);
                }
            }
            else
            {
                s_ucSyncFrameDelay--;
                Hv_Cal_OsdFrame_SetSync();
            }
        }
    }

    Hv_Vos_WClrMiscInt(irqNum - HV_CHIP_IRQ_BASE);
    return HV_VOS_ISR_HANDLED;
}

VOID Hv_Mw_OsdInterrupt_Enable(OsdInterruptTrigType enTrigType, USHORT16 usEnabledBits)
{
    HV_R32_DECL_VAR();

    Hv_Mw_OsdInterrupt_Clear(0x3ff);
    Hv_Mw_OsdInterrupt_SetTriggerType(enTrigType);

    /* mask interrupts except READ_DONE and reg_en clear */
    HV_W32_FIELD(OSD_KV_DMA_CTRL_A0, rdma_int_msk, (~(usEnabledBits)) & 0x3ff);

    Hv_Vos_ConfigIrq(HV_CHIP_IRQ_OSD_INT, HV_TRUE, 0);
    Hv_Vos_AttachIsr(HV_CHIP_IRQ_OSD_INT, Hv_Mw_Osd_ISRHandler, NULL);

    Hv_Vos_UnmaskIrq(HV_CHIP_IRQ_OSD_INT);
}

VOID Hv_Mw_OsdInterrupt_Disable(VOID)
{
    /* mask all */
    HV_W32_FIELD(OSD_KV_DMA_CTRL_A0, rdma_int_msk, 0x3ff);
    /* clear all */
    Hv_Mw_OsdInterrupt_Clear(0x3ff);

    Hv_Vos_MaskIrq(HV_CHIP_IRQ_OSD_INT);
    Hv_Vos_ISR_Detach(HV_CHIP_IRQ_OSD_INT, Hv_Mw_Osd_ISRHandler);
}
