天嵌 ARM开发社区

 找回密码
 注册
查看: 24515|回复: 33

u-boot-2010.03在tq6410上的移植详解(连载)

[复制链接]
freewing 发表于 2010-9-26 16:57:02 | 显示全部楼层 |阅读模式
原创文章版权所有!如需转载,请注明出处: http://hi.baidu.com/liushuiyue1/myhome谢谢合作!!!!!

由于Uboot2010.03对S3C6410有了很好的支持,所以采用Uboot2010.03版本。

一、             移植环境

主 机:VMWare--Fedora 8

开发板:天嵌TQ6410—256M nandflash,Kernel:2.6.30.4

编译器:EABI-4.3.3_V0.1

u-boot:u-boot-2010.08

二、       源码获得

              Uboot源码到:ftp://ftp.denx.de/pub/u-boot/下载

三、     本次移植的功能实现

· 支持Nand Flash读写

· 支持从Nand Flash/SD启动(SD卡启动只在uboot1.1.6中完成)

· 支持CS8900或者DM9000网卡

· 支持Yaffs文件系统

· 支持USB下载

四、     移植步骤

              1. 建立自己的开发板项目并测试编译

目前u-boot对很多CPU直接支持,可以查看board目录的一些子目录,如:board/samsung/目录下就是对三星一些ARM处理器的支持,有smdk2400、smdk2410和smdk6400,但没有6410,所以我们就在这里建立自己的开发板项目。

1)因6410和6400的资源差不多,主频和外设有点差别,所以我们就在board/samsung/下建立自己开发板的项目,取名叫my2440

#tar -jxvf u-boot-2010.03.tar.bz2    //解压源码
#cd u-boot-2010.03/board/samsung/    //进入目录
#mkdir smdk6410                        //创建smkd6410文件夹



2)因6410和6400的资源差不多,所以就以6400项目的代码作为模板,以后再修改

#cp -rf smdk6400/* smdk6410/   //将6400下所有的代码复制到6410下

#cd smdk6410                   //进入smdk6410目录

#mv smdk6400.c my6410.c      //将smdk6410下的smdk6400.c改名为smdk6410.c

#cd ../../../                //回到u-boot根目录
#cp include/configs/smdk6400.h include/configs/smdk6410.h //建立6410配置头文件

评分

参与人数 4 +13 收起 理由
Fighting + 1 赞一个!
天使之翼 + 1 赞一个!
春夏秋冬 + 10 谢谢
灰太狼 + 1

查看全部评分

 楼主| freewing 发表于 2010-9-26 17:00:46 | 显示全部楼层
(二)
3)修改u-boot跟目录下的Makefile文件。查找到smdk6400_config的地方,在他下面按照smdk6400_config的格式建立smdk6410_config的编译选项,另外还要指定交叉编译器

#gedit Makefile




CROSS_COMPILE ?= arm-linux-        //指定交叉编译器为arm-linux-gcc

smdk6410_noUSB_config \

smdk6410_config      :      unconfig

      @mkdir -p $(obj)include $(obj)board/samsung/smdk6410

      @mkdir -p $(obj)nand_spl/board/samsung/smdk6410

      @echo "#define CONFIG_NAND_U_BOOT" > $(obj)include/config.h

      @if [ -z "$(findstring smdk6410_noUSB_config,$@)" ]; then                   \

             echo "RAM_TEXT = 0x57e00000" >> $(obj)board/samsung/smdk6410/config.tmp;\

             $(MKCONFIG) $(@:_config=) arm arm1176 smdk6410 samsung s3c64xx;            \

      else                                                                \

             echo "RAM_TEXT = 0xc7e00000" >> $(obj)board/samsung/smdk6410/config.tmp;\

             $(MKCONFIG) $(@:_noUSB_config=) arm arm1176 smdk6410 samsung s3c64xx;       \

      fi

      @echo "CONFIG_NAND_U_BOOT = y" >> $(obj)include/config.mk

*说明:arm    :CPU的架构(ARCH)

       arm1176:CPU的类型

       smdk6410 :对应在board目录下建立新的开发板项目的目录

       samsung:新开发板项目目录的上级目录,如直接在board下建立新的开发板项目的目录,则这里就为NULL

       s3c64xx:CPU型号

*注意:编译选项格式的第二行要用Tab键开始,否则编译会出错



4)进入顶层目录nand_spl/board/samsung目录新建目录smdk6410,并将smdk6400下的文件复制到刚刚新建的smdk6410下

