基於JZ2440開發板編寫bootloader總結(一)


凡走過必留下痕跡,學點什么都會有用的。

本系列博文總結了自己在學習嵌入式Linux編程過程中的收獲,若有錯誤,懇請指正,謝謝!

——參考教材韋東山系列教材


 

bootloader 是一個用於啟動linux內核的C程序,為了達到最終啟動內核的目的需要完成以下幾個步驟:

step1:硬件相關初始化,為啟動內核准備硬件平台;

step2:將內核從NAND FLASH讀取到SDRAM;

step3:設置需要傳遞給內核的啟動參數;

step4:跳轉到SDRAM,運行內核;

下面將詳細講述各個步驟細節:


 第一步:硬件相關初始化,為啟動內核准備硬件平台

基本流程見下圖1

(1)禁看門狗

1     ldr r0, =0x53000000  //WTCON : WATCHDOG TIMER CONTROL REGISTER  Address = 0x53000000
2     mov r1, #0           //bit 0 = 0 : Disable the reset function of the watchdog timer.
3     str r1, [r0]         //將r1中的值存到r0所指定的地址中

(2)設置系統時鍾

         配置時鍾之前先參考下芯片手冊  S3C2440A_UserManual_Rev13,需要操作兩個寄存器:

  1. MPLLCON 設置MPLL鎖相環倍頻因子;

          MPLL計算公式 : Mpll = (2 * m * Fin) / (p * 2S)   ;   m = (MDIV + 8), p = (PDIV + 2), s = SDIV ;Fin取決於外部晶振頻率,JZ2440開發板的 [OM2:OM3] 設置為 [0:0] ,因此

          main clock和USB clock 依賴外部12MHZ 晶振。

        2. CLKDIVN 設置 HCLK , FCLK,PCLK比例關系;

         FCLK, HCLK, and PCLK
         FCLK is used by ARM920T.
         HCLK is used for AHB bus, which is used by the ARM920T, the memory controller, the interrupt controller, the LCD controller, the DMA and USB host block.
         PCLK is used for APB bus, which is used by the peripherals such as WDT, IIS, I2C, PWM timer, MMC interface,ADC, UART, GPIO, RTC and SPI.

    #define S3C2440_MPLL_200MHZ     ((0x5c<<12)|(0x01<<4)|(0x02))

/*
2. 設置時鍾 */ //先設置各個時鍾的比例對CLKDIVN賦值,之后設置系統時鍾對MPLLCON賦值 ldr r0, =0x4c000014 //CLKDIVN : CLOCK DIVIDER CONTROL REGISTER  Address = 0x4c000014 mov r1, #0x03 //FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1 FCLK=200MHZ HCLK=100MHZ PCLK=50MHZ str r1, [r0] //將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 /* 寫入控制寄存器 */ /* MPLLCON = S3C2440_MPLL_200MHZ */ ldr r0, =0x4c000004 //MPLLCON Address = 0x4c000004 ldr r1, =S3C2440_MPLL_200MHZ // S3C2440_MPLL_200MHZ值比較復雜,使用ldr偽匯編 str r1, [r0]

(3)初始化SDRAM

       在使用SDRAM之前,有必要了解下什么是SDRAM。請參閱《高手進階_終極內存技術指南——完整》,這篇文章解釋了SDRAM的基本原理。系統上電需要對SDRAM進行初始化,完成對模式寄存器(MR,Mode Register)的配置。主要設置操作模式、CAS潛伏期時間、突發傳輸方式和突發長度,完成配置后可以根據地址讀寫SDRAM。本文操作的SDRAM型號是K4S561632N,S3C2440提供標准的總線接口(BANK6),用於操作SDRAM,因此建立了硬件連接之后,操作S3C2440相應的控制寄存器即可完成對SDRAM的配置和讀寫,具體操作參閱《[嵌入式Linux應用開發完全手冊]》第6章 存儲控制器。

1 /* 3. 初始化SDRAM */
2     ldr r0, =MEM_CTL_BASE //SDRAM控制器寄存器首地址,總計需要對13個寄存器配置完成SDRAM的初始化工作
3     adr r1, sdram_config  //讀取sdram_config的當前地址到r1,此地址取決於當前PC值,是相對跳轉
4     add r3, r0, #(13*4)   //r3=r0+52  r3值代表了全部控制寄存器所占地址空間大小,總計52字節
5 1:
6     ldr r2, [r1], #4      //從r1所指的地方加載指存入r2,之后r1=r1+4,地址加4字節,32位
7     str r2, [r0], #4      //將r2的值存入r0所指的地方,之后r0=r0+4
8     cmp r0, r3
9     bne 1b                //b表示back
 1 sdram_config:
 2     .long 0x22011110     //BWSCON
 3     .long 0x00000700     //BANKCON0
 4     .long 0x00000700     //BANKCON1
 5     .long 0x00000700     //BANKCON2
 6     .long 0x00000700     //BANKCON3  
 7     .long 0x00000700     //BANKCON4
 8     .long 0x00000700     //BANKCON5
 9     .long 0x00018005     //BANKCON6
10     .long 0x00018005     //BANKCON7
11     .long 0x008C04F4     //REFRESH
12     .long 0x000000B1     //BANKSIZE
13     .long 0x00000030     //MRSRB6
14     .long 0x00000030     //MRSRB7

  下圖是SDRAM的原理圖,由兩片32M的SDRAM級聯成64M,訪問一次傳遞4字節數據。

 

SDRAM 原理圖

SDRAM由BANK6控制,bank6地址空間為0x30000000~0x38000000,共計128MB。上圖所示SDRAM存儲空間為64M,因此SDRAM地址空間為0X30000000~0X33FFFFFF。

(4)重定位代碼

將啟動代碼從片內SRAM復制到SDRAM中,使用C代碼編寫。調用C代碼需要設置棧,至於為什么要設置棧請參閱http://www.cnblogs.com/xmphoenix/archive/2012/04/28/2475399.html。這里涉及到三個參數:從哪去讀取啟動代碼,將代碼復制到哪去,啟動代碼多大。

  • 從哪去讀取啟動代碼(源地址)

啟動代碼燒寫在NAND,待系統上電后,片內SRAM會加載NAND的起始4K內容。因此啟動代碼起始地址為:0x00000000

  • 讀到哪去(目的地址)

在鏈接文件中指定了啟動代碼在SDRAM的中存放地址:0x33f80000,啟動代碼存到SDRAM頂端512k的地址空間中。

  • 讀多少(大小)

啟動代碼大小 = 代碼段+只讀數據段+數據段。BSS段不包含在啟動代碼中,bss段存放沒有初始化的全局變量,或者初始化為0的全局變量,程序運行前將bss段清零。

 1 /* 4. 重定位 : 把bootloader本身的代碼從flash復制到它的鏈接地址去 */
 2     ldr sp, =0x34000000    //設置棧,copy函數使用C語言寫,調用C代碼之前需要設置棧
 3     bl nand_init
 4     
 5     mov r0, #0              //傳遞參數給 copy_code_to_sdram, 對於NOR 啟動
 6     ldr r1, =_start         //鏈接地址即為代碼存儲區的首地址 _start = 0x33f80000;
 7     ldr r2, =__bss_start    //代碼段不包括bss段
 8     sub r2, r2, r1          //除去BSS段外的所有代碼的空間大小
 9 
10     bl copy_code_to_sdram   //參數依次為r0,r1,r2
11     bl clear_bss

完成以上4個步驟后,CPU會轉到SDRAM中取指令執行。

 

 

 

 

 

       

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM