• (转)关于三星cortex A9 Sate4412 开发板 uboot 启动的一些问题释疑


    说明:本文转载自:http://blog.csdn.net/gooogleman/article/details/17238079 
    作者:gooogleman                   日期:2013.11.27            

    最近,发现4412 和S5PV210的一些iNand/TF启动方式有些不同,4412 的一些磁盘索引不是固定在某一个通道的上的,而S5PV210 是固定的,这就导致一些人在烧写4412 ,分区格式化的时候会莫名其妙,不知所以然,现在看看代码,看是4412 代码到底是为何会这样了。
    首先看从iNand 启动时候uboot打印信息。
    U-Boot 2010.12 (Jul 29 2013 - 10:01:49) for SMDK4412


    CPU: S5PC220 [Samsung SOC on SMP Platform Base on ARM CortexA9]
    APLL = 1200MHz, MPLL = 800MHz
    DRAM:  1023 MiB
    TrustZone Enabled BSP
    BL1 version: 20120711
    OM_STAT=0x00000029
    Checking Boot Mode ... EMMC4.41
    REVISION: 1.1
    NAME: S5P_MSHC4
    MMC Device 0: 7576 MB
    MMC Device 1: 0 MB
    MMC Device 2 not found
    Using default environment


    MMC read: dev # 0, block # 26624, count 1 ... 1 blocks read: OK
    Hit 'a' key to stop autoboot:  0 
    SMDK4412 #
    查找OM_STAT 所在位置
    unsigned int OmPin;
    OmPin = INF_REG3_REG;
            printf("OM_STAT=0x%08x ", *((unsigned int *)(0x10020000)));
            printf("Checking Boot Mode ...");
            if(OmPin == BOOT_ONENAND) {
                    printf(" OneNand ");
            } else if (OmPin == BOOT_NAND) {
                    printf(" NAND ");
            } else if (OmPin == BOOT_MMCSD) {
                    printf(" SDMMC ");
            } else if (OmPin == BOOT_EMMC) {
                    printf(" EMMC4.3 ");
            } else if (OmPin == BOOT_EMMC_4_4) {
                    printf(" EMMC4.41 ");
            }

    查询一下 OmPin 所用到的位置,这个变量的确非常重要,决定了到底烧写哪个存储器(nandflash ,还是mmc,还是iNand.........等等)


    common/cmd_fastboot.c:extern unsigned int OmPin;
    common/cmd_fastboot.c:                        if (OmPin == BOOT_MMCSD) {
    common/cmd_fastboot.c:                        } else if (OmPin == BOOT_EMMC_4_4 || OmPin == BOOT_EMMC) {
    common/cmd_fastboot.c:                        } else if (OmPin == BOOT_ONENAND) {
    common/cmd_fastboot.c:                        if (OmPin == BOOT_MMCSD) {
    common/cmd_fastboot.c:                        } else if(OmPin == BOOT_EMMC_4_4 || OmPin == BOOT_EMMC) {
    common/cmd_fastboot.c:                        else if(OmPin == BOOT_ONENAND) {
    common/cmd_fastboot.c:....                                if (OmPin == BOOT_ONENAND) {
    common/cmd_fastboot.c:                                } else if (OmPin == BOOT_MMCSD) {
    common/cmd_fastboot.c:                                } else if (OmPin == BOOT_EMMC_4_4 || OmPin == BOOT_EMMC) {
    common/cmd_fastboot.c:                                if (OmPin == BOOT_ONENAND) {
    common/cmd_fastboot.c:                                } else if (OmPin == BOOT_MMCSD) {
    common/cmd_fastboot.c:                                } else if (OmPin == BOOT_EMMC_4_4 || OmPin == BOOT_EMMC) {
    common/cmd_fastboot.c:                                        if (OmPin == BOOT_ONENAND) {
    common/cmd_fastboot.c:                                        } else if (OmPin == BOOT_MMCSD) {
    common/cmd_fastboot.c:                                        } else if (OmPin == BOOT_EMMC_4_4 || OmPin == BOOT_EMMC) {
    common/cmd_fastboot.c:        switch(OmPin) {
    common/cmd_fastboot.c:        switch(OmPin) {
    drivers/mmc/s5p_mshc.c:extern unsigned int OmPin;
    drivers/mmc/s5p_mshc.c:        if (OmPin == BOOT_EMMC_4_4 || OmPin == BOOT_EMMC) {

    从上面的代码看,我以前写的Sate4412 开发板镜像烧写方法似乎是错误的,但是...........那个步骤是我一边烧写一边写的,的的确确是能够烧写成功启动的,why?
    我觉得其中程序必有一些暗藏的东西,继续找找......




    #if defined(CFG_FASTBOOT_SDMMCBSP)
    #if defined(CONFIG_S5P6450) && !defined(CONFIG_EMMC_4_4)
    #define        DEV_NUM 1
    #else
    #define        DEV_NUM 0
    #endif
    static int write_to_ptn_sdmmc(struct fastboot_ptentry *ptn, unsigned int addr, unsigned int size)
    {

       .......

    /* use the partition name that can be understood by a command, movi */
                    if (!strcmp(ptn->name, "bl_uboot"))
                    {
                            strncpy(part, "bl_uboot", 10);
                            sprintf(run_cmd,"emmc open 0");
                            run_command(run_cmd, 0);
                    }

    ..............................

    if (INF_REG3_REG == 7 && (!strcmp(ptn->name, "bl_uboot"))){
                            sprintf(run_cmd,"emmc close 0");
                            run_command(run_cmd, 0);
    }

    前面看到了吧INF_REG3_REG 这个不是OM 的寄存器啊,只是在启动阶段读OM寄存器,然后存到INF_REG3_REG,也够恶心的。这里居然不用OM,直接用这个,用意何在?!INF_REG3_REG == 7 这个值正是OM为 EMMC4.4 时候的值(INF_REG3_REG不是OM寄存器的值,只是一个强制的赋值,所以不要混淆,不是Sate4412 开发板TF 小卡启动的配置),这里判断到是iNand启动,烧写完毕镜像那么就关闭了emmc?
    所以一般人找不到,总以为OM是在开机时候读一次就没再改过了.........囧!

    这个INF_REG3_REG 只是被系统用来存放OM设置值而已.请看lowlevel_init.S中的read_om函数, 
            ldr        r0, =S5PV310_POWER_BASE
            ldr        r1, [r0,#OMR_OFFSET]
            bic        r2, r1, #0xffffffc1
    这个就是读取OM设置pin状态,并写入r2.
            /* SD/MMC BOOT */
            cmp     r2, #0x4
            moveq   r3, #BOOT_MMCSD

            /* eMMC BOOT */
            cmp        r2, #0x6
            moveq        r3, #BOOT_EMMC

            /* eMMC 4.4 BOOT */
            cmp        r2, #0x8
            moveq        r3, #BOOT_EMMC_4_4
            cmp        r2, #0x28
            moveq        r3, #BOOT_EMMC_4_4
    上面就是根据r2值,记入相应的启动方式到r3
            ldr        r0, =INF_REG_BASE
            str        r3, [r0, #INF_REG3_OFFSET]
            mov        pc, lr
    上面就是将存放在r3中的OM设置值存入INF_REG3_REG.

    INF_REG3_REG 这个也太扯了吧,本身就有OM_STAT 寄存器的,为啥这么搞,其实可以随时对OM_STAT  来判断的。
    上面的INF_REG3_REG 这个不是OM 的寄存器啊,只是在启动阶段读OM寄存器,然后存到INF_REG3_REG,也够恶心的。这里居然不用OM,直接用这个,用意何在?!INF_REG3_REG == 7 这个值正是OM为 EMMC4.4 时候的值(INF_REG3_REG不是OM寄存器的值,只是一个强制的赋值,所以不要混淆,不是Sate4412 开发板TF 小卡启动的配置),这里判断到是iNand启动,烧写完毕镜像那么就关闭了emmc?
    去看看emmc close 命令的代码,发现有一些注释,就是要求镜像烧写完毕以后,需要关闭这个成功烧写的emmc,难道不关闭会被刷掉吗?

    int do_emmc(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
    {
            int rc = 0;
            u32 dev;

            switch (argc) {
            case 5:
                    if (strcmp(argv[1], "partition") == 0) {
                            dev = simple_strtoul(argv[2], NULL, 10);
                            struct mmc *mmc = find_mmc_device(dev);
                            u32 bootsize = simple_strtoul(argv[3], NULL, 10);
                            u32 rpmbsize = simple_strtoul(argv[4], NULL, 10);

                            if (!mmc)
                                    rc = 1;

                            rc = emmc_boot_partition_size_change(mmc, bootsize, rpmbsize);
                            if (rc == 0) {
                                    printf("eMMC boot partition Size is %d MB.!! ", bootsize);
                                    printf("eMMC RPMB partition Size is %d MB.!! ", rpmbsize);
                            } else {
                                    printf("eMMC boot partition Size change Failed.!! ");
                            }
                    } else {
                            printf("Usage: %s ", cmdtp->usage);
                            rc =1;
                    }
                    break;

            case 3:
                    if (strcmp(argv[1], "open") == 0) {
                            int dev = simple_strtoul(argv[2], NULL, 10);
                            struct mmc *mmc = find_mmc_device(dev);

                            if (!mmc)
                                    rc = 1;

                            rc = emmc_boot_open(mmc);

                            if (rc == 0) {
                            printf("eMMC OPEN Success.!! ");
                            printf(" !!!Notice!!! ");
                            printf("!You must close eMMC boot Partition after all image writing! ");
                            printf("!eMMC boot partition has continuity at image writing time.! ");
                            printf("!So, Do not close boot partition, Before, all images is written.! ");
                            } else {
                                    printf("eMMC OPEN Failed.!! ");
                            }
                    } else if (strcmp(argv[1], "close") == 0) {
                            int dev = simple_strtoul(argv[2], NULL, 10);
                            struct mmc *mmc = find_mmc_device(dev);

                            if (!mmc)
                                    rc = 1;

                            rc = emmc_boot_close(mmc);

                            if (rc == 0) {
                                    printf("eMMC CLOSE Success.!! ");
                            } else {
                                    printf("eMMC CLOSE Failed.!! ");
                            }
                    } else {
                            printf("Usage: %s ", cmdtp->usage);
                            rc =1;
                    }
                    break;
            case 0:
            case 1:                
            case 2:
            case 4:
            default:
                    printf("Usage: %s ", cmdtp->usage);
                    rc = 1;
                    break;
            }
            
            return rc;
    }


    注意这里emmc 的关闭不是指电源关闭,而是关闭了一些功能

    int emmc_boot_open(struct mmc *mmc)


    {
            int err;
            struct mmc_cmd cmd;

            /* Boot ack enable, boot partition enable , boot partition access */
            cmd.cmdidx = MMC_CMD_SWITCH;
            cmd.resp_type = MMC_RSP_R1b;
            cmd.cmdarg = ((3<<24)|(179<<16)|(((1<<6)|(1<<3)|(1<<0))<<8));
            cmd.flags = 0;

            err = mmc_send_cmd(mmc, &cmd, NULL);
            if (err)
                    return err;

            /* 4bit transfer mode at booting time. */
            cmd.cmdidx = MMC_CMD_SWITCH;
            cmd.resp_type = MMC_RSP_R1b;
            cmd.cmdarg = ((3<<24)|(177<<16)|((1<<0)<<8));
            cmd.flags = 0;

            err = mmc_send_cmd(mmc, &cmd, NULL);
            if (err)
                    return err;

            return 0;
    }

    int emmc_boot_close(struct mmc *mmc)
    {
            int err;
            struct mmc_cmd cmd;

            /* Boot ack enable, boot partition enable , boot partition access */
            cmd.cmdidx = MMC_CMD_SWITCH;
            cmd.resp_type = MMC_RSP_R1b;
            cmd.cmdarg = ((3<<24)|(179<<16)|(((1<<6)|(1<<3)|(0<<0))<<8));
            cmd.flags = 0;

            err = mmc_send_cmd(mmc, &cmd, NULL);
            if (err)
                    return err;

            return 0;
    }
    上面可以知道,有一个判断,判断是iNand启动烧写后 才关闭了mmc ,但是TF 卡却没有,这个就是OM 在TF 烧写模式下,TF 烧写完毕会连bootloader 都会被冲掉的原因。囧。S5pv210 没有这个现象,难道这个是4412 有什么特殊的原因要这么样的?三星不可能会这么混的啊。

    INF_REG3_REG  应该是这个 ,就是Base Address: 0x1002_0000 +0x080C
    INFORM3  0x080C  Information register 3  0x0000_0000

    比较奇怪, 0x1002_0000 本身就是OM 寄存器地址但是却转存到INFORM3  ,再看看,三星不可能绕一大圈来做这个无谓的事情。

    ——这个里面有笔误,上面应该改成如下就可以了。
    先把薄码开关拨到MMC2启动,即OM[5:1] 为b'00010,把启动TF卡插入MMC2,上电启动,进入uboot命令行模式后执行命令:
    mmc erase boot 1 0 1024 (当从mmc2 TF卡启动时i,TF卡设备索引号是0,而nand 设备索引号应该是1)
    即可擦除iNand uboot分区最前面的引导部分。注意,不要此时烧写uboot,此时烧写会把uboot烧写到TF卡上而不是INAND上。接着断电,薄码开关调回INAND启动,即OM[5:1] B'10100,上电就会检查iNand,但是iNand 没有uboot启动代码,所以就会自动切换到TF卡启动,但是此时的OM值是iNand 模式的,所以iNand 设备索引值是0,而mmc2 TF卡是1,所以能够正常用fdisk -c 0 ,ext3format mmc 0:1 等分区命令进行烧写。这时就可以烧写uboot到inand上了。整个过程终于明白了,今天主要看了Sate4412 的uboot代码,并且举一反三,终于明白4412 烧写是怎么回事。终于清静了......

    intdo_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
    {
             int rc = 0;
             int part = 0;

             switch (argc) {
             case 3:
                       if (strcmp(argv[1],"rescan") == 0) {
                                int dev =simple_strtoul(argv[2], NULL, 10);
                                struct mmc *mmc =find_mmc_device(dev);

                                if (!mmc)
                                         return 1;

                                mmc_init(mmc);

                                return 0;
                       }

             case 0:
             case 1:
             case 4:
                       printf("Usage: %s ",cmdtp->usage);
                       return 1;

             case 2:
                       if (!strcmp(argv[1],"list")) {
                                print_mmc_devices(' ');
                                return 0;
                       }
                       return 1;
             case 6:
                       if (strcmp(argv[1],"erase") == 0) {
                                /* Read inputvariable */
                                int dev =simple_strtoul(argv[3], NULL, 10);
                                u32 start =simple_strtoul(argv[4], NULL, 10);
                                u32 block =simple_strtoul(argv[5], NULL, 10);

                                struct mmc *mmc =find_mmc_device(dev);

                                if (!mmc)
                                         return 1;

                                u32 count = 0;

                                /* Select erasepartition */
                                if (strcmp(argv[2],"boot") == 0) {
                                         part = 0;
                                         /* ReadBoot partition size. */
                                         count =((mmc->ext_csd.boot_size_multi)*256);
                                } else if(strcmp(argv[2], "user") == 0) {
                                         part = 1;
                                         /* ReadUser partition size. */
                                         count =mmc->capacity;
                                } else {
                                         part = 1;
                                         count =mmc->capacity;
                                         printf("Defaulterase user partition ");
                                }

                                /* If input counteris larger than max counter */
                                if ((start + block)> count) {
                                         block =(count - start) - 1;
                                         printf("Blockcount is Too BIG!! ");
                                }

                                /* If input counteris 0 */
                                if (!block ) {
                                         block =(count - start) - 1;
                                         printf("Eraseall from %d block ", start);
                                }

                                rc = mmc_erase(mmc,part, start, block);

                                if (rc == 0) {
                                         printf("MMCerase Success.!! ");
                                } else {
                                         printf("MMCerase Failed.!! ");
                                         return -1;
                                }
                                return 0;
                       } else if (strcmp(argv[1],"read") == 0) {
                                int dev =simple_strtoul(argv[2], NULL, 10);
                                void *addr = (void*)simple_strtoul(argv[3], NULL, 16);
                                u32 cnt =simple_strtoul(argv[5], NULL, 10);
                                u32 n;
                                u32 blk =simple_strtoul(argv[4], NULL, 10);
                                u32 read_cnt;
                                u32 cnt_to_read;
                                void *addr_to_read =addr;
                                struct mmc *mmc =find_mmc_device(dev);

                                if (!mmc)
                                         return 1;

                                printf(" MMCread: dev # %d, block # %d, count %d ... ",
                                         dev, blk,cnt);

                                n = 0;
                                addr_to_read = addr;
                                do {
                                         if (cnt - n> MAXIMUM_BLOCK_COUNT)
                                                   cnt_to_read= MAXIMUM_BLOCK_COUNT;
                                         else
                                                   cnt_to_read= cnt - n;

                                         read_cnt =mmc->block_dev.block_read(dev, blk, cnt_to_read, addr_to_read);
                                         n +=read_cnt;
                                         blk +=read_cnt;
                                         addr_to_read+= read_cnt * 512;
                                         if(cnt_to_read!= read_cnt) {
                                                   printf("%dblocks read: %s ",
                                                            n,"ERROR");
                                                   return-1;
                                         }
                                } while(cnt > n);

                                /* flush cache afterread */
                                flush_cache((ulong)addr,cnt * 512); /* FIXME */

                                printf("%dblocks read: %s ",
                                         n, (n==cnt)? "OK" : "ERROR");
                                return (n == cnt) ?0 : 1;
                       } else if (strcmp(argv[1],"write") == 0) {
                                int dev =simple_strtoul(argv[2], NULL, 10);
                                void *addr = (void*)simple_strtoul(argv[3], NULL, 16);
                                u32 cnt =simple_strtoul(argv[5], NULL, 10);
                                int blk =simple_strtoul(argv[4], NULL, 10);
                                u32 n;
                                u32 written_cnt;
                                u32 cnt_to_write;
                                void *addr_to_write= addr;
                                struct mmc *mmc =find_mmc_device(dev);


                                if (!mmc)
                                         return 1;

                                printf(" MMCwrite: dev # %d, block # %d, count %d ... ",
                                         dev, blk,cnt);

                                n = 0;
                                addr_to_write =addr;
                                do {
                                         if (cnt - n> MAXIMUM_BLOCK_COUNT)
                                                   cnt_to_write= MAXIMUM_BLOCK_COUNT;
                                         else
                                                   cnt_to_write= cnt - n;

                                         written_cnt= mmc->block_dev.block_write(dev, blk, cnt_to_write, addr_to_write);
                                         n +=written_cnt;
                                         blk +=written_cnt;
                                         addr_to_write+= written_cnt * 512;
                                         if(cnt_to_write!= written_cnt) {
                                                   printf("%dblocks written: %s ",
                                                            n,"ERROR");
                                                   return-1;
                                         }
                                } while(cnt > n);

                                printf("%dblocks written: %s ",
                                         n, (n ==cnt) ? "OK" : "ERROR");
                                return (n == cnt) ?0 : 1;
                       } else {
                                printf("Usage: %s ",cmdtp->usage);
                                rc = 1;
                       }

                       return rc;
             default: /* at least 5 args */
                       printf("Usage: %s ",cmdtp->usage);
                       return 1;
             }
    }
     
    晚上搞定这个事情先。
    iNand启动时候
    SKD4X12 # mmc list
    S5P_MSHC4: 0
    S3C_HSMMC2: 1
    SKD4X12 # 

    不关机切换成
    SD/TF MM2 启动的时候一样
    SKD4X12 # mmc list
    S5P_MSHC4: 0
    S3C_HSMMC2: 1
    SKD4X12 # 
    SKD4X12 # mmc list
    S5P_MSHC4: 0
    S3C_HSMMC2: 1
    fdisk -c 0 分区仍然是给iNand 分的区
    SKD4X12 # fdisk -c 0
    NAME: S5P_MSHC4
    fdisk is completed

    partion #    size(MB)     block start #    block count    partition_Id 
       1           500           102400         1024000          0x83 
       2           150          1126400          307200          0x83 
       3          6876          1433600        14082048          0x83 
    SKD4X12 # 

    设置SD/TF MM2 启动,关机,重启
    发现变了。索引号 mmc2 和inand 颠倒了位置所以对应分区命令也跟着变了。
    SMDK4412 # mmc list
    S3C_HSMMC2: 0
    S5P_MSHC4: 1
    SMDK4412 # 
    SMDK4412 # fdisk -c 0
    fdisk is completed

    partion #    size(MB)     block start #    block count    partition_Id 
       1           500            67584         1024000          0x83 
       2           150          1091584          307200          0x83 
       3          6777          1398784        13879296          0x83 
    SMDK4412 # fdisk -c 1
    NAME: S5P_MSHC4
    fdisk is completed

    partion #    size(MB)     block start #    block count    partition_Id 
       1           500            67584         1024000          0x83 
       2           150          1091584          307200          0x83 
       3          6893          1398784        14116864          0x83 
    SMDK4412 #

    ,昨晚我看了一下,这个主要还是uboot代码里面他自己这么做了,这样做也没什么不好,或者这样做有他的好处,就是他可以自由选择从mmc2 还是iNand 通道启动系统应该都没问题,不过内核那些要匹配一下。

    现在Sate4412 开发板用户手册已经升级更改,需要参考的广大网友和Sate4412 用户请到如下地址下载

    http://download.csdn.net/detail/gooogleman/6688457

     
  • 相关阅读:
    localStorage
    node开发 npm install -g express-generator@4
    Vue 爬坑之路(一)—— 使用 vue-cli 搭建项目
    WebSocket 教程
    解决Git报错:error: You have not concluded your merge (MERGE_HEAD exists).
    ThinkPHP5 支付宝 电脑与手机支付扩展库
    apache中通过mod_rewrite实现伪静态页面的方法
    一个PHP文件搞定微信H5支付
    Windows下安装Redis及php的redis拓展教程
    GIT 常用命令
  • 原文地址:https://www.cnblogs.com/lihaiping/p/boot.html
Copyright © 2020-2023  润新知