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/09/09 11:28:03 UTC

[incubator-nuttx] branch master updated (2892f18f15 -> c754df6411)

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

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


    from 2892f18f15 Fix some register's values, enable TWAI extended registers and add a missing prototype. Also, replaced critical_sections with spinlocks.
     new 25c2f3e042 driver: move find_mtddriver() to fs.h and add close_mtddriver.c
     new c754df6411 drivers/mtd: add rpmsg mtd support

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 boards/sim/sim/sim/configs/rpproxy/defconfig       |   6 +
 boards/sim/sim/sim/configs/rpserver/defconfig      |   6 +
 boards/sim/sim/sim/src/sim_bringup.c               |  31 +-
 drivers/drivers_initialize.c                       |   5 +
 drivers/mtd/Kconfig                                |  16 +-
 drivers/mtd/Make.defs                              |   8 +
 drivers/{misc/rpmsgdev.c => mtd/rpmsgmtd.c}        | 773 ++++++++++++---------
 drivers/{misc/rpmsgdev.h => mtd/rpmsgmtd.h}        |  74 +-
 .../rpmsgdev_server.c => mtd/rpmsgmtd_server.c}    | 292 +++++---
 fs/driver/Make.defs                                |   2 +-
 fs/driver/driver.h                                 |  22 -
 .../fs_closemtddriver.c}                           |  47 +-
 fs/driver/fs_findmtddriver.c                       |   1 -
 include/nuttx/fs/fs.h                              |  38 +
 include/nuttx/mtd/mtd.h                            |  43 ++
 15 files changed, 800 insertions(+), 564 deletions(-)
 copy drivers/{misc/rpmsgdev.c => mtd/rpmsgmtd.c} (51%)
 copy drivers/{misc/rpmsgdev.h => mtd/rpmsgmtd.h} (61%)
 copy drivers/{misc/rpmsgdev_server.c => mtd/rpmsgmtd_server.c} (55%)
 copy fs/{inode/fs_inodegetpath.c => driver/fs_closemtddriver.c} (75%)


[incubator-nuttx] 01/02: driver: move find_mtddriver() to fs.h and add close_mtddriver.c

Posted by xi...@apache.org.
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 25c2f3e042b9e07d604ad0d883380db7a289efa9
Author: wangbowen6 <wa...@xiaomi.com>
AuthorDate: Mon Sep 5 09:49:57 2022 +0800

    driver: move find_mtddriver() to fs.h and add close_mtddriver.c
    
    Rpmsg mtd need a way to find the mtd device according to the
    mtd device path.
    
    Signed-off-by: wangbowen6 <wa...@xiaomi.com>
---
 fs/driver/Make.defs                                |  2 +-
 fs/driver/driver.h                                 | 22 -------
 .../{fs_findmtddriver.c => fs_closemtddriver.c}    | 72 ++++------------------
 fs/driver/fs_findmtddriver.c                       |  1 -
 include/nuttx/fs/fs.h                              | 38 ++++++++++++
 5 files changed, 51 insertions(+), 84 deletions(-)

diff --git a/fs/driver/Make.defs b/fs/driver/Make.defs
index e34f437781..330f559b10 100644
--- a/fs/driver/Make.defs
+++ b/fs/driver/Make.defs
@@ -25,7 +25,7 @@ CSRCS += fs_registerdriver.c fs_unregisterdriver.c
 ifneq ($(CONFIG_DISABLE_MOUNTPOINT),y)
 CSRCS += fs_registerblockdriver.c fs_unregisterblockdriver.c
 CSRCS += fs_findblockdriver.c fs_openblockdriver.c fs_closeblockdriver.c
-CSRCS += fs_blockpartition.c fs_findmtddriver.c
+CSRCS += fs_blockpartition.c fs_findmtddriver.c fs_closemtddriver.c
 
 ifeq ($(CONFIG_MTD),y)
 CSRCS += fs_registermtddriver.c fs_unregistermtddriver.c
diff --git a/fs/driver/driver.h b/fs/driver/driver.h
index a0bfa4cde2..b8d9959821 100644
--- a/fs/driver/driver.h
+++ b/fs/driver/driver.h
@@ -124,28 +124,6 @@ int mtd_proxy(FAR const char *mtddev, int mountflags,
               FAR struct inode **ppinode);
 #endif
 
-/****************************************************************************
- * Name: find_mtddriver
- *
- * Description:
- *   Return the inode of the named MTD driver specified by 'pathname'
- *
- * Input Parameters:
- *   pathname   - the full path to the named MTD driver to be located
- *   ppinode    - address of the location to return the inode reference
- *
- * Returned Value:
- *   Returns zero on success or a negated errno on failure:
- *
- *   ENOENT  - No MTD driver of this name is registered
- *   ENOTBLK - The inode associated with the pathname is not an MTD driver
- *
- ****************************************************************************/
-
-#ifndef CONFIG_DISABLE_MOUNTPOINT
-int find_mtddriver(FAR const char *pathname, FAR struct inode **ppinode);
-#endif
-
 #undef EXTERN
 #if defined(__cplusplus)
 }
diff --git a/fs/driver/fs_findmtddriver.c b/fs/driver/fs_closemtddriver.c
similarity index 53%
copy from fs/driver/fs_findmtddriver.c
copy to fs/driver/fs_closemtddriver.c
index 7dc4a83fef..3d9d6922a7 100644
--- a/fs/driver/fs_findmtddriver.c
+++ b/fs/driver/fs_closemtddriver.c
@@ -1,5 +1,5 @@
 /****************************************************************************
- * fs/driver/fs_findmtddriver.c
+ * fs/driver/fs_closemtddriver.c
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -24,96 +24,48 @@
 
 #include <nuttx/config.h>
 
-#include <sys/types.h>
-#include <stdbool.h>
-#include <assert.h>
 #include <errno.h>
-#include <debug.h>
-
 #include <nuttx/fs/fs.h>
 
 #include "inode/inode.h"
-#include "driver/driver.h"
-
-#ifdef CONFIG_MTD
 
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
 
 /****************************************************************************
- * Name: find_mtddriver
+ * Name: close_mtddriver
  *
  * Description:
- *   Return the inode of the named MTD driver specified by 'pathname'
+ *   Release the inode got by function find_mtddriver()
  *
  * Input Parameters:
- *   pathname   - the full path to the named MTD driver to be located
- *   ppinode    - address of the location to return the inode reference
+ *   pinode    - pointer to the inode
  *
  * Returned Value:
  *   Returns zero on success or a negated errno on failure:
  *
- *   ENOENT  - No MTD driver of this name is registered
- *   ENOTBLK - The inode associated with the pathname is not an MTD driver
+ *   EINVAL  - inode is NULL
  *
  ****************************************************************************/
 
-int find_mtddriver(FAR const char *pathname, FAR struct inode **ppinode)
+#ifdef CONFIG_MTD
+int close_mtddriver(FAR struct inode *pinode)
 {
-  struct inode_search_s desc;
-  FAR struct inode *inode;
-  int ret = 0; /* Assume success */
-
-  DEBUGASSERT(pathname != NULL || ppinode != NULL);
+  /* Sanity checks */
 
-  /* Find the inode registered with this pathname */
-
-  SETUP_SEARCH(&desc, pathname, false);
-
-  ret = inode_find(&desc);
-  if (ret < 0)
+  if (pinode == NULL)
     {
-      ferr("ERROR: Failed to find %s\n", pathname);
-      ret = -ENOENT;
-      goto errout_with_search;
+      return -EINVAL;
     }
 
-  /* Get the search results */
-
-  inode = desc.node;
-  DEBUGASSERT(inode != NULL);
+  inode_release(pinode);
 
-  /* Verify that the inode is a block driver. */
-
-  if (!INODE_IS_MTD(inode))
-    {
-      ferr("ERROR: %s is not a named MTD driver\n", pathname);
-      ret = -ENOTBLK;
-      goto errout_with_inode;
-    }
-
-  /* Return the MTD inode reference */
-
-  DEBUGASSERT(inode->u.i_mtd != NULL);
-
-  *ppinode = inode;
-  RELEASE_SEARCH(&desc);
   return OK;
-
-errout_with_inode:
-  inode_release(inode);
-
-errout_with_search:
-  RELEASE_SEARCH(&desc);
-  return ret;
 }
-
 #else
-
-int find_mtddriver(FAR const char *pathname, FAR struct inode **ppinode)
+int close_mtddriver(FAR struct inode *pinode)
 {
   return -ENODEV;
 }
-
 #endif /* CONFIG_MTD */
diff --git a/fs/driver/fs_findmtddriver.c b/fs/driver/fs_findmtddriver.c
index 7dc4a83fef..fad08f0900 100644
--- a/fs/driver/fs_findmtddriver.c
+++ b/fs/driver/fs_findmtddriver.c
@@ -33,7 +33,6 @@
 #include <nuttx/fs/fs.h>
 
 #include "inode/inode.h"
-#include "driver/driver.h"
 
 #ifdef CONFIG_MTD
 
