u-boot-2010.03在tq6410上的移植详解

原创文章版权所有!如需转载,请注明出处: http://hi.baidu.com/liushuiyue1/myhome谢谢合作!!!!!

由于Uboot2010.03S3C6410有了很好的支持,所以采用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项目的代码作为模板,以后再修改


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

  2. #cd smdk6410 //进入smdk6410目录

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

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

            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下

  1. #cd nand_spl/board/samsung //

  2. #cp –ar smdk6400/* smdk6410/
 5)测试编译新建的smdk6410开发板项目
  1. #make smdk6410_config //如果出现Configuring for smdk6410 board...则表示设置正确

  2. #make

由于此版本的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下载。


五、DM9000在Uboot2010.03上的移植

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

  1. #cd include/configs///

  2. #gedit smdk6410.h //

  3. smdk6410.h修改内容如下:

  4. #define CONFIG_NET_MULTI 1

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

  6. //#define CONFIG_CS8900_BASE 0x18800300

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

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

  9. #define CONFIG_DM9000_BASE 0x18000300

  10. #define DM9000_IO CONFIG_DM9000_BASE

  11. #define DM9000_DATA (CONFIG_DM9000_BASE + 4)

  12. #define CONFIG_DM9000_USE_16BIT

  13. #define CONFIG_ETHADDR 10:23:45:67:89:ab //你的网卡物理地址

  14. #define CONFIG_NETMASK 255.255.255.0

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

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

  17. #define CONFIG_GATEWAYIP 192.168.174.6

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

  19. 2)修改net/eth.c,在int eth_initialize(bd_t *bis)里添加DM9000AE的初始化函数(红色部分为修改的地方):

  20. int eth_initialize(bd_t *bis)

  21. {

  22.       unsigned char env_enetaddr[6];

  23.       int eth_number = 0;

  24.       eth_devices = NULL;

  25.       eth_current = NULL;

  26.       show_boot_progress (64);

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

  28.       miiphy_init();

  29. #endif

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

  31.        * present, try the cpu-specific initialization */

  32.       if (board_eth_init(bis) < 0)

  33.              cpu_eth_init(bis);

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

  35.       mv6436x_eth_initialize(bis);

  36. #endif

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

  38.       mv6446x_eth_initialize(bis);

  39. #endif

  40. #if defined(CONFIG_DRIVER_DM9000)

  41.       dm9000_initialize(bis);

  42. #endif

  43.       if (!eth_devices) {

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

  45.              show_boot_progress (-64);

  46.       } else {

  47.              struct eth_device *dev = eth_devices;

  48.              char *ethprime = getenv ("ethprime");

  49.              show_boot_progress (65);

  50.              do {

  51.                     if (eth_number)

  52.                            puts (", ");

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

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

  55.                            eth_current = dev;

  56.                            puts (" [PRIME]");

  57.                     }

  58.                     eth_getenv_enetaddr_by_index(eth_number, env_enetaddr);

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

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

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

  62.                            {

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

  64.                                          dev->name);

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

  66.                                          dev->enetaddr);

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

  68.                                          env_enetaddr);

  69.                            }

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

  71.                     }

  72.                     eth_number++;

  73.                     dev = dev->next;

  74.              } while(dev != eth_devices);

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

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

至此,uboot已经能支持dm9000的网卡,可以使用tftp协议下载程序并在ram中运行了。

六.对Nor flash的支持:

