You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2022/06/15 12:29:24 UTC

[incubator-nuttx] 02/02: nucleo-wl55jc: add partition table support for progmem FLASH

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

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

commit 4d4566e9ed070e749ad27a5a24d7772b7c340116
Author: Michał Łyszczek <mi...@bofc.pl>
AuthorDate: Tue Jun 14 01:11:33 2022 +0200

    nucleo-wl55jc: add partition table support for progmem FLASH
    
    This patch adds working integration of progmem FLASH. User can partition
    internal FLASH memory to up to 4 partitions and use any combination of
    raw, nxffs, smartfs and mtd_config filesystems (unless there are other
    limitations like nxffs supports only single instance).
    
    Support for dual CPU is added to Kconfig to not overwrite CPU2 program code.
    
    Code guards user to not allocate more memory than there is on FLASH, and
    warns user if not all FLASH memory is used. Errors will be printed when
    user tries to initialize two instances of nxffs or mtd_config filesystems.
    
    Signed-off-by: Michał Łyszczek <mi...@bofc.pl>
---
 boards/arm/stm32wl5/nucleo-wl55jc/Kconfig          | 258 ++++++++++++++++++
 .../stm32wl5/nucleo-wl55jc/configs/demo/defconfig  |  19 ++
 boards/arm/stm32wl5/nucleo-wl55jc/src/Makefile     |   4 +
 .../arm/stm32wl5/nucleo-wl55jc/src/nucleo-wl55jc.h |  10 +
 .../arm/stm32wl5/nucleo-wl55jc/src/stm32_appinit.c |  10 +
 .../arm/stm32wl5/nucleo-wl55jc/src/stm32_flash.c   | 297 +++++++++++++++++++++
 6 files changed, 598 insertions(+)

diff --git a/boards/arm/stm32wl5/nucleo-wl55jc/Kconfig b/boards/arm/stm32wl5/nucleo-wl55jc/Kconfig
index 1d568310d2..a65425890d 100644
--- a/boards/arm/stm32wl5/nucleo-wl55jc/Kconfig
+++ b/boards/arm/stm32wl5/nucleo-wl55jc/Kconfig
@@ -17,4 +17,262 @@ config ARCH_BOARD_NUCLEO_WL55JC_DEMO_LED_IRQ
 comment "[demo] LED on button interrupt requires NSH_ARCHINIT"
 	depends on !NSH_ARCHINIT || !ARCH_BUTTONS
 
