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/
gedit Makefile
找到:
# set default to nothing for native builds
ifeq ($(HOSTARCH),$(ARCH))
CROSS_COMPILE ?=
endif
在下方新插入一行:
CROSS_COMPILE ?=arm-linux-
(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
cp include/configs/smdk2410.h include/configs/tq2440.h
编辑该文件:
gedit include/configs/tq2440.h
替换S3C2410为S3C2440,替换SMDK2410为TQ2440
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
创建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)清理环境并重新编译
make distclean
make tq2440_defconfig
make
编译失败,并提示” Not enough room for program headers, try linking with -N”错误:
错误信息:
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”错误
错误信息:
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)编写自动编译脚本
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开发板的前期准备工作。
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)修改芯片时钟初始化代码
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
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 */
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
GPB共有11个引脚,有高到低依次为GPB10-GPB0。TQ2440开发板的四个板载LED分别位于GPB8-GPB5,由GPBCON、GPBUP和GPBDAT三个寄存器控制。
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);
gedit arch/arm/lib/cache.c
由于前面我们已经启用了I/D Cache,所以这个警告是错误的,找到:
puts("WARNING: Caches not enabled\n");
用/**/注释掉。
至此,我们完成了芯片级初始化和高级初始化代码的修改。需要注意的是,在board/samsung/tq2440/tq2440.c的board_init函数中有一句:
/* adress of boot parameters */
gd->bd->bi_boot_params = 0x30000100;
指定了在SDRAM中运行时环境变量保存地址,后面再来研究。
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启动的连接地址 */
根据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函数的调用:
在配置头文件中添加该宏:
gedit include/configs/tq2440.h
在文件开头插入:
/*
* Debug Options
*/
#define DEBUG /* 输出详细的调试信息 */
#define CONFIG_SKIP_LOWLEVEL_INIT /* 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)烧写天嵌科技官方的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
启动时正确识别出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版本自带了DM9000网卡驱动程序,只需要做简单修改和调用即可使用。DM9000位于TQ2440的BANK4,则对应基地址为0x20000000;使用LADDR2作为CMD信号,所以命令寄存器地址为0x20000004。
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
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)添加网卡地址到默认环境变量数组中
gedit include/env_default.h
找到:
#ifdef CONFIG_SERVERIP
"serverip=" __stringify(CONFIG_SERVERIP) "\0"
#endif
在下面添加:
#ifdef CONFIG_ETHADDR
"ethaddr=" __stringify(CONFIG_ETHADDR) "\0"
#endif
(1)下载到SDRAM运行
从TFTP下载u-boot.bin到SDRAM中运行;
tftp 30008000 u-boot.bin;go 30008000
已经正确识别到DM9000网卡。
(2)ping测试
ping 192.168.1.10
(3)TFTP下载功能测试
tftp 320000 u-boot.bin
有空回来完善ethaddr环境变量保存问题。
gedit include/configs/tq2440.h
配置头文件中支持NOR FLASH的相关宏参数包括:
根据芯片手册修改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
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)从TFTP下载u-boot.bin到SDRAM中启动;
tftp 30008000 u-boot.bin;go 30008000
protect off all
erase 100000 +10000
(3)从SDRAM拷贝64K数据到NOR Flash
cp.b 30008000 100000 10000
cp.b 100000 30108000 10000
(5)比较64K数据
cmp.b 30108000 30008000 10000
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启动的连接地址 */
从NOR Flash或者NAND Flash启动时,需要在硬件初始化阶段调用lowlevel_init初始化SDRAM。
gedit include/configs/tq2440.h
用/**/屏蔽以下代码:
/*#define CONFIG_SKIP_LOWLEVEL_INIT*/ /* SDRAM中运行时跳过底层初始化操作 */
(1)下载到NOR Flash运行
从TFTP下载u-boot.bin到SDRAM中;
tftp 30008000 u-boot.bin
(2)去掉NOR Flash写保护
protect off all
erase 0 +100000
cp.b 30008000 0 100000
(4)重启开发板从NOR Flash启动
reset
从NOR Flash启动正常,但保存环境变量之后无法启动。
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后问题解决:
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
};
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);
找到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);
gedit include/configs/tq2440.h
找到:
#define CONFIG_SYS_S3C2440_NAND_HWECC
在下面插入一行定义该宏:
#define CONFIG_S3C2440_NAND_HWECC
找到:
#define CONFIG_S3C2440_NAND_HWECC
在下面插入S3C2440硬件ECC参数:
#define CONFIG_SYS_NAND_ECCSIZE 2048 /* 单次校验字节数 */
#define CONFIG_SYS_NAND_ECCBYTES 4 /* 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)开启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)下载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
(1)擦除测试
擦除Nand Flash中0x0开始的0x300000字节空间
nand erase 0x0 0x300000
(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
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)"
在分区信息下添加:
#define CONFIG_BOOTARGS "root=/dev/mtdblock4 rootfstype=yaffs2 init=/linuxrc console=ttySAC0,115200"
#define CONFIG_BOOTCOMMAND "nand read 32000000 kernel;bootm 32000000"
即启动时将uImage烧到名为kernel的分区。
为防止保存环境变量时将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)下载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)擦除NAND Flash(非必须操作)
nand erase.chip
(2)加载默认MTD分区
mtd default
(3)查看MTD分区信息
mtd
在链接的时候,如果我们启用了PIE功能,那么程序中的变量就会被抽出来放到代码段后面的一些特殊段,而这些变量的地址肯定超过了4K而无法再访问了,所以我们要去除这个PIE功能。
gedit arch/arm/config.mk
找到LDFLAGS_u-boot += -pie,用#号注释掉。由于我们禁用了PIE选项,所以找到相对位置检查的配置项ALL-y += checkarmreloc选项,用#号注释掉。这样,在后续程序中我们就不需要在重定位代码后再去计算变量的相对位置。
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();
}
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
将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*)
gedit include/configs/tq2440.h
找到:
#define CONFIG_SYS_TEXT_BASE 0x32000000 /* 从SDRAM启动的连接地址 */
替换为:
#define CONFIG_SYS_TEXT_BASE 0x32000000 /* 从NAND启动后拷贝到SDRAM中的运行地址 */
arm-linux-objdump -D u-boot > u-boot.dis
gedit u-boot.dis
查找nand_init_ll
地址段为:330005b4~330005c8,而拷贝代码的及地址为33000000,二者之差小于1000,所以在4k范围内。
查找copy_code_to_sdram
也在前4K地址范围内。
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
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*/ /* 不定义编译的时候会报错 */
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 */
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
在u-boot启动信息中可看到,当前输入输出设备均为serial。
使用coninifo命令查看支持的终端:
使用setenv stdout 'lcd,serial'命令将输出终端设置为LCD和串口,使用saveenv命令保存。
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