移植u-boot-2016.11到TQ2440开发板全过程记录

  • 移植前的准备
  1. 获取并解压源码

SAMSUNG公司于2017年初停止了对S3C2410系列CPU的官方u-boot支持(可在最新版u-boot源码中打开doc/README.scrapyard,搜索关键字S3C2440查看相关说明)。从http://ftp.denx.de/pub/u-boot/下载支持S3C2410处理器的最后一版官方u-boot源码u-boot-2016.11.tar.bz2,放到宿主机的/opt/u-boot/下。

解压源代码并进入根目录:

tar jxvf u-boot-2016.11.tar.bz2

cd u-boot-2016.11/

  1. 指定交叉编译器

gedit Makefile

找到:

# set default to nothing for native builds

ifeq ($(HOSTARCH),$(ARCH))

CROSS_COMPILE ?=

endif

在下方新插入一行:

CROSS_COMPILE ?=arm-linux-

  1. 创建板卡支持文件

(1)创建板卡支持文件夹

拷贝官方smdk2410文件夹进行修改:

cp -rf board/samsung/smdk2410/ board/samsung/tq2440

(2)修改板卡硬件初始化文件

gedit board/samsung/tq2440/lowlevel_init.S

修改s3c2410.S为tq2440.S,修改SMDK2410为TQ2440。

(3)修改板卡高级初始化文件

重命名该文件夹下的smdk2410.c为tq2440.c:

mv board/samsung/tq2440/smdk2410.c board/samsung/tq2440/tq2440.c

编辑该文件:

gedit board/samsung/tq2440/tq2440.c

替换所有SMDK2410为TQ2440,并添加编译选项。

gedit board/samsung/tq2440/Makefile

修改smdk2410.o为tq2440.o

(4)修改板卡配置文件

编辑该文件:

gedit board/samsung/tq2440/Kconfig

内容为:

if TARGET_TQ2440

 

config SYS_BOARD

       default "tq2440"

 

config SYS_VENDOR

       default "samsung"

 

config SYS_SOC

       default "s3c24x0"

 

config SYS_CONFIG_NAME

       default "tq2440"

 

endif

(5)添加板卡支持文件信息

gedit arch/arm/Kconfig

找到

config TARGET_SMDK2410

       bool "Support smdk2410"

       select CPU_ARM920T

在下方插入:

config TARGET_TQ2440

       bool "Support tq2440"

       select CPU_ARM920T

找到:

source "board/samsung/smdk2410/Kconfig"

在下方插入:

source "board/samsung/tq2440/Kconfig"

(6)修改板卡支持维护信息

gedit board/samsung/tq2440/MAINTAINERS

修改内容为:

TQ2440 BOARD

M:   Lion <[email protected]>

S:    Maintained

F:    board/samsung/tq2440/

F:    include/configs/tq2440.h

F:    configs/tq2440_defconfig

(7)添加板卡识别信息

gedit arch/arm/include/asm/mach-types.h

找到:

#define MACH_TYPE_SMDK2410             193

在下方插入:

#define MACH_TYPE_TQ2440          168

找到:

#ifdef CONFIG_ARCH_SMDK2410

# ifdef machine_arch_type

#  undef machine_arch_type

#  define machine_arch_type __machine_arch_type

# else

#  define machine_arch_type MACH_TYPE_SMDK2410

# endif

# define machine_is_smdk2410()   (machine_arch_type == MACH_TYPE_SMDK2410)

#else

# define machine_is_smdk2410()   (0)

#endif

在下面插入一段:

#ifdef CONFIG_ARCH_TQ2440

# ifdef machine_arch_type

#  undef machine_arch_type

#  define machine_arch_type __machine_arch_type

# else

#  define machine_arch_type MACH_TYPE_TQ2440

# endif

# define machine_is_tq2440()  (machine_arch_type == MACH_TYPE_TQ2440)

#else

# define machine_is_tq2440()  (0)

#endif

  1. 创建板卡配置头文件

cp include/configs/smdk2410.h include/configs/tq2440.h

编辑该文件:

gedit include/configs/tq2440.h

替换S3C2410为S3C2440,替换SMDK2410为TQ2440

  1. 创建NAND Flash驱动文件

cp drivers/mtd/nand/s3c2410_nand.c drivers/mtd/nand/s3c2440_nand.c

      编辑该文件:

gedit drivers/mtd/nand/s3c2440_nand.c

      添加编译选项:

gedit drivers/mtd/nand/Makefile

找到:

obj-$(CONFIG_NAND_S3C2410) += s3c2410_nand.o

在下方插入一行:

obj-$(CONFIG_NAND_S3C2440) += s3c2440_nand.o

  1. 创建默认编译配置文件

创建tq2440开发板默认配置文件:

cp configs/smdk2410_defconfig configs/tq2440_defconfig

编辑该文件:

gedit configs/tq2440_defconfig

修改开发板目标:

替换CONFIG_TARGET_SMDK2410=y为CONFIG_TARGET_TQ2440=y;

修改命令行前缀:

替换CONFIG_SYS_PROMPT="SMDK2410 # "为CONFIG_SYS_PROMPT="TQ2440 # ";

  1. 测试编译环境

(1)清理环境并重新编译

make distclean

make tq2440_defconfig

make

编译失败,并提示” Not enough room for program headers, try linking with -N”错误:

移植u-boot-2016.11到TQ2440开发板全过程记录_第1张图片

错误信息:

arm-linux-ld.bfd: u-boot: Not enough room for program headers, try linking with -N

arm-linux-ld.bfd: final link failed: Bad value

Makefile:1209: recipe for target 'u-boot' failed

make: *** [u-boot] Error 1

(2)根据网上资料,修改顶层配置文件:

gedit Makefile

找到:

LDFLAGS_u-boot += $(LDFLAGS_FINAL)

在下面插入:

# Avoid 'Not enough room for program headers' error on binutils 2.28 onwards

LDFLAGS_u-boot += $(call ld-option, --no-dynamic-linker)

(3)重新编译

make

在根目录下生成了u-boot.bin文件,但提示“Error: You must add new CONFIG options using Kconfig”错误

移植u-boot-2016.11到TQ2440开发板全过程记录_第2张图片

错误信息:

Error: You must add new CONFIG options using Kconfig

The following new ad-hoc CONFIG options were detected:

CONFIG_NAND_S3C2440

CONFIG_SYS_S3C2440_NAND_HWECC

CONFIG_TQ2440

 

Please add these via Kconfig instead. Find a suitable Kconfig

file and add a 'config' or 'menuconfig' option.

Makefile:827: recipe for target 'all' failed

make: *** [all] Error 1

这一个错误产生的原因是修改了配置头文件中的默认宏定义而导致配置检查无法通过,如果根据消息提示手工在whitelist.txt文件中添加相应宏,由于不知道whitelist.txt文件中的排序规则,仍旧可能报错。

(4)解决白名单校验不通过问题

根据网上资料来看,目前切实有效的解决办法是关闭该校验功能。

gedit Makefile

找到:

       $(srctree)/scripts/check-config.sh u-boot.cfg \

              $(srctree)/scripts/config_whitelist.txt ${srctree} 1>&2

在开头位置使用#屏蔽这两行:

#     $(srctree)/scripts/check-config.sh u-boot.cfg \

#            $(srctree)/scripts/config_whitelist.txt ${srctree} 1>&2

  1. 创建自动编译批处理脚本

(1)编写自动编译脚本

gedit auto_build.sh

添加如下内容:

#!/bin/bash 

echo "Clean Configuration File..." 

make distclean 

echo "Clean Obj..." 

make clean 

echo "Load Configuration File..." 

make tq2440_defconfig 

echo "make..." 

make CROSS_COMPILE=arm-linux-

echo "Copy bins to TFTP Folder...."

cp /opt/u-boot/u-boot-2016.11/u-boot.bin /opt/TFTP/u-boot.bin

cp /opt/u-boot/u-boot-2016.11/spl/u-boot-spl.bin /opt/TFTP/u-boot-spl.bin