+menuconfig ARCH_BOARD_FLASH_MOUNT
+	bool "Enable FLASH partitioning and mounting"
+	depends on !DISABLE_MOUNTPOINT
+	select MTD
+	select MTD_PROGMEM
+	select MTD_PARTITION
+	select MTD_PARTITION_NAMES
+	select FS_PROCFS
+	default n
+	---help---
+		When enabled, you will be able to configure partition table
+		for onboard FLASH memory to create and mount flash filesystems.
+		All partition sizes are specified in PAGE_SIZE size. On
+		STM32WL5 page size is always 2048.
+
+		On STM32WL55JC there are 128 pages of flash memory. Size of
+		all configured partitions shall not exceed 128. In fact, it
+		should be equal to 128 or else you will simply have unused
+		space on flash. Even if you want some raw flash access you
+		should specify this partition in table and select fs_raw.
+
+		By default there are only 4 partitions defined, if you need
+		more, you can define more in Kconfig and stm32_flash.c files.
+
+comment "FLASH partitioning and mounting requires !DISABLE_MOUNTPOINT"
+	depends on DISABLE_MOUNTPOINT
+
+if ARCH_BOARD_FLASH_MOUNT
+
+config ARCH_BOARD_FLASH_CPU1_PROG_SIZE
+	int "Size reserved for CPU1 program code"
+	default 127
+	---help---
+		How much memory to reserve for CPU1 program code. This should
+		specified as other partitions will be created at offset to
+		this partition.
+
+config ARCH_BOARD_FLASH_CPU2_PROG_SIZE
+	int "Size reserved for CPU2 program code"
+	default 0
+	---help---
+		How much memory to reserve for CPU2 program code. If you use
+		dual CPU you should specify how much memory you want to
+		reserve for code for second CPU. User partition will be
+		created at this offset. If you don't use CPU2, set this to 0.
+
+config ARCH_BOARD_FLASH_PART1_SIZE
+	int "Size of user partition 1"
+	default 1
+	---help---
+		Size of partition specified in PAGE_SIZE. Page size on
+		stm32wl5xxx is always 2048.
+
+config ARCH_BOARD_FLASH_PART1_NAME
+	string "Name of user partition 1"
+	default "part1"
+	---help---
+		MTD partition name, this can be later read by MTD API,
+		or it can also be read from /proc/partitions to easily
+		identify partitions.
+
+config ARCH_BOARD_FLASH_PART1_MNT
+	string "Mount point for user partition 1"
+	default "/mnt/part1"
+	---help---
+		Directory where filesystem should be mounted.
+
+		Note: not all filesystems can be mounted. rawfs and
+		mtdconfig for example cannot be mounted. In that case
+		this config will be ignored.
+
+config ARCH_BOARD_FLASH_PART1_FS
+	string
+	default "rawfs" if ARCH_BOARD_FLASH_PART1_FS_RAWFS
+	default "nxffs" if ARCH_BOARD_FLASH_PART1_FS_NXFFS
+	default "smartfs" if ARCH_BOARD_FLASH_PART1_FS_SMARTFS
+	default "mtdconfig" if ARCH_BOARD_FLASH_PART1_FS_MTDCONFIG
+
+choice
+	prompt "Filesystem of user partition 1"
+	default ARCH_BOARD_FLASH_PART1_FS_RAW
+
+config ARCH_BOARD_FLASH_PART1_FS_RAWFS
+	bool "rawfs"
+	---help---
+		Raw block device /dev/mtdblockN will be available to use
+		with standard open(2)/fopen(3) functions.
+
+config ARCH_BOARD_FLASH_PART1_FS_NXFFS
+	select FS_NXFFS
+	bool "nxffs"
+	---help---
+		Partition will be used as nxffs. Only one nxffs partition
+		can be enabled at one given time!
+
+config ARCH_BOARD_FLASH_PART1_FS_SMARTFS
+	select FS_SMARTFS
+	select MTD_SMART
+	bool "smartfs"
+	---help---
+		Partition will be used as smartfs. After first flash, you
+		will have to format partition with "mksmartfs /dev/smartN"
+		command. This has to be done only once unless you change
+		partition table that would affect offsets and/or sizes.
+		Programmers (like openocd) should not touch this memory
+		when flashing new software, unless you exceeded reserved
+		memory for program code.
+
+		Smartfs uses quite substential ammount of FLASH data to
+		get to workable state and mount. Looks like 8 page sizes
+		is absolute minimum (so a 16KiB!).
+
+config ARCH_BOARD_FLASH_PART1_FS_MTDCONFIG
+	select MTD_CONFIG
+	bool "mtdconfig"
+	---help---
+		Purpose build filesystem to hold application's configuration.
+		It's not a filesystem per se, as it cannot be mounted and
+		setting and retrieving configuration is done via ioctl(2)
+		calls.
+
+endchoice # Filesystem of user partition 1
+
+config ARCH_BOARD_FLASH_PART2_SIZE
+	int "Size of user partition 2"
+	default 0
+
+if ARCH_BOARD_FLASH_PART2_SIZE > 0
+
+config ARCH_BOARD_FLASH_PART2_NAME
+	string "Name of user partition 2"
+	default "part2"
+
+config ARCH_BOARD_FLASH_PART2_MNT
+	string "Mount point for user partition 2"
+	default "/mnt/part2"
+
+config ARCH_BOARD_FLASH_PART2_FS
+	string
+	default "rawfs" if ARCH_BOARD_FLASH_PART2_FS_RAWFS
+	default "nxffs" if ARCH_BOARD_FLASH_PART2_FS_NXFFS
+	default "smartfs" if ARCH_BOARD_FLASH_PART2_FS_SMARTFS
+	default "mtdconfig" if ARCH_BOARD_FLASH_PART2_FS_MTDCONFIG
+
+choice
+	prompt "Filesystem of user partition 2"
+	default ARCH_BOARD_FLASH_PART2_FS_RAW
+
+config ARCH_BOARD_FLASH_PART2_FS_RAWFS
+	bool "rawfs"
+
+config ARCH_BOARD_FLASH_PART2_FS_NXFFS
+	select FS_NXFFS
+	bool "nxffs"
+
+config ARCH_BOARD_FLASH_PART2_FS_SMARTFS
+	select FS_SMARTFS
+	select MTD_SMART
+	bool "smartfs"
+
+config ARCH_BOARD_FLASH_PART2_FS_MTDCONFIG
+	select MTD_CONFIG
+	bool "mtdconfig"
+
+endchoice # Filesystem of user partition 2
+
+config ARCH_BOARD_FLASH_PART3_SIZE
+	int "Size of user partition 3"
+	default 0
+
+if ARCH_BOARD_FLASH_PART3_SIZE > 0
+
+config ARCH_BOARD_FLASH_PART3_NAME
+	string "Name of user partition 3"
+	default "part3"
+
+config ARCH_BOARD_FLASH_PART3_MNT
+	string "Mount point for user partition 3"
+	default "/mnt/part3"
+
+config ARCH_BOARD_FLASH_PART3_FS
+	string
+	default "rawfs" if ARCH_BOARD_FLASH_PART3_FS_RAWFS
+	default "nxffs" if ARCH_BOARD_FLASH_PART3_FS_NXFFS
+	default "smartfs" if ARCH_BOARD_FLASH_PART3_FS_SMARTFS
+	default "mtdconfig" if ARCH_BOARD_FLASH_PART3_FS_MTDCONFIG
+
+choice
+	prompt "Filesystem of user partition 3"
+	default ARCH_BOARD_FLASH_PART3_FS_RAW
+
+config ARCH_BOARD_FLASH_PART3_FS_RAWFS
+	bool "rawfs"
+
+config ARCH_BOARD_FLASH_PART3_FS_NXFFS
+	select FS_NXFFS
+	bool "nxffs"
+
+config ARCH_BOARD_FLASH_PART3_FS_SMARTFS
+	select FS_SMARTFS
+	select MTD_SMART
+	bool "smartfs"
+
+config ARCH_BOARD_FLASH_PART3_FS_MTDCONFIG
+	select MTD_CONFIG
+	bool "mtdconfig"
+
+endchoice # Filesystem of user partition 3
+
+config ARCH_BOARD_FLASH_PART4_SIZE
+	int "Size of user partition 4"
+	default 0
+
+if ARCH_BOARD_FLASH_PART4_SIZE > 0
+
+config ARCH_BOARD_FLASH_PART4_NAME
+	string "Name of user partition 4"
+	default "part4"
+
+config ARCH_BOARD_FLASH_PART4_MNT
+	string "Mount point for user partition 4"
+	default "/mnt/part4"
+
+config ARCH_BOARD_FLASH_PART4_FS
+	string
+	default "rawfs" if ARCH_BOARD_FLASH_PART4_FS_RAWFS
+	default "nxffs" if ARCH_BOARD_FLASH_PART4_FS_NXFFS
+	default "smartfs" if ARCH_BOARD_FLASH_PART4_FS_SMARTFS
+	default "mtdconfig" if ARCH_BOARD_FLASH_PART4_FS_MTDCONFIG
+
+choice
+	prompt "Filesystem of user partition 4"
+	default ARCH_BOARD_FLASH_PART4_FS_RAW
+
+config ARCH_BOARD_FLASH_PART4_FS_RAWFS
+	bool "rawfs"
+
+config ARCH_BOARD_FLASH_PART4_FS_NXFFS
+	select FS_NXFFS
+	bool "nxffs"
+
+config ARCH_BOARD_FLASH_PART4_FS_SMARTFS
+	select FS_SMARTFS
+	select MTD_SMART
+	bool "smartfs"
+
+config ARCH_BOARD_FLASH_PART4_FS_MTDCONFIG
+	select MTD_CONFIG
+	bool "mtdconfig"
+
+endchoice # Filesystem of user partition 4
+
+endif # ARCH_BOARD_FLASH_PART2_SIZE > 0
+endif # ARCH_BOARD_FLASH_PART3_SIZE > 0
+endif # ARCH_BOARD_FLASH_PART4_SIZE > 0
+
+endif # ARCH_BOARD_FLASH_MOUNT
+
 endif # ARCH_BOARD_NUCLEO_WL55JC
