原创 【原创】移植U-Boot2009-01到阳初S3C2440超值版支持NAND启动,支持YAFFS文件

2009-8-27 09:41 3209 8 8 分类: MCU/ 嵌入式

移植U-Boot2009-01到阳初S<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />3C2440超值版支持NAND启动,支持YAFFS文件系统


参考了《移植U-Boot-2008.10到友善之臂mini2440


flyslightly.cublog.cn


 


要知道需要修改那些文件就要分析顶层Makefile【bootloader是什么?分为几个阶段?每阶段分别完成什么任务?】<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />


根据README,先要运行make <board_name>_config然后再运行make来生成uboot执行文件,根据makefile的语法这个<board_name>_config必然是makefile中定义的一个target,那么我们就要


①仿照其他的开发板来建立自己开发板的<board_name>_config,与我的开发板最相近的为smdk2410,所以根据smdk2410_config来写自己的gateway_config并加入到顶层makefile中;从顶层makefile中<board_name>_config目标的执行命令可以看出调用了mkconfig脚本,正常执行本脚本后应该会在./include中生成两个文件:config.mk和config.h并且会将输入的参数传递到ARCH、CPU、BOARD、VENDOR、SOC几个变量中,且在生成的config.h文件中将包含configs/$1.h文件,所以我们要


②在configs下建立自己开发板的.h头文件,可以通过拷贝相似开发板的头文件;


③修改子目录下的makefile;


④修改源文件中与2440不符的内容。


    一个调试方法就是用板子上已能正常跑起来的bootloader将刚改过编译好的uboot下载到内存中运行,具体操作为:定义CONFIG_SKIP_LOWLEVEL_INIT为1,或者注释掉start.s中


#ifndef CONFIG_SKIP_LOWLEVEL_INIT


   bl       cpu_init_crit


#endif


这三句中间的那句跳转,然后修改当前开发板目录下的config.mk中的text_base为0x33000000,使用vivi命令load ram 0x33000000 0x17ea8 x将u-boot.bin装入内存。再用go 0x33000000命令,即可。


 


·                     1、建立开发板目录,因为开发板跟smdk2440的硬件结构类似,而u-boot中最相近的配置为smdk2410,所以先复制smdk2410开发板目录为新的开发板目录:#cp -r /board/smdk2410 /board/hgateway。


·                     2、将开发板目录中的开发板配置文件更名#mv /board/smdk2410/smdk2410.c /board/smdk2410/hgateway.c。


·                     3、修改/board/hgateway下的makefile,将COBJS:=smdk2410.o flash.o改为COBJS:=hgateway.o flash.o


·                     4、在/include/configs下建立新的开发板配置头文件#cp /include/configs/smdk2410.h /include/configs/hgateway.h。


·                     5、修改顶层Makefile文件建立新开发板选项:在smdk2410_config:unconfig下增加:


        hgateway_config:unconfig


        @$(MCCONFIG)$(@:_config=)arm arm920t gateway NULL s3c24x0


注意还要改一点:__LIBS := $(subst $(obj),,$(LIBS)) $(subst $(obj),,$(LIBBOARD))


改为:__LIBS := $(subst $(obj),,$(LIBBOARD)) $(subst $(obj),,$(LIBS)) 网上说UBOOT1.3.3以后Makefile发生了变化,编译器会将我们添加唉的用于nandboot的子函数放到4k以后。这个可以通过比较查看System.map文件可知。(有时间真要把这个两个编译一下比较看看)


       这时执行#make hgateway_config&&make all可以顺利得到u-boot.bin文件了,但是别忘了这是对S3C2410的,并且是针对smdk2410开发板的,如果下到我们自己的开发板上,呵呵因为硬件配置不同,肯定是跑不起来的。下面就要更改源文件,编译出适合我们自己开发板的u-boot了。


·                     6、根据芯片Datasheet及板子的硬件配置更改相应的源文件,根据顶层makefile可知,跟移植相关的几个文件夹及文件为:cpu/arm920t/start.S;cpu/arm920t/s3c24x0/;lib_arm/;board/hgateway/。首先是CPU初始化的汇编文件,根据顶层Makefile的可知在/cpu/arm920t下的start.S文件,其次是cpu/soc/下的相关文件,再次是改include/config/<board_name>.h,然后就是更改跟板密切相关的/board/下的开发板子目录中的文件。(我的开发板的LED状况:LED1-GPF6,LED2-GPF7低电平亮)


