开发板:JZ2440v2
内核:64M
NAND Flash:256M
烧写内核使用到的U-boo及kernelt:

bootloader一般分为两部分,对于系统的初始化用汇编完成,C部分实现一些更加负责的功能。我们来实现一个简单的bootloader把内核从NAND指定位置拷贝到内存,然后跳转到这个位置执行。

Boot2Docker安装和入门_#define

说明:红色部分中的程序,处于NAND方式启动时,上电后会自动加载到4K SRAM中,这部分的程序初始化完内存后把灰色区域的程序(bootloader的另一部分)加载到64M内存的最后1M内存处,并把黄色区域(使用uboot烧写至NAND Flash的内核)拷贝到0x30008000处,然后跳转至灰色区域程序(bootloader的下部分)执行。


bootloader第一部分:
关闭看门狗(否则会重启),设置时钟,初始化内存,拷贝bootloader下部分及内核至内存(在大多数uboot中读取内核在下部分完成)。
程序可以参考,只是多了对nand的操作。

head.S
@clock manegment
.equ MPLLCON  ,0x4C000004
.equ CLKDIVN  ,0x4C000014   
@memory controller
.equ BWSCON   ,0x48000000 
.equ BANKCON0 ,0x48000004   
.equ BANKCON1 ,0x48000008  
.equ BANKCON2 ,0x4800000C   
.equ BANKCON3 ,0x48000010  
.equ BANKCON4 ,0x48000014  
.equ BANKCON5 ,0x48000018 
.equ BANKCON6 ,0x4800001C  
.equ BANKCON7 ,0x48000020  
.equ REFRESH  ,0x48000024 
.equ BANKSIZE ,0x48000028  
.equ MRSRB6   ,0x4800002C  
.equ MRSRB7   ,0x48000030  
.text
.global _start
_start:
            ldr     r0, =0x53000000     @Close WATCHDOG
            mov     r1, #0x0                     
            str     r1, [r0]             

        ldr     r0,=MPLLCON         @Clock Init 400:100:50
            ldr     r1,=(192<<12)|(4<<4)|(1<<0)
            str     r1,[r0]

            ldr     r0,=CLKDIVN
            ldr     r1,=(2<<1)|(1<<0)
            str     r1,[r0]

        mrc p15,0,r0,c1,c0,0
            orr r0,r0,#0xc0000000//R1_nF:OR:R1_iA
            mcr p15,0,r0,c1,c0,0

        ldr     r0,=BWSCON      @Init sdram
        ldr     r1,=0x22011110  
        str     r1,[r0]

        ldr     r0,= BANKCON6         
            ldr     r1,=0x00018005
            str     r1,[r0]

        ldr     r0,=REFRESH
            ldr     r1,=0x008c07a3
            str     r1,[r0]

        ldr     r0,=BANKSIZE
            ldr     r1,=0x000000b1
            str     r1,[r0]

        ldr     r0,=MRSRB6
            ldr     r1,=0x00000030
            str     r1,[r0]

            ldr     sp, =1024*4         @Call C 

        bl      nand_init       @Nand init

        @ldr        r0,=0x30000000  @Copy bootloader to 0x30000000
        ldr            r0,=0x33f80000
        ldr     r1,=4096
        ldr     r2,=2048
        bl      nand_read

        @nand_read((unsigned char *)0x30008000,0x60000+64,0x400000);
        ldr     r0,=0x30008000      @Copy kernel to 0x30000000
            ldr     r1,=0x60000
            ldr     r2,=0x400000
            bl      nand_read

        ldr     sp,=0x34000000
            ldr     lr,=loop      
            @bl      main
        ldr     pc,=main    @main           @0x800 
loop:
            b       loop
nand.c
#define BUSY            1

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

#define NAND_SECTOR_SIZE_LP    2048
#define NAND_BLOCK_MASK_LP     (NAND_SECTOR_SIZE_LP - 1)

typedef unsigned int S3C24X0_REG32;


/* NAND FLASH (see S3C2440 manual chapter 6, www.100ask.net) */
typedef struct {
    S3C24X0_REG32   NFCONF;
    S3C24X0_REG32   NFCONT;
    S3C24X0_REG32   NFCMD;
    S3C24X0_REG32   NFADDR;
    S3C24X0_REG32   NFDATA;
    S3C24X0_REG32   NFMECCD0;
    S3C24X0_REG32   NFMECCD1;
    S3C24X0_REG32   NFSECCD;
    S3C24X0_REG32   NFSTAT;
    S3C24X0_REG32   NFESTAT0;
    S3C24X0_REG32   NFESTAT1;
    S3C24X0_REG32   NFMECC0;
    S3C24X0_REG32   NFMECC1;
    S3C24X0_REG32   NFSECC;
    S3C24X0_REG32   NFSBLK;
    S3C24X0_REG32   NFEBLK;
} S3C2440_NAND;