diff --git a/boards/arm/stm32wl5/nucleo-wl55jc/configs/demo/defconfig b/boards/arm/stm32wl5/nucleo-wl55jc/configs/demo/defconfig
index 49e2feacd3..ba1b1efb25 100644
--- a/boards/arm/stm32wl5/nucleo-wl55jc/configs/demo/defconfig
+++ b/boards/arm/stm32wl5/nucleo-wl55jc/configs/demo/defconfig
@@ -8,6 +8,22 @@
 # CONFIG_STANDARD_SERIAL is not set
 CONFIG_ARCH="arm"
 CONFIG_ARCH_BOARD="nucleo-wl55jc"
+CONFIG_ARCH_BOARD_FLASH_CPU1_PROG_SIZE=116
+CONFIG_ARCH_BOARD_FLASH_MOUNT=y
+CONFIG_ARCH_BOARD_FLASH_PART1_MNT=""
+CONFIG_ARCH_BOARD_FLASH_PART1_NAME="raw"
+CONFIG_ARCH_BOARD_FLASH_PART2_FS_SMARTFS=y
+CONFIG_ARCH_BOARD_FLASH_PART2_MNT="/mnt/smart"
+CONFIG_ARCH_BOARD_FLASH_PART2_NAME="smartie"
+CONFIG_ARCH_BOARD_FLASH_PART2_SIZE=8
+CONFIG_ARCH_BOARD_FLASH_PART3_FS_NXFFS=y
+CONFIG_ARCH_BOARD_FLASH_PART3_MNT="/mnt/nx"
+CONFIG_ARCH_BOARD_FLASH_PART3_NAME="nxf"
+CONFIG_ARCH_BOARD_FLASH_PART3_SIZE=2
+CONFIG_ARCH_BOARD_FLASH_PART4_FS_MTDCONFIG=y
+CONFIG_ARCH_BOARD_FLASH_PART4_MNT=""
+CONFIG_ARCH_BOARD_FLASH_PART4_NAME="config"
+CONFIG_ARCH_BOARD_FLASH_PART4_SIZE=1
 CONFIG_ARCH_BOARD_NUCLEO_WL55JC=y
 CONFIG_ARCH_BOARD_NUCLEO_WL55JC_DEMO_LED_IRQ=y
 CONFIG_ARCH_BUTTONS=y