·Ⅰ、更改/cpu/arm920t/start.S这是bootloader的stage1负责初始化硬件环境并把uboot从flash加载到RAM中,然后跳转到C语言中去。之所以后缀名为大写是因为start.S中有很多预处理,而GNU as是不能做宏处理和文件包含处理的,要处理这些宏只有交给CPP预处理器来做,查看GCC帮助可以看出要用大写的S才能。【来源于天行者博客vivi源码分析】,注意在这个文件中包含了config.h,而config.h是由mkconfig生成的,其中只有一句话"#include <configs/$1.h>",所以注意再更改完start.S及相关的启动文件后还要更改configs/$1.h中有关板子的配置。


                第一阶段流程:


·                                  异常向量表


·                                  置处理器为管理模式


·                                  关闭看门狗(加入对S3C2440的支持:defined(CONFIG_S3C2440))


·                                  关闭所有中断(S3C2440的INTSUBMSK寄存器有15位可用,加入对S3C2440的支持的代码)


·                                  设置LOCKTIME寄存器


·                                  设置摄像头时钟分频寄存器


·                                  设置时钟分频(S3C2440的时钟高达400M,设置分频为1:4:8)


·                                  设置写处理器P15给快时钟一个缓冲


·                                  写UPLLCON寄存器,使USB的PLL时钟生效


·                                  等待USB的PLL时钟生效


·                                  写MPLLCON寄存器,使主PLL生效,产生FCLK时钟


·                                  CPU初始化


                        关闭CACHE和MMU


                        底层硬件初始化(这里跟开发板密切相关,需要更改,主要更改lowlevel_init.S文件)


                    将UBOOT自己拷贝到RAM中(这里加上从NAND启动,因为S3C2440的NAND的前4K为自启动区,所以只要在4K范围内完成前面的工作及其自身的拷贝就可以了。这里加上的代码为对NAND的初始化,以及将UBOOT从NAND搬移到RAM的功能)


                    跳到C语言中完成第二阶段


分析start.S可知,在uboot中为了做到通用性,将跟特定SOC或开发板有关的初始化都放到板级目录下的lowlevel_init.S中去了。所以uboot的第一阶段初始化其实涉及到两个文件start.S和板级目录下的lowlevel_init.S


·Ⅱ、更改/board/hgateway/lowlever_init.S,此文件主要完成对储存器的初始化.


·                              1、因为S3C2410和S3C2440的内存控制寄存器的地址相同,所以寄存器的地址不用更改。


·                                          2、因为内存芯片可能不同,需要修改相应BANKCON的值。自己开发板所用的芯片为:HY57V566120FTP-H,RAS to CAS的延时最小要求20ns,若HCLK(就是提供给SDRAM的时钟)为100MHz的话,时钟周期为10ns,那么至少需要2个时钟周期,保险起见,可以多一点。如果要提升速度应该可以改小一点。这里按默认的2个时钟。


·Ⅲ、因为启动第一阶段的两个文件都引用了/config.h而/config.h中,只是包含了/include/configs/hgateway.h,在这个文件里配置了开发板的基本情况,包括晶振,网卡,网络MAC,IP,主机IP,分配内存空间,启动延时等。在其中添加上有关2440的配置,并修改。(这里面的uboot启动参数真是难设置啊)


·Ⅳ、在board/hgateway/中加入NAND读取函数(start.S中需要的nand_read_ll),文件nand_read.c


·Ⅴ、修改board/hgateway/Makefile,将nand_read.c编译进uboot:OBJS := mini2440.o nand_read.o flash.o


·Ⅵ、修改board/hgateway/hgateway.c中关于时钟的宏定义、GPIO的设置、开发板类型设置。


·Ⅶ、【在/common/cmd_nand.c中的do_nand函数中增加对nand write.yaffs命令的支持,让uboot支持烧写yaffs映像文件。在include/linux/mtd/mtd.h的 mtd_info 结构体定义中加入两个变量,在drivers/mtd/nand/nand_util.c的nand_write_skip_bad函数中加两段程序,一段是为了计算正常数据的长度,一段是为了在写入一段数据后,数据指针能正常跳到下一段数据,在/drivers/mtd/nand/nand_base.c的nand_write函数中,加入一段把正常数据与oob数据分离的代码,再加入页写时的模式设置为MTD_OOB_RAW,在页写时,不进行ECC的校验,ECC的校验在yaffs的oob数据中已自带了,不能重写。此模式下,写入正常数据后,会把oob的数据写入nand的oob区。『参考移植uboot2008.10到友善之臂mini2440』】


·Ⅷ、修改/cpu/arm920t/s3c24x0/nand.c,因为2440和2410的NAND控制寄存器不同,所以首先要修改寄存器定义的宏,


·Ⅸ、更改speed.c中的时钟计算公式


