/**
 * @file hv_chip_debuguart.h
 * @brief define uart debug interface
 * @details anyware
 * @author HiView SoC Software Team
 * @version 1.0.0
 * @date 2022-09-05
 * @copyright Copyright(c),2022-9, Hiview Software. All rights reserved.
*/
#ifndef _HV_CHIP_DEBUG_UART_H
#define _HV_CHIP_DEBUG_UART_H

/**
 * @brief interface for write register.
 * @param[in] address to write.
 * @param[in] value to write.
 * @return none.
 */
static void Hv_Chip_WriteReg(unsigned int uAddr, unsigned int uValue)
{
    uAddr= ((uAddr) | 0xA0000000);
    *(volatile unsigned int*)uAddr = uValue;
}

/**
 * @brief interface for read register.
 * @param[in] address to read.
 * @return value from register.
 */
static unsigned int Hv_Chip_ReadReg(unsigned int uAddr)
{
    uAddr= ((uAddr) | 0xA0000000);

    return *(volatile unsigned int*)uAddr;
}

#define BOARD_DEBUG_UART_STOP_BITS  0  /* for 1bit */
#define BOARD_DEBUG_UART_DATA_BITS  8
#define BOARD_W32 Hv_Chip_WriteReg
#define BOARD_R32 Hv_Chip_ReadReg
#define BOARD_REG_VAL(reg) (*(unsigned int*)&(reg))
#define BOARD_W32_REG(addr, reg) BOARD_W32(addr, BOARD_REG_VAL(reg))

/**
 * @brief interface to switch qsti to rsic.
 * @param[in] none.
 * @return none.
 */
static void Hv_Chip_SwitchQspiRsic(void)
{
    unsigned int uiRegVal = 0;
    uiRegVal = BOARD_R32(STANDBY_SH08_TOP_STBY_CTRL_0);
    rs_standby_sh08_top_stby_ctrl_0 stProgSpi = (*(standby_sh08_top_stby_ctrl_0(uiRegVal)));
    stProgSpi.reg_prog_spi_clk_func_sel  = 0;
    stProgSpi.reg_prog_spi_csn_func_sel  = 0;
    stProgSpi.reg_prog_spi_hold_func_sel = 0;
    stProgSpi.reg_prog_spi_miso_func_sel = 0;
    stProgSpi.reg_prog_spi_mosi_func_sel = 0;
    stProgSpi.reg_prog_spi_wp_func_sel   = 0;
    BOARD_W32_REG(STANDBY_SH08_TOP_STBY_CTRL_0, stProgSpi);
}



