嵌入式Linux开发环境的搭建之:U-Boot移植

1.概念

简单地说,Bootloader就是在操作系统内核运行之前运行的一段程序,它类似于PC机中的BIOS程序。通过这段程序,可以完成硬件设备的初始化,并建立内存空间的映射关系,从而将系统的软硬件环境带到一个合适的状态,为最终加载系统内核做好准备。

通常,Bootloader比较依赖于硬件平台,特别是在嵌入式系统中,更为如此。因此,在嵌入式世界里建立一个通用的Bootloader是一件比较困难的事情。尽管如此,仍然可以对Bootloader归纳出一些通用的概念来指导面向用户定制的Bootloader设计与实现。

嵌入式Linux开发环境的搭建之:U-Boot移植

(1)Bootloader所支持的CPU和嵌入式开发板。

每种不同的CPU体系结构都有不同的Bootloader。有些Bootloader也支持多种体系结构的CPU,如后面要介绍的U-Boot支持ARMMIPS、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所示。

嵌入式Linux开发环境的搭建之:U-Boot移植

图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 –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  

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

 

  • 嵌入式Linux开发环境的搭建之:U-Boot移植已关闭评论
    A+
发布日期:2019年07月14日  所属分类:物联网