uboot nand flash 启动 流程

1、initr_nand

首先在board_r.c中,initr_nand函数正式进入nand flash的初始化等操作。

static int initr_nand(void)
{puts("NAND:  ");nand_init();return 0;
}

2、nand_init

之后进入nand_init函数,该函数位于drivers\mtd\nand文件中的nand.c文件中,由于CONFIG_SYS_NAND_SELF_INIT未定义,所以后续调用nand_init_chip函数。

void nand_init(void)
{#ifdef CONFIG_SYS_NAND_SELF_INIT//未定义board_nand_init();
#elseint i;for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++)//初始化板上nand flashnand_init_chip(i);
#endifprintf("%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
}

3、nand_init_chip

而nand_init_chip同样位于drivers\mtd\nand文件中的nand.c文件中,该函数调用初始化函数,给mtd和nand两个结构体赋值,首先调用board_nand_init函数

#ifndef CONFIG_SYS_NAND_SELF_INIT
static void nand_init_chip(int i)
{struct mtd_info *mtd = &nand_info[i];//该结构体位于\include\linux\mtd文件中的mtd.h文件中struct nand_chip *nand = &nand_chip[i];//该结构体位于\include\linux\mtd文件中的nand.h文件中ulong base_addr = base_address[i];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);
}
#endif

4.1、board_nand_init

函数主要初始化开发板相关与nand_flash的寄存器,和绑定nand_chip结构体中的调用函数,由于不同开发板调用函数不同,所以该函数内部赋值会不一样,本次使用的是NXP MX6ULL开发板,调用的是mxs_nand.c中的函数,其中关于带有ECC的读写函数和ECC的模式,**这里使用的是硬件自带ECC,每512字节需要9字节的ECC数据,最大可纠正8bit数据。**而不同的flash,会规定不同的nand flash ECC,这里规定每最少需要纠正4bit数据,需要用512Byte数据+4Byte备用数据和8字节奇偶校验数据。所以uboot中的ECC符合nand flash 最低ECC 标准。

int board_nand_init(struct nand_chip *nand)
{struct mxs_nand_info *nand_info;int err;nand_info = malloc(sizeof(struct mxs_nand_info));if (!nand_info) {printf("MXS NAND: Failed to allocate private data\n");return -ENOMEM;}memset(nand_info, 0, sizeof(struct mxs_nand_info));err = mxs_nand_alloc_buffers(nand_info);if (err)goto err1;err = mxs_nand_init(nand_info);if (err)goto err2;memset(&fake_ecc_layout, 0, sizeof(fake_ecc_layout));nand->priv = nand_info;nand->options |= NAND_NO_SUBPAGE_WRITE;nand->cmd_ctrl        = mxs_nand_cmd_ctrl;nand->dev_ready     = mxs_nand_device_ready;nand->select_chip   = mxs_nand_select_chip;nand->block_bad      = mxs_nand_block_bad;nand->scan_bbt     = mxs_nand_scan_bbt;nand->read_byte     = mxs_nand_read_byte;nand->read_buf     = mxs_nand_read_buf;nand->write_buf     = mxs_nand_write_buf;nand->ecc.read_page    = mxs_nand_ecc_read_page;nand->ecc.write_page   = mxs_nand_ecc_write_page;nand->ecc.read_oob    = mxs_nand_ecc_read_oob;nand->ecc.write_oob = mxs_nand_ecc_write_oob;nand->ecc.layout   = &fake_ecc_layout;nand->ecc.mode       = NAND_ECC_HW;nand->ecc.bytes       = 9;nand->ecc.size      = 512;nand->ecc.strength    = 8;return 0;err2:free(nand_info->data_buf);free(nand_info->cmd_buf);
err1:free(nand_info);return err;
}

4.1.1 mxs_nand_init

其中mxs_nand_init主要配置nand flash相关的硬件寄存器,GMPI和BCH寄存器。