·Ⅹ、把其他文件中含有CONFIG_S3C2410的宏增加对CONFIG_S3C2440的定义(cpu/arm920t/s3c24x0/i2c.c,在相应的文件中把包含了CONFIG_SMDK2410的文件,增加CONFIG_GATEWAY2440


·Ⅺ、为了能将环境变量保存到NAND中,还要修改common/env_nand.c文件


·Ⅻ、修改\board\hgateway\u-boot.lds,在cpu/arm920t/start.o(.text)下增加一行board/hgateway/nand_read.o(.text)


·修改DM9000驱动,注释掉/drivers/net/dm9000x.c中与MII接口相关的语句


·编译、下载:#make distclean&&make hgateway_config&&make all,然后通过JFLASH,JSF或者是开发板原有的bootloader下载到NAND FLASH中,【uboot:首先把二进制文件下到ram中:loadb,然后利用nand write命令:nand write 内存地址 nand偏移地址『注意NAND也是从0地址开始的,所以在烧写bootloader的时候要从0地址开始写』 写入大小『要是页大小的整数倍』。还要注意写之前一定要先擦除。对于linux内核镜像,若是uImage可以用bootm来启动,若是zImage格式则可以用go来运行,当然也可以先处理后再用bootm来启动。把阳初的zImage烧到内存0x30008000地址处,然后用go 0x30008000命令来启动内核,结果停在了booting the kernel处。网上查到原因:是我的mach_type参数在传给内核的时候,参数不匹配才会一直卡在那里,在内核中mach_type在/arch/arm/tools中的mach_type文件中,在uboot中mach_type有hgateway.c中决定的我定义的为362。那么我们来查找阳初的vivi中开发板的mach_type为多少,在include/platform下有一句:#define MACH_TYPE   193.很明显两个参数不一样,所以修改内核中的参数增加MACH_TYPE_S3C2440 362的定义『/* adress of boot parameters */0x30000100』


·vivi中传递给内核的启动参数在linux_cmd[] 数组中。


·vivi中的很多设置在smdk.c文件中,GPIO寄存器的配置在SMDK2440.h中


·注意:uboot启动内核的命令是bootm,bootm会将一些内核用的到的参数传递到R0,R1,R2中,但是bootm只能处理由uboot工具mkimage生成的镜像。如果用go来运行ram中的内核可能导致不正常。


【mkimage -A arm -O linux -T kernel -C none -a 30008000 -e 30008040 -n linux-2.6.17.13 -d zImage uImage2.6.17.13


-A arm -------- 架构是arm


-O linux -------- 操作系统是linux


-T kernel -------- 类型是kernel


-C none -------- 压缩类型为无压缩


-a 30008000 ---- image的载入地址(hex)


-e 30008040 ---- 内核的入口地址(hex),因为信息头的大小是0x40


-n linux-2.6.17.13 --- image的名字


-d zImage ---- 无头信息的image文件名


uImage2.6.17.13 ---- 加了头信息之后的image文件名】【自带vivi:Linux command line: noinitrd init="/linuxrc" console="ttyS0" root="/dev/mtdblock/2" ma


c=00:01:5d:68:7a:0f,mach_type362】


 

1.         修改顶层Makefile,增加一行


hgateway_config    :      unconfig


       @$(MKCONFIG) $(@:_config=) arm arm920t hgateway NULL s3c24x0


hgateway为我的目标板名字。注意第二行前面有一个TAB,这是Makefile的语法规定的命令前面必须有个TAB5个参数顺序分别为:CPU架构(ARCH);CPU类型(CPU);开发板型号(BOARD);开发者/经销商(VENDER);片上系统(SOC)。


在《移植U-Boot-2008.10到友善之臂mini2440》中提到对于1.3.3版本以上的U-Boot还要修改__LIBS := $(subst $(obj),,$(LIBS)) $(subst $(obj),,$(LIBBOARD))__LIBS := $(subst $(obj),,$(LIBBOARD)) $(subst $(obj),,$(LIBS))才能保证nand_read_ll放在前4K中,我觉得这里不改,而改链接文件,将nand_read.o放到代码段的前面也是一样的。


2.         修改/cpu/arm920t/start.S


a)         删除关于AR91RM9200的代码


#include <status_led.h>


……


bl coloured_LED_init


bl red_LED_on


……


#if   defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK)


       /*


        * relocate exception table


        */


       ldr   r0, =_start


       ldr   r1, =0x0


       mov r2, #16


copyex:


       subs r2, r2, #1


       ldr   r3, [r0], #4


       str    r3, [r1], #4


       bne  copyex


#endif


b)        修改为对S3C2440的支持


#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)改为


#if defined (CONFIG_S3C2440) 


c)         删除关于2400的部分


# if defined(CONFIG_S3C2400)


#  define pWTCON             0x15300000