static void Hv_Chip_DebugUartConfig(void)
{
    unsigned int uiUart = 0;

#if 0 // TODO please open this if using HDMI0/1 DDC as uart0
    /* use hdmi0 uart0 to debug */
    /* set SYS_BLK3_TOP_REG_38 reg_uart0_sin_sel 1 */
    uiUart = BOARD_R32(SYS_BLK3_TOP_REG_38);
    rs_sys_blk3_top_reg_38 uart0_blk = (*(sys_blk3_top_reg_38(uiUart)));
    uart0_blk.reg_uart0_sin_sel = 1;
    BOARD_W32_REG(SYS_BLK3_TOP_REG_38, uart0_blk);

    uiUart = BOARD_R32(STANDBY_SH08_TOP_STBY_CTRL_24);
    rs_standby_sh08_top_stby_ctrl_24 uart0_tx__func = (*(standby_sh08_top_stby_ctrl_24(uiUart)));
    uart0_tx__func.reg_hdmi_rx0_ddc1_func_sel = 3;
    BOARD_W32_REG(STANDBY_SH08_TOP_STBY_CTRL_24, uart0_tx__func);

    uiUart = BOARD_R32(STANDBY_SH08_TOP_STBY_CTRL_0);
    rs_standby_sh08_top_stby_ctrl_0 uart0_rx__func = (*(standby_sh08_top_stby_ctrl_0(uiUart)));
    uart0_rx__func.reg_hdmi_rx0_ddc0_func_sel = 0;
    BOARD_W32_REG(STANDBY_SH08_TOP_STBY_CTRL_0, uart0_rx__func);

    //io_ctrl
    uiUart = BOARD_R32(STANDBY_SH08_TOP_STBY_CTRL_10);
    rs_standby_sh08_top_stby_ctrl_10 uart0_tx_ctrl= (*(standby_sh08_top_stby_ctrl_10(uiUart)));
    uart0_tx_ctrl.reg_hdmi_rx0_ddc1_io_ctrl = 0x1;
    uart0_tx_ctrl.reg_hdmi_rx0_ddc0_io_ctrl = 0x10;
    BOARD_W32_REG(STANDBY_SH08_TOP_STBY_CTRL_10, uart0_tx_ctrl);

    //sin_in_sel
    uiUart = BOARD_R32(STANDBY_SH08_TOP_STBY_CTRL_24);
    rs_standby_sh08_top_stby_ctrl_24 uart0_in_sel = (*(standby_sh08_top_stby_ctrl_24(uiUart)));
    uart0_in_sel.reg_uart0_sin_use_sel = 0;
    BOARD_W32_REG(STANDBY_SH08_TOP_STBY_CTRL_24, uart0_in_sel);

    uiUart = BOARD_R32(STANDBY_SH08_TOP_STBY_CTRL_4);
    rs_standby_sh08_top_stby_ctrl_4 stby_uart0_in_sel = (*(standby_sh08_top_stby_ctrl_4(uiUart)));
    stby_uart0_in_sel.reg_uart0_sin_in_sel = 0;
    BOARD_W32_REG(STANDBY_SH08_TOP_STBY_CTRL_4, stby_uart0_in_sel);


    /* use hdmi1 uart0 to debug */
    uiUart = BOARD_R32(STANDBY_SH08_TOP_STBY_CTRL_24);
    rs_standby_sh08_top_stby_ctrl_24 hdmi1_uart0_tx__func = (*(standby_sh08_top_stby_ctrl_24(uiUart)));
    hdmi1_uart0_tx__func.reg_hdmi_rx1_ddc1_func_sel = 3;
    BOARD_W32_REG(STANDBY_SH08_TOP_STBY_CTRL_24, hdmi1_uart0_tx__func);

    uiUart = BOARD_R32(STANDBY_SH08_TOP_STBY_CTRL_0);
    rs_standby_sh08_top_stby_ctrl_0 hdmi1_uart0_rx__func = (*(standby_sh08_top_stby_ctrl_0(uiUart)));
    hdmi1_uart0_rx__func.reg_hdmi_rx1_ddc0_func_sel = 0;
    BOARD_W32_REG(STANDBY_SH08_TOP_STBY_CTRL_0, hdmi1_uart0_rx__func);

    //io_ctrl
    uiUart = BOARD_R32(rs_standby_sh08_top_stby_ctrl_14);
    rs_standby_sh08_top_stby_ctrl_14 hdmi1_uart0_tx_ctrl= (*(standby_sh08_top_stby_ctrl_14(uiUart)));
    hdmi1_uart0_tx_ctrl.reg_hdmi_rx1_ddc1_io_ctrl = 0x1;
    hdmi1_uart0_tx_ctrl.reg_hdmi_rx1_ddc0_io_ctrl = 0x10;
    BOARD_W32_REG(STANDBY_SH08_TOP_STBY_CTRL_10, hdmi1_uart0_tx_ctrl);

    //sin_in_sel
    uiUart = BOARD_R32(STANDBY_SH08_TOP_STBY_CTRL_24);
    rs_standby_sh08_top_stby_ctrl_24 hdmi1_uart0_in_sel = (*(standby_sh08_top_stby_ctrl_24(uiUart)));
    hdmi1_uart0_in_sel.reg_uart0_sin_use_sel = 0;
    BOARD_W32_REG(STANDBY_SH08_TOP_STBY_CTRL_24, hdmi1_uart0_in_sel);

    uiUart = BOARD_R32(STANDBY_SH08_TOP_STBY_CTRL_4);
    rs_standby_sh08_top_stby_ctrl_4 hdmi1_stby_uart0_in_sel = (*(standby_sh08_top_stby_ctrl_4(uiUart)));
    hdmi1_stby_uart0_in_sel.reg_uart0_sin_in_sel = 0;
    BOARD_W32_REG(STANDBY_SH08_TOP_STBY_CTRL_4, hdmi1_stby_uart0_in_sel);
    #else

    /* use uart0 to debug */
    uiUart = BOARD_R32(RX_SH08_TOP_RX_CTRL_4);
    rs_rx_sh08_top_rx_ctrl_4 uart0_func = (*(rx_sh08_top_rx_ctrl_4(uiUart)));
    uart0_func.reg_uart0_rx_func_sel = 1;
    uart0_func.reg_uart0_tx_func_sel = 1;
    BOARD_W32_REG(RX_SH08_TOP_RX_CTRL_4, uart0_func);
    //pin_sel
    uiUart = BOARD_R32(RX_SH08_TOP_RX_CTRL_10);
    rs_rx_sh08_top_rx_ctrl_10 uart0_pin= (*(rx_sh08_top_rx_ctrl_10(uiUart)));
    uart0_pin.reg_uart0_rx_pin_sel = 0;
    uart0_pin.reg_uart0_tx_pin_sel = 0;
    BOARD_W32_REG(RX_SH08_TOP_RX_CTRL_10, uart0_pin);
    //io_ctrl
    uiUart = BOARD_R32(RX_SH08_TOP_RX_CTRL_38);
    rs_rx_sh08_top_rx_ctrl_38 uart0_tx_ctrl= (*(rx_sh08_top_rx_ctrl_38(uiUart)));
    uart0_tx_ctrl.reg_uart0_tx_io_ctrl = 0x1;
    uart0_tx_ctrl.reg_uart0_rx_io_ctrl = 0x40;
    BOARD_W32_REG(RX_SH08_TOP_RX_CTRL_38, uart0_tx_ctrl);
    //sin_in_sel
    uiUart = BOARD_R32(RX_SH08_TOP_RX_CTRL_8);
    rs_rx_sh08_top_rx_ctrl_8 uart0_in_sel = (*(rx_sh08_top_rx_ctrl_8(uiUart)));
    uart0_in_sel.reg_uart0_sin_in_sel = 0;
    BOARD_W32_REG(RX_SH08_TOP_RX_CTRL_8, uart0_in_sel);
    uiUart = BOARD_R32(STANDBY_SH08_TOP_STBY_CTRL_4);
    rs_standby_sh08_top_stby_ctrl_4 stby_uart0_in_sel = (*(standby_sh08_top_stby_ctrl_4(uiUart)));
    stby_uart0_in_sel.reg_uart0_sin_in_sel = 0;
    BOARD_W32_REG(STANDBY_SH08_TOP_STBY_CTRL_4, stby_uart0_in_sel);

    #endif

    return;
}

