185 lines
4.4 KiB
C
185 lines
4.4 KiB
C
/*
|
|
* 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);
|