zephyr/drivers/flash/flash_gd32.c
HaiLong Yang 51363ae7c2 drivers: flash: introduce gd32 fmc driver
This supports three types GD32 FMC flash memory. GD32 FMC v1,
GD32 FMC v2 and GD32 FMC v3.

GD32 FMC v1 for small flash memory, flash size can be up to 512KB.

GD32 FMC v2 for large flash memory, flash size can be up to 3072KB.

GD32 FMC v3 not use page but sector as minimum block, flash size can
be up to 3072KB.

Signed-off-by: HaiLong Yang <hailong.yang@brainco.cn>
2022-09-08 10:13:05 +02:00

123 lines
2.4 KiB
C

/*
* Copyright (c) 2022 BrainCo Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT gd_gd32_flash_controller
#include "flash_gd32.h"
#include <zephyr/kernel.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/flash.h>
#include <zephyr/logging/log.h>
#include <gd32_fmc.h>
LOG_MODULE_REGISTER(flash_gd32, CONFIG_FLASH_LOG_LEVEL);
struct flash_gd32_data {
struct k_sem mutex;
};
static struct flash_gd32_data flash_data;
static const struct flash_parameters flash_gd32_parameters = {
.write_block_size = SOC_NV_FLASH_PRG_SIZE,
.erase_value = 0xff,
};
static int flash_gd32_read(const struct device *dev, off_t offset,
void *data, size_t len)
{
if ((offset > SOC_NV_FLASH_SIZE) ||
((offset + len) > SOC_NV_FLASH_SIZE)) {
return -EINVAL;
}
if (len == 0U) {
return 0;
}
memcpy(data, (uint8_t *)SOC_NV_FLASH_ADDR + offset, len);
return 0;
}
static int flash_gd32_write(const struct device *dev, off_t offset,
const void *data, size_t len)
{
struct flash_gd32_data *dev_data = dev->data;
int ret = 0;
if (!flash_gd32_valid_range(offset, len, true)) {
return -EINVAL;
}
if (len == 0U) {
return 0;
}
k_sem_take(&dev_data->mutex, K_FOREVER);
ret = flash_gd32_write_range(offset, data, len);
k_sem_give(&dev_data->mutex);
return ret;
}
static int flash_gd32_erase(const struct device *dev, off_t offset, size_t size)
{
struct flash_gd32_data *data = dev->data;
int ret = 0;
if (size == 0U) {
return 0;
}
if (!flash_gd32_valid_range(offset, size, false)) {
return -EINVAL;
}
k_sem_take(&data->mutex, K_FOREVER);
ret = flash_gd32_erase_block(offset, size);
k_sem_give(&data->mutex);
return ret;
}
static const struct flash_parameters*
flash_gd32_get_parameters(const struct device *dev)
{
ARG_UNUSED(dev);
return &flash_gd32_parameters;
}
static const struct flash_driver_api flash_gd32_driver_api = {
.read = flash_gd32_read,
.write = flash_gd32_write,
.erase = flash_gd32_erase,
.get_parameters = flash_gd32_get_parameters,
#ifdef CONFIG_FLASH_PAGE_LAYOUT
.page_layout = flash_gd32_pages_layout,
#endif
};
static int flash_gd32_init(const struct device *dev)
{
struct flash_gd32_data *data = dev->data;
k_sem_init(&data->mutex, 1, 1);
return 0;
}
DEVICE_DT_INST_DEFINE(0, flash_gd32_init, NULL,
&flash_data, NULL, POST_KERNEL,
CONFIG_FLASH_INIT_PRIORITY, &flash_gd32_driver_api);