RT-Thread下移植添加nand-flash驱动

1:版本

使用的版本上v3.1.4中移除了mtd的相关代码,如果需要添加就从v3.1.3中获取。
由于我要移植yaffs所以需要这个框架

在这里插入图片描述

2:注册函数

//mtd.c
/*
 * Register MTD driver
 *
 * @parts partion description
 * @np number of partitions
 * @return number of unregistered partitions
 *
*/
int rt_mtd_register(rt_mtd_t *master, const struct mtd_part *parts, int np)
{
    int ret;
    rt_mtd_t *slave;

    master->master = master;
    master->parent.type = RT_Device_Class_MTD;

    if (np > 0)
    {
        master->offset = parts->offset;
        master->size = parts->size;

        ret = rt_device_register((rt_device_t)master, parts->name, 0);
        if (ret != 0)
            goto _out;

        np --;
        parts ++;
    }

    while (np > 0)
    {
        slave = mtd_part_alloc(master, parts);
        if (!slave)
            break;
        ret = rt_device_register((rt_device_t)slave, parts->name, 0);
        if (ret)
            break;
        parts ++;
        np --;
    }

_out:
    return np;
}

这个函数会注册一个mtd设备
所以要对
rt_mtd_t *master
const struct mtd_part *parts
int np
进行赋值

typedef struct mtd_info
{
    struct rt_device parent;  

    const struct mtd_ops *ops; //集体的操作函数,看下个图

    uint16_t oob_size;
    uint16_t sector_size;   /* Minimal writable flash unit size */
    uint32_t block_size:28; /* Erase size for the device */
    uint32_t type:4;

    size_t size;    /* Total size of the MTD */
    loff_t offset;  /* At which this MTD starts, from the beginning of the MEMORY */
    struct mtd_info *master;

    void *priv;
}rt_mtd_t;

这个具体的函数指针,要对这样指针进行赋值具体的函数,如果设备注册成功的话。调用设备里的读写函数就是调用这里的指向的函数。

struct mtd_ops
{
    int(*erase)(rt_mtd_t *mtd, loff_t addr, size_t len);    /* return 0 if success */
    int(*read) (rt_mtd_t *mtd, loff_t from, struct mtd_io_desc *ops); /* return 0 if success */
    int(*write) (rt_mtd_t *mtd, loff_t to, struct mtd_io_desc *ops);  /* return 0 if success */
    int(*isbad) (rt_mtd_t *mtd, uint32_t block);    /* return 1 if bad, 0 not bad */
    int(*markbad) (rt_mtd_t *mtd, uint32_t block);  /* return 0 if success */
};

这个结构体:由设备的名字,起始位置,大小。

struct mtd_part
{
    const char *name;           /* name of the MTD partion */
    loff_t offset;              /* start addr of partion */
    size_t size;                /* size of partion */
};

3:赋值

在Rt-thread下自带的文件mtdnand.c中已经对操作函数进行赋值:

//mtdnand.c

static const struct mtd_ops _ops =
{
    nand_erase,
    nand_read,
    nand_write,
    nand_block_isbad,
    nand_block_markbad,
};

int rt_mtd_nand_init(rt_nand_t *nand, int blk_size, int page_size, int oob_size)
{
    uint8_t *buf;

    buf = rt_malloc(oob_size * 3);
    if (buf == RT_NULL)
        return -ENOMEM;

    nand->oob_poi = buf;
    buf += oob_size;
    nand->buffers.ecccalc = buf;
    buf += oob_size;
    nand->buffers.ecccode = buf;
    nand->pagebuf = 0; /* alloc when unaligen access */

    nand->pages_pb = blk_size / page_size;
    nand->ecc._step = page_size / nand->ecc.stepsize;
    nand->page_size = page_size;
    nand->oobsize = oob_size;

    nand->parent.type = MTD_TYPE_NAND;
    nand->parent.ops = &_ops;
    nand->parent.sector_size = page_size;
    nand->parent.block_size = blk_size;
    nand->parent.oob_size = oob_size;

    switch (nand->ecc.mode)
    {
    case NAND_ECCM_NONE:
    {
        nand->read_page = nand_read_page_raw;
        nand->write_page = nand_write_page_raw;
    }break;
    case NAND_ECCM_HW:
    {
        nand->read_page = nand_read_page_hwecc;
        nand->write_page = nand_write_page_hwecc;
    }break;
    default:
    {
        rt_free(buf);
        return -1;
    }
    }

    return 0;
}