typedef struct {
    void (*nand_reset)(void);
    void (*wait_idle)(void);
    void (*nand_select_chip)(void);
    void (*nand_deselect_chip)(void);
    void (*write_cmd)(int cmd);
    void (*write_addr)(unsigned int addr);
    unsigned char (*read_data)(void);
}t_nand_chip;

static S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;

static t_nand_chip nand_chip;

/* 供外部调用的函数 */
void nand_init(void);
void nand_read(unsigned char *buf, unsigned long start_addr, int size);

/* NAND Flash操作的总入口, 它们将调用S3C2440的相应函数 */
static void nand_reset(void);
static void wait_idle(void);
static void nand_select_chip(void);
static void nand_deselect_chip(void);
static void write_cmd(int cmd);
static void write_addr(unsigned int addr);
static unsigned char read_data(void);


/* S3C2440的NAND Flash处理函数 */
static void s3c2440_nand_reset(void);
static void s3c2440_wait_idle(void);
static void s3c2440_nand_select_chip(void);
static void s3c2440_nand_deselect_chip(void);
static void s3c2440_write_cmd(int cmd);
static void s3c2440_write_addr(unsigned int addr);
static unsigned char s3c2440_read_data(void);


/* S3C2440的NAND Flash操作函数 */

/* 复位 */
static void s3c2440_nand_reset(void)
{
    s3c2440_nand_select_chip();
    s3c2440_write_cmd(0xff);  // 复位命令
    s3c2440_wait_idle();
    s3c2440_nand_deselect_chip();
}

/* 等待NAND Flash就绪 */
static void s3c2440_wait_idle(void)
{
    int i;
    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFSTAT;
    while(!(*p & BUSY))
        for(i=0; i<10; i++);
}

/* 发出片选信号 */
static void s3c2440_nand_select_chip(void)
{
    int i;
    s3c2440nand->NFCONT &= ~(1<<1);
    for(i=0; i<10; i++);    
}

/* 取消片选信号 */
static void s3c2440_nand_deselect_chip(void)
{
    s3c2440nand->NFCONT |= (1<<1);
}

/* 发出命令 */
static void s3c2440_write_cmd(int cmd)
{
    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFCMD;
    *p = cmd;
}

/* 发出地址 */
static void s3c2440_write_addr(unsigned int addr)
{
    int i;
    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR;

    *p = addr & 0xff;
    for(i=0; i<10; i++);
    *p = (addr >> 9) & 0xff;
    for(i=0; i<10; i++);
    *p = (addr >> 17) & 0xff;
    for(i=0; i<10; i++);
    *p = (addr >> 25) & 0xff;
    for(i=0; i<10; i++);
}


static void s3c2440_write_addr_lp(unsigned int addr)
{
    int i;
    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR;
    int col, page;

    col = addr & NAND_BLOCK_MASK_LP;
    page = addr / NAND_SECTOR_SIZE_LP;

    *p = col & 0xff;            /* Column Address A0~A7 */
    for(i=0; i<10; i++);        
    *p = (col >> 8) & 0x0f;     /* Column Address A8~A11 */
    for(i=0; i<10; i++);
    *p = page & 0xff;           /* Row Address A12~A19 */
    for(i=0; i<10; i++);
    *p = (page >> 8) & 0xff;    /* Row Address A20~A27 */
    for(i=0; i<10; i++);
    *p = (page >> 16) & 0x03;   /* Row Address A28~A29 */
    for(i=0; i<10; i++);
}


/* 读取数据 */
static unsigned char s3c2440_read_data(void)
{
    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFDATA;
    return *p;
}


/* 在第一次使用NAND Flash前,复位一下NAND Flash */
static void nand_reset(void)
{
    nand_chip.nand_reset();
}

static void wait_idle(void)
{
    nand_chip.wait_idle();
}

static void nand_select_chip(void)
{
    int i;
    nand_chip.nand_select_chip();
    for(i=0; i<10; i++);
}

static void nand_deselect_chip(void)
{
    nand_chip.nand_deselect_chip();
}

static void write_cmd(int cmd)
{
    nand_chip.write_cmd(cmd);
}
static void write_addr(unsigned int addr)
{
    nand_chip.write_addr(addr);
}