diff --git a/include/nuttx/fs/fs.h b/include/nuttx/fs/fs.h
index 0e631ea05c..92ffdc432e 100644
--- a/include/nuttx/fs/fs.h
+++ b/include/nuttx/fs/fs.h
@@ -986,6 +986,44 @@ int open_blockdriver(FAR const char *pathname, int mountflags,
 
 int close_blockdriver(FAR struct inode *inode);
 
+/****************************************************************************
+ * Name: find_mtddriver
+ *
+ * Description:
+ *   Return the inode of the named MTD driver specified by 'pathname'
+ *
+ * Input Parameters:
+ *   pathname   - the full path to the named MTD driver to be located
+ *   ppinode    - address of the location to return the inode reference
+ *
+ * Returned Value:
+ *   Returns zero on success or a negated errno on failure:
+ *
+ *   ENOENT  - No MTD driver of this name is registered
+ *   ENOTBLK - The inode associated with the pathname is not an MTD driver
+ *
+ ****************************************************************************/
+
+int find_mtddriver(FAR const char *pathname, FAR struct inode **ppinode);
+
+/****************************************************************************
+ * Name: close_mtddriver
+ *
+ * Description:
+ *   Release the inode got by function find_mtddriver()
+ *
+ * Input Parameters:
+ *   pinode    - pointer to the inode
+ *
+ * Returned Value:
+ *   Returns zero on success or a negated errno on failure:
+ *
+ *   EINVAL  - inode is NULL
+ *
+ ****************************************************************************/
+
+int close_mtddriver(FAR struct inode *pinode);
+
 /****************************************************************************
  * Name: fs_fdopen
  *


[incubator-nuttx] 02/02: drivers/mtd: add rpmsg mtd support

Posted by xi...@apache.org.
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 c754df6411323c0758807191b1c76df8cd5fcc5f
Author: wangbowen6 <wa...@xiaomi.com>
AuthorDate: Mon Sep 5 09:46:44 2022 +0800

    drivers/mtd: add rpmsg mtd support
    
    Signed-off-by: wangbowen6 <wa...@xiaomi.com>
---
 boards/sim/sim/sim/configs/rpproxy/defconfig  |    6 +
 boards/sim/sim/sim/configs/rpserver/defconfig |    6 +
 boards/sim/sim/sim/src/sim_bringup.c          |   31 +-
 drivers/drivers_initialize.c                  |    5 +
 drivers/mtd/Kconfig                           |   16 +-
 drivers/mtd/Make.defs                         |    8 +
 drivers/mtd/rpmsgmtd.c                        | 1118 +++++++++++++++++++++++++
 drivers/mtd/rpmsgmtd.h                        |  105 +++
 drivers/mtd/rpmsgmtd_server.c                 |  420 ++++++++++
 include/nuttx/mtd/mtd.h                       |   43 +
 10 files changed, 1736 insertions(+), 22 deletions(-)

diff --git a/boards/sim/sim/sim/configs/rpproxy/defconfig b/boards/sim/sim/sim/configs/rpproxy/defconfig
index 5841640176..7554654060 100644
--- a/boards/sim/sim/sim/configs/rpproxy/defconfig
+++ b/boards/sim/sim/sim/configs/rpproxy/defconfig
@@ -16,9 +16,12 @@ CONFIG_BUILTIN=y
 CONFIG_DEBUG_ASSERTIONS=y
 CONFIG_DEBUG_ERROR=y
 CONFIG_DEBUG_FEATURES=y
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_FS_ERROR=y
 CONFIG_DEBUG_SYMBOLS=y
 CONFIG_DEV_RPMSG=y
 CONFIG_DEV_SIMPLE_ADDRENV=y
+CONFIG_EXAMPLES_HELLO=y
 CONFIG_EXAMPLES_RPMSGSOCKET=y
 CONFIG_FS_PROCFS=y
 CONFIG_FS_RPMSGFS=y
@@ -26,6 +29,8 @@ CONFIG_IDLETHREAD_STACKSIZE=4096
 CONFIG_INIT_ENTRYPOINT="nsh_main"
 CONFIG_INPUT=y
 CONFIG_LIBC_HOSTNAME="proxy"
+CONFIG_MTD=y
+CONFIG_MTD_BYTE_WRITE=y
 CONFIG_NDEBUG=y
 CONFIG_NET=y
 CONFIG_NETDB_DNSCLIENT=y
@@ -48,6 +53,7 @@ CONFIG_NSH_READLINE=y
 CONFIG_OPENAMP=y
 CONFIG_READLINE_CMD_HISTORY=y
 CONFIG_READLINE_TABCOMPLETION=y
+CONFIG_RPMSGMTD=y
 CONFIG_RPMSG_UART=y
 CONFIG_RPTUN=y
 CONFIG_RTC=y
diff --git a/boards/sim/sim/sim/configs/rpserver/defconfig b/boards/sim/sim/sim/configs/rpserver/defconfig
index e46e2f517e..966f059c46 100644
--- a/boards/sim/sim/sim/configs/rpserver/defconfig
+++ b/boards/sim/sim/sim/configs/rpserver/defconfig
@@ -17,6 +17,8 @@ CONFIG_CLK_RPMSG=y
 CONFIG_DEBUG_ASSERTIONS=y
 CONFIG_DEBUG_ERROR=y
 CONFIG_DEBUG_FEATURES=y
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_FS_ERROR=y
 CONFIG_DEBUG_SYMBOLS=y
 CONFIG_DEV_RPMSG_SERVER=y
 CONFIG_DEV_SIMPLE_ADDRENV=y
@@ -30,6 +32,8 @@ CONFIG_INPUT=y
 CONFIG_IOEXPANDER=y
 CONFIG_IOEXPANDER_RPMSG=y
 CONFIG_LIBC_HOSTNAME="server"
+CONFIG_MTD=y
+CONFIG_MTD_BYTE_WRITE=y
 CONFIG_NDEBUG=y
 CONFIG_NET=y
 CONFIG_NETDB_DNSCLIENT=y
@@ -60,10 +64,12 @@ CONFIG_NSH_BUILTIN_APPS=y
 CONFIG_NSH_PROMPT_STRING="server> "
 CONFIG_NSH_READLINE=y
 CONFIG_OPENAMP=y
+CONFIG_RAMMTD=y
 CONFIG_READLINE_CMD_HISTORY=y
 CONFIG_READLINE_TABCOMPLETION=y
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_RPMSG=y
+CONFIG_RPMSGMTD_SERVER=y
 CONFIG_RPMSG_UART=y
 CONFIG_RPTUN=y
 CONFIG_RTC=y
diff --git a/boards/sim/sim/sim/src/sim_bringup.c b/boards/sim/sim/sim/src/sim_bringup.c
index 11f8eba4ef..bc37dc57cd 100644
--- a/boards/sim/sim/sim/src/sim_bringup.c
+++ b/boards/sim/sim/sim/src/sim_bringup.c
@@ -176,14 +176,6 @@ int sim_bringup(void)
               syslog(LOG_ERR, "ERROR: IOCTL MTDIOC_BULKERASE failed\n");
             }
 
-#if defined(CONFIG_MTD_SMART) && defined(CONFIG_FS_SMARTFS)
-          /* Initialize a SMART Flash block device and bind it to the MTD
-           * device.
-           */
-
-          smart_initialize(0, mtd, NULL);
-
-#elif defined(CONFIG_FS_SPIFFS)
           /* Register the MTD driver so that it can be accessed from the
            * VFS.
            */
@@ -195,6 +187,14 @@ int sim_bringup(void)
                      ret);
             }
 
+#if defined(CONFIG_MTD_SMART) && defined(CONFIG_FS_SMARTFS)
+          /* Initialize a SMART Flash block device and bind it to the MTD
+           * device.
+           */
+
+          smart_initialize(0, mtd, NULL);
+
+#elif defined(CONFIG_FS_SPIFFS)
           /* Mount the SPIFFS file system */
 
           ret = nx_mount("/dev/rammtd", "/mnt/spiffs", "spiffs", 0, NULL);
@@ -206,17 +206,6 @@ int sim_bringup(void)
             }
 
 #elif defined(CONFIG_FS_LITTLEFS)