用其中的擦除为例nand_erase

static int nand_erase(rt_mtd_t *mtd, loff_t addr, size_t size)
{
    rt_nand_t *chip;
    int status;
    int page;
    uint32_t blksize;

    chip = MTDTONAND(mtd);
    blksize = mtd->block_size;
    page = addr / chip->page_size;

    while (size >= blksize)
    {
        status = chip->ops->cmdfunc(chip, NAND_CMD_BLK_ERASE, page, 0);
        if (status & NAND_STATUS_FAIL)
        {
            break;
        }
        size -= blksize;
        page += chip->pages_pb;
    }

    return size;
}

其中由status = chip->ops->cmdfunc(chip, NAND_CMD_BLK_ERASE, page, 0); 表示通过这个语句可以经行具体的命令的操作。这里就操作到的底层的驱动。这个需要实现。这个函数在下面这个结构体中的const struct nand_ops *ops;

typedef struct nand_chip
{
    rt_mtd_t parent;
    /* driver must init these */
    const struct nand_ops *ops;
    struct nand_ecc ecc;
    const struct mtd_oob_region *freelayout;

    /* driver do not touch */
    struct nand_buffers buffers;
    uint8_t *oob_poi;
    uint8_t *pagebuf;
    uint32_t size;
    uint16_t oobsize;
    uint8_t pages_pb;
    uint16_t page_size;
    int(*read_page)(struct nand_chip *chip, uint8_t *buf, int oob_required, int page);
    int(*write_page)(struct nand_chip *chip, const uint8_t *buf, int oob_required, int page);
}rt_nand_t;
struct nand_ops
{
    int(*cmdfunc)(rt_nand_t *nand, int cmd, int page, int offset); /* send nand operation cmd, return Status bits(0 success),
                                                                      if nand is busy please wait in low driver */
    int(*read_buf)(rt_nand_t *nand, uint8_t *buf, int len);        /* read data from nand chip's page buffer */
    int(*write_buf)(rt_nand_t *nand, const  uint8_t *buf, int len);/* write data to nand chip's page buffer */
    int(*isbad)(rt_nand_t *nand, uint32_t blk);   /* if NULL OOB[0] used as bad mark(not 0xff is bad) */
    int(*markbad)(rt_nand_t *nand, uint32_t blk); /* if NULL OOB[0] used as bad mark(set to 0x00) */
};

4:底层驱动

所以我们在这里建立新的文件对应自己的nand-flash驱动,对上面的函数和结构体进行赋值
并进行初始化flash控制器的操作

static const struct nand_ops nuc970_nand_ops =
{
	nuc977_nand_cmdfunc,
    nuc977_nand_read_buf,
    nuc977_nand_write_buf,
    nuc977_nand_isbad,
	nuc977_nand_markbad
 
};
/* nandflash confg */

