Chinaunix首页 | 论坛 | 博客
  • 博客访问: 57489
  • 博文数量: 17
  • 博客积分: 370
  • 博客等级: 一等列兵
  • 技术积分: 150
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-14 10:11
文章分类
文章存档

2011年(17)

我的朋友

分类: LINUX

2011-03-01 23:20:37

原文作者Jacky Xu

原文地址:http://blogold.chinaunix.net/u1/58780/showart_459188.html

前面大致分析了u-boot启动的两个阶段的大致流程,今天再更详细的分析一下启动过程中涉及的几个用于初始化的子函数。分析不当的地方,希望能得到指正。

1、lowlevel_init(start.S中用于配置内存区控制寄存器,位于board/smdk2410/lowlevel_init.S)
start.S中跳转代码:

* before relocating, we have to setup RAM timing
* because memory timing is board-dependend, you will
* find a lowlevel_init.S in your board directory.
*/
mov ip, lr
bl lowlevel_init
/* 位于board/smdk2410/lowlevel_init.S:用于完成芯片存储器的初始化,执行完成后返回*/
mov lr, ip
mov pc, lr


Lowlevel_init文件代码不是很多,精简一下贴在这里:
#define BWSCON 0x48000000

/* BWSCON */
#define DW8 (0x0)
#define DW16 (0x1)
#define DW32 (0x2)
#define WAIT (0x1<<2)
#define UBLB (0x1<<3)

#define B1_BWSCON (DW32) /* 定义每个bank的数据总线宽度 */
#define B2_BWSCON (DW16)
#define B3_BWSCON (DW16 + WAIT + UBLB)
#define B4_BWSCON (DW16)
#define B5_BWSCON (DW16)
#define B6_BWSCON (DW32)
#define B7_BWSCON (DW32)

/* BANK0CON */
#define B0_Tacs 0x0 /* 0clk */
#define B0_Tcos 0x0 /* 0clk */
#define B0_Tacc 0x7 /* 14clk */
#define B0_Tcoh 0x0 /* 0clk */
#define B0_Tah 0x0 /* 0clk */
#define B0_Tacp 0x0
#define B0_PMC 0x0 /* normal */

/* BANK1CON */
/* 之间省略了多个bank区的配置,类似上面的BANK0CON。具体配置参数见源文件 */
/* BANK7CON */
/* REFRESH parameter */
#define REFEN 0x1 /* Refresh enable */
#define TREFMD 0x0 /* CBR(CAS before RAS)/Auto refresh */
#define Trp 0x0 /* 2clk */
#define Trc 0x3 /* 7clk */
#define Tchr 0x2 /* 3clk */
#define REFCNT 1113 /* period=15.6us, HCLK=60Mhz, (2048+1-15.6*60) */
/**************************************/

_TEXT_BASE:
.word TEXT_BASE

.globl lowlevel_init
lowlevel_init:
/* memory control configuration */
/* make r0 relative the current location so that it */
/* reads SMRDATA out of FLASH rather than memory ! */
ldr r0, =SMRDATA /* SMRDATA见下面,BWSCON寄存器的后面紧接着就是0-7个bank的控制寄存器的地址,这里整个数据是8个bank的配置参数和另外4个寄存器的配置参数,具体按照s3c2410的datasheet进行配置 */
ldr r1, _TEXT_BASE
sub r0, r0, r1
ldr r1, =BWSCON /* Bus Width Status Controller 从BWSCON寄存器的地址开始写13*4这么长的数据,也就是从SMRDATA标号开始的那些配置好的数据,一并写入 */
add r2, r0, #13*4
0:
ldr r3, [r0], #4
str r3, [r1], #4
cmp r2, r0
bne 0b

/* everything is fine now 上面都配置好了,返回start.S */
mov pc, lr

.ltorg
/* the literal pools origin */


/* 下面共有13个word,设置了一系列连续的寄存器的值,给上面循环赋值用*/
SMRDATA:
.word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28))
.word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC))
.word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC))
.word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC))
.word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC))
.word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC))
.word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC))
.word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN))
.word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN))
.word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)
.word 0x32
.word 0x30
.word 0x30



2、分析init_sequence里的初始化函数

(1) cpu_init()

为IRQ和FIQ设置中断的开始地址。具体可查看u-boot存储映射图。
int cpu_init (void)
{
/*
* setup up stacks if necessary
*/
#ifdef CONFIG_USE_IRQ
DECLARE_GLOBAL_DATA_PTR;

IRQ_STACK_START = _armboot_start - CFG_MALLOC_LEN - CFG_GBL_DATA_SIZE - 4;
FIQ_STACK_START = IRQ_STACK_START - CONFIG_STACKSIZE_IRQ;
#endif
return 0;
}


(2)board_init()

