6410 UBOOT 支持SD/SDHC卡启动 FAT32文件系统 yaffs2烧录 图片显示烧录状态

6410 UBOOT 支持SD/SDHC卡启动 FAT32文件系统  yaffs2烧录 图片显示烧录状态

开发板: 飞凌6410 256M DDR 2G nand (4K pagesize)



需要csdn帐号和资源分才可以下载,其它朋友有需要可以QQ 67016879 或 [email protected]


移植好的uboot下载地址:http://download.csdn.net/source/3561490

三星IROM boot 文档:http://download.csdn.net/source/3561602

烧录工具下载:http://download.csdn.net/source/3561492

Raw data bmp 转换工具(PIC2RAW):http://www.mculee.cn/post/%E5%9B%BE%E7%89%87,bmp,raw,%E8%BD%AC%E6%8D%A2.html


移植说明:

1.支持SD/SDHC启动,相关文件:

include/confisg/smdk6410.h 定义  #define CONFIG_BOOT_MOVINAND 关掉 //#define CONFIG_BOOT_NAND

其它参考: cpu/s3c64xx/movi.c 主要功能是通过三星IROM code 函数CopyMMCtoMem(z,a,b,c,e) 拷贝BL2到DDR内存,

前8K(BL1)由CPU上电时自行拷贝,需要设置CPU启动跳线;


内存已经配置成256M了,飞凌提供的mmc.bin只支持128M(浪费了128M),烧大于126M的文件几乎很难烧录。

一般在加入越来越多的应用后,文件系统会越来越大,

最大文件支持为253M,uboot 2M(地址0x5FE00000) framebuffer 1M(0x5FD00000),

超过的话,可能需要改程序分块烧(目前uboot FAT不支持分块读文件)。

2.烧录bin到SD卡:

SD启动的bin文件会被分成BL1,BL2两块,移植好的uboot目录下有mkmovi脚本工具可以生成u-boot-movi.bin可供SD_Write.exe烧录;

也可以使用三星提供的IROM_Fusing_Tool工具(网上可以下载到源码,可以自己修改)烧录;

如果没有工具也可以使用WinHex工具直接写SD卡,注意SD ,SDHC写入的偏移不一样,都是写在SD尾部,

卡的块大小可通过IROM code 全局变量globalBlockSizeHide得到,

具体看三星IROM boot文档,这些uboot代码已经写好了;

到此,sd uboot 应该可以跑起来了,注意飞凌256M内存uboot中,include/configs/smdk6410.h文件

改了CFG_ENV_SIZE 的大小需要改回到0x4000,这个值会在include/movi.h中参与BL2地址的计算;

3.SD卡驱动:

cpu/s3c64xx/hs_mmc.c 此驱动文件比较旧,不支持SDHC卡和SD2.0协议,SD/MMC(2G或以下)可以;

需要修改初始化函数hsmmc_init(),

SD2.0初始化卡顺序

SD rest CMD0 -> SD_SEND_IF_COND CMD8 -> 选中SD ...    具体参考移植好的代码,

更详细可以搜索SD2.0协议

SDMA也有问题,它是大块一次读完,我测试当文件大于16M时,读取的数据就不正确了。需要修改movi_read()函数,

改成每次按512Byte字节读,直到把block num读完为止,为什么要这样,我仔细看过datasheet,

原本程序应该也是没有问题,估计三星的SDMA没有做好或有BUG,网上也可以搜到,但不多。

4.uboot1.1.6的FAT文件系统支持:

fs/fat/fat.c 此文件也有BUG,读文件目录时有问题,去uboot官网下载最新代码,

替换fs/fat/fat.c 应该可以直接替换,我是用比较工具替换的;

支持FAT文件系统后,就可以将编译好的u-boot.bin,zImage,rootfs.yaffs2文件直接复制SD卡中(将SD卡格式化为FAT32),

可以使用 fatload mmc 0:1 0x50008000 u-boot.bin ; 首先将文件放到内存,再用 nand.write 命令烧写。

5.支持yaffs2烧录:

加入了nand write.yaffs 命令,这里一定要注意,yaffs文件直接烧录到nand中, kernel是不识别的(根本没有检测到文件数据),

因为yaffs文件是按 PageSize + OOB 格式存储的,OOB是用来识别文件信息的,直接烧录所以找不到文件。

还要注意mkyaffs2image工具生成的pagesize和oob一定要和uboot的对上,否则烧进去,也是白搭。

飞凌用的是K9GAG08U0D_2G 4K pagesize的nand,

需要修改 kernel/fs/yaffs2/utils/ mkyaffs2image.c