-          /* Register the MTD driver so that it can be accessed from the
-           * VFS.
-           */
-
-          ret = register_mtddriver("/dev/rammtd", mtd, 0755, NULL);
-          if (ret < 0)
-            {
-              syslog(LOG_ERR, "ERROR: Failed to register MTD driver: %d\n",
-                     ret);
-            }
-
           /* Mount the LittleFS file system */
 
           ret = nx_mount("/dev/rammtd", "/mnt/lfs", "littlefs", 0,
@@ -452,6 +441,10 @@ int sim_bringup(void)
   rpmsgdev_register("server", "/dev/console", "/dev/server-console");
   rpmsgdev_register("server", "/dev/null", "/dev/server-null");
 #endif
+
+#ifdef CONFIG_RPMSGMTD
+  rpmsgmtd_register("server", "/dev/rammtd", NULL);
+#endif
 #endif
 
 #ifdef CONFIG_SIM_WTGAHRS2_UARTN
diff --git a/drivers/drivers_initialize.c b/drivers/drivers_initialize.c
index 605f35a1a4..085c50a435 100644
--- a/drivers/drivers_initialize.c
+++ b/drivers/drivers_initialize.c
@@ -28,6 +28,7 @@
 #include <nuttx/drivers/rpmsgdev.h>
 #include <nuttx/fs/loop.h>
 #include <nuttx/input/uinput.h>
+#include <nuttx/mtd/mtd.h>
 #include <nuttx/net/loopback.h>
 #include <nuttx/net/tun.h>
 #include <nuttx/net/telnet.h>
@@ -167,4 +168,8 @@ void drivers_initialize(void)
 #ifdef CONFIG_DEV_RPMSG_SERVER
   rpmsgdev_server_init();
 #endif
+
+#ifdef CONFIG_RPMSGMTD_SERVER
+  rpmsgmtd_server_init();
+#endif
 }
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index 08486d9446..3b2ddb4016 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -137,7 +137,7 @@ config MTD_PROGMEM
 		interfaces must be exported by chip-specific logic.
 
 if MTD_PROGMEM
-		
+
 endif #MTD_PROGMEM
 
 config MTD_CONFIG
@@ -271,6 +271,16 @@ config MTD_NAND_EMBEDDEDECC
 
 endif # MTD_NAND
 
+config RPMSGMTD
+	bool "MTD RPMSG Client Enable"
+	default n
+	depends on RPTUN
+
+config RPMSGMTD_SERVER
+	bool "MTD RPMSG Server Enable"
+	default n
+	depends on RPTUN
+
 config RAMMTD
 	bool "RAM-based MTD driver"
 	default n
@@ -719,11 +729,11 @@ config MX25RXX_SECTOR512
 config MX25RXX_PAGE128
 	bool "128 byte size pages"
 	default n
-	
+
 config MX25RXX_LXX
 	bool "Run MX25RXX driver in MX25LXX mode"
 	default n
-	
+
 endif # MTD_MX25RXX
 
 config MTD_SMART
diff --git a/drivers/mtd/Make.defs b/drivers/mtd/Make.defs
index 893d8d5035..461c0c6a80 100644
--- a/drivers/mtd/Make.defs
+++ b/drivers/mtd/Make.defs
@@ -68,6 +68,14 @@ ifeq ($(CONFIG_NULLMTD),y)
 CSRCS += nullmtd.c
 endif
 
+ifeq ($(CONFIG_RPMSGMTD),y)
+CSRCS += rpmsgmtd.c
+endif
+
+ifeq ($(CONFIG_RPMSGMTD_SERVER),y)
+CSRCS += rpmsgmtd_server.c
+endif
+
 ifeq ($(CONFIG_MTD_AT24XX),y)
 CSRCS += at24xx.c
 endif
