diff --git a/arch/arm/src/samv7/Kconfig b/arch/arm/src/samv7/Kconfig index e0dc801581a..772c84ba921 100644 --- a/arch/arm/src/samv7/Kconfig +++ b/arch/arm/src/samv7/Kconfig @@ -517,6 +517,24 @@ config SAMV7_GPIOE_IRQ endif # SAMV7_GPIO_IRQ +menuconfig SAMV7_PROGMEM + bool "FLASH program memory" + ---help--- + Enable support FLASH interfaces as defined in include/nuttx/progmem.h + +if SAMV7_PROGMEM + +config SAMV7_PROGMEM_NSECTORS + int "Number of 128KB sectors" + default 4 + range 1 15 + ---help--- + This is the number of 128KB FLASH sectors at the end of the program + flash memory that will be reserved for use with by the interfaces + prototyped in include/nuttx/progmem.h + +endif # SAMV7_PROGMEM + menu "SDRAM Configuration" depends on SAMV7_SDRAMC diff --git a/arch/arm/src/samv7/Make.defs b/arch/arm/src/samv7/Make.defs index 8a8f86fd2cd..d54d5e656bd 100644 --- a/arch/arm/src/samv7/Make.defs +++ b/arch/arm/src/samv7/Make.defs @@ -175,3 +175,7 @@ endif ifeq ($(CONFIG_SAMV7_USBDEVHS),y) CHIP_CSRCS += sam_usbdevhs.c endif + +ifeq ($(CONFIG_SAMV7_PROGMEM),y) +CHIP_CSRCS += sam_progmem.c +endif diff --git a/arch/arm/src/samv7/chip/sam_eefc.h b/arch/arm/src/samv7/chip/sam_eefc.h index aee93614ae5..3ea86810af3 100644 --- a/arch/arm/src/samv7/chip/sam_eefc.h +++ b/arch/arm/src/samv7/chip/sam_eefc.h @@ -78,14 +78,40 @@ /* EEFC Flash Command Register */ +Start read unique identifier 0x0E STUI + +#define FCMD_GETD (0) /* Get Flash Descriptor */ +#define FCMD_WP (1) /* Write page */ +#define FCMD_WPL (2) /* Write page and lock */ +#define FCMD_EWP (3) /* Erase page and write page */ +#define FCMD_EWPL (4) /* Erase page and write page then lock */ +#define FCMD_EA (5) /* Erase all */ +#define FCMD_EPA (7) /* Erase pages */ +#define FCMD_SLB (8) /* Set Lock Bit */ +#define FCMD_CLB (9) /* Clear Lock Bit */ +#define FCMD_GLB (10) /* Get Lock Bit */ +#define FCMD_SGPB (11) /* Set GPNVM Bit */ +#define FCMD_CGPB (12) /* Clear GPNVM Bit */ +#define FCMD_GGPB (13) /* Get GPNVM Bit */ +#define FCMD_STUI (14) /* Start Read Unique Identifier */ +#define FCMD_SPUI (15) /* Stop Read Unique Identifier */ +#define FCMD_GCALB (16) /* Get CALIB Bit */ +#define FCMD_ES (17) /* Erase Sector */ +#define FCMD_WUS (18) /* Write User Signature */ +#define FCMD_EUS (19) /* Erase User Signature */ +#define FCMD_STUS (20) /* Start Read User Signature */ +#define FCMD_SPUS (21) /* Stop Read User Signature */ + #define EEFC_FCR_FCMD_SHIFT (0) /* Bits 0-7: Flash Command */ #define EEFC_FCR_FCMD_MASK (0xff << EEFC_FCR_FCMD_SHIFT) +# define EEFC_FCR_FCMD(cmd) ((uint32_t)(cmd) << EEFC_FCR_FCMD_SHIFT) # define EEFC_FCR_FCMD_GETD (0 << EEFC_FCR_FCMD_SHIFT) /* Get Flash Descriptor */ # define EEFC_FCR_FCMD_WP (1 << EEFC_FCR_FCMD_SHIFT) /* Write page */ # define EEFC_FCR_FCMD_WPL (2 << EEFC_FCR_FCMD_SHIFT) /* Write page and lock */ # define EEFC_FCR_FCMD_EWP (3 << EEFC_FCR_FCMD_SHIFT) /* Erase page and write page */ # define EEFC_FCR_FCMD_EWPL (4 << EEFC_FCR_FCMD_SHIFT) /* Erase page and write page then lock */ # define EEFC_FCR_FCMD_EA (5 << EEFC_FCR_FCMD_SHIFT) /* Erase all */ +# define EEFC_FCR_FCMD_EPA (7 << EEFC_FCR_FCMD_SHIFT) /* Erase pages */ # define EEFC_FCR_FCMD_SLB (8 << EEFC_FCR_FCMD_SHIFT) /* Set Lock Bit */ # define EEFC_FCR_FCMD_CLB (9 << EEFC_FCR_FCMD_SHIFT) /* Clear Lock Bit */ # define EEFC_FCR_FCMD_GLB (10 << EEFC_FCR_FCMD_SHIFT) /* Get Lock Bit */ @@ -102,7 +128,7 @@ # define EEFC_FCR_FCMD_SPUS (21 << EEFC_FCR_FCMD_SHIFT) /* Stop Read User Signature */ #define EEFC_FCR_FARG_SHIFT (8) /* Bits 8-23: Flash Command Argument */ #define EEFC_FCR_FARG_MASK (0xffff << EEFC_FCR_FARG_SHIFT) -# define EEFC_FCR_FARG(n) ((uint32_t)(n) << EEFC_FCR_FARG_SHIFT) +# define EEFC_FCR_FARG(arg) ((uint32_t)(arg) << EEFC_FCR_FARG_SHIFT) #define EEFC_FCR_FKEY_SHIFT (24) /* Bits 24-31: Flash Writing Protection Key */ #define EEFC_FCR_FKEY_MASK (0xff << EEFC_FCR_FKEY_SHIFT) # define EEFC_FCR_FKEY_PASSWD (0x5a << EEFC_FCR_FKEY_SHIFT) diff --git a/arch/arm/src/samv7/sam_flash.c b/arch/arm/src/samv7/sam_flash.c deleted file mode 100644 index 98595e9ad93..00000000000 --- a/arch/arm/src/samv7/sam_flash.c +++ /dev/null @@ -1,373 +0,0 @@ -/**************************************************************************** - * arch/arm/src/samv7/sam_flash.c - * - * Copyright (C) 2015 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include - -#include -#include /* For SAMV7_ALIGNED_FLASH_SIZE */ - -#include "up_arch.h" -#include "cache.h" - -#include "sam_flash.h" - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ -/* Configuration ************************************************************/ - -#if defined(CONFIG_ARCH_CHIP_SAMV71) -# define SAMV7_SECTOR_SHIFT (17) /* 2**17 = 128KB */ -# define SAMV7_PAGE_SHIFT (9) /* 2**9 = 512B */ -#else -# error FLASH geometry for this SAMV7 chip not known -#endif - -#define SAMV7_SECTOR_SIZE (1 << SAMV7_SECTOR_SHIFT) -#define SAMV7_SECTOR_MASK (SAMV7_SECTOR_SIZE - 1) -#define SAMV7_PAGE_SIZE (1 << SAMV7_PAGE_SHIFT) -#define SAMV7_PAGE_MASK (SAMV7_PAGE_SIZE - 1) -#define SAMV7_SEC2PAGE_SHIFT (SAMV7_SECTOR_SHIFT - SAMV7_PAGE_SHIFT) -#define SAMV7_PAGE_PER_SEC (1 << SAMV7_SEC2PAGE_SHIFT) - -/* Free FLASH begins at the first sector after the FLASH image */ -#warning Missing logic -#define SAMV7_FREE_FLASH_BASE To be provided - -#define ALIGN_UP(v,m) (((v) + (m)) & ~(m)) -#define ALIGN_DOWN(v,m) ((v) & ~(m)) -#define SAMV7_ALIGNED_FLASH_BASE ALIGN_UP(SAMV7_FREE_FLASH_BASE) -#define SAMV7_FREE_FLASH_SIZE (SAMV7_ALIGNED_FLASH_SIZE - SAMV7_ALIGNED_FLASH_BASE) -#define SAMV7_ALIGNED_FLASH_SIZE ALIGN_DOWN(SAMV7_FREE_FLASH_SIZE) -#define SAMV7_NSECTORS (SAMV7_ALIGNED_FLASH_SIZE >> SAMV7_SECTOR_SHIFT) -#define SAMV7_NPAGES (SAMV7_ALIGNED_FLASH_SIZE >> SAMV7_PAGE_SHIFT) - -#define SAMV7_WRITE_ALIGN (16) -#define SAMV7_WRITE_ALIGN_MASK (15) - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -static void sam_flash_unlock(void) -{ -#warning Missing logic -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: up_progmem_npages - * - * Description: - * Return number of pages - * - ****************************************************************************/ - -size_t up_progmem_npages(void) -{ - return SAMV7_NPAGES; -} - -/**************************************************************************** - * Name: up_progmem_isuniform - * - * Description: - * Is program memory uniform or page size differs? - * - ****************************************************************************/ - -bool up_progmem_isuniform(void) -{ - return true; -} - -/**************************************************************************** - * Name: up_progmem_pagesize - * - * Description: - * Return page size - * - ****************************************************************************/ - -size_t up_progmem_pagesize(size_t page) -{ - return SAMV7_PAGE_SIZE; -} - -/**************************************************************************** - * Name: up_progmem_getpage - * - * Description: - * Address to page conversion - * - * Input Parameters: - * addr - Address with or without flash offset (absolute or aligned to page0) - * - * Returned Value: - * Page or negative value on error. The following errors are reported - * (errno is not set!): - * - * EFAULT: On invalid address - * - ****************************************************************************/ - -ssize_t up_progmem_getpage(size_t addr) -{ - if (addr >= SAMV7_ALIGNED_FLASH_BASE) - { - addr -= SAMV7_ALIGNED_FLASH_BASE; - } - - if (addr >= SAMV7_ALIGNED_FLASH_SIZE) - { - return -EFAULT; - } - - return addr >> SAMV7_PAGE_SHIFT; -} - -/**************************************************************************** - * Name: up_progmem_getaddress - * - * Description: - * Page to address conversion - * - * Input Parameters: - * page - page index - * - * Returned Value: - * Base address of given page, SIZE_MAX if page index is not valid. - * - ****************************************************************************/ - -size_t up_progmem_getaddress(size_t page) -{ - if (page >= SAMV7_NPAGES) - { - return SAMV7_ALIGNED_FLASH_SIZE; - } - - return (page << SAMV7_PAGE_SHIFT) + SAMV7_ALIGNED_FLASH_BASE; -} - -/**************************************************************************** - * Name: up_progmem_erasepage - * - * Description: - * Erase selected page. - * - * Input Parameters: - * page - - * - * Returned Value: - * Page size or negative value on error. The following errors are reported - * (errno is not set!): - * - * EFAULT: On invalid page - * EIO: On unsuccessful erase - * EROFS: On access to write protected area - * EACCES: Insufficient permissions (read/write protected) - * EPERM: If operation is not permitted due to some other constraints - * (i.e. some internal block is not running etc.) - * - ****************************************************************************/ - -ssize_t up_progmem_erasepage(size_t page) -{ - size_t page_address; - - if (page >= SAMV7_NPAGES) - { - return -EFAULT; - } - - /* Erase a single page */ - - sam_flash_unlock(); -#warning Missing logic - - /* Invalidate I- and D-Cache in this address range */ -#warning Mising logic - - /* Verify */ - - if (up_progmem_ispageerased(page) == 0) - { - return SAMV7_PAGE_SIZE; /* Success */ - } - else - { - return -EIO; /* Failure */ - } -} - -/**************************************************************************** - * Name: up_progmem_ispageerased - * - * Description: - * Checks whether page is erased - * - * Input Parameters: - * page - - * - * Returned Value: - * Returns number of bytes written or negative value on error. If it - * returns zero then complete page is empty (erased). - * - * The following errors are reported (errno is not set!) - * EFAULT: On invalid page - * - ****************************************************************************/ - -ssize_t up_progmem_ispageerased(size_t page) -{ - size_t addr; - size_t bwritten; - int count; - - if (page >= SAMV7_NPAGES) - { - return -EFAULT; - } - - /* Invalidate D-Cache for this address range */ - - addr = up_progmem_getaddress(page); - arch_invalidate_dcache(addr, addr + SAMV7_PAGE_SIZE); - - /* Verify that the page is erased (i.e., all 0xff) */ - - for (count = SAMV7_PAGE_SIZE, bwritten = 0; - count > 0; - count--, addr++) - { - if (getreg8(addr) != 0xff) - { - bwritten++; - } - } - - return bwritten; -} - -/**************************************************************************** - * Name: up_progmem_write - * - * Description: - * Program data at given address - * - * Note: this function is not limited to single page and nor it requires - * the address be aligned inside the page boundaries. - * - * Input Parameters: - * addr - Address with or without flash offset (absolute or aligned to page0) - * buf - Pointer to buffer - * count - Number of bytes to write - * - * Returned Value: - * Bytes written or negative value on error. The following errors are - * reported (errno is not set!) - * - * EINVAL: If count is not aligned with the flash boundaries (i.e. - * some MCU's require per half-word or even word access) - * EFAULT: On invalid address - * EIO: On unsuccessful write - * EROFS: On access to write protected area - * EACCES: Insufficient permissions (read/write protected) - * EPERM: If operation is not permitted due to some other constraints - * (i.e. some internal block is not running etc.) - * - ****************************************************************************/ - -ssize_t up_progmem_write(size_t addr, const void *buf, size_t count) -{ - uint8_t *src = (uint8_t *)buf; - size_t written = count; - - /* SAMV7 requires 128-bit/16-byte aligned access */ - - if ((addr & SAMV7_WRITE_ALIGN_MASK) != 0 || - (count & SAMV7_WRITE_ALIGN_MASK) != 0) - { - return -EINVAL; - } - - /* Check for valid address range */ - - if (addr >= SAMV7_ALIGNED_FLASH_BASE) - { - /* Convert address to an offset relative to be beginning of the - * writable FLASH region. - */ - - addr -= SAMV7_ALIGNED_FLASH_BASE; - } - - if ((addr + count) >= SAMV7_ALIGNED_FLASH_SIZE) - { - return -EFAULT; - } - - /* Write the data to FLASH */ - - sam_flash_unlock(); -#warning Missing logic - - for (addr += SAMV7_ALIGNED_FLASH_BASE; - count; - count -= SAMV7_WRITE_ALIGN, src += SAMV7_WRITE_ALIGN, addr += SAMV7_WRITE_ALIGN) - { - /* Write 128-bit/16-bytes block to FLASH and wait to complete */ -#warning Mising logic - - /* Invalidate I- and D-Caches for this address range */ -#warning Mising logic - - /* Verify */ -#warning Mising logic - - } - - return written; -} diff --git a/arch/arm/src/samv7/sam_progmem.c b/arch/arm/src/samv7/sam_progmem.c new file mode 100644 index 00000000000..54480ec9549 --- /dev/null +++ b/arch/arm/src/samv7/sam_progmem.c @@ -0,0 +1,705 @@ +/**************************************************************************** + * arch/arm/src/samv7/sam_progmem.c + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include + +#include "up_arch.h" +#include "cache.h" +#include "chip/memorymap.h" + +#include "sam_progmem.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +/* Configuration ************************************************************/ + +#ifndef CONFIG_SAMV7_PROGMEM_NSECTORS +# error CONFIG_SAMV7_PROGMEM_NSECTORS is not defined +#endif + +/* Chip dependencies */ + +#if defined(CONFIG_ARCH_CHIP_SAMV71) +/* All sectors are 128KB and are uniform in size. + * The only execption is sector 0 which is subdivided into two small sectors + * of 8KB and one larger sector of 112KB. + * The page size is 515 bytes. However, the smallest thing that can be + * erased is four pages. We will refer to this as a "cluster". + */ + +# define SAMV7_SECTOR_SHIFT (17) /* 2**17 = 128KB */ +# define SAMV7_PAGE_SHIFT (9) /* 2**9 = 512B */ +# define SAMV7_CLUSTER_SHIFT (11) /* 2**13 = 8*KB = 16 pages */ +# define SAMV7_LOCK_REGION_SHIFT (11) /* 2**13 = 8*KB = 16 pages */ +#else +# error FLASH geometry for this SAMV7 chip not known +#endif + +/* Start address */ + +#define SAMV7_PROGMEM_NBYTES (CONFIG_SAMV7_PROGMEM_NSECTORS << SAMV7_SECTOR_SHIFT) +#define SAMV7_PROGMEM_END (SAM_INTFLASH_BASE + SAMV7_FLASH_SIZE) +#define SAMV7_PROGMEM_START (SAMV7_PROGMEM_END - SAMV7_PROGMEM_NBYTES) + +/* Sizes and masks */ + +#define SAMV7_SECTOR_SIZE (1 << SAMV7_SECTOR_SHIFT) +#define SAMV7_SECTOR_MASK (SAMV7_SECTOR_SIZE - 1) + +#define SAMV7_PAGE_SIZE (1 << SAMV7_PAGE_SHIFT) +#define SAMV7_PAGE_WORDS (1 << (SAMV7_PAGE_SHIFT - 2)) +#define SAMV7_PAGE_MASK (SAMV7_PAGE_SIZE - 1) + +#define SAMV7_CLUSTER_SIZE (1 << SAMV7_CLUSTER_SHIFT) +#define SAMV7_CLUSTER_MASK (SAMV7_CLUSTER_SHIFT - 1) + +/* Relationships */ + +#define SAMV7_PAGE2SEC_SHIFT (SAMV7_SECTOR_SHIFT - SAMV7_PAGE_SHIFT) +#define SAMV7_PAGE_PER_SEC (1 << SAMV7_PAGE2SEC_SHIFT) + +#define SAMV7_PAGE2CLUST_SHIFT (SAMV7_CLUSTER_SHIFT - SAMV7_PAGE_SHIFT) +#define SAMV7_PAGE_PER_CLUSTER (1 << SAMV7_PAGE2CLUST_SHIFT) + +#define SAMV7_CLUST2SECT_SHIFT (SAMV7_SECTOR_SHIFT - SAMV7_CLUSTER_SHIFT) +#define SAMV7_CLUSTER_PER_SEC (1 << SAMV7_CLUST2SECT_SHIFT) + +/* Conversions */ + +#define SAMV7_OFFSET2PAGE(o) ((o) >> SAMV7_PAGE_SHIFT) +#define SAMV7_OFFSET2CLUST(o) ((o) >> SAMV7_CLUSTER_SHIFT) +#define SAMV7_OFFSET2SECT(o) ((o) >> SAMV7_SECTOR_SHIFT) + +#define SAMV7_PAGE2OFFSET(p) ((p) << SAMV7_PAGE_SHIFT) +#define SAMV7_PAGE2CLUST(p) ((p) >> SAMV7_PAGE2CLUST_SHIFT) +#define SAMV7_PAGE2SEC(p) ((p) >> SAMV7_PAGE2SEC_SHIFT) + +#define SAMV7_CLUST2OFFSET(c) ((c) << SAMV7_CLUSTER_SHIFT) +#define SAMV7_CLUST2PAGE(c) ((c) << SAMV7_PAGE2CLUST_SHIFT) +#define SAMV7_CLUST2SEC(c) ((c) >> SAMV7_CLUST2SECT_SHIFT) + +#define SAMV7_SEC2OFFSET(s) ((s) << SAMV7_SECTOR_SHIFT) +#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) + +/* Sizes of the programmable region */ + +#define SAMV7_NSECTORS (CONFIG_SAMV7_PROGMEM_NSECTORS) +#define SAMV7_NPAGES SAMV7_SEC2PAGE(CONFIG_SAMV7_PROGMEM_NSECTORS) +#define SAMV7_NCLUSTERS SAMV7_SEC2CLUST(CONFIG_SAMV7_PROGMEM_NSECTORS) + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static uint32_t g_page_buffer[SAMV7_PAGE_WORDS]; +static sem_t g_page_sem; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: page_lock + * + * Description: + * Get exclusive access to the global page buffer + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void page_lock(void) +{ + while ((ret = sem_wait(&g_page_sem)) < 0) + { + int errcode = errno; + + /* sem_wait should only fail if it was awakened by a signal */ + + DEBUGASSERT(errcode == EINTR); + if (errcode != EINTER) + { + break; + } + } +} + +#define page_unlock() sem_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 = start_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; + } + } + } +} +#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 void 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 = start_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; + } + } + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sam_progmem_initialize + * + * Description: + * Call to initialize FLASH programming memory access + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void sam_progmem_initialize(void) +{ + uint32_t regval; + + /* Make sure that the read interrupt is disabled */ + + regval = getreg32(SAM_EEFC_FMR); + regval &= ~EEFC_FMR_FRDY; + putreg32(regval, SAM_EEFC_FMR); + + /* Initialize the semaphore that manages exclusive access to the global + * page buffer. + */ + + sem_init(&g_page_sem, 0, 1); +} + +/**************************************************************************** + * Name: up_progmem_npages + * + * Description: + * Return number of clusters in the available FLASH memory. + * + ****************************************************************************/ + +size_t up_progmem_npages(void) +{ + return SAMV7_NCLUSTERS; +} + +/**************************************************************************** + * Name: up_progmem_isuniform + * + * Description: + * Cluster size is uniform? Say 'yes' even though that is not strictly + * true do to the odd organization of sector 0. + * + ****************************************************************************/ + +bool up_progmem_isuniform(void) +{ + return true; +} + +/**************************************************************************** + * Name: up_progmem_pagesize + * + * Description: + * Return cluster size + * + ****************************************************************************/ + +size_t up_progmem_pagesize(size_t cluster) +{ + return SAMV7_CLUSTER_SIZE; +} + +/**************************************************************************** + * Name: up_progmem_getpage + * + * Description: + * Address to cluster conversion + * + * Input Parameters: + * address - Address with or without flash offset + * + * Returned Value: + * Page or negative value on error. The following errors are reported + * (errno is not set!): + * + * -EFAULT: On invalid address + * + ****************************************************************************/ + +ssize_t up_progmem_getpage(size_t address) +{ + if (address >= SAMV7_PROGMEM_START) + { + address -= SAMV7_PROGMEM_START; + } + + if (address >= SAMV7_PROGMEM_NBYTES) + { + return -EFAULT; + } + + return address >> SAMV7_CLUSTER_SHIFT; +} + +/**************************************************************************** + * Name: up_progmem_getaddress + * + * Description: + * Cluster to address conversion + * + * Input Parameters: + * cluster - cluster index + * + * Returned Value: + * Base address of given cluster, maximum size if cluster index is not valid. + * + ****************************************************************************/ + +size_t up_progmem_getaddress(size_t cluster) +{ + if (cluster >= SAMV7_NCLUSTERS) + { + return SAMV7_PROGMEM_NBYTES; + } + + return (cluster << SAMV7_CLUSTER_SHIFT) + SAMV7_PROGMEM_START; +} + +/**************************************************************************** + * Name: up_progmem_erasepage + * + * Description: + * Erase selected cluster. + * + * Input Parameters: + * cluster - cluster index to be erased + * + * Returned Value: + * Page size or negative value on error. The following errors are reported + * (errno is not set!): + * + * -EFAULT: On invalid cluster + * -EIO: On unsuccessful erase + * -EROFS: On access to write protected area + * -EACCES: Insufficient permissions (read/write protected) + * -EPERM: If operation is not permitted due to some other constraints + * (i.e. some internal block is not running etc.) + * + ****************************************************************************/ + +ssize_t up_progmem_erasepage(size_t cluster) +{ + uintptr_t address; + uint32_t page; + uint32_t arg; + + if (cluster >= SAMV7_NCLUSTERS) + { + return -EFAULT; + } + + /* Get the page number of the start of the cluster */ + + page = SAMV7_CLUST2PAGE((uint32_t)cluster); + + /* Erase all pages in the cluster */ + + efc_unlock(page, SAMV7_PAGE_PER_CLUSTER); + + /* Get FARG field for EPA command: + * + * The first page to be erased is specified in the FARG[15:2] field of + * the EEFC_FCR register. The first page number must be modulo 4, 8,16 or + * 32 according to the number of pages to erase at the same time. + * + * The 2 lowest bits of the FARG field define the number of pages to + * be erased (FARG[1:0]). + */ + +#if SAMV7_CLUSTER_SIZE == 32 + arg = (page << 2) | 3; /* Not valid for small 8 KB sectors */ +#elif SAMV7_CLUSTER_SIZE == 16 + arg = (page << 2) | 2; +#elif SAMV7_CLUSTER_SIZE == 8 +# error Cluster size of 8 not suportted + arg = (page << 2) | 1; /* 0nly valid for small 8 KB sectors */ +#elif SAMV7_CLUSTER_SIZE == 4 +# error Cluster size of 4 not suportted + arg = (page << 2) | 0; /* 0nly valid for small 8 KB sectors */ +#else +# error Unsupported/undefined cluster size +#endif + + ret = efc_command(pEfc, FCMD_EPA, arg); + + /* Invalidate I- and D-Cache in this address range */ + + address = SAMV7_CLUST2OFFSET((uintptr_t)cluster) + SAMV7_PROGMEM_START; + arch_dcache_invalidate(address, address + SAMV7_CLUSTER_SIZE); + + /* Verify */ + + if (up_progmem_ispageerased(cluster) == 0) + { + return SAMV7_CLUSTER_SIZE; /* Success */ + } + else + { + return -EIO; /* Failure */ + } +} + +/**************************************************************************** + * Name: up_progmem_ispageerased + * + * Description: + * Checks whether cluster is erased + * + * Input Parameters: + * cluster - cluster to be checked + * + * Returned Value: + * Returns number of bytes erased or negative value on error. If it + * returns zero then complete cluster is empty (erased). + * + * The following errors are reported (errno is not set!) + * -EFAULT: On invalid cluster + * + ****************************************************************************/ + +ssize_t up_progmem_ispageerased(size_t cluster) +{ + size_t address; + size_t nwritten; + int nleft; + + if (cluster >= SAMV7_NCLUSTERS) + { + return -EFAULT; + } + + /* Invalidate D-Cache for this address range */ + + address = (cluster << SAMV7_CLUSTER_SHIFT) + SAMV7_PROGMEM_START; + arch_invalidate_dcache(address, address + SAMV7_CLUSTER_SIZE); + + /* Verify that the cluster is erased (i.e., all 0xff) */ + + for (nleft = SAMV7_CLUSTER_SIZE, nwritten = 0; + nleft > 0; + nleft--, address++) + { + if (getreg8(address) != 0xff) + { + nwritten++; + } + } + + return nwritten; +} + +/**************************************************************************** + * Name: up_progmem_write + * + * Description: + * Program data at given address + * + * Input Parameters: + * address - Address with or without flash offset + * buffer - Pointer to buffer + * buflen - Number of bytes to write + * + * Returned Value: + * Bytes written or negative value on error. The following errors are + * reported (errno is not set!) + * + * EINVAL: If buflen is not aligned with the flash boundaries (i.e. + * some MCU's require per half-word or even word access) + * EFAULT: On invalid address + * EIO: On unsuccessful write + * EROFS: On access to write protected area + * EACCES: Insufficient permissions (read/write protected) + * EPERM: If operation is not permitted due to some other constraints + * (i.e. some internal block is not running etc.) + * + ****************************************************************************/ + +ssize_t up_progmem_write(size_t address, const void *buffer, size_t buflen) +{ + FAR uint32_t *dest; + FAR const uint32_t *src; + size_t written; + size_t xfrsize; + size_t offset; + size_t page; + + /* Convert the address into a FLASH offset, if necessary */ + + offset = address; + if (address >= SAMV7_PROGMEM_START) + { + /* Convert address to an offset relative to be beginning of the + * writable FLASH region. + */ + + offset -= SAMV7_PROGMEM_START; + } + + /* Check for valid address range */ + + if ((offset + buflen) >= SAMV7_PROGMEM_NBYTES) + { + return -EFAULT; + } + + /* Get the page number corresponding to the flash offset and the byte + * offset into the page. + */ + + page = offset >> SAMV7_PAGE_SHIFT; + offset &= SAMV7_PAGE_MASK; + + /* Get exclusive access to the global page buffer */ + + page_lock(); + + /* Make sure that the FLASH is unlocked */ + + efc_unlock(page, SAMV7_SECTOR_SHIFT(buflen)); + + /* Loop until all of the data has been written */ + + dest = (FAR uint32_t *)address; + written = 0; + + while (buflen > 0) + { + /* How much can we write into this page? */ + + xfrsize = min((size_t)SAMV7_PAGE_SIZE - offset, buflen) ; + + /* Do we need to use the intermediate buffer? */ + + if (offset == 0 && xfsize == SAMV7_PAGE_SIZE) + { + /* No, we can take the data directly from the user buffer */ + + src = (FAR const uint32_t *)buffer; + } + else + { + /* Yes, copy data into global page buffer */ + + memcpy(g_page_buffer, dest, offset); + memcpy((uint8_t *)g_page_buffer + offset, buffer, xfrsize); + memcpy((uint8_t *)g_page_buffer + offset + xfrsize, + (const uint8_t *)dest + offset + xfrsize, + SAMV7_PAGE_SIZE - offset - xfrsize); + + src = g_page_buffer; + } + + /* Write the page */ + + for (i = 0; i < (SAMV7_PAGE_SIZE / sizeof(uint32_t)); i++) + { + *dest++ = *src++; + ARM_DMB(); + } + + /* Flush the data cache to memory */ + + arch_clean_dcache(address, address + SAMV7_PAGE_SIZE); + + /* Send the write command */ + + ret = efc_command(FCMD_WP, page); + if (ret >= 0) + { + written += wrsize; + } + + /* Adjust pointers and counts for the next time through the loop */ + + address += wrsize; + dest = (FAR uint32_t *)address; + buffer = (FAR void *)((uintptr_t)buffer + wrsize); + buflen -= wrsize; + page++; + } + + page_unlock(); + return written; +} diff --git a/arch/arm/src/samv7/sam_flash.h b/arch/arm/src/samv7/sam_progmem.h similarity index 73% rename from arch/arm/src/samv7/sam_flash.h rename to arch/arm/src/samv7/sam_progmem.h index 66de9fb4af9..6c2deaff7f0 100644 --- a/arch/arm/src/samv7/sam_flash.h +++ b/arch/arm/src/samv7/sam_progmem.h @@ -1,5 +1,5 @@ /**************************************************************************** - * arch/arm/src/samv7/sam_flash.c + * arch/arm/src/samv7/sam_progmem.c * * Copyright (C) 2015 Gregory Nutt. All rights reserved. * Author: Gregory Nutt @@ -33,8 +33,8 @@ * ****************************************************************************/ -#ifndef __ARCH_ARM_SRC_SAMV7_SAM_FLASH_H -#define __ARCH_ARM_SRC_SAMV7_SAM_FLASH_H +#ifndef __ARCH_ARM_SRC_SAMV7_SAM_PROGMEM_H +#define __ARCH_ARM_SRC_SAMV7_SAM_PROGMEM_H /**************************************************************************** * Included Files @@ -42,9 +42,29 @@ #include -#include "chip.h" +#include "up_arch.h" #include "chip/sam_eefc.h" #include -#endif /* __ARCH_ARM_SRC_SAMV7_SAM_FLASH_H */ +/**************************************************************************** + * Inline Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sam_progmem_initialize + * + * Description: + * Call to initialize FLASH programming memory access + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void sam_progmem_initialize(void); + +#endif /* __ARCH_ARM_SRC_SAMV7_SAM_PROGMEM_H */