Newer
Older
mbed-os / targets / TARGET_Cypress / TARGET_PSOC6 / mtb-pdl-cat1 / drivers / source / cy_mxotpc.c
@Dustin Crossman Dustin Crossman on 4 Jun 2021 31 KB Fix file modes.
/***************************************************************************//**
* \file cy_mxotpc.c
* \version 1.0
*
* Provides an API implementation of the OTP driver.
*
********************************************************************************
* \copyright
* Copyright 2016-2019 Cypress Semiconductor Corporation
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/

#include "cy_device.h"

#if defined (CY_IP_MXS28OTPC)

#include "cy_mxotpc.h"
#include <stdlib.h>

/* Static Functions */
static cy_mxotpc_status_t Cy_MXOTPC_GetWriteProtectedData(uint32_t otpRowNum, uint32_t otpWriteData, uint32_t *otpWriteProtData);

/* Static Data types */
/** OTP Program Enable Sequence Data */
static uint8_t otpProgramEnable[] = { 0xf, 0x4, 0x8, 0xd};

/** \cond PARAM_CHECK_MACROS */
/** Parameter check macros */ 

#define CY_MXOTPC_IS_ROW_VALID(row)              (row < CY_MXOTPC_MAX_OTP_ROW)
#define CY_MXOTPC_IS_BITNUM_VALID(bit)           (bit < 32)
#define CY_MXOTPC_IS_DEST_ADDR_ALIGNED(addr)     (!((uint32_t)addr % 4u))
#define CY_MXOTPC_IS_ARRAY_SIZE_VALID(row, size) ((row+size) < CY_MXOTPC_MAX_OTP_ROW)
#define CY_MXOTPC_IS_SIZE_VALID(size)            (size != 0)
/** \endcond */

/*******************************************************************************
* Function Name: Cy_MXOTPC_Init
****************************************************************************//**
*
* Initializes the MXOTP Driver:
* - Enables the MXOTPC IP.
*
*  \param mxotpcConfig
*  This structure contains the data that needs to be filled in OTP_CTL register.
*
* Note - Allow NULL also, meaning OTP IP will go with default Configuration 
*
*  \return the MXOTPC API status \ref cy_mxotpc_status_t.
*
*******************************************************************************/
cy_mxotpc_status_t Cy_MXOTPC_Init(cy_mxotpc_ctl_config_t const *mxotpcConfig)
{
    Cy_MXOTPC_IpEnable();

    if(mxotpcConfig != NULL)
        Cy_MXOTPC_OtpCtlConfig(mxotpcConfig);

    return CY_MXOTPC_SUCCESS;
}

/*******************************************************************************
* Function Name: Cy_MXOTPC_DeInit
****************************************************************************//**
*
* DeInitializes the MXOTP Driver:
* - Disables the MXOTPC IP.
*
* Note - Allow NULL also, meaning OTP IP will go with default Configuration 
*
*  \return the MXOTPC API status \ref cy_mxotpc_status_t.
*
*******************************************************************************/
cy_mxotpc_status_t Cy_MXOTPC_DeInit(void)
{
    Cy_MXOTPC_IpDisable();

    return CY_MXOTPC_SUCCESS;
}


