文档章节

u-boot的NAND初始化分析,及cubieboard移植nand驱动初步分析

cubieboard
 cubieboard
发布于 2014/08/17 13:24
字数 1931
阅读 156
收藏 0

原文:http://blog.csdn.net/andy_wsj/article/details/9335755

分析一下u-boot内nand初始化过程,都是我所看所想的一些东西
以前从未写过nand相关代码,也没了解过nand的工作方式,理解可能有所偏差,各位请不吝指正。
针对soc片上nand控制器而言,硬件初始化应该包含一下几个方面:
1、nand模块使用的时钟设置
2、既然接了一颗芯片,那么相关几个引脚需要初始化成支持nand的功能
3、nand控制寄存器的配置,例如中断、DMA模式等等
这是简单的一些想法,下面看看u-boot内的代码流程
一、流程分析
假设定义了nand驱动,上电时就会调用下面一段代码
...........
#if defined(CONFIG_CMD_NAND)
puts("NAND:  ");
nand_init(); /* go init the NAND */
#endif
............
这段代码在文件\u-boot-sunxi-sunxi\arch\arm\lib\board.c内
可见想要使用nand驱动,得定义宏 CONFIG_CMD_NAND
调用了一个函数 nand_init(),在文件\u-boot-sunxi-sunxi\drivers\mtd\nand\nand.c内:
void nand_init(void)
{
#ifdef CONFIG_SYS_NAND_SELF_INIT
board_nand_init();
#else
int i;

for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++)
nand_init_chip(i);
#endif

printf("%lu MiB\n", total_nand_size / 1024);

#ifdef CONFIG_SYS_NAND_SELECT_DEVICE
/*
* Select the chip in the board/cpu specific driver
*/
board_nand_select_device(nand_info[nand_curr_device].priv, nand_curr_device);
#endif
}
这个函数用了一个宏CONFIG_SYS_MAX_NAND_DEVICE,很明显,表示板子上有几颗nand芯片,
cubieboard当然是一颗,这个宏需要自己定义,值为1
一般来说,这个函数都将调用nand_init_chip(),在来看看这个函数,也在这个文件内:
static void nand_init_chip(int i)
{
struct mtd_info *mtd = &nand_info;
struct nand_chip *nand = &nand_chip;
ulong base_addr = base_address;
int maxchips = CONFIG_SYS_NAND_MAX_CHIPS;

if (maxchips < 1)   // 防止错误的数据
maxchips = 1;

mtd->priv = nand; 
nand->IO_ADDR_R = nand->IO_ADDR_W = (void  __iomem *)base_addr;

if (board_nand_init(nand))    // 硬件初始化
return;

if (nand_scan(mtd, maxchips))  // 接口函数初始化
return;

nand_register(i);   //设备注册
}
这个函数调用了三个函数,完成初始化工作
board_nand_init()函数就是跟板子相关的初始化,就是自己需要实现的代码。
nand_scan()函数,我的理解就是接口的初始化,就是将MTD模块使用的部分函数初始化到用户自己实现的代码上
nand_register()注册驱动,这个代码不需要用户实现
这里有一个代码细节
mtd->priv = nand; 
mtd模块的私有数据就是nand这个结构体,初始化时实现nand结构体的初始化就能把操作传递到mtd层去了
这个后面在分析一下。
再来看看这三个函数,board_nand_init()不存在,就是需要用户自己实现
例如,在\u-boot-sunxi-sunxi\drivers\mtd\nand\创建自己的驱动代码文件sunxi_nand.c
里面就需要定义这个函数
int  board_nand_init(struct nand_chip *nand)
这个函数有两部分:
1、就是开始提到的三个方面
     nand模块使用的时钟设置
     相关几个引脚需要初始化成支持nand的功能
    nand控制寄存器的配置,例如中断、DMA模式等等
2、相关结构体数据的初始化
sunxi_nand.c内还需要实现其他部分代码,这个要根据实际的CPU来确定
到这里就需要说说编程模式了,nand驱动的编写也是采用面向对象的方式,而board_nand_init的作用就是将一个nand类实例化
这里操作了一个结构体
struct nand_chip {
void __iomem *IO_ADDR_R;
void __iomem *IO_ADDR_W;

uint8_t (*read_byte)(struct mtd_info *mtd);
u16 (*read_word)(struct mtd_info *mtd);
void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);
int (*verify_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
void (*select_chip)(struct mtd_info *mtd, int chip);
int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);
int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl);
int (*init_size)(struct mtd_info *mtd, struct nand_chip *this,
u8 *id_data);
int (*dev_ready)(struct mtd_info *mtd);
void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column,
int page_addr);
int(*waitfunc)(struct mtd_info *mtd, struct nand_chip *this);
void (*erase_cmd)(struct mtd_info *mtd, int page);
int (*scan_bbt)(struct mtd_info *mtd);
int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state,
int status, int page);
int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int page, int cached, int raw);

