首页 / 操作系统 / Linux / U-Boot1.3.1移植YC2440
ARM and Linux,一个伟大的行业,鄙人正处于摸索阶段的新手。既然如此,就先从U-Boot下手,在此过程中参考了网上一些高手的资料。下面是他们的链接,感谢他们分享经验让新手快速入门、找到学习方法,再次感谢他们对于技术资料无私奉献、共享。 由于YC2440网卡芯片DM9000AEP,网卡移植参考了Weibing的一位网友。<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /> U-Boot源码: U-Boot源码下载免费下载地址在 http://linux.linuxidc.com/用户名与密码都是www.linuxidc.com具体下载目录在 /pub/u-boot/ U-Boot-<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />1.3.1还没有支持s3c2440,这次移植是用s3c2410的文件修改而成。红色为修改的地方,蓝色为运行指令、重要注释 一、在U-Boot中建立自己开发板类型,测试编译1 进入U-Boot目录,修改Makefile# tar –jxvf u-boot-1.3.1.tar.bz2# cd u-boot-1.3.1# gedit Makefile//为liao2440建立编译项sbc2410x_config: unconfig @$(MKCONFIG) $(@:_config=) arm arm920t sbc2410x NULL s3c24x0liao2440_config : unconfig @$(MKCONFIG) $(@:_config=) arm arm920t liao2440 liao s3c24x0说明:arm: CPU的架构(ARCH)arm920t: CPU的类型(CPU),其对应于cpu/arm920t子目录。liao2440: 开发板的型号(BOARD),对应于board/liao/liao2440目录。liao: 开发者/或经销商(vender)。s3c24x0: 片上系统(SOC)。 同时在“ifndef CROSS_COMPILE”之前 加上自己交叉编译器的路径,比如我使用crosstool-0.43制作的基于2.6.24内核和gcc-4.1.1-glibc-2.3.2的ARM9TDMI交叉编译器,则: CROSS_COMPILE=CROSS_COMPILE=/home/liao/crosstool/gcc-4.1.1-glibc-2.3.2/arm-9tdmi-linux-gnu/bin/arm-9tdmi-linux-gnu- 2 /board子目录中建立自己开发板liao2440目录 由于上一步板子的开发者/或经销商(vender)中填了liao,所以开发板liao2440目录一定要建在/board子目录liao目录下 ,否则编译会出错。 # cd board# mkdir liao liao/liao2440# cp -arf sbc2410x/* liao/liao2440/# cd liao/liao2440# mv sbc2410x.c liao2440.c 修改自己开发板liao2440目录下Makefile文件# gedit MakefileCOBJS := sbc2410x.o flash.o COBJS := liao2440.o flash.o 3 建立配置头文件在include/configs/# cd …/u-boot-1.2.0/include/configs# cp include/configs/sbc2410x.h include/configs/liao2440.h 4 测试编译是否成功# make liao2440_configConfiguring for liao2440 board…(如果出现:Makefile:1927: *** 遗漏分隔符 。 停止。请在U-boot的根目录下的Makefile的 @$(MKCONFIG) $(@:_config=) arm arm920t liao2440 liao)前加上“Tab”键)# make Ok,到这里前期准备工作完成!!!!!!! 二、修改U-Boot中文件,根据开发板YC2440配置1 修改/cpu/arm920t/start.S 1.0 修改一些AT91RM9200定义#include <config.h>#include <version.h>//#include <status_led.h> /*这是针对AT91RM9200DK开发板*/....../* * 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 //bl coloured_LED_init //bl red_LED_on 1.1修改寄存器定义#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# if defined(CONFIG_S3C2440)# define MDIV_405 0x7f << 12# define PSDIV_405 0x21# endif# if defined(CONFIG_S3C2410)# define MDIV_200 0xa1 << 12# define PSDIV_200 0x31# endif/*这一段为后面修改时钟定义的一些参数*/ 1.2修改中断禁止部分# if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440) ldr r0, =pWTCON mov r1, #0x0 str r1, [r0] /* * mask all IRQs by setting all bits in the INTMR - default */ mov r1, #0xffffffff ldr r0, =INTMSK str r1, [r0]# if defined(CONFIG_S3C2410) ldr r1, =0x7ff //根据2410芯片手册,INTSUBMSK有11位可用, //vivi也是0x7ff,不知为什么U-Boot一直没改过来。 ldr r0, =INTSUBMSK str r1, [r0]# endif# if defined(CONFIG_S3C2440) ldr r1, =0x7fff //根据2440芯片手册,INTSUBMSK有15位可用 ldr r0, =INTSUBMSK str r1, [r0]# endif 1.3 修改时钟设置/*时钟控制逻辑单元能够产生s3c2440需要的时钟信号,包括CPU使用的主频FCLK,AHB总线使用的HCLK,APB总线设备使用的PCLK,2440里面的两个锁相环(PLL),其中一个对应FCLK、HCLK、PCLK,另外一个对应UCLK(48MHz)*//* FCLK:HCLK:PCLK = 1:4:8 */ ldr r0, =CLKDIVN mov r1, #5 str r1, [r0]/*下面协处理器指令是用来把CPU的模式设置成Asynchronous 模式,为什么要这样做?s3c2440的datasheet说得很清楚,具体可在datasheet中搜索R1_nF或R1_iA内容。至于R1_nF和R1_iA的值可以在vivi源码的s3c2440.h中得到。单从指令上看,下面指令的作用把协处理器p15的寄存器c1的最高两位置1,仔细看过《arm 体系结构与编程》的朋友可能会发现个问题:《arm 体系结构与编程》里面说 p15 的bit30和bit31是保留的,那么下面的指令又怎么会有意义呢?其实《arm 体系结构与编程》里面说这两个bit是保留的是针对arm7的,对arm9的s3c2440并不适用。《ARM体系结构与编程》杜春雷 PDF 下载地址 http://www.linuxidc.com/Linux/2011-09/43099.htm*/ mrc p15, 0, r1, c1, c0, 0 /*read ctrl register liao*/ orr r1, r1, #0xc0000000 /*Asynchronous liao*/ mcr p15, 0, r1, c1, c0, 0 /*write ctrl register liao*/ # if defined(CONFIG_S3C2440) /*now, CPU clock is 405.00 Mhz */ mov r1, #CLK_CTL_BASE mov r2, #MDIV_405 /* mpll_405mhz liao*/ add r2, r2, #PSDIV_405 /* mpll_405mhz liao*/ str r2, [r1, #0x04] /* MPLLCON liao */# endif# if defined(CONFIG_S3C2410) /*now, CPU clock is 202.8 Mhz liao*/ mov r1, #CLK_CTL_BASE /* liao*/ mov r2, #MDIV_200 /* mpll_200mhz liao*/ add r2, r2, #PSDIV_200 /* mpll_200mhz liao*/ str r2, [r1, #0x04] /* MPLLCON liao */# endif# endif /* CONFIG_S3C2400 || CONFIG_S3C2410|| CONFIG_S3C2440 *//*时钟设置参照vivi代码,主频405MHZ*/ 1.4 将Flash启动改为从NAND Flash启动(2410与2440不同,参照vivi)# if 0# ifndef CONFIG_SKIP_RELOCATE_UBOOTrelocate: /* 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 r0!, {r3-r10} /* copy from source address [r0] */ stmia r1!, {r3-r10} /* copy to target address [r1] */ cmp r0, r2 /* until source end addreee [r2] */ ble copy_loop# endif /* CONFIG_SKIP_RELOCATE_UBOOT */# endif/*参照vivi代码,nandflash拷贝*/# ifdef CONFIG_S3C2440_NAND_BOOT @ reset NAND mov r1, #NAND_CTL_BASE ldr r2, =( (7<<12)|(7<<8)|(7<<4)|(0<<0) ) str r2, [r1, #oNFCONF] /*这些宏在includes/configs/liao2440.h中定义*/ 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 @ waitnand1: 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]/*汇编调用C函数,初始化栈*/@ 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, #0x30000 bl nand_read_ll/*nand_read_ll为uboot拷贝代码入口函数,r0,r1,r2为入口参数tst r0,#0x0中r0为函数返回值*/ 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-bytesgo_next: ldr r3, [r0], #4 ldr r4, [r1], #4 teq r3, r4 bne notmatch subs r2, r2, #4 beq stack_setupbne go_next notmatch:loop3: b loop3 @ infinite loop #endif @ CONFIG_S3C2440_NAND_BOOT#ifdef CONFIG_S3C2410_NAND_BOOT @ reset NANDmov 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 @ waitnand1: 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, #0x30000 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-bytesgo_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 @ CONFIG_S3C2410_NAND_BOOT 1.5 调出start.S前,利用点灯大法查看程序运行位置在 ldr pc,_start_armboot 之前加入LEDmov r1, #GPIO_CTL_BASEadd r1, r1, #oGPIO_Fldr r2,=0x55aastr r2, [r1, #oGPIO_CON]mov r2, #0xffstr r2, [r1, #oGPIO_UP]mov r2, #0xe0str r2, [r1, #oGPIO_DAT]/*YC2440开发板有4个LED,GPIO_F[4:7],点亮一个LED,下面函数进入第二阶段*/ldr pc,_start_armboot_start_armboot: .word start_armboot.align 2 DW_STACK_START: .word STACK_BASE+STACK_SIZE-4/*栈空间是从高地址向低地址增长,用于调用nand_read_ll函数时设置占空间,STACK_BASE STACK_SIZE定义在后面/include/configs/liao2440.h */ 2 在board/liao/liao2440加入NAND Flash读函数文件,复制vivi中nand_read.c文件#include <config.h> #define __REGb(x) (*(volatile unsigned char *)(x))#define __REGi(x) (*(volatile unsigned int *)(x))#define NF_BASE 0x4e000000 #if defined(CONFIG_S3C2440) /*s3c2440部分*/ #define NFCONF __REGi(NF_BASE + 0x0)#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 GPDAT __REGi(GPIO_CTL_BASE+oGPIO_F+oGPIO_DAT) #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)) );} #define BUSY 4inline void wait_idle(void) { while(!(NFSTAT & BUSY)); NFSTAT |= BUSY;} #define NAND_SECTOR_SIZE 512#define NAND_BLOCK_MASK (NAND_SECTOR_SIZE - 1) /* low level nand read function */intnand_read_ll(unsigned char *buf, unsigned long start_addr, int size){ int i, j;/* 下面if保证对flash的读操作是从某一页的页头开始的,也就是保证start_addr[0:8]位都为0,本次flash的一页的大小位512-bytes,也就是从0x0到0x1ff */ 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 *//*下面这个送地址的过程最难懂的一部分,为什么送进nand flash的地址忽略了bit8,纵观整个for(i) 循环,i并不是一个随机的地址,而应该是每一页的首地址。其实nand flash并不是忽略了bit8这个地址,而是bit8早就被定下来了,就是上面的NFCMD = 0;语句,(K9F1208U0B)支持从半页开始读取,从而它有两个读的命令,分别是0x00(从一页的上半页开始读) 和 0x01(从一页的下半页开始读),当取0x00时,bit8=0,当取0x01时 bit8=1*/ 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) /*s3c2410部分*/ #define NFCONF __REGi(NF_BASE + 0x0)#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 */intnand_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