diff --git a/drivers/flash/CMakeLists.txt b/drivers/flash/CMakeLists.txt index b61b132454755..842f54fad9a9a 100644 --- a/drivers/flash/CMakeLists.txt +++ b/drivers/flash/CMakeLists.txt @@ -13,7 +13,6 @@ zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_NRF soc_flash_nrf.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_NRF_RADIO_SYNC_TICKER soc_flash_nrf_ticker.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_MCUX soc_flash_mcux.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_LPC soc_flash_lpc.c) -zephyr_library_sources_ifdef(CONFIG_FLASH_PAGE_LAYOUT flash_page_layout.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE flash_handlers.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_SAM0 flash_sam0.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_SAM flash_sam.c) @@ -27,6 +26,10 @@ zephyr_library_sources_ifdef(CONFIG_FLASH_MCUX_FLEXSPI_NOR flash_mcux_flexspi_no zephyr_library_sources_ifdef(CONFIG_FLASH_MCUX_FLEXSPI_HYPERFLASH flash_mcux_flexspi_hyperflash.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_ESP32 flash_esp32.c) +if (CONFIG_FLASH_PAGE_LAYOUT OR CONFIG_FLASH_PAGE_LAYOUT_WITHOUT_API_PAGE_LAYOUT) + zephyr_library_sources(flash_page_layout.c) +endif() + if(CONFIG_FLASH_MCUX_FLEXSPI_XIP) dt_chosen(chosen_flash PROPERTY "zephyr,flash") dt_prop(compat_flash PATH ${chosen_flash} PROPERTY compatible) diff --git a/drivers/flash/Kconfig b/drivers/flash/Kconfig index 9bf12889fb0e0..7a32f91151b1d 100644 --- a/drivers/flash/Kconfig +++ b/drivers/flash/Kconfig @@ -53,7 +53,7 @@ config FLASH_SHELL config FLASH_PAGE_LAYOUT bool "API for retrieving the layout of pages" - depends on FLASH_HAS_PAGE_LAYOUT + depends on FLASH_HAS_PAGE_LAYOUT && !FLASH_PAGE_LAYOUT_WITHOUT_API_PAGE_LAYOUT default y help Enables API for retrieving the layout of flash memory pages. @@ -66,6 +66,13 @@ config FLASH_INIT_PRIORITY priority is used unless the driver implementation has its own initialization priority +config FLASH_PAGE_LAYOUT_WITHOUT_API_PAGE_LAYOUT + bool "Use new API to emulate page_layout API call" + help + Enables support for flash_page_get_info_by_idx, flash_page_get_info_by_offs and + flash_page_foreach without page_layout Flash API call, with use of the + flash_get_page_info, flash_get_page_count and flash_get_size. + source "drivers/flash/Kconfig.b91" source "drivers/flash/Kconfig.cc13xx_cc26xx" diff --git a/drivers/flash/flash_esp32.c b/drivers/flash/flash_esp32.c index d8492834143c7..d2ce23e6fcc96 100644 --- a/drivers/flash/flash_esp32.c +++ b/drivers/flash/flash_esp32.c @@ -64,6 +64,7 @@ struct flash_esp32_dev_data { static const struct flash_parameters flash_esp32_parameters = { .write_block_size = FLASH_WRITE_BLK_SZ, .erase_value = 0xff, + .flags = 0, }; static inline void flash_esp32_sem_take(const struct device *dev) @@ -142,6 +143,35 @@ flash_esp32_get_parameters(const struct device *dev) return &flash_esp32_parameters; } +static int +flash_esp32_get_page_info(const struct device *dev, off_t offset, struct flash_page_info *fpi) +{ + if (offset < 0 || offset >= DT_REG_SIZE(SOC_NV_FLASH_NODE)) { + return -EINVAL; + } + + fpi->offset = offset & ~(FLASH_ERASE_BLK_SZ - 1); + fpi->size = FLASH_ERASE_BLK_SZ; + + return 0; +} + +static ssize_t +flash_esp32_get_page_count(const struct device *dev) +{ + ARG_UNUSED(dev); + + return DT_REG_SIZE(SOC_NV_FLASH_NODE) / FLASH_ERASE_BLK_SZ; +} + +static ssize_t +flash_esp32_get_size(const struct device *dev) +{ + ARG_UNUSED(dev); + + return DT_REG_SIZE(SOC_NV_FLASH_NODE); +} + static int flash_esp32_init(const struct device *dev) { struct flash_esp32_dev_data *const dev_data = dev->data; @@ -156,6 +186,9 @@ static const struct flash_driver_api flash_esp32_driver_api = { .write = flash_esp32_write, .erase = flash_esp32_erase, .get_parameters = flash_esp32_get_parameters, + .get_page_info = flash_esp32_get_page_info, + .get_page_count = flash_esp32_get_page_count, + .get_size = flash_esp32_get_size, #ifdef CONFIG_FLASH_PAGE_LAYOUT .page_layout = flash_esp32_page_layout, #endif diff --git a/drivers/flash/flash_gecko.c b/drivers/flash/flash_gecko.c index aa3be96960f6c..09bceb0c2bcc8 100644 --- a/drivers/flash/flash_gecko.c +++ b/drivers/flash/flash_gecko.c @@ -191,6 +191,37 @@ flash_gecko_get_parameters(const struct device *dev) return &flash_gecko_parameters; } +static int +flash_gecko_get_page_info(const struct device *dev, off_t offset, struct flash_page_info *fpi) +{ + ARG_UNUSED(dev); + + if (offset < 0 || offset >= DT_REG_SIZE(SOC_NV_FLASH_NODE)) { + return -EINVAL; + } + + fpi->offset = offset & ~(DT_PROP(SOC_NV_FLASH_NODE, erase_block_size) - 1); + fpi->size = DT_PROP(SOC_NV_FLASH_NODE, erase_block_size); + + return 0; +} + +static ssize_t +flash_gecko_get_page_count(const struct device *dev) +{ + ARG_UNUSED(dev); + + return DT_REG_SIZE(SOC_NV_FLASH_NODE) / DT_PROP(SOC_NV_FLASH_NODE, erase_block_size); +} + +static ssize_t +flash_gecko_get_size(const struct device *dev) +{ + ARG_UNUSED(dev); + + return DT_PROP(SOC_NV_FLASH_NODE, erase_block_size); +} + static int flash_gecko_init(const struct device *dev) { struct flash_gecko_data *const dev_data = dev->data; @@ -212,6 +243,9 @@ static const struct flash_driver_api flash_gecko_driver_api = { .write = flash_gecko_write, .erase = flash_gecko_erase, .get_parameters = flash_gecko_get_parameters, + .get_page_info = flash_gecko_get_page_info, + .get_page_count = flash_gecko_get_page_count, + .get_size = flash_gecko_get_size, #ifdef CONFIG_FLASH_PAGE_LAYOUT .page_layout = flash_gecko_page_layout, #endif diff --git a/drivers/flash/flash_handlers.c b/drivers/flash/flash_handlers.c index 6ffb6c7fe4293..3dda2d03039d9 100644 --- a/drivers/flash/flash_handlers.c +++ b/drivers/flash/flash_handlers.c @@ -28,6 +28,30 @@ static inline int z_vrfy_flash_write(const struct device *dev, off_t offset, } #include +static inline int z_vrfy_flash_get_page_info(const struct device *dev, off_t offset, + struct flash_page_info *fpi) +{ + Z_OOPS(Z_SYSCALL_DRIVER_FLASH(dev, get_page_info)); + Z_OOPS(Z_SYSCALL_MEMORY_WRITE(fpi, sizeof(*fpi))); + return z_impl_flash_get_page_info((const struct device *)dev, offset, + (struct flash_page_info *)fpi); +} +#include + +static ssize_t z_vrfy_flash_get_page_count(const struct device *dev) +{ + Z_OOPS(Z_SYSCALL_DRIVER_FLASH(dev, get_page_count)); + return z_impl_flash_get_page_count((const struct device *)dev); +} +#include + +static ssize_t z_vrfy_flash_get_size(const struct device *dev) +{ + Z_OOPS(Z_SYSCALL_DRIVER_FLASH(dev, get_size)); + return z_impl_flash_get_size((const struct device *)dev); +} +#include + static inline size_t z_vrfy_flash_get_write_block_size(const struct device *dev) { Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_FLASH)); @@ -67,13 +91,6 @@ static inline int z_vrfy_flash_get_page_info_by_idx(const struct device *dev, } #include -static inline size_t z_vrfy_flash_get_page_count(const struct device *dev) -{ - Z_OOPS(Z_SYSCALL_DRIVER_FLASH(dev, page_layout)); - return z_impl_flash_get_page_count((const struct device *)dev); -} -#include - #endif /* CONFIG_FLASH_PAGE_LAYOUT */ #ifdef CONFIG_FLASH_JESD216_API diff --git a/drivers/flash/flash_mcux_flexspi_mx25um51345g.c b/drivers/flash/flash_mcux_flexspi_mx25um51345g.c index 8c443a51a7b82..c64718c8317eb 100644 --- a/drivers/flash/flash_mcux_flexspi_mx25um51345g.c +++ b/drivers/flash/flash_mcux_flexspi_mx25um51345g.c @@ -488,6 +488,37 @@ static const struct flash_parameters *flash_flexspi_nor_get_parameters( return &data->flash_parameters; } +static int +flash_flexspi_nor_get_page_info(const struct device *dev, off_t offset, struct flash_page_info *fpi) +{ + const struct flash_flexspi_nor_config *config = dev->config; + + if (offset < 0 || offset > (config->layout.pages_count * SPI_NOR_SECTOR_SIZE)) { + return -EINVAL; + } + + fpi->offset = offset & ~(config->layout.pages_size - 1); + fpi->size = config->layout.pages_size; + + return 0; +} + +static ssize_t +flash_flexspi_nor_get_page_count(const struct device *dev) +{ + const struct flash_flexspi_nor_config *config = dev->config; + + return config->layout.pages_count; +} + +static ssize_t +flash_flexspi_nor_get_size(const struct device *dev) +{ + const struct flash_flexspi_nor_config *config = dev->config; + + return (config->layout.pages_count * config->layout.pages_size); +} + #if defined(CONFIG_FLASH_PAGE_LAYOUT) static void flash_flexspi_nor_pages_layout(const struct device *dev, const struct flash_pages_layout **layout, size_t *layout_size) @@ -544,6 +575,9 @@ static const struct flash_driver_api flash_flexspi_nor_api = { .write = flash_flexspi_nor_write, .read = flash_flexspi_nor_read, .get_parameters = flash_flexspi_nor_get_parameters, + .get_page_info = flash_flexspi_nor_get_page_info, + .get_page_count = flash_flexspi_nor_get_page_count, + .get_size = flash_flexspi_nor_get_size, #if defined(CONFIG_FLASH_PAGE_LAYOUT) .page_layout = flash_flexspi_nor_pages_layout, #endif @@ -595,6 +629,7 @@ static const struct flash_driver_api flash_flexspi_nor_api = { .flash_parameters = { \ .write_block_size = NOR_WRITE_SIZE, \ .erase_value = NOR_ERASE_VALUE, \ + .flags = 0, \ }, \ }; \ \ diff --git a/drivers/flash/flash_mcux_flexspi_nor.c b/drivers/flash/flash_mcux_flexspi_nor.c index 169558b1fa6cb..05f1e17d00e6c 100644 --- a/drivers/flash/flash_mcux_flexspi_nor.c +++ b/drivers/flash/flash_mcux_flexspi_nor.c @@ -454,6 +454,35 @@ static const struct flash_parameters *flash_flexspi_nor_get_parameters( return &data->flash_parameters; } +static int flash_flexspi_nor_get_page_info(const struct device *dev, off_t offset, + struct flash_page_info *fpi) +{ + const struct flash_flexspi_nor_config *config = dev->config; + + if (offset < 0 || offset >= (config->layout.pages_count * config->layout.pages_size)) { + return -EINVAL; + } + + fpi->offset = offset & ~(config->layout.pages_size - 1); + fpi->size = config->layout.pages_count; + + return 0; +} + +static ssize_t flash_flexspi_nor_get_page_count(const struct device *dev) +{ + const struct flash_flexspi_nor_config *config = dev->config; + + return config->layout.pages_count; +} + +static ssize_t flash_flexspi_nor_get_size(const struct device *dev) +{ + const struct flash_flexspi_nor_config *config = dev->config; + + return config->layout.pages_size; +} + #if defined(CONFIG_FLASH_PAGE_LAYOUT) static void flash_flexspi_nor_pages_layout(const struct device *dev, const struct flash_pages_layout **layout, size_t *layout_size) @@ -510,6 +539,9 @@ static const struct flash_driver_api flash_flexspi_nor_api = { .write = flash_flexspi_nor_write, .read = flash_flexspi_nor_read, .get_parameters = flash_flexspi_nor_get_parameters, + .get_page_info = flash_flexspi_nor_get_page_info, + .get_page_count = flash_flexspi_nor_get_page_count, + .get_size = flash_flexspi_nor_get_size, #if defined(CONFIG_FLASH_PAGE_LAYOUT) .page_layout = flash_flexspi_nor_pages_layout, #endif @@ -561,6 +593,7 @@ static const struct flash_driver_api flash_flexspi_nor_api = { .flash_parameters = { \ .write_block_size = NOR_WRITE_SIZE, \ .erase_value = NOR_ERASE_VALUE, \ + .flags = 0, \ }, \ }; \ \ diff --git a/drivers/flash/flash_page_layout.c b/drivers/flash/flash_page_layout.c index 266957ec91216..492c10ec8f365 100644 --- a/drivers/flash/flash_page_layout.c +++ b/drivers/flash/flash_page_layout.c @@ -1,12 +1,14 @@ /* - * Copyright (c) 2017 Nordic Semiconductor ASA + * Copyright (c) 2017-2021 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ #include -static int flash_get_page_info(const struct device *dev, off_t offs, +#if !defined(CONFIG_FLASH_PAGE_LAYOUT_WITHOUT_API_PAGE_LAYOUT) + +static int flash_get_page_info_non_syscall(const struct device *dev, off_t offs, uint32_t index, struct flash_pages_info *info) { const struct flash_driver_api *api = dev->api; @@ -43,32 +45,137 @@ static int flash_get_page_info(const struct device *dev, off_t offs, int z_impl_flash_get_page_info_by_offs(const struct device *dev, off_t offs, struct flash_pages_info *info) { - return flash_get_page_info(dev, offs, 0U, info); + return flash_get_page_info_non_syscall(dev, offs, 0U, info); } int z_impl_flash_get_page_info_by_idx(const struct device *dev, uint32_t page_index, struct flash_pages_info *info) { - return flash_get_page_info(dev, 0, page_index, info); + return flash_get_page_info_non_syscall(dev, 0, page_index, info); } -size_t z_impl_flash_get_page_count(const struct device *dev) +#else + +int z_impl_flash_get_page_info_by_offs(const struct device *dev, off_t offs, + struct flash_pages_info *info) { const struct flash_driver_api *api = dev->api; - const struct flash_pages_layout *layout; - size_t layout_size; - size_t count = 0; + const struct flash_parameters *fparam = api->get_parameters(dev); + struct flash_page_info fpi; + int rc = -EINVAL; - api->page_layout(dev, &layout, &layout_size); + rc = api->get_page_info(dev, offs, &fpi); - while (layout_size--) { - count += layout->pages_count; - layout++; + if (rc == 0) { + info->start_offset = fpi.offset; + info->size = fpi.size; + + if (!(fparam->flags & FPF_NON_UNIFORM_LAYOUT)) { + /* Uniform layout */ + info->index = offs / fpi.size; + } else { + /* Non-uniform layout requires to iterate through the pages */ + info->index = 0; + while (fpi.offset) { + ++info->index; + api->get_page_info(dev, fpi.offset - fpi.size, &fpi); + if (rc < 0) { + break; + } + } + } + } + + return rc; +} + +int z_impl_flash_get_page_info_by_idx(const struct device *dev, + uint32_t page_index, + struct flash_pages_info *info) +{ + const struct flash_driver_api *api = dev->api; + const struct flash_parameters *fparam = api->get_parameters(dev); + struct flash_page_info fpi; + int rc = -EINVAL; + ssize_t page_count = 0; + + + BUILD_ASSERT(sizeof(ssize_t) >= sizeof(uint32_t), + "The function will not work properly when uin32_t > ssize_t"); + /* + * Get total page count to check if request does not fall out of the flash range; + * in case of the non-uniform layout, the value will be also used to evaluate + * whether it is better to start index calculation from the beginning or the end + * of the flash. + */ + if ((ssize_t)page_index < 0) { + return -EINVAL; + } + + page_count = api->get_page_count(dev); + if (page_count < 0) { + return (int)page_count; + } + + rc = api->get_page_info(dev, 0, &fpi); + + if (rc >= 0 && page_count < (ssize_t)page_index) { + info->index = page_index; + + if (!(fparam->flags & FPF_NON_UNIFORM_LAYOUT)) { + /* Uniform layout */ + info->start_offset = (ssize_t)page_index * fpi.size; + info->size = fpi.size; + } else { + /* Non-uniform layout */ + ssize_t size = api->get_size(dev); + + if (size < 0) { + return size; + } + + if ((ssize_t)page_index > (page_count >> 1)) { + /* + * For an index that is above the half of the page count, + * go from the end of the flash. + */ + fpi.offset = size; + fpi.size = 1; + + while (rc >= 0 && page_count >= (ssize_t)page_index) { + --page_count; + rc = api->get_page_info(dev, fpi.offset - fpi.size, &fpi); + } + } else { + /* + * For an index that is below or equal to the half of + * the page count go from beginning of the flash. + */ + page_count = 0; + fpi.offset = 0; + fpi.size = 0; + + while (rc >= 0 && page_count != (ssize_t)page_index) { + ++page_count; + rc = api->get_page_info(dev, fpi.offset + fpi.size, &fpi); + if (rc < 0) { + break; + } + } + if (rc > 0) { + info->start_offset = fpi.offset; + info->size = fpi.size; + } + } + } } - return count; + return rc; } +#endif /* !defined(CONFIG_FLASH_PAGE_LAYOUT_WITHOUT_API_PAGE_LAYOUT) */ + +#if !defined(CONFIG_FLASH_PAGE_LAYOUT_WITHOUT_API_PAGE_LAYOUT) void flash_page_foreach(const struct device *dev, flash_page_cb cb, void *data) @@ -98,3 +205,46 @@ void flash_page_foreach(const struct device *dev, flash_page_cb cb, } } } + +#else + +void flash_page_foreach(const struct device *dev, flash_page_cb cb, + void *data) +{ + const struct flash_parameters *fparam = flash_get_parameters(dev); + struct flash_pages_info page_info; + size_t num_blocks; + struct flash_page_info fpi; + + num_blocks = flash_get_page_count(dev); + page_info.start_offset = 0; + page_info.index = 0; + + + if (!(fparam->flags & FPF_NON_UNIFORM_LAYOUT)) { + flash_get_page_info(dev, 0, &fpi); + page_info.size = fpi.size; + + while (page_info.index < num_blocks) { + if (!cb(&page_info, data)) { + return; + } + page_info.index++; + page_info.start_offset += fpi.size; + } + } else { + while (page_info.index < num_blocks) { + flash_get_page_info(dev, page_info.start_offset, &fpi); + + page_info.size = fpi.size; + + if (!cb(&page_info, data)) { + return; + } + + page_info.index++; + page_info.start_offset += fpi.size; + } + } +} +#endif /* !defined(CONFIG_FLASH_PAGE_LAYOUT_WITHOUT_API_PAGE_LAYOUT) */ diff --git a/drivers/flash/flash_sam.c b/drivers/flash/flash_sam.c index aceac8eca47f1..d19eca9eb73c5 100644 --- a/drivers/flash/flash_sam.c +++ b/drivers/flash/flash_sam.c @@ -49,6 +49,7 @@ struct flash_sam_dev_data { static const struct flash_parameters flash_sam_parameters = { .write_block_size = FLASH_WRITE_BLK_SZ, .erase_value = 0xff, + .flags = 0, }; static int flash_sam_write_protection(const struct device *dev, bool enable); @@ -364,6 +365,35 @@ flash_sam_get_parameters(const struct device *dev) return &flash_sam_parameters; } +static int flash_sam_get_page_info(const struct device *dev, off_t offset, + struct flash_page_info *fpi) +{ + ARG_UNUSED(dev); + + if (offset < 0 || offset >= DT_REG_SIZE(SOC_NV_FLASH_NODE)) { + return -EINVAL; + } + + fpi->offset = offset & ~(FLASH_ERASE_BLK_SZ - 1); + fpi->size = FLASH_ERASE_BLK_SZ; + + return 0; +} + +static ssize_t flash_sam_get_page_count(const struct device *dev) +{ + ARG_UNUSED(dev); + + return DT_REG_SIZE(SOC_NV_FLASH_NODE) / FLASH_ERASE_BLK_SZ; +} + +static ssize_t flash_sam_get_size(const struct device *dev) +{ + ARG_UNUSED(dev); + + return DT_REG_SIZE(SOC_NV_FLASH_NODE); +} + static int flash_sam_init(const struct device *dev) { struct flash_sam_dev_data *const data = dev->data; @@ -378,6 +408,9 @@ static const struct flash_driver_api flash_sam_api = { .write = flash_sam_write, .read = flash_sam_read, .get_parameters = flash_sam_get_parameters, + .get_page_info = flash_sam_get_page_info, + .get_page_count = flash_sam_get_page_count, + .get_size = flash_sam_get_size, #ifdef CONFIG_FLASH_PAGE_LAYOUT .page_layout = flash_sam_page_layout, #endif diff --git a/drivers/flash/flash_sam0.c b/drivers/flash/flash_sam0.c index fddf64ed00bc6..89acb0fa3f75a 100644 --- a/drivers/flash/flash_sam0.c +++ b/drivers/flash/flash_sam0.c @@ -439,6 +439,31 @@ flash_sam0_get_parameters(const struct device *dev) return &flash_sam0_parameters; } +static int +flash_sam0_get_page_info(const struct device *dev, off_t offset, struct flash_page_info *fpi) +{ + ARG_UNUSED(dev); + + if (offset < 0 || offset >= CONFIG_FLASH_SIZE) { + return -EINVAL; + } + + fpi->offset = offset & ~(ROW_SIZE - 1); + fpi->size = ROW_SIZE; + + return 0; +} + +static ssize_t flash_sam0_get_page_count(const struct device *dev) +{ + return CONFIG_FLASH_SIZE * 1024 / ROW_SIZE; +} + +static ssize_t flash_sam0_get_size(const struct device *dev) +{ + return CONFIG_FLASH_SIZE; +} + static int flash_sam0_init(const struct device *dev) { #if defined(CONFIG_MULTITHREADING) @@ -467,6 +492,9 @@ static const struct flash_driver_api flash_sam0_api = { .write = flash_sam0_write, .read = flash_sam0_read, .get_parameters = flash_sam0_get_parameters, + .get_page_info = flash_sam0_get_page_info, + .get_page_count = flash_sam0_get_page_count, + .get_size = flash_sam0_get_size, #ifdef CONFIG_FLASH_PAGE_LAYOUT .page_layout = flash_sam0_page_layout, #endif diff --git a/drivers/flash/flash_simulator.c b/drivers/flash/flash_simulator.c index 9cd643904bb18..fc1179c34a9eb 100644 --- a/drivers/flash/flash_simulator.c +++ b/drivers/flash/flash_simulator.c @@ -156,7 +156,8 @@ static const struct flash_driver_api flash_sim_api; static const struct flash_parameters flash_sim_parameters = { .write_block_size = FLASH_SIMULATOR_PROG_UNIT, - .erase_value = FLASH_SIMULATOR_ERASE_VALUE + .erase_value = FLASH_SIMULATOR_ERASE_VALUE, + .flags = 0, }; static int flash_range_is_valid(const struct device *dev, off_t offset, @@ -347,6 +348,29 @@ static void flash_sim_page_layout(const struct device *dev, } #endif +static ssize_t flash_sim_get_page_count(const struct device *dev) +{ + return FLASH_SIMULATOR_PAGE_COUNT; +} + +static ssize_t flash_sim_get_size(const struct device *dev) +{ + return FLASH_SIMULATOR_FLASH_SIZE; +} + +static int flash_sim_get_page_info(const struct device *dev, off_t offset, + struct flash_page_info *fpi) +{ + if (offset < 0 || offset > FLASH_SIMULATOR_FLASH_SIZE) { + return -EINVAL; + } + + fpi->offset = offset & ~(FLASH_SIMULATOR_ERASE_UNIT - 1); + fpi->size = FLASH_SIMULATOR_ERASE_UNIT; + + return 0; +} + static const struct flash_parameters * flash_sim_get_parameters(const struct device *dev) { @@ -360,6 +384,9 @@ static const struct flash_driver_api flash_sim_api = { .write = flash_sim_write, .erase = flash_sim_erase, .get_parameters = flash_sim_get_parameters, + .get_page_info = flash_sim_get_page_info, + .get_page_count = flash_sim_get_page_count, + .get_size = flash_sim_get_size, #ifdef CONFIG_FLASH_PAGE_LAYOUT .page_layout = flash_sim_page_layout, #endif diff --git a/drivers/flash/flash_stm32.c b/drivers/flash/flash_stm32.c index 0d952ef861298..6b8c9edad5d6e 100644 --- a/drivers/flash/flash_stm32.c +++ b/drivers/flash/flash_stm32.c @@ -24,6 +24,18 @@ LOG_MODULE_REGISTER(flash_stm32, CONFIG_FLASH_LOG_LEVEL); +#if defined(CONFIG_SOC_SERIES_STM32F4X) || defined(CONFIG_SOC_SERIES_STM32F7X) +/* Non-uniform access */ +#define STM32_FLASH_PARAMETERS_FLAGS FPF_NON_UNIFORM_LAYOUT +#elif defined(FLASH_OPTR_DBANK) && (CONFIG_FLASH_SIZE < STM32G4_SERIES_MAX_FLASH) +/* Gapped layout is always considered non-uniform as gap is counted, and described + * as a page. + */ +#define STM32_FLASH_PARAMETERS_FLAGS (FPF_NON_UNIFORM_LAYOUT | FPF_GAPS_IN_LAYOUT) +#else +#define STM32_FLASH_PARAMETERS_FLAGS 0 +#endif + /* Let's wait for double the max erase time to be sure that the operation is * completed. */ @@ -39,6 +51,7 @@ static const struct flash_parameters flash_stm32_parameters = { #else .erase_value = 0xff, #endif + .flags = STM32_FLASH_PARAMETERS_FLAGS, }; static int flash_stm32_write_protection(const struct device *dev, bool enable); @@ -329,6 +342,9 @@ static const struct flash_driver_api flash_stm32_api = { .write = flash_stm32_write, .read = flash_stm32_read, .get_parameters = flash_stm32_get_parameters, + .get_page_info = flash_stm32_get_page_info, + .get_page_count = flash_stm32_get_page_count, + .get_size = flash_stm32_get_size, #ifdef CONFIG_FLASH_PAGE_LAYOUT .page_layout = flash_stm32_page_layout, #endif diff --git a/drivers/flash/flash_stm32.h b/drivers/flash/flash_stm32.h index a503d80d22d4e..4a710a846ae88 100644 --- a/drivers/flash/flash_stm32.h +++ b/drivers/flash/flash_stm32.h @@ -220,6 +220,10 @@ int flash_stm32_block_erase_loop(const struct device *dev, int flash_stm32_wait_flash_idle(const struct device *dev); +int flash_stm32_get_page_info(const struct device *dev, off_t offset, struct flash_page_info *fpi); +ssize_t flash_stm32_get_page_count(const struct device *dev); +ssize_t flash_stm32_get_size(const struct device *dev); + #ifdef CONFIG_SOC_SERIES_STM32WBX int flash_stm32_check_status(const struct device *dev); #endif /* CONFIG_SOC_SERIES_STM32WBX */ diff --git a/drivers/flash/flash_stm32_qspi.c b/drivers/flash/flash_stm32_qspi.c index cc088b1362384..0b7e8224b4b23 100644 --- a/drivers/flash/flash_stm32_qspi.c +++ b/drivers/flash/flash_stm32_qspi.c @@ -527,7 +527,8 @@ static int flash_stm32_qspi_erase(const struct device *dev, off_t addr, static const struct flash_parameters flash_stm32_qspi_parameters = { .write_block_size = 1, - .erase_value = 0xff + .erase_value = 0xff, + .flags = 0, }; static const struct flash_parameters * @@ -538,6 +539,37 @@ flash_stm32_qspi_get_parameters(const struct device *dev) return &flash_stm32_qspi_parameters; } +static int +flash_stm32_qspi_get_page_info(const struct device *dev, off_t offset, struct flash_page_info *fpi) +{ + const struct flash_stm32_qspi_config *dev_cfg = dev->config; + + if (offset < 0 || offset >= dev_cfg->flash_size) { + return -EINVAL; + } + + fpi->offset = offset & ~(SPI_NOR_PAGE_SIZE - 1); + fpi->size = SPI_NOR_PAGE_SIZE; + + return 0; +} + +static ssize_t +flash_stm32_qspi_get_size(const struct device *dev) +{ + const struct flash_stm32_qspi_config *dev_cfg = dev->config; + + return dev_cfg->flash_size; +} + +static ssize_t +flash_stm32_qspi_get_page_count(const struct device *dev) +{ + const struct flash_stm32_qspi_config *dev_cfg = dev->config; + + return dev_cfg->flash_size / SPI_NOR_PAGE_SIZE; +} + static void flash_stm32_qspi_isr(const struct device *dev) { struct flash_stm32_qspi_data *dev_data = dev->data; @@ -657,6 +689,9 @@ static const struct flash_driver_api flash_stm32_qspi_driver_api = { .write = flash_stm32_qspi_write, .erase = flash_stm32_qspi_erase, .get_parameters = flash_stm32_qspi_get_parameters, + .get_page_info = flash_stm32_qspi_get_page_info, + .get_page_count = flash_stm32_qspi_get_page_count, + .get_size = flash_stm32_qspi_get_size, #if defined(CONFIG_FLASH_PAGE_LAYOUT) .page_layout = flash_stm32_qspi_pages_layout, #endif diff --git a/drivers/flash/flash_stm32_v1.c b/drivers/flash/flash_stm32_v1.c index 236a234489f51..a8e5f5800e4f8 100644 --- a/drivers/flash/flash_stm32_v1.c +++ b/drivers/flash/flash_stm32_v1.c @@ -250,3 +250,39 @@ void flash_stm32_page_layout(const struct device *dev, *layout = &flash_layout; *layout_size = 1; } + +#if defined(CONFIG_SOC_SERIES_STM32F3X) +#define STM32_FLASH_SIZE (DT_REG_SIZE(DT_INST(0, soc_nv_flash))) +#else +#define STM32_FLASH_SIZE (CONFIG_FLASH_SIZE * 1024) +#endif +#define STM32_PAGE_COUNT (STM32_FLASH_SIZE / FLASH_PAGE_SIZE) + + +int flash_stm32_get_page_info(const struct device *dev, off_t offset, struct flash_page_info *fpi) +{ + ARG_UNUSED(dev); + + if (offset < 0 || offset >= STM32_FLASH_SIZE) { + return -EINVAL; + } + + fpi->offset = offset & ~(FLASH_PAGE_SIZE - 1); + fpi->size = FLASH_PAGE_SIZE; + + return 0; +} + +ssize_t flash_stm32_get_page_count(const struct device *dev) +{ + ARG_UNUSED(dev); + + return STM32_PAGE_COUNT; +} + +ssize_t flash_stm32_get_size(const struct device *dev) +{ + ARG_UNUSED(dev); + + return STM32_FLASH_SIZE; +} diff --git a/drivers/flash/flash_stm32f2x.c b/drivers/flash/flash_stm32f2x.c index f3781855f576c..dbf0298c9503f 100644 --- a/drivers/flash/flash_stm32f2x.c +++ b/drivers/flash/flash_stm32f2x.c @@ -183,6 +183,54 @@ static const struct flash_pages_layout stm32f2_flash_layout[] = { {.pages_count = 1, .pages_size = KB(64)}, {.pages_count = 7, .pages_size = KB(128)}, }; + +#define K16_COUNT 4 +#define K64_COUNT 1 +#define K128_COUNT 7 + +#define K16_MASK 0x0000c000 +#define K64_MASK 0x00010000 +#define K128_MASK 0x000e0000 + +#define KALL_COUNT (K16_COUNT + K64_COUNT + K128_COUNT) +#define KALL_SIZE (K16_COUNT * KB(16) + K64_COUNT * KB(64) + K128_COUNT * KB(128)) + +int flash_stm32_get_page_info(const struct device *dev, off_t offset, struct flash_page_info *fpi) +{ + ARG_UNUSED(dev); + + if (offset < 0 || offset >= KALL_SIZE) { + return -EINVAL; + } + + if (offset & K128_MASK) { + fpi->offset = offset & K128_MASK; + fpi->size = KB(128); + } else if (offset & K64_MASK) { + fpi->offset = offset & K64_MASK; + fpi->size = KB(64); + } else { + fpi->offset = offset & K16_MASK; + fpi->size = KB(16); + } + + return 0; +} + +ssize_t flash_stm32_get_page_count(const struct device *dev) +{ + ARG_UNUSED(dev); + + return KALL_COUNT; +} + +ssize_t flash_stm32_get_size(const struct device *dev) +{ + ARG_UNUSED(dev); + + return KALL_SIZE; +} + #else #error "Unknown flash layout" #endif /* FLASH_SECTOR_TOTAL == 12 */ diff --git a/drivers/flash/flash_stm32f4x.c b/drivers/flash/flash_stm32f4x.c index c58ad3ad2a354..65848948aed10 100644 --- a/drivers/flash/flash_stm32f4x.c +++ b/drivers/flash/flash_stm32f4x.c @@ -277,6 +277,79 @@ static const struct flash_pages_layout stm32f4_flash_layout[] = { #endif /* FLASH_SECTOR_TOTAL == 5 */ #endif/* !defined(FLASH_SECTOR_TOTAL) */ +#if !defined(FLASH_SECTOR_TOTAL) +#error "Unknown flash layout" +#else + +#define K128_COUNT ((FLASH_SECTOR_TOTAL == 6) * 1 + \ + (FLASH_SECTOR_TOTAL == 8) * 3 + \ + (FLASH_SECTOR_TOTAL == 12) * 7 + \ + (FLASH_SECTOR_TOTAL == 16) * 11 + \ + (FLASH_SECTOR_TOTAL == 24) * 7) +#define K64_COUNT 1 +#define K16_COUNT 4 + +/* For the FLASH_SECTOR_TOTAL == 24 the layout is twice the layout of FLASH_SECTOR_TOTAL = 12 */ +#define KALL_COUNT ((K16_COUNT + K64_COUNT + K128_COUNT) * (1 + (FLASH_SECTOR_TOTAL == 24))) + +#define KALL_SIZE ((K16_COUNT * KB(16) + K64_COUNT * KB(64) + K128_COUNT * KB(128)) * \ + (1 + (FLASH_SECTOR_TOTAL == 24))) + +#define K128_MASK (0x00000000 | 0x00020000 * (FLASH_SECTOR_TOTAL == 6) | \ + 0x00060000 * (FLASH_SECTOR_TOTAL == 8) | \ + 0x000e0000 * (FLASH_SECTOR_TOTAL == 12) | \ + 0x001e0000 * (FLASH_SECTOR_TOTAL == 16) | \ + 0x000e0000 * (FLASH_SECTOR_TOTAL == 24)) + +/* Bank mask is needed for FLASH_SECTOR_TOTAL == 24 to properly calculate offsets of second bank */ +#define BANK_MASK (0x00100000 * (FLASH_SECTOR_TOTAL == 24)) +#define K64_MASK 0x00010000 +#define K16_MASK 0x0000c000 + +int flash_stm32_get_page_info(const struct device *dev, off_t off, struct flash_page_info *fpi) +{ + ARG_UNUSED(dev); + + if (off < 0 || off >= KALL_SIZE) { + return -EINVAL; + } + + if (K128_MASK != 0 && off & K128_MASK) { + fpi->offset = off & (K128_MASK | BANK_MASK); + fpi->size = KB(128); + } else if (off & K64_MASK) { + fpi->offset = off & (K64_MASK | BANK_MASK); + fpi->size = KB(64); + } else { + fpi->offset = off & (K16_MASK | BANK_MASK); + fpi->size = KB(16); + } + + return 0; +} + +ssize_t flash_stm32_get_page_count(const struct device *dev) +{ + ARG_UNUSED(dev); + + return KALL_COUNT; +} + +ssize_t flash_stm32_get_size(const struct device *dev) +{ + ARG_UNUSED(dev); + + return KALL_SIZE; +} + +#undef K16_MASK +#undef K64_MASK +#undef K128_MASK +#undef KALL_COUNT +#undef KALL_SIZE + +#endif /* !define(FLASH_SECTOR_TOTAL) */ + void flash_stm32_page_layout(const struct device *dev, const struct flash_pages_layout **layout, size_t *layout_size) diff --git a/drivers/flash/flash_stm32f7x.c b/drivers/flash/flash_stm32f7x.c index ac8c674e1268a..b55932464f488 100644 --- a/drivers/flash/flash_stm32f7x.c +++ b/drivers/flash/flash_stm32f7x.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2018 Aurelien Jarno * Copyright (c) 2018 Yong Jin + * Copyright (c) 2021 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -237,3 +238,143 @@ void flash_stm32_page_layout(const struct device *dev, *layout_size = ARRAY_SIZE(stm32f7_flash_layout); #endif } + +#if !defined(FLASH_SECTOR_TOTAL) +#error "Unknown flash layout" +#else + +/** Single bank or single bank layout in dual bank mode **/ +/* Counts */ +#define K256_COUNT (3 * ((FLASH_SECTOR_TOTAL == 8) && (CONFIG_FLASH_SIZE == 1024)) + \ + 7 * (FLASH_SECTOR_TOTAL == 24)) + +#define K128_COUNT (1 * (((FLASH_SECTOR_TOTAL == 8) && (CONFIG_FLASH_SIZE == 1024)) || \ + (FLASH_SECTOR_TOTAL == 24)) + \ + 3 * ((FLASH_SECTOR_TOTAL == 8) && (CONFIG_FLASH_SIZE == 512))) + +#define K64_COUNT (1 * ((FLASH_SECTOR_TOTAL == 8) && (CONFIG_FLASH_SIZE == 512))) + +#define K32_COUNT (4 * (((FLASH_SECTOR_TOTAL == 8) && (CONFIG_FLASH_SIZE == 1024)) || \ + (FLASH_SECTOR_TOTAL == 24)) + \ + 2 * (FLASH_SECTOR_TOTAL == 2)) + +#define K16_COUNT (4 * (((FLASH_SECTOR_TOTAL == 8) && (CONFIG_FLASH_SIZE == 512)) || \ + (FLASH_SECTOR_TOTAL == 4))) + +#define KALL_COUNT (K16_COUNT + K32_COUNT + K64_COUNT + K128_COUNT + K256_COUNT) + +#define KALL_SIZE (K16_COUNT * KB(16) + K32_COUNT * KB(32) + K64_COUNT * KB(64) + \ + K128_COUNT * KB(128) + K256_COUNT * KB(256)) + +/* Masks */ +#define K256_MASK (0x001c0000 * (K256_COUNT != 0)) + +#define K128_MASK (0x00020000 * (((FLASH_SECTOR_TOTAL == 8) && \ + (CONFIG_FLASH_SIZE == 1024)) || \ + (FLASH_SECTOR_TOTAL == 24)) + \ + 0x00060000 * ((FLASH_SECTOR_TOTAL == 8) && (CONFIG_FLASH_SIZE == 512))) + +#define K64_MASK (0x00010000 * (K64_COUNT != 0)) + +#define K32_MASK (0x00018000 * (K32_COUNT != 0)) + +#define K16_MASK (0x0000c000 * (K16_COUNT != 0)) + +/** Second bank layout in dual bank mode **/ +#if FLASH_SECTOR_TOTAL == 24 && !defined(FLASH_OPTCR_nDBANK) +#error "The 24 sectors allow single/dual bank mode and require FLASH_OPTCR_nDBANK" +#endif +/* In dual bank mode, the second bank layout is the same in size of flash but the number of pages + * dubles as sizes of all pages are divided by two; this means that istead of having N pages of + * size M we now have N * 2 pages of size M / 2. + */ +#define K128_COUNT_D K256_COUNT +#define K64_COUNT_D K128_COUNT +#define K16_COUNT_D K32_COUNT +#define KALL_COUNT_D ((K128_COUNT_D + K64_COUNT_D + K16_COUNT_D) * 1) + +/* Masks are also shifted right by one as now they mask bits for pages that are in size M / 2 */ +#define K128_MASK_D (K256_MASK >> 1) +#define K64_MASK_D (K128_MASK >> 1) +#define K16_MASK_D (K32_MASK >> 1) +/* Mask where second bank layout starts */ +#define BANK_MASK 0x00100000 + +int flash_stm32_get_page_info(const struct device *dev, off_t off, struct flash_page_info *fpi) +{ + ARG_UNUSED(dev); + + if (off < 0 || off >= KALL_SIZE) { + return -EINVAL; + } + +#if FLASH_SECTOR_TOTAL == 24 + if (!(FLASH_STM32_REGS(dev)->OPTCR & FLASH_OPTCR_nDBANK)) { + /* Dual bank mode, dual layout */ + /* RM0410, table 4: STM32F76xxx and STM32F77xxx in dual bank */ + if (off & K128_MASK_D) { + fpi->offset = off & (K128_MASK_D | BANK_MASK); + fpi->size = KB(128); + } else if (off & K64_MASK_D) { + fpi->offset = off & (K64_MASK_D | BANK_MASK); + fpi->size = KB(64); + } else { + fpi->offset = off & (K16_MASK_D | BANK_MASK); + fpi->size = KB(16); + } + return 0; + } +#endif + + /* Single bank mode or single layout in dual bank bank mode */ + /* RM0385, table 4: STM32F750xx */ + /* RM0431, table 4: STM32F730xx */ + /* RM0385, table 3: STM32F756xx and STM32F74xxx */ + /* RM0410, table 3: STM32F76xxx and STM32F77xxx in single bank */ + if (off & K256_MASK) { + fpi->offset = off & K256_MASK; + fpi->size = KB(256); + } else if (off & K128_MASK) { + fpi->offset = off & K128_MASK; + fpi->size = KB(128); + } else if (off & K64_MASK) { + fpi->offset = off & K64_MASK; + fpi->size = KB(64); + } else if (K32_MASK != 0) { + fpi->offset = off & K32_MASK; + fpi->size = KB(32); + } else if (K16_MASK != 0) { + fpi->offset = off & K16_MASK; + fpi->size = KB(16); + } + + return 0; +} + +ssize_t flash_stm32_get_page_count(const struct device *dev) +{ + ARG_UNUSED(dev); + +#if FLASH_SECTOR_TOTAL == 24 + if (!(FLASH_STM32_REGS(dev)->OPTCR & FLASH_OPTCR_nDBANK)) { + return KALL_COUNT_D; + } +#endif + + return KALL_COUNT; +} + +ssize_t flash_stm32_get_size(const struct device *dev) +{ + ARG_UNUSED(dev); + + /* + * In case when FLASH_SECTOR_TOTAL == 24, the number of pages changes due to how the flash + * gets divided, but the KALL_SIZE is the same as the division into pages does not change + * the overall size. + */ + return KALL_SIZE; +} + + +#endif /* !define(FLASH_SECTOR_TOTAL) */ diff --git a/drivers/flash/flash_stm32g0x.c b/drivers/flash/flash_stm32g0x.c index 3486ddf4a23db..7eaff53a1da54 100644 --- a/drivers/flash/flash_stm32g0x.c +++ b/drivers/flash/flash_stm32g0x.c @@ -246,3 +246,31 @@ int flash_stm32_check_configuration(void) #endif return 0; } + +int flash_stm32_get_page_info(const struct device *dev, off_t offset, struct flash_page_info *fpi) +{ + ARG_UNUSED(dev); + + if (offset < 0 || offset >= FLASH_SIZE) { + return -EINVAL; + } + + fpi->offset = offset & ~(FLASH_PAGE_SIZE - 1); + fpi->size = FLASH_PAGE_SIZE; + + return 0; +} + +ssize_t flash_stm32_get_page_count(const struct device *dev) +{ + ARG_UNUSED(dev); + + return FLASH_SIZE / FLASH_PAGE_SIZE; +} + +ssize_t flash_stm32_get_size(const struct device *dev) +{ + ARG_UNUSED(dev); + + return FLASH_SIZE; +} diff --git a/drivers/flash/flash_stm32g4x.c b/drivers/flash/flash_stm32g4x.c index f0e036b72c600..58b9d812b0adc 100644 --- a/drivers/flash/flash_stm32g4x.c +++ b/drivers/flash/flash_stm32g4x.c @@ -284,6 +284,55 @@ void flash_stm32_page_layout(const struct device *dev, *layout_size = ARRAY_SIZE(stm32g4_flash_layout); } +int flash_stm32_get_page_info(const struct device *dev, off_t offset, struct flash_page_info *fpi) +{ + ARG_UNUSED(dev); + +#if defined(FLASH_OPTR_DBANK) && (CONFIG_FLASH_SIZE < STM32G4_SERIES_MAX_FLASH) + if (offset < 0 || offset >= (BANK2_OFFSET + FLASH_SIZE / 2)) { + return -EINVAL; + } + + /* In case of a "gap" return its offset and size and report -ENOENT */ + if (offset >= (FLASH_SIZE / 2) && offset < BANK2_OFFSET) { + fpi->offset = FLASH_SIZE / 2; + fpi->size = BANK2_OFFSET - FLASH_SIZE / 2; + return -ENOENT; + } + + fpi->offset = offset & ~(FLASH_PAGE_SIZE - 1); + fpi->size = FLASH_PAGE_SIZE; +#else + + if (offset < 0 || offset >= FLASH_SIZE) { + return -EINVAL; + } + + fpi->offset = offset & ~(FLASH_PAGE_SIZE - 1); + fpi->size = FLASH_PAGE_SIZE; +#endif + + return 0; +} + +ssize_t flash_stm32_get_page_count(const struct device *dev) +{ + ARG_UNUSED(dev); + +#if defined(FLASH_OPTR_DBANK) && (CONFIG_FLASH_SIZE < STM32G4_SERIES_MAX_FLASH) +#define PAGES_PER_BANK ((FLASH_SIZE / FLASH_PAGE_SIZE) / 2) + /* Count returns gaps too */ + return FLASH_SIZE / FLASH_PAGE_SIZE + 1; +#else + return FLASH_SIZE / FLASH_PAGE_SIZE; +#endif +} + +ssize_t flash_stm32_get_size(const struct device *dev) +{ + return FLASH_SIZE; +} + /* Override weak function */ int flash_stm32_check_configuration(void) { diff --git a/drivers/flash/flash_stm32h7x.c b/drivers/flash/flash_stm32h7x.c index 1c8f0ba4ac5b5..7848089717da9 100644 --- a/drivers/flash/flash_stm32h7x.c +++ b/drivers/flash/flash_stm32h7x.c @@ -584,7 +584,10 @@ static int flash_stm32h7_read(const struct device *dev, off_t offset, } -static const struct flash_parameters flash_stm32h7_parameters = { +#if !defined(DUAL_BANK) +const +#endif +static struct flash_parameters flash_stm32h7_parameters = { .write_block_size = FLASH_STM32_WRITE_BLOCK_SIZE, .erase_value = 0xff, }; @@ -594,6 +597,12 @@ flash_stm32h7_get_parameters(const struct device *dev) { ARG_UNUSED(dev); +#if defined(DUAL_BANK) + if (DISCONTINUOUS_BANKS == 1) { + flash_stm32h7_parameters.flags = FPF_NON_UNIFORM_LAYOUT | FPF_GAPS_IN_LAYOUT; + } +#endif + return &flash_stm32h7_parameters; } @@ -651,11 +660,71 @@ static struct flash_stm32_priv flash_data = { .enr = DT_INST_CLOCKS_CELL(0, bits)}, }; +static int +flash_stm32h7_get_page_info(const struct device *dev, off_t offset, struct flash_page_info *fpi) +{ + ARG_UNUSED(dev); + + +#if defined(DUAL_BANK) + if (offset < 0) { + return -EINVAL; + } + + if (DISCONTINUOUS_BANKS) { + if (offset >= (BANK2_OFFSET + KB(REAL_FLASH_SIZE_KB) / 2)) { + return -EINVAL; + } + + if (offset >= (KB(REAL_FLASH_SIZE_KB) / 2) && offset < BANK2_OFFSET) { + fpi->offset = KB(REAL_FLASH_SIZE_KB) / 2; + fpi->size = BANK2_OFFSET - (KB(REAL_FLASH_SIZE_KB) / 2); + return -ENOENT; + } + } else if (offset >= KB(REAL_FLASH_SIZE_KB)) { + return -EINVAL; + } +#else + if (offset < 0 || offset >= KB(REAL_FLASH_SIZE_KB)) { + return -EINVAL; + } +#endif + fpi->offset = offset & ~(FLASH_SECTOR_SIZE - 1); + fpi->size = FLASH_SECTOR_SIZE; + + return 0; +} + +static ssize_t +flash_stm32h7_get_page_count(const struct device *dev) +{ + ARG_UNUSED(dev); + +#if defined(DUAL_BANK) + /* Gap is counted as single page */ + return KB(REAL_FLASH_SIZE_KB) / FLASH_SECTOR_SIZE + (DISCONTINUOUS_BANKS == 1); +#else + return KB(REAL_FLASH_SIZE_KB) / FLASH_SECTOR_SIZE; +#endif + +} + +static ssize_t +flash_stm32h7_get_size(const struct device *dev) +{ + ARG_UNUSED(dev); + + return KB(REAL_FLASH_SIZE_KB); +} + static const struct flash_driver_api flash_stm32h7_api = { .erase = flash_stm32h7_erase, .write = flash_stm32h7_write, .read = flash_stm32h7_read, .get_parameters = flash_stm32h7_get_parameters, + .get_page_info = flash_stm32h7_get_page_info, + .get_page_count = flash_stm32h7_get_page_count, + .get_size = flash_stm32h7_get_size, #ifdef CONFIG_FLASH_PAGE_LAYOUT .page_layout = flash_stm32_page_layout, #endif diff --git a/drivers/flash/flash_stm32l4x.c b/drivers/flash/flash_stm32l4x.c index 39b5faebc64ee..da295dcc45aa9 100644 --- a/drivers/flash/flash_stm32l4x.c +++ b/drivers/flash/flash_stm32l4x.c @@ -266,3 +266,31 @@ void flash_stm32_page_layout(const struct device *dev, *layout = &stm32l4_flash_layout; *layout_size = 1; } + +int flash_stm32_get_page_info(const struct device *dev, off_t offset, struct flash_page_info *fpi) +{ + ARG_UNUSED(dev); + + if (offset < 0 || offset >= FLASH_SIZE) { + return -EINVAL; + } + + fpi->offset = offset & ~(FLASH_PAGE_SIZE - 1); + fpi->size = FLASH_PAGE_SIZE; + + return 0; +} + +ssize_t flash_stm32_get_page_count(const struct device *dev) +{ + ARG_UNUSED(dev); + + return FLASH_SIZE / FLASH_PAGE_SIZE; +} + +ssize_t flash_stm32_get_size(const struct device *dev) +{ + ARG_UNUSED(dev); + + return FLASH_SIZE; +} diff --git a/drivers/flash/flash_stm32l5_u5.c b/drivers/flash/flash_stm32l5_u5.c index 4d0e373ffc2fe..5e2ce720b5873 100644 --- a/drivers/flash/flash_stm32l5_u5.c +++ b/drivers/flash/flash_stm32l5_u5.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2021 STMicroelectronics + * Copyright (c) 2022 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -397,3 +398,59 @@ void flash_stm32_page_layout(const struct device *dev, *layout = stm32_flash_layout; *layout_size = ARRAY_SIZE(stm32_flash_layout); } + +#define BANK_SIZE (FLASH_SIZE / 2) + +int flash_stm32_get_page_info(const struct device *dev, off_t offset, struct flash_page_info *fpi) +{ + FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); + + if (offset < 0 || offset >= FLASH_SIZE) { + return -EINVAL; + } + + if (((regs->OPTR & FLASH_STM32_DBANK) == FLASH_STM32_DBANK) && + (CONFIG_FLASH_SIZE < STM32_SERIES_MAX_FLASH)) { + /* For stm32l552xx with 256 KB flash */ + if (offset > BANK_SIZE && offset < BANK2_OFFSET) { + /* Dummy page corresponding to discontinuity between + * bank 1/2 + */ + fpi->offset = offset & (BANK2_OFFSET - BANK_SIZE); + fpi->size = BANK2_OFFSET - BANK_SIZE; + + return -ENOENT; + } + + /* Bank1 and Bank2 */ + fpi->offset = offset & (FLASH_PAGE_SIZE); + fpi->size = FLASH_PAGE_SIZE; + + } else { + /* For stm32l562xx & stm32l552xx with 512 KB flash */ + fpi->offset = offset & (FLASH_SIZE / FLASH_PAGE_SIZE); + fpi->size = FLASH_PAGE_SIZE; + } + + return 0; +} + +ssize_t flash_stm32_get_page_count(const struct device *dev) +{ + FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); + + if (((regs->OPTR & FLASH_STM32_DBANK) == FLASH_STM32_DBANK) && + (CONFIG_FLASH_SIZE < STM32_SERIES_MAX_FLASH)) { + /* All pages + gap */ + return (FLASH_SIZE / FLASH_PAGE_SIZE + 1); + } + + return (FLASH_SIZE / FLASH_PAGE_SIZE); +} + +ssize_t flash_stm32_get_size(const struct device *dev) +{ + ARG_UNUSED(dev); + + return FLASH_SIZE; +} diff --git a/drivers/flash/flash_stm32wbx.c b/drivers/flash/flash_stm32wbx.c index 2cda8508796af..9f46fa4e709a7 100644 --- a/drivers/flash/flash_stm32wbx.c +++ b/drivers/flash/flash_stm32wbx.c @@ -409,6 +409,34 @@ void flash_stm32_page_layout(const struct device *dev, *layout_size = 1; } +int flash_stm32_get_page_info(const struct device *dev, off_t offset, struct flash_page_info *fpi) +{ + ARG_UNUSED(dev); + + if (offset < 0 || offset >= FLASH_SIZE) { + return -EINVAL; + } + + fpi->offset = offset & ~(FLASH_PAGE_SIZE - 1); + fpi->size = FLASH_PAGE_SIZE; + + return 0; +} + +ssize_t flash_stm32_get_page_count(const struct device *dev) +{ + ARG_UNUSED(dev); + + return FLASH_SIZE / FLASH_PAGE_SIZE; +} + +ssize_t flash_stm32_get_size(const struct device *dev) +{ + ARG_UNUSED(dev); + + return FLASH_SIZE; +} + int flash_stm32_check_status(const struct device *dev) { FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); diff --git a/drivers/flash/nrf_qspi_nor.c b/drivers/flash/nrf_qspi_nor.c index eddba3de5cfbc..664ef90efcf11 100644 --- a/drivers/flash/nrf_qspi_nor.c +++ b/drivers/flash/nrf_qspi_nor.c @@ -44,6 +44,10 @@ struct qspi_nor_data { #endif }; +/* instance 0 page count */ +#define LAYOUT_PAGES_COUNT (INST_0_BYTES / \ + CONFIG_NORDIC_QSPI_NOR_FLASH_LAYOUT_PAGE_SIZE) + struct qspi_nor_config { nrfx_qspi_config_t nrfx_cfg; @@ -1200,10 +1204,6 @@ static int qspi_nor_init(const struct device *dev) #if defined(CONFIG_FLASH_PAGE_LAYOUT) -/* instance 0 page count */ -#define LAYOUT_PAGES_COUNT (INST_0_BYTES / \ - CONFIG_NORDIC_QSPI_NOR_FLASH_LAYOUT_PAGE_SIZE) - BUILD_ASSERT((CONFIG_NORDIC_QSPI_NOR_FLASH_LAYOUT_PAGE_SIZE * LAYOUT_PAGES_COUNT) == INST_0_BYTES, @@ -1213,7 +1213,6 @@ static const struct flash_pages_layout dev_layout = { .pages_count = LAYOUT_PAGES_COUNT, .pages_size = CONFIG_NORDIC_QSPI_NOR_FLASH_LAYOUT_PAGE_SIZE, }; -#undef LAYOUT_PAGES_COUNT static void qspi_nor_pages_layout(const struct device *dev, const struct flash_pages_layout **layout, @@ -1237,11 +1236,43 @@ qspi_flash_get_parameters(const struct device *dev) return &qspi_flash_parameters; } +ssize_t qspi_nor_get_size(const struct device *dev) +{ + ARG_UNUSED(dev); + + return CONFIG_NORDIC_QSPI_NOR_FLASH_LAYOUT_PAGE_SIZE * LAYOUT_PAGES_COUNT; +} + +ssize_t qspi_nor_get_page_count(const struct device *dev) +{ + ARG_UNUSED(dev); + + return LAYOUT_PAGES_COUNT; +} + +int qspi_nor_get_page_info(const struct device *dev, off_t offset, struct flash_page_info *fpi) +{ + ARG_UNUSED(dev); + + if (offset < 0 || + offset >= (CONFIG_NORDIC_QSPI_NOR_FLASH_LAYOUT_PAGE_SIZE * LAYOUT_PAGES_COUNT)) { + return -EINVAL; + } + + fpi->offset = offset & ~(CONFIG_NORDIC_QSPI_NOR_FLASH_LAYOUT_PAGE_SIZE - 1); + fpi->size = CONFIG_NORDIC_QSPI_NOR_FLASH_LAYOUT_PAGE_SIZE; + + return 0; +} + static const struct flash_driver_api qspi_nor_api = { .read = qspi_nor_read, .write = qspi_nor_write, .erase = qspi_nor_erase, .get_parameters = qspi_flash_get_parameters, + .get_page_info = qspi_nor_get_page_info, + .get_page_count = qspi_nor_get_page_count, + .get_size = qspi_nor_get_size, #if defined(CONFIG_FLASH_PAGE_LAYOUT) .page_layout = qspi_nor_pages_layout, #endif diff --git a/drivers/flash/soc_flash_lpc.c b/drivers/flash/soc_flash_lpc.c index df9a86c1b7900..a406c06768883 100644 --- a/drivers/flash/soc_flash_lpc.c +++ b/drivers/flash/soc_flash_lpc.c @@ -39,6 +39,7 @@ static const struct flash_parameters flash_lpc_parameters = { .write_block_size = FSL_FEATURE_FLASH_PFLASH_BLOCK_WRITE_UNIT_SIZE, #endif .erase_value = 0xff, + .flags = 0, }; static inline void prepare_erase_write(off_t offset, size_t len, @@ -141,6 +142,35 @@ flash_lpc_get_parameters(const struct device *dev) return &flash_lpc_parameters; } +static int flash_lpc_get_page_info(const struct device *dev, off_t offset, + struct flash_page_info *fpi) +{ + ARG_UNUSED(dev); + + if (offset < 0 || offset >= DT_REG_SIZE(SOC_NV_FLASH_NODE)) { + return -EINVAL; + } + + fpi->offset = offset & ~(DT_PROP(SOC_NV_FLASH_NODE, erase_block_size) - 1); + fpi->size = DT_PROP(SOC_NV_FLASH_NODE, erase_block_size); + + return 0; +} + +static ssize_t flash_lpc_get_page_count(const struct device *dev) +{ + ARG_UNUSED(dev); + + return DT_REG_SIZE(SOC_NV_FLASH_NODE) / DT_PROP(SOC_NV_FLASH_NODE, erase_block_size); +} + +static ssize_t flash_lpc_get_size(const struct device *dev) +{ + ARG_UNUSED(dev); + + return DT_REG_SIZE(SOC_NV_FLASH_NODE); +} + static struct flash_priv flash_data; static const struct flash_driver_api flash_lpc_api = { @@ -148,6 +178,9 @@ static const struct flash_driver_api flash_lpc_api = { .write = flash_lpc_write, .read = flash_lpc_read, .get_parameters = flash_lpc_get_parameters, + .get_page_info = flash_lpc_get_page_info, + .get_page_count = flash_lpc_get_page_count, + .get_size = flash_lpc_get_size, #if defined(CONFIG_FLASH_PAGE_LAYOUT) .page_layout = flash_lpc_pages_layout, #endif diff --git a/drivers/flash/soc_flash_mcux.c b/drivers/flash/soc_flash_mcux.c index 5e8bd594c74a0..3490588657bf0 100644 --- a/drivers/flash/soc_flash_mcux.c +++ b/drivers/flash/soc_flash_mcux.c @@ -125,6 +125,7 @@ static const struct flash_parameters flash_mcux_parameters = { .write_block_size = FSL_FEATURE_FLASH_PFLASH_BLOCK_WRITE_UNIT_SIZE, #endif .erase_value = 0xff, + .flags = 0, }; /* @@ -248,6 +249,35 @@ flash_mcux_get_parameters(const struct device *dev) return &flash_mcux_parameters; } +static int flash_mcux_get_page_info(const struct device *dev, off_t offset, + struct flash_page_info *fpi) +{ + ARG_UNUSED(dev); + + if (offset < 0 || offset >= DT_REG_SIZE(SOC_NV_FLASH_NODE)) { + return -EINVAL; + } + + fpi->offset = offset & ~(DT_PROP(SOC_NV_FLASH_NODE, erase_block_size) - 1); + fpi->size = DT_PROP(SOC_NV_FLASH_NODE, erase_block_size); + + return 0; +} + +static ssize_t flash_mcux_get_page_count(const struct device *dev) +{ + ARG_UNUSED(dev); + + return DT_REG_SIZE(SOC_NV_FLASH_NODE) / DT_PROP(SOC_NV_FLASH_NODE, erase_block_size); +} + +static ssize_t flash_mcux_get_size(const struct device *dev) +{ + ARG_UNUSED(dev); + + return DT_REG_SIZE(SOC_NV_FLASH_NODE); +} + static struct flash_priv flash_data; static const struct flash_driver_api flash_mcux_api = { @@ -255,6 +285,9 @@ static const struct flash_driver_api flash_mcux_api = { .write = flash_mcux_write, .read = flash_mcux_read, .get_parameters = flash_mcux_get_parameters, + .get_page_info = flash_mcux_get_page_info, + .get_page_count = flash_mcux_get_page_count, + .get_size = flash_mcux_get_size, #if defined(CONFIG_FLASH_PAGE_LAYOUT) .page_layout = flash_mcux_pages_layout, #endif diff --git a/drivers/flash/soc_flash_nios2_qspi.c b/drivers/flash/soc_flash_nios2_qspi.c index 6cf1f94be4a1f..37dd8bbdd6b73 100644 --- a/drivers/flash/soc_flash_nios2_qspi.c +++ b/drivers/flash/soc_flash_nios2_qspi.c @@ -64,6 +64,7 @@ struct flash_nios2_qspi_config { static const struct flash_parameters flash_nios2_qspi_parameters = { .write_block_size = NIOS2_WRITE_BLOCK_SIZE, .erase_value = 0xff, + .flags = 0, }; static int flash_nios2_qspi_write_protection(const struct device *dev, @@ -488,11 +489,48 @@ flash_nios2_qspi_get_parameters(const struct device *dev) return &flash_nios2_qspi_parameters; } +static int +flash_nios2_qspi_get_page_info(const struct device *dev, off_t offset, struct flash_page_info *fpi) +{ + struct flash_nios2_qspi_config *flash_cfg = dev->data; + alt_qspi_controller2_dev *qspi_dev = &flash_cfg->qspi_dev; + + if (offset < 0 || offset >= qspi_dev->data_end) { + return -EINVAL; + } + + fpi->offset = offset & ~(qspi_dev->sector_size - 1); + fpi->size = qspi_dev->sector_size; + + return 0; +} + +static ssize_t +flash_nios2_qspi_get_page_count(const struct device *dev) +{ + struct flash_nios2_qspi_config *flash_cfg = dev->data; + alt_qspi_controller2_dev *qspi_dev = &flash_cfg->qspi_dev; + + return (qspi_dev->data_end / qspi_dev->sector_size); +} + +static ssize_t +flash_nios2_qspi_get_size(const struct device *dev) +{ + struct flash_nios2_qspi_config *flash_cfg = dev->data; + alt_qspi_controller2_dev *qspi_dev = &flash_cfg->qspi_dev; + + return qspi_dev->data_end; +} + static const struct flash_driver_api flash_nios2_qspi_api = { .erase = flash_nios2_qspi_erase, .write = flash_nios2_qspi_write, .read = flash_nios2_qspi_read, .get_parameters = flash_nios2_qspi_get_parameters, + .get_page_info = flash_nios2_qspi_get_page_info, + .get_page_count = flash_nios2_qspi_get_page_count, + .get_size = flash_nios2_qspi_get_size, #if defined(CONFIG_FLASH_PAGE_LAYOUT) .page_layout = (flash_api_pages_layout) flash_page_layout_not_implemented, diff --git a/drivers/flash/soc_flash_nrf.c b/drivers/flash/soc_flash_nrf.c index 2b81f5e9c99ca..bbc2b83c509b5 100644 --- a/drivers/flash/soc_flash_nrf.c +++ b/drivers/flash/soc_flash_nrf.c @@ -60,6 +60,7 @@ static const struct flash_parameters flash_nrf_parameters = { .write_block_size = 4, #endif .erase_value = 0xff, + .flags = 0, }; #if defined(CONFIG_MULTITHREADING) @@ -232,6 +233,32 @@ static int flash_nrf_erase(const struct device *dev, off_t addr, size_t size) return ret; } +static ssize_t flash_nrf_get_page_count(const struct device *dev) +{ + ARG_UNUSED(dev); + + return nrfx_nvmc_flash_page_count_get(); +} + +static int flash_nrf_get_page_info(const struct device *dev, off_t off, struct flash_page_info *fpi) +{ + ARG_UNUSED(dev); + + size_t page_size = nrfx_nvmc_flash_page_size_get(); + + fpi->size = page_size; + fpi->offset = off & ~(page_size - 1); + + return 0; +} + +static ssize_t flash_nrf_get_size(const struct device *dev) +{ + ARG_UNUSED(dev); + + return nrfx_nvmc_flash_size_get(); +} + #if defined(CONFIG_FLASH_PAGE_LAYOUT) static struct flash_pages_layout dev_layout; @@ -242,6 +269,8 @@ static void flash_nrf_pages_layout(const struct device *dev, *layout = &dev_layout; *layout_size = 1; } + + #endif /* CONFIG_FLASH_PAGE_LAYOUT */ static const struct flash_parameters * @@ -257,6 +286,9 @@ static const struct flash_driver_api flash_nrf_api = { .write = flash_nrf_write, .erase = flash_nrf_erase, .get_parameters = flash_nrf_get_parameters, + .get_page_info = flash_nrf_get_page_info, + .get_page_count = flash_nrf_get_page_count, + .get_size = flash_nrf_get_size, #if defined(CONFIG_FLASH_PAGE_LAYOUT) .page_layout = flash_nrf_pages_layout, #endif diff --git a/drivers/flash/soc_flash_rv32m1.c b/drivers/flash/soc_flash_rv32m1.c index 7971bf1503962..110c346cb9aeb 100644 --- a/drivers/flash/soc_flash_rv32m1.c +++ b/drivers/flash/soc_flash_rv32m1.c @@ -31,6 +31,7 @@ struct flash_priv { static const struct flash_parameters flash_mcux_parameters = { .write_block_size = FSL_FEATURE_FLASH_PFLASH_BLOCK_WRITE_UNIT_SIZE, .erase_value = 0xff, + .flags = 0, }; /* @@ -130,6 +131,35 @@ flash_mcux_get_parameters(const struct device *dev) return &flash_mcux_parameters; } +static int flash_mcux_get_page_info(const struct device *dev, off_t offset, + struct flash_page_info *fpi) +{ + ARG_UNUSED(dev); + + if (offset < 0 || offset >= DT_REG_SIZE(SOC_NV_FLASH_NODE)) { + return -EINVAL; + } + + fpi->offset = offset & ~(DT_PROP(SOC_NV_FLASH_NODE, erase_block_size) - 1); + fpi->size = DT_PROP(SOC_NV_FLASH_NODE, erase_block_size); + + return 0; +} + +static ssize_t flash_mcux_get_page_count(const struct device *dev) +{ + ARG_UNUSED(dev); + + return DT_REG_SIZE(SOC_NV_FLASH_NODE) / DT_PROP(SOC_NV_FLASH_NODE, erase_block_size); +} + +static ssize_t flash_mcux_get_size(const struct device *dev) +{ + ARG_UNUSED(dev); + + return DT_REG_SIZE(SOC_NV_FLASH_NODE); +} + static struct flash_priv flash_data; static const struct flash_driver_api flash_mcux_api = { @@ -137,6 +167,9 @@ static const struct flash_driver_api flash_mcux_api = { .write = flash_mcux_write, .read = flash_mcux_read, .get_parameters = flash_mcux_get_parameters, + .get_page_info = flash_mcux_get_page_info, + .get_page_count = flash_mcux_get_page_count, + .get_size = flash_mcux_get_size, #if defined(CONFIG_FLASH_PAGE_LAYOUT) .page_layout = flash_mcux_pages_layout, #endif diff --git a/drivers/flash/spi_flash_at45.c b/drivers/flash/spi_flash_at45.c index 4aa9db53eb198..7bdf1d540bc6a 100644 --- a/drivers/flash/spi_flash_at45.c +++ b/drivers/flash/spi_flash_at45.c @@ -85,6 +85,7 @@ struct spi_flash_at45_config { static const struct flash_parameters flash_at45_parameters = { .write_block_size = 1, .erase_value = 0xff, + .flags = 0, }; static void acquire(const struct device *dev) @@ -626,11 +627,44 @@ flash_at45_get_parameters(const struct device *dev) return &flash_at45_parameters; } +static ssize_t +spi_flash_at45_get_page_count(const struct device *dev) +{ + return get_dev_config(dev)->pages_layout.pages_count; +} + +static ssize_t +spi_flash_at45_get_size(const struct device *dev) +{ + const struct flash_pages_layout *fpl = &get_dev_config(dev)->pages_layout; + + return fpl->pages_count * fpl->pages_size; +} + +static int +spi_flash_at45_get_page_info(const struct device *dev, off_t offset, struct flash_page_info *fpi) +{ + const struct flash_pages_layout *fpl = &get_dev_config(dev)->pages_layout; + + if (offset < 0 || + offset >= (fpl->pages_count * fpl->pages_size)) { + return -EINVAL; + } + + fpi->offset = offset & ~(fpl->pages_size - 1); + fpi->size = fpl->pages_size; + + return 0; +} + static const struct flash_driver_api spi_flash_at45_api = { .read = spi_flash_at45_read, .write = spi_flash_at45_write, .erase = spi_flash_at45_erase, .get_parameters = flash_at45_get_parameters, + .get_page_info = spi_flash_at45_get_page_info, + .get_page_count = spi_flash_at45_get_page_count, + .get_size = spi_flash_at45_get_size, #if IS_ENABLED(CONFIG_FLASH_PAGE_LAYOUT) .page_layout = spi_flash_at45_pages_layout, #endif diff --git a/drivers/flash/spi_nor.c b/drivers/flash/spi_nor.c index 3bd1cb362b6a1..7a7f6ca13e202 100644 --- a/drivers/flash/spi_nor.c +++ b/drivers/flash/spi_nor.c @@ -1164,11 +1164,48 @@ flash_nor_get_parameters(const struct device *dev) return &flash_nor_parameters; } +static int +flash_nor_get_page_info(const struct device *dev, off_t offset, struct flash_page_info *fpi) +{ + ssize_t total = dev_flash_size(dev); + ssize_t page = dev_page_size(dev); + + BUILD_ASSERT(sizeof(uint32_t) <= sizeof(ssize_t), "ssize_t not ge the uint32_t"); + + /* This is possible when uint32_t value is big enough to cross into negative ssize_t */ + if (total < 0) { + LOG_ERR("ssize_t not enough to handle flash size"); + return -ERANGE; + } + + if (offset < 0 || offset >= total) { + return -EINVAL; + } + + fpi->offset = offset & ~(page - 1); + fpi->size = page; + + return 0; +} + +static ssize_t flash_nor_get_page_count(const struct device *dev) +{ + return dev_flash_size(dev) / dev_page_size(dev); +} + +static ssize_t flash_nor_get_size(const struct device *dev) +{ + return dev_flash_size(dev); +} + static const struct flash_driver_api spi_nor_api = { .read = spi_nor_read, .write = spi_nor_write, .erase = spi_nor_erase, .get_parameters = flash_nor_get_parameters, + .get_page_info = flash_nor_get_page_info, + .get_page_count = flash_nor_get_page_count, + .get_size = flash_nor_get_size, #if defined(CONFIG_FLASH_PAGE_LAYOUT) .page_layout = spi_nor_pages_layout, #endif diff --git a/include/zephyr/drivers/flash.h b/include/zephyr/drivers/flash.h index 73923eddb6746..9a834f30f7624 100644 --- a/include/zephyr/drivers/flash.h +++ b/include/zephyr/drivers/flash.h @@ -29,12 +29,15 @@ extern "C" { #endif -#if defined(CONFIG_FLASH_PAGE_LAYOUT) struct flash_pages_layout { size_t pages_count; /* count of pages sequence of the same size */ size_t pages_size; }; -#endif /* CONFIG_FLASH_PAGE_LAYOUT */ + +struct flash_page_info { + off_t offset; /* Beginning of page */ + size_t size; /* Page size */ +}; /** * @} @@ -53,10 +56,26 @@ struct flash_pages_layout { * through a runtime. */ struct flash_parameters { - const size_t write_block_size; - uint8_t erase_value; /* Byte value of erased flash */ + size_t write_block_size; + uint32_t flags; /* FPF_ flags */ + uint8_t erase_value; /* Byte value of erased flash */ }; +/** + * Definitions for flash_parameters.flags + */ +#define FPF_NON_UNIFORM_LAYOUT 0x01 /* Pages across device have various sizes. + * NOTE: device with uniform page size but with holes in + * addressing is non-uniform device. + */ +#define FPF_GAPS_IN_LAYOUT 0x02 /* There are gaps in addressing of flash; the flag will + * usually be combined with FPF_NON_UNIFORM_LAYOUT, even + * if all flash pages are of equal size, as gaps + * are reported as single region, spanning from some offset + * up to first valid page, and are rarely of size of a + * single page. + */ + /** * @} */ @@ -120,6 +139,52 @@ typedef void (*flash_api_pages_layout)(const struct device *dev, size_t *layout_size); #endif /* CONFIG_FLASH_PAGE_LAYOUT */ +/** + * @brief Get flash page info at given offset + * + * Fills in flash_page_info structure with information on the flash page that is at given offset. + * In case when the dev is virtual device that begins at the middle of page the returned offset + * this will return error if the offset is at the split page. + * + * @param[in] dev flash device; + * @param[in] off offset; + * @param[out] fpi pointer to flash_page_info for obtained information; + * + * If flash has non-uniform layout with holes, asking for offset that is within hole will return + * an error. + * + * @return 0 on success; + * -EINVAL if offset is outside of flash device; + * other negative errno code on error. + */ +typedef int (*flash_api_get_page_info)(const struct device *dev, off_t off, + struct flash_page_info *fpi); + +/** + * @brief Get flash page count + * + * Returns total number of pages available on device; in case of virtual devices that are + * incorrectly * configured to split pages at the beginning or the end of range, this will return + * number of complete pages. + * + * @param[in] dev flash device. + * + * @return Total number of flash pages on device on success; + * negative errno code on error. + */ +typedef ssize_t (*flash_api_get_page_count)(const struct device *dev); + +/** + * @brief Get flash size. + * + * Total size of flash device in bytes. + * + * @param[in] dev flash device. + * + * @return Total size of device in bytes; negative errno code on error. + */ +typedef ssize_t (*flash_api_get_size)(const struct device *dev); + typedef int (*flash_api_sfdp_read)(const struct device *dev, off_t offset, void *data, size_t len); typedef int (*flash_api_read_jedec_id)(const struct device *dev, uint8_t *id); @@ -129,6 +194,9 @@ __subsystem struct flash_driver_api { flash_api_write write; flash_api_erase erase; flash_api_get_parameters get_parameters; + flash_api_get_page_info get_page_info; + flash_api_get_page_count get_page_count; + flash_api_get_size get_size; #if defined(CONFIG_FLASH_PAGE_LAYOUT) flash_api_pages_layout page_layout; #endif /* CONFIG_FLASH_PAGE_LAYOUT */ @@ -248,7 +316,7 @@ struct flash_pages_info { uint32_t index; }; -#if defined(CONFIG_FLASH_PAGE_LAYOUT) +#if defined(CONFIG_FLASH_PAGE_LAYOUT) || defined(CONFIG_FLASH_PAGE_LAYOUT_WITHOUT_API_PAGE_LAYOUT) /** * @brief Get the size and start offset of flash page at certain flash offset. * @@ -275,15 +343,6 @@ __syscall int flash_get_page_info_by_idx(const struct device *dev, uint32_t page_index, struct flash_pages_info *info); -/** - * @brief Get the total number of flash pages. - * - * @param dev flash device - * - * @return Number of flash pages. - */ -__syscall size_t flash_get_page_count(const struct device *dev); - /** * @brief Callback type for iterating over flash pages present on a device. * @@ -398,7 +457,6 @@ static inline size_t z_impl_flash_get_write_block_size(const struct device *dev) return api->get_parameters(dev)->write_block_size; } - /** * @brief Get pointer to flash_parameters structure * @@ -420,6 +478,76 @@ static inline const struct flash_parameters *z_impl_flash_get_parameters(const s return api->get_parameters(dev); } +/** + * @brief Get flash page info at given offset + * + * Fills in flash_page_info structure with information on the flash page that is at given offset. + * In case when the dev is virtual device that begins at the middle of page the returned offset + * this will return error if the offset is at the split page. + * + * @param[in] dev flash device; + * @param[in] off offset; + * @param[out] fpi pointer to flash_page_info for obtained information; + * + * If flash has gaps and the offset is within gap, then the \p fpi will be filled with information + * on that gap, as a single continuous page, and -ENOENT will be returned. + * + * @return 0 on success; + * -ENOENT if returned information is about gap in flash address space; + * -EINVAL if offset is outside of flash device; + * other negative errno code on error. + */ +__syscall int flash_get_page_info(const struct device *dev, off_t off, struct flash_page_info *fpi); + +static int z_impl_flash_get_page_info(const struct device *dev, off_t off, + struct flash_page_info *fpi) +{ + const struct flash_driver_api *api = (const struct flash_driver_api *)dev->api; + + return api->get_page_info(dev, off, fpi); +} + +/** + * @brief Get flash page count + * + * Returns total number of pages available on device; in case of virtual devices that are + * incorrectly configured to split pages at the beginning or the end of range, this will return + * number of complete pages. + * When device has gaps in address space, each gap is considered single continuous range and + * is added to a number of real pages. + * + * @param[in] dev flash device; + * + * @return Total number of flash pages on device on success; + * negative errno code on error. + */ +__syscall ssize_t flash_get_page_count(const struct device *dev); + +static ssize_t z_impl_flash_get_page_count(const struct device *dev) +{ + const struct flash_driver_api *api = (const struct flash_driver_api *)dev->api; + + return api->get_page_count(dev); +} + +/** + * @brief Get flash size + * + * Get total size of flash in bytes. The size does not include gaps in address space. + * + * @param[in] dev flash device; + * + * @return Total size of device in bytes; negative errno code on error. + */ +__syscall ssize_t flash_get_size(const struct device *dev); + +static ssize_t z_impl_flash_get_size(const struct device *dev) +{ + const struct flash_driver_api *api = (const struct flash_driver_api *)dev->api; + + return api->get_size(dev); +} + #ifdef __cplusplus } #endif diff --git a/tests/drivers/flash/testcase.yaml b/tests/drivers/flash/testcase.yaml index fbf5051464dfa..c4ac77dc30ecd 100644 --- a/tests/drivers/flash/testcase.yaml +++ b/tests/drivers/flash/testcase.yaml @@ -31,6 +31,25 @@ tests: tags: mcux integration_platforms: - mimxrt1060_evk + drivers.flash_new_api.nrf_qspi_nor: + platform_allow: nrf52840dk_nrf52840 + tags: flash nrf52 nrf_qspi_fash + extra_args: OVERLAY_CONFIG=boards/nrf52840_flash_qspi.conf + extra_configs: + - CONFIG_FLASH_PAGE_LAYOUT_WITHOUT_API_PAGE_LAYOUT=y + drivers.flash_new_api.soc_flash_nrf: + platform_allow: nrf52840dk_nrf52840 + tags: nrf52 soc_flash_nrf_new_api + extra_args: OVERLAY_CONFIG=boards/nrf52840_flash_soc.conf + extra_configs: + - CONFIG_FLASH_PAGE_LAYOUT_WITHOUT_API_PAGE_LAYOUT=y + drivers.flash_new_api.default: + platform_allow: mimxrt1060_evk + tags: mcux + integration_platforms: + - mimxrt1060_evk + extra_configs: + - CONFIG_FLASH_PAGE_LAYOUT_WITHOUT_API_PAGE_LAYOUT=y drivers.flash.stm32: integration_platforms: - nucleo_f091rc diff --git a/tests/drivers/flash_api/CMakeLists.txt b/tests/drivers/flash_api/CMakeLists.txt new file mode 100644 index 0000000000000..21baa2063f0ac --- /dev/null +++ b/tests/drivers/flash_api/CMakeLists.txt @@ -0,0 +1,12 @@ +# +# Copyright (c) 2021 Nordic Semiconductor ASA. +# +# SPDX-License-Identifier: Apache-2.0 +# + +cmake_minimum_required(VERSION 3.13.1) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(flash_api_tests) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/drivers/flash_api/prj.conf b/tests/drivers/flash_api/prj.conf new file mode 100644 index 0000000000000..d7f11fde28cb8 --- /dev/null +++ b/tests/drivers/flash_api/prj.conf @@ -0,0 +1,7 @@ +# +# Copyright (c) 2021 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# +CONFIG_ZTEST=y +CONFIG_FLASH=y diff --git a/tests/drivers/flash_api/src/main.c b/tests/drivers/flash_api/src/main.c new file mode 100644 index 0000000000000..92ab4b3c2ea4f --- /dev/null +++ b/tests/drivers/flash_api/src/main.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2021 Nordic Semiconductor ASA. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +/** Test instrumentation **/ +/* + * Below structure gathers variables that may be used by simulate API calls to mock behaviour + * of a flash device; the variables may be used however it is desired, because the it is + * up to mocked function and check afterwards to relate a variable to result + */ +static struct { + /* Set to value returned from any API call */ + int ret; + /* Some offset */ + off_t offset; + /* Some size */ + size_t size; + /* Allowed offset alignment */ +} api_test_values = { + .ret = 0, + .offset = 0, + .size = 0, +}; + +/*** Device definition atd == API Test Dev ***/ +/** Device API callbacks **/ +static int atd_get_page_info(const struct device *dev, off_t offset, struct flash_page_info *fpi) +{ + __ASSERT_NO_MSG(dev != NULL); + __ASSERT_NO_MSG(fpi != NULL); + + fpi->offset = offset; + fpi->size = api_test_values.size; + + return api_test_values.ret; +} + +static ssize_t atd_get_page_count(const struct device *dev) +{ + __ASSERT_NO_MSG(dev != NULL); + + return api_test_values.size; +} + +static ssize_t atd_get_size(const struct device *dev) +{ + __ASSERT_NO_MSG(dev != NULL); + + return api_test_values.size; +} + +/** Device objects **/ +/* The device state */ +static struct device_state atd_state = { + .init_res = 0, + .initialized = 1, +}; + +/* Device structure */ +static struct flash_driver_api atd_op = { + .get_page_info = atd_get_page_info, + .get_page_count = atd_get_page_count, + .get_size = atd_get_size, +}; + +/* The device */ +static struct device atd = { + "test_flash", NULL, &atd_op, &atd_state, NULL, NULL, +}; + +static void test_get_page_info(void) +{ + struct flash_page_info pi; + + /* Check if flash_get_page_info properly calls the get_page_info API call */ + api_test_values.offset = 10; + api_test_values.size = 30; + api_test_values.ret = 40; + zassert_equal(flash_get_page_info(&atd, api_test_values.offset, &pi), + api_test_values.ret, "Other ret value expected"); + zassert_equal(pi.offset, api_test_values.offset, "Offset mismatch"); + zassert_equal(pi.size, api_test_values.size, "Size mismatch"); + /* Never trust one call */ + api_test_values.offset = 11; + api_test_values.size = 32; + api_test_values.ret = 43; + zassert_equal(flash_get_page_info(&atd, api_test_values.offset, &pi), + api_test_values.ret, "Other ret value expected"); + zassert_equal(pi.offset, api_test_values.offset, "Offset mismatch"); + zassert_equal(pi.size, api_test_values.size, "Size mismatch"); +} + +static void test_get_page_count(void) +{ + api_test_values.size = 30; + zassert_equal(flash_get_page_count(&atd), api_test_values.size, "Page count mismatch"); + api_test_values.size = 31; + zassert_equal(flash_get_page_count(&atd), api_test_values.size, "Page count mismatch"); +} + +static void test_get_size(void) +{ + api_test_values.size = 45; + zassert_equal(flash_get_size(&atd), api_test_values.size, "Size mismatch"); + api_test_values.size = 46; + zassert_equal(flash_get_size(&atd), api_test_values.size, "Size mismatch"); +} + +void test_main(void) +{ + ztest_test_suite(flash_api, + ztest_unit_test(test_get_page_info), + ztest_unit_test(test_get_page_count), + ztest_unit_test(test_get_size) + ); + + ztest_run_test_suite(flash_api); +} diff --git a/tests/drivers/flash_api/testcase.yaml b/tests/drivers/flash_api/testcase.yaml new file mode 100644 index 0000000000000..8666bd40c0203 --- /dev/null +++ b/tests/drivers/flash_api/testcase.yaml @@ -0,0 +1,55 @@ +# +# Copyright (c) 2021 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# +tests: + drivers.flash.api: + tags: driver flash_api + platform_exclude: \ + hexiwear_kw40z \ + nucleo_h745zi_q_m4 \ + stm32h747i_disco_m4 + drivers.flash.api.userspace: + tags: driver flash_api userspace + extra_configs: + - CONFIG_USERSPACE=y + platform_exclude: \ + hexiwear_kw40z \ + nucleo_h745zi_q_m4 \ + stm32h747i_disco_m4 + # Just trick twister into building other flash drivers; they are not really used here but + # other flash tests require definition of flash partitions to work or attaching flash + # simulator, so there is not a test case that at least checks, in an easy way, whether + # the drivers still compile. + drivers.flash.api.build_only: + tags: driver flash_api + build_only: true + platform_allow: \ + altera_max10 \ + atsamd20_xpro \ + disco_l475_iot1 \ + efm32gg_slwstk6121a \ + esp32 \ + intel_s1000_crb \ + lpcxpresso54114_m4 \ + lpcxpresso55s28 \ + mimxrt1064_evk \ + nrf52840dk_nrf52840 \ + nrf9160dk_nrf9160 \ + nucleo_h723zg \ + nucleo_g431rb \ + nucleo_g474re \ + nucleo_wb55rg \ + rv32m1_vega_zero_riscy \ + sam_e70_xplained \ + sam4e_xpro \ + stm32f3_disco \ + stm32f4_disco \ + stm32f411e_disco \ + stm32f412g_disco \ + stm32f429i_disc1 \ + stm32f746g_disco \ + stm32h747i_disco_m7 \ + stm32g0316_disco \ + stm32l1_disco