色婷婷AⅤ一区二区三区|亚洲精品第一国产综合亚AV|久久精品官方网视频|日本28视频香蕉

          新聞中心

          自己寫bootloader

          作者: 時間:2016-11-21 來源:網(wǎng)絡(luò) 收藏
          啟動匯編文件
          #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)看門狗 //
          ldr r0, =0x53000000
          mov r1, #0
          str r1, [r0]
          // 2、設(shè)置系統(tǒng)時鐘 //
          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的總線模式應(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 // 寫入控制寄存器 //
          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復(fù)制到它的鏈接地址去 //
          ldr sp, =0x34000000 //讓SP指向最高的內(nèi)存,棧是往下增長的
          bl nand_init //即使是nor啟動也要初始化nand flash,因為內(nèi)核是存在nandflash上面的,還 //要去nandflash上面把內(nèi)核讀出來。
          mov r0, #0
          ldr r1, =_start //鏈接地址在鏈接腳本中注明,即程序運(yùn)行時應(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指令是因為該指令會跳到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è)置時序 //
          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)行時應(yīng)該在的地方,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
          {
          // 發(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)行到此時如果是nand啟動,則上電后nand flash的前4K會被復(fù)制到片內(nèi)SARM中運(yùn)行,往地址0寫入數(shù)據(jù)相當(dāng)于往片內(nèi)內(nèi)存0地址寫數(shù)據(jù)可以成功;但是如果是nor啟動,上電后直接在nor的0地址運(yùn)行,程序依然在nor flash中,nor flash可以像內(nèi)存一樣讀,但是無法像內(nèi)存一樣寫,故直接向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函數(shù)設(shè)置PCLK為50MHz
          #define UART_CLK PCLK // UART0的時鐘源設(shè)為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內(nèi)部上拉
          ULCON0 = 0x03; // 8N1(8個數(shù)據(jù)位,無較驗,1個停止位)
          UCON0 = 0x05; // 查詢方式,UART時鐘源為PCLK
          UFCON0 = 0x00; // 不使用FIFO
          UMCON0 = 0x00; // 不使用流控
          UBRDIV0 = UART_BRD; // 波特率為115200
          }
          //
          * 發(fā)送一個字符
          //
          void putc(unsigned char c)
          {
          // 等待,直到發(fā)送緩沖區(qū)中的數(shù)據(jù)已經(jīng)全部發(fā)送出去 //
          while (!(UTRSTAT0 & TXD0READY));
          // 向UTXH0寄存器中寫入數(shù)據(jù),UART即自動將它發(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++) !=