/*******************************************************************************
* Function Name: Cy_MXOTPC_WriteProgramSequence
****************************************************************************//**
*
* Program Sequence for Writes
*
* 1.Write Following Bit
* OTP_CTL.OTPProg_En =1 // Enable OTP programming at top level control
* 2.Check whether OTP is busy or not
* OTP_CMD.START == 0 // OTP is not busy
* 3.Check whether programming is enabled or not (PROGRAM Enable Seq)
* OTP_STATUS.ProgOK == 1 // OTP programming enabled
* If this bit is not set, perform following steps, otherwise skip.
* a.OTP commands to enable OTP Programming 
* i.Write OTP_PROGDATA = 0xF
* ii.Write OTP_CMD reg (with CMD =0x02), VALUE:  0x9100_0000
* iii.Wait for OTP_CMD.START == 0
* iv.Repeat from point i to iii for OTP_PROGDATA 0x4, 0x8 and 0xd in sequence
* Check whether programming is enabled or not
* OTP_STATUS.ProgOK == 1 // OTP programming enabled
*
*  \return the MXOTPC API status \ref cy_mxotpc_status_t.
*
*******************************************************************************/
cy_mxotpc_status_t Cy_MXOTPC_WriteProgramSequence(void)
{
    uint32_t idx;
    cy_mxotpc_cmd_t otpCmd = {0, 0, 0};

    /* Check if programming is already enabled or not */
    if(!Cy_MXOTPC_OtpGetStatus(MXOTPC_OTP_STATUS_PROGOK_Msk))  
    {
        /* PROGRAM Sequence */
        /* 1.Write Following Bit
        * OTP_CTL.OTPProg_En =1 // Enable OTP programming at top level control */
        Cy_MXOTPC_OtpProgEnable(true);

        /* 2.Check whether OTP is busy or not
        * OTP_CMD.START == 0 // OTP is not busy */
        if(Cy_MXOTPC_OtpCheckStartStatus(CY_START_STATUS_CHECK_TIMEOUT) == CY_MXOTPC_TIMEOUT)
            return CY_MXOTPC_TIMEOUT;

        /* 3.Check whether programming is enabled or not (PROGRAM Enable Seq)
        * OTP_STATUS.ProgOK == 1 // OTP programming enabled
        * If this bit is not set, perform following steps, otherwise skip.
        * a.OTP commands to enable OTP Programming.
        * i.Write OTP_PROGDATA = 0xF
        * ii.Write OTP_CMD reg (with CMD =0x02), VALUE:    0x9100_0000
        * iii.Wait for OTP_CMD.START == 0
        * iv.Repeat from point i to iii for OTP_PROGDATA 0x4, 0x8 and 0xd in sequence
        * Check whether programming is enabled or not
        * OTP_STATUS.ProgOK == 1 // OTP programming enabled */
        for(idx = 0; idx < sizeof(otpProgramEnable); idx++)
        {
            Cy_MXOTPC_OtpSetProgData(otpProgramEnable[idx]);

            otpCmd.cmd = CY_MXOTPC_OTP_PROGENABLE_CMD;
            Cy_MXOTPC_OtpCmd(&otpCmd);

            if(Cy_MXOTPC_OtpCheckStartStatus(CY_START_STATUS_CHECK_TIMEOUT) == CY_MXOTPC_TIMEOUT)
               return CY_MXOTPC_TIMEOUT;
        }
        if(!Cy_MXOTPC_OtpGetStatus(MXOTPC_OTP_STATUS_PROGOK_Msk))
            return CY_MXOTPC_WRITE_ERROR;
    }

    return CY_MXOTPC_SUCCESS;
}

/*******************************************************************************
* Function Name: Cy_MXOTPC_GetWriteProtectedData
****************************************************************************//**
*
* Write Protection for already set OTP bits
*
*  \param otpRowNum
*  Contains the Row Number to be written
*  \param otpWriteData
*  Contains the Data to be written
*  \param otpFinalWriteData
*  Contains the corrected Data to be Written
*
*  \return the MXOTPC API status \ref cy_mxotpc_status_t.
*
*******************************************************************************/
static cy_mxotpc_status_t Cy_MXOTPC_GetWriteProtectedData(uint32_t otpRowNum, uint32_t otpWriteData, uint32_t *otpWriteProtData)
{
    uint32_t otpReadData;
    cy_mxotpc_status_t status;

    status = Cy_MXOTPC_ReadRow( otpRowNum, &otpReadData );
    if( !status )
    {
        *otpWriteProtData = (otpWriteData ^ otpReadData) & otpWriteData;
        return CY_MXOTPC_SUCCESS;
    }
    else
        return status;
}