此函数首先按照datasheet初始化了CPU和各个GPIO,然后将CPU体系结构编号和内核启动的参数赋给全局变量gd。
int board_init (void)
{
DECLARE_GLOBAL_DATA_PTR;
//此全局变量指定用r8寄存器存储其地址,所以在任意子函数里面声明一下,就可以使用同一个全局变量的了

S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
/* 以上使clk_power指向0x4C000000这个PLL lock time count register,后面为一系列配置CPU的寄存器,具体都用S3C24X0_CLOCK_POWER这个结构体封装起来了,内部变量的顺序正好和datasheet中定义的一致;gpio指向0x56000000这个GPACON,后面为一系列GPIO寄存器,用S3C24X0_GPIO封装了,同上。如:
typedef struct {
S3C24X0_REG32 LOCKTIME;
S3C24X0_REG32 MPLLCON;
S3C24X0_REG32 UPLLCON;
S3C24X0_REG32 CLKCON;
S3C24X0_REG32 CLKSLOW;
S3C24X0_REG32 CLKDIVN;
} /*__attribute__((__packed__))*/ S3C24X0_CLOCK_POWER;
*/


/* 下面都是根据datasheet来设置CPU和GPIO的 */
/* to reduce PLL lock time, adjust the LOCKTIME register */
clk_power->LOCKTIME = 0xFFFFFF;

/* configure MPLL */
clk_power->MPLLCON = ((M_MDIV << 12) + (M_PDIV << 4) + M_SDIV);

/* some delay between MPLL and UPLL */
delay (4000);

/* configure UPLL */
clk_power->UPLLCON = ((U_M_MDIV << 12) + (U_M_PDIV << 4) + U_M_SDIV);

/* some delay between MPLL and UPLL */
delay (8000);

/* set up the I/O ports */
gpio->GPACON = 0x007FFFFF;
gpio->GPBCON = 0x00044555;
gpio->GPBUP = 0x000007FF;
gpio->GPCCON = 0xAAAAAAAA;
gpio->GPCUP = 0x0000FFFF;
gpio->GPDCON = 0xAAAAAAAA;
gpio->GPDUP = 0x0000FFFF;
gpio->GPECON = 0xAAAAAAAA;
gpio->GPEUP = 0x0000FFFF;
gpio->GPFCON = 0x000055AA;
gpio->GPFUP = 0x000000FF;
gpio->GPGCON = 0xFF95FFBA;
gpio->GPGUP = 0x0000FFFF;
gpio->GPHCON = 0x002AFAAA;
gpio->GPHUP = 0x000007FF;

/* arch number of SMDK2410-Board */
gd->bd->bi_arch_number = MACH_TYPE_SMDK2410; //CPU体系结构编号

/* adress of boot parameters */
gd->bd->bi_boot_params = 0x30000100;
//存放内核启动引导的参数,此变量在后面可传递给go函数的第三个参数

icache_enable();
dcache_enable();

return 0;
}


(3)env_init

初始化环境变量。全局定义的env_t *env_ptr = (env_t *)CFG_ENV_ADDR,先CRC校验是否正确,若正确就设置gd->env_valid = 1,否之调用默认环境变量,并设置gd->env_valid = 0。冷复位时,env_ptr->data无数据,CRC肯定错误,所以开机后会提示bad CRC...
int env_init(void)
{
DECLARE_GLOBAL_DATA_PTR;
if (crc32(0, env_ptr->data, ENV_SIZE) == env_ptr->crc) {
gd->env_addr = (ulong)&(env_ptr->data);
gd->env_valid = 1;
return(0);
}
gd->env_addr = (ulong)&default_environment[0];
gd->env_valid = 0;
return (0);
}


(4)init_baudrate

获取环境变量,把其中的波特率值给全局gd,若获取为空值,则赋默认的115200。
static int init_baudrate (void)
{
DECLARE_GLOBAL_DATA_PTR;

uchar tmp[64]; /* long enough for environment variables */
int i = getenv_r ("baudrate", tmp, sizeof (tmp));
//将环境变量获取到tmp中,i为得到的环境变量的长度

gd->bd->bi_baudrate = gd->baudrate = (i > 0)
//如果确实获取到了env,则给gd,否则把宏定义的115200给gd

? (int) simple_strtoul (tmp, NULL, 10) //此函数把字符串转换成ulong整型

: CONFIG_BAUDRATE; //此宏为115200


return (0);
}


(5)serial_init

此函数调用serial_setbrg ()函数,主函数返回0。serial_setbrg()函数初始化串口,具体的配置参数根据datasheet设置。
void serial_setbrg (void)
{
DECLARE_GLOBAL_DATA_PTR;
S3C24X0_UART * const uart = S3C24X0_GetBase_UART(UART_NR);
int i;
unsigned int reg = 0;

/* value is calculated so : (int)(PCLK/16./baudrate) -1 */
reg = get_PCLK() / (16 * gd->baudrate) - 1;

/* FIFO enable, Tx/Rx FIFO clear */
uart->UFCON = 0x07;
uart->UMCON = 0x0;
/* Normal,No parity,1 stop,8 bit */
uart->ULCON = 0x3;
/*
* tx=level,rx=edge,disable timeout int.,enable rx error int.,
* normal,interrupt or polling
*/
uart->UCON = 0x245;
uart->UBRDIV = reg;

#ifdef CONFIG_HWFLOW
uart->UMCON = 0x1; /* RTS up */
#endif
for (i = 0; i < 100; i++);
}