#cd nand_spl/board/samsung //

#cp –ar smdk6400/* smdk6410/




5)测试编译新建的smdk6410开发板项目

#make smdk6410_config //如果出现Configuring for smdk6410 board...则表示设置正确

#make //编译后在根目录下会出现u-boot.bin和u-boot-nand.bin文件,则u-boot移植的第一步就算完成了



由于此版本的u-boot对于串口和时钟在开始配置文件中就已经初始化,对于ARM1176有很好的支持,利用从SD卡启动的uboot将u-boot-nand.bin下载到nand flash中,同时将开发板上SW2设置到从Nand flash启动位置。利用SecureCRT.exe软件观察串口打印信息如下:


可以看到移植在tq6410上移植uboot已经成功。可是Nor flash是2M可是信息上显示为0,是因为没有添加Nor flash的驱动引起的,而且开发板上自带的是DM9000AE的100M网卡,而uboot默认支持CS8900所以开始添加uboot的相关功能。

移植是采用SD烧写nand flash的uboot,为了方便烧写和调试首先移植网卡实现tftp下载。
 楼主| freewing 发表于 2010-9-26 17:15:17 | 显示全部楼层
(三)
五、             DM9000在Uboot2010.03上的移植

1)首先进入include/configs/修改smdk6410.h文件,屏蔽CS8900的相关宏定义同时添加DM9000AE的相关宏

#cd include/configs///

#gedit smdk6410.h //

smdk6410.h修改内容如下:

#define CONFIG_NET_MULTI           1

//#define CONFIG_CS8900                  /* we have a CS8900 on-board */

//#define CONFIG_CS8900_BASE           0x18800300

//#define CONFIG_CS8900_BUS16           /* follow the Linux driver    */



#define CONFIG_DRIVER_DM9000          1/* we have a DM9000AE on-board      */

#define CONFIG_DM9000_BASE              0x18000300

#define DM9000_IO               CONFIG_DM9000_BASE

#define DM9000_DATA                (CONFIG_DM9000_BASE + 4)

#define CONFIG_DM9000_USE_16BIT


#define CONFIG_ETHADDR        10:23:45:67:89:ab

#define CONFIG_NETMASK              255.255.255.0

#define CONFIG_IPADDR            192.168.174.2 //开发板上的ip地址

#define CONFIG_SERVERIP        192.168.174.1//虚拟机上的ip地址

#define CONFIG_GATEWAYIP   192.168.174.6

#define CONFIG_DM9000_DEBUG//一定要加上否则会出现没有设置ipaddr的现象

2)修改net/eth.c,添加DM9000AE的初始化函数(红色部分为修改的地方):

int eth_initialize(bd_t *bis)