#define HS_DEBUG_UART_BASE_ADDR (0)

/**
 * @brief interface to int debug uart.
 * @param[in] baudrate to set.
 * @return none.
 */
static void Hv_Chip_DebugUartInit(unsigned int uBaudrate)
{
    unsigned int uDdiv = 0;
    unsigned int uData = 0;
    unsigned int uVal  = 0;
    unsigned int uUart = 0;

    Hv_Chip_SwitchQspiRsic();
    Hv_Chip_SetIOUserMode();
    {
        if(!HS_DEBUG_UART_BASE_ADDR)
        {
            Hv_Chip_DebugUartConfig();
        } 
        // else 
        // {
        //     /* use uart1 to debug */
        //     rs_sys_sh08_top_tx_ctrl_0 uart1_func={0};
        //     uart1_func.reg_uart1_rx_func_sel =0;
        //     uart1_func.reg_uart1_tx_func_sel =0;
        //     BOARD_W32_REG(SYS_SH08_TOP_TX_CTRL_0, uart1_func);
        //     rs_sys_sh08_top_tx_ctrl_8 uart1_pin={0};
        //     uart1_pin.reg_uart1_rx_pin_sel = 0;
        //     uart1_pin.reg_uart1_tx_pin_sel = 0;
        //     BOARD_W32_REG(SYS_SH08_TOP_TX_CTRL_8, uart1_pin);
        //     rs_sys_sh08_top_tx_ctrl_20 uart1_tx_ctrl={0};
        //     uart1_tx_ctrl.reg_uart1_tx_io_ctrl = 0x1;
        //     uart1_tx_ctrl.reg_uart1_rx_io_ctrl = 0x40;
        //     BOARD_W32_REG(SYS_SH08_TOP_TX_CTRL_20, uart1_tx_ctrl);
        // }
    }

    /* set fcr */
    {
        rs_cpu_sys_uart0_fcr fcr = {0};
        fcr.reg_FIFOE = 1;
        fcr.reg_RFIFOR = 1;
        fcr.reg_XFIFOR = 1;
        BOARD_W32_REG(HS_DEBUG_UART_BASE_ADDR + CPU_SYS_UART0_FCR, fcr);
    }

    /* set baudrate */
    {
        uDdiv = ((HV_CHIP_CLK_AHB >> 4) + (uBaudrate >> 2)) / uBaudrate;

        uVal = BOARD_R32(HS_DEBUG_UART_BASE_ADDR + CPU_SYS_UART0_LCR);
        /* Enable setup baudrate */
        BOARD_W32(HS_DEBUG_UART_BASE_ADDR + CPU_SYS_UART0_LCR, uVal | 0x80);
        BOARD_W32(HS_DEBUG_UART_BASE_ADDR + CPU_SYS_UART0_THR_DLL, uDdiv & 0xff);
        BOARD_W32(HS_DEBUG_UART_BASE_ADDR + CPU_SYS_UART0_DLH_IER, (uDdiv >> 8) & 0xff);
        /* Disable setup baudrate */
        BOARD_W32(HS_DEBUG_UART_BASE_ADDR + CPU_SYS_UART0_LCR, uVal & 0x7f);
    }

    /* set lcr: stop bit, data bit, 奇偶 */
    {
        uData = (((BOARD_DEBUG_UART_STOP_BITS << 2) & 0x04) | ((BOARD_DEBUG_UART_DATA_BITS - 5) & 0x3));
        uVal = BOARD_R32(HS_DEBUG_UART_BASE_ADDR + CPU_SYS_UART0_LCR);
         /* NO ODD/EVEN */
        uVal = (uVal & 0xE0) | uData;
        BOARD_W32(HS_DEBUG_UART_BASE_ADDR + CPU_SYS_UART0_LCR, uVal);
    }
}