(2)为自动编译脚本文件添加执行权限

sudo chmod +X auto_build.sh

(3)修改自动编译脚本文件所有者

sudo chown -R tq2440:root /opt/u-boot/u-boot-2016.11/auto_build.sh

(4)执行自动编译脚本

bash ./auto_build.sh

编译成功:

移植u-boot-2016.11到TQ2440开发板全过程记录_第3张图片

  1. 小结

至此,我们完成了u-boot-2016.11移植到TQ2440开发板的前期准备工作。

  • 修改芯片初始化代码
  1. 修改屏蔽中断代码

gedit arch/arm/cpu/arm920t/start.S

找到:

# if defined(CONFIG_S3C2410)

       ldr   r1, =0x3ff

       ldr   r0, =INTSUBMSK

       str   r1, [r0]

# endif

在下面为S3C2440芯片添加:

# if defined(CONFIG_S3C2440)

       ldr   r1, =0x7ff

       ldr   r0, =INTSUBMSK

       str   r1, [r0]

# endif

  1. 修改时钟初始化代码

(1)修改芯片时钟初始化代码

gedit arch/arm/cpu/arm920t/start.S

找到:

       /* FCLK:HCLK:PCLK = 1:2:4 */

       /* default FCLK is 120 MHz ! */

       ldr   r0, =CLKDIVN

       mov       r1, #3

       str   r1, [r0]

替换为:

#if defined(CONFIG_S3C2440)

#define CLK_CTL_BASE      0x4C000000

#define MDIV_405   0x7f<<12

#define PSDIV_405  0x21

       /* FCLK:HCLK:PCLK = 1:4:8 */

       /* default FCLK is 405 MHz ! */

       ldr   r0, =CLKDIVN

       mov       r1, #5

       str   r1, [r0]

       /* set asynchronous bus mod */

       mrc p15, 0, r1, c1, c0, 0

       orr   r1, r1, #0xc0000000  

       mcr p15, 0, r1, c1, c0, 0

       /* MPLL is 405 MHz ! */

       mov       r1, #CLK_CTL_BASE

       mov       r2, #MDIV_405

       add r2, r2, #PSDIV_405

       str   r2, [r1, #0x04]

#else

       /* FCLK:HCLK:PCLK = 1:2:4 */

       /* default FCLK is 120 MHz ! */

       ldr   r0, =CLKDIVN

       mov       r1, #3

       str   r1, [r0]

#endif    /* CONFIG_S3C2440 */

(2)修改板卡时钟初始化代码

gedit board/samsung/tq2440/tq2440.c

添加一个新的FCLK配置模式,找到:

#define FCLK_SPEED 1

修改为:

#if !defined(CONFIG_S3C2440)

#define FCLK_SPEED 1

#else

#define FCLK_SPEED 2

#endif /* CONFIG_S3C2440 */

找到对应的配置项:

#if (FCLK_SPEED == 0)        /* Fout = 203MHz, Fin = 12MHz for Audio */

#define M_MDIV      0xC3

#define M_PDIV 0x4

#define M_SDIV 0x1

#elif (FCLK_SPEED == 1)            /* Fout = 202.8MHz */

#define M_MDIV      0xA1

#define M_PDIV 0x3

#define M_SDIV 0x1

#endif

添加配置模式为2的分支选项:

#if (FCLK_SPEED == 0)        /* Fout = 203MHz, Fin = 12MHz for Audio */

#define M_MDIV      0xC3

#define M_PDIV 0x4

#define M_SDIV 0x1

#elif (FCLK_SPEED == 1)            /* Fout = 202.8MHz */

#define M_MDIV      0xA1

#define M_PDIV 0x3

#define M_SDIV 0x1

#elif (FCLK_SPEED == 2)            /* Fout = 405Hz */

#define M_MDIV      0x7f

#define M_PDIV 0x2

#define M_SDIV 0x1

#endif

添加一个新的UCLK配置模式,找到:

#define USB_CLOCK 1

替换为:

#if !defined(CONFIG_S3C2440)

#define USB_CLOCK 1

#else

#define USB_CLOCK 2

#endif /* CONFIG_S3C2440 */

找到对应的配置项:

#if (USB_CLOCK == 0)

#define U_M_MDIV 0xA1

#define U_M_PDIV  0x3

#define U_M_SDIV  0x1

#elif (USB_CLOCK == 1)

#define U_M_MDIV 0x48

#define U_M_PDIV  0x3

#define U_M_SDIV  0x2

#endif

添加配置模式为2的分支选项:

#if (USB_CLOCK == 0)

#define U_M_MDIV 0xA1

#define U_M_PDIV  0x3

#define U_M_SDIV  0x1

#elif (USB_CLOCK == 1)

#define U_M_MDIV 0x48

#define U_M_PDIV  0x3

#define U_M_SDIV  0x2

#elif (USB_CLOCK == 2)

#define U_M_MDIV 0x38

#define U_M_PDIV  0x2

#define U_M_SDIV  0x2

#endif

  1. 启动I/D CACHE

gedit arch/arm/cpu/arm920t/start.S

找到:

#endif    /* CONFIG_S3C24X0 */

在上一行插入:

#if defined(CONFIG_S3C2440)

       /* 启动I/DCACHE */

       mrc p15, 0, r0, c1, c0, 0

       orr   r0, r0, #(1<<12)

       mcr p15, 0, r0, c1, c0, 0

#endif    /* CONFIG_S3C2440 */

  1. 修改SDRAM初始化代码

gedit board/samsung/tq2440/lowlevel_init.S

替换:

SMRDATA:

    .word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28))

    .word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC))

    .word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC))

    .word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC))

    .word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC))

    .word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC))

    .word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC))

    .word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN))

    .word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN))

    .word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)

    .word 0x32

    .word 0x30

    .word 0x30

为:

SMRDATA:

       .long 0x22011110 @ BWSCON

       .long 0x00000700 @ BANKCON0

       .long 0x00000700 @ BANKCON1

       .long 0x00000700 @ BANKCON2

       .long 0x00000700 @ BANKCON3

       .long 0x00000700 @ BANKCON4

       .long 0x00000700 @ BANKCON5

       .long 0x00018005 @ BANKCON6

       .long 0x00018005 @ BANKCON7

       .long 0x008C07A3 @ REFRESH

       .long 0x000000B1 @ BANKSIZE

       .long 0x00000030 @ MRSRB6

       .long 0x00000030 @ MRSRB7

  1. 修改GPIO引脚初始化代码

GPB共有11个引脚,有高到低依次为GPB10-GPB0。TQ2440开发板的四个板载LED分别位于GPB8-GPB5,由GPBCON、GPBUP和GPBDAT三个寄存器控制。

  1. GPBCON(0x56000010)每两位控制一个引脚,为00时表示输入引脚,为01时表示输出引脚,为10时表示复用功能;
  2. GPBDAT(0x56000014)每一位表示一个引脚的输入或输出状态;
  3. GPBUP(0x56000018)每一位控制一个引脚,为0时表示使用上拉电阻,为1表示禁用上拉电阻。

gedit board/samsung/tq2440/tq2440.c

可看到:

writel(0x00044555, &gpio->gpbcon);

则源代码中GPB管脚配置情况如下:

GPB10

GPB9

GPB8

GPB7

GPB6

GPB5

GPB4

GPB3

GPB2

GPB1

GPB0

0

0

0

1

0

0

0

1

0

0

0

1

0

1

0

1

0

1

0

1

0

1

输入

输出

输入

输出

输入

输出

输出

输出

输出

输出

输出

                                           

即源码中板卡初始化代码将GPB10、GPB8和GPB6设置为输入模式,其余设置为输出模式。

根据TQ2440开发板原理图来看:GPB0为蜂鸣器接口,GPB5~GPB8为LED接口,均设置为输出模式,其他管脚设置为复用模式。

TQ2440开发板GPB管脚配置情况如下:

GPB10

GPB9

GPB8

GPB7

GPB6

GPB5

GPB4

GPB3

GPB2

