Files
arcs/arcs-sdk/drivers/lisa_flash/lisa_flash_arcs.c
2026-08-13 16:50:52 +08:00

507 lines
16 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* Copyright (c) 2025, LISTENAI
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file lisa_flash_arcs.c
* @brief LISA Flash ARCS 平台适配层
*
* 此文件实现 ARCS 芯片平台的 Flash 硬件适配
*/
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <lisa_mutex.h>
#include "lisa_flash.h"
#include "flash_if.h"
#include "arcs_ap.h"
#include "cache.h"
#define LOG_TAG "lisa_flash_arcs"
#include <lisa_log.h>
/* ========================================================================
* Flash 常量定义
* ======================================================================== */
/* Flash 页/扇区/块大小 */
#ifndef LISA_FLASH_SECTOR_SIZE
#define LISA_FLASH_SECTOR_SIZE CONFIG_LISA_FLASH_ARCS_ERASE_SECTOR_SIZE
#endif
#ifndef LISA_FLASH_WRITE_BLOCK_SIZE
#define LISA_FLASH_WRITE_BLOCK_SIZE CONFIG_LISA_FLASH_ARCS_WRITE_BLOCK_SIZE
#endif
/* Flash 物理地址范围配置 */
#define FLASH_PHYS_ADDR_START CONFIG_LISA_FLASH_ARCS_FLASH_PHYS_ADDR
#define FLASH_PHYS_ADDR_END (CONFIG_LISA_FLASH_ARCS_FLASH_PHYS_ADDR + CONFIG_LISA_FLASH_ARCS_FLASH_PHYS_RESERVE_SIZE)
/* Flash 写入缓冲区大小 (4KB) */
#define FLASH_WRITE_BUFFER_SIZE (4 * 1024)
/* ========================================================================
* Flash 私有数据结构定义
* ======================================================================== */
/* ===== Flash 设备私有数据 ===== */
typedef struct {
lisa_mutex_t *mutex; /* 互斥锁 */
bool initialized; /* 初始化标志 */
lisa_flash_parameters_t parameters; /* Flash 参数 */
lisa_flash_pages_layout_t layout; /* 页面布局(均匀扇区,只需一个布局段) */
} lisa_flash_priv_t;
/* ===== Flash 设备静态实例 ===== */
static lisa_flash_priv_t flash0_priv;
/* ===== 辅助宏定义 ===== */
#define DEVICE_LOCK(priv) \
do { \
if (priv->mutex) { \
lisa_mutex_lock(priv->mutex, LISA_OS_WAIT_FOREVER); \
} \
} while (0)
#define DEVICE_UNLOCK(priv) \
do { \
if (priv->mutex) { \
lisa_mutex_unlock(priv->mutex); \
} \
} while (0)
/* ===== 内部辅助函数 ===== */
/**
* @brief 检查数据指针是否位于 Flash 物理地址区域
*
* @param ptr 数据指针
* @return true 数据位于 Flash 区域
* @return false 数据不在 Flash 区域
*/
static inline bool is_data_in_flash_region(const void *ptr)
{
uintptr_t addr = (uintptr_t)ptr;
return (addr >= FLASH_PHYS_ADDR_START && addr < FLASH_PHYS_ADDR_END);
}
/**
* @brief 根据 JEDEC device ID 计算 Flash 容量
*
* Device ID 表示 2^N Bytes其中 N = device_id
* 计算公式capacity_bytes = 2^(device_id)
*
* @param device_id JEDEC device ID (RDID 命令返回的第3个字节)
* @return Flash 容量(字节),如果 ID 无效则返回默认值 16MB
*/
static size_t calculate_flash_size_from_id(uint32_t device_id)
{
/* 计算容量2^(device_id) bytes */
size_t capacity = 1UL << (device_id);
return capacity;
}
/**
* @brief 动态获取 Flash 大小
*
* 通过读取 JEDEC ID 并解析容量字节来确定实际容量
*
* @return Flash 容量(字节),失败则返回 0
*/
static size_t get_flash_size_dynamic(void)
{
uint32_t jedec_id = 0;
/* 使用 RDID (0x9F) 命令读取完整的 JEDEC ID */
int ret = flash_if_read_jedec_id(&jedec_id);
if (ret != 0) {
LISA_LOGE(LOG_TAG, "Failed to read JEDEC ID: %d, using default size", ret);
return 0;
}
/* JEDEC ID 格式: [Manufacturer(byte2)][Type(byte1)][Capacity(byte0)] */
uint8_t manufacturer = (jedec_id >> 16) & 0xFF;
uint8_t memory_type = (jedec_id >> 8) & 0xFF;
uint8_t capacity_id = jedec_id & 0xFF;
LISA_LOGD(LOG_TAG, "JEDEC ID: 0x%06X (Manufacturer=0x%02X, Type=0x%02X, Capacity=0x%02X)", jedec_id, manufacturer,
memory_type, capacity_id);
/* 根据容量 ID 计算实际容量 */
size_t capacity = calculate_flash_size_from_id(capacity_id);
LISA_LOGD(LOG_TAG, "Detected flash size from ID 0x%02X: %zu bytes (%.1f MB)", capacity_id, capacity,
capacity / (1024.0 * 1024.0));
return capacity;
}
static inline int check_device_initialized(lisa_device_t *dev)
{
if (!dev || !dev->priv_data) {
return LISA_DEVICE_ERR_INVALID;
}
lisa_flash_priv_t *priv = (lisa_flash_priv_t *)dev->priv_data;
if (!priv->initialized) {
LISA_LOGE(LOG_TAG, "Flash device not initialized");
return LISA_DEVICE_ERR_NOT_READY;
}
return LISA_DEVICE_OK;
}
/**
* @brief 检查访问范围是否超出 Flash 边界
*
* @param priv Flash 私有数据结构
* @param offset 访问偏移量
* @param size 访问大小
* @return LISA_DEVICE_OK 范围有效
* @return LISA_DEVICE_ERR_INVALID 范围超出边界
*/
static inline int check_flash_boundary(lisa_flash_priv_t *priv, size_t offset, size_t size)
{
size_t flash_size = priv->layout.pages_count * priv->layout.pages_size;
if (offset >= flash_size) {
LISA_LOGE(LOG_TAG, "Offset 0x%zx exceeds flash size 0x%zx", offset, flash_size);
return LISA_DEVICE_ERR_INVALID;
}
if (offset + size > flash_size) {
LISA_LOGE(LOG_TAG, "Access range [0x%zx, 0x%zx) exceeds flash boundary 0x%zx",
offset, offset + size, flash_size);
return LISA_DEVICE_ERR_INVALID;
}
return LISA_DEVICE_OK;
}
static inline void _dcache_invalidate_range_expand(unsigned long start, unsigned long end){
uint32_t line_mask = HAL_DCACHE_CFG_LINE_SIZE - 1;
// 对start向下取整到cache line边界
unsigned long aligned_start = start & (~line_mask);
// 对end向上取整到cache line边界
unsigned long aligned_end = (end + line_mask) & (~line_mask);
// 只有当有完整的cache line需要处理时才进行操作
if (aligned_start < aligned_end) {
HAL_InvalidateDCache_by_Addr((uint32_t *)aligned_start, (aligned_end - aligned_start));
}
}
/* ===== API 实现函数 ===== */
/**
* @brief 从 Flash 读取数据
*/
static int arcs_flash_read(lisa_device_t *dev, size_t offset, void *data, size_t len)
{
uint32_t start_phys_addr;
if (!data || len == 0) {
return LISA_DEVICE_ERR_INVALID;
}
int ret = check_device_initialized(dev);
if (ret != LISA_DEVICE_OK) {
return ret;
}
lisa_flash_priv_t *priv = (lisa_flash_priv_t *)dev->priv_data;
ret = check_flash_boundary(priv, offset, len);
if (ret != LISA_DEVICE_OK) {
return ret;
}
start_phys_addr = CONFIG_LISA_FLASH_ARCS_FLASH_PHYS_ADDR + offset;
_dcache_invalidate_range_expand(start_phys_addr ,start_phys_addr + len);
memcpy(data,start_phys_addr,len);
return LISA_DEVICE_OK;
}
/**
* @brief 向 Flash 写入数据
*
* 如果数据位于 flash 区域上,需要先将数据拷贝进内存中,然后再进行写入,
* 避免在操作 flash 时进行 flash 读取操作。如果数据长度超过 4K则逐步写入。
*/
static int arcs_flash_write(lisa_device_t *dev, size_t offset, const void *data, size_t len)
{
lisa_flash_priv_t *priv = (lisa_flash_priv_t *)dev->priv_data;
const void *write_data = data;
uint8_t *temp_buffer = NULL;
int32_t hal_ret = 0;
if (!data || len == 0) {
return LISA_DEVICE_ERR_INVALID;
}
int ret = check_device_initialized(dev);
if (ret != LISA_DEVICE_OK) {
return ret;
}
ret = check_flash_boundary(priv, offset, len);
if (ret != LISA_DEVICE_OK) {
return ret;
}
DEVICE_LOCK(priv);
/* 检查数据是否位于 Flash 物理地址区域 */
if (is_data_in_flash_region(data)) {
LISA_LOGD(LOG_TAG, "Data is in flash region (0x%p), copying to RAM buffer", data);
/* 如果数据长度超过 4K则分块处理 */
if (len > FLASH_WRITE_BUFFER_SIZE) {
/* 分配临时缓冲区 */
temp_buffer = malloc(FLASH_WRITE_BUFFER_SIZE);
if (!temp_buffer) {
LISA_LOGE(LOG_TAG, "Failed to allocate temporary buffer (%u bytes)", FLASH_WRITE_BUFFER_SIZE);
DEVICE_UNLOCK(priv);
return LISA_DEVICE_ERR_NO_MEM;
}
/* 逐块写入 */
flash_if_write_protection_set(false);
size_t remaining = len;
size_t current_offset = offset;
const uint8_t *src_ptr = (const uint8_t *)data;
while (remaining > 0) {
size_t chunk_size = (remaining > FLASH_WRITE_BUFFER_SIZE) ? FLASH_WRITE_BUFFER_SIZE : remaining;
/* 将数据从 Flash 区域拷贝到 RAM 缓冲区 */
memcpy(temp_buffer, src_ptr, chunk_size);
/* 写入到 Flash */
hal_ret = flash_if_write(current_offset, temp_buffer, chunk_size);
if (hal_ret != 0) {
LISA_LOGE(LOG_TAG, "Flash write failed at offset 0x%zx, len %zu: %d", current_offset, chunk_size,
hal_ret);
break;
}
remaining -= chunk_size;
current_offset += chunk_size;
src_ptr += chunk_size;
}
flash_if_write_protection_set(true);
free(temp_buffer);
} else {
/* 数据长度 <= 4K一次性拷贝并写入 */
temp_buffer = malloc(len);
if (!temp_buffer) {
LISA_LOGE(LOG_TAG, "Failed to allocate temporary buffer (%u bytes)", len);
DEVICE_UNLOCK(priv);
return LISA_DEVICE_ERR_NO_MEM;
}
/* 将数据从 Flash 区域拷贝到 RAM 缓冲区 */
memcpy(temp_buffer, data, len);
write_data = temp_buffer;
/* 写入到 Flash */
flash_if_write_protection_set(false);
hal_ret = flash_if_write(offset, write_data, len);
flash_if_write_protection_set(true);
free(temp_buffer);
}
} else {
/* 数据不在 Flash 区域,直接写入 */
flash_if_write_protection_set(false);
hal_ret = flash_if_write(offset, data, len);
flash_if_write_protection_set(true);
}
DEVICE_UNLOCK(priv);
if (hal_ret != 0) {
LISA_LOGE(LOG_TAG, "Flash write failed at offset 0x%zx, len %zu: %d", offset, len, hal_ret);
return LISA_DEVICE_ERR_IO;
}
return LISA_DEVICE_OK;
}
/**
* @brief 擦除 Flash 区域
*/
static int arcs_flash_erase(lisa_device_t *dev, size_t offset, size_t size)
{
int ret;
if (size == 0) {
return LISA_DEVICE_ERR_INVALID;
}
ret = check_device_initialized(dev);
if (ret != LISA_DEVICE_OK) {
return ret;
}
lisa_flash_priv_t *priv = (lisa_flash_priv_t *)dev->priv_data;
ret = check_flash_boundary(priv, offset, size);
if (ret != LISA_DEVICE_OK) {
return ret;
}
DEVICE_LOCK(priv);
/* 调用 HAL 擦除 */
flash_if_write_protection_set(false);
ret = flash_if_erase(offset, size);
flash_if_write_protection_set(true);
DEVICE_UNLOCK(priv);
if (ret != 0) {
LISA_LOGE(LOG_TAG, "Flash erase failed at offset 0x%x, size %u: %d", offset, size, ret);
return LISA_DEVICE_ERR_IO;
}
return LISA_DEVICE_OK;
}
/**
* @brief 获取 Flash 参数
*
* @return 返回指向常量参数结构体的指针
*/
static const lisa_flash_parameters_t *arcs_flash_get_parameters(lisa_device_t *dev)
{
if (!dev || !dev->priv_data) {
return NULL;
}
lisa_flash_priv_t *priv = (lisa_flash_priv_t *)dev->priv_data;
if (!priv->initialized) {
LISA_LOGE(LOG_TAG, "Flash device not initialized");
return NULL;
}
/* 返回常量参数指针 */
return &priv->parameters;
}
/**
* @brief 获取页面布局
*
* @return 整个 Flash 的页面布局信息
*/
static const lisa_flash_pages_layout_t *arcs_flash_page_layout(lisa_device_t *dev, size_t *layout_size)
{
if (!layout_size) {
return NULL;
}
if (!dev || !dev->priv_data) {
return NULL;
}
lisa_flash_priv_t *priv = (lisa_flash_priv_t *)dev->priv_data;
if (!priv->initialized) {
LISA_LOGE(LOG_TAG, "Flash device not initialized");
return NULL;
}
/* SPI Flash 通常是均匀扇区布局,只返回一个布局段 */
*layout_size = 1;
return &priv->layout;
}
/* ===== API 实例 ===== */
static const lisa_flash_api_t arcs_flash_api = {
.read = arcs_flash_read,
.write = arcs_flash_write,
.erase = arcs_flash_erase,
.get_parameters = arcs_flash_get_parameters,
.page_layout = arcs_flash_page_layout,
};
/* ===== 设备初始化函数 ===== */
static int arcs_flash0_init(void)
{
FLASH_DEV hal_flash_dev = {0};
/* 初始化私有数据 */
memset(&flash0_priv, 0, sizeof(flash0_priv));
/* 创建互斥锁 */
flash0_priv.mutex = lisa_mutex_create();
if (!flash0_priv.mutex) {
LISA_LOGE(LOG_TAG, "Failed to create mutex");
return LISA_DEVICE_ERR_INIT_FAIL;
}
/* 配置 HAL Flash 设备参数 */
hal_flash_dev.base_addr = CONFIG_LISA_FLASH_ARCS_CONTROLLER_BASE_ADDR;
hal_flash_dev.d_width = CONFIG_LISA_FLASH_ARCS_DATA_WIDTH;
hal_flash_dev.sclk_div = CONFIG_LISA_FLASH_ARCS_SCLK_DIV;
hal_flash_dev.addr_bytes = CONFIG_LISA_FLASH_ARCS_ADDR_BYTES;
hal_flash_dev.w_protect = CONFIG_LISA_FLASH_ARCS_WRITE_PROTECT_ENABLE ? 1 : 0;
#if CONFIG_LISA_FLASH_ARCS_DISABLE_INTERRUPTS
hal_flash_dev.run_mod = RUN_WITHOUT_INT; /* 默认不使用中断模式 */
#else
hal_flash_dev.run_mod = RUN_WITH_INT;
#endif
hal_flash_dev.timeout = FLASH_RETRY_TIMES;
hal_flash_dev.addr_auto = 0;
hal_flash_dev.dualflash_mode = 0;
hal_flash_dev.interrupt_enable = NULL;
hal_flash_dev.interrupt_disable = NULL;
/* 调用 HAL 初始化 */
int32_t ret = flash_if_init(&hal_flash_dev, 0, 0);
if (ret != 0) {
LISA_LOGE(LOG_TAG, "Flash HAL init failed: %d", ret);
lisa_mutex_delete(flash0_priv.mutex);
return LISA_DEVICE_ERR_INIT_FAIL;
}
/* 填充 Flash 参数(仅写操作相关的基本参数) */
flash0_priv.parameters.write_block_size = LISA_FLASH_WRITE_BLOCK_SIZE;
flash0_priv.parameters.caps.no_explicit_erase = false; /* SPI Flash 需要显式擦除 */
flash0_priv.parameters.erase_value = 0xFF; /* Flash 擦除后的值 */
/* 填充页面布局SPI Flash 通常是均匀的扇区布局) */
flash0_priv.layout.pages_size = LISA_FLASH_SECTOR_SIZE; /* 扇区大小: 4KB */
/* 动态获取 Flash 总容量(通过读取 Flash ID */
size_t total_size = get_flash_size_dynamic();
flash0_priv.layout.pages_count = total_size / flash0_priv.layout.pages_size; /* 扇区数量 */
flash0_priv.initialized = true;
LISA_LOGD(LOG_TAG, "Flash initialized successfully (layout: %zu pages × %zu bytes, total: %zu bytes)",
flash0_priv.layout.pages_count, flash0_priv.layout.pages_size,
flash0_priv.layout.pages_count * flash0_priv.layout.pages_size);
return LISA_DEVICE_OK;
}
/* ===== 设备注册 ===== */
LISA_DEVICE_REGISTER(flash0, /* 设备名称 */
&arcs_flash_api, /* API 指针 */
&flash0_priv, /* 私有数据指针 */
NULL, /* 用户数据 */
arcs_flash0_init, /* 初始化函数 */
CONFIG_LISA_FLASH_INIT_PRIORITY); /* 优先级 */