From 17680faaa8cbafa3451a2783fb36bac747f1a091 Mon Sep 17 00:00:00 2001 From: Michal Lenc Date: Wed, 25 Jun 2025 10:54:40 +0200 Subject: [PATCH] boards/arm/samv7/samv71-xult: initialize s25fl1 NOR flash This moves the initialization of s25fl1 NOR flash from sam_bringup.c to a separate file sam_s25fl1.c and allows to easily set what types of partitions should be present on the NOR flash. New example configuration that allows NXFFS, BCH and MTD layers is added. SmartFS is currently not configured as the initialization fails on s25fl1 flash. Signed-off-by: Michal Lenc --- .../samv7/samv71-xult/configs/mtd/defconfig | 93 ++++ boards/arm/samv7/samv71-xult/src/Make.defs | 4 + .../arm/samv7/samv71-xult/src/sam_bringup.c | 100 +--- boards/arm/samv7/samv71-xult/src/sam_s25fl1.c | 454 ++++++++++++++++++ .../arm/samv7/samv71-xult/src/samv71-xult.h | 23 +- 5 files changed, 572 insertions(+), 102 deletions(-) create mode 100644 boards/arm/samv7/samv71-xult/configs/mtd/defconfig create mode 100644 boards/arm/samv7/samv71-xult/src/sam_s25fl1.c diff --git a/boards/arm/samv7/samv71-xult/configs/mtd/defconfig b/boards/arm/samv7/samv71-xult/configs/mtd/defconfig new file mode 100644 index 0000000000000..b720b0375ef1c --- /dev/null +++ b/boards/arm/samv7/samv71-xult/configs/mtd/defconfig @@ -0,0 +1,93 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_ARCH_RAMFUNCS is not set +# CONFIG_MMCSD_MMCSUPPORT is not set +# CONFIG_MMCSD_SPI is not set +# CONFIG_SAMV7_SDRAMHEAP is not set +# CONFIG_SAMV7_UART0 is not set +# CONFIG_SAMV7_UART2 is not set +# CONFIG_SAMV7_UART4 is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="samv71-xult" +CONFIG_ARCH_BOARD_COMMON=y +CONFIG_ARCH_BOARD_SAMV71_XULT=y +CONFIG_ARCH_BUTTONS=y +CONFIG_ARCH_CHIP="samv7" +CONFIG_ARCH_CHIP_SAMV71=y +CONFIG_ARCH_CHIP_SAMV71Q21=y +CONFIG_ARCH_CHIP_SAMV71Q=y +CONFIG_ARCH_CHIP_SAMV7=y +CONFIG_ARCH_CHIP_SAMV7_MEM_FLASH=0x200000 +CONFIG_ARCH_CHIP_SAMV7_MEM_RAM=0x60000 +CONFIG_ARCH_INTERRUPTSTACK=2048 +CONFIG_ARCH_IRQBUTTONS=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_ARMV7M_DCACHE=y +CONFIG_ARMV7M_ICACHE=y +CONFIG_AT24XX_ADDR=0x57 +CONFIG_AT24XX_EXTENDED=y +CONFIG_AT24XX_EXTSIZE=160 +CONFIG_AT24XX_SIZE=2 +CONFIG_BOARD_LOOPSPERMSEC=51262 +CONFIG_BUILTIN=y +CONFIG_FAT_LCNAMES=y +CONFIG_FAT_LFN=y +CONFIG_FS_FAT=y +CONFIG_FS_NXFFS=y +CONFIG_FS_PROCFS=y +CONFIG_FS_SMARTFS=y +CONFIG_I2CTOOL_MAXBUS=0 +CONFIG_I2C_RESET=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_LINE_MAX=64 +CONFIG_MMCSD_MULTIBLOCK_LIMIT=1 +CONFIG_MMCSD_SDIO=y +CONFIG_MTD=y +CONFIG_MTD_AT24XX=y +CONFIG_MTD_AT25=y +CONFIG_MTD_BYTE_WRITE=y +CONFIG_MTD_CONFIG=y +CONFIG_MTD_PARTITION=y +CONFIG_MTD_PARTITION_REGISTER=y +CONFIG_MTD_PROGMEM=y +CONFIG_MTD_S25FL1=y +CONFIG_MTD_SMART=y +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_DISABLE_LOSMART=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_READLINE=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_RAM_SIZE=393216 +CONFIG_RAM_START=0x20400000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SAMV7_GPIOA_IRQ=y +CONFIG_SAMV7_GPIOB_IRQ=y +CONFIG_SAMV7_GPIOD_IRQ=y +CONFIG_SAMV7_GPIO_IRQ=y +CONFIG_SAMV7_HSMCI0=y +CONFIG_SAMV7_JTAG_FULL_SW_ENABLE=y +CONFIG_SAMV7_QSPI=y +CONFIG_SAMV7_QSPI_DMA=y +CONFIG_SAMV7_SDRAMC=y +CONFIG_SAMV7_SDRAMSIZE=2097152 +CONFIG_SAMV7_TWIHS0=y +CONFIG_SAMV7_TWIHS0_GLITCH_FILTER=0 +CONFIG_SAMV7_USART1=y +CONFIG_SAMV7_XDMAC=y +CONFIG_SCHED_HPWORK=y +CONFIG_SCHED_WAITPID=y +CONFIG_SDIO_BLOCKSETUP=y +CONFIG_START_DAY=10 +CONFIG_START_MONTH=3 +CONFIG_START_YEAR=2014 +CONFIG_SYSTEM_I2CTOOL=y +CONFIG_SYSTEM_NSH=y +CONFIG_TESTING_RAMTEST=y +CONFIG_USART1_SERIAL_CONSOLE=y diff --git a/boards/arm/samv7/samv71-xult/src/Make.defs b/boards/arm/samv7/samv71-xult/src/Make.defs index 15df7aea06883..6d638847f02e9 100644 --- a/boards/arm/samv7/samv71-xult/src/Make.defs +++ b/boards/arm/samv7/samv71-xult/src/Make.defs @@ -105,6 +105,10 @@ ifeq ($(CONFIG_LCD_ST7789),y) CSRCS += sam_st7789.c endif +ifeq ($(CONFIG_MTD_S25FL1),y) +CSRCS += sam_s25fl1.c +endif + .PHONY = context distclean $(SCRIPTOUT): $(LDSCRIPT_TEMPLATE) $(CONFIGFILE) diff --git a/boards/arm/samv7/samv71-xult/src/sam_bringup.c b/boards/arm/samv7/samv71-xult/src/sam_bringup.c index 06e32bc08895b..e9b210236ba41 100644 --- a/boards/arm/samv7/samv71-xult/src/sam_bringup.c +++ b/boards/arm/samv7/samv71-xult/src/sam_bringup.c @@ -50,15 +50,6 @@ #include "sam_twihs.h" #include "samv71-xult.h" -#if defined(HAVE_S25FL1) || defined(HAVE_PROGMEM_CHARDEV) -# include -#endif - -#ifdef HAVE_S25FL1 -# include -# include "sam_qspi.h" -#endif - #ifdef HAVE_LED_DRIVER # include #endif @@ -208,20 +199,8 @@ static void sam_i2ctool(void) int sam_bringup(void) { -#ifdef HAVE_S25FL1 - struct qspi_dev_s *qspi; -#endif -#if defined(HAVE_S25FL1) - struct mtd_dev_s *mtd; -#endif #if defined(HAVE_RTC_DSXXXX) || defined(HAVE_RTC_PCF85263) struct i2c_master_s *i2c; -#endif -#if defined(HAVE_S25FL1_CHARDEV) -#if defined(CONFIG_BCH) - char blockdev[18]; - char chardev[12]; -#endif /* defined(CONFIG_BCH) */ #endif int ret; @@ -409,82 +388,11 @@ int sam_bringup(void) #endif #ifdef HAVE_S25FL1 - /* Create an instance of the SAMV71 QSPI device driver */ - - qspi = sam_qspi_initialize(0); - if (!qspi) - { - syslog(LOG_ERR, "ERROR: sam_qspi_initialize failed\n"); - } - else + ret = sam_s25fl1_init(); + if (ret < 0) { - /* Use the QSPI device instance to initialize the - * S25FL1 device. - */ - - mtd = s25fl1_initialize(qspi, true); - if (!mtd) - { - syslog(LOG_ERR, "ERROR: s25fl1_initialize failed\n"); - } - -#ifdef HAVE_S25FL1_SMARTFS - /* Configure the device with no partition support */ - - ret = smart_initialize(S25FL1_SMART_MINOR, mtd, NULL); - if (ret != OK) - { - syslog(LOG_ERR, "ERROR: Failed to initialize SmartFS: %d\n", ret); - } - -#elif defined(HAVE_S25FL1_NXFFS) - /* Initialize to provide NXFFS on the S25FL1 MTD interface */ - - ret = nxffs_initialize(mtd); - if (ret < 0) - { - syslog(LOG_ERR, "ERROR: NXFFS initialization failed: %d\n", ret); - } - - /* Mount the file system at /mnt/s25fl1 */ - - ret = nx_mount(NULL, "/mnt/s25fl1", "nxffs", 0, NULL); - if (ret < 0) - { - syslog(LOG_ERR, "ERROR: Failed to mount the NXFFS volume: %d\n", - ret); - return ret; - } - -#else /* if defined(HAVE_S25FL1_CHARDEV) */ - /* Use the FTL layer to wrap the MTD driver as a block driver */ - - ret = ftl_initialize(S25FL1_MTD_MINOR, mtd); - if (ret < 0) - { - syslog(LOG_ERR, "ERROR: Failed to initialize the FTL layer: %d\n", - ret); - return ret; - } - -#if defined(CONFIG_BCH) - /* Use the minor number to create device paths */ - - snprintf(blockdev, sizeof(blockdev), "/dev/mtdblock%d", - S25FL1_MTD_MINOR); - snprintf(chardev, sizeof(chardev), "/dev/mtd%d", S25FL1_MTD_MINOR); - - /* Now create a character device on the block device */ - - ret = bchdev_register(blockdev, chardev, false); - if (ret < 0) - { - syslog(LOG_ERR, "ERROR: bchdev_register %s failed: %d\n", - chardev, ret); - return ret; - } -#endif /* defined(CONFIG_BCH) */ -#endif + syslog(LOG_ERR, "ERROR: Failed to initialize s25fl flash: %d\n", + ret); } #endif diff --git a/boards/arm/samv7/samv71-xult/src/sam_s25fl1.c b/boards/arm/samv7/samv71-xult/src/sam_s25fl1.c new file mode 100644 index 0000000000000..b3294324515c9 --- /dev/null +++ b/boards/arm/samv7/samv71-xult/src/sam_s25fl1.c @@ -0,0 +1,454 @@ +/**************************************************************************** + * boards/arm/samv7/samv71-xult/src/sam_s25fl1.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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 + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "sam_qspi.h" +#include "samv71-xult.h" +#include "board_progmem.h" /* For struct mtd_partition_s definition */ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define QSPI_PORTNO 0 + +typedef enum + { + MTD_TYPE_BCH, + MTD_TYPE_SMARTFS, + MTD_TYPE_NXFFS, + MTD_TYPE_MTD, + } mtd_types; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct mtd_partition_s g_mtd_partition_table[] = +{ + { + .size = 0x4000, /* 16 KiB */ + .devpath = "/nxffs", + .type = MTD_TYPE_NXFFS, + }, + { + .size = 0x8000, /* 32 KiB */ + .devpath = "/dev/bch", + .type = MTD_TYPE_BCH, + }, + { + .size = 0x8000, /* 32 KiB */ + .devpath = "/dev/mtd", + .type = MTD_TYPE_MTD, + }, +}; + +static const size_t g_mtd_partition_table_size = + nitems(g_mtd_partition_table); + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: issmartfs + * + * Description: + * Check a SMART (Sector Mapped Allocation for Really Tiny) Flash file + * system image on the specified block device (must be a SMART device). + * + * Inputs: + * pathname - the full path to a registered block driver + * + * Return: + * Zero (OK) on success; -1 (ERROR) on failure with errno set: + * + * EINVAL - NULL block driver string + * ENOENT - 'pathname' does not refer to anything in the filesystem. + * ENOTBLK - 'pathname' does not refer to a block driver + * EFTYPE - the block driver hasn't been formatted yet + * + ****************************************************************************/ + +#ifdef CONFIG_FS_SMARTFS +static int issmartfs(FAR const char *pathname) +{ + struct smart_format_s fmt; + int fd; + int ret; + + /* Find the inode of the block driver identified by 'source' */ + + fd = open(pathname, O_RDONLY); + if (fd < 0) + { + return ERROR; + } + + /* Get the format information so we know the block have been formatted */ + + ret = ioctl(fd, BIOC_GETFORMAT, (unsigned long)&fmt); + if (ret < 0) + { + close(fd); + return ret; + } + + if (!(fmt.flags & SMART_FMT_ISFORMATTED)) + { + errno = EFTYPE; + ret = ERROR; + } + + close(fd); + return ret; +} + +/**************************************************************************** + * Name: mksmartfs + * + * Description: + * Make a SMART Flash file system image on the specified block device + * + * Inputs: + * pathname - the full path to a registered block driver + * sectorsize - the size of logical sectors on the device from 256-16384. + * Setting this to zero will cause the device to be formatted + * using the default CONFIG_MTD_SMART_SECTOR_SIZE value. + * nrootdirs - Number of root directory entries to create. + * + * Return: + * Zero (OK) on success; -1 (ERROR) on failure with errno set. + * + * Assumptions: + * - The caller must assure that the block driver is not mounted and not in + * use when this function is called. The result of formatting a mounted + * device is indeterminate (but likely not good). + * + ****************************************************************************/ + +static int mksmartfs(FAR const char *pathname, uint16_t sectorsize) +{ + struct smart_format_s fmt; + struct smart_read_write_s request; + uint8_t type; + int fd; + int ret; + + /* Find the inode of the block driver identified by 'pathname' */ + + fd = open(pathname, O_RDWR); + if (fd < 0) + { + ret = -ENOENT; + goto errout; + } + + /* Perform a low-level SMART format */ + + ret = ioctl(fd, BIOC_LLFORMAT, sectorsize << 16); + if (ret != OK) + { + ret = -errno; + goto errout_with_driver; + } + + /* Get the format information so we know how big the sectors are */ + + ret = ioctl(fd, BIOC_GETFORMAT, (unsigned long) &fmt); + if (ret != OK) + { + ret = -errno; + goto errout_with_driver; + } + + /* Now write the filesystem to media. */ + + ret = ioctl(fd, BIOC_ALLOCSECT, SMARTFS_ROOT_DIR_SECTOR); + if (ret != SMARTFS_ROOT_DIR_SECTOR) + { + ret = -EIO; + goto errout_with_driver; + } + + /* Mark this block as a directory entry */ + + type = SMARTFS_SECTOR_TYPE_DIR; + request.offset = 0; + request.count = 1; + request.buffer = &type; + request.logsector = SMARTFS_ROOT_DIR_SECTOR; + + /* Issue a write to the sector, single byte */ + + ret = ioctl(fd, BIOC_WRITESECT, (unsigned long) &request); + if (ret != OK) + { + ret = -EIO; + goto errout_with_driver; + } + +errout_with_driver: + + /* Close the driver */ + + close(fd); + +errout: + + /* Return any reported errors */ + + if (ret < 0) + { + errno = -ret; + return ERROR; + } + + return OK; +} +#endif /* CONFIG_FS_SMARTFS */ + +/**************************************************************************** + * Name: sam_s25fl1_alloc_mtdpart + * + * Description: + * Allocate an MTD partition from FLASH. + * + * Input Parameters: + * mtd - The MTD device to be partitioned + * mtd_offset - MTD Partition offset from the base address in FLASH. + * mtd_size - Size for the MTD partition. + * + * Returned Value: + * MTD partition data pointer on success, NULL on failure. + * + ****************************************************************************/ + +static struct mtd_dev_s +*sam_s25fl1_alloc_mtdpart(struct mtd_dev_s *mtd, + struct mtd_geometry_s *geo, + struct mtd_partition_s + *part) +{ + ASSERT((part->offset + part->size) <= geo->neraseblocks * geo->erasesize); + ASSERT((part->offset % geo->erasesize) == 0); + ASSERT((part->size % geo->erasesize) == 0); + + size_t startblock = part->offset / geo->blocksize; + size_t blocks = part->size / geo->blocksize; + + return mtd_partition(mtd, startblock, blocks); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sam_s25fl1_init + * + * Description: + * Initialize s25fl1. + * + ****************************************************************************/ + +int sam_s25fl1_init(void) +{ + int ret = OK; +#ifdef CONFIG_FS_SMARTFS + char partref[4]; + char smartfs_path[30]; +#endif + + struct qspi_dev_s *qspi = sam_qspi_initialize(QSPI_PORTNO); + if (!qspi) + { + syslog(LOG_ERR, "ERROR: sam_qspi_initialize failed\n"); + return ERROR; + } + + /* Use the QSPI device instance to initialize the s25fl1 device. */ + + struct mtd_dev_s *mtd = s25fl1_initialize(qspi, true); + if (!mtd) + { + syslog(LOG_ERR, "ERROR: s25fl1_initialize failed\n"); + return ERROR; + } + + /* Get geometry of s25fl1 */ + + struct mtd_geometry_s geometry; + ret = MTD_IOCTL(mtd, MTDIOC_GEOMETRY, (unsigned long)&geometry); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: s25fl1 ioctl failed: %s\n", + strerror(errno)); + return ret; + } + + size_t i; + size_t offset = 0; + for (i = 0; i < g_mtd_partition_table_size; i++) + { + struct mtd_partition_s *part = &g_mtd_partition_table[i]; + part->offset = offset; + if (part->size == 0) + { + part->size = (geometry.neraseblocks * geometry.erasesize) - offset; + } + + part->mtd = sam_s25fl1_alloc_mtdpart(mtd, &geometry, part); + if (!part->mtd) + { + syslog(LOG_ERR, "ERROR: sam_s25fl1_alloc_mtdpart failed\n"); + return ERROR; + } + + /* Use the FTL layer to wrap the MTD driver as a block driver */ + + if (part->type == MTD_TYPE_BCH) + { + ret = ftl_initialize(S25FL1_MTD_MINOR + i, part->mtd); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: Failed to initialize FTL layer: %d\n", + ret); + return ret; + } + + /* Now create a character device on the block device */ + +#if defined(CONFIG_BCH) + char blockdev[18]; + snprintf(blockdev, sizeof(blockdev), "/dev/mtdblock%d", + S25FL1_MTD_MINOR + i); + ret = bchdev_register(blockdev, part->devpath, false); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: bchdev_register %s failed: %d\n", + part->devpath, ret); + return ret; + } +#endif /* defined(CONFIG_BCH) */ + } + else if (part->type == MTD_TYPE_SMARTFS) + { +#if defined (CONFIG_FS_SMARTFS) + sprintf(partref, "p%d", i); + ret = smart_initialize(0, part->mtd, partref); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: smart_initialize %s failed: %d\n", + part->devpath, ret); + return ret; + } + + sprintf(smartfs_path, "/dev/smart0%s", partref); + if (issmartfs(smartfs_path) != OK) + { + mksmartfs(smartfs_path, 0); + } + + ret = nx_mount(smartfs_path, part->devpath, "smartfs", 0, + NULL); + if (ret < 0) + { + /* Mount failed. */ + + syslog(LOG_ERR, "ERROR: mount %s failed: %d\n", smartfs_path, + ret); + return ret; + } +#endif + } + else if (part->type == MTD_TYPE_NXFFS) + { +#if defined (HAVE_S25FL1_NXFFS) + /* Initialize to provide NXFFS on the S25FL1 MTD interface */ + + ret = nxffs_initialize(mtd); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: NXFFS initialization failed: %d\n", + ret); + } + + /* Mount the file system at /mnt/s25fl1 */ + + ret = nx_mount(NULL, part->devpath, "nxffs", 0, NULL); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: Failed to mount NXFFS volume: %d\n", + ret); + return ret; + } +#endif + } + else if (part->type == MTD_TYPE_MTD) + { +#if defined (HAVE_S25FL1_MTDDEV) + ret = mtd_partition_register(part->mtd, part->devpath, false); + if (ret < 0) + { + syslog(LOG_ERR, "failed to register %d %d\n", ret, errno); + } +#endif + } + else + { + syslog(LOG_ERR, "ERROR: Incorrect device type %d for %s.\n", + part->type, part->devpath); + } + + offset += part->size; + } + + return ret; +} diff --git a/boards/arm/samv7/samv71-xult/src/samv71-xult.h b/boards/arm/samv7/samv71-xult/src/samv71-xult.h index e806afbb1a813..1dce5c4d73a46 100644 --- a/boards/arm/samv7/samv71-xult/src/samv71-xult.h +++ b/boards/arm/samv7/samv71-xult/src/samv71-xult.h @@ -53,6 +53,7 @@ #define HAVE_S25FL1_NXFFS 1 #define HAVE_S25FL1_SMARTFS 1 #define HAVE_S25FL1_CHARDEV 1 +#define HAVE_S25FL1_MTDDEV 1 #define HAVE_PROGMEM_CHARDEV 1 #define HAVE_WM8904 1 #define HAVE_AUDIO_NULL 1 @@ -180,6 +181,7 @@ # undef HAVE_S25FL1_NXFFS # undef HAVE_S25FL1_SMARTFS # undef HAVE_S25FL1_CHARDEV +# undef HAVE_S25FL1_MTDDEV #endif #ifndef CONFIG_SAMV7_QSPI @@ -187,6 +189,7 @@ # undef HAVE_S25FL1_NXFFS # undef HAVE_S25FL1_SMARTFS # undef HAVE_S25FL1_CHARDEV +# undef HAVE_S25FL1_MTDDEV #endif #ifndef CONFIG_FS_NXFFS @@ -197,12 +200,8 @@ # undef HAVE_S25FL1_SMARTFS #endif -#if defined(HAVE_S25FL1_NXFFS) && defined(HAVE_S25FL1_SMARTFS) -# undef HAVE_S25FL1_NXFFS -#endif - -#if defined(HAVE_S25FL1_NXFFS) || defined(HAVE_S25FL1_SMARTFS) -# undef HAVE_S25FL1_CHARDEV +#ifndef CONFIG_MTD_PARTITON_REGISTER +# undef HAVE_S25FL1_MTDDEV #endif /* On-chip Programming Memory */ @@ -733,6 +732,18 @@ int sam_emac0_setmac(void); int sam_at24config(void); #endif +/**************************************************************************** + * Name: sam_s25fl1_init + * + * Description: + * Create an S25F1 NOR flash based MTD configuration device. + * + ****************************************************************************/ + +#ifdef CONFIG_MTD_S25FL1 +int sam_s25fl1_init(void); +#endif + /**************************************************************************** * Name: sam_tsc_setup *