/*******************************************************************************
* Function Name: Cy_MXOTPC_WriteRowReadBack
****************************************************************************//**
*
* Writes a particular row with 32-bit data with/without ECC and reads the row back.
*
* Indirect PROGRAM Sequence
* 1.Write Following Bit
* OTP_CTL.OTPProg_En =1 // Enable OTP programming at top level control
* 2.Check whether OTP is busy or not
* OTP_CMD.START == 0 // OTP is not busy
* 3.Check whether programming is enabled or not (PROGRAM Enable Seq)
* OTP_STATUS.ProgOK == 1 // OTP programming enabled
* If this bit is not set, perform following steps, otherwise skip.
* a.OTP commands to enable OTP Programming
* i.Write OTP_PROGDATA = 0xF
* ii.Write OTP_CMD reg (with CMD =0x02), VALUE:  0x9100_0000
* iii.Wait for OTP_CMD.START == 0
* iv.Repeat from point i to iii for OTP_PROGDATA 0x4, 0x8 and 0xd in sequence
* Check whether programming is enabled or not
* OTP_STATUS.ProgOK == 1 // OTP programming enabled
* 4.Write OTP_PROGDATA register
* Write 32-bit data value to be programmed inside OTP_PROGDATA reg
* 5.WRITE OTP_CMD Register
* Write following value in OTP_CMD reg.
* For OTP_CMD command (0x0A) at 511th row, you may use following value,
* 0x8501FF00
* 6.check completion of access
* Read 31st bit of OTP_CMD register to check completion of programming.
* OTP_CMD.START == 0 // access completed
* 7. Check programming status
* OTP_STATUS.PROGFAIL == 1 // Program failure
*
*  \param otpRowNum
*  Contains the Row Number to be written
*  \param otpWriteData
*  Contains the Data to be written
*  \param otpReadBackData
*  Contains the Read back Data of the Row Number passed.
*  \param enable_ecc
*  Contains boolean, which tells to enable ECC for that row or not.
*
*  \return the MXOTPC API status \ref cy_mxotpc_status_t.
*
*******************************************************************************/
cy_mxotpc_status_t Cy_MXOTPC_WriteRowReadBack(uint32_t otpRowNum, uint32_t otpWriteData, uint32_t *otpReadBackData, bool enable_ecc)
{
    cy_mxotpc_cmd_t otpCmd = {0, 0, 0};
    cy_mxotpc_status_t result = CY_MXOTPC_INVALID;
    uint32_t otpWriteProtData, otpReadData;

    CY_ASSERT_L2(CY_MXOTPC_IS_ROW_VALID(otpRowNum));

    /* Indirect PROGRAM Sequence */
    result = Cy_MXOTPC_WriteProgramSequence();
    if(result != CY_MXOTPC_SUCCESS)
        return result;

    /* 4.Write OTP_PROGDATA register
    * Write 32-bit data value to be programmed inside OTP_PROGDATA reg */
    /* Write Protection : OTP bit that is already set shouldnt be set again */
    result = Cy_MXOTPC_GetWriteProtectedData(otpRowNum, otpWriteData, &otpWriteProtData);
    if(result != CY_MXOTPC_SUCCESS)
        return result;

    /* otpWriteProtData = 0 means required OTP's set already, Nothing to Write */
    if(otpWriteProtData)
    {
        Cy_MXOTPC_OtpSetProgData(otpWriteProtData);

        /* 5.WRITE OTP_CMD Register
        * Write following value in OTP_CMD reg.
        * For OTP_CMD command (0x0A) at 511th row, you may use following value,
        * 0x8501FF00 */
        if(enable_ecc)
            otpCmd.cmd = CY_MXOTPC_PROG_ECC_CMD;
        else
            otpCmd.cmd = CY_MXOTPC_PROG_CMD;

        otpCmd.rowAddr = otpRowNum;
        Cy_MXOTPC_OtpCmd(&otpCmd);

        /* 6.check completion of access
        * Read 31st bit of OTP_CMD register to check completion of programming.
        * OTP_CMD.START == 0 // access completed */
        if(Cy_MXOTPC_OtpCheckStartStatus(CY_START_STATUS_CHECK_TIMEOUT) == CY_MXOTPC_TIMEOUT)
            return CY_MXOTPC_TIMEOUT;

        /* 7. Check programming status
        * OTP_STATUS.PROGFAIL == 1 // Program failure */
        if(Cy_MXOTPC_OtpGetStatus(MXOTPC_OTP_STATUS_PROGFAIL_Msk))  
            return CY_MXOTPC_WRITE_PROG_ERROR;

        /* Read the row back and verify if the data is written successfully */
        result = Cy_MXOTPC_ReadRow( otpRowNum, &otpReadData );
        if(result != CY_MXOTPC_SUCCESS)
            return result;
        
        if((otpReadData & otpWriteData) != otpWriteData)
            return CY_MXOTPC_WRITE_ERROR;
        
        /* Read back the Row Data and pass it back to caller for cross check */
        if( otpReadBackData )
            *otpReadBackData = otpReadData;
    }
    return CY_MXOTPC_SUCCESS;
}

/*******************************************************************************
* Function Name: Cy_MXOTPC_WriteRow
****************************************************************************//**
*
* Writes a particular row with 32-bit data with/without ECC.
*
*  \param otpRowNum
*  Contains the Row Number to be written
*  \param otpWriteData
*  Contains the Data to be written
*  \param enable_ecc
*  Contains boolean, which tells to enable ECC for that row or not.
*
*  \return the MXOTPC API status \ref cy_mxotpc_status_t.
*
*******************************************************************************/
cy_mxotpc_status_t Cy_MXOTPC_WriteRow(uint32_t otpRowNum, uint32_t otpWriteData, bool enable_ecc)
{
    CY_ASSERT_L2(CY_MXOTPC_IS_ROW_VALID(otpRowNum));

    return Cy_MXOTPC_WriteRowReadBack(otpRowNum, otpWriteData, NULL, enable_ecc);
}

