diff --git a/drivers/flash/CMakeLists.txt b/drivers/flash/CMakeLists.txt index 97d9cd55059..4bc76b2d516 100644 --- a/drivers/flash/CMakeLists.txt +++ b/drivers/flash/CMakeLists.txt @@ -47,6 +47,7 @@ zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_ESP32 flash_esp32.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_GECKO flash_gecko.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_ITE_IT8XXX2 flash_ite_it8xxx2.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_LPC soc_flash_lpc.c) +zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_MAX32 flash_max32.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_MCUX soc_flash_mcux.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_NIOS2_QSPI soc_flash_nios2_qspi.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_NRF soc_flash_nrf.c) diff --git a/drivers/flash/Kconfig b/drivers/flash/Kconfig index 4ab3e9da14f..bc9f6e69d7e 100644 --- a/drivers/flash/Kconfig +++ b/drivers/flash/Kconfig @@ -177,6 +177,7 @@ source "drivers/flash/Kconfig.gecko" source "drivers/flash/Kconfig.ifx_cat1" source "drivers/flash/Kconfig.it8xxx2" source "drivers/flash/Kconfig.lpc" +source "drivers/flash/Kconfig.max32" source "drivers/flash/Kconfig.mcux" source "drivers/flash/Kconfig.mspi" source "drivers/flash/Kconfig.nios2_qspi" diff --git a/drivers/flash/Kconfig.max32 b/drivers/flash/Kconfig.max32 new file mode 100644 index 00000000000..fd7cb0a8591 --- /dev/null +++ b/drivers/flash/Kconfig.max32 @@ -0,0 +1,12 @@ +# Copyright (c) 2023 Analog Devices, Inc. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FLASH_MAX32 + bool "ADI MAX32 flash driver" + default y + depends on DT_HAS_ADI_MAX32_FLASH_CONTROLLER_ENABLED + select FLASH_HAS_DRIVER_ENABLED + select FLASH_HAS_EXPLICIT_ERASE + select FLASH_HAS_PAGE_LAYOUT + help + Enable MAX32 internal flash driver. diff --git a/drivers/flash/flash_max32.c b/drivers/flash/flash_max32.c new file mode 100644 index 00000000000..9e75f0557a2 --- /dev/null +++ b/drivers/flash/flash_max32.c @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2023-2024 Analog Devices, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT adi_max32_flash_controller + +#include +#include +#include +#include + +#include "flc.h" + +struct max32_flash_dev_config { + uint32_t flash_base; + uint32_t flash_erase_blk_sz; + struct flash_parameters parameters; +#if CONFIG_FLASH_PAGE_LAYOUT + struct flash_pages_layout pages_layouts; +#endif /* CONFIG_FLASH_PAGE_LAYOUT */ +}; + +struct max32_flash_dev_data { +#ifdef CONFIG_MULTITHREADING + struct k_sem sem; +#endif +}; + +#ifdef CONFIG_MULTITHREADING +static inline void max32_sem_take(const struct device *dev) +{ + struct max32_flash_dev_data *data = dev->data; + + k_sem_take(&data->sem, K_FOREVER); +} + +static inline void max32_sem_give(const struct device *dev) +{ + struct max32_flash_dev_data *data = dev->data; + + k_sem_give(&data->sem); +} +#else + +#define max32_sem_take(dev) +#define max32_sem_give(dev) + +#endif /* CONFIG_MULTITHREADING */ + +static int api_read(const struct device *dev, off_t address, void *buffer, size_t length) +{ + const struct max32_flash_dev_config *const cfg = dev->config; + + address += cfg->flash_base; + MXC_FLC_Read(address, buffer, length); + return 0; +} + +static int api_write(const struct device *dev, off_t address, const void *buffer, size_t length) +{ + const struct max32_flash_dev_config *const cfg = dev->config; + int ret = 0; + + max32_sem_take(dev); + + address += cfg->flash_base; + ret = MXC_FLC_Write(address, length, (uint32_t *)buffer); + + max32_sem_give(dev); + + return ret != 0 ? -EIO : 0; +} + +static int api_erase(const struct device *dev, off_t start, size_t len) +{ + const struct max32_flash_dev_config *const cfg = dev->config; + uint32_t page_size = cfg->flash_erase_blk_sz; + uint32_t addr = (start + cfg->flash_base); + int ret = 0; + + max32_sem_take(dev); + + while (len) { + ret = MXC_FLC_PageErase(addr); + if (ret) { + break; + } + + addr += page_size; + if (len > page_size) { + len -= page_size; + } else { + len = 0; + } + } + + max32_sem_give(dev); + + return ret != 0 ? -EIO : 0; +} + +#if CONFIG_FLASH_PAGE_LAYOUT +static void api_page_layout(const struct device *dev, const struct flash_pages_layout **layout, + size_t *layout_size) +{ + const struct max32_flash_dev_config *const cfg = dev->config; + + *layout = &cfg->pages_layouts; + *layout_size = 1; +} +#endif /* CONFIG_FLASH_PAGE_LAYOUT */ + +static const struct flash_parameters *api_get_parameters(const struct device *dev) +{ + const struct max32_flash_dev_config *const cfg = dev->config; + + return &cfg->parameters; +} + +static int flash_max32_init(const struct device *dev) +{ + int ret = MXC_FLC_Init(); + +#ifdef CONFIG_MULTITHREADING + struct max32_flash_dev_data *data = dev->data; + + /* Mutex for flash controller */ + k_sem_init(&data->sem, 1, 1); +#endif + return ret != 0 ? -EIO : 0; +} + +static const struct flash_driver_api flash_max32_driver_api = { + .read = api_read, + .write = api_write, + .erase = api_erase, + .get_parameters = api_get_parameters, +#ifdef CONFIG_FLASH_PAGE_LAYOUT + .page_layout = api_page_layout, +#endif +}; + +#if CONFIG_FLASH_PAGE_LAYOUT +#define FLASH_MAX32_CONFIG_PAGE_LAYOUT(n) \ + .pages_layouts = { \ + .pages_count = DT_INST_FOREACH_CHILD(n, GET_FLASH_SIZE) / \ + DT_INST_FOREACH_CHILD(n, GET_ERASE_BLOCK_SIZE), \ + .pages_size = DT_INST_FOREACH_CHILD(n, GET_ERASE_BLOCK_SIZE), \ + }, +#else +#define FLASH_MAX32_CONFIG_PAGE_LAYOUT(n) +#endif + +#define GET_WRITE_BLOCK_SIZE(n) DT_PROP(n, write_block_size) +#define GET_ERASE_BLOCK_SIZE(n) DT_PROP(n, erase_block_size) +#define GET_FLASH_BASE(n) DT_REG_ADDR(n) +#define GET_FLASH_SIZE(n) DT_REG_SIZE(n) + +#define DEFINE_FLASH_MAX32(_num) \ + static const struct max32_flash_dev_config max32_flash_dev_cfg_##_num = { \ + .flash_base = DT_INST_FOREACH_CHILD(_num, GET_FLASH_BASE), \ + .flash_erase_blk_sz = DT_INST_FOREACH_CHILD(_num, GET_ERASE_BLOCK_SIZE), \ + .parameters = \ + { \ + .write_block_size = \ + DT_INST_FOREACH_CHILD(_num, GET_WRITE_BLOCK_SIZE), \ + .erase_value = 0xFF, \ + }, \ + FLASH_MAX32_CONFIG_PAGE_LAYOUT(_num)}; \ + static struct max32_flash_dev_data max32_flash_dev_data_##_num; \ + DEVICE_DT_INST_DEFINE(_num, flash_max32_init, NULL, &max32_flash_dev_data_##_num, \ + &max32_flash_dev_cfg_##_num, POST_KERNEL, \ + CONFIG_FLASH_INIT_PRIORITY, &flash_max32_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(DEFINE_FLASH_MAX32)