/* Copyright Statement:
 *
 * This software/firmware and related documentation "Autochips Software") are
 * protected under relevant copyright laws. The information contained herein
 * is confidential and proprietary to Autochips Inc. and/or its licensors.
 * Without the prior written permission of Autochips inc. and/or its licensors,
 * any reproduction, modification, use or disclosure of Autochips Software,
 * and information contained herein, in whole or in part, shall be strictly prohibited.
 *
 * Copyright(C) 2020, Autochips ( All rights reserved. )
 *
 * BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
 * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("Autochips SOFTWARE")
 * RECEIVED FROM Autochips AND/OR ITS REPRESENTATIVES ARE PROVIDED TO BUYER ON
 * AN "AS-IS" BASIS ONLY. Autochips EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
 * NEITHER DOES Autochips PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
 * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
 * SUPPLIED WITH THE Autochips SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH
 * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. Autochips SHALL ALSO
 * NOT BE RESPONSIBLE FOR ANY Autochips SOFTWARE RELEASES MADE TO BUYER'S
 * SPECIFICATION OR TO CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM.
 *
 * BUYER'S SOLE AND EXCLUSIVE REMEDY AND Autochips'S ENTIRE AND CUMULATIVE
 * LIABILITY WITH RESPECT TO THE Autochips SOFTWARE RELEASED HEREUNDER WILL BE,
 * AT Autochips'S OPTION, TO REVISE OR REPLACE THE Autochips SOFTWARE AT ISSUE,
 * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY BUYER TO
 *
 * Autochips FOR SUCH Autochips SOFTWARE AT ISSUE.
 *
 * THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE
 * WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT OF
 * LAWS PRINCIPLES.  ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING THEREOF AND
 * RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN FRANCISCO, CA, UNDER
 * THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE (ICC).
 *****************************************************************************/

/*!
* @file ac780x_eflash.c
*
* @brief This file provides EFLASH integration functions.
*
*/

/* ===========================================  Includes  =========================================== */
#include "ac780x_eflash_reg.h"
#include "device_assert.h"
/* ============================================  Define  ============================================ */
#define EFLSH_UNLOCK_KEY1                   0xac7811UL          /* eflash controler ulock key 1    */
#define EFLSH_UNLOCK_KEY2                   0x01234567UL        /* eflash controler ulock key 2    */
#define NUM_OF_OPTION_BYTE_REG              (48UL >> 2)         /* option byte address total count */

/* ======================================  Functions define  ======================================== */
/*!
 * @brief Unlock the eflash control
 *
 * @param[in] none
 * @return EFLASH STATUS: eflash operation status
 */
EFLASH_StatusType EFLASH_UnlockCtrl(void)
{
    EFLASH_StatusType statusRes = EFLASH_STATUS_SUCCESS;
    uint8_t ctrlLockBit = 0;
    uint32_t timeoutCount = 0;

    ctrlLockBit = EFLASH_GetCtrlLockBitReg();
    while (1 == ctrlLockBit)
    {
        EFLASH_SetKeyReg(EFLSH_UNLOCK_KEY1);
        EFLASH_SetKeyReg(EFLSH_UNLOCK_KEY2);

        if (100 < timeoutCount)
        {
            statusRes = EFLASH_STATUS_TIMEOUT;
            break;
        }
        ctrlLockBit = EFLASH_GetCtrlLockBitReg();
        timeoutCount++;
    }

    return statusRes;
}

/*!
 * @brief Lock the eflash control
 *
 * @param[in] none
 * @return none
 */
void EFLASH_LockCtrl(void)
{
    EFLASH_LockCtrlReg();
}

/*!
 * @brief Waiting for the end of all operation
 *
 * @param[in] timeout: Time out value
 * @return EFLASH STATUS: eflash operation status
 */
EFLASH_StatusType EFLASH_WaitForLastOperation(uint32_t timeout)
{
    EFLASH_StatusType statusRes = EFLASH_STATUS_SUCCESS;

    if (1 == EFLASH_GetPVDWarningReg())
    {
        statusRes = EFLASH_STATUS_PVDWARNING_ERROR;
    }
    else
    {
        while ((1 == EFLASH_GetAnyBusySTReg()) && (0 != timeout))
        {
            timeout--;
        }
        if (0 == timeout)
        {
            statusRes = EFLASH_STATUS_TIMEOUT;
        }
    }

    return statusRes;
}

/*!
 * @brief Waiting for the end of the operation
 *
 * @param[in] timeout: Time out
 * @return EFLASH STATUS: eflash operation status
 */
EFLASH_StatusType EFLASH_WaitEop(uint32_t timeout)
{
    EFLASH_StatusType statusRes = EFLASH_STATUS_SUCCESS;

    while ((1 != EFLASH_GetEopReg()) && (0 != timeout))
    {
        timeout--;
    }
    if (0 == timeout)
    {
        statusRes = EFLASH_STATUS_TIMEOUT;
    }

    return statusRes;
}


/*!
 * @brief Erase specified eflash user area address
 *
 * @param[in] pageAddress: Specified eflash addrees to be erased
 * @return EFLASH STATUS: eflash operation status
 */