/**
 * @brief interface to put uart a char.
 * @param[in] the char to put.
 * @return always 1.
 */
static int Hv_Chip_DebugUartPutc(int iChar)
{
    unsigned int uVal = 0;

    if (iChar == '\n')
    {
        Hv_Chip_DebugUartPutc('\r');
    }

    uVal = BOARD_R32(HS_DEBUG_UART_BASE_ADDR + CPU_SYS_UART0_LSR);
    while (cpu_sys_uart0_lsr(uVal)->reg_THRE == 0){
        uVal = BOARD_R32(HS_DEBUG_UART_BASE_ADDR + CPU_SYS_UART0_LSR);
    }
    BOARD_W32(HS_DEBUG_UART_BASE_ADDR + CPU_SYS_UART0_THR_DLL, iChar);
    return 1;
}

/**
 * @brief whether to get a kb hit.
 * @param[in] none.
 * @return the value to hit or 0 for none.
 */
static int Hv_Chip_DebugUartKbhit(void)
{
    unsigned int uVal = BOARD_R32(HS_DEBUG_UART_BASE_ADDR + CPU_SYS_UART0_LSR);

    if (cpu_sys_uart0_lsr(uVal)->reg_DR)
    {
        return BOARD_R32(HS_DEBUG_UART_BASE_ADDR + CPU_SYS_UART0_THR_DLL);
    } else {
        return 0;
    }
}

/**
 * @brief interface to get a input char.
 * @param[in] the char value to get.
 * @return 0-success 1-fail.
 */
static int Hv_Chip_DebugUartGetc(char *ch)
{
    unsigned int uVal = BOARD_R32(HS_DEBUG_UART_BASE_ADDR + CPU_SYS_UART0_LSR);
    if (cpu_sys_uart0_lsr(uVal)->reg_DR == 0)
    {
        return 1;/*1代表fail*/
    }
    else
    {
        *ch = BOARD_R32(HS_DEBUG_UART_BASE_ADDR + CPU_SYS_UART0_THR_DLL);
    }
    return 0;
}

#undef BOARD_W32
#undef BOARD_R32
#undef BOARD_REG_VAL
#undef BOARD_W32_REG
#undef BOARD_DEBUG_UART_STOP_BITS
#undef BOARD_DEBUG_UART_DATA_BITS

/**
 * @brief interface to put chars.
 * @param[in] the strings to put.
 * @return none.
 */
static void Hv_Chip_DebugUartPuts(const char *pcChar)
{
    if (!pcChar)
    {
        return;
    }
    while (*pcChar)
    {
        Hv_Chip_DebugUartPutc(*pcChar);
        ++pcChar;
    }
}

/**
 * @brief interface to put chars with length to separate fd.
 * @param[in] debug fd. not usr now.
 * @param[in] the strings to put.
 * @param[in] the length.
 * @return none.
 */
static void Hv_Chip_DebugUartWrite(int iFd, const char *pcBuf, int iLen)
{
    int iLoop = 0;

    if (!pcBuf)
    {
        return;
    }

    if (iFd != 1 && iFd != 2)
    {
        Hv_Chip_DebugUartPuts("Unknown fd for write\n");
    } else {
        for (iLoop = 0; iLoop < iLen; iLoop++)
        {
            Hv_Chip_DebugUartPutc(pcBuf[iLoop]);
        }
    }
}

#endif