{

      unsigned char env_enetaddr[6];

      int eth_number = 0;


      eth_devices = NULL;

      eth_current = NULL;


      show_boot_progress (64);

#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)

      miiphy_init();

#endif

      /* Try board-specific initialization first. If it fails or isn't

       * present, try the cpu-specific initialization */

      if (board_eth_init(bis) < 0)

             cpu_eth_init(bis);


#if defined(CONFIG_DB64360) || defined(CONFIG_CPCI750)

      mv6436x_eth_initialize(bis);

#endif

#if defined(CONFIG_DB64460) || defined(CONFIG_P3Mx)

      mv6446x_eth_initialize(bis);

#endif

#if defined(CONFIG_DRIVER_DM9000)

      dm9000_initialize(bis);

#endif

      if (!eth_devices) {

             puts ("No ethernet found.\n");

             show_boot_progress (-64);

      } else {

             struct eth_device *dev = eth_devices;

             char *ethprime = getenv ("ethprime");


             show_boot_progress (65);

             do {

                    if (eth_number)

                           puts (", ");


                    printf("%s", dev->name);


                    if (ethprime && strcmp (dev->name, ethprime) == 0) {

                           eth_current = dev;

                           puts (" [PRIME]");

                    }


                    eth_getenv_enetaddr_by_index(eth_number, env_enetaddr);


                    if (memcmp(env_enetaddr, "\0\0\0\0\0\0", 6)) {

                           if (memcmp(dev->enetaddr, "\0\0\0\0\0\0", 6) &&

                               memcmp(dev->enetaddr, env_enetaddr, 6))

                           {

                                  printf ("\nWarning: %s MAC addresses don't match:\n",

                                         dev->name);

                                  printf ("Address in SROM is         %pM\n",

                                         dev->enetaddr);

                                  printf ("Address in environment is %pM\n",

                                         env_enetaddr);

                           }


                           memcpy(dev->enetaddr, env_enetaddr, 6);

                    }


                    eth_number++;

                    dev = dev->next;

             } while(dev != eth_devices);

重新编译uboot,并下载uboot到nand flash中,重新启动开发板,观察打印信息如下,可以发现uboot已经能识别DM9000芯片:


使用ping指令进行测试如下:



至此,uboot已经能支持dm9000的网卡,可以使用tftp协议下载程序并在ram中运行了。
 楼主| freewing 发表于 2010-9-26 17:35:50 | 显示全部楼层
(五)
原创文章版权所有!如需转载,请注明出处: http://hi.baidu.com/liushuiyue1/myhome谢谢合作!!!!!

七.Uboot支持yaffs2文件的读写

       由于Uboot本身支持yaffs2文件的读写直接修改./include/configs/smdk6410.h的配置文件,使得uboot支持yaffs2的读写,重新编译Uboot并下载到Nand Flash中,串口打印信息如下,uboot已经支持yaffs2烧写到nand flash(由于本人对于此uboot中指令不熟悉,所以至今还未写yaffs2文件成功,如有知道的可告知,谢谢)。

于是又重新手动yaffs2文件的烧写指令。首先修改./include/configs/smdk6410.h

#cd include/configs/smdk6410.h//

#define CONFIG_YAFFS2



于是又重新手动yaffs2文件的烧写指令。

1)       修改./include/configs/smdk6410.h

注意一定要屏蔽掉CONFIG_YAFFS2,否则yaffs文件读写有冲突。

#cd include/configs/smdk6410.h//

//#define CONFIG_YAFFS2

#define CONFIG_SYS_NAND_YAFFS_WRITE     1 /* support yaffs write    EN       */

#define CONFIG_MTD_NAND_ECC_YAFFS 1


2)修改common/cmd_nand.c

在373行,红色字体为添加部分

if (!s || !strcmp(s, ".jffs2") ||

                 !strcmp(s, ".e") || !strcmp(s, ".i")) {

                    if (read)

                           ret = nand_read_skip_bad(nand, off, &size,

                                                (u_char *)addr);

                    else

                           ret = nand_write_skip_bad(nand, off, &size,

                                                (u_char *)addr);

             }

              #if defined(ENABLE_CMD_NAND_YAFFS)

              }else if ( s != NULL &&

                     (!strcmp(s, ".yaffs") || !strcmp(s, ".yaffs1"))){

                         if(read) {

                            printf("nand read.yaffs[1] is not provide temporarily!");

                         } else    {

                            nand->rw_oob = 1;

#if defined(ENABLE_CMD_NAND_YAFFS_SKIPFB)

                            nand->skipfirstblk = 1;

#else

                            nand->skipfirstblk = 0;

#endif

                            ret = nand_write_skip_bad(nand,off,&size,(u_char *)addr);

#if defined(ENABLE_CMD_NAND_YAFFS_SKIPFB)

                            nand->skipfirstblk = 0;

#endif

                            nand->rw_oob = 0;

                         }

#endif

}            

             else if (!strcmp(s, ".oob")) {

                    /* out-of-band data */

                    mtd_oob_ops_t ops = {

                           .oobbuf = (u8 *)addr,

                           .ooblen = size,

                           .mode = MTD_OOB_RAW

                    };

在505行添加,红色字体为添加部分

"nand erase [clean] [off size] - erase 'size' bytes from\n"

      "    offset 'off' (entire device if not specified)\n"

      #if defined(CONFIG_SYS_NAND_YAFFS_WRITE)

      "nand read[.yaffs[1]] is not provide temporarily\n"

      "nand write[.yaffs[1]] addr off size -write the 'size' byte yaffs image starting\n"

      "at offset 'off' from memory address 'addr' (.yaffs for 512+16 Nand)"

      #endif

      "nand bad - show bad blocks\n"
 楼主| freewing 发表于 2010-9-26 17:41:30 | 显示全部楼层
(六)
原创文章版权所有!如需转载,请注明出处: http://hi.baidu.com/liushuiyue1/myhome谢谢合作!!!!!

3)drivers/mtd/nand/nand_base.c

在2095行处红色字体为修改部分:

static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,

                    size_t *retlen, const uint8_t *buf)