GPB1

GPB0

1

0

0

1

0

1

0

1

0

1

0

1

1

0

1

0

1

0

1

0

0

1

复用

输出

输出

输出

输出

输出

复用

复用

复用

复用

复用

                                           

则修改该代码为:

writel(0x002556A9, &gpio->gpbcon);

  1. 取消"WARNING: Caches not enabled "警告

gedit arch/arm/lib/cache.c

由于前面我们已经启用了I/D Cache,所以这个警告是错误的,找到:

puts("WARNING: Caches not enabled\n");

用/**/注释掉。

  1. 小结

至此,我们完成了芯片级初始化和高级初始化代码的修改。需要注意的是,在board/samsung/tq2440/tq2440.c的board_init函数中有一句:

       /* adress of boot parameters */

       gd->bd->bi_boot_params = 0x30000100;

指定了在SDRAM中运行时环境变量保存地址,后面再来研究。

  • 从SDRAM启动
  1. 修改u-boot连接地址

TQ2440开发板的SDRAM型号为K4S561632N,接BANK6,地址段为:0x3000_0000~0x33FF_FFFF,需要修改u-boot.bin文件的链接地址到该区域。

gedit include/configs/tq2440.h

找到:

#define CONFIG_SYS_TEXT_BASE 0x0

替换为:

#define CONFIG_SYS_TEXT_BASE 30008000     /* 从SDRAM启动的连接地址 */

  1. 跳过底层初始化函数

根据u-boot的启动流程来看,如果将u-boot烧写到SDRAM中直接运行,需要在arch/arm/cpu/arm920t/start.S文件中屏蔽掉对底层初始化函数lowlevel_init的调用(底层初始化函数位于board/Samsung/smdk2440/lowlevel_init.S文件中),否则启动过程中会对SDRAM重新进行初始化,破坏掉u-boot的代码。

gedit arch/arm/cpu/arm920t/start.S

可以看到u-boot源码中相应代码,可以通过定义一个CONFIG_SKIP_LOWLEVEL_INIT宏来跳过对lowlevel_init函数的调用:

移植u-boot-2016.11到TQ2440开发板全过程记录_第4张图片

在配置头文件中添加该宏:

gedit include/configs/tq2440.h

在文件开头插入:

/*

 * Debug Options

 */

#define DEBUG                             /* 输出详细的调试信息 */

#define CONFIG_SKIP_LOWLEVEL_INIT           /* SDRAM中运行时跳过底层初始化操作 */

  1. 修改SDRAM刷新频率

gedit board/samsung/tq2440/lowlevel_init.S

在start.S中设置了FCLK为405MHZ,分频系数FCLK:HCLK:PCLK = 1:4:8。SDRAM使用HCLK,则频率为101.25MHz,一个时钟周期为1/101.25MHz=9.876ns。

S3C2440手册中对于Trp参数的描述:0x00=2 clocks,0x01=3 clocks,0x10=4 clocks,11=Not。

SDRAM手册知:最小时钟周期为10ns,Row Precharge time最小值为20ns,则Trp=20/9.876=2个时钟周期。

找到:

#define REFCNT                    1012      /* period=10.37us, HCLK=100Mhz, (2048+1-10.37*100) */

替换为:

#define REFCNT                    999        /* period=10.37us, HCLK=101.25Mhz, (2048+1-10.37*101.25) */

  1. 下载到SDRAM中运行

(1)烧写天嵌科技官方的u-boot到NOR Flash并启动;

(2)在u-boot界面下连按两次’q’进入命令行;

(3)设置网络环境变量并保存(首次使用官方u-boot时必须进行此操作);

set ethaddr 00:12:34:56:ab:cd

set ipaddr 192.168.1.11

set serverip 192.168.1.10

saveenv

(4)从TFTP下载u-boot.bin到SDRAM中运行;

tftp 30008000 u-boot.bin;go 30008000

移植u-boot-2016.11到TQ2440开发板全过程记录_第5张图片

启动时正确识别出SDRAM(内存)大小为64MiB,但之后就卡死了。按网上说法是因为u-boot执行到board.c中的board_init_r函数时,调用mem_malloc_init函数时出错。

临时解决办法是:

gedit common/dlmalloc.c

找到mem_malloc_init中的:

#ifdef CONFIG_SYS_MALLOC_CLEAR_ON_INIT

       memset((void *)mem_malloc_start, 0x0, size);

#endif

替换为:

#ifdef CONFIG_SYS_MALLOC_CLEAR_ON_INIT

       memset((void *)mem_malloc_start, 0x0, size/2);

#endif

即将系统初始化阶段开辟的缓存区大小减少为1/2后重新烧录,启动正常

移植u-boot-2016.11到TQ2440开发板全过程记录_第6张图片

  1. 小结

回头再来研究初始化阶段清空堆栈出错的原因。

  • 移植DM9000网卡驱动

u-boot-2016.11版本自带了DM9000网卡驱动程序,只需要做简单修改和调用即可使用。DM9000位于TQ2440的BANK4,则对应基地址为0x20000000;使用LADDR2作为CMD信号,所以命令寄存器地址为0x20000004。

  1. 修改DM9000网卡相关宏和寄存器定义

gedit include/configs/tq2440.h

找到:

/*

 * Hardware drivers

 */

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

#define CONFIG_CS8900_BASE 0x19000300

#define CONFIG_CS8900_BUS16      /* the Linux driver does accesses as shorts */

替换为

/*

 * Hardware drivers

 */

#define CONFIG_DRIVER_DM9000

#define CONFIG_DM9000_NO_SROM                  /* TQ2440开发板无网卡SROM */

#define CONFIG_DM9000_BASE 0x20000000             /* TQ2440开发板DM9000接在S3C2440的bank4 */

#define DM9000_IO CONFIG_DM9000_BASE

#define DM9000_DATA (CONFIG_DM9000_BASE+4)       /* TQ2440开发板DM9000的cmd引脚接在S3C2440的ADDR2 */

设置默认的网络配置信息,找到:

#define CONFIG_NETMASK             255.255.255.0

#define CONFIG_IPADDR           10.0.0.110

#define CONFIG_SERVERIP       10.0.0.1

替换为:

#define CONFIG_NETMASK             255.255.255.0

#define CONFIG_IPADDR                  192.168.1.11

#define CONFIG_SERVERIP       192.168.1.10

#define CONFIG_ETHADDR       00:11:22:33:44:aa

  1. 调用DM9000网卡初始化函数

gedit board/samsung/tq2440/tq2440.c

找到board_eth_init函数,添加:

#ifdef CONFIG_DRIVER_DM9000

       rc = dm9000_initialize(bis);

#endif

解决新版u-boot中“could not establish link“提示

gedit drivers/net/dm9000x.c

找到dm9000_init函数,注释掉网络测试代码:

#if 0

       i = 0;

       while (!(dm9000_phy_read(1) & 0x20)) {   /* autonegation complete bit */

              udelay(1000);

              i++;

              if (i == 10000) {

                     printf("could not establish link\n");

                     return 0;

              }

       }

#endif

  1. 添加环境变量

(1)添加网卡地址到默认环境变量数组中

gedit include/env_default.h

找到:

#ifdef     CONFIG_SERVERIP

       "serverip="   __stringify(CONFIG_SERVERIP) "\0"

#endif

在下面添加:

#ifdef     CONFIG_ETHADDR

       "ethaddr="    __stringify(CONFIG_ETHADDR)       "\0"

#endif

  1. 网络功能测试

(1)下载到SDRAM运行

从TFTP下载u-boot.bin到SDRAM中运行;

tftp 30008000 u-boot.bin;go 30008000

移植u-boot-2016.11到TQ2440开发板全过程记录_第7张图片

已经正确识别到DM9000网卡。

(2)ping测试

ping 192.168.1.10

移植u-boot-2016.11到TQ2440开发板全过程记录_第8张图片

(3)TFTP下载功能测试

tftp 320000 u-boot.bin

移植u-boot-2016.11到TQ2440开发板全过程记录_第9张图片

  1. 小结