/*******************************************************************************
* Function Name: Cy_MXOTPC_WriteBitReadBack
****************************************************************************//**
*
* Writes a particular row with 32-bit data without ECC and Read the Row back
*
* Indirect PROGRAM Sequence
* 1.Write Following Bit
* OTP_CTL.OTPProg_En =1 // Enable OTP programming at top level control
* 2.Check whether OTP is busy or not
* OTP_CMD.START == 0 // OTP is not busy
* 3.Check whether programming is enabled or not (PROGRAM Enable Seq)
* OTP_STATUS.ProgOK == 1 // OTP programming enabled
* If this bit is not set, perform following steps, otherwise skip.
* a.OTP commands to enable OTP Programming 
* i.Write OTP_PROGDATA = 0xF
* ii.Write OTP_CMD reg (with CMD =0x02), VALUE:  0x9100_0000
* iii.Wait for OTP_CMD.START == 0
* iv.Repeat from point i to iii for OTP_PROGDATA 0x4, 0x8 and 0xd in sequence
* Check whether programming is enabled or not
* OTP_STATUS.ProgOK == 1 // OTP programming enabled
* 4.Write OTP_PROGDATA register after reading back and masking the
* required bit position, Write 32-bit data value to be programmed
* inside OTP_PROGDATA reg.
* 5.WRITE OTP_CMD Register
* Write following value in OTP_CMD reg.
* For OTP_CMD command (0x0A) at 511th row, you may use following value,
* 0x8501FF00
* 6.check completion of access
* Read 31st bit of OTP_CMD register to check completion of programming.
* OTP_CMD.START == 0 // access completed
* 7. Check programming status
* OTP_STATUS.PROGFAIL == 1 // Program failure
*
*  \param otpRowNum
*  Contains the Row Number to be written
*  \param bitNum
*  Contains the bit position to be written
*  \param otpReadBackData
*  Contains the Read back Data of the Row Number passed.
*
*  \return the MXOTPC API status \ref cy_mxotpc_status_t.
*
*******************************************************************************/
cy_mxotpc_status_t Cy_MXOTPC_WriteBitReadBack(uint32_t otpRowNum, uint32_t bitNum, uint32_t *otpReadBackData)
{
    cy_mxotpc_cmd_t otpCmd = {0, 0, 0};
    cy_mxotpc_status_t result = CY_MXOTPC_INVALID;
    uint32_t otpWriteProtData, otpReadData;

    CY_ASSERT_L2(CY_MXOTPC_IS_ROW_VALID(otpRowNum));
    CY_ASSERT_L2(CY_MXOTPC_IS_BITNUM_VALID(bitNum));

    /* Indirect PROGRAM Sequence */
    result = Cy_MXOTPC_WriteProgramSequence();
    if(result != CY_MXOTPC_SUCCESS)
        return result;

    /* 4.Write OTP_PROGDATA register after reading back and masking the
    * required bit position, Write 32-bit data value to be programmed
    * inside OTP_PROGDATA reg */
    /* Write Protection : OTP bit that is already set shouldnt be set again */
    result = Cy_MXOTPC_GetWriteProtectedData(otpRowNum, (1 << bitNum), &otpWriteProtData);
    if(result != CY_MXOTPC_SUCCESS)
        return result;

    /* otpWriteProtData = 0 means required OTP's set already, Nothing to Write */
    if(otpWriteProtData)
    {
        Cy_MXOTPC_OtpSetProgData(otpWriteProtData);

        /* 5.WRITE OTP_CMD Register
        * Write following value in OTP_CMD reg.
        * For OTP_CMD command (0x0A) at 511th row, you may use following value,
        * 0x8501FF00 */
        otpCmd.cmd = CY_MXOTPC_PROG_CMD;
        otpCmd.rowAddr = otpRowNum;
        Cy_MXOTPC_OtpCmd(&otpCmd);

        /* 6.check completion of access
        * Read 31st bit of OTP_CMD register to check completion of programming.
        * OTP_CMD.START == 0 // access completed */
        if(Cy_MXOTPC_OtpCheckStartStatus(CY_START_STATUS_CHECK_TIMEOUT) == CY_MXOTPC_TIMEOUT)
            return CY_MXOTPC_TIMEOUT;

        /* 7. Check programming status
        * OTP_STATUS.PROGFAIL == 1 // Program failure */
        if(Cy_MXOTPC_OtpGetStatus(MXOTPC_OTP_STATUS_PROGFAIL_Msk))  
            return CY_MXOTPC_WRITE_ERROR;

    }
    
    /* Read the row back and verify if the data is written successfully */
    result = Cy_MXOTPC_ReadRow( otpRowNum, &otpReadData );
    if(result != CY_MXOTPC_SUCCESS)
        return result;

    if(!(otpReadData & (1 << bitNum)))
        return CY_MXOTPC_WRITE_ERROR;

    /* Read back the Row Data and pass it back to caller for cross check */
    if(otpReadBackData)
        *otpReadBackData = otpReadData;
    return CY_MXOTPC_SUCCESS;
}

