天天看點

u-boot-1.3.4 移植到S3C2440

<b>一.預備知識:</b>

<b>1.</b><b>       </b> <b>首先,</b> <b>u-boot1.3.4</b> <b>還沒有支援</b> <b>s3c2440</b> <b>,移植仍是用</b> <b>2410</b> <b>的檔案稍作修改而成的。</b>

2.       <b>2440</b> <b>和</b> <b>2410</b> <b>的差別:</b>

2440和 2410的差別主要是 2440的主頻更高,增加了攝像頭接口和 ac‘97音頻接口;寄存器方面,除了新增模 塊的寄存器外,移植所要注意的是 nand flash控制器的寄存器有較大的變化、晶片的時鐘頻率控制寄存器(晶片 pll的寄存器)有一定的變化。其他寄存器基本是相容的。

<b>3.  </b> <b>你開發闆的</b> <b>boot</b> <b>方式是什麼,開發闆上電以後是怎麼執行的。</b>

一般來說三星的開發闆有三種啟動方式: nand、 nor、 ram。

具體用那一種方式來啟動決定于 cpu的 0m[0:1]這兩個引腳,具體請參考 s3c2440的 datasheet

nand:對于 2440來說, cpu是不給 nand-flash配置設定位址空間的, nand-flash隻相當于 cpu的一個外設, s3c2440做了一個從 nand-flash啟動的機制。開發闆一上電, cpu就自動複制

      nand-flash裡面的前 4k-bytes内容到 s3c2440内部內建的 sdram,然後把 4k内容所在          的 ram映射到 s3c2440的 0位址,從 0位址開始執行。這 4k的内容主要負責下面這些工          作:初始化中斷矢量、設定 cpu的工作模式為 svc32模式、屏蔽看門狗、屏蔽中斷、             初始化時鐘、把整個 u-boot重定向到外部 sdram、跳到主要的 c函數入口。

nor:  早期的時候利用 nor-flash啟動的方式比較多,就是把 u-boot燒寫到 nor-flash裡面,        直接把 nor-flash映射到 s3c2440的 0位址,上電從 0位址開始執行。

ram:  直接把 u-boot放到外部 sdram上跑,這一般 debug時候用到。

<b>4.  u-boot</b> <b>程式的入口位址問題</b>

    要了解程式的入口位址,自然想到的是連接配接檔案,首先看看開發闆相對于某個開發闆的連接配接檔案 "/board/你的開發闆 /u-boot.lds",看一個 2410的例子:

entry(_start)

sections

{

       . = 0x00000000;

       . = align(4);

       .text      :

       {

         cpu/arm920t/start.o (.text)

         *(.text)

       }

       .rodata : { *(.rodata) }

       .data : { *(.data) }

       .got : { *(.got) }

       __u_boot_cmd_start = .;

       .u_boot_cmd : { *(.u_boot_cmd) }

       __u_boot_cmd_end = .;

       __bss_start = .;

       .bss : { *(.bss) }

       _end = .;

}

(1) 從 entry(_start)可以看出 u-boot的入口函數是 _start,這個沒錯

(2) 從 . = 0x00000000也許可以看出 _start的位址是 0x00000000,事實并不是這樣的,這裡的 0x00000000沒效,在連接配接的時候最終會被 tetx_base所代替的,具體請參考 u-boot根目錄下的 config.mk.

(3) 網上很多說法是 _start=text_base,我想這種說法也是正确的,但沒有說具體原因。

本人的了解是這樣的, text_base表示 text段的起始位址,而從

.text      :

  cpu/arm920t/start.o (.text)

  *(.text)

看,放在 text段的第一個檔案就是 start.c編譯後的内容,而 start.c中的第一個函數就是

_start,是以 _start應該是放在 text段的起始位置,是以說 _start=text_base也不為過。

<b>5.  </b> <b>一直不明白的</b> <b>u-boot</b> <b>是怎樣從</b> <b>4ksteppingstone</b> <b>跳到</b> <b>ram</b> <b>中執行的,現在終于明白了。關鍵在于:</b>

              ldr   pc, _start_armboot

_start_armboot:    .word start_armboot

這兩條語句, ldr       pc, _start_armboot指令把 _start_armboot這個标簽的地方存放的内容 (也即是 start_armboot)移到 pc寄存器裡面, start_armboot是一個函數位址,在編譯的時候給配置設定了一個絕對位址,是以上面語句實際上是完成了一個絕對位址的跳轉。而我一直不明白的為什麼在 start.s裡面有很多 bl,b跳轉語句都沒有跳出 4ksteppingstone,原因是他們都是相對于 pc的便宜的跳轉,而不是絕對位址的跳轉。還有要補充一下 ldr,mov,ldr僞指令的差別。

ldr      r0,0x12345678   //把位址 0x12345678存放的内容放到 r0裡面

mov    r0,#x                   //把立即數 x放到 r0裡面, x必須是一個 8 bits的數移到偶數次得到的數。

ldr      r0,=0x12345678        //把立即數 0x12345678放到 r0裡面

<b>6.  </b> <b>在移植</b> <b>u-boot-1.3.3</b> <b>以上版本的時候要注意:</b>

    在u-boot1.3.3及以上版本makefile有一定的變化,使得對于24x0處理器從nand啟動的遇到問題。也就是網上有人說的:無法運作過 lowlevel_init。其實這個問題是由于編譯器将我們自己添加的用于nandboot的子函數nand_read_ll放到了4k之後造成的(到 這不了解的話,請仔細看看24x0處理器nandboot原理)。我是在運作失敗後,利用mini2440的4個led調試發現u-boot根本沒有完成 自我拷貝,然後看了uboot根目錄下的system.map檔案就可知道原因。

解決辦法其實很簡單:

将__libs := $(subst $(obj),,$(libs)) $(subst $(obj),,$(libboard))

改為__libs := $(subst $(obj),,$(libboard)) $(subst $(obj),,$(libs))

<b>7.   </b> <b>然後說一下跳轉指令。</b> <b>arm</b> <b>有兩種跳轉方式。</b>

( 1)mov p c &lt;跳轉位址〉

 這種向程式計數器 pc直接寫跳轉位址,能在 4gb連續空間内任意跳轉。

( 2)通過 b bl blx bx可以完成在目前指令向前或者向後 32mb的位址空間的跳轉(為什麼是 32mb呢?寄存器是 32位的,此時的值是 24位有符号數,是以 32mb)。

b是最簡單的跳轉指令。要注意的是,跳轉指令的實際值不是絕對位址,而是相對位址——是相對目前 pc值的一個偏移量,它的值由彙編器計算得出。

bl非常常用。它在跳轉之前會在寄存器 lr(r14)中儲存 pc的目前内容。 bl的經典用法如下:

       bl next  ; 跳轉到next

       ……

    next

       mov pc, lr   ; 從子程式傳回。

<b>二.開始上機移植:</b> <b>(</b> <b>紅色字型為添加的内容,藍色字型為修改的内容,下同</b> <b>)</b>

給自己的開發闆取名為 qljt2440。

1.       随便找個目錄解壓 u-boot,

$tar –xjvf u-boot-1.3.4.tar.gz2

2.       進入 u-boot目錄修改 makefile (你要編譯 u-boot那當然少不了配置啦 )

$cd u-boot-1.3.4

__libs := $(subst $(obj),,$(libs)) $(subst $(obj),,$(libboard))

改為

__libs := $(subst $(obj),,$(libboard)) $(subst $(obj),,$(libs))

sbc2410x_config: unconfig @$(mkconfig) $(@:_config=) arm arm920t sbc2410x null s3c24x0

qljt2440_config : unconfig @$(mkconfig) $(@:_config=) arm arm920t qljt2440 qljt s3c24x0

/*

各項的意思如下 :

       qljt2440_config : 這個名字是将來你配置闆子時候用到的名字,參見 make qljt2440_config指令。

arm: cpu的架構 (arch)

arm920t: cpu的類型 (cpu),其對應于 cpu/arm920t子目錄。

qljt2440: 開發闆的型号 (board),對應于 board/qljt/qljt2440目錄。

qljt: 開發者 /或經銷商 (vender)。 s3c24x0: 片上系統 (soc)。

*/

4. 在 /board子目錄中建立自己的開發闆 qljt2440目錄

由于我在上一步闆子的開發者 /或經銷商 (vender)中填了 qljt ,是以開發闆 qljt2440目錄一定要建在 /board子目錄中的 qljt目錄下 ,否則編譯會出錯。

       config.mk  flash.c  lowlevel_init.s   makefile   qljt2440.c  u-boot.lds

       cobjs := qljt2440.o flash.o

5. 在 include/configs/ 中建立開發闆所需要的配置頭檔案

6. 測試交叉編譯能否成功

( 1)配置

       configure for qljt2440 board…

(2)測試編譯

詳細資訊如下:

編譯資訊最後兩行:

       arm-linux-objcopy --gap-fill=0xff -o srec u-boot u-boot.srec

arm-linux-objcopy --gap-fill=0xff -o binary u-boot u-boot.bin

到此交叉編譯成功。

三.開始針對自己的開發闆移植

1.<b>  </b> <b>修改</b> <b>/cpu/arm920t/start.s </b>

<b>1.1 </b> <b>修改寄存器位址定義</b>

<b>#if defined(config_s3c2400) || defined(config_s3c2410) </b><b>|| defined(config_s3c2440)</b><b>   </b> <b></b>

<b>/* turn off the watchdog */</b> <b></b>

<b>#if defined(config_s3c2400)</b> <b></b>

<b># define pwtcon        0x15300000</b> <b></b>

<b># define intmsk        0x14400008    /* interupt-controller base addresses */</b> <b></b>

<b># define clkdivn    0x14800014    /* clock divisor register */</b> <b></b>

<b>#else</b>

<b># define pwtcon        0x53000000     /*</b> <b>該位址用來屏蔽看門狗</b> <b>*/</b> <b></b>

<b># define intmsk        0x4a000008    /* interupt-controller base addresses </b> <b>該位址用來屏蔽中斷</b> <b>*/</b> <b></b>

<b># define intsubmsk    0x4a00001c  /*</b> <b>該位址用來屏蔽子中斷</b> <b>*/</b> <b></b>

