U-BOOT 移植到友善之臂mini2440

2022年01月13日 阅读数:4
这篇文章主要向大家介绍U-BOOT 移植到友善之臂mini2440,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。



U-BOOT 移植到友善之臂mini2440linux




开发环境:ubuntu 10.10编程


编译器:友善之臂mini2440光盘自带arm-linux-gcc 4.4.3ubuntu



一. 在denx官网下载源码,我所用版本号为u-boot-2010.03。               
二. 主机编译环境为友善之臂提供的arm-linux-gcc.所參考板子为smdk2410。
三. 启动第一阶段移植过程
网络

1.首先測试编译环境,因为arm-linux-gcc,已经添�了PATH环境变量,在lib_arm文件夹下的config.mk 定义了CRPSS_COMPILE 为arm-linux-,而主文件夹下的Makefile包括这个文件,因此交叉编译工具连就已经肯定了。无需再改。架构

$cd  u-boot-mini2440
$make smdk2410_config
$make

编译经过,说明编译环境没有问题。ssh

2.创建mini2440配置以及文件ide

 (1)进入顶层文件夹Makefile,找到:函数

smdk2410_config :       unconfig
@$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 samsung s3c24x0

复制并改动成:工具

mini2440_config :       unconfig
@$(MKCONFIG) $(@:_config=) arm arm920t mini2440 samsung s3c24x0

注意:@前面是tab键,不然编译配置的时候出错。oop

            这条命令实际是运行顶层文件夹下的 mkconfig,后面的都是參数

 (2)进入/board/samsung,将smdk2410文件夹,复制成为mini2440.这个是咱们的开发板的文件夹。进入mini2440文件夹,改动smdk2410.c为mini2440.c。改动Makefile:

COBJS   := mini2440.o flash.o

 (3)进入/include/configs,将smdk2410.h,复制成为mini2440.h,这个是咱们的配置文件。

这样咱们的开发板的文件就都有了,但是内容都是smdk2410开发板的。

编译測试

make clean
make mini2440_config
make

编译经过说明没有问题。

3. start.S的改动(1)

@       bl      coloured_LED_init
@ bl red_LED_on

这个mini2440没有彩色灯,因此要凝视掉

# if defined(CONFIG_S3C2440)
ldr r1, =0x3fff
ldr r0, =INTSUBMSK
str r1, [r0]
# endif

因为子中断2440有15个,因此要改一下。

# if defined(CONFIG_S3C2440)
#define MPLLCON 0x4c000004
#define UPLLCON 0x4c000008
/* FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 405 MHz ! */
ldr r0, =CLKDIVN
mov r1, #5
str r1, [r0]
ldr r0, =MPLLCON
ldr r1, =(0x7f<<12)|(0x02<<4)|(0x01)
str r1, [r0]
ldr r0, =UPLLCON
ldr r1, =(0x38<<12)|(0x02<<4)|(0x02)
str r1, [r0]
# else
/* FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
#endif /* CONFIG_S3C2440 */

以上是S3C2440时钟初始化的代码,可以看出2410和2440时钟初始化仍是区别很是大的。

4.  初始化时钟后,紧接着就是cpu内部初始化。这个函数cpu_init_crit无需改动,但是里面调用的lowlevel_init函数必须改动,因为是初始化内存的代码,每个开发板的内存都不一样,因此lowlevel_init.S在/board/samsung/mini2440文件夹里。

#define Trp                     0x2     /* 2clk */
#define REFCNT 1012


5. 加入�检查代码位置以及推断启动方式的代码

/*********** CHECK_CODE_POSITION ************/
adr r0, _start /* r0 <- current position of code */
ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
cmp r0, r1 /* don't reloc during debug */
beq stack_setup
/***************** CHECK_CODE_POSITION ****/
/***************** CHECK_BOOT_FLASH *******/
#define rBWSCON 0x48000000
mov r0, #rBWSCON
ldr r0, [r0]
bic r0, r0, #0xfffffff5 /* BWSCON[2:1] is controled by OM[1:0] */
cmp r0, #0 /* when OM[1:0] is 00,BSWCON[2:1]=00, nand flash boot */


bne relocate /* norflash boot */
/*****************CHECK_BOOT_FLASH*************************/

检查启动代码位置,是经过比較当前的代码位置和TEXT_BASE之间是否一样来推断的