int chip_delay;
unsigned int options;

int page_shift;
int phys_erase_shift;
int bbt_erase_shift;
int chip_shift;
int numchips;
uint64_t chipsize;
int pagemask;
int pagebuf;
int subpagesize;
uint8_t cellinfo;
int badblockpos;
int badblockbits;

int onfi_version;
#ifdef CONFIG_SYS_NAND_ONFI_DETECTION
struct nand_onfi_params onfi_params;
#endif

int state;

uint8_t *oob_poi;
struct nand_hw_control *controller;
struct nand_ecclayout *ecclayout;

struct nand_ecc_ctrl ecc;
struct nand_buffers *buffers;
struct nand_hw_control hwcontrol;

struct mtd_oob_ops ops;

uint8_t *bbt;
struct nand_bbt_descr *bbt_td;
struct nand_bbt_descr *bbt_md;

struct nand_bbt_descr *badblock_pattern;

void *priv;
};
这个结构体就是一个“类”,所有的nand都可以这样实现,用户只要实现其中的一些“方法”就可以了
这些“方法“都已经有了默认的实现,在文件\u-boot-sunxi-sunxi\drivers\mtd\nand\nand_base.c内都已经写好了
例如比较老的芯片s3c2440,s3c6410都可以直接使用这些库函数,不需要在另外写,很遗憾,cubieboard的A10不在此列。
针对A10,在board_nand_init函数内,如下初始化是必要的:
......
/* initialize nand_chip data structure */
nand->IO_ADDR_R = (void *)&nand_reg->io_data;  // 读写寄存器,这个初始化还需要斟酌,没有资料就是苦B啊
nand->IO_ADDR_W = (void *)&nand_reg->io_data;
nand->select_chip = sunxi_select_chip;     //  片选函数,任何一款CPU都要实现这个功能
/* hwcontrol always must be implemented */
nand->dev_ready = sunxi_dev_ready;        // 读取芯片就绪状态
nand->cmdfunc    = sunxi_nand_command; //命令操作函数,有了这个就不需要 nand->cmd_ctrl 啦

#ifdef CONFIG_SUNXI_NAND_HWECC
nand->ecc.hwctl      = sunxi_nand_enable_hwecc;  //这些差错控制都没实现,先留下接口,等进一步改进,使用默认的实现
nand->ecc.calculate = sunxi_nand_calculate_ecc;
nand->ecc.correct   = sunxi_nand_correct_data;
nand->ecc.mode     = NAND_ECC_HW;
nand->ecc.size       = CONFIG_SYS_NAND_ECCSIZE;
nand->ecc.bytes     = CONFIG_SYS_NAND_ECCBYTES;
#else
nand->ecc.mode     = NAND_ECC_SOFT;
#endif

#ifdef CONFIG_SUNXI_NAND_BBT
nand->options = NAND_USE_FLASH_BBT;
#else
nand->options = 0;  /* 8bit */                // flash的操作位宽,看看芯片资料8位的
#endif
nand->priv = nand_cs + chip_n++;  // 这个相当于是C++的私有数据了,我存了芯片的编号,只有一片nand,就是0
....
这里nand指针就是前面说的细节
mtd->priv = nand; 
这是后相当部分mtd内容也已经初始化了。
再来看看nand_scan()函数,\u-boot-sunxi-sunxi\drivers\mtd\nand\nand_base.c内
int nand_scan(struct mtd_info *mtd, int maxchips)
{
int ret;

ret = nand_scan_ident(mtd, maxchips, NULL);
if (!ret)
ret = nand_scan_tail(mtd);
return ret;
}
这个函数的调用关系分析下去,可以看出,根据前面的初始化,读取nand的信息,就是id,厂商,名字,页大小,容量等等;
初始化用户未实现的部分,这些代码使用如下形式,举例如下:
/* check for proper chip_delay setup, set 20us if not */
if (!chip->chip_delay)  
chip->chip_delay = 20;    //如果没有定义芯片延时,则默认20ns,这个值要看具体的芯片手册了
/* check, if a user supplied command function given */
if (chip->cmdfunc == NULL)
chip->cmdfunc = nand_command;    // 如果没有实现chip->cmdfunc,那么使用默认的命令操作函数
                                                                                  // 而默认的不合适A10,board_nand_init函数定义了nand->cmdfunc    = sunxi_nand_command
                                                                                  // 所以这个不会被再次初始化