从上图的启动信息可以看到flash:0kb。Uboot还没有添加对Nor flash的支持。我们使用的nor flash型号是EN29LV160AB,与AMD的兼容,所以添加对Nor flash的支持。


  1. #cd include/configs///

  2. #gedit smdk6410.h //

  3. /*-----------------------------------------------------------------------

  4. * FLASH and environment organization

  5. */

  6. #define CONFIG_SYS_FLASH_BASE 0x00000000//0x10000000Flash的基地址

  7. #define CONFIG_SYS_MONITOR_BASE 0x00000000

  8. #define CONFIG_SYS_MAX_FLASH_BANKS 1 /* max number of memory banks */

  9. //一定要定义为>0

  10. /* AM29LV160B has 35 sectors, AM29LV800B - 19 */

  11. #define CONFIG_SYS_MAX_FLASH_SECT 35//40硬件得来

  12. #define CONFIG_AMD_LV800

  13. //#define CONFIG_SYS_FLASH_CFI 1 /* Use CFI parameters (needed?) */

  14. #define PHYS_FLASH_SIZE 0x200000 //2M Flash的大小

  15. #define PHYS_FLASH_1 0x00000000

  16. /* Use drivers/cfi_flash.c, even though the flash is not CFI-compliant */

  17. //CFI相关的屏蔽掉

  18. //#define CONFIG_FLASH_CFI_DRIVER 1

  19. //#define CONFIG_SYS_FLASH_CFI_WIDTH FLASH_CFI_16BIT

  20. //#define CONFIG_FLASH_CFI_LEGACY

  21. //#define CONFIG_SYS_FLASH_LEGACY_512Kx16

  22. /* timeout values are in ticks */

  23. #define CONFIG_SYS_FLASH_ERASE_TOUT (5 * CONFIG_SYS_HZ) /* Timeout for Flash Erase */

  24. #define CONFIG_SYS_FLASH_WRITE_TOUT (5 * CONFIG_SYS_HZ) /* Timeout for Flash Write */

  25. #define CONFIG_ENV_ADDR 0x00000

  26. #define CONFIG_ENV_SIZE 0x4000 /* Total Size of Environment Sector */

说明:Uboot2010.03中支持Nor flash的两种读写方式:CFI和JEDEC。本文章采用JEDEC的方式。因为S3C2440S3C6410nor flash接口兼容,所以将S3C2440目录下的flash.c复制到./board/samsung/s3c6410/下,并修改Makefile文件。

#cd board/samsung/s3c6410/Makefile//

#gedit Makefile //

COBJS-y    := smdk6410.o flash.o

重新编译Uboot并下载到Nand Flash中,串口打印信息如下。说明板子已经能检测到Nor flash



七. Uboot支持yaffs2文件的读写


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

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


  1. #cd include/configs/smdk6410.h//
  2. #define CONFIG_YAFFS2

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

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

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


  1. #cd include/configs/smdk6410.h//

  2. //#define CONFIG_YAFFS2

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

  4. #define CONFIG_MTD_NAND_ECC_YAFFS 1

2)修改common/cmd_nand.c

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

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

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

  4.                     if (read)

  5.                            ret = nand_read_skip_bad(nand, off, &size,

  6.                                                 (u_char *)addr);

  7.                     else

  8.                            ret = nand_write_skip_bad(nand, off, &size,

  9.                                                 (u_char *)addr);

  10.              }

  11.               #if defined(ENABLE_CMD_NAND_YAFFS)

  12.               }else if ( s != NULL &&

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

  14.                          if(read) {

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

  16.                          } else {

  17.                             nand->rw_oob = 1;

  18. #if defined(ENABLE_CMD_NAND_YAFFS_SKIPFB)

  19.                             nand->skipfirstblk = 1;

  20. #else

  21.                             nand->skipfirstblk = 0;

  22. #endif

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

  24. #if defined(ENABLE_CMD_NAND_YAFFS_SKIPFB)

  25.                             nand->skipfirstblk = 0;

  26. #endif

  27.                             nand->rw_oob = 0;

  28.                          }

  29. #endif

  30. }

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

  32.                     /* out-of-band data */

  33.                     mtd_oob_ops_t ops = {

  34.                            .oobbuf = (u8 *)addr,

  35.                            .ooblen = size,

  36.                            .mode = MTD_OOB_RAW

  37.                     };

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

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

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

  41.       #if defined(CONFIG_SYS_NAND_YAFFS_WRITE)

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

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

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

  45.       #endif

  46.       "nand bad - show bad blocks\n"

