U-boot移植到mini2440上
来源:互联网 发布:有限元分析软件msc 编辑:程序博客网 时间:2024/05/15 12:40
本文章中的很多内容参考友善之臂的说明文档《mini2440之U-boot移植详细手册-20100419》,使用的U-boot的版本是u-boot-2010.03
说明:此次移植的目的不是为了制作一个功能强大的U-boot,只是做一个最简单的U_boot。该U-boot能够实现通过串口和电脑通信,可以将环境变量保存在NOR Flash中,通过TFTP服务器将使用NFS根文件系统的内核镜像从电脑拷贝到内存中执行。而且这个U-boot只支持从NOR中启动。
在移植U-Boot之前建议对U-Boot中的源码组织结构有较深的理解,可参考我的另一篇博文Bootloader介绍和Uboot源码结构
移植U-Boot的原则是,先选取与目标板相似的板子,将其的源码内容进行一份拷贝,然后从整个U-Boot的启动流程更改相应的代码。
一、移植初处理
拷贝文件
因为smdk2410与mini2440最相近,所以我们选择smdk2410作为修改对象。
拷贝/board/samsung/smdk2410到/board/samsung/mini2440
拷贝/include/configs/smdk2410.h到/include/configs/mini2440.h
修改顶层makefile
仿照smdk2410添加如下代码:
mini2440_config : unconfig @$(MKCONFIG) $(@:_config=) arm arm920t mini2440 samsung s3c24x0
初步修改/board/samsung/mini2440目录中的文件
在makefile中修改下列代码:
COBJS := smdk2410.o flash.o
修改成:
COBJS := mini2440.o flash.o
将文件smdk2410.c重新命名为mini2440.c
现在可以尝试着编译:
make mini2440_configmake all
二、具体代码移植
现在的思路是,跟随着U-Boot代码的启动流程进行修改和开发板相关的内容。
第一阶段(汇编语言)
.globl _start_start: b start_code
首先运行的是标号为start_code处的代码
下面的代码是针对需要改的部分。
@ bl coloured_LED_init@ bl red_LED_on
因为没有必要实现LED的操作,所以直接注释掉。
s3c2440的频率设定方式与其它的有些区别,需要一些额外的寄存器如下:
#ifdef CONFIG_S3C2440# define CLK_CTL_BASE 0x4C00000# define MDIV_405 0x7f << 12 # define PSDIV_405 0x21 # define MDIV_200 0xa1 << 12 # define PSDIV_200 0x31 #endif
需要屏蔽的子中断个数也不一样,所以要进行不同的设定:
#if defined(CONFIG_S3C2440) ldr r1, =0x7fff ldr r0, =INTSUBMSK str r1, [r0]# endif
针对频率需要进行如下修改:
#if defined(CONFIG_S3C2440)/* FCLK:HCLK:PCLK = 1:4:8 */ ldr r0, =CLKDIVN mov r1, #5 str r1, [r0] mrc p15, 0, r1, c1, c0, 0 orr r1, r1, #0xc0000000 mcr p15, 0, r1, c1, c0, 0 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 */
下面修改lowlevel_init.S,这个文件位于/board/samsung/mini2440目录下,显然和硬件关系密切。
这个文件主要是对开发板的内存地址空间硬件的挂载有关,开发板上的NOR FLASH、NAND FLASH、SDRAM、DM9000都是挂载在内存地址空间上的,所以和它们相关的内容需要在这个文件中设置。
注意:该文件不要用smdk2410中的lowlevel_init.c,应该以sbc2410x文件夹中的lowlevel_init.c为修改代码来源。否则,网络功能无法使用。
#define Trp 0x0 /* 2clk */#define REFCNT 1113
将上述代码修改成下列代码:
#define Trp 0x2 /* 4clk */#define REFCNT 1012
这一部分是和SDRAM有关的参数设定,需要查阅mini2440开发板上的SDRAM的芯片手册来获取。
ldr r0, =SMRDATA ldr r1, _TEXT_BASE sub r0, r0, r1
这段代码是进行地址的转换,当将U-Boot下载到内存中直接运行时,需要更改上面的代码。我们假定U-boot是从Flash中启动的,不进行更改。
如果需要更改能同时在SDRAM中启动,需要将上述代码进行如下修改:
ldr r0, =SMRDATA ldr r1, =lowlevel_init sub r0, r0, r1 adr r3, lowlevel_init add r0,r0,r3
其中的adr是伪代码,它会返回实际运行时,lowlevel_init的物理地址,而不是逻辑地址。
然后继续看start.s中的代码:
后面的代码是将Flash中的代码复制到内存中,清零bbs段,设置堆栈,然后跳转到C语言的入口start_armboot。
注意:如果将U-Boot烧写到NOR Flash中,跟汇编有关的代码就已经完成了,但是如果将其烧写到NAND FLASH中,需要对U-Boot.lds进行如下修改:
.text :{ /cpu/arm920t/start.o(.text) /board/samsung/mini2440/lowlevel_init.o(.text) *(.text)}
因为当将U-Boot下载到NAND Flash中时,只将U-Boot的前4K内容复制到芯片内部RAM中运行,采取默认连接方式时,lowlevel_init.o有可能放在4K后面的地址上,此时还没有将Flash中的代码拷贝到内存中,不能执行这部分代码。
第二阶段(C语言)
首先我们在mini2440.h中进行下列修改:
//#define CONFIG_S3C2410 1#define CONFIG_S3C2440 1
修改完之后我们的程序就无法正常编译了。因为很多文件的编译内容和头文件(配置文件)中的宏定义相关。现在,我们修改了一个和体系相关的很重要的宏,所以会出现问题。因为我们不可能找出所有与该宏定义相关的代码,我们只需要找出影响我们正常编译的宏定义处,进行修改。还有在我们需要用到的地方修改宏定义。
以下代码摘自s3c24x0_cpu.h
#elif defined(CONFIG_S3C2410)
改成下列代码:
#elif defined(CONFIG_S3C2410)||defined(CONFIG_S3C2440)
以下代码摘自s3c24x0.h
#ifdef CONFIG_S3C2410
上述代码改为:
#if defined(CONFIG_S3C2410)||defined(CONFIG_S3C2440)
这样重新编译后能够成功。
接下来继续按照程序的运行顺序进行分析更改。
init_sequence函数数组
#if defined(CONFIG_ARCH_CPU_INIT) arch_cpu_init, /* basic arch cpu dependent setup */#endif
对于mini2440上列代码不执行
board_init函数是和开发板紧密相关的,下面介绍对board_init的移植。
#define M_MDIV 0xA1#define M_PDIV 0x3#define M_SDIV 0x1
上列代码更改为:
#define M_MDIV 0x7f#define M_PDIV 0x2#define M_SDIV 0x1
#define U_M_MDIV 0x48#define U_M_PDIV 0x3#define U_M_SDIV 0x2
上列代码更改为:
#define U_M_MDIV 0x38#define U_M_PDIV 0x2#define U_M_SDIV 0x2
上面的更改是对CPU频率进行的更改。
对GPIO端口进行配置:
gpio->GPACON = 0x007FFFFF; gpio->GPBCON = 0x00295551; gpio->GPBUP = 0x000007FF; gpio->GPCCON = 0xAAAAAAAA; gpio->GPCUP = 0xFFFFFFFF; gpio->GPDCON = 0xAAAAAAAA; gpio->GPDUP = 0xFFFFFFFF; gpio->GPECON = 0xAAAAAAAA; gpio->GPEUP = 0x0000FFFF; gpio->GPFCON = 0x000055AA; gpio->GPFUP = 0x000000FF; gpio->GPGCON = 0xFF95FFBA; gpio->GPGUP = 0x0000FFFF; gpio->GPHCON = 0x002AFAAA; gpio->GPHUP = 0x000007FF; gpio->EXTINT1=0x22222222; gpio->EXTINT2=0x22222222;
gd->bd->bi_arch_number = MACH_TYPE_MINI2440;
设置开发板的ID,其实这一步是没有意义的,我们一般在R1寄存器中保存开发板ID。而且即使设置了,我们也不将其保存到tag中。
#if defined(CONFIG_USE_IRQ) interrupt_init, /* set up exceptions */#endif
这一部分代码是否执行取决于CONFIG_USE_IQR,这个宏如果有定义的话,需要在mini2440.h中定义,我们没有定义。
timer_init, /* initialize timer */
这个函数的作用是设定一个定时器,涉及到的操作是对定时器寄存器的操作,无须修改。
#ifdef CONFIG_FSL_ESDHC get_clocks,#endif
这一部分代码是否执行取决于CONFIG_FSL_ESDHC,这个宏如果有定义的话,需要在mini2440.h中定义,我们没有定义。
env_init, /* initialize environment */
env_init在U_boot中多处有定义,最终选用的定义取决于mini2440.h中的宏定义。
#define CONFIG_ENV_IS_IN_FLASH 1
我们将环境变量定义保存在NOR FLASH中。
这一块代码复杂,不深究,但结构只是设置了下列两个值:
gd->env_addr = gd->env_valid =
init_baudrate
这个函数是为了设定波特率的值,没有涉及到具体的硬件操作,只是在gd中保存波特率。
波特率的值在mini2440.h中定义,如果没有使用默认值115200
#define CONFIG_BAUDRATE 115200
我们在mini2440.h中设置了波特率为115200
serial_init
进行串口初始化,需要设定相应寄存器的值,U-Boot自带的驱动程序中包含具体的实现过程。在该函数中还调用了另一个和移植相关的重要函数:
void _serial_setbrg(const int dev_index){ struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index); unsigned int reg = 0; int i; /* value is calculated so : (int)(PCLK/16./baudrate) -1 */ reg = get_PCLK() / (16 * gd->baudrate) - 1; writel(reg, &uart->UBRDIV); for (i = 0; i < 100; i++) /* Delay */ ;}
其中的get_PCLK和移植相关,因为s3c2410和s3c2440处理时钟的寄存器差别较大,不能直接使用,需要修改。
这里需要修改的文件是speed.c
在static ulong get_PLLCLK(int pllreg)中进行如下修改:
return (CONFIG_SYS_CLK_FREQ * m) / (p << s);改为: if (pllreg == MPLL) return (2*CONFIG_SYS_CLK_FREQ * m) / (p << s); else if (pllreg == UPLL) return (CONFIG_SYS_CLK_FREQ * m) / (p << s); else hang();
在函数ulong get_HCLK(void)中修改如下代码:
return (readl(&clk_power->CLKDIVN) & 2) ? get_FCLK() / 2 : get_FCLK();改为:return (readl(&clk_power->CLKDIVN) & 2) ? get_FCLK() / 2 : get_FCLK()/4;
console_init_f
进行控制台的初始化,其实只是设定了:
gd->have_console = 1;
这应该是表示控制台存在。
display_banner
这个只是向控制台输出一些信息,表示我们之前的工作顺利完成。
display_banner, /* say that we are here */#if defined(CONFIG_DISPLAY_CPUINFO) print_cpuinfo, /* display cpu info (and speed) */#endif
上述代码取决于CONFIG_DISPLAY_CPUINFO宏定义,需要定义在mini2440.h中,我们没有定义。
#if defined(CONFIG_DISPLAY_BOARDINFO) checkboard, /* display board info */#endif
上述代码取决于CONFIG_DISPLAY_BOARDINFO宏定义,需要定义在mini2440.h中,我们没有定义。
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C) init_func_i2c,#endif
同上,没有定义。
dram_init
这个必须要执行,设定SDRAM的其实地址和大小,最终需要传递给内核的。
int dram_init (void){ gd->bd->bi_dram[0].start = PHYS_SDRAM_1; gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE; return 0;}
上述代码在mini2440.c中定义。
#define PHYS_SDRAM_1 0x30000000 /* SDRAM Bank #1 */#define PHYS_SDRAM_1_SIZE 0x04000000 /* 64 MB */
我们在mini2440.h中定义了SDRAM的参数,需要和开发板中的内存匹配。
#if defined(CONFIG_CMD_PCI) || defined (CONFIG_PCI) arm_pci_init,#endif
这个不执行,我们的ARM中没有PCI总线。
display_dram_config
显示内存的信息,无须修改。
现在编译生成的二进制文件就可以在开发板上运行了,但是很多功能没有实现。可以把这里当为一个检测点,要求能正常编译,控制台能正常显示内容。
第二阶段剩余部分
mem_malloc_init (_armboot_start - CONFIG_SYS_MALLOC_LEN, CONFIG_SYS_MALLOC_LEN);
对堆进行清零操作
#ifndef CONFIG_SYS_NO_FLASH /* configure available FLASH banks */ display_flash_config (flash_init ());#endif /* CONFIG_SYS_NO_FLASH */
我们没有定义CONFIG_SYS_NO_FLASH
该函数中最重要的是flash_init(),display_flash_config()只是对返回值进行格式处理,然后再显示出来。
flash_init()函数在/board/samsung/mini2440/flash.c中定义,可见该函数是与开发板密切相关,移植时应当重视。
NOR FLASH基础知识:
NOR FLASH的读操作和内存的读操作一模一样,但是写操作复杂,需要特定的指令序。
一个NOR FLASH chip由多个BLOCK组成,每个BLOCK由多个SECTION组成
在写操作时,NOR FLASH只能将1转化成0,所以在写之前要进行擦除
擦除的最小对象为SECTION
该部分的代码移植不介绍了,具体的参考《mini2440之U-boot移植详细手册-20100419》。
#ifdef CONFIG_VFD...#endif
我们没有定义,不用管
#ifdef CONFIG_LCD...#endif
也没有定义,忽略
#if defined(CONFIG_CMD_NAND)...#endif
没有定义,忽略
#if defined(CONFIG_CMD_ONENAND)...#endif
没有定义,忽略
#ifdef CONFIG_HAS_DATAFLASH...#endif
没有定义,忽略
env_relocate ();
环境变量的重定位,其中的重要内容如下:
#ifdef ENV_IS_EMBEDDED#ifndef CONFIG_RELOC_FIXUP_WORKS env_ptr = (env_t *)((ulong)env_ptr + gd->reloc_off);#endif DEBUGF ("%s[%d] embedded ENV at %p\n", __FUNCTION__,__LINE__,env_ptr);#else env_ptr = (env_t *)malloc (CONFIG_ENV_SIZE); DEBUGF ("%s[%d] malloced ENV at %p\n", __FUNCTION__,__LINE__,env_ptr);#endif
我们没有定义ENV_IS_EMBEDDED,所以环境变量的指针是指向动态分配的内存。
#ifdef CONFIG_VFD...#endif
不执行
#ifdef CONFIG_SERIAL_MULTI serial_initialize();#endif
不执行
gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
获得IP地址,储存到全局变量gd中。
stdio_init ();
一系列标准的IO口初始化,前提是定义了相应的宏。
jumptable_init ();
其中的代码如下:
void jumptable_init(void){ gd->jt = malloc(XF_MAX * sizeof(void *));#include <_exports.h>}
#if defined(CONFIG_API) api_init ();#endif
没有定义,不执行
console_init_r (); /* fully init console as a device */
过程太复杂了,没有去了解,最后会在控制台输出
IN : serialOUT :serialERR :serial
#if defined(CONFIG_ARCH_MISC_INIT) arch_misc_init ();#endif#if defined(CONFIG_MISC_INIT_R) misc_init_r ();#endif
不执行
interrupt_init (void)
因为我们没有定义CONFIG_USE_IRQ,所以该函数是一个空的函数
#ifdef CONFIG_DRIVER_TI_EMAC...#endif
没定义,不执行
#if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)...#endif
没定义,不执行
if ((s = getenv ("loadaddr")) != NULL) { load_addr = simple_strtoul (s, NULL, 16); }
这一段,根据环境变量来设置加载地址,没有定义就使用默认值。
#if defined(CONFIG_CMD_NET) if ((s = getenv ("bootfile")) != NULL) { copy_filename (BootFile, s, sizeof (BootFile)); }#endif
其中的CONFIG_CMD_NET是定义了的,但是不是我们自己在mini2440.h中定义的。在哪呢?
但是这里的if语句不满足,所以也是没有执行。
#ifdef BOARD_LATE_INIT board_late_init ();#endif
没定义,不执行
#ifdef CONFIG_GENERIC_MMC puts ("MMC: "); mmc_initialize (gd->bd);#endif
没定义,不执行
#ifdef CONFIG_BITBANGMII bb_miiphy_init();#endif
没定义,不执行
#if defined(CONFIG_CMD_NET)#if defined(CONFIG_NET_MULTI) puts ("Net: ");#endif eth_initialize(gd->bd);#if defined(CONFIG_RESET_PHY_R) debug ("Reset Ethernet PHY\n"); reset_phy();#endif#endif
没有定义CONFIG_RESET_PHY_R,重要的地方就是eth_initialize(gd->bd);这一部分决定了能否使用网卡。这一部分不深入研究,请参考《mini2440之U-boot移植详细手册-20100419》。注意:《mini2440之U-boot移植详细手册-20100419》不是以smdk2410作为模板进行移植的,在移植lowlevel_init时,不应该使用smdk2410中的,否则网络功能不能执行。因为其中涉及较多很网卡有关的知识,先不在这一块深入研究,只是模仿拷贝代码。
至此已经完成了移植工作的全部内容,因为移植部分复杂,涉及更改的地方较多,所以难免会有遗漏的地方,尤其是对mini2440.h头文件相关的代码。所以建议先按上述思路移植,遇到问题之后自己检查,查看源代码是解决问题最好的方法,建议用Source Insight工具建立源码工程。哪里有问题就补哪里。
最后附上按照上面的步骤编译的U_boot.bin,实测可以在mini2440上使用。
U-Boot.bin下载地址
- U-boot移植到mini2440上
- u-boot移植到mini2440
- u-boot-2009.11移植到mini2440(一)
- 移植u-boot到mini2440开发板。
- u-boot-2011.03移植nandflash到mini2440
- u-boot移植到mini2440之一
- u-boot移植到mini2440之二
- u-boot移植到mini2440之三
- u-boot移植到mini2440之四
- 移植u-boot到mini2440--board_init_r 分析
- 移植u-boot到mini2440--SPL初探
- u-boot移植到mini2440,u-boot版本2008.10
- 原创 u-boot移植到mini2440,u-boot版本2008.10
- u-boot移植到mini2440,u-boot版本2008.10 收藏
- u-boot移植到mini2440,u-boot版本2008.10
- u-boot移植到mini2440,u-boot版本2008.10
- u-boot移植到mini2440,u-boot版本2008.10
- u-boot移植到mini2440,u-boot版本2008.10
- class类
- 反转链表
- UVa 10375 Choose and divide
- Log的学习和使用
- Android 通知栏Notification的整合 全面学习 (一个DEMO让你完全了解它)
- U-boot移植到mini2440上
- Oracle查询server字符集+修改字符集
- STM32M4DA_AD
- 巴菲特选股10招
- Android心得--对ContentProvide分解介绍
- WinSock编程流程(2)- UDP
- cocos2d-x3.4json动画删除问题
- Oracle查看字符集后修改oracle服务端和客户端字符集的步骤
- Visual Studio 2013 如何关闭调试而不关闭IIS Express