精华内容
参与话题
问答
  • ubootflash初始化

    2017-05-17 18:07:39
    nand_init()函数其实现过程与内核nand驱动大致差不多,涉及到的结构体有pxa3xx_nand,此结构体包含mtd_info,mtd_info结构体在...应该提供:选中,发命令,发地址,发数据,数据,判断状态的功能void nand_init() { struct

    nand_init()函数其实现过程与内核nand驱动大致差不多,涉及到的结构体有pxa3xx_nand,此结构体包含mtd_info,mtd_info结构体在注册进mtd子系统时需要用到
    比较重要的结构体还有nand_chip,这个结构体实现对nand操作的基本方法。应该提供:选中,发命令,发地址,发数据,读数据,判断状态的功能

    void nand_init()
    {
            struct pxa3xx_nand_platform_data pxa_nandinfo;
            struct pxa3xx_nand *nand;                     //具体哪类型芯片如下:
            int chip;
    
            pxa_nandinfo.mmio_base          = CONFIG_SYS_NAND_BASE;
            pxa_nandinfo.enable_arbiter     = 1;
            pxa_nandinfo.RD_CNT_DEL         = 0;
    
            nand = pxa3xx_nand_probe(&pxa_nandinfo);         
            if (!nand) {
                    printf("pxa3xx-nand probe failed!!\n");
                    return;
            }
    
            for (chip = 0; chip < CONFIG_SYS_MAX_NAND_DEVICE; chip ++) {
                    if (nand->mtd[chip]) {
                            memcpy(&(nand_info[chip]), nand->mtd[chip], sizeof(struct mtd_info));
    
                            if (nand_curr_device < 0)
                                    nand_curr_device = chip;
                    }
            }
    
            if (nand_curr_device < 0)
                    printf("No NAND dev is found !!!\n\n");
    }

    此处的probe与内核层的probe功能差不多,即实现nand的初始化和基本操作函数。

    struct pxa3xx_nand *pxa3xx_nand_probe(struct pxa3xx_nand_platform_data *pdata)
    {
            struct pxa3xx_nand               *nand;
            struct pxa3xx_bbm                *bbm;
            struct mtd_info                  *mtd;
            int    i;
    
            nand = alloc_nand_resource(pdata);          //分配一个nand资源
            if (!nand)
                    return NULL;
          //对分配的nand结构体资源进行初始化
            nand->enable_arbiter    = pdata->enable_arbiter;
            nand->RD_CNT_DEL        = pdata->RD_CNT_DEL;
            //通过id号找到具体的nand设备
            pxa3xx_nand_detect_flash(nand);
            //
            for (i = 0; i < NUM_CHIP_SELECT; i ++) {
                    mtd = nand->mtd[i];
    
                    if (mtd) {
                            bbm = mtd->bbm;
                            pxa3xx_nand_init_mtd(mtd);        //重要:对nand_chip结构体进行赋值,包括对nand的基本操作如选中,发命令,发地址,发数据,读数据,判断状态的功能,
                            if (pxa3xx_nand_scan(mtd)) {       //对mtd和chip最后进行初始化
                                    printf("failed to scan nand\n");
                            }
                            mtd->name = mtd_names[i];
    #ifdef CONFIG_CMD_UBI
                            add_mtd_device(mtd);           //添加设备
    #endif
                    }
            }

    下面函数中的f取值是具体支持的flash各参数指标。如
    static struct pxa3xx_nand_flash esmt1G81A = {
    .timing = &esmt_timing,
    .cmdset = &largepage_cmdset,
    .name = “ESMT F59L1G81A”,
    .page_per_block = 64,
    .page_size = 2048,
    .flash_width = 8,
    .dfc_width = 8,
    .num_blocks = 1024,
    .chip_id = 0xf192,
    .chip_id_mask = 0xffff,
    .ecc_type = ECC_BCH,
    .ecc_strength = 1,
    };

    static int pxa3xx_nand_detect_flash(struct pxa3xx_nand *nand)
    {
            struct pxa3xx_nand_flash *f;
            struct nand_chip *chip;
            struct pxa3xx_nand_info *info;
            struct mtd_info *mtd;
            uint32_t id = -1;
            int i, ret, chip_select;
    
            f = builtin_flash_types[0];   //取出一个支持的具体设备并给f赋初值
            chip_select = 0;
            for (; chip_select < NUM_CHIP_SELECT; chip_select ++) {
                    mtd = nand->mtd[chip_select];
                    chip = mtd->priv;
                    info = mtd->priv;
                    ret = pxa3xx_nand_sensing(info, chip_select);   //对nand控制器的寄存器进行赋值并复位
                    if (!ret) {
                            free (nand->mtd[chip_select]);
                            nand->mtd[chip_select] = NULL;
                            continue;
                    }
    
                    pxa3xx_nand_cmdfunc(mtd, NAND_CMD_READID, 0, 0);   //读取ID操作
    
                    id = *((uint32_t *)(info->data_buff));
    
                    if (id == 0) {
                            kfree(mtd);
                            nand->mtd[chip_select] = NULL;
                            continue;
                    }
    
                    for (i = 1; i < ARRAY_SIZE(builtin_flash_types); i++) {
    
                            f = builtin_flash_types[i];
    
                            /* find the chip in default list */
                            if (f->chip_id == (id & f->chip_id_mask)) {                        //查找是否支持此id类型设备。若支持则对mtd进行赋值初始化。
    //                                      printf("detect chip id 0x%x on cs %d, %s\n",
    //                                                      f->chip_id, chip_select, f->name);
                                    pxa3xx_nand_config_flash(info, f, 1);
                                    chip->cellinfo = info->data_buff[2];
                                    mtd->writesize = f->page_size;
                                    mtd->oobsize = mtd->writesize / 32;
                                    mtd->erasesize = f->page_size * f->page_per_block;
                                    if (is_power_of_2(mtd->erasesize))
                                            mtd->erasesize_shift = ffs(mtd->erasesize) - 1;
                                    else
                                            mtd->erasesize_shift = 0;
    
                                    if (is_power_of_2(mtd->writesize))
                                            mtd->writesize_shift = ffs(mtd->writesize) - 1;
                                    else
                                            mtd->writesize_shift = 0;
    
                                    mtd->erasesize_mask = (1 << mtd->erasesize_shift) - 1;
                                    mtd->writesize_mask = (1 << mtd->writesize_shift) - 1;
                                    break;
                            }
                    }
    
                    if (i == ARRAY_SIZE(builtin_flash_types)) {
                            kfree(mtd);
                            nand->mtd[chip_select] = NULL;
                            printf("ERROR!! flash on cs %d id %x not defined!!!\n",
                                           chip_select, id);
                            continue;
                    }
            }
    
            return 0;
    }
    

    具体函数调用关系如下:
    nand_init()–>pxa3xx_nand_probe(&pxa_nandinfo)
    –>pxa3xx_nand_detect_flash(nand)
    –>pxa3xx_nand_sensing(info, chip_select)
    –>pxa3xx_nand_cmdfunc(mtd, NAND_CMD_READID, 0, 0)

    –>pxa3xx_nand_init_mtd(mtd)
    –>pxa3xx_nand_scan(mtd)
    –>nand_scan_tail(mtd)
    –>add_mtd_device(mtd)

    展开全文
  • Application将一些数据写到这片区域,之后重启,UBoot起来之后会去查看该区域,发现有标志、数据表明需要升级,便把这片区域的数据出来覆盖到原有kernel、rootfs的分区。 现在比较疑惑的是,linux中都是基于文件...
  • 目标板:华中科技大学惠世科技S3C2440实验箱,采用SAMSUNG公司型号为K9F2G08U0B的256M*8Bit NAND Flash Memory 1. NAND Flash的组织结构  NAND Flash芯片的存储空间是按照块和页的概念来组织的。...

    移植环境:

    Linux系统:Fedora9

    交叉编译环境:arm-linux-gcc4.4.3

    目标板:华中科技大学惠世科技S3C2440实验箱,采用SAMSUNG公司型号为K9F2G08U0B256M*8Bit NAND Flash Memory


    1. NAND Flash的组织结构

     NAND Flash芯片的存储空间是按照块和页的概念来组织的。现在市面上的NAND主要按大页和小页两种存储类型来进行数据管理。以NAND型号K9F2G08U0B为例,该NAND为大页结构,即芯片每块(Block)64(Page),每页有2K Byte的数据存储区和64Byte的冗余数据区(用来存放ECC校验码)。2K Byte的数据存储区作为数据缓冲单元,用来实现I/0缓冲和存储器之间的数据传输。

     NAND Flash的物理层驱动主要涉及到:NAND Flash的初始化(ID以及相关属性信息的读取)、擦除(以块作为单位),数据读写(以页作为基本单位)。在这一系列的过程中,会涉及到NAND Flash命令的发送以及 NAND Flash地址的发送。其中地址的发送会因NAND Flash型号的不同而有所区别。一般来说,小页的 NAND Flash其地址周期通常为4个:1个列地址(Column Address)和3个行地址(Row Address),而对大页的NAND Flash来说,列地址至少是2个周期,行地址会因芯片的容量大小而有所区别。本文采用的三星NAND Flash芯片是2个列地址和3个行地址行地址就是页地址,列地址为页内地址)。对于 NAND FLASH 来讲,地址和命令只能在I/O[7:0]上并行传递。NAND Flash以页为单位读写数据,而以块为单位擦除数据。NAND的数据传输方式有基本的I/O传输方式,即在I/O[7:0]数据线上进行的数据传输。这种操作的缺点是系统CPU要频繁参与控制数据的传输,会影响到数据传输速度。S3C2440芯片集成了 NAND Flash控制寄存器,大大简化了对 NAND Flash的操作。

    K9F2G08U0B Array Organization

    2. NAND Flash 中的坏块(Bad Block) 

     NAND Flash 中,一个块中含有 1 个或多个位是坏的,就称为其为坏块 Bad Block。坏块的稳定性是无法保证的,也就是说,不能保证你写入的数据是对的,或者写入对了,读出来也不一定对的。与此对应的正常的块,肯定是写入读出都是正常的。坏块有两种:

     (1) 出厂时就有存在的坏块:

     一种是出厂的时候,也就是,你买到的新的,还没用过的 NAND Flash,就可以包含了坏块。此类出厂时就有的坏块,被称作 factory (masked) bad block 或 initial bad/invalid block,在出厂之前,就会做对应的标记,标为坏块。

     (2) 使用过程中产生的坏块:

     第二类叫做在使用过程中产生的,由于使用过程时间长了,在擦块除的时候,出错了,说明此块坏了,也要在程序运行过程中,发现,并且标记成坏块的。具体标记的位置,和上面一样。这类块叫做 worn-out bad block。即用坏了的块。

    2.1坏块的标记

     具体标记的地方是,对于现在常见的页大小为2K的 NAND Flash,是块中第一个页的 oob 起始位置的第1个字节(旧的小页面,pagesize是512B至256B的 NAND Flash,坏块标记是第 6 个字节)。如果不是 0xFF, 就说明是坏块。相对应的是,所有正常的块,好的块,里面所有数据都是 0xFF 的。不过,对于现在新出的有些 Nand Flash,很多标记方式,有些变化,有的变成该坏块的第一个页或者第二个页,也有的是,倒数最后一个或倒数第二个页,用于标记坏块的。具体的信息,请参考对应的 Nand Flash 的数据手册,其中会有说明。对于坏块的标记,本质上,也只是对应的 flash 上的某些字节的数据是非 0xFF 而已,所以,只要是数据,就是可以读取和写入的。也就意味着,可以写入其他值,也就把这个坏块标记信息破坏了。对于出厂时的坏块,一般是不建议将标记好的信息擦除掉的。uboot 中有个命令是“nand scrub”就可以将块中所有的内容都擦除了,包括坏块标记,不论是出厂时的,还是后来使用过程中出现而新标记的。一般来说,不建议用这个。其实最好的做法是,用“nand erase”只擦除好的块,对于已经标记坏块的块,不要轻易擦除掉,否则就很难区分哪些是出厂时就坏的,哪些是后来使用过程中用坏的了。

    2.2坏块的管理

     对于坏块的管理,在Linux系统中,叫做坏块管理(BBM,Bad Block Management),对应的会有一个表去记录好块,坏块的信息,以及坏块是出厂就有的,还是后来使用产生的,这个表叫做坏块表(BBT,Bad Block Table) 。在 Linux 内核 MTD 架构下的Nand Flash驱动,和 Uboot 中 NAND Flash 驱动中,在加载完驱动之后,如果你没有加入参数主动要求跳过坏块扫描的话,那么都会去主动扫描坏块,建立必要的 BBT 的,以备后面坏块管理所使用。K9F2G08U0B建立BBT的流程图如下所示:

    2.3坏块的比例

     而关于好块和坏块,Nand Flash 在出厂的时候,会做出保证:

     1.关于好的,可以使用的块的数目达到一定的数目,比如三星的K9F2G08U0B,整个 Flash一共有2048个块,出厂的时候,保证好的块至少大于2008个,也就是意思是,你新买到这个型号的Nand Flash,最坏的可能, 有 2048-2008=40个坏块。不过,事实上,现在出厂时的坏块,比较少,绝大多数,都是使用时间长了,在使用过程中出现的。

    2.保证第一个块是好的,并且一般相对来说比较耐用。做此保证的主要原因是,很多 NandFlash 坏块管理方法中,就是将第一个块,用来存储上面提到的 BBT,否则,都是出错几率一样的块,那么也就不太好管理了,连放 BBT 的地方,都不好找了。一般来说,不同型号的Nand Flash的数据手册中,也会提到自己的这个NAND Flash,最多允许多少个坏块。

    3. 移植uboot NAND Flash代码的疑问

    参考Mini2440之U-boot使用及移植详细手册.pdf,移植NAND Flash代码重定向时,新添加了nand_read.c源文件。摘录读取NAND Flash读取数据函数如下:

    点击(此处)折叠或打开

    1. static int nand_read_page_ll(struct boot_nand_t * nand, unsigned char *buf, 
    2.      unsigned long addr)
    3. {
    4. unsigned short *ptr16 = (unsigned short *)buf;
    5. unsigned int i, page_num;
    6. nand_clear_RnB();
    7. NFCMD = NAND_CMD_READ0;//发送读数据命令
    8. if (nand->page_size == 512) {
    9. /* Write Address */
    10. NFADDR = addr & 0xff;
    11. NFADDR = (addr >> 9) & 0xff;
    12. NFADDR = (addr >> 17) & 0xff;
    13. NFADDR = (addr >> 25) & 0xff;
    14. else if (nand->page_size == 2048) {
    15. page_num = addr >> 11; /* addr / 2048 */
    16. /* Write Address */
    17. NFADDR = 0;
    18. NFADDR = 0;
    19. NFADDR = page_num & 0xff;
    20. NFADDR = (page_num >> 8) & 0xff;
    21. NFADDR = (page_num >> 16) & 0xff;
    22. NFCMD = NAND_CMD_READSTART;
    23. } else {
    24. return -1;
    25. }
    26. nand_wait();
    27. #if defined(CONFIG_S3C2410)
    28. for (i = 0; i < nand->page_size; i++) {
    29. *buf = (NFDATA & 0xff);
    30. buf++;
    31. }
    32. #elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
    33. for (i = 0; i < (nand->page_size>>1); i++) {//读2K字节数据
    34. *ptr16 = NFDATA16;
    35. ptr16++;
    36. }
    37. #endif
    38. return nand->page_size;
    39. }

    参照K9F2G08U0B芯片手册,发送地址的时序如下图所示:

    前两个周期发送A0~A11,为列地址,即页内地址。后三个周期发送A12~A28,为行地址,即页地址。但是程序中获取页地址是把地址addr右移11位,而不是12位。开始一直很困惑。经过一番探索之后才理解了其中缘由。首先需要了解NAND Flash页内地址的结构,它分为Main Field(2K)和Spare Field(64Byte)两部分,而我们的数据是存放在2K当中,普通的数据读写不对后面64Byte操作,使用A0~A10地址就可实现对2K数据存储区的寻址。下图为K9F2G08U0B页内结构:

    函数nand_read_page_ll传递进来的addr地址没有包含对Sapre Field的寻址。所以只移11位,而不是移12位。NAND Flash读取数据是以页为单位,当NAND Flash接收到地址后,会把该页内addr&0x7F地址之后的数据依次输出包括Spare Field。在nand_read_page_ll函数里,列地址为0,读取此页所有数据。所以for循环读数据时,只读前2K的内容后就跳出循环。

    那如何只读取Sapre Field中的内容呢?以检查K9F2G08U0B中某一块是否是坏块为例,我们需要读取该块第一页地址为2048处的数据是否为0xFF。摘录nand_read.c源文件中检查坏块函数is_bad_block如下:

    点击(此处)折叠或打开

    1. static int is_bad_block(struct boot_nand_t * nand, unsigned long i)
    2. {
    3. unsigned char data;
    4. unsigned long page_num;
    5. nand_clear_RnB();
    6. if (nand->page_size == 512) {
    7. NFCMD = NAND_CMD_READOOB; /* 0x50 */
    8. NFADDR = nand->bad_block_offset & 0xf;
    9. NFADDR = (i >> 9) & 0xff;
    10. NFADDR = (i >> 17) & 0xff;
    11. NFADDR = (i >> 25) & 0xff;
    12. } else if (nand->page_size == 2048) {     //K9F2G08U0B执行这里
    13. page_num = i >> 11; /* addr / 2048 */
    14. NFCMD = NAND_CMD_READ0;
    15. NFADDR = nand->bad_block_offset & 0xff;
    16. NFADDR = (nand->bad_block_offset >> 8) & 0xff;
    17. NFADDR = page_num & 0xff;
    18. NFADDR = (page_num >> 8) & 0xff;
    19. NFADDR = (page_num >> 16) & 0xff;
    20. NFCMD = NAND_CMD_READSTART;
    21. } else {
    22. return -1;
    23. }
    24. nand_wait();
    25. data = (NFDATA & 0xff);    //读2048处一个字节数据
    26. if (data != 0xff)
    27. return 1;
    28. return 0;
    29. }

    在这里只需把列地址的值设为2048,即0x80。此时就需要用到A11来寻址了。这里只需要读取第一个字节就可以了。

    小结:

    这里开始无法理解的原因是不知道传递进来的地址addr不包括对Spare Feild的寻址,只有对2K数据的寻址。检查是否是坏块,是直接给列地址赋值为0x80,并没有用到传递进来的地址参数。

    附nand_read.c源码(摘自Mini2440之U-boot使用及移植详细手册.pdf):

    点击(此处)折叠或打开

    1. /*
    2. * nand_read.c: Simple NAND read functions for booting from NAND
    3. *
    4. * This is used by cpu/arm920/start.S assembler code,
    5. * and the board-specific linker script must make sure this
    6. * file is linked within the first 4kB of NAND flash.
    7. *
    8. * Taken from GPLv2 licensed vivi bootloader,
    9. * Copyright (C) 2002 MIZI Research, Inc.
    10. *
    11. * Author: Hwang, Chideok <hwang@mizi.com>
    12. * Date : $Date: 2004/02/04 10:37:37 $
    13. *
    14. * u-boot integration and bad-block skipping (C) 2006 by OpenMoko, Inc.
    15. * Author: Harald Welte <laforge@openmoko.org>
    16. */
    17. #include <common.h>
    18. #include <linux/mtd/nand.h>
    19. #define __REGb(x) (*(volatile unsigned char *)(x))
    20. #define __REGw(x) (*(volatile unsigned short *)(x))
    21. #define __REGi(x) (*(volatile unsigned int *)(x))
    22. #define NF_BASE 0x4e000000
    23. #if defined(CONFIG_S3C2410)
    24. #define NFCONF __REGi(NF_BASE + 0x0)
    25. #define NFCMD __REGb(NF_BASE + 0x4)
    26. #define NFADDR __REGb(NF_BASE + 0x8)
    27. #define NFDATA __REGb(NF_BASE + 0xc)
    28. #define NFSTAT __REGb(NF_BASE + 0x10)
    29. #define NFSTAT_BUSY 1
    30. #define nand_select() (NFCONF &= ~0x800)
    31. #define nand_deselect() (NFCONF |= 0x800)
    32. #define nand_clear_RnB() do {} while (0)
    33. #elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
    34. #define NFCONF __REGi(NF_BASE + 0x0)
    35. #define NFCONT __REGi(NF_BASE + 0x4)
    36. #define NFCMD __REGb(NF_BASE + 0x8)
    37. #define NFADDR __REGb(NF_BASE + 0xc)
    38. #define NFDATA __REGb(NF_BASE + 0x10)
    39. #define NFDATA16 __REGw(NF_BASE + 0x10)
    40. #define NFSTAT __REGb(NF_BASE + 0x20)
    41. #define NFSTAT_BUSY 1
    42. #define nand_select() (NFCONT &= ~(<< 1))
    43. #define nand_deselect() (NFCONT |= (<< 1))
    44. #define nand_clear_RnB() (NFSTAT |= (<< 2))
    45. #endif
    46. static inline void nand_wait(void)
    47. {
    48.     int i;
    49.     while (!(NFSTAT & NFSTAT_BUSY))
    50.     for (i=0; i<10; i++);
    51. }
    52. struct boot_nand_t {
    53.     int page_size;
    54.     int block_size;
    55.     int bad_block_offset;
    56.     // unsigned long size;
    57. };
    58. #if 0
    59. #if defined(CONFIG_S3C2410) || defined(CONFIG_MINI2440)
    60. /* configuration for 2410 with 512byte sized flash */
    61. #define NAND_PAGE_SIZE 512
    62. #define BAD_BLOCK_OFFSET 5
    63. #define NAND_BLOCK_MASK (NAND_PAGE_SIZE - 1)
    64. #define NAND_BLOCK_SIZE 0x4000
    65. #else
    66. /* configuration for 2440 with 2048byte sized flash */
    67. #define NAND_5_ADDR_CYCLE
    68. #define NAND_PAGE_SIZE 2048
    69. #define BAD_BLOCK_OFFSET NAND_PAGE_SIZE
    70. #define NAND_BLOCK_MASK (NAND_PAGE_SIZE - 1)
    71. #define NAND_BLOCK_SIZE (NAND_PAGE_SIZE * 64)
    72. #endif
    73. /* compile time failure in case of an invalid configuration */
    74. #if defined(CONFIG_S3C2410) && (NAND_PAGE_SIZE != 512)
    75. #error "S3C2410 does not support nand page size != 512"
    76. #endif
    77. #endif
    78. static int is_bad_block(struct boot_nand_t * nand, unsigned long i)
    79. {
    80.     unsigned char data;
    81.     unsigned long page_num;
    82.     nand_clear_RnB();
    83.     if (nand->page_size == 512) {
    84.         NFCMD = NAND_CMD_READOOB; /* 0x50 */
    85.         NFADDR = nand->bad_block_offset & 0xf;
    86.         NFADDR = (>> 9) & 0xff;
    87.         NFADDR = (>> 17) & 0xff;
    88.         NFADDR = (>> 25) & 0xff;
    89.     } else if (nand->page_size == 2048) {
    90.         page_num = i >> 11; /* addr / 2048 */
    91.         NFCMD = NAND_CMD_READ0;
    92.         NFADDR = nand->bad_block_offset & 0xff;
    93.         NFADDR = (nand->bad_block_offset >> 8) & 0xff;
    94.         NFADDR = page_num & 0xff;
    95.         NFADDR = (page_num >> 8) & 0xff;
    96.         NFADDR = (page_num >> 16) & 0xff;
    97.         NFCMD = NAND_CMD_READSTART;
    98.     } else {
    99.         return -1;
    100.     }
    101.     nand_wait();
    102.     data = (NFDATA & 0xff);
    103.     if (data != 0xff)
    104.         return 1;
    105.     return 0;
    106. }
    107. static int nand_read_page_ll(struct boot_nand_t * nand, unsigned char *buf, unsigned long addr)
    108. {
    109.     unsigned short *ptr16 = (unsigned short *)buf;
    110.     unsigned int i, page_num;
    111.     nand_clear_RnB();
    112.     NFCMD = NAND_CMD_READ0;
    113.     if (nand->page_size == 512) {
    114. /* Write Address */
    115.     NFADDR = addr & 0xff;
    116.     NFADDR = (addr >> 9) & 0xff;
    117.     NFADDR = (addr >> 17) & 0xff;
    118.     NFADDR = (addr >> 25) & 0xff;
    119.     } else if (nand->page_size == 2048) {
    120.     page_num = addr >> 11; /* addr / 2048 */
    121. /* Write Address */
    122.     NFADDR = 0;
    123.     NFADDR = 0;
    124.     NFADDR = page_num & 0xff;
    125.     NFADDR = (page_num >> 8) & 0xff;
    126.     NFADDR = (page_num >> 16) & 0xff;
    127.     NFCMD = NAND_CMD_READSTART;
    128.     } else {
    129.         return -1;
    130.     }
    131.     nand_wait();
    132. #if defined(CONFIG_S3C2410)
    133.     for (= 0; i < nand->page_size; i++) {
    134.         *buf = (NFDATA & 0xff);
    135.         buf++;
    136.     }
    137. #elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
    138.     for (= 0; i < (nand->page_size>>1); i++) {
    139.         *ptr16 = NFDATA16;
    140.         ptr16++;
    141.     }
    142. #endif
    143.     return nand->page_size;
    144. }
    145. static unsigned short nand_read_id()
    146. {
    147.     unsigned short res = 0;
    148.     NFCMD = NAND_CMD_READID;
    149.     NFADDR = 0;
    150.     res = NFDATA;
    151.     res = (res << 8) | NFDATA;
    152.     return res;
    153. }
    154. extern unsigned int dynpart_size[];
    155. /* low level nand read function */
    156. int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)
    157. {
    158.     int i, j;
    159.     unsigned short nand_id;
    160.     struct boot_nand_t nand;
    161.     /* chip Enable */
    162.     nand_select();
    163.     nand_clear_RnB();
    164.     for (= 0; i < 10; i++)
    165.         ;
    166.     nand_id = nand_read_id();
    167.     if (0) { /* dirty little hack to detect if nand id is misread */
    168.         unsigned short * nid = (unsigned short *)0x31fffff0;
    169.         *nid = nand_id;
    170.     }
    171.     if (nand_id == 0xec76 || /* Samsung K91208 */
    172.         nand_id == 0xad76 ) { /*Hynix HY27US08121A*/
    173.         nand.page_size = 512;
    174.         nand.block_size = 16 * 1024;
    175.         nand.bad_block_offset = 5;
    176.         // nand.size = 0x4000000;
    177.     } else if (nand_id == 0xecf1 || /* Samsung K9F1G08U0B */
    178.         nand_id == 0xecda || /* Samsung K9F2G08U0B */
    179.         nand_id == 0xecd3 ) { /* Samsung K9K8G08 */
    180.         nand.page_size = 2048;
    181.         nand.block_size = 128 * 1024;
    182.         nand.bad_block_offset = nand.page_size;
    183.         // nand.size = 0x8000000;
    184.     } else {
    185.         return -1; // hang
    186. }
    187.     if ((start_addr & (nand.block_size-1)) || (size & (nand.block_size-1)))
    188.         return -1; /* invalid alignment */
    189.     for (i=start_addr; i < (start_addr + size);) {
    190.     #ifdef CONFIG_S3C2410_NAND_SKIP_BAD
    191.         if (& (nand.block_size-1)== 0) {
    192.             if (is_bad_block(&nand, i) ||
    193.             is_bad_block(&nand, i + nand.page_size)) {
    194.             /* Bad block */
    195.             i += nand.block_size;
    196.             size += nand.block_size;
    197.             continue;
    198.             }
    199.         }
    200.     #endif
    201.         j = nand_read_page_ll(&nand, buf, i);
    202.         i += j;
    203.         buf += j;
    204.     }
    205. /* chip Disable */
    206.     nand_deselect();
    207.     return 0;
    208. }
    展开全文
  • uboot中对Flash和DDR的管理

    千次阅读 2016-04-15 14:38:38
    uboot中对flash和ddr的管理 uboot阶段对flash的分区, uboot,var,kernel,rootfs,自由。 uboot中是没有操作系统中的,但是都有一个分区表决定分配方法, 这个分配不是随意的,比如soc要从第1个扇区开始,我们...

    《朱老师物联网大讲堂》学习笔记

    学习地址:www.zhulaoshi.org


    uboot中对flash和ddr的管理


    uboot阶段对flash的分区,

    uboot,var,kernel,rootfs,自由。

    uboot中是没有操作系统中的,但是都有一个分区表决定分配方法,

    这个分配不是随意的,比如soc要从第1个扇区开始读,我们的分配就得配合它,

    在移植前,这个分配得定好,这个标准是:

    uboot:uboot必须从Flash起始地址开始存放(也许是扇区0,也许是扇区1,也许是其他,取决于SoC的启动设计),

    uboot分区的大小一般设计为512KB或者1MB(因为一般uboot肯定不足512KB);

    环境变量:环境变量分区一般紧贴着uboot来存放,大小为32KB或者更多一点。

    kernel:kernel可以紧贴环境变量存放,大小一般为3MB或5MB或其他。

    rootfs:······

    剩下的就是自由分区,一般kernel启动后将自由分区挂载到rootfs下使用


    uboot必须在Flash开头,其他分区相对位置是可变的。

    分区在系统移植前确定好,在uboot中和kernel中使用同一个分区表。将来在系统部署时和系统代码中的分区方法也必须一样。



    uboot阶段DDR的分区

    Flash是掉电存在的,DDR是掉电消失,因此DDR每次系统运行时才开始部署使用的,

    内存的分区一般是在linux内核启动起来之前,linux内核启动后内核的内存管理模块会接管整个内存空间,我们就不用管了,

    内存中分区必须分配好,以避免各个不同功能使用了同一块内存造成的互相踩踏,

    比如tftp 0x23E00000 zImage去下载zImage到内存的0x23E00000处就会出错,因为这个内存处实际是uboot的镜像所在,

    这样下载会导致下载的zImage把内存中的uboot给冲掉。



    展开全文
  • 1:对mmc操作 mmc read addr blk# cnt 2:对mmc写操作 mmc write addr blk# cnt 3:对mmc擦除操作 mmc erase blk# cnt 4:重新搜索mmc设备 mmc rescan 5:列出mmc的分区 mmc part - lists available partition...
    
    
    uboot mmc命令详解
    
    一:mmc的命令如下:
    1:对mmc读操作
    mmc read addr blk# cnt
    
    2:对mmc写操作
    mmc write addr blk# cnt
    
    3:对mmc擦除操作
    mmc erase blk# cnt
    
    4:重新搜索mmc设备
    mmc rescan
    
    5:列出mmc的分区
    mmc part - lists available partition oncurrent mmc device
    
    6:查看当前的设备号,或者设置设备号及分区
    mmc dev [dev] [part] - show or set currentmmc device [partition]
    
    7:显示boot分区号
    mmc bootpart [dev] [part] - show or setboot partition
    
    8:列出当前的mmc设备
    mmc list - lists available devices
    
    9: 打印一些当前mmc设备的信息
    mmcinfo
    
    二:mmc的命令详解
    1:mmcinfo
    输入:
    mmcinfo
    显示结果:
    Manufacturer ID: 45
    OEM: 100
    Name: SEM08
    Tran Speed: 25000000
    Rd Block Len: 512
    MMC version 4.0
    Clock: 52000000
    High Capacity: Yes
    Capacity: 7944011776 Bytes
    Bus Width: 8-bit DDR
    Current Partition for boot: Boot partition 1
    
    2:mmc list -lists available devices
    
    输入:
    mmc list
    显示如下:
    FSL_USDHC: 0
    FSL_USDHC: 1
    FSL_USDHC: 2
    FSL_USDHC: 3
    
    分析:boot中配置了四个mmc资源,SD卡是2,EMMC是3
    
    3:mmc dev[dev] [part] - show or set current mmc device [partition]
    
    输入:
    mmc dev 3
    显示如下:
    mmc3(part 0) is current device
    
    分析:表示当前处于EMMC设备的第0个分区
    
    输入:
    mmc dev 3 1
    显示如下:
    mmc3(part 1) is current device
    
    分析:设置当前处于EMMC设备的第1个分区
    
    4:mmc bootpart [dev] [part] - show or set boot partition
    
    输入:
    mmc bootpart
    显示如下:
    Device 3: boot partition 1 is for boot
    
    分析:uboot处于第一个分区
    
    5:mmc part -lists available partition on current mmc device
    
    输入:
    mmc part
    显示如下:
    Partition Map for UNKNOWN device 3 -- Partition Type: DOS
    
    Partition Start Sector Num Sectors Type
    1 16384 16384 83
    2 32768 16384 83
    3 49152 6397952 5 Extd
    4 6447104 9150464 83
    5 49153 3145727 83
    6 3194881 3145727 83
    7 6340609 16383 83
    8 6356993 8191 83
    
    分析:显示当前EMMC的所有分区
    
    6:mmc read addr blk# cnt
    这个命令的作用是读取mmc上的数据到内存上
    
    参数:
    addr: 读取到内存的位置
    blk: 读取block位置,这个位置是mmc的0地址的偏移量,是16进 制,block单位是512字节
    cnt: 读取block个数,要读取到内存的数据大小,是16进制
    block单位是512字节
    
    例:
    mmc dev 3 0
    mmc read 0x10800000 600 10
    
    命令分析:表示从mmc上1536×512个字节开始处(1536是600的十进制),读取16×512个字节(16是10的10进制)到内存0x10800000 处
    
    显示结果:
    MMC read: dev #3, block # 1536, count 16 ... 16 blocks read: OK
    结果分析:
    我们只能从结果看出来读取成功,但不能确定读取的内容是否正确,所以打印下内存的数据,看是否与mmc中的内容一致
    
    输入:
    md.b 0x10800000 100
    命令分析:打印内存位置0x10800000的100个字节
    显示结果:
    10800000: b15ecb3c 6f62 746f 6564 616c 3d79 0033 ^.<.bootdelay=3.
    10800010: 61626475 6172 6574 313d 3531 3032 0030 baudrate=115200.
    10800020: 70696461 7264 313d 3239 312e 3836 312e ipaddr=192.168.1
    10800030: 312e3330 7300 7265 6576 6972 3d70 3931 .103.serverip=19
    10800040: 2e323631 2e38 2e31 3031 0031 656e 6d74 2.168.1.101.netm
    10800050: 73613d6b 3532 2e35 3532 2e35 3532 2e35 ask=255.255.255.
    .....
    .......
    结果分析:
    我在mmc位置1536×512的位置储存的是环境变量,与内存打印的一致,读取正确
    
    7:mmc write addr blk# cnt
    这个命令的作用是将内存上的数据写入mmc中
    
    参数:
    addr: 从内存读取的位置
    blk: 写入到mmc中block位置,这个位置是mmc的0地址的偏移量,是16进制,block单位是512字节
    cnt: 写入到mmc中block个数,要写入的数据大小,是16进制,
    block单位是512字节
    
    例:
    mmc dev 3
    mmc write 0x108000000 0 100
    
    命令分析:表示从内存0x108000000的位置上读取256*512的数据(256是100的十进制)到mmc上0的位置处,这里就不举例验证了
    
    mmc上0的位置处是分区表,我把内存上的乱数据写进去后,uboot检测不到分区了
    
    8:mmc erase blk# cnt
    参数:
    blk: 擦除的mmc中block位置,这个位置是mmc的0地址的偏移量,是16进制,block单位是512字节
    cnt: 擦除的mmc中block个数,是16进制,block单位是512字节
    
    
    
    
    Nand flash uboot 命令详解 
    

    nand info & nand device

    显示flash的信息:

    DM365 :>nand info
    Device 0: NAND 32MiB 3,3V 8-bit, sector size 16 KiB
    DM365 :>nand device
    Device 0: NAND 32MiB 3,3V 8-bit


    nand read(.oob) addr off size

    不管是读取data, 使用nand read,还是读取oob,使用命令nand read.oob, 后面跟的地址addr,都是ram的地址, off指的是nand flash的地址, size:指要读取nand flash的数据大小, 但是如果是读取oob, size不能超过一个page的oob size, 如果page size为512个字节, oob size就是16个字节.

    DM365 :>nand read 86000000 58000 100
    NAND read: device 0 offset 0x58000, size 0x100
    256 bytes read: OK
    DM365 :>md 86000000 40
    86000000: ea000012 e59ff014 e59ff014 e59ff014 ................
    …………
    860000f0: e1a0000d eb00022e 00000000 00000000 ................
    DM365 :>nand read.oob 86000000 58000 10
    NAND read: device 0 offset 0x58000, size 0x10
    16 bytes read: OK
    DM365 :>md 86000000 40
    86000000: ffffffff 2707ffff 33e316ad 44b2e1a1 .......'...3...D

    如果一次想读取完整的一个page 的值,包含oob, 使用下面将的命令, nand dump.


    nand dump [addr] [size]

    调用过程: nand dump addr size (common/cmd_nand.c)==> nand_dump() ==> nand_read_raw();
    nand dump 不管你的size有多大,至少会dump出一个page的大小:

    SMDK2440 # nand dump 0 100
    Page 00000000 dump:
    12 00 00 ea 14 f0 9f e5 14 f0 9f e5 14 f0 9f e5
    14 f0 9f e5 14 f0 9f e5 14 f0 9f e5 14 f0 9f e5
    00 02 f8 33 60 02 f8 33 c0 02 f8 33 20 03 f8 33
    80 03 f8 33 e0 03 f8 33 40 04 f8 33 ef be ad de
    00 00 f8 33 00 00 f8 33 58 19 fa 33 34 6d fa 33
    00 00 0f e1 1f 00 c0 e3 d3 00 80 e3 00 f0 29 e1
    …………
    04 30 8c e5 fc 4d 00 eb 00 01 9f e5 f0 3c 00 eb
    02 0d 00 eb 41 42 00 eb f4 00 9f e5 00 40 98 e5
    04 02 00 eb 0d 10 a0 e1 04 00 84 e5 40 20 a0 e3
    OOB:
    ff ff ff ff ff ff ff ff
    ff ff ff ff ff ff ff ff
    ff ff ff ff ff ff ff ff
    ff ff ff ff ff ff ff ff
    ff ff ff ff ff ff ff ff
    69 a6 ab 3c 33 cf 66 5a
    a7 cf f0 33 a6 96 97 3f
    0c c3 30 30 c3 cc 33 f3


    nand write - addr off size

    这个命令和nand read一样, 只是方向是反的, 是把ram的值写到 nand flash中, 但是这个写只能将1改为0, 不能将0写成1. 这个command会自动skipping bad blocks。


    nand erase [clean] [off size]

    在擦之前会先check是不是坏块,如果是坏块,就不能做擦的动作了。

    DM365 :>nand dump 1cc000 10
    Page 001cc000 dump:
    68 73 71 73 12 05 00 00 87 04 08 78 19 00 40 02
    …………
    df 88 5b 80 bb 11 32 11 6e e7 77 5a 3d b9 c8 bf
    OOB:
    ff ff ff ff ff ff ff 45
    ed cc 3a e0 8e 52 f9 ad
    DM365 :>nand erase 1cc000 100
    NAND erase: device 0 offset 0x1cc000, size 0x100
    Warning: Erase size 0x00000100 smaller than one erase block 0x00004000
    Erasing 0x00004000 instead
    Erasing at 0x1cc000 -- 100% complete.
    OK
    DM365 :>nand dump 1cc000 10  
    Page 001cc000 dump:
    ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
    …………
    ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
    OOB:
    ff ff ff ff ff ff ff ff
    ff ff ff ff ff ff ff ff
    DM365 :>mw 86000000 00000000
    DM365 :>mw 86000004 00000000
    DM365 :>mw 86000008 00000000
    DM365 :>mw 8600000c 00000000
    DM365 :>md 86000000
    86000000: 00000000 00000000 00000000 00000000 ................
    DM365 :>nand write.oob 86000000 1cc000 10
    NAND write: device 0 offset 0x1cc000, size 0x10
    16 bytes written: OK
    DM365 :>nand dump 1cc000 10 
    Page 001cc000 dump:
    ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
    …………
    ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
    OOB:
    00 00 00 00 00 00 00 00
    00 00 00 00 00 00 00 00
    DM365 :>nand erase 1cc000 100
    NAND erase: device 0 offset 0x1cc000, size 0x100
    Warning: Erase size 0x00000100 smaller than one erase block 0x00004000
    Erasing 0x00004000 instead
    Skipping bad block at 0x001cc000
    OK


    不常用的命令

    这些命令都是测试时使用的,正常是不会使用到的。

     "nand scrub - really clean NAND erasing bad blocks (UNSAFE)\n"
    "nand markbad off - mark bad block at offset (UNSAFE)\n"
    "nand biterr off - make a bit error at offset (UNSAFE)\n"
    "nand lock [tight] [status]\n"
    " bring nand to lock state or display locked pages\n"
    "nand unlock [offset] [size] - unlock section\n");

    展开全文
  • 1. ID S3C2440 u-boot 选中 NFCONT的bit1设为0 md.l 0x4E000004 1; mw.l 0x4E000004 1发出命令0x90 ...
  • UBOOT

    2017-06-18 20:39:18
    PC是怎样启动的? 上电,BIOS,引导操作系统Windows,识别各种盘,运行应用程序 嵌入式是怎样启动的?...UBOOT一般从flash中读入内核,放到SDRAM中去,然后启动内核。 UBOOT为了达到这个目的,得能fl
  • uboot分析

    2019-08-02 23:26:52
    1.在链接脚本里面查看启动地址和第一个启动文件(start.s),u_boot_cmd的起始地址,截止地址。 2.分析Makefile。 3.start.s分析: 1)切换管理模式 ...7)重定位(把代码从flash里面到内存的链接地址) ...
  • 首先要明确:uboot目标是从flash读出内核(nand read.jffs2 0x30007FC0 kernel;),启动它(bootm 0x30007FC0)。 /*从NAND读出内核:从哪里,从kernel分区 放到哪里去:0x30007FC0(可以随便放) nand read...
  • 分析uboot启动内核命令 从uboot的终端执行print命令可以看到以下命令 bootcmd=nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0 这就是读出内核,启动内核的命令...从哪里: 从nandflash 的kernel分区读出内核,...
  • uboot第二阶段 ...需要从flash内核,就需初始化flash,使之能读写 start_armboot --> flash_init (); /* norflash初始化*/ --> mem_malloc_init (_armboot_start - CFG_MALLOC_LEN); /*堆初始...
  • 1 uboot编译: 打补丁:patch -p1 配置:make 100ask24x0_config 编译:make 执行make 100ask24x0_config后发生了什么 uboot的目标: ...1 读flash 2 初始化ram、初始化时钟、初始化串口 3 启动内核
  • UBOOT学习总结

    2017-11-25 18:36:00
    UBOOT的主要任务是初始化硬件(如:串口,内存),然后将内核从Flash到RAM中,然后跳转到内核的入口点去运行,也就是启动操作系统。   UBOOT和BIOS的差异:PC机的引导程序由BIOS和位于硬盘MBR中的引导程序...
  • 2440 uboot分析

    2019-12-02 17:05:21
    bootloader的最终目的,启动内核 ...读FLASH 关看门狗 初始化时钟 初始化SDRAM 初始化时钟 初始化网卡 初始化USB 初始化串口 启动内核 结合makefile分析uboot的功能和结构 分析Makefile...
  • uboot启动内核

    2018-04-25 10:11:45
    uboot流程分为第一阶段(芯片初始化、重定位等)和第二阶段(各项功能),在第二阶段的最后,启动内核1、s = getenv ("bootcmd"...内核到SDRAM:(1)NAND FLASH分区#define MTDPARTS_DEF...
  • uboot学习笔记

    2017-10-26 22:35:19
    2017年10月7日10:00 ...1. 读flash(+写flash,用于开发方便1、写flash,2、写网卡,3USB等) 2. 初始化SDRAM;(初始化时钟,初始化串口) 3. 启动内核 Uboot配置和编译 配置编译 Make 100
  • uboot环境变量

    2019-01-09 00:25:00
    一. uboot运行时环境变量分布  1.1.环境变量有2份,一份在Flash中,另一份在DDR中。uboot开机时一次性从Flash中读取全部环境变量到DDR中作为环境...下次开机时又会从Flash中再一次。 二. ubooth环境变量分析 ...
  • Linux uboot详解

    2020-10-20 20:08:47
    BIOS在完成硬件检测和资源分配后,将硬盘中的引导程序到内存中然后把控制权交给引导程序。引导程序的主要任务是将内核从flash读取到内存中,然后跳转到内核的入口地址区去运行,即启动操作系统。 在嵌入式系统中,...
  • uboot正常启动后,会调用main_loop(void)函数,进入main_loop()之后,如果在规定的时间(CONFIG_BOOTDELAY)内,没有检查到任何按键事件的发生,就会去加载OS,并启动系统,比如把linux内核压缩镜像从nand flash...
  • bootloader作用: 1.初始化硬件,设置cpu模式,关闭看门狗,设置...3.将内核从nand flash 到sdram 4.设置要传给内核的参数 5.跳转启动内核。 source insight 工程 uboot目录删减 1:arch->arm->add ...
  • 搞了3天终于是可以把Nand FlashUboot代码拷到内存了,真郁闷......   /*板子为FL2440,接了一片256M的K9F2G08UXA,一页2048+64,交叉编绎工*具cross-3.3.2.tar.bz2*/ NFCONF EQU 0x4E000000 NFCONT EQU 0x4E000004...
  • uboot-环境变量

    2019-01-06 10:46:29
    uboot环境变量 1 环境变量描述 环境变量有2份,一份在Flash中,另一份在DDR中。uboot开机时一次性从Flash中读取全部环境变量到...下次开机时又会从Flash中再一次。 环境变量在uboot中是用字符串表示的,也就是说u...
  • my uboot学习笔记

    2019-10-22 22:36:33
    一、u-boot 的最终目的 ...读flash写入sdram 二、u-boot 安装 1、解压缩u-boot 2、打补丁 patch -px < 补丁文件(x代表忽略掉补丁目录的几个/) 3、配置 make xxxx_config 4、编译 make 三、u-...
  • uboot global_data

    2020-10-23 17:52:53
    在某些情况下,uboot是在某些只读存储器上运行,比如ROM、nor flash等等。 在uboot被重定向到RAM(可可写)之前,我们都无法写入数据,更无法通过全局变量来传递数据。 而global_data则是为了解决这个问题。 ...
  • uboot功能分析与patch

    2017-03-04 17:08:51
    能够读Flash 初始化SDRam,初始化时钟(开发板上电,时钟的运行频率是12M,2440最大的频率是400M) 虽然uboot的最终目的是启动内核,但是在开发阶段我们想增加更多的功能方便开发。 初始化串口 写f
  • 嵌入式 uboot-sd升级

    2019-10-24 17:44:50
    此操作要严谨,否则uboot也被擦除,一旦reset,完蛋,...#fatload mmc 0 0x81800000 flash.bin //sd卡上的文件 flash.bin 到 0x818000000(这个是相对于cpu来说的地址,要看soc手册,这里对应的就是sdram的地址) 2...
  • 学习笔记之uboot启动

    2019-09-11 22:27:33
    首先板子在上电之后,CPU会从nandflash或者norflash读汇编指令,这段儿汇编代码主要功能是初始化最基本的硬件和自搬移到内存,硬件包括时钟、串口、内存等基本硬件,同时为考虑,会关闭中断、看门狗、mmu等,关掉...
  • uboot命令模式的实现

    千次阅读 2012-04-06 10:46:41
    uboot正常启动后,会调用main_loop(void)函数,进入main_loop()之后,如果在规定的时间(CONFIG_BOOTDELAY)内,没有检查到任何按键事件的发生,就会去加载OS,并启动系统,比如把linux内核压缩镜像从nand flash...

空空如也

1 2 3 4 5 6
收藏数 109
精华内容 43
关键字:

uboot读flash