(6)dram_init(),display_dram_config ()

填充全局gd里面有关RAM的地址和大小,即.start和.size两个变量,之后一个函数把内容打印到终端。
int dram_init (void)
{
DECLARE_GLOBAL_DATA_PTR;

gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;
//smdk2410.h中定义:

// #define PHYS_SDRAM_1 0x30000000 /* SDRAM Bank #1 */
// #define PHYS_SDRAM_1_SIZE 0x04000000 /* 64 MB */

return 0;
}




3、flash_init ()(此函数紧接着上面那一串初始化函数,用于初始化Nor flash的函数,初始化了每个扇区的首地址)
ulong flash_init (void)
{
int i, j;
ulong size = 0;

for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) { //我的板子有1块Nor flash

ulong flashbase = 0;
/* 上面定义了全局变量:flash_info_t flash_info[CFG_MAX_FLASH_BANKS]。此类型定义了NorFlash的基本信息,具体结构如下:
* FLASH Info: contains chip specific data, per FLASH bank
typedef struct {
ulong size; /* total bank size in bytes */
ushort sector_count; /* number of erase units */
ulong flash_id; /* combined device & manufacturer code */
ulong start[CFG_MAX_FLASH_SECT]; /* physical sector start addresses */
uchar protect[CFG_MAX_FLASH_SECT]; /* sector protection status */
#ifdef CFG_FLASH_CFI
uchar portwidth; /* the width of the port */
uchar chipwidth; /* the width of the chip */
ushort buffer_size; /* # of bytes in write buffer */
ulong erase_blk_tout; /* maximum block erase timeout */
ulong write_tout; /* maximum write timeout */
ulong buffer_write_tout; /* maximum buffer write timeout */
ushort vendor; /* the primary vendor id */
ushort cmd_reset; /* Vendor specific reset command */
ushort interface; /* used for x8/x16 adjustments */
#endif
} flash_info_t;
下面就是对这个结构的填充 */
flash_info[i].flash_id = //我这块sbc2410的NorFlash型号是29LV160DB

#if defined(CONFIG_AMD_LV400)
(AMD_MANUFACT & FLASH_VENDMASK) |
(AMD_ID_LV400B & FLASH_TYPEMASK);
#elif defined(CONFIG_AMD_LV800)
(AMD_MANUFACT & FLASH_VENDMASK) |
(AMD_ID_LV800B & FLASH_TYPEMASK);
#else
#error "Unknown flash configured"
//以上没有这个型号,若默认编译,只能认出是512K的,实际是2M的,若要移植到sbc2410上,这里要修改才能得到正确的容量

#endif
flash_info[i].size = FLASH_BANK_SIZE;
//在/include/configs/smdk2410.h文件中定义了此块NorFlash的PHY_FLASH_SIZE,我这个应该是2M

flash_info[i].sector_count = CFG_MAX_FLASH_SECT;
//擦除的单元总数,在smdk2410.h中定义为19(1M容量的NorFlash,我这块应该是多少个?),即flash中的扇区总数目

memset (flash_info[i].protect, 0, CFG_MAX_FLASH_SECT);//取消扇区的写保护?

if (i == 0)
flashbase = PHYS_FLASH_1;
else
panic ("configured too many flash banks!\n"); //只有一块Norflash,如果i > 0了表示不止一块

for (j = 0; j < flash_info[i].sector_count; j++) {
//初始化每个扇区的首地址。其中,前4个扇区的大小和后面不同,需要分开设置。??

if (j <= 3) {
/* 1st one is 16 KB */
if (j == 0) {
flash_info[i].start[j] =
flashbase + 0;
}

/* 2nd and 3rd are both 8 KB */
if ((j == 1) || (j == 2)) {
flash_info[i].start[j] =
flashbase + 0x4000 + (j -
1) *
0x2000;
}

/* 4th 32 KB */
if (j == 3) {
flash_info[i].start[j] =
flashbase + 0x8000;
}
} else {
flash_info[i].start[j] =
flashbase + (j - 3) * MAIN_SECT_SIZE;
//后面的扇区都是0x10000,即64KB

}
}
size += flash_info[i].size; //计算此块flash的总size,供最后return

}

flash_protect (FLAG_PROTECT_SET,
CFG_FLASH_BASE,
CFG_FLASH_BASE + monitor_flash_len - 1,
&flash_info[0]);
//此函数有待研究

flash_protect (FLAG_PROTECT_SET,
CFG_ENV_ADDR,
CFG_ENV_ADDR + CFG_ENV_SIZE - 1, &flash_info[0]);

return size;
}
阅读(1900) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~