int nuc970_fmi_nand_init(void)
{
	char *name = "nand1";
	rt_uint32_t eBCHAlgo;
	rt_nand_t *nand	= &nand_chip[0];
	
	nand->ops = &nuc970_nand_ops;
	nand->oobsize = PAGE_OOB_SIZE;
	
    /* initial NAND controller */
    outpw(REG_CLK_HCLKEN, (inpw(REG_CLK_HCLKEN) | 0x300000));

    /* select NAND function pins */
    if (inpw(REG_SYS_PWRON) & 0x08000000)
    {
        /* Set GPI1~15 for NAND */
        outpw(REG_SYS_GPI_MFPL, 0x55555550);
        outpw(REG_SYS_GPI_MFPH, 0x55555555);
    }
    else
    {
        /* Set GPC0~14 for NAND */
        outpw(REG_SYS_GPC_MFPL, 0x55555555);
        outpw(REG_SYS_GPC_MFPH, 0x05555555);
    }

    // Enable SM_EN
    outpw(REG_FMI_CTL, NAND_EN);
    outpw(REG_NANDTMCTL, 0x20305);

    // Enable SM_CS0
    outpw(REG_NANDCTL, (inpw(REG_NANDCTL)&(~0x06000000))|0x04000000);
    outpw(REG_NANDECTL, 0x1); /* un-lock write protect */

    // NAND Reset
    outpw(REG_NANDCTL, inpw(REG_NANDCTL) | 0x1);    // software reset
    while (inpw(REG_NANDCTL) & 0x1);

    /* Detect NAND chips */
    /* first scan to find the device and get the page size */
//	if (nand_scan_ident(&(nuc970_nand->mtd), 1, NULL)) {
//        rt_kprintf("NAND Flash not found !\n");
//        return -1;
//    }
	
    //Set PSize bits of SMCSR register to select NAND card page size
    switch (PAGE_PAGE_SIZE) {
        case 2048:
            outpw(REG_NANDCTL, (inpw(REG_NANDCTL)&(~0x30000)) + 0x10000);
            eBCHAlgo = 0; /* T4 */
           // nuc970_layout_oob_table ( &nuc970_nand_oob, mtd->oobsize, g_i32ParityNum[1][nuc970_nand->eBCHAlgo] );
            break;

        case 4096:
            outpw(REG_NANDCTL, (inpw(REG_NANDCTL)&(~0x30000)) + 0x20000);
            eBCHAlgo = 1; /* T8 */
            //nuc970_layout_oob_table ( &nuc970_nand_oob, mtd->oobsize, g_i32ParityNum[2][nuc970_nand->eBCHAlgo] );
            break;

        case 8192:
            outpw(REG_NANDCTL, (inpw(REG_NANDCTL)&(~0x30000)) + 0x30000);
            eBCHAlgo = 2; /* T12 */
            //nuc970_layout_oob_table ( &nuc970_nand_oob, mtd->oobsize, g_i32ParityNum[3][nuc970_nand->eBCHAlgo] );
            break;

        /* Not support now. */
        case 512:

        default:
            rt_kprintf("NUC970 NAND CONTROLLER IS NOT SUPPORT THE PAGE SIZE. (%d, %d)\n", 2048, 64 );
    }
	
    // Redundant area size
    outpw(REG_NANDRACTL, PAGE_OOB_SIZE);

    // Protect redundant 3 bytes
    // because we need to implement write_oob function to partial data to oob available area.
    // Please note we skip 4 bytes
    outpw(REG_NANDCTL, inpw(REG_NANDCTL) | 0x100);

    // To read/write the ECC parity codes automatically from/to NAND Flash after data area field written.
    outpw(REG_NANDCTL, inpw(REG_NANDCTL) | 0x10);
    // Set BCH algorithm
    outpw(REG_NANDCTL, (inpw(REG_NANDCTL) & (~0x007C0000)) | g_i32BCHAlgoIdx[eBCHAlgo]);
    // Enable H/W ECC, ECC parity check enable bit during read page
    outpw(REG_NANDCTL, inpw(REG_NANDCTL) | 0x00800080);

	rt_mtd_nand_init(nand, PAGE_BLOCK_SIZE, PAGE_PAGE_SIZE, PAGE_OOB_SIZE);
	rt_mtd_register(&(nand->parent), &parts, 1);
    return 0;
}

void nuc970_nand_mtd_init(void)
{

	nuc970_fmi_nand_init();
	nuc970_nand_read_id();
	
}
INIT_DEVICE_EXPORT(nuc970_nand_mtd_init);

5:总结

mtd.c提供了注册函数。mtdnand.c 实现内部的操作函数,但是到底层的具体操作没有实现。再加上自己的驱动文件,来实现底层操作来供mtdnand.c 来使用

这样就能注册MTD的设备
在这里插入图片描述

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值