/*
 * Copyright (c) 2016, Freescale Semiconductor, Inc.
 * Copyright 2016-2018 NXP
 * All rights reserved.
 *
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include "fsl_flexspi.h"
#include "app.h"
//#include "evkmimxrt1020_flexspi_nor_config.h"
#include "fsl_debug_console.h"
#include "fsl_edma.h"
#include "fsl_dmamux.h"
/*******************************************************************************
* Definitions
******************************************************************************/
#define FLASH_BUSY_STATUS_POL 1
#define FLASH_BUSY_STATUS_OFFSET 0
#define FLASH_ERROR_STATUS_MASK 0x0e
#define FLASH_A_SIZE                                    (8u * 1024u * 1024u)
#define FLEXSPI_LUT_KEY_VAL (0x5AF05AF0ul)
/*******************************************************************************
* Prototypes
******************************************************************************/
#define FLEXSPI_DMA_TX_CHANNEL            0
#define FLEXSPI_DMA_RX_CHANNEL            1
#define FLEXSPI_DMA                       DMA0
/*******************************************************************************
 * Variables
 *****************************************************************************/
//extern flexspi_device_config_t deviceconfig;
extern const uint32_t customLUT[];
static edma_handle_t g_EDMA_FlexSPITxHandle;
static edma_handle_t g_EDMA_FlexSPIRxHandle;

extern status_t FLEXSPI_CheckAndClearError(FLEXSPI_Type *base, uint32_t status);
/*******************************************************************************
 * Code
 ******************************************************************************/
flexspi_device_config_t deviceconfig = {
    .flexspiRootClk = 50000000,
    .flashSize = 0x2000,
    .CSIntervalUnit = kFLEXSPI_CsIntervalUnit1SckCycle,
    .CSInterval = 2,
    .CSHoldTime = 3,
    .CSSetupTime = 3,
    .dataValidTime = 0,
    .columnspace = 0,
    .enableWordAddress = 0,
    .AWRSeqIndex = 0,
    .AWRSeqNumber = 0,
    .ARDSeqIndex = 0,
    .ARDSeqNumber = 1,
    .AHBWriteWaitUnit = kFLEXSPI_AhbWriteWaitUnit2AhbCycle,
    .AHBWriteWaitInterval = 0,
};
void FLEXSPI_DMA_Init(void)
{
    edma_config_t userConfig;
    DMAMUX_Init(DMAMUX);
    DMAMUX_SetSource(DMAMUX, FLEXSPI_DMA_TX_CHANNEL, kDmaRequestMuxFlexSPITx);
    DMAMUX_EnableChannel(DMAMUX, FLEXSPI_DMA_TX_CHANNEL);
    DMAMUX_SetSource(DMAMUX, FLEXSPI_DMA_RX_CHANNEL, kDmaRequestMuxFlexSPIRx);
    DMAMUX_EnableChannel(DMAMUX, FLEXSPI_DMA_RX_CHANNEL);
    /* Configure EDMA one shot transfer */
    /*
     * userConfig.enableRoundRobinArbitration = false;
     * userConfig.enableHaltOnError = true;
     * userConfig.enableContinuousLinkMode = false;
     * userConfig.enableDebugMode = false;
     */
    EDMA_GetDefaultConfig(&userConfig);
    EDMA_Init(FLEXSPI_DMA, &userConfig);
    EDMA_CreateHandle(&g_EDMA_FlexSPITxHandle, FLEXSPI_DMA, FLEXSPI_DMA_TX_CHANNEL);
    EDMA_CreateHandle(&g_EDMA_FlexSPIRxHandle, FLEXSPI_DMA, FLEXSPI_DMA_RX_CHANNEL);
    //EDMA_SetCallback(&g_EDMA_FlexSPITxHandle, EDMA_Callback, NULL);

  
}
__ramfunc void AHBPrefetchEnable(FLEXSPI_Type *base)
{
  base->AHBCR |= 0x20;
}
__ramfunc void AHBPrefetchDisable(FLEXSPI_Type *base)
{
  base->AHBCR &= ~0x20;
}
__ramfunc void FLEXSPI_SoftwareReset_RAM(FLEXSPI_Type *base)
{
    base->MCR0 |= FLEXSPI_MCR0_SWRESET_MASK;
    while (base->MCR0 & FLEXSPI_MCR0_SWRESET_MASK)
    {
    }
}
status_t FLEXSPI_WriteBlocking_DMA(FLEXSPI_Type *base, uint32_t *buffer, size_t size)
{
    uint8_t txWatermark = ((base->IPTXFCR & FLEXSPI_IPTXFCR_TXWMRK_MASK) >> FLEXSPI_IPTXFCR_TXWMRK_SHIFT) + 1;
    status_t result = kStatus_Success;
    edma_transfer_config_t transferConfig;
    uint32_t status;
    status = base->INTR;
    result = FLEXSPI_CheckAndClearError(base, status);

    if (result)
    {
        return result;
    }
    
    EDMA_PrepareTransfer(&transferConfig, buffer, 8, (void *)&base->TFDR[0], 8,
                         txWatermark*8, size, kEDMA_MemoryToMemory);
    transferConfig.destOffset = 0;
    transferConfig.srcOffset = 8;
    EDMA_SubmitTransfer(&g_EDMA_FlexSPITxHandle, &transferConfig);
    g_EDMA_FlexSPITxHandle.base->TCD[g_EDMA_FlexSPITxHandle.channel].CSR &= ~DMA_CSR_INTMAJOR_MASK;
    EDMA_StartTransfer(&g_EDMA_FlexSPITxHandle);
    base->IPTXFCR |= FLEXSPI_IPTXFCR_TXDMAEN_MASK;
    
    //GPIO6->DR_TOGGLE = 0x01<<9;
    
    
    base->IPCMD |= FLEXSPI_IPCMD_TRG_MASK;
    while(!(FLEXSPI_DMA->TCD[FLEXSPI_DMA_TX_CHANNEL].CSR & DMA_CSR_DONE_MASK));
    EDMA_ClearChannelStatusFlags(FLEXSPI_DMA, FLEXSPI_DMA_TX_CHANNEL, kEDMA_DoneFlag|kEDMA_ErrorFlag);
    EDMA_AbortTransfer(&g_EDMA_FlexSPITxHandle);
    //GPIO6->DR_TOGGLE = 0x01<<9;
    
    

    
   
    base->IPTXFCR &= ~FLEXSPI_IPTXFCR_TXDMAEN_MASK;
    status = base->INTR;
    result = FLEXSPI_CheckAndClearError(base, status);
  
    return result;
}



status_t FLEXSPI_TransferBlocking_DMA(FLEXSPI_Type *base, flexspi_transfer_t *xfer)
{
    uint32_t configValue = 0;
    status_t result = kStatus_Success;

    /* Clear sequence pointer before sending data to external devices. */
    base->FLSHCR2[xfer->port] |= FLEXSPI_FLSHCR2_CLRINSTRPTR_MASK;

    /* Clear former pending status before start this tranfer. */
    base->INTR |= FLEXSPI_INTR_AHBCMDERR_MASK | FLEXSPI_INTR_IPCMDERR_MASK | FLEXSPI_INTR_AHBCMDGE_MASK |
                  FLEXSPI_INTR_IPCMDGE_MASK;

    /* Configure base addresss. */
    base->IPCR0 = xfer->deviceAddress;

    /* Reset fifos. */
    base->IPTXFCR |= FLEXSPI_IPTXFCR_CLRIPTXF_MASK;
    base->IPRXFCR |= FLEXSPI_IPRXFCR_CLRIPRXF_MASK;

    /* Configure data size. */
    if ((xfer->cmdType == kFLEXSPI_Read) || (xfer->cmdType == kFLEXSPI_Write) || (xfer->cmdType == kFLEXSPI_Config))
    {
        configValue = FLEXSPI_IPCR1_IDATSZ(xfer->dataSize);
    }

    /* Configure sequence ID. */
    configValue |= FLEXSPI_IPCR1_ISEQID(xfer->seqIndex) | FLEXSPI_IPCR1_ISEQNUM(xfer->SeqNumber - 1);
    base->IPCR1 = configValue;

    //disable interrupt setting.
    uint32_t regPrimask = DisableGlobalIRQ();
    
    /* Start Transfer. */
    if ((xfer->cmdType == kFLEXSPI_Write) || (xfer->cmdType == kFLEXSPI_Config))
    {
        result = FLEXSPI_WriteBlocking_DMA(base, xfer->data, xfer->dataSize);
    }
    else if (xfer->cmdType == kFLEXSPI_Read)
    {
        base->IPCMD |= FLEXSPI_IPCMD_TRG_MASK;
        result = FLEXSPI_ReadBlocking(base, xfer->data, xfer->dataSize);
    }
    else
    {
        base->IPCMD |= FLEXSPI_IPCMD_TRG_MASK;
    }
    /* Wait for bus idle. */
    while (!((base->STS0 & FLEXSPI_STS0_ARBIDLE_MASK) && (base->STS0 & FLEXSPI_STS0_SEQIDLE_MASK)))
    {
    }
    
    //restore interrupt setting.
    EnableGlobalIRQ(regPrimask);
    
    

    if (xfer->cmdType == kFLEXSPI_Command)
    {
        result = FLEXSPI_CheckAndClearError(base, base->INTR);
    }

    return result;
}
status_t flexspi_nor_write_enable(FLEXSPI_Type *base, uint32_t baseAddr)
{
    flexspi_transfer_t flashXfer;
    status_t status;

    /* Write enable */
    flashXfer.deviceAddress = baseAddr;
    flashXfer.port = kFLEXSPI_PortA1;
    flashXfer.cmdType = kFLEXSPI_Command;
    flashXfer.SeqNumber = 1;
    flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_WRITEENABLE;

    status = FLEXSPI_TransferBlocking_DMA(base, &flashXfer);

    return status;
}

