Exemple #1
0
/**************************************************************************//**
 * See mss_nvm.h for details of how to use this function.
 */
nvm_status_t
NVM_write
(
    uint32_t start_addr,
    const uint8_t * pidata,
    uint32_t length,
    uint32_t lock_page
)
{
    nvm_status_t status;
    uint32_t nvm_offset;
    uint32_t device_version;
    uint32_t initial_nvm_config;

    /* 
     * SAR 57547: Set the FREQRNG field of the eNVM configuration register 
     * to its maximum value (i.e. 15) to ensure successful writes to eNVM. 
     * Store the value of the eNVM configuration before updating it, so 
     * that the prior configuration can be restored when the eNVM write
     * operation has completed. 
     */
    initial_nvm_config = SYSREG->ENVM_CR;
    SYSREG->ENVM_CR = (initial_nvm_config & NVM_FREQRNG_MASK) | NVM_FREQRNG_MAX;

    /* Check input parameters */
    if((start_addr >= (NVM_BASE_ADDRESS + NVM_RSV_PROTECTION_OFFSET)) || \
        ((start_addr >= NVM_RSV_PROTECTION_OFFSET) && \
        (start_addr < NVM_BASE_ADDRESS)) || \
        (!pidata) || \
        (!length) || \
        ((start_addr + length) >= (NVM_BASE_ADDRESS + NVM_RSV_PROTECTION_OFFSET))|| \
        (((start_addr + length) >= NVM_RSV_PROTECTION_OFFSET) && \
        ((start_addr + length) < NVM_BASE_ADDRESS))|| \
        (lock_page > PARAM_LOCK_PAGE_FLAG))
    {
        if(((start_addr >= (NVM_BASE_ADDRESS + NVM_RSV_PROTECTION_OFFSET)) && \
            (start_addr <= (NVM_BASE_ADDRESS + NVM_TOP_OFFSET))) || \
            ((start_addr >= NVM_RSV_PROTECTION_OFFSET) && (start_addr <= NVM_TOP_OFFSET)) || \
            (((start_addr + length) >= (NVM_BASE_ADDRESS + NVM_RSV_PROTECTION_OFFSET)) && \
            ((start_addr + length) <= (NVM_BASE_ADDRESS + NVM_TOP_OFFSET))) || \
            (((start_addr + length) >= NVM_RSV_PROTECTION_OFFSET) && \
            ((start_addr + length) <= NVM_TOP_OFFSET)))
        {
            status =  NVM_PROTECTION_ERROR;
        }
        else
        {
            status =  NVM_INVALID_PARAMETER;
        }
    }
    else
    {
        /*
         * Prevent pages being locked for silicon versions which do not allow
         * locked pages to be unlocked.
         */
        device_version = SYSREG->DEVICE_VERSION;
        if((0x0000F802u == device_version) || (0x0001F802u == device_version))
        {
            lock_page = NVM_DO_NOT_LOCK_PAGE;
        }

        /* Ignore upper address bits to ignore remapping setting. */
        nvm_offset = start_addr & NVM_OFFSET_SIGNIFICANT_BITS;  /* Ignore remapping. */

        /* Check against attempt to write data larger than eNVM. */
        ASSERT((nvm_offset + length) <= MAX_504K_OFFSET);
        if((nvm_offset + length) <= MAX_504K_OFFSET)
        {
            /* Gain exclusive access to eNVM controller */
            status = get_ctrl_access(nvm_offset, length);

            /* Write eNVM one page at a time. */
            if(NVM_SUCCESS == status)
            {
                uint32_t remaining_length = length;
                uint32_t errors_and_warnings;
                
                while(remaining_length > 0u)
                {
                    uint32_t length_written;
                    uint32_t nvm_hw_status = 0u;

                    length_written = write_nvm(start_addr + (length - remaining_length),
                                                &pidata[length - remaining_length],
                                                remaining_length,
                                                lock_page,
                                                &nvm_hw_status);

                    /* Check for errors and warnings. */
                    errors_and_warnings = nvm_hw_status & (WRITE_ERROR_MASK | MSS_NVM_WRCNT_OVER);
                    if(errors_and_warnings)
                    {
                       /* 
                        * Ensure that the status returned by the NVM_write()
                        * function is NVM_WRITE_THRESHOLD_WARNING if at least one
                        * of the written eNVM pages indicate a write over
                        * threshold condition.
                        */ 
                        status = get_error_code(nvm_hw_status);
                    }

                    if((NVM_SUCCESS == status) || (NVM_WRITE_THRESHOLD_WARNING == status ))
                    {
                        if(remaining_length > length_written)
                        {
                            remaining_length -= length_written;
                        }
                        else
                        {
                            remaining_length = 0u;
                        }
                    }
                    else
                    {
                        remaining_length = 0u;
                    }
                }

                /* Release eNVM controllers so that other masters can gain access to it. */
                release_ctrl_access();
            }
        }
        else
        {
            status = NVM_INVALID_PARAMETER;
        }
    }
    
    /* Restore back to original value. */
    SYSREG->ENVM_CR = initial_nvm_config;
    
    return status;
}
/**************************************************************************//**
 * See mss_nvm.h for details of how to use this function.
 */
nvm_status_t 
NVM_write
(
    uint32_t start_addr,
    const uint8_t * pidata,
    uint32_t  length,
    uint32_t  lock_page
)
{
    nvm_status_t status;
    uint32_t nvm_offset;
    uint32_t device_version;
    
    /*
     * Prevent pages being locked for silicon versions which do not allow
     * locked pages to be unlocked.
     */
    device_version = SYSREG->DEVICE_VERSION;
    if((0x0000F802u == device_version) || (0x0001F802u == device_version))
    {
        lock_page = NVM_DO_NOT_LOCK_PAGE;
    }
    
    /* Ignore upper address bits to ignore remapping setting. */
    nvm_offset = start_addr & NVM_OFFSET_SIGNIFICANT_BITS;  /* Ignore remapping. */
    
    /* Check against attempt to write data larger than eNVM. */
    ASSERT((nvm_offset + length) < MAX_512K_OFFSET);
    if((nvm_offset + length) < MAX_512K_OFFSET)
    {
        /* Gain exclusive access to eNVM controller */
        status = get_ctrl_access(nvm_offset, length);

        /* Write eNVM one page at a time. */
        if(NVM_SUCCESS == status)
        {
            uint32_t remaining_length = length;
            
            while((remaining_length > 0u) && (NVM_SUCCESS == status))
            {
                uint32_t length_written;
                uint32_t nvm_hw_status = 0u;
                
                length_written = write_nvm(start_addr + (length - remaining_length), 
                                           &pidata[length - remaining_length],
                                           remaining_length,
                                           lock_page,
                                           &nvm_hw_status);
                
                if(0u == length_written)
                {
                    status = get_error_code(nvm_hw_status);
                }
                else if(remaining_length > length_written)
                {
                    remaining_length -= length_written;
                }
                else
                {
                    remaining_length = 0u;
                }
            }
            
            /* Release eNVM controllers so that other masters can gain access to it. */
            release_ctrl_access();
        }
    }
    else
    {
        status = NVM_INVALID_PARAMETER;
    }

    return status;
}