新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > 自己寫bootloader

        自己寫bootloader

        作者: 時間:2016-11-21 來源:網絡 收藏
        啟動匯編文件
        #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、關看門狗 //
        ldr r0, =0x53000000
        mov r1, #0
        str r1, [r0]
        // 2、設置系統時鐘 //
        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的總線模式應該從“fast bus mode”變為“asynchronous bus mode” //
        mrc p15, 0, r1, c1, c0, 0 // 讀出控制寄存器 //
        orr r1, r1, #0xc0000000 // 設置為“asynchronous bus mode” //
        mcr p15, 0, r1, c1, c0, 0 // 寫入控制寄存器 //
        ldr r0, =0x4c000004
        ldr r1, =S3C2440_MPLL_400MHZ
        str r1, [r0]
        // 啟動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復制到它的鏈接地址去 //
        ldr sp, =0x34000000 //讓SP指向最高的內存,棧是往下增長的
        bl nand_init //即使是nor啟動也要初始化nand flash,因為內核是存在nandflash上面的,還 //要去nandflash上面把內核讀出來。
        mov r0, #0
        ldr r1, =_start //鏈接地址在鏈接腳本中注明,即程序運行時應該在的地方,0x33f80000
        ldr r2, =__bss_start
        sub r2, r2, r1
        bl copy_code_to_sdram
        bl clear_bss
        // 5、執行main函數 //
        ldr lr, =halt
        ldr pc, =main //跳到main函數中運行,不用bl指令是因為該指令會跳到sdarm中執行
        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
        // 設置時序 //
        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函數從nand flash的0地址讀數據放在buf地方
        //buf---->_start 即鏈接地址在鏈接腳本中注明,程序運行時應該在的地方,0x33f80000,把程序拷貝過去
        //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
        {
        // 發讀命令 //
        nand_cmd(0x00);
        // 發地址 //
        nand_addr(addr);
        // 發讀命令 //
        nand_cmd(0x30);
        // 判斷狀態 //
        nand_wait_ready();
        // 讀數據 //
        for(; (col<2048) && (i
        {
        buf[i] = nand_data();
        i++;
        addr++;
        }
        col = 0;
        }
        // 取消片選 //
        del_select();
        }
        //
        為什么該函數能夠判斷成功,因為程序運行到此時如果是nand啟動,則上電后nand flash的前4K會被復制到片內SARM中運行,往地址0寫入數據相當于往片內內存0地址寫數據可以成功;但是如果是nor啟動,上電后直接在nor的0地址運行,程序依然在nor flash中,nor flash可以像內存一樣讀,但是無法像內存一樣寫,故直接向0地址賦值會失敗。
        //
        int isBootFromNorFlash(void)
        {
        volatile int *p =(volatile int *)0;
        int val=0;
        val = *p;
        *p = 0x1234ab;
        if(*p == 0x1234ab)
        {
        //寫成功,表示是nand flash啟動
        *p=val;
        return 0;
        }
        else
        {
        //寫失敗,說明是nor flash啟動
        return 1;
        }
        }
        void copy_code_to_sdram(unsigned char *src, unsigned char *dest, unsigned int len)
        {
        unsigned int i=0;
        if(isBootFromNorFlash())//nor啟動
        {
        while(i
        {
        dest[i] = src[i];
        i++;
        }
        }
        else //nand啟動
        {
        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函數設置PCLK為50MHz
        #define UART_CLK PCLK // UART0的時鐘源設為PCLK
        #define UART_BAUD_RATE 115200 // 波特率
        #define UART_BRD ((UART_CLK / (UART_BAUD_RATE * 16)) - 1)
        //
        * 初始化UART0
        * 115200,8N1,無流控
        //
        void uart0_init(void)
        {
        GPHCON |= 0xa0; // GPH2,GPH3用作TXD0,RXD0
        GPHUP = 0x0c; // GPH2,GPH3內部上拉
        ULCON0 = 0x03; // 8N1(8個數據位,無較驗,1個停止位)
        UCON0 = 0x05; // 查詢方式,UART時鐘源為PCLK
        UFCON0 = 0x00; // 不使用FIFO
        UMCON0 = 0x00; // 不使用流控
        UBRDIV0 = UART_BRD; // 波特率為115200
        }
        //
        * 發送一個字符
        //
        void putc(unsigned char c)
        {
        // 等待,直到發送緩沖區中的數據已經全部發送出去 //
        while (!(UTRSTAT0 & TXD0READY));
        // 向UTXH0寄存器中寫入數據,UART即自動將它發送出去 //
        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++) != 主站蜘蛛池模板: 新乡市| 锡林浩特市| 上虞市| 隆安县| 沙坪坝区| 本溪市| 阜新| 分宜县| 日土县| 高碑店市| 澄江县| 车险| 民和| 乌兰察布市| 涡阳县| 枞阳县| 惠州市| 巴东县| 禹城市| 温州市| 丰城市| 锦州市| 娱乐| 洛南县| 阳朔县| 依安县| 静安区| 天祝| 宿松县| 天全县| 彰武县| 嘉禾县| 清水县| 漳州市| 汕头市| 巴塘县| 安岳县| 略阳县| 松原市| 寻乌县| 徐州市|