status_t flexspi_nor_wait_bus_busy(FLEXSPI_Type *base)
{
    /* Wait status ready. */
    bool isBusy;
    uint32_t readValue;
    status_t status;
    flexspi_transfer_t flashXfer;

    flashXfer.deviceAddress = FLASH_A_SIZE;
    flashXfer.port = kFLEXSPI_PortA1;
    flashXfer.cmdType = kFLEXSPI_Read;
    flashXfer.SeqNumber = 1;
    flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_READSTATUS;
    flashXfer.data = &readValue;
    flashXfer.dataSize = 1;

    do
    {
        status = FLEXSPI_TransferBlocking_DMA(base, &flashXfer);
        if (status != kStatus_Success)
        {
            return status;
        }
        if (FLASH_BUSY_STATUS_POL)
        {
            if (readValue & (1U << FLASH_BUSY_STATUS_OFFSET))
            {
                isBusy = true;
            }
            else
            {
                isBusy = false;
            }
        }
        else
        {
            if (readValue & (1U << FLASH_BUSY_STATUS_OFFSET))
            {
                isBusy = false;
            }
            else
            {
                isBusy = true;
            }
        }

    } while (isBusy);

    return status;
}

status_t flexspi_nor_flash_erase_sector(FLEXSPI_Type *base, uint32_t address)
{
    status_t status;
    flexspi_transfer_t flashXfer;

    /* Write enable */
    flashXfer.deviceAddress = address;
    flashXfer.port = kFLEXSPI_PortA1;
    flashXfer.cmdType = kFLEXSPI_Command;
    flashXfer.SeqNumber = 1;
    flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_WRITEENABLE;

    status = FLEXSPI_TransferBlocking_DMA(base, &flashXfer);

    if (status != kStatus_Success)
    {
        return status;
    }

    flashXfer.deviceAddress = address;
    flashXfer.port = kFLEXSPI_PortA1;
    flashXfer.cmdType = kFLEXSPI_Command;
    flashXfer.SeqNumber = 1;
    flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_ERASESECTOR;
    status = FLEXSPI_TransferBlocking_DMA(base, &flashXfer);

    if (status != kStatus_Success)
    {
        return status;
    }

    status = flexspi_nor_wait_bus_busy(base);

    return status;
}