#  define INTMSK              0x14400008    /* Interupt-Controller base addresses */


#  define CLKDIVN     0x14800014    /* clock divisor register */


#else


d)        增加S3C2440的时钟控制寄存器


#     define CAMDIVN              0x4C000018  


//CAMDIVN 2440增加了摄像头,CAMDIVN将影响到CLKDIVN


#     define MPLLCON              0x4C000004   //MPLLCON register


#     define UPLLCON        0x4C000008   //UPLLCON register


e)         去掉宏# if defined(CONFIG_S3C2410)并修改子中断屏蔽控制寄存器的值


ldr   r1, =0x7ff


       ldr   r0, =INTSUBMSK


       str    r1, [r0]


改为      


ldr   r1, =0x7fff


       ldr   r0, =INTSUBMSK


       str    r1, [r0]


f)         增加PLL的初始化,对于S3C2440来说,只有当PLL初始化以后CPU才能按照设定的时钟进行工作,即使全部用初始值也必须重新写一次PLL


//初始化时钟,晶振为12MHz,主频为405MHz


//locktime用来在正常运行时更改时钟的时候保护时钟


       ldr r0,=LOCKTIME


       mov r1,#0xffffff


       str r1,[r0]


//清除摄像头分频寄存器值 


       ldr r0,=CAMDIVN


       mov r1,#0


       str r1,[r0]


修改时钟分频为148


       ldr   r0, =CLKDIVN


       mov r1, #3


       str    r1, [r0]


改为


ldr   r0, =CLKDIVN


mov r1, #5


str    r1, [r0]


在其后增加对UPLLMPLL的初始设置


//2440的手册中写着若HDIVN不为0,则需要下面几句 


       mrc  p15, 0, r1, c1, c0, 0              @ read ctrl register


       orr   r1, r1, #0xc0000000             @ Asynchronous 


       mcr  p15, 0, r1, c1, c0, 0              @ write ctrl register


//USB时钟48MHz       (56<<12)+(2<<4)+(2)


       ldr   r0, =UPLLCON


       ldr   r1, =0x00038022


       str    r1, [r0]


//arm920t5级流水线,延迟几个周期,使指令生效


       nop


       nop


       nop


       nop


       nop


       nop


       nop


       nop


//MPLL使pll生效,405MHz(127<<12)+(2<<4)+(1)


       ldr   r0, =MPLLCON


       ldr   r1, =0x0007f021


       str    r1, [r0]


# endif   


g)        U-Boot中本是FlashRAM的重定向代码,改为NANDRAM的重定向代码


删除


#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    


新增NAND初始化及重定向代码