{

      struct nand_chip *chip = mtd->priv;

      int ret;


      #if defined(CONFIG_SYS_NAND_YAFFS_WRITE)

             int oldopsmode = 0;

             if(mtd->rw_oob==1)

             {

                    size_t oobsize =mtd->oobsize;   

                    size_t datasize = mtd->writesize;

                    int i=0;

                    uint8_t oobtemp[oobsize];

                    int datapages = 0;

                    datapages = len/(datasize);

                    for(i=0;i<(datapages);i++)

                    {

                           memcpy((void *)oobtemp,(void *)(buf+datasize*(i+1)),oobsize);

                           memmove((void *)(buf+datasize*(i+1)),(void *)(buf+datasize*(i+1)+oobsize),(datapages-(i+1))*(datasize)+(datapages-1)*oobsize);

                           memcpy((void *)(buf+(datapages)*(datasize+oobsize)-oobsize),(void *)(oobtemp),oobsize);

                    }

             }

      #endif


      /* Do not allow reads past end of device */

      if ((to + len) > mtd->size)

             return -EINVAL;

      if (!len)

             return 0;

      nand_get_device(chip, mtd, FL_WRITING);

      chip->ops.len = len;

      chip->ops.datbuf = (uint8_t *)buf;

      #if !defined(CONFIG_SYS_NAND_YAFFS_WRITE)

      chip->ops.oobbuf = NULL;

      #endif

      #if defined(CONFIG_SYS_NAND_YAFFS_WRITE)

             if(mtd->rw_oob!=1)

             {

                    chip->ops.oobbuf = NULL;

             }

             else

             {

                    chip->ops.oobbuf = (uint8_t*)(buf+len);

                    chip->ops.ooblen = mtd->oobsize;

                    oldopsmode = chip->ops.mode;

                    chip->ops.mode = MTD_OOB_RAW;

             }     

      #endif

      ret = nand_do_write_ops(mtd, to, &chip->ops);


      *retlen = chip->ops.retlen;


      nand_release_device(mtd);

      #if defined(CONFIG_SYS_NAND_YAFFS_WRITE)

             chip->ops.mode = oldopsmode;      

      #endif


      return ret;

}
 楼主| freewing 发表于 2010-9-26 17:46:29 | 显示全部楼层
(7)
原创文章版权所有!如需转载,请注明出处: http://hi.baidu.com/liushuiyue1/myhome谢谢合作!!!!!

4)修改drivers/mtd/nand/nand_util.c

int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,

                    u_char *buffer)

{

      int rval;

      size_t left_to_write = *length;

      size_t len_incl_bad;

      u_char *p_buffer = buffer;

      

      #if defined(CONFIG_SYS_NAND_YAFFS_WRITE)

             if(nand->rw_oob==1)

             {

             size_t oobsize=nand->oobsize;

             size_t datasize = nand->writesize;

             int datapages = 0;


             if(((*length)%(nand->oobsize+nand->writesize))!=0)

             {

                    printf("Attempt to write error lenght data!\n");

                    return -EINVAL;

             }

             datapages = *length/(datasize+oobsize);

             *length = datapages*datasize;

             left_to_write = *length;

             }

      #endif

     ........


      len_incl_bad = get_len_incl_bad (nand, offset, *length);


      if ((offset + len_incl_bad) > nand->size) {

             printf ("Attempt to write outside the flash area\n");

             return -EINVAL;

      }

      

      #if !defined(CONFIG_SYS_NAND_YAFFS_WRITE)

      if (len_incl_bad == *length) {

             rval = nand_write (nand, offset, length, buffer);

             if (rval != 0)

                    printf ("NAND write to offset %llx failed %d\n",

                           offset, rval);


             return rval;

      }

      #endif


      while (left_to_write > 0) {

             size_t block_offset = offset & (nand->erasesize - 1);

             size_t write_size;


             WATCHDOG_RESET ();


             if (nand_block_isbad (nand, offset & ~(nand->erasesize - 1))) {

                    printf ("Skip bad block 0x%08llx\n",

                           offset & ~(nand->erasesize - 1));

                    offset += nand->erasesize - block_offset;

                    continue;

             }

             #if defined(CONFIG_SYS_NAND_YAFFS_WRITE)

             if (nand->skipfirstblk==1)

             {

                    nand->skipfirstblk = 0;

                    printf("Skip the first good block%llx\n",offset&~(nand->erasesize-1));

                    offset+=nand->erasesize-block_offset;

                    continue;

             }            

             #endif


....


             left_to_write -= write_size;

             printf("%d%% is complete",100-(left_to_write/(*length/100)));

             offset        += write_size;

            

//           p_buffer      += write_size;

             #if defined(CONFIG_SYS_NAND_YAFFS_WRITE)

             if(nand->rw_oob==1)

             {

             p_buffer+=write_size+(write_size/nand->writesize*nand->oobsize);

             }            

             else

             {

             p_buffer+=write_size;

             }

             #else

             p_buffer      += write_size;

             #endif

      }

      return 0;

}




