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

#ifndef CC_LOADER_MEM_OFFSET
#define CC_LOADER_MEM_OFFSET            (DRAM_START + 0xd00000)
#endif /* CC_LOADER_MEM_OFFSET */

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

UINT32 CHIP_RS232Init(void)
{
#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);
#if (defined(CC_MTK_HOTBOOT_PRELOADER) || defined(CC_MTK_HOTBOOT_START))
    RS232_WRITE32(REG_CMD_STATUS, TRANS_MODE);
#endif

#ifdef CC_S_PLATFORM
    #ifdef CC_MTK_PRELOADER
    RS232_WRITE32(REG_RS232_MODE, UART_ACTIVE);
    #endif
    #if defined(CC_LMP_CUST) || defined(CC_PHX_CUST)
    #ifndef CC_NO_LOG
    RS232_WRITE32(REG_RS232_MODE, RISC_ACTIVE);
    #endif
    #else
    //#ifndef NOLOG
    #if 1
    RS232_WRITE32(REG_RS232_MODE, RISC_ACTIVE);  //this stage enable this for debug
    #endif
    #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) || defined(CC_MT5891) || defined(CC_MT5886) || defined(CC_MT5893) || defined(CC_MT5895)
    //vIO32Write4B(PDWNC_GPIOEN2, (u4IO32Read4B(PDWNC_GPIOEN2) | PAD_UR0_TX_EN));
    vIO32WriteFldAlign(PDWNC_GPIOEN2, 0x1, FLD_CPU_URTX_EN);
#elif defined(CC_MT5863) || defined(CC_MT5865)
    vIO32WriteFldAlign(PDWNC_CPU_TX_EN, 0x1, FLD_CPU_URTX_EN);
#elif defined(CC_MT5882)
    if (IS_IC_5885())
    {
        vIO32WriteFldAlign(PDWNC_GPIOEN1, 0x1, FLD_CPU_TX_EN);
    }
    else
    {
        vIO32WriteFldAlign(PDWNC_GPIOEN1, 0x1, FLD_UART_TX_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, BROM_BASE);
        pfnJump = NULL;
        pfnJump();
        return 1;
    }
#endif /* CC_NAND_BOOT */
    return 0;
}

UINT32 CHIP_GetStack(void)
{
#ifdef CC_MTK_PRELOADER

#ifdef CC_SECURE_BOOT_V3
    // clear the stack/heap of ROM
    UINT8 *ptr = SRAM_CORE1_BASE + 0x100; // the begin 0x100 is reserverd for core 1/2/3
    UINT32 count = SRAM_DMX_END - SRAM_CORE1_BASE - 0x100;
    while (count--)
        *ptr++ = 0;
#endif //CC_SECURE_BOOT_V3

    #ifdef CC_FPGA
    return SRAM_LZHS_BASE; //stack will use from SRAM_LZHS_BASE to SRAM_LZHS_BASE+4K
    #else
    #ifdef CC_MT5863
    return SRAM_OSD_BASE; //DMX RAM SIZE 41K can not use (41K-4K)~41K as stack since rom code will copy 40K flash data to sram(from SRAM_DMX_BASE)
    #else
    return SRAM_DMX_END - 0x1000;
    #endif
    #endif
#elif defined(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_PRELOADER */
}

static void CHIP_DisplayErrChar(UINT32 u4Char)
{
    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');
    }
}

void CHIP_DisplayChar(UINT32 u4Char)
{
#ifndef NOLOG
    CHIP_DisplayErrChar(u4Char);
#endif
}

void CHIP_DisplayErrMessage(const CHAR *szString)
{
    if (szString == NULL)
    {
        return;
    }

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

void CHIP_DisplayString(const CHAR *szString)
{
#ifndef NOLOG
    CHIP_DisplayErrMessage(szString);
#endif
}

#ifdef CC_MTK_PRELOADER
#ifndef NOLOG
static void CHIP_DisplayDigit(UINT32 u4Char)
{
    if (u4Char <= 9) { u4Char += '0'; }
    if ((u4Char >= 0x0a) && (u4Char <= 0x0f)) { u4Char += ('a' - 0x0a); }
    CHIP_DisplayChar(u4Char);
}

static void put_num(const CHAR c)
{
    CHIP_DisplayChar((UINT32)(UINT8)(c + '0'));
}
#endif // !NOLOG

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((CHAR)l);
    }
    if (p >= 100)
    {
        put_num((CHAR)k);
    }
    if (p >= 10)
    {
        put_num((CHAR)j);
    }
    put_num((CHAR)m);
#endif // !NOLOG
}

void CHIP_DisplayHex(UINT32 u4Val)
{
#ifndef NOLOG
    CHIP_DisplayChar('0');
    CHIP_DisplayChar('x');
    CHIP_DisplayDigit(((u4Val >> 28) & 0x0f));
    CHIP_DisplayDigit(((u4Val >> 24) & 0x0f));
    CHIP_DisplayDigit(((u4Val >> 20) & 0x0f));
    CHIP_DisplayDigit(((u4Val >> 16) & 0x0f));
    CHIP_DisplayDigit(((u4Val >> 12) & 0x0f));
    CHIP_DisplayDigit(((u4Val >> 8) & 0x0f));
    CHIP_DisplayDigit(((u4Val >> 4) & 0x0f));
    CHIP_DisplayDigit(((u4Val >> 0) & 0x0f));
#endif // !NOLOG
}

#endif // CC_MTK_PRELOADER