/*******************************************************************************
* Function Name: Cy_MXOTPC_WriteBit
****************************************************************************//**
*
* Writes a particular row with 32-bit data without ECC
*
*  \param otpRowNum
*  Contains the Row Number to be written
*  \param bitNum
*  Contains the bit position to be written
*
*  \return the MXOTPC API status \ref cy_mxotpc_status_t.
*
*******************************************************************************/
cy_mxotpc_status_t Cy_MXOTPC_WriteBit(uint32_t otpRowNum, uint32_t bitNum)
{
    CY_ASSERT_L2(CY_MXOTPC_IS_ROW_VALID(otpRowNum));
    CY_ASSERT_L2(CY_MXOTPC_IS_BITNUM_VALID(bitNum));

    return Cy_MXOTPC_WriteBitReadBack(otpRowNum, bitNum, NULL);
}

/*******************************************************************************
* Function Name: Cy_MXOTPC_WriteEcc
****************************************************************************//**
*
* Writes a particular row with ECC.
*
* Indirect PROGRAM Sequence
* 1.Write Following Bit
* OTP_CTL.OTPProg_En =1 // Enable OTP programming at top level control
* 2.Check whether OTP is busy or not
* OTP_CMD.START == 0 // OTP is not busy
* 3.Check whether programming is enabled or not (PROGRAM Enable Seq)
* OTP_STATUS.ProgOK == 1 // OTP programming enabled
* If this bit is not set, perform following steps, otherwise skip.
* a.OTP commands to enable OTP Programming 
* i.Write OTP_PROGDATA = 0xF
* ii.Write OTP_CMD reg (with CMD =0x02), VALUE:  0x9100_0000
* iii.Wait for OTP_CMD.START == 0
* iv.Repeat from point i to iii for OTP_PROGDATA 0x4, 0x8 and 0xd in sequence
* Check whether programming is enabled or not
* OTP_STATUS.ProgOK == 1 // OTP programming enabled
* 4.WRITE OTP_CMD Register
* Write following value in OTP_CMD reg.
* For OTP_CMD command (0x0A) at 511th row, you may use following value,
* 0x8401FF00
* 5.check completion of access
* Read 31st bit of OTP_CMD register to check completion of programming.
* OTP_CMD.START == 0 // access completed
* 6. Check programming status
* OTP_STATUS.PROGFAIL == 1 // Program failure
* 7. Read back the Row and check the ECC_STATUS register
* Check ECC_STATUS.ECC_ENABLE bits , if set then ECC_STATUS.ECC_DBL_ERR shouldnt
* be set.
*  \param otpRowNum
*  Contains the Row Number to be written with ECC
*
*  \return the MXOTPC API status \ref cy_mxotpc_status_t.
*
*******************************************************************************/
cy_mxotpc_status_t Cy_MXOTPC_WriteEcc(uint32_t otpRowNum)
{
    cy_mxotpc_cmd_t otpCmd = {0, 0, 0};
    uint32_t otpTempData;
    cy_mxotpc_status_t result = CY_MXOTPC_INVALID;

    CY_ASSERT_L2(CY_MXOTPC_IS_ROW_VALID(otpRowNum));

    /* Indirect ECC PROGRAM Sequence */
    result = Cy_MXOTPC_WriteProgramSequence();
    if(result != CY_MXOTPC_SUCCESS)
        return result;

    /* 4.WRITE OTP_CMD Register
    * Write following value in OTP_CMD reg.
    * For OTP_CMD command (0x0A) at 511th row, you may use following value,
    * 0x8481FF00 */
    otpCmd.cmd = CY_MXOTPC_PROG_ECC_WREAD_CMD;
    otpCmd.rowAddr = otpRowNum;
    Cy_MXOTPC_OtpCmd(&otpCmd);

    /* 5.check completion of access
    * Read 31st bit of OTP_CMD register to check completion of programming.
    * OTP_CMD.START == 0 // access completed */
    if(Cy_MXOTPC_OtpCheckStartStatus(CY_START_STATUS_CHECK_TIMEOUT) == CY_MXOTPC_TIMEOUT)
        return CY_MXOTPC_TIMEOUT;

    /* 6. Check programming status
    * OTP_STATUS.PROGFAIL == 1 // Program failure */
    if(Cy_MXOTPC_OtpGetStatus(MXOTPC_OTP_STATUS_PROGFAIL_Msk))  
        return CY_MXOTPC_WRITE_PROG_ERROR;

    /* Read the Row to check the ECC_STATUS */
    Cy_MXOTPC_ReadRow(otpRowNum, &otpTempData);

    if(!Cy_MXOTPC_OtpGetEccStatus(MXOTPC_ECC_STATUS_ECC_ENABLE_Msk))
        return CY_MXOTPC_WRITE_ECC_ERROR; 

    if(Cy_MXOTPC_OtpGetEccStatus(MXOTPC_ECC_STATUS_ECC_DBL_ERR_Msk))
        return CY_MXOTPC_WRITE_ECC_ERROR; 

    return CY_MXOTPC_SUCCESS;
}

