From d97479fdc3bcfdb1fee83ffda7da770f094d5e6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Pouiller?= Date: Fri, 31 Jan 2025 12:15:36 +0100 Subject: [PATCH] drivers: flash: Introduce SiWx91x Flash driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add flash driver for Silicon Labs SiWx91x family. Co-authored-by: Martin Hoff Signed-off-by: Martin Hoff Signed-off-by: Jérôme Pouiller --- drivers/flash/CMakeLists.txt | 1 + drivers/flash/Kconfig | 1 + drivers/flash/Kconfig.siwx91x | 15 ++ drivers/flash/soc_flash_silabs_siwx91x.c | 176 ++++++++++++++++++ .../silabs,siwx91x-flash-controller.yaml | 8 + 5 files changed, 201 insertions(+) create mode 100644 drivers/flash/Kconfig.siwx91x create mode 100644 drivers/flash/soc_flash_silabs_siwx91x.c create mode 100644 dts/bindings/flash_controller/silabs,siwx91x-flash-controller.yaml diff --git a/drivers/flash/CMakeLists.txt b/drivers/flash/CMakeLists.txt index 50f6498c3a7..474205e3973 100644 --- a/drivers/flash/CMakeLists.txt +++ b/drivers/flash/CMakeLists.txt @@ -60,6 +60,7 @@ zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_RV32M1 soc_flash_rv32m1.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_SAM flash_sam.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_SAM0 flash_sam0.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_SI32 flash_si32.c) +zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_SILABS_SIWX91X soc_flash_silabs_siwx91x.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_SMARTBOND flash_smartbond.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_TELINK_B91 soc_flash_b91.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_XMC4XXX soc_flash_xmc4xxx.c) diff --git a/drivers/flash/Kconfig b/drivers/flash/Kconfig index edfa81224dc..00ffd104a88 100644 --- a/drivers/flash/Kconfig +++ b/drivers/flash/Kconfig @@ -198,6 +198,7 @@ source "drivers/flash/Kconfig.sam" source "drivers/flash/Kconfig.sam0" source "drivers/flash/Kconfig.si32" source "drivers/flash/Kconfig.simulator" +source "drivers/flash/Kconfig.siwx91x" source "drivers/flash/Kconfig.smartbond" source "drivers/flash/Kconfig.stm32" source "drivers/flash/Kconfig.stm32_ospi" diff --git a/drivers/flash/Kconfig.siwx91x b/drivers/flash/Kconfig.siwx91x new file mode 100644 index 00000000000..ec7e7af209b --- /dev/null +++ b/drivers/flash/Kconfig.siwx91x @@ -0,0 +1,15 @@ +# Copyright (c) 2024 Silicon Laboratories Inc. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FLASH_SILABS_SIWX91X + bool "Silicon Labs SiWx91x flash driver" + default y + depends on DT_HAS_SILABS_SIWX91X_FLASH_CONTROLLER_ENABLED + select FLASH_HAS_DRIVER_ENABLED + select FLASH_HAS_EXPLICIT_ERASE + select FLASH_HAS_PAGE_LAYOUT + # Flash controller is handled by the network coprocessor + select WISECONNECT_NETWORK_STACK + help + Enable flash controller for flash embedded on Silicon Labs SiWx91x + chips. diff --git a/drivers/flash/soc_flash_silabs_siwx91x.c b/drivers/flash/soc_flash_silabs_siwx91x.c new file mode 100644 index 00000000000..9e714ce814d --- /dev/null +++ b/drivers/flash/soc_flash_silabs_siwx91x.c @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2024 Silicon Laboratories Inc. + * SPDX-License-Identifier: Apache-2.0 + */ +#define DT_DRV_COMPAT silabs_siwx91x_flash_controller + +#include +#include +#include +#include + +#include "sl_si91x_driver.h" + +LOG_MODULE_REGISTER(siwx91x_soc_flash); + +struct siwx91x_config { + uintptr_t base_address; + uint32_t size; + uint32_t write_block_size; + uint32_t erase_block_size; + struct flash_parameters flash_parameters; +#ifdef CONFIG_FLASH_PAGE_LAYOUT + struct flash_pages_layout flash_pages_layout; +#endif +}; + +struct siwx91x_data { + struct k_sem lock; +}; + +static bool flash_siwx91x_range_is_in_bounds(const struct device *dev, off_t offset, size_t len) +{ + const struct siwx91x_config *cfg = dev->config; + + /* Note: If offset < __rom_region_end, the user to overwriting the current firmware. User + * is probably doing a mistake, but not an error from this driver point of view. + */ + if (offset < 0) { + return false; + } + if (offset + len > cfg->size) { + return false; + } + return true; +} + +static const struct flash_parameters *flash_siwx91x_get_parameters(const struct device *dev) +{ + const struct siwx91x_config *cfg = dev->config; + + return &cfg->flash_parameters; +} + +static int flash_siwx91x_read(const struct device *dev, off_t offset, void *buf, size_t len) +{ + const struct siwx91x_config *cfg = dev->config; + struct siwx91x_data *data = dev->data; + void *location = (void *)(cfg->base_address + offset); + + if (!flash_siwx91x_range_is_in_bounds(dev, offset, len)) { + return -EINVAL; + } + k_sem_take(&data->lock, K_FOREVER); + memcpy(buf, location, len); + k_sem_give(&data->lock); + return 0; +} + +static int flash_siwx91x_write(const struct device *dev, off_t offset, const void *buf, size_t len) +{ + const struct siwx91x_config *cfg = dev->config; + struct siwx91x_data *data = dev->data; + uint32_t ret; + + if (!flash_siwx91x_range_is_in_bounds(dev, offset, len)) { + return -EINVAL; + } + if (offset % cfg->write_block_size) { + return -EINVAL; + } + if (len % cfg->write_block_size) { + return -EINVAL; + } + k_sem_take(&data->lock, K_FOREVER); + ret = sl_si91x_command_to_write_common_flash(cfg->base_address + offset, (void *)buf, len, + false); + k_sem_give(&data->lock); + if (ret) { + return -EIO; + } + return 0; +} + +static int flash_siwx91x_erase(const struct device *dev, off_t offset, size_t len) +{ + const struct siwx91x_config *cfg = dev->config; + struct siwx91x_data *data = dev->data; + uint32_t ret; + + if (!flash_siwx91x_range_is_in_bounds(dev, offset, len)) { + return -EINVAL; + } + if (offset % cfg->erase_block_size) { + return -EINVAL; + } + if (len % cfg->erase_block_size) { + return -EINVAL; + } + k_sem_take(&data->lock, K_FOREVER); + ret = sl_si91x_command_to_write_common_flash(cfg->base_address + offset, NULL, len, true); + k_sem_give(&data->lock); + if (ret) { + return -EIO; + } + return 0; +} + +#ifdef CONFIG_FLASH_PAGE_LAYOUT +static void flash_siwx91x_page_layout(const struct device *dev, + const struct flash_pages_layout **layout, size_t *layout_size) +{ + const struct siwx91x_config *cfg = dev->config; + + *layout = &cfg->flash_pages_layout; + *layout_size = 1; +} +#endif + +static DEVICE_API(flash, siwx91x_api) = { + .read = flash_siwx91x_read, + .write = flash_siwx91x_write, + .erase = flash_siwx91x_erase, + .get_parameters = flash_siwx91x_get_parameters, +#ifdef CONFIG_FLASH_PAGE_LAYOUT + .page_layout = flash_siwx91x_page_layout, +#endif +}; + +static int flash_siwx91x_init(const struct device *dev) +{ + struct siwx91x_data *data = dev->data; + + k_sem_init(&data->lock, 1, 1); + return 0; +} + +#ifdef CONFIG_FLASH_PAGE_LAYOUT +#define SIWX91X_PAGE_LAYOUT_FLASH_INIT(n) \ + .flash_pages_layout.pages_count = DT_REG_SIZE(n) / DT_PROP(n, erase_block_size), \ + .flash_pages_layout.pages_size = DT_PROP(n, erase_block_size), +#else +#define SIWX91X_PAGE_LAYOUT_FLASH_INIT(n) +#endif + +#define SIWX91X_FLASH_INIT_P(n, p) \ + static const struct siwx91x_config flash_siwx91x_config_##p = { \ + .base_address = DT_REG_ADDR(n), \ + .size = DT_REG_SIZE(n), \ + .write_block_size = DT_PROP(n, write_block_size), \ + .erase_block_size = DT_PROP(n, erase_block_size), \ + .flash_parameters.write_block_size = DT_PROP(n, write_block_size), \ + .flash_parameters.erase_value = 0xff, \ + SIWX91X_PAGE_LAYOUT_FLASH_INIT(n) \ + }; \ + static struct siwx91x_data flash_siwx91x_data_##p = { \ + .lock = Z_SEM_INITIALIZER(flash_siwx91x_data_##p.lock, 1, 1), \ + }; \ + DEVICE_DT_INST_DEFINE(p, flash_siwx91x_init, NULL, &flash_siwx91x_data_##p, \ + &flash_siwx91x_config_##p, POST_KERNEL, CONFIG_FLASH_INIT_PRIORITY, \ + &siwx91x_api); + +#define SIWX91X_FLASH_INIT(p) \ + BUILD_ASSERT(DT_INST_CHILD_NUM_STATUS_OKAY(p) == 1); \ + DT_INST_FOREACH_CHILD_STATUS_OKAY_VARGS(p, SIWX91X_FLASH_INIT_P, p) + +DT_INST_FOREACH_STATUS_OKAY(SIWX91X_FLASH_INIT) diff --git a/dts/bindings/flash_controller/silabs,siwx91x-flash-controller.yaml b/dts/bindings/flash_controller/silabs,siwx91x-flash-controller.yaml new file mode 100644 index 00000000000..c12753253a0 --- /dev/null +++ b/dts/bindings/flash_controller/silabs,siwx91x-flash-controller.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2024 Silicon Laboratories Inc. +# SPDX-License-Identifier: Apache-2.0 + +description: Silicon Labs SiWx91x flash controller + +compatible: "silabs,siwx91x-flash-controller" + +include: flash-controller.yaml