diff --git a/drivers/mtd/rpmsgmtd.c b/drivers/mtd/rpmsgmtd.c
new file mode 100644
index 0000000000..6873ece02b
--- /dev/null
+++ b/drivers/mtd/rpmsgmtd.c
@@ -0,0 +1,1118 @@
+/****************************************************************************
+ * drivers/mtd/rpmsgmtd.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 <sys/types.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <debug.h>
+
+#include <nuttx/kmalloc.h>
+#include <nuttx/mtd/mtd.h>
+#include <nuttx/mutex.h>
+#include <nuttx/rptun/openamp.h>
+
+#include "rpmsgmtd.h"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct rpmsgmtd_s
+{
+  struct mtd_dev_s      mtd;         /* MTD device */
+  struct rpmsg_endpoint ept;         /* Rpmsg endpoint */
+  FAR const char       *remotecpu;   /* The server cpu name */
+  FAR const char       *remotepath;  /* The device path in the server cpu */
+  sem_t                 wait;        /* Wait sem, used for preventing any
+                                      * opreation until the connection
+                                      * between two cpu established.
+                                      */
+  mutex_t               geoexcl;     /* Get mtd geometry operation mutex */
+  struct mtd_geometry_s geo;         /* MTD geomerty */
+};
+
+/* Rpmsg device cookie used to handle the response from the remote cpu */
+
+struct rpmsgmtd_cookie_s
+{
+  sem_t     sem;     /* Semaphore used fo rpmsg */
+  int       result;  /* The return value of the remote call */
+  FAR void *data;    /* The return data buffer of the remote call */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* The mtd operation functions */
+
+static int     rpmsgmtd_erase(FAR struct mtd_dev_s *dev, off_t startblock,
+                              size_t nblocks);
+static int     rpmsgmtd_get_geometry(FAR struct rpmsgmtd_s *dev);
+static ssize_t rpmsgmtd_bread(FAR struct mtd_dev_s *dev, off_t startblock,
+                              size_t nblocks, FAR uint8_t *buffer);
+static ssize_t rpmsgmtd_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
+                               size_t nblocks, FAR const uint8_t *buffer);
+static ssize_t rpmsgmtd_read(FAR struct mtd_dev_s *dev, off_t offset,
+                             size_t nbytes, FAR uint8_t *buffer);
+#ifdef CONFIG_MTD_BYTE_WRITE
+static ssize_t rpmsgmtd_write(FAR struct mtd_dev_s *dev, off_t offset,
+                              size_t nbytes, FAR const uint8_t *buffer);
+#endif
+static size_t  rpmsgmtd_ioctl_arglen(int cmd);
+static int     rpmsgmtd_ioctl(FAR struct mtd_dev_s *dev, int cmd,
+                              unsigned long arg);
+
+/* Functions for sending data to the remote cpu */
+
+static int     rpmsgmtd_send_recv(FAR struct rpmsgmtd_s *priv,
+                                  uint32_t command, bool copy,
+                                  FAR struct rpmsgmtd_header_s *msg,
+                                  int len, FAR void *data);
+static FAR void *rpmsgmtd_get_tx_payload_buffer(FAR struct rpmsgmtd_s *priv,
+                                                FAR uint32_t *len);
+
+/* Functions handle the responses from the remote cpu */
+
+static int     rpmsgmtd_default_handler(FAR struct rpmsg_endpoint *ept,
+                                        FAR void *data, size_t len,
+                                        uint32_t src, FAR void *priv);
+static int     rpmsgmtd_bread_handler(FAR struct rpmsg_endpoint *ept,
+                                      FAR void *data, size_t len,
+                                      uint32_t src, FAR void *priv);
+static int     rpmsgmtd_read_handler(FAR struct rpmsg_endpoint *ept,
+                                     FAR void *data, size_t len,
+                                     uint32_t src, FAR void *priv);
+static int     rpmsgmtd_ioctl_handler(FAR struct rpmsg_endpoint *ept,
+                                      FAR void *data, size_t len,
+                                      uint32_t src, FAR void *priv);
+
+/* Functions for creating communication with remote cpu */
+
+static void    rpmsgmtd_device_created(struct rpmsg_device *rdev,
+                                       FAR void *priv_);
+static void    rpmsgmtd_device_destroy(struct rpmsg_device *rdev,
+                                       FAR void *priv_);
+static int     rpmsgmtd_ept_cb(FAR struct rpmsg_endpoint *ept,
+                               FAR void *data, size_t len, uint32_t src,
+                               FAR void *priv);
+static void    rpmsgmtd_ns_bound(struct rpmsg_endpoint *ept);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* Rpmsg device response handler table */
+
+static const rpmsg_ept_cb g_rpmsgmtd_handler[] =
+{
+  [RPMSGMTD_ERASE]  = rpmsgmtd_default_handler,
+  [RPMSGMTD_BREAD]  = rpmsgmtd_bread_handler,
+  [RPMSGMTD_BWRITE] = rpmsgmtd_default_handler,
+  [RPMSGMTD_READ]   = rpmsgmtd_read_handler,
+  [RPMSGMTD_WRITE]  = rpmsgmtd_default_handler,
+  [RPMSGMTD_IOCTL]  = rpmsgmtd_ioctl_handler,
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: rpmsgmtd_erase
+ *
+ * Description:
+ *   Rpmsg-mtd erase operation
+ *
+ * Parameters:
+ *   dev        - the mtd device
+ *   startblock - erase start block
+ *   nblocks    - erase block number
+ *
+ * Returned Values:
+ *   OK on success; A negated errno value is returned on any failure.
+ *
+ ****************************************************************************/
+
+static int rpmsgmtd_erase(FAR struct mtd_dev_s *dev, off_t startblock,
+                          size_t nblocks)
+{
+  FAR struct rpmsgmtd_s *priv = (FAR struct rpmsgmtd_s *)dev;
+  struct rpmsgmtd_erase_s msg;
+
+  /* Sanity checks */
+
+  DEBUGASSERT(priv != NULL);
+
+  msg.startblock = startblock;
+  msg.nblocks    = nblocks;
+
+  return rpmsgmtd_send_recv(priv, RPMSGMTD_ERASE, true, &msg.header,
+                            sizeof(msg), NULL);
+}
+
+/****************************************************************************
+ * Name: rpmsgmtd_get_geometry
+ *
+ * Description:
+ *   Rpmsg-mtd get the server mtd device geometry
+ *
+ * Parameters:
+ *   dev - the mtd device
+ *
+ * Returned Values:
+ *   OK on success; A negated errno value is returned on any failure.
+ *
+ ****************************************************************************/
+
+static int rpmsgmtd_get_geometry(FAR struct rpmsgmtd_s *dev)
+{
+  int ret;
+
+  ret = nxmutex_lock(&dev->geoexcl);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  if (dev->geo.blocksize == 0)
+    {
+      /* Get the server mtd device geometry */
+
+      ret = rpmsgmtd_ioctl(&dev->mtd, MTDIOC_GEOMETRY,
+                           (unsigned long)&dev->geo);
+    }
+
+  nxmutex_unlock(&dev->geoexcl);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: rpmsgmtd_bread
+ *
+ * Description:
+ *   Rpmsg-mtd block read operation
+ *
+ * Parameters:
+ *   dev        - the mtd device
+ *   startblock - read start block
+ *   nblocks    - read block number
+ *   buffer     - read buffer
+ *
+ * Returned Values:
+ *   The positive non-zero number of blocks read on success, 0 on if an
+ *   end-of-file condition, or a negated errno value on any failure.
+ *
+ ****************************************************************************/
+
+static ssize_t rpmsgmtd_bread(FAR struct mtd_dev_s *dev, off_t startblock,
+                              size_t nblocks, FAR uint8_t *buffer)
+{
+  FAR struct rpmsgmtd_s *priv = (FAR struct rpmsgmtd_s *)dev;
+  struct rpmsgmtd_bread_s msg;
+  struct iovec iov;
+  int ret;
+
+  if (buffer == NULL)
+    {
+      return -EINVAL;
+    }
+
+  /* Sanity checks */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Get the server mtd geometry */
+
+  ret = rpmsgmtd_get_geometry(priv);
+  if (ret < 0)
+    {
+      ferr("Get geometry failed, ret=%d\n", ret);
+      return ret;
+    }
+
+  /* In block read, iov_len represent the received block number */
+
+  iov.iov_base = buffer;
+  iov.iov_len  = 0;
+
+  msg.startblock = startblock;
+  msg.nblocks    = nblocks;
+  msg.blocksize  = priv->geo.blocksize;
+
+  ret = rpmsgmtd_send_recv(priv, RPMSGMTD_BREAD, true, &msg.header,
+                           sizeof(msg) - 1, &iov);
+
+  return ret < 0 ? ret : iov.iov_len;
+}
+
+/****************************************************************************
+ * Name: rpmsgmtd_bwrite
+ *
+ * Description:
+ *   Rpmsg-mtd block write operation
+ *
+ * Parameters:
+ *   dev        - the mtd device
+ *   startblock - write start block
+ *   nblocks    - write block number
+ *   buffer     - write buffer
+ *
+ * Returned Values:
+ *   On success, the number of blocks written are returned (zero indicates
+ *   nothing was written).  On any failure, a negated errno value is returned
+ *   (see comments withwrite() for a description of the appropriate errno
+ *   values).
+ *
+ ****************************************************************************/
+
+static ssize_t rpmsgmtd_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
+                               size_t nblocks, FAR const uint8_t *buffer)
+{
+  FAR struct rpmsgmtd_s *priv = (FAR struct rpmsgmtd_s *)dev;
+  FAR struct rpmsgmtd_bwrite_s *msg;
+  struct rpmsgmtd_cookie_s cookie;
+  uint32_t blocksize;
+  uint32_t space;
+  size_t written = 0;
+  int ret;
+
+  if (buffer == NULL)
+    {
+      return -EINVAL;
+    }
+
+  /* Sanity checks */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Get the server mtd geometry */
+
+  ret = rpmsgmtd_get_geometry(priv);
+  if (ret < 0)
+    {
+      ferr("Get geometry failed, ret=%d\n", ret);
+      return ret;
+    }
+
+  /* Perform the rpmsg write */
+
+  memset(&cookie, 0, sizeof(cookie));
+  nxsem_init(&cookie.sem, 0, 0);
+  nxsem_set_protocol(&cookie.sem, SEM_PRIO_NONE);
+
+  blocksize = priv->geo.blocksize;
+  while (written < nblocks)
+    {
+      msg = rpmsgmtd_get_tx_payload_buffer(priv, &space);
+      if (msg == NULL)
+        {
+          ret = -ENOMEM;
+          goto out;
+        }
+
+      DEBUGASSERT(sizeof(*msg) - 1 + blocksize <= space);
+
+      msg->nblocks = (space - sizeof(*msg) + 1) / blocksize;
+      if (msg->nblocks >= nblocks - written)
+        {
+          /* Send complete, set cookie is valid, need ack */
+
+          msg->nblocks = nblocks - written;
+          msg->header.cookie = (uintptr_t)&cookie;
+        }
+      else
+        {
+          /* Not send complete, set cookie invalid, do not need ack */
+
+          msg->header.cookie = 0;
+        }
+
+      msg->header.command = RPMSGMTD_BWRITE;
+      msg->header.result  = -ENXIO;
+      msg->startblock     = startblock;
+      msg->blocksize      = blocksize;
+      memcpy(msg->buf, buffer, msg->nblocks * blocksize);
+
+      buffer     += msg->nblocks * blocksize;
+      startblock += msg->nblocks;
+      written    += msg->nblocks;
+
+      ret = rpmsg_send_nocopy(&priv->ept, msg,
+                              sizeof(*msg) - 1 + msg->nblocks * blocksize);
+      if (ret < 0)
+        {
+          goto out;
+        }
+    }
+
+  ret = rpmsg_wait(&priv->ept, &cookie.sem);
+  if (ret < 0)
+    {
+      goto out;
+    }
+
+  ret = cookie.result;
+
+out:
+  nxsem_destroy(&cookie.sem);
+  return ret < 0 ? ret : nblocks;
+}
+
+/****************************************************************************
+ * Name: rpmsgmtd_read
+ *
+ * Description:
+ *   Rpmsg-mtd read operation
+ *
+ * Parameters:
+ *   dev    - the mtd device
+ *   offset - read offset address in the mtd device
+ *   nbytes - read number in bytes
+ *   buffer - read buffer
+ *
+ * Returned Values:
+ *   The positive non-zero number of bytes read on success, 0 on if an
+ *   end-of-file condition, or a negated errno value on any failure.
+ *
+ ****************************************************************************/
+
+static ssize_t rpmsgmtd_read(FAR struct mtd_dev_s *dev, off_t offset,
+                             size_t nbytes, FAR uint8_t *buffer)
+{
+  FAR struct rpmsgmtd_s *priv = (FAR struct rpmsgmtd_s *)dev;
+  struct rpmsgmtd_read_s msg;
+  struct iovec iov;
+  ssize_t ret;
+
+  if (buffer == NULL)
+    {
+      return -EINVAL;
+    }
+
+  /* Sanity checks */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Call the host to perform the read */
+
+  iov.iov_base = buffer;
+  iov.iov_len  = 0;
+
+  msg.offset = offset;
+  msg.nbytes = nbytes;
+
+  ret = rpmsgmtd_send_recv(priv, RPMSGMTD_READ, true, &msg.header,
+                           sizeof(msg) - 1, &iov);
+
+  return ret < 0 ? ret : iov.iov_len;
+}
+
+/****************************************************************************
+ * Name: rpmsgmtd_write
+ *
+ * Description:
+ *   Rpmsg-mtd write operation
+ *
+ * Parameters:
+ *   dev    - the mtd device
+ *   offset - write offset address in the mtd device
+ *   nbytes - write number in bytes
+ *   buffer - write buffer
+ *
+ * Returned Values:
+ *   On success, the number of bytes written are returned (zero indicates
+ *   nothing was written).  On any failure, a negated errno value is returned
+ *   (see comments withwrite() for a description of the appropriate errno
+ *   values).
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_MTD_BYTE_WRITE
+static ssize_t rpmsgmtd_write(FAR struct mtd_dev_s *dev, off_t offset,
+                              size_t nbytes, FAR const uint8_t *buffer)
+{
+  FAR struct rpmsgmtd_s *priv = (FAR struct rpmsgmtd_s *)dev;
+  FAR struct rpmsgmtd_write_s *msg;
+  struct rpmsgmtd_cookie_s cookie;
+  uint32_t space;
+  size_t written = 0;
+  int ret;
+
+  if (buffer == NULL)
+    {
+      return -EINVAL;
+    }
+
+  /* Sanity checks */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Perform the rpmsg write */
+
+  memset(&cookie, 0, sizeof(cookie));
+  nxsem_init(&cookie.sem, 0, 0);
+  nxsem_set_protocol(&cookie.sem, SEM_PRIO_NONE);
+
+  while (written < nbytes)
+    {
+      msg = rpmsgmtd_get_tx_payload_buffer(priv, &space);
+      if (msg == NULL)
+        {
+          ret = -ENOMEM;
+          goto out;
+        }
+
+      space -= sizeof(*msg) - 1;
+      if (space >= nbytes - written)
+        {
+          /* Send complete, set cookie is valid, need ack */
+
+          space = nbytes - written;
+          msg->header.cookie = (uintptr_t)&cookie;
+        }
+      else
+        {
+          /* Not send complete, set cookie invalid, do not need ack */
+
+          msg->header.cookie = 0;
+        }
+
+      msg->header.command = RPMSGMTD_WRITE;
+      msg->header.result  = -ENXIO;
+      msg->offset         = offset;
+      msg->nbytes         = space;
+      memcpy(msg->buf, buffer, space);
+
+      ret = rpmsg_send_nocopy(&priv->ept, msg, sizeof(*msg) - 1 + space);
+      if (ret < 0)
+        {
+          goto out;
+        }
+
+      buffer  += space;
+      offset  += space;
+      written += space;
+    }
+
+  ret = rpmsg_wait(&priv->ept, &cookie.sem);
+  if (ret < 0)
+    {
+      goto out;
+    }
+
+  ret = cookie.result;
+
+out:
+  nxsem_destroy(&cookie.sem);
+  return ret < 0 ? ret : nbytes;
+}
+#endif
+
+/****************************************************************************
+ * Name: rpmsgmtd_ioctl_arglen
+ *
+ * Description:
+ *   Get rpmsg mtd ioctl argument length according to the command
+ *
+ * Parameters:
+ *   cmd - the ioctl command
+ *
+ * Returned Values:
+ *   0        - ioctl command not support
+ *   positive - the argument length
+ *
+ ****************************************************************************/
+
+static size_t rpmsgmtd_ioctl_arglen(int cmd)
+{
+  switch (cmd)
+    {
+      case MTDIOC_GEOMETRY:
+        return sizeof(struct mtd_geometry_s);
+      case MTDIOC_PROTECT:
+      case MTDIOC_UNPROTECT:
+        return sizeof(struct mtd_protect_s);
+      default:
+        return 0;
+    }
+}
+
+/****************************************************************************
+ * Name: rpmsgmtd_ioctl
+ *
+ * Description:
+ *   Rpmsg-mtd ioctl operation
+ *
+ * Parameters:
+ *   dev - the mtd device
+ *   cmd - the ioctl command
+ *   arg - the ioctl arguments
+ *
+ * Returned Values:
+ *   OK on success; A negated errno value is returned on any failure.
+ *
+ ****************************************************************************/
+
+static int rpmsgmtd_ioctl(FAR struct mtd_dev_s *dev, int cmd,
+                          unsigned long arg)
+{
+  FAR struct rpmsgmtd_s *priv = (FAR struct rpmsgmtd_s *)dev;
+  FAR struct rpmsgmtd_ioctl_s *msg;
+  uint32_t space;
+  size_t arglen;
+  size_t msglen;
+
+  /* Sanity checks */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Call our internal routine to perform the ioctl */
+
+  arglen = rpmsgmtd_ioctl_arglen(cmd);
+  msglen = sizeof(*msg) + arglen - 1;
+
+  msg = rpmsgmtd_get_tx_payload_buffer(priv, &space);
+  if (msg == NULL)
+    {
+      return -ENOMEM;
+    }
+
+  msg->request = cmd;
+  msg->arg     = arg;
+  msg->arglen  = arglen;
+
+  if (arglen > 0)
+    {
+      memcpy(msg->buf, (FAR void *)(uintptr_t)arg, arglen);
+    }
+
+  return rpmsgmtd_send_recv(priv, RPMSGMTD_IOCTL, false, &msg->header,
+                            msglen, arglen > 0 ? (FAR void *)arg : NULL);
+}
+
+/****************************************************************************
+ * Name: rpmsgmtd_get_tx_payload_buffer
+ *
+ * Description:
+ *   Get the rpmsg mtd tx payload, the buffer is from the rpmsg share memory
+ *   that can be accessed by local and remote cpu.
+ *
+ * Parameters:
+ *   priv  - The rpmsg-mtd handle
+ *   len   - The got memroy size
+ *
+ * Returned Values:
+ *   NULL     - failure
+ *   not NULL - success
+ *
+ ****************************************************************************/
+
+static FAR void *rpmsgmtd_get_tx_payload_buffer(FAR struct rpmsgmtd_s *priv,
+                                                FAR uint32_t *len)
+{
+  int sval;
+
+  nxsem_get_value(&priv->wait, &sval);
+  if (sval <= 0)
+    {
+      rpmsg_wait(&priv->ept, &priv->wait);
+      rpmsg_post(&priv->ept, &priv->wait);
+    }
+
+  return rpmsg_get_tx_payload_buffer(&priv->ept, len, true);
+}
+
+/****************************************************************************
+ * Name: rpmsgmtd_send_recv
+ *
+ * Description:
+ *   Send and receive the rpmsg data.
+ *
+ * Parameters:
+ *   priv    - rpmsg mtd handle
+ *   command - the command, RPMSGMTD_OPEN, RPMSGMTD_CLOSE, RPMSGMTD_READ,
+ *                          RPMSGMTD_WRITE, RPMSGMTD_IOCTL
+ *   copy    - true, send a message across to the remote processor, and the
+ *                   tx buffer will be alloced inside function rpmsg_send()
+ *             false, send a message in tx buffer reserved by
+ *                    rpmsg_get_tx_payload_buffer() across to the remote
+ *                    processor.
+ *   msg     - the message header
+ *   len     - length of the payload
+ *   data    - the data
+ *
+ * Returned Values:
+ *   OK on success; A negated errno value is returned on any failure.
+ *
+ ****************************************************************************/
+
+static int rpmsgmtd_send_recv(FAR struct rpmsgmtd_s *priv,
+                              uint32_t command, bool copy,
+                              FAR struct rpmsgmtd_header_s *msg,
+                              int len, FAR void *data)
+{
+  struct rpmsgmtd_cookie_s cookie;
+  int ret;
+
+  memset(&cookie, 0, sizeof(cookie));
+  nxsem_init(&cookie.sem, 0, 0);
+  nxsem_set_protocol(&cookie.sem, SEM_PRIO_NONE);
+
+  if (data != NULL)
+    {
+      cookie.data = data;
+    }
+  else if (copy)
+    {
+      cookie.data = msg;
+    }
+
+  msg->command = command;
+  msg->result  = -ENXIO;
+  msg->cookie  = (uintptr_t)&cookie;
+
+  if (copy)
+    {
+      ret = rpmsg_send(&priv->ept, msg, len);
+    }
+  else
+    {
+      ret = rpmsg_send_nocopy(&priv->ept, msg, len);
+    }
+
+  if (ret < 0)
+    {
+      goto fail;
+    }
+
+  ret = rpmsg_wait(&priv->ept, &cookie.sem);
+  if (ret >= 0)
+    {
+      ret = cookie.result;
+    }
+
+fail:
+  nxsem_destroy(&cookie.sem);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: rpmsgmtd_default_handler
+ *
+ * Description:
+ *   Default rpmsg-mtd response handler, this function will be called to
+ *   process the return message of rpmsgmtd_open(), rpmsgmtd_close() and
+ *   rpmsgmtd_write().
+ *
+ * Parameters:
+ *   ept  - The rpmsg endpoint
+ *   data - The return message
+ *   len  - The return message length
+ *   src  - unknow
+ *   priv - unknow
+ *
+ * Returned Values:
+ *   Always OK
+ *
+ ****************************************************************************/
+
+static int rpmsgmtd_default_handler(FAR struct rpmsg_endpoint *ept,
+                                    FAR void *data, size_t len,
+                                    uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgmtd_header_s *header = data;
+  FAR struct rpmsgmtd_cookie_s *cookie =
+      (FAR struct rpmsgmtd_cookie_s *)(uintptr_t)header->cookie;
+
+  cookie->result = header->result;
+  if (cookie->result >= 0 && cookie->data)
+    {
+      memcpy(cookie->data, data, len);
+    }
+
+  rpmsg_post(ept, &cookie->sem);
+  return 0;
+}
+
+/****************************************************************************
+ * Name: rpmsgmtd_bread_handler
+ *
+ * Description:
+ *   Rpmsg-mtd block read response handler, this function will be called to
+ *   process the return message of rpmsgmtd_bread().
+ *
+ * Parameters:
+ *   ept  - The rpmsg endpoint
+ *   data - The return message
+ *   len  - The return message length
+ *   src  - unknow
+ *   priv - unknow
+ *
+ * Returned Values:
+ *   Always OK
+ *
+ ****************************************************************************/
+
+static int rpmsgmtd_bread_handler(FAR struct rpmsg_endpoint *ept,
+                                  FAR void *data, size_t len,
+                                  uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgmtd_header_s *header = data;
+  FAR struct rpmsgmtd_cookie_s *cookie =
+      (FAR struct rpmsgmtd_cookie_s *)(uintptr_t)header->cookie;
+  FAR struct rpmsgmtd_bread_s *rsp = data;
+  FAR struct iovec *iov = cookie->data;
+  size_t read;
+
+  cookie->result = header->result;
+  if (cookie->result > 0)
+    {
+      read = cookie->result * rsp->blocksize;
+      memcpy(iov->iov_base, rsp->buf, read);
+      iov->iov_base += read;
+      iov->iov_len  += cookie->result;
+    }
+
+  if (cookie->result <= 0 || iov->iov_len >= rsp->nblocks)
+    {
+      rpmsg_post(ept, &cookie->sem);
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: rpmsgmtd_read_handler
+ *
+ * Description:
+ *   Rpmsg-mtd read response handler, this function will be called to
+ *   process the return message of rpmsgmtd_read().
+ *
+ * Parameters:
+ *   ept  - The rpmsg endpoint
+ *   data - The return message
+ *   len  - The return message length
+ *   src  - unknow
+ *   priv - unknow
+ *
+ * Returned Values:
+ *   Always OK
+ *
+ ****************************************************************************/
+
+static int rpmsgmtd_read_handler(FAR struct rpmsg_endpoint *ept,
+                                 FAR void *data, size_t len,
+                                 uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgmtd_header_s *header = data;
+  FAR struct rpmsgmtd_cookie_s *cookie =
+      (FAR struct rpmsgmtd_cookie_s *)(uintptr_t)header->cookie;
+  FAR struct rpmsgmtd_read_s *rsp = data;
+  FAR struct iovec *iov = cookie->data;
+
+  cookie->result = header->result;
+  if (cookie->result > 0)
+    {
+      memcpy(iov->iov_base + iov->iov_len, rsp->buf, cookie->result);
+      iov->iov_len += cookie->result;
+    }
+
+  if (cookie->result <= 0 || iov->iov_len >= rsp->nbytes)
+    {
+      rpmsg_post(ept, &cookie->sem);
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: rpmsgmtd_ioctl_handler
+ *
+ * Description:
+ *   Rpmsg-mtd ioctl response handler, this function will be called to
+ *   process the return message of rpmsgmtd_ioctl().
+ *
+ * Parameters:
+ *   ept  - The rpmsg endpoint
+ *   data - The return message
+ *   len  - The return message length
+ *   src  - unknow
+ *   priv - unknow
+ *
+ * Returned Values:
+ *   Always OK
+ *
+ ****************************************************************************/
+
+static int rpmsgmtd_ioctl_handler(FAR struct rpmsg_endpoint *ept,
+                                  FAR void *data, size_t len,
+                                  uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgmtd_header_s *header = data;
+  FAR struct rpmsgmtd_cookie_s *cookie =
+      (FAR struct rpmsgmtd_cookie_s *)(uintptr_t)header->cookie;
+  FAR struct rpmsgmtd_ioctl_s *rsp = data;
+
+  if (cookie->result >= 0 && rsp->arglen > 0)
+    {
+      memcpy(cookie->data, (FAR void *)(uintptr_t)rsp->buf, rsp->arglen);
+    }
+
+  rpmsg_post(ept, &cookie->sem);
+  return 0;
+}
+
+/****************************************************************************
+ * Name: rpmsgmtd_ns_bound
+ *
+ * Description:
+ *   Rpmsg mtd end point service bound callback function , called when
+ *   remote end point address is received.
+ *
+ * Parameters:
+ *   ept  - The rpmsg-mtd end point
+ *
+ * Returned Values:
+ *   None
+ *
+ ****************************************************************************/
+
+static void rpmsgmtd_ns_bound(FAR struct rpmsg_endpoint *ept)
+{
+  FAR struct rpmsgmtd_s *priv = ept->priv;
+
+  rpmsg_post(&priv->ept, &priv->wait);
+}
+
+/****************************************************************************
+ * Name: rpmsgmtd_device_created
+ *
+ * Description:
+ *   Rpmsg mtd create function, this function will be called by rptun to
+ *   create a rpmsg-mtd end point.
+ *
+ * Parameters:
+ *   rdev  - The rpmsg-mtd end point
+ *   priv_ - Rpmsg-mtd handle
+ *
+ * Returned Values:
+ *   None
+ *
+ ****************************************************************************/
+
+static void rpmsgmtd_device_created(FAR struct rpmsg_device *rdev,
+                                    FAR void *priv_)
+{
+  FAR struct rpmsgmtd_s *priv = priv_;
+  char buf[RPMSG_NAME_SIZE];
+
+  if (strcmp(priv->remotecpu, rpmsg_get_cpuname(rdev)) == 0)
+    {
+      priv->ept.priv = priv;
+      priv->ept.ns_bound_cb = rpmsgmtd_ns_bound;
+      snprintf(buf, sizeof(buf), "%s%s", RPMSGMTD_NAME_PREFIX,
+               priv->remotepath);
+      rpmsg_create_ept(&priv->ept, rdev, buf,
+                       RPMSG_ADDR_ANY, RPMSG_ADDR_ANY,
+                       rpmsgmtd_ept_cb, NULL);
+    }
+}
+
+/****************************************************************************
+ * Name: rpmsgmtd_device_destroy
+ *
+ * Description:
+ *   Rpmsg mtd destroy function, this function will be called by rptun to
+ *   destroy rpmsg-mtd end point.
+ *
+ * Parameters:
+ *   rdev  - The rpmsg-mtd end point
+ *   priv_ - Rpmsg-mtd handle
+ *
+ * Returned Values:
+ *   None
+ *
+ ****************************************************************************/
+
+static void rpmsgmtd_device_destroy(FAR struct rpmsg_device *rdev,
+                                    FAR void *priv_)
+{
+  FAR struct rpmsgmtd_s *priv = priv_;
+
+  if (strcmp(priv->remotecpu, rpmsg_get_cpuname(rdev)) == 0)
+    {
+      rpmsg_destroy_ept(&priv->ept);
+    }
+}
+
+/****************************************************************************
+ * Name: rpmsgmtd_ept_cb
+ *
+ * Description:
+ *   Rpmsg mtd end point callback function, this function will be called
+ *   when receive the remote cpu message.
+ *
+ * Parameters:
+ *   ept  - The rpmsg-mtd end point
+ *   data - The received data
+ *   len  - The received data length
+ *   src  - unknow
+ *   priv - unknow
+ *
+ * Returned Values:
+ *   OK on success; A negated errno value is returned on any failure.
+ *
+ ****************************************************************************/
+
+static int rpmsgmtd_ept_cb(FAR struct rpmsg_endpoint *ept,
+                           FAR void *data, size_t len, uint32_t src,
+                           FAR void *priv)
+{
+  FAR struct rpmsgmtd_header_s *header = data;
+  uint32_t command = header->command;
+
+  if (command < ARRAY_SIZE(g_rpmsgmtd_handler))
+    {
+      return g_rpmsgmtd_handler[command](ept, data, len, src, priv);
+    }
+
+  return -EINVAL;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: rpmsgmtd_register
+ *
+ * Description:
+ *   Rpmsg-mtd client initialize function, the client cpu should call
+ *   this function in the board initialize process.
+ *
+ * Parameters:
+ *   remotecpu  - the server cpu name
+ *   remotepath - the device you want to access in the remote cpu
+ *   localpath  - the device path in local cpu, if NULL, the localpath is
+ *                same as the remotepath, provide this argument to supoort
+ *                custom device path
+ *
+ * Returned Values:
+ *   OK on success; A negated errno value is returned on any failure.
+ *
+ ****************************************************************************/
+
+int rpmsgmtd_register(FAR const char *remotecpu, FAR const char *remotepath,
+                      FAR const char *localpath)
+{
+  FAR struct rpmsgmtd_s *dev;
+  int ret;
+
+  /* Arguments check */
+
+  if (remotecpu == NULL || remotepath == NULL)
+    {
+      ferr("ERROR: Input arguments null\n");
+      return -EINVAL;
+    }
+
+  /* Create an instance of the RPMSG MTD device */
+
+  dev = kmm_zalloc(sizeof(*dev));
+  if (dev == NULL)
+    {
+      ferr("ERROR: Failed to allocate the RPMSG MTD degice\n");
+      return -ENOMEM;
+    }
+
+  /* Perform initialization as necessary. (unsupported methods were
+   * nullified by kmm_zalloc).
+   */
+
+  dev->mtd.erase  = rpmsgmtd_erase;
+  dev->mtd.bread  = rpmsgmtd_bread;
+  dev->mtd.bwrite = rpmsgmtd_bwrite;
+  dev->mtd.read   = rpmsgmtd_read;
+#ifdef CONFIG_MTD_BYTE_WRITE
+  dev->mtd.write  = rpmsgmtd_write;
+#endif
+  dev->mtd.ioctl  = rpmsgmtd_ioctl;
+  dev->mtd.name   = "rpmsgmtd";
+
+  /* Initialize the rpmsg device */
+
+  dev->remotecpu  = remotecpu;
+  dev->remotepath = remotepath;
+
+  nxsem_init(&dev->wait, 0, 0);
+  nxsem_set_protocol(&dev->wait, SEM_PRIO_NONE);
+  nxmutex_init(&dev->geoexcl);
+
+  /* Register the rpmsg callback */
+
+  ret = rpmsg_register_callback(dev,
+                                rpmsgmtd_device_created,
+                                rpmsgmtd_device_destroy,
+                                NULL,
+                                NULL);
+  if (ret < 0)
+    {
+      ferr("ERROR: register callback failed, ret=%d\n", ret);
+      goto fail;
+    }
+
+  /* Register driver, using the remotepath if localpath is NULL */
+
+  if (localpath == NULL)
+    {
+      localpath = remotepath;
+    }
+
+  ret = register_mtddriver(localpath, &dev->mtd, 0755, dev);
+  if (ret < 0)
+    {
+      ferr("ERROR: register driver failed, ret=%d\n", ret);
+      goto fail_with_rpmsg;
+    }
+
+  return OK;
+
+fail_with_rpmsg:
+  rpmsg_unregister_callback(dev,
+                            rpmsgmtd_device_created,
+                            rpmsgmtd_device_destroy,
+                            NULL,
+                            NULL);
+
+fail:
+  nxsem_destroy(&dev->wait);
+  kmm_free(dev);
+  return ret;
+}
diff --git a/drivers/mtd/rpmsgmtd.h b/drivers/mtd/rpmsgmtd.h
new file mode 100644
index 0000000000..523c515957
--- /dev/null
+++ b/drivers/mtd/rpmsgmtd.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+ * drivers/mtd/rpmsgmtd.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 __DRIVERS_MTD_RPMSGMTD_H
+#define __DRIVERS_MTD_RPMSGMTD_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/compiler.h>
+#include <sys/types.h>
+
+/****************************************************************************
+ * Pre-processor definitions
+ ****************************************************************************/
+
+#ifndef ARRAY_SIZE
+#  define ARRAY_SIZE(x)         (sizeof(x) / sizeof((x)[0]))
+#endif
+
+#define RPMSGMTD_NAME_PREFIX     "rpmsgmtd-"
+#define RPMSGMTD_NAME_PREFIX_LEN 9
+
+#define RPMSGMTD_ERASE           1
+#define RPMSGMTD_BREAD           2
+#define RPMSGMTD_BWRITE          3
+#define RPMSGMTD_READ            4
+#define RPMSGMTD_WRITE           5
+#define RPMSGMTD_IOCTL           6
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+begin_packed_struct struct rpmsgmtd_header_s
+{
+  uint32_t                 command;
+  int32_t                  result;
+  uint64_t                 cookie;
+} end_packed_struct;
+
+begin_packed_struct struct rpmsgmtd_erase_s
+{
+  struct rpmsgmtd_header_s header;
+  int64_t                  startblock;
+  uint64_t                 nblocks;
+} end_packed_struct;
+
+begin_packed_struct struct rpmsgmtd_bread_s
+{
+  struct rpmsgmtd_header_s header;
+  int64_t                  startblock;
+  uint64_t                 nblocks;
+  uint32_t                 blocksize;
+  uint8_t                  buf[1];
+} end_packed_struct;
+
+#define rpmsgmtd_bwrite_s rpmsgmtd_bread_s
+
+begin_packed_struct struct rpmsgmtd_read_s
+{
+  struct rpmsgmtd_header_s header;
+  int64_t                  offset;
+  uint64_t                 nbytes;
+  uint8_t                  buf[1];
+} end_packed_struct;
+
+#define rpmsgmtd_write_s rpmsgmtd_read_s
+
+begin_packed_struct struct rpmsgmtd_ioctl_s
+{
+  struct rpmsgmtd_header_s header;
+  int32_t                  request;
+  uint64_t                 arg;
+  uint32_t                 arglen;
+  uint8_t                  buf[1];
+} end_packed_struct;
+
+/****************************************************************************
+ * Internal function prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Internal data
+ ****************************************************************************/
+
+#endif /* __DRIVERS_MTD_RPMSGMTD_H */
diff --git a/drivers/mtd/rpmsgmtd_server.c b/drivers/mtd/rpmsgmtd_server.c
new file mode 100644
index 0000000000..fd6377866f
--- /dev/null
+++ b/drivers/mtd/rpmsgmtd_server.c
@@ -0,0 +1,420 @@
+/****************************************************************************
+ * drivers/mtd/rpmsgmtd_server.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 <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/kmalloc.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/mtd/mtd.h>
+#include <nuttx/rptun/openamp.h>
+
+#include "rpmsgmtd.h"
+
+/****************************************************************************
+ * Pre-processor definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct rpmsgmtd_server_s
+{
+  struct rpmsg_endpoint ept;
+  FAR struct mtd_dev_s *dev;
+  FAR struct inode     *mtdnode;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Functions handle the messages from the client cpu */
+
+static int rpmsgmtd_erase_handler(FAR struct rpmsg_endpoint *ept,
+                                  FAR void *data, size_t len,
+                                  uint32_t src, FAR void *priv);
+static int rpmsgmtd_bread_handler(FAR struct rpmsg_endpoint *ept,
+                                  FAR void *data, size_t len,
+                                  uint32_t src, FAR void *priv);
+static int rpmsgmtd_bwrite_handler(FAR struct rpmsg_endpoint *ept,
+                                   FAR void *data, size_t len,
+                                   uint32_t src, FAR void *priv);
+static int rpmsgmtd_read_handler(FAR struct rpmsg_endpoint *ept,
+                                 FAR void *data, size_t len,
+                                 uint32_t src, FAR void *priv);
+static int rpmsgmtd_write_handler(FAR struct rpmsg_endpoint *ept,
+                                  FAR void *data, size_t len,
+                                  uint32_t src, FAR void *priv);
+static int rpmsgmtd_ioctl_handler(FAR struct rpmsg_endpoint *ept,
+                                  FAR void *data, size_t len,
+                                  uint32_t src, FAR void *priv);
+
+/* Functions for creating communication with client cpu */
+
+static bool rpmsgmtd_ns_match(FAR struct rpmsg_device *rdev,
+                              FAR void *priv, FAR const char *name,
+                              uint32_t dest);
+static void rpmsgmtd_ns_bind(FAR struct rpmsg_device *rdev,
+                             FAR void *priv, FAR const char *name,
+                             uint32_t dest);
+static void rpmsgmtd_ns_unbind(FAR struct rpmsg_endpoint *ept);
+static int  rpmsgmtd_ept_cb(FAR struct rpmsg_endpoint *ept,
+                            FAR void *data, size_t len, uint32_t src,
+                            FAR void *priv);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const rpmsg_ept_cb g_rpmsgmtd_handler[] =
+{
+  [RPMSGMTD_ERASE]  = rpmsgmtd_erase_handler,
+  [RPMSGMTD_BREAD]  = rpmsgmtd_bread_handler,
+  [RPMSGMTD_BWRITE] = rpmsgmtd_bwrite_handler,
+  [RPMSGMTD_READ]   = rpmsgmtd_read_handler,
+  [RPMSGMTD_WRITE]  = rpmsgmtd_write_handler,
+  [RPMSGMTD_IOCTL]  = rpmsgmtd_ioctl_handler,
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: rpmsgmtd_erase_handler
+ ****************************************************************************/
+
+static int rpmsgmtd_erase_handler(FAR struct rpmsg_endpoint *ept,
+                                  FAR void *data, size_t len,
+                                  uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgmtd_server_s *server = ept->priv;
+  FAR struct rpmsgmtd_erase_s *msg = data;
+
+  msg->header.result = MTD_ERASE(server->dev, msg->startblock, msg->nblocks);
+
+  return rpmsg_send(ept, msg, sizeof(*msg));
+}
+
+/****************************************************************************
+ * Name: rpmsgmtd_bread_handler
+ ****************************************************************************/
+
+static int rpmsgmtd_bread_handler(FAR struct rpmsg_endpoint *ept,
+                                  FAR void *data, size_t len,
+                                  uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgmtd_server_s *server = ept->priv;
+  FAR struct rpmsgmtd_bread_s *msg = data;
+  FAR struct rpmsgmtd_bread_s *rsp;
+  int ret = -ENOENT;
+  size_t read = 0;
+  size_t nblocks;
+  uint32_t space;
+
+  while (read < msg->nblocks)
+    {
+      rsp = rpmsg_get_tx_payload_buffer(ept, &space, true);
+      if (rsp == NULL)
+        {
+          ferr("get tx payload failed or no enough space\n");
+          return -ENOMEM;
+        }
+
+      DEBUGASSERT(space >= sizeof(*msg) - 1 + msg->blocksize);
+
+      *rsp = *msg;
+
+      nblocks = (space - sizeof(*msg) + 1) / msg->blocksize;
+      if (nblocks > msg->nblocks - read)
+        {
+          nblocks = msg->nblocks - read;
+        }
+
+      ret = MTD_BREAD(server->dev, msg->startblock + read, nblocks,
+                      rsp->buf);
+
+      rsp->header.result = ret;
+      rpmsg_send_nocopy(ept, rsp, (ret < 0 ? 0 : ret * msg->blocksize) +
+                        sizeof(*rsp) - 1);
+      if (ret <= 0)
+        {
+          ferr("mtd block read failed\n");
+          break;
+        }
+
+      read += ret;
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: rpmsgmtd_bwrite_handler
+ ****************************************************************************/
+
+static int rpmsgmtd_bwrite_handler(FAR struct rpmsg_endpoint *ept,
+                                   FAR void *data, size_t len,
+                                   uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgmtd_server_s *server = ept->priv;
+  FAR struct rpmsgmtd_bwrite_s *msg = data;
+  int ret;
+
+  ret = MTD_BWRITE(server->dev, msg->startblock, msg->nblocks, msg->buf);
+  if (ret <= 0)
+    {
+      ferr("mtd block write failed\n");
+    }
+
+  /* cookie != 0 indicate the data has been sent complete, so send back
+   * the total written blocks.
+   */
+
+  if (msg->header.cookie != 0)
+    {
+      msg->header.result = ret;
+      rpmsg_send(ept, msg, sizeof(*msg) - 1);
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: rpmsgmtd_read_handler
+ ****************************************************************************/
+
+static int rpmsgmtd_read_handler(FAR struct rpmsg_endpoint *ept,
+                                 FAR void *data, size_t len,
+                                 uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgmtd_server_s *server = ept->priv;
+  FAR struct rpmsgmtd_read_s *msg = data;
+  FAR struct rpmsgmtd_read_s *rsp;
+  int ret = -ENOENT;
+  size_t read = 0;
+  uint32_t space;
+
+  while (read < msg->nbytes)
+    {
+      rsp = rpmsg_get_tx_payload_buffer(ept, &space, true);
+      if (rsp == NULL)
+        {
+          ferr("get tx payload failed\n");
+          return -ENOMEM;
+        }
+
+      *rsp = *msg;
+
+      space -= sizeof(*msg) - 1;
+      if (space > msg->nbytes - read)
+        {
+          space = msg->nbytes - read;
+        }
+
+      ret = MTD_READ(server->dev, msg->offset + read, space,
+                     (FAR uint8_t *)rsp->buf);
+
+      rsp->header.result = ret;
+      rpmsg_send_nocopy(ept, rsp, (ret < 0 ? 0 : ret) + sizeof(*rsp) - 1);
+      if (ret <= 0)
+        {
+          break;
+        }
+
+      read += ret;
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: rpmsgmtd_write_handler
+ ****************************************************************************/
+
+static int rpmsgmtd_write_handler(FAR struct rpmsg_endpoint *ept,
+                                  FAR void *data, size_t len,
+                                  uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgmtd_server_s *server = ept->priv;
+  FAR struct rpmsgmtd_write_s *msg = data;
+  int ret;
+
+  ret = MTD_WRITE(server->dev, msg->offset, msg->nbytes, msg->buf);
+  if (ret <= 0)
+    {
+      ferr("mtd write failed\n");
+    }
+
+  /* cookie != 0 indicate the data has been sent complete, so send back
+   * the total written bytes.
+   */
+
+  if (msg->header.cookie != 0)
+    {
+      msg->header.result = ret;
+      rpmsg_send(ept, msg, sizeof(*msg) - 1);
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: rpmsgmtd_ioctl_handler
+ ****************************************************************************/
+
+static int rpmsgmtd_ioctl_handler(FAR struct rpmsg_endpoint *ept,
+                                  FAR void *data, size_t len,
+                                  uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgmtd_server_s *server = ept->priv;
+  FAR struct rpmsgmtd_ioctl_s *msg = data;
+
+  msg->header.result = MTD_IOCTL(server->dev, msg->request,
+                                 msg->arglen > 0 ? (unsigned long)msg->buf :
+                                 msg->arg);
+
+  return rpmsg_send(ept, msg, len);
+}
+
+/****************************************************************************
+ * Name: rpmsgmtd_ns_match
+ ****************************************************************************/
+
+static bool rpmsgmtd_ns_match(FAR struct rpmsg_device *rdev,
+                              FAR void *priv, FAR const char *name,
+                              uint32_t dest)
+{
+  return !strncmp(name, RPMSGMTD_NAME_PREFIX, RPMSGMTD_NAME_PREFIX_LEN);
+}
+
+/****************************************************************************
+ * Name: rpmsgmtd_ns_bind
+ ****************************************************************************/
+
+static void rpmsgmtd_ns_bind(FAR struct rpmsg_device *rdev,
+                             FAR void *priv, FAR const char *name,
+                             uint32_t dest)
+{
+  FAR struct rpmsgmtd_server_s *server;
+  FAR struct inode *mtdnode;
+  int ret;
+
+  server = kmm_zalloc(sizeof(*server));
+  if (server == NULL)
+    {
+      ferr("mtd server malloced failed\n");
+      return;
+    }
+
+  ret = find_mtddriver(&name[RPMSGMTD_NAME_PREFIX_LEN], &mtdnode);
+  if (ret < 0)
+    {
+      ferr("mtd device find failed, ret=%d\n", ret);
+      goto errout;
+    }
+
+  server->ept.priv = server;
+  server->mtdnode  = mtdnode;
+  server->dev      = mtdnode->u.i_mtd;
+
+  ret = rpmsg_create_ept(&server->ept, rdev, name,
+                         RPMSG_ADDR_ANY, dest,
+                         rpmsgmtd_ept_cb, rpmsgmtd_ns_unbind);
+  if (ret < 0)
+    {
+      ferr("endpoint create failed, ret=%d\n", ret);
+      close_mtddriver(mtdnode);
+      goto errout;
+    }
+
+  return;
+
+errout:
+  kmm_free(server);
+}
+
+/****************************************************************************
+ * Name: rpmsgmtd_ns_unbind
+ ****************************************************************************/
+
+static void rpmsgmtd_ns_unbind(FAR struct rpmsg_endpoint *ept)
+{
+  FAR struct rpmsgmtd_server_s *server = ept->priv;
+
+  rpmsg_destroy_ept(&server->ept);
+  close_mtddriver(server->mtdnode);
+  kmm_free(server);
+}
+
+/****************************************************************************
+ * Name: rpmsgmtd_ept_cb
+ ****************************************************************************/
+
+static int rpmsgmtd_ept_cb(FAR struct rpmsg_endpoint *ept,
+                           FAR void *data, size_t len, uint32_t src,
+                           FAR void *priv)
+{
+  FAR struct rpmsgmtd_header_s *header = data;
+  uint32_t command = header->command;
+
+  if (command < ARRAY_SIZE(g_rpmsgmtd_handler))
+    {
+      return g_rpmsgmtd_handler[command](ept, data, len, src, priv);
+    }
+
+  return -EINVAL;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: rpmsgmtd_server_init
+ *
+ * Description:
+ *   Rpmsg-mtd server initialize function, the server cpu should call
+ *   this function.
+ *
+ * Parameters:
+ *   None
+ *
+ * Returned Values:
+ *   OK on success; A negated errno value is returned on any failure.
+ *
+ ****************************************************************************/
+
+int rpmsgmtd_server_init(void)
+{
+  return rpmsg_register_callback(NULL,
+                                 NULL,
+                                 NULL,
+                                 rpmsgmtd_ns_match,
+                                 rpmsgmtd_ns_bind);
+}
diff --git a/include/nuttx/mtd/mtd.h b/include/nuttx/mtd/mtd.h
index 3039bf950a..a029b9a4b0 100644
--- a/include/nuttx/mtd/mtd.h
+++ b/include/nuttx/mtd/mtd.h
@@ -687,6 +687,49 @@ bool filemtd_isfilemtd(FAR struct mtd_dev_s *mtd);
 FAR struct mtd_dev_s *nullmtd_initialize(size_t mtdlen, int16_t sectsize,
                                          int32_t erasesize);
 
+/****************************************************************************
+ * Name: rpmsgmtd_register
+ *
+ * Description:
+ *   Rpmsg-mtd client register function, the client cpu should call
+ *   this function in the board initialize process.
+ *
+ * Parameters:
+ *   remotecpu  - the server cpu name
+ *   remotepath - the device you want to access in the remote cpu
+ *   localpath  - the device path in local cpu, if NULL, the localpath is
+ *                same as the remotepath, provide this argument to supoort
+ *                custom device path
+ *
+ * Returned Values:
+ *   OK on success; A negated errno value is returned on any failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_RPMSGMTD
+int rpmsgmtd_register(FAR const char *remotecpu, FAR const char *remotepath,
+                      FAR const char *localpath);
+#endif
+
+/****************************************************************************
+ * Name: rpmsgmtd_server_init
+ *
+ * Description:
+ *   Rpmsg-mtd server initialize function, the server cpu should call
+ *   this function.
+ *
+ * Parameters:
+ *   None
+ *
+ * Returned Values:
+ *   OK on success; A negated errno value is returned on any failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_RPMSGMTD_SERVER
+int rpmsgmtd_server_init(void);
+#endif
+
 #undef EXTERN
 #ifdef __cplusplus
 }