//这段代码即VIVI中的copy_myself,但要注意24402410NAND寄存器不同


       @ reset NAND


       mov r1, #NAND_CTL_BASE                            //0x4E000000


       ldr   r2, =( (7<<12)|(7<<8)|(7<<4)|(0<<0) )


       str    r2, [r1, #oNFCONF]                                 //根据手册设置NAND


       ldr   r2, [r1, #oNFCONF]


 


       ldr   r2, =( (1<<4)|(0<<1)|(1<<0) ) @ Active low CE Control


       str    r2, [r1, #oNFCONT]     //允许片选,允许NAND Flash控制寄存器


       ldr   r2, [r1, #oNFCONT]


 


       ldr   r2, =(0x6)             @ RnB Clear


       str    r2, [r1, #oNFSTAT]              //清除忙标志,Rnb_TransDetect位写“1即可清楚忙标志


       ldr   r2, [r1, #oNFSTAT]


      


       mov r2, #0xff        @ RESET command     //发送复位命令


       strb  r2, [r1, #oNFCMD]


       mov r3, #0                    @ wait


1:    add  r3, r3, #0x1


       cmp r3, #0xa


       blt   1b


2:    ldr   r2, [r1, #oNFSTAT]       @ wait ready        


//等待前一次操作完成,通过判断Rnb_TransDetect位实现


       tst    r2, #0x4


       beq  2b


 


       ldr   r2, [r1, #oNFCONT]


       orr   r2, r2, #0x2           @ Flash Memory Chip Disable


       str    r2, [r1, #oNFCONT]            // 关闭片选,到这里只是完成了NAND初始化。


 


       @ get read to call C functions (for nand_read())         //C准备堆栈


       ldr   sp, DW_STACK_START       @ setup stack pointer


       mov fp, #0                    @ no previous frame, so fp="0"


 


       @ copy vivi to RAM


//r0,r1,r2为传递给C的参数


       ldr          r0,=TEXT_BASE   //数据存放位置,即要拷贝到哪里


       mov     r1, #0x0               //拷贝的起始地址


       mov r2, #0x30000                //拷贝长度


       bl    nand_read_ll                 //跳到C语言中


 


       tst    r0, #0x0         //nand_read_ll返回0则读取成功


       beq  ok_nand_read


      


bad_nand_read:


       1:    b     1b           @ infinite loop     


//为什么读取错误时设一个无限循?这样不是启动不来了么?为什么不重新读取


      


ok_nand_read:


       @ verify


      


       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        //比较前4K的内容是否拷贝正确


       subs r2, r2, #4


       beq  stack_setup


       bne  go_next


      


notmatch:


1:    b     1b


 


#endif    // CONFIG_S3C2440_NAND_BOOT


3.         /board子目录中建立自己的目标板hgateway目录


a)         复制/board/smdk2410/board/hgateway


b)        更改smdk2410.cgateway.c


c)         增加NAND Flash读取函数,复制VIVI中的nand_read.c/board/hgateway


nand_read.c


#include <config.h>


 


#define __REGb(x)       (*(volatile unsigned char *)(x))


#define __REGi(x) (*(volatile unsigned int *)(x))


#define NF_BASE        0x4e000000           //定义NAND 控制寄存器


 


#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 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) {        //等待NAND操作完成


       while(!(NFSTAT & BUSY));


       NFSTAT |= BUSY;


}


 


#define NAND_SECTOR_SIZE   512  /      /页大小


#define NAND_BLOCK_MASK          (NAND_SECTOR_SIZE - 1)


 


/* low level nand read function */


//底层NAND读取函数


int


nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)


{


       int i, j;


 


//检测是否达到NAND页边缘,若超过边界就返回-1


       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;         //清除忙标志


              NFCMD = 0;                       //发送读取前半页命令


 


              /* Write Address */               //写入读取地址


              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);


                     buf++;


              }


       }


       NAND_CHIP_DISABLE;                   //关片选,读取函数结束


       return 0;


}


d)        修改lowlevel_init.S


BANK3DM9000ABANK6RAM,注意BANK6BANK7要设置成相同的值


修改SDRAM的刷新时间


#define REFCNT                 1259       /* period="7".9us, HCLK="100Mhz", (2048+1-7.9*100) */


7.9us的周期是因为手册上写着68ms/8192clk


e)         修改hgateway.c


根据手册修改时钟


#define FCLK_SPEED 1


 


//将时钟改为2440405MHz


#if FCLK_SPEED==0          /* Fout = 532MHz, Fin = 12MHz for Audio */


#define M_MDIV   0x7d


#define M_PDIV    0x1


#define M_SDIV    0x1


#elif FCLK_SPEED==1              /* Fout = 405MHz */


#define M_MDIV   0x7f


#define M_PDIV    0x2


#define M_SDIV    0x1


#endif


 


#define USB_CLOCK 1


 


#if USB_CLOCK==0


#define U_M_MDIV     0x38       //96MHz


#define U_M_PDIV      0x2


#define U_M_SDIV      0x1


#elif USB_CLOCK==1                //48MHz


#define U_M_MDIV     0x38


#define U_M_PDIV      0x2


#define U_M_SDIV      0x2


#endif


board_init()函数中可以加入一些点灯操作。以便调试方便。


f)         修改此目录下的Makefile


COBJS    := smdk2410.o flash.o改为:COBJS   := hgateway.o nand_read.o flash.o


g)        修改链接脚本u-boot.lds


       .text      :


       {


         cpu/arm920t/start.o    (.text)


         *(.text)


       }


改为


       .text      :


       {


         cpu/arm920t/start.o    (.text)


         board/hgateway/lowlevel_init.o(.text)


         board/hgateway/nand_read.o(.text)


         *(.text)


       }


确保把lowlevel_init.Snand_read.c放到代码的前面。


4.         修改/cpu/arm920t/s3c24x0/nand.c


加入S3C2440NAND控制寄存器地址


#if defined(CONFIG_S3C2440)   //增加对2440NAND FLASH控制寄存器的定义


 


#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 NFMECCD0     __REGi(NF_BASE + 0x14)


#define NFMECCD1     __REGi(NF_BASE + 0x18)


#define NFSECCD        __REGi(NF_BASE + 0x1C)


#define NFSTAT           __REGb(NF_BASE + 0x20)


#define NFSTAT0          __REGb(NF_BASE + 0x24)


#define NFSTAT1          __REGb(NF_BASE + 0x28)


#define NFMECC0        __REGb(NF_BASE + 0x2C)


#define NFMECC1        __REGb(NF_BASE + 0x30)


#define NFSECC          __REGb(NF_BASE + 0x34)


#define NFSBLK          __REGb(NF_BASE + 0x38)


#define NFEBLK          __REGb(NF_BASE + 0x3C)


 


