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

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

add    r2, r0, r2     /* r2

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

}

}

/* 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

for (i = start_addr; i

{

/* 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

{

*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

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开发环境 cpu,嵌入式Linux开发环境的搭建之:U-Boot移植-嵌入式系统-与非网...相关推荐

  1. linux嵌入式开发arm7,基于ARM7系列芯片嵌入式平台上实现的设计方案-嵌入式系统-与非网...

    本文介绍的方法是在用ARM7系列芯片S3C4510B和μClinux构建的嵌入式平台上实现的.在嵌入式系统设计过程中,系统的掉电保护越来越受到重视整个掉电保护实现的基本思路是:产生掉电信号,捕捉掉电信 ...

  2. qprocess回调_Qt图形编程基础之:Qt/Embedded开发入门-嵌入式系统-与非网

    12.2.1  Qt/Embedded介绍 1.架构 Qt/Embedded以原始Qt为基础,并做了许多出色的调整以适用于嵌入式环境.Qt/Embedded通过Qt API与Linux I/O设施直接 ...

  3. freertos与linux区别,μClinux、μC/OS-II、eCos、FreeRTOS和djyos操作系统的特点及不足-嵌入式系统-与非网...

    基于 STM 平台且满足实时控制要求操作系统,有以下 5 种可供移植选择.分别为μClinux.μC/OS-II.eCos.FreeRTOS 和都江堰操作系统(djyos). 下面分别介绍这五种嵌入式 ...

  4. 监护仪系统都是Linux吗,基于Linux和MiniGUI的心电监护仪设计-嵌入式系统-与非网...

    0 引言 随着人们生活节奏加快,人口逐渐老龄化,心脏疾病成为危害人类健康和生命的主要疾病之一.心电监护系统为心脏病人诊断和治疗提供了一个有效的手段,对心脏疾病的防治和诊断具有重大的意义,本介绍一种基于 ...

  5. linux基金会认证考试,Linux基金会宣布新的Linux认证计划-嵌入式系统-与非网

    新计划推出首个全虚拟化.注重实际表现.不限发行版的认证考试,将有助扩大全球Linux专业人才库 Marketwired 2014年8月20日美国伊利诺伊州芝加哥消息--LINUXCON+CLOUDOP ...

  6. 跑linux编译什么CPU速度快,linux 加快编译速度

    <操作系统>课程设计报告课程设计题目:操作系统课程设计 设计时间:2016/1/10一. 课程设计目的与要求需要完成的内容:(1) 安装虚拟机:Vmware.Vmware palyer ( ...

  7. linux usleep占用cpu,[RK_2014_0918]linux下,测试usleep函数对CPU占用率的影响

    一.本机环境 CPU信息 Intel(R) Core(TM) i3 CPU M350 @ 2.27GHz Intel(R) Core(TM) i3 CPU M 350 @ 2.27GHz Intel( ...

  8. linux命令查看cpu序列号,Linux下用命令查看CPU ID以及厂家等信息

    Linux下用命令查看CPU ID // 获得CPU ID dmidecode -t 4 | grep ID |sort -u |awk -F': ' '{print $2}' // 获得磁盘ID f ...

  9. linux怎么增加cpu负载,Linux下的CPU平均负载

    linux下的CPU平均负载 一.注销登陆过的用户 先用w命令查看该用户tty号,然后用fuser -k tty号(或显示pts/*)就可以踢出了 先用w命令查看在线用户 然后 pkill -kill ...

  10. 如何在linux下查看cpu个数,linux如何查看cpu个数

    linux查看cpu个数!用什么方法好呢?下面由学习啦小编给你做出详细的linux查看cpu个数方法介绍!希望对你有帮助! linux查看cpu个数方法一 1查看物理cpu个数 grep 'physi ...

最新文章

  1. java中random的头文件_JAVA中的Random()函數
  2. SIFT四部曲之——构建关键点特征描述符
  3. java.lang包—枚举类Enum
  4. 解决 IntelliJ IDEA 中 .propertise 文件保存后中文乱码
  5. 12.15模拟:总结
  6. java 与 xml_xml与java对象转换
  7. 【kafka】 kafka如何设置指定分区进行发送和消费
  8. 自定义cell的左侧滑动
  9. 深度学习框架 —— tflearn 的学习
  10. ttl接地是高电平还是低电平_TTL 门电路输入端分别接大电阻接地,小电阻接地,或空接,输入的是什么电平???跟是什么类型的门电路......
  11. 微积分基础1-微分篇
  12. Ubuntu20软件商店无法正确加载,解决办法
  13. java smslib rxtx_SMSLIB+RXTX 短信猫开发模块
  14. Vue的MVVM框架
  15. 移动播放器html,支持移动平台的Html5播放器
  16. android默认打开方式修改,教你修改安卓智能手机默认打开方式
  17. PTA数组后五道演讲比赛中有10个评委打分(实型数据,十分制分数)一维数组中,然后输入欲删除数x,最后删除数组中值为x的元素并输出,键盘输入一个4×4阶的矩阵,编程输出它的转置矩阵。
  18. R语言读取(加载)txt格式数据为dataframe、按照指定字段(数据列)对dataframe进行升序排序(ascending)、返回行索引的位置向量
  19. 细胞穿膜肽TAT/血管肽Angiopep/靶向多肽cRGD偶联TIO2二氧化钛纳米粒(TiO2-Angiopep)
  20. android修改recovery菜单,安卓刷机Recovery菜单介绍刷入教程详解

热门文章

  1. Cannot find package module @sap/cds/common
  2. rxjs里merge operators的用法
  3. ant target间的dependency
  4. SAP CRM WebClient UI端到端的字段扩展
  5. Java单例模式(Singleton)的五种实现
  6. SAP UI5 web Component里的条件渲染机制
  7. SAP CRM pricing read的实现逻辑
  8. repeated call of attachBrowserEvent
  9. 如何自行查找SAP ERP的物料主数据和CRM产品主数据的映射关系
  10. 如何获得SAP CRM SalesOrder里involved party的详细信息