/*
 * Copyright 2017-2018 NXP
 * All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <stdint.h>
#include "fsl_common.h"
#include "fsl_debug_console.h"
#include "board.h"
#if defined(SDK_I2C_BASED_COMPONENT_USED) && SDK_I2C_BASED_COMPONENT_USED
#include "fsl_i2c.h"
#endif /* SDK_I2C_BASED_COMPONENT_USED */
#if defined BOARD_USE_CODEC
#include "fsl_wm8904.h"
#endif



#include "fsl_usart.h"
#include "mcmgr.h"

#define CORE1_BOOT_ADDRESS (void *)0x04000000

extern unsigned char core1_image_start[];
#define CORE1_IMAGE_START core1_image_start

/*******************************************************************************
 * Variables
 ******************************************************************************/

#if defined BOARD_USE_CODEC
codec_config_t boardCodecConfig = {.I2C_SendFunc = BOARD_Codec_I2C_Send,
                                   .I2C_ReceiveFunc = BOARD_Codec_I2C_Receive,
                                   .op.Init = WM8904_Init,
                                   .op.Deinit = WM8904_Deinit,
                                   .op.SetFormat = WM8904_SetAudioFormat};
#endif

/*******************************************************************************
 * Code
 ******************************************************************************/

extern uint32_t get_core1_image_size(void);
extern void BOARD_InitPins_Core0(void);

void BOARD_InitHardware(void)
{
        /* added intialize function here for LPC5500 */
#ifdef COREMARK_SCORE_TEST
    usart_config_t config;
#endif

    /* Initialize MCMGR, install generic event handlers */
    MCMGR_Init();


    /* Set Main Freq as 12Mhz */
    BOARD_BootClockFRO12M();


    /* Don't alter lower bits */
    /* Adjust FMC waiting time cycles */
    SYSCON->FMCCR = (SYSCON->FMCCR & 0xFFFF0FFF) | (0x06 << 12); /* Flash accesses use 7 CPU clocks */
    /* Set Main Freq as 96Mhz */
//    BOARD_BootClockFROHF96M();
    BOARD_BootClockPLL150M();
    
    /* Update System Frequency Value */
    SystemCoreClockUpdate();
    /* Board pin init */
//    BOARD_InitPins();
    BOARD_InitPins_Core0();


#ifdef COREMARK_SCORE_TEST
    /* attach 12 MHz clock to FLEXCOMM0 (debug console) */
    CLOCK_AttachClk(BOARD_DEBUG_UART_CLK_ATTACH);
    BOARD_InitDebugConsole();
    /*
     * config.baudRate_Bps = 115200U;
     * config.parityMode = kUSART_ParityDisabled;
     * config.stopBitCount = kUSART_OneStopBit;
     * config.loopback = false;
     * config.enableTx = false;
     * config.enableRx = false;
     */
    USART_GetDefaultConfig(&config);
    config.baudRate_Bps = 115200;
    config.enableTx = true;
    config.enableRx = true;
    USART_Init(USART0, &config, 12000000);
#endif


    /* Print main clock frequency information */
    //ee_printf("CORE0_SystemCoreClock: %d\n", SystemCoreClock);
    //ee_printf("CORE1_SystemCoreClock: %d\n", SystemCoreClock);


#ifdef CORE1_IMAGE_COPY_TO_RAM
    /* Calculate size of the image  - not required on MCUXpresso IDE. MCUXpresso copies the secondary core
       image to the target memory during startup automatically */
    uint32_t core1_image_size;
    core1_image_size = get_core1_image_size();
//    ee_printf("Copy Secondary core image to address: 0x%x, size: %d\n", CORE1_BOOT_ADDRESS, core1_image_size);

    /* Copy Secondary core application from FLASH to the target memory. */
    memcpy(CORE1_BOOT_ADDRESS, (void *)CORE1_IMAGE_START, core1_image_size);
#endif


    MCMGR_StartCore(kMCMGR_Core1, CORE1_BOOT_ADDRESS, 5, kMCMGR_Start_Synchronous);
//    NVIC_DisableIRQ(MAILBOX_IRQn);









    #ifndef COREMARK_SCORE_TEST
    /* Enable Automatic Clock Gating for all modules */
    SYSCON->AUTOCLKGATEOVERRIDE = 0xC0DE0000;
    /* Enable clocks only for : ROM, all SRAM_CTRL, Flexcomm0 and Analog Controller. All others modules clocks are disabled */
#ifdef RUN_IN_RAMX
    SYSCON->AHBCLKCTRLX[0] = 0x00000078;    /* SRAM_CTRL1,2,3,4  */
    SYSCON->AHBCLKCTRLX[1] = 0x00000000;    /* Flexcomm 0 */
    SYSCON->AHBCLKCTRLX[2] = 0x00000000;    /* Analog Controller */
#endif
#ifdef RUN_IN_FLASH
    SYSCON->AHBCLKCTRLX[0] = 0x000001FB;    /* SRAM_CTRL1,2,3,4, FMC  */
    SYSCON->AHBCLKCTRLX[1] = 0x00000000;    /* Flexcomm 0 */
    SYSCON->AHBCLKCTRLX[2] = 0x00000000;    /* Analog Controller */
#endif

  /*
   * Power down all modules not required
   */
  PMC->PDRUNCFGSET0 =   //PMC_PDRUNCFG0_PDEN_DCDC_MASK          |
                        //PMC_PDRUNCFG0_PDEN_BIAS_MASK          |
                        PMC_PDRUNCFG0_PDEN_BODCORE_MASK         |
                        PMC_PDRUNCFG0_PDEN_BODVBAT_MASK         |
                        //PMC_PDRUNCFG0_PDEN_FRO192M_MASK       |
                        PMC_PDRUNCFG0_PDEN_FRO32K_MASK          |
                        PMC_PDRUNCFG0_PDEN_XTAL32K_MASK         |
                        PMC_PDRUNCFG0_PDEN_XTAL32M_MASK         |
                        PMC_PDRUNCFG0_PDEN_PLL0_MASK            |
                        PMC_PDRUNCFG0_PDEN_PLL1_MASK            |
                        PMC_PDRUNCFG0_PDEN_USBFSPHY_MASK        |
                        PMC_PDRUNCFG0_PDEN_USBHSPHY_MASK        |
                        PMC_PDRUNCFG0_PDEN_COMP_MASK            |
                        //PMC_PDRUNCFG0_PDEN_LDOMEM_MASK        |
                        PMC_PDRUNCFG0_PDEN_LDODEEPSLEEP_MASK    |
                        PMC_PDRUNCFG0_PDEN_LDOUSBHS_MASK        |
                        PMC_PDRUNCFG0_PDEN_AUXBIAS_MASK         |
                        PMC_PDRUNCFG0_PDEN_LDOXO32M_MASK        |
                        //PMC_PDRUNCFG0_PDEN_LDOFLASHNV_MASK    |
                        PMC_PDRUNCFG0_PDEN_RNG_MASK             |
                        PMC_PDRUNCFG0_PDEN_PLL0_SSCG_MASK;
#endif


  #if RUN_IN_RAMX
    /* Re-allicate interrput VTOR table to SRAM-0 */
    memcpy((uint32_t*)0x20000000, (uint32_t*)SCB->VTOR, 0x140);
    SCB->VTOR = (uint32_t)0x20000000;
    /* Power Down the Flash */
    //FLASH->CMD = 0x1;
#endif


}






