微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > s3c6410 uboot代码分析

s3c6410 uboot代码分析

时间:11-09 来源:互联网 点击:

clbss_l:
strr2, [r0]/* clear loop... */
addr0, r0, #4
cmpr0, r1
bleclbss_l

--------------------

/*跳转到uboot代码的第二个阶段,第二阶段基本上都是用C实现的,幸好前面sp的值已经设置好了 */

--------------------

ldrpc, _start_armboot

_start_armboot:
.word start_armboot

--------------------

2.第二阶段代码分析(代码在lib_arm目录下的board.c里面,start_armboot函数)

1)初始化CPU及外围硬件


init_fnc_t init_fnc_ptr;
char *s;
#ifndef CFG_NO_FLASH
ulong size;
#endif

#if defined(CONFIG_VFD) || defined(CONFIG_LCD)
unsigned long addr;
#endif

#if defined(CONFIG_BOOT_MOVINAND)
uint *magic = (uint *) (PHYS_SDRAM_1);
#endif

/* Pointer is writable since we allocated a register for it */
#ifdef CONFIG_MEMORY_UPPER_CODE /* by scsuh */
ulong gd_base;

gd_base = CFG_UBOOT_BASE + CFG_UBOOT_SIZE - CFG_MALLOC_LEN - CFG_STACK_SIZE - sizeof(gd_t);
#ifdef CONFIG_USE_IRQ
gd_base -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ);
#endif
gd = (gd_t*)gd_base;
#else
gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));
#endif

/* compiler optimization barrier needed for GCC >= 3.4 */
__asm__ __volatile__("": : :"memory");

memset ((void*)gd, 0, sizeof (gd_t));
gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
memset (gd->bd, 0, sizeof (bd_t));

monitor_flash_len = _bss_start - _armboot_start;

for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}

解释:定义二级指针init_fnc_ptr指向一个存放函数指针的数组,init_fnc_ptr是typedef int (init_fnc_t) (void)类型,即函数类型,init_fnc_ptr可以指向一个没有参数,返回值为int型的函数指针的地址(很绕哦,),我们看上面代码最后的for循环init_fnc_ptr = init_sequence,if中会使用(*init_fnc_ptr)()方式调用init_sequence中的函数(函数名可以看为一个地址),如果返回值不是0,则执行hang报错。

因为我们定义了CONFIG_MEMORY_UPPER_CODE宏,所以gd = (gd_t*)gd_base,由gd_base的值我们知道,malloc区域、stack区域、bdinfo数据在内存的位置是放在upper of uboot。

__asm__ __volatile__("": : :"memory");这条是内嵌汇编,请查看另一篇介绍内嵌汇编的博文。

gd->bd指针指向数据类型为bd_t的结构体,bd_t结构体记录开发板的参数,例如串口波特率、ip地址、机器类型、启动参数、环境变量位置等。

下面分析for循环执行的函数:

cpu_init:因为我们没有定义CONFIG_USE_IRQ,所以这个函数直接返回0

board_init:


函数内首先执行dm9000_pre_init()函数,因为我们把DM9000AEP网卡映射到内存的Xm0CSn[1]上,所以我们要设置访问CSn[1]的方式,SROM_BW_REG &= ~(0xf < 4);SROM_BW_REG |= (1<7) | (1<6) | (1<4);两条代码的含义为设置0x70000000控制器的CSn[1]访问方式为nBE enable、wait enable、16位数据总线访问模式,SROM_BC1_REG = ((DM9000_Tacs<28)+(DM9000_Tcos<24)+(DM9000_Tacc<16)+(DM9000_Tcoh<12)+(DM9000_Tah<8)+(DM9000_Tacp<4)+(DM9000_PMC));这句话的意思是设置访问的时序,s3c6410 datasheet中已经给出了时序代码,欢迎查看哦。因为我的zc6410开发箱接了4.3的TFT LCD,所以在代码中增加了对LCD的配置工作,代码如下:

writel(readl(MIFPCON) & (~(1 < 3)), MIFPCON);

writel(readl(MIFPCON) & (~(3 < 0)) | 0x1, SPCON);

writel(0xaaaaaaaa, GPICON);
writel(0xaaaaaa, GPJCON);

以上四行代码分别对MIFPCON、SPCON、GPICON、GPJCON四个寄存器赋值。为什么赋值?查看s3c6410 datasheet手册14.5.1节,给出了DisplayController的引脚配置,MIFPCON的[3]位设置为0(normal mode)instead of “1”(by-pass mode),SPCON[1:0]位的值设置为“01”(useRGB I/F Style)or “00” to use Host I/F Style,我们设置的是01。GPICON、GPJCON赋值的原因请看下面图:

第一张图是LCD控制器接口连接原理图,后面的是图是芯片手册,通过两个图我们就知道为什么要写后面两行代码了吧。

好了,73-74行一个是记录机器类型,一个是指定向内核传参的地址。

interrupt_init:


184行:值0x0101的含义是设置env_init:如下图,因为没有定义ENV_IS_EMBEDDED,所有只是执行了142-143,把环境变量的首地址赋值给gd->env_addr。

init_baudrate:

139行使用getenv_r函数在default_environment里找baudrate关键字,找到后把“=”号后面的值赋值给gd->baudrate,然后

再放到gd->bd->bi_baudrate里面。simple_strtoul是uboot实现的字符串转UL类型。

serial_init:什么都没做,保持默认的8位数据、无奇偶校验、1 停止位、无开始位。

console_init_f:gd->have_console = 1就这一句话

display_ba

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top