一.预备知识:
1.       首先,U-Boot1.3.4还没有支持s3c2440,移植仍是用2410的文件稍作修改而成的。
2.       2440 2410的区别:
24402410的区别主要是 2440的主频更高,增加了摄像头接口和 AC‘97音频接口;寄存器方面,除了新增模 块的寄存器外,移植所要注意的是 NAND FlASH控制器的寄存器有较大的变化、芯片的时钟频率控制寄存器(芯片 PLL的寄存器)有一定的变化。其他寄存器基本是兼容的。
3. 你开发板的boot方式是什么,开发板上电以后是怎么执行的。
一般来说三星的开发板有三种启动方式: nandnorram
具体用那一种方式来启动决定于 CPU0M[0:1]这两个引脚,具体请参考 S3C2440datasheet
nand:对于 2440来说, CPU是不给 nand-flash分配地址空间的, nand-flash只相当于 CPU的一个外设, S3C2440做了一个从 nand-flash启动的机制。开发板一上电, CPU就自动复制
nand-flash里面的前 4K-Bytes内容到 S3C2440内部集成的 SDRAM,然后把 4K内容所在 的 RAM映射到 S3C24400地址,从 0地址开始执行。这 4K的内容主要负责下面这些工 作:初始化中断矢量、设定 CPU的工作模式为 SVC32模式、屏蔽看门狗、屏蔽中断、 初始化时钟、把整个 u-boot重定向到外部 SDRAM、跳到主要的 C函数入口。
nor: 早期的时候利用 nor-flash启动的方式比较多,就是把 u-boot烧写到 nor-flash里面, 直接把 nor-flash映射到 S3C24400地址,上电从 0地址开始执行。
ram: 直接把 u-boot放到外部 SDRAM上跑,这一般 debug时候用到。
4.  u-boot程序的入口地址问题
要理解程序的入口地址,自然想到的是连接文件,首先看看开发板相对于某个开发板的连接文件 "/board/你的开发板 /u-boot.lds",看一个 2410的例子:
ENTRY(_start)
SECTIONS
{
. = 0x00000000;
. = ALIGN(4);
.text      :
{
cpu/arm920t/start.o (.text)
*(.text)
}
. = ALIGN(4);
.rodata : { *(.rodata) }
. = ALIGN(4);
.data : { *(.data) }
. = ALIGN(4);
.got : { *(.got) }
__u_boot_cmd_start = .;
.u_boot_cmd : { *(.u_boot_cmd) }
__u_boot_cmd_end = .;
. = ALIGN(4);
__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也不为过。
5. 一直不明白的U-BOOT是怎样从4Ksteppingstone跳到RAM中执行的,现在终于明白了。关键在于:
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里面
6. 在移植u-boot-1.3.3以上版本的时候要注意:
在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))
7. 然后说一下跳转指令。ARM有两种跳转方式。
1)mov p c <跳转地址〉
这种向程序计数器 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   ; 从子程序返回。
二.开始上机移植:(红色字体为添加的内容,蓝色字体为修改的内容,下同 )
给自己的开发板取名为 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
[uboot@localhost u-boot-1.3.4]$ vim Makefile 修改内容如下:
__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目录下 ,否则编译会出错。
[uboot@localhost u-boot-1.3.4]$ cd board
[uboot@localhost board]$ mkdir qljt qljt/qljt2440
[uboot@localhost board]$ cp -arf sbc2410x/* qljt/qljt2440/
[uboot@localhost board]$ cd qljt/qljt2440/
[uboot@localhost qljt2440]$ mv sbc2410x.c qljt2440.c
[uboot@localhost qljt2440]$ ls 可以看到下面这些文件:
config.mk  flash.c  lowlevel_init.s   Makefile   qljt2440.c  u-boot.lds
[uboot@localhost qljt2440]$ vim Makefile
COBJS := qljt2440.o flash.o
5.include/configs/ 中建立开发板所需要的配置头文件
[uboot@localhost qljt2440]$ cd ../../..
[uboot@localhost u-boot-1.3.4]$ cp include/configs/sbc2410x.h include/configs/qljt2440.h
6. 测试交叉编译能否成功
1)配置
[uboot@localhost u-boot-1.3.4]$ make qljt2440_config
Configure for qljt2440 board…
(2)测试编译
[uboot@localhost u-boot-1.3.4]$ make
详细信息如下:
编译信息最后两行:
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.  修改 /cpu/arm920t/start.S
1.1 修改寄存器地址定义
#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440)  
/* turn off the watchdog */
#if defined(CONFIG_S3C2400)
# define pWTCON        0x15300000
# define INTMSK        0x14400008    /* Interupt-Controller base addresses */
# define CLKDIVN    0x14800014    /* clock divisor register */
#else
# define pWTCON        0x53000000     /*该地址用来屏蔽看门狗*/
# define INTMSK        0x4A000008    /* Interupt-Controller base addresses 该地址用来屏蔽中断*/
# define INTSUBMSK    0x4A00001C  /*该地址用来屏蔽子中断*/
# define CLKDIVN    0x4C000014    /* clock divisor register 该地址用来决定FCLKHCLKPCLK的比例
*/
#define CLK_CTL_BASE        0x4c000000  /* qljt S3C2440A.pdf中可以看出该寄存器是存放MpllUpll P254 */
#if defined(CONFIG_S3C2440)      
#define MDIV_405       0x7f << 12   /* qljt  参见P255表,同时要知道本开发板的Fin12MHz,需要的Fclk(也就
Mpll) 405MHz*/
#define PSDIV_405       0x21       /* qljt 同上,同时设定PDIVSDIV的值,PDIVSDIV参见 S3C2440A.pdf*/
#endif
#endif
1.2 修改中断禁止部分
# if defined(CONFIG_S3C2410)
    ldr    r1, =0x7ff   // 根据2410芯片手册,INTSUBMSK11位可用,
                       //vivi 也是0x7ff,不知为什么UBoot一直没改过来。但是由于芯片复位默认
//所有的终端都是被屏蔽的,所以这个不影响工作
ldr    r0, =INTSUBMSK
str    r1, [r0]
# endif
# if  defined(CONFIG_S3C2440)
ldr    r1, =0x7fff   //根据2440芯片手册,INTSUBMSK15位可用
ldr    r0, =INTSUBMSK
str    r1, [r0]
# endif
1.3 修改时钟设置
/*时钟控制逻辑单元能够产生s3c2440需要的时钟信号,包括CPU使用的主频FCLK,AHB总线使用的HCLK,APB总线设备使用的PCLK2440里面的两个锁相环(PLL),其中一个对应FCLKHCLKPCLK,另外一个对应 UCLK(48MHz)*/
/*注意:AHPAPB总线的简介参见“AHBAPB总线.doc */
/* FCLK:HCLK:PCLK = 1:4:8 */
ldr    r0, =CLKDIVN
    mov    r1, #5