static unsigned char read_data(void)
{
    return nand_chip.read_data();
}

void win9(){

__asm__(
    //"mrc    p15, 0, r1, c1, c0, 0\n"       
    "LDR     R0,=0x56000050\n"  //config
    "MOV     R1,#0x00000100\n"        
    "STR     R1,[R0]\n"
    "LDR     R0,=0x56000054\n"  //set
    "MOV     R1,#0x00000000\n"      
    "STR     R1,[R0]\n"
    );

}


/* 初始化NAND Flash */
void nand_init(void)
{
#define TACLS   0
#define TWRPH0  2//3
#define TWRPH1  0

        nand_chip.nand_reset         = s3c2440_nand_reset;
        nand_chip.wait_idle          = s3c2440_wait_idle;
        nand_chip.nand_select_chip   = s3c2440_nand_select_chip;
        nand_chip.nand_deselect_chip = s3c2440_nand_deselect_chip;
        nand_chip.write_cmd          = s3c2440_write_cmd;
        nand_chip.write_addr         = s3c2440_write_addr_lp;
        nand_chip.read_data          = s3c2440_read_data;

        /* 设置时序 */
        s3c2440nand->NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
        /* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */
        s3c2440nand->NFCONT = (1<<4)|(1<<1)|(1<<0);


    /* 复位NAND Flash */
    nand_reset();
}

/* 读函数 */
void nand_read(unsigned char *buf, unsigned long start_addr, int size)
{
    int i, j;

    if ((start_addr & NAND_BLOCK_MASK_LP) || (size & NAND_BLOCK_MASK_LP)) {
        return ;    /* 地址或长度不对齐 */
    }

    /* 选中芯片 */
    nand_select_chip();

    for(i=start_addr; i < (start_addr + size);) {
      /* 发出READ0命令 */
      write_cmd(0);

      /* Write Address */
      write_addr(i);
      write_cmd(0x30);      

      wait_idle();

      for(j=0; j < NAND_SECTOR_SIZE_LP; j++, i++) {
          *buf = read_data();
          buf++;
      }
    }

    /* 取消片选信号 */
    nand_deselect_chip();

    return ;
}


#define BUSY            1

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

#define NAND_SECTOR_SIZE_LP    2048
#define NAND_BLOCK_MASK_LP     (NAND_SECTOR_SIZE_LP - 1)

typedef unsigned int S3C24X0_REG32;


/* NAND FLASH (see S3C2440 manual chapter 6, www.100ask.net) */
typedef struct {
    S3C24X0_REG32   NFCONF;
    S3C24X0_REG32   NFCONT;
    S3C24X0_REG32   NFCMD;
    S3C24X0_REG32   NFADDR;
    S3C24X0_REG32   NFDATA;
    S3C24X0_REG32   NFMECCD0;
    S3C24X0_REG32   NFMECCD1;
    S3C24X0_REG32   NFSECCD;
    S3C24X0_REG32   NFSTAT;
    S3C24X0_REG32   NFESTAT0;
    S3C24X0_REG32   NFESTAT1;
    S3C24X0_REG32   NFMECC0;
    S3C24X0_REG32   NFMECC1;
    S3C24X0_REG32   NFSECC;
    S3C24X0_REG32   NFSBLK;
    S3C24X0_REG32   NFEBLK;
} S3C2440_NAND;


typedef struct {
    void (*nand_reset)(void);
    void (*wait_idle)(void);
    void (*nand_select_chip)(void);
    void (*nand_deselect_chip)(void);
    void (*write_cmd)(int cmd);
    void (*write_addr)(unsigned int addr);
    unsigned char (*read_data)(void);
}t_nand_chip;

static S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;

static t_nand_chip nand_chip;

/* 供外部调用的函数 */
void nand_init(void);
void nand_read(unsigned char *buf, unsigned long start_addr, int size);

/* NAND Flash操作的总入口, 它们将调用S3C2440的相应函数 */
static void nand_reset(void);
static void wait_idle(void);
static void nand_select_chip(void);
static void nand_deselect_chip(void);
static void write_cmd(int cmd);
static void write_addr(unsigned int addr);
static unsigned char read_data(void);


/* S3C2440的NAND Flash处理函数 */
static void s3c2440_nand_reset(void);
static void s3c2440_wait_idle(void);
static void s3c2440_nand_select_chip(void);
static void s3c2440_nand_deselect_chip(void);
static void s3c2440_write_cmd(int cmd);
static void s3c2440_write_addr(unsigned int addr);
static unsigned char s3c2440_read_data(void);