#define S3C2440_NFCONT_nCE (1<<1)


#define S3C2440_ADDR_NALE  0x0c


#define S3C2440_ADDR_NCLE  0x08


 


#endif


以下参考《移植U-Boot-2008.10到友善之臂mini2440


u-boot.2008.10自带的S3C2410s3c2410_hwcontrol函数有错在此函数中,把chip->IO_ADDR_W值改写了,导致在写数据时出现错误。解决方法是使用一全局变量代替 chip->IO_ADDR_W。在 s3c2410_hwcontrol 函数上一行定义这个全局变量,然后修改 s3c2410_hwcontrol 函数,让它支持 S3C2440,修改后如下:


 


#define S3C2410_ADDR_NCLE 8


 


ulong IO_ADDR_W = NF_BASE;


 static void s3c2410_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)


 {


        struct nand_chip *chip = mtd->priv;


 


        DEBUGN("hwcontrol(): 0x%02x 0x%02x\n", cmd, ctrl);


 


#if defined(CONFIG_S3C2410)


        if (ctrl & NAND_CTRL_CHANGE) {


                //ulong IO_ADDR_W = NF_BASE;


               IO_ADDR_W = NF_BASE;


               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)


                       NFCONF &= ~S3C2410_NFCONF_nFCE;


……


 


        }


 


        if (cmd != NAND_CMD_NONE)


               //writeb(cmd, chip->IO_ADDR_W);


               writeb(cmd,(void *)IO_ADDR_W);


#endif


#if defined(CONFIG_S3C2440)


        if (ctrl & NAND_CTRL_CHANGE) {


               IO_ADDR_W = NF_BASE;


               if (!(ctrl & NAND_CLE)) //要写的是地址


                       {


                       IO_ADDR_W |= S3C2440_ADDR_NALE;}


               if (!(ctrl & NAND_ALE)) //要写的是命令


                       {


                       IO_ADDR_W |= S3C2440_ADDR_NCLE;}


 


               //chip->IO_ADDR_W = (void *)IO_ADDR_W;


 


               if (ctrl & NAND_NCE)  


                       {NFCONT &= ~S3C2440_NFCONT_nCE; //使能nand flash


                       //DEBUGN("NFCONT is 0x%x ",NFCONT);


                       //DEBUGN("nand Enable ");


                       }


               else


                       {NFCONT |= S3C2440_NFCONT_nCE;  //禁止nand flash


                       //DEBUGN("nand disable ");


                       }


        }


 


        if (cmd != NAND_CMD_NONE)


               writeb(cmd,(void *)IO_ADDR_W);


               //writeb(cmd, chip->IO_ADDR_W);


#endif


}


 


修改board_nand_init 函数如下:


 


        DEBUGN("board_nand_init()\n");


 


        clk_power->CLKCON |= (1 << 4);


 


  #if  defined(CONFIG_S3C2410)
           DEBUGN("CONFIG_S3C2410\n");


        /* initialize hardware */


        twrph0 = 3; twrph1 = 0; tacls = 0;


 


……


        nand->cmd_ctrl = s3c2410_hwcontrol;


 


        nand->dev_ready = s3c2410_dev_ready;


#else


#if defined(CONFIG_S3C2440)


        DEBUGN("CONFIG_S3C2440\n");


        twrph0 = 4; twrph1 = 2; tacls = 0;


        cfg = (tacls<<12)|(twrph0<<8)|(twrph1<<4);


        NFCONF = cfg;


        //DEBUGN("cfg is %x\n",cfg);


        //DEBUGN("NFCONF is %lx\n",NFCONF);


        cfg = (1<<6)|(1<<4)|(0<<1)|(1<<0);


        NFCONT = cfg;


        //DEBUGN("cfg is %lx\n",cfg);


        //DEBUGN("NFCONT is %x\n",NFCONT);


/* initialize nand_chip data structure */


        nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)0x4e000010;


 


        /* read_buf and write_buf are default */


        /* read_byte and write_byte are default */


 


        /* hwcontrol always must be implemented */


        nand->cmd_ctrl = s3c2410_hwcontrol;


 


        nand->dev_ready = s3c2410_dev_ready;


#endif


#endif


 


 #ifdef CONFIG_S3C2410_NAND_HWECC


5.         修改/cpu/arm920t/s3c24x0/speed.c


这部分代码是配置PLL及内核总线频率的


a)         修改FCLK的计算公式:


#if defined(CONFIG_S3C2440)


              if(pllreg == MPLL)


                     return((CONFIG_SYS_CLK_FREQ * m*2) / (p << s));


              else if(pllreg == UPLL)


#endif    


        return((CONFIG_SYS_CLK_FREQ * m) / (p << s));