str    r1, [r0]
/*这三条协处理器命令确实不知道什么意思,在ATXJGYBC_ql.pdf中搜p15c1,只知道它们执行以后会把协处理器p15的寄存器c1的最高两位置1,但c1的最高两位是没有意义啊,弄不懂它的真正意思
不过我却知道这三条语句是从哪里出来的,详细请参考s3c2440datasheets3c2440datasheet中的R1_nFR1_iA.doc */
    mrc    p15, 0, r1, c1, c0, 0        /*read ctrl register   qljt*/
    orr    r1, r1, #0xc0000000       /*Asynchronous  qljt 改变总线模式为异步模式网上某位朋友说不知到在哪里看到过
如果FCLKHCLK不同的话就要选择这种模式的 */
    mcr    p15, 0, r1, c1, c0, 0      /*write ctrl register qljt*/

#if defined(CONFIG_S3C2440)   // 2440的主频可达533MHz,但听说设到533MHz时系统

//很不稳定,不知是不是SDRAM和总线配置的影响,所以现在先设到//405MHz,以后在改进。)
/*now, CPU clock is 405.00 Mhz   qljt*/
    mov    r1, #CLK_CTL_BASE    /* qljt*/
    mov    r2, #MDIV_405                   /* mpll_405mhz    qljt*/
    add    r2, r2, #PSDIV_405             /* mpll_405mhz    qljt*/
    str    r2, [r1, #0x04]               /* MPLLCON qljt 实际上是设置寄存器CLK_CTL_BASE+0x04=0x4c000004的值 */
#endif

#endif    /* CONFIG_S3C2400 || CONFIG_S3C2410|| CONFIG_S3C2440 */
1.4 将从Flash启动改成从NAND Flash启动。(特别注意:这和2410的程序有不同,不可混用!!!是拷贝vivi的代码。)
将以下UBoot的重定向语句段:
@#if ndef         CONFIG_AT91RM9200
#if  0
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
relocate:                /* relocate U-Boot to RAM        */
adr    r0, _start        /* r0 <- current position of code   */
ldr    r1, _TEXT_BASE        /* test if we run from flash or RAM */
cmp     r0, r1                /* don't reloc during debug         */
beq     stack_setup

ldr    r2, _armboot_start
ldr    r3, _bss_start
sub    r2, r3, r2        /* r2 <- size of armboot            */
add    r2, r0, r2        /* r2 <- source end address         */

copy_loop:
ldmia    r0!, {r3-r10}        /* copy from source address [r0]    */
stmia    r1!, {r3-r10}        /* copy to   target address [r1]    */
cmp    r0, r2            /* until source end addreee [r2]    */
ble    copy_loop
#endif    /* CONFIG_SKIP_RELOCATE_UBOOT */

#endif  /*CONFIG_AT91RM9200 */
然后添加:
/*下载了一个vivi源代码看了一下,还真的有下面哪一段代码*/
#ifdef CONFIG_S3C2440_NAND_BOOT   @qljt@@@@@@@@@@@@@@@@SSSSSSSSSSSSS
    @ reset NAND
/*往下四段内容都是针对S3C2440的关于NAND-FLASH的寄存器的设置,具体有什么作用,看了datasheet,有些明白有些不明白*/
mov    r1, #NAND_CTL_BASE
ldr    r2, =( (7<<12)|(7<<8)|(7<<4)|(0<<0) )
    str    r2, [r1, #oNFCONF]          /* 这些宏是在include/configs/qljt2440.h中被定义的*/
    ldr    r2, [r1, #oNFCONF]  /* 还是弄不懂为什么上面一句str以后还要有这句的ldr命令?why?难道是多余的?*/

    ldr    r2, =( (1<<4)|(0<<1)|(1<<0) ) @ Active low CE Control
str    r2, [r1, #oNFCONT]
ldr    r2, [r1, #oNFCONT]

    ldr    r2, =(0x6)        @ RnB Clear
str    r2, [r1, #oNFSTAT]
ldr    r2, [r1, #oNFSTAT]

    mov    r2, #0xff        @ RESET command
strb    r2, [r1, #oNFCMD]
/*delay一段时间*/
  mov r3, #0                   @ wait
nand1:
add  r3, r3, #0x1
cmp r3, #0xa
blt   nand1
/*等待nand-flash的复位完毕信号*/
nand2:
  ldr   r2, [r1, #oNFSTAT]      @ wait ready
tst    r2, #0x4
beq  nand2

  ldr    r2, [r1, #oNFCONT]
 orr    r2, r2, #0x2        @ Flash Memory Chip Disable  /* 在这里先Display fansh CE先,在C函数中对falsh进行 */

str    r2, [r1, #oNFCONT]                          /* 操作的时候才enable,为什么这样操作不太清楚 */   
/*下面这段用来初始化栈指针sp和帧指针fp,至于它们的定义和作用参考文件夹
栈指针sp和帧指针fp”里面的内容
记住它们都是与函数调用时候相关的。简单来讲就是子函数被调用以后是通过指针的相对位置来查找调用参数和局部变量的,但是由于sp经常变化,所以需要fp来协助。*/
@ get ready to call C functions (for nand_read())
  ldr   sp, DW_STACK_START       @ setup stack pointer /*sp 是指堆栈指针*/
mov fp, #0                    @ no previous frame, so fp=0
@ copy U-Boot to RAM                   /*vivi里面应该是有一段是针对gpio的程序,也许使用来debug用的信号灯,这里省略了*/
/* TEXT_BASEuboot自己的入口地址,在u-boot-1.3.4-board/qljt/qljt2440config.mk中定义
有趣的是外国人的逆向思维很厉害,它们很灵活地把它放在SDRAM的最后0x80000地方,也就是 0x33F80000
*/
  ldr   r0, =TEXT_BASE         /*r0 : u-boot复制到ram的那个位置*/
         mov     r1, #0x0                          /*r1 : falsh的那个位置开始复制*/
         mov r2, #0x20000                     /*r2 : 复制多大的内容*/
         bl    nand_read_ll              /* 跳到执行uboot复制的程序入口,这个函数从哪里来?也是来自vivi的,没办法*/
         tst    r0, #0x0                    /* 这里特别注意r0的值是指nand_read_ll 执行完以后的返回值,而不是上面
ldr   r0, =TEXT_BASE 的值,初学者往往在这里想不通*/
beq  ok_nand_read
bad_nand_read:                  /*如果读nand_read失败的话,那么sorry,重来,或者检查硬件*/
loop2:    b     loop2          @ infinite loop
ok_nand_read:
@ verify          
/*计算机就是好,很容易就可以检测我们放在SDRAM中的u-boot是不是flash中的uboot
本开发板使用的是nand-falsh的启动方式,板子一上电并不是马上进入SDRAM执行程序的。是这样的:板子一上电,S3C2440自动把nand-falsh中从0地址开始的4Kbytes复制到S3C2440集成的某个缓冲区里面(起始地址是0x00),从那里开始执行,那4K程序负责把整个uboot复制到SDRAM,然后才跳到SDRAM开始正真的UBOOT(这个技术是有个专业名字的我忘记了 ),*/
/*下面这段程序的作用就是用开始执行的4Kbytes程序跟我们复制到SDRAM中的uboot的前4K程序进行比较,从而校验*/
mov r0, #0
ldr   r1, =TEXT_BASE
mov r2, #0x400     @ 4 bytes * 1024 = 4K-bytes
go_next:
ldr   r3, [r0], #4
ldr   r4, [r1], #4
teq   r3, r4
bne  notmatch
subs r2, r2, #4
beq  stack_setup
bne  go_next

notmatch:
loop3:     b     loop3         @ infinite loop
#endif @ CONFIG_S3C2440_NAND_BOOT  @qljt@@@@@@@@@@@@@@@@@@EEEEEEEEE

1.5 在跳到 C函数执行前,也就是跳出 start.S前,添加几个 LED灯的控制,说明程序跑到这里了,移植的第一阶段完成了。
/* 本开发板上面有四个LED灯,分别接到CPUGPIO_F[4:7]这四个引脚上 */
#if defined(CONFIG_S3C2440)
@  LED1 on u-boot stage 1 is ok!
mov    r1, #GPIO_CTL_BASE
add    r1, r1, #oGPIO_F
ldr    r2,=0x5500
str    r2, [r1, #oGPIO_CON]
mov    r2, #0xff
str    r2, [r1, #oGPIO_UP]
mov    r2, #0xdf
    str    r2, [r1, #oGPIO_DAT]
#endif
1.6“  _start_armboot:    .word start_armboot  ” 后加入:
#if defined(CONFIG_S3C2440_NAND_BOOT)
.align     2         /*??? 这里我一直不明白为什么是 .align 2,因为如果按照ARM的规则,意思是按照 22次方=4bit
方式对齐,那么就是半个字节对齐,有可能吗?*/
DW_STACK_START:  .word  STACK_BASE+STACK_SIZE-4   /* 从这里可以看出该堆栈是从高地址向低地址增长的
注意这里的STACK_BASESTACK_SIZE还没定义,在1.1节中定义 */
#endif
2. 修改include/configs/qljt2440.h文件,在结尾处添加如下内容(注意:s3c2410与s3c2440的Nand Flash控制器寄存器不同,不能混用!!):
......
/*
 * Nandflash Boot
 */
#define CONFIG_S3C2440_NAND_BOOT 1
#define STACK_BASE    0x33f00000
#define STACK_SIZE    0x8000
/* NAND Flash Controller */
#define NAND_CTL_BASE        0x4E000000
/* Offset */
#define oNFCONF            0x00       /*这些宏是在start.S中被调用的*/
#define oNFCONT            0x04
#define oNFCMD            0x08
#define oNFADDR            0x0c
#define oNFDATA            0x10
#define oNFSTAT            0x20
#define oNFECC            0x2c
/* GPIO */
#define GPIO_CTL_BASE        0x56000000
#define oGPIO_F            0x50
#define oGPIO_CON       0x0   /* R/W, Configures the pins of the port */
#define oGPIO_DAT        0x4    /* R/W,    Data register for port */
#define oGPIO_UP        0x8    /* R/W, Pull-up disable register */
#endif    /* __CONFIG_H */
3.  在board/qljt/qljt2440加入NAND Flash读函数文件,拷贝vivi中的nand_read.c文件到此文件夹即可,基本上大陆上移植的都是这样做的,在此把该文件的内容贴出来,目的是对一些难理解的代码进行解析:
#include

#define __REGb(x)    (*(volatile unsigned char *)(x))
#define __REGi(x)    (*(volatile unsigned int *)(x))
#define NF_BASE        0x4e000000

#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 NFSTAT        __REGb(NF_BASE + 0x20)

//#define GPDAT        __REGi(GPIO_CTL_BASE+oGPIO_F+oGPIO_DAT)

#define NAND_CHIP_ENABLE  (NFCONT &= ~(1<<1))
#define NAND_CHIP_DISABLE (NFCONT |=  (1<<1))
#define NAND_CLEAR_RB      (NFSTAT |=  (1<<2))
#define NAND_DETECT_RB      { while(! (NFSTAT&(1<<2)) );}

#define BUSY 4
inline void wait_idle(void) {
while(!(NFSTAT & BUSY));
NFSTAT |= BUSY;
}

#define NAND_SECTOR_SIZE    512
#define NAND_BLOCK_MASK        (NAND_SECTOR_SIZE - 1)

/* low level nand read function */

/*下面nand_read_ll 的三个参数来自start.S里面调用nand_read_ll 前的r0r1r2*/
int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)
{
int i, j;
/*下面这个if保证对flash的读操作是从某一页的页头开始的,从直观来看是保证start_addr[0:8]位都为0
为什么呢?因为本flash的一页的大小位512-bytes,也就是从0x00x1ff*/
if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {
return -1;    /* invalid alignment */
}

NAND_CHIP_ENABLE;

for(i=start_addr; i < (start_addr + size);) {
/* READ0 */
NAND_CLEAR_RB;
         /* 到此应该可以明白s3c2440 nandflash 相关寄存器的确切含义了,就是说s3c2440里面已经集成了对nand flash

作的相关寄存器,只要你的nand flash接线符合s3c2440 datasheet的接法,就可以随便使用s3c2440 对于 nand
flash的相关寄存器,例如如果你想像nand flash写一个命令,那么只要对命令寄存器写入你的命令就可以了,s3c2440 可以自动帮你完成所有的时序动作,写地址也是一样。反过来说如果没有了对nand flash的支持,那么我们对nand falsh的操作就会增加好多对I/O口的控制,例如对CLE,ALE的控制。s3c2440已经帮我们完成了这部分工作了 */
NFCMD = 0;

        /* Write Address */

/*下面这个送地址的过程可以说是这段程序里最难懂的一部分了,难就难于为什么送进nand flash的地址忽略了bit8
纵观整个for(i) 循环,i并不是一个随机的地址,而应该是每一页的首地址。其实nand flash并不是忽略了bit 8这个
地址,而是bit 8早就被定下来了,什么时候定下来,就是上面的NFCMD = 0;语句,本flash (K9F1208U0B)支持从
半页开始读取,从而它有两个读的命令,分别是0x00(从一页的上半页开始读)0x01(从一页的下半页开始读)
当取0x00时,bit 8=0,当取0x01bit 8=1.*/
NFADDR = i & 0xff;
NFADDR = (i >> 9) & 0xff;
NFADDR = (i >> 17) & 0xff;
NFADDR = (i >> 25) & 0xff;

NAND_DETECT_RB;

for(j=0; j < NAND_SECTOR_SIZE; j++, i++) {
            *buf = (NFDATA & 0xff); /* 每读一次NANDFLASH就往IO口送下一个byte,直到送

NAND_SECTOR_SIZE 个为止*/
buf++;
}
}
NAND_CHIP_DISABLE;
return 0;
}
4. 修改board/qljt/qljt2440/Makefile文件,让刚刚添加的nand_read.c编译进来
......
COBJS := qljt2440.o  nand_read.o flash.o
......
/*===========================================================
到这里,应该是可以编译通过的,否则就是编辑的时候出现了错误
===========================================================*/
5. 修改 board/qljt/qljt2440/lowlevel_init.S文件
依照开发板的内存区的配置情况 , 修改 board/qljt/qljt2440/lowlevel_init.S文件, :
......
/* REFRESH parameter 下面这 6个配置都可以参考 s3c2440A datasheet P210REFRESH寄存器 */
#define REFEN             0x1    /* Refresh enable */
#define TREFMD             0x0    /* CBR(CAS before RAS)/Auto refresh */
#define Trp             0x01    /* 3clk 这个值可以参考本版子上的 SDRAMdatasheet*/
#define Trc             0x3    /* 也就是 SDRAM datasheet里面的 Tsrc 7clk 本来这个地方是 Trc,但从 lowlevel_init.S里面的调用来看,应该是寄存器REFRESH
Tsrc才对,好多地方都没有改过来,我我觉得只是个名字而已,不影响结果
注意:如果这里改了,那么下面这句中的 Trc也要改为相应的 Tsrc
.word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)*/
#define Tchr             0x2    /* 3clk,这个从 lowlevel_init.S里面的调用来看是属于 REFRESH的保留位,不知道为什
么还要给他赋值 */
#define REFCNT    1259 /*这个值的算法参考 s3c2440A datasheet P210的Refresh Counter */
/*下面不厌其烦地解析一下 lowlevel_init.S这个原文件 */
#define BWSCON  0x48000000
……
#define Tchr                      0x2   /* 3clk */
#define REFCNT                        0x0459
/**************************************/
/*1.要知道上面这些配置的最终会被用到下面SMRDATA 这个数据池里面,所以必须要明白SMRDATA 这个数据池是用
来干什么的,SMRDATA 后面每一个.word 后面防止的数据都是将要写入BWSCON 开始的寄存器的,总共有13.work ,它们后面放置的值将会分别别写入0x480000000x480000040x48000008…一直到0x4800003013个寄存器。 */
/*2.上面那些配置的值是怎样决定的呢,详细请参考s3c2440A和你所用SDRAMdatasheet。细心找总是能找到的。 */
/*3.而上面的那些配置值最终是通过下面lowlevel_init后面的这段函数写到寄存器里面的,下面对该段函数逐一分析: */
_TEXT_BASE:
         .word         TEXT_BASE
.globl lowlevel_init
lowlevel_init:
         /* memory control configuration */
         /* make r0 relative the current location so that it */
         /* reads SMRDATA out of FLASH rather than memory ! */
         ldr     r0, =SMRDATA
         ldr    r1, _TEXT_BASE
     sub   r0, r0, r1        /* 其实明白了前三条语句这段程序就不难懂了,归根到底就是为什么将SMRDATA 的值减
_TEXT_BASE的值?原因是这样的:我们使用的是从nandflash boot的方式,目前程序
仍然在4K-bytes ‘Steppingstone’(这里为什么突然冒出个Steppingstone’,这个就是我前面提到从nand flash 引导的方法,但不知道名字,后来重新看 s3c2440A  datasheetnand flash那一章的开头才知道)上面 运行,在SMRDATA后面的的内容仍然在Steppingstone里面。但是 SMRDATA的值是相对于_TEXT_BASE 值的地址,而且_TEXT_BASE 是放置u-boot的开始地方,所以用SMRDATA-_TEXT_BASE 就可以得到SMRDATA后面内容在Steppingstone里面 相对于地址0x00000000的放置的所在地方(相对于0x00的地址值) */
/*从这三条语句可以看出前人为了实现从nand flash启动可谓费尽心思啊! */
         ldr    r1, =BWSCON        /* Bus Width Status Controller */
         add     r2, r0, #13*4  /* 总共13个寄存器 */
0:
         ldr     r3, [r0], #4
         str     r3, [r1], #4
         cmp     r2, r0
         bne     0b
         /* everything is fine now */
         mov  pc, lr
         .ltorg         /* 数据缓冲池,上网可以查得资料 */
/* the literal pools origin */
SMRDATA:
   ……  
    .word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)
    .word 0xb2
.word 0x30       /*需要注意的是CAS Latency的值在这里直接配置 */
.word 0x30
/*===========================================================
到这里,应该是可以编译通过的,否则就是编辑的时候出现了错误
===========================================================*/
6 修改 /board/qljt/qljt2440/qljt2440.c,修改这个文件主要针对下面两点:
(1) GPIO的控制
(2) PLL,毕竟s3c2410跟s3c2440不同
修改其对 GPIOPLL的配置 (请参阅 SBC2440的硬件说明和 2440芯片手册 )......
#elif FCLK_SPEED==1 /* Fout = 405MHz */
//#define M_MDIV 0x5c
//#define M_PDIV 0x4
//#define M_SDIV 0x0
#define M_MDIV 0x7f
#define M_PDIV 0x2
#define M_SDIV 0x1
#elif USB_CLOCK==1
//#define U_M_MDIV 0x48
//#define U_M_PDIV 0x3
#define U_M_MDIV 0x38
#define U_M_PDIV 0x2
#define U_M_SDIV 0x2
......
/* set up the I/O ports */
gpio->GPACON = 0x007FFFFF;
// gpio->GPFCON = 0x000055AA;
gpio->GPFCON = 0x5500; /*for LED*/
......
/* arch number of S3C2440 -Board */
gd->bd->bi_arch_number = MACH_TYPE_S3C2440 ;
/* adress of boot parameters */
gd->bd->bi_boot_params = 0x30000100;
icache_enable();
dcache_enable();
gpio->GPFDAT = 0xbf; /*for LED*/
//int board_init (void)设置完成后, LED1LED2会亮起!
return 0;
}
/*===========================================================
到这里,应该是可以编译通过的,否则就是编辑的时候出现了错误
===========================================================*/
7. 为了实现NAND Flash的读写,再次修改/include/configs/qljt2440.h
......
/*
 * High Level Configuration Options
 * (easy to change)
 */
#define CONFIG_ARM920T        1    /* This is an ARM920T Core    */
//#define    CONFIG_S3C2410       1   /* in a SAMSUNG S3C2410 SoC     */
//#define CONFIG_SBC2410X        1   /* on a friendly-arm SBC-2410X Board  */

#define    CONFIG_S3C2440        1  /* 在前面很多地方调用到CONFIG_S3C2440 ,他是在这里定义  */
#define CONFIG_qljt2440    1  /* 针对一些本开发板配置的宏控制*/
......
/***********************************************************
 * Command definition
 ***********************************************************/
#define CONFIG_CMD_DHCP
#define CONFIG_CMD_ELF
#define CONFIG_CMD_PING    
#define CONFIG_CMD_NAND          
#define CONFIG_CMD_NET
#define CONFIG_CMD_ENV

/* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */
#include
#define    CFG_LONGHELP               
/* undef to save memory        */
#define    CFG_PROMPT   "[qljt2440]#" /*这个就是你启动开发板后命令行显示的内容了*/
/*Monitor Command Prompt  */
#define    CFG_CBSIZE        256       
/* Console I/O Buffer Size    */
......
#define    CFG_LOAD_ADDR      0x30008000   /*以后linux kernel就要放在这里执行 */
 /* default load address    */

......

//#define CFG_ENV_IS_IN_FLASH       1 /这里的flash应该是指nor了,都不知道外国人为什么这么默认/
#define    CFG_ENV_IS_IN_NAND    1 /*定义这个宏的目的是为了调用nand flash类型的saveenv
因为还有其它类型存储器的saveenv,在u-boot中查看saveenv
的定义,有多少中定义就有多少种*/
/*在linux对nand flash分区的时候,给u-boot分配256k的空间(0~0x40000)
其中 u-boot.bin    [0x0~0x30000]  占192K
而   u-boot的参数 [0x30000~0x40000] 占64k
*/
#define CFG_ENV_OFFSET  0x30000         
#define CFG_ENV_SIZE         0x10000
/*注意:网上很多地方都有关于CONFIG_CMD_NAND 、CFG_NAND_LEGACY、drivers/mtd/nand/nand.c中的nand_init()函数以及board/qljt/qljt2440/qljt2440.c中的nand_init()函数这四个东西的关系,但大多说的不清不楚,我把它门的关系用表格一一列出来,请参考附录。*/
#define CFG_NAND_LEGACY                  1
/*----------------------------------------------------------------------
 * NAND flash settings
 */
#if defined (CONFIG_CMD_NAND)
#define CFG_NAND_BASE 0x4E000000     /*这个鬼东西在drivers/mtd/nand/nand.c中被调用,它
是NAND控制寄存器的基地址*/
/* NandFlash控制器在SFR区起始寄存器地址 */
#define CFG_MAX_NAND_DEVICE 1
 /* 支持的最在Nand Flash数据 */
#define SECTORSIZE 512
/* 1页的大小 */
#define NAND_SECTOR_SIZE SECTORSIZE /*这两个东西好像也是多余的,备用吧,在次文章搜一下
就知道其它用到的地方也有定义*/
#define NAND_BLOCK_MASK 511         /*本flash一个block的大小-1*/
/* 页掩码 */
#define ADDR_COLUMN 1 /*意思是你所用的nandflash的Column地址占多少个字节*/
/* 一个字节的Column地址 */
#define ADDR_PAGE 3 /*意思是你所用的nandflash的(row)page地址占多少个字节*/
/* 3字节的页块地址!!!!!*/
#define ADDR_COLUMN_PAGE 4 /*意思是你所用的nandflash的column地址+page地址共占多少个字节*/
/* 总共4字节的页块地址!!!!! */
#define NAND_ChipID_UNKNOWN 0x00
/* 未知芯片的ID*/
#define NAND_MAX_FLOORS 1           /*怎样算一floor*/
#define NAND_MAX_CHIPS 1
/* Nand Flash命令层底层接口函数
*/
#define rNFCONF (*(volatile unsigned int *)0x4e000000)
#define rNFCONT (*(volatile unsigned int *)0x4e000004)
#define rNFCMD (*(volatile unsigned char *)0x4e000008)
#define rNFADDR (*(volatile unsigned char *)0x4e00000c)
#define rNFDATA (*(volatile unsigned char *)0x4e000010)
#define rNFSTAT (*(volatile unsigned int *)0x4e000020)
#define rNFECC (*(volatile unsigned int *)0x4e00002c)
/*下面部分内容是修改的 */
/* Nand Flash命令层底层接口函数 */
/*
#define NAND_WAIT_READY(nand)      NF_WaitRB()
#define NAND_DISABLE_CE(nand)        NF_SetCE(NFCE_HIGH)
#define NAND_ENABLE_CE(nand)         NF_SetCE(NFCE_LOW)
#define WRITE_NAND_COMMAND(d, adr) NF_Cmd(d)
#define WRITE_NAND_COMMANDW(d, adr)      NF_CmdW(d)
#define WRITE_NAND_ADDRESS(d, adr)    NF_Addr(d)
#define WRITE_NAND(d, adr)                 NF_Write(d)
#define READ_NAND(adr)                         NF_Read()
*/
#define WRITE_NAND_ADDRESS(d, adr) {rNFADDR = d;}
#define WRITE_NAND(d, adr) {rNFDATA = d;}
#define READ_NAND(adr) (rNFDATA)
#define NAND_WAIT_READY(nand) {while(!(rNFSTAT&(1<<0)));}
#define WRITE_NAND_COMMAND(d, adr) {rNFCMD = d;}
#define WRITE_NAND_COMMANDW(d, adr)    NF_CmdW(d)
# if defined(CONFIG_S3C2440)
#define NAND_DISABLE_CE(nand) {rNFCONT |= (1<<1);}
#define NAND_ENABLE_CE(nand) {rNFCONT &= ~(1<<1);}
#endif
# if defined(CONFIG_S3C2410)
#define NAND_DISABLE_CE(nand) {rNFCONF |= (1<<11);}
#define NAND_ENABLE_CE(nand) {rNFCONF &= ~(1<<11);}
#endif

/* 允许Nand Flash写校验 打开下面宏定义*/
#define CONFIG_MTD_NAND_VERIFY_WRITE 1
......
#endif    /* __CONFIG_H */
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->NFCONF = conf;
}

static inline void NF_Cmd(u8 cmd)
{
    S3C2410_NAND * const nand = S3C2410_GetBase_NAND();
    nand->NFCMD = cmd;
}

static inline void NF_CmdW(u8 cmd)
{
    NF_Cmd(cmd);
    udelay(1);
}

static inline void NF_Addr(u8 addr)
{
    S3C2410_NAND * const nand = S3C2410_GetBase_NAND();
    nand->NFADDR = addr;
}

static inline void NF_WaitRB(void)
{
    S3C2410_NAND * const nand = S3C2410_GetBase_NAND();
    while (!(nand->NFSTAT & (1<<0)));
}

static inline void NF_Write(u8 data)
{
    S3C2410_NAND * const nand = S3C2410_GetBase_NAND();
    nand->NFDATA = data;
}

static inline u8 NF_Read(void)
{
    S3C2410_NAND * const nand = S3C2410_GetBase_NAND();
    return(nand->NFDATA);
}

static inline u32 NF_Read_ECC(void)
{
    S3C2410_NAND * const nand = S3C2410_GetBase_NAND();
    return(nand->NFECC);
}

#if defined(CONFIG_S3C2440)
static inline void NF_Cont(u16 cont)
{
    S3C2410_NAND * const nand = S3C2410_GetBase_NAND();
    nand->NFCONT = cont;
}

static inline void NF_SetCE(NFCE_STATE s)
{
    S3C2410_NAND * const nand = S3C2410_GetBase_NAND();
    switch (s) {
    case NFCE_LOW:
        nand->NFCONT &= ~(1<<1);
        break;
    case NFCE_HIGH:
        nand->NFCONT |= (1<<1);
        break;
    }
}

static inline void NF_Init_ECC(void)
{
    S3C2410_NAND * const nand = S3C2410_GetBase_NAND();
    nand->NFCONT |= (1<<4);
}

#else
static inline void NF_SetCE(NFCE_STATE s)
{
    S3C2410_NAND * const nand = S3C2410_GetBase_NAND();
    switch (s) {
    case NFCE_LOW:
        nand->NFCONF &= ~(1<<11);
        break;
    case NFCE_HIGH:
        nand->NFCONF |= (1<<11);
        break;
    }
}

static inline void NF_Init_ECC(void)
{
    S3C2410_NAND * const nand = S3C2410_GetBase_NAND();
    nand->NFCONF |= (1<<12);
}
#endif /*对应#if defined(CONFIG_S3C2440)*/

static inline void NF_Init(void)
{
#if 0
#define TACLS 0
#define TWRPH0 3
#define TWRPH1 0
#else
#define TACLS 0
#define TWRPH0 4
#define TWRPH1 2
#endif

#if defined(CONFIG_S3C2440)
    NF_Conf((TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4));
    NF_Cont((0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(0<<6)|(0<<5)|(1<<4)|(0<<1)|(1<<0));
#else
    NF_Conf((1<<15)|(0<<14)|(0<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0));
    /*nand->NFCONF = (1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0); */
    /* 1 1 1 1, 1 xxx, r xxx, r xxx */
    /* En 512B 4step ECCR nFCE=H tACLS tWRPH0 tWRPH1 */
#endif
    NF_Reset();
}

#endif

9. cpu\arm920t\s3c24x0\ 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"
/*===========================================================
到这里,编译是不能通过的,原因上一节中CONFIG_S3C2410这个宏定义被注释掉,下面要用CONFIG_S3C2440这个宏打开CONFIG_S3C2410所打开的内容===========================================================*/
10.  在S3C2440与s3c2410能够共用的文件中添加“CONFIG_S3C2440”,使得原来s3c2410的代码可以编译进来。
(1)/include/common.h文件的第492行:/*一些公用的常用函数,例如get_fclk()*/
#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410) || defined(CONFIG_LH7A40X) || defined(CONFIG_S3C2440)
(2)/include/s3c24x0.h:文件的第85、95、99、110、148、404行:/*一些关于S3C2440寄存器的结构体*/
#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)
(3)/cpu/arm920t/s3c24x0/interrupts.c文件的第33行:/*主要把一些头文件包含进去*/
#if defined(CONFIG_S3C2400) || defined (CONFIG_S3C2410) || defined (CONFIG_TRAB) || defined (CONFIG_S3C2440)
第38行:
#elif defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)
(4)/cpu/arm920t/s3c24x0/serial.c文件的第22行:/*主要把一些头文件包含进去*/
#if defined(CONFIG_S3C2400) || defined (CONFIG_S3C2410) || defined (CONFIG_TRAB) || defined (CONFIG_S3C2440)
第26行:
#elif defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)
(5)/cpu/arm920t/s3c24x0/speed.c文件的第33行:
#if defined(CONFIG_S3C2400) || defined (CONFIG_S3C2410) || defined (CONFIG_TRAB) || defined (CONFIG_S3C2440)
第37行:
#elif defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)
顺便修改源代码,以匹配s3c2440:
static ulong get_PLLCLK(int pllreg)
{
......

m = ((r & 0xFF000) >> 12) + 8;
p = ((r & 0x003F0) >> 4) + 2;
s = r & 0x3;
//qljt  /*这两个PLL的算法参见S3C2440datasheet的254页*/
#if defined(CONFIG_S3C2440)
if (pllreg == MPLL)
return((CONFIG_SYS_CLK_FREQ * m * 2) / (p << s)); /* CONFIG_SYS_CLK_FREQ 在qljt2440.h中定义*/
    else if (pllreg == UPLL)
#endif
//qljt
return((CONFIG_SYS_CLK_FREQ * m) / (p << s));
}

......
/* return FCLK frequency */
ulong get_FCLK(void)
{
    return(get_PLLCLK(MPLL));
}
/* return HCLK frequency */
ulong get_HCLK(void)
{
    S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
 /*看看s3c2410与s3c2440的datasheet就知道s3c2440的HCLK可选择的值多很多*/
  if (clk_power->CLKDIVN & 0x6)   
  {/*这里注意:编译的时候发现CLKDIVN ,这个将会在12节解决*/
       if ((clk_power->CLKDIVN & 0x6)==2)        return(get_FCLK()/2);
if ((clk_power->CLKDIVN & 0x6)==6)        return((clk_power->CAMDIVN & 0x100) ? get_FCLK()/6 : get_FCLK()/3);         /*注意这里的CAMDIVN还没有被定义,在/include/s3c24x0.h中定义 */
      if ((clk_power->CLKDIVN & 0x6)==4)        return((clk_power->CAMDIVN & 0x200) ? get_FCLK()/8 : get_FCLK()/4);        
        return(get_FCLK());
 } 
 else   {
        return(get_FCLK());
     }
//    return((clk_power->CLKDIVN & 0x2) ? get_FCLK()/2 : get_FCLK());
}
......
(6)/cpu/arm920t/s3c24x0/usb_ohci.c文件的第45行:
#elif defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440)
(7)drivers/rtc/s3c24x0_rtc.c文件的第35行:
#elif defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440) 
(8)在文件中添加“defined(CONFIG_qljt2440)”,使得原来SBC2410X开发板的代码可以编译进来,
/cpu/arm920t/s3c24x0/interrupts.c文件的第181行: 
   #elif defined(CONFIG_SBC2410X) || \
      defined(CONFIG_SMDK2410) || \
      defined(CONFIG_VCMA9) || defined(CONFIG_qljt2440)
    tbclk = CFG_HZ;   /*对于CFG_HZ 的值,结合uboot的说明和s3c2440的datasheet就比较容易理解*/
#else
(9)/cpu/arm920t/s3c24x0/usb.c文件的第31行:
#elif defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)
(10)/cpu/arm920t/s3c24x0/i2c.c文件的第35行:
#elif defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)
第66、85、142、150、174行:
将“#ifdef CONFIG_S3C2410”改为
#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)
(11)drivers/usb/usb_ohci.c文件的第68行附近:
#if defined(CONFIG_ARM920T) || \
    defined(CONFIG_S3C2400) || \
    defined(CONFIG_S3C2410) || \
    defined(CONFIG_S3C2440) || \
    defined(CONFIG_440EP) || \
    defined(CONFIG_PCI_OHCI) || \
    defined(CONFIG_MPC5200)
11. 在/include/s3c24x0.h中加入2440 的NAND FLASH 寄存器定义和CAMDIVN定义:
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)  // 2440 的NAND FLASH 寄存器
typedef struct {
S3C24X0_REG32   NFCONF;
S3C24X0_REG32   NFCMD;
S3C24X0_REG32   NFADDR;
S3C24X0_REG32   NFDATA;
S3C24X0_REG32   NFSTAT;
S3C24X0_REG32   NFECC;
} S3C2410_NAND;
#endif
#if defined (CONFIG_S3C2440)
typedef struct {
S3C24X0_REG32   NFCONF;
S3C24X0_REG32   NFCONT;
S3C24X0_REG32   NFCMD;
S3C24X0_REG32   NFADDR;
S3C24X0_REG32   NFDATA;
S3C24X0_REG32   NFMECC0;
S3C24X0_REG32   NFMECC1;
S3C24X0_REG32   NFSECC;
S3C24X0_REG32   NFSTAT;
S3C24X0_REG32   NFESTAT0;
S3C24X0_REG32   NFESTAT1;
S3C24X0_REG32   NFECC;
} S3C2410_NAND;
#endif
12. 修改/lib_arm中的board.c。
......
#include
#include
#include
#include
#include
#include
#include  
 
......
13. 修改common/env_nand.c
......
#ifdef CONFIG_INFERNO
#error CONFIG_INFERNO not supported yet
#endif

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 < CFG_ENV_SIZE)
        return 1;
    puts ("Erasing Nand...\n");

/*在248行附近*/
//    if (nand_erase_opts(&nand_info[0], &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,&total, (u_char*)env_ptr);
 if (ret || total != CFG_ENV_SIZE)
        return 1;
    puts ("done\n");
    return ret;
}

#else /* ! CFG_ENV_OFFSET_REDUND */
.......
/*
 * 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)
    size_t total;
    int ret;

total = CFG_ENV_SIZE;

/*在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, &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->data, ENV_SIZE) != env_ptr->crc)
        return use_default();
#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

.......
//#ifndef CFG_NAND_LEGACY
#include
#include
#include
.......
//#endif /* !CFG_NAND_LEGACY */
/*===========================================================
到这里,应该是可以编译通过的,否则就是编辑的时候出现了错误
===========================================================*/
9、在 include/linux/mtd/nand_ids.h的结构体nand_flash_ids加入 /*至于这个结构体的值怎么得来,有待研究*/
static struct nand_flash_dev nand_flash_ids[] = {
....../*结构体nand_flash_dev 在doc2000.h中定义*/
/*厂家 型号,生产商编号,本模块的编号,总共容纳地址的位数,存储页字节数是否为256 地址需要多少字节数减一(行列地址总共) ,擦除1个block的大小,是否为16位总线 */
{"Samsung KM29N16000",NAND_MFR_SAMSUNG, 0x64, 21, 1, 2, 0x1000, 0},
{"Samsung K9F1208U0B",  NAND_MFR_SAMSUNG, 0x76, 26, 0, 3, 0x4000, 0},
    {"Samsung unknown 4Mb", NAND_MFR_SAMSUNG, 0x6b, 22, 0, 2, 0x2000, 0},
......
};
/*下面说说上面结构体的 8个参数是怎么得出来的,以便日后再次移植的时候会更换 nand flash*/
/*
1.“厂家 型号”:这个从 nand flashdatasheet就可以直接找到了吧。
2. 生产商的编号:也就是 datasheet里面的 Maker code,它也同时被存放在 nand flash里面的 ID(nand flash应该有一个读 ID命令的 )信息里面)。
3. 本模块的编号:也就是 datasheet里面的 device code,跟 Maker code一样它也被放到 ID信息里面。
4. 总共容纳的地址位数:也就是有效的地址位数。针对于本 flash(K9F1208U0M)可以参考它的 datasheet7页。
5. 一页所存储的字节数是否为 256个:针对于本 flash(K9F1208U0M)可以参考它的 datasheet7页。
6. 地址需要多少字节数减一 (行列地址总共 ):举个例子可能更容易明白,第 4点中可以知道本 flash(K9F1208U0M)26位,而对本 flash地址的写入每次只能写 8位,所以至少要写 4次才能把 26位地址写入本 flash4次的写入针对于编程来说就是 [0:3],所以本 falsh相对于该结构体的该变量的值是 3.
7. 擦除 1block的大小:简单来说就是 1block的大小,本 flash 1block=32 pages1 page=512 bytes,所以 1 block=512x32=16 k-bytes,也就是 0x4000
8. 是否为 16位总线:本 flash地址和数据总线共用,都是 8位的,所以上面值为 0
*/
15. 修改/lib_arm中的board.c。添加几个debug信息  (这一步可以不用修改)
......
#include
#include
#include
#include
#include
#include
......
static int display_banner (void)
{
S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
gpio->GPFDAT = 0x8f; //qljtninja
// 在串口初始化和console 初始化完成,串口输出信息之前,LED1 LED2 LED3 会亮起!
printf ("\n\n%s\n\n", version_string);
debug ("U-Boot code: %08lX -> %08lX BSS: -> %08lX\n",
_armboot_start, _bss_start, _bss_end);
printf ("U-Boot code: %08lX -> %08lX BSS: -> %08lX\n", //qljt
_armboot_start, _bss_start, _bss_end); //qljt
#ifdef CONFIG_MODEM_SUPPORT
debug ("Modem Support enabled\n");
#endif
#ifdef CONFIG_USE_IRQ
debug ("IRQ Stack: %08lx\n", IRQ_STACK_START);
debug ("FIQ Stack: %08lx\n", FIQ_STACK_START);
#endif

return (0);
}

......
void start_armboot (void)
{
init_fnc_t **init_fnc_ptr;
char *s;
#ifndef CFG_NO_FLASH
ulong size;
#endif
#if defined(CONFIG_VFD) || defined(CONFIG_LCD)
unsigned long addr;
#endif
S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
......
gpio->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 */
}
/*===========================================================
到这里,应该是可以编译通过的,否则就是编辑的时候出现了错误
===========================================================*/
16. 裁减flash的支持 (这一步也可以不执行)
(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
#undef CONFIG_CMD_IMLS
#endif
附录:
一.
U-boot的命令默认配置存放在/include/config_cmd_default.h里,可以修改该文件或者在qq2440.h里添加#undef里裁减不需要的内容
二.
1.u-boot-1.3.2(不含 u-boot-1.3.2)nand_init函数的调用关系,它的调用是被“ CONFIG_COMMANDS&
CFG_CMD_NAND”和“ CFG_NAND_LEGACY”控制的, 1:表示该值为真, 0:表示该值为假
CONFIG_COMMANDS&
CFG_CMD_NAND
CFG_NAND_LEGACY
/drivers/mtd/nand/nand.c中的
nand_init()函数
/board/qljt/qljt2440/qljt2440.c中的 nand_init()函数
0
0
0
0
0
1
0
0
1
0
1
1
1
1
0
1

u-boot-1.3.4 移植到S3C2440 (带有某些解析)相关推荐

  1. mplayer移植到S3C2440(二)

    相信大家在前面弄了下会发现在开发板上还是不能播放文件,这里还得修改下内核: 内核版本:2.6.12 编译器版本:arm-linux-gcc 3.4.1 1  修改/arch/arm/mach-s3c2 ...

  2. Spring Boot:(六)默认日志logback配置解析

    Spring Boot:(六)默认日志logback配置解析 前言 今天来介绍下Spring Boot如何配置日志logback,我刚学习的时候,是带着下面几个问题来查资料的,你呢 如何引入日志? 日 ...

  3. Spring Boot整合EasyExcel(完整版包含上传解析excel和下载模板)

    Spring Boot整合EasyExcel(完整版包含上传解析excel和下载模板) 1. 加入依赖 2. 对读取excel内容(批量添加) 3. 模板下载: 1. 加入依赖 <depende ...

  4. linux 内核2.6.35.3,linux-2.6.35.3内核移植(s3c2440)

    忙乎了一个下午,总算忙乎出来了,不过前期大量的搜索工作别人已经完成. 大量参考:http://blog.csdn.net /huihui1988/archive/2010/08/09/5799500. ...

  5. u-boot-1.3.4 移植到S3C2440

    2019独角兽企业重金招聘Python工程师标准>>> 一.预备知识: 1.       首先, U-Boot1.3.4 还没有支持 s3c2440 ,移植仍是用 2410 的文件稍 ...

  6. linux mpc boot 串口初始化,uboot移植阶段二--3串口终结篇

    2011-03-20 23:00:37 前天U-boot移植串口后,能成功显示数据. 今天的主要目的是再次进行U-boot移植.看是否成功.花了40分钟,很顺利. 接着就是要把之前有问题的U-boot ...

  7. Spring Boot Profile使用详解及配置源码解析

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 作者 | 二师兄 来源 | 程序新视界 在实践的过程中我 ...

  8. Spring Boot文档阅读笔记-对Messaging with RabbitMQ解析

    此篇教程以Rabbitmq作为消息队列服务端,使用Spring Boot产生和发布消息. 使用Spring AMQP的RabbitTemplate发布消息,使用MessageListenerAdapt ...

  9. 【2021最新版】Spring Boot面试题总结(92道题含答案解析)

    文章目录 1.什么是Spring Boot? 2.为什么要用SpringBoot? 3.Spring Boot有哪些优点? 4.Spring Boot的核心注解是哪个?它主要由哪几个注解组成的? 5. ...

最新文章

  1. SQL查询语句大全集锦(一)
  2. linux centos yum 报错 获取GPG密钥失败 Errno 14
  3. c/c++对象模型大总结:第5-8章、数据成员的存取与布局
  4. 雷林鹏分享:Ruby Web Services 应用 - SOAP4R
  5. ModalPopupExtender使用技巧( operate ModalPopupExtender by JavaScript)
  6. APPSCAN学习目录
  7. fit函数中verbose含义解释
  8. Mac与远程服务器数据交互软件Cyberduck
  9. 华为Mate20系列赢得各界盛誉,棋圣聂卫平也对其AI性能称赞
  10. 复利现值系数怎么用计算机计算,复利现值系数计算方法是怎样的?
  11. Python 绘制椭圆 平移 旋转
  12. 2021.7纪中快乐游记(下)
  13. Android 三星手机拍照图片旋转处理
  14. 全国各地DNS地址详细列表
  15. MySQL中聚合函数count的使用和性能优化
  16. echarts字变大_EChart 文字大小调整 饼状图为例
  17. pip install warning
  18. 【Mybatis】缓存
  19. 移动物联网卡资费标准,这样收费最划算
  20. CD2-pFed: Cyclic Distillation-guided Channel Decoupling for ModelPersonalization in Federated Lear论文

热门文章

  1. win10任务栏图标无法固定,也无法取消固定,
  2. 解决MySql登录 提示caching_sha2_password
  3. aix系统挂载nas
  4. butter滤波器是iir吗_MATLAB IIR滤波器设计函数buttord与butter
  5. 15000 字的 SQL 语句大全!
  6. 基于matlab的指纹识别程序
  7. 系统架构师(软考)------网络互联模型与常见的网络协议
  8. Android 应用签名
  9. 《笨方法学PYTHON》——fourteenthlesson
  10. 用CSS实现HTML图文混排