有空回来完善ethaddr环境变量保存问题。

  • 从NOR Flash启动
  1. 修改相关参数宏定义

gedit include/configs/tq2440.h

配置头文件中支持NOR FLASH的相关宏参数包括:

  1. CONFIG_SYS_FLASH_LEGACY_512Kx16:指明;
  2. CONFIG_SYS_MAX_FLASH_BANKS:指明系统中有几个FLASH,TQ2440只有1个;
  3. CONFIG_SYS_MAX_FLASH_SECT:指明该FLASH中有多少个段,根据芯片资料手册可知,TQ2440用的NOR FLASH一共有35个段;
  4. CONFIG_ENV_ADDR:指明环境变量保存位置;
  5. CONFIG_ENV_IS_IN_FLASH:指明环境变量保存在NOR Flash中;
  6. CONFIG_ENV_SIZE:指明环境变量大小。

根据芯片手册修改NOR Flash扇区数,找到:

#define CONFIG_SYS_MAX_FLASH_SECT (19)

修改为:

#define CONFIG_SYS_MAX_FLASH_SECT (35)

找到:

#define CONFIG_SYS_FLASH_LEGACY_512Kx16

修改为:

#define CONFIG_SYS_FLASH_LEGACY_1024Kx16

  1. 添加NOR Flash芯片信息

gedit drivers/mtd/jedec_flash.c

找到jedec_table[]数组,在末尾};上一行添加:

#ifdef CONFIG_SYS_FLASH_LEGACY_1024Kx16

       {

              .mfr_id          = 0x1c,

              .dev_id         = 0x2249,

              .name            = "EON EN29LV160AB",

              .uaddr           = {

                     [1] = MTD_UADDR_0x0555_0x02AA /* x16 */

              },

              .DevSize              = SIZE_2MiB,

              .CmdSet              = P_ID_AMD_STD,

              .NumEraseRegions    = 4,

              .regions         = {

                     ERASEINFO(0x04000, 1),            /* 1个16K */

                     ERASEINFO(0x02000, 2),            /* 2个8K */

                     ERASEINFO(0x08000, 1),            /* 1个32K */

                     ERASEINFO(0x10000, 31),          /* 31个32K */

              }

       },

#endif

  1. NOR Flash读写功能测试

(1)从TFTP下载u-boot.bin到SDRAM中启动;

tftp 30008000 u-boot.bin;go 30008000

移植u-boot-2016.11到TQ2440开发板全过程记录_第10张图片

  1. 去掉NOR Flash写保护

protect off all

  1. 擦除指定区域(避开u-boot所在区域)

erase 100000 +10000

(3)从SDRAM拷贝64K数据到NOR Flash

cp.b 30008000 100000 10000

  1. 从NOR Flash读取64K数据到SDRAM

cp.b 100000 30108000 10000

(5)比较64K数据

cmp.b 30108000 30008000 10000

移植u-boot-2016.11到TQ2440开发板全过程记录_第11张图片

  1. 修改u-boot连接地址

TQ2440开发板板载NOR Flash为EON EN29LV160AB,2MB,挂载在0x0000_0000~0x001F_FFFF,2MB、16bit数据位宽,需要修改u-boot.bin文件的链接地址到该区域。

gedit include/configs/tq2440.h

找到:

#define CONFIG_SYS_TEXT_BASE 0x30008000

替换为:

#define CONFIG_SYS_TEXT_BASE 0     /* 从NOR启动的连接地址 */

  1. 使能SDRAM初始化操作

从NOR Flash或者NAND Flash启动时,需要在硬件初始化阶段调用lowlevel_init初始化SDRAM。

gedit include/configs/tq2440.h

用/**/屏蔽以下代码:

/*#define CONFIG_SKIP_LOWLEVEL_INIT*/     /* SDRAM中运行时跳过底层初始化操作 */

  1. 烧录到NOR Flash启动

(1)下载到NOR Flash运行

从TFTP下载u-boot.bin到SDRAM中;

tftp 30008000 u-boot.bin

(2)去掉NOR Flash写保护

protect off all

  1. 擦除NOR Flash

erase 0 +100000

  1. 拷贝到NOR Flash中(NOR Flash写入较慢,约30秒)

cp.b 30008000 0 100000

(4)重启开发板从NOR Flash启动

reset

移植u-boot-2016.11到TQ2440开发板全过程记录_第12张图片

从NOR Flash启动正常,但保存环境变量之后无法启动。

  1. 调整环境变量保存地址

gedit include/configs/tq2440.h

找到:

#define CONFIG_ENV_ADDR                  (CONFIG_SYS_FLASH_BASE + 0x070000)

#define CONFIG_ENV_IS_IN_FLASH

#define CONFIG_ENV_SIZE              0x10000

从TFTP下载时发现:

编译后的u-boot.bin大小为516612字节,占用了NOR Flash的0x0~0x07e204。而源码中默认将环境变量保存在NOR Flash基地址+0x070000位置,所以保存环境变量时破坏了u-boot代码。

修改:

#define CONFIG_ENV_ADDR                  (CONFIG_SYS_FLASH_BASE + 0x070000)

为:

#define CONFIG_ENV_ADDR                  (CONFIG_SYS_FLASH_BASE + 0x100000)

重新烧录到NOR Flash后问题解决:

移植u-boot-2016.11到TQ2440开发板全过程记录_第13张图片

  • 移植NAND Flash驱动
  1. 修改S3C2440的NAND Flash控制器结构体

gedit arch/arm/include/asm/arch-s3c24x0/s3c24x0.h

找到:

/* NAND FLASH (see manual chapter 6) */

struct s3c24x0_nand {

       u32 nfconf;

#ifndef CONFIG_S3C2410

       u32 nfcont;

#endif

       u32 nfcmd;

       u32 nfaddr;

       u32 nfdata;

#ifndef CONFIG_S3C2410

       u32 nfeccd0;

       u32 nfeccd1;

       u32 nfeccd;

#endif

       u32 nfstat;

#ifdef CONFIG_S3C2410

       u32 nfecc;

#else

       u32 nfstat0;

       u32 nfstat1;

       u32 nfmecc0;

       u32 nfmecc1;

       u32 nfsecc;

       u32 nfsblk;

       u32 nfeblk;

#endif

};

对照S3C2440芯片手册,修改为:

/* NAND FLASH (see manual chapter 6) */

struct s3c24x0_nand {

       u32 nfconf;

#if defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440)  

       u32 nfcont;

#endif

       u32 nfcmd;

       u32 nfaddr;

       u32 nfdata;

#if defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440)  

       u32 nfeccd0;

       u32 nfeccd1;

       u32 nfeccd;

#endif

       u32 nfstat;

#ifdef CONFIG_S3C2410

       u32 nfecc;

#elif defined(CONFIG_S3C2440)

       u32 nfstat0;

       u32 nfstat1;

#else

       u32 nfstat0;

       u32 nfstat1;

       u32 nfmecc0;

       u32 nfmecc1;

       u32 nfsecc;

       u32 nfsblk;

       u32 nfeblk;

#endif

};

  1. 修改NAND Flash读写时序

gedit drivers/mtd/nand/s3c2440_nand.c

在board_nand_init函数中找到:

#define S3C2440_NFCONF_EN          (1<<15)

#define S3C2440_NFCONF_512BYTE     (1<<14)

#define S3C2440_NFCONF_4STEP       (1<<13)

#define S3C2440_NFCONF_INITECC     (1<<12)

#define S3C2440_NFCONF_nFCE        (1<<11)

#define S3C2440_NFCONF_TACLS(x)    ((x)<<8)

#define S3C2440_NFCONF_TWRPH0(x)   ((x)<<4)

#define S3C2440_NFCONF_TWRPH1(x)   ((x)<<0)

 

#define S3C2440_ADDR_NALE 4

#define S3C2440_ADDR_NCLE 8

替换为S3C2440的相关寄存器定义:

#define S3C2440_NFCONT_SECCL         (1<<6)

