You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by gn...@apache.org on 2020/02/20 14:34:45 UTC

[incubator-nuttx] 01/02: add eefc driver and read uid

This is an automated email from the ASF dual-hosted git repository.

gnutt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git

commit 286d8875d555d70b191ec5be3f86fa6707e436c5
Author: klmchp <ke...@gmail.com>
AuthorDate: Thu Feb 20 18:32:08 2020 +0800

    add eefc driver and read uid
---
 arch/arm/src/samv7/Make.defs                       |   4 +-
 arch/arm/src/samv7/sam_eefc.c                      | 331 +++++++++++++++++++++
 arch/arm/src/samv7/sam_eefc.h                      | 127 ++++++++
 arch/arm/src/samv7/sam_progmem.c                   | 160 ++--------
 arch/arm/src/samv7/sam_uid.c                       |  73 +++++
 arch/arm/src/samv7/sam_uid.h                       |  44 +++
 boards/arm/samv7/same70-xplained/src/sam_appinit.c |  30 ++
 boards/arm/samv7/samv71-xult/README.txt            |   1 +
 boards/arm/samv7/samv71-xult/src/sam_appinit.c     |   2 +
 9 files changed, 628 insertions(+), 144 deletions(-)

diff --git a/arch/arm/src/samv7/Make.defs b/arch/arm/src/samv7/Make.defs
index b0e7a21..138cf3f 100644
--- a/arch/arm/src/samv7/Make.defs
+++ b/arch/arm/src/samv7/Make.defs
@@ -106,7 +106,7 @@ endif
 
 CHIP_ASRCS  =
 CHIP_CSRCS  = sam_start.c sam_clockconfig.c sam_irq.c sam_allocateheap.c
-CHIP_CSRCS += sam_lowputc.c sam_serial.c sam_gpio.c sam_pck.c
+CHIP_CSRCS += sam_lowputc.c sam_serial.c sam_gpio.c sam_pck.c sam_uid.c
 
 # Configuration-dependent SAMV7 files
 
@@ -199,7 +199,7 @@ CHIP_CSRCS += sam_trng.c
 endif
 
 ifeq ($(CONFIG_SAMV7_PROGMEM),y)
-CHIP_CSRCS += sam_progmem.c
+CHIP_CSRCS += sam_progmem.c sam_eefc.c
 endif
 
 ifeq ($(CONFIG_SAMV7_DAC),y)
