DIY编程器网

标题: 嵌入式Linux开发环境的搭建之:U-Boot移植 [打印本页]

作者: admin    时间: 2014-10-10 07:37
标题: 嵌入式Linux开发环境的搭建之:U-Boot移植
        5.2  U-Boot移植

        5.2.1  Bootloader介绍

        1.概念

        简单地说,Bootloader就是在操作系统内核运行之前运行的一段程序,它类似于PC机中的BIOS程序。通过这段程序,可以完成硬件设备的初始化,并建立内存空间的映射关系,从而将系统的软硬件环境带到一个合适的状态,为最终加载系统内核做好准备。
         
        通常,Bootloader比较依赖于硬件平台,特别是在嵌入式系统中,更为如此。因此,在嵌入式世界里建立一个通用的Bootloader是一件比较困难的事情。尽管如此,仍然可以对Bootloader归纳出一些通用的概念来指导面向用户定制的Bootloader设计与实现。
         
        (1)Bootloader所支持的CPU和嵌入式开发板。
        每种不同的CPU体系结构都有不同的Bootloader。有些Bootloader也支持多种体系结构的CPU,如后面要介绍的U-Boot支持ARM、MIPS、PowerPC等众多体系结构。除了依赖于CPU的体系结构外,Bootloader实际上也依赖于具体的嵌入式板级设备的配置。
         
        (2)Bootloader的存储位置。
        系统加电或复位后,所有的CPU通常都从某个由CPU制造商预先安排的地址上取指令。而基于CPU构建的嵌入式系统通常都有某种类型的固态存储设备(比如ROM、EEPROM或Flash等)被映射到这个预先安排的地址上。因此在系统加电后,CPU将首先执行Bootloader程序。
         
        (3)Bootloader的启动过程分为单阶段和多阶段两种。通常多阶段的Bootloader能提供更为复杂的功能,以及更好的可移植性。
         
        (4)Bootloader的操作模式。大多数Bootloader都包含两种不同的操作模式:“启动加载”模式和“下载”模式,这种区别仅对于开发人员才有意义。
         
        n 启动加载模式:这种模式也称为“自主”模式。也就是Bootloader从目标机上的某个固态存储设备上将操作系统加载到RAM中运行,整个过程并没有用户的介入。这种模式是嵌入式产品发布时的通用模式。
         
        n 下载模式:在这种模式下,目标机上的Bootloader将通过串口连接或网络连接等通信手段从主机(Host)下载文件,比如:下载内核映像和根文件系统映像等。从主机下载的文件通常首先被Bootloader保存到目标机的RAM中,然后再被Bootloader写入到目标机上的Flash类固态存储设备中。Bootloader的这种模式在系统更新时使用。工作于这种模式下的Bootloader通常都会向它的终端用户提供一个简单的命令行接口。
         
        (5)Bootloader与主机之间进行文件传输所用的通信设备及协议,最常见的情况就是,目标机上的Bootloader通过串口与主机之间进行文件传输,传输协议通常是xmodem/ ymodem/zmodem等。但是,串口传输的速度是有限的,因此通过以太网连接并借助TFTP等协议来下载文件是个更好的选择。
         
        2.Bootloader启动流程

        Bootloader的启动流程一般分为两个阶段:stage1和stage2,下面分别对这两个阶段进行讲解。
         
        (1)Bootloader的stage1。
        在stage1中Bootloader主要完成以下工作。
        n 基本的硬件初始化,包括屏蔽所有的中断、设置CPU的速度和时钟频率、RAM初始化、初始化外围设备、关闭CPU内部指令和数据cache等。
        n 为加载stage2准备RAM空间,通常为了获得更快的执行速度,通常把stage2加载到RAM空间中来执行,因此必须为加载Bootloader的stage2准备好一段可用的RAM空间。
        n 复制stage2到RAM中,在这里要确定两点:①stage2的可执行映像在固态存储设备的存放起始地址和终止地址;②RAM空间的起始地址。
        n 设置堆栈指针sp,这是为执行stage2的C语言代码做好准备。
         
        (2)Bootloader的stage2。
        在stage2中Bootloader主要完成以下工作。
        n 用汇编语言跳转到main入口函数。
        由于stage2的代码通常用C语言来实现,目的是实现更复杂的功能和取得更好的代码可读性和可移植性。但是与普通C语言应用程序不同的是,在编译和链接Bootloader这样的程序时,不能使用glibc库中的任何支持函数。
        n 初始化本阶段要使用到的硬件设备,包括初始化串口、初始化计时器等。在初始化这些设备之前可以输出一些打印信息。
        n 检测系统的内存映射,所谓内存映射就是指在整个4GB物理地址空间中指出哪些地址范围被分配用来寻址系统的内存。
        n 加载内核映像和根文件系统映像,这里包括规划内存占用的布局和从Flash上复制数据。
        n 设置内核的启动参数。
         
        5.2.2  U-Boot概述

        1.U-Boot简介

        U-Boot(UniversalBootloader)是遵循GPL条款的开放源码项目。它是从FADSROM、8xxROM、PPCBOOT逐步发展演化而来。其源码目录、编译形式与Linux内核很相似,事实上,不少U-Boot源码就是相应的Linux内核源程序的简化,尤其是一些设备的驱动程序,这从U-Boot源码的注释中能体现这一点。但是U-Boot不仅仅支持嵌入式Linux系统的引导,而且还支持NetBSD、VxWorks、QNX、RTEMS、ARTOS、LynxOS等嵌入式操作系统。其目前要支持的目标操作系统是OpenBSD、NetBSD、FreeBSD、4.4BSD、Linux、SVR4、Esix、Solaris、Irix、SCO、Dell、NCR、VxWorks、LynxOS、pSOS、QNX、RTEMS、ARTOS。这是U-Boot中Universal的一层含义,另外一层含义则是U-Boot除了支持PowerPC系列的处理器外,还能支持MIPS、x86、ARM、NIOS、XScale等诸多常用系列的处理器。这两个特点正是U-Boot项目的开发目标,即支持尽可能多的嵌入式处理器和嵌入式操作系统。就目前为止,U-Boot对PowerPC系列处理器支持最为丰富,对Linux的支持最完善。
         
        2.U-Boot特点

        U-Boot的特点如下。
        n 开放源码;
        n 支持多种嵌入式操作系统内核,如Linux、NetBSD、VxWorks、QNX、RTEMS、ARTOS、LynxOS;
        n 支持多个处理器系列,如PowerPC、ARM、x86、MIPS、XScale;
        n 较高的可靠性和稳定性;
        n 高度灵活的功能设置,适合U-Boot调试、操作系统不同引导要求和产品发布等;
        n 丰富的设备驱动源码,如串口、以太网、SDRAM、Flash、LCD、NVRAM、EEPROM、RTC、键盘等;
        n 较为丰富的开发调试文档与强大的网络技术支持。
         
        3.U-Boot主要功能

        U-Boot可支持的主要功能列表。
        n 系统引导:支持NFS挂载、RAMDISK(压缩或非压缩)形式的根文件系统。支持NFS挂载,并从Flash中引导压缩或非压缩系统内核。
        n 基本辅助功能:强大的操作系统接口功能;可灵活设置、传递多个关键参数给操作系统,适合系统在不同开发阶段的调试要求与产品发布,尤其对Linux支持最为强劲;支持目标板环境参数多种存储方式,如Flash、NVRAM、EEPROM;CRC32校验,可校验Flash中内核、RAMDISK映像文件是否完好。
        n 设备驱动:串口、SDRAM、Flash、以太网、LCD、NVRAM、EEPROM、键盘、USB、PCMCIA、PCI、RTC等驱动支持。
        n 上电自检功能:SDRAM、Flash大小自动检测;SDRAM故障检测;CPU型号。
        n 特殊功能:XIP内核引导。
         
        5.2.3  U-Boot源码导读

        1.U-Boot源码结构

        U-Boot源码结构如图5.27所示。
       

        图5.27  U-Boot源码结构

         

        n board:和一些已有开发板有关的代码,比如makefile和U-Boot.lds等都和具体开发板的硬件和地址分配有关。
        n common:与体系结构无关的代码,用来实现各种命令的C程序。
        n cpu:包含CPU相关代码,其中的子目录都是以U-BOOT所支持的CPU为名,比如有子目录arm926ejs、mips、mpc8260和nios等,每个特定的子目录中都包括cpu.c和interrupt.c,start.S等。其中cpu.c初始化CPU、设置指令Cache和数据Cache等;interrupt.c设置系统的各种中断和异常,比如快速中断、开关中断、时钟中断、软件中断、预取中止和未定义指令等;汇编代码文件start.S是U-BOOT启动时执行的第一个文件,它主要是设置系统堆栈和工作方式,为进入C程序奠定基础。
         
        n disk:disk驱动的分区相关代码。
        n doc:文档。
        n drivers:通用设备驱动程序,比如各种网卡、支持CFI的Flash、串口和USB总线等。
        n fs:支持文件系统的文件,U-BOOT现在支持cramfs、fat、fdos、jffs2和registerfs等。
        n include:头文件,还有对各种硬件平台支持的汇编文件,系统的配置文件和对文件系统支持的文件。
        n net:与网络有关的代码,BOOTP协议、TFTP协议、RARP协议和NFS文件系统的实现。
        n lib_arm:与ARM体系结构相关的代码。
        n tools:创建S-Record格式文件和U-BOOT images的工具。
         
        2.U-Boot重要代码

        (1)cpu/arm920t/start.S
        这是U-Boot的起始位置。在这个文件中设置了处理器的状态、初始化中断向量和内存时序等,从Flash中跳转到定位好的内存位置执行。
        .globl_start (起始位置:中断向量设置)
        _start:     b         reset
              ldr    pc, _undefined_instruction
              ldr    pc, _software_interrupt
              ldr    pc, _prefetch_abort
              ldr    pc, _data_abort
              ldr    pc, _not_used
              ldr    pc, _irq
              ldr    pc, _fiq
         
        _undefined_instruction:   .word undefined_instruction
        _software_interrupt:   .word software_interrupt
        _prefetch_abort:   .word prefetch_abort
        _data_abort:       .word data_abort
        _not_used:      .word not_used
        _irq:            .word irq
        _fiq:            .word fiq
         
            _TEXT_BASE: (代码段起始位置)
        .word   TEXT_BASE
         
        .globl _armboot_start
        _armboot_start:
            .word _start
         
        /*
         * These are defined in the board-specific linker script.
         */
        .globl _bss_start (BSS段起始位置)
        _bss_start:
              .word __bss_start
         
        .globl _bss_end
        _bss_end:
             .word _end
        reset: (执行入口)
               /*
               * set the cpu to SVC32 mode;使处理器进入特权模式
               */
               mrs    r0,cpsr
               bic    r0,r0,#0x1f
               orr    r0,r0,#0xd3
               msr    cpsr,r0
        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
         
              /* Set up the stack;设置堆栈  */
        stack_setup:
              ldr   r0, _TEXT_BASE      /* upper 128 KiB: relocated uboot   */
              sub   r0, r0, #CFG_MALLOC_LEN    /* malloc area                      */
              sub   r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo                        */
         
        clear_bss: (清空BSS段)
              ldr    r0, _bss_start     /* find start of bss segment        */
              ldr    r1, _bss_end        /* stop here                        */
              mov     r2, #0x00000000     /* clear                            */
         
        clbss_l:str    r2, [r0]        /* clear loop...                    */
              add   r0, r0, #4
              cmp   r0, r1
              bne   clbss_l
              ldr   pc, _start_armboot
         
        _start_armboot:     .word start_armboot
         
        (2)interrupts.c
        这个文件是处理中断的,如打开和关闭中断等。
         
        #ifdef CONFIG_USE_IRQ
        /* enable IRQ interrupts;中断使能函数 */
        void enable_interrupts (void)
        {
             unsigned long temp;
             __asm__ __volatile__("mrs %0, cpsr\n"
                                 "bic %0, %0, #0x80\n"
                                 "msr cpsr_c, %0"
                                 : "=r" (temp)
                                 :
                                 : "memory");
        }
         
        /*
         * disable IRQ/FIQ interrupts;中断屏蔽函数
         * returns true if interrupts had been enabled before we disabled them
         */
        int disable_interrupts (void)
        {
             unsigned long old,temp;
             __asm__ __volatile__("mrs %0, cpsr\n"
                                 "orr %1, %0, #0xc0\n"
                                 "msr cpsr_c, %1"
                                 : "=r" (old), "=r" (temp)
                                 :
                                 : "memory");
             return (old & 0x80) == 0;
        }
        #endif
        void show_regs (struct pt_regs *regs)
        {
             unsigned long flags;
             const char *processor_modes[] = {
             "USER_26", "FIQ_26",  "IRQ_26",  "SVC_26",
             "UK4_26",  "UK5_26",  "UK6_26",  "UK7_26",
             "UK8_26",  "UK9_26",  "UK10_26", "UK11_26",
             "UK12_26", "UK13_26", "UK14_26", "UK15_26",
             "USER_32", "FIQ_32",  "IRQ_32",  "SVC_32",
             "UK4_32",  "UK5_32",  "UK6_32",   "ABT_32",
             "UK8_32",  "UK9_32",  "UK10_32", "UND_32",
             "UK12_32", "UK13_32", "UK14_32", "SYS_32",
             };
        …
        }
        /* 在U-Boot启动模式下,在原则上要禁止中断处理,所以如果发生中断,当作出错处理 */
        void do_fiq (struct pt_regs *pt_regs)
        {
             printf ("fast interrupt request\n");
             show_regs (pt_regs);
             bad_mode ();
        }
         
        void do_irq (struct pt_regs *pt_regs)
        {
             printf ("interrupt request\n");
             show_regs (pt_regs);
             bad_mode ();
        }
         
        (3)cpu.c
        这个文件是对处理器进行操作,如下所示:
         
        int cpu_init (void)
        {
             /*
               * setup up stacks if necessary;设置需要的堆栈
             */
        #ifdef CONFIG_USE_IRQ
             DECLARE_GLOBAL_DATA_PTR;
         
             IRQ_STACK_START=_armboot_start - CFG_MALLOC_LEN - CFG_GBL_DATA_SIZE - 4;
             FIQ_STACK_START = IRQ_STACK_START - CONFIG_STACKSIZE_IRQ;
        #endif
             return 0;
        }
        int cleanup_before_linux (void) /* 准备加载linux */
        {
             /*
              * this function is called just before we call linux
              * it prepares the processor for linux
              *
              * we turn off caches etc ...
              */
             unsigned long i;
             disable_interrupts ();
         
             /* turn off I/D-cache:关闭cache */
             asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
             i &= ~(C1_DC | C1_IC);
             asm ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
         
             /* flush I/D-cache */
             i = 0;
             asm ("mcr p15, 0, %0, c7, c7, 0": :"r" (i));
             return (0);
        }
         
        OUTPUT_ARCH(arm)
        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 = .;
        }
         
        (4)memsetup.S
        这个文件是用于配置开发板参数的,如下所示:
         
        /* memsetup.c */
             /* 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
            ldr r1, =BWSCON /* Bus Width Status Controller */
             add     r2, r0, #52
        0:
             ldr     r3, [r0], #4
             str     r3, [r1], #4
             cmp     r2, r0
             bne     0b
          
             /* everything is fine now */
            mov pc, lr
         
             .ltorg
         
        5.2.4  U-Boot移植主要步骤

        (1)建立自己的开发板类型。
        阅读makefile文件,在makefile文件中添加两行,如下所示:
         
        fs2410_config: unconfig
            @./mkconfig $(@:_config=) arm arm920t fs2410
         
        其中“arm”为表示处理器体系结构的种类,“arm920t”表示处理器体系结构的名称,“fs2410”为主板名称。
         
        在board目录中建立fs2410目录,并将smdk2410目录中的内容(cp &ndash;a smdk2410/*  fs2410)复制到该目录中。
         
        n 在include/configs/目录下将smdk2410.h复制到(cp smdk2410.h fs2410.h)。
        n 修改ARM编译器的目录名及前缀(都要改成以“fs2410”开头)。
        n 完成之后,可以测试配置。
         
        $ make fs2410_config;make
         
        (2)修改程序链接地址。
        在board/s3c2410中有一个config.mk文件,它是用于设置程序链接的起始地址,因为会在U-Boot中增加功能,所以留下6MB的空间,修改33F80000为33A00000。
        为了以后能用U-Boot的“go”命令执行修改过的用loadb或tftp下载的U-Boot,需要在board/ s3c2410的memsetup.S中标记符”0:”上加入5句:
         
        mov r3, pc
        ldr r4, =0x3FFF0000
        and r3, r3, r4 (以上3句得到实际代码启动的内存地址)
        aad r0, r0, r3 (用go命令调试u-boot时,启动地址在RAM)
        add r2, r2, r3 (把初始化内存信息的地址,加上实际启动地址)
         
        (3)将中断禁止的部分应该改为如下所示(/cpu/arm920t/start.S):
         
        # if defined(CONFIG_S3C2410)
             ldr    r1, =0x7ff  
             ldr    r0, =INTSUBMSK
             str    r1, [r0]
        # endif
         
        (4)因为在fs2410开发板启动时是直接从Nand Flash加载代码,所以启动代码应该改成如下所示(/cpu/arm920t/start.S):
         
        #ifdef CONFIG_S3C2410_NAND_BOOT   @START
        @ reset NAND
            mov r1, #NAND_CTL_BASE
            ldr   r2, =0xf830           @ initial value
            str   r2, [r1, #oNFCONF]
            ldr   r2, [r1, #oNFCONF]
            bic  r2, r2, #0x800              @ enable chip
            str   r2, [r1, #oNFCONF]
            mov r2, #0xff         @ RESET command
            strb r2, [r1, #oNFCMD]
            mov r3, #0                   @ wait
            nand1:  
            add  r3, r3, #0x1
            cmp r3, #0xa
            blt   nand1
        nand2:
            ldr   r2, [r1, #oNFSTAT]      @ wait ready
            tst    r2, #0x1
            beq  nand2
            ldr   r2, [r1, #oNFCONF]
            orr  r2, r2, #0x800              @ disable chip
            str   r2, [r1, #oNFCONF]
            @ get read to call C functions (for nand_read())
            ldr   sp, DW_STACK_START       @ setup stack pointer
            mov fp, #0                    @ no previous frame, so fp=0
        @ copy U-Boot to RAM
            ldr   r0, =TEXT_BASE
            mov     r1, #0x0
            mov r2, #0x20000
            bl    nand_read_ll
            tst    r0, #0x0
            beq  ok_nand_read
        bad_nand_read:
            loop2:    b     loop2          @ 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
            subs r2, r2, #4
            beq  stack_setup
            bne  go_next
        notmatch:
        loop3:     b     loop3         @ infinite loop
        #endif @ CONFIG_S3C2410_NAND_BOOT  @END
         
        在 “ _start_armboot:    .word start_armboot  ” 后加入:
         
        .align     2
        DW_STACK_START:  .word  STACK_BASE+STACK_SIZE-4
         
        (5)修改内存配置(board/fs2410/lowlevel_init.S)。
         
        #define BWSCON     0x48000000
        #define PLD_BASE   0x2C000000
        #define SDRAM_REG  0x2C000106
         
        /* BWSCON */
        #define DW8              (0x0)
        #define DW16            (0x1)
        #define DW32            (0x2)
        #define WAIT            (0x1<<2)
        #define UBLB            (0x1<<3)
         
        /* BANKSIZE */
        #define BURST_EN        (0x1<<7)
         
        #define B1_BWSCON      (DW16 + WAIT)
        #define B2_BWSCON      (DW32)
        #define B3_BWSCON      (DW32)
        #define B4_BWSCON      (DW16 + WAIT + UBLB)
        #define B5_BWSCON      (DW8 + UBLB)
        #define B6_BWSCON      (DW32)
        #define B7_BWSCON      (DW32)
        /* BANK0CON */
        #define B0_Tacs             0x0 /*  0clk */
        #define B0_Tcos             0x1 /*  1clk */
        #define B0_Tacc             0x7 /*  14clk */
        #define B0_Tcoh             0x0 /*  0clk */
        #define B0_Tah       0x0   /*  0clk */
        #define B0_Tacp            0x0     /* page mode is not used */
        #define B0_PMC          0x0 /* page mode disabled */
         
        /* BANK1CON */
        #define B1_Tacs             0x0 /*  0clk */
        #define B1_Tcos             0x1 /*  1clk */
        #define B1_Tacc             0x7 /*  14clk */
        #define B1_Tcoh             0x0 /*  0clk */
        #define B1_Tah          0x0 /*  0clk */
        #define B1_Tacp            0x0     /* page mode is not used */
        #define B1_PMC          0x0 /* page mode disabled */
        ……
        /* REFRESH parameter */
        #define REFEN           0x1 /* Refresh enable */
        #define TREFMD          0x0 /* CBR(CAS before RAS)/Auto refresh */
        #define Trp         0x0 /* 2clk */
        #define Trc         0x3 /* 7clk */
        #define Tchr            0x2 /* 3clk */
        #define REFCNT           1113 /*period=15.6us,HCLK=60Mhz, (2048+1-15.6*60) */
        ......
            .word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN))
            .word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN))
            .word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)
            .word 0x32
            .word 0x30
            .word 0x30
         
        (6)加入Nand Flash读函数(创建board/fs2410/nand_read.c文件)。
         
        #include <config.h>
        #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 NFCMD  __REGb(NF_BASE + 0x4)
        #define NFADDR  __REGb(NF_BASE + 0x8)
        #define NFDATA  __REGb(NF_BASE + 0xc)
        #define NFSTAT  __REGb(NF_BASE + 0x10)
        #define BUSY 1
        inline void wait_idle(void)
        {
             Int i;
             while(!(NFSTAT & BUSY))
             {
                 for (i = 0; i < 10; i++);
             }
        }
         
        /* low level nand read function */
        int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)
        {
             int i, j;
             if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK))
             {
                  return -1; /* invalid alignment */
             }
             /* chip Enable */
             NFCONF &= ~0x800;
             for (i = 0; i < 10; i++);
             for (i = start_addr; i < (start_addr + size);)
             {
                 /* READ0 */
                 NFCMD = 0;
                 /* Write Address */
                 NFADDR = i & 0xff;
                 NFADDR = (i >> 9) & 0xff;
                 NFADDR = (i >> 17) & 0xff;
                 NFADDR = (i >> 25) & 0xff;
                 wait_idle();
                 for (j = 0; j < NAND_SECTOR_SIZE; j++, i++)
                 {
                     *buf = (NFDATA & 0xff);
                      buf++;
                 }
             }
             /* chip Disable */
             NFCONF |= 0x800; /* chip disable */
             return 0;
        }
         
        修改board/fs2410/makefile文件,以增加nand_read()函数。
         
        OBJS := fs2410.o  flash.o  nand_read.o
         
        (7)加入Nand Flash的初始化函数(board/fs2410/fs2410.c)。
         
        #if (CONFIG_COMMANDS & CFG_CMD_NAND)
        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_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_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 void NF_Init_ECC(void)
        {
             S3C2410_NAND * const nand = S3C2410_GetBase_NAND();
             nand->NFCONF |= (1<<12);
        }
        static inline u32 NF_Read_ECC(void)
        {
             S3C2410_NAND * const nand = S3C2410_GetBase_NAND();
             return(nand->NFECC);
        }
        #endif
        /*
        * NAND flash initialization.
        */
        #if (CONFIG_COMMANDS & CFG_CMD_NAND)
        extern ulong nand_probe(ulong physadr);
        static inline void NF_Reset(void)
        {
             int i;
             NF_SetCE(NFCE_LOW);
             NF_Cmd(0xFF); /* reset command */
             for (i = 0; i < 10; i++); /* tWB = 100ns. */
             NF_WaitRB(); /* wait 200~500us; */
             NF_SetCE(NFCE_HIGH);
        }
        static inline void NF_Init(void)
        {
             #define TACLS 0
             #define TWRPH0 4
             #define TWRPH1 2
             NF_Conf((1<<15)|(0<<14)|(0<<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 */
             NF_Reset();
        }
        void nand_init(void)
        {
             S3C2410_NAND * const nand = S3C2410_GetBase_NAND();
             NF_Init();
             #ifdef DEBUG
                 printf("NAND flash probing at 0x%.8lX\n", (ulong)nand);
             #endif
             printf ("%4lu MB\n", nand_probe((ulong)nand) >> 20);
        }
        #endif
         
        (8)修改GPIO配置(board/fs2410/fs2410.c)。
         
        /* set up the I/O ports */
        gpio->GPACON = 0x007FFFFF;
        gpio->GPBCON = 0x002AAAAA;
        gpio->GPBUP = 0x000002BF;
        gpio->GPCCON = 0xAAAAAAAA;
        gpio->GPCUP = 0x0000FFFF;
        gpio->GPDCON = 0xAAAAAAAA;
        gpio->GPDUP = 0x0000FFFF;
        gpio->GPECON = 0xAAAAAAAA;
        gpio->GPEUP = 0x000037F7;
        gpio->GPFCON = 0x00000000;
        gpio->GPFUP = 0x00000000;
        gpio->GPGCON = 0xFFEAFF5A;
        gpio->GPGUP = 0x0000F0DC;
        gpio->GPHCON = 0x0018AAAA;
        gpio->GPHDAT = 0x000001FF;
        gpio->GPHUP = 0x00000656
         
        (9)提供nand flash相关宏定义(include/configs/fs2410.h),具体参考源码。
         
        (10)加入Nand Flash设备(include/linux/mtd/nand_ids.h)
         
        static struct nand_flash_dev nand_flash_ids[] =
        {
             ......
            {"Samsung KM29N16000",NAND_MFR_SAMSUNG, 0x64, 21, 1, 2, 0x1000, 0},
            {"Samsung K9F1208U0M",  NAND_MFR_SAMSUNG, 0x76, 26, 0, 3, 0x4000, 0},
            {"Samsung unknown 4Mb", NAND_MFR_SAMSUNG, 0x6b, 22, 0, 2, 0x2000, 0},
             ......
             {NULL,}
        };
         
        (11)设置Nand Flash环境(common/env_nand.c)
         
        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 */
        extern nand_info_t nand_info[CFG_MAX_NAND_DEVICE];
        ......
        #else /* ! CFG_ENV_OFFSET_REDUND */
        int saveenv(void)
        {
            ulong total;
            int ret = 0;
            puts ("Erasing Nand...");
             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;
             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 */
        void env_relocate_spec (void)
        {
        #if !defined(ENV_IS_EMBEDDED)
             ulong total;
             int ret;
             total = CFG_ENV_SIZE;
             ret = nand_legacy_rw(nand_dev_desc + 0, 0x01 | 0x02, CFG_ENV_OFFSET,
                     CFG_ENV_SIZE, &total, (u_char*)env_ptr);




欢迎光临 DIY编程器网 (http://diybcq.com/) Powered by Discuz! X3.2