#define S3C2440_NFCONT_MECCL        (1<<5)

#define S3C2440_NFCONT_INITECC             (1<<4)

#define S3C2440_NFCONT_nCE       (1<<1)

#define S3C2440_NFCONT_MODE          (1<<0)

#define S3C2440_NFCONF_TACLS(x)            ((x)<<12)

#define S3C2440_NFCONF_TWRPH0(x) ((x)<<8)

#define S3C2440_NFCONF_TWRPH1(x) ((x)<<4)

 

#define S3C2440_ADDR_NALE        0x08

#define S3C2440_ADDR_NCLE         0x0C

找到board_nand_init函数,替换其中的时序控制和初始化代码:

#else

       tacls = 4;

       twrph0 = 8;

       twrph1 = 8;

#endif

 

       cfg = S3C2440_NFCONF_EN;

       cfg |= S3C2440_NFCONF_TACLS(tacls - 1);

       cfg |= S3C2440_NFCONF_TWRPH0(twrph0 - 1);

       cfg |= S3C2440_NFCONF_TWRPH1(twrph1 - 1);

       writel(cfg, &nand_reg->nfconf);

为:

#else

       tacls = 2;

       twrph0 = 3;

       twrph1 = 1;

#endif

 

        cfg = S3C2440_NFCONF_TACLS(tacls - 1);

        cfg |= S3C2440_NFCONF_TWRPH0(twrph0 - 1);

        cfg |= S3C2440_NFCONF_TWRPH1(twrph1 - 1);

        writel(cfg, &nand_reg->nfconf);

 

        cfg = S3C2440_NFCONT_SECCL;

        cfg |= S3C2440_NFCONT_MECCL;

        cfg |= S3C2440_NFCONT_MODE;

        writel(cfg,&nand_reg->nfcont);

  1. 修改NAND Flash硬件控制

找到s3c24x0_hwcontrol函数,替换写命令和写地址操作相关代码,并在写完命令和地址后把IO端口的地址重新设置为寄存器NFDATA,否则数据无法写入(但仍显示””OK”):

              if (!(ctrl & NAND_CLE))

                     IO_ADDR_W |= S3C2440_ADDR_NCLE;

              if (!(ctrl & NAND_ALE))

                     IO_ADDR_W |= S3C2440_ADDR_NALE;

为:

              if (!(ctrl & NAND_CLE))

                     IO_ADDR_W |= S3C2440_ADDR_NCLE;

              if (!(ctrl & NAND_ALE))

                     IO_ADDR_W |= S3C2440_ADDR_NALE;

              if(cmd ==NAND_CMD_NONE)

                     IO_ADDR_W = (long int) &nand->nfdata;

修改芯片选择操作,找到:

              if (ctrl & NAND_NCE)

                     writel(readl(&nand->nfconf) & ~S3C2440_NFCONF_nFCE,

                            &nand->nfconf);

              else

                     writel(readl(&nand->nfconf) | S3C2440_NFCONF_nFCE,

                            &nand->nfconf);

替换为:

              if (ctrl & NAND_NCE)

                     writel(readl(&nand->nfcont) & ~S3C2440_NFCONT_nCE,

                            &nand->nfcont);

              else

                     writel(readl(&nand->nfcont) | S3C2440_NFCONT_nCE,

                     &nand->nfcont);

  • 实现硬件ECC功能
  1. 定义硬件ECC操作宏

gedit include/configs/tq2440.h

找到:

#define CONFIG_SYS_S3C2440_NAND_HWECC

在下面插入一行定义该宏:

#define CONFIG_S3C2440_NAND_HWECC

  1. 设置S3C2440处理器硬件ECC参数

找到:

#define CONFIG_S3C2440_NAND_HWECC

在下面插入S3C2440硬件ECC参数:

#define CONFIG_SYS_NAND_ECCSIZE       2048      /* 单次校验字节数 */

#define CONFIG_SYS_NAND_ECCBYTES   4     /* ECC字节长度 */

  1. 修改ECC驱动程序

gedit drivers/mtd/nand/s3c2440_nand.c

找到s3c24x0_nand_enable_hwecc函数中的:

writel(readl(&nand->nfconf) | S3C2440_NFCONF_INITECC, &nand->nfconf);

替换为:

writel(readl(&nand->nfcont) | S3C2440_NFCONT_INITECC, &nand->nfcont);

找到s3c24x0_nand_calculate_ecc函数中的:

       struct s3c24x0_nand *nand = s3c24x0_get_base_nand();

       ecc_code[0] = readb(&nand->nfecc);

       ecc_code[1] = readb(&nand->nfecc + 1);

       ecc_code[2] = readb(&nand->nfecc + 2);

       debug("s3c24x0_nand_calculate_hwecc(%p,): 0x%02x 0x%02x 0x%02x\n",

             mtd , ecc_code[0], ecc_code[1], ecc_code[2]);

替换为:

       struct s3c24x0_nand *nand = s3c24x0_get_base_nand();

       unsigned int mecc0;

       writel(readl(&nand->nfcont)|S3C2440_NFCONT_MECCL,&nand->nfcont);

       mecc0 = readl(&nand->nfeccd);

       ecc_code[0] = mecc0 & 0xff;

       ecc_code[1] = (mecc0 >> 8) & 0xff;

       ecc_code[2] = (mecc0 >>16) & 0xff;

       ecc_code[3] = (mecc0 >>24) & 0xff;

       debug("s3c24x0_nand_calculate_hwecc(%p,): 0x%02x 0x%02x 0x%02x 0x%02x\n",

              mtd , ecc_code[0], ecc_code[1], ecc_code[2],ecc_code[3]);

找到s3c24x0_nand_correct_data函数中的:

       if (read_ecc[0] == calc_ecc[0] &&

           read_ecc[1] == calc_ecc[1] &&

           read_ecc[2] == calc_ecc[2])

              return 0;

 

       printf("s3c24x0_nand_correct_data: not implemented\n");

       return -1;

替换为:

       struct s3c24x0_nand *nand = s3c24x0_get_base_nand();

       u32 meccdata0,meccdata1,estat0,err_byte_addr;

       int ret=-1;

       u8 repaired;

       meccdata0 = (read_ecc[1] << 16) | read_ecc[0];

       meccdata1 = (read_ecc[3] << 16) | read_ecc[2];

       writel(meccdata0,&nand->nfeccd0);

       writel(meccdata1,&nand->nfeccd1);

       /* read ecc status */

       estat0 = readl(&nand->nfstat0);

       switch (estat0 &0x3){

       case 0: /* no error */

              ret =0;

              break;

       case 1:

              /*

              * 1bit error(correctable)

              * (nfestat0 >>7) & 0x7ff    error byte number

              * (nfestat0 >>4) & 0x7      error bit number

                */

              err_byte_addr = (estat0 >>7 ) & 0x7ff;

              repaired = dat[err_byte_addr]^(1<<((estat0 >>4) & 0x7));

              printf("S3C NAND: 1 bit error detected at byte %ld.Correcting from 0x%02x to0x%02x...OK\n", (long int) err_byte_addr, dat[err_byte_addr],repaired);

              dat[err_byte_addr]= repaired;

              ret= 1;

              break;

       case  2: /* Multiple error */

       case  3: /* ECC area error */

              printf("S3C NAND: ECC uncorrectable errordetected.Not correctable.\n");

              ret= -1;

              break;

       }

       return ret;

  1. 实现软件擦除坏块功能

(1)开启Nand Flash数据读写校验功能

gedit include/configs/tq2440.h

在NAND configuration段添加:

#define CONFIG_MTD_NAND_VERIFY_WRITE 1     /* 开启NAND读写校验 */

(2)实现软件擦除坏块功能

gedit drivers/mtd/nand/nand_util.c

在nand_erase_opts函数定义前面(文件开头)插入:

static int nand_block_bad_scrub(struct mtd_info *mtd, loff_t ofs, int getchip)

{

       return 0;

}

(3)修改nand_erase_opts函数

找到:

int percent_complete = -1;

在下一行插入:

