天天看點

fl2440——u-boot的移植1、u-boot移植前期準備2、開發闆建立與編譯測試3、u-boot移植4、添加支援從nandflash啟動代碼 5、添加DM9000網絡支援

1、u-boot移植前期準備

       1.1建立開發闆目錄結構

       我建立了fl2440這個檔案夾,除了bootloader的u-boot之外,以後需要制作的Linux核心,根檔案系統,相關的驅動,第三方應用,自己寫的程式等,都放入對應目錄下,便于管理。

[[email protected] ~]$ cd fl2440/
[[email protected] fl2440]$ ls
3rdparty bootloader  driver  kernel mkdir  program  rootfs
[[email protected] fl2440]$ ll
total 28
drwxrwxr-x 2 tangbin tangbin 4096 Oct 1615:28 3rdparty
drwxrwxr-x 4 tangbin tangbin 4096Mar  9 19:57 bootloader
drwxrwxr-x 3 tangbin tangbin 4096 Mar 1620:22 driver
drwxrwxr-x 3 tangbin tangbin 4096 Mar 1620:10 kernel
drwxrwxr-x 2 tangbin tangbin 4096 Oct 1615:28 mkdir
drwxrwxr-x 2 tangbin tangbin 4096 Oct 1615:28 program
drwxrwxr-x 2 tangbin tangbin 4096 Oct 1615:28 rootfs
           

1.2準備好u-boot源碼包