<b># define clkdivn    0x4c000014    /* clock divisor register </b> <b>該位址用來決定</b> <b>fclk</b> <b>、</b> <b>hclk</b> <b>、</b> <b>pclk</b> <b>的比例</b> <b>*/</b>

<b>#define clk_ctl_base        0x4c000000  /*</b><b> qljt </b> <b>從</b> <b>s3c2440a.pdf</b> <b>中可以看出該寄存器是存放</b> <b>mpll</b> <b>和</b> <b>upll</b> <b>的</b> <b>p254</b><b> */</b> <b></b>

<b>#if defined(config_s3c2440)       </b>

<b>#define mdiv_405       0x7f &lt;&lt; 12   /* </b><b>qljt  </b> <b>參見</b> <b>p255</b> <b>表,同時要知道本開發闆的</b> <b>fin</b> <b>是</b> <b>12mhz</b> <b>,需要的</b> <b>fclk(</b> <b>也就</b>

<b>是</b> <b>mpll)</b> <b>是</b> <b>405mhz</b><b>*/</b> <b></b>

<b>#define psdiv_405       0x21       /* </b><b>qljt </b> <b>同上,同時設定</b> <b>pdiv</b> <b>和</b> <b>sdiv</b> <b>的值,</b> <b>pdiv</b> <b>和</b> <b>sdiv</b> <b>參見</b> <b>s3c2440a.pdf</b><b>*/</b> <b></b>

<b>#endif</b> <b></b>

<b>#endif</b>

<b>1.2  </b> <b>修改中斷禁止部分</b> <b></b>

<b>  # if defined(config_s3c2410)</b> <b></b>

<b>    ldr    r1, =0x</b><b>7</b><b>ff   </b><b>//</b> <b>根據</b> <b>2410</b> <b>晶片手冊,</b> <b>intsubmsk</b> <b>有</b> <b>11</b> <b>位可用,</b> <b></b>

<b>                       </b><b>//vivi</b> <b>也是</b> <b>0x7ff</b> <b>,不知為什麼</b> <b>u</b> <b>-</b> <b>boot</b> <b>一直沒改過來。但是由于晶片複位預設</b>

<b>//</b> <b>所有的終端都是被屏蔽的,是以這個不影響工作</b> <b></b>

<b>    ldr    r0, =intsubmsk</b> <b></b>

<b>    str    r1, [r0]</b> <b></b>

<b># endif</b> <b></b>

<b># if  defined(config_s3c2440)</b> <b></b>

<b>    ldr    r1, =0x7fff   //</b> <b>根據</b> <b>2440</b> <b>晶片手冊,</b> <b>intsubmsk</b> <b>有</b> <b>15</b> <b>位可用</b>

<b># endif</b>

<b>1.3 </b> <b>修改時鐘設定</b>

<b>/*</b> <b>時鐘控制邏輯單元能夠産生</b> <b>s3c2440</b> <b>需要的時鐘信号,包括</b> <b>cpu</b> <b>使用的主頻</b> <b>fclk,ahb</b> <b>總線使用的</b> <b>hclk,apb</b> <b>總線裝置使用的</b> <b>pclk</b> <b>,</b> <b>2440</b> <b>裡面的兩個鎖相環</b> <b>(pll)</b> <b>,其中一個對應</b> <b>fclk</b> <b>、</b> <b>hclk</b> <b>、</b> <b>pclk</b> <b>,另外一個對應</b> <b>uclk(48mhz)*/</b>

<b>/*</b> <b>注意:</b> <b>ahp</b> <b>、</b> <b>apb</b> <b>總線的簡介參見“</b> <b>ahb</b> <b>與</b> <b>apb</b> <b>總線</b> <b>.doc</b> <b>”</b> <b>*/</b>

<b>/* fclk:hclk:pclk = 1:4:8 */</b> <b></b>

<b>    ldr    r0, =clkdivn</b> <b></b>

<b> </b><b>   </b><b>mov    r1, #5</b> <b></b>

<b>/*</b> <b>這三條協處理器指令确實不知道什麼意思,在</b> <b>atxjgybc_ql.pdf</b> <b>中搜</b> <b>p15</b> <b>和</b> <b>c1</b> <b>,隻知道它們執行以後會把協處理器</b> <b>p15</b> <b>的寄存器</b> <b>c1</b> <b>的最高兩位置</b> <b>1</b> <b>,但</b> <b>c1</b> <b>的最高兩位是沒有意義啊,弄不懂它的真正意思</b>

<b>不過我卻知道這三條語句是從哪裡出來的,詳細請參考</b> <b>s3c2440</b> <b>的</b> <b>datasheet</b> <b>和</b> <b>s3c2440datasheet</b> <b>中的</b> <b>r1_nf</b> <b>和</b> <b>r1_ia.doc */</b> <b></b>

<b>    mrc    p15, 0, r1, c1, c0, 0       </b><b> /*read ctrl register   qljt*/</b> <b></b>

<b>    orr    r1, r1, #0xc0000000       </b><b>/*asynchronous  qljt</b><b> </b> <b>改變總線模式為異步模式網上某位朋友說不知到在哪裡看到過</b>

<b>如果</b> <b>fclk</b> <b>與</b> <b>hclk</b> <b>不同的話就要選擇這種模式的</b> <b>*/</b> <b></b>

<b>    mcr    p15, 0, r1, c1, c0, 0     </b><b> /*write ctrl register qljt*/</b> <b></b>

<b>#if defined(config_s3c2440)  </b><b> // </b> <b>(</b> <b>2440</b> <b>的主頻可達</b> <b>533mhz</b> <b>,但聽說設到</b> <b>533mhz</b> <b>時系統</b>

<b>//</b> <b>很不穩定,不知是不是</b> <b>sdram</b> <b>和總線配置的影響,是以現在先設到</b> <b>//405mhz</b> <b>,以後在改進。)</b>

<b>    /*now, cpu clock is 405.00 mhz   qljt*/</b> <b></b>

<b>    mov    r1, #clk_ctl_base    </b><b>/* qljt*/</b> <b></b>

<b>    mov    r2, #mdiv_405                   </b><b>/* mpll_405mhz    qljt*/</b> <b></b>

<b>    add    r2, r2, #psdiv_405            </b><b> /* mpll_405mhz    qljt*/</b> <b></b>