/* Initialize debug console. */
void BOARD_InitDebugConsole(void)
{
    RESET_ClearPeripheralReset(BOARD_DEBUG_UART_RST);

    uint32_t uartClkSrcFreq = BOARD_DEBUG_UART_CLK_FREQ;

    DbgConsole_Init(BOARD_DEBUG_UART_INSTANCE, BOARD_DEBUG_UART_BAUDRATE, BOARD_DEBUG_UART_TYPE, uartClkSrcFreq);
}

void BOARD_InitDebugConsole_Core1(void)
{
    RESET_ClearPeripheralReset(BOARD_DEBUG_UART_RST_CORE1);

    uint32_t uartClkSrcFreq = BOARD_DEBUG_UART_CLK_FREQ_CORE1;

    DbgConsole_Init(BOARD_DEBUG_UART_INSTANCE_CORE1, BOARD_DEBUG_UART_BAUDRATE_CORE1, BOARD_DEBUG_UART_TYPE_CORE1,
                    uartClkSrcFreq);
}

#if defined(SDK_I2C_BASED_COMPONENT_USED) && SDK_I2C_BASED_COMPONENT_USED
void BOARD_I2C_Init(I2C_Type *base, uint32_t clkSrc_Hz)
{
    i2c_master_config_t i2cConfig = {0};

    I2C_MasterGetDefaultConfig(&i2cConfig);
    I2C_MasterInit(base, &i2cConfig, clkSrc_Hz);
}

status_t BOARD_I2C_Send(I2C_Type *base,
                        uint8_t deviceAddress,
                        uint32_t subAddress,
                        uint8_t subaddressSize,
                        uint8_t *txBuff,
                        uint8_t txBuffSize)
{
    i2c_master_transfer_t masterXfer;

    /* Prepare transfer structure. */
    masterXfer.slaveAddress = deviceAddress;
    masterXfer.direction = kI2C_Write;
    masterXfer.subaddress = subAddress;
    masterXfer.subaddressSize = subaddressSize;
    masterXfer.data = txBuff;
    masterXfer.dataSize = txBuffSize;
    masterXfer.flags = kI2C_TransferDefaultFlag;

    return I2C_MasterTransferBlocking(base, &masterXfer);
}

status_t BOARD_I2C_Receive(I2C_Type *base,
                           uint8_t deviceAddress,
                           uint32_t subAddress,
                           uint8_t subaddressSize,
                           uint8_t *rxBuff,
                           uint8_t rxBuffSize)
{
    i2c_master_transfer_t masterXfer;

    /* Prepare transfer structure. */
    masterXfer.slaveAddress = deviceAddress;
    masterXfer.subaddress = subAddress;
    masterXfer.subaddressSize = subaddressSize;
    masterXfer.data = rxBuff;
    masterXfer.dataSize = rxBuffSize;
    masterXfer.direction = kI2C_Read;
    masterXfer.flags = kI2C_TransferDefaultFlag;

    return I2C_MasterTransferBlocking(base, &masterXfer);
}

void BOARD_Codec_I2C_Init(void)
{
    BOARD_I2C_Init(BOARD_CODEC_I2C_BASEADDR, BOARD_CODEC_I2C_CLOCK_FREQ);
}

status_t BOARD_Codec_I2C_Send(
    uint8_t deviceAddress, uint32_t subAddress, uint8_t subAddressSize, const uint8_t *txBuff, uint8_t txBuffSize)
{
    return BOARD_I2C_Send(BOARD_CODEC_I2C_BASEADDR, deviceAddress, subAddress, subAddressSize, (uint8_t *)txBuff,
                          txBuffSize);
}

status_t BOARD_Codec_I2C_Receive(
    uint8_t deviceAddress, uint32_t subAddress, uint8_t subAddressSize, uint8_t *rxBuff, uint8_t rxBuffSize)
{
    return BOARD_I2C_Receive(BOARD_CODEC_I2C_BASEADDR, deviceAddress, subAddress, subAddressSize, rxBuff, rxBuffSize);
}
#endif /* SDK_I2C_BASED_COMPONENT_USED */
