diff options
Diffstat (limited to '')
-rw-r--r-- | bsps/arm/imxrt/mcux-sdk/drivers/ocotp/fsl_ocotp.c | 406 | ||||
-rw-r--r-- | bsps/arm/imxrt/mcux-sdk/drivers/ocotp/fsl_ocotp.h | 211 |
2 files changed, 617 insertions, 0 deletions
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/ocotp/fsl_ocotp.c b/bsps/arm/imxrt/mcux-sdk/drivers/ocotp/fsl_ocotp.c new file mode 100644 index 0000000000..4c15d6974d --- /dev/null +++ b/bsps/arm/imxrt/mcux-sdk/drivers/ocotp/fsl_ocotp.c @@ -0,0 +1,406 @@ +/* + * Copyright 2019-2020 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_ocotp.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.ocotp" +#endif + +#if defined(FSL_FEATURE_OCOTP_HAS_STATUS) && FSL_FEATURE_OCOTP_HAS_STATUS +#define OCOTP_STATUS_READ_DED_MASK \ + (OCOTP_OUT_STATUS0_DED0_MASK | OCOTP_OUT_STATUS0_DED1_MASK | OCOTP_OUT_STATUS0_DED2_MASK | \ + OCOTP_OUT_STATUS0_DED3_MASK) +#endif + +/* Wait time should be not less than 150ns . */ +#define OCOTP_TIMING_WAIT_NS (uint64_t)150 +/* Relex time should be not less than 100ns . */ +#define OCOTP_TIMING_RELEX_NS (uint64_t)100 +/* Program time should be rang from 9000ns~11000ns. */ +#define OCOTP_TIMING_PROGRAM_NS (uint64_t)10000 +/* Read time should be less than 40ns. */ +#define OCOTP_TIMING_READ_NS (uint64_t)40 + +/* Unlock key is 0x3E77. */ +#define OCOTP_WRITE_UNLOCK_KEY (0x3E77) +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +#if (defined(FSL_FEATURE_OCOTP_HAS_TIMING_CTRL) && FSL_FEATURE_OCOTP_HAS_TIMING_CTRL) +/*! + * @brief Set read timing configuration. + * + * @param base OCOTP peripheral base addess. + * @param timingConfig configuration of timing. + */ +static void OCOTP_SetReadTiming(OCOTP_Type *base, ocotp_timing_t timingConfig); + +/*! + * @brief Set write timing configuration. + * + * @param base OCOTP peripheral base addess. + * @param timingConfig configuration of timing. + */ +static void OCOTP_SetWriteTiming(OCOTP_Type *base, ocotp_timing_t timingConfig); +#endif + +/******************************************************************************* + * Variables + ******************************************************************************/ +#if (defined(FSL_FEATURE_OCOTP_HAS_TIMING_CTRL) && FSL_FEATURE_OCOTP_HAS_TIMING_CTRL) +/* Timing configuration for OCOTP controller. */ +static ocotp_timing_t s_timingConfig; +#endif + +/******************************************************************************* + * Code + *******************************************************************************/ +/* Reload the shadow register. */ +status_t OCOTP_ReloadShadowRegister(OCOTP_Type *base) +{ + assert(NULL != base); + + status_t status = kStatus_Success; + + /* Make sure the OCOTP is ready, Overlapped accesses are not supported by the controller. */ + while (OCOTP_CheckBusyStatus(base)) + { + } + + /* Clear access error status bit. */ + OCOTP_ClearErrorStatus(base); + +#if (defined(FSL_FEATURE_OCOTP_HAS_TIMING_CTRL) && FSL_FEATURE_OCOTP_HAS_TIMING_CTRL) + /* Set the read timing. */ + OCOTP_SetReadTiming(base, s_timingConfig); + + /* Wait for the OCOTP controller not busy. */ + while (OCOTP_CheckBusyStatus(base)) + { + } +#endif + +#if defined(OCOTP_OUT_STATUS0_DED_RELOAD_MASK) + /* Clear reload error status. */ + base->OUT_STATUS0_CLR = OCOTP_OUT_STATUS0_DED_RELOAD_MASK; +#endif + + /* Set reload bit. */ + base->CTRL_SET = OCOTP_CTRL_RELOAD_SHADOWS(1); + + /* Wait for the OCOTP controller not busy. */ + while (OCOTP_CheckBusyStatus(base)) + { + } + /* Wait for shadow register reload complete. this bit will be auto clear by OCOTP once operation is complete. */ + while (OCOTP_CTRL_RELOAD_SHADOWS_MASK == (base->CTRL & OCOTP_CTRL_RELOAD_SHADOWS_MASK)) + { + } + +#if defined(OCOTP_OUT_STATUS0_DED_RELOAD_MASK) + if ((base->OUT_STATUS0 & OCOTP_OUT_STATUS0_DED_RELOAD_MASK) != 0U) + { + status = kStatus_OCOTP_ReloadError; + } +#endif + + return status; +} + +#if (defined(FSL_FEATURE_OCOTP_HAS_TIMING_CTRL) && FSL_FEATURE_OCOTP_HAS_TIMING_CTRL) +static void OCOTP_SetReadTiming(OCOTP_Type *base, ocotp_timing_t timingConfig) +{ + uint32_t timingValue = base->TIMING; + + timingValue &= ~(OCOTP_TIMING_RELAX_MASK | OCOTP_TIMING_STROBE_READ_MASK | OCOTP_TIMING_WAIT_MASK); + timingValue |= OCOTP_TIMING_RELAX(timingConfig.relax) | OCOTP_TIMING_STROBE_READ(timingConfig.strobe_read) | + OCOTP_TIMING_WAIT(timingConfig.wait); + base->TIMING = timingValue; +} + +static void OCOTP_SetWriteTiming(OCOTP_Type *base, ocotp_timing_t timingConfig) +{ + uint32_t timingValue = base->TIMING; + + timingValue &= ~(OCOTP_TIMING_RELAX_MASK | OCOTP_TIMING_STROBE_PROG_MASK | OCOTP_TIMING_WAIT_MASK); + timingValue |= OCOTP_TIMING_RELAX(timingConfig.relax) | OCOTP_TIMING_STROBE_PROG(timingConfig.strobe_prog) | + OCOTP_TIMING_WAIT(timingConfig.wait); + + base->TIMING = timingValue; +} +#endif + +/* Initializes OCOTP controller. */ +void OCOTP_Init(OCOTP_Type *base, uint32_t srcClock_Hz) +{ + assert(NULL != base); +#if (defined(FSL_FEATURE_OCOTP_HAS_TIMING_CTRL) && FSL_FEATURE_OCOTP_HAS_TIMING_CTRL) + assert(0UL != srcClock_Hz); +#endif + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + /* Enable OCOTP clock */ + CLOCK_EnableClock(kCLOCK_Ocotp); +#endif + +#if (defined(FSL_FEATURE_OCOTP_HAS_TIMING_CTRL) && FSL_FEATURE_OCOTP_HAS_TIMING_CTRL) + /* tWait time shoule be higher than OCOTP_TIMING_WAIT_NS. */ + s_timingConfig.wait = (uint32_t)((OCOTP_TIMING_WAIT_NS * srcClock_Hz + 1000000000U) / 1000000000U - 1U); + + /* tRelax time shoule be higher than OCOTP_TIMING_RELEX_NS. */ + s_timingConfig.relax = (uint32_t)((OCOTP_TIMING_RELEX_NS * srcClock_Hz + 1000000000U) / 1000000000U - 1U); + + /* tStrobe_prog time should be close to OCOTP_TIMING_PROGRAM_NS, only add half of 1000000000. */ + s_timingConfig.strobe_prog = (uint32_t)((OCOTP_TIMING_PROGRAM_NS * srcClock_Hz + 500000000U) / 1000000000U) + + 2U * (s_timingConfig.relax + 1U) - 1U; + + /* tStrobe_read time should be higher than OCOTP_TIMING_READ_NS. */ + s_timingConfig.strobe_read = (uint32_t)((OCOTP_TIMING_READ_NS * srcClock_Hz + 1000000000U) / 1000000000U) + + 2U * (s_timingConfig.relax + 1U) - 1U; +#endif +} + +/* De-init OCOTP controller. */ +void OCOTP_Deinit(OCOTP_Type *base) +{ + assert(NULL != base); + +#if (defined(FSL_FEATURE_OCOTP_HAS_TIMING_CTRL) && FSL_FEATURE_OCOTP_HAS_TIMING_CTRL) + s_timingConfig.wait = 0UL; + s_timingConfig.relax = 0UL; + s_timingConfig.strobe_prog = 0UL; + s_timingConfig.strobe_read = 0UL; +#endif + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + /* Disable OCOTP clock */ + CLOCK_DisableClock(kCLOCK_Ocotp); +#endif +} + +/* Read the fuse shadow register. */ +uint32_t OCOTP_ReadFuseShadowRegister(OCOTP_Type *base, uint32_t address) +{ + assert(NULL != base); + + uint32_t data = 0U; + + (void)OCOTP_ReadFuseShadowRegisterExt(base, address, &data, 1); + + return data; +} + +status_t OCOTP_ReadFuseShadowRegisterExt(OCOTP_Type *base, uint32_t address, uint32_t *data, uint8_t fuseWords) +{ + assert((fuseWords > 0U) && (fuseWords <= OCOTP_READ_FUSE_DATA_COUNT)); + assert(NULL != data); + + status_t status = kStatus_Success; + +#if (OCOTP_READ_FUSE_DATA_COUNT > 1U) + uint32_t i; +#endif + + /* Make sure the OCOTP is ready, Overlapped accesses are not supported by the controller. */ + while (OCOTP_CheckBusyStatus(base)) + { + } + + /* If ERROR bit was set, clear access error status bit. */ + if (OCOTP_CheckErrorStatus(base)) + { + OCOTP_ClearErrorStatus(base); + } + +#if (defined(FSL_FEATURE_OCOTP_HAS_TIMING_CTRL) && FSL_FEATURE_OCOTP_HAS_TIMING_CTRL) + /* Set the read timing. */ + OCOTP_SetReadTiming(base, s_timingConfig); + + /* Wait for busy bit is cleared. */ + while (OCOTP_CheckBusyStatus(base)) + { + } + + /* Clear access error status bit. */ + if (OCOTP_CheckErrorStatus(base)) + { + OCOTP_ClearErrorStatus(base); + } +#endif + +#if defined(OCOTP_STATUS_READ_DED_MASK) + /* Clear error flags. */ + base->OUT_STATUS0_CLR = OCOTP_STATUS_READ_DED_MASK; +#endif + + /* Write requested address to register. */ + base->CTRL_CLR = OCOTP_CTRL_CLR_ADDR_MASK; + base->CTRL_SET = OCOTP_CTRL_SET_ADDR(address); + + /* Set OCOTP auto read enable. */ +#if defined(OCOTP_READ_CTRL_READ_NUM_MASK) + base->READ_CTRL = (base->READ_CTRL & ~(OCOTP_READ_CTRL_READ_NUM_MASK)) | + OCOTP_READ_CTRL_READ_NUM((uint32_t)fuseWords - 1U) | OCOTP_READ_CTRL_READ_FUSE_MASK; +#else + base->READ_CTRL |= OCOTP_READ_CTRL_READ_FUSE_MASK; +#endif + + /* Wait for busy bit is cleared, and no error occurred on controller. */ + while (OCOTP_CheckBusyStatus(base)) + { + } + + /* If ERROR bit was set, this may be mean that the accsee to the register was wrong. */ + if (OCOTP_CheckErrorStatus(base)) + { + /* Clear access error status bit. */ + OCOTP_ClearErrorStatus(base); + + status = kStatus_OCOTP_AccessError; + } + +#if defined(OCOTP_STATUS_READ_DED_MASK) + if ((base->OUT_STATUS0 & OCOTP_STATUS_READ_DED_MASK) != 0U) + { + status = kStatus_Fail; + } +#endif + +#if (OCOTP_READ_FUSE_DATA_COUNT == 1U) + *data = base->READ_FUSE_DATA; +#else + for (i = 0; i < fuseWords; i++) + { + data[i] = base->READ_FUSE_DATAS[i].READ_FUSE_DATA; + } +#endif + + return status; +} + +/* Write the fuse shadow register. */ +status_t OCOTP_WriteFuseShadowRegister(OCOTP_Type *base, uint32_t address, uint32_t data) +{ + return OCOTP_WriteFuseShadowRegisterWithLock(base, address, data, false); +} + +status_t OCOTP_WriteFuseShadowRegisterWithLock(OCOTP_Type *base, uint32_t address, uint32_t data, bool lock) +{ + assert(NULL != base); + + status_t status = kStatus_Success; + +#if defined(FSL_FEATURE_OCOTP_HAS_STATUS) && FSL_FEATURE_OCOTP_HAS_STATUS + uint32_t regStatus; +#endif + +#if !(defined(FSL_FEATURE_OCOTP_HAS_WORDLOCK) && FSL_FEATURE_OCOTP_HAS_WORDLOCK) + if (lock) + { + return kStatus_InvalidArgument; + } +#endif + + /* Make sure the OCOTP is ready, Overlapped accesses are not supported by the controller. */ + while (OCOTP_CheckBusyStatus(base)) + { + } + + /* Clear access error status bit. */ + if (OCOTP_CheckErrorStatus(base)) + { + OCOTP_ClearErrorStatus(base); + } + +#if (defined(FSL_FEATURE_OCOTP_HAS_TIMING_CTRL) && FSL_FEATURE_OCOTP_HAS_TIMING_CTRL) + /* Set write timing for OCOTP controller. */ + OCOTP_SetWriteTiming(base, s_timingConfig); + + /* Wait for busy bit is cleared. */ + while (OCOTP_CheckBusyStatus(base)) + { + } + + /* Clear access error status bit. */ + if (OCOTP_CheckErrorStatus(base)) + { + OCOTP_ClearErrorStatus(base); + } +#endif + +#if defined(FSL_FEATURE_OCOTP_HAS_STATUS) && FSL_FEATURE_OCOTP_HAS_STATUS + /* Clear errors. */ + base->OUT_STATUS0_CLR = (OCOTP_OUT_STATUS0_PROGFAIL_MASK | OCOTP_OUT_STATUS0_LOCKED_MASK); +#endif + + /* Write requested address and unlock key to register. */ +#if (defined(FSL_FEATURE_OCOTP_HAS_WORDLOCK) && FSL_FEATURE_OCOTP_HAS_WORDLOCK) + base->CTRL_CLR = OCOTP_CTRL_CLR_ADDR_MASK | OCOTP_CTRL_WR_UNLOCK_MASK | OCOTP_CTRL_WORDLOCK_MASK; +#else + base->CTRL_CLR = OCOTP_CTRL_CLR_ADDR_MASK | OCOTP_CTRL_WR_UNLOCK_MASK; +#endif + +#if (defined(FSL_FEATURE_OCOTP_HAS_WORDLOCK) && FSL_FEATURE_OCOTP_HAS_WORDLOCK) + if (lock) + { + base->CTRL_SET = + OCOTP_CTRL_SET_ADDR(address) | OCOTP_CTRL_WR_UNLOCK(OCOTP_WRITE_UNLOCK_KEY) | OCOTP_CTRL_WORDLOCK_MASK; + } + else +#endif + { + base->CTRL_SET = OCOTP_CTRL_SET_ADDR(address) | OCOTP_CTRL_WR_UNLOCK(OCOTP_WRITE_UNLOCK_KEY); + } + + /* Write data to register. */ + base->DATA = data; + + /* Wait for busy bit is cleared, and no error occurred on controller. */ + while (OCOTP_CheckBusyStatus(base)) + { + } + + /* If ERROR bit was set, this may be mean that the accsee to the register was wrong. */ + if (OCOTP_CheckErrorStatus(base)) + { + /* Clear access error status bit. */ + OCOTP_ClearErrorStatus(base); + + status = kStatus_OCOTP_AccessError; + } + +#if defined(FSL_FEATURE_OCOTP_HAS_STATUS) && FSL_FEATURE_OCOTP_HAS_STATUS + regStatus = base->OUT_STATUS0; + + if ((regStatus & OCOTP_OUT_STATUS0_PROGFAIL_MASK) != 0U) + { + status = kStatus_OCOTP_ProgramFail; + } + else if ((regStatus & OCOTP_OUT_STATUS0_LOCKED_MASK) != 0U) + { + status = kStatus_OCOTP_Locked; + } + else + { + /* For MISRA rules. */ + } +#endif + + if (kStatus_Success == status) + { + /* Reload the fuse register. */ + status = OCOTP_ReloadShadowRegister(base); + } + + return status; +} diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/ocotp/fsl_ocotp.h b/bsps/arm/imxrt/mcux-sdk/drivers/ocotp/fsl_ocotp.h new file mode 100644 index 0000000000..73a405a12a --- /dev/null +++ b/bsps/arm/imxrt/mcux-sdk/drivers/ocotp/fsl_ocotp.h @@ -0,0 +1,211 @@ +/* + * Copyright 2019-2020 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef _FSL_OCOTP_H_ +#define _FSL_OCOTP_H_ + +#include "fsl_common.h" + +/*! + * @addtogroup ocotp + * @{ + */ + +/******************************************************************************* + * Definitions + *******************************************************************************/ +/*! @name Driver version */ +/*@{*/ +/*! @brief OCOTP driver version. */ +#define FSL_OCOTP_DRIVER_VERSION (MAKE_VERSION(2, 1, 3)) +/*@}*/ + +#ifndef OCOTP_READ_FUSE_DATA_COUNT +#define OCOTP_READ_FUSE_DATA_COUNT (1U) +#endif + +/*! @brief _ocotp_status Error codes for the OCOTP driver. */ +enum +{ + kStatus_OCOTP_AccessError = MAKE_STATUS(kStatusGroup_SDK_OCOTP, 0), /*!< eFuse and shadow register access error. */ + kStatus_OCOTP_CrcFail = MAKE_STATUS(kStatusGroup_SDK_OCOTP, 1), /*!< CRC check failed. */ + kStatus_OCOTP_ReloadError = + MAKE_STATUS(kStatusGroup_SDK_OCOTP, 2), /*!< Error happens during reload shadow register. */ + kStatus_OCOTP_ProgramFail = MAKE_STATUS(kStatusGroup_SDK_OCOTP, 3), /*!< Fuse programming failed. */ + kStatus_OCOTP_Locked = MAKE_STATUS(kStatusGroup_SDK_OCOTP, 4), /*!< Fuse is locked and cannot be programmed. */ +}; + +#if (defined(FSL_FEATURE_OCOTP_HAS_TIMING_CTRL) && FSL_FEATURE_OCOTP_HAS_TIMING_CTRL) +/*! @brief OCOTP timing structure. + * Note that, these value are used for calcalating the read/write timings. + * And the values should statisfy below rules: + * + * Tsp_rd=(WAIT+1)/ipg_clk_freq should be >= 150ns; + * Tsp_pgm=(RELAX+1)/ipg_clk_freq should be >= 100ns; + * Trd = ((STROBE_READ+1)- 2*(RELAX_READ+1)) /ipg_clk_freq, + * The Trd is required to be larger than 40 ns. + * Tpgm = ((STROBE_PROG+1)- 2*(RELAX_PROG+1)) /ipg_clk_freq; + * The Tpgm should be configured within the range of 9000 ns < Tpgm < 11000 ns; + */ +typedef struct _ocotp_timing +{ + uint32_t wait; /*!< Wait time value to fill in the TIMING register. */ + uint32_t relax; /*!< Relax time value to fill in the TIMING register. */ + uint32_t strobe_prog; /*!< Storbe program time value to fill in the TIMING register. */ + uint32_t strobe_read; /*!< Storbe read time value to fill in the TIMING register. */ +} ocotp_timing_t; +#endif /* FSL_FEATURE_OCOTP_HAS_TIMING_CTRL */ + +/******************************************************************************* + * API + *******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @brief Initializes OCOTP controller. + * + * @param base OCOTP peripheral base address. + * @param srcClock_Hz source clock frequency in unit of Hz. When the macro + * FSL_FEATURE_OCOTP_HAS_TIMING_CTRL is defined as 0, this parameter is not used, + * application could pass in 0 in this case. + */ +void OCOTP_Init(OCOTP_Type *base, uint32_t srcClock_Hz); + +/*! + * @brief De-initializes OCOTP controller. + * + * @retval kStatus_Success upon successful execution, error status otherwise. + */ +void OCOTP_Deinit(OCOTP_Type *base); + +/*! + * @brief Checking the BUSY bit in CTRL register. + * Checking this BUSY bit will help confirm if the OCOTP controller is ready for access. + * + * @param base OCOTP peripheral base address. + * @retval true for bit set and false for cleared. + */ +static inline bool OCOTP_CheckBusyStatus(OCOTP_Type *base) +{ + return ((OCOTP_CTRL_BUSY_MASK == (base->CTRL & OCOTP_CTRL_BUSY_MASK)) ? (true) : (false)); +} + +/*! + * @brief Checking the ERROR bit in CTRL register. + * + * @param base OCOTP peripheral base address. + * @retval true for bit set and false for cleared. + */ +static inline bool OCOTP_CheckErrorStatus(OCOTP_Type *base) +{ + return ((OCOTP_CTRL_ERROR_MASK == (base->CTRL & OCOTP_CTRL_ERROR_MASK)) ? (true) : (false)); +} + +/*! + * @brief Clear the error bit if this bit is set. + * + * @param base OCOTP peripheral base address. + */ +static inline void OCOTP_ClearErrorStatus(OCOTP_Type *base) +{ + base->CTRL_CLR = OCOTP_CTRL_CLR_ERROR_MASK; +} + +/*! + * @brief Reload the shadow register. + * This function will help reload the shadow register without reseting the OCOTP module. + * Please make sure the OCOTP has been initialized before calling this API. + * + * @param base OCOTP peripheral base addess. + * @retval kStatus_Success Reload success. + * @retval kStatus_OCOTP_ReloadError Reload failed. + */ +status_t OCOTP_ReloadShadowRegister(OCOTP_Type *base); + +/*! + * @brief Read the fuse shadow register with the fuse addess. + * + * @deprecated Use @ref OCOTP_ReadFuseShadowRegisterExt instead of this function. + * + * @param base OCOTP peripheral base address. + * @param address the fuse address to be read from. + * @return The read out data. + */ +uint32_t OCOTP_ReadFuseShadowRegister(OCOTP_Type *base, uint32_t address); + +/*! + * @brief Read the fuse shadow register from the fuse addess. + * + * This function reads fuse from @p address, how many words to read is specified + * by the parameter @p fuseWords. This function could read at most + * OCOTP_READ_FUSE_DATA_COUNT fuse word one time. + * + * @param base OCOTP peripheral base address. + * @param address the fuse address to be read from. + * @param data Data array to save the readout fuse value. + * @param fuseWords How many words to read. + * @retval kStatus_Success Read success. + * @retval kStatus_Fail Error occurs during read. + */ +status_t OCOTP_ReadFuseShadowRegisterExt(OCOTP_Type *base, uint32_t address, uint32_t *data, uint8_t fuseWords); + +/*! + * @brief Write the fuse shadow register with the fuse addess and data. + * Please make sure the wrtie address is not locked while calling this API. + * + * @param base OCOTP peripheral base address. + * @param address the fuse address to be written. + * @param data the value will be writen to fuse address. + * @retval write status, kStatus_Success for success and kStatus_Fail for failed. + */ +status_t OCOTP_WriteFuseShadowRegister(OCOTP_Type *base, uint32_t address, uint32_t data); + +/*! + * @brief Write the fuse shadow register and lock it. + * + * Please make sure the wrtie address is not locked while calling this API. + * + * Some OCOTP controller supports ECC mode and redundancy mode (see reference mananual + * for more details). OCOTP controller will auto select ECC or redundancy + * mode to program the fuse word according to fuse map definition. In ECC mode, the + * 32 fuse bits in one word can only be written once. In redundancy mode, the word can + * be written more than once as long as they are different fuse bits. Set parameter + * @p lock as true to force use ECC mode. + * + * @param base OCOTP peripheral base address. + * @param address The fuse address to be written. + * @param data The value will be writen to fuse address. + * @param lock Lock or unlock write fuse shadow register operation. + * @retval kStatus_Success Program and reload success. + * @retval kStatus_OCOTP_Locked The eFuse word is locked and cannot be programmed. + * @retval kStatus_OCOTP_ProgramFail eFuse word programming failed. + * @retval kStatus_OCOTP_ReloadError eFuse word programming success, but + * error happens during reload the values. + * @retval kStatus_OCOTP_AccessError Cannot access eFuse word. + */ +status_t OCOTP_WriteFuseShadowRegisterWithLock(OCOTP_Type *base, uint32_t address, uint32_t data, bool lock); + +/*! + * @brief Get the OCOTP controller version from the register. + * + * @param base OCOTP peripheral base address. + * @retval return the version value. + */ +static inline uint32_t OCOTP_GetVersion(OCOTP_Type *base) +{ + return (base->VERSION); +} + +#if defined(__cplusplus) +} +#endif + +/*! @}*/ + +#endif /* _FSL_OCOTP_H_ */ |