diff --git a/arch/arm/src/samv7/sam_eefc.c b/arch/arm/src/samv7/sam_eefc.c
new file mode 100755
index 0000000..84e043f
--- /dev/null
+++ b/arch/arm/src/samv7/sam_eefc.c
@@ -0,0 +1,331 @@
+/****************************************************************************
+ * arch/arm/src/samv7/sam_eefc.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <string.h>
+#include <semaphore.h>
+#include <errno.h>
+
+#include <nuttx/arch.h>
+#include <arch/samv7/chip.h>
+
+#include "barriers.h"
+
+#include "hardware/sam_memorymap.h"
+
+#include "sam_eefc.h"
+
+#if defined(CONFIG_ARCH_HAVE_RAMFUNCS) && defined(CONFIG_ARCH_RAMFUNCS)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Configuration ************************************************************/
+
+#if defined(CONFIG_ARCH_CHIP_SAMV71) || defined(CONFIG_ARCH_CHIP_SAME70)
+/* All sectors are 128KB and are uniform in size.
+ * The only exception is sector 0 which is subdivided into two small sectors
+ * of 8KB and one larger sector of 112KB.
+ * The page size is 512 bytes.  However, the smallest thing that can be
+ * erased is four pages.  We will refer to this as a "cluster".
+ */
+#  define SAMV7_LOCK_REGION_SHIFT (13)   /* 2**13 = 8*KB = 16 pages */
+#else
+#  error FLASH geometry for this SAMV7 chip not known
+#endif
+
+/* Lock region */
+
+#define SAMV7_LOCK_REGION_SIZE   (1 << SAMV7_LOCK_REGION_SHIFT)
+#define SAMV7_LOCK_REGION_MASK   (SAMV7_LOCK_REGION_SIZE - 1)
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: sam_eefc_writefmr
+ *
+ * Description:
+ *   Write flash mode register
+ *
+ * Input Parameters:
+ *   regval - The FLASH mode register to be set
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+__ramfunc__ void sam_eefc_writefmr(uint32_t regval)
+{
+  putreg32(regval, SAM_EEFC_FMR);
+}
+
+/****************************************************************************
+ * Name: sam_eefc_command
+ *
+ * Description:
+ *   Send a FLASH command
+ *
+ * Input Parameters:
+ *   cmd - The FLASH command to be sent
+ *   arg - The argument to accompany the command
+ *
+ * Returned Value:
+ *   Zero is returned on success; a negated errno value is returned on any
+ *   failure.
+ *
+ ****************************************************************************/
+
+__ramfunc__ int sam_eefc_command(uint32_t cmd, uint32_t arg)
+{
+  volatile uint32_t regval;
+  irqstate_t flags;
+
+  flags = up_irq_save();
+
+  /* Write the command to the flash command register */
+
+  regval = EEFC_FCR_FCMD(cmd) |  EEFC_FCR_FARG(arg) | EEFC_FCR_FKEY_PASSWD;
+  putreg32(regval, SAM_EEFC_FCR);
+
+  /* Wait for the FLASH to become ready again */
+
+  do
+    {
+      regval = getreg32(SAM_EEFC_FSR);
+    }
+  while ((regval & EEFC_FSR_FRDY) != EEFC_FSR_FRDY);
+
+  up_irq_restore(flags);
+
+  /* Check for errors */
+
+  if ((regval & (EEFC_FSR_FLOCKE | EEFC_FSR_FCMDE | EEFC_FSR_FLERR)) != 0)
+    {
+      return -EIO;
+    }
+  else
+    {
+      return OK;
+    }
+}
+
+/****************************************************************************
+ * Name: sam_eefc_readsequence
+ *
+ * Description:
+ *   Flash sequence read
+ *
+ * Input Parameters:
+ *   start_cmd - Start command to perform.
+ *   stop_cmd - Stop command to perform.
+ *   buffer - Pointer to a data buffer.
+ *
+ * Returned Value:
+ *   ENOMEM: Input buffer error
+ *   OK: Sequence read success
+ *
+ ****************************************************************************/
+
+__ramfunc__ int sam_eefc_readsequence(uint32_t start_cmd, uint32_t stop_cmd,
+                                      uint32_t* buffer, size_t bufsize)
+{
+  volatile uint32_t regval;
+  uint32_t* flash_data;
+  size_t read_count;
+
+  if (buffer == NULL)
+    {
+      return -EINVAL;
+    }
+
+  flash_data = (uint32_t *)SAM_INTFLASH_BASE;
+
+  /* Enabled Sequential Code Optimization of flash controller */
+
+  regval = getreg32(SAM_EEFC_FMR);
+  regval |= EEFC_FMR_SCOD;
+  sam_eefc_writefmr(regval);
+
+  /* Send the Start Read command */
+
+  regval = EEFC_FCR_FCMD(start_cmd) |  EEFC_FCR_FARG(FCMD_GETD)| EEFC_FCR_FKEY_PASSWD;
+  putreg32(regval, SAM_EEFC_FCR);
+
+  /* Wait for the FRDY bit in the Flash Programming Status Register
+   * (EEFC_FSR) falls.
+   */
+
+  do
+    {
+      regval = getreg32(SAM_EEFC_FSR);
+    }
+  while ((regval & EEFC_FSR_FRDY) == EEFC_FSR_FRDY);
+
+  /* The data is located in the first address of the Flash
+   * memory mapping.
+   */
+
+  for (read_count = 0; read_count < bufsize; read_count++)
+    {
+      buffer[read_count] = flash_data[read_count];
+    }
+
+  /* Send the Stop Read command */
+
+  regval = EEFC_FCR_FCMD(stop_cmd) |  EEFC_FCR_FARG(FCMD_GETD) | EEFC_FCR_FKEY_PASSWD;
+  putreg32(regval, SAM_EEFC_FCR);
+
+  /* Wait for the FRDY bit in the Flash Programming Status Register
+   * rises.
+   */
+
+  do
+    {
+      regval = getreg32(SAM_EEFC_FSR);
+    }
+  while ((regval & EEFC_FSR_FRDY) != EEFC_FSR_FRDY);
+
+  regval = getreg32(SAM_EEFC_FMR);
+  regval &= ~EEFC_FMR_SCOD;
+  sam_eefc_writefmr(regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: sam_eefc_initaccess
+ *
+ * Description:
+ *   Initial flash access mode and wait status
+ *
+ * Input Parameters:
+ *   access_mode - 0 for 128-bit, EEFC_FMR_FAM for 64-bit.
+ *   wait_status - The number of wait states in cycle (no shift).
+ *
+ * Returned Value:
+ *   NONE
+ ****************************************************************************/
+
+void sam_eefc_initaccess(uint32_t access_mode, uint32_t wait_status)
+{
+	sam_eefc_writefmr(access_mode | EEFC_FMR_FWS(wait_status));
+}
+
+/****************************************************************************
+ * Name: sam_eefc_lock
+ *
+ * Description:
+ *   Lock a region of FLASH
+ *
+ * Input Parameters:
+ *   page  - The first page to unlock
+ *   npages - The number of consecutive pages to unlock
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+#if 0 /* Not used */
+int sam_eefc_lock(size_t page, size_t npages)
+{
+  size_t start_page;
+  size_t end_page;
+  size_t lockpage;
+  int ret;
+
+  /* Align the page to the lock region */
+
+  end_page   = page + npages;
+  start_page = page & SAMV7_LOCK_REGION_MASK;
+
+  for (lockpage = start_page;
+       lockpage < end_page;
+       lockpage += SAMV7_LOCK_REGION_SIZE)
+    {
+      ret = sam_eefccommand(FCMD_SLB, lockpage);
+      if (ret < 0)
+        {
+          return ret;
+        }
+    }
+
+  return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: sam_eefc_unlock
+ *
+ * Description:
+ *   Make sure that the FLASH is unlocked
+ *
+ * Input Parameters:
+ *   page  - The first page to unlock
+ *   npages - The number of consecutive pages to unlock
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int sam_eefc_unlock(size_t page, size_t npages)
+{
+  size_t start_page;
+  size_t end_page;
+  size_t lockpage;
+  irqstate_t flags;
+  int ret;
+
+  /* Align the page to the lock region */
+
+  end_page   = page + npages;
+  start_page = page & SAMV7_LOCK_REGION_MASK;
+
+  for (lockpage = start_page;
+       lockpage < end_page;
+       lockpage += SAMV7_LOCK_REGION_SIZE)
+    {
+      flags = up_irq_save();
+      ret = sam_eefc_command(FCMD_CLB, lockpage);
+      up_irq_restore(flags);
+      if (ret < 0)
+        {
+          return ret;
+        }
+    }
+
+  return OK;
+}
+
+#endif /* defined(CONFIG_ARCH_HAVE_RAMFUNCS) && defined(CONFIG_ARCH_RAMFUNCS) */
diff --git a/arch/arm/src/samv7/sam_eefc.h b/arch/arm/src/samv7/sam_eefc.h
new file mode 100755
index 0000000..b7e8643
--- /dev/null
+++ b/arch/arm/src/samv7/sam_eefc.h
@@ -0,0 +1,127 @@
+/****************************************************************************
+ * arch/arm/src/samv7/sam_eefc.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_SAMV7_SAM_EEFC_H
+#define __ARCH_ARM_SRC_SAMV7_SAM_EEFC_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include "up_arch.h"
+#include "up_internal.h"
+#include "hardware/sam_eefc.h"
+
+#include <nuttx/progmem.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define SAM_EFC_ACCESS_MODE_128    0
+#define SAM_EFC_ACCESS_MODE_64     EEFC_FMR_FAM
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Inline Functions
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: sam_eefc_writefmr
+ *
+ * Description:
+ *   Write flash mode register.
+ *
+ ****************************************************************************/
+
+__ramfunc__ void sam_eefc_writefmr(uint32_t regval);
+
+/****************************************************************************
+ * Name: sam_eefc_command
+ *
+ * Description:
+ *   Send a FLASH command.
+ *
+ ****************************************************************************/
+
+__ramfunc__ int sam_eefc_command(uint32_t cmd, uint32_t arg);
+
+/****************************************************************************
+ * Name: sam_eefc_readsequence
+ *
+ * Description:
+ *   Flash sequence read.
+ *
+ ****************************************************************************/
+
+__ramfunc__ int sam_eefc_readsequence(uint32_t start_cmd, uint32_t stop_cmd,
+                                      uint32_t* buffer, size_t bufsize);
+
+/****************************************************************************
+ * Name: sam_eefc_initaccess
+ *
+ * Description:
+ *   Initial enhanced embedded flash access mode.
+ *
+ ****************************************************************************/
+
+void sam_eefc_initaccess(uint32_t access_mode, uint32_t wait_status);
+
+/****************************************************************************
+ * Name: sam_eefc_unlock
+ *
+ * Description:
+ *   Make sure that the FLASH is unlocked
+ *
+ ****************************************************************************/
+
+int sam_eefc_unlock(size_t page, size_t npages);
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __ASSEMBLY__ */
+#endif /* __ARCH_ARM_SRC_SAMV7_SAM_EEFC_H */
diff --git a/arch/arm/src/samv7/sam_progmem.c b/arch/arm/src/samv7/sam_progmem.c
index 8045869..1f3efff 100644
--- a/arch/arm/src/samv7/sam_progmem.c
+++ b/arch/arm/src/samv7/sam_progmem.c
@@ -47,10 +47,12 @@
 #include <arch/samv7/chip.h>
 
 #include "up_arch.h"
+#include "up_internal.h"
 #include "barriers.h"
 
 #include "hardware/sam_memorymap.h"
 
+#include "sam_eefc.h"
 #include "sam_progmem.h"
 
 /****************************************************************************
@@ -62,11 +64,15 @@
 #  error CONFIG_SAMV7_PROGMEM_NSECTORS is not defined
 #endif
 
+#ifndef CONFIG_ARCH_RAMFUNCS
+#   error "Flashing function should executed in ram"
+#endif
+
 /* Chip dependencies */
 
 #if defined(CONFIG_ARCH_CHIP_SAMV71) || defined(CONFIG_ARCH_CHIP_SAME70)
 /* All sectors are 128KB and are uniform in size.
- * The only execption is sector 0 which is subdivided into two small sectors
+ * The only exception is sector 0 which is subdivided into two small sectors
  * of 8KB and one larger sector of 112KB.
  * The page size is 512 bytes.  However, the smallest thing that can be
  * erased is four pages.  We will refer to this as a "cluster".
@@ -121,11 +127,6 @@
 #define SAMV7_SEC2PAGE(s)        ((s) << SAMV7_PAGE2SEC_SHIFT)
 #define SAMV7_SEC2CLUST(s)       ((s) << SAMV7_CLUST2SECT_SHIFT)
 
-/* Lock region */
-
-#define SAMV7_LOCK_REGION_SIZE   (1 << SAMV7_LOCK_REGION_SHIFT)
-#define SAMV7_LOCK_REGION_MASK   (SAMV7_LOCK_REGION_SIZE - 1)
-
 /* Total FLASH sizes */
 
 #define SAMV7_TOTAL_NSECTORS     (SAMV7_FLASH_SIZE >> SAMV7_SECTOR_SHIFT)
@@ -193,135 +194,6 @@ static void page_buffer_lock(void)
 #define page_buffer_unlock() nxsem_post(&g_page_sem)
 
 /****************************************************************************
- * Name: efc_command
- *
- * Description:
- *   Send a FLASH command
- *
- * Input Parameters:
- *   cmd - The FLASH command to be sent
- *   arg - The argument to accompany the command
- *
- * Returned Value:
- *   Zero is returned on success; a negated errno value is returned on any
- *   failure.
- *
- ****************************************************************************/
-
-static int efc_command(uint32_t cmd, uint32_t arg)
-{
-  uint32_t regval;
-
-  /* Write the command to the flash command register */
-
-  regval = EEFC_FCR_FCMD(cmd) |  EEFC_FCR_FARG(arg) | EEFC_FCR_FKEY_PASSWD;
-  putreg32(regval, SAM_EEFC_FCR);
-
-  /* Wait for the FLASH to become ready again */
-
-  do
-    {
-      regval = getreg32(SAM_EEFC_FSR);
-    }
-  while ((regval & EEFC_FSR_FRDY) == 0);
-
-  /* Check for errors */
-
-  if ((regval & (EEFC_FSR_FLOCKE | EEFC_FSR_FCMDE | EEFC_FSR_FLERR)) != 0)
-    {
-      return -EIO;
-    }
-  else
-    {
-      return OK;
-    }
-}
-
-/****************************************************************************
- * Name: efc_lock
- *
- * Description:
- *   Lock a region of FLASH
- *
- * Input Parameters:
- *   page  - The first page to unlock
- *   npages - The number of consecutive pages to unlock
- *
- * Returned Value:
- *   Zero on success; a negated errno value on failure.
- *
- ****************************************************************************/
-
-#if 0 /* Not used */
-static int efc_lock(size_t page, size_t npages)
-{
-  size_t start_page;
-  size_t end_page;
-  size_t lockpage;
-  int ret;
-
-  /* Align the page to the lock region */
-
-  end_page   = page + npages;
-  start_page = page & SAMV7_LOCK_REGION_MASK;
-
-  for (lockpage = start_page;
-       lockpage < end_page;
-       lockpage += SAMV7_LOCK_REGION_SIZE)
-    {
-      ret = efc_command(FCMD_SLB, lockpage);
-      if (ret < 0)
-        {
-          return ret;
-        }
-    }
-
-  return OK;
-}
-#endif
-
-/****************************************************************************
- * Name: efc_unlock
- *
- * Description:
- *   Make sure that the FLASH is unlocked
- *
- * Input Parameters:
- *   page  - The first page to unlock
- *   npages - The number of consecutive pages to unlock
- *
- * Returned Value:
- *   Zero on success; a negated errno value on failure.
- *
- ****************************************************************************/
-
-static int efc_unlock(size_t page, size_t npages)
-{
-  size_t start_page;
-  size_t end_page;
-  size_t lockpage;
-  int ret;
-
-  /* Align the page to the lock region */
-
-  end_page   = page + npages;
-  start_page = page & SAMV7_LOCK_REGION_MASK;
-
-  for (lockpage = start_page;
-       lockpage < end_page;
-       lockpage += SAMV7_LOCK_REGION_SIZE)
-    {
-      ret = efc_command(FCMD_CLB, lockpage);
-      if (ret < 0)
-        {
-          return ret;
-        }
-    }
-
-  return OK;
-}
-
-/****************************************************************************
  * Public Functions
  ****************************************************************************/
 
@@ -343,11 +215,15 @@ void sam_progmem_initialize(void)
 {
   uint32_t regval;
 
+  /* Set flash access mode to 128bit and wait status to 4 */
+
+  sam_eefc_initaccess(SAM_EFC_ACCESS_MODE_128, 4);
+
   /* Make sure that the read interrupt is disabled */
 
   regval  = getreg32(SAM_EEFC_FMR);
   regval &= ~EEFC_FMR_FRDY;
-  putreg32(regval, SAM_EEFC_FMR);
+  sam_eefc_writefmr(regval);
 
   /* Initialize the semaphore that manages exclusive access to the global
    * page buffer.
@@ -504,7 +380,7 @@ ssize_t up_progmem_eraseblock(size_t cluster)
 
   /* Erase all pages in the cluster */
 
-  efc_unlock(page, SAMV7_PAGE_PER_CLUSTER);
+  sam_eefc_unlock(page, SAMV7_PAGE_PER_CLUSTER);
 
   /* Get FARG field for EPA command:
    *
@@ -522,15 +398,15 @@ ssize_t up_progmem_eraseblock(size_t cluster)
     arg   = page | 2;
 #elif SAMV7_PAGE_PER_CLUSTER == 8
 #  error Cluster size of 8 not suportted
-    arg   = page | 1;   /* 0nly valid for small 8 KB sectors */
+    arg   = page | 1;   /* Only valid for small 8 KB sectors */
 #elif SAMV7_PAGE_PER_CLUSTER == 4
 #  error Cluster size of 4 not suportted
-    arg   = page | 0;   /* 0nly valid for small 8 KB sectors */
+    arg   = page | 0;   /* Only valid for small 8 KB sectors */
 #else
 #  error Unsupported/undefined pages-per-cluster size
 #endif
 
-  ret = efc_command(FCMD_EPA, arg);
+  ret = sam_eefc_command(FCMD_EPA, arg);
   if (ret < 0)
     {
       return ret;
@@ -666,7 +542,7 @@ ssize_t up_progmem_write(size_t address, const void *buffer, size_t buflen)
 
   /* Make sure that the FLASH is unlocked */
 
-  efc_unlock(page, SAMV7_BYTE2PAGE(buflen + SAMV7_PAGE_MASK));
+  sam_eefc_unlock(page, SAMV7_BYTE2PAGE(buflen + SAMV7_PAGE_MASK));
 
   /* Loop until all of the data has been written */
 
@@ -722,7 +598,7 @@ ssize_t up_progmem_write(size_t address, const void *buffer, size_t buflen)
 
       /* Send the write command */
 
-      ret = efc_command(FCMD_WP, page);
+      ret = sam_eefc_command(FCMD_WP, page);
       if (ret >= 0)
         {
           written += xfrsize;
diff --git a/arch/arm/src/samv7/sam_uid.c b/arch/arm/src/samv7/sam_uid.c
new file mode 100755
index 0000000..de1c1ee
--- /dev/null
+++ b/arch/arm/src/samv7/sam_uid.c
@@ -0,0 +1,73 @@
+/****************************************************************************
+ * arch/arm/src/samv7/sam_uid.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include "sam_eefc.h"
+#include "sam_uid.h"
+
+
+#ifdef CONFIG_BOARDCTL_UNIQUEID
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: sam_get_uniqueid
+ *
+ * Description:
+ *   Get unique id of device.
+ *
+ * Input Parameters:
+ *   uniqueid  - The buffer to store unique id.
+ *
+ * Returned Value:
+ *   NONE.
+ *
+ ****************************************************************************/
+
+void sam_get_uniqueid(uint8_t uniqueid[16])
+{
+  uint32_t buffer[4];
+  uint8_t  index;
+
+  /* Set flash access mode to 128bit and wait status to 4 */
+
+  sam_eefc_initaccess(SAM_EFC_ACCESS_MODE_128, 4);
+
+  /* Get device unique id */
+
+  sam_eefc_readsequence(FCMD_STUI, FCMD_SPUI, buffer, 4);
+
+  for (index = 0; index < 4; index++)
+    {
+      uniqueid[4*index + 3] = (uint8_t)buffer[index];
+      uniqueid[4*index + 2] = (uint8_t)(buffer[index] >> 8);
+      uniqueid[4*index + 1] = (uint8_t)(buffer[index] >> 16);
+      uniqueid[4*index + 0] = (uint8_t)(buffer[index] >> 24);
+    }
+}
+
+#endif /* CONFIG_BOARDCTL_UNIQUEID */
diff --git a/arch/arm/src/samv7/sam_uid.h b/arch/arm/src/samv7/sam_uid.h
new file mode 100755
index 0000000..e5e4ca7
--- /dev/null
+++ b/arch/arm/src/samv7/sam_uid.h
@@ -0,0 +1,44 @@
+/****************************************************************************
+ * arch/arm/src/samv7/sam_uid.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_SAMV7_SAM_UID_H
+#define __ARCH_ARM_SRC_SAMV7_SAM_UID_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <stdint.h>
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: sam_get_uniqueid
+ *
+ * Description:
+ *   Get unique id of device.
+ *
+ ****************************************************************************/
+
+void sam_get_uniqueid(uint8_t uniqueid[16]);
+
+#endif /* __ARCH_ARM_SRC_SAMV7_SAM_UID_H */
diff --git a/boards/arm/samv7/same70-xplained/src/sam_appinit.c b/boards/arm/samv7/same70-xplained/src/sam_appinit.c
index 30f756d..629e6ff 100644
--- a/boards/arm/samv7/same70-xplained/src/sam_appinit.c
+++ b/boards/arm/samv7/same70-xplained/src/sam_appinit.c
@@ -41,8 +41,11 @@
 
 #include <sys/types.h>
 
+#include <nuttx/arch.h>
 #include <nuttx/board.h>
+#include <arch/board/board.h>
 
+#include "sam_uid.h"
 #include "same70-xplained.h"
 
 #ifdef CONFIG_LIB_BOARDCTL
@@ -87,4 +90,31 @@ int board_app_initialize(uintptr_t arg)
 #endif
 }
 
+#ifdef CONFIG_BOARDCTL_IOCTL
+int board_ioctl(unsigned int cmd, uintptr_t arg)
+{
+  switch (cmd)
+    {
+      default:
+        return -ENOTTY;  /* Standard return for command not supported */
+        break;
+    }
+
+  return OK;
+}
+#endif
+
+#if defined(CONFIG_BOARDCTL_UNIQUEID)
+int board_uniqueid(uint8_t *uniqueid)
+{
+  if (uniqueid == NULL)
+    {
+      return -EINVAL;
+    }
+
+  sam_get_uniqueid(uniqueid);
+  return OK;
+}
+#endif
+
 #endif /* CONFIG_LIB_BOARDCTL */
diff --git a/boards/arm/samv7/samv71-xult/README.txt b/boards/arm/samv7/samv71-xult/README.txt
index 426d09e..16153b9 100644
--- a/boards/arm/samv7/samv71-xult/README.txt
+++ b/boards/arm/samv7/samv71-xult/README.txt
@@ -579,6 +579,7 @@ An on-chip FLASH driver was added and verified on 2015-11-13.  These
 configuration options were enabled to test the on-chip FLASH support:
 
   CONFIG_MTD_PROGMEM=y
+  CONFIG_ARCH_RAMFUNCS=y
   CONFIG_SAMV7_PROGMEM=y
   CONFIG_SAMV7_PROGMEM_NSECTORS=8
 
diff --git a/boards/arm/samv7/samv71-xult/src/sam_appinit.c b/boards/arm/samv7/samv71-xult/src/sam_appinit.c
index d8c9035..b16daad 100644
--- a/boards/arm/samv7/samv71-xult/src/sam_appinit.c
+++ b/boards/arm/samv7/samv71-xult/src/sam_appinit.c
@@ -45,6 +45,7 @@
 #include <nuttx/board.h>
 #include <arch/board/board.h>
 
+#include "sam_uid.h"
 #include "samv71-xult.h"
 
 #ifdef CONFIG_LIB_BOARDCTL
@@ -111,6 +112,7 @@ int board_uniqueid(uint8_t *uniqueid)
       return -EINVAL;
     }
 
+  sam_get_uniqueid(uniqueid);
   return OK;
 }
 #endif