/*******************************************************************************
* Function Name: Cy_MXOTPC_ReadRow
****************************************************************************//**
*
*  Reads the 32-bit value of a particular Row
*
*  \param otpRowNum
*  Contains the Row Number to be read
*  \param otpReadData
*  Contains the Read Data of the Row Number passed.
*
*  \return the MXOTPC API status \ref cy_mxotpc_status_t.
*
*******************************************************************************/
cy_mxotpc_status_t Cy_MXOTPC_ReadRow(uint32_t otpRowNum, uint32_t *otpReadData)
{
    CY_ASSERT_L2(CY_MXOTPC_IS_ROW_VALID(otpRowNum));

    *otpReadData = CY_GET_REG32((CY_MXOTPC_BASE + MXOTPC_SECTION_SIZE) + (otpRowNum * 4));

    if(Cy_MXOTPC_OtpGetEccStatus(MXOTPC_ECC_STATUS_ECC_DBL_ERR_Msk))
        return CY_MXOTPC_READ_ECC_ERROR;

    return CY_MXOTPC_SUCCESS;
}

/*******************************************************************************
* Function Name: Cy_MXOTPC_ReadBootRow
****************************************************************************//**
*
*  Reads the 32-bit value of Boot Row
*
*  \param otpReadData
*  Contains the Read Data of the Boot Row.
*
*  \return the MXOTPC API status \ref cy_mxotpc_status_t.
*
*******************************************************************************/
cy_mxotpc_status_t Cy_MXOTPC_ReadBootRow( uint32_t *otpReadData)
{
    *otpReadData = MXOTPC_BOOTROW;

    if(Cy_MXOTPC_OtpGetFoutEccStatus(MXOTPC_BOOT_ROW_FOUT_ECC_DED_STATUS_Msk))
        return CY_MXOTPC_READ_ECC_ERROR;

    return CY_MXOTPC_SUCCESS;
}

/*******************************************************************************
* Function Name: Cy_MXOTPC_ReadBit
****************************************************************************//**
*
*  Reads a bit status of a particular OTP Row
*
*  \param otpRowNum
*  Contains the Row Number, whose bit status should be Read
*  \param bitNum
*  Contains the bit position to be Read
*  \param otpReadBit
*  Contains the Read bit of bitNum position from the Row Number passed.
*
*  \return the MXOTPC API status \ref cy_mxotpc_status_t.
*
*******************************************************************************/
cy_mxotpc_status_t Cy_MXOTPC_ReadBit(uint32_t otpRowNum, uint32_t bitNum, uint32_t *otpReadBit)
{

    CY_ASSERT_L2(CY_MXOTPC_IS_ROW_VALID(otpRowNum));
    CY_ASSERT_L2(CY_MXOTPC_IS_BITNUM_VALID(bitNum));

    *otpReadBit = CY_GET_REG32((CY_MXOTPC_BASE + MXOTPC_SECTION_SIZE) + (otpRowNum * 4));
    /* Get the value of position:bitNum */
    *otpReadBit = (*otpReadBit & (1 << bitNum)? 1 : 0) ;

    if(Cy_MXOTPC_OtpGetEccStatus(MXOTPC_ECC_STATUS_ECC_DBL_ERR_Msk))
        return CY_MXOTPC_READ_ECC_ERROR;

    return CY_MXOTPC_SUCCESS;
}

