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

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

commit 4924a42115f7380afaae1e51b3ae51c880467ef0
Author: Daniel P. Carvalho <[email protected]>
AuthorDate: Sun Oct 18 16:15:22 2026 -0300

    arch/mips/pic32mz: add program flash storage for the PIC32MZ-W1.
    
    Add PIC32MZ_PROGMEM, which exposes the last PIC32MZ_PROGMEM_NPAGES pages
    of the 1 MB program flash through the progmem interface, so that
    MTD_PROGMEM makes an MTD device of them.  It is the place to keep data
    that must survive a reset, such as a configuration, in a chip with no
    other non-volatile memory.
    
    The flash controller (NVM) erases a 4 KB page and programs a 1 KB row at
    a time, from a buffer that the driver flushes from the cache.  The data
    is read through the uncached window and the lines of the cached window
    are invalidated after each operation, for the users of
    BIOC_XIPBASE.  Word programming is not used because it does not write
    the ECC.
    
    The program image must not reach the pages: the build defines
    PIC32MZ_PROGMEM_START, where they begin, for the linker script of the
    board to check.
    
    Tested on an EV49N51A (see the next commit): erasing and programming
    the whole area and reading it back through the MTD and through the
    cached window, 16 rewrites of the 8 KB under a ping flood (600 of 600
    answered), and the data across a reset.
    
    Assisted-by: Claude Code:claude-sonnet-5-5
    Signed-off-by: Daniel P. Carvalho <[email protected]>
---
 arch/mips/src/pic32mz/Kconfig                      |  25 ++
 arch/mips/src/pic32mz/Make.defs                    |   9 +
 .../src/pic32mz/hardware/pic32mzw1_memorymap.h     |   1 +
 arch/mips/src/pic32mz/hardware/pic32mzw1_nvm.h     |  79 ++++
 arch/mips/src/pic32mz/pic32mz_progmem.c            | 420 +++++++++++++++++++++
 5 files changed, 534 insertions(+)

diff --git a/arch/mips/src/pic32mz/Kconfig b/arch/mips/src/pic32mz/Kconfig
index cc2a5aeaf5c..cb7b512dbd1 100644
--- a/arch/mips/src/pic32mz/Kconfig
+++ b/arch/mips/src/pic32mz/Kconfig
@@ -248,6 +248,31 @@ config PIC32MZ_WDT_BASE_US
 
 endif # PIC32MZ_WDT
 
+config PIC32MZ_PROGMEM
+       bool "Program flash storage (NVM)"
+       default n
+       depends on ARCH_CHIP_PIC32MZW1
+       select ARCH_HAVE_PROGMEM
+       select ARCH_HAVE_PROGMEM_READ
+       ---help---
+               Use the last pages of the program flash to store data, through 
the
+               progmem interface (MTD_PROGMEM makes an MTD device of it).  The
+               pages are erased and programmed by the flash controller (NVM), 
so
+               the program image must not reach them: the linker script of the
+               board has to stop the program flash PIC32MZ_PROGMEM_NPAGES pages
+               before its end.
+
+if PIC32MZ_PROGMEM
+
+config PIC32MZ_PROGMEM_NPAGES
+       int "Number of 4 KB pages"
+       default 2
+       range 1 64
+       ---help---
+               Pages reserved at the end of the 1 MB program flash.
+
+endif # PIC32MZ_PROGMEM
+
 config PIC32MZ_T2
        bool "Timer 2 (T2)"
        default n
diff --git a/arch/mips/src/pic32mz/Make.defs b/arch/mips/src/pic32mz/Make.defs
index eb198a483c7..1897eed4af5 100644
--- a/arch/mips/src/pic32mz/Make.defs
+++ b/arch/mips/src/pic32mz/Make.defs
@@ -171,6 +171,15 @@ ifeq ($(CONFIG_PIC32MZ_WDT),y)
 CHIP_CSRCS += pic32mz_wdt.c
 endif
 
+ifeq ($(CONFIG_PIC32MZ_PROGMEM),y)
+CHIP_CSRCS += pic32mz_progmem.c
+
+# The pages at the end of the 1 MB program flash (0x90000000) are not
+# part of the program image: tell the linker script where they start.
+
+LDFLAGS += --defsym=PIC32MZ_PROGMEM_START=$(shell printf '0x%x' $$((0x90100000 
- $(CONFIG_PIC32MZ_PROGMEM_NPAGES) * 4096)))
+endif
+
 ifeq ($(CONFIG_PIC32MZ_FREERUN),y)
 CHIP_CSRCS += pic32mz_freerun.c
 endif