int mxs_nand_init(struct mxs_nand_info *info)
{struct mxs_gpmi_regs *gpmi_regs =(struct mxs_gpmi_regs *)MXS_GPMI_BASE;struct mxs_bch_regs *bch_regs =(struct mxs_bch_regs *)MXS_BCH_BASE;int i = 0, j, ret = 0;#ifdef CONFIG_MX6if (check_module_fused(MX6_MODULE_GPMI)) {printf("NAND GPMI@0x%x is fused, disable it\n", MXS_GPMI_BASE);return -EPERM;}
#endifinfo->desc = malloc(sizeof(struct mxs_dma_desc *) *MXS_NAND_DMA_DESCRIPTOR_COUNT);  //MXS_NAND_DMA_DESCRIPTOR_COUNT = 4if (!info->desc) {ret = -ENOMEM;goto err1;}/* Allocate the DMA descriptors. */for (i = 0; i < MXS_NAND_DMA_DESCRIPTOR_COUNT; i++) {info->desc[i] = mxs_dma_desc_alloc();if (!info->desc[i]) {ret = -ENOMEM;goto err2;}}/* Init the DMA controller. */for (j = MXS_DMA_CHANNEL_AHB_APBH_GPMI0;j <= MXS_DMA_CHANNEL_AHB_APBH_GPMI7; j++) {ret = mxs_dma_init_channel(j);if (ret)goto err3;}/* Reset the GPMI block. */mxs_reset_block(&gpmi_regs->hw_gpmi_ctrl0_reg);mxs_reset_block(&bch_regs->hw_bch_ctrl_reg);/** Choose NAND mode, set IRQ polarity, disable write protection and* select BCH ECC.*///设置GPMI_CTRL1n寄存器clrsetbits_le32(&gpmi_regs->hw_gpmi_ctrl1,GPMI_CTRL1_GPMI_MODE,GPMI_CTRL1_ATA_IRQRDY_POLARITY | GPMI_CTRL1_DEV_RESET |GPMI_CTRL1_BCH_MODE);return 0;err3:for (--j; j >= MXS_DMA_CHANNEL_AHB_APBH_GPMI0; j--)mxs_dma_release(j);
err2:for (--i; i >= 0; i--)mxs_dma_desc_free(info->desc[i]);free(info->desc);
err1:if (ret == -ENOMEM)printf("MXS NAND: Unable to allocate DMA descriptors\n");return ret;
}

4.2 nand_init_chip

函数中还有nand_scan函数,扫描NAND设备,读取flash ID,并在mtd_info结构中填充相关的值。

int nand_scan(struct mtd_info *mtd, int maxchips)
{int ret;/* Many callers got this wrong, so check for it for a while... */if (!mtd->owner && caller_is_module()) {pr_crit("%s called with NULL mtd->owner!\n", __func__);BUG();}ret = nand_scan_ident(mtd, maxchips, NULL);if (!ret)ret = nand_scan_tail(mtd);return ret;
}

4.2.1 nand_scan_ident

函数就是具体实施read id和设置MTD结构体

int nand_scan_ident(struct mtd_info *mtd, int maxchips,struct nand_flash_dev *table)
{int i, nand_maf_id, nand_dev_id;struct nand_chip *chip = mtd->priv;struct nand_flash_dev *type;/* Set the default functions */nand_set_defaults(chip, chip->options & NAND_BUSWIDTH_16);//如果nand chip结构体没有赋值,设置为默认值/* Read the flash type */type = nand_get_flash_type(mtd, chip, &nand_maf_id,&nand_dev_id, table); //read id 确认flash 类型if (IS_ERR(type)) {if (!(chip->options & NAND_SCAN_SILENT_NODEV))pr_warn("No NAND device found\n");chip->select_chip(mtd, -1);return PTR_ERR(type);}chip->select_chip(mtd, -1);//再次确认ID/* Check for a chip array */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) ||nand_dev_id != chip->read_byte(mtd)) {chip->select_chip(mtd, -1);break;}chip->select_chip(mtd, -1);}#ifdef DEBUGif (i > 1)pr_info("%d chips detected\n", i);
#endif/* Store the number of chips and calc total size for mtd */chip->numchips = i;mtd->size = i * chip->chipsize;return 0;
}
EXPORT_SYMBOL(nand_scan_ident);

4.2.2 nand_scan_tail

函数就是初始化oob区、ecc校验相关参数和函数指针、初始化MTD驱动接口函数、调用nand_bbt()创建坏块表。