b)        修改HCLK的配置


#if defined(CONFIG_S3C2440)


       if(clk_power->CLKDIVN & 0x6){


              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);


              if((clk_power->CLKDIVN & 0x6)==4)


                     return ((clk_power->CAMDIVN & 0x200)? get_FCLK()/8 : get_FCLK()/4);


              return(get_FCLK());


       }


       else return(get_FCLK());


#else


    return((clk_power->CLKDIVN & 0x2) ? get_FCLK()/2 : get_FCLK());


#endif


6.         修改/common/cmd_nand.c中的do_nand函数加入对yaffs写的支持。


a)         在对jffs2操作的下面加入:


else if(s!= NULL && !strcmp(s,".yaffs")){  //支持yaffs文件的写入


                     if(read){


                            printf("nand read.yaffs is not provide!");


                            }


                     else{


                            nand->writeoob=1;


                            ret = nand_write_skip_bad(nand,off,&size,(u_char *)addr);


                            nand->writeoob=0;


                            }


b)        nand命令说明中加入对nand write yaffs的描述:


          "nand write.yaffs - addr off|partition size\n"


          "       write 'size' bytes starting at offset 'off'\n"


          "       to/from yaffs image in memory address 'addr',skipping bad blocks.\n"


c)         /include/linux/mtd/mtd.h中的mtd_info结构体定义中加入两个变量:


struct mtd_info {


    u_char writeoob;


    u_char skipfirstblock;


//上面两个是根据增加yaffs文件支持添加的变量 


d)       /drivers/mtd/nand/nand_util.cnand_write_skip_bad函数中加入两段程序


//计算正常数据的长度,从yaffs映像中提取要写入的正常数据长度,即去掉oob数据长度


    int rval;


    size_t left_to_write = *length;


    size_t len_incl_bad;


    u_char *p_buffer = buffer;


    if(nand->writeoob == 1){


        size_t oobsize = nand->oobsize;


        size_t datasize = nand->writesize;


 


        int datapages = 0;     


if(((*length)%(nand->oobsize+nand->writesize))!= 0){


            printf("Attemp to write error length data!\n");


            return -EINVAL;


        }


        datapages = *length/(datasize+oobsize);


        *length = datapages*datasize;


        left_to_write = *length;


        nand->skipfirstblock = 1;


    }


while (left_to_write > 0)循环中添加指针移动的代码


        left_to_write -= write_size;


        //添加的使指针正常移动的代码


        printf("%ld%%is complete.",100-(left_to_write/(*length/100)));


        offset      += write_size;


        //p_buffer      += write_size;


        if(nand->writeoob == 1){


            p_buffer += write_size+(write_size/nand->writesize*nand->oobsize); 


        }


        else{


            p_buffer += write_size;


        }


e)       /drivers/mtd/nand/nand_base.cnand_write函数中,加入一段把正常数据与oob数据分离的代码,再加入页写时的模式设置为MTD_OOB_RAW,在页写时,不进行ECC的校验,ECC的校验在yaffsoob数据中已自带了,不能重写。此模式下,写入正常数据后,会把oob的数据写入nandoob区。修改后如下:


static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
     size_t *retlen, const uint8_t *buf)


{


        struct nand_chip *chip = mtd->priv;


        int ret;


        //printf("0 len is %d ",len);


        //此段数据是将要写入的数据中的正常数据移到buf中的前段,把oob数据移到后段。


        int oldopsmode = 0;


        if(mtd->writeoob==1)


        {


 


               size_t oobsize = mtd->oobsize;  //定义oobsize的大小


               size_t datasize = mtd->writesize;


               int i = 0;


               uint8_t oobtemp[16];


               int datapages = 0;


               datapages = len/(datasize); //传进来的len是没有包括oob的数据长度


               for(i=0;i<(datapages);i++)


               {


                       memcpy(oobtemp,buf+datasize*(i+1),oobsize);


               memmove(buf+datasize*(i+1),buf+datasize*(i+1)+oobsize,(datapages-(i+1))*(datasize)+(datapages-1)*oobsize);


                       memcpy(buf+(datapages)*(datasize+oobsize)-oobsize,oobtemp,oobsize);


               }


 


        }


 


        //printf("1 len is %d ",len);


        /* Do not allow reads past end of device */


        if ((to + len) > mtd->size)


               return -EINVAL;


        if (!len)


               //return 0;


               {printf("Write data length is %d ",len);return 0;}


 


        nand_get_device(chip, mtd, FL_WRITING);


 


        chip->ops.len = len;


        chip->ops.datbuf = (uint8_t *)buf;


        //chip->ops.oobbuf = NULL;


 


        if(mtd->writeoob!=1)


        {


               chip->ops.oobbuf = NULL;


        }


        else


        {


               chip->ops.oobbuf = (uint8_t *)(buf+len); //oob缓存的指针指向buf的后段,即oob数据区的起始地址。


               chip->ops.ooblen = mtd->oobsize;


               oldopsmode = chip->ops.mode;


               chip->ops.mode = MTD_OOB_RAW;            //将写入模式改为直接书写oob区,即写入数据时,不进行ECC校验的计算和写入。(yaffs映像的oob数据中,本身就带有ECC校验)


        }


7.       修改DM9000驱动


修改/drivers/net/dm9000x.c


注释掉与MII接口相关的语句


#if 0


    i = 0;


    while (!(phy_read(1) & 0x20)) { /* autonegation complete bit */


        udelay(1000);


        i++;


        if (i == 10000) {


            printf("could not establish link\n");


            return 0;


        }


    }


 


    /* see what we've got */


    lnk = phy_read(17) >> 12;


    printf("operating at ");


    。。。。。。


    }


    printf("mode\n");


