コード例 #1
0
ファイル: mss_nvm.c プロジェクト: fengyanhua/smartfusion2
/**************************************************************************//**
 * Get access to eNVM controller for eNVM0 and eNVM1
 */
static nvm_status_t get_ctrl_access(uint32_t nvm_offset, uint32_t length)
{
    nvm_status_t access_req_status;
    
    /*
     * Gain access to eNVM controller(s).
     */
    if(nvm_offset < NVM1_BOTTOM_OFFSET)
    {
        access_req_status = request_nvm_access(NVM_BLOCK_0);
        if(NVM_SUCCESS == access_req_status)
        {
            uint32_t last_offset;
            last_offset = nvm_offset + (length - 0x1u);
            if(last_offset >= NVM1_BOTTOM_OFFSET)
            {
                access_req_status = request_nvm_access(NVM_BLOCK_1);
                if(NVM_IN_USE_BY_OTHER_MASTER == access_req_status)
                {
                    release_ctrl_access();
                }
            }
        }
    }
    else
    {
        access_req_status = request_nvm_access(NVM_BLOCK_1);
    }
    
    return access_req_status;
}
コード例 #2
0
ファイル: mss_nvm.c プロジェクト: fengyanhua/smartfusion2
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;
    }
コード例 #3
0
ファイル: mss_nvm.c プロジェクト: fengyanhua/smartfusion2
/**************************************************************************//**
 * 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;
}
コード例 #4
0
ファイル: mss_nvm.c プロジェクト: fengyanhua/smartfusion2
/**************************************************************************//**
 * 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;
}
コード例 #5
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;
    
    /* 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;
}
コード例 #6
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;
    
    /*
     * 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;
}