以前年搞过一次,将yaffs2移植到低版本的uboot上,刚好前段时间又有需求移植到ucos上,记录一下
yaffs2移植专题:
使用的是2017-08-11更新的版本yaffs2-c1422c2.tar,路径:http://www.aleph1.co.uk/gitweb/?p=yaffs2.git;a=snapshot;h=c1422c27f5f17c68acf261209292c7489085df6b;sf=tgzyaffs2移植实地址模式YDI主要适配os,以及flash的读写接口。
yaffs2重要的结构体:
yaffs_dev: 总的结构,需分配空间
yaffs_param: 属性结构,param = &dev->param;包含分区名,nand的页,块等属性,起始地址,结束地址,保留块数量,tag等
yaffs_driver: 驱动对接接口, drv = &dev->drv;主要:drv_write_chunk_fn,drv_read_chunk_fn,drv_erase_fn,drv_mark_bad_fn,drv_check_bad_fn...需要全部实现。
最后由yaffs_add_device(dev);添加进去,所以可以支持多个分区,多次yaffs_add_device(devN);
完成后可以用yaffs_mount(ROOT_PATH);注意ROOT_PATH必须和param的分区名对应,否则找不到。
测试过程可以通过yaffs_set_trace(YAFFS_TRACE_ALWAYS | YAFFS_TRACE_ERROR | YAFFS_TRACE_BUG | 0);设置需要调试的模块信息。
完成后即可用yaffs_access,yaffs_open,yaffs_write,yaffs_read,yaffs_close,yaffs_flush等接口正常操作。
调试过程注意nand flash本身是否存在坏块,烧写之前进行erase擦除,不要使用scrub命令擦除,否则可能会将烧写内容写异常。
#include "yaffs2/yportenv.h"
#include "yaffs2/yaffs_trace.h"
#include "yaffs2/yaffs_guts.h"
#include "yaffs2/yaffs_packedtags2.h"
// for mt_nand config(w25n01gv spi nand flash) add by jason.luo at 2017/9/8 11:22:16
#define MTAPP_DEVICE_BASE 0x3000000 //yaffs2 mount addr at 48MB need fix
#define SIZE_IN_MB 60 //flash total size: 128MB, yaffs size 60MB need fix
static const char *yaffs_dev_name = "nand";
struct yaffs_dev *mtDev;
#ifndef RET_CODE
#define RET_CODE s32
#endif
static void *p_dev = NULL;
charsto_flash_info_t flash_info;
static int yflash2_GetStartBlock(){
int startblock = (MTAPP_DEVICE_BASE/flash_info.blocksize);
return startblock;
}
static int yflash2_GetNumberOfBlocks(void)
{
int nBolocks = (SIZE_IN_MB * 1024 * 1024)/(flash_info.blocksize);
return nBolocks;
}
static int yflash2_GetEndBlock(){
int endblock = yflash2_GetStartBlock() + yflash2_GetNumberOfBlocks();
return endblock;
}
static u32 yflash2_GetEndAddr(){
u32 addr = yflash2_GetEndBlock()*flash_info.blocksize;
return addr;
}
static int yflash2_Deinitialise(struct yaffs_dev *dev){
(void)dev;
return 0;
}
static int yflash2_WriteChunk(struct yaffs_dev *dev, int nand_chunk, const u8 *data, int data_len,const u8 *oob, int oob_len){
int ret = -1;
struct mtd_oob_ops ops;
if (!data || !data_len) {
data = NULL;
data_len = 0;
}
if (!oob || !oob_len) {
oob = NULL;
oob_len = 0;
}
u32 addr = ((u32) nand_chunk) * dev->param.total_bytes_per_chunk;
if(addr < MTAPP_DEVICE_BASE|| addr > yflash2_GetEndAddr()){
return YAFFS_FAIL;
}
if(data && data_len)
{
ret = charsto_writeonly(p_dev,addr,(u8 *)data,data_len);
if(ret)
{
OS_PRINTF("%s %d ret = %d\n",__FUNCTION__,__LINE__,ret);
}
}
if(oob && oob_len)
{
memset(&ops, 0, sizeof(ops));
ops.datbuf = NULL;
ops.len = 0;
ops.ooblen = oob_len;
ops.mode = MTD_OOB_AUTO;
ops.ooboffs = 0;
ops.oobbuf = (u8 *)oob;
ret = charsto_write_oob(p_dev,addr,&ops);
if(ret)
{
OS_PRINTF("%s %d ret = %d\n",__FUNCTION__,__LINE__,ret);
}
}
if(ret < 0){
{
OS_PRINTF("%s %d ret = %d\n",__FUNCTION__,__LINE__,ret);
return YAFFS_FAIL;
}
}else{
return YAFFS_OK;
}
}
static int yflash2_Initialise(struct yaffs_dev *dev)
{
(void) dev;
return YAFFS_OK;
}
static int yflash2_CheckBad(struct yaffs_dev *dev, int block_no)
{
charsto_flash_bad_block_info_t info;
u8 ret = 0;
if(block_no < yflash2_GetStartBlock() || block_no > yflash2_GetEndBlock()){
return YAFFS_FAIL;
}
info.addr = block_no;
dev_io_ctrl(p_dev, CHARSTO_IOCTRL_IS_BAD_BLOCK, (u32)&info);
ret = info.block_is_bad;
if(ret == 0)
return YAFFS_OK;
return YAFFS_FAIL;
}
static int yflash2_MarkBad(struct yaffs_dev *dev, int block_no)
{
int ret = 0;
if(block_no < yflash2_GetStartBlock() || block_no > yflash2_GetEndBlock()){
return YAFFS_FAIL;
}
u32 offset = block_no;
dev_io_ctrl(p_dev, CHARSTO_IOCTRL_MARK_BAD_BLOCK,offset);
if(ret != 0)
return YAFFS_FAIL;
return YAFFS_OK;
}
static int yflash2_write_chunk_tags (struct yaffs_dev *dev,
int nand_chunk, const u8 *data,
const struct yaffs_ext_tags *tags){
struct mtd_oob_ops ops;
int retval = 0;
loff_t addr;
struct yaffs_packed_tags2 pt;
int packed_tags_size = dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
void *packed_tags_ptr = dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
yaffs_trace(YAFFS_TRACE_MTD,
"nandmtd2_write_chunk_tags chunk %d data %p tags %p",
nand_chunk, data, tags);
addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
/* For yaffs2 writing there must be both data and tags.
* If we're using inband tags, then the tags are stuffed into
* the end of the data buffer.
*/
if (!data || !tags)
BUG();
else if (dev->param.inband_tags) {
struct yaffs_packed_tags2_tags_only *pt2tp;
pt2tp = (struct yaffs_packed_tags2_tags_only *)(data + dev->data_bytes_per_chunk);
yaffs_pack_tags2_tags_only(dev,pt2tp, tags);
} else {
yaffs_pack_tags2(dev,&pt, tags, !dev->param.no_tags_ecc);
}
charsto_writeonly(p_dev,addr,(u8 *)data,dev->param.total_bytes_per_chunk);
ops.mode = MTD_OOB_AUTO;
ops.ooblen = (dev->param.inband_tags) ? 0 : packed_tags_size;
ops.len = 0;//dev->param.total_bytes_per_chunk;
ops.ooboffs = 0;
ops.datbuf = NULL;//(u8 *) data;
ops.oobbuf = (dev->param.inband_tags) ? NULL : packed_tags_ptr;
retval = charsto_write_oob(p_dev, addr, &ops);
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
static int yflash2_read_chunk_tags(struct yaffs_dev *dev,
int nand_chunk, u8 *data,
struct yaffs_ext_tags *tags){
u8 local_spare[128];
struct mtd_oob_ops ops;
int retval = 0;
int local_data = 0;
struct yaffs_packed_tags2 pt;
loff_t addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
int packed_tags_size =
dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
void *packed_tags_ptr =
dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
yaffs_trace(YAFFS_TRACE_ERROR,
"nandmtd2_read_chunk_tags chunk %d data %p tags %p",
nand_chunk, data, tags);
if (dev->param.inband_tags) {
if (!data) {
local_data = 1;
data = yaffs_get_temp_buffer(dev);
}
}
if (dev->param.inband_tags || (data && !tags)){
/* Do not allow reads past end of device */
if ((addr + dev->param.total_bytes_per_chunk) > flash_info.chipsize)
return -1;
retval = charsto_read(p_dev, addr,data,dev->param.total_bytes_per_chunk);
}
else if (tags) {
ops.mode = MTD_OOB_AUTO;
ops.ooblen = packed_tags_size;
ops.len = data ? dev->data_bytes_per_chunk : packed_tags_size;
ops.ooboffs = 0;
ops.datbuf = data;
ops.oobbuf = local_spare;
retval = charsto_read_oob(p_dev, addr, &ops);
}
if (dev->param.inband_tags) {
if (tags) {
struct yaffs_packed_tags2_tags_only *pt2tp;
pt2tp =
(struct yaffs_packed_tags2_tags_only *)
&data[dev->data_bytes_per_chunk];
yaffs_unpack_tags2_tags_only(dev,tags, pt2tp);
}
} else {
if (tags) {
memcpy(packed_tags_ptr,
local_spare,
packed_tags_size);
yaffs_unpack_tags2(dev,tags, &pt, !dev->param.no_tags_ecc);
}
}
if (local_data)
yaffs_release_temp_buffer(dev, data);
if (tags && retval == -EBADMSG
&& tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) {
tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED;
dev->n_ecc_unfixed++;
}
if (tags && retval == -EUCLEAN
&& tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) {
tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
dev->n_ecc_fixed++;
}
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
static int yflash2_QueryBlock (struct yaffs_dev *dev, int block_no,enum yaffs_block_state *state,u32 *seq_number){
int retval = 0;
charsto_flash_bad_block_info_t info;
yaffs_trace(YAFFS_TRACE_MTD, "nandmtd2_QueryNANDBlock %d", block_no);
info.addr = block_no;
dev_io_ctrl(p_dev, CHARSTO_IOCTRL_IS_BAD_BLOCK, (u32)&info);
retval = info.block_is_bad;
if (retval) {
yaffs_trace(YAFFS_TRACE_MTD, "block is bad");
*state = YAFFS_BLOCK_STATE_DEAD;
*seq_number = 0;
} else {
struct yaffs_ext_tags t;
yflash2_read_chunk_tags(dev,
block_no *
dev->param.chunks_per_block, NULL,
&t);
if (t.chunk_used) {
*seq_number = t.seq_number;
*state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
} else {
*seq_number = 0;
*state = YAFFS_BLOCK_STATE_EMPTY;
}
}
yaffs_trace(YAFFS_TRACE_MTD, "block is bad seq %d state %d",
*seq_number, *state);
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
static int yflash2_EraseBlock(struct yaffs_dev *dev, int block_no)
{
if(block_no < yflash2_GetStartBlock() || block_no > yflash2_GetEndBlock()){
return YAFFS_FAIL;
}
charsto_erase(p_dev,block_no*128*1024,1);
return YAFFS_OK;
}
static int yflash2_ReadChunk(struct yaffs_dev *dev, int nand_chunk,u8 *data, int data_len,u8 *oob, int oob_len,enum yaffs_ecc_result *ecc_result_out){
int ret = -1;
struct mtd_oob_ops ops;
u32 addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
if(addr < MTAPP_DEVICE_BASE|| addr > yflash2_GetEndAddr()){
return YAFFS_FAIL;
}
if(data && data_len){
ret = charsto_read(p_dev,addr,data,data_len);
}
if(oob && oob_len){
memset(&ops, 0, sizeof(ops));
ops.mode = MTD_OOB_AUTO;
ops.len = 0;
ops.ooblen = oob_len;
ops.datbuf = NULL;
ops.oobbuf = oob;
ret = charsto_read_oob(p_dev,addr,&ops);
}
if(ret < 0)
{
OS_PRINTF("spi_nand_do_read_ops 0x%x error\n",addr);
return YAFFS_FAIL;
}
*ecc_result_out = YAFFS_ECC_RESULT_NO_ERROR;
return YAFFS_OK;
}
static struct yaffs_dev *yflash2_install_drv(const char *name,int startblock,int endblock){
struct yaffs_param *param;
struct yaffs_driver *drv = NULL;
struct yaffs_dev *dev = NULL;
struct yaffs_tags_handler *tagger = NULL;
dev = malloc(sizeof(*dev));
if(!dev){
return NULL;
}
memset(dev, 0, sizeof(*dev));
dev->param.name = strdup(name);
if(!dev->param.name) {
free(dev);
return NULL;
}
param = &dev->param;
param->total_bytes_per_chunk = flash_info.pagesize;
param->chunks_per_block = flash_info.blocksize / flash_info.pagesize;
param->spare_bytes_per_chunk = flash_info.oobsize;
param->start_block = startblock; //0X3000000 = 384
param->end_block = endblock-1;
param->is_yaffs2 = 1;
param->use_nand_ecc=1; //nand ecc or yaffs ecc
param->empty_lost_n_found = 1; //auto empty
param->n_reserved_blocks = 5;
param->refresh_period = 1000;
param->n_caches = 10; // Use caches
param->inband_tags = 0; //must set for yaffs2 big page
param->no_tags_ecc = 1;
drv = &dev->drv;
drv->drv_initialise_fn = yflash2_Initialise;
drv->drv_deinitialise_fn = yflash2_Deinitialise;
drv->drv_write_chunk_fn = yflash2_WriteChunk;
drv->drv_read_chunk_fn = yflash2_ReadChunk;
drv->drv_erase_fn = yflash2_EraseBlock;
drv->drv_mark_bad_fn = yflash2_MarkBad;
drv->drv_check_bad_fn = yflash2_CheckBad;
tagger = &dev->tagger;
tagger->mark_bad_fn = yflash2_MarkBad;
tagger->query_block_fn = yflash2_QueryBlock;
tagger->write_chunk_tags_fn = yflash2_write_chunk_tags;
tagger->read_chunk_tags_fn = yflash2_read_chunk_tags;
yaffs_add_device(dev);
return dev;
}
int yaffs_start_up(void){
static int start_up_called = 0;
if(start_up_called){
return 0;
}
start_up_called = 1;
yaffsfs_OSInitialisation();
//get snf first
p_dev = dev_find_identifier(NULL, DEV_IDT_TYPE, SYS_DEV_TYPE_CHARSTO);
// charsto_flash_info_t flash_info;
dev_io_ctrl(p_dev, CHARSTO_IOCTRL_GET_FLASH_INFO, (u32)&flash_info);
int start_block = yflash2_GetStartBlock();
int end_block = yflash2_GetEndBlock();
mtDev = yflash2_install_drv(yaffs_dev_name,start_block,end_block);
if(mtDev == NULL){
return -1;
}
return -1;
}
int mt_yaffs_start_up(void){
// yaffs_set_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_ALWAYS | YAFFS_TRACE_BUG | YAFFS_TRACE_BAD_BLOCKS | YAFFS_TRACE_SCAN_DEBUG | YAFFS_TRACE_SCAN);
return yaffs_start_up();
}
name对应的是挂载点"/name"
param->inband_tags = 0; OOB存储tag
tagger = &dev->tagger;函数不能偷懒,都得设置起