新聞中心

自己寫(xiě)bootloader

作者: 時(shí)間:2016-11-21 來(lái)源:網(wǎng)絡(luò) 收藏
啟動(dòng)匯編文件
#define S3C2440_MPLL_200MHZ ((0x5c<<12)|(0x01<<4)|(0x02))
#define S3C2440_MPLL_400MHZ ((0x5c<<12)|(0x01<<4)|(0x01))
#define MEM_CTL_BASE 0x48000000
.text
.global _start
_start:
// 1、關(guān)看門(mén)狗 //
ldr r0, =0x53000000
mov r1, #0
str r1, [r0]
// 2、設(shè)置系統(tǒng)時(shí)鐘 //
ldr r0, =0x4c000014
//mov r1, #0x03 // FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1
mov r1, #0x05; // FCLK:HCLK:PCLK=1:4:8
str r1, [r0]
// 如果HDIVN非0,CPU的總線(xiàn)模式應(yīng)該從“fast bus mode”變?yōu)?ldquo;asynchronous bus mode” //
mrc p15, 0, r1, c1, c0, 0 // 讀出控制寄存器 //
orr r1, r1, #0xc0000000 // 設(shè)置為“asynchronous bus mode” //
mcr p15, 0, r1, c1, c0, 0 // 寫(xiě)入控制寄存器 //
ldr r0, =0x4c000004
ldr r1, =S3C2440_MPLL_400MHZ
str r1, [r0]
// 啟動(dòng)ICACHE //
mrc p15, 0, r0, c1, c0, 0 @ read control reg
orr r0, r0, #(1<<12)
mcr p15, 0, r0, c1, c0, 0 @ write it back
// 3、初始化SDARM //
ldr r0, =MEM_CTL_BASE
adr r1, sdarm_config
add r3, r0,#(13*4)
1:
ldr r2, [r1],#4
str r2, [r0],#4
cmp r0, r3
bne 1b
// 4. 重定位 : 把bootloader本身的代碼從flash復(fù)制到它的鏈接地址去 //
ldr sp, =0x34000000 //讓SP指向最高的內(nèi)存,棧是往下增長(zhǎng)的
bl nand_init //即使是nor啟動(dòng)也要初始化nand flash,因?yàn)閮?nèi)核是存在nandflash上面的,還 //要去nandflash上面把內(nèi)核讀出來(lái)。
mov r0, #0
ldr r1, =_start //鏈接地址在鏈接腳本中注明,即程序運(yùn)行時(shí)應(yīng)該在的地方,0x33f80000
ldr r2, =__bss_start
sub r2, r2, r1
bl copy_code_to_sdram
bl clear_bss
// 5、執(zhí)行main函數(shù) //
ldr lr, =halt
ldr pc, =main //跳到main函數(shù)中運(yùn)行,不用bl指令是因?yàn)樵撝噶顣?huì)跳到sdarm中執(zhí)行
halt:
halt
sdarm_config:
.long 0x22011110 //BWSCON
.long 0x00000700 //BANKCON0
.long 0x00000700 //BANKCON1
.long 0x00000700 //BANKCON2
.long 0x00000700 //BANKCON3
.long 0x00000700 //BANKCON4
.long 0x00000700 //BANKCON5
.long 0x00018005 //BANKCON6
.long 0x00018005 //BANKCON7
.long 00x008C04F4 //REFRESH
.long 00x000000B1 //BANKSIZE
.long 00x00000030 //MRSRB6
.long 00x00000030 //MRSRB7
==============================================================
nand flash初始化文件:
// NAND FLASH控制器 //
#define NFCONF (*((volatile unsigned long *)0x4E000000))
#define NFCONT (*((volatile unsigned long *)0x4E000004))
#define NFCMMD (*((volatile unsigned char *)0x4E000008))
#define NFADDR (*((volatile unsigned char *)0x4E00000C))
#define NFDATA (*((volatile unsigned char *)0x4E000010))
#define NFSTAT (*((volatile unsigned char *)0x4E000020))
void nand_init(void)
{
#define TACLS 0
#define TWRPH0 3
#define TWRPH1 0
// 設(shè)置時(shí)序 //
NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
// 使能NAND Flash控制器, 初始化ECC, 禁止片選 //
NFCONT = (1<<4)|(1<<1)|(1<<0);
}
void nand_select(void)
{
NFCONT &= ~(1<<1);
}
void del_select(void)
{
NFCONT |= (1<<1);
}
void nand_cmd(unsigned char cmd)
{
volatile int i=0;
NFCMMD = cmd;
for(i=0; i<10; i++);
}
void nand_wait_ready(void)
{
while (!(NFSTAT & 1));
}
unsigned char nand_data(void)
{
return NFDATA;
}
void nand_addr(unsigned int addr)
{
unsigned int col = addr % 2048;
unsigned int page = addr / 2048;
unsigned int i=0;
NFADDR = col & 0xff;
for(i=0; i<10; i++);
NFADDR = (col>>8) & 0xff;
for(i=0; i<10; i++);
NFADDR = page & 0xff;
for(i=0; i<10; i++);
NFADDR = (page>>8) & 0xff;
for(i=0; i<10; i++);
NFADDR = (page>>16) & 0xff;
for(i=0; i<10; i++);
}
//addr--->0,下面的nand_read函數(shù)從nand flash的0地址讀數(shù)據(jù)放在buf地方
//buf---->_start 即鏈接地址在鏈接腳本中注明,程序運(yùn)行時(shí)應(yīng)該在的地方,0x33f80000,把程序拷貝過(guò)去
//len----->__bss_start-_start
void nand_read(unsigned int addr, unsigned char *buf, unsigned int len)
{
int col = addr 48;
int i = 0;
// 選中片選 //
nand_select();
while(i
{
// 發(fā)讀命令 //
nand_cmd(0x00);
// 發(fā)地址 //
nand_addr(addr);
// 發(fā)讀命令 //
nand_cmd(0x30);
// 判斷狀態(tài) //
nand_wait_ready();
// 讀數(shù)據(jù) //
for(; (col<2048) && (i
{
buf[i] = nand_data();
i++;
addr++;
}
col = 0;
}
// 取消片選 //
del_select();
}
//
為什么該函數(shù)能夠判斷成功,因?yàn)槌绦蜻\(yùn)行到此時(shí)如果是nand啟動(dòng),則上電后nand flash的前4K會(huì)被復(fù)制到片內(nèi)SARM中運(yùn)行,往地址0寫(xiě)入數(shù)據(jù)相當(dāng)于往片內(nèi)內(nèi)存0地址寫(xiě)數(shù)據(jù)可以成功;但是如果是nor啟動(dòng),上電后直接在nor的0地址運(yùn)行,程序依然在nor flash中,nor flash可以像內(nèi)存一樣讀,但是無(wú)法像內(nèi)存一樣寫(xiě),故直接向0地址賦值會(huì)失敗。
//
int isBootFromNorFlash(void)
{
volatile int *p =(volatile int *)0;
int val=0;
val = *p;
*p = 0x1234ab;
if(*p == 0x1234ab)
{
//寫(xiě)成功,表示是nand flash啟動(dòng)
*p=val;
return 0;
}
else
{
//寫(xiě)失敗,說(shuō)明是nor flash啟動(dòng)
return 1;
}
}
void copy_code_to_sdram(unsigned char *src, unsigned char *dest, unsigned int len)
{
unsigned int i=0;
if(isBootFromNorFlash())//nor啟動(dòng)
{
while(i
{
dest[i] = src[i];
i++;
}
}
else //nand啟動(dòng)
{
nand_read(src,dest,len);
}
}
void clear_bss(void)
{
extern int __bss_start, __bss_end;
int *p = &__bss_start;
for(; p < &__bss_end; p++)
*p = 0;
}
#define PCLK 50000000 // init.c中的clock_init函數(shù)設(shè)置PCLK為50MHz
#define UART_CLK PCLK // UART0的時(shí)鐘源設(shè)為PCLK
#define UART_BAUD_RATE 115200 // 波特率
#define UART_BRD ((UART_CLK / (UART_BAUD_RATE * 16)) - 1)
//
* 初始化UART0
* 115200,8N1,無(wú)流控
//
void uart0_init(void)
{
GPHCON |= 0xa0; // GPH2,GPH3用作TXD0,RXD0
GPHUP = 0x0c; // GPH2,GPH3內(nèi)部上拉
ULCON0 = 0x03; // 8N1(8個(gè)數(shù)據(jù)位,無(wú)較驗(yàn),1個(gè)停止位)
UCON0 = 0x05; // 查詢(xún)方式,UART時(shí)鐘源為PCLK
UFCON0 = 0x00; // 不使用FIFO
UMCON0 = 0x00; // 不使用流控
UBRDIV0 = UART_BRD; // 波特率為115200
}
//
* 發(fā)送一個(gè)字符
//
void putc(unsigned char c)
{
// 等待,直到發(fā)送緩沖區(qū)中的數(shù)據(jù)已經(jīng)全部發(fā)送出去 //
while (!(UTRSTAT0 & TXD0READY));
// 向UTXH0寄存器中寫(xiě)入數(shù)據(jù),UART即自動(dòng)將它發(fā)送出去 //
UTXH0 = c;
}
void puts(char *str)
{
int i = 0;
while (str[i])
{
putc(str[i]);
i++;
}
}
void puthex(unsigned int val)
{
// 0x1234abcd //
int i;
int j;
puts("0x");
for (i = 0; i < 8; i++)
{
j = (val >> ((7-i)*4)) & 0xf;
if ((j >= 0) && (j <= 9))
putc(0 + j);
else
putc(A + j - 0xa);
}
}
=================================================================
boot.c
#include "setup.h"
extern void uart0_init(void);
extern void nand_read(unsigned int addr, unsigned char *buf, unsigned int len);
extern void puts(char *str);
extern void puthex(unsigned int val);
static struct tag *params;
void setup_start_tag(void)
{
params = (struct tag *)0x30000100;
params->hdr.tag = ATAG_CORE;
params->hdr.size = tag_size (tag_core);
params->u.core.flags = 0;
params->u.core.pagesize = 0;
params->u.core.rootdev = 0;
params = tag_next (params);
}
void setup_memory_tags(void)
{
params->hdr.tag = ATAG_MEM;
params->hdr.size = tag_size (tag_mem32);
params->u.mem.start = 0x30000000;
params->u.mem.size = 64*1024*1024;
params = tag_next (params);
}
int strlen(char *str)
{
int i = 0;
while (str[i])
{
i++;
}
return i;
}
void strcpy(char *dest, char *src)
{
while ((*dest++ = *src++) !=