5)修改include/linux/mtd/mtd.h

在131行添加红色字体部分

#if defined(CONFIG_SYS_NAND_YAFFS_WRITE)

      u_char rw_oob;

      u_char skipfirstblk;      

      #endif
 楼主| freewing 发表于 2010-9-26 18:04:56 | 显示全部楼层
(八)
原创文章版权所有!如需转载,请注明出处: http://hi.baidu.com/liushuiyue1/myhome谢谢合作!!!!!

重新编译uboot并下载到Nand Flash中,使用nand指令烧写yaffs2文件到nand中如下图所示,至此uboot已支持yaffs的烧写。


八.支持串口xmodem协议

U-Boot默认支持的loadb命令需要配合Linux下的kermit工具来使用,loady命令通过串口ymodem协议来传输文件。Windows下的超级终端虽然支持ymodem,但是它的使用界面实在不友好。而SecureCRT只支持xmodem和zmodem。而上位机和开发板之间的文件传输又实在是一件非常重要的事,所以现在修改代码以增加对xmodem的支持,即增加一个命令loadx。

1)依照loady的实现来编写代码,首先使用U_BOOT_CMD宏来增加loadx命令(在文件common/cmd_load.c文件中):

U_BOOT_CMD(

      loadx, 3, 0,    do_load_serial_bin,

      "load binary file over serial line (xmodem mode)",

      "[ off ] [ baud ]\n"

      "    - load binary file over serial line"

      " with offset 'off' and baudrate 'baud'"

);



2)依照loady在do_load_serial_bin函数中增加对loadx命令的处理分支。

else if(strcmp(argv[0],"loadx")==0) {

             printf ("## Ready for binary (xmodem) download "

                    "to 0x%08lX at %d bps...\n",

                    offset,

                    load_baudrate);

             addr = load_serial_xmodem (offset);

      }



3)由于addr行调用了load_serial_xmodem函数,依照load_serial_ymodem实现的一个函数。首先在文件开头增加loadx_serial_xmodem函数的声明,然后复制load_serial_ymodem函数为load_serial_xmodem,稍作修改:(1)、将局部数组ymodemBuf改名为xmodemBuf,并在后面使用到的地方统一修改,这只是为了与函数名称一致,可改可不改。(2)、info.mode的值从xyzModem_ymodem改为xyzModem_xmodem。

#if defined(CONFIG_CMD_LOADB)

static ulong load_serial_ymodem (ulong offset);

static ulong load_serial_xmodem (ulong offset);

#endif



重新编译,执行loadx,然后在secureCRT的Transfer菜单下点Send Xmodem(xxx已经放在了Upload目录里),完成对串口xmodem协议的支持。
天嵌_support1 发表于 2010-9-26 19:15:51 | 显示全部楼层
不错呀,顶一个!!
wjqqwer 发表于 2010-9-26 21:04:44 | 显示全部楼层
顶一下,希望有空了弄个PDF格式的,方便大家,个人意见。
竹影 发表于 2010-10-7 14:45:11 | 显示全部楼层
严重支持。。。
 楼主| freewing 发表于 2010-10-8 14:11:11 | 显示全部楼层
好,不过,pdf 要等连载完之后。
lgfsee 发表于 2010-10-9 12:09:35 | 显示全部楼层
TQ2440板子的Uboot移植什么时候能出来啊?
kiss351513637 发表于 2010-11-8 13:25:55 | 显示全部楼层
↑↑↑↑↑↑↑↑↑↑↑↑↑
yzg0930 发表于 2010-11-19 13:28:19 | 显示全部楼层
支持,支持,支持
CX4359481 发表于 2010-12-16 05:05:12 | 显示全部楼层
都是精品!!!!
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

i.MX8系列ARM cortex A53 M4 工控板上一条 /1 下一条

Archiver|手机版|小黑屋|天嵌 嵌入式开发社区 ( 粤ICP备11094220号 )

GMT+8, 2024-3-29 05:30 , Processed in 1.031250 second(s), 21 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表