Beispiel #1
0
uint32_t
NVM_read_page_write_count
(
    uint32_t addr
)
{
    uint32_t write_count = 0;
    uint32_t block;
    uint32_t offset;
    uint32_t status;

    if((addr >= NVM_BASE_ADDRESS) && (addr < (NVM_BASE_ADDRESS + NVM_RSV_PROTECTION_OFFSET)))
    {  
        offset = addr & NVM_OFFSET_SIGNIFICANT_BITS;

        /* Gain exclusive access to eNVM controller */
        status = get_ctrl_access(offset, BYTES_PER_PAGE);

        /* Read page write counter. */
        if(NVM_SUCCESS == status)
        {
            if(offset < NVM1_BOTTOM_OFFSET)
            {
                block = NVM_BLOCK_0;
            }
            else
            {
                block = NVM_BLOCK_1;
                offset = offset - NVM1_BOTTOM_OFFSET;
            }

            g_nvm[block]->NV_PAGE_STATUS |= 0x2u;

            if(block == NVM_BLOCK_0)
            {
                write_count = *((uint32_t *)((NVM0_BASE_ADDRESS + offset) & PAGE_ADDR_MASK));
            }
            else
            {
                write_count = *((uint32_t *)((NVM1_BASE_ADDRESS + offset) & PAGE_ADDR_MASK));
            }
    
            /* Wait for NVM to become ready. */
            status = wait_nvm_ready(block);
    
            g_nvm[block]->NV_PAGE_STATUS &= ~(0x2u);
        }

        /* Release eNVM controllers so that other masters can gain access to it. */
        release_ctrl_access();

        /* The write count is contained in bits [24:4] of the page's auxiliary data. */
        write_count = (write_count & AUX_DATA_WC_MASK) >> AUX_DATA_WC_SHIFT;
    }
Beispiel #2
0
/**************************************************************************//**
 * See mss_nvm.h for details of how to use this function.
 */
nvm_status_t
NVM_unlock
(
    uint32_t start_addr,
    uint32_t length
)
{
    nvm_status_t status;
    uint32_t nvm_offset;
    uint32_t first_page;
    uint32_t last_page;
    uint32_t current_page;
    uint32_t current_offset;
    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)) || \
        (!length) || \
        ((start_addr + length) >= (NVM_BASE_ADDRESS + NVM_RSV_PROTECTION_OFFSET))|| \
        (((start_addr + length) >= NVM_RSV_PROTECTION_OFFSET) && \
        ((start_addr + length) < NVM_BASE_ADDRESS)))
    {
        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
    {
        /* 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)
        {

            first_page = nvm_offset / BYTES_PER_PAGE;
            last_page = (nvm_offset + (length - 1u)) / BYTES_PER_PAGE;

            /* Gain exclusive access to eNVM controller */
            status = get_ctrl_access(nvm_offset, length);

            /* Unlock eNVM one page at a time. */
            if(NVM_SUCCESS == status)
            {
                uint32_t block;
                uint32_t inc;
                uint32_t * p_nvm32;
                uint32_t errors_and_warnings;


                for(current_page = first_page; (current_page <= last_page) &&
                    ((NVM_SUCCESS == status) ||(NVM_WRITE_THRESHOLD_WARNING == status));
                    ++current_page)
                {
                    uint32_t ctrl_status;

                    if(current_page > PAGES_PER_BLOCK)
                    {
                        block = NVM_BLOCK_1;
                    }
                    else
                    {
                        block = NVM_BLOCK_0;
                    }

                    if(g_nvm[block]->STATUS & MSS_NVM_WR_DENIED)
                    {
                        /* Clear the access denied flag */
                        g_nvm[block]->CLRHINT |= ACCESS_DENIED_FLAG_CLEAR;
                    }

                    current_offset = (current_page << 0x7u);
                    p_nvm32 = (uint32_t *)(NVM_BASE_ADDRESS + current_offset);
                     
                    for(inc = 0u; inc < WD_WORD_SIZE; ++inc)
                    {
                        g_nvm32[block]->WD[inc] = p_nvm32[inc];
                    }
                    
                    g_nvm[block]->PAGE_LOCK = NVM_DO_NOT_LOCK_PAGE;
                    g_nvm[block]->CMD = USER_UNLOCK | (current_offset & PAGE_ADDR_MASK);

                    /* Issue program command */
                    g_nvm[block]->CMD = PROG_ADS | (current_offset & PAGE_ADDR_MASK);

                    /* Wait for NVM to become ready. */
                    ctrl_status = wait_nvm_ready(block);

                    /* Check for errors and warnings. */
                    errors_and_warnings = ctrl_status & (WRITE_ERROR_MASK | MSS_NVM_WRCNT_OVER);
                    if(errors_and_warnings)
                    {
                        uint32_t nvm_hw_status;
                        nvm_hw_status = g_nvm[block]->STATUS;
                        status = get_error_code(nvm_hw_status);
                    }
                }

                /* 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;
}
Beispiel #3
0
/**************************************************************************//**
  Write as much data as will fit into the eNVM page corresponding to the
  address "addr" passed as parameter. Return the number of bytes written into
  the page.
  In case of error, return the content of the eNVM controller status register
  into the 32-bit word pointed to by p_status.
 */
static uint32_t 
write_nvm
(
    uint32_t addr,
    const uint8_t * pidata,
    uint32_t  length,
    uint32_t  lock_page,
    uint32_t * p_status
)
{
    uint32_t length_written;
    uint32_t offset;
   
    *p_status = 0u;
    
    offset = addr & NVM_OFFSET_SIGNIFICANT_BITS;  /* Ignore remapping. */
    
    ASSERT(offset <= NVM1_TOP_OFFSET);
    
    /* Adjust length to fit within one page. */
    length_written = get_remaining_page_length(offset, length);
    
    if(offset <= NVM1_TOP_OFFSET)
    {
        uint32_t block;
        volatile uint32_t ctrl_status;
        uint32_t errors;
        
        if(offset < NVM1_BOTTOM_OFFSET)
        {
            block = NVM_BLOCK_0;
        }
        else
        {
            block = NVM_BLOCK_1;
            offset = offset - NVM1_BOTTOM_OFFSET;
        }
        
        if(g_nvm[block]->STATUS & MSS_NVM_WR_DENIED)
        {
            /* Clear the access denied flag */
            g_nvm[block]->CLRHINT |= ACCESS_DENIED_FLAG_CLEAR;
        }

        fill_wd_buffer(pidata, length_written, block, offset);

        /* Set requested locking option. */
        g_nvm[block]->PAGE_LOCK = lock_page;
        
        /* Issue program command */
        g_nvm[block]->CMD = PROG_ADS | (offset & PAGE_ADDR_MASK);
        
        /* Wait for NVM to become ready. */
        ctrl_status = wait_nvm_ready(block);

        /* Check for errors. */
        errors = ctrl_status & WRITE_ERROR_MASK;
        if(errors)
        {
            *p_status = g_nvm[block]->STATUS;
        }
        else
        {
            /* Perform a verify. */
            g_nvm[block]->CMD = VERIFY_ADS | (offset & PAGE_ADDR_MASK);
            /* Wait for NVM to become ready. */
            ctrl_status = wait_nvm_ready(block);

            *p_status = g_nvm[block]->STATUS;
        }
    }
    
    return length_written;
}
/**************************************************************************//**
 * See mss_nvm.h for details of how to use this function.
 */
nvm_status_t
NVM_unlock
(
    uint32_t start_addr,
    uint32_t length
)
{
    nvm_status_t status;
    uint32_t nvm_offset;
    uint32_t first_page;
    uint32_t last_page;
    uint32_t current_page;
    uint32_t current_offset;
    
    /* 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)
    {
        current_offset = nvm_offset;
        
        first_page = nvm_offset / BYTES_PER_PAGE;
        last_page = (nvm_offset + length) / BYTES_PER_PAGE;

        /* Gain exclusive access to eNVM controller */
        status = get_ctrl_access(nvm_offset, length);

        /* Unlock eNVM one page at a time. */
        if(NVM_SUCCESS == status)
        {
            uint32_t block;
            uint32_t inc;
            uint32_t first_word;
            uint32_t word_offset;
            uint32_t * p_nvm32;
            uint32_t errors;
            
            p_nvm32 = (uint32_t *)NVM_BASE_ADDRESS;
            
            first_word = nvm_offset / 4u;
            word_offset = first_word;
            
            for(current_page = first_page;
                (current_page <= last_page) && (NVM_SUCCESS == status);
                ++current_page)
            {
                uint32_t ctrl_status;
            
                if(word_offset >= BLOCK1_FIRST_WORD_OFFSET)
                {
                    block = NVM_BLOCK_1;
                }
                else
                {
                    block = NVM_BLOCK_0;
                }
                
                for(inc = 0u; inc < WD_WORD_SIZE; ++inc)
                {
                    g_nvm32[block]->WD[inc] = p_nvm32[word_offset];
                    ++word_offset;
                }
                
                g_nvm[block]->PAGE_LOCK = NVM_DO_NOT_LOCK_PAGE;
                g_nvm[block]->CMD = USER_UNLOCK;

                /* Issue program command */
                g_nvm[block]->CMD = PROG_ADS | (current_offset & PAGE_ADDR_MASK);
                current_offset += BYTES_PER_PAGE;
                
                /* Wait for NVM to become ready. */
                ctrl_status = wait_nvm_ready(block);

                /* Check for errors. */
                errors = ctrl_status & WRITE_ERROR_MASK;
                if(errors)
                {
                    uint32_t nvm_hw_status;
                    nvm_hw_status = g_nvm[block]->STATUS;
                    status = get_error_code(nvm_hw_status);
                }
            }
            
            /* Release eNVM controllers so that other masters can gain access to it. */
            release_ctrl_access();
        }
    }
    else
    {
        status = NVM_INVALID_PARAMETER;
    }
    
    return status;
}