ok6410下的uboot分析与实现

时间:2024-01-03 09:07:02

uboot 由两阶段代码组成:

•第一阶段主要步骤:

1.将cpu设置为svc模式

2.关闭mmu

3.设置外设端口地址

4.关闭watchdog

5.关闭中断

6.初始化时钟

7.初始化内存DRAM

8.把 nandflash 中的代码搬移到链接地址处

9.初始化堆栈

10.清bss段

11.使用与地址相关的跳转指令,跳转到 c 入口处。

OK6410上的启动代码如下:

@start.S
.text
.global _start
_start:
/*set the cpu to svc32 mode*/
mrs r0,cpsr
bic r0,r0,#0x1f
orr r0,r0,#0xd3
msr cpsr,r0 /*disable_mmu*/
mcr p15,0,r0,c7,c7,0
mrc p15,0,r0,c1,c0,0
bic r0,r0,#0x00000007
mcr p15,0,r0,c1,c0,0
/*peri port setup*/
ldr r0,=0x70000000
orr r0,r0,#0x13
mcr p15,0,r0,c15,c2,4
/*Disable Watchdog
*if you don't disable watchdog,because you don't to feed dog,so the CPU will conti *nue reboot.
*/
ldr r0,=0x7e000000
orr r0,r0,#0x4000
mov r1,#0
str r1,[r0]
/*Disable interrupt*/
mvn r1,#0
ldr r0,=0x71200014
str r1,[r0] ldr r0,=0x71300014
str r1,[r0] /*Init clock*/
#define APLL_LOCK 0x7e00f000
#define MPLL_LOCK 0x7e00f004
#define EPLL_LOCK 0x7e00f008
#define LOCK_TIME 0xffff #define OTHERS 0x7e00f900 #define CLK_DIV0 0x7e00f020 #define CLK_SRC 0x7e00f01c @ set the lock time to max
ldr r0, =LOCK_TIME
ldr r1, =APLL_LOCK
str r0, [r1]
ldr r1, =MPLL_LOCK
str r0, [r1]
ldr r1, =EPLL_LOCK
str r0, [r1] @ set async mode
ldr r0, =OTHERS
ldr r1, [r0]
bic r1, #0xc0
str r1, [r0] loop1:
ldr r0, =OTHERS
ldr r1, [r0]
and r1, #0xf00
cmp r1, #0
bne loop1 @ set the divider #define DIV_VAL ( (0)|(1<<4)|(1<<8)|(1<<9)|(3<<12) )
ldr r0, =CLK_DIV0
ldr r1, =DIV_VAL
str r1, [r0] @ set APLL, MPLL, EPLL
#define SDIV 1
#define PDIV 3
#define MDIV 266
#define PLL_ENABLE ( 1 << 31 )
#define APLL_VAL ( (SDIV<<0)|(PDIV<<8)|(MDIV<<16)|(PLL_ENABLE) )
#define MPLL_VAL APLL_VAL
#define EPLL0_VAL ( (2<<0)|(1<<8)|(32<<16)|PLL_ENABLE)
#define EPLL1_VAL ( 0 ) #define APLL_CON 0x7e00f00c
#define MPLL_CON 0x7e00f010
#define EPLL_CON0 0x7e00f014
#define EPLL_CON1 0x7e00f018 ldr r0, =APLL_CON
ldr r1, =APLL_VAL
str r1, [r0] ldr r0, =MPLL_CON
ldr r1, =MPLL_VAL
str r1, [r0] ldr r0, =EPLL_CON0
ldr r1, =EPLL0_VAL
str r1, [r0] ldr r0, =EPLL_CON1
ldr r1, =EPLL1_VAL
str r1, [r0] @ select the source
ldr r0, =CLK_SRC
mov r1, #7
str r1, [r0] init_mem:
ldr r0,=0x7e00f120
mov r1, #0x8
str r1, [r0] ldr r0, =0x7e001004
mov r1, #0x4
str r1, [r0] ldr r0, =0x7e001010
ldr r1, =( ( 7800 / ( 1000000000/133000000 ) + 1 ) )
str r1, [r0] ldr r0, =0x7e001014
mov r1, #(3 << 1)
str r1, [r0] ldr r0, =0x7e001018
mov r1, #0x1
str r1, [r0] ldr r0, =0x7e00101c
mov r1, #0x2
str r1, [r0] ldr r0, =0x7e001020
ldr r1, =( ( 45 / ( 1000000000 / 133000000 ) + 1 ) )
str r1, [r0] ldr r0, =0x7e001024
ldr r1, =( ( 68 / ( 1000000000 / 133000000 ) + 1 ) )
str r1, [r0] ldr r0, =0x7e001028
ldr r1, =( ( 23 / ( 1000000000 / 133000000 ) + 1 ) )
str r1, [r0] ldr r0, =0x7e00102c
ldr r1, =( ( 80 / ( 1000000000 / 133000000 ) + 1 ) )
str r1, [r0] ldr r0, =0x7e001030
ldr r1, =( ( 23 / ( 1000000000 / 133000000 ) + 1 ) )
str r1, [r0] ldr r0, =0x7e001034
ldr r1, =( ( 15 / ( 1000000000 / 133000000 ) + 1 ) )
str r1, [r0] ldr r0, =0x7e001038
ldr r1, =( ( 15 / ( 1000000000 / 133000000 ) + 1 ) )
str r1, [r0] ldr r0, =0x7e00103c
mov r1, #0x07
str r1, [r0] ldr r0, =0x7e001040
mov r1, #0x02
str r1, [r0] ldr r0, =0x7e001044
ldr r1, =( ( 120 / ( 1000000000 / 133000000 ) + 1 ) )
str r1, [r0] ldr r0, =0x7e001048
ldr r1, =( ( 120 / ( 1000000000 / 133000000 ) + 1 ) )
str r1, [r0] ldr r0, =0x7e00100c
ldr r1, =0x00010012
str r1, [r0] ldr r0, =0x7e00104c
ldr r1, =0x0b45
str r1, [r0] ldr r0, =0x7e001200
ldr r1, =0x150f8
str r1, [r0] ldr r0, =0x7e001304
mov r1, #0x0
str r1, [r0] ldr r0, =0x7e001008
ldr r1, =0x000c0000
str r1, [r0] ldr r1, =0x00000000
str r1, [r0] ldr r1, =0x00040000
str r1, [r0] ldr r1, =0x000a0000
str r1, [r0] ldr r1, =0x00080032
str r1, [r0] ldr r0, =0x7e001004
mov r1, #0x0
str r1, [r0] check_dmc1_ready: ldr r0, =0x7e001000
ldr r1, [r0]
mov r2, #0x3
and r1, r1, r2
cmp r1, #0x1
bne check_dmc1_ready
nop /*prepare C language environment*/ /*
*copy_to_ram:
* ldr r0,=0x0c000000
* ldr r1,=0x50000000
* add r3,r0,#1024*4
*copy_loop:
* ldr r2,[r0],#4
* str r2,[r1],#4
* cmp r0,r3
* bne copy_loop
*/ init_stack:
ldr sp,=0x54000000 copy_to_ram:
adr r0, _start /* »ñµÃ_startÖ¸ÁǰËùÔڵĵØÖ· : 0*/
ldr r1, =_start /* _startµÄÁ´½ÓµØÖ· 0x51000000 */ ldr r2, =bss_start /* bss¶ÎµÄÆðʼÁ´½ÓµØÖ· */ sub r2, r2, r1 cmp r0,r1
beq clean_bss bl copy2ddr
cmp r0, #0
bne halt
clean_bss:
ldr r0,=bss_start
ldr r1,=bss_end
cmp r0,r1
beq to_ddr
clean_loop:
mov r2,#0
str r2,[r0],#4
cmp r0,r1
bne clean_loop to_ddr:
bl light_led
ldr pc,=main light_led:
ldr r1, =0x7F008820
ldr r0, =0x1111
str r0, [r1] ldr r1, =0x7F008824
mov r0,#0xe
str r0,[r1]
mov pc, lr halt:
b halt
//nand.c