@@ -24,12 +40,15 @@ CONFIG_INPUT=y
 CONFIG_INPUT_BUTTONS=y
 CONFIG_INPUT_BUTTONS_LOWER=y
 CONFIG_LPUART1_SERIAL_CONSOLE=y
+CONFIG_MTD_CONFIG_NAMED=y
+CONFIG_MTD_SMART_SECTOR_SIZE=2048
 CONFIG_NSH_ARCHINIT=y
 CONFIG_NSH_BUILTIN_APPS=y
 CONFIG_RAM_SIZE=32768
 CONFIG_RAM_START=0x20000000
 CONFIG_RAW_BINARY=y
 CONFIG_STM32WL5_LPUART1=y
+CONFIG_SYSTEM_CFGDATA=y
 CONFIG_SYSTEM_NSH=y
 CONFIG_USERLED=y
 CONFIG_USERLED_LOWER=y
diff --git a/boards/arm/stm32wl5/nucleo-wl55jc/src/Makefile b/boards/arm/stm32wl5/nucleo-wl55jc/src/Makefile
index 9532b20cd4..16a184a937 100644
--- a/boards/arm/stm32wl5/nucleo-wl55jc/src/Makefile
+++ b/boards/arm/stm32wl5/nucleo-wl55jc/src/Makefile
@@ -30,4 +30,8 @@ ifeq ($(CONFIG_ARCH_BUTTONS),y)
 CSRCS += stm32_buttons.c
 endif
 