<b>    str    r2, [r1, #0x04]              </b><b> /* mpllcon qljt</b> <b>實際上是設定寄存器</b> <b>clk_ctl_base+0x04=0x4c000004</b> <b>的值</b> <b></b><b>*/</b> <b></b>

<b>#endif    /* config_s3c2400 || config_s3c2410|| config_s3c2440 */</b>

<b>1.4 </b> <b>将從</b> <b>flash</b> <b>啟動改成從</b> <b>nand flash</b> <b>啟動</b> <b>。(特别注意:這和</b> <b>2410</b> <b>的程式有不同,不可混用!!!是拷貝</b> <b>vivi</b> <b>的代碼。)</b> <b></b>

<b>将以下</b> <b>u</b> <b>-</b> <b>boot</b> <b>的重定向語句段:</b>

<b>@#if ndef         config_at91rm9200</b>

<b>#if  0</b> <b></b>

<b>#ifndef config_skip_relocate_uboot</b> <b></b>

<b>relocate:                /* relocate u-boot to ram        */</b> <b></b>

<b>    adr    r0, _start        /* r0 &lt;- current position of code   */</b> <b></b>

<b>    ldr    r1, _text_base        /* test if we run from flash or ram */</b> <b></b>

<b>    cmp     r0, r1                /* don't reloc during debug         */</b> <b></b>

<b>    beq     stack_setup</b> <b></b>

<b>    ldr    r2, _armboot_start</b> <b></b>

<b>    ldr    r3, _bss_start</b> <b></b>

<b>    sub    r2, r3, r2        /* r2 &lt;- size of armboot            */</b> <b></b>

<b>    add    r2, r0, r2        /* r2 &lt;- source end address         */</b> <b></b>

<b>copy_loop:</b> <b></b>

<b>    ldmia    r0!, {r3-r10}        /* copy from source address [r0]    */</b> <b></b>

<b>    stmia    r1!, {r3-r10}        /* copy to   target address [r1]    */</b> <b></b>

<b>    cmp    r0, r2            /* until source end addreee [r2]    */</b> <b></b>

<b>    ble    copy_loop</b> <b></b>

<b>#endif    /* config_skip_relocate_uboot */</b>

<b>#endif </b><b> /*config_at91rm9200 */</b> <b></b>

<b>然後添加:</b> <b></b>

<b>/*</b> <b>下載下傳了一個</b> <b>vivi</b> <b>源代碼看了一下,還真的有下面哪一段代碼</b> <b>*/</b> <b></b>

<b>#ifdef config_s3c2440_nand_boot   @qljt@@@@@@@@@@@@@@@@sssssssssssss</b> <b></b>

<b>    @ reset nand</b>

<b>/*</b> <b>往下四段内容都是針對</b> <b>s3c2440</b> <b>的關于</b> <b>nand-flash</b> <b>的寄存器的設定,具體有什麼作用,看了</b> <b>datasheet</b> <b>,有些明白有些不明白</b> <b>*/</b> <b></b>

<b>    mov    r1, #nand_ctl_base           </b> <b></b>

<b>    ldr    r2, =( (7&lt;&lt;12)|(7&lt;&lt;8)|(7&lt;&lt;4)|(0&lt;&lt;0) )</b> <b></b>

<b>    str    r2, [r1, #onfconf]          </b><b>/*</b> <b>這些宏是在</b> <b>include/configs/qljt2440.h</b> <b>中被定義的</b> <b>*/</b> <b></b>

<b>    ldr    r2, [r1, #onfconf]  </b><b>/*</b> <b>還是弄不懂為什麼上面一句</b> <b>str</b> <b>以後還要有這句的</b> <b>ldr</b> <b>指令?</b> <b>why</b> <b>?難道是多餘的?</b> <b>*/</b> <b></b>

<b>    ldr    r2, =( (1&lt;&lt;4)|(0&lt;&lt;1)|(1&lt;&lt;0) ) </b><b>@ active low ce control </b> <b></b>

<b>    str    r2, [r1, #onfcont]</b> <b></b>

<b>    ldr    r2, [r1, #onfcont]</b> <b></b>

<b>    ldr    r2, =(0x6)       </b><b> @ rnb clear</b> <b></b>

<b>    str    r2, [r1, #onfstat]</b> <b></b>

<b>    ldr    r2, [r1, #onfstat]</b> <b></b>

<b>    </b> <b></b>

<b>    mov    r2, #0xff        </b><b>@ reset command</b> <b></b>

<b>    strb    r2, [r1, #onfcmd]</b> <b></b>

<b>/*delay</b> <b>一段時間</b> <b>*/</b> <b></b>

<b>  mov r3, #0                   </b><b>@ wait</b> <b></b>

<b>nand1: </b> <b></b>

<b>  add  r3, r3, #0x1</b> <b></b>

<b>  cmp r3, #0xa</b> <b></b>

<b>  blt   nand1</b> <b></b>

<b>/*</b> <b>等待</b> <b>nand-flash</b> <b>的複位完畢信号</b> <b>*/</b> <b></b>

<b>nand2:</b> <b></b>

<b>  ldr   r2, [r1, #onfstat]      </b><b>@ wait ready</b> <b></b>

<b>  tst    r2, #0x4</b> <b></b>

<b>  beq  nand2</b> <b></b>

<b>  </b><b>ldr    r2, [r1, #onfcont]</b> <b></b>

<b> orr    r2, r2, #0x2       </b><b> @ flash memory chip disable  /*</b> <b>在這裡先</b> <b>display fansh ce</b> <b>先,在</b> <b>c</b> <b>函數中對</b> <b>falsh</b> <b>進行</b> <b>*/</b>

<b>str    r2, [r1, #onfcont]                         </b><b> /*</b> <b>操作的時候才</b> <b>enable</b> <b>,為什麼這樣操作不太清楚</b> <b>*/</b><b>   </b> <b></b>

<b>/*</b> <b>下面這段用來初始化棧指針</b> <b>sp</b> <b>和幀指針</b> <b>fp,</b> <b>至于它們的定義和作用參考檔案夾</b> <b>”</b> <b>棧指針</b> <b>sp</b> <b>和幀指針</b> <b>fp”</b> <b>裡面的内容</b>

<b>記住它們都是與函數調用時候相關的。簡單來講就是子函數被調用以後是通過指針的相對位置來查找調用參數和局部變量的,但是由于</b> <b>sp</b> <b>經常變化,是以需要</b> <b>fp</b> <b>來協助。</b> <b>*/</b> <b></b>

<b>@ get ready to call c functions (for nand_read())</b> <b></b>

<b>  ldr   sp, dw_stack_start       @ setup stack pointer /*</b><b>sp </b> <b>是指堆棧指針</b> <b>*/</b> <b></b>

<b>  mov fp, #0                    @ no previous frame, so fp=0                 </b> <b></b>

<b>@ copy u-boot to ram                   /*vivi</b> <b>裡面應該是有一段是針對</b> <b>gpio</b> <b>的程式,也許使用來</b> <b>debug</b> <b>用的信号燈,這裡省略了</b> <b>*/</b> <b></b>

<b>         /* text_base </b> <b>是</b> <b>uboot</b> <b>自己的入口位址,在</b> <b>u-boot-1.3.4-board/qljt/qljt2440</b> <b>的</b> <b>config.mk</b> <b>中定義</b>

<b>有趣的是外國人的逆向思維很厲害,它們很靈活地把它放在</b> <b>sdram</b> <b>的最後</b> <b>0x80000</b> <b>地方,也就是</b> <b>0x33f80000 </b>

<b>*/</b>

<b>  ldr   r0, =text_base         </b><b>/*r0 : </b> <b>把</b> <b>u-boot</b> <b>複制到</b> <b>ram</b> <b>的那個位置</b> <b>*/</b> <b></b>

<b>         mov     r1, #0x0                          </b><b>/*r1 : </b> <b>從</b> <b>falsh</b> <b>的那個位置開始複制</b> <b>*/</b> <b></b>

<b>         mov r2, #0x20000                     </b><b>/*r2 : </b> <b>複制多大的内容</b> <b>*/</b> <b></b>

<b>         bl    nand_read_ll              </b><b>/*</b> <b>跳到執行</b> <b>uboot</b> <b>複制的程式入口</b> <b>,</b> <b>這個函數從哪裡來?也是來自</b> <b>vivi</b> <b>的,沒辦法</b> <b>*/</b> <b></b>

<b>         tst    r0, #0x0                    </b><b>/*</b> <b>這裡特别注意</b> <b>r0</b> <b>的值是指</b> <b>nand_read_ll </b> <b>執行完以後的傳回值,而不是上面</b>

<b>ldr   r0, =text_base </b> <b>的值,初學者往往在這裡想不通</b> <b>*/   </b> <b></b>

<b>         beq  ok_nand_read</b> <b></b>

<b>bad_nand_read:                  /*</b> <b>如果讀</b> <b>nand_read</b> <b>失敗的話,那麼</b> <b>sorry</b> <b>,重來,或者檢查硬體</b> <b>*/</b> <b></b>

<b>loop2:    b     loop2          @ infinite loop</b> <b></b>

<b>ok_nand_read:</b> <b></b>

<b>@ verify           </b>

<b>/*</b> <b>計算機就是好,很容易就可以檢測我們放在</b> <b>sdram</b> <b>中的</b> <b>u-boot</b> <b>是不是</b> <b>flash</b> <b>中的</b> <b>uboot</b> <b>。</b>

<b>本開發闆使用的是</b> <b>nand-falsh</b> <b>的啟動方式,闆子一上電并不是馬上進入</b> <b>sdram</b> <b>執行程式的。是這樣的:闆子一上電,</b> <b>s3c2440</b> <b>自動把</b> <b>nand-falsh</b> <b>中從</b> <b>0</b> <b>位址開始的</b> <b>4kbytes</b> <b>複制到</b> <b>s3c2440</b> <b>內建的某個緩沖區裡面</b> <b>(</b> <b>起始位址是</b> <b>0x00)</b> <b>,從那裡開始執行,那</b> <b>4k</b> <b>程式負責把整個</b> <b>uboot</b> <b>複制到</b> <b>sdram</b> <b>,然後才跳到</b> <b>sdram</b> <b>開始正真的</b> <b>uboot(</b> <b>這個技術是有個專業名字的我忘記了</b> <b>),*/</b>

<b>/*</b> <b>下面這段程式的作用就是用開始執行的</b> <b>4kbytes</b> <b>程式跟我們複制到</b> <b>sdram</b> <b>中的</b> <b>uboot</b> <b>的前</b> <b>4k</b> <b>程式進行比較,進而校驗</b> <b>*/</b> <b></b>

<b>  mov r0, #0</b> <b></b>

<b>  ldr   r1, =text_base</b> <b></b>

<b>  mov r2, #0x400     @ 4 bytes * 1024 = 4k-bytes</b> <b></b>

<b>go_next:</b> <b></b>

<b>  ldr   r3, [r0], #4</b> <b></b>

<b>  ldr   r4, [r1], #4</b> <b></b>

<b>  teq   r3, r4</b> <b></b>

<b>  bne  notmatch</b> <b></b>

<b>  subs r2, r2, #4</b> <b></b>

<b>  beq  stack_setup</b> <b></b>

<b>  bne  go_next</b> <b></b>

<b>notmatch:</b> <b></b>

<b>loop3:     b     loop3         @ infinite loop</b> <b></b>

<b>#endif @ config_s3c2440_nand_boot  @qljt@@@@@@@@@@@@@@@@@@eeeeeeeee</b>

1.5 在跳到 c函數執行前,也就是跳出 start.s前,添加幾個 led燈的控制,說明程式跑到這裡了,移植的第一階段完成了。

<b>/</b><b>*</b> <b>本開發闆上面有四個</b> <b>led</b> <b>燈,分别接到</b> <b>cpu </b> <b>的</b> <b>gpio_f[4:7]</b> <b>這四個引腳上</b> <b>*</b><b>/</b>

<b>#if defined(config_s3c2440)</b>

<b>@  led1 on u-boot stage 1 is ok!</b> <b></b>

<b>    mov    r1, #gpio_ctl_base   </b> <b></b>

<b>    add    r1, r1, #ogpio_f</b> <b></b>

<b>    ldr    r2,=0x5500</b> <b></b>

<b>    str    r2, [r1, #ogpio_con]</b> <b></b>

<b>    mov    r2, #0xff</b> <b></b>

<b>    str    r2, [r1, #ogpio_up]</b> <b></b>

<b>    mov    r2, #0xdf</b> <b></b>

<b>    str    r2, [r1, #ogpio_dat]</b>

<b>1.6 </b> <b>在</b> <b>“  _start_armboot:    .word start_armboot  ” </b> <b>後加入:</b>

<b>#if defined(config_s3c2440_nand_boot)</b> <b></b>

<b>.align     2         </b><b>/*</b><b>???</b> <b>這裡我一直不明白為什麼是</b> <b>.align 2,</b> <b>因為如果按照</b> <b>arm</b> <b>的規則,意思是按照</b> <b>2</b> <b>的</b> <b>2</b> <b>次方</b> <b>=4bit</b> <b>的</b>

<b>方式對齊,那麼就是半個位元組對齊,有可能嗎?</b> <b>*/</b> <b></b>

<b>dw_stack_start:  .word  stack_base+stack_size-4  </b><b> /*</b> <b>從這裡可以看出該堆棧是從高位址向低位址增長的</b>

<b>注意這裡的</b> <b>stack_base</b> <b>和</b> <b>stack_size</b> <b>還沒定義,在</b> <b>1.1</b> <b>節中定義</b> <b>*/</b>

<b>2. </b> <b>修改</b> <b>include/configs/qljt2440.h</b> <b>檔案,在結尾處添加如下内容(</b> <b>注意:</b> <b>s3c2410</b> <b>與</b> <b>s3c2440</b> <b>的</b> <b>nand flash</b> <b>控制器寄存器不同,不能混用!!</b> <b>):</b> <b></b>

<b>......</b> <b></b>

<b>/*</b> <b></b>

<b> * nandflash boot</b> <b></b>

<b> */</b> <b></b>

<b>#define config_s3c2440_nand_boot 1</b> <b></b>

<b>#define stack_base    0x33f00000</b> <b></b>

<b>#define stack_size    0x8000</b> <b></b>

<b>/* nand flash controller */</b> <b></b>

<b>#define nand_ctl_base        0x4e000000</b> <b></b>

<b>/* offset */</b> <b></b>

<b>#define onfconf            0x00       </b> <b>/*</b> <b>這些宏是在</b> <b>start.s</b> <b>中被調用的</b> <b>*/</b> <b></b>

<b>#define onfcont            0x04</b> <b></b>

<b>#define onfcmd            0x08</b> <b></b>

<b>#define onfaddr            0x0c</b> <b></b>

<b>#define onfdata            0x10</b> <b></b>

<b>#define onfstat            0x20</b> <b></b>

<b>#define onfecc            0x2c</b>

<b>/* gpio */</b> <b></b>

<b>#define gpio_ctl_base        0x56000000</b> <b></b>

<b>#define ogpio_f            0x50</b> <b></b>

<b>#define ogpio_con       0x0   /* r/w, configures the pins of the port */</b> <b></b>

<b>#define ogpio_dat        0x4    /* r/w,    data register for port */</b> <b></b>

<b>#define ogpio_up        0x8    /* r/w, pull-up disable register */</b> <b></b>

<b>#endif    /* __config_h */</b>

<b>3.  </b> <b>在</b> <b>board/qljt/qljt2440</b> <b>加入</b> <b>nand flash</b> <b>讀函數檔案,拷貝</b> <b>vivi</b> <b>中的</b> <b>nand_read.c</b> <b>檔案到此檔案夾即可,基本上大陸上移植的都是這樣做的,在此把該檔案的内容貼出來,目的是對一些難了解的代碼進行解析:</b> <b></b>

<b>#include &lt;config.h&gt;</b> <b></b>

<b>#define __regb(x)    (*(volatile unsigned char *)(x))</b> <b></b>

<b>#define __regi(x)    (*(volatile unsigned int *)(x))</b> <b></b>

<b>#define nf_base        0x4e000000</b> <b></b>

<b>#define nfconf        __regi(nf_base + 0x0)</b> <b></b>

<b>#define nfcont        __regi(nf_base + 0x4)</b> <b></b>

<b>#define nfcmd        __regb(nf_base + 0x8)</b> <b></b>

<b>#define nfaddr        __regb(nf_base + 0xc)</b> <b></b>

<b>#define nfdata        __regb(nf_base + 0x10)</b> <b></b>

<b>#define nfstat        __regb(nf_base + 0x20)</b> <b></b>

<b>//#define gpdat        __regi(gpio_ctl_base+ogpio_f+ogpio_dat)</b> <b></b>

<b>#define nand_chip_enable  (nfcont &amp;= ~(1&lt;&lt;1))</b> <b></b>

<b>#define nand_chip_disable (nfcont |=  (1&lt;&lt;1))</b> <b></b>

<b>#define nand_clear_rb      (nfstat |=  (1&lt;&lt;2))</b> <b></b>

<b>#define nand_detect_rb      { while(! (nfstat&amp;(1&lt;&lt;2)) );}</b> <b></b>

<b>#define busy 4</b> <b></b>

<b>inline void wait_idle(void) {</b> <b></b>

<b>    while(!(nfstat &amp; busy));</b> <b></b>

<b>    nfstat |= busy;</b> <b></b>

<b>}</b> <b></b>

<b>#define nand_sector_size    512</b> <b></b>

<b>#define nand_block_mask        (nand_sector_size - 1)</b> <b></b>

<b>/* low level nand read function */</b>

<b>/*</b> <b>下面</b> <b>nand_read_ll </b> <b>的三個參數來自</b> <b>start.s</b> <b>裡面調用</b> <b>nand_read_ll </b> <b>前的</b> <b>r0</b> <b>、</b> <b>r1</b> <b>、</b> <b>r2*/</b> <b></b>

<b>int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)</b> <b></b>

<b>{</b> <b></b>

<b>    int i, j;</b> <b></b>

<b>/*</b> <b>下面這個</b> <b>if</b> <b>保證對</b> <b>flash</b> <b>的讀操作是從某一頁的頁頭開始的,從直覺來看是保證</b> <b>start_addr[0:8]</b> <b>位都為</b> <b>0</b> <b>,</b>

<b>為什麼呢?因為本</b> <b>flash</b> <b>的一頁的大小位</b> <b>512-bytes</b> <b>,也就是從</b> <b>0x0</b> <b>到</b> <b>0x1ff*/</b> <b></b>

<b>    if ((start_addr &amp; nand_block_mask) || (size &amp; nand_block_mask)) {</b> <b></b>

<b>        return -1;    /* invalid alignment */</b> <b></b>

<b>    }</b> <b></b>

<b>    nand_chip_enable;</b> <b></b>

<b>    for(i=start_addr; i &lt; (start_addr + size);) {</b> <b></b>

<b>        /* read0 */</b> <b></b>

<b>        nand_clear_rb;        </b> <b></b>

<b>         </b><b>/*</b> <b>到此應該可以明白</b> <b>s3c2440 nandflash </b> <b>相關寄存器的确切含義了,就是說</b> <b>s3c2440</b> <b>裡面已經內建了對</b> <b>nand flash</b> <b>操</b>

<b>作的相關寄存器,隻要你的</b> <b>nand flash</b> <b>接線符合</b> <b>s3c2440 datasheet</b> <b>的接法,就可以随便使用</b> <b>s3c2440 </b> <b>對于</b> <b>nand </b>

<b>flash</b> <b>的相關寄存器,例如如果你想像</b> <b>nand flash</b> <b>寫一個指令,那麼隻要對指令寄存器寫入你的指令就可以了,</b> <b>s3c2440 </b> <b>可以自動幫你完成所有的時序動作,寫位址也是一樣。反過來說如果沒有了對</b> <b>nand flash</b> <b>的支援,那麼我們對</b> <b>nand falsh</b> <b>的操作就會增加好多對</b> <b>i/o</b> <b>口的控制,例如對</b> <b>cle,ale</b> <b>的控制。</b> <b>s3c2440</b> <b>已經幫我們完成了這部分工作了</b> <b>*/</b>

<b>        nfcmd = 0;</b> <b></b>

<b>        /* write address */</b>

<b>/*</b> <b>下面這個送位址的過程可以說是這段程式裡最難懂的一部分了,難就難于為什麼送進</b> <b>nand flash</b> <b>的位址忽略了</b> <b>bit8</b> <b>,</b>

<b>縱觀整個</b> <b>for(i) </b> <b>循環,</b> <b>i</b> <b>并不是一個随機的位址,而應該是每一頁的首位址。其實</b> <b>nand flash</b> <b>并不是忽略了</b> <b>bit 8</b> <b>這個</b>

<b>位址,而是</b> <b>bit 8</b> <b>早就被定下來了,什麼時候定下來,就是上面的</b> <b>nfcmd = 0;</b> <b>語句,本</b> <b>flash (k9f1208u0b)</b> <b>支援從</b>

<b>半頁開始讀取,進而它有兩個讀的指令,分别是</b> <b>0x00(</b> <b>從一頁的上半頁開始讀</b> <b>) </b> <b>和</b> <b>0x01(</b> <b>從一頁的下半頁開始讀</b> <b>)</b> <b>,</b>

<b>當取</b> <b>0x00</b> <b>時,</b> <b>bit 8=0</b> <b>,當取</b> <b>0x01</b> <b>時</b> <b>bit 8=1.*/</b> <b></b>

<b>        nfaddr = i &amp; 0xff;</b> <b></b>

<b>        nfaddr = (i &gt;&gt; 9) &amp; 0xff;</b> <b></b>

<b>        nfaddr = (i &gt;&gt; 17) &amp; 0xff;</b> <b></b>

<b>        nfaddr = (i &gt;&gt; 25) &amp; 0xff;</b> <b></b>

<b>        nand_detect_rb;</b> <b></b>

<b>        for(j=0; j &lt; nand_sector_size; j++, i++) {</b> <b></b>

<b>            *buf = (nfdata &amp; 0xff);</b><b> /*</b> <b>每讀一次</b> <b>nandflash</b> <b>就往</b> <b>io</b> <b>口送下一個</b> <b>byte</b> <b>,直到送</b>

<b>完</b> <b>nand_sector_size </b> <b>個為止</b> <b>*/</b> <b></b>

<b>            buf++;</b> <b></b>

<b>        }</b> <b></b>

<b>    nand_chip_disable;</b> <b></b>

<b>    return 0;</b> <b></b>

<b>}</b>

<b>4. </b> <b>修改</b> <b>board/qljt/qljt2440/makefile</b> <b>檔案,讓剛剛添加的nand_read.c編譯進來</b> <b></b>

<b>c</b> <b>objs := qljt2440.o  </b> <b>nand_read.o</b> <b> flash.o</b> <b></b>

<b>......</b>

<b>/*===========================================================</b>

<b>到這裡,應該是可以編譯通過的,否則就是編輯的時候出現了錯誤</b>

<b>===========================================================*/</b>

5. 修改 board/qljt/qljt2440/lowlevel_init.s檔案

    依照開發闆的記憶體區的配置情況 , 修改 board/qljt/qljt2440/lowlevel_init.s檔案, :

......

/* refresh parameter 下面這 6個配置都可以參考 s3c2440a datasheet p210的 refresh寄存器 */

#define refen             0x1    /* refresh enable */

#define trefmd             0x0    /* cbr(cas before ras)/auto refresh */

#define trp             0x01    /* 3clk 這個值可以參考本版子上的 sdram的 datasheet*/

#define trc             0x3    /* 也就是 sdram datasheet裡面的 tsrc 7clk 本來這個地方是 trc,但從 lowlevel_init.s裡面的調用來看,應該是寄存器refresh

的 tsrc才對,好多地方都沒有改過來,我我覺得隻是個名字而已,不影響結果

注意:如果這裡改了,那麼下面這句中的 trc也要改為相應的 tsrc:

<b>.word ((refen&lt;&lt;23)+(trefmd&lt;&lt;22)+(trp&lt;&lt;20)+(trc&lt;&lt;18)+(tchr&lt;&lt;16)+refcnt)*/</b>

#define tchr             0x2    /* 3clk,這個從 lowlevel_init.s裡面的調用來看是屬于 refresh的保留位,不知道為什

麼還要給他指派 */

#define refcnt    1259 /*這個值的算法參考 s3c2440a datasheet p210的refresh counter */

<b>/*</b> <b>下面不厭其煩地解析一下</b> lowlevel_init.s這個原檔案 <b>*/</b>

<b>#define bwscon  0x48000000</b>

<b>……</b>

<b>#define tchr                      0x2   /* 3clk */</b>

<b>#define refcnt                        0x0459</b>

<b>/**************************************/</b>

<b>/*1.</b> <b>要知道上面這些配置的最終會被用到下面</b> <b>smrdata </b> <b>這個資料池裡面,是以必須要明白</b> <b>smrdata </b> <b>這個資料池是用</b>

<b>來幹什麼的,</b> <b>smrdata </b> <b>後面每一個</b> <b>.word </b> <b>後面防止的資料都是将要寫入</b> <b>bwscon </b> <b>開始的寄存器的,總共有</b> <b>13</b> <b>個</b> <b>.work ,</b> <b>它們後面放置的值将會分别别寫入</b> <b>0x48000000</b> <b>、</b> <b>0x48000004</b> <b>、</b> <b>0x48000008…</b> <b>一直到</b> <b>0x48000030</b> <b>共</b> <b>13</b> <b>個寄存器。</b> <b>*/</b>

<b>/*2.</b> <b>上面那些配置的值是怎樣決定的呢,詳細請參考</b> <b>s3c2440a</b> <b>和你所用</b> <b>sdram</b> <b>的</b> <b>datasheet</b> <b>。細心找總是能找到的。</b> <b>*/</b>

<b>/*3.</b> <b>而上面的那些配置值最終是通過下面</b> <b>lowlevel_init</b> <b>後面的這段函數寫到寄存器裡面的,下面對該段函數逐一分析:</b> <b>*/</b>

<b>_text_base:</b>

<b>         .word         text_base</b>

<b>.globl lowlevel_init</b>

<b>lowlevel_init:</b>

<b>         /* memory control configuration */</b>

<b>         /* make r0 relative the current location so that it */</b>

<b>         /* reads smrdata out of flash rather than memory ! */</b>

<b>         ldr     r0, =smrdata</b>

<b>         ldr    r1, _text_base</b>

<b>     sub   r0, r0, r1</b><b>        /*</b> <b>其實明白了前三條語句這段程式就不難懂了,歸根到底就是為什麼将</b> <b>smrdata </b> <b>的值減</b>

<b>去</b> <b>_text_base</b> <b>的值?原因是這樣的:我們使用的是從</b> <b>nandflash boot</b> <b>的方式,目前程式</b>

<b>仍然在</b> <b>4k-bytes</b> ‘steppingstone’(這裡為什麼突然冒出個steppingstone’,這個就是我前面提到從nand flash 引導的方法,但不知道名字,後來重新看 <b>s3c2440a  datasheet</b> <b>的</b> <b>nand flash</b> <b>那一章的開頭才知道</b>)上面 <b>運作,在</b> <b>smrdata</b> <b>後面的的内容仍然在</b>steppingstone裡面。但是 <b>smrdata</b> <b>的值是相對于</b> <b>_text_base </b> <b>值的位址,而且</b> <b>_text_base </b> <b>是放置</b> <b>u-boot</b> <b>的開始地方,是以用</b> <b>smrdata-_text_base </b> <b>就可以得到</b> <b>smrdata</b> <b>後面内容在</b>steppingstone裡面 <b>相對于位址</b> <b>0x00000000</b> <b>的放置的所在地方</b> <b>(</b> <b>相對于</b> <b>0x00</b> <b>的位址值</b> <b>)</b> <b>。</b> <b>*/</b>

<b>/*</b> <b>從這三條語句可以看出前人為了實作從</b> <b>nand flash</b> <b>啟動可謂費盡心思啊!</b> <b>*/</b>

<b>         ldr    r1, =bwscon        </b><b>/* bus width status controller */</b>

<b>         add     r2, r0, #13*4  </b><b>/*</b> <b>總共</b> <b>13</b> <b>個寄存器</b> <b>*/</b>

<b>0:</b>

<b>         ldr     r3, [r0], #4</b>

<b>         str     r3, [r1], #4</b>

<b>         cmp     r2, r0</b>

<b>         bne     0b</b>

<b>         /* everything is fine now */</b>

<b>         mov  pc, lr</b>

<b>         .ltorg         </b><b>/*</b> <b>資料緩沖池,上網可以查得資料</b> <b>*/</b>

<b>/* the literal pools origin */</b>

<b>smrdata:</b>

<b>   ……   </b>

<b>    .word ((refen&lt;&lt;23)+(trefmd&lt;&lt;22)+(trp&lt;&lt;20)+(trc&lt;&lt;18)+(tchr&lt;&lt;16)+refcnt)</b>

<b>    .word 0xb2</b>

<b>    .word 0x30       /*</b> <b>需要注意的是</b> <b>cas latency</b>的值在這裡直接配置 <b>*/</b>

<b>.word 0x30</b>

<b>6 </b>修改 <b>/board/qljt/qljt2440/qljt2440.c</b>,修改這個檔案主要針對下面兩點:

(1) gpio的控制

(2) pll,畢竟s3c2410跟s3c2440不同

修改其對 <b>gpio</b>和 <b>pll</b>的配置 <b>(</b>請參閱 <b>sbc2440</b>的硬體說明和 <b>2440</b>晶片手冊 <b>)</b>: <b>...... </b>

<b>#elif fclk_speed==1 /* fout = 405mhz */ </b>

<b>//#define m_mdiv 0x5c </b>

<b>//#define m_pdiv 0x4 </b>

<b>//#define m_sdiv 0x0</b> <b></b>

<b>#define m_mdiv 0x7f </b>

<b>#define m_pdiv 0x2 </b>

<b>#define m_sdiv 0x1 </b>

<b>#elif usb_clock==1 </b>

<b>//#define u_m_mdiv 0x48 </b>

<b>//#define u_m_pdiv 0x3 </b>

<b>#define u_m_mdiv 0x38 </b>

<b>#define u_m_pdiv 0x2 </b>

<b>#define u_m_sdiv 0x2 </b>

<b>...... </b>

/* set up the i/o ports */

gpio-&gt;gpacon = 0x007fffff;

<b>// gpio-&gt;gpfcon = 0x000055aa; </b>

<b>gpio-&gt;gpfcon = 0x5500; </b> <b>/*for led*/</b>

<b>/* arch number of s3c2440 -board */ </b>

<b>gd-&gt;bd-&gt;bi_arch_number = </b> <b>mach_type_s3c2440 </b> <b>; </b>

<b>/* adress of boot parameters */ </b>

<b>gd-&gt;bd-&gt;bi_boot_params = 0x30000100; </b>

<b>icache_enable(); </b>

dcache_enable();

<b>gpio-&gt;gpfdat = 0xbf; </b> <b>/*for led*/</b>

<b>//int board_init (void)</b>設定完成後, <b>led1</b>和 <b>led2</b>會亮起!

<b>return 0; </b>

<b>} </b>

<b>7. </b> <b>為了實作</b> <b>nand flash</b> <b>的讀寫,再次修改</b> <b>/include/configs/qljt2440.h</b> <b></b>

<b> * high level configuration options</b> <b></b>

<b> * (easy to change)</b> <b></b>

<b>#define config_arm920t        1</b> <b>  </b> <b>  /* this is an arm920t core    */</b>

<b>//#define    config_s3c2410       1   /* in a samsung s3c2410 soc     */</b>

<b>//#define config_sbc2410x        1   /* on a friendly-arm sbc-2410x board  */</b>

<b></b>

<b>#define    config_s3c2440        1  </b> <b>/* </b> <b>在前面很多地方調用到</b> <b>config_s3c2440 ,</b> <b>他是在這裡定義</b> <b>  */</b> <b></b>

<b>#define config_qljt2440    1  </b> <b>/* </b> <b>針對一些本開發闆配置的宏控制</b> <b>*/</b> <b></b>

<b>/***********************************************************</b> <b></b>

<b> * command definition</b> <b></b>

<b> ***********************************************************/</b>

<b>#define config_cmd_dhcp</b>

<b>#define config_cmd_elf</b>

<b>#define config_cmd_ping</b> <b>     </b>

<b>#define config_cmd_nand           </b>

<b>#define config_cmd_net</b>

<b>#define config_cmd_env</b>

<b>/* this must be included after the definition of config_commands (if any) */</b> <b></b>

<b>#include &lt;cmd_confdefs.h&gt;</b> <b></b>

<b>#define    cfg_longhelp                </b> <b></b>

<b>/* undef to save memory        */</b>

<b>#define    cfg_prompt   "[qljt2440]#"</b> <b></b> <b>/*</b> <b>這個就是你啟動開發闆後指令行顯示的内容了</b> <b>*/</b> <b></b>

<b>/*monitor command prompt  */</b> <b></b>

<b>#define    cfg_cbsize        256        </b> <b></b>

<b>/* console i/o buffer size    */</b> <b></b>

<b>#define    cfg_load_addr      0x30008000  </b> <b></b> <b>/*</b> <b>以後</b> <b>linux kernel</b> <b>就要放在這裡執行</b> <b>*/</b> <b></b>

<b> /* default load address    */</b> <b></b>

<b>//#define cfg_env_is_in_flash       1</b> <b></b> <b>/</b> <b>這裡的</b> <b>flash</b> <b>應該是指</b> <b>nor</b> <b>了,都不知道外國人為什麼這麼預設</b> <b>/</b> <b></b>

<b>#define    cfg_env_is_in_nand    1 </b> <b>/*</b> <b>定義這個宏的目的是為了調用</b> <b>nand flash</b> <b>類型的</b> <b>saveenv</b>

<b>因為還有其它類型存儲器的</b> <b>saveenv</b> <b>,在</b> <b>u-boot</b> <b>中檢視</b> <b>saveenv</b>

<b>的定義,有多少中定義就有多少種</b> <b>*/</b>

<b>/*</b> <b>在</b> <b>linux</b> <b>對</b> <b>nand flash</b> <b>分區的時候,給</b> <b>u-boot</b> <b>配置設定</b> <b>256k</b> <b>的空間</b> <b>(0~0x40000)</b>

<b>其中</b> <b>u-boot.bin    [0x0~0x30000]  </b> <b>占</b> <b>192k</b>

<b>而</b> <b>   u-boot</b> <b>的參數</b> <b>[0x30000~0x40000] </b> <b>占</b> <b>64k</b>

<b>*/</b> <b></b>

<b>#define cfg_env_offset  0x30000          </b>

<b>#define cfg_env_size         0x10000</b>

<b>/*</b> <b>注意:網上很多地方都有關于</b> <b>config_cmd_nand </b> <b>、</b> <b>cfg_nand_legacy</b> <b>、</b> <b>drivers/mtd/nand/nand.c</b> <b>中的</b> <b>nand_init()</b> <b>函數以及</b> <b>board/qljt/qljt2440/qljt2440.c</b> <b>中的</b> <b>nand_init()</b> <b>函數這四個東西的關系,但大多說的不清不楚,我把它門的關系用表格一一列出來,請參考附錄。</b> <b>*/</b> <b></b>

<b>#define cfg_nand_legacy    </b> <b>              1</b> <b></b>

<b>/*----------------------------------------------------------------------</b> <b></b>

<b> * nand flash settings</b> <b></b>

<b>#if defined (config_cmd_nand)</b> <b></b>

<b>#define cfg_nand_base 0x4e000000 </b> <b>    /*</b> <b>這個鬼東西在</b> <b>drivers/mtd/nand/nand.c</b> <b>中被調用</b> <b>,</b> <b>它</b>

<b>是</b> <b>nand</b> <b>控制寄存器的基位址</b> <b>*/</b> <b></b>

<b>/* nandflash</b> <b>控制器在</b> <b>sfr</b> <b>區起始寄存器位址 </b> <b>*/</b> <b></b>

<b>#define cfg_max_nand_device 1</b> <b></b>

<b> /* </b> <b>支援的最在</b> <b>nand flash</b> <b>資料 </b> <b>*/</b> <b></b>

<b>#define sectorsize 512 </b> <b></b>

<b>/* 1</b> <b>頁的大小 </b> <b>*/</b> <b></b>

<b>#define nand_sector_size sectorsize </b> <b>/*</b> <b>這兩個東西好像也是多餘的,備用吧,在次文章搜一下</b>

<b>就知道其它用到的地方也有定義</b> <b>*/</b> <b></b>

<b>#define nand_block_mask 511         </b> <b>/*</b> <b>本</b> <b>flash</b> <b>一個</b> <b>block</b> <b>的大小</b> <b>-1*/</b> <b></b>

<b>/* </b> <b>頁掩碼 </b> <b>*/</b> <b></b>

<b>#define addr_column 1 </b> <b>/*</b> <b>意思是你所用的</b> <b>nandflash</b> <b>的</b> <b>column</b> <b>位址占多少個位元組</b> <b>*/</b> <b></b>

<b>/* </b> <b>一個位元組的</b> <b>column</b> <b>位址 </b> <b>*/ </b>

<b>#define addr_page 3</b><b> </b> <b>/*</b> <b>意思是你所用的</b> <b>nandflash</b> <b>的</b> <b>(row)page</b> <b>位址占多少個位元組</b> <b>*/</b> <b></b>

<b>/* 3</b> <b>位元組的頁塊位址</b> <b>!!!!!*/</b> <b></b>

<b>#define addr_column_page 4</b><b> </b> <b>/*</b> <b>意思是你所用的</b> <b>nandflash</b> <b>的</b> <b>column</b> <b>位址</b> <b>+page</b> <b>位址共占多少個位元組</b> <b>*/</b> <b></b>

<b>/* </b> <b>總共</b> <b>4</b> <b>位元組的頁塊位址</b> <b>!!!!! */</b> <b></b>

<b>#define nand_chipid_unknown 0x00 </b> <b></b>

<b>/* </b> <b>未知晶片的</b> <b>id</b> <b>号 </b> <b>*/</b> <b></b>

<b>#define nand_max_floors 1           /*</b> <b>怎樣算一</b> <b>floor*/</b> <b></b>

<b>#define nand_max_chips 1</b> <b></b>

<b>/* nand flash</b> <b>指令層底層接口函數 </b> <b>*/</b>

<b>#define rnfconf (*(volatile unsigned int *)0x4e000000)</b>

<b>#define rnfcont (*(volatile unsigned int *)0x4e000004)</b>

<b>#define rnfcmd (*(volatile unsigned char *)0x4e000008)</b>

<b>#define rnfaddr (*(volatile unsigned char *)0x4e00000c)</b>

<b>#define rnfdata (*(volatile unsigned char *)0x4e000010)</b>

<b>#define rnfstat (*(volatile unsigned int *)0x4e000020)</b>

<b>#define rnfecc (*(volatile unsigned int *)0x4e00002c)</b>

<b>/*</b> <b>下面部分内容是修改的</b> <b>*/</b>

<b>/* nand flash</b> <b>指令層底層接口函數</b> <b>*/</b>

<b>/*</b>

<b>#define nand_wait_ready(nand)      nf_waitrb()</b>

<b>#define nand_disable_ce(nand)        nf_setce(nfce_high)</b>

<b>#define nand_enable_ce(nand)         nf_setce(nfce_low)</b>

<b>#define write_nand_command(d, adr) nf_cmd(d)</b>

<b>#define write_nand_commandw(d, adr)      nf_cmdw(d)</b>

<b>#define write_nand_address(d, adr)    nf_addr(d)</b>

<b>#define write_nand(d, adr)                 nf_write(d)</b>

<b>#define read_nand(adr)                         nf_read()</b>

<b>*/ </b>

<b>#define write_nand_address(d, adr) {rnfaddr = d;}</b>

<b>#define write_nand(d, adr) {rnfdata = d;}</b>

<b>#define read_nand(adr) (rnfdata)</b>

<b>#define nand_wait_ready(nand) {while(!(rnfstat&amp;(1&lt;&lt;0)));}</b>

<b>#define write_nand_command(d, adr) {rnfcmd = d;}</b>

<b>#define write_nand_commandw(d, adr)    nf_cmdw(d)</b>

<b># if defined(config_s3c2440)</b>

<b>#define nand_disable_ce(nand) {rnfcont |= (1&lt;&lt;1);}</b>

<b>#define nand_enable_ce(nand) {rnfcont &amp;= ~(1&lt;&lt;1);}</b>

<b># if defined(config_s3c2410)</b>

<b>#define nand_disable_ce(nand) {rnfconf |= (1&lt;&lt;11);}</b>

<b>#define nand_enable_ce(nand) {rnfconf &amp;= ~(1&lt;&lt;11);}</b>

<b>/* </b> <b>允許</b> <b>nand flash</b> <b>寫校驗 打開下面宏定義</b> <b>*/</b> <b></b>

<b>#define config_mtd_nand_verify_write 1</b> <b></b>

8. 在/board/qljt/qljt2440/qljt2440.c檔案的末尾添加對nand flash 的初始化函數(在後面nand flash的操作都要用到)

#if defined(config_cmd_nand) /*大概在145行*/

typedef enum {

    nfce_low,

    nfce_high

} nfce_state;

static inline void nf_conf(u16 conf)

    s3c2410_nand * const nand = s3c2410_getbase_nand();

    nand-&gt;nfconf = conf;

static inline void nf_cmd(u8 cmd)

    nand-&gt;nfcmd = cmd;

static inline void nf_cmdw(u8 cmd)

    nf_cmd(cmd);

    udelay(1);

static inline void nf_addr(u8 addr)

    nand-&gt;nfaddr = addr;

static inline void nf_waitrb(void)

    while (!(nand-&gt;nfstat &amp; (1&lt;&lt;0)));

static inline void nf_write(u8 data)

    nand-&gt;nfdata = data;

static inline u8 nf_read(void)

    return(nand-&gt;nfdata);

static inline u32 nf_read_ecc(void)

    return(nand-&gt;nfecc);

#if defined(config_s3c2440)

static inline void nf_cont(u16 cont)

    nand-&gt;nfcont = cont;

static inline void nf_setce(nfce_state s)

    switch (s) {

    case nfce_low:

        nand-&gt;nfcont &amp;= ~(1&lt;&lt;1);

        break;

    case nfce_high:

        nand-&gt;nfcont |= (1&lt;&lt;1);

    }

static inline void nf_init_ecc(void)

    nand-&gt;nfcont |= (1&lt;&lt;4);

#else

        nand-&gt;nfconf &amp;= ~(1&lt;&lt;11);

        nand-&gt;nfconf |= (1&lt;&lt;11);

    nand-&gt;nfconf |= (1&lt;&lt;12);

#endif /*對應#if defined(config_s3c2440)*/

static inline void nf_init(void)

#if 0

#define tacls 0

#define twrph0 3

#define twrph1 0

#define twrph0 4

#define twrph1 2

#endif

    nf_conf((tacls&lt;&lt;12)|(twrph0&lt;&lt;8)|(twrph1&lt;&lt;4));

    nf_cont((0&lt;&lt;13)|(0&lt;&lt;12)|(0&lt;&lt;10)|(0&lt;&lt;9)|(0&lt;&lt;8)|(0&lt;&lt;6)|(0&lt;&lt;5)|(1&lt;&lt;4)|(0&lt;&lt;1)|(1&lt;&lt;0));

    nf_conf((1&lt;&lt;15)|(0&lt;&lt;14)|(0&lt;&lt;13)|(1&lt;&lt;12)|(1&lt;&lt;11)|(tacls&lt;&lt;8)|(twrph0&lt;&lt;4)|(twrph1&lt;&lt;0));

    /*nand-&gt;nfconf = (1&lt;&lt;15)|(1&lt;&lt;14)|(1&lt;&lt;13)|(1&lt;&lt;12)|(1&lt;&lt;11)|(tacls&lt;&lt;8)|(twrph0&lt;&lt;4)|(twrph1&lt;&lt;0); */

    /* 1 1 1 1, 1 xxx, r xxx, r xxx */

    /* en 512b 4step eccr nfce=h tacls twrph0 twrph1 */

    nf_reset();

9. cpuarm920ts3c24x0 nand.c ,很多人說u-boot-1.3.4已經不支援cfg_nand_legacy了,但其實還是支援的,定義了cfg_nand_legacy後nand.c要做如下修改:

#error "u-boot legacy nand support not available for s3c2410"

改成

// #error "u-boot legacy nand support not available for s3c2410"

<b>到這裡,編譯是不能通過的,原因上一節中</b> <b>config_s3c2410</b> <b>這個宏定義被注釋掉,下面要用</b> <b>config_s3c2440</b> <b>這個宏打開</b> <b>config_s3c2410</b> <b>所打開的内容</b> <b>===========================================================*/</b>

<b>10.  </b> <b>在</b> <b>s3c2440</b> <b>與</b> <b>s3c2410</b> <b>能夠共用的檔案中添加</b> <b>“config_s3c2440”</b> <b>,使得原來</b> <b>s3c2410</b> <b>的代碼可以編譯進來。</b>

<b>(</b> <b>1</b> <b>)</b> <b>/include/common.h</b> <b>檔案的第</b> <b>492</b> <b>行:</b> <b>/*</b> <b>一些公用的常用函數,例如</b> <b>get_fclk()*/</b>

<b>#if defined(config_s3c2400) || defined(config_s3c2410) || defined(config_lh7a40x)</b> <b> || defined(config_s3c2440)</b>

<b>(</b> <b>2</b> <b>)</b> <b>/include/s3c24x0.h</b> <b>:檔案的第</b> <b>85</b> <b>、</b> <b>95</b> <b>、</b> <b>99</b> <b>、</b> <b>110</b> <b>、</b> <b>148</b> <b>、</b> <b>404</b> <b>行:</b> <b>/*</b> <b>一些關于</b> <b>s3c2440</b> <b>寄存器的結構體</b> <b>*/</b>

<b>#if defined(config_s3c2410)</b> <b></b> <b>|| defined (config_s3c2440)</b>

<b>(</b> <b>3</b> <b>)</b> <b>/cpu/arm920t/s3c24x0/interrupts.c</b> <b>檔案的第</b> <b>33</b> <b>行:</b> <b>/*</b> <b>主要把一些頭檔案包含進去</b> <b>*/</b>

<b>#if defined(config_s3c2400) || defined (config_s3c2410) || defined (config_trab)</b> <b></b> <b>|| defined (config_s3c2440)</b>

<b>第</b> <b>38</b> <b>行:</b>

<b>#elif defined(config_s3c2410)</b> <b></b> <b>|| defined (config_s3c2440)</b>

<b>(</b> <b>4</b> <b>)</b> <b>/cpu/arm920t/s3c24x0/serial.c</b> <b>檔案的第</b> <b>22</b> <b>行:</b> <b>/*</b> <b>主要把一些頭檔案包含進去</b> <b>*/</b>

<b>第</b> <b>26</b> <b>行:</b>

<b>(</b> <b>5</b> <b>)</b> <b>/cpu/arm920t/s3c24x0/speed.c</b> <b>檔案的第</b> <b>33</b> <b>行:</b>

<b>#if defined(config_s3c2400) || defined (config_s3c2410) || defined (config_trab)</b> <b> || defined (config_s3c2440)</b>

<b>第</b> <b>37</b> <b>行:</b>

<b>順便修改源代碼,以比對</b> <b>s3c2440</b> <b>:</b>

<b>static ulong get_pllclk(int pllreg)</b> <b></b>

<b>   ......</b> <b></b>

<b>    m = ((r &amp; 0xff000) &gt;&gt; 12) + 8;</b> <b></b>

<b>    p = ((r &amp; 0x003f0) &gt;&gt; 4) + 2;</b> <b></b>

<b>    s = r &amp; 0x3;</b> <b></b>

<b>//qljt </b> <b> /*</b> <b>這兩個</b> <b>pll</b> <b>的算法參見</b> <b>s3c2440datasheet</b> <b>的</b> <b>254</b> <b>頁</b> <b>*/</b> <b></b>

<b>#if defined(config_s3c2440)</b> <b></b>

<b>   if (pllreg == mpll)</b> <b></b>

<b>    return((config_sys_clk_freq * m * 2) / (p &lt;&lt; s)); </b> <b>/* config_sys_clk_freq </b> <b>在</b> <b>qljt2440.h</b> <b>中定義</b> <b>*/</b> <b></b>

<b>    else if (pllreg == upll)</b> <b></b>

<b>//qljt</b> <b></b>

<b>    </b> <b>return((config_sys_clk_freq * m) / (p &lt;&lt; s));</b> <b></b>

<b>/* return fclk frequency */</b>

<b>ulong get_fclk(void)</b>

<b>{</b>

<b>    return(get_pllclk(mpll));</b>

<b>/* return hclk frequency */</b>

<b>ulong get_hclk(void)</b>

<b>    s3c24x0_clock_power * const clk_power = s3c24x0_getbase_clock_power();</b>

<b> /*</b> <b>看看</b> <b>s3c2410</b> <b>與</b> <b>s3c2440</b> <b>的</b> <b>datasheet</b> <b>就知道</b> <b>s3c2440</b> <b>的</b> <b>hclk</b> <b>可選擇的值多很多</b> <b>*/</b>

<b>  </b> <b>if (clk_power-&gt;clkdivn &amp; 0x6)    </b>

<b>  {</b> <b>/*</b> <b>這裡注意:編譯的時候發現</b> <b>clkdivn </b> <b>,這個将會在</b> <b>12</b> <b>節解決</b> <b>*/</b>

<b>       if ((clk_power-&gt;clkdivn &amp; 0x6)==2)        return(get_fclk()/2);</b>

<b>if ((clk_power-&gt;clkdivn &amp; 0x6)==6)        return((clk_power-&gt;camdivn &amp; 0x100) ? get_fclk()/6 : get_fclk()/3);        </b> <b> /*</b> <b>注意這裡的</b> <b>camdivn</b> <b>還沒有被定義,在</b> <b>/include/s3c24x0.h</b> <b>中定義 */</b>

<b>      if ((clk_power-&gt;clkdivn &amp; 0x6)==4)        return((clk_power-&gt;camdivn &amp; 0x200) ? get_fclk()/8 : get_fclk()/4);         </b>

<b>        return(get_fclk());</b>

<b> } </b>

<b> else   {</b>

<b>     }</b>

//    return((clk_power-&gt;clkdivn &amp; 0x2) ? get_fclk()/2 : get_fclk());

<b>(</b> <b>6</b> <b>)</b> <b>/cpu/arm920t/s3c24x0/usb_ohci.c</b> <b>檔案的第</b> <b>45</b> <b>行:</b>

<b>#elif defined(config_s3c2410)</b> <b></b> <b>|| defined(config_s3c2440)</b>

<b>(</b> <b>7</b> <b>)</b> <b>drivers/rtc/s3c24x0_rtc.c</b> <b>檔案的第</b> <b>35</b> <b>行:</b>

<b>#elif defined(config_s3c2410)</b> <b></b> <b>|| defined(config_s3c2440)</b> <b> </b>

<b>(</b> <b>8</b> <b>)在檔案中添加</b> <b>“defined(config_qljt2440)”</b> <b>,使得原來</b> <b>sbc2410x</b> <b>開發闆的代碼可以編譯進來,</b>

<b>/cpu/arm920t/s3c24x0/interrupts.c</b> <b>檔案的第</b> <b>181</b> <b>行:</b> <b>  </b>

<b>   </b> <b>#elif defined(config_sbc2410x) || </b>

<b>      defined(config_smdk2410) || </b>

<b>      defined(config_vcma9) || </b> <b>defined(config_qljt2440)</b>

<b>    tbclk = cfg_hz;   </b> <b>/*</b> <b>對于</b> <b>cfg_hz </b> <b>的值,結合</b> <b>uboot</b> <b>的說明和</b> <b>s3c2440</b> <b>的</b> <b>datasheet</b> <b>就比較容易了解</b> <b>*/</b>

<b>(</b> <b>9</b> <b>)</b> <b>/cpu/arm920t/s3c24x0/usb.c</b> <b>檔案的第</b> <b>31</b> <b>行:</b>

#elif defined(config_s3c2410) || defined (config_s3c2440)

<b>(</b> <b>10</b> <b>)</b> <b>/cpu/arm920t/s3c24x0/i2c.c</b> <b>檔案的第</b> <b>35</b> <b>行:</b> <b></b>

<b>第</b> <b>66</b> <b>、</b> <b>85</b> <b>、</b> <b>142</b> <b>、</b> <b>150</b> <b>、</b> <b>174</b> <b>行:</b>

将“#ifdef config_s3c2410”改為

#if defined(config_s3c2410) || defined (config_s3c2440)

<b>(</b> <b>11</b> <b>)</b> <b>drivers/usb/usb_ohci.c</b> <b>檔案的第</b> <b>68</b> <b>行附近:</b>

#if defined(config_arm920t) ||

    defined(config_s3c2400) ||

    defined(config_s3c2410) ||

    defined(config_s3c2440) ||

    defined(config_440ep) ||

    defined(config_pci_ohci) ||

    defined(config_mpc5200)

<b>11.</b> <b>在/include/s3c24x0.h中加入2440 的nand flash</b> <b>寄存器定義和camdivn定義:</b>

typedef struct {

         s3c24x0_reg32   locktime;

         s3c24x0_reg32   mpllcon;

         s3c24x0_reg32   upllcon;

         s3c24x0_reg32   clkcon;

         s3c24x0_reg32   clkslow;

         s3c24x0_reg32   clkdivn;

         s3c24x0_reg32   camdivn;

} s3c24x0_clock_power;

#if defined(config_s3c2410)  // <b>2440 </b> <b>的nand flash</b> <b>寄存器</b>

         s3c24x0_reg32   nfconf;

         s3c24x0_reg32   nfcmd;

         s3c24x0_reg32   nfaddr;

         s3c24x0_reg32   nfdata;

         s3c24x0_reg32   nfstat;

         s3c24x0_reg32   nfecc;

} s3c2410_nand;

#if defined (config_s3c2440)

         s3c24x0_reg32   nfcont;

         s3c24x0_reg32   nfmecc0;

         s3c24x0_reg32   nfmecc1;

         s3c24x0_reg32   nfsecc;

         s3c24x0_reg32   nfestat0;

         s3c24x0_reg32   nfestat1;

12. 修改/lib_arm中的board.c。 <b></b>

#include &lt;common.h&gt;

#include &lt;command.h&gt;

#include &lt;malloc.h&gt;

#include &lt;devices.h&gt;

#include &lt;version.h&gt;

#include &lt;net.h&gt;

#include &lt;s3c2410.h&gt; 

13. 修改common/env_nand.c

#ifdef config_inferno

#error config_inferno not supported yet

int nand_legacy_rw (struct nand_chip* nand, int cmd,

        size_t start, size_t len,

        size_t * retlen, u_char * buf);

extern struct nand_chip nand_dev_desc[cfg_max_nand_device];

extern int nand_legacy_erase(struct nand_chip *nand, size_t ofs, size_t len, int clean);

/* info for nand chips, defined in drivers/nand/nand.c */

nand_info_t nand_info[cfg_max_nand_device];

#else /* ! cfg_env_offset_redund */

int saveenv(void)

    size_t total;

    int ret = 0;

    nand_erase_options_t nand_erase_options;

    nand_erase_options.length = cfg_env_range;

    nand_erase_options.quiet = 0;

    nand_erase_options.jffs2 = 0;

    nand_erase_options.scrub = 0;

    nand_erase_options.offset = cfg_env_offset;

    if (cfg_env_range &lt; cfg_env_size)

        return 1;

    puts ("erasing nand...n");

/*在248行附近*/

//    if (nand_erase_opts(&amp;nand_info[0], &amp;nand_erase_options))

  if (nand_legacy_erase(nand_dev_desc + 0, cfg_env_offset, cfg_env_size, 0))           

    return 1;

    puts ("writing to nand... ");

    total = cfg_env_size;

/*在254行附近*/

//    if (writeenv(cfg_env_offset, (u_char *) env_ptr)) {

//        puts("failed!n");

//        return 1;

//    }

ret = nand_legacy_rw(nand_dev_desc + 0,0x00 | 0x02, cfg_env_offset, cfg_env_size,&amp;total, (u_char*)env_ptr);

 if (ret || total != cfg_env_size)

        return 1;

    puts ("donen");

    return ret;

.......

 * the legacy nand code saved the environment in the first nand device i.e.,

 * nand_dev_desc + 0. this is also the behaviour using the new nand code.

 */

void env_relocate_spec (void)

#if !defined(env_is_embedded)

    int ret;

/*在360行附近*/

//    ret = readenv(cfg_env_offset, (u_char *) env_ptr);

     ret = nand_legacy_rw(nand_dev_desc + 0, 0x01 | 0x02, cfg_env_offset,cfg_env_size, &amp;total, (u_char*)env_ptr);/*edited by yaoyi 20090314,1.3.4是先進入到readenv,而非直接調用nand_legacy_rw。 是以幹脆就不用到readenv了,直接注釋掉,添加以上代碼 */

    if (ret || total != cfg_env_size)

        return use_default();

    if (crc32(0, env_ptr-&gt;data, env_size) != env_ptr-&gt;crc)

#endif /* ! env_is_embedded */

u-boot運作至第二階段進入start_armboot()函數。其中nand_init()函數 是對nand flash的最初初始化函數。nand_init()函數在兩個檔案中實作。其調用與cfg_nand_legacy宏有關,如果沒有定義這個宏,系統調 用 drivers/nand/nand.c中的nand_init();否則調用自己在board/qljt/qljt2440/qljt2440.c中的 nand_init()函數。這裡我選擇第二種方式。*/

14. 修改include/nand.h <b></b>

//#ifndef cfg_nand_legacy

#include &lt;linux/mtd/compat.h&gt;

#include &lt;linux/mtd/mtd.h&gt;

#include &lt;linux/mtd/nand.h&gt;

//#endif /* !cfg_nand_legacy */

<b>9</b> <b>、在</b> <b>include/linux/mtd/nand_ids.h</b> <b>的結構體</b> <b>nand_flash_ids</b> <b>加入</b> <b></b> <b>/*</b> <b>至于這個結構體的值怎麼得來,有待研究</b> <b>*/</b>

<b>static struct nand_flash_dev nand_flash_ids[] = {</b>

<b>......</b> <b>/*</b> <b>結構體</b> <b>nand_flash_dev </b> <b>在</b> <b>doc2000.h</b> <b>中定義</b> <b>*/</b>

<b>/*</b> <b>廠家</b> <b></b> <b>型号,生産商編号,本子產品的編号,</b>總共容納位址的位數,存儲頁位元組數是否為256 <b></b> <b>,</b>位址需要多少位元組數減一(行列位址總共) <b></b> <b>,擦除</b> <b>1</b> <b>個</b> <b>block</b> <b>的大小,</b>是否為16位總線 <b>*/</b> <b></b>

<b>    {"samsung km29n16000",nand_mfr_samsung, 0x64, 21, 1, 2, 0x1000, 0}, </b> <b></b>

<b>    </b> <b>{"samsung k9f1208u0b",  nand_mfr_samsung, 0x76, 26, 0, 3, 0x4000, 0},</b> <b></b>

<b>    {"samsung unknown 4mb", nand_mfr_samsung, 0x6b, 22, 0, 2, 0x2000, 0},</b> <b></b>

<b>};</b>

/*下面說說上面結構體的 8個參數是怎麼得出來的,以便日後再次移植的時候會更換 nand flash*/

1.“廠家 型号”:這個從 nand flash的 datasheet就可以直接找到了吧。

2. 生産商的編号:也就是 datasheet裡面的 maker code,它也同時被存放在 nand flash裡面的 id(nand flash應該有一個讀 id指令的 )資訊裡面)。

3. 本子產品的編号:也就是 datasheet裡面的 device code,跟 maker code一樣它也被放到 id資訊裡面。

4. 總共容納的位址位數:也就是有效的位址位數。針對于本 flash(k9f1208u0m)可以參考它的 datasheet第 7頁。

5. 一頁所存儲的位元組數是否為 256個:針對于本 flash(k9f1208u0m)可以參考它的 datasheet第 7頁。

6. 位址需要多少位元組數減一 (行列位址總共 ):舉個例子可能更容易明白,第 4點中可以知道本 flash(k9f1208u0m)有 26位,而對本 flash位址的寫入每次隻能寫 8位,是以至少要寫 4次才能把 26位位址寫入本 flash, 4次的寫入針對于程式設計來說就是 [0:3],是以本 falsh相對于該結構體的該變量的值是 3.

7. 擦除 1個 block的大小:簡單來說就是 1個 block的大小,本 flash 1block=32 pages, 1 page=512 bytes,是以 1 block=512x32=16 k-bytes,也就是 <b>0x4000</b> <b>。</b>

8. 是否為 16位總線:本 flash位址和資料總線共用,都是 8位的,是以上面值為 0

<b>15. </b> <b>修改</b> <b>/lib_arm</b> <b>中的</b> <b>board.c</b> <b>。添加幾個</b> <b>debug</b> <b>資訊</b> <b>  </b> <b>(這一步可以不用修改)</b>

static int display_banner (void)

{       

         s3c24x0_gpio * const gpio = s3c24x0_getbase_gpio();

         gpio-&gt;gpfdat = 0x8f;   //qljtninja

// 在序列槽初始化和console 初始化完成,序列槽輸出資訊之前,led1 、led2 、led3 會亮起!

    printf ("nn%snn", version_string);

    debug ("u-boot code: %08lx -&gt; %08lx   bss: -&gt; %08lxn",

           _armboot_start, _bss_start, _bss_end);

    printf ("u-boot code: %08lx -&gt; %08lx   bss: -&gt; %08lxn",     //qljt

        _armboot_start, _bss_start, _bss_end);       //qljt

#ifdef config_modem_support

    debug ("modem support enabledn");

#ifdef config_use_irq

    debug ("irq stack: %08lxn", irq_stack_start);

    debug ("fiq stack: %08lxn", fiq_stack_start);

    return (0);

void start_armboot (void)

         init_fnc_t **init_fnc_ptr;

         char *s;

#ifndef cfg_no_flash

         ulong size;

#if defined(config_vfd) || defined(config_lcd)

         unsigned long addr;

         gpio-&gt;gpfdat = 0x7f;  //qljtninja

// 在進入指令提示符之前,四個led 會同時亮起!

         /* main_loop() can return to retry autoboot, if so just run it again. */

         for (;;) {

                   main_loop ();

         }

         /* notreached - no way out of command loop except booting */

<b>16. </b> <b>裁減flash的支援 (這一步也可以不執行)</b>

(1)在board/qljt/qljt2440/flash.c的頭部加上:#if 0,尾部加上:#endif

(2)在include/configs/qq2440.h加上:

#undef config_cmd_flash

#undef config_cmd_imls

….

#define cfg_no_flash  1

(3)在common/cmd_bootm.c的”#include”語句後加上

#ifdef config_cmd_imls

<b>附錄:</b>

<b>一.</b>

<b>u-boot</b> <b>的指令預設配置存放在/include/config_cmd_default.h裡,可以修改該檔案或者在qq2440.h裡添加#undef裡裁減不需要的内容</b>

<b>二.</b>

1.在 u-boot-1.3.2前 (不含 u-boot-1.3.2)nand_init函數的調用關系,它的調用是被“ config_commands&amp;

cfg_cmd_nand”和“ cfg_nand_legacy”控制的, 1:表示該值為真, 0:表示該值為假

config_commands&amp;

cfg_cmd_nand

cfg_nand_legacy

/drivers/mtd/nand/nand.c中的

nand_init()函數

/board/qljt/qljt2440/qljt2440.c中的 nand_init()函數

1

2.在 u-boot-1.3.2後 (含 u-boot-1.3.2)nand_init函數的調用關系,它的調用是被“ config_cmd_nand”和“ cfg_nand_legacy”控制的, 1:表示該值為真, 0:表示該值為假

config_cmd_nand

繼續閱讀