/*******************************************************************************
 * (c) Copyright 2011-2016 Microsemi SoC Products Group.  All rights reserved.
 * 
 * This file contains public APIs for SmartFusion2 eNVM software driver.
 * 
 * SVN $Revision: 8442 $
 * SVN $Date: 2016-06-23 12:32:32 +0530 (Thu, 23 Jun 2016) $
 */
/*=========================================================================*//**
  @mainpage SmartFusion2 MSS eNVM Bare Metal Driver.
  
  @section intro_sec Introduction
  The SmartFusion2 microcontroller subsystem (MSS) includes up to two embedded
  non-volatile memory (eNVM) blocks. Each of these eNVM blocks can be a maximum
  size of 256kB. This software driver provides a set of functions for accessing
  and controlling the MSS eNVM as part of a bare metal system where no operating
  system is available. The driver can be adapted for use as part of an operating
  system, but the implementation of the adaptation layer between the driver and
  the operating system's driver model is outside the scope of the driver.
  
  The MSS eNVM driver provides support for the following features:
    - eNVM write (program) operations.
    - eNVM page unlocking
    - eNVM read page write count
  The MSS eNVM driver is provided as C source code.

  
  @section configuration Driver Configuration
  The size of the MSS eNVM varies with different SmartFusion2 device types. You
  must only use this driver to access memory locations within the valid MSS eNVM
  address space for the targeted device. The size of the valid MSS eNVM address
  space corresponds to the size of the MSS eNVM in the device. Some pages of the
  MSS eNVM may be write protected by the SmartFusion2 MSS configurator as part
  of the hardware design flow. The driver cannot unlock or write to these
  protected pages.
  The base address, register addresses and interrupt number assignment for the
  MSS eNVM blocks are defined as constants in the SmartFusion2 CMSIS HAL. You
  must ensure that the latest SmartFusion2 CMSIS HAL is included in the project
  settings of the software tool chain used to build your project and that it is
  generated into your project.

  @section theory_op Theory of Operation
  The total amount of eNVM available in a SmartFusion2 device ranges from 128kB
  to 512kB, provided in one or two physical eNVM blocks. The eNVM blocks are
  divided into pages, with each page holding 128 bytes of data. The MSS eNVM
  driver treats the entire eNVM as a contiguous memory space. It provides write
  access to all pages that are in the valid eNVM address range for the
  SmartFusion2 device and that are not write-protected. The driver imposes no
  restrictions on writing data across eNVM block or page boundaries. The driver
  supports random access writes to the eNVM memory. 

 *//*=========================================================================*/
#ifndef __MSS_NVM_H
#define __MSS_NVM_H

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

/******************************************************************************/
/* Public definitions                                                         */
/******************************************************************************/
/*******************************************************************************
 * Page Locking constants:
 */
/*
 * Indicates that the NVM_write() function should not lock the addressed pages
 * after programming the data.
 */
#define NVM_DO_NOT_LOCK_PAGE    0u

/*
 * Indicates that the NVM_write() function should lock the addressed pages after
 * programming the data.
 */
#define NVM_LOCK_PAGE           1u

/*******************************************************************************
  The nvm_status_t enumeration specifies the possible return values from the
  NVM_write() and NVM_unlock() functions.

    NVM_SUCCESS:
      Indicates that the programming was successful.

    NVM_PROTECTION_ERROR:
      Indicates that the operation could not be completed because of a
      protection error. This happens when attempting to program a page that was
      set as protected in the hardware flow.

    NVM_VERIFY_FAILURE:
      Indicates that one of the verify operations failed.

    NVM_PAGE_LOCK_ERROR:
      Indicates that the operation could not complete because one of the pages
      is locked. This may happen if the page was locked during a previous call
      to NVM_write() or if the page was locked in the hardware design flow.

    NVM_PAGE_LOCK_WARNING:
      Indicates that the page write operation completed but page was not locked.
      This happens in following situations while writing the page with lock.
      
        - Access of M2S060 - eNVM0 block memory 
        - Access of M2S090/150 - eNVM1 block memory.
        - Access of eNVM memory pages when any protection region in the same
          block (eNVM0 or eNVM1 block) is write protected. 

    NVM_WRITE_THRESHOLD_WARNING:
      Indicates that the NVM maximum number of programming cycles has been
      reached.

    NVM_IN_USE_BY_OTHER_MASTER:
      Indicates that some other MSS AHB Bus Matrix master is accessing the NVM.
      This could be due to the FPGA logic or the system controller programming
      the NVM.

    NVM_INVALID_PARAMETER:
      Indicates that one of more of the function parameters has an invalid
      value. This is typically returned when attempting to write or unlock
      the eNVM for invalid address, data pointer, lock page and more
      eNVM than is available on the device.
 */
typedef enum nvm_status
{
    NVM_SUCCESS = 0,
    NVM_PROTECTION_ERROR,
    NVM_VERIFY_FAILURE,
    NVM_PAGE_LOCK_ERROR,
    NVM_PAGE_LOCK_WARNING,
    NVM_WRITE_THRESHOLD_WARNING,
    NVM_IN_USE_BY_OTHER_MASTER,
    NVM_INVALID_PARAMETER
} nvm_status_t;

