diff --git a/arch/Kconfig b/arch/Kconfig index a0fa9402bb..c66100a98c 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -303,6 +303,11 @@ config ARCH_HAVE_PROGMEM bool default n +config ARCH_HAVE_PROGMEM_READ + bool + default n + depends on ARCH_HAVE_PROGMEM + config ARCH_HAVE_RESET bool default n diff --git a/drivers/mtd/mtd_progmem.c b/drivers/mtd/mtd_progmem.c index ab722ab5c7..cb489f3884 100644 --- a/drivers/mtd/mtd_progmem.c +++ b/drivers/mtd/mtd_progmem.c @@ -200,6 +200,13 @@ static ssize_t progmem_bread(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, FAR uint8_t *buffer) { FAR struct progmem_dev_s *priv = (FAR struct progmem_dev_s *)dev; +#ifdef CONFIG_ARCH_HAVE_PROGMEM_READ + ssize_t result; + + result = up_progmem_read(up_progmem_getaddress(startblock), buffer, + nblocks << priv->blkshift); + return result < 0 ? result : nblocks; +#else FAR const uint8_t *src; /* Read the specified blocks into the provided user buffer and return @@ -210,6 +217,7 @@ static ssize_t progmem_bread(FAR struct mtd_dev_s *dev, off_t startblock, src = (FAR const uint8_t *)up_progmem_getaddress(startblock); memcpy(buffer, src, nblocks << priv->blkshift); return nblocks; +#endif } /**************************************************************************** @@ -248,19 +256,26 @@ static ssize_t progmem_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes, FAR uint8_t *buffer) { FAR struct progmem_dev_s *priv = (FAR struct progmem_dev_s *)dev; + off_t startblock = offset >> priv->blkshift; +#ifdef CONFIG_ARCH_HAVE_PROGMEM_READ + ssize_t result; + + result = up_progmem_read(up_progmem_getaddress(startblock) + + (offset & ((1 << priv->blkshift) - 1)), buffer, nbytes); + return result < 0 ? result : nbytes; +#else FAR const uint8_t *src; - off_t startblock; /* Read the specified bytes into the provided user buffer and return * status (The positive, number of bytes actually read or a negated * errno) */ - startblock = offset >> priv->blkshift; src = (FAR const uint8_t *)up_progmem_getaddress(startblock) + (offset & ((1 << priv->blkshift) - 1)); memcpy(buffer, src, nbytes); return nbytes; +#endif } /**************************************************************************** diff --git a/include/nuttx/progmem.h b/include/nuttx/progmem.h index 0a7f99cfdd..7aa55bfd7c 100644 --- a/include/nuttx/progmem.h +++ b/include/nuttx/progmem.h @@ -216,6 +216,39 @@ ssize_t up_progmem_ispageerased(size_t page); ssize_t up_progmem_write(size_t addr, FAR const void *buf, size_t count); +/**************************************************************************** + * Name: up_progmem_read + * + * Description: + * Read data at given address + * + * Note: this function is not limited to single page and nor it requires + * the address be aligned inside the page boundaries. + * + * Input Parameters: + * addr - Address with or without flash offset + * (absolute or aligned to page0) + * buf - Pointer to buffer + * count - Number of bytes to read + * + * Returned Value: + * Bytes read or negative value on error. The following errors are + * reported (errno is not set!) + * + * EINVAL: If count is not aligned with the flash boundaries (i.e. + * some MCU's require per half-word or even word access) + * EFAULT: On invalid address + * EIO: On unsuccessful read + * EACCES: Insufficient permissions (read/write protected) + * EPERM: If operation is not permitted due to some other constraints + * (i.e. some internal block is not running etc.) + * + ****************************************************************************/ + +#ifdef CONFIG_ARCH_HAVE_PROGMEM_READ +ssize_t up_progmem_read(size_t addr, FAR void *buf, size_t count); +#endif + #undef EXTERN #if defined(__cplusplus) }