#define chunkSize 4096//2048
#define spareSize 128//64

如果使用其它mkyaffs2image.c版本,注意oob格式

关掉内核nand驱动ECC硬件检测

6.烧录uboot:

三星6410从nand启动时,控制器只支持2K pagesize,所以换成4K pagesize nand后,直接烧uboot后,

导致uboot跑不起来,可以将uboot分成每2K分别烧录4K page  size的每页,

可以参考这个牛人的方法:http://bbs.witech.com.cn/archiver/?tid-3743.html

本来想用IROM boot启动nand(直接支持4K Pagesize),

可是bin文件需要ECC校验(其实完全不需要的,nand第1个block是有保证的),否则启动不了,取消ECC也设置不了,

还没有找到写ECC的资料,就没有搞定;

后来还是增加了 nand write.uboot  命令,也是2K一烧,4K 一跳;

修改 commom/cmd_nand.c do_nand() 函数

7.LCD显示支持:

实际生产中,不可能每个工作人员接一台电脑用串口看烧录状态,

加入了 LCD显示烧录状态(6410支持5层windows framebuffer,我用了2层,0层背景,1层OSD同时显示串口打印信息,颜色用的565),

烧录状态显示的图片存放在SD卡中(burnIcon.bin 565 raw data bmp),因为uboot很难存下480*272*2Byte的图片,烧录前nand也没法存图片,

存在SD卡是最好的。

烧录完成蜂呜器响10声。

common/lcd.c 

include/confisg/smdk6410.h 定义  #define CONFIG_LCD

修改void lcd_ctrl_init(void *lcdbase) LCD控制器时序


注意:图片的字节序,我用的565是小端(低字节在前),6410 LCD控制器默认是大端(高字节在前),所以要倒序否则图片显示有些不正常:

S3C_WINCON0 = S3C_WINCONx_BPPMODE_F_16BPP_565 |S3C_WINCONx_HAWSWP_ENABLE;


8.修改开机白屏,默认背光是关闭的,framebuffer写好后,再开背光;

我们修改了LCD电路板(加一个三极管和GPIO控制LT1937 SHDN (PIN4) ,上电时自动拉低,关背光)

图片显示后再开背光(GPIO拉高),主要是防闪,平滑过渡

9.u-boot自动执行烧录命令:

在include/configs/smdk6410.h中修改 CONFIG_BOOTCOMMAND 宏,让u-boot自动执行命令

#define CONFIG_BOOTCOMMAND    "fatload mmc 0:1  0x5FD00000 burnIcon.bin;                  "\
                            "nand scrub       0x00000000 0x00100000;                    "/*u-boot*/\
                            "nand erase       0x00000000 0x00100000;                    "\
                            "fatload mmc 0:1  0x50008000 u-boot.bin;                    "\
                            "nand write.uboot 0x50008000 0x00000000 $filesize;          "\
                            "nand scrub       0x00100000 0x00300000;                    "\
                            "nand erase       0x00100000 0x00300000;                    "\
                            "fatload mmc 0:1  0x50008000 zImage;                        "/*kernel zImage*/\
                            "nand write.e     0x50008000 0x00100000 $filesize;          "\
                            "nand scrub       0x00400000;                               "\
                            "nand erase       0x00400000;                               "\
                            "fatload          mmc 0:1 0x50008000 rootfs.yaffs2;         "/*root filesystem yaffs2*/\
                            "nand write.yaffs 0x50008000 0x00400000 $filesize;          "\
                            "nand ok                                                    "/*beep sound ok*/

0x5FD00000 为背景层windows framebuffer的地址, burnIcon.bin为565 raw data bmp图片,直接丢到framebuffer就可以显示图片了。

注意: $filesize 代表文件的大小,所以文件大小不要超过kernel nand分区表,否则会错误。

飞凌烧cramfs时烧写大小直接写的是32M,所以大于32M时,就容易出错,并且飞凌烧yaffs2还要跑到内核去烧,不实用。


补充:之前版本是按512字节每块读的,现在改为256K每块读,速度从读100M文件需要100秒提升到只需20秒,进5倍提示,

但是我设置成512K每块读,会出现数据丢失现象。

更新代码 cpu/s3c64xx/hs_mmc.c 

void movi_read (uint addr, uint start_blk, uint blknum)
{
    uint dma=0,cmd,multi_blk,i,count,spare;

    /*Enable interrupt*/
    s3c_hsmmc_writew(s3c_hsmmc_readw(HM_NORINTSTSEN) & ~(DMA_STS_INT_EN | BLOCKGAP_EVENT_STS_INT_EN), HM_NORINTSTSEN);
    s3c_hsmmc_writew((HM_NORINTSIGEN & ~(0xffff)) | TRANSFERCOMPLETE_SIG_INT_EN, HM_NORINTSIGEN);

    /*clear interrupt*/
    ClearCommandCompleteStatus();

    ClearDMAStatus();
    ClearTransferCompleteStatus();

    spare = blknum;
    count = ( (blknum * Card_OneBlockSize_ver1) - 1 ) / (Card_OneBlockSize_ver1 * 512) + 1;


    for(i=0;i         while(!check_card_status());

        SetSystemAddressReg(addr);                           //AHB System Address For Write
        addr += Card_OneBlockSize_ver1 * 512;                //256K ++

        set_blksize_register(6,Card_OneBlockSize_ver1);      //Maximum DMA Buffer Size, Block Size
        set_blkcnt_register((spare > 512) ? 512 : spare);    //Block Numbers to read

        /*Card Start Block Address to read*/
        if (movi_hc){
            set_arg_register(start_blk);
        }else{
            set_arg_register(start_blk*Card_OneBlockSize_ver1);
        }

        start_blk += 512;

        dma = 1;
        multi_blk = (spare > 1);
        cmd = multi_blk ? 18 : 17;

        if(spare>512){
            spare -= 512;
        }


        /*CMD17 signle block, CMD18 mutil block read*/
        set_transfer_mode_register(multi_blk,1,1,multi_blk,dma);
        set_cmd_register(cmd,1,MMC_RSP_R1);

        if (wait_for_cmd_done()){
            printf("ERROR: Command NOT Complete\n");
            goto error;
        }

        /*wait for transfer complete*/
        check_dma_int();

error:
        ClearCommandCompleteStatus();

        ClearDMAStatus();
        ClearTransferCompleteStatus();
    }

    return;
}




对于普通的SD卡,我有个2gsd卡,拿它作为例子:

1)使用本站提供的windows工具完全格式化一次你的sd

2)进到ubuntu环境下查看SD卡扇区数量:

zswan@zswan-laptop-ubuntu:~/tmp$ sudo fdisk /dev/sdb1

WARNING: DOS-compatible mode is deprecated. It's strongly recommended to

         switch off the mode (command 'c') and change display units to

         sectors (command 'u').

Command (m for help): p

Disk /dev/sdb1: 2059 MB, 2059278848 bytes

64 heads, 62 sectors/track, 1013 cylinders

Units = cylinders of 3968 * 512 = 2031616 bytes

Sector size (logical/physical): 512 bytes / 512 bytes

I/O size (minimum/optimal): 512 bytes / 512 bytes

Disk identifier: 0x00000000


计算扇区数量:

2059278848/512 = 4022029个扇区,按图1的结构,BL1应该烧写在第4022029-18=4022011个扇区当中。BL2应该烧写在第(4022011-BL2扇区数)的中。

飞凌提供的MMC启动的bin文件,其实就是个支持SD卡的uboot,其结构是这样的:


所以为了一次性烧写方便,MMC.bin其实应该是BL2代码BL2的前8k字节作为BL1的代码。但是由于BL2,BL1是分着烧写的,不大方便,所以干脆在BL2的后面再附上一个BL1的相同代码,这样结合出来的mmc.bin,我只需要把它烧写到:4022029-2-560mmc.bin280k=560个扇区)= 4021467起始的扇区中去,就可以了。

烧写方法:

Ubuntu环境下:

sudo dd of=/dev/sdb1 if=./mmc.bin count=560 seek=4021467

这样就可以了。

SDHC的类同,只是总的扇区数减去(1026+560)才是mmc bin烧写的位置。


(二)
拷贝的过程


BL1被拷贝到8ksteppingstone中这个是硬件就做好了的。但是BL2被拷贝到SDRAM中是BL1中的代码实现的。在BL1中也使用了IROM硬件code定义好了的copyMMCtoMEM函数,直接从MMC中拷贝BL2的代码。


两次拷贝执行完后MMC.BIN作为一个完整的uboot就已经被拷贝到SDRAM中了。


ok6410的开发板上,SDboot主要的作用就是启动mmc.BINuboot去初始化NAND,把保存在sd
中的uboot.bin, zImage拷贝到内存中,然后写进NAND中,是为了从NANDboot做准备的。


实际上是将u-boot.bin内容重复一次后(为了保证达到256K,假如 这个bin更小,那么可能须要 重复3次、4次,直到超过256K 为止),将前256K制成u-boot_256k.bin,再将前8K制成u-boot_8k.bin,结尾 将u-boot_256k.bin +u-boot_8k.bin合并成一个256K+8K大小的文件u-boot_mmc.bin,这个文件前256K就是u-boot_256k.bin 而后8K就是u-boot_8k.bin。把这个u-boot_mmc.bin议决 IROM_Fusing_tools烧写到SD卡就能够 成功启动系统了。

  为什么要做这样的处理这个bin文件呢?下面议决 剖析 IROM_Fusing_tools、uboot的源码来揭示其中的由来。

  从网上能够 下载到IROM_Fusing_tools的源码,在按下这个软件的start控件后,先是读取这个SD卡的第一个扇区,也就是这个硬盘 的MBR 扇区,判断是不是FAT32格式的硬盘 (这也是为什么用来做启动的SD必须格式化为FAT32格式),接着获取总的扇区数目TOTAl_SECOTR,并将所要烧写的bin文件烧写到硬盘 的这个扇区:TOTAL_SECTOR – 2 - SIZE_OF_IMAGE/512。其中TOTAl_SECTOR是这个硬盘 总的扇区数目;SIZE_OF_IMAGE/512是这个bin文件将要占据的扇区数(这里是以512为扇区大小的,因此对于扇区更大的SD卡也就没要领 运用 了,而现在的大容量SD都可能运用 了2K甚至4K的扇区,除非修改这个程序,并同步地在uboot中修改程序);至于2则是保存 的2个扇区,至于为什么要保存 这2个扇区,须要 剖析 uboot的源码情况,下面将做进一步的阐述。

  在SD启动方式下,S3C6410内部的IROM程序BL0最先 运行,并将SD中的结尾 18个扇区开始的16个扇区内容复制到片内的8K SRAM,也就是SteppingStone,接着跳转到这块SRAM的开始地址开始运行,这8K的代码实际上就是上面u-boot_mmc.bin这个文件的结尾 8K,也是u-boot.bin的最开始8K代码,这段代码也叫BL1。从BL0跳转到BL1的时刻 uboot也就接管了CPU。

  Uboot的入口在start.S这个文件,cpu/s3c64x0/start.S中有这样一段代码:

  #ifdef CONFIG_BOOT_MOVINAND

  ldr   sp, _TEXT_PHY_BASE

  bl     movi_bl2_copy

  b     after_copy


#endif

  这段代码是实现SD启动的首要 。到了这里后就执行movi_bl2_copy,这个函数负责将SD内的uboot完整地复制到SDRAM,这时刻 完整的uboot也叫BL2,而这个函数实际上是调用了以下函数:

  CopyMovitoMem(HSMMC_CHANNEL, MOVI_BL2_POS, MOVI_BL2_BLKCNT, (uint *)BL2_BASE, MOVI_INIT_REQUIRED);

  HSMMC_CHANNEL这是SD/MMC通道号,手上板子运用 的是CH1,而默认是CH0,所以须要 对这个实行 修改。

  MOVI_BL2_POS 是须要 拷贝的数据位于SD的起始扇区,其计算要领 是这样的,先得到这个SD的总扇区数TOTAL,再减去256K的BL2和8K的BL1所占的扇区数,结尾 减去0.5K 的eFuse和0.5K的保存 区所占的扇区数,而这里还定义SD的扇区为512B。从这里能够 看到和IROM_Fusing_tools对SD卡的处理是完全对应的。这里还有一个疑问 ,总扇区数TOTAL是如何 得到的?从程序来看是从(TCM_BASE - 0x4)这个地址读取到的,至于TOTAL是如何 被放到这里的就只好 从BL0的代码找答案了。

  MOVI_BL2_BLKCNT是须要 复制的扇区数目,这里就是定义为256K,这也是为什么必须把u-boot.bin转换成256K的文件。

  BL2_BASE是目标 地址,也就是SDRAM中的地址。这里定义为0x57E00000,就是128M 的SDRAM的结尾 2M,因为到这里为止MMU尚未打开,因此这里运用 的是物理地址。

  MOVI_INIT_REQUIRED这个参数的意义是什么暂时没有任何资料表明 。

  而CopyMovitoMem这个函数的定义是这样的:

  #define CopyMovitoMem(a,b,c,d,e)     (((int(*)(int, uint, ushort, uint *, int))(*((uint *)(TCM_BASE + 0x8))))(a,b,c,d,e))

  这个定义实际上是调用了位于TCM_BASE + 0x8这个地址的函数指针,其中TCM_BASE的值为0x0C004000,至于这个地址放的是什么,也没资料表明 。

  当复制完BL2后便会跳转到BL2的start_armboot这个C语言函数中运行了,此后的运行流程 就不须要 再剖析 了。 

你可能感兴趣的:(u-boot)