status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t dstAddr, const uint32_t *src)
{
    status_t status;
    flexspi_transfer_t flashXfer;

    /* Write enable */
    status = flexspi_nor_write_enable(base, dstAddr);

    if (status != kStatus_Success)
    {
        return status;
    }

    /* Prepare page program command */
    flashXfer.deviceAddress = dstAddr;
    flashXfer.port = kFLEXSPI_PortA1;
    flashXfer.cmdType = kFLEXSPI_Write;
    flashXfer.SeqNumber = 1;
    flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD;
    flashXfer.data = (uint32_t *)src;
    flashXfer.dataSize = FLASH_PAGE_SIZE;
  
    status = FLEXSPI_TransferBlocking_DMA(base, &flashXfer);
    
    if (status != kStatus_Success)
    {
        return status;
    }

    status = flexspi_nor_wait_bus_busy(base);

    return status;
}

__ramfunc void FLEXSPI_UpdateLUT_RAM(FLEXSPI_Type *base, uint32_t index, const uint32_t *cmd, uint32_t count)
{
    assert(index < 64U);

    uint8_t i = 0;
    volatile uint32_t *lutBase;
    
    // disable interrupt to avoid issue.
    __disable_irq();
    
    AHBPrefetchDisable(base);
    FLEXSPI_SoftwareReset_RAM(base);

    /* Wait for bus idle before change flash configuration. */
    while (!((base->STS0 & FLEXSPI_STS0_ARBIDLE_MASK) && (base->STS0 & FLEXSPI_STS0_SEQIDLE_MASK)))
    {
    }

    /* Unlock LUT for update. */
    base->LUTKEY = FLEXSPI_LUT_KEY_VAL;
    base->LUTCR = 0x02;

    lutBase = &base->LUT[index];
    for (i = 0; i < count; i++)
    {
        *lutBase++ = *cmd++;
    }

    /* Lock LUT. */
    base->LUTKEY = FLEXSPI_LUT_KEY_VAL;
    base->LUTCR = 0x01;
    
    AHBPrefetchEnable(base);
    
    //restore interrupt setting.
    __enable_irq();
 
}




status_t flexspi_nor_get_vendor_id(FLEXSPI_Type *base, uint8_t *vendorId)
{
    uint32_t temp;
    flexspi_transfer_t flashXfer;
    flashXfer.deviceAddress = 0;
    flashXfer.port = kFLEXSPI_PortA1;
    flashXfer.cmdType = kFLEXSPI_Read;
    flashXfer.SeqNumber = 1;
    flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_READID;
    flashXfer.data = &temp;
    flashXfer.dataSize = 1;

    status_t status = FLEXSPI_TransferBlocking(base, &flashXfer);

    *vendorId = temp;

    return status;
}

status_t flexspi_nor_erase_chip(FLEXSPI_Type *base)
{
    status_t status;
    flexspi_transfer_t flashXfer;

    /* Write enable */
    status = flexspi_nor_write_enable(base, 0);

    if (status != kStatus_Success)
    {
        return status;
    }

    flashXfer.deviceAddress = 0;
    flashXfer.port = kFLEXSPI_PortA1;
    flashXfer.cmdType = kFLEXSPI_Command;
    flashXfer.SeqNumber = 1;
    flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_ERASECHIP;

    status = FLEXSPI_TransferBlocking(base, &flashXfer);

    if (status != kStatus_Success)
    {
        return status;
    }

    status = flexspi_nor_wait_bus_busy(base);

    return status;
}

