uboot2016在jz2440的移植笔记

JZ2440 带的uboot太老,各种操蛋的问题和bug。现参考博客进行了boot2016.11的移植

作者:光明顶魔教工程师

联系方式:junchao_zhao@yeah.net

2018年10月25日

Bootloader 主要目的是对硬件进行必要的初始化设置(时钟的分配、设置,内存控制器的初始化,存储器的初始化),我们移植的步骤也是按这个线路来的。

以下是对uboot主要目录的说明

├── api 存放uboot提供的接口函数

├── arch 与体系结构相关的代码,uboot的重头戏

├── board 根据不同开发板定制的代码,代码也不少

├── common 通用的代码,涵盖各个方面,已命令行处理为主

├── disk 磁盘分区相关代码

├── doc 文档,一堆README开头的文件

├── drivers 驱动,很丰富,每种类型的设备驱动占用一个子目录

├── fs 文件系统,支持嵌入式开发板常见的文件系统

├── include 头文件,已通用的头文件为主

├── lib 通用库文件

├── nand_spl NAND存储器相关代码

├── net 网络相关代码,小型的协议栈

└── tools 辅助程序,用于编译和检查uboot目标文件

移植uboot或kernel来说,我们一般回找个和我们目标板相近的配置来进行修改。在configs文件夹中,我们可以看见有很多配置文件,2410 和 2440的体系相同,硬件差异不大,二默认配置没有2440,所以我们以2410为模板进行修改、移植。

  1. 建立jz2440的配置文件
  2. 建立configs文件
    1. 进入configs目录
    2. # cp smdk2410_defconfig smdk2440_defconfig
    3. 把smdk2440_defconfig中所有2410的字样改为2440
  3. 建立board 文件
    1. 进入 boardd/samsung/目录
    2. #cp smdk2410/ smdk2440 –r
    3. 进入boardd/samsung/smdk2440
    4. 把Kconfig、Makefile、smdk2410.c文件中2410字样替换为2440
    5. #mv smdk2410.c smdk2440.c
  4. 建立板子配置头文件
    1. 进入cd include/configs/
    2. # cp smdk2410.h smdk2440.h
    3. 把smdk2440.h文件中2410字样替换为2440
  5. 建立nand 文件支持
    1. 进入drivers/mtd/nand
    2. # cp s3c2410_nand.c s3c2440_nand.c
    3. s3c2440_nand.c文件中2410字样替换为2440
    4. 修改Makefile
      1. 增加s3c2440_nand.o 条件编译
  6. 编辑scripts/config_whitelist.txt
    1. 把CONFIG_SMDK2410、CONFIG_SYS_S3C2410_NAND_HWECC、CONFIG_NAND_S3C2410 复制并替换2410为2440
  7. 编辑arch/arm/Kconfig
    1. 搜索2410,并模仿其配置,添加2440的配置
  8. 编辑arch/arm/include/asm/mach-types.h
    1. 增加mach号#define MACH_TYPE_SMDK2440             193
  9. 测试我们的配置
    1. #make smdk2440_defconfig
    2. #export ARCH=arm
    3. #export CORSS_COMPILE=你的交叉编译器
    4. #make
      1. 我们把生成的u-boot.bin烧写到Nor flash,可以发现虽然串口没有输出,但是板子上的LED亮了,说明我们的Uboot运行了起来,其实因为时钟配置之类的没完成所以 看不见输出
  10. 时钟配置
    1. 我们先设置分频比FCLK:HCLK:PCLK = 1:4:8。官方手册对这几个时钟解释为:FCLK for CPU, HCLK for the AHB bus peripherals, and PCLK for the APB bus peripherals.
      1. 修改代码 arch/arm/cpu/arm920t/start.S
      2. 手册260页
      3. 参考手册,我们确定值为0101 ,十六进制为0x5。所以我们设置CLKDIVN寄存器值为0x5
      4. 手册256页
        1. 设置主频,参考官方手册,我们把MDIV、PDIV、SDIV设置为0x5c、0x1、0x1。
        2. 修改代码board/samsung/smdk2440/smdk2440.c
      5. 到这里我们的uboot串口就能正常工作,有输出了
        1. 还有几个错误,NAND没识别到、网卡也是错误的,后面我们将一一修正

