/* 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.
 *
 *****************************************************************************/

//-----------------------------------------------------------------------------
// Include files
//-----------------------------------------------------------------------------

#include "x_typedef.h"
#include "x_bim.h"
#include "x_ckgen.h"
#include "x_pdwnc.h"
#include "x_hal_5381.h"
#include "rs232.h"

#if defined(CC_MTK_PRELOADER) && defined(CC_SUPPORT_USB_DIRECT_UART)
#include "x_gpio.h"
#endif
#ifndef CC_LOADER_MEM_OFFSET
#define CC_LOADER_MEM_OFFSET            (0xd00000)
#endif /* CC_LOADER_MEM_OFFSET */

UINT32 CHIP_RS232Init(void);
void CHIP_DisplayChar(UINT32 u4Char);
void CHIP_DisplayInteger(INT32 i);
void put_num(const CHAR c);
UINT32 CHIP_IsRemap(void);

#if defined(CC_ROM_BOOT) && !defined(CC_NAND_BOOT) && !defined(CC_EMMC_BOOT)
typedef void (*FUNC_JUMP_T)(void);
#endif

UINT32 CHIP_RS232Init()
{
#if defined(CC_ROM_BOOT) && !defined(CC_NAND_BOOT) && !defined(CC_EMMC_BOOT)
    FUNC_JUMP_T pfnJump;
#endif

    // Setup CPU to UART0 output parameter.
//    RS232_WRITE32(REG_CMD_STATUS, CMD_MODE);
#ifdef CC_NO_LOG
#ifdef CC_MTK_PRELOADER
#if defined(CC_SUPPORT_USB_DIRECT_UART)
    INT32 i4GpioNum=USB_DIRECT_UART_SWITCH_GPIO;
	INT32 i4Idx = ((UINT32)i4GpioNum >> 5);
	UINT32 u4Val=0;   
	
	#if USB_DIRECT_UART_SWITCH_GPIO==84
	IO_WRITE32MSK(CKGEN_PMUX4,0,0,0x38);//pinmux4[5:3]=0.TCON4 for MT5565
	#else
	#error "Please config the USB_DIRECT_UART_SWITCH_GPIO!"
	#endif
	
	u4Val = GPIO_OUT_REG(i4Idx);
    u4Val = (u4Val | (1U << (i4GpioNum & GPIO_INDEX_MASK)));
    GPIO_OUT_WRITE(i4Idx, u4Val);
	//enable output mode
	u4Val = GPIO_EN_REG(i4Idx);
	u4Val = (u4Val | (1U << (i4GpioNum & GPIO_INDEX_MASK)));
	GPIO_EN_WRITE(i4Idx, u4Val);
#endif	
		RS232_WRITE32(REG_RS232_MODE, UART_ACTIVE);
#endif
#else
    RS232_WRITE32(REG_RS232_MODE, RISC_ACTIVE);
#endif
    RS232_WRITE32(REG_BUFFER_SIZE, SINGLE_BYTE);
    RS232_WRITE32(REG_U0_BUFCTL, DEF_BUFCTL);

    // Turn UART TX pad.
    #if defined(CC_MT5890) || defined(CC_MT5861)
	//vIO32Write4B(PDWNC_GPIOEN2, (u4IO32Read4B(PDWNC_GPIOEN2) | PAD_UR0_TX_EN));
	vIO32WriteFldAlign(PDWNC_GPIOEN2, 0x1, FLD_CPU_URTX_EN);
	#else
    //vIO32Write4B(PDWNC_GPIOEN1, (u4IO32Read4B(PDWNC_GPIOEN1) | PAD_UR0_TX_EN));
    vIO32WriteFldAlign(PDWNC_GPIOEN1, 0x1, FLD_UART_TX_EN);
	#endif

#if defined(CC_ROM_BOOT) && !defined(CC_NAND_BOOT) && !defined(CC_EMMC_BOOT)
    // if ROM enable & ROM is not moved yet, remove ROM and goto 0 again.
#ifdef CC_FPGA
    if (BIM_READ32(0x4) == 0)
#else
    if (BIM_IS_SECURE_BOOT && (BIM_READ32(0x4) == 0))
#endif
    {
        BIM_WRITE32(0x4, 0xf4000000);
        pfnJump = NULL;
        pfnJump();
        return 1;
    }
#endif /* CC_NAND_BOOT */
    return 0;
}

UINT32 CHIP_GetStack()
{
#ifdef CC_MTK_PRELOADER
    #ifdef CC_FPGA
        return SRAM_LZHS_BASE; //stack will use from SRAM_LZHS_BASE to SRAM_LZHS_BASE+4K
    #else
        return SRAM_DMX_END - 0x1000;
    #endif
#else /* CC_MTK_PRELOADER */
    #ifdef CC_MTK_LOADER
        return (CC_LOADER_MEM_OFFSET - 0x10000);    // DRAM ready, loader use 12.75MB as stack.
    #else /* CC_MTK_LOADER */
        return SRAM_OSD_BASE;  // TV image, use LZHS buffer as stack, but TV image won't call this function.
    #endif /* CC_MTK_LOADER */
#endif /* CC_MTK_PRELOADER */
}

#if defined(CC_MTK_PRELOADER) && defined(NDEBUG)
void CHIP_DisplayDigit(UINT32 u4Char)
{
    if (u4Char <= 9) { u4Char += '0'; }
    if ((u4Char >= 0x0a) && (u4Char <= 0x0f)) { u4Char += ('a' - 0x0a); }
    CHIP_DisplayChar(u4Char);
}
#endif /* defined(CC_MTK_PRELOADER) && defined(NDEBUG) */

void CHIP_DisplayString(const CHAR *szString)
{
#ifndef NOLOG
    if(szString == NULL)
    {
        return;
    }

    while (*szString != 0)
    {
        // busy wait if no tx buffer slot.
        CHIP_DisplayChar(((UINT32)((UINT8)(*szString))));
        szString++;
    }
#endif
}

void CHIP_DisplayChar(UINT32 u4Char)
{
#ifndef NOLOG
    while ((RS232_READ32(REG_U0_STATUS) & STATUS_TXBUF) != STATUS_TXBUF) { }
    RS232_WRITE32(REG_U0_OUTPORT, (UINT32)(u4Char & 0xff));
    if (u4Char == ((UINT32)'\n'))
    {
        RS232_WRITE32(REG_U0_OUTPORT, (UINT32)'\r');
    }
#endif
}

UINT32 CHIP_IsRemap(void)
{
#ifdef CC_RUN_ON_NOR_EMPTY
    return 1;
#else /* CC_RUN_ON_NOR_EMPTY */
    return (BIM_READ32(REG_RW_REMAP) & REMAP_ENABLE);
#endif /* CC_RUN_ON_NOR_EMPTY */
}

void put_num(const CHAR c)
{
    CHIP_DisplayChar((UINT32)(UINT8)(c + '0'));
}

void CHIP_DisplayInteger(INT32 i)
{
#ifndef NOLOG
    UINT32 j, k, l, m, p;

    if (i < 0)
    {
        CHIP_DisplayChar('-');
        p = (UINT32)(0 - i);
    }
    else
    {
        p = (UINT32)i;
    }

    l = p/1000;
    k = (p-l*1000) / 100;
    j = (p-(l*1000)-(k*100)) / 10;
    m = p - (j * 10) - (k * 100) -(l*1000);

    if (p >= 1000)
    {
        put_num(l);
    }

    if (p >= 100)
    {
        put_num(k);
    }

    if (p >= 10)
    {
        put_num(j);
    }
    
    put_num(m);
#endif
}
