Files
base/middleware/disk/disk_norflash.c
2025-11-07 09:57:14 +08:00

451 lines
15 KiB
C

/**
* @file disk_norflash.c
*
* Copyright (c) 2021 Semidrive Semiconductor.
* All rights reserved.
*
* Description:
*
* Revision History:
* -----------------
*/
#include <debug.h>
#include <disk.h>
#include <disk_norflash.h>
#include <param.h>
#include <stdlib.h>
#include <string.h>
#include <types.h>
static inline int norflash_dev_read(struct disk_norflash_info *norflash_info,
disk_addr_t addr, uint8_t *buf,
disk_size_t length)
{
if (norflash_info->config.norflash_read)
return norflash_info->config.norflash_read(
norflash_info->config.norflash_dev, addr, buf, length);
else
return -DISK_ERROR_READ_ACCESS;
}
static inline int norflash_dev_write(struct disk_norflash_info *norflash_info,
disk_addr_t addr, const uint8_t *buf,
disk_size_t length)
{
if (norflash_info->config.norflash_write)
return norflash_info->config.norflash_write(
norflash_info->config.norflash_dev, addr, buf, length);
else
return -DISK_ERROR_WRITE_ACCESS;
}
static inline int norflash_dev_erase(struct disk_norflash_info *norflash_info,
disk_addr_t addr, disk_size_t length)
{
if (norflash_info->config.norflash_erase)
return norflash_info->config.norflash_erase(
norflash_info->config.norflash_dev, addr, length);
else
return -DISK_ERROR_ERASE_ACCESS;
}
static int disk_norflash_read(struct disk_info *info, uint8_t *dst,
disk_addr_t addr, disk_size_t size)
{
int ret = 0;
struct disk_norflash_info *norflash_info = info->private_data;
ssdk_printf(SSDK_DEBUG,
"norflash disk read:%s mem:%p addr:%lld size:%lld\n",
info->disk_name, dst, addr, size);
disk_size_t tmp_len = 0;
while (size) {
tmp_len = size;
if (!IS_ALIGNED(dst, CONFIG_ARCH_CACHE_LINE)) {
tmp_len =
MIN(ROUNDUP((addr_t)dst, CONFIG_ARCH_CACHE_LINE) - (addr_t)dst,
size);
}
tmp_len = tmp_len > CONFIG_ARCH_CACHE_LINE
? (tmp_len - tmp_len % CONFIG_ARCH_CACHE_LINE)
: tmp_len;
if (tmp_len < CONFIG_ARCH_CACHE_LINE) {
xSemaphoreTake(norflash_info->disk_norflash_mutex, portMAX_DELAY);
if (norflash_dev_read(norflash_info, addr,
norflash_info->buff_sector,
ROUNDUP(tmp_len, 4))) {
ret = -1;
goto error;
}
memcpy(dst, norflash_info->buff_sector, tmp_len);
xSemaphoreGive(norflash_info->disk_norflash_mutex);
} else {
if (norflash_dev_read(norflash_info, addr, dst, tmp_len)) {
return -1;
}
}
addr += tmp_len;
size -= tmp_len;
dst += tmp_len;
}
return 0;
error:
xSemaphoreGive(norflash_info->disk_norflash_mutex);
return ret;
}
#if CONFIG_DISK_NOR_FLASH_BYTES_API_SUPPORT
static int disk_norflash_write(struct disk_info *info, const uint8_t *src,
disk_addr_t addr, disk_size_t size)
{
int ret = 0;
struct disk_norflash_info *norflash_info = info->private_data;
ssdk_printf(SSDK_DEBUG,
"norflash disk write:%s mem:%p addr:%lld size:%lld\n",
info->disk_name, src, addr, size);
uint32_t sector_size = norflash_info->config.sector_size;
uint32_t tmp_len;
uint8_t *buf;
while (size) {
buf = norflash_info->buff_sector;
tmp_len = size;
if (!IS_ALIGNED(addr, sector_size)) {
tmp_len = MIN(ROUNDUP(addr, sector_size) - addr, size);
} else if (IS_ALIGNED(src, CONFIG_ARCH_CACHE_LINE) &&
size >= sector_size) {
buf = (uint8_t *)src;
}
tmp_len =
tmp_len > sector_size ? (tmp_len - tmp_len % sector_size) : tmp_len;
if (src == buf) {
if (norflash_dev_erase(norflash_info, addr, tmp_len)) {
return -1;
}
if (norflash_dev_write(norflash_info, addr, buf, tmp_len)) {
return -1;
}
} else {
if (tmp_len < sector_size) {
xSemaphoreTake(norflash_info->disk_norflash_mutex,
portMAX_DELAY);
if (norflash_dev_read(norflash_info,
ROUNDDOWN(addr, sector_size), buf,
sector_size)) {
ret = -1;
goto error;
}
if (norflash_dev_erase(norflash_info,
ROUNDDOWN(addr, sector_size),
sector_size)) {
return -1;
}
} else {
if (norflash_dev_erase(norflash_info, addr, tmp_len)) {
return -1;
}
xSemaphoreTake(norflash_info->disk_norflash_mutex,
portMAX_DELAY);
}
for (disk_size_t size_tmp = 0;
size_tmp < ROUNDUP(tmp_len, sector_size);
size_tmp += sector_size) {
memcpy(buf + ((addr + size_tmp) % sector_size), src,
MIN(sector_size, tmp_len));
if (norflash_dev_write(norflash_info,
ROUNDDOWN(addr + size_tmp, sector_size),
buf, sector_size)) {
ret = -1;
goto error;
}
}
xSemaphoreGive(norflash_info->disk_norflash_mutex);
}
addr += tmp_len;
src += tmp_len;
size -= tmp_len;
}
return 0;
error:
xSemaphoreGive(norflash_info->disk_norflash_mutex);
return ret;
}
#endif
static int disk_norflash_read_block(struct disk_info *info, uint8_t *dst,
block_t block, block_count_t read_count,
block_size_t blk_sz)
{
ssdk_printf(SSDK_DEBUG,
"disk norflash read block:%s mem:%p block:%lld"
"read_count:%d blk_sz:%d addr:%lld size:%d\n",
info->disk_name, dst, block, read_count, blk_sz, block * blk_sz,
read_count * blk_sz);
return disk_norflash_read(info, dst, (disk_addr_t)block * blk_sz,
(disk_size_t)read_count * blk_sz);
}
static int disk_norflash_write_block(struct disk_info *info, const uint8_t *src,
block_t block, block_count_t write_count,
block_size_t blk_sz)
{
disk_size_t write_len;
disk_size_t remain_len = write_count * blk_sz;
disk_addr_t addr = block * blk_sz;
struct disk_norflash_info *norflash_info = info->private_data;
ssdk_printf(SSDK_DEBUG,
"disk norflash write block:%s mem:%p block:%lld"
"write_count:%d blk_sz:%d addr:%lld size:%d\n",
info->disk_name, src, block, write_count, blk_sz, block * blk_sz,
write_count * blk_sz);
while (remain_len) {
write_len = remain_len;
if (!IS_ALIGNED(src, CONFIG_ARCH_CACHE_LINE)) {
write_len =
MIN(ROUNDUP((addr_t)src, CONFIG_ARCH_CACHE_LINE) - (addr_t)src,
write_len);
}
write_len = write_len > CONFIG_ARCH_CACHE_LINE
? ROUNDDOWN(write_len, CONFIG_ARCH_CACHE_LINE)
: write_len;
if (write_len < CONFIG_ARCH_CACHE_LINE) {
xSemaphoreTake(norflash_info->disk_norflash_mutex, portMAX_DELAY);
memcpy(norflash_info->buff_sector, src, write_len);
if (norflash_dev_write(norflash_info, addr,
norflash_info->buff_sector,
ROUNDUP(write_len, 4))) {
xSemaphoreGive(norflash_info->disk_norflash_mutex);
return -1;
}
xSemaphoreGive(norflash_info->disk_norflash_mutex);
} else {
if (norflash_dev_write(norflash_info, addr, src, write_len)) {
return -1;
}
}
addr += write_len;
src += write_len;
remain_len -= write_len;
}
return 0;
}
#if CONFIG_DISK_NOR_FLASH_BYTES_API_SUPPORT
static int disk_norflash_erase(struct disk_info *info, disk_addr_t addr,
disk_size_t size, uint32_t flag)
{
int ret = 0;
struct disk_norflash_info *norflash_info = info->private_data;
ssdk_printf(SSDK_DEBUG,
"norflash disk %s erase,addr:%lld size:%lld:"
"flag:%d\n",
info->disk_name, addr, size, flag);
uint32_t sector_size = norflash_info->config.sector_size;
uint32_t tmp_len;
uint8_t *buf;
while (size) {
buf = norflash_info->buff_sector;
tmp_len = size;
if (!IS_ALIGNED(addr, sector_size)) {
tmp_len = MIN(ROUNDUP(addr, sector_size) - addr, size);
}
tmp_len =
tmp_len > sector_size ? (tmp_len - tmp_len % sector_size) : tmp_len;
if (tmp_len < sector_size) {
xSemaphoreTake(norflash_info->disk_norflash_mutex, portMAX_DELAY);
if (norflash_dev_read(norflash_info, ROUNDDOWN(addr, sector_size),
buf, sector_size)) {
ret = -1;
goto error;
}
if (norflash_dev_erase(norflash_info, ROUNDDOWN(addr, sector_size),
sector_size) < 0) {
ret = -1;
goto error;
}
memset(buf + addr % sector_size, 0xff, tmp_len);
if (norflash_dev_write(norflash_info, ROUNDDOWN(addr, sector_size),
buf, sector_size)) {
ret = -1;
goto error;
}
xSemaphoreGive(norflash_info->disk_norflash_mutex);
} else {
if (norflash_dev_erase(norflash_info, addr, tmp_len)) {
return -1;
}
}
addr += tmp_len;
size -= tmp_len;
}
return 0;
error:
xSemaphoreGive(norflash_info->disk_norflash_mutex);
return ret;
}
#endif
static int disk_norflash_erase_group(struct disk_info *info,
uint32_t erase_block, uint32_t erase_count,
uint32_t erase_sz, uint32_t flag)
{
return norflash_dev_erase(info->private_data,
(disk_addr_t)erase_block * erase_sz,
(disk_size_t)erase_count * erase_sz);
}
static int disk_norflash_status(struct disk_info *info)
{
return DISK_STATUS_OK;
}
static int disk_norflash_ioctl(struct disk_info *info, uint32_t cmd, void *buff)
{
return 0;
}
static struct disk_operations disk_norflash_ops = {
#if CONFIG_DISK_NOR_FLASH_BYTES_API_SUPPORT
.disk_read = disk_norflash_read,
.disk_write = disk_norflash_write,
.disk_erase = disk_norflash_erase,
#else
.disk_read = NULL,
.disk_write = NULL,
.disk_erase = NULL,
#endif
.disk_read_block = disk_norflash_read_block,
.disk_write_block = disk_norflash_write_block,
.disk_erase_group = disk_norflash_erase_group,
.disk_status = disk_norflash_status,
.disk_ioctl = disk_norflash_ioctl,
};
int register_norflash_disk(struct disk_norflash_info *norflash_info)
{
int ret = 0;
struct disk_info *info = &norflash_info->info;
struct disk_norflash_config *norflash_config = &norflash_info->config;
#ifdef CONFIG_DISK_NOR_FLASH_BYTES_API_SUPPORT
norflash_info->buff_size = norflash_config->sector_size;
#else
norflash_info->buff_size = CONFIG_ARCH_CACHE_LINE;
#endif
norflash_info->buff_sector = (uint8_t *)pvPortMallocAligned(
norflash_info->buff_size, CONFIG_ARCH_CACHE_LINE);
if (NULL == norflash_info->buff_sector) {
ssdk_printf(SSDK_ERR, "norflash disk %s buff malloc error\n",
norflash_config->disk_name);
return -1;
}
norflash_info->disk_norflash_mutex = xSemaphoreCreateMutex();
/* base on config init info */
info->disk_name = norflash_config->disk_name;
info->disk_size = norflash_config->disk_size;
info->disk_offset = 0;
info->erase_size = norflash_config->sector_size;
info->mem_align_size = CONFIG_ARCH_CACHE_LINE;
info->block_align_size = 4;
info->private_data = norflash_info;
info->disk_ops = &disk_norflash_ops;
#ifdef CONFIG_DISK_CACHE_NOOP
struct disk_cache_noop *cache_noop = &norflash_info->cache_noop;
/* base on config cache,cache in disk dev layer??? */
cache_noop->cache_align_size = 4u * 1024u;
cache_noop->cache.private_data = cache_noop;
ret = register_disk_cache_noop(cache_noop);
if (ret < 0) {
ssdk_printf(SSDK_ERR, "norflash disk register cache noop:%d\n", ret);
return ret;
}
#endif
ssdk_printf(SSDK_INFO,
"register norflash disk:%s disk_size:%lld"
"erase_size:%d sector_size:%d\n",
info->disk_name, info->disk_size, info->erase_size,
norflash_config->sector_size);
xSemaphoreTake(g_disk_mutex, portMAX_DELAY);
list_add_tail(&g_disk_list, &info->node);
info->use_count = 0;
xSemaphoreGive(g_disk_mutex);
return ret;
}
int unregister_norflash_disk(struct disk_norflash_info *norflash_info)
{
int ret = 0;
struct disk_info *info = &norflash_info->info;
ssdk_printf(SSDK_INFO, "unregister norflash disk:%s\n", info->disk_name);
#ifdef CONFIG_DISK_CACHE_NOOP
struct disk_cache_noop *cache_noop = &norflash_info->cache_noop;
/* unregister disk cache noop */
ret = unregister_disk_cache_noop(cache_noop);
if (ret < 0) {
ssdk_printf(SSDK_ERR, "norflash disk unregister cache noop:%d\n", ret);
return ret;
}
#endif
vPortFree(norflash_info->buff_sector);
vSemaphoreDelete(norflash_info->disk_norflash_mutex);
xSemaphoreTake(g_disk_mutex, portMAX_DELAY);
if (info->use_count) {
xSemaphoreGive(g_disk_mutex);
ret = -DISK_ERROR_BUSY;
ssdk_printf(SSDK_ERR, "norflash disk unregister:%d\n", ret);
return ret;
}
if (list_in_list(&info->node))
list_delete(&info->node);
xSemaphoreGive(g_disk_mutex);
return ret;
}