| /* |
| * Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd. |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #define DT_DRV_COMPAT espressif_esp32_flash_controller |
| #define SOC_NV_FLASH_NODE DT_INST(0, soc_nv_flash) |
| |
| #define FLASH_WRITE_BLK_SZ DT_PROP(SOC_NV_FLASH_NODE, write_block_size) |
| #define FLASH_ERASE_BLK_SZ DT_PROP(SOC_NV_FLASH_NODE, erase_block_size) |
| |
| /* |
| * HAL includes go first to |
| * avoid BIT macro redefinition |
| */ |
| #include <esp_flash.h> |
| #include <spi_flash_mmap.h> |
| #include <soc/spi_struct.h> |
| #include <esp_flash_encrypt.h> |
| #include <esp_flash_internal.h> |
| |
| #include <zephyr/kernel.h> |
| #include <zephyr/device.h> |
| #include <stddef.h> |
| #include <string.h> |
| #include <errno.h> |
| #include <zephyr/drivers/flash.h> |
| #include <soc.h> |
| |
| #include <zephyr/logging/log.h> |
| LOG_MODULE_REGISTER(flash_esp32, CONFIG_FLASH_LOG_LEVEL); |
| |
| #define FLASH_SEM_TIMEOUT (k_is_in_isr() ? K_NO_WAIT : K_FOREVER) |
| |
| struct flash_esp32_dev_config { |
| spi_dev_t *controller; |
| }; |
| |
| struct flash_esp32_dev_data { |
| #ifdef CONFIG_MULTITHREADING |
| struct k_sem sem; |
| #endif |
| }; |
| |
| static const struct flash_parameters flash_esp32_parameters = { |
| .write_block_size = FLASH_WRITE_BLK_SZ, |
| .erase_value = 0xff, |
| }; |
| |
| #ifdef CONFIG_MULTITHREADING |
| static inline void flash_esp32_sem_take(const struct device *dev) |
| { |
| struct flash_esp32_dev_data *data = dev->data; |
| |
| k_sem_take(&data->sem, FLASH_SEM_TIMEOUT); |
| } |
| |
| static inline void flash_esp32_sem_give(const struct device *dev) |
| { |
| struct flash_esp32_dev_data *data = dev->data; |
| |
| k_sem_give(&data->sem); |
| } |
| #else |
| |
| #define flash_esp32_sem_take(dev) do {} while (0) |
| #define flash_esp32_sem_give(dev) do {} while (0) |
| |
| #endif /* CONFIG_MULTITHREADING */ |
| |
| static int flash_esp32_read(const struct device *dev, off_t address, void *buffer, size_t length) |
| { |
| int ret = 0; |
| |
| flash_esp32_sem_take(dev); |
| if (!esp_flash_encryption_enabled()) { |
| ret = esp_flash_read(NULL, buffer, address, length); |
| } else { |
| ret = esp_flash_read_encrypted(NULL, address, buffer, length); |
| } |
| flash_esp32_sem_give(dev); |
| if (ret != 0) { |
| LOG_ERR("esp_flash_read failed %d", ret); |
| return -EIO; |
| } |
| return 0; |
| } |
| |
| static int flash_esp32_write(const struct device *dev, |
| off_t address, |
| const void *buffer, |
| size_t length) |
| { |
| int ret = 0; |
| |
| flash_esp32_sem_take(dev); |
| if (!esp_flash_encryption_enabled()) { |
| ret = esp_flash_write(NULL, buffer, address, length); |
| } else { |
| ret = esp_flash_write_encrypted(NULL, address, buffer, length); |
| } |
| flash_esp32_sem_give(dev); |
| |
| if (ret != 0) { |
| LOG_ERR("esp_flash_write failed %d", ret); |
| return -EIO; |
| } |
| return 0; |
| } |
| |
| static int flash_esp32_erase(const struct device *dev, off_t start, size_t len) |
| { |
| flash_esp32_sem_take(dev); |
| int ret = esp_flash_erase_region(NULL, start, len); |
| flash_esp32_sem_give(dev); |
| if (ret != 0) { |
| LOG_ERR("esp_flash_erase_region failed %d", ret); |
| return -EIO; |
| } |
| return 0; |
| } |
| |
| #if CONFIG_FLASH_PAGE_LAYOUT |
| static const struct flash_pages_layout flash_esp32_pages_layout = { |
| .pages_count = DT_REG_SIZE(SOC_NV_FLASH_NODE) / FLASH_ERASE_BLK_SZ, |
| .pages_size = DT_PROP(SOC_NV_FLASH_NODE, erase_block_size), |
| }; |
| |
| void flash_esp32_page_layout(const struct device *dev, |
| const struct flash_pages_layout **layout, |
| size_t *layout_size) |
| { |
| *layout = &flash_esp32_pages_layout; |
| *layout_size = 1; |
| } |
| #endif /* CONFIG_FLASH_PAGE_LAYOUT */ |
| |
| static const struct flash_parameters * |
| flash_esp32_get_parameters(const struct device *dev) |
| { |
| ARG_UNUSED(dev); |
| |
| return &flash_esp32_parameters; |
| } |
| |
| static int flash_esp32_init(const struct device *dev) |
| { |
| uint32_t ret = 0; |
| |
| #ifdef CONFIG_MULTITHREADING |
| struct flash_esp32_dev_data *const dev_data = dev->data; |
| |
| k_sem_init(&dev_data->sem, 1, 1); |
| #endif /* CONFIG_MULTITHREADING */ |
| ret = esp_flash_init_default_chip(); |
| if (ret != 0) { |
| LOG_ERR("esp_flash_init_default_chip failed %d", ret); |
| return 0; |
| } |
| return 0; |
| } |
| |
| static const struct flash_driver_api flash_esp32_driver_api = { |
| .read = flash_esp32_read, |
| .write = flash_esp32_write, |
| .erase = flash_esp32_erase, |
| .get_parameters = flash_esp32_get_parameters, |
| #ifdef CONFIG_FLASH_PAGE_LAYOUT |
| .page_layout = flash_esp32_page_layout, |
| #endif |
| }; |
| |
| static struct flash_esp32_dev_data flash_esp32_data; |
| |
| static const struct flash_esp32_dev_config flash_esp32_config = { |
| .controller = (spi_dev_t *) DT_INST_REG_ADDR(0), |
| }; |
| |
| DEVICE_DT_INST_DEFINE(0, flash_esp32_init, |
| NULL, |
| &flash_esp32_data, &flash_esp32_config, |
| POST_KERNEL, CONFIG_FLASH_INIT_PRIORITY, |
| &flash_esp32_driver_api); |