+ifeq ($(CONFIG_ARCH_BOARD_FLASH_MOUNT),y)
+CSRCS += stm32_flash.c
+endif
+
 include $(TOPDIR)/boards/Board.mk
diff --git a/boards/arm/stm32wl5/nucleo-wl55jc/src/nucleo-wl55jc.h b/boards/arm/stm32wl5/nucleo-wl55jc/src/nucleo-wl55jc.h
index a9585eb37d..e3b7b86338 100644
--- a/boards/arm/stm32wl5/nucleo-wl55jc/src/nucleo-wl55jc.h
+++ b/boards/arm/stm32wl5/nucleo-wl55jc/src/nucleo-wl55jc.h
@@ -74,4 +74,14 @@
 
 void board_leds_initialize(void);
 
+/****************************************************************************
+ * Name: stm32wl5_flash_init
+ *
+ * Description:
+ *   Initialize on-board FLASH partition table
+ *
+ ****************************************************************************/
+
+int stm32wl5_flash_init(void);
+
 #endif /* __BOARDS_ARM_STM32WL5_NUCLEO_WL55JC_SRC_NUCLEO_WL55JC_H */
diff --git a/boards/arm/stm32wl5/nucleo-wl55jc/src/stm32_appinit.c b/boards/arm/stm32wl5/nucleo-wl55jc/src/stm32_appinit.c
index 5da9d754c6..4955cf1381 100644
--- a/boards/arm/stm32wl5/nucleo-wl55jc/src/stm32_appinit.c
+++ b/boards/arm/stm32wl5/nucleo-wl55jc/src/stm32_appinit.c
@@ -116,6 +116,16 @@ int board_app_initialize(uintptr_t arg)
     }
 #endif
 
+#if defined(CONFIG_ARCH_BOARD_ENABLE_FLASH_MOUNT)
+  /* Register partition table for on-board FLASH memory */
+
+  ret = stm32wl5_flash_init();
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: stm32wl5_flash_init() failed: %d\n", ret);
+    }
+#endif
+
   return ret;
 }
 