__ramfunc status_t FLEXSPI_CheckAndClearError_RAM(FLEXSPI_Type *base, uint32_t status)
{
    status_t result = kStatus_Success;

    /* Check for error. */
    status &= kFLEXSPI_SequenceExecutionTimeoutFlag | kFLEXSPI_IpCommandSequenceErrorFlag |
                  kFLEXSPI_IpCommandGrantTimeoutFlag;
    if (status)
    {
        /* Select the correct error code.. */
        if (status & kFLEXSPI_SequenceExecutionTimeoutFlag)
        {
            result = kStatus_FLEXSPI_SequenceExecutionTimeout;
        }
        else if (status & kFLEXSPI_IpCommandSequenceErrorFlag)
        {
            result = kStatus_FLEXSPI_IpCommandSequenceError;
        }
        else if (status & kFLEXSPI_IpCommandGrantTimeoutFlag)
        {
            result = kStatus_FLEXSPI_IpCommandGrantTimeout;
        }
        else
        {
            assert(false);
        }

        /* Clear the flags. */
				base->INTR = status;
        //FLEXSPI_ClearInterruptStatusFlags(base, status);

        /* Reset fifos. These flags clear automatically. */
        base->IPTXFCR |= FLEXSPI_IPTXFCR_CLRIPTXF_MASK;
        base->IPRXFCR |= FLEXSPI_IPRXFCR_CLRIPRXF_MASK;
    }

    return result;
}
__ramfunc status_t FLEXSPI_WriteBlocking_RAM(FLEXSPI_Type *base, uint32_t *buffer, size_t size)
{
    uint8_t txWatermark = ((base->IPTXFCR & FLEXSPI_IPTXFCR_TXWMRK_MASK) >> FLEXSPI_IPTXFCR_TXWMRK_SHIFT) + 1;
    uint32_t status;
    status_t result = kStatus_Success;
    uint32_t i = 0;

    /* Send data buffer */
    while (size)
    {
        /* Wait until there is room in the fifo. This also checks for errors. */
        while (!((status = base->INTR) & kFLEXSPI_IpTxFifoWatermarkEmpltyFlag))
        {
        }

        result = FLEXSPI_CheckAndClearError_RAM(base, status);

        if (result)
        {
            return result;
        }

        /* Write watermark level data into tx fifo . */
        if (size >= 8 * txWatermark)
        {
            for (i = 0; i < 2 * txWatermark; i++)
            {
                base->TFDR[i] = *buffer++;
            }

            size = size - 8 * txWatermark;
        }
        else
        {
            for (i = 0; i < (size / 4 + 1); i++)
            {
                base->TFDR[i] = *buffer++;
            }
            size = 0;
        }

        /* Push a watermark level datas into IP TX FIFO. */
        base->INTR |= kFLEXSPI_IpTxFifoWatermarkEmpltyFlag;
    }

    return result;
}

/*!
 * brief Receives a buffer of data bytes using a blocking method.
 * note This function blocks via polling until all bytes have been sent.
 * param base FLEXSPI peripheral base address
 * param buffer The data bytes to send
 * param size The number of data bytes to receive
 * retval kStatus_Success read success without error
 * retval kStatus_FLEXSPI_SequenceExecutionTimeout sequence execution timeout
 * retval kStatus_FLEXSPI_IpCommandSequenceError IP command sequencen error detected
 * retval kStatus_FLEXSPI_IpCommandGrantTimeout IP command grant timeout detected
 */