/*** nand_scan_tail - [NAND Interface] Scan for the NAND device* @mtd: MTD device structure** This is the second phase of the normal nand_scan() function. It fills out* all the uninitialized function pointers with the defaults and scans for a* bad block table if appropriate.*/
int nand_scan_tail(struct mtd_info *mtd)
{int i;struct nand_chip *chip = mtd->priv;struct nand_ecc_ctrl *ecc = &chip->ecc;struct nand_buffers *nbuf;/* New bad blocks should be marked in OOB, flash-based BBT, or both */BUG_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) &&!(chip->bbt_options & NAND_BBT_USE_FLASH));if (!(chip->options & NAND_OWN_BUFFERS)) {nbuf = kzalloc(sizeof(struct nand_buffers), GFP_KERNEL);chip->buffers = nbuf;} else {if (!chip->buffers)return -ENOMEM;}/* Set the internal oob buffer location, just after the page data */chip->oob_poi = chip->buffers->databuf + mtd->writesize;/** If no default placement scheme is given, select an appropriate one.*/if (!ecc->layout && (ecc->mode != NAND_ECC_SOFT_BCH)) {switch (mtd->oobsize) {case 8:ecc->layout = &nand_oob_8;break;case 16:ecc->layout = &nand_oob_16;break;case 64:ecc->layout = &nand_oob_64;break;case 128:ecc->layout = &nand_oob_128;break;default:pr_warn("No oob scheme defined for oobsize %d\n",mtd->oobsize);BUG();}}if (!chip->write_page)chip->write_page = nand_write_page;/** Check ECC mode, default to software if 3byte/512byte hardware ECC is* selected and we have 256 byte pagesize fallback to software ECC*/switch (ecc->mode) {case NAND_ECC_HW_OOB_FIRST:/* Similar to NAND_ECC_HW, but a separate read_page handle */if (!ecc->calculate || !ecc->correct || !ecc->hwctl) {pr_warn("No ECC functions supplied; hardware ECC not possible\n");BUG();}if (!ecc->read_page)ecc->read_page = nand_read_page_hwecc_oob_first;case NAND_ECC_HW:/* Use standard hwecc read page function? */if (!ecc->read_page)ecc->read_page = nand_read_page_hwecc;if (!ecc->write_page)ecc->write_page = nand_write_page_hwecc;if (!ecc->read_page_raw)ecc->read_page_raw = nand_read_page_raw;if (!ecc->write_page_raw)ecc->write_page_raw = nand_write_page_raw;if (!ecc->read_oob)ecc->read_oob = nand_read_oob_std;if (!ecc->write_oob)ecc->write_oob = nand_write_oob_std;if (!ecc->read_subpage)ecc->read_subpage = nand_read_subpage;if (!ecc->write_subpage)ecc->write_subpage = nand_write_subpage_hwecc;case NAND_ECC_HW_SYNDROME:if ((!ecc->calculate || !ecc->correct || !ecc->hwctl) &&(!ecc->read_page ||ecc->read_page == nand_read_page_hwecc ||!ecc->write_page ||ecc->write_page == nand_write_page_hwecc)) {pr_warn("No ECC functions supplied; hardware ECC not possible\n");BUG();}/* Use standard syndrome read/write page function? */if (!ecc->read_page)ecc->read_page = nand_read_page_syndrome;if (!ecc->write_page)ecc->write_page = nand_write_page_syndrome;if (!ecc->read_page_raw)ecc->read_page_raw = nand_read_page_raw_syndrome;if (!ecc->write_page_raw)ecc->write_page_raw = nand_write_page_raw_syndrome;if (!ecc->read_oob)ecc->read_oob = nand_read_oob_syndrome;if (!ecc->write_oob)ecc->write_oob = nand_write_oob_syndrome;if (mtd->writesize >= ecc->size) {if (!ecc->strength) {pr_warn("Driver must set ecc.strength when using hardware ECC\n");BUG();}break;}pr_warn("%d byte HW ECC not possible on %d byte page size, fallback to SW ECC\n",ecc->size, mtd->writesize);ecc->mode = NAND_ECC_SOFT;case NAND_ECC_SOFT:ecc->calculate = nand_calculate_ecc;ecc->correct = nand_correct_data;ecc->read_page = nand_read_page_swecc;ecc->read_subpage = nand_read_subpage;ecc->write_page = nand_write_page_swecc;ecc->read_page_raw = nand_read_page_raw;ecc->write_page_raw = nand_write_page_raw;ecc->read_oob = nand_read_oob_std;ecc->write_oob = nand_write_oob_std;if (!ecc->size)ecc->size = 256;ecc->bytes = 3;ecc->strength = 1;break;case NAND_ECC_SOFT_BCH:if (!mtd_nand_has_bch()) {pr_warn("CONFIG_MTD_NAND_ECC_BCH not enabled\n");BUG();}ecc->calculate = nand_bch_calculate_ecc;ecc->correct = nand_bch_correct_data;ecc->read_page = nand_read_page_swecc;ecc->read_subpage = nand_read_subpage;ecc->write_page = nand_write_page_swecc;ecc->read_page_raw = nand_read_page_raw;ecc->write_page_raw = nand_write_page_raw;ecc->read_oob = nand_read_oob_std;ecc->write_oob = nand_write_oob_std;/** Board driver should supply ecc.size and ecc.strength values* to select how many bits are correctable. Otherwise, default* to 4 bits for large page devices.*/if (!ecc->size && (mtd->oobsize >= 64)) {ecc->size = 512;ecc->strength = 4;}/* See nand_bch_init() for details. */ecc->bytes = DIV_ROUND_UP(ecc->strength * fls(8 * ecc->size), 8);ecc->priv = nand_bch_init(mtd, ecc->size, ecc->bytes,&ecc->layout);if (!ecc->priv) {pr_warn("BCH ECC initialization failed!\n");BUG();}break;case NAND_ECC_NONE:pr_warn("NAND_ECC_NONE selected by board driver. This is not recommended!\n");ecc->read_page = nand_read_page_raw;ecc->write_page = nand_write_page_raw;ecc->read_oob = nand_read_oob_std;ecc->read_page_raw = nand_read_page_raw;ecc->write_page_raw = nand_write_page_raw;ecc->write_oob = nand_write_oob_std;ecc->size = mtd->writesize;ecc->bytes = 0;ecc->strength = 0;break;default:pr_warn("Invalid NAND_ECC_MODE %d\n", ecc->mode);BUG();}/* For many systems, the standard OOB write also works for raw */if (!ecc->read_oob_raw)ecc->read_oob_raw = ecc->read_oob;if (!ecc->write_oob_raw)ecc->write_oob_raw = ecc->write_oob;/** The number of bytes available for a client to place data into* the out of band area.*/ecc->layout->oobavail = 0;for (i = 0; ecc->layout->oobfree[i].length&& i < ARRAY_SIZE(ecc->layout->oobfree); i++)ecc->layout->oobavail += ecc->layout->oobfree[i].length;mtd->oobavail = ecc->layout->oobavail;/* ECC sanity check: warn if it's too weak */if (!nand_ecc_strength_good(mtd))pr_warn("WARNING: %s: the ECC used on your system is too weak compared to the one required by the NAND chip\n",mtd->name);/** Set the number of read / write steps for one page depending on ECC* mode.*/ecc->steps = mtd->writesize / ecc->size;if (ecc->steps * ecc->size != mtd->writesize) {pr_warn("Invalid ECC parameters\n");BUG();}ecc->total = ecc->steps * ecc->bytes;/* Allow subpage writes up to ecc.steps. Not possible for MLC flash */if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && nand_is_slc(chip)) {switch (ecc->steps) {case 2:mtd->subpage_sft = 1;break;case 4:case 8:case 16:mtd->subpage_sft = 2;break;}}chip->subpagesize = mtd->writesize >> mtd->subpage_sft;/* Initialize state */chip->state = FL_READY;/* Invalidate the pagebuffer reference */chip->pagebuf = -1;/* Large page NAND with SOFT_ECC should support subpage reads */switch (ecc->mode) {case NAND_ECC_SOFT:case NAND_ECC_SOFT_BCH:if (chip->page_shift > 9)chip->options |= NAND_SUBPAGE_READ;break;default:break;}/* Fill in remaining MTD driver data */mtd->type = nand_is_slc(chip) ? MTD_NANDFLASH : MTD_MLCNANDFLASH;mtd->flags = (chip->options & NAND_ROM) ? MTD_CAP_ROM :MTD_CAP_NANDFLASH;mtd->_erase = nand_erase;mtd->_read = nand_read;mtd->_write = nand_write;mtd->_panic_write = panic_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->_block_isreserved = nand_block_isreserved;mtd->_block_isbad = nand_block_isbad;mtd->_block_markbad = nand_block_markbad;mtd->writebufsize = mtd->writesize;/* propagate ecc info to mtd_info */mtd->ecclayout = ecc->layout;mtd->ecc_strength = ecc->strength;mtd->ecc_step_size = ecc->size;/** Initialize bitflip_threshold to its default prior scan_bbt() call.* scan_bbt() might invoke mtd_read(), thus bitflip_threshold must be* properly set.*/if (!mtd->bitflip_threshold)mtd->bitflip_threshold = DIV_ROUND_UP(mtd->ecc_strength * 3, 4);return 0;
}
EXPORT_SYMBOL(nand_scan_tail);