/* check, if a user supplied wait function given */
if (chip->waitfunc == NULL)                        
chip->waitfunc = nand_wait;               //这个没有被定义,将使用默认函数nand_wait
诸如此类的一大堆调用,当然,用户也可以完全将所有函数都自己实现一遍,但如果有合适的就没有必要啦,站在别人肩膀上,才能看得更远
二、总结
通过分析,假设自己需要实现初始化工作,从代码角度来看,需要实现一下几项:
1、定义相关的宏,例如
CONFIG_CMD_NAND
CONFIG_SYS_MAX_NAND_DEVICE
这不是全部宏,请参考其他芯片定义,如s3c2440
2、实现自己的int  board_nand_init(struct nand_chip *nand)函数
这个函数内初始化cpu的寄存器,IO脚功能,设置模块时钟
设置用户自己的硬件操作函数
片选操作、命令操作或硬件控制操作、芯片就绪等等,具体情况根据不同CPU而不同
有的芯片还要自己实现读写操作。
3、没有详细CPU用户手册情况下,写驱动就是一苦B事


原文作者:andy
原文链接:http://forum.cubietech.com/forum.php?mod=viewthread&tid=745&extra=page%3D1

本文转载自:http://forum.cubietech.com/forum.php?mod=viewthread&tid=745&extra=page%3D1​

cubieboard
粉丝 11
博文 64
码字总数 2651
作品 1
珠海
私信 提问
[2013.12.28更新:构建教程,支持CB2、CT] 构建自己的Debian Linux

2013.12.28, 更正了内核仓库下载位置;其他微不足道的小修改。 2013.11.08, 加入Cubietruck支持 2013.10.07, realm520网友反映一个问题,提请大家构建系统时注意。文档已更新。 发现个错误,...

cubieboard
2014/08/08
336
0
[教程]使用buildroot完全自定义自己的embedded linux系统(nand)

ubuntu, fedora, debian太过庞大了,你是否想完完全全的构建自己的embedded linux系统?本篇文章教你如何实现 编译环境: ubuntu 12.04(x8664) 目标环境: 1) linux-3.4内核 2) buildroot 2...

cubieboard
2014/08/29
507
0
Cubieboard开发环境与Uboot的SD启动卡制作

原文在我博客:http://blog.csdn.net/andy_wsj/article/details/8515197 拿到Cubieboard已经蛮久了,平时上班比较忙,只能晚上玩一会,年关将近,周末都要加班呀.... 所谓U-boot 移植,其实别...

cubieboard
2014/09/03
157
0
Cubieboard团队发布 “cubieboard2双卡版”开源硬件

“cubieboard2双卡版”(英文名:cubieboard2-dualcard,简称CB2-2CARD)是一个cubieboard团队酝酿已久的产物,也是一个为了适应中国国情而推出的一个可玩性更高的开源硬件。在极大地保留了硬...

cubieboard
2014/08/19
150
0
pcDuino的u-boot移植与分析

一、准备工作 1.获取支持pcDuino的u-boot源码 https://github.com/linux-sunxi/u-boot-sunxi 在XP下直接点ZIP即可开始下载 2.获取交叉编译链 http://code.google.com/p/smp-on-qemu/downloa...

pc朵拉
2013/07/02
297
0

没有更多内容

加载失败,请刷新页面

加载更多

Vue warn]: Computed property "activeNames" was assigned to but it has no setter.

在使用 vue,element-ui时,如下代码 <template> <el-form :model="numberValidateForm" ref="numberValidateForm"> <el-form-item> <el-tabs v-model="activeNames" @tab-cl......

牧云橙
9分钟前
2
0
重构-改善既有代码的设计-6.2内联函数

6.2内联函数 动机 本书经常以简短的函数表现动作意图,这样会使代码更清晰易读。但有时候你会遇到某些函数,其内部代码和函数名称同样清晰易读。也可能你充够了该函数的内部实现,使其内容和...

还仙
10分钟前
1
0
Less 混入

混合类似于编程语言中的函数。 Mixins 是一组CSS属性,允许我们将一个类的属性嵌套于另一个类,被嵌入的类可以看作是变量,并且包含类名作为其属性,也就是说我们可以用一个类定义样式然后把...

凌兮洛
13分钟前
1
0
频繁FGC的真凶原来是它

频繁FGC的真凶原来是它 上周排查了一个线上问题,主要现象是CPU占用过高,jvm old区占用过高,同时频繁fgc,我简单排查了下就草草收场了,但是过后我对这个问题又进行了复查,发现问题没有那...

每天晒白牙
13分钟前
3
0
简单的树形菜单如何写

业务需求 数据结构中含有图片、名称、children的树形结构,需要展示出每一级的图片名称和图片,找了些树形图的插件,都没有展示大的图片的,一般都是小图标,就自己试着写一个包含图的简单的...

tianyawhl
15分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部