123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406 |
- /*
- * 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;
- }
|