uboot中nand详细分析(一)
来源:互联网 发布:mysql更新字段值 编辑:程序博客网 时间:2024/05/17 09:28
一.gpmc初始化
uboot首先执行start.s,初始化cpu并从nand中拷贝其他代码到内存中;最后跳转到start_armboot()函数;
在start_armboot()中,循环初始化外设,其中board_init()函数就调用gpmc_init()初始化了gpmc:
void gpmc_init(void)
{
//通过把gpmc_cfg指向gpmc基地址,使gpmc_cfg中的数据类型所代表的是gpmc寄存器地址
gpmc_cfg = (struct gpmc *)GPMC_BASE;
#if defined(CONFIG_CMD_NAND) || defined(CONFIG_CMD_ONENAND)
const u32 *gpmc_config = NULL;
u32 base = 0;
u32 size = 0;
#if defined(CONFIG_ENV_IS_IN_NAND) || defined(CONFIG_ENV_IS_IN_ONENAND)
u32 f_off = CONFIG_SYS_MONITOR_LEN;
u32 f_sec = 0;
#endif
/* global settings;初始化gpmc基本设置 */
writel(0x00000008, &gpmc_cfg->sysconfig);
writel(0x00000100, &gpmc_cfg->irqstatus);
writel(0x00000200, &gpmc_cfg->irqenable);
writel(0x00000012, &gpmc_cfg->config);
/*Disable the GPMC0 config set by ROM code*/
writel(0, &gpmc_cfg->cs[0].config7);
sdelay(1000);
#if defined(CONFIG_CMD_NAND) /* CS 0 */
//gpmc_m_nand是gpmc cs的设置
gpmc_config = gpmc_m_nand;
base = PISMO1_NAND_BASE;
size = PISMO1_NAND_SIZE;
//根据gpmc_m_nand中的配置设置gpmc_cfg->cs[0]
enable_gpmc_cs_config(gpmc_config, &gpmc_cfg->cs[0], base, size);
#endif
}
二.nand底层初始化
nand_init()调用nand_init_chip()来初始化寄存器设置和赋值相关操作函数;
uboot将nand操作封装成mtd子系统,其中mtd_info结构体表示mtd通用层的数据结构和操作函数;而nand_chip表示nand底层相关的数据结构和操作函数;其中mtd->priv=nand;即把底层的数据结构赋给mtd的priv,方便直接通过mtd获得;
在nand_init_chip()中,通过调用board_nand_init()来初始化基本寄存器和赋值chip相关函数,调用nand_scan()来初始化通用层需要的数据和赋值mtd层相关函数。
1.底层初始化
我们先来看board_nand_init():
int board_nand_init(struct nand_chip *nand)
{
cs = 0;
while (cs < GPMC_MAX_CS) {
/* Check if NAND type is set;看是否有设备连接上 */
if ((readl(&gpmc_cfg->cs[cs].config1) & 0xC00) == 0x800) {
/* Found it!! */
break;
}
cs++;
}
//赋值io读写地址
nand->IO_ADDR_R = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat;
nand->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd;
nand->cmd_ctrl = ti81xx_nand_hwcontrol;
nand->options = NAND_NO_PADDING | NAND_CACHEPRG | NAND_NO_AUTOINCR;
/* If we are 16 bit dev, our gpmc config tells us that;判断是否是16位nand */
if ((readl(&gpmc_cfg->cs[cs].config1) & 0x3000) == 0x1000) {
nand->options |= NAND_BUSWIDTH_16;
}
/* fallback ecc info(备用ecc信息), this will be overridden by
* ti81xx_nand_switch_ecc() below to 1-bit h/w ecc;
将nand_prib指向bch_priv*/
nand->priv = &bch_priv;
nand->ecc.mode = NAND_ECC_SOFT;
/* required in case of BCH;lem(错误位置模块)提取错误地址 */
elm_init();
nand_curr_device = 0;
ti81xx_nand_switch_ecc(NAND_ECC_HW, 2);
return 0;
}
在函数的最后,我们来看看ti81xx_nand_switch_ecc(NAND_ECC_HW,2):
/*__ti81xx_nand_switch_ecc - switch the ECC operation ib/w h/w ecc
* (i.e. hamming / bch) and s/w ecc.
* The default is to come up on s/w ecc
* @nand: NAND chip datastructure
* @hardware: NAND_ECC_HW -switch to h/w ecc
* NAND_ECC_SOFT -switch to s/w ecc
* @mode: 0 - hamming code
* 1 - bch4
* 2 - bch8
* 3 - bch16
* @return: 0 - success, or error */
int __ti81xx_nand_switch_ecc(struct nand_chip *nand,
nand_ecc_modes_t hardware, int32_t mode)
{
struct nand_bch_priv *bch;
bch = nand->priv;
nand->options |= NAND_OWN_BUFFERS;
nand->ecc.mode = hardware;
/* Setup the ecc configurations again */
if (hardware == NAND_ECC_HW) {
if (mode) {
bch->mode = NAND_ECC_HW_BCH;
/* -1 for converting mode to bch type */
bch->type = mode - 1;
printf("HW ECC BCH");
switch (bch->type) {
case ECC_BCH8:
default:
//ecc校验码数量
nand->ecc.bytes = 14;
//清空的nand中使用的校验码
nand->ecc.layout = &hw_bch8_nand_oob;
nand->ecc.read_page_raw =
ti81xx_nand_read_page_raw_bch;
nand->ecc.write_page_raw =
ti81xx_nand_write_page_raw_bch;
nand->ecc.read_oob =
ti81xx_nand_read_oob_bch;
nand->ecc.write_oob =
ti81xx_nand_write_oob_bch;
bch->nibbles = ECC_BCH8_NIBBLES;
printf("8 Selected\n");
break;
}
bch->mode = NAND_ECC_HW;
nand->ecc.mode = NAND_ECC_HW_SYNDROME;
nand->ecc.steps = 4;
nand->ecc.size = 512;
nand->ecc.total = (nand->ecc.steps * nand->ecc.bytes);
nand->ecc.write_page = ti81xx_write_page_bch;
nand->ecc.read_page = ti81xx_read_page_bch;
nand->ecc.hwctl = ti81xx_enable_ecc_bch;
nand->ecc.correct = ti81xx_correct_data_bch;
nand->ecc.calculate = ti81xx_calculate_ecc_bch;
ti81xx_hwecc_init_bch(nand, NAND_ECC_READ);
}
return ret;
}
该函数调用ti81xx_hwecc_init_bch初始化bch 硬件ecc:
/*
* ti81xx_hwecc_init_bch - Initialize the BCH Hardware ECC for NAND flash in
* GPMC controller
* @mtd: MTD device structure
* @mode: Read/Write mode
*/
static void ti81xx_hwecc_init_bch(struct nand_chip *chip, int32_t mode)
{
uint32_t val, dev_width = (chip->options & NAND_BUSWIDTH_16) >> 1;
uint32_t unused_length = 0;
struct nand_bch_priv *bch = chip->priv;
switch(bch->nibbles) {
case ECC_BCH8_NIBBLES:
unused_length = 2;
break;
}
/* Clear the ecc result registers, select ecc reg as 1 */
writel(ECCCLEAR | ECCRESULTREG1, &gpmc_cfg->ecc_control);
switch (mode) {
case NAND_ECC_WRITE:
/* eccsize1 config */
val = ((unused_length + bch->nibbles) << 22);
break;
case NAND_ECC_READ:
default:
/* by default eccsize0 selected for ecc1resultsize */
/* eccsize0 config */
val = (bch->nibbles << 12);
/* eccsize1 config */
val |= (unused_length << 22);
break;
}
/* ecc size configuration */
writel(val, &gpmc_cfg->ecc_size_config);
/* by default 512bytes sector page is selected */
/* set bch mode */
val = (1 << 16);
/* bch4 / bch8 / bch16 */
val |= (bch->type << 12);
/* set wrap mode to 1 */
val |= (1 << 8);
val |= (dev_width << 7);
val |= (cs << 1);
/* enable ecc */
/* val |= (1); */ /* should not enable ECC just init i.e. config */
writel(val, &gpmc_cfg->ecc_config);
}
2.mtd层初始化
/*nand_scan_ident - [NAND Interface] Scan for the NAND device
* @mtd: MTD device structure
* @maxchips: Number of chips to scan for
* This is the first phase of the normal nand_scan() function. It
* reads the flash ID and sets up MTD fields accordingly.
* The mtd->owner field must be set to the module of the caller. */
int nand_scan_ident(struct mtd_info *mtd, int maxchips)
{
int i, busw, nand_maf_id;
struct nand_chip *chip = mtd->priv;
struct nand_flash_dev *type;
/* Set the default functions;初始化chip层通用函数 */
nand_set_defaults(chip, busw);
/* Read the flash type ;通过读取id等信息获取nand的大小,页大小,block大小,ecc大小及转换成需要的信息*/
type = nand_get_flash_type(mtd, chip, busw, &nand_maf_id);
/* Check for a chip array;检测系统中的nand */
for (i = 1; i < maxchips; i++) {
chip->select_chip(mtd, i);
/* See comment in nand_get_flash_type for reset */
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
/* Send the command for reading device ID */
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
/* Read manufacturer and device IDs */
if (nand_maf_id != chip->read_byte(mtd) ||
type->id != chip->read_byte(mtd))
break;
}
/* Store the number of chips and calc total size for mtd */
chip->numchips = i;
mtd->size = i * chip->chipsize;
return 0;
}
最后的nand_scan_tail()主要初始化mtd层函数:
/* Fill in remaining MTD driver data */
mtd->type = MTD_NANDFLASH;
mtd->flags = MTD_CAP_NANDFLASH;
mtd->erase = nand_erase;
mtd->point = NULL;
mtd->unpoint = NULL;
mtd->read = nand_read;
mtd->write = nand_write;
mtd->read_oob = nand_read_oob;
mtd->write_oob = nand_write_oob;
mtd->sync = nand_sync;
mtd->lock = NULL;
mtd->unlock = NULL;
mtd->suspend = nand_suspend;
mtd->resume = nand_resume;
mtd->block_isbad = nand_block_isbad;
mtd->block_markbad = nand_block_markbad;
- uboot中nand详细分析(一)
- uboot中nand flash代码分析(1)
- uboot中nand flash代码分析(2)
- uboot中nand flash代码分析(3)
- uboot中mkconfig详细分析
- [NAND]UBOOT中NAND操作
- UBOOT中NAND操作
- UBOOT中NAND操作
- UBOOT中NAND操作
- UBOOT中NAND操作
- UBOOT中NAND操作
- UBOOT中NAND操作
- [NAND]UBOOT从NAND FLASH启动分析
- [NAND]UBOOT从NAND FLASH启动分析
- TQ335X UBOOT分析(nand部分)
- uboot中mkconfig详细分析-- 转载
- uboot第一阶段详细分析
- uboot详细分析
- .bat脚本将windows server 2008设置成ntp时间同步服务器
- SYN Flood DOS Attack with C Source Code (Linux)
- alarm函数详解
- 实用API大全
- hdu 2955 Robberies 01背包变形
- uboot中nand详细分析(一)
- hibernate one-to-many many-to-one 双向注解
- #号无法正常传输的解决方法
- 设计模式详解(总纲)
- CSS中怎么让DIV居中
- linux 下创建动态链接库的一个很简单的例子
- java 先进先出
- EL表达式笔记
- Android电话Phone UI分析