而推断启动方式是经过检查BWSCON[2:1]来推断的,详细实现见start.S的分析

6.加入�Nandflash启动代码

#define LENGTH_UBOOT 0x60000
#define NAND_CTL_BASE 0x4E000000
#ifdef CONFIG_S3C2440
/* Offset */
#define oNFCONF 0x00
#define oNFCONT 0x04
#define oNFCMD 0x08
#define oNFSTAT 0x20
@ reset NAND
mov r1, #NAND_CTL_BASE
ldr r2, =( (7<<12)|(7<<8)|(7<<4)|(0<<0) )
str r2, [r1, #oNFCONF]
ldr r2, [r1, #oNFCONF]
ldr r2, =( (1<<4)|(0<<1)|(1<<0) ) @ Active low CE Control
str r2, [r1, #oNFCONT]
ldr r2, [r1, #oNFCONT]
ldr r2, =(0x6) @ RnB Clear
str r2, [r1, #oNFSTAT]
ldr r2, [r1, #oNFSTAT]
mov r2, #0xff @ RESET command
strb r2, [r1, #oNFCMD]
mov r3, #0 @ wait
nand1:
add r3, r3, #0x1
cmp r3, #0xa
blt nand1
nand2:
ldr r2, [r1, #oNFSTAT] @ wait ready
tst r2, #0x4
beq nand2
ldr r2, [r1, #oNFCONT]
orr r2, r2, #0x2 @ Flash Memory Chip Disable
str r2, [r1, #oNFCONT]
@ get read to call C functions (for nand_read())
ldr sp, DW_STACK_START @ setup stack pointer
mov fp, #0 @ no previous frame, so fp=0
@ copy U-Boot to RAM
ldr r0, =TEXT_BASE
mov r1, #0x0
mov r2, #LENGTH_UBOOT
bl nand_read_ll
tst r0, #0x0
beq ok_nand_read
bad_nand_read:
loop2:
b loop2 @ infinite loop
ok_nand_read:
@ verify
mov r0, #0
ldr r1, =TEXT_BASE
mov r2, #0x400 @ 4 bytes * 1024 = 4K-bytes
go_next:
ldr r3, [r0], #4
ldr r4, [r1], #4
teq r3, r4
bne notmatch
subs r2, r2, #4
beq stack_setup
bne go_next
notmatch:
loop3:
b loop3 @ infinite loop
#endif


nand_read_ll 这个函数是nand_read.c里面的,这个文件应该在板级文件夹里,加入�这个文件到/board/samsung/mini2440里面。并且改动Makefile,使得编译进代码

COBJS   := mini2440.o flash.o nand_read.o

到此第一阶段的代码改动完成。因为要測试编译是否经过,而代码中有CONFIG_S3C2440配置,因此要改动mini2440.h。

7 编译排错:

(1).发现DW_STACK_START未定义,这个是进入C语言初始话栈的时候用到的,加上定义。

#define STACK_BASE 0x33f00000
#define STACK_SIZE 0x10000
.align 2
DW_STACK_START: .word STACK_BASE+STACK_SIZE-4

(2)发现include/asm/arch/s3c24x0_cpu.h错误,里面定义了CONFIG_S3C2410包括了s3c2410.h,因为咱们定义的是CONFIG_S3C2440因此没有包括头文件,因此改一下,将s3c2410.h复制为s3c2440.h。

(3)  发现s3c2440.h未定义CONFIG_S3C2440,将当中有关CONFIG_S3C2410 的预处理选项都换成CONFIG_S3C2410||CONFIG_S3C2440,这样代码才能够编译进来。

8 加上led灯显示程序。

#  if defined(CONFIG_MINI2440_LED)
#define rGPBCON 0x56000010
#define rGPBDATA 0x56000014
#define rGPBUP 0x56000018
ldr r0, =rGPBCON
ldr r1, =(0x01<<10)|(0x01<<12)|(0x01<<14)|(0x01<<16)
str r1, [r0]
ldr r0, =rGPBUP
ldr r1, =0x7fff
str r1, [r0]
ldr r0, =rGPBDATA
ldr r1, =(0x1<<5)|(0x0<<6)|(0x1<<7)|(0x0<<8)
str r1, [r0]
#endif

9 改动u-boot.lds 中的连接顺序,因为lowlevel_init.S,和nand_read.c都需要在前4K代码中,改动为

cpu/arm920t/start.o     (.text)
board/samsung/mini2440/lowlevel_init.o
board/samsung/mini2440/nand_read.o

配置mini2440.h,加入�CONFIG_MINI2440_LED宏定义,又一次编译,下载到板子上,假设LED灯,第一个和第三个亮了,其它是灭的。说明程序第一阶段正确运行了。kermit(串口终端)出现乱码,说明串口驱动尚未移植,是正常现象。

四. 启动第二阶段移植过程

1.串口初始化改动

        串口实现基本上不用改动什么,串口初始化函数是serial_init,在/drivers/serial/serial_s3c24x0.c中,因为串口要初始化波特率,需要get_PCLK()这个函数,而这个函数在/cpu/arm920t/speed.c里面,2410与2440实现是不一样的,因此需要改动这个函数。改动完了,又一次编译出现错误,CAMDIVN未定义,因为2410里面没有这个寄存器,在s3c24x0.h中添�定义就可以了。而后下载到板子上,串口就会出现正常的终端显示。但是很是多命令用不了。因为是其它的驱动没有移植。

2. LCD终端移植

參考代码的LCD驱动是经过VFD方式实现的,但是分析一下代码感受其编程方式让人很是不爽,看了一下LCD实现的方式,更加贴近本身的风格。因此果断转向LCD方式实现LCD终端。

(1)首先在mini2440.h中加入�宏定义

#define CONFIG_LCD
#define LCD_VIDEO_ADDR 0x33d00000

(2)加入�2440寄存器

2410和2440寄存器是同样的,因此仅仅需要添加�CONFIG_S3C2440就可以了。

(3)加入�底层LCD驱动代码lcd.c

将lcd.c复制到/board/samsung/mini2440里面,说明是底层驱动。这个文件是依据參考代码改动而成。

#include <common.h>
#include <netdev.h>
#include <asm/arch/s3c24x0_cpu.h>
#include <video_fb.h>
#include <lcd.h>
#include <asm/io.h>

#if defined(CONFIG_CMD_NAND)
#include <linux/mtd/nand.h>
#endif

DECLARE_GLOBAL_DATA_PTR;

#define MVAL (0)
#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


//TFT 240320
#define LCD_XSIZE_TFT_240320 (240)
#define LCD_YSIZE_TFT_240320 (320)
#define LCD_MEM_SIZE 240*320*16

//TFT240320
#define HOZVAL_TFT_240320 (LCD_XSIZE_TFT_240320-1)
#define LINEVAL_TFT_240320 (LCD_YSIZE_TFT_240320-1)

//Timing parameter for NEC3.5"
#define VBPD_240320 (3)
#define VFPD_240320 (10)
#define VSPW_240320 (1)

#define HBPD_240320 (5)
#define HFPD_240320 (2)
#define HSPW_240320_NEC (36) //Adjust the horizontal displacement of the screen :tekkamanninja@163.com
#define HSPW_240320_TD (23) //64MB nand mini2440 is 36 ,128MB is 23
//+ : --> - : <--
#define CLKVAL_TFT_240320 (3)
//FCLK=101.25MHz,HCLK=50.625MHz,VCLK=6.33MHz

#ifdef CONFIG_LCD

vidinfo_t panel_info = {
LCD_XSIZE_TFT_240320,
LCD_YSIZE_TFT_240320,
LCD_BPP
};
int lcd_line_length;
int lcd_color_fg;
int lcd_color_bg;

void *lcd_base; /* Start of framebuffer memory */
void *lcd_console_address; /* Start of console buffer */

short console_col;
short console_row;
void lcd_ctrl_init (void *lcd_base)
{
struct s3c24x0_lcd * const lcd = s3c24x0_get_base_lcd();
struct s3c2410_nand * const nand = s3c2410_get_base_nand();

/* select LCM type by env variable */

/* Configuration for GTA01 LCM on QT2410 */
lcd->LCDCON1 = 0x00000378; /* CLKVAL=4, BPPMODE=16bpp, TFT, ENVID=0 */
lcd->LCDCON2 = (VBPD_240320<<24)|(LINEVAL_TFT_240320<<14)|(VFPD_240320<<6)|(VSPW_240320);
lcd->LCDCON3 = (HBPD_240320<<19)|(HOZVAL_TFT_240320<<8)|(HFPD_240320);

if ( (nand->NFCONF) & 0x08 ) {
lcd->LCDCON4 = (MVAL<<8)|(HSPW_240320_TD);
}
else {
lcd->LCDCON4 = (MVAL<<8)|(HSPW_240320_NEC);
}

lcd->LCDCON5 = 0x00000f09;
lcd->LPCSEL = 0x00000000;
printf("Video: ");
printf ("TongBao 240*320 LCD 16bit 565 mode\n");
/* Init LCD base address */
writel((((ulong)lcd_base) >> 1), &lcd->LCDSADDR1);
writel((((readl(&lcd->LCDSADDR1))&0x1fffff) + (LCD_XSIZE_TFT_240320+0) * LCD_YSIZE_TFT_240320), &lcd->LCDSADDR2);
writel((LCD_XSIZE_TFT_240320 & 0x7ff), &lcd->LCDSADDR3);

/* Clear video memory */
memset((void *)lcd_base, 0, LCD_MEM_SIZE);

/* Enable Display */
writel((readl(&lcd->LCDCON1) | 0x01), & lcd->LCDCON1); /* ENVID = 1 */

}
void lcd_enable (void)
{
}


详细实现见u-boot lcd 分析

(4)定义颜色位数

因为/common/lcd.c中的默认的颜色是8位的,而统宝的是16位的。因此在mini440.h中定义

#define LCD_BPP                 LCD_COLOR16

(5)又一次编译

make clean
make mini2440_config
make

可以看到终端提示符到LCD上了,但是字是白的,背景是黑的。

在mini2440.h中定义#define CONFIG_SYS_WHITE_ON_BLACK       1 

就会反白了。这样才够帅。因为默认是LCD终端提示符,这个是因为注冊设备顺序的缘故,在/common/stdio.c stdio_init函数中,将drv_lcd_init ()放到serial_stdio_init ()后面就可以了。而后又一次编译下载。就会默认串口终端了,可以经过输入 setenv stdout lcd 进行切换。

(6)加入�logo.

在mini2440.h,定义CONFIG_LCD_LOGO。又一次编译就会出现denx 的开机logo假设还觉的不够帅,加入�本身的logo。改动方法,/tools/Makefile

ifeq ($(LOGO_BMP),)
LOGO_BMP= logos/ayst.bmp
endif

而后将ayst.bmp复制到/tools/logos里面,注意bmp图像是有要求的,宽度要是四的倍数,还得是16位的。仅仅有这样才干正确的显示。

3. Nandflash驱动移植

(1)改动底层驱动代码

改动/drivers/mtd/nand/s3c2410_nand.c

(2)加入�配置

在mini2440.h中加入�Nandflash的配置

#define CONFIG_CMD_NAND 1
/*--------------------------------------------------------------------------------------------
* NAND flash settings
*/
#if defined(CONFIG_CMD_NAND)
#define CONFIG_NAND_S3C2410
#define CONFIG_SYS_NAND_BASE 0x4E000000
#define CONFIG_SYS_MAX_NAND_DEVICE 1
#define SECTORSIZE 512
#define SECTORSIZE_2K 2048
#define NAND_SECTOR_SIZE SECTORSIZE
#define NAND_SECTOR_SIZE_2K SECTORSIZE_2K
#define NAND_BLOCK_MASK 511
#define NAND_BLOCK_MASK_2K 2047
#define NAND_MAX_CHIPS 1
#define CONFIG_MTD_NAND_VERIFY_WRITE
#define CONFIG_SYS_64BIT_VSPRINTF /* needed for nand_util.c */
#endif /* CONFIG_CMD_NAND */
(3)加入�2440 nandflash寄存器
在/include/asm-arm/arch-s3c24x0/s3c24x0.h 中
#if defined (CONFIG_S3C2440)
/* NAND FLASH (see S3C2440 manual chapter 6) */
struct s3c2410_nand {
u32 NFCONF;
u32 NFCONT;
u32 NFCMD;
u32 NFADDR;
u32 NFDATA;
u32 NFMECCD0;
u32 NFMECCD1;
u32 NFSECCD;
u32 NFSTAT;
u32 NFESTAT0;
u32 NFESTAT1;
u32 NFMECC0;
u32 NFMECC1;
u32 NFSECC;
u32 NFSBLK;
u32 NFEBLK;
};
#endif

4. 网络驱动的移植

(1)改动网卡初始化代码

在mini2440.c中加入�

#ifdef CONFIG_DRIVER_DM9000
rc = dm9000_initialize(bis);
#endif

(2)加入�配置

在mini244.h中加入�

#define  CONFIG_CMD_PING  1
#define CONFIG_NET_MULTI 1
#define CONFIG_NET_RETRY_COUNT 20
#define CONFIG_DRIVER_DM9000 1
#define CONFIG_DM9000_BASE 0x20000300
#define DM9000_IO CONFIG_DM9000_BASE
#define DM9000_DATA (CONFIG_DM9000_BASE+4)
#define CONFIG_DM9000_USE_16BIT 1
#define CONFIG_DM9000_NO_SROM 1
#undef CONFIG_DM9000_DEBUG

(3)dm9000x.c的改动

364行

if (i == 1000) {
printf("could not establish link\n");
return 0;
break;
}

(4)nfs代码的改动

33行

#define NFS_TIMEOUT (10*2000UL)

5 默认环境变量改动

/*-----------------------------------------------------------------------------------------------------
*Environment variables setting
*/
#define CONFIG_BOOTDELAY 5
#define CONFIG_BOOTARGS "noinitrd root=/dev/nfs rw nfsroot=192.168.1.111:/home/sun/study/nfsshare/rootfs_qtopia_qt4 ip=192.168.1.230:192.168.1.1::255.255.255.0 console=ttySAC0,115200 init=/linuxrc mem=64M"
#define CONFIG_ETHADDR 08:08:11:18:12:27
#define CONFIG_NETMASK 255.255.255.0
#define CONFIG_IPADDR 192.168.1.230
#define CONFIG_SERVERIP 192.168.1.111
#define CONFIG_GATEWAYIP 192.168.1.1
#define CONFIG_OVERWRITE_ETHADDR_ONCE
#define CONFIG_BOOTCOMMAND "tftp 0x30008000 zImage;bootm"
#if defined(CONFIG_CMD_KGDB)
#define CONFIG_KGDB_BAUDRATE 115200 /* speed to run kgdb serial port */
/* what's this ? it's not used anywhere */
#define CONFIG_KGDB_SER_INDEX 1 /* which serial port to use */
#endif
/* timeout values are in ticks */
#define CONFIG_SYS_FLASH_ERASE_TOUT (5*CONFIG_SYS_HZ) /* Timeout for Flash Erase */
#define CONFIG_SYS_FLASH_WRITE_TOUT (5*CONFIG_SYS_HZ) /* Timeout for Flash Write */
#define CONFIG_ENV_IS_IN_NAND 1
#define CONFIG_ENV_OFFSET 0x40000 /* Total Size of Environment Sector */
#define CONFIG_ENV_SIZE 0x20000 /*size of environment */


这个是所处的存储介质,默认的Flash,这里是NandFlash

/*-----------------------------------------------------------------------------------------------------
* linux kernel tags
* This is important for starting kernel
*/
#define CONFIG_SETUP_MEMORY_TAGS
#define CONFIG_INITRD_TAG
#define CONFIG_CMDLINE_TAG


#define CONFIG_SYS_HUSH_PARSER
#define CONFIG_SYS_PROMPT_HUSH_PS2 "> "
#define CONFIG_CMDLINE_EDITING
#define CONFIG_AUTO_COMPLETE

这个标记列表配置对内核启动十分重要,没有就不会启动内核

五。总结

本次移植參考tekkamaninja对友善之臂mini2440的移植代码。好多地方都是照搬其代码。因为没有时间的缘故,对一些代码的实现仍是不是很是了解。但是对u-boot的主要的软件架构有了必定的了解。本身首创的地方就是推断启动方式上,还有lcd驱动的移植。前一个是參考裸机程序的启动代码写的,后一个全然依照本身对代码的理解移植而成。仍是比較成功的。u-boot软件分层结构给了我深入的印象。还有Makefile的结构也对我很是有启示。这个第一个接触的开源项目。之后还会经常常使用到。