#define MEM_SYS_CFG     (*((volatile unsigned long *)0x7E00F120))
#define NFCONF (*((volatile unsigned long *)0x70200000))
#define NFCONT (*((volatile unsigned long *)0x70200004))
#define NFCMMD (*((volatile unsigned long *)0x70200008))
#define NFADDR (*((volatile unsigned long *)0x7020000C))
#define NFDATA (*((volatile unsigned char *)0x70200010))
#define NFSTAT (*((volatile unsigned long *)0x70200028)) #define NAND_DISABLE_CE() (NFCONT |= (1 << 1))
#define NAND_ENABLE_CE() (NFCONT &= ~(1 << 1))
#define NF_TRANSRnB() do { while(!(NFSTAT & (1 << 0))); } while(0) #define NAND_CMD_RESET 0xff
#define NAND_CMD_READID 0x90
#define NAND_CMD_READ0 0
#define NAND_CMD_READSTART 0x30 void nand_select(void)
{
NFCONT &= ~(1<<1);
} void nand_deselect(void)
{
NFCONT |= (1<<1);
} void nand_cmd(unsigned char cmd)
{
NFCMMD = cmd;
} void nand_addr(unsigned char addr)
{
NFADDR = addr;
} unsigned char nand_get_data(void)
{
return NFDATA;
} void wait_ready(void)
{
while ((NFSTAT & 0x1) == 0);
} void nand_reset(void)
{
/* Ñ¡ÖÐ */
nand_select(); /* ·¢³ö0xffÃüÁî */
nand_cmd(0xff); /* µÈ´ý¾ÍÐ÷ */
wait_ready(); /* È¡ÏûÑ¡ÖÐ */
nand_deselect();
} void nand_init(void)
{
/* ÈÃxm0csn2ÓÃ×÷nand flash cs0 ƬѡÒý½Å */
MEM_SYS_CFG &= ~(1<<1); /* ÉèÖÃʱ¼ä²ÎÊý:hclk = 7.5ns */
#define TACLS 0
#define TWRPH0 3
#define TWRPH1 1
NFCONF &= ~((1<<30) | (7<<12) | (7<<8) | (7<<4));
NFCONF |= ((TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4)); /* ʹÄÜnand flash controller */
NFCONT |= 1; nand_reset();
} void nand_send_addr(unsigned int addr)
{
#if 0
unsigned int page = addr / 2048;
unsigned int colunm = addr & (2048 - 1); /* ÕâÁ½¸öµØÖ·±íʾ´ÓÒ³ÄÚÄÄÀ↑ʼ */
nand_addr(colunm & 0xff);
nand_addr((colunm >> 8) & 0xff); /* ÏÂÃæÈý¸öµØÖ·±íʾÄÄÒ»Ò³ */
nand_addr(page & 0xff);
nand_addr((page >> 8) & 0xff);
nand_addr((page >> 16) & 0xff);
#else
nand_addr(addr & 0xff); /* a0~a7 */
nand_addr((addr >> 8) & 0x7); /* ³ÌÐòµÄ½Ç¶È: a8~a10 */ nand_addr((addr >> 11) & 0xff); /* ³ÌÐòµÄ½Ç¶È: a11~a18 */
nand_addr((addr >> 19) & 0xff); /* ³ÌÐòµÄ½Ç¶È: a19~a26 */
nand_addr((addr >> 27) & 0xff); /* ³ÌÐòµÄ½Ç¶È: a27 ~ */ #endif
} int nand_read(unsigned int nand_start, unsigned int ddr_start, unsigned int len)
{
unsigned int addr = nand_start;
int i, count = 0;
unsigned char *dest = (unsigned char *)ddr_start; /* Ñ¡ÖÐоƬ */
nand_select(); while (count < len)
{
/* ·¢³öÃüÁî0x00 */
nand_cmd(0x00); /* ·¢³öµØÖ· */
nand_send_addr(addr); /* ·¢³öÃüÁî0x30 */
nand_cmd(0x30); /* µÈ´ý¾ÍÐ÷ */
wait_ready(); /* ¶ÁÊý¾Ý */
for (i = 0; i < 2048 && count < len; i++)
{
dest[count++] = nand_get_data();
} addr += 2048;
} /* È¡ÏûƬѡ */
nand_deselect();
return 0;
} static int nandll_read_page (unsigned char *buf, unsigned long addr, int large_block)
{
int i;
int page_size = 512; if (large_block==2)
page_size = 4096; NAND_ENABLE_CE(); // Ñ¡ÖÐnand NFCMMD = NAND_CMD_READ0; /* Write Address */
NFADDR = 0; if (large_block)
NFADDR = 0; NFADDR = (addr) & 0xff;
NFADDR = (addr >> 8) & 0xff;
NFADDR = (addr >> 16) & 0xff; if (large_block)
NFCMMD = NAND_CMD_READSTART; NF_TRANSRnB(); for(i=0; i < page_size; i++) {
*buf++ = NFDATA;
} NAND_DISABLE_CE(); return 0;
} int copy2ddr(unsigned int nand_start, unsigned int ddr_start, unsigned int len)
{
unsigned char *dest = (unsigned char *)ddr_start;
int i; /* ³õʼ»¯nand flash controller */
nand_init(); /* ¶Ánand flash */
/* Read pages */
for (i = 0; i < 4; i++, dest+=2048){
nandll_read_page(dest, i, 2);
} /* Read pages */
for (i = 4; i < ((len+4096)>>13); i++, dest+=8192) {
nandll_read_page(dest, i, 2);
} return 0;
}
//main.c

#define rGPMCON        (*(volatile unsigned *)(0x7F008820))
#define rGPMDAT (*(volatile unsigned *)(0x7F008824))
#define rGPMPUD (*(volatile unsigned *)(0x7F008828)) void msDelay(int time)
{
volatile unsigned int i,j;
for (i=0;i<20000;i++)
for(j=0;j<time;j++);
} void GPIO_Init(void)
{
rGPMCON = 0x11111;
rGPMPUD = 0x00;
rGPMDAT = 0x1F;
} void LedTest(void)
{
volatile unsigned int i;
while(1)
{
for(i=0;i<4;i++)
{
rGPMDAT =~(1<<i);
msDelay(10);
}
}
}
int main()
{
GPIO_Init();
LedTest(); return 0;
}

总结如下:

第一阶段启动代码主要完成此阶段所需硬件的初始化。初始化 c 语言运行环境,即初始化堆栈。进入 c 语言,跳到第二阶段。