int (*nand_block_bad_old)(struct mtd_info *, loff_t, int) = NULL;

找到:

if (opts->scrub) {

              erase.scrub = opts->scrub;

下一行插入:

              nand_block_bad_old = chip->block_bad;

              chip->block_bad = nand_block_bad_scrub;

找到:

       if (opts->scrub)

上一行插入:

       if(nand_block_bad_old)

       {

              chip->block_bad=nand_block_bad_old;

       }

  1. 烧写到NOR Flash运行

(1)下载u-boot到NOR Flash中

从TFTP下载u-boot.bin到SDRAM中;

tftp 30008000 u-boot.bin

(2)去掉NOR Flash写保护

protect off all

(3)擦除NOR Flash

erase 0 +100000

(4)拷贝到NOR Flash中(NOR Flash写入较慢,约30秒)

cp.b 30008000 0 100000

(5)重启开发板从NOR Flash启动

reset

移植u-boot-2016.11到TQ2440开发板全过程记录_第14张图片

  1. NAND Flash读写功能测试

(1)擦除测试

擦除Nand Flash中0x0开始的0x300000字节空间

nand erase 0x0 0x300000

移植u-boot-2016.11到TQ2440开发板全过程记录_第15张图片

(2)写操作测试

将SDRAM的0x32000000地址的0xff字节数据写到NAND FLASH的0地址

nand write 32000000 0 ff

(3)读操作测试

从NAND FLASH的0地址读0xff字节数据到SDRAM的0x31000000地址

nand read 31000000 0 ff

(4)比较数据是否正确

cmp.b 31000000 32000000 ff

(5)查看NAND Flash分区信息

mtd

  • 创建MTD分区
  1. 定义MTD分区信息

gedit include/configs/tq2440.h

确认CONFIG_CMD_MTDPARTS、CONFIG_MTD_DEVICE和CONFIG_MTD_PARTITIONS宏已打开,然后找到:

/*

 * NAND configuration

 */

#ifdef CONFIG_CMD_NAND

#define CONFIG_NAND_S3C2440

#define CONFIG_SYS_S3C2440_NAND_HWECC

#define CONFIG_SYS_MAX_NAND_DEVICE     1

#define CONFIG_SYS_NAND_BASE       0x4E000000

#endif

在下方添加:

#define MTDIDS_DEFAULT "nand0=tq2440-nand.0"

#define MTDPARTS_DEFAULT "mtdparts=tq2440-nand.0:512k(u-boot-spl)," \

                                   "1m(u-boot)," \

                                   "256k(params)," \

                                   "4m(kernel)," \

                                   "-(rootfs)"

  1. 设置u-boot默认启动参数和命令

在分区信息下添加:

#define CONFIG_BOOTARGS "root=/dev/mtdblock4 rootfstype=yaffs2 init=/linuxrc console=ttySAC0,115200"

#define CONFIG_BOOTCOMMAND "nand read 32000000 kernel;bootm 32000000"

即启动时将uImage烧到名为kernel的分区。

  • 保存环境变量到NAND Flash
  1. 设置环境变量保存地址

为防止保存环境变量时将u-boot程序破坏掉,重新定义环境变量的偏移地址:

gedit include/configs/tq2440.h

找到:

define CONFIG_ENV_ADDR(CONFIG_SYS_FLASH_BASE + 0x070000)

#define CONFIG_ENV_IS_IN_FLASH

#define CONFIG_ENV_SIZE 0x10000

#define CONFIG_ENV_OVERWRITE

替换为:

#define CONFIG_ENV_IS_IN_NAND

#define CONFIG_ENV_OFFSET 0x00180000

#define CONFIG_ENV_SIZE 0x40000

#define CONFIG_ENV_RANGE CONFIG_ENV_SIZE

其中:

  1. CONFIG_ENV_OFFSET:环境变量的写入地址,0x00180000表示前面预留了512k+1m作为spl和u-boot的分区;
  2. CONFIG_ENV_SIZE:预留的环境变量大小,0x40000表示环境变量分区大小为256K
  3. CONFIG_ENV_RANGE:环境变量擦除范围,必须大于等于CONFIG_ENV_SIZE。
  1. 烧写到NOR Flash运行

(1)下载u-boot到NOR Flash中

从TFTP下载u-boot.bin到SDRAM中;

setenv ethaddr 11:22:33:44:55:66;tftp 30008000 u-boot.bin

(2)擦除并拷贝到NOR Flash中(NOR Flash写入较慢,约30秒)

protect off all;erase 0 +100000;cp.b 30008000 0 100000

(3)重启开发板从NOR Flash启动

reset

  1. 重新创建MTD分区

(1)擦除NAND Flash(非必须操作)

nand erase.chip

(2)加载默认MTD分区

mtd default

(3)查看MTD分区信息

mtd

移植u-boot-2016.11到TQ2440开发板全过程记录_第16张图片

  • 非SPL方式从NAND Flash启动
  1. 取消链接时的PIE选项

在链接的时候,如果我们启用了PIE功能,那么程序中的变量就会被抽出来放到代码段后面的一些特殊段,而这些变量的地址肯定超过了4K而无法再访问了,所以我们要去除这个PIE功能。

gedit arch/arm/config.mk

找到LDFLAGS_u-boot += -pie,用#号注释掉。由于我们禁用了PIE选项,所以找到相对位置检查的配置项ALL-y += checkarmreloc选项,用#号注释掉。这样,在后续程序中我们就不需要在重定位代码后再去计算变量的相对位置。

  1. 新建一个自定义的初始化函数

gedit board/samsung/tq2440/init.c

内容如下:

/* NAND FLASH控制器 */ 

#define NFCONF (*((volatile unsigned long *)0x4E000000)) 

#define NFCONT (*((volatile unsigned long *)0x4E000004)) 

#define NFCMMD (*((volatile unsigned char *)0x4E000008)) 

#define NFADDR (*((volatile unsigned char *)0x4E00000C)) 

#define NFDATA (*((volatile unsigned char *)0x4E000010)) 

#define NFSTAT (*((volatile unsigned char *)0x4E000020)) 

/* GPIO */ 

#define GPHCON              (*(volatile unsigned long *)0x56000070) 

#define GPHUP               (*(volatile unsigned long *)0x56000078) 

/* UART registers*/ 

#define ULCON0              (*(volatile unsigned long *)0x50000000) 

#define UCON0               (*(volatile unsigned long *)0x50000004) 

#define UFCON0              (*(volatile unsigned long *)0x50000008) 

#define UMCON0              (*(volatile unsigned long *)0x5000000c) 

#define UTRSTAT0            (*(volatile unsigned long *)0x50000010) 

#define UTXH0               (*(volatile unsigned char *)0x50000020) 

#define URXH0               (*(volatile unsigned char *)0x50000024) 

#define UBRDIV0             (*(volatile unsigned long *)0x50000028) 

#define TXD0READY   (1<<2) 

void nand_read_ll(unsigned int addr, unsigned char *buf, unsigned int len);

static int isBootFromNorFlash(void) 

{

       volatile int *p = (volatile int *)0;

       int val;

       val = *p;

       *p = 0x12345678;

       if (*p == 0x12345678) 

       {

              /* 写成功, 是nand启动 */ 

              *p = val;

              return 0;

       }

       else 

       {

              /* NOR不能像内存一样写 */ 

       return 1;

       }

}

 

void copy_code_to_sdram(unsigned char *src, unsigned char *dest, unsigned int len) 

{  

       int i = 0;

       /* 如果是NOR启动 */ 

       if (isBootFromNorFlash()) 

       {

              while (i < len) 

              {

                     dest[i] = src[i];

                     i++;

              }

       }

       else 

       {

              //nand_init();

              nand_read_ll((unsigned int)src, dest, len);

       }

}

 

void clear_bss(void) 

{

       extern int __bss_start, __bss_end;

       int *p = &__bss_start;

       for (; p < &__bss_end; p++) 

       *p = 0;

}

 

void nand_init_ll(void) 

{

#define TACLS   0 

#define TWRPH0  1 

#define TWRPH1  0 

       /* 设置时序 */ 

       NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);

       /* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */ 

       NFCONT = (1<<4)|(1<<1)|(1<<0); 

}

 

