bootloader功能介紹
初始化開發(fā)板上主要硬件(時鐘,,內(nèi)存,,硬盤),,
把操作系統(tǒng)從硬盤拷貝到內(nèi)存,,然后讓cpu跳轉(zhuǎn)到內(nèi)存中執(zhí)行操作系統(tǒng)。
boot階段
1.關(guān)閉影響CPU正常執(zhí)行的外設(shè)
-關(guān)閉看門狗(watch dog) WTCON 0xE2700000
-關(guān)閉中斷 CPSR I和F位設(shè)置為1,,關(guān)閉,,不響應(yīng)任何中斷。
2.初始化時鐘
-倍頻到1Ghz,,為外設(shè)分頻
*串口驅(qū)動
3.初始化內(nèi)存控制器,,DDRAM
-驗證內(nèi)存,往里面寫一個值,,然后再讀出來
4.初始化硬盤,,nand Flash
-nand flash 讀驅(qū)動(從nand往外讀數(shù)據(jù))
loader階段
1.從硬盤指定的地址加載kernel到內(nèi)存指定的地址。
2.跳轉(zhuǎn)到內(nèi)存kernel所在的地址,,執(zhí)行
附加功能:
實現(xiàn)bootloader中shell(命令解釋器)
附加功能:
實現(xiàn)bootloader中shell(命令解釋器)
uboot中支持的命令,,
help
loadb 下載程序, kermit 協(xié)議
go 0X21000000;
例如:在uboot中直接控制蜂鳴器
mm 0xe02000a0 0x1(控制寄存器)
mm 0xe02000a4 0x1(數(shù)據(jù)寄存器)
常用調(diào)試手段:
1.led點燈大法
2.串口調(diào)試,,uart_getchar,uart_putchar,進一步實現(xiàn)stdio.h
時鐘初始化設(shè)置
pll 鎖相環(huán),,
倍頻
串口工作原理
串口工作核心圖
#define ULCON0 *((volatile unsigned int *)0XE2900000)
volatile 關(guān)鍵字,防止編譯器做優(yōu)化,,每次讀取寄存器的值,,都是重新讀取寄存器,。
- //start.s
- AREA start_main,CODE, READONLY
- ENTRY
- IMPORT uart_test
- START
- B uart_test
-
- END
- //uart.c
- #define ULCON0 *((volatile unsigned int *)0XE2900000)
- #define UCON0 *((volatile unsigned int *)0XE2900004)
- #define UTRSTAT0 *((volatile unsigned int *)0XE2900010)
- #define UTXH0 *((volatile unsigned int *)0XE2900020)
- #define URXH0 *((volatile unsigned int *)0XE2900024)
- #define UBRDIV0 *((volatile unsigned int *)0XE2900028)
- #define UDIVSLOT0 *((volatile unsigned int *)0XE290002C)
- #define GPACON0 *((volatile unsigned int *)0XE0200000)
- void uart_init(void)
- {
- //串口管腳設(shè)置成功能態(tài)
- GPACON0 = 0x22;
- //設(shè)置8 N 1
- ULCON0 = 0X3;
- //設(shè)置輪詢工作模式
- UCON0 = 0X5;
- //設(shè)置波特率
- UBRDIV0 = 34;
- UDIVSLOT0 = 0XDDDD;
-
- }
- char uart_getchar(void)
- {
- char ch;
- //如果有數(shù)據(jù)到達,狀態(tài)寄存器第0位置1
- //判斷狀態(tài)位是否為1,,決定讀接收緩沖寄存器,,讀到的值作為函數(shù)的返回值
- while (!(UTRSTAT0 & 0x1))
- ;
- ch = URXH0;
- return ch;
- }
- void uart_putchar(char ch)
- {
- //如果狀態(tài)寄存器第1為置1,表示發(fā)送單元為空,,可以發(fā)送數(shù)據(jù)
- //把ch賦值到發(fā)送緩沖寄存器里,,狀態(tài)寄存器第1為置0, 自動發(fā)送,,當(dāng)發(fā)送完畢
- while (!(UTRSTAT0 & 0X2))
- ;
- UTXH0 = ch;
- }
- void uart_test(void)
- {
- char ch;
-
- uart_init();
- uart_putchar('a');
- uart_putchar('b');
- uart_putchar('c');
- //串口回顯功能
- while (1)
- {
- ch = uart_getchar();
- uart_putchar(ch);
- }
- }
內(nèi)存工作原理
--------------------------------------------------
NandFlash工作原理
內(nèi)存是總線設(shè)備,,nandflash屬于非總線設(shè)備。
沒有地址線,, 只有數(shù)據(jù)線,。
內(nèi)存:總線數(shù)據(jù), nandflash:非總線設(shè)備,。
命令,、地址、數(shù)據(jù)復(fù)用端口,。
忙閑位,。
裸板操作NandFlash的示例代碼:
- #define NFCONF (*(volatile unsigned int *)0xB0E00000)
- #define NFCONT (*(volatile unsigned int *)0xB0E00004)
- #define NFCMMD (*(volatile unsigned int *)0xB0E00008)
- #define NFADDR (*(volatile unsigned int *)0xB0E0000C)
- #define NFDATA (*(volatile unsigned int *)0xB0E00010)
- #define NFSTAT (*(volatile unsigned int *)0xB0E00028)
-
- #define MP0_3CON (*(volatile unsigned int *)0xE0200320)
-
- #define PAGE_SIZE 2048
-
- void nand_init(void)
- {
- //[15:12]TACLS = 1->(1) 1/133Mhz = 7.5ns
- //[11:8] TWRPH0 = 1->(1+7) 7.5ns*2 = 15ns
- //[7:4] TWRPH1 = 1->(1+1) 7.5ms *2 = 15ns
- NFCONF |= 1<<2 | 1<< 8 | 1<< 4;
- //AdrCycle [1]1=5 address cycle
- NFCONF |= 1<<1;
- //MODE [0] NAND Flash controller operating node
- // 0=disable nand flash controller
- // *1 = enable nand flash controller
- NFCONT |= 1<<0;
- //Reg_nCE0 [1] nandflash memort nRCS[0] signal control
- // *0 = force nRCS[0] to low (enable chip select)
- // 1 = force nRCS[0] to high(disable chip select)
- NFCONT &= ~(1<<1);
- //GPIO functional mux setting
- // 0010 = NF_xxx
- MP0_3CON = 0X22222222;
- return ;
- }
-
- void nand_read_id(char id[])
- {
- int i;
- //write read_id cmd 90th
- NFCMMD = 0X90;
- //write address 00h
- NFADDR = 0x00;
- for(i=0; i<5; i++)
- {
- id[i] = NFDATA;
- }
- return ;
- }
-
- void nand_read_page(int addr, char buf[])
- {
- int i;
- char tmp;
- //write read_page cmd 00h
- NFCMMD = 0X00;
- //write 5 address
- NFADDR = (addr >> 0) & 0xFF;
- NFADDR = (addr >> 8) & 0x7;
- NFADDR = (addr >> 11) & 0xFF;
- NFADDR = (addr >> 19) & 0xFF;
- NFADDR = (addr >> 27) & 0x1;
- //write read_page cmd 30h
- NFCMMD = 0X30;
- //wait for R/nB -->ready
- while( (NFSTAT &(1<<0))==0 )
- ;
- //read data 2048 bytes
- for(i=0; i<PAGE_SIZE; i++)
- {
- buf[i] = NFDATA;
- }
- for (i=0; i<64; i++)
- {
- tmp = NFDATA;
- }
- return ;
-
- }
-
- void nand_read(int nand_addr, char *sdram_addr, int size)
- {
- int pages = (size -1)/PAGE_SIZE + 1;
- int i;
-
- for (i=0; i<pages; i++)
- {
- nand_read_page(nand_addr + i*PAGE_SIZE, sdram_addr + i*PAGE_SIZE);
- }
-
- }
uboot中操作NandFlash的示例代碼:
//s3c2440_nand.c
- #include <common.h>
-
- #if 0
- #define DEBUGN printf
- #else
- #define DEBUGN(x,args ...){}
- #endif
- #include <nand.h>
- #include <asm/arch/s3c24x0_cpu.h>
- #include <asm/arch/s3c2410.h>
- #include <asm/io.h>
-
- #define __REGb(x) (*(volatile unsigned char *)(x))
- #define __REGi(x) (*(volatile unsigned int *)(x))
-
-
- #define NF_BASE 0x4e000000
-
- #define NFCONF __REGi(NF_BASE + 0x0)
- #define NFCONT __REGi(NF_BASE + 0x4)
- #define NFCMD __REGb(NF_BASE + 0x8)
- #define NFADDR __REGb(NF_BASE + 0xc)
- #define NFDATA __REGb(NF_BASE + 0x10)
- #define NFMECCD0 __REGi(NF_BASE + 0x14)
- #define NFMECCD1 __REGi(NF_BASE + 0x18)
- #define NFSECCD __REGi(NF_BASE + 0x1C)
- #define NFSTAT __REGb(NF_BASE + 0x20)
- #define NFSTAT0 __REGi(NF_BASE + 0x24)
- #define NFSTAT1 __REGi(NF_BASE + 0x28)
- #define NFMECC0 __REGi(NF_BASE + 0x2C)
- #define NFMECC1 __REGi(NF_BASE + 0x30)
- #define NFSECC __REGi(NF_BASE + 0x34)
- #define NFSBLK __REGi(NF_BASE + 0x38)
- #define NFEBLK __REGi(NF_BASE + 0x3C)
-
- #define S3C2440_NFCONT_nCE (1<<1)
- #define S3C2440_ADDR_NALE 0x08
- #define S3C2440_ADDR_NCLE 0x0c
-
-
-
- #ifdef CONFIG_NAND_SPL
-
- /* in the early stage of NAND flash booting, printf() is not available */
- #define printf(fmt, args...)
-
- static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
- {
- int i;
- struct nand_chip *this = mtd->priv;
-
- for (i = 0; i < len; i++)
- buf[i] = readb(this->IO_ADDR_R);
- }
- #endif
-
- ulong IO_ADDR_W = NF_BASE;
- static void s3c2440_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
- {
- struct nand_chip *chip = mtd->priv;
- DEBUGN("hwcontrol(): 0x%02x 0x%02x\n", cmd, ctrl);
- if (ctrl & NAND_CTRL_CHANGE) {
- IO_ADDR_W = NF_BASE;
- if (!(ctrl & NAND_CLE))
- IO_ADDR_W |= S3C2440_ADDR_NCLE;
- if (!(ctrl & NAND_ALE))
- IO_ADDR_W |= S3C2440_ADDR_NALE;
-
- if (ctrl & NAND_NCE)
- NFCONT &= ~ S3C2440_NFCONT_nCE;
- else
- NFCONT |= S3C2440_NFCONT_nCE;
- }
- if (cmd != NAND_CMD_NONE)
- writeb(cmd, (void *)IO_ADDR_W);
- }
-
-
-
- static int s3c2440_dev_ready(struct mtd_info *mtd)
- {
- DEBUGN("dev_ready\n");
- return(NFSTAT & 0x01);
- }
-
- #ifdef CONFIG_S3C2410_NAND_HWECC
- void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)
- {
- struct s3c2410_nand *nand = s3c2410_get_base_nand();
- debugX(1, "s3c2410_nand_enable_hwecc(%p, %d)\n", mtd, mode);
- writel(readl(&nand->NFCONF) | S3C2410_NFCONF_INITECC, &nand->NFCONF);
- }
-
- static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
- u_char *ecc_code)
- {
- struct s3c2410_nand *nand = s3c2410_get_base_nand();
- ecc_code[0] = readb(&nand->NFECC);
- ecc_code[1] = readb(&nand->NFECC + 1);
- ecc_code[2] = readb(&nand->NFECC + 2);
- debugX(1, "s3c2410_nand_calculate_hwecc(%p,): 0x%02x 0x%02x 0x%02x\n",
- mtd , ecc_code[0], ecc_code[1], ecc_code[2]);
-
- return 0;
- }
-
- static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
- u_char *read_ecc, u_char *calc_ecc)
- {
- if (read_ecc[0] == calc_ecc[0] &&
- read_ecc[1] == calc_ecc[1] &&
- read_ecc[2] == calc_ecc[2])
- return 0;
-
- printf("s3c2410_nand_correct_data: not implemented\n");
- return -1;
- }
- #endif
-
- int board_nand_init(struct nand_chip *nand)
- {
- u_int32_t cfg;
- u_int8_t tacls, twrph0, twrph1;
- struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power();
-
- DEBUGN("board_nand_init()\n");
-
- writel(readl(&clk_power->CLKCON) | (1 << 4), &clk_power->CLKCON);
-
- /* initialize hardware */
- twrph0 = 4;
- twrph1 =2;
- tacls = 0;
-
- cfg = ((tacls<<12)|(twrph0<<8)|(twrph1<<4));
- NFCONF=cfg;
- cfg = ((1<<6)|(1<<4)|(0<<1)|(1<<0));
- NFCONT=cfg;
- /* initialize nand_chip data structure */
- nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)0x4e000010;
-
-
- /* read_buf and write_buf are default */
- /* read_byte and write_byte are default */
-
- /* hwcontrol always must be implemented */
- nand->cmd_ctrl = s3c2440_hwcontrol;
- nand->dev_ready = s3c2440_dev_ready;
- nand->ecc.mode = NAND_ECC_SOFT;
-
- DEBUGN("end of nand_init\n");
-
- return 0;
- }
|