/******************************************************************************/
/* Public variables                                                           */
/******************************************************************************/


/******************************************************************************/
/* Public function declarations                                               */
/******************************************************************************/

/***************************************************************************//**
  The NVM_write() function is used to program (or write) data into the eNVM.
  This function treats the two eNVM blocks contiguously, so a total of 512kB of
  memory can be accessed linearly. The start address and end address of the
  memory range to be programmed do not need to be page aligned. This function
  supports programming of data that spans multiple pages. This function is a
  blocking function.
  Note: The NVM_write() function performs a verify operation on each page 
        programmed to ensure the eNVM is programmed with the expected data.

  @param start_addr
    The start_addr parameter is the byte aligned start address in the eNVM
    address space, to which the data is to be programmed.

  @param pidata
    The pidata parameter is the byte aligned start address of a buffer 
    containing the data to be programmed.

  @param length
    The length parameter is the number of bytes of data to be programmed.

  @param lock_page
    The lock_page parameter specifies whether the pages that are programmed
    must be locked or not once programmed. Locking the programmed pages prevents
    them from being overwritten by mistake. Subsequent programming of these
    pages will require the pages to be unlocked prior to calling NVM_write().
    Allowed values for lock_page are:
        - NVM_DO_NOT_LOCK_PAGE
        - NVM_LOCK_PAGE

  @return
    This function returns NVM_SUCCESS or NVM_WRITE_THRESHOLD_WARNING or 
    NVM_PAGE_LOCK_WARNING on successful execution. It returns one of the
    following error codes if the programming of the eNVM fails:
    
        - NVM_PROTECTION_ERROR
        - NVM_VERIFY_FAILURE
        - NVM_PAGE_LOCK_ERROR
        - NVM_IN_USE_BY_OTHER_MASTER
        - NVM_INVALID_PARAMETER
        
  Example:
  @code
    uint8_t idata[815] = {"Z"};
    status = NVM_write(0x0, idata, sizeof(idata), NVM_DO_NOT_LOCK_PAGE);
  @endcode
 */
nvm_status_t
NVM_write
(
    uint32_t start_addr,
    const uint8_t * pidata,
    uint32_t length,
    uint32_t lock_page
);

/******************************** Additional API's ******************************/
#define MSS_NVM_ECC2                (1u<<8)     /* NVM 2-bit error occurred */

/***************************************************************************//**
  The NVM_unlock() function is used to unlock the eNVM pages for a specified
  range of eNVM addresses in preparation for writing data into the unlocked
  locations. This function treats the two eNVM blocks contiguously, so a total
  of 512kB of memory can be accessed linearly. The start address and end address
  of the memory range to be unlocked do not need to be page aligned. This
  function supports unlocking of an eNVM address range that spans multiple
  pages. This function is a blocking function.

  @param start_addr
    The start_addr parameter is the byte aligned start address, in the eNVM
    address space, of the memory range to be unlocked.
    
  @param length
    The length parameter is the size in bytes of the memory range to be
    unlocked.

  @return
    This function returns NVM_SUCCESS or NVM_WRITE_THRESHOLD_WARNING or on successful
    execution. It returns one of the following error codes if the unlocking of the eNVM
    fails:
    
        - NVM_PROTECTION_ERROR
        - NVM_VERIFY_FAILURE
        - NVM_PAGE_LOCK_ERROR
        - NVM_IN_USE_BY_OTHER_MASTER
        - NVM_INVALID_PARAMETER
        
  The example code below demonstrates the intended use of the NVM_unlock()
  function:
  @code
    int program_locked_nvm(uint32_t target_addr, uint32_t length)
    {
        nvm_status_t status;
        int success = 0;
        
        status = NVM_unlock(target_addr, length);
        if((NVM_SUCCESS == status)||(NVM_WRITE_THRESHOLD_WARNING == status))
        {
            status = NVM_write(target_addr, buffer, length, NVM_LOCK_PAGE);
            if((NVM_SUCCESS == status)||(NVM_WRITE_THRESHOLD_WARNING == status))
            {
                success = 1; 
            }
        }
        return success;
    }
  @endcode
 */
nvm_status_t
NVM_unlock
(
    uint32_t start_addr,
    uint32_t length
);
/***************************************************************************//**
  The NVM_read_page_write_count() function is used to read the eNVM page 
  write counter value from eNVM aux page. The value returned by 
  NVM_read_page_write_count() is the number of times the eNVM page containing
  the eNVM location specified by the address passed as parameter has been written.

  @param addr
    The addr parameter is the byte aligned address, in the eNVM address space,
    of the eNVM memory location for which we are requesting to read the 
    page write counter value.

  @return
   This function returns the number of write cycles performed on the eNVM page
   containing the eNVM memory location specified by the addr function parameter.
   Return '0' if addr is other than eNVM memory or eNVM reserved protection area.

  The example code below demonstrates the intended use of the NVM_read_page_write_count()
  function:
  @code
        #define NVM_ADDRESS     0x60000100u
        
        uint32_t count;
        count = NVM_read_page_write_count(NVM_ADDRESS);
  @endcode
 */
uint32_t
NVM_read_page_write_count
(
    uint32_t addr
);
#ifdef __cplusplus
}
#endif

#endif /* __MSS_NVM_H */