/* S3C2440的NAND Flash操作函数 */

/* 复位 */
static void s3c2440_nand_reset(void)
{
    s3c2440_nand_select_chip();
    s3c2440_write_cmd(0xff);  // 复位命令
    s3c2440_wait_idle();
    s3c2440_nand_deselect_chip();
}

/* 等待NAND Flash就绪 */
static void s3c2440_wait_idle(void)
{
    int i;
    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFSTAT;
    while(!(*p & BUSY))
        for(i=0; i<10; i++);
}

/* 发出片选信号 */
static void s3c2440_nand_select_chip(void)
{
    int i;
    s3c2440nand->NFCONT &= ~(1<<1);
    for(i=0; i<10; i++);    
}

/* 取消片选信号 */
static void s3c2440_nand_deselect_chip(void)
{
    s3c2440nand->NFCONT |= (1<<1);
}

/* 发出命令 */
static void s3c2440_write_cmd(int cmd)
{
    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFCMD;
    *p = cmd;
}

/* 发出地址 */
static void s3c2440_write_addr(unsigned int addr)
{
    int i;
    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR;

    *p = addr & 0xff;
    for(i=0; i<10; i++);
    *p = (addr >> 9) & 0xff;
    for(i=0; i<10; i++);
    *p = (addr >> 17) & 0xff;
    for(i=0; i<10; i++);
    *p = (addr >> 25) & 0xff;
    for(i=0; i<10; i++);
}


static void s3c2440_write_addr_lp(unsigned int addr)
{
    int i;
    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR;
    int col, page;

    col = addr & NAND_BLOCK_MASK_LP;
    page = addr / NAND_SECTOR_SIZE_LP;

    *p = col & 0xff;            /* Column Address A0~A7 */
    for(i=0; i<10; i++);        
    *p = (col >> 8) & 0x0f;     /* Column Address A8~A11 */
    for(i=0; i<10; i++);
    *p = page & 0xff;           /* Row Address A12~A19 */
    for(i=0; i<10; i++);
    *p = (page >> 8) & 0xff;    /* Row Address A20~A27 */
    for(i=0; i<10; i++);
    *p = (page >> 16) & 0x03;   /* Row Address A28~A29 */
    for(i=0; i<10; i++);
}


/* 读取数据 */
static unsigned char s3c2440_read_data(void)
{
    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFDATA;
    return *p;
}


/* 在第一次使用NAND Flash前,复位一下NAND Flash */
static void nand_reset(void)
{
    nand_chip.nand_reset();
}

static void wait_idle(void)
{
    nand_chip.wait_idle();
}

static void nand_select_chip(void)
{
    int i;
    nand_chip.nand_select_chip();
    for(i=0; i<10; i++);
}

static void nand_deselect_chip(void)
{
    nand_chip.nand_deselect_chip();
}

static void write_cmd(int cmd)
{
    nand_chip.write_cmd(cmd);
}
static void write_addr(unsigned int addr)
{
    nand_chip.write_addr(addr);
}

static unsigned char read_data(void)
{
    return nand_chip.read_data();
}

void win9(){

__asm__(
    //"mrc    p15, 0, r1, c1, c0, 0\n"       
    "LDR     R0,=0x56000050\n"  //config
    "MOV     R1,#0x00000100\n"        
    "STR     R1,[R0]\n"
    "LDR     R0,=0x56000054\n"  //set
    "MOV     R1,#0x00000000\n"      
    "STR     R1,[R0]\n"
    );

}


/* 初始化NAND Flash */
void nand_init(void)
{
#define TACLS   0
#define TWRPH0  2//3
#define TWRPH1  0

        nand_chip.nand_reset         = s3c2440_nand_reset;
        nand_chip.wait_idle          = s3c2440_wait_idle;
        nand_chip.nand_select_chip   = s3c2440_nand_select_chip;
        nand_chip.nand_deselect_chip = s3c2440_nand_deselect_chip;
        nand_chip.write_cmd          = s3c2440_write_cmd;
        nand_chip.write_addr         = s3c2440_write_addr_lp;
        nand_chip.read_data          = s3c2440_read_data;

        /* 设置时序 */
        s3c2440nand->NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
        /* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */
        s3c2440nand->NFCONT = (1<<4)|(1<<1)|(1<<0);


    /* 复位NAND Flash */
    nand_reset();
}