3)drivers/mtd/nand/nand_base.c



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

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

  3.                     size_t *retlen, const uint8_t *buf)

  4. {

  5.       struct nand_chip *chip = mtd->priv;

  6.       int ret;

  7.       #if defined(CONFIG_SYS_NAND_YAFFS_WRITE)

  8.              int oldopsmode = 0;

  9.              if(mtd->rw_oob==1)

  10.              {

  11.                     size_t oobsize =mtd->oobsize;

  12.                     size_t datasize = mtd->writesize;

  13.                     int i=0;

  14.                     uint8_t oobtemp[oobsize];

  15.                     int datapages = 0;

  16.                     datapages = len/(datasize);

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

  18.                     {

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

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

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

  22.                     }

  23.              }

  24.       #endif

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

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

  27.              return -EINVAL;

  28.       if (!len)

  29.              return 0;

  30.       nand_get_device(chip, mtd, FL_WRITING);

  31.       chip->ops.len = len;

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

  33.       #if !defined(CONFIG_SYS_NAND_YAFFS_WRITE)

  34.       chip->ops.oobbuf = NULL;

  35.       #endif

  36.       #if defined(CONFIG_SYS_NAND_YAFFS_WRITE)

  37.              if(mtd->rw_oob!=1)

  38.              {

  39.                     chip->ops.oobbuf = NULL;

  40.              }

  41.              else

  42.              {

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

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

  45.                     oldopsmode = chip->ops.mode;

  46.                     chip->ops.mode = MTD_OOB_RAW;

  47.              }

  48.       #endif

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

  50.       *retlen = chip->ops.retlen;

  51.       nand_release_device(mtd);

  52.       #if defined(CONFIG_SYS_NAND_YAFFS_WRITE)

  53.              chip->ops.mode = oldopsmode;

  54.       #endif

  55.       return ret;

  56. }


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


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

  2.                     u_char *buffer)

  3. {

  4.       int rval;

  5.       size_t left_to_write = *length;

  6.       size_t len_incl_bad;

  7.       u_char *p_buffer = buffer;

  8.      

  9.       #if defined(CONFIG_SYS_NAND_YAFFS_WRITE)

  10.              if(nand->rw_oob==1)

  11.              {

  12.              size_t oobsize=nand->oobsize;

  13.              size_t datasize = nand->writesize;

  14.              int datapages = 0;

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

  16.              {

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

  18.                     return -EINVAL;

  19.              }

  20.              datapages = *length/(datasize+oobsize);

  21.              *length = datapages*datasize;

  22.              left_to_write = *length;

  23.              }

  24.       #endif

  25.      ........

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

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

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

  29.              return -EINVAL;

  30.       }

  31.      

  32.       #if !defined(CONFIG_SYS_NAND_YAFFS_WRITE)

  33.       if (len_incl_bad == *length) {

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

  35.              if (rval != 0)

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

  37.                            offset, rval);

  38.              return rval;

  39.       }

  40.       #endif

  41.       while (left_to_write > 0) {

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

  43.              size_t write_size;

  44.              WATCHDOG_RESET ();

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

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

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

  48.                     offset += nand->erasesize - block_offset;

  49.                     continue;

  50.              }

  51.              #if defined(CONFIG_SYS_NAND_YAFFS_WRITE)

  52.              if (nand->skipfirstblk==1)

  53.              {

  54.                     nand->skipfirstblk = 0;

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

  56.                     offset+=nand->erasesize-block_offset;

  57.                     continue;

  58.              }

  59.              #endif

  60. ....

  61.              left_to_write -= write_size;

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

  63.              offset += write_size;

  64.             

  65. // p_buffer += write_size;

  66.              #if defined(CONFIG_SYS_NAND_YAFFS_WRITE)

  67.              if(nand->rw_oob==1)

  68.              {

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

  70.              }

  71.              else

  72.              {

  73.              p_buffer+=write_size;

  74.              }

  75.              #else

  76.              p_buffer += write_size;

  77.              #endif

  78.       }

  79.       return 0;

  80. }

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

  1. 在131行添加红色字体部分

  2. #if defined(CONFIG_SYS_NAND_YAFFS_WRITE)

  3.       u_char rw_oob;

  4.       u_char skipfirstblk;

  5.       #endif

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


八. 支持串口xmodemo协议


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

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

  1. U_BOOT_CMD(

  2.       loadx, 3, 0, do_load_serial_bin,

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

  4.       "[ off ] [ baud ]\n"

  5.       " - load binary file over serial line"

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

  7. );

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

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

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

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

  4.                     offset,

  5.                     load_baudrate);

  6.              addr = load_serial_xmodem (offset);

  7.       }

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。

  1. #if defined(CONFIG_CMD_LOADB)

  2. static ulong load_serial_ymodem (ulong offset);

  3. static ulong load_serial_xmodem (ulong offset);

  4. #endif

重新编译,执行loadx,然后在secureCRTTransfer菜单下点Send Xmodemxxx已经放在了Upload目录里),完成对串口xmodem协议的支持。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值