diff --git a/boards/arm/stm32wl5/nucleo-wl55jc/src/stm32_flash.c b/boards/arm/stm32wl5/nucleo-wl55jc/src/stm32_flash.c
new file mode 100644
index 0000000000..463f84a9e0
--- /dev/null
+++ b/boards/arm/stm32wl5/nucleo-wl55jc/src/stm32_flash.c
@@ -0,0 +1,297 @@
+/****************************************************************************
+ * boards/arm/stm32wl5/nucleo-wl55jc/src/stm32_flash.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 <nuttx/mtd/mtd.h>
+#include <nuttx/mtd/configdata.h>
+#include <nuttx/fs/nxffs.h>
+#include <nuttx/fs/smart.h>
+#include <nuttx/fs/fs.h>
+
+#include <debug.h>
+#include <stdio.h>
+
+#include "nucleo-wl55jc.h"
+#include "hardware/stm32wl5_flash.h"
+
+/****************************************************************************
+ * Pre-Processor Definitions
+ ****************************************************************************/
+
+#if (CONFIG_ARCH_BOARD_FLASH_CPU1_PROG_SIZE + \
+     CONFIG_ARCH_BOARD_FLASH_CPU2_PROG_SIZE + \
+     CONFIG_ARCH_BOARD_FLASH_PART1_SIZE + \
+     CONFIG_ARCH_BOARD_FLASH_PART2_SIZE + \
+     CONFIG_ARCH_BOARD_FLASH_PART3_SIZE + \
+     CONFIG_ARCH_BOARD_FLASH_PART4_SIZE) > 128
+#   error "Sum of all flash pertitions cannot be bigger than 128"
+#endif
+
+#if (CONFIG_ARCH_BOARD_FLASH_CPU1_PROG_SIZE + \
+     CONFIG_ARCH_BOARD_FLASH_CPU2_PROG_SIZE + \
+     CONFIG_ARCH_BOARD_FLASH_PART1_SIZE + \
+     CONFIG_ARCH_BOARD_FLASH_PART2_SIZE + \
+     CONFIG_ARCH_BOARD_FLASH_PART3_SIZE + \
+     CONFIG_ARCH_BOARD_FLASH_PART4_SIZE) < 128
+#   warning "There is unused space on flash"
+#endif
+
+#define FLASH_PAGE_SIZE    STM32WL5_FLASH_PAGESIZE
+
+/****************************************************************************
+ * Private Definitions
+ ****************************************************************************/
+
+struct part_table
+{
+    int         size; /* partition size in pages */
+    const char *name; /* name of the partition */
+    const char *mnt;  /* mount point for the partition */
+    const char *fs;   /* fs type (smart, raw, nxffs) */
+};
+
+/* partition table, first entry *must always* be program flash memory */
+
+static const struct part_table part_table[] =
+{
+  {
+    .size   = CONFIG_ARCH_BOARD_FLASH_CPU1_PROG_SIZE,
+    .name   = "cpu1-progmem",
+    .mnt    = NULL,
+    .fs     = "rawfs"
+  },
+
+#if CONFIG_ARCH_BOARD_FLASH_CPU2_PROG_SIZE > 0
+    .size   = CONFIG_ARCH_BOARD_FLASH_CPU2_PROG_SIZE,
+    .name   = "cpu2-progmem",
+    .mnt    = NULL,
+    .fs     = "rawfs"
+#endif
+
+  {
+    .size   = CONFIG_ARCH_BOARD_FLASH_PART1_SIZE,
+    .name   = CONFIG_ARCH_BOARD_FLASH_PART1_NAME,
+    .mnt    = CONFIG_ARCH_BOARD_FLASH_PART1_MNT,
+    .fs     = CONFIG_ARCH_BOARD_FLASH_PART1_FS
+  },
+
+#if CONFIG_ARCH_BOARD_FLASH_PART2_SIZE > 0
+  {
+    .size   = CONFIG_ARCH_BOARD_FLASH_PART2_SIZE,
+    .name   = CONFIG_ARCH_BOARD_FLASH_PART2_NAME,
+    .mnt    = CONFIG_ARCH_BOARD_FLASH_PART2_MNT,
+    .fs     = CONFIG_ARCH_BOARD_FLASH_PART2_FS
+  },
+#endif /* CONFIG_ARCH_BOARD_FLASH_PART2_SIZE */
+
+#if CONFIG_ARCH_BOARD_FLASH_PART3_SIZE > 0
+  {
+    .size   = CONFIG_ARCH_BOARD_FLASH_PART3_SIZE,
+    .name   = CONFIG_ARCH_BOARD_FLASH_PART3_NAME,
+    .mnt    = CONFIG_ARCH_BOARD_FLASH_PART3_MNT,
+    .fs     = CONFIG_ARCH_BOARD_FLASH_PART3_FS
+  },
+#endif /* CONFIG_ARCH_BOARD_FLASH_PART3_SIZE */
+
+#if CONFIG_ARCH_BOARD_FLASH_PART4_SIZE > 0
+  {
+    .size   = CONFIG_ARCH_BOARD_FLASH_PART4_SIZE,
+    .name   = CONFIG_ARCH_BOARD_FLASH_PART4_NAME,
+    .mnt    = CONFIG_ARCH_BOARD_FLASH_PART4_MNT,
+    .fs     = CONFIG_ARCH_BOARD_FLASH_PART4_FS
+  },
+#endif /* CONFIG_ARCH_BOARD_FLASH_PART4_SIZE */
+};
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int stm32wl5_flash_init(void)
+{
+  FAR struct mtd_dev_s *mtd;
+  FAR struct mtd_dev_s *mtd_part;
+  int offset;
+  int mtdconfig_minor;
+  int mtdblk_minor;
+  int smart_minor;
+  int nxf_minor;
+  int ret;
+  int i;
+
+  /* create an instance of the stm32 flash program memory device driver */
+
+  if ((mtd = progmem_initialize()) == NULL)
+    {
+      ferr("ERROR: progmem_initialize failed %d\n", errno);
+      return -1;
+    }
+
+  /* create partitions, this does not actually write anything
+   * to flash memory, we only create partition table in ram
+   */
+
+  mtdconfig_minor = 0;
+  mtdblk_minor = 0;
+  smart_minor = 0;
+  nxf_minor = 0;
+  offset = 0;
+
+  for (i = 0; i != sizeof(part_table) / sizeof(struct part_table); i++)
+    {
+      int         size;
+      const char *name;
+      const char *mnt;
+      const char *fs;
+
+      size = part_table[i].size;
+      name = part_table[i].name;
+      mnt  = part_table[i].mnt;
+      fs   = part_table[i].fs;
+
+      finfo("[%s] creating partition, size: %d, fs: %s, offset: %d\n",
+            name, size, fs, offset);
+
+      /* create mtd parition */
+
+      mtd_part = mtd_partition(mtd, offset, size);
+
+      /* calculate offset for next partition */
+
+      offset += size;
+
+      if (mtd_part == NULL)
+        {
+          ferr("[%s]ERROR: mtd_partition() failed %d\n", name, errno);
+          continue;
+        }
+
+      if (mtd_setpartitionname(mtd_part, name))
+        {
+          ferr("[%s]ERROR: mtd_setpartitionname() failed %d\n", name, errno);
+          continue;
+        }
+
+      /* initialize filesystems */
+
+      if (strcmp(fs, "rawfs") == 0)
+        {
+          /* for raw fs just create mtdblock using ftl */
+
+          if ((ret = ftl_initialize(mtdblk_minor, mtd_part)))
+            {
+              ferr("[%s]ERROR: ftl_initialize failed %d\n", name, ret);
+              continue;
+            }
+
+          mtdblk_minor++;
+        }
+
+#if defined(CONFIG_FS_NXFFS)
+      else if (strcmp(fs, "nxffs") == 0)
+        {
+          if (nxf_minor)
+            {
+              ferr("[%s]ERROR: only 1 nxffs is allowed, ignoring\n", name);
+              continue;
+            }
+
+          /* attach mtd to nxffs */
+
+          if ((ret = nxffs_initialize(mtd_part)))
+            {
+              ferr("[%s]ERROR: nxffs_initialize failed %d\n", name, ret);
+              continue;
+            }
+
+          /* mount nxffs */
+
+          if ((ret = nx_mount(NULL, mnt, "nxffs", 0, NULL)))
+            {
+              ferr("[%s]ERROR: nx_mount failed: %d", name, ret);
+              continue;
+            }
+
+          nxf_minor++;
+        }
+#endif
+
+#if defined(CONFIG_FS_SMARTFS)
+      else if (strcmp(fs, "smartfs") == 0)
+        {
+          /* attach mtd to smartfs */
+
+          char src[32];
+          snprintf(src, sizeof(src), "/dev/smart%d", smart_minor);
+
+          if ((ret = smart_initialize(smart_minor, mtd_part, NULL)))
+            {
+              ferr("[%s]ERROR: smart_initialize() failed %d\n", name, ret);
+              continue;
+            }
+
+          /* mount smartfs */
+
+          if ((ret = nx_mount(src, mnt, "smartfs", 0, NULL)))
+            {
+              ferr("[%s]ERROR: nx_mount failed: %d\n", name, ret);
+              if (ret == ENODEV)
+                {
+                  syslog(LOG_INFO, "[%s] mtd, smartfs seems unformated. "
+                         "Did you run 'mksmartfs %s'?\n", name, src);
+                }
+
+              continue;
+            }
+
+          smart_minor++;
+        }
+#endif
+
+#if defined(CONFIG_MTD_CONFIG)
+      else if (strcmp(fs, "mtdconfig") == 0)
+        {
+          if (mtdconfig_minor)
+            {
+              ferr("[%s]ERROR: only 1 mtdconfig is allowed, ignoring\n",
+                   name);
+              continue;
+            }
+
+          /* attach mtd to mtdconfig driver */
+
+          if (mtdconfig_register(mtd_part) != 0)
+            {
+              ferr("[%s]ERROR: mtdconfig_register() failed %d\n",
+                   name, errno);
+              continue;
+            }
+
+          mtdconfig_minor++;
+        }
+#endif
+    }
+
+  return 0;
+}