/*******************************************************************************
* Function Name: Cy_MXOTPC_DirectWriteRow
****************************************************************************//**
*
* Writes a particular row with 32-bit data without ECC.
*
* Direct PROGRAM Sequence
* 1.Write Following Bit
* OTP_CTL.OTPProg_En =1 // Enable OTP programming at top level control
* 2.Check whether OTP is busy or not
* OTP_CMD.START == 0 // OTP is not busy
* 3.Check whether programming is enabled or not (PROGRAM Enable Seq)
* OTP_STATUS.ProgOK == 1 // OTP programming enabled
* If this bit is not set, perform following steps, otherwise skip.
* a.OTP commands to enable OTP Programming 
* i.Write OTP_PROGDATA = 0xF
* ii.Write OTP_CMD reg (with CMD =0x02), VALUE:  0x9100_0000
* iii.Wait for OTP_CMD.START == 0
* iv.Repeat from point i to iii for OTP_PROGDATA 0x4, 0x8 and 0xd in sequence
* Check whether programming is enabled or not
* OTP_STATUS.ProgOK == 1 // OTP programming enabled
* 4.Write CPU_PROG_CMD register
* Write command (0x0A) for Direct write
* Write command (0x08) for Direct write with ECC
* 5.Directly write to the memory mapped OTP address
*
*  \param otpRowNum
*  Contains the Row Number to be written
*  \param otpWriteData
*  Contains the Data to be written
*  \param otpReadBackData
*  Contains the Read back Data of the Row Number passed.
*  \param otpProgEccEnable
*  Contains the data whether we have to enable ECC or not.
*
*  \return the MXOTPC API status \ref cy_mxotpc_status_t.
*
*******************************************************************************/
cy_mxotpc_status_t Cy_MXOTPC_DirectWriteRow(uint32_t otpRowNum, uint32_t otpWriteData, uint32_t *otpReadBackData, bool otpProgEccEnable)
{
    cy_mxotpc_status_t result = CY_MXOTPC_INVALID;
    uint32_t otpWriteProtData;

    CY_ASSERT_L2(CY_MXOTPC_IS_ROW_VALID(otpRowNum));

    /* Indirect PROGRAM Sequence */
    result = Cy_MXOTPC_WriteProgramSequence();
    if(result != CY_MXOTPC_SUCCESS)
        return result;

    /* 4.Write CPU_PROG_CMD register
    * Write command (0x0A) for Direct write */
    if(otpProgEccEnable)
        Cy_MXOTPC_OtpCpuProgCmd(CY_MXOTPC_PROG_ECC_CMD);
    else
        Cy_MXOTPC_OtpCpuProgCmd(CY_MXOTPC_PROG_CMD);

    /* 5.Directly write to the memory mapped OTP address */
    /* Write Protection : OTP bit that is already set shouldnt be set again */
    result = Cy_MXOTPC_GetWriteProtectedData(otpRowNum, otpWriteData, &otpWriteProtData);
    if( result != CY_MXOTPC_SUCCESS )
        return result;

    /* otpWriteProtData = 0 means required OTP's set already, Nothing to Write */
    if(otpWriteProtData)
    {
        CY_SET_REG32((CY_MXOTPC_BASE + MXOTPC_SECTION_SIZE) + (otpRowNum * 4), otpWriteProtData);
    }

    /* Read back the Row Data and pass it back to caller for cross check */
    if(otpReadBackData)
        return Cy_MXOTPC_ReadRow(otpRowNum, otpReadBackData);

    return CY_MXOTPC_SUCCESS;
}

/*******************************************************************************
* Function Name: Cy_MXOTPC_IndirectReadBit
****************************************************************************//**
*
*  Reads a bit status of a particular OTP Row using Indirect access
*
* Indirect READ Sequence
* 1.    Check whether OTP is busy or not
* OTP_CMD.START == 0 // OTP is not busy
* 2.    WRITE OTP_CMD Register
* Write following value in OTP_CMD reg.
* For READ command (0x00) at 15th row and 3rd bit, and clearing previous read error if exist, you may use following value,
* 0X9000_0F03
* 3.    check completion of access
* Read 31st bit of OTP_CMD register to check completion of programming.
* OTP_CMD.START == 0 // access completed
* 4.    Check Read status & Read bit
* OTP_CMD.ReadVal // Read value from specified bit.
* OTP_CMD.RD_ERR == 1 // Error in bit reading
* Read ECC_STATUS register for ECC status of the row. More details on ECC refer to register description.
*
*  \param otpRowNum
*  Contains the Row Number, whose bit status should be Read
*  \param bitNum
*  Contains the bit position to be Read
*  \param otpReadBit
*  Contains the Read bit of bitNum position from the Row Number passed.
*
*  \return the MXOTPC API status \ref cy_mxotpc_status_t.
*
*******************************************************************************/
cy_mxotpc_status_t Cy_MXOTPC_IndirectReadBit(uint32_t otpRowNum, uint32_t bitNum, uint32_t *otpReadBit)
{
    cy_mxotpc_cmd_t otpCmd = {0, 0, 0};

    CY_ASSERT_L2(CY_MXOTPC_IS_ROW_VALID(otpRowNum));
    CY_ASSERT_L2(CY_MXOTPC_IS_BITNUM_VALID(bitNum));

    /* Indirect READ Sequence */
    /* 1.    Check whether OTP is busy or not
    * OTP_CMD.START == 0 // OTP is not busy */
    if(Cy_MXOTPC_OtpCheckStartStatus(CY_START_STATUS_CHECK_TIMEOUT) == CY_MXOTPC_TIMEOUT)
        return CY_MXOTPC_READ_ERROR;

    /* 2.    WRITE OTP_CMD Register
    * Write following value in OTP_CMD reg.
    * For READ command (0x00) at 15th row and 3rd bit, and clearing previous read error if exist, you may use following value,
    * 0X9000_0F03 */
    otpCmd.cmd = CY_MXOTPC_READ_CMD;
    otpCmd.rowAddr = otpRowNum;
    otpCmd.colAddr = bitNum;
    Cy_MXOTPC_OtpCmd(&otpCmd);

    /* 3.    check completion of access
    * Read 31st bit of OTP_CMD register to check completion of programming.
    * OTP_CMD.START == 0 // access completed */
    if(Cy_MXOTPC_OtpCheckStartStatus(CY_START_STATUS_CHECK_TIMEOUT) == CY_MXOTPC_TIMEOUT)
        return CY_MXOTPC_READ_ERROR;

    /* 4.    Check Read status & Read bit
    * OTP_CMD.ReadVal // Read value from specified bit.
    * OTP_CMD.RD_ERR == 1 // Error in bit reading
    * Read ECC_STATUS register for ECC status of the row. More details on ECC refer to register description.*/
    if(Cy_MXOTPC_OtpGetReadBitStatus())
        return CY_MXOTPC_READ_ERROR;

    *otpReadBit = Cy_MXOTPC_OtpIndirectReadBit();

    if(Cy_MXOTPC_OtpGetEccStatus(MXOTPC_ECC_STATUS_ECC_DBL_ERR_Msk))
        return CY_MXOTPC_READ_ECC_ERROR;

    return CY_MXOTPC_SUCCESS;
}

/*******************************************************************************
* Function Name: Cy_MXOTPC_ReadRowArray
****************************************************************************//**
*
*  Reads Array of Rows
*
*  \param otpRowNum
*  Contains the starting Row Number to be read
*  \param otpDstPointer
*  Contains the Destination Address where the data read has to be written back.
*  \param size
*  Contains the number of rows to be read from otpRowNum.
*
*  \return the MXOTPC API status \ref cy_mxotpc_status_t.
*
*******************************************************************************/
cy_mxotpc_status_t Cy_MXOTPC_ReadRowArray(uint32_t otpRowNum, uint32_t *otpDstPointer, uint32_t size)
{
    cy_mxotpc_status_t status = CY_MXOTPC_READ_ERROR;
    CY_ASSERT_L2(CY_MXOTPC_IS_SIZE_VALID(size));
    CY_ASSERT_L2(CY_MXOTPC_IS_ROW_VALID(otpRowNum));
    CY_ASSERT_L2(CY_MXOTPC_IS_DEST_ADDR_ALIGNED(otpDstPointer));
    CY_ASSERT_L2(CY_MXOTPC_IS_ARRAY_SIZE_VALID(otpRowNum, size));

    while(size != 0)
    {
        status = Cy_MXOTPC_ReadRow( otpRowNum, otpDstPointer);
        if(status != CY_MXOTPC_SUCCESS)
            break;

        otpRowNum++;
        otpDstPointer++;
        size--;
    }

    return status;
}

/*******************************************************************************
* Function Name: Cy_MXOTPC_WriteRowArray
****************************************************************************//**
*
*  Writes Array of Rows
*
*  \param otpRowNum
*  Contains the starting Row Number to be written
*  \param otpSrcPointer
*  Contains the Destination Address where the data has to be read has to be written to rows.
*  \param size
*  Contains the number of rows to be written from otpRowNum.
*  \param enable_ecc
*  Contains boolean, which tells to enable ECC for that row or not.
*
*  \return the MXOTPC API status \ref cy_mxotpc_status_t.
*
*******************************************************************************/
cy_mxotpc_status_t Cy_MXOTPC_WriteRowArray(uint32_t otpRowNum, uint32_t *otpSrcPointer, uint32_t size, bool enable_ecc)
{
    cy_mxotpc_status_t status = CY_MXOTPC_WRITE_ERROR;
    CY_ASSERT_L2(CY_MXOTPC_IS_SIZE_VALID(size));
    CY_ASSERT_L2(CY_MXOTPC_IS_ROW_VALID(otpRowNum));
    CY_ASSERT_L2(CY_MXOTPC_IS_DEST_ADDR_ALIGNED(otpSrcPointer));
    CY_ASSERT_L2(CY_MXOTPC_IS_ARRAY_SIZE_VALID(otpRowNum, size));

    while(size != 0)
    {
        status = Cy_MXOTPC_WriteRow( otpRowNum, *otpSrcPointer, enable_ecc);
        if(status != CY_MXOTPC_SUCCESS)
            break;

        otpRowNum++;
        otpSrcPointer++;
        size--;
    }

    return status;
}

#endif /* CY_IP_MXS28OTPC */
/* [] END OF FILE */