static void nand_select(void) 

{

       NFCONT &= ~(1<<1);

}

 

static void nand_deselect(void) 

{

       NFCONT |= (1<<1);  

}

 

static void nand_cmd(unsigned char cmd) 

{

       volatile int i;

       NFCMMD = cmd;

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

}

 

static void nand_addr(unsigned int addr) 

{

       unsigned int col  = addr % 2048;

       unsigned int page = addr / 2048;

       volatile int i;

       NFADDR = col & 0xff;

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

       NFADDR = (col >> 8) & 0xff;

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

       NFADDR  = page & 0xff;

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

       NFADDR  = (page >> 8) & 0xff;

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

       NFADDR  = (page >> 16) & 0xff;

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

}

 

static void nand_wait_ready(void) 

{

       while (!(NFSTAT & 1));

}

 

static unsigned char nand_data(void) 

{

       return NFDATA;

}

 

void nand_read_ll(unsigned int addr, unsigned char *buf, unsigned int len) 

{

       int col = addr % 2048;

       int i = 0;

       /* 1. 选中 */ 

       nand_select();

       while (i < len) 

       {

              /* 2. 发出读命令00h */ 

              nand_cmd(0x00);

              /* 3. 发出地址(分5步发出) */ 

              nand_addr(addr);

              /* 4. 发出读命令30h */ 

              nand_cmd(0x30);

              /* 5. 判断状态 */ 

              nand_wait_ready();

              /* 6. 读数据 */ 

              for (; (col < 2048) && (i < len); col++) 

              {

                     buf[i] = nand_data();

                     i++;

                     addr++;

              }

              col = 0;

       }

       /* 7. 取消选中 */        

       nand_deselect();

}

  1. 修改启动代码

gedit arch/arm/lib/crt0.S

找到:

       mov       r0, sp

       bl    board_init_f_alloc_reserve

       mov       sp, r0

替换为:

       bl nand_init_ll

       mov       r0, #0

       ldr   r1, =_start

       ldr   r2, =__bss_start

       sub  r2, r2, r1

       ldr   r1, =CONFIG_SYS_TEXT_BASE

       bl    copy_code_to_sdram

       bl    clear_bss

       ldr   pc, =START_ON_RAM          //start run on RAM

START_ON_RAM:

       mov       r0, sp

       bl    board_init_f_alloc_reserve

       mov       sp, r0

找到:

       mov       r0, #0

       bl    board_init_f

在下面插入一行:

       str   r1, [r0]

找到:

       ldr   r0, [r9, #GD_RELOCADDR]        /* r0 = gd->relocaddr */

       b     relocate_code

替换为:

       ldr   r0, [r9, #GD_RELOCADDR]        /* r0 = gd->relocaddr */

       ldr   r2, =__rel_dyn_start

       ldr   r3, =__rel_dyn_end

找到:

       bl    relocate_vectors

 

/* Set up final (full) environment */

 

       bl    c_runtime_cpu_setup /* we still call old routine here */

替换为:

#if 0

       bl    relocate_vectors

 

/* Set up final (full) environment */

 

       bl    c_runtime_cpu_setup /* we still call old routine here */

#endif

找到:

       ldr   r0, =__bss_start   /* this is auto-relocated! */

在前面插入一行:

#if 0

找到:

       blo  clbss_l

在后面插入一行:

#endif

  1. 修改编译链接选项

将crt0.c和vectors.c单独编译,不要链接到built-in.o

gedit arch/arm/lib/Makefile

找到:

obj-y      += vectors.o crt0.o

替换为:

extra-y   += vectors.o crt0.o

修改连接文件,保证代码拷贝函数编译到前4K

gedit arch/arm/cpu/u-boot.lds

找到:

              CPUDIR/start.o (.text*)

在下面插入:

              arch/arm/lib/crt0.o (.text*)

              arch/arm/lib/vectors.o (.text*)

              board/samsung/tq2440/built-in.o (.text*)

  1. 修改连接地址

gedit include/configs/tq2440.h

找到:

#define CONFIG_SYS_TEXT_BASE 0x32000000 /* 从SDRAM启动的连接地址 */

替换为:

#define CONFIG_SYS_TEXT_BASE 0x32000000 /* 从NAND启动后拷贝到SDRAM中的运行地址 */

  1. 查看NAND初始化和代码拷贝函数编译位置

arm-linux-objdump -D u-boot > u-boot.dis

gedit u-boot.dis

查找nand_init_ll

移植u-boot-2016.11到TQ2440开发板全过程记录_第17张图片

地址段为:330005b4~330005c8,而拷贝代码的及地址为33000000,二者之差小于1000,所以在4k范围内。

查找copy_code_to_sdram

移植u-boot-2016.11到TQ2440开发板全过程记录_第18张图片

也在前4K地址范围内。

  1. 烧录到NAND Flash运行

setenv ethaddr 11:22:33:44:55:66;set serverip 192.168.1.10;nand erase 0 0x100000;tftp 32000000 u-boot.bin;nand write 32000000 0 0x100000

移植u-boot-2016.11到TQ2440开发板全过程记录_第19张图片

  • 添加LCD支持
  1. 添加LCD配置

gedit include/configs/tq2440.h

在末尾添加:

/*

 *LCD

 */

#define CONFIG_LCD

#define LCD_BPP     LCD_COLOR16

#define CONFIG_LCD_LOGO    /* 显示LOGO */

#undef LCD_TEST_PATTERN

#define CONFIG_LCD_INFO      /* 显示用户定义的信息 */

#define CONFIG_LCD_INFO_BELOW_LOGO     /* 用户自定义的信息与LOGO的位置关系 */

#define CONFIG_SYS_WHITE_ON_BLACK /* 颜色, 黑底白字 */

#define CONFIG_SYS_CONSOLE_IS_IN_ENV

 

#define CONFIG_CONSOLE_SCROLL_LINES 16 /* 屏幕显示总行数 */

 

#define CONFIG_TQ2440_LCD  /* 这个是我自己加的,负责将我添加的文件编译进来 */

#define CONFIG_CONSOLE_MUX   /* 这个配置可以支持将u-boot的打印输出同时定向到串口和LCD屏,否则只支持一个 */

 

/*

下面这些参数是LCD的硬件信息,需要阅读LCD的芯片手册,我使用的LCD的分辨率是480*272,下面的值我选用的

是LCD芯片手册中的典型值,芯片手册的名字:WXCAT43-TG6#001_V1.0.pdf

*/

#define  CONFIG_TQ2440_LCD_VBPD   1

#define  CONFIG_TQ2440_LCD_VFPD   1

#define  CONFIG_TQ2440_LCD_VSPW  9

#define  CONFIG_TQ2440_LCD_HBPD   1

#define  CONFIG_TQ2440_LCD_HFPD   1

#define  CONFIG_TQ2440_LCD_HSPW  40

#define  CONFIG_TQ2440_LCD_CLKVAL    4

 

#define LCD_XSIZE_TFT     (480)

#define LCD_YSIZE_TFT     (272)

 

#define MVAL    (13)

#define MVAL_USED     (0)   //0=each frame   1=rate by MVAL

#define INVVDEN   (1)   //0=normal       1=inverted

#define BSWP    (0)   //Byte swap control

#define HWSWP (1)   //Half word swap control

/*#define CONFIG_SYS_DCACHE_OFF*/   /* 不定义编译的时候会报错 */

  1. 利用LCD输出欢迎信息

gedit board/samsung/tq2440/tq2440.c

在开头添加

#include

#include

在末尾添加:

#ifdef CONFIG_LCD_INFO

void lcd_show_board_info(void)

{

       lcd_printf ("%s (%s - %s)\n", U_BOOT_VERSION, U_BOOT_DATE, U_BOOT_TIME);

}

#endif /* CONFIG_LCD_INFO */

  1. 添加LCD初始化函数

gedit drivers/video/tq2440_fb.c

代码如下:

#include

#include

 

#include

#include

#include

 

DECLARE_GLOBAL_DATA_PTR;

 

#define U32 unsigned int

#define M5D(n)  ( ( n ) & 0x1fffff ) // To get lower 21bits

#define SCR_XSIZE_TFT LCD_XSIZE_TFT

 

#define HOZVAL_TFT        ( LCD_XSIZE_TFT - 1 )

#define LINEVAL_TFT        ( LCD_YSIZE_TFT - 1 )

 

vidinfo_t panel_info = {

       .vl_col = LCD_XSIZE_TFT,   /* 水平分辨率 */

       .vl_row = LCD_YSIZE_TFT,   /* 垂直分辨率 */

       .vl_bpix = LCD_BPP,        /* 每个像素用几位表示,这个在 include/configs/tq2440.h中配置了,我使用的是16位 */

};

 

//volatile unsigned short (*embedsky_LCD_BUFFER)[SCR_XSIZE_TFT] = (volatile unsigned short (*)[SCR_XSIZE_TFT])(gd->fb_base);

/*

       gd->fb_base指向的是FreamBuffer的其实地址,这里我们把它强制转换为一个二维数组来使用

*/

#define embedsky_LCD_BUFFER ((volatile unsigned short (*)[SCR_XSIZE_TFT])(gd->fb_base))

volatile char vbpd = 1, vfpd = 1, vspw = 1, hbpd = 1, hfpd = 1, hspw = 1, clkval_tft = 1 ;

 

void tq2440_lcd_ClearScr(U32 c)

{

       unsigned int x,y ;

        

       for( y = 0 ; y < LCD_YSIZE_TFT ; y++ )

       {

              for( x = 0 ; x < (SCR_XSIZE_TFT) ; x++ )

              {

                     embedsky_LCD_BUFFER[y][x] = c;

              }

       }  

}

 

void tq2440_lcd_PowerEnable(int invpwren , int pwren)

{

       struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio() ;

       struct s3c24x0_lcd * const lcd = s3c24x0_get_base_lcd() ;

 

       //GPG4 is setted as LCD_PWREN

       gpio -> gpgup = gpio -> gpgup & (( ~( 1 << 4) ) | ( 1 << 4) );        // Pull-up disable

       gpio -> gpgcon = gpio -> gpgcon & (( ~( 3 << 8) ) | ( 3 << 8) );        //GPG4=LCD_PWREN

       gpio -> gpgdat = gpio -> gpgdat | (1 << 4 ) ;

       //invpwren=pwren;

       //Enable LCD POWER ENABLE Function

       lcd -> lcdcon5 = lcd -> lcdcon5 & (( ~( 1 << 3 ) ) | ( pwren << 3 ) );    // PWREN

       lcd -> lcdcon5 = lcd -> lcdcon5 & (( ~( 1 << 5 ) ) | ( invpwren << 5 ) );    // INVPWREN

}

 

void lcd_ctrl_init(void *lcdbase)

{

       struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio() ;

       struct s3c24x0_lcd * const lcd = s3c24x0_get_base_lcd() ;

       char *s_lcd;

 

       lcd -> lcdsaddr1 = ( ( ( U32 ) embedsky_LCD_BUFFER >> 22 ) << 21 ) | M5D ( ( U32 ) embedsky_LCD_BUFFER >> 1 ) ;

       lcd -> lcdsaddr2 = M5D( ( ( U32) embedsky_LCD_BUFFER + ( SCR_XSIZE_TFT * LCD_YSIZE_TFT * 2 ) ) >> 1 ) ;

       lcd -> lcdsaddr3 = ( ( ( SCR_XSIZE_TFT - LCD_XSIZE_TFT ) / 1 ) << 11 ) | ( LCD_XSIZE_TFT /1 ) ;

 

       s_lcd = getenv ("dwVBPD");

       vbpd = s_lcd ? (int)simple_strtol(s_lcd, NULL, 10) : CONFIG_TQ2440_LCD_VBPD;

 

       s_lcd = getenv ("dwVFPD");

       vfpd = s_lcd ? (int)simple_strtol(s_lcd, NULL, 10) : CONFIG_TQ2440_LCD_VFPD;

 

       s_lcd = getenv ("dwVSPW");

       vspw = s_lcd ? (int)simple_strtol(s_lcd, NULL, 10) : CONFIG_TQ2440_LCD_VSPW;

 

       s_lcd = getenv ("dwHBPD");

       hbpd = s_lcd ? (int)simple_strtol(s_lcd, NULL, 10) : CONFIG_TQ2440_LCD_HBPD;

 

       s_lcd = getenv ("dwHFPD");

       hfpd = s_lcd ? (int)simple_strtol(s_lcd, NULL, 10) : CONFIG_TQ2440_LCD_HFPD;

 

       s_lcd = getenv ("dwHSPW");

       hspw = s_lcd ? (int)simple_strtol(s_lcd, NULL, 10) : CONFIG_TQ2440_LCD_HSPW;

 

       s_lcd = getenv ("dwCLKVAL");

       clkval_tft = s_lcd ? (int)simple_strtol(s_lcd, NULL, 10) : CONFIG_TQ2440_LCD_CLKVAL;

 

       tq2440_lcd_ClearScr( 0x0 ) ;

 

       gpio -> gpcup  = 0xffffffff ;

       gpio -> gpccon = 0xaaaaaaaa ;                        //Initialize VD[0:7]    

        

       gpio -> gpdup  = 0xffffffff ;

       gpio -> gpdcon = 0xaaaaaaaa ;                        //Initialize VD[15:8]

 

       lcd -> lcdcon1 = ( clkval_tft << 8 ) | ( MVAL_USED << 7 ) | (3 << 5 ) | ( 12 << 1 ) | 0 ;

       // TFT LCD panel,16bpp TFT,ENVID=off

       lcd -> lcdcon2 = ( vbpd << 24 ) | ( LINEVAL_TFT << 14 ) | ( vfpd << 6 ) | ( vspw ) ;

       lcd -> lcdcon3 = ( hbpd << 19 ) | ( HOZVAL_TFT << 8 ) | ( hfpd ) ;

       lcd -> lcdcon4 = ( MVAL << 8 ) | ( hspw ) ;

       lcd -> lcdcon5 = ( 1 << 11) | ( 0 << 10 ) | ( 1 << 9 ) | ( 1 << 8 ) | ( 0 << 7 ) | ( 0 << 6 ) | ( 1 << 3 ) | ( BSWP << 1 ) | ( HWSWP ) ;

 

       lcd -> lcdintmsk |= (3) ;                        // MASK LCD Sub Interrupt

       lcd -> lpcsel &= ( ~7 ) ;                        // Disable LPC3480

       lcd -> tpal = 0x0 ;                            // Disable Temp Palette

 

       tq2440_lcd_PowerEnable( 0, 1 ) ;

}

 

void lcd_enable(void)

{

       struct s3c24x0_lcd * const lcd = s3c24x0_get_base_lcd() ;

       lcd -> lcdcon1 |= 1 ;                        // ENVID=ON

}

添加编译选项:

gedit drivers/video/Makefile

在其中添加:

obj-$(CONFIG_TQ2440_LCD) += tq2440_fb.o

  1. 将调试信息同时定位到LCD和串口输出

在u-boot启动信息中可看到,当前输入输出设备均为serial。

使用coninifo命令查看支持的终端:

移植u-boot-2016.11到TQ2440开发板全过程记录_第20张图片

使用setenv stdout 'lcd,serial'命令将输出终端设置为LCD和串口,使用saveenv命令保存。

  1. 烧录到NAND Flash运行

setenv ethaddr 11:22:33:44:55:66;set serverip 192.168.1.10;nand erase 0 0x100000;tftp 32000000 u-boot.bin;nand write 32000000 0 0x100000

你可能感兴趣的:(移植u-boot-2016.11到TQ2440开发板全过程记录)