EFLASH_StatusType EFLASH_PageErase(uint32_t pageAddress)
{
    EFLASH_StatusType statusRes = EFLASH_STATUS_SUCCESS;
    uint32_t cmdValue = 0x0;

    /* check eflash address */
    DEVICE_ASSERT(EFLASH_BASE_ADDRESS <= pageAddress);
    DEVICE_ASSERT(EFLASH_END_ADDRESS > pageAddress);
    /* Wait for last operation to be completed */
    statusRes = EFLASH_WaitForLastOperation(EFLASH_PAGE_ERASE_TIMEOUT);
    if (EFLASH_STATUS_SUCCESS != statusRes)
    {
        return statusRes;
    }
    /* Configure start address */
    EFLASH_SetStartAddressReg(pageAddress);

    /* Configure command and CMD_ST goes back to 0 */
    cmdValue = (uint32_t)EFLASH_CMD_PAGERASE;  /* Normal operation */
    EFLASH_SetCtrlReg1(cmdValue);

    /* Trigger to start */
    EFLASH_TrigCtrlCmdReg();

    /* Check whether the command is finished */
    statusRes = EFLASH_WaitForLastOperation(EFLASH_PAGE_ERASE_TIMEOUT);
    if (EFLASH_STATUS_SUCCESS == statusRes)
    {
        statusRes = EFLASH_WaitEop(EFLASH_PAGE_ERASE_TIMEOUT);
        if (EFLASH_STATUS_SUCCESS == statusRes)
        {
            /* Check error */
            if (EFLASH_GetStatusReg() & EFLASH_SR0_ERAER_Msk)
            {
                statusRes = EFLASH_STATUS_ERAER_ERROR;
            }
            else
            {
                /* Erase page success now */
                statusRes = EFLASH_STATUS_SUCCESS;
            }
        }
        else
        {
            statusRes = EFLASH_STATUS_BUSY;
        }
    }
    EFLASH_SetCtrlReg1(0x0);

    return statusRes;
}

/*!
 * @brief User page program
 *
 * @param[in] writeAddress: Specified eflash addrees to be programed
 * @param[in] dataBuffer: Point to the data to be programed
 * @param[in] dataLength: Data length to be programed
 * @return EFLASH STATUS: eflash operation status
 */
EFLASH_StatusType EFLASH_PageProgram(uint32_t writeAddress, uint32_t *dataBuffer, uint32_t dataLength)
{
    EFLASH_StatusType statusRes = EFLASH_STATUS_SUCCESS;
    uint32_t cmdValue = 0x0;
    uint32_t dataCount = 0x0;

    /* check eflash address */
    DEVICE_ASSERT(EFLASH_BASE_ADDRESS <= writeAddress);
    DEVICE_ASSERT(EFLASH_END_ADDRESS > writeAddress);

    DEVICE_ASSERT(NULL != dataBuffer);
    /* check program length,Max length is 512 Dword */
    if (512 < dataLength)
    {
        return EFLASH_STATUS_PARAMETER_ERROR;
    }

    /* Wait for last operation to be completed */
    statusRes = EFLASH_WaitForLastOperation(EFLASH_PAGE_ERASE_TIMEOUT);
    if (EFLASH_STATUS_SUCCESS != statusRes)
    {
        return EFLASH_STATUS_BUSY;
    }
    /* Configure start address */
    EFLASH_SetStartAddressReg(writeAddress);

    /* Configure command and CMD_ST goes back to 0 */
    cmdValue = (dataLength << EFLASH_CTRL0_PROG_LENGTH_Pos) | (uint32_t)EFLASH_CMD_PAGEPROGRAM;
    EFLASH_SetCtrlReg1(cmdValue);

    /* Trigger to start */
    EFLASH_TrigCtrlCmdReg();

    /*program data */
    for (dataCount = 0; dataCount < dataLength; dataCount++)
    {
        *(uint32_t *)writeAddress = dataBuffer[dataCount];
        writeAddress += 4;
    }

    /* Check whether the command is finished */
    statusRes = EFLASH_WaitForLastOperation(EFLASH_PAGE_ERASE_TIMEOUT);
    if (EFLASH_STATUS_SUCCESS == statusRes)
    {
        statusRes =  EFLASH_WaitEop(EFLASH_PAGE_ERASE_TIMEOUT);
        if (EFLASH_STATUS_SUCCESS == statusRes)
        {
            /* Check error */
            if (EFLASH_GetStatusReg() & EFLASH_SR0_PPADRER_Msk)
            {
                statusRes = EFLASH_STATUS_PPADRER_ERROR;
            }
            else
            {
                /* Progeam page success now */
                statusRes = EFLASH_STATUS_SUCCESS;
            }
        }
        else
        {
            statusRes = EFLASH_STATUS_BUSY;
        }
    }
    else
    {
        statusRes = EFLASH_STATUS_BUSY;
    }
    EFLASH_SetCtrlReg1(0x0);

    return statusRes;
}



/* =============================================  EOF  ============================================== */
