Files
luban-lite-t3e-pro/packages/third-party/dfs/filesystems/elmfat/spinand_disk/spinand_disk.c

245 lines
6.8 KiB
C
Raw Normal View History

2023-11-09 20:19:51 +08:00
/*
* Copyright (c) 2023, ArtInChip Technology Co., Ltd
*
* SPDX-License-Identifier: Apache-2.0
*
* Authors: xuan.wen <xuan.wen@artinchip.com>
*/
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <dfs_bare.h>
#include <rtconfig.h>
#include "aic_osal.h"
#include "spinand_disk.h"
#include "mtd.h"
static struct spinand_blk_device *blk_device = NULL;
static struct rt_device_blk_geometry info = { 0 };
/*******************************************************************************
* Code
******************************************************************************/
DRESULT spinand_disk_write(const char *device_name, const uint8_t *buf,
uint32_t sector, uint8_t cnt)
{
if (!blk_device->mtd_device)
return RES_NOTRDY;
return RES_OK;
}
DRESULT spinand_disk_read(const char *device_name, uint8_t *buf,
uint32_t sector, uint8_t cnt)
{
rt_size_t sectors_per_page;
rt_size_t start_page, block, offset;
unsigned char *copybuf = NULL;
rt_size_t sectors_read = 0;
rt_size_t copysize = 0;
rt_size_t pages_per_block;
rt_size_t ret = 0;
struct mtd_dev *mtd = blk_device->mtd_device;
if (!blk_device->mtd_device)
return RES_NOTRDY;
pages_per_block = mtd->erasesize / mtd->writesize;
sectors_per_page = mtd->writesize / info.bytes_per_sector;
block = sector * info.bytes_per_sector / mtd->erasesize;
offset = block * mtd->erasesize;
/* Search for the first good block after the given offset */
while (mtd->ops.block_isbad(mtd, offset)) {
pr_warn("Find a bad block, sector adjust to the next block\n");
sector += pages_per_block * sectors_per_page;
block++;
}
start_page = sector / sectors_per_page;
offset = start_page * mtd->writesize;
/*sector is not aligned with page, read unalign part first*/
if (sector % sectors_per_page) {
memset(blk_device->pagebuf, 0xFF, mtd->writesize);
ret = mtd->ops.read_oob(mtd, offset, blk_device->pagebuf,
mtd->writesize, NULL, 0);
if (ret != RT_EOK) {
pr_err("Mtd read page failed!\n");
return -RT_ERROR;
}
copybuf = blk_device->pagebuf +
(sector % sectors_per_page) * info.bytes_per_sector;
if (cnt > (sectors_per_page - sector % sectors_per_page)) {
copysize = (sectors_per_page - sector % sectors_per_page) *
info.bytes_per_sector;
sectors_read += (sectors_per_page - sector % sectors_per_page);
} else {
copysize = cnt * info.bytes_per_sector;
sectors_read += cnt;
}
memcpy(buf, copybuf, copysize);
buf += copysize;
start_page++;
}
if (cnt - sectors_read == 0)
return RES_OK;
#ifdef AIC_SPINAND_CONT_READ
if ((cnt - sectors_read) > sectors_per_page) {
uint8_t *data_ptr = RT_NULL;
uint32_t copydata = (cnt - sectors_read) * info.bytes_per_sector;
data_ptr = (uint8_t *)aicos_malloc_align(0, copydata, CACHE_LINE_SIZE);
if (data_ptr == RT_NULL) {
pr_err("Malloc buf data_ptr failed\n");
goto exit_spinand_disk_read_malloc;
}
memset(data_ptr, 0, copydata);
offset = start_page * mtd->writesize;
ret = mtd->ops.cont_read(mtd, offset, data_ptr, copydata);
if (ret != RT_EOK) {
pr_err("continuous_read failed!\n");
goto exit_spinand_disk_read;
}
memcpy(buf, data_ptr, copydata);
if (data_ptr)
aicos_free_align(0, data_ptr);
return RES_OK;
exit_spinand_disk_read:
if (data_ptr)
aicos_free_align(0, data_ptr);
}
exit_spinand_disk_read_malloc:
#endif
/*sector is aligned with page*/
while (cnt > sectors_read) {
if (start_page / pages_per_block != block) {
block = start_page / pages_per_block;
offset = block * mtd->erasesize;
while (mtd->ops.block_isbad(mtd, offset)) {
pr_warn("Find a bad block, sector adjust to the next block\n");
block++;
start_page += pages_per_block;
}
}
memset(blk_device->pagebuf, 0xFF, mtd->writesize);
offset = start_page * mtd->writesize;
ret = mtd->ops.read_oob(mtd, offset, blk_device->pagebuf,
mtd->writesize, NULL, 0);
if (ret != RT_EOK) {
pr_err("Mtd read page failed!\n");
return -RT_ERROR;
}
if ((cnt - sectors_read) > sectors_per_page) {
copysize = sectors_per_page * info.bytes_per_sector;
sectors_read += sectors_per_page;
} else {
copysize = (cnt - sectors_read) * info.bytes_per_sector;
sectors_read += (cnt - sectors_read);
}
memcpy(buf, blk_device->pagebuf, copysize);
buf += copysize;
start_page++;
}
return RES_OK;
}
DRESULT spinand_disk_ioctl(const char *device_name, uint8_t command, void *buf)
{
DRESULT result = RES_OK;
switch (command) {
case GET_SECTOR_COUNT:
if (buf) {
*(uint32_t *)buf = info.sector_count;
} else {
result = RES_PARERR;
}
break;
case GET_SECTOR_SIZE:
if (buf) {
*(uint32_t *)buf = info.bytes_per_sector;
} else {
result = RES_PARERR;
}
break;
case GET_BLOCK_SIZE:
if (buf) {
*(uint32_t *)buf = info.block_size;
} else {
result = RES_PARERR;
}
break;
case CTRL_SYNC:
result = RES_OK;
break;
default:
result = RES_PARERR;
break;
}
return result;
}
DSTATUS spinand_disk_status(const char *device_name)
{
return RES_OK;
}
DSTATUS spinand_disk_initialize(const char *device_name)
{
blk_device = (struct spinand_blk_device *)aicos_malloc(
MEM_CMA, sizeof(struct spinand_blk_device));
if (!blk_device) {
pr_err("Error: no memory for create SPI NAND block device");
return RES_ERROR;
}
/*Obtain devices by part name*/
blk_device->mtd_device = mtd_get_device(device_name);
if (!blk_device->mtd_device) {
pr_err("Failed to get mtd %s\n", device_name);
return RES_NOTRDY;
}
blk_device->pagebuf = aicos_malloc_align(
0, blk_device->mtd_device->writesize, CACHE_LINE_SIZE);
if (!blk_device->pagebuf) {
pr_err("Malloc buf failed\n");
return RES_ERROR;
}
info.bytes_per_sector = 512;
info.block_size = info.bytes_per_sector;
info.sector_count = blk_device->mtd_device->size / info.bytes_per_sector;
return RES_OK;
}