diff --git a/arch/mips/src/pic32mz/hardware/pic32mzw1_memorymap.h 
b/arch/mips/src/pic32mz/hardware/pic32mzw1_memorymap.h
index 3c4a2e12626..bd4d3ef2c27 100644
--- a/arch/mips/src/pic32mz/hardware/pic32mzw1_memorymap.h
+++ b/arch/mips/src/pic32mz/hardware/pic32mzw1_memorymap.h
@@ -102,6 +102,7 @@
  */
 
 #define PIC32MZ_CONFIG_K1BASE       (PIC32MZ_SFR_K1BASE + 0x00000000) /* 
CFGCONx, SYSKEY, PMDx */
+#define PIC32MZ_NVM_K1BASE          (PIC32MZ_SFR_K1BASE + 0x00000600) /* Flash 
controller (NVM) */
 #define PIC32MZ_WDT_K1BASE          (PIC32MZ_SFR_K1BASE + 0x00000800) /* 
Watchdog Timer */
 #define PIC32MZ_DMT_K1BASE          (PIC32MZ_SFR_K1BASE + 0x00000a00) /* 
Deadman Timer */
 #define PIC32MZ_OSC_K1BASE          (PIC32MZ_SFR_K1BASE + 0x00001200) /* 
Oscillator, RCON, RSWRST */
diff --git a/arch/mips/src/pic32mz/hardware/pic32mzw1_nvm.h 
b/arch/mips/src/pic32mz/hardware/pic32mzw1_nvm.h
new file mode 100644
index 00000000000..294358b8a8e
--- /dev/null
+++ b/arch/mips/src/pic32mz/hardware/pic32mzw1_nvm.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+ * arch/mips/src/pic32mz/hardware/pic32mzw1_nvm.h
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_MIPS_SRC_PIC32MZ_HARDWARE_PIC32MZW1_NVM_H
+#define __ARCH_MIPS_SRC_PIC32MZ_HARDWARE_PIC32MZW1_NVM_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include "pic32mz_memorymap.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Register Offsets *********************************************************/
+
+#define PIC32MZ_NVM_CON_OFFSET      0x0000 /* Programming control */
+#define PIC32MZ_NVM_CONCLR_OFFSET   0x0004 /* Programming control clear */
+#define PIC32MZ_NVM_CONSET_OFFSET   0x0008 /* Programming control set */
+#define PIC32MZ_NVM_CONINV_OFFSET   0x000c /* Programming control invert */
+#define PIC32MZ_NVM_KEY_OFFSET      0x0020 /* Unlock register */
+#define PIC32MZ_NVM_ADDR_OFFSET     0x0030 /* Flash address (physical) */
+#define PIC32MZ_NVM_SRCADDR_OFFSET  0x00c0 /* Row source address (physical) */
+
+/* Register Addresses *******************************************************/
+
+#define PIC32MZ_NVM_CON             (PIC32MZ_NVM_K1BASE + 
PIC32MZ_NVM_CON_OFFSET)
+#define PIC32MZ_NVM_CONCLR          (PIC32MZ_NVM_K1BASE + 
PIC32MZ_NVM_CONCLR_OFFSET)
+#define PIC32MZ_NVM_CONSET          (PIC32MZ_NVM_K1BASE + 
PIC32MZ_NVM_CONSET_OFFSET)
+#define PIC32MZ_NVM_CONINV          (PIC32MZ_NVM_K1BASE + 
PIC32MZ_NVM_CONINV_OFFSET)
+#define PIC32MZ_NVM_KEY             (PIC32MZ_NVM_K1BASE + 
PIC32MZ_NVM_KEY_OFFSET)
+#define PIC32MZ_NVM_ADDR            (PIC32MZ_NVM_K1BASE + 
PIC32MZ_NVM_ADDR_OFFSET)
+#define PIC32MZ_NVM_SRCADDR         (PIC32MZ_NVM_K1BASE + 
PIC32MZ_NVM_SRCADDR_OFFSET)
+
+/* Programming Control Register Bit Definitions *****************************/
+
+#define NVM_CON_NVMOP_SHIFT         (0)       /* Bits 0-3: NVM operation */
+#define NVM_CON_NVMOP_MASK          (15 << NVM_CON_NVMOP_SHIFT)
+#  define NVM_CON_NVMOP_NOP         (0 << NVM_CON_NVMOP_SHIFT) /* No operation 
*/
+#  define NVM_CON_NVMOP_WORD        (1 << NVM_CON_NVMOP_SHIFT) /* Word program 
*/
+#  define NVM_CON_NVMOP_QUADWORD    (2 << NVM_CON_NVMOP_SHIFT) /* Quad word 
(256 bit) program */
+#  define NVM_CON_NVMOP_ROW         (3 << NVM_CON_NVMOP_SHIFT) /* Row program 
*/
+#  define NVM_CON_NVMOP_PAGEERASE   (4 << NVM_CON_NVMOP_SHIFT) /* Page erase */
+
+#define NVM_CON_HTDPGM              (1 << 8)  /* Bit 8:  High temperature 
detected */
+#define NVM_CON_LVDERR              (1 << 12) /* Bit 12: Low voltage detected 
*/
+#define NVM_CON_WRERR               (1 << 13) /* Bit 13: Write error */
+#define NVM_CON_WREN                (1 << 14) /* Bit 14: Write enable */
+#define NVM_CON_WR                  (1 << 15) /* Bit 15: Start (HW clears when 
done) */
+
+/* Unlock sequence written to NVMKEY, after a zero */
+
+#define NVM_KEY1                    0xaa996655
+#define NVM_KEY2                    0x556699aa
+
+#endif /* __ARCH_MIPS_SRC_PIC32MZ_HARDWARE_PIC32MZW1_NVM_H */
diff --git a/arch/mips/src/pic32mz/pic32mz_progmem.c 
b/arch/mips/src/pic32mz/pic32mz_progmem.c
new file mode 100644
index 00000000000..845de3e7166
--- /dev/null
+++ b/arch/mips/src/pic32mz/pic32mz_progmem.c
@@ -0,0 +1,420 @@
+/****************************************************************************
+ * arch/mips/src/pic32mz/pic32mz_progmem.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/* Program flash storage for the PIC32MZ-W1.
+ *
+ * The last CONFIG_PIC32MZ_PROGMEM_NPAGES pages of the program flash are
+ * kept out of the program image (see the linker script of the board) and
+ * exposed through the progmem interface, which drivers/mtd/mtd_progmem.c
+ * turns into an MTD device.
+ *
+ * Facts used below, with their source:
+ *   [DS]  DS70005425 (PIC32MZ-W1 / WFI32E01 data sheet), Flash Program
+ *         Memory chapter: 1 MB of flash, 4 KB pages, 1 KB rows, the
+ *         NVMCON/NVMADDR/NVMSRCADDR/NVMKEY registers, the NVMOP codes,
+ *         ECC written by the row and quad word operations.
+ *   [DFP] PIC32MZ-W_DFP header pwfi32e01.h: register addresses and bits.
+ *   [EX]  Microchip's Harmony NVM peripheral library (the example code of
+ *         the reference design): the unlock sequence written to NVMKEY.
+ */
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/cache.h>
+#include <nuttx/irq.h>
+#include <nuttx/mutex.h>
+#include <nuttx/progmem.h>
+
+#include "mips_internal.h"
+
+#include "hardware/pic32mz_memorymap.h"
+#include "hardware/pic32mzw1_nvm.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define PROGMEM_FLASHSIZE   (1024 * 1024)  /* [DS] Program flash size */
+#define PROGMEM_PAGESIZE    4096           /* [DS] Erase size */
+#define PROGMEM_ROWSIZE     1024           /* [DS] Program size */
+#define PROGMEM_ERASED      0xff
+
+#define PROGMEM_NPAGES      CONFIG_PIC32MZ_PROGMEM_NPAGES
+#define PROGMEM_SIZE        (PROGMEM_NPAGES * PROGMEM_PAGESIZE)
+#define PROGMEM_NROWS       (PROGMEM_SIZE / PROGMEM_ROWSIZE)
+
+/* Start of the area, as seen through the cached and uncached windows, and
+ * its physical address.  The flash is always read through the uncached
+ * window, since the cache is not aware of the operations of the NVM.
+ */
+
+#define PROGMEM_OFFSET      (PROGMEM_FLASHSIZE - PROGMEM_SIZE)
+#define PROGMEM_K0START     (PIC32MZ_PROGFLASH_K0BASE + PROGMEM_OFFSET)
+#define PROGMEM_K1START     (PIC32MZ_PROGFLASH_K1BASE + PROGMEM_OFFSET)
+#define PROGMEM_PSTART      (PIC32MZ_PROGFLASH_PBASE + PROGMEM_OFFSET)
+
+#define PHYS_ADDR(va)       ((uint32_t)(va) & 0x1fffffff)
+
+/* A flash operation takes a few milliseconds */
+
+#define PROGMEM_TIMEOUT_US  200000
+#define PROGMEM_POLL_US     20
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static mutex_t g_progmem_lock = NXMUTEX_INITIALIZER;
+
+/* The source of a row program operation is a physical address read by the
+ * NVM itself: use a buffer that is aligned and flushed from the cache,
+ * whatever the buffer of the caller is.
+ */
+
+static uint8_t g_rowbuf[PROGMEM_ROWSIZE] aligned_data(4);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: progmem_offset
+ *
+ * Description:
+ *   Convert an address, in the cached window or relative to the start of the
+ *   area, to an offset in the area.
+ *
+ * Returned Value:
+ *   The offset, or a negated errno value if the address is not in the area.
+ *
+ ****************************************************************************/
+
+static ssize_t progmem_offset(size_t addr)
+{
+  if (addr >= PROGMEM_K0START && addr < PROGMEM_K0START + PROGMEM_SIZE)
+    {
+      return addr - PROGMEM_K0START;
+    }
+
+  if (addr < PROGMEM_SIZE)
+    {
+      return addr;
+    }
+
+  return -EFAULT;
+}
+
+/****************************************************************************
+ * Name: progmem_invalidate
+ *
+ * Description:
+ *   Drop from the data cache the lines of a range of the area that the NVM
+ *   changed, for those that read it through the cached window.
+ *
+ ****************************************************************************/
+
+static void progmem_invalidate(size_t offset, size_t size)
+{
+  up_invalidate_dcache(PROGMEM_K0START + offset,
+                       PROGMEM_K0START + offset + size);
+}
+
+/****************************************************************************
+ * Name: progmem_operation
+ *
+ * Description:
+ *   Run one operation of the NVM, with the unlock sequence, and wait for
+ *   its end.
+ *
+ ****************************************************************************/
+
+static int progmem_operation(uint32_t op, uint32_t paddr)
+{
+  irqstate_t flags;
+  uint32_t regval;
+  int timeout;
+
+  /* NVMOP can only be written while WREN is clear, and the unlock sequence
+   * must not be interrupted.
+   */
+
+  flags = up_irq_save();
+
+  putreg32(paddr, PIC32MZ_NVM_ADDR);
+  putreg32(NVM_CON_WREN, PIC32MZ_NVM_CONCLR);
+  putreg32(NVM_CON_NVMOP_MASK, PIC32MZ_NVM_CONCLR);
+  putreg32(op, PIC32MZ_NVM_CONSET);
+  putreg32(NVM_CON_WREN, PIC32MZ_NVM_CONSET);
+
+  putreg32(0, PIC32MZ_NVM_KEY);
+  putreg32(NVM_KEY1, PIC32MZ_NVM_KEY);
+  putreg32(NVM_KEY2, PIC32MZ_NVM_KEY);
+  putreg32(NVM_CON_WR, PIC32MZ_NVM_CONSET);
+
+  up_irq_restore(flags);
+
+  /* The hardware clears WR when the operation is done */
+
+  for (timeout = PROGMEM_TIMEOUT_US; timeout > 0; timeout -= PROGMEM_POLL_US)
+    {
+      if ((getreg32(PIC32MZ_NVM_CON) & NVM_CON_WR) == 0)
+        {
+          break;
+        }
+
+      up_udelay(PROGMEM_POLL_US);
+    }
+
+  regval = getreg32(PIC32MZ_NVM_CON);
+  putreg32(NVM_CON_WREN, PIC32MZ_NVM_CONCLR);
+
+  if (timeout <= 0 || (regval & (NVM_CON_WRERR | NVM_CON_LVDERR)) != 0)
+    {
+      /* The errors are cleared by a no operation command */
+
+      if (op != NVM_CON_NVMOP_NOP)
+        {
+          progmem_operation(NVM_CON_NVMOP_NOP, paddr);
+        }
+
+      return -EIO;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_progmem_neraseblocks
+ ****************************************************************************/
+
+size_t up_progmem_neraseblocks(void)
+{
+  return PROGMEM_NPAGES;
+}
+
+/****************************************************************************
+ * Name: up_progmem_isuniform
+ ****************************************************************************/
+
+bool up_progmem_isuniform(void)
+{
+  return false;
+}
+
+/****************************************************************************
+ * Name: up_progmem_pagesize
+ *
+ * Description:
+ *   The read/write page is the row of the flash.
+ *
+ ****************************************************************************/
+
+size_t up_progmem_pagesize(size_t page)
+{
+  return page < PROGMEM_NROWS ? PROGMEM_ROWSIZE : 0;
+}
+
+/****************************************************************************
+ * Name: up_progmem_erasesize
+ ****************************************************************************/
+
+size_t up_progmem_erasesize(size_t block)
+{
+  return block < PROGMEM_NPAGES ? PROGMEM_PAGESIZE : 0;
+}
+
+/****************************************************************************
+ * Name: up_progmem_getpage
+ ****************************************************************************/
+
+ssize_t up_progmem_getpage(size_t addr)
+{
+  ssize_t offset = progmem_offset(addr);
+
+  return offset < 0 ? offset : offset / PROGMEM_ROWSIZE;
+}
+
+/****************************************************************************
+ * Name: up_progmem_getaddress
+ ****************************************************************************/
+
+size_t up_progmem_getaddress(size_t page)
+{
+  return page < PROGMEM_NROWS ?
+         PROGMEM_K0START + page * PROGMEM_ROWSIZE : SIZE_MAX;
+}
+
+/****************************************************************************
+ * Name: up_progmem_eraseblock
+ ****************************************************************************/
+
+ssize_t up_progmem_eraseblock(size_t block)
+{
+  int ret;
+
+  if (block >= PROGMEM_NPAGES)
+    {
+      return -EFAULT;
+    }
+
+  ret = nxmutex_lock(&g_progmem_lock);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  ret = progmem_operation(NVM_CON_NVMOP_PAGEERASE,
+                          PROGMEM_PSTART + block * PROGMEM_PAGESIZE);
+  progmem_invalidate(block * PROGMEM_PAGESIZE, PROGMEM_PAGESIZE);
+
+  nxmutex_unlock(&g_progmem_lock);
+  return ret < 0 ? ret : PROGMEM_PAGESIZE;
+}
+
+/****************************************************************************
+ * Name: up_progmem_ispageerased
+ ****************************************************************************/
+
+ssize_t up_progmem_ispageerased(size_t page)
+{
+  const uint8_t *row;
+  ssize_t nwritten = 0;
+  size_t i;
+
+  if (page >= PROGMEM_NROWS)
+    {
+      return -EFAULT;
+    }
+
+  row = (const uint8_t *)(PROGMEM_K1START + page * PROGMEM_ROWSIZE);
+  for (i = 0; i < PROGMEM_ROWSIZE; i++)
+    {
+      if (row[i] != PROGMEM_ERASED)
+        {
+          nwritten++;
+        }
+    }
+
+  return nwritten;
+}
+
+/****************************************************************************
+ * Name: up_progmem_write
+ *
+ * Description:
+ *   Program whole rows of an erased area.
+ *
+ ****************************************************************************/
+
+ssize_t up_progmem_write(size_t addr, const void *buf, size_t count)
+{
+  const uint8_t *src = buf;
+  ssize_t offset;
+  size_t done;
+  int ret;
+
+  offset = progmem_offset(addr);
+  if (offset < 0)
+    {
+      return offset;
+    }
+
+  if ((offset % PROGMEM_ROWSIZE) != 0 || (count % PROGMEM_ROWSIZE) != 0)
+    {
+      return -EINVAL;
+    }
+
+  if (offset + count > PROGMEM_SIZE)
+    {
+      return -EFAULT;
+    }
+
+  ret = nxmutex_lock(&g_progmem_lock);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  for (done = 0; done < count; done += PROGMEM_ROWSIZE)
+    {
+      memcpy(g_rowbuf, src + done, PROGMEM_ROWSIZE);
+      up_flush_dcache((uintptr_t)g_rowbuf,
+                      (uintptr_t)g_rowbuf + PROGMEM_ROWSIZE);
+
+      putreg32(PHYS_ADDR(g_rowbuf), PIC32MZ_NVM_SRCADDR);
+      ret = progmem_operation(NVM_CON_NVMOP_ROW,
+                              PROGMEM_PSTART + offset + done);
+      if (ret < 0)
+        {
+          break;
+        }
+    }
+
+  progmem_invalidate(offset, count);
+
+  nxmutex_unlock(&g_progmem_lock);
+  return ret < 0 ? ret : (ssize_t)count;
+}
+
+/****************************************************************************
+ * Name: up_progmem_read
+ ****************************************************************************/
+
+ssize_t up_progmem_read(size_t addr, void *buf, size_t count)
+{
+  ssize_t offset = progmem_offset(addr);
+
+  if (offset < 0)
+    {
+      return offset;
+    }
+
+  if (offset + count > PROGMEM_SIZE)
+    {
+      return -EFAULT;
+    }
+
+  memcpy(buf, (const void *)(PROGMEM_K1START + offset), count);
+  return count;
+}
+
+/****************************************************************************
+ * Name: up_progmem_erasestate
+ ****************************************************************************/
+
+uint8_t up_progmem_erasestate(void)
+{
+  return PROGMEM_ERASED;
+}

Reply via email to