You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1418 lines
43 KiB
1418 lines
43 KiB
/*
|
|
* Copyright (c) Hisilicon Technologies Co., Ltd. 2020-2020. All rights reserved.
|
|
* Description: external interface module, support emmc, nand, spi-nor
|
|
* Author: Hisilicon
|
|
* Create: 2020-10-15
|
|
*/
|
|
|
|
#include "flash_ext.h"
|
|
#include <pthread.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <limits.h>
|
|
|
|
#include "soc_log.h"
|
|
#include "uapi_flash.h"
|
|
#include "nand.h"
|
|
#include "spi_raw.h"
|
|
#include "nand_raw.h"
|
|
#include "emmc_raw.h"
|
|
#include "ufs_raw.h"
|
|
#include "cmdline_parts.h"
|
|
#include "securec.h"
|
|
|
|
#define MAX_HANDLE MAX_PARTS /* Flash max handle number */
|
|
#undef LOG_MODULE_ID
|
|
#define LOG_MODULE_ID SOC_ID_FLASH
|
|
|
|
/* Expand flash handle fd, only ext_Flash_OpenByTypeAndName() use it */
|
|
#define SPAN_PART_HANDLE 1000
|
|
|
|
/* Flash operation descriptions */
|
|
typedef struct {
|
|
td_s32(*raw_read)(flash_rw_info_s *rw_info, td_u8 *buffer, td_ulong length, td_s32 skip_badblock);
|
|
td_s32(*raw_write)(flash_rw_info_s *rw_info, td_u8 *buffer, td_ulong length);
|
|
td_s64(*raw_erase)(td_s32 fd, td_u64 startaddr,
|
|
td_u64 length, td_u64 openaddr, td_u64 limit_leng);
|
|
} flash_opt;
|
|
|
|
/* Flash Infomation */
|
|
typedef struct {
|
|
td_u64 total_size; /* flash total size */
|
|
td_u64 part_size; /* flash partition size */
|
|
td_u32 block_size; /* flash block size */
|
|
td_u32 page_size; /* flash page size */
|
|
td_u32 oob_size; /* flash OOB size */
|
|
td_void *fd; /* file handle */
|
|
td_u64 open_addr; /* flash open address */
|
|
td_u64 open_len; /* flash open length */
|
|
uapi_flash_type flash_type; /* flash type */
|
|
flash_opt *flash_opt; /* operation callbacks on this flash */
|
|
uapi_flash_partinfo *part_info; /* parition descriptions on this flash */
|
|
} flash_inter_info_s;
|
|
|
|
typedef struct {
|
|
td_u64 total_size;
|
|
td_u32 page_size;
|
|
td_u32 block_size;
|
|
td_u32 oob_size;
|
|
td_u32 block_shift;
|
|
} flash_spinand_info_s;
|
|
|
|
typedef enum {
|
|
EXT_FLASH_STAT_INSTALL,
|
|
EXT_FLASH_STAT_UNINSTALL,
|
|
/* lint -save -e749 */
|
|
EXT_FLASH_STAT_BUTT,
|
|
} flash_dev_stat_e;
|
|
|
|
static flash_inter_info_s g_flash_info[MAX_HANDLE];
|
|
static uapi_flash_partinfo g_part_info[MAX_PARTS];
|
|
static td_bool g_init_flag = TD_FALSE;
|
|
static volatile td_bool g_init_mutex = TD_FALSE;
|
|
static td_u8 g_bootargs_str[COMMAND_LINE_SIZE];
|
|
static td_char g_flash_str[UAPI_FLASH_TYPE_MAX][MAX_FLASH_TYPE_LEN] = {
|
|
"flash_auto", "fmc_sfc:", "fmc_sfc1:", "fmc_sfc2:",
|
|
"soct_nand:", "soct_nand1:", "soct_nand2:", "soct_nand3:",
|
|
"mmcblk0:", "mmcblk1:", "mmcblk2:", "mmcblk3:",
|
|
"sdd:",
|
|
};
|
|
static td_char *g_dev_pos[UAPI_FLASH_TYPE_MAX];
|
|
static flash_dev_stat_e g_dev_stat[UAPI_FLASH_TYPE_MAX];
|
|
static pthread_mutex_t g_flash_mutex;
|
|
|
|
static flash_opt g_dev_flash_opt[UAPI_FLASH_TYPE_MAX];
|
|
|
|
static td_s32 check_flash_init(td_handle flash)
|
|
{
|
|
do {
|
|
if (!g_init_flag) {
|
|
soc_log_err("NOT init yet!\n");
|
|
return TD_FAILURE;
|
|
}
|
|
if (flash >= MAX_HANDLE || g_flash_info[(flash)].fd == (td_void *)(intptr_t)INVALID_FD) {
|
|
return TD_FAILURE;
|
|
}
|
|
} while (0);
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_s32 check_addr_len(td_u64 address, td_u64 len, td_u64 limit_len)
|
|
{
|
|
do {
|
|
if (((address) >= (limit_len)) || (((address) + (len)) > (limit_len))) {
|
|
soc_log_err("startaddr(0x%llX) + length(0x%llx) or startaddr should be smaller than partsize(0x%llX)\n",
|
|
(address), (len), (limit_len));
|
|
return TD_FAILURE;
|
|
}
|
|
} while (0);
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
/* Call this should init g_bootargs_str and g_dev_pos firstly */
|
|
uapi_flash_type get_flashtype_by_bootargs(const td_char *part_name)
|
|
{
|
|
td_char *partition_pos = NULL;
|
|
td_char *partition_pos1 = NULL;
|
|
td_char *tmp_pos = NULL;
|
|
td_char tmp_str[64]; /* 64 - The size of storage partition name temporary buffer */
|
|
td_u32 i;
|
|
uapi_flash_type flash_type = UAPI_FLASH_TYPE_MAX;
|
|
|
|
if (part_name == NULL) {
|
|
return UAPI_FLASH_TYPE_MAX;
|
|
}
|
|
|
|
if (strchr(part_name, ' ')) {
|
|
soc_log_err("Invalid partition_name, should not include ' '.\n");
|
|
return UAPI_FLASH_TYPE_MAX;
|
|
}
|
|
|
|
memset_s(tmp_str, sizeof(tmp_str), 0, sizeof(tmp_str));
|
|
if (snprintf_s(tmp_str, sizeof(tmp_str), sizeof(tmp_str) - 1, "(%s)", part_name) == -1) {
|
|
soc_log_err("Failed to snprintf_s.\n");
|
|
return UAPI_FLASH_TYPE_MAX;
|
|
}
|
|
|
|
partition_pos = strstr((td_char *)g_bootargs_str, tmp_str);
|
|
if (partition_pos == NULL) {
|
|
return UAPI_FLASH_TYPE_MAX;
|
|
}
|
|
|
|
/* The bootargs has the same partition call this would failed */
|
|
partition_pos1 = strstr((td_char *)partition_pos + 1, tmp_str);
|
|
if (partition_pos1 != NULL) {
|
|
soc_log_err("The same patition(%s) on bootargs!%s", part_name, partition_pos);
|
|
return UAPI_FLASH_TYPE_MAX;
|
|
}
|
|
|
|
for (i = 0; i < UAPI_FLASH_TYPE_MAX; i++) {
|
|
if ((g_dev_pos[i] == NULL) || (g_dev_pos[i] > partition_pos)) {
|
|
continue;
|
|
}
|
|
|
|
/* tmp_pos is used to be a cursor */
|
|
if ((partition_pos >= g_dev_pos[i]) && (g_dev_pos[i] >= tmp_pos)) {
|
|
flash_type = (uapi_flash_type)i;
|
|
tmp_pos = g_dev_pos[i];
|
|
}
|
|
}
|
|
|
|
return flash_type;
|
|
}
|
|
|
|
/* Call this should init g_bootargs_str and g_dev_pos firstly */
|
|
static uapi_flash_type ext_get_flash_type(const td_char *partition_name)
|
|
{
|
|
int i, flash_num;
|
|
uapi_flash_type flash_type = UAPI_FLASH_TYPE_MAX;
|
|
uapi_flash_type boot_flash_type;
|
|
|
|
if (partition_name != NULL) {
|
|
return get_flashtype_by_bootargs(partition_name);
|
|
}
|
|
|
|
flash_num = 0;
|
|
for (i = 0; i < UAPI_FLASH_TYPE_MAX; i++) {
|
|
if (g_dev_pos[i]) {
|
|
flash_type = (uapi_flash_type)i;
|
|
flash_num++;
|
|
}
|
|
}
|
|
|
|
/* 2: flash number */
|
|
if (flash_num > 2) {
|
|
soc_log_err("Get flash type failed, %d flashes detected.\n", flash_num);
|
|
return UAPI_FLASH_TYPE_MAX;
|
|
} else if (flash_num > 1) {
|
|
boot_flash_type = get_flashtype_by_bootargs("fastboot");
|
|
if (boot_flash_type == UAPI_FLASH_TYPE_MAX) {
|
|
soc_log_err("Failed to get the boot flash type.\n");
|
|
return boot_flash_type;
|
|
}
|
|
|
|
for (i = 0; i < UAPI_FLASH_TYPE_MAX; i++) {
|
|
if (g_dev_pos[i] && ((uapi_flash_type)i != boot_flash_type)) {
|
|
flash_type = (uapi_flash_type)i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return flash_type;
|
|
}
|
|
|
|
static td_s32 permission_check(td_u64 start_addr, td_u64 length)
|
|
{
|
|
td_u64 end_addr = start_addr + length - 1;
|
|
td_u32 i;
|
|
|
|
for (i = 0; i < MAX_PARTS; i++) {
|
|
if (g_part_info[i].perm != ACCESS_NONE) {
|
|
continue;
|
|
}
|
|
if ((g_part_info[i].start_addr >= start_addr) && (g_part_info[i].start_addr <= end_addr)) {
|
|
soc_log_info("%s(%s) is not permitted to be opened.\n", g_part_info[i].dev_name, g_part_info[i].part_name);
|
|
return TD_FAILURE;
|
|
}
|
|
}
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_s32 flash_partition_perm(td_s32 part)
|
|
{
|
|
td_s32 fd = -1;
|
|
td_s32 ret;
|
|
|
|
ret = snprintf_s(g_part_info[part].dev_name, FLASH_NAME_LEN, FLASH_NAME_LEN - 1, DEV_MTDBASE"%d", part);
|
|
if (ret == -1) {
|
|
ret = snprintf_s(g_part_info[part].dev_name, FLASH_NAME_LEN, FLASH_NAME_LEN - 1, "/dev/mtd%d", part);
|
|
if (ret == -1) {
|
|
soc_log_err("Failed to snprintf_s.\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
fd = open(g_part_info[part].dev_name, O_RDWR);
|
|
if (fd == -1) {
|
|
fd = open(g_part_info[part].dev_name, O_RDONLY);
|
|
if (fd == -1) {
|
|
soc_log_err("Can't open \"%s\"\n", g_part_info[part].dev_name);
|
|
g_part_info[part].perm = ACCESS_NONE;
|
|
return -1;
|
|
}
|
|
soc_log_info("access %s readonly!\n", g_part_info[part].dev_name);
|
|
g_part_info[part].perm = ACCESS_RD;
|
|
} else {
|
|
soc_log_info("access %s read and write, i:%d, fd:%x!\n", g_part_info[part].dev_name, part, fd);
|
|
g_part_info[part].perm = ACCESS_RDWR;
|
|
}
|
|
close(fd);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static td_s32 flash_part_info_init(td_void)
|
|
{
|
|
td_s32 i;
|
|
td_char line[BUF_LINE_SIZE];
|
|
td_u64 start_addr[UAPI_FLASH_TYPE_MAX] = {0};
|
|
uapi_flash_type flash_type;
|
|
FILE *fp = NULL;
|
|
|
|
fp = fopen("/proc/mtd", "r");
|
|
if (fp == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
if (fgets(line, sizeof(line), fp) == NULL) { /* skip first line */
|
|
(td_void)fclose(fp);
|
|
return -1;
|
|
}
|
|
|
|
/* dev_name part_size block_size part_name Startaddr */
|
|
for (i = 0; fgets(line, sizeof(line), fp) != 0; i++) {
|
|
td_char *p = NULL;
|
|
td_char argv[4][32]; /* 4 - Get the number of vars, 32 - The size of each var buffer */
|
|
|
|
p = &line[0];
|
|
p = skip_space(p);
|
|
p = skip_word(p);
|
|
p = get_word(p, argv[1]); /* 1 - partition size */
|
|
p = get_word(p, argv[2]); /* 2 - block size */
|
|
p = get_word(p, argv[3]); /* 3 - partition name */
|
|
|
|
if (i >= MAX_PARTS) {
|
|
soc_print("Detected there has more than %d partitions.\n"
|
|
"You should encrease MAX_PARTS in order to use left partitions!\n", MAX_PARTS);
|
|
break;
|
|
}
|
|
|
|
g_part_info[i].part_size = (td_u64)(td_s64)strtoull(
|
|
(const td_char*)argv[1], (td_char**)NULL, HEX); /* 1 - partition size */
|
|
|
|
memset_s(g_part_info[i].part_name, sizeof(g_part_info[i].part_name), 0, sizeof(g_part_info[i].part_name));
|
|
if (strncpy_s(g_part_info[i].part_name, sizeof(g_part_info[i].part_name),
|
|
(td_char*)(argv[3] + 1), (strlen((td_char*)argv[3]) - 2)) != 0) { /* 3 - partition name, 2 - */
|
|
break;
|
|
}
|
|
|
|
flash_type = get_flashtype_by_bootargs(g_part_info[i].part_name);
|
|
if (flash_type >= UAPI_FLASH_TYPE_MAX) {
|
|
continue;
|
|
}
|
|
|
|
g_part_info[i].start_addr = start_addr[flash_type];
|
|
start_addr[flash_type] += g_part_info[i].part_size;
|
|
|
|
if (flash_partition_perm(i) < 0) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
(td_void)fclose(fp);
|
|
return 0;
|
|
}
|
|
|
|
static td_void flash_device_init(td_void)
|
|
{
|
|
if (spi_raw_init() == TD_SUCCESS) {
|
|
g_dev_stat[UAPI_FLASH_TYPE_NOR_0] = EXT_FLASH_STAT_INSTALL;
|
|
}
|
|
|
|
if (nand_raw_init() == TD_SUCCESS) {
|
|
g_dev_stat[UAPI_FLASH_TYPE_NAND_0] = EXT_FLASH_STAT_INSTALL;
|
|
}
|
|
|
|
if (emmc_raw_init((td_char *)g_bootargs_str) == TD_SUCCESS) {
|
|
g_dev_stat[UAPI_FLASH_TYPE_EMMC_0] = EXT_FLASH_STAT_INSTALL;
|
|
}
|
|
|
|
if (ufs_raw_init((td_char *)g_bootargs_str) == TD_SUCCESS) {
|
|
g_dev_stat[UAPI_FLASH_TYPE_UFS_0] = EXT_FLASH_STAT_INSTALL;
|
|
}
|
|
}
|
|
|
|
static td_void flash_opt_init(td_void)
|
|
{
|
|
g_dev_flash_opt[UAPI_FLASH_TYPE_NOR_0].raw_erase = spi_raw_erase;
|
|
g_dev_flash_opt[UAPI_FLASH_TYPE_NOR_0].raw_read = spi_raw_read;
|
|
g_dev_flash_opt[UAPI_FLASH_TYPE_NOR_0].raw_write = spi_raw_write;
|
|
g_dev_flash_opt[UAPI_FLASH_TYPE_NAND_0].raw_erase = nand_raw_erase;
|
|
g_dev_flash_opt[UAPI_FLASH_TYPE_NAND_0].raw_read = nand_raw_read;
|
|
g_dev_flash_opt[UAPI_FLASH_TYPE_NAND_0].raw_write = nand_raw_write;
|
|
}
|
|
|
|
static td_s32 flash_info_init(td_void)
|
|
{
|
|
td_u32 i;
|
|
|
|
for (i = 0; i < MAX_PARTS; i++) {
|
|
memset_s(&g_part_info[i], sizeof(uapi_flash_partinfo), 0, sizeof(uapi_flash_partinfo));
|
|
g_part_info[i].perm = ACCESS_BUTT;
|
|
}
|
|
|
|
for (i = 0; i < MAX_HANDLE; i++) {
|
|
(td_void)pthread_mutex_lock(&g_flash_mutex);
|
|
g_flash_info[i].fd = (td_void *)INVALID_FD;
|
|
g_flash_info[i].open_addr = 0;
|
|
g_flash_info[i].open_len = 0;
|
|
g_flash_info[i].part_info = NULL;
|
|
g_flash_info[i].flash_type = UAPI_FLASH_TYPE_MAX;
|
|
(td_void)pthread_mutex_unlock(&g_flash_mutex);
|
|
}
|
|
|
|
flash_opt_init();
|
|
|
|
if ((g_dev_stat[UAPI_FLASH_TYPE_NOR_0] == EXT_FLASH_STAT_INSTALL) ||
|
|
(g_dev_stat[UAPI_FLASH_TYPE_NAND_0] == EXT_FLASH_STAT_INSTALL)) {
|
|
if (flash_part_info_init() < 0) {
|
|
return TD_FAILURE;
|
|
}
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_s32 flash_all_init(uapi_flash_type flash_type)
|
|
{
|
|
td_u8 loop = 0;
|
|
|
|
if (g_init_mutex) {
|
|
while ((g_init_mutex != 0) && (loop < 100)) { /* 100 - Number of cycles */
|
|
usleep(100); /* sleep 100us */
|
|
loop++;
|
|
}
|
|
} else {
|
|
g_init_mutex = TD_TRUE;
|
|
}
|
|
|
|
if (!g_init_flag) {
|
|
(td_void)pthread_mutex_init(&g_flash_mutex, NULL);
|
|
|
|
if (get_bootargs(g_bootargs_str, (sizeof(g_bootargs_str) - 1)) != TD_SUCCESS) {
|
|
soc_log_err("Failed to get bootargs. \n");
|
|
g_init_mutex = TD_FALSE;
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
for (loop = 0; loop < UAPI_FLASH_TYPE_MAX; loop++) {
|
|
g_dev_stat[loop] = EXT_FLASH_STAT_UNINSTALL;
|
|
g_dev_pos[loop] = strstr((td_char *)g_bootargs_str, g_flash_str[loop]);
|
|
}
|
|
|
|
flash_device_init();
|
|
|
|
if (flash_info_init() == TD_FAILURE) {
|
|
(td_void)spi_raw_destroy();
|
|
(td_void)nand_raw_destroy();
|
|
soc_log_err("Flash info init fail! \n");
|
|
g_init_mutex = TD_FALSE;
|
|
return TD_FAILURE;
|
|
}
|
|
}
|
|
g_init_flag = TD_TRUE;
|
|
g_init_mutex = TD_FALSE;
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_s32 flash_unused_handle(void)
|
|
{
|
|
td_s8 loop;
|
|
|
|
for (loop = 0; loop < MAX_HANDLE; loop++) {
|
|
if (g_flash_info[loop].fd == (td_void *)INVALID_FD) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return loop;
|
|
}
|
|
|
|
static td_void flash_get_spinand_info(uapi_flash_type flash_type, flash_spinand_info_s *info)
|
|
{
|
|
if (flash_type == UAPI_FLASH_TYPE_NOR_0) {
|
|
spi_raw_get_info(&info->total_size, &info->page_size,
|
|
&info->block_size, &info->oob_size, &info->block_shift);
|
|
} else {
|
|
nand_raw_get_info(&info->total_size, &info->page_size,
|
|
&info->block_size, &info->oob_size, &info->block_shift);
|
|
}
|
|
}
|
|
|
|
static td_s32 flash_open_emmc_get_info(emmc_cb_s *emmc_cb)
|
|
{
|
|
td_s32 flash;
|
|
|
|
flash = flash_unused_handle();
|
|
if (flash == MAX_HANDLE) {
|
|
soc_log_err("flash array full! \n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
g_flash_info[flash].fd = emmc_cb;
|
|
g_flash_info[flash].flash_type = UAPI_FLASH_TYPE_EMMC_0;
|
|
|
|
return flash;
|
|
}
|
|
|
|
static td_handle flash_open_emmc_by_addr(td_u64 address, td_u64 length)
|
|
{
|
|
td_s32 flash;
|
|
emmc_cb_s *emmc_cb;
|
|
|
|
emmc_cb = emmc_raw_open(address, length);
|
|
if (emmc_cb == NULL) {
|
|
return (td_handle)INVALID_FD;
|
|
}
|
|
|
|
flash = flash_open_emmc_get_info(emmc_cb);
|
|
if (flash < 0) {
|
|
(td_void)emmc_raw_close(emmc_cb);
|
|
emmc_cb = NULL;
|
|
return (td_handle)INVALID_FD;
|
|
}
|
|
|
|
return (td_handle)flash;
|
|
}
|
|
|
|
static td_s32 flash_open_ufs_get_info(ufs_cb_s *ufs_cb)
|
|
{
|
|
td_s32 flash;
|
|
|
|
flash = flash_unused_handle();
|
|
if (flash == MAX_HANDLE) {
|
|
soc_log_err("flash array full! \n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
g_flash_info[flash].fd = ufs_cb;
|
|
g_flash_info[flash].flash_type = UAPI_FLASH_TYPE_UFS_0;
|
|
|
|
return flash;
|
|
}
|
|
|
|
static td_handle flash_open_ufs_by_addr(td_u64 address, td_u64 length)
|
|
{
|
|
td_s32 flash;
|
|
ufs_cb_s *ufs_cb;
|
|
|
|
ufs_cb = ufs_raw_open(address, length);
|
|
if (ufs_cb == NULL) {
|
|
return (td_handle)INVALID_FD;
|
|
}
|
|
|
|
flash = flash_open_ufs_get_info(ufs_cb);
|
|
if (flash < 0) {
|
|
(td_void)ufs_raw_close(ufs_cb);
|
|
ufs_cb = NULL;
|
|
return (td_handle)INVALID_FD;
|
|
}
|
|
|
|
return (td_handle)flash;
|
|
}
|
|
|
|
static td_handle flash_open_spi_nand_by_addr(uapi_flash_type flash_type, td_u64 address, td_u64 length)
|
|
{
|
|
td_u32 flash;
|
|
flash_spinand_info_s raw_info;
|
|
|
|
flash_get_spinand_info(flash_type, &raw_info);
|
|
|
|
if (raw_info.block_size == 0) {
|
|
soc_log_err("block_size shouldn't equal 0!\n");
|
|
return (td_handle)INVALID_FD;
|
|
}
|
|
|
|
if (((td_s32)(address % raw_info.block_size) != 0) || ((td_s32)(length % raw_info.block_size) != 0)) {
|
|
soc_log_err("Open addr(%#llx) and len(%#llx) should be align with block_size(0x%X)!\n",
|
|
address, length, raw_info.block_size);
|
|
return (td_handle)INVALID_FD;
|
|
}
|
|
|
|
if ((address >= raw_info.total_size) || (address + length) > raw_info.total_size) {
|
|
soc_log_err("Open addr(%#llx) and len(%#llx) should be smaller than total_size(0x%llX)!\n",
|
|
address, length, raw_info.total_size);
|
|
return (td_handle)INVALID_FD;
|
|
}
|
|
|
|
if (permission_check(address, length) != TD_SUCCESS) {
|
|
soc_log_info("not permission to be opened.\n");
|
|
return (td_handle)INVALID_FD;
|
|
}
|
|
|
|
flash = (td_u32)flash_unused_handle();
|
|
if (flash == MAX_HANDLE) {
|
|
soc_log_err("flash array full! \n");
|
|
return (td_handle)INVALID_FD;
|
|
}
|
|
|
|
g_flash_info[flash].fd = (td_slong *)(uintptr_t)(SPAN_PART_HANDLE + flash);
|
|
g_flash_info[flash].open_addr = address;
|
|
g_flash_info[flash].open_len = length;
|
|
g_flash_info[flash].part_info = NULL;
|
|
g_flash_info[flash].flash_type = flash_type;
|
|
g_flash_info[flash].page_size = raw_info.page_size;
|
|
g_flash_info[flash].oob_size = raw_info.oob_size;
|
|
g_flash_info[flash].block_size = raw_info.block_size;
|
|
if (flash_type == UAPI_FLASH_TYPE_NOR_0) {
|
|
g_flash_info[flash].flash_opt = (flash_opt *)&g_dev_flash_opt[UAPI_FLASH_TYPE_NOR_0];
|
|
} else if (flash_type == UAPI_FLASH_TYPE_NAND_0) {
|
|
g_flash_info[flash].flash_opt = (flash_opt *)&g_dev_flash_opt[UAPI_FLASH_TYPE_NAND_0];
|
|
}
|
|
|
|
return (td_handle)flash;
|
|
}
|
|
|
|
static td_handle flash_open_emmc_by_node(const td_char *partition_name)
|
|
{
|
|
td_u64 address, length;
|
|
td_s32 flash, ret;
|
|
emmc_cb_s *emmc_cb = NULL;
|
|
|
|
ret = strncmp(partition_name, "/dev/block/mmcblk0p", strlen("/dev/block/mmcblk0p"));
|
|
if (ret != 0) {
|
|
ret = strncmp(partition_name, "/dev/mmcblk0p", strlen("/dev/mmcblk0p"));
|
|
if (ret != 0) {
|
|
return (td_handle)INVALID_FD;
|
|
}
|
|
}
|
|
|
|
emmc_cb = emmc_node_open((td_u8*)partition_name);
|
|
if (emmc_cb == NULL) {
|
|
return (td_handle)INVALID_FD;
|
|
}
|
|
|
|
if (emmc_find_part_from_devname("mmcblk0", (td_char *)g_bootargs_str,
|
|
partition_name, &address, &length) != TD_SUCCESS) {
|
|
soc_log_err("Cannot find partiton from %s\n", partition_name);
|
|
(td_void)emmc_raw_close(emmc_cb);
|
|
emmc_cb = NULL;
|
|
return (td_handle)INVALID_FD;
|
|
}
|
|
emmc_cb->part_size = length;
|
|
|
|
flash = flash_open_emmc_get_info(emmc_cb);
|
|
if (flash < 0) {
|
|
emmc_raw_close(emmc_cb);
|
|
emmc_cb = NULL;
|
|
return (td_handle)INVALID_FD;
|
|
}
|
|
|
|
return (td_handle)flash;
|
|
}
|
|
|
|
static td_handle flash_open_emmc_by_bootargs(const td_char *partition_name)
|
|
{
|
|
td_u64 address, length;
|
|
td_s32 flash;
|
|
td_char *ptr = NULL;
|
|
emmc_cb_s *emmc_cb = NULL;
|
|
|
|
ptr = strstr((td_char*)g_bootargs_str, "mmcblk0:");
|
|
if (ptr == NULL) {
|
|
return (td_handle)INVALID_FD;
|
|
}
|
|
|
|
if (find_flash_part(ptr, "mmcblk0", partition_name, &address, &length) == 0) {
|
|
soc_log_err("Cannot find partition: %s\n", partition_name);
|
|
return (td_handle)INVALID_FD;
|
|
}
|
|
|
|
if (length == (td_u64)(-1)) {
|
|
soc_log_err("Can not contain char '-'\n");
|
|
return (td_handle)INVALID_FD;
|
|
}
|
|
|
|
emmc_cb = emmc_raw_open(address, length);
|
|
if (emmc_cb == NULL) {
|
|
return (td_handle)INVALID_FD;
|
|
}
|
|
|
|
flash = flash_open_emmc_get_info(emmc_cb);
|
|
if (flash < 0) {
|
|
emmc_raw_close(emmc_cb);
|
|
emmc_cb = NULL;
|
|
return (td_handle)INVALID_FD;
|
|
}
|
|
|
|
return (td_handle)flash;
|
|
}
|
|
|
|
static td_handle flash_open_emmc_by_name(const td_char *partition_name)
|
|
{
|
|
td_handle flash;
|
|
|
|
flash = flash_open_emmc_by_node(partition_name);
|
|
if (flash != (td_handle)INVALID_FD) {
|
|
return flash;
|
|
}
|
|
|
|
flash = flash_open_emmc_by_bootargs(partition_name);
|
|
return flash;
|
|
}
|
|
|
|
static td_handle flash_open_ufs_by_node(const td_char *partition_name)
|
|
{
|
|
td_u64 address, length;
|
|
td_s32 flash, ret;
|
|
ufs_cb_s *ufs_cb = NULL;
|
|
|
|
ret = strncmp(partition_name, "/dev/block/sdd", strlen("/dev/block/sdd"));
|
|
if (ret != 0) {
|
|
ret = strncmp(partition_name, "/dev/sdd", strlen("/dev/sdd"));
|
|
if (ret != 0) {
|
|
return (td_handle)INVALID_FD;
|
|
}
|
|
}
|
|
|
|
ufs_cb = ufs_node_open((td_u8*)partition_name);
|
|
if (ufs_cb == NULL) {
|
|
return (td_handle)INVALID_FD;
|
|
}
|
|
|
|
if (ufs_find_part_from_devname("sdd", (td_char *)g_bootargs_str, partition_name, &address, &length) != TD_SUCCESS) {
|
|
soc_log_err("Cannot find partiton from %s\n", partition_name);
|
|
(td_void)ufs_raw_close(ufs_cb);
|
|
ufs_cb = NULL;
|
|
return (td_handle)INVALID_FD;
|
|
}
|
|
ufs_cb->part_size = length;
|
|
|
|
flash = flash_open_ufs_get_info(ufs_cb);
|
|
if (flash < 0) {
|
|
ufs_raw_close(ufs_cb);
|
|
ufs_cb = NULL;
|
|
return (td_handle)INVALID_FD;
|
|
}
|
|
|
|
return (td_handle)flash;
|
|
}
|
|
|
|
static td_handle flash_open_ufs_by_bootargs(const td_char *partition_name)
|
|
{
|
|
td_u64 address, length;
|
|
td_s32 flash;
|
|
td_char *ptr = NULL;
|
|
ufs_cb_s *ufs_cb = NULL;
|
|
|
|
ptr = strstr((td_char*)g_bootargs_str, "sdd:");
|
|
if (ptr == NULL) {
|
|
return (td_handle)INVALID_FD;
|
|
}
|
|
|
|
if (find_flash_part(ptr, "sdd", partition_name, &address, &length) == 0) {
|
|
soc_log_err("Cannot find partition: %s\n", partition_name);
|
|
return (td_handle)INVALID_FD;
|
|
}
|
|
|
|
if (length == (td_u64)(-1)) {
|
|
soc_log_err("Can not contain char '-'\n");
|
|
return (td_handle)INVALID_FD;
|
|
}
|
|
|
|
ufs_cb = ufs_raw_open(address, length);
|
|
if (ufs_cb == NULL) {
|
|
return (td_handle)INVALID_FD;
|
|
}
|
|
|
|
flash = flash_open_ufs_get_info(ufs_cb);
|
|
if (flash < 0) {
|
|
ufs_raw_close(ufs_cb);
|
|
ufs_cb = NULL;
|
|
return (td_handle)INVALID_FD;
|
|
}
|
|
|
|
return (td_handle)flash;
|
|
}
|
|
|
|
static td_handle flash_open_ufs_by_name(const td_char *partition_name)
|
|
{
|
|
td_handle flash;
|
|
|
|
flash = flash_open_ufs_by_node(partition_name);
|
|
if (flash != (td_handle)INVALID_FD) {
|
|
return flash;
|
|
}
|
|
|
|
flash = flash_open_ufs_by_bootargs(partition_name);
|
|
return flash;
|
|
}
|
|
|
|
static td_s32 flash_partition_match(td_s32 part, uapi_flash_type flash_type, const td_char *partition_name)
|
|
{
|
|
uapi_flash_type check_flash_type;
|
|
|
|
check_flash_type = get_flashtype_by_bootargs(partition_name);
|
|
if ((strncmp(g_part_info[part].dev_name, partition_name, strlen(partition_name) + 1) == 0) &&
|
|
(check_flash_type == flash_type)) { /* eg: "/dev/mtd* " */
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
if ((strncmp(g_part_info[part].part_name, partition_name, strlen(partition_name) + 1) == 0) &&
|
|
(check_flash_type == flash_type)) {
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
static td_s32 flash_partition_get(uapi_flash_type flash_type, const td_char *partition_name)
|
|
{
|
|
td_s32 i, j;
|
|
|
|
for (i = 0; i < MAX_PARTS; i++) {
|
|
if (flash_partition_match(i, flash_type, partition_name) == TD_SUCCESS) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (j = MAX_PARTS - 1; j >= 0; j--) {
|
|
if (flash_partition_match(j, flash_type, partition_name) == TD_SUCCESS) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* add i < 0 test in if branch to avoid pclint warning:
|
|
* Warning 676: Possibly negative subscript (-1) in operator '['
|
|
*/
|
|
if ((i == MAX_PARTS) || (i != j) || i < 0) {
|
|
soc_log_err("can not find a right flash part(partition: %s, i=%d, j=%d)!\n", partition_name, i, j);
|
|
return -1;
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
static td_s64 flash_open_spi_nand_get_fd(td_s32 part)
|
|
{
|
|
td_s32 i;
|
|
td_s32 fd = -1;
|
|
td_char dev_name[FLASH_NAME_LEN] = {0};
|
|
td_char tmp_name[PATH_MAX] = {0};
|
|
|
|
if (strncpy_s(dev_name, sizeof(dev_name), g_part_info[part].dev_name, sizeof(dev_name) - 1) != 0) {
|
|
return (td_handle)INVALID_FD;
|
|
}
|
|
dev_name[sizeof(dev_name) - 1] = '\0';
|
|
|
|
for (i = 0; i < MAX_HANDLE; i++) { /* if the partition open, return index of array(g_flash_info) */
|
|
if ((g_flash_info[i].part_info != 0) &&
|
|
(strncmp(g_flash_info[i].part_info->dev_name, dev_name, strlen(dev_name) + 1) == 0)) {
|
|
if (g_flash_info[i].fd != (td_void *)(intptr_t)INVALID_FD) {
|
|
soc_log_info("dev_name =\"%s\"(%s)\n",
|
|
g_flash_info[i].part_info->dev_name,
|
|
g_flash_info[i].part_info->part_name);
|
|
return (td_s64)(intptr_t)g_flash_info[i].fd;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (realpath(dev_name, tmp_name) == NULL) {
|
|
soc_log_err("Failed to realpath: %s.\n", dev_name);
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
if (g_part_info[part].perm == ACCESS_RDWR) {
|
|
fd = open(tmp_name, O_RDWR);
|
|
} else if (g_part_info[part].perm == ACCESS_RD) {
|
|
fd = open(tmp_name, O_RDONLY);
|
|
} else if (g_part_info[part].perm == ACCESS_WR) {
|
|
fd = open(tmp_name, O_WRONLY);
|
|
} else {
|
|
soc_log_err("Device \"%s\"(%s) can not be opened \n", g_part_info[part].dev_name, g_part_info[part].part_name);
|
|
return ((td_handle)INVALID_FD);
|
|
}
|
|
|
|
if ((fd < 0) || (fd >= SPAN_PART_HANDLE)) {
|
|
soc_log_err("Open %s flash partition failure(fd = %lld)!\n", tmp_name, (td_s64)fd);
|
|
if (fd >= 0) {
|
|
close(fd);
|
|
}
|
|
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
return fd;
|
|
}
|
|
|
|
static td_void flash_open_spi_nand_get_info(uapi_flash_type flash_type, td_u32 flash, td_s64 fd, td_s32 part)
|
|
{
|
|
flash_spinand_info_s raw_info;
|
|
|
|
flash_get_spinand_info(flash_type, &raw_info);
|
|
|
|
g_flash_info[flash].fd = (long *)(intptr_t)fd;
|
|
g_flash_info[flash].open_len = g_part_info[part].part_size;
|
|
g_flash_info[flash].part_info = &g_part_info[part];
|
|
g_flash_info[flash].open_addr = g_flash_info[flash].part_info->start_addr;
|
|
g_flash_info[flash].flash_type = flash_type;
|
|
g_flash_info[flash].page_size = raw_info.page_size;
|
|
g_flash_info[flash].oob_size = raw_info.oob_size;
|
|
g_flash_info[flash].block_size = raw_info.block_size;
|
|
|
|
if (flash_type == UAPI_FLASH_TYPE_NOR_0) {
|
|
g_flash_info[flash].flash_opt = (flash_opt *)&g_dev_flash_opt[UAPI_FLASH_TYPE_NOR_0];
|
|
}
|
|
|
|
if (flash_type == UAPI_FLASH_TYPE_NAND_0) {
|
|
g_flash_info[flash].flash_opt = (flash_opt *)&g_dev_flash_opt[UAPI_FLASH_TYPE_NAND_0];
|
|
}
|
|
|
|
soc_log_info("dev_name =\"%s\"(%s)\n",
|
|
g_flash_info[flash].part_info->dev_name,
|
|
g_flash_info[flash].part_info->part_name);
|
|
}
|
|
|
|
static td_handle flash_open_spi_nand_by_name(uapi_flash_type flash_type, const td_char *partition_name)
|
|
{
|
|
td_s32 part;
|
|
td_u32 flash;
|
|
td_s64 fd;
|
|
|
|
if (!strstr((char*)g_bootargs_str, "soct_nand:") && !strstr((char*)g_bootargs_str, "fmc_sfc:")) {
|
|
return (td_handle)INVALID_FD;
|
|
}
|
|
|
|
/* add i < 0 test in if branch to avoid pclint warning:
|
|
* Warning 676: Possibly negative subscript (-1) in operator '['
|
|
*/
|
|
part = flash_partition_get(flash_type, partition_name);
|
|
if (part < 0) {
|
|
return (td_handle)INVALID_FD;
|
|
}
|
|
|
|
flash = (td_u32)flash_unused_handle();
|
|
if (flash == MAX_HANDLE) {
|
|
soc_log_err("flash array full! \n");
|
|
return (td_handle)INVALID_FD;
|
|
}
|
|
|
|
fd = flash_open_spi_nand_get_fd(part);
|
|
if (fd < 0) {
|
|
return (td_handle)INVALID_FD;
|
|
}
|
|
flash_open_spi_nand_get_info(flash_type, flash, fd, part);
|
|
|
|
soc_log_info("end.\n");
|
|
return (td_handle)flash;
|
|
}
|
|
|
|
td_handle uapi_flash_open_by_addr(uapi_flash_type flash_type, td_u64 address, td_u64 len)
|
|
{
|
|
td_handle flash;
|
|
uapi_flash_type temp_flash_type = flash_type;
|
|
|
|
if (flash_all_init(temp_flash_type) == TD_FAILURE) {
|
|
return (td_handle)INVALID_FD;
|
|
}
|
|
|
|
if (temp_flash_type == UAPI_FLASH_TYPE_AUTO) {
|
|
temp_flash_type = ext_get_flash_type(NULL);
|
|
}
|
|
|
|
if (temp_flash_type >= UAPI_FLASH_TYPE_MAX) {
|
|
soc_log_err("flash_type error! \n");
|
|
return (td_handle)INVALID_FD;
|
|
}
|
|
|
|
if (g_dev_stat[temp_flash_type] != EXT_FLASH_STAT_INSTALL) {
|
|
soc_log_err("No config flash[type: %d].\n", temp_flash_type);
|
|
return (td_handle)INVALID_FD;
|
|
}
|
|
|
|
(td_void)pthread_mutex_lock(&g_flash_mutex);
|
|
|
|
if (temp_flash_type == UAPI_FLASH_TYPE_EMMC_0) {
|
|
flash = flash_open_emmc_by_addr(address, len);
|
|
} else if (temp_flash_type == UAPI_FLASH_TYPE_UFS_0) {
|
|
flash = flash_open_ufs_by_addr(address, len);
|
|
} else {
|
|
flash = flash_open_spi_nand_by_addr(temp_flash_type, address, len);
|
|
}
|
|
|
|
(td_void)pthread_mutex_unlock(&g_flash_mutex);
|
|
|
|
soc_log_info("end.\n");
|
|
|
|
return flash;
|
|
}
|
|
|
|
td_handle uapi_flash_open(uapi_flash_type flash_type, const td_char *partition_name)
|
|
{
|
|
td_handle flash;
|
|
uapi_flash_type temp_flash_type = flash_type;
|
|
|
|
if (partition_name == NULL) {
|
|
return (td_handle)INVALID_FD;
|
|
}
|
|
|
|
if (flash_all_init(temp_flash_type) == TD_FAILURE) {
|
|
return (td_handle)INVALID_FD;
|
|
}
|
|
|
|
if (temp_flash_type == UAPI_FLASH_TYPE_AUTO) {
|
|
temp_flash_type = ext_get_flash_type(partition_name);
|
|
}
|
|
|
|
if (temp_flash_type >= UAPI_FLASH_TYPE_MAX) {
|
|
soc_log_err("flash_type error(flash_type=%d)! \n", temp_flash_type);
|
|
return (td_handle)INVALID_FD;
|
|
}
|
|
|
|
if (g_dev_stat[temp_flash_type] != EXT_FLASH_STAT_INSTALL) {
|
|
soc_log_err("No config flash[type:%d]", temp_flash_type);
|
|
return (td_handle)INVALID_FD;
|
|
}
|
|
|
|
(td_void)pthread_mutex_lock(&g_flash_mutex);
|
|
|
|
if (temp_flash_type == UAPI_FLASH_TYPE_EMMC_0) {
|
|
flash = flash_open_emmc_by_name(partition_name);
|
|
} else if (temp_flash_type == UAPI_FLASH_TYPE_UFS_0) {
|
|
flash = flash_open_ufs_by_name(partition_name);
|
|
} else {
|
|
flash = flash_open_spi_nand_by_name(temp_flash_type, partition_name);
|
|
}
|
|
|
|
(td_void)pthread_mutex_unlock(&g_flash_mutex);
|
|
return flash;
|
|
}
|
|
|
|
static td_void flash_close_emmc(td_handle flash)
|
|
{
|
|
emmc_cb_s *emmc_cb = ((emmc_cb_s *)(g_flash_info[flash].fd));
|
|
(td_void)emmc_raw_close(emmc_cb);
|
|
emmc_cb = NULL;
|
|
g_flash_info[flash].fd = (td_s64 *)(td_s64)INVALID_FD;
|
|
g_flash_info[flash].open_addr = 0;
|
|
g_flash_info[flash].open_len = 0;
|
|
g_flash_info[flash].part_info = NULL;
|
|
g_flash_info[flash].flash_type = UAPI_FLASH_TYPE_MAX;
|
|
}
|
|
|
|
static td_void flash_close_ufs(td_handle flash)
|
|
{
|
|
ufs_cb_s *ufs_cb = ((ufs_cb_s *)(g_flash_info[flash].fd));
|
|
(td_void)ufs_raw_close(ufs_cb);
|
|
ufs_cb = NULL;
|
|
g_flash_info[flash].fd = (td_s64 *)(td_s64)INVALID_FD;
|
|
g_flash_info[flash].open_addr = 0;
|
|
g_flash_info[flash].open_len = 0;
|
|
g_flash_info[flash].part_info = NULL;
|
|
g_flash_info[flash].flash_type = UAPI_FLASH_TYPE_MAX;
|
|
}
|
|
|
|
static td_s32 flash_close_spi_nand(td_handle flash)
|
|
{
|
|
td_u32 i;
|
|
|
|
if (g_flash_info[flash].fd >= (td_void *)(intptr_t)SPAN_PART_HANDLE) {
|
|
g_flash_info[flash].fd = (td_s64 *)(td_s64)INVALID_FD;
|
|
g_flash_info[flash].open_addr = 0;
|
|
g_flash_info[flash].open_len = 0;
|
|
g_flash_info[flash].part_info = NULL;
|
|
} else {
|
|
if (close((int)(intptr_t)g_flash_info[flash].fd) != 0) {
|
|
soc_log_err("Close %s flash partition failure!\n",
|
|
g_flash_info[flash].part_info->dev_name);
|
|
return TD_FAILURE;
|
|
}
|
|
g_flash_info[flash].fd = (td_void *)(td_s64)INVALID_FD;
|
|
g_flash_info[flash].open_addr = 0;
|
|
g_flash_info[flash].open_len = 0;
|
|
g_flash_info[flash].part_info = NULL;
|
|
}
|
|
|
|
for (i = 0; i < MAX_HANDLE; i++) {
|
|
if (g_flash_info[i].fd != (td_void *)INVALID_FD) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == MAX_HANDLE) {
|
|
(td_void)spi_raw_destroy();
|
|
(td_void)nand_raw_destroy();
|
|
g_init_flag = TD_FALSE;
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
td_s32 uapi_flash_close(td_handle handle)
|
|
{
|
|
if (check_flash_init(handle) == TD_FAILURE) {
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
(td_void)pthread_mutex_lock(&g_flash_mutex);
|
|
|
|
if (g_flash_info[handle].flash_type == UAPI_FLASH_TYPE_EMMC_0) {
|
|
flash_close_emmc(handle);
|
|
(td_void)pthread_mutex_unlock(&g_flash_mutex);
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
if (g_flash_info[handle].flash_type == UAPI_FLASH_TYPE_UFS_0) {
|
|
flash_close_ufs(handle);
|
|
(td_void)pthread_mutex_unlock(&g_flash_mutex);
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
/* spi nand close */
|
|
if (flash_close_spi_nand(handle) != TD_SUCCESS) {
|
|
(td_void)pthread_mutex_unlock(&g_flash_mutex);
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
(td_void)pthread_mutex_unlock(&g_flash_mutex);
|
|
soc_log_info("end.\n");
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_s32 compensate_nand_address(td_u64 address, td_u64 *start_addr)
|
|
{
|
|
td_s32 idx;
|
|
flash_spinand_info_s raw_info;
|
|
|
|
flash_get_spinand_info(UAPI_FLASH_TYPE_NAND_0, &raw_info);
|
|
if (raw_info.block_size == 0) {
|
|
soc_log_err("block_size shouldn't equal 0!\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
idx = (td_s32)(address >> raw_info.block_shift);
|
|
if (nand_raw_get_physical_index(*start_addr, &idx, (td_s32)raw_info.block_size) != 0) {
|
|
soc_log_err("logical addr change to physical addr error!\n");
|
|
return TD_FAILURE;
|
|
}
|
|
*start_addr += (td_u64)(((td_u32)idx) << raw_info.block_shift);
|
|
*start_addr += (address % raw_info.block_size);
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_void flash_get_addr_len_value(td_handle flash, td_u64 *start_addr, td_u64 *limit_len)
|
|
{
|
|
if (g_flash_info[flash].fd >= (td_void *)(intptr_t)SPAN_PART_HANDLE) {
|
|
*start_addr = g_flash_info[flash].open_addr;
|
|
*limit_len = g_flash_info[flash].open_len;
|
|
} else {
|
|
*start_addr = g_flash_info[flash].part_info->start_addr;
|
|
*limit_len = g_flash_info[flash].part_info->part_size;
|
|
}
|
|
}
|
|
|
|
td_s64 uapi_flash_erase(td_handle handle, td_u64 offset, td_u64 len)
|
|
{
|
|
td_u64 start_addr = 0;
|
|
td_u64 limit_len = 0;
|
|
td_s64 ret;
|
|
|
|
if (check_flash_init(handle) == TD_FAILURE) {
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
if (g_flash_info[handle].flash_type == UAPI_FLASH_TYPE_EMMC_0) {
|
|
return (td_s64)len;
|
|
}
|
|
|
|
if (g_flash_info[handle].flash_type == UAPI_FLASH_TYPE_UFS_0) {
|
|
return (td_s64)len;
|
|
}
|
|
|
|
(td_void)pthread_mutex_lock(&g_flash_mutex);
|
|
|
|
flash_get_addr_len_value(handle, &start_addr, &limit_len);
|
|
if (check_addr_len(offset, len, limit_len) == TD_FAILURE) {
|
|
(td_void)pthread_mutex_unlock(&g_flash_mutex);
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
if (g_flash_info[handle].flash_type == UAPI_FLASH_TYPE_NAND_0) {
|
|
ret = (td_s64)compensate_nand_address(offset, &start_addr);
|
|
if (ret != TD_SUCCESS) {
|
|
(td_void)pthread_mutex_unlock(&g_flash_mutex);
|
|
return TD_FAILURE;
|
|
}
|
|
} else {
|
|
start_addr += offset;
|
|
}
|
|
soc_log_info("HANDLE=%d, addr=0x%llx, len=0x%llx\n", handle, start_addr, len);
|
|
|
|
if (g_flash_info[handle].flash_opt->raw_erase == NULL) {
|
|
soc_log_err("flash service function ptr(raw_erase) is NULL! \n");
|
|
(td_void)pthread_mutex_unlock(&g_flash_mutex);
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
ret = (td_s64)g_flash_info[handle].flash_opt->raw_erase((td_s32)(intptr_t)g_flash_info[handle].fd,
|
|
(unsigned long long)start_addr, len, g_flash_info[handle].open_addr, limit_len);
|
|
soc_log_info("end.\n");
|
|
(td_void)pthread_mutex_unlock(&g_flash_mutex);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static td_s32 flash_get_rw_info(td_handle flash, td_u64 address,
|
|
td_u32 len, td_u32 flags, flash_rw_info_s *info)
|
|
{
|
|
td_u64 len_without_oob;
|
|
|
|
flash_get_addr_len_value(flash, &info->start_addr, &info->limit_len);
|
|
if (check_addr_len(address, (td_u64)len, info->limit_len) == TD_FAILURE) {
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
if ((flags & UAPI_FLASH_RW_FLAG_WITH_OOB) == UAPI_FLASH_RW_FLAG_WITH_OOB) {
|
|
len_without_oob = (len / (g_flash_info[flash].oob_size + g_flash_info[flash].page_size));
|
|
if ((len_without_oob * g_flash_info[flash].page_size) > MAX_U64) {
|
|
return TD_FAILURE;
|
|
}
|
|
len_without_oob *= g_flash_info[flash].page_size;
|
|
|
|
if ((len % (g_flash_info[flash].oob_size + g_flash_info[flash].page_size)) != 0) {
|
|
len_without_oob += g_flash_info[flash].page_size;
|
|
}
|
|
|
|
if (check_addr_len(address, len_without_oob, info->limit_len) == TD_FAILURE) {
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
info->with_oob = 1;
|
|
} else {
|
|
if (check_addr_len(address, (td_u64)len, info->limit_len) == TD_FAILURE) {
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
info->with_oob = 0;
|
|
}
|
|
|
|
if (g_flash_info[flash].flash_type == UAPI_FLASH_TYPE_NAND_0) {
|
|
if (compensate_nand_address(address, &info->start_addr) != TD_SUCCESS) {
|
|
return TD_FAILURE;
|
|
}
|
|
} else {
|
|
info->start_addr += address;
|
|
}
|
|
|
|
info->fd = (td_s32)(uintptr_t)g_flash_info[flash].fd;
|
|
info->open_addr = g_flash_info[flash].open_addr;
|
|
|
|
soc_log_info("HANDLE=%d, addr=0x%llx, len=0x%x, Flag=%d\n", flash, info->start_addr, len, flags);
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_s32 flash_read_emmc(td_handle flash, td_u64 address, td_u8 *buf, td_u32 len)
|
|
{
|
|
emmc_cb_s *emmc_cb = (emmc_cb_s *)(g_flash_info[flash].fd);
|
|
return emmc_raw_read(emmc_cb, address, len, buf);
|
|
}
|
|
|
|
static td_s32 flash_read_ufs(td_handle flash, td_u64 address, td_u8 *buf, td_u32 len)
|
|
{
|
|
ufs_cb_s *ufs_cb = (ufs_cb_s *)(g_flash_info[flash].fd);
|
|
return ufs_raw_read(ufs_cb, address, len, buf);
|
|
}
|
|
|
|
static td_s64 flash_read_spi_nand(td_handle flash, td_u64 address, td_u8 *buf, td_u32 len, td_u32 flags)
|
|
{
|
|
flash_rw_info_s info;
|
|
|
|
if (flash_get_rw_info(flash, address, len, flags, &info) != TD_SUCCESS) {
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
if (g_flash_info[flash].flash_opt->raw_read == NULL) {
|
|
soc_log_err("flash service function ptr(raw_read) is NULL! \n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
return g_flash_info[flash].flash_opt->raw_read(&info, buf, len, 1);
|
|
}
|
|
|
|
td_s64 uapi_flash_read(td_handle handle, td_u64 offset, td_u8 *buf, td_u64 len, td_u32 flags)
|
|
{
|
|
td_s64 total_read;
|
|
|
|
if (buf == NULL) {
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
if (check_flash_init(handle) == TD_FAILURE) {
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
(td_void)pthread_mutex_lock(&g_flash_mutex);
|
|
|
|
if (g_flash_info[handle].flash_type == UAPI_FLASH_TYPE_EMMC_0) {
|
|
total_read = flash_read_emmc(handle, offset, buf, (td_u32)len);
|
|
} else if (g_flash_info[handle].flash_type == UAPI_FLASH_TYPE_UFS_0) {
|
|
total_read = flash_read_ufs(handle, offset, buf, (td_u32)len);
|
|
} else {
|
|
total_read = flash_read_spi_nand(handle, offset, buf, (td_u32)len, flags);
|
|
}
|
|
|
|
(td_void)pthread_mutex_unlock(&g_flash_mutex);
|
|
soc_log_info("totalread =0x%llx, end.\n", total_read);
|
|
|
|
return total_read;
|
|
}
|
|
|
|
static td_s32 flash_write_emmc(td_handle flash, td_u64 address, const td_u8 *buf, td_u32 len)
|
|
{
|
|
emmc_cb_s *emmc_cb = (emmc_cb_s *)(g_flash_info[flash].fd);
|
|
return emmc_raw_write(emmc_cb, address, len, buf);
|
|
}
|
|
|
|
static td_s32 flash_write_ufs(td_handle flash, td_u64 address, const td_u8 *buf, td_u32 len)
|
|
{
|
|
ufs_cb_s *ufs_cb = (ufs_cb_s *)(g_flash_info[flash].fd);
|
|
return ufs_raw_write(ufs_cb, address, len, buf);
|
|
}
|
|
|
|
static td_s32 flash_write_erase_first(td_handle flash,
|
|
flash_rw_info_s *rw_info,
|
|
flash_spinand_info_s *raw_info,
|
|
td_u32 len, td_u32 flags)
|
|
{
|
|
td_s32 ret;
|
|
td_u64 block_size_new;
|
|
td_u64 erase_len;
|
|
|
|
if ((flags & UAPI_FLASH_RW_FLAG_WITH_OOB) == UAPI_FLASH_RW_FLAG_WITH_OOB) {
|
|
block_size_new = raw_info->block_size + raw_info->oob_size * (raw_info->block_size / raw_info->page_size);
|
|
} else {
|
|
block_size_new = raw_info->block_size;
|
|
}
|
|
|
|
if ((flags & UAPI_FLASH_RW_FLAG_ERASE_FIRST) == UAPI_FLASH_RW_FLAG_ERASE_FIRST) {
|
|
/* avoid pclint div 0 warning */
|
|
if (block_size_new == 0) {
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
erase_len = len / block_size_new;
|
|
if ((len % block_size_new) != 0) {
|
|
erase_len += 1;
|
|
}
|
|
|
|
if ((erase_len * raw_info->block_size) > MAX_U64) {
|
|
return TD_FAILURE;
|
|
}
|
|
erase_len = erase_len * raw_info->block_size;
|
|
|
|
if (g_flash_info[flash].flash_opt->raw_erase == 0) {
|
|
soc_log_err("flash service function ptr(raw_erase) is NULL! \n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
ret = (td_s32)g_flash_info[flash].flash_opt->raw_erase((td_s32)(uintptr_t)g_flash_info[flash].fd,
|
|
rw_info->start_addr, erase_len,
|
|
g_flash_info[flash].open_addr, rw_info->limit_len);
|
|
if ((ret <= 0) && (ret != UAPI_FLASH_END_DUETO_BADBLOCK)) {
|
|
soc_log_err("earse fail!\n");
|
|
return TD_FAILURE;
|
|
}
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_s32 flash_write_spi_nand(td_handle flash, td_u64 address, td_u8 *buf, td_u32 len, td_u32 flags)
|
|
{
|
|
flash_rw_info_s rw_info;
|
|
flash_spinand_info_s raw_info;
|
|
|
|
if (flash_get_rw_info(flash, address, len, flags, &rw_info) != TD_SUCCESS) {
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
flash_get_spinand_info(g_flash_info[flash].flash_type, &raw_info);
|
|
|
|
/* avoid pclint div 0 warning */
|
|
if (raw_info.page_size == 0) {
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
if (flash_write_erase_first(flash, &rw_info, &raw_info, len, flags) != TD_SUCCESS) {
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
if (g_flash_info[flash].flash_opt->raw_write == 0) {
|
|
soc_log_err("flash service function ptr(raw_write) is NULL! \n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
return g_flash_info[flash].flash_opt->raw_write(&rw_info, buf, len);
|
|
}
|
|
|
|
td_s64 uapi_flash_write(td_handle handle, td_u64 offset, td_u8 *buf, td_u64 len, td_u32 flags)
|
|
{
|
|
td_s32 total_write;
|
|
|
|
if (buf == NULL) {
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
if (check_flash_init(handle) == TD_FAILURE) {
|
|
return TD_FAILURE;
|
|
}
|
|
(td_void)pthread_mutex_lock(&g_flash_mutex);
|
|
|
|
if (g_flash_info[handle].flash_type == UAPI_FLASH_TYPE_EMMC_0) {
|
|
total_write = flash_write_emmc(handle, offset, buf, (td_u32)len);
|
|
} else if (g_flash_info[handle].flash_type == UAPI_FLASH_TYPE_UFS_0) {
|
|
total_write = flash_write_ufs(handle, offset, buf, (td_u32)len);
|
|
} else {
|
|
total_write = flash_write_spi_nand(handle, offset, buf, (td_u32)len, flags);
|
|
}
|
|
|
|
(td_void)pthread_mutex_unlock(&g_flash_mutex);
|
|
|
|
soc_log_info("totalwrite =0x%x, end.\n", total_write);
|
|
return total_write;
|
|
}
|
|
|
|
static td_void flash_get_spi_nand_info(td_handle flash, uapi_flash_info *flash_info)
|
|
{
|
|
flash_spinand_info_s raw_info;
|
|
|
|
flash_get_spinand_info(g_flash_info[flash].flash_type, &raw_info);
|
|
|
|
flash_info->total_size = raw_info.total_size;
|
|
if (g_flash_info[flash].fd >= (td_void *)SPAN_PART_HANDLE) {
|
|
flash_info->part_info = NULL;
|
|
} else {
|
|
flash_info->part_info = g_flash_info[flash].part_info;
|
|
}
|
|
flash_info->block_size = raw_info.block_size;
|
|
flash_info->page_size = raw_info.page_size;
|
|
flash_info->oob_size = raw_info.oob_size;
|
|
flash_info->flash_type = g_flash_info[flash].flash_type;
|
|
flash_info->open_addr = g_flash_info[flash].open_addr;
|
|
flash_info->open_len = g_flash_info[flash].open_len;
|
|
}
|
|
|
|
td_s32 uapi_flash_getinfo(td_handle handle, uapi_flash_info *flash_info)
|
|
{
|
|
if (flash_info == NULL) {
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
if (check_flash_init(handle) == TD_FAILURE) {
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
if (g_flash_info[handle].flash_type == UAPI_FLASH_TYPE_EMMC_0) {
|
|
emmc_raw_get_info(handle, flash_info, (emmc_cb_s *)(g_flash_info[handle].fd));
|
|
} else if (g_flash_info[handle].flash_type == UAPI_FLASH_TYPE_UFS_0) {
|
|
ufs_raw_get_info(handle, flash_info, (ufs_cb_s *)(g_flash_info[handle].fd));
|
|
} else {
|
|
flash_get_spi_nand_info(handle, flash_info);
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|