可以到u-boot的FTP上直接下載下傳(ftp://ftp.denx.de/pub/u-boot/u-boot-2010.09.tar.bz2),下載下傳完成後得到一個壓縮包。

将其解壓,得到如下檔案:

[[email protected] bootloader]$ tar -xjf u-boot-2010.09.tar.bz2
[[email protected] bootloader]$ ls
u-boot-2010.09   u-boot-2010.09.tar.bz2
           
fl2440——u-boot的移植1、u-boot移植前期準備2、開發闆建立與編譯測試3、u-boot移植4、添加支援從nandflash啟動代碼 5、添加DM9000網絡支援

2、開發闆建立與編譯測試

       2.1u-boot 源碼中添加 fl2440 開發闆

依次執行:cd board
       mkdir -p lingyun/fl2440         #建立以後我們要用的檔案夾,-p是指一次性建立多層次的目錄
       #     FL2440開發闆移植u-boot以smdk2410為主機闆進行移植,是以用smdk2410建立配置檔案。
       cp samsung/smdk2410/* lingyun/fl2440/   
       cd lingyun/fl2440/
       mv smdk2410.c fl2440.c
       修改Makefile
       vim Makefile
       -COBJS :=smdk2410.o flash.o
       +COBJS := fl2440.o flash.o                   #将原來的smdk2410.o改成fl2440.o
       cd ../../../
       cp include/configs/smdk2410.hinclude/configs/fl2440.h
[[email protected] u-boot-2010.09bk]$ vim boards.cfg
           

在smdk2410下添加一條代碼:

fl2440——u-boot的移植1、u-boot移植前期準備2、開發闆建立與編譯測試3、u-boot移植4、添加支援從nandflash啟動代碼 5、添加DM9000網絡支援
fl2440——u-boot的移植1、u-boot移植前期準備2、開發闆建立與編譯測試3、u-boot移植4、添加支援從nandflash啟動代碼 5、添加DM9000網絡支援

這一行中的小“-”代表u-boot下的board目錄,是以,如果你是在board下建立fl2440檔案夾,就用“-”,如果你在board下建立了其他的檔案下,再建立的fl2440目錄,就要填寫那個目錄名

[[email protected] u-boot-2010.09bk]$ vim Makefile
           
fl2440——u-boot的移植1、u-boot移植前期準備2、開發闆建立與編譯測試3、u-boot移植4、添加支援從nandflash啟動代碼 5、添加DM9000網絡支援
fl2440——u-boot的移植1、u-boot移植前期準備2、開發闆建立與編譯測試3、u-boot移植4、添加支援從nandflash啟動代碼 5、添加DM9000網絡支援

添加交叉編譯器。

接下來執行:

make fl2440_config
make
           
fl2440——u-boot的移植1、u-boot移植前期準備2、開發闆建立與編譯測試3、u-boot移植4、添加支援從nandflash啟動代碼 5、添加DM9000網絡支援
fl2440——u-boot的移植1、u-boot移植前期準備2、開發闆建立與編譯測試3、u-boot移植4、添加支援從nandflash啟動代碼 5、添加DM9000網絡支援

這時候編譯出來的 u-boot.bin 就是要燒到開發闆上的 u-boot 檔案,但這個代碼是基于smdk2410 開發闆的,我們并沒有對這個代碼作任何的修改,是以這個 bin 檔案隻能在smdk2410 這個開發闆上跑。

如果想運作在 FL2440 這個開發闆上,接下來我們就要開始對源代碼進行修改。

       注:make fl2440_config(make xxx_config)這個指令的作用。因為在執行make之前,先要執行make $(board)_config 對工程進行配置,以确定特定于目标闆的各個子目錄和頭檔案。

$(board)_config:是makefile 中的一個僞目标,它傳入指定的CPU,ARCH,BOARD,SOC參數去執行mkconfig腳本。

這個腳本的主要功能在于連接配接目标闆平台相關的頭檔案夾,生成config.h檔案包含闆子的配置頭檔案。

使得makefile能根據目标闆的這些參數去編譯正确的平台相關的子目錄。

以fl2440闆為例,執行 make fl2410_config

3、u-boot移植

       3.1概述

我們的u-boot是從Nand flash啟動的,以此做分析。

fl2440——u-boot的移植1、u-boot移植前期準備2、開發闆建立與編譯測試3、u-boot移植4、添加支援從nandflash啟動代碼 5、添加DM9000網絡支援
fl2440——u-boot的移植1、u-boot移植前期準備2、開發闆建立與編譯測試3、u-boot移植4、添加支援從nandflash啟動代碼 5、添加DM9000網絡支援

前面已經提到了前期準備工作,下面就是對u-boot啟動代碼的修改了。

主要修改start.S、lowlevel_init.S,硬體初始化:設定異常向量—>cpu進入SVC模式—>設定控制寄存器位址—>關看門狗—>關中斷—>設定時鐘寄存器—>執行cpu_init_crit關閉MMU和cache。

接着添加DM9000網卡的支援,最後是Nand flash啟動代碼修改,支援nandflash啟動。

       3.2Start.S分析

       Start.S的執行流程大緻為:

1.硬體初始化:

進入svc模式;關閉watch dog;屏蔽所有IRQ掩碼;設定時鐘頻率FCLK、HCLK、PCLK;清I/D cache;禁止MMU和CACHE;配置memory control;

2.重定位:

如果目前代碼不在連接配接指定的位址上(對于s3c2440是0x33f80000)則需要把u-boot從目前位置拷貝到RAM指定位置中;

3.建立堆棧,堆棧是進入C函數前必須初始化的。

4.清.bss區。

5.跳到start_armboot函數中執行。(lib_arm/board.c)

3.3 Start.S的修改

1.将用于LED跳轉的兩行代碼注釋,我們不在這裡做程式跳轉:

fl2440——u-boot的移植1、u-boot移植前期準備2、開發闆建立與編譯測試3、u-boot移植4、添加支援從nandflash啟動代碼 5、添加DM9000網絡支援
fl2440——u-boot的移植1、u-boot移植前期準備2、開發闆建立與編譯測試3、u-boot移植4、添加支援從nandflash啟動代碼 5、添加DM9000網絡支援

2.删除從120行到169行,這些代碼是用于定義特殊寄存器和屏蔽中斷的,我們在後面統一定義:

fl2440——u-boot的移植1、u-boot移植前期準備2、開發闆建立與編譯測試3、u-boot移植4、添加支援從nandflash啟動代碼 5、添加DM9000網絡支援
fl2440——u-boot的移植1、u-boot移植前期準備2、開發闆建立與編譯測試3、u-boot移植4、添加支援從nandflash啟動代碼 5、添加DM9000網絡支援
fl2440——u-boot的移植1、u-boot移植前期準備2、開發闆建立與編譯測試3、u-boot移植4、添加支援從nandflash啟動代碼 5、添加DM9000網絡支援
fl2440——u-boot的移植1、u-boot移植前期準備2、開發闆建立與編譯測試3、u-boot移植4、添加支援從nandflash啟動代碼 5、添加DM9000網絡支援
fl2440——u-boot的移植1、u-boot移植前期準備2、開發闆建立與編譯測試3、u-boot移植4、添加支援從nandflash啟動代碼 5、添加DM9000網絡支援
vim arch/arm/cpu/arm920t/start.S
           

打開star.S後添加如下代碼:以下宏定義設定了s3c2440中斷、時鐘、nandflash控制器、看門狗、GPIO的基位址,具體詳見s3c2440開發闆的晶片手冊。

#define S3C24X0_INTERRUPT_BASE      0x4A000000
#define S3C24X0_CLOCK_POWER_BASE    0x4C000000
#define S3C2410_NAND_BASE           0x4E000000
#define S3C24X0_WATCHDOG_BASE       0x53000000
#define S3C24X0_GPIO_BASE           0x56000000
 
#define INTMSK_OFFSET               0x08
#define INTSUBMSK_OFFSET            0x1c
#define MPLLCON_OFFSET              0x04
#define CLKDIVN_OFFSET              0x14
#define NFCONF_OFFSET               0x00
#define NFCONT_OFFSET               0x04
#define NFCMD_OFFSET                0x08
#define NFSTAT_OFFSET               0x20
 
#define MDIV_405                    0x7f << 12
#define PSDIV_405                   0x21
#define MDIV_200                    0xa1 << 12
#define PSDIV_200                   0x31
           

接着上面的宏定義下,繼續添加關閉看門狗、屏蔽中斷、設定時鐘、初始化nandflash控制器代碼:

/****** Disable Watchdog ******/
    ldr r0, =S3C24X0_WATCHDOG_BASE
    mov r1, #0
    str r1, [r0]
 
/****** Disable interrupt by mask all IRQmask ******/
    ldr r0, =S3C24X0_INTERRUPT_BASE
    mvn r1, #0x0
    str r1, [r0, #INTMSK_OFFSET]
    str r1, [r0, #INTSUBMSK_OFFSET]
 
/****** Initialize System Clock,FCLK:HCLK:PCLK = 1:4:8,default FCLK is 120MHz ******/
    ldr r0, =S3C24X0_CLOCK_POWER_BASE
    mov r1, #5
    str r1, [r0, #CLKDIVN_OFFSET]
 
    mrc p15, 0, r1, c1, c0, 0
    orr r1, r1, #0xc0000000
    mcr p15, 0, r1, c1, c0, 0
 
    mov r2, #MDIV_405
    add r2, r2, #PSDIV_405
    str r2, [r0, #MPLLCON_OFFSET]
 
/***** Initialize Nandflash controller******/
    mov r1, #S3C2410_NAND_BASE
     ldr r2, =((7<<12)|(7<<8)|(7<<4)|(0<<0) )
    str r2, [r1, #NFCONF_OFFSET]
 
    ldr r2, =( (1<<4)|(0<<1)|(1<<0) )   @ Active low CE controller
    str r2, [r1, #NFCONT_OFFSET]
 
    ldr r2, =(0x6)                     @ RnB Clear
    str r2, [r1, #NFSTAT_OFFSET]
 
    mov r2, #0xff                      @ Reset Nandflash
    strb    r2, [r1, #NFCMD_OFFSET]
 
    mov r3, #0       @ Delay for awhile
delay:
    add r3, r3, #0x1
    cmp r3, #0xa
    blt delay
 
wait:
    ldr r2, [r1, #NFSTAT_OFFSET]  @wait ready
    tst r2, #0x4
    beq wait
           

然後執行cpu_init_crit,關閉MMU和CACHE,再跳轉到board/fl2440/lowlevel_init.S中初始化RAM控制器:

fl2440——u-boot的移植1、u-boot移植前期準備2、開發闆建立與編譯測試3、u-boot移植4、添加支援從nandflash啟動代碼 5、添加DM9000網絡支援
fl2440——u-boot的移植1、u-boot移植前期準備2、開發闆建立與編譯測試3、u-boot移植4、添加支援從nandflash啟動代碼 5、添加DM9000網絡支援
fl2440——u-boot的移植1、u-boot移植前期準備2、開發闆建立與編譯測試3、u-boot移植4、添加支援從nandflash啟動代碼 5、添加DM9000網絡支援
fl2440——u-boot的移植1、u-boot移植前期準備2、開發闆建立與編譯測試3、u-boot移植4、添加支援從nandflash啟動代碼 5、添加DM9000網絡支援

3.4lowlevel_init.S的修改

修改RAM控制每個BANK的位址宏定義和參數設定,修改如下代碼,粗體部分為在原先代碼基礎上修改後的:

#define BWSCON  0x48000000
 
/* BWSCON */
#define DW8         	(0x0)
#define DW16            (0x1)
#define DW32            (0x2)
#define WAIT            (0x1<<2)
#define UBLB            (0x1<<3)
 
 #define B1_BWSCON       (DW16)
 #define B2_BWSCON       (DW16) #define B3_BWSCON       (DW16 + WAIT + UBLB)
 #define B4_BWSCON       (DW16)
 #define B5_BWSCON       (DW16)
 #define B6_BWSCON       (DW32)
 #define B7_BWSCON       (DW32)
 
 /*BANK0CON */
 #define B0_Tacs         0x0 /* 0clk */
 #define B0_Tcos         0x0 /* 0clk */
 #define B0_Tacc         0x7 /* 14clk */
 #define B0_Tcoh         0x0 /* 0clk */
 #define B0_Tah          0x0 /*  0clk */
 #define B0_Tacp         0x0
 #define B0_PMC          0x0 /* normal */
 
 /*BANK1CON */
 #define B1_Tacs         0x0 /*  0clk */
 #define B1_Tcos         0x0 /* 0clk */
 #define B1_Tacc         0x7 /* 14clk */
 #define B1_Tcoh         0x0 /* 0clk */
 #define B1_Tah          0x0 /*  0clk */
 #define B1_Tacp         0x0
 #define B1_PMC         0x0
 
 #define B2_Tacs         0x0
 #define B2_Tcos         0x0
 #define B2_Tacc         0x7
 #define B2_Tcoh         0x0
 #define B2_Tah          0x0
 #define B2_Tacp         0x0
 #define B2_PMC          0x0
 
 #define B3_Tacs         0xc /*  0clk */
 #define B3_Tcos         0x7 /* 4clk */
 #define B3_Tacc         0xf /* 14clk */
 #define B3_Tcoh         0x1 /* 1clk */
 #define B3_Tah          0x0 /*  0clk */
 #define B3_Tacp         0x0 /* 6clk */
 #define B3_PMC          0x0 /* normal */
 #define B4_Tacs         0x0 /* 0clk */
 #define B4_Tcos         0x0 /* 0clk */
 #define B4_Tacc         0x7 /* 14clk */
 #define B4_Tcoh         0x0 /* 0clk */
 #define B4_Tah          0x0 /*  0clk */
 #define B4_Tacp         0x0
 #define B4_PMC          0x0 /* normal */
 
 #define B5_Tacs        0xc /*  0clk */
 #define B5_Tcos         0x7 /* 0clk */
 #define B5_Tacc         0xf /* 14clk */
 #define B5_Tcoh         0x1 /* 0clk */
 #define B5_Tah          0x0 /*  0clk */
 #define B5_Tacp         0x0
 #define B5_PMC          0x0 /* normal */
 
 #define B6_MT           0x3 /* SDRAM */
 #define B6_Trcd          0x1
 #define B6_SCAN        0x1 /* 9bit */
 
 #define B7_MT           0x3 /* SDRAM */
 #define B7_Trcd          0x1 /* 3clk */
 #define B7_SCAN        0x1 /* 9bit */
 
修改初始化參數:
 /* REFRESH parameter */
 #define REFEN           0x1 /* Refresh enable */
 #define TREFMD         0x0 /* CBR(CAS before RAS)/Autorefresh */
 #define Trp         0x2 /* 4clk */
 #define Trc         0x3 /* 7clk */
 #define Tchr            0x2 /* 3clk */
 #define REFCNT          1012    /* period=15.6us, HCLK=60Mhz,(2048+1-15.6*60) */
修改166行左右:
SMRDATA:(這部分定義的是BWSCON的13個寄存器的值)
     .word 0x32         .word 0x32改為:  .word 0xb2
     .word 0x30
     .word 0x30
           

3.5 修改配置支援s3c2440

修改include/asm/arch-s3c24x0/s3c24x0.h

#if defined(CONFIG_S3C2410)修改為#ifdefined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)
           

修改nandflash的寄存器定義,修改s3c2410_nand結構體為如下:

#if defined (CONFIG_S3C2440)
/*  NAND FLASH (see S3C2440 manual chapter 6) */
struct s3c2410_nand {
   u32 NFCONF;
   u32 NFCONT;
   u32 NFCMD;
   u32 NFADDR;
   u32 NFDATA;
   u32 NFMECCD0;
   u32 NFMECCD1;
   u32 NFSECCD;
   u32 NFSTAT;
   u32 NFESTAT0;
   u32 NFESTAT1;
   u32 NFMECC0;               
   u32 NFMECC1;
   u32 NFSECC;
   u32 NFSBLK;
   u32 NFEBLK;
};#endif
           

修改s3c24x0_clock_power結構體

struct s3c24x0_clock_power {
u32 LOCKTIME;
u32 MPLLCON;
   u32 UPLLCON;
   u32 CLKCON;
   u32 CLKSLOW;
   u32 CLKDIVN;
#if defined (CONFIG_S3C2440)
   u32 CAMDIVN;
#endif
}
           

修改include/asm/arch/s3c24x0_cpu.h,補充對s3c2440的支援

檔案23行,修改#elif defined (CONFIG_S3C2410)為
#elif defined (CONFIG_S3C2410) ||(CONFIG_S3C2440)
           

修改arch/arm/cpu/arm920t/s3c24x0/timer.c檔案

184行添加支援s3c2440
 defined(CONFIG_S3C2440) || \
           

修改arch/arm/cpu/arm920t/s3c24x0/speed.c

66行添加
#if defined(CONFIG_S3C2440)
  if(pllreg == MPLL)
       return((CONFIG_SYS_CLK_FREQ * m * 2) / (p << s));
   else if(pllreg == UPLL)
#endif
           

修改get_HCLK()函數如下:

ulong get_HCLK(void)
{
   struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power();
 
   //return (readl(&clk_power->CLKDIVN) & 2) ? get_FCLK() / 2 :get_FCLK();
#if defined(CONFIG_S3C2440) /* Modify byhurryliu*/
       if (readl(&clk_power->CLKDIVN) & 0x6)
       {
            if((readl(&clk_power->CLKDIVN) & 0x6)==2)
                      return(get_FCLK()/2);
      if ((readl(&clk_power->CLKDIVN) & 0x6)==6)
              return((readl(&clk_power->CAMDIVN) & 0x100) ? get_FCLK()/6 :get_FCLK()/3);
          if ((readl(&clk_power->CLKDIVN) & 0x6)==4)
                 return((readl(&clk_power->CAMDIVN) & 0x200) ? get_FCLK()/8 :get_FCLK()/4);
             return(get_FCLK());
       }
       else
              return(get_FCLK());
#else
             return((readl(&clk_power->CLKDIVN)& 0x2) ? get_FCLK()/2 : get_FCLK());
#endif /* Modify end*/
}
           

修改include/configs/fl2440.h

38行添加#define CONFIG_S3C2440     1 
           

4、添加支援從nandflash啟動代碼

4.1nandflash啟動代碼添加

vim arch/arm/cpu/arm920t/start.S

       添加支援nandflash啟動代碼:

NANDFLASH_BOOT:
     /*Get ready to call C functions fornand_read_ll() */
     ldr sp, DW_STACK_START  @ setup stack pointer
     mov fp, #0 @ no previous frame, so fp=0
 
     /* Read u-boot from Nandflash to SDRAMaddress $TEXT_BASE */
     ldr r0, =TEXT_BASE     /*nand_read_ll() 1st argument*/
     mov r1, #0x0           /*nand_read_ll() 2nd argument*/
     mov r2, #CONFIG_UBOOT_LENGTH  /*nand_read_ll() 3rd argument*/
     bl nand_read_ll
 
     tst r0, #0x0           /*Check nand_read_ll() returnvalue*/
     bne infinite_loop     /*nand_read_ll() not return 0, then gotodead loop*/
 
nand_read_ok:
     /*Then verify the read data validation*/
     mov r0, #0             /*The first 4K data in internalSRAM*/
     ldr r1, =TEXT_BASE     /*The first 4K data read from Nandflash inSDRAM*/
     mov r2, #0x400         /*The compare data length*/
 
compare_next_byte:
     ldr r3, [r0], #4
     ldr r4, [r1], #4
     teq r3, r4
     bne infinite_loop
 
     subs r2, r2, #4
     beq stack_setup
 
     bne compare_next_byte
 
infinite_loop:
     b  infinite_loop
           

注意:nandflash啟動代碼中的nand_read_ll()函數,nand_read_ll函數的作用是在NAND Flash中搬運U-Boot到RAM,該函數在board/samsung/mini2440/nand_read.c中定義。

4.2board/fl2440目錄下添加nand_read.c

添加C語言從NAND Flash搬移代碼部分,剛剛我們看到了彙編部分會調用一個C函數nand_read_ll,這個函數就在nand_read.c檔案中,要在board/fl2440目錄下建立一個名為nand_read.c的檔案.

/*
 * nand_read.c: Simple NAND read functions forbooting from NAND
 *
 * This is used by cpu/arm920/start.S assemblercode,
 * and the board-specific linker script mustmake sure this
 * file is linked within the first 4kB of NANDflash.
 *
 * Taken from GPLv2 licensed vivi bootloader,
 * Copyright (C) 2002 MIZI Research, Inc.
 *
 * Author: Hwang, Chideok<[email protected]>
 * Date : $Date: 2004/07/14 10:37:37 $
 *
 * u-boot integration and bad-block skipping(C) 2006 by OpenMoko, Inc.
 * Author: Harald Welte<[email protected]>
 *
 *
 
 */
 
#include<common.h>
#include<linux/mtd/nand.h>
 
 
#define __REGb(x)   (*(volatile unsigned char*)(x))
#define __REGw(x)   (*(volatile unsigned short*)(x))
#define __REGi(x)     (*(volatile unsigned int*)(x))
#define NF_BASE               0x4e000000
#ifdefined(CONFIG_S3C2410)
#define NFCONF                __REGi(NF_BASE +0x0)
#define NFCMD         __REGb(NF_BASE + 0x4)
#define NFADDR                __REGb(NF_BASE +0x8)
#define NFDATA                __REGb(NF_BASE +0xc)
#define NFSTAT                 __REGb(NF_BASE + 0x10)
#define NFSTAT_BUSY    		 1
#define nand_select()        (NFCONF &=~0x800)
#define nand_deselect()   (NFCONF |= 0x800)
#define nand_clear_RnB()do {} while (0)
#elifdefined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
#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 NFDATA16              __REGw(NF_BASE + 0x10)
#define NFSTAT                 __REGb(NF_BASE +0x20)
#define NFSTAT_BUSY   		  1
#define nand_select()          (NFCONT &= ~(1<< 1))
#define nand_deselect()        (NFCONT |= (1 <<1))
#defin enand_clear_RnB()	(NFSTAT |= (1 << 2))
#endif
 
static inline void nand_wait(void)
{
         int i;
 
         while (!(NFSTAT & NFSTAT_BUSY))
                  for (i=0; i<10; i++);
}
 
struct boot_nand_t {
         int page_size;
         int block_size;
         int bad_block_offset;
//       unsigned long size;
};
 
#if0
#ifdefined(CONFIG_S3C2410) || defined(CONFIG_MINI2440)
/*configuration for 2410 with 512byte sized flash */
#define NAND_PAGE_SIZE                 512
#define BAD_BLOCK_OFFSET 5
#define NAND_BLOCK_MASK           (NAND_PAGE_SIZE - 1)
#define NAND_BLOCK_SIZE              0x4000
#else
/*configuration for 2440 with 2048byte sized flash */
#define NAND_5_ADDR_CYCLE
#define NAND_PAGE_SIZE                 2048
#define BAD_BLOCK_OFFSET NAND_PAGE_SIZE
#define NAND_BLOCK_MASK                 (NAND_PAGE_SIZE - 1)
#define NAND_BLOCK_SIZE             (NAND_PAGE_SIZE * 64)
#endif
 
/*compile time failure in case of an invalid configuration */
#ifdefined(CONFIG_S3C2410) && (NAND_PAGE_SIZE != 512)
#error"S3C2410 does not support nand page size != 512"
#endif
#endif
 
static int is_bad_block(struct boot_nand_t * nand, unsigned long i)
{
         unsigned char data;
         unsigned long page_num;
 
         nand_clear_RnB();
         if (nand->page_size == 512) {
                  NFCMD = NAND_CMD_READOOB; /*0x50 */
                  NFADDR =nand->bad_block_offset & 0xf;
                  NFADDR = (i >> 9) &0xff;
                  NFADDR = (i >> 17)& 0xff;
                  NFADDR = (i >> 25)& 0xff;
         } else if (nand->page_size == 2048){
                  page_num = i >> 11; /*addr / 2048 */
                  NFCMD = NAND_CMD_READ0;
                  NFADDR =nand->bad_block_offset & 0xff;
                  NFADDR =(nand->bad_block_offset >> 8) & 0xff;
                  NFADDR = page_num & 0xff;
                  NFADDR = (page_num >>8) & 0xff;
                  NFADDR = (page_num >>16) & 0xff;
                  NFCMD = NAND_CMD_READSTART;
         } else {
                  return -1;
         }
         nand_wait();
         data = (NFDATA & 0xff);
         if (data != 0xff)
                  return 1;
 
         return 0;
}
 
static int nand_read_page_ll(struct boot_nand_t * nand, unsigned char *buf, unsignedlong addr)
{
         unsigned short *ptr16 = (unsignedshort *)buf;
         unsigned int i, page_num;
 
         nand_clear_RnB();
 
         NFCMD = NAND_CMD_READ0;
 
         if (nand->page_size == 512) {
                  /* Write Address */
                  NFADDR = addr & 0xff;
                  NFADDR = (addr >> 9)& 0xff;
                  NFADDR = (addr >> 17)& 0xff;
                  NFADDR = (addr >> 25)& 0xff;
         } else if (nand->page_size == 2048){
                  page_num = addr >> 11;/* addr / 2048 */
                  /* Write Address */
                  NFADDR = 0;
                  NFADDR = 0;
                  NFADDR = page_num & 0xff;
                  NFADDR = (page_num >>8) & 0xff;
                  NFADDR = (page_num >>16) & 0xff;
                  NFCMD = NAND_CMD_READSTART;
         } else {
                  return -1;
         }
         nand_wait();
 
#ifdefined(CONFIG_S3C2410)
         for (i = 0; i < nand->page_size;i++) {
                  *buf = (NFDATA & 0xff);
                  buf++;
         }
#elifdefined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
         for (i = 0; i <(nand->page_size>>1); i++) {
                  *ptr16 = NFDATA16;
                  ptr16++;
         }
#endif
 
         return nand->page_size;
}
 
static unsigned short nand_read_id()
{
         unsigned short res = 0;
         NFCMD = NAND_CMD_READID;
         NFADDR = 0;
         res = NFDATA;
         res = (res << 8) | NFDATA;
         return res;
}
 
extern unsigned int dynpart_size[];
 
/*low level nand read function */
int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)
{
         int i, j;
         unsigned short nand_id;
         struct boot_nand_t nand;
 
         /* chip Enable */
         nand_select();
         nand_clear_RnB();
       
         for (i = 0; i < 10; i++)
                  ;
         nand_id = nand_read_id();
         if (0) { /* dirty little hack todetect if nand id is misread */
                  unsigned short * nid =(unsigned short *)0x31fffff0;
                  *nid = nand_id;
         }      
 
       if (nand_id == 0xec76 ||           /* Samsung K91208 on SD2410 board */
           nand_id == 0xad76 ) {      /*Hynix HY27US08121A*/
                  nand.page_size = 512;
                  nand.block_size = 16 * 1024;
                  nand.bad_block_offset = 5;
         //       nand.size = 0x4000000;
         } else if (nand_id == 0xecf1 ||      /* Samsung K9F1G08U0B */
           nand_id == 0xadda || /*  Hynix HY27UF082G2B on FL2440 board */
                     nand_id == 0xecda ||     /* Samsung K9F2G08U0B on FL2440 board */
                     nand_id == 0xecd3 )      { /* Samsung K9K8G08 */
                  nand.page_size = 2048;
                  nand.block_size = 128 * 1024;
                  nand.bad_block_offset =nand.page_size;
         //       nand.size = 0x8000000;
         } else {
                  return -1; // hang
         }
         if ((start_addr &(nand.block_size-1)) || (size & ((nand.block_size-1))))
                  return -1;  /* invalid alignment */
 
         for (i=start_addr; i < (start_addr+ size);) {
#ifdef CONFIG_S3C2410_NAND_SKIP_BAD
                  if (i &(nand.block_size-1)== 0) {
                           if(is_bad_block(&nand, i) ||
                              is_bad_block(&nand, i + nand.page_size)) {
                                    /* Badblock */
                                    i +=nand.block_size;
                                    size +=nand.block_size;
                                    continue;
                           }
                  }
#endif
                  j =nand_read_page_ll(&nand, buf, i);
                  i += j;
                  buf += j;
         }
 
         /* chip Disable */
         nand_deselect();
 
         return 0;
}
           

4.3将nand_read.c檔案連結到u-boot.bin檔案的前4K代碼

vim board/fl2440/Makefile

添加nand_read.o使得nand_read.c能被編譯到u-boot.bin中

COBJS   := fl2440.o nand_read.o
           

修改檔案arch/arm/cpu/arm920t/u-boot.lds,将u-boot從nandflash搬運的代碼連結到前4K的u-boot.bin中:

SECTIONS
{
      . = 0x00000000;
 
      . = ALIGN(4);
      .text :
      {
          arch/arm/cpu/arm920t/start.o    (.text)
          board/fl2440/lowlevel_init.o (.text)(粗體部分為要添加的部分)
          board/fl2440/nand_read.o (.text)
          *(.text)
      }
 
     . = ALIGN(4);
           

4.4添加u-boot支援nandflash序列槽操作

vim include/configs/fl2440.h

/*
 * NAND flash settings
 */
#ifdefined(CONFIG_CMD_NAND)
#define CONFIG_NAND_S3C2410
#define CONFIG_SYS_MAX_NAND_DEVICE   1   /* Maxnumber of NAND devices       */
#define CONFIG_SYS_NAND_BASE  0x4E000000
#define SECTORSIZE  512
#define SECTORSIZE_2K  2048
#define NAND_SECTOR_SIZE  SECTORSIZE
#define NAND_SECTOR_SIZE_2K  SECTORSIZE_2K
#define NAND_BLOCK_MASK  511
#define NAND_BLOCK_MASK_2K  2047
#define NAND_MAX_CHIPS  1
#define CONFIG_MTD_NAND_VERIFY_WRITE
#define CONFIG_SYS_64BIT_VSPRINTF      /* neededfor nand_util.c */
#endif  /* CONFIG_CMD_NAND */
 
           

vim drivers/mtd/nand/s3c2410_nand.c 支援s3c2440開發闆對nandflash的讀寫:

#define NF_BASE        0x4e000000
#ifdefined(CONFIG_S3C2410) 
#define S3C2410_NFCONF_EN         (1<<15)
#define S3C2410_NFCONF_512BYTE    (1<<14)
#define S3C2410_NFCONF_4STEP      (1<<13)
#define S3C2410_NFCONF_INITECC    (1<<12)
#define S3C2410_NFCONF_nFCE       (1<<11)
#define S3C2410_NFCONF_TACLS(x)   ((x)<<8)
#define S3C2410_NFCONF_TWRPH0(x)  ((x)<<4)
#define S3C2410_NFCONF_TWRPH1(x)  ((x)<<0)
 
#define S3C2410_ADDR_NALE 4
#define S3C2410_ADDR_NCLE 8
#endif
 
           

 添加S3C2440開發闆的nandflash各功能寄存器定義

#ifdefined(CONFIG_S3C2440) 
#define S3C2410_NFCONT_EN        (1<<0) 
#define S3C2410_NFCONT_INITECC   (1<<4) 
#define S3C2410_NFCONT_nFCE      (1<<1) 
#define S3C2410_NFCONT_MAINECCLOCK (1<<5) 
#define S3C2410_NFCONF_TACLS(x)   ((x)<<12) 
#define S3C2410_NFCONF_TWRPH0(x) ((x)<<8) 
#define S3C2410_NFCONF_TWRPH1(x) ((x)<<4) 
 
#define S3C2410_ADDR_NALE 0x08 
#define S3C2410_ADDR_NCLE 0x0c 
#endif
           

修改這個全局變量

ulongIO_ADDR_W = NF_BASE;
 
#ifdef CONFIG_NAND_SPL
           

修改s3c2410_hwcontrol函數:

staticvoid s3c2410_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
//  struct nand_chip *chip = mtd->priv;
    struct s3c2410_nand *nand =s3c2410_get_base_nand();
 
    debugX(1, "hwcontrol(): 0x%02x0x%02x\n", cmd, ctrl);
 
    if (ctrl & NAND_CTRL_CHANGE) {
        //ulong IO_ADDR_W = (ulong)nand;
        IO_ADDR_W = (ulong)nand;
 
        if (!(ctrl & NAND_CLE))
            IO_ADDR_W |= S3C2410_ADDR_NCLE;
        if (!(ctrl & NAND_ALE))
            IO_ADDR_W |= S3C2410_ADDR_NALE;
 
//      chip->IO_ADDR_W = (void *)IO_ADDR_W;
 
        if (ctrl & NAND_NCE)
#ifdefined(CONFIG_S3C2410) 
            writel(readl(&nand->NFCONF)& ~S3C2410_NFCONF_nFCE,&nand->NFCONF);
#elifdefined(CONFIG_S3C2440)
            writel(readl(&nand->NFCONT)& ~S3C2410_NFCONT_nFCE,&nand->NFCONT);
#endif
        else
#ifdefined(CONFIG_S3C2410) 
            writel(readl(&nand->NFCONF)| S3C2410_NFCONF_nFCE,&nand->NFCONF);
#elifdefined(CONFIG_S3C2440)
            writel(readl(&nand->NFCONT)| S3C2410_NFCONT_nFCE,&nand->NFCONT);
#endif
    }
 
    if (cmd != NAND_CMD_NONE)
        //writeb(cmd, chip->IO_ADDR_W);
        writeb(cmd, (void *)IO_ADDR_W);
}
           

修改s3c2410_nand_enable_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);
#ifdefined(CONFIG_S3C2410)
    writel(readl(&nand->NFCONF) |S3C2410_NFCONF_INITECC, &nand->NFCONF);
#elifdefined(CONFIG_S3C2440)            
    writel(readl(&nand->NFCONT) |S3C2410_NFCONT_INITECC, &nand->NFCONT);
#endif
}
           

修改board_nand_init函數如下:

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();
    struct s3c2410_nand *nand_reg =s3c2410_get_base_nand();
 
    debugX(1, "board_nand_init()\n");
 
    writel(readl(&clk_power->CLKCON) |(1 << 4), &clk_power->CLKCON);
 
#ifdefined(CONFIG_S3C2410)
    /* initialize hardware */
    twrph0 = 3;
    twrph1 = 0;
    tacls = 0;
 
    cfg = S3C2410_NFCONF_EN;
    cfg |= S3C2410_NFCONF_TACLS(tacls - 1);
    cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
    cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
    writel(cfg, &nand_reg->NFCONF);
 
    /* initialize nand_chip data structure */
    nand->IO_ADDR_R = nand->IO_ADDR_W =(void *)&nand_reg->NFDATA;
#elifdefined(CONFIG_S3C2440) 
   /* initialize hardware */
    tacls = 0;
    twrph0 = 4;
    twrph1 = 2;
 
 
        cfg = 0;
        cfg |= S3C2410_NFCONF_TACLS(tacls - 1);
        cfg |= S3C2410_NFCONF_TWRPH0(twrph0 -1);
        cfg |= S3C2410_NFCONF_TWRPH1(twrph1 -1);
        writel(cfg, &nand_reg->NFCONF);
 
        cfg =(0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(0<<6)|(0<<5)|(1<<4)|(0<<1)|(1<<0);
        writel(cfg, &nand_reg->NFCONT);
        /* initialize nand_chip data structure */
        nand->IO_ADDR_R = nand->IO_ADDR_W= (void *)&nand_reg->NFDATA;
#endif
 
    nand->select_chip = NULL;
 
    /* read_buf and write_buf are default */
    /* read_byte and write_byte are default */
#ifdef CONFIG_NAND_SPL
    nand->read_buf = nand_read_buf;
#endif
 
    /* hwcontrol always must be implemented */
    nand->cmd_ctrl = s3c2410_hwcontrol;
 
    nand->dev_ready = s3c2410_dev_ready;
 
#ifdef CONFIG_S3C2410_NAND_HWECC
    nand->ecc.hwctl =s3c2410_nand_enable_hwecc;
    nand->ecc.calculate =s3c2410_nand_calculate_ecc;
    nand->ecc.correct =s3c2410_nand_correct_data;
    nand->ecc.mode = NAND_ECC_HW;
    nand->ecc.size =CONFIG_SYS_NAND_ECCSIZE;
    nand->ecc.bytes =CONFIG_SYS_NAND_ECCBYTES;
#else
    nand->ecc.mode = NAND_ECC_SOFT;
#endif
 
#ifdef CONFIG_S3C2410_NAND_BBT
    nand->options = NAND_USE_FLASH_BBT;
#else
    nand->options = 0;
#endif
 
    debugX(1, "end of nand_init\n");
 
    return 0;
}
           

修改arch/arm/include/asm/arch-s3c24x0/s3c24x0.h中nandflash控制寄存器的結構體:

struct s3c24x0_interrupt {
u32 SRCPND;
u32 INTMOD;
u32 INTMSK;
u32 PRIORITY;
u32 INTPND;
u32 INTOFFSET;
…………
           
#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)
u32 SUBSRCPND;
u32 INTSUBMSK;
#endif
};
…………
           
struct s3c24x0_dma {
u32 DISRC;
#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)
u32 DISRCC;
#endif
u32 DIDST;
           
#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)
u32 DIDSTC;
#endif
u32 DCON;
u32 DSTAT;
u32 DCSRC;
u32 DCDST;
u32 DMASKTRIG;
#ifdef CONFIG_S3C2400
u32 res[1];
#endif
           
#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)
u32 res[7];
#endif
};
…………
           
struct s3c24x0_clock_power {
u32 LOCKTIME;
u32 MPLLCON;
u32 UPLLCON;
u32 CLKCON;
u32 CLKSLOW;
u32 CLKDIVN;
 
           
#if defined (CONFIG_S3C2440)
u32 CAMDIVN;
#endif
};
…………
           
#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)
u32 LCDINTPND;
u32 LCDSRCPND;
u32 LCDINTMSK;
u32 LPCSEL;
#endif
};
           
#if defined(CONFIG_S3C2410)
struct s3c2410_nand {
u32 NFCONF;
u32 NFCMD;
u32 NFADDR;
u32 NFDATA;
u32 NFSTAT;
u32 NFECC;
};
           
#elif defined (CONFIG_S3C2440)
struct s3c2410_nand {
u32 NFCONF;
u32 NFCONT;
u32 NFCMD;
u32 NFADDR;
u32 NFDATA;
u32 NFMECCD0;
u32 NFMECCD1;
u32 NFSECCD;
u32 NFSTAT;
u32 NFESTAT0;
u32 NFESTAT1;
u32 NFMECC0;
u32 NFMECC1;
u32 NFSECC;
u32 NFSBLK;
u32 NFEBLK;
};
#endif
           
…………
#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)
u32 GPACON;
u32 GPADAT;
u32 res1[2];
           
u32 GPBCON;
…………
           
#if defined (CONFIG_S3C2440)
u32 res9[3];
u32 MSLCON;
u32 GPJCON;
u32 GPJDAT;
u32 GPJUP;
#endif
           
#endif
};
           

5、添加DM9000網絡支援

vim include/configs/fl2440.h

…………

#if 0 //禁用 CS89000 網卡
#define CONFIG_NET_MULTI
#define CONFIG_CS8900 /* we have a CS8900on-board */
#define CONFIG_CS8900_BASE 0x19000300
#define CONFIG_CS8900_BUS16 /* the Linux driverdoes accesses as shorts */
           
#else //添加 DM9000 網卡
#define CONFIG_NET_MULTI 1
#define CONFIG_NET_RETRY_COUNT 20
#define CONFIG_DRIVER_DM9000 1
#define CONFIG_DM9000_BASE0x20000300 /* nGCS4 */
#define DM9000_IOCONFIG_DM9000_BASE
#define DM9000_DATA(CONFIG_DM9000_BASE+4)#define CONFIG_DM9000_USE_16BIT 1
#define CONFIG_DM9000_NO_SROM 1
#undef CONFIG_DM9000_DEBUG
#endif
           

…………

#define CONFIG_CMD_CACHE
#define CONFIG_CMD_DATE
#define CONFIG_CMD_ELF
           
#define CONFIG_CMD_PING 添加 ping指令支援
           

我們可以在這裡修改 CONFIG_BOOTDELAY 來改變啟動時按任意鍵進入 debug 模式的延時時間

#define CONFIG_BOOTDELAY 5
/*#define CONFIG_BOOTARGS "root=ramfsdevfs=mount console=ttySA0,9600" */
#define CONFIG_ETHADDR 11:22:33:44:55:66 //配置網卡的 MAC位址
#define CONFIG_NETMASK255.255.255.0      //配置網絡子網路遮罩
#define CONFIG_IPADDR 192.168.199.200    //配置網卡 IP位址
#define CONFIG_SERVERIP 192.168.199.2    //配置 TFTP伺服器 IP 位址
/*#define CONFIG_BOOTFILE"elinos-lart" */
/*#define CONFIG_BOOTCOMMAND "tftp;bootm" */
           

…………

我們可以在這裡通過修改 CONFIG_SYS_PROMPT 來修改 u-boot 的指令提示符

#define CONFIG_SYS_PROMPT"[[email protected]]# " /* Monitor Command Prompt */
           

修改 board/lingyun/fl2440/fl2440.c,添加 dm9000 網卡的初始化

vim board/lingyun/fl2440/fl2440.c

…………
#ifdef CONFIG_CMD_NET
int board_eth_init(bd_t *bis)
{
int rc = 0;
#ifdef CONFIG_CS8900
rc = cs8900_initialize(0, CONFIG_CS8900_BASE);
#endif
           
#ifdef CONFIG_DRIVER_DM9000
rc = dm9000_initialize(bis);
#endif
           
return rc;
}
#endif
           

…………

對 DM9000 網卡驅動作一些小的修改

vim drivers/net/dm9000x.c

…………

static int dm9000_init(struct eth_device *dev,bd_t *bd)
{
	…………
        while (!(phy_read(1) & 0x20)) { /*autonegation complete bit */
	udelay(1000);
	i++;
	if(i == 2000) {
	  printf("couldnot establish link\n");
	  break;
	}
           
}
}
           

以上代碼的修改後,我們可以編譯測試 u-boot 代碼進行網絡測試了。

繼續閱讀