#endif


8.       修改/include/configs/hgateway.h头文件


#define CONFIG_S3C2410      1   /* in a SAMSUNG S3C2410 SoC     */


#define CONFIG_SMDK2410     1   /* on a SAMSUNG SMDK2410 Board  */


改为


#define CONFIG_S3C2440          1


#define CONFIG_GATEWAY2440      1


网卡的配置改为


//DM9000的配置


#define CONFIG_DRIVER_DM9000    1


#define CONFIG_DM9000_USE_16BIT 1


#define CONFIG_DM9000_BASE  0x20000300    


#define DM9000_IO               0x20000300          //I/O的默认基址为300


#define DM9000_DATA              0x20000304         //数据端口


 


添加配置


#define CONFIG_CMD_PING


#define CONFIG_CMD_NFS                      //支持NFS


#define CONFIG_CMDLINE_TAG          1   //允许给内核传递参数,下面三个必须配置


#define CONFIG_SETUP_MEMORY_TAGS    1


#define CONFIG_INITRD_TAG           1


#define CONFIG_CMD_NAND             1


#define CONFIG_CMDLINE_EDITING


 


//NAND FLASH设置


#if defined(CONFIG_CMD_NAND)


#define CONFIG_SYS_NAND_BASE            0x4E000000


#define CONFIG_SYS_MAX_NAND_DEVICE      1


#define CONFIG_MTD_NAND_VERIFY_WRITE    1


#define CONFIG_MAX_NAND_DEVICE          1


#define NAND_MAX_CHIPS                  1


//#define NAND_SECTOR_SIZE


//#define NAND_BLOCK_MASK


#define SECTORSIZE                  512         //一页的大小


 


/////NAND中保存uboot参数(SAVEENV功能)


#define CONFIG_CMD_ENV          //支持saveenv命令


#define CONFIG_ENV_IS_IN_NAND       1


#define CONFIG_ENV_OFFSET       0x30000 //参数在NAND中的起始位置


 


//#define   CONFIG_ENV_IS_IN_FLASH  1


#define CONFIG_ENV_SIZE     0x10000 /* Total Size of Environment Sector */


 


//////NAND Flash启动设置的一些寄存器


#define CONFIG_S3C2440_NAND_BOOT    1


#define STACK_BASE  0x33F00000


#define STACK_SIZE  0x8000


 


#define NAND_CTL_BASE   0x4e000000


#define bINT_CTL(Nb)    __REG(INT_CTL_BASE+(Nb))


 


#define oNFCONF     0x00


#define oNFCONT     0x04


#define oNFCMD      0x08


#define oNFADDR     0x0C


#define oNFDATA     0x10


#define oNFSTAT     0x20


#define oNFECC      0x2C


#define rNFCONF     (*(volatile unsigned int *)0x4e000000)


#define rNFCONT     (*(volatile unsigned int *)0x4e000004)


#define rNFCMD      (*(volatile unsigned int *)0x4e000008)


#define rNFADDR     (*(volatile unsigned int *)0x4e00000C)


#define rNFDATA     (*(volatile unsigned int *)0x4e000010)


#define rNFSTAT     (*(volatile unsigned int *)0x4e000020)


#define rNFECC      (*(volatile unsigned int *)0x4e00002C)


9.       然后在其他所有包含define(CONFIG_S3C2410)的地方改为:


define(CONFIG_S3C2410)|| define(CONFIG_S3C2440)


CONFIG_SMDK2410改为


define(CONFIG_SMDK2410)|| define(CONFIG_GATEWAY2440)


 

doc

文章评论0条评论)

登录后参与讨论
我要评论
0
8
关闭 站长推荐上一条 /2 下一条