__ramfunc status_t FLEXSPI_ReadBlocking_RAM(FLEXSPI_Type *base, uint32_t *buffer, size_t size)
{
    uint8_t rxWatermark = ((base->IPRXFCR & FLEXSPI_IPRXFCR_RXWMRK_MASK) >> FLEXSPI_IPRXFCR_RXWMRK_SHIFT) + 1;
    uint32_t status;
    status_t result = kStatus_Success;
    uint32_t i = 0;

    /* Send data buffer */
    while (size)
    {
        if (size >= 8 * rxWatermark)
        {
            /* Wait until there is room in the fifo. This also checks for errors. */
            while (!((status = base->INTR) & kFLEXSPI_IpRxFifoWatermarkAvailableFlag))
            {
                result = FLEXSPI_CheckAndClearError_RAM(base, status);

                if (result)
                {
                    return result;
                }
            }
        }
        else
        {
            /* Wait fill level. This also checks for errors. */
            while (size > ((((base->IPRXFSTS) & FLEXSPI_IPRXFSTS_FILL_MASK) >> FLEXSPI_IPRXFSTS_FILL_SHIFT) * 8U))
            {
                result = FLEXSPI_CheckAndClearError_RAM(base, base->INTR);

                if (result)
                {
                    return result;
                }
            }
        }

        result = FLEXSPI_CheckAndClearError_RAM(base, base->INTR);

        if (result)
        {
            return result;
        }

        /* Read watermark level data from rx fifo . */
        if (size >= 8 * rxWatermark)
        {
            for (i = 0; i < 2 * rxWatermark; i++)
            {
                *buffer++ = base->RFDR[i];
            }

            size = size - 8 * rxWatermark;
        }
        else
        {
            for (i = 0; i < (size / 4 + 1); i++)
            {
                *buffer++ = base->RFDR[i];
            }
            size = 0;
        }

        /* Pop out a watermark level datas from IP RX FIFO. */
        base->INTR |= kFLEXSPI_IpRxFifoWatermarkAvailableFlag;
    }

    return result;
}
__ramfunc status_t FLEXSPI_TransferBlocking_RAM(FLEXSPI_Type *base, flexspi_transfer_t *xfer)
{
    uint32_t configValue = 0;
    status_t result = kStatus_Success;

    /* Clear sequence pointer before sending data to external devices. */
    base->FLSHCR2[xfer->port] |= FLEXSPI_FLSHCR2_CLRINSTRPTR_MASK;

    /* Clear former pending status before start this tranfer. */
    base->INTR |= FLEXSPI_INTR_AHBCMDERR_MASK | FLEXSPI_INTR_IPCMDERR_MASK | FLEXSPI_INTR_AHBCMDGE_MASK |
                  FLEXSPI_INTR_IPCMDGE_MASK;

    /* Configure base addresss. */
    base->IPCR0 = xfer->deviceAddress;

    /* Reset fifos. */
    base->IPTXFCR |= FLEXSPI_IPTXFCR_CLRIPTXF_MASK;
    base->IPRXFCR |= FLEXSPI_IPRXFCR_CLRIPRXF_MASK;

    /* Configure data size. */
    if ((xfer->cmdType == kFLEXSPI_Read) || (xfer->cmdType == kFLEXSPI_Write) || (xfer->cmdType == kFLEXSPI_Config))
    {
        configValue = FLEXSPI_IPCR1_IDATSZ(xfer->dataSize);
    }

    /* Configure sequence ID. */
    configValue |= FLEXSPI_IPCR1_ISEQID(xfer->seqIndex) | FLEXSPI_IPCR1_ISEQNUM(xfer->SeqNumber - 1);
    base->IPCR1 = configValue;

    /* Start Transfer. */
    base->IPCMD |= FLEXSPI_IPCMD_TRG_MASK;

    if ((xfer->cmdType == kFLEXSPI_Write) || (xfer->cmdType == kFLEXSPI_Config))
    {
        result = FLEXSPI_WriteBlocking_RAM(base, xfer->data, xfer->dataSize);
    }
    else if (xfer->cmdType == kFLEXSPI_Read)
    {
        result = FLEXSPI_ReadBlocking_RAM(base, xfer->data, xfer->dataSize);
    }
    else
    {
    }

    /* Wait for bus idle. */
    while (!((base->STS0 & FLEXSPI_STS0_ARBIDLE_MASK) && (base->STS0 & FLEXSPI_STS0_SEQIDLE_MASK)))
    {
    }

    if (xfer->cmdType == kFLEXSPI_Command)
    {
        result = FLEXSPI_CheckAndClearError_RAM(base, base->INTR);
    }

    return result;
}
status_t flexspi_nor_enable_quad_mode(FLEXSPI_Type *base)
{
    flexspi_transfer_t flashXfer;
    status_t status;
    uint32_t writeValue = 0x40;
    
    /* Write enable */
    status = flexspi_nor_write_enable(base, 0x800000);

    if (status != kStatus_Success)
    {
        return status;
    }

    /* Enable quad mode. */
    flashXfer.deviceAddress = 0x800000;
    flashXfer.port          = kFLEXSPI_PortA2;
    flashXfer.cmdType       = kFLEXSPI_Write;
    flashXfer.SeqNumber     = 1;
    flashXfer.seqIndex      = NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG;
    flashXfer.data          = &writeValue;
    flashXfer.dataSize      = 1;
    uint32_t regPrimask;
    regPrimask = DisableGlobalIRQ();
    status = FLEXSPI_TransferBlocking_RAM(base, &flashXfer);
    EnableGlobalIRQ(regPrimask);
    if (status != kStatus_Success)
    {
        return status;
    }

    status = flexspi_nor_wait_bus_busy(base);

    /* Do software reset. */
  //  FLEXSPI_SoftwareReset_RAM(base);

    return status;
}