一、移植准备:修改Makefile文件,在U-Boot中建立自己的开发板文件(以友善之臂的sbc2410x为基础)。 1 解压u-boot-1.3.4,并进入u-boot目录,修改Makefile文件,添加开发板的配置选项。 tar -xjvf u-boot-1.3.4.tar.bz2 cd u-boot-1.3.4 vi Makefile
in Makefile:
#为mini2440建立配置项
smdk2410_config : unconfig @$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0
mini2440_config : unconfig @$(MKCONFIG) $(@:_config=) arm arm920t mini2440 tekkamanninja s3c24x0
各项的意思如下: arm : CPU的架构(ARCH) arm920t : CPU的类型(CPU),其对应于cpu/arm920t子目录。 mini2440: 开发板的型号(BOARD),对应于board/tekkamanninja/mini2440目录。 tekkamanninja: 开发者/或经销商(vender)。 s3c24x0 : 片上系统(SOC)。
同时在“ifndef CROSS_COMPILE ”之前加上自己交叉编译器的路径,比如我使用crosstool-0.43制作的基于2.6.27.4内核和gcc-4.1.1-glibc-2.3.2的ARM9TDMI交叉编译器,则: CROSS_COMPILE=arm-9tdmi-linux-gnu-
别忘了在环境变量PATH中加上你的编译器路径!!!!
特别注意: 在u-boot1.3.3及以上版本Makefile有一定的变化,使得对于24x0处理器从nand启动的遇到问题。也就是网上有人说的:无法运行过lowlevel_init。其实这个问题是由于编译器将我们自己添加的用于nandboot的子函数nand_read_ll放到了4K之后造成的(到这不理解的话,请仔细看看24x0处理器nandboot原理)。我是在运行失败后,利用mini2440的4个LED调试发现u-boot根本没有完成自我拷贝,然后看了uboot根目录下的System.map文件就可知道原因。
解决办法其实很简单: 将__LIBS := $(subst $(obj),,$(LIBS)) $(subst $(obj),,$(LIBBOARD)) 改为__LIBS := $(subst $(obj),,$(LIBBOARD)) $(subst $(obj),,$(LIBS))
2 在/board子目录中建立自己的开发板mini2440目录 由于我在上一步板子的开发者/或经销商(vender)中填了 tekkamanninja ,所以开发板mini2440目录一定要建在/board子目录中的tekkamanninja目录下 ,否则编译会出错。 cd board mkdir tekkamanninja tekkamanninja/mini2440 cp -arf sbc2410x/* tekkamanninja/mini2440/ cd tekkamanninja/mini2440/ mv sbc2410x.c mini2440.c
还要记得修改自己的开发板mini2440目录下的Makefile文件,不然编译时会出错:
vi Makefile
in Makefile: COBJS := mini2440.o flash.o
3 在include/configs/中建立配置头文件 cd ../../.. cp include/configs/sbc2410x.h include/configs/mini2440.h
4 测试编译能否成功 make mini2440_config Configuring for mini2440 board... make
测试编译成功后继续。 可能出现的问题: (1) 如果出现: $ make mini2440_config Makefile:xxxx: *** 遗漏分隔符 。 停止。 请在U-boot的根目录下的Makefile的 @$(MKCONFIG) $(@:_config=) arm arm920t mini2440 tekkamanninja) 前加上“Tab”键
--------------------------------------------------------------------------------
二、修改U-Boot中的文件,以同时匹配2440和2410。 1 修改/cpu/arm920t/start.S (1)删除AT91RM9200使用的LED代码。 #include #include #if defined(CONFIG_AT91RM9200DK) #include /*这是针对AT91RM9200DK开发板的。对于mini2440也有4个LED指示灯,我用来指示程序用行的进度。*/ #endif ...... /* * the actual start code */
start_code: /* * set the cpu to SVC32 mode */ mrs r0,cpsr bic r0,r0,#0x1f orr r0,r0,#0xd3 msr cpsr,r0 #if defined(CONFIG_AT91RM9200DK) bl coloured_LED_init bl red_LED_on #endif
(2)修改寄存器地址定义 #if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)|| defined(CONFIG_S3C2440) /* turn off the watchdog */
#if defined(CONFIG_S3C2400) #define pWTCON 0x15300000 #define INTMSK 0x14400008 /* Interupt-Controller base addresses */ #define CLKDIVN 0x14800014 /* clock divisor register */ #else #define pWTCON 0x53000000 #define INTMSK 0x4A000008 /* Interupt-Controller base addresses */ #define INTSUBMSK 0x4A00001C #define CLKDIVN 0x4C000014 /* clock divisor register */ #endif #define CLK_CTL_BASE 0x4C000000 /* tekkaman */ #define MDIV_405 0x7f << 12 /* tekkaman */ #define PSDIV_405 0x21 /* tekkaman */ #define MDIV_200 0xa1 << 12 /* tekkaman */ #define PSDIV_200 0x31 /* tekkaman */
(3)修改中断禁止部分 #if defined(CONFIG_S3C2410) ldr r1, =0x7ff /*根据2410芯片手册,INTSUBMSK有11位可用*/ ldr r0, =INTSUBMSK str r1, [r0] #endif #if defined(CONFIG_S3C2440) ldr r1, =0x7fff /*根据2440芯片手册,INTSUBMSK有15位可用*/ ldr r0, =INTSUBMSK str r1, [r0] #endif
(4)修改时钟设置(2440的主频为405MHz。) # if defined(CONFIG_S3C2440) /* FCLK:HCLKCLK = 1:4:8 */ ldr r0, =CLKDIVN mov r1, #5 str r1, [r0] mrc p15, 0, r1, c1, c0, 0 /*read ctrl register tekkaman*/ orr r1, r1, #0xc0000000 /*Asynchronous tekkaman*/ mcr p15, 0, r1, c1, c0, 0 /*write ctrl register tekkaman*/
/*now, CPU clock is 405.00 Mhz tekkaman*/ mov r1, #CLK_CTL_BASE /* tekkaman*/ mov r2, #MDIV_405 /* mpll_405mhz tekkaman*/ add r2, r2, #PSDIV_405 /* mpll_405mhz tekkaman*/ str r2, [r1, #0x04] /* MPLLCON tekkaman */
#else /* FCLK:HCLKCLK = 1:2:4 */ /* default FCLK is 12 MHz ! 在这里U-Boot有一个错误:以为默认时钟为120MHz。其实如果没有添加以下设置FCLK的语句,芯片内部的PLL是无效的,即FCLK为12MHz。S3C24x0的芯片手册说得很明白。我一开始没有注意到这一点,是 CalmArrow提醒了我并和我讨论过,他也做过实验证实了这点。在这里对CalmArrow表示感谢和敬意!*/ ldr r0, =CLKDIVN mov r1, #3 str r1, [r0]
mrc p15, 0, r1, c1, c0, 0 /*read ctrl register tekkaman*/ orr r1, r1, #0xc0000000 /*Asynchronous tekkaman*/ mcr p15, 0, r1, c1, c0, 0 /*write ctrl register tekkaman*/
/*now, CPU clock is 202.8 Mhz tekkaman*/ mov r1, #CLK_CTL_BASE /* tekkaman*/ mov r2, #MDIV_200 /* mpll_200mhz tekkaman*/ add r2, r2, #PSDIV_200 /* mpll_200mhz tekkaman*/ str r2, [r1, #0x04]
# endif #endif /* CONFIG_S3C2400 || CONFIG_S3C2410|| CONFIG_S3C2440 */
(5)将从Flash启动改成从NAND Flash启动。 在以下U-Boot的重定向语句段(作用是将u-boot的源代码从nor flash到sdram中): #ifndef CONFIG_AT91RM9200
#ifndef CONFIG_SKIP_RELOCATE_UBOOT relocate: /* relocate U-Boot to RAM */ 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
ldr r2, _armboot_start ldr r3, _bss_start sub r2, r3, r2 /* r2 <- size of armboot */ add r2, r0, r2 /* r2 <- source end address*/
copy_loop: ldmia {r3-r10} /* copy from source address [r0] */ stmia {r3-r10} /* copy to target address [r1] */ cmp r0, r2 /* until source end addreee [r2] */ ble copy_loop #endif /* CONFIG_SKIP_RELOCATE_UBOOT */ #endif
的前面添加上以下的nand boot代码: #ifdef CONFIG_S3C2440_NAND_BOOT
#define NAND_CTL_BASE 0x4E000000 /* Offset */ #define oNFCONF 0x00 #define oNFCONT 0x04 #define oNFCMD 0x08 #define oNFSTAT 0x20 #define LENGTH_UBOOT 0x40000
@ 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
#ifdef CONFIG_S3C2410_NAND_BOOT
#define NAND_CTL_BASE 0x4E000000 /* Offset */ #define oNFCONF 0x00 #define oNFCMD 0x04 #define oNFSTAT 0x10 #define LENGTH_UBOOT 0x40000
@ reset NAND mov r1, #NAND_CTL_BASE ldr r2, =0xf830 @ initial value str r2, [r1, #oNFCONF] ldr r2, [r1, #oNFCONF] bic r2, r2, #0x800 @ enable chip str r2, [r1, #oNFCONF] 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, #0x1 beq nand2 ldr r2, [r1, #oNFCONF] orr r2, r2, #0x800 @ disable chip str r2, [r1, #oNFCONF] @ 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
在“ldr pc, _start_armboot”之前加入:
#if defined(CONFIG_MINI2440_LED) #define GPIO_CTL_BASE 0x56000000 #define oGPIO_B 0x10 #define oGPIO_CON 0x0 /* R/W, Configures the pins of the port */ #define oGPIO_DAT 0x4 #define oGPIO_UP 0x8 /* R/W, Pull-up disable register */ mov r1, #GPIO_CTL_BASE add r1, r1, #oGPIO_B ldr r2, =0x295551 str r2, [r1, #oGPIO_CON] mov r2, #0xff str r2, [r1, #oGPIO_UP] ldr r2, =0x1c1 str r2, [r1, #oGPIO_DAT] #endif
修改目的:如果看到只有LED1亮了,并响起蜂鸣器,说明U-Boot的第一阶段已完成!(针对mini2440,若不是这块开发板的,必须修改或不添加)
在 “ _start_armboot: .word start_armboot ” 后加入: #define STACK_BASE 0x33f00000 #define STACK_SIZE 0x10000 .align 2 DW_STACK_START: .word STACK_BASE+STACK_SIZE-4
2 在board/tekkamaninija/mini2440加入NAND Flash读取函数(start.S中需要的nand_read_ll函数)文件nand_read.c nand_read.c: #include
#define __REGb(x) (*(volatile unsigned char *)(x)) #define __REGi(x) (*(volatile unsigned int *)(x)) #define NF_BASE 0x4e000000 #define NFCONF __REGi(NF_BASE + 0x0)
#if defined(CONFIG_S3C2440)
#define NFCONT __REGi(NF_BASE + 0x4) #define NFCMD __REGb(NF_BASE + 0x8) #define NFADDR __REGb(NF_BASE + 0xC) #define NFDATA __REGb(NF_BASE + 0x10) #define NFSTAT __REGb(NF_BASE + 0x20)
#define NAND_CHIP_ENABLE (NFCONT &= ~(1<<1)) #define NAND_CHIP_DISABLE (NFCONT |= (1<<1)) #define NAND_CLEAR_RB (NFSTAT |= (1<<2)) #define NAND_DETECT_RB { while(! (NFSTAT&(1<<2)));}
/* low level nand read function */ int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size) { int i, j; if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) { return -1; /* invalid alignment */ } NAND_CHIP_ENABLE; for(i=start_addr; i < (start_addr + size);) { /* READ0 */ NAND_CLEAR_RB; NFCMD = 0; /* Write Address */ NFADDR = i & 0xff; NFADDR = (i >> 9) & 0xff; NFADDR = (i >> 17) & 0xff; NFADDR = (i >> 25) & 0xff; NAND_DETECT_RB; for(j=0; j < NAND_SECTOR_SIZE; j++, i++) { *buf = (NFDATA & 0xff); buf++; } } NAND_CHIP_DISABLE; return 0; } #endif
#if defined(CONFIG_S3C2410)
#define NFCMD __REGb(NF_BASE + 0x4) #define NFADDR __REGb(NF_BASE + 0x8) #define NFDATA __REGb(NF_BASE + 0xc) #define NFSTAT __REGb(NF_BASE + 0x10) #define BUSY 1
inline void wait_idle(void) { int i; while(!(NFSTAT & BUSY)) for(i=0; i<10; i++); } /* low level nand read function */ int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size) { int i, j; if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) { return -1; /* invalid alignment */ } /* chip Enable */ NFCONF &= ~0x800; for(i=0; i<10; i++); for(i=start_addr; i < (start_addr + size);) { /* READ0 */ NFCMD = 0; /* Write Address */ NFADDR = i & 0xff; NFADDR = (i >> 9) & 0xff; NFADDR = (i >> 17) & 0xff; NFADDR = (i >> 25) & 0xff; wait_idle(); for(j=0; j < NAND_SECTOR_SIZE; j++, i++) { *buf = (NFDATA & 0xff); buf++; } } /* chip Disable */ NFCONF |= 0x800; /* chip disable */ return 0; } #endif
顺便修改board/tekkamanninja/mini2440/Makefile文件,将nand_read.c编译进u-boot。 OBJS := mini2440.o nand_read.o flash.o
3 修改board/tekkamanninja/mini2440/lowlevel_init.S文件 /* REFRESH parameter */ #define REFEN 0x1 /* Refresh enable */ #define TREFMD 0x0 /* CBR(CAS before RAS)/Auto refresh */ #define Trc 0x3 /* 7clk */ #define Tchr 0x2 /* 3clk */
#if defined(CONFIG_S3C2440) #define Trp 0x2 /* 4clk */ #define REFCNT 1012 #else #define Trp 0x0 /* 2clk */ #define REFCNT 0x0459 #endif
4 修改/board/tekkamanninja/mini2440/mini2440.c 修改其对GPIO和PLL的配置(请参阅开发板的硬件说明和芯片手册);并针对LCD显示部分和nand flash驱动添加相应的代码: ...... #include #include #include
#if defined(CONFIG_CMD_NAND) #include #endif
DECLARE_GLOBAL_DATA_PTR;
#define FCLK_SPEED 1
#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 */
#if defined(CONFIG_S3C2410) /* Fout = 202.8MHz */ #define M_MDIV 0xA1 #define M_PDIV 0x3 #define M_SDIV 0x1 #endif
#if defined(CONFIG_S3C2440) /* Fout = 405MHz */ #define M_MDIV 0x7f #define M_PDIV 0x2 #define M_SDIV 0x1 #endif #endif
#define USB_CLOCK 1
#if USB_CLOCK==0 #define U_M_MDIV 0xA1 #define U_M_PDIV 0x3 #define U_M_SDIV 0x1 #elif USB_CLOCK==1
#if defined(CONFIG_S3C2410) #define U_M_MDIV 0x48 #define U_M_PDIV 0x3 #endif
#if defined(CONFIG_S3C2440) #define U_M_MDIV 0x38 #define U_M_PDIV 0x2 #endif
#define U_M_SDIV 0x2 #endif ......
为连接LED和蜂鸣器的GPIO修改配置寄存器:
int board_init (void):
......
#if defined(CONFIG_MINI2440) gpio->GPBCON = 0x00295551; #else gpio->GPBCON = 0x00044556; #endif ......
为引导linux 内核,修改开发板的类型代码:
int board_init (void):
......
#if defined(CONFIG_S3C2410) /* arch number of SMDK2410-Board */ gd->bd->bi_arch_number = MACH_TYPE_SMDK2410; #endif
#if defined(CONFIG_S3C2440) /* arch number of S3C2440-Board */ gd->bd->bi_arch_number = MACH_TYPE_S3C2440 ; #endif
......
为使int board_init (void)设置完成后,LED1和LED2同时亮起,蜂鸣器继续鸣叫,在int board_init (void)的最后添加: ......
icache_enable(); dcache_enable(); #if defined(CONFIG_MINI2440_LED) gpio->GPBDAT = 0x00000181; #endif return 0; }
针对LCD显示部分,在int board_init (void)函数后添加2440的LCD控制器的初始化代码: #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)
//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 (36)
#define CLKVAL_TFT_240320 (3) //FCLK=101.25MHz,HCLK=50.625MHz,VCLK=6.33MHz
void board_video_init(GraphicDevice *pGD) { S3C24X0_LCD * const lcd = S3C24X0_GetBase_LCD(); /* FIXME: 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); lcd->LCDCON4 = (MVAL<<8)|(HSPW_240320); lcd->LCDCON5 = 0x00000f09; lcd->LPCSEL = 0x00000000; }
为nand flash驱动屏蔽相应的代码,因为此次使用的是u-boot从Linux移植来的代码,而不是原来的nand_legacy驱动: #if 0 #if defined(CONFIG_CMD_NAND) extern ulong nand_probe(ulong physadr);
static inline void NF_Reset(void) { int i;
NF_SetCE(NFCE_LOW); NF_Cmd(0xFF); /* reset command */ for(i = 0; i < 10; i++); /* tWB = 100ns. */ NF_WaitRB(); /* wait 200~500us; */ NF_SetCE(NFCE_HIGH); }
static inline void NF_Init(void) { #if 1 #define TACLS 0 #define TWRPH0 3 #define TWRPH1 0 #else #define TACLS 0 #define TWRPH0 4 #define TWRPH1 2 #endif
NF_Conf((1<<15)|(0<<14)|(0<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0)); /*nand->NFCONF = (1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0); */ /* 1 1 1 1, 1 xxx, r xxx, r xxx */ /* En 512B 4step ECCR nFCE=H tACLS tWRPH0 tWRPH1 */
NF_Reset(); }
void nand_init(void) { S3C2410_NAND * const nand = S3C2410_GetBase_NAND();
NF_Init(); #ifdef DEBUG printf('NAND flash probing at 0x%.8lX ', (ulong)nand); #endif printf ('%4lu MB ', nand_probe((ulong)nand) >> 20); } #endif
#endif
|