/* 读函数 */
void nand_read(unsigned char *buf, unsigned long start_addr, int size)
{
    int i, j;

    if ((start_addr & NAND_BLOCK_MASK_LP) || (size & NAND_BLOCK_MASK_LP)) {
        return ;    /* 地址或长度不对齐 */
    }

    /* 选中芯片 */
    nand_select_chip();

    for(i=start_addr; i < (start_addr + size);) {
      /* 发出READ0命令 */
      write_cmd(0);

      /* Write Address */
      write_addr(i);
      write_cmd(0x30);      

      wait_idle();

      for(j=0; j < NAND_SECTOR_SIZE_LP; j++, i++) {
          *buf = read_data();
          buf++;
      }
    }

    /* 取消片选信号 */
    nand_deselect_chip();

    return ;
}

bootloader第二部分:
初始化串口,设置tag(传递给内核),跳转到内核。(注意uImage有一个0x40大小的头部)

main.c
#include "setup.h"

#define GPFCON      (*(volatile unsigned long *)0x56000050)

#define GPF4_out    (1<<(4*2))
#define GPF5_out    (1<<(5*2))
#define GPF6_out    (1<<(6*2))

extern void uart0_init(void);
extern void puts(char *str);

static struct tag *params;

void setup_start_tag(void)
{
    params = (struct tag *)0x30000100;

    params->hdr.tag = ATAG_CORE;
    params->hdr.size = tag_size (tag_core);

    params->u.core.flags = 0;
    params->u.core.pagesize = 0;
    params->u.core.rootdev = 0;

    params = tag_next (params);
}

void setup_memory_tags(void)
{
    params->hdr.tag = ATAG_MEM;
    params->hdr.size = tag_size (tag_mem32);

    params->u.mem.start = 0x30000000;
    params->u.mem.size  = 64*1024*1024;

    params = tag_next (params);
}

int strlen(char *str)
{
    int i = 0;
    while (str[i])
    {
        i++;
    }
    return i;
}

void strcpy(char *dest, char *src)
{
    while ((*dest++ = *src++) != '\0');
}

void setup_commandline_tag(char *cmdline)
{
    int len = strlen(cmdline) + 1;

    params->hdr.tag  = ATAG_CMDLINE;
    params->hdr.size = (sizeof (struct tag_header) + len + 3) >> 2;

    strcpy (params->u.cmdline.cmdline, cmdline);

    params = tag_next (params);
}

void setup_end_tag(void)
{
    params->hdr.tag = ATAG_NONE;
    params->hdr.size = 0;
}


int main(void)
{
    void (*theKernel)(int zero, int arch, unsigned int params);

    GPFCON = GPF4_out|GPF5_out|GPF6_out;        //Configure the gpio of led  
    /*init*/
    uart0_init();
    puts("init\n\r");
    /*set params*/
    puts("Set boot params\n\r");
    setup_start_tag();
    setup_memory_tags();
    setup_commandline_tag("noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0");
    setup_end_tag();
    /*read kernel to 0x30008000*/
        //puts("read kernel\n\r");
        //nand_read((unsigned char *)0x30008000,0x60000+64,0x400000);
    /*boot kernel*/
    puts("boot kernle\n\r");    
    theKernel=(void (*)(int zero, int arch, unsigned int params))0x30008040;
    theKernel(0,362,0x30000100);

    puts("error\n\r");
    while(1){

    }
    return -1;
}

root@ubuntu:/work/2440/bin# ls
dnw.ini             fs_mini_mdev_new.jffs2   fs_mini.yaffs2    hardware         leds_0x31000000.bin  uImage_3.5
fs_mini.jffs2       fs_mini_mdev_new.yaffs2  fs_qtopia.jffs2   lcd_3.5_4.3.bin  u-boot.bin           uImage_4.3
fs_mini_mdev.jffs2  fs_mini_mdev.yaffs2      fs_qtopia.yaffs2  leds_0x31000000  uImage
root@ubuntu:/work/2440/bin# oflash u-boot.bin

首先使用oflash烧写uboot至NOR Flash

setenv mtdparts mtdparts=nandflash0:256k@0(bootloader),128k(params),4m(kernel),-(root)
save 修改分区
nfs 30000000 192.168.0.105:/work/bin/uImage 将uImage下载到地址0x30000000处区
nand write.jffs2 30000000 kernel烧写到kernel分区

然后修改uboot的kernel分区,在使用uboot烧写内核至nand中指定位置。

root@ubuntu:/work#oflash main.bin

使用烧写main.bin至NAND Flash,将启动开关拨至NAND启动。

效果:

Boot2Docker安装和入门_#define_02