uboot nand flash 流程相关推荐

  1. u-boot nand flash read/write cmd

    支援的命令函數說明 1. nand info/nand device 功能:顯示當前nand flash晶片資訊. 函數調用關係如下(按先後順序): static void nand_print(st ...

  2. 从Nand Flash启动U-BOOT的基本原理

    从Nand Flash启动U-BOOT的基本原理 前4K的问题  如果S3C2410被配置成从Nand Flash启动(配置由硬件工程师在电路板设置), S3C2410的Nand Flash控制器有一 ...

  3. DM365视频处理流程/DM368 NAND Flash启动揭秘

    DM365的视频处理涉及到三个相关处理器,分别是视频采集芯片.ARM处理器和视频图像协处理器(VICP),整个处理流程由ARM核协调.视频处理主要涉及三个处理流程,分别是视频采集.视频编码和对编码后的 ...

  4. jz2440开发板修改UBOOT支持NAND FLASH

    很多天没有看嵌入式的东西了,今天来看一下,继续之前移植uboot到jz2440开发板.今天我们来实现Uboot支持NAND FLASH. 在之前的文章里(点击连接查看之前的记录),我们为了编译通过把N ...

  5. uboot下的nand flash驱动分析

    Nand flash芯片工作原理: ------------------------------------     Nand flash芯片型号为Samsung K9F2G08U0A,数据存储容量为 ...

  6. 使用u-boot的tftp下载功能烧写程序到Nand Flash ——韦东山嵌入式Linux学习笔记09

    本文实验环境: 1. windows 7(64bit) 2. JZ2440(V2) 操作步骤: (1)设置好开发板和PC的IP地址,使开发板可以 ping 通 PC 如果搞不定,可以参考我的博文 ht ...

  7. 使用u-boot的USB下载功能烧写程序到Nand Flash ——韦东山嵌入式Linux学习笔记06

    本文实验环境: 1. windows 7(64bit) 2. JZ2440(V2) 假设板子的Nor Flash上已经烧好了u-boot,如果我想利用u-boot的USB下载功能,把一个裸板程序烧写到 ...

  8. 关于NAND flash的MTD分区与uboot中分区的理解 .

    今天做内核移植,准备添加NAND flash的驱动,做到MTD分区时,想起在一本书上看到的一句话,说的是分区时每个区之间没有间隙,前一个区的结束地址是后一个区的起始地址.可是当我看我的开发板的教程时, ...

  9. Tiny210(S5PV210) U-BOOT(五)----Nand Flash源码分析

    1.u-boot参考源码  Nand Flash的初始化代码在board/samsung/tiny210/lowlevel_init.S 2.初始化Nand Flash 在u-boot中,Nand的低 ...

最新文章

  1. .Net Core 图片文件上传下载
  2. daatable动态创建
  3. [LeetCode] 118. Pascal's Triangle Java
  4. POJ2246 HDU1082 ZOJ1094 UVA442 Matrix Chain Multiplication题解
  5. java api文档_JAVA浏览器控件JxBrowser v7.3上线!最新API文档打包带走
  6. 云服务器与传统服务器的优劣对比_相比于传统服务器,云服务器的优势在哪
  7. python—多进程的消息队列
  8. mysql自增函数_mysql实现自增函数
  9. 电脑上如何进行录屏?
  10. 写论文word生成目录
  11. QQ音乐爬虫(with scrapy)/QQ Music Spider
  12. Ice通信之Ice::Application
  13. python查火车票_Python查询火车票(三)
  14. c语言编程图案大全,C语言中图案的编程
  15. [oeasy]python0072_修改字体前景颜色_foreground_color_font
  16. Automative SPICE 之五 工作产品特性
  17. Ethercat解析(三)之命令行工具的使用
  18. 快速排序算法具体步骤
  19. 成功入职字节跳动!南京java培训机构排名榜
  20. 无货源淘宝,新手小白快速进入电商圈的捷径

热门文章

  1. 自学网络安全方向要如何开始?
  2. feign原理和使用
  3. python安装之后没有pip
  4. python 打印卷尺
  5. 重温经典排序算法之冒泡排序——图解+C/C++实现
  6. Android开发 ---- 两分钟写一个录音演示软件
  7. C语言字符串函数----strcat()函数用法
  8. sha256可以解密?用网上的sha256在线解密平台能解出来吗
  9. GlLookAt的用法
  10. 技术中台实践 :微服务篇