现在我们uboot大小有500多K,太过于臃肿,下面进行裁剪

  1. 修改configs\smdk2440_defconfig去掉以下配置

CONFIG_CMD_USB=y
CONFIG_CMD_DHCP=y
CONFIG_CMD_UBI=y

#CONFIG_USB=y
CONFIG_USB_STORAGE=y
CONFIG_USB_KEYBOARD=y

  1. #make distclean
  2. #./build
  3. 可以看见有很多错误跳出来,这是因为我们在include/configs/smdk2440.h 中有对以上几项的依赖
  4. 编辑include/configs/smdk2440.h 去掉以下宏配置

#define CONFIG_USB_OHCI

#define CONFIG_USB_OHCI_S3C24XX

#define CONFIG_DOS_PARTITION

#define CONFIG_CMD_DATE

#define CONFIG_BOOTP_BOOTFILESIZE

#define CONFIG_BOOTP_BOOTPATH

#define CONFIG_BOOTP_GATEWAY

#define CONFIG_BOOTP_HOSTNAME

#define CONFIG_CMD_UBIFS

#define CONFIG_CMD_MTDPARTS

#define CONFIG_MTD_DEVICE

#define CONFIG_MTD_PARTITIONS

#define CONFIG_YAFFS2

#define CONFIG_RBTREE

  1. 支持nand flash。做完这一步我们的uboot就可以步履蹒跚的启动内核了
    1. 我们在include/configs/smdk2440.h 文件中看见了关于NAND flash支持的配置,有个配置宏是CONFIG_NAND_S3C2410,我们搜索这个宏定义
    2. # grep “CONFIG_NAND_S3C2410” -nR

可以看见第一行,在drivers/mtd/nand/Makefile有这个宏定义的作用

    1. 进入drivers/mtd/nand/
      1. 参考三星官方手册225页,来配置NFCONF寄存器
      2. 在源代码中,我们发现,NFCONF寄存器配置的宏有错误(这个文件我们是复制2410的,这个问题应该是2410和2440的NFCONF寄存器定义不同)
      3. 按手册修正各个移位
        1. 可以看见TACLS、TWRPH0、TWRPH1 分别在12、8、4位我们对宏定义位移进行修正
        2. nFCE、INITECC没在NFCONF寄存器
        3. 配置NFCONT寄存器(增加宏定义)
          1. 手册227页
          2. 增加如图宏定义
          3. 修改代码drivers/mtd/nand/s3c2440_nand.c

在170行写nfcont寄存器,写入我们刚刚的宏定义值

        1. 重写s3c24x0_hwcontrol 函数为下图所示
        2. 增加nand片选函数
          1. 在board_nand_init函数中增加片选函数的指针

        1. 到这里我们的nand flash的支持就完成了,我们就可以在uboot里使用nand write、nand read等函数来对nand flash进行读写。我们再对网卡进行支持后就完成了基本的支持了
  1. 对DM9k网卡的支持
    1. 我们进入到 driver/net/ 目录,可以看见有dm9000的驱动文件,我们查看Makefile文件,查找dm9000相关的编译条件
      1. 我们再uboot目录里继续搜索CONFIG_DRIVER_DM9000 关键字,可以看见最下面几个配置文件中有这个宏定义,我们参考他们对DM9000的配置来配置
      2. 我们打开include/configs/pm9261.h 搜索CONFIG_DRIVER_DM9000 。可以看见DM9000的配置,我们以此为参考进行配置
      3. 我们先看CONFIG_DM9000_BASE 这个宏配置,这里是设置网卡的基地址,这里我们要查看开发板的硬件原理图,BASE地址由芯片的片选来决定,他在内存哪个的bank,这里我们看见DM9K的CS#接的是nGCS4,
      4. 我们继续查看三星官方手册
      5. 可以看见,nGCS4的基地址是0x20000000
    2. 我们继续看DM9000_IO、DM9000_DATA这两个宏定义,这里是定义了DM9000的写命令地址和写数据地址,当我们往DM9000_IO写数据时代表的是写命令,对网卡发送的命令,而往DM9000_DATA写数据时代码的是网线传输的数据。而这里的DM9000_DATA (CONFIG_DM9000_BASE + 4) 是由硬件电路决定的,
      1. 这里吧LADDR2接到了CMD管脚,意味着当写0x20000000地址到0x28000000地址时,最低一位16进展的二进制的第三位为1时CMD管脚会为高电平如 0x20000004 、0x20000006(我们展开最后一位4的二进制为0100, 6的二进制位0110,可以看见第三位都是1)如下图所示
      2. 我们查看DM9000的数据手册第10页,可以看见CMD管脚的定义,当CMD为高时 写的是数据,为低时写的的命令。所以这里也就能理解这两个宏定义了
    3. 我们继续修改代码,现在开启了dm9000代码的宏配置,他会加入到编译,但还需要我们手动添加他的初始化代码board/samsung/smdk2440/smdk2440.c 修改如下配置
    4. 修改完毕后我们开始编译
      1. 编译器在LD链接时出现错误,说undefined reference to `reset_phy’。我们查看common/board_r.c:657代码
      2. #vim common/board_r.c +657
      3. 我们在配置文件里去掉include/configs/smdk2440.h这个配置宏定义,重新编译烧写uboot
      4. 有一个Error,我们直接ping 测试,发现address必须要设置。我们搜索关键字grep “address not set” –nR
      5. vim net/eth_legacy.c +163 分析代码可知是我们的env_enetaddr is_zero_ethaddr

我们跟踪代码:

eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr);

->sprintf(enetvar, index ? “%s%daddr” : “%saddr”, base_name, index);

eth_getenv_enetaddr(enetvar, enetaddr);

->eth_parse_enetaddr(getenv(name), enetaddr);

 

发现是我们没有在环境变量里设置网卡的MAC地址,具体环境变量我们不清楚,我们加入一段测试代码

#vim net/eth_common.c +46

重新编译烧写

下面开始设置环境变量#vim include/env_default.h +37

#vim include/configs/smdk2440.h +97

      1. 烧写测试

应该是我们的环境变量没设置,查看include/env_default.h文件,我们在include/configs/smdk2440.h中增加CONFIG_GATEWAYIP

 

        1. #vim include/configs/smdk2440.h +102
        2. 现在网络正常,可以tftp下载文件了
    1. 到处我们的大体移植就已经完成
  1. 环境变量、MTD分区设置、内核启动
    1. vim include/configs/smdk2440.h
      1. 删掉define CONFIG_ENV_ADDR(CONFIG_SYS_FLASH_BASE + 0x070000)、#define CONFIG_ENV_IS_IN_FLASH、#define CONFIG_ENV_SIZE 0x10000、#define CONFIG_ENV_OVERWRITE
      2. 增加
          1. #define CONFIG_ENV_IS_IN_NAND
          2. #define CONFIG_ENV_OFFSET 0x00080000
          3. #define CONFIG_ENV_SIZE 0x20000
          4. #define CONFIG_ENV_RANGE 0x40000
    2. vim include/configs/smdk2440.h
      1. 增加分区
    3. 设置启动参数vim include/configs/smdk2440.h
      1. #define CONFIG_BOOTARGS “console=ttySAC0,115200 root=/dev/mtdblock3 rootfstype=jffs2 “
      2. #define CONFIG_BOOTCOMMAND “nand read 30000000 kernel;bootm 30000000”
    4. 启动后若没有启动内核,则uboot下执行 nand write 30000000 params 0x123 破坏下params的数据,使我们的变量生效
      1. 内核启动时出现错误,我们修改下machine ID
      2. #vim arch/arm/include/asm/mach-types.h +60
  2. 烧写内核、文件系统
    1. tftp 30000000 uImage_4.3
    2. nand erase.part kernel
    3. nand write 30000000 kernel 0x1c359c
    4. tftp 30000000 fs_mini.jffs2
    5. nand erase.part rootfs
    6. nand write.jffs2 30000000 rootfs 0x59ad78
    7. reset

 

superyin