u-boot-2014.10移植第29天----nand flash的SPL啟動(一)

fulinux發表於2015-03-29

硬體平臺:tq2440

開發環境:Ubuntu-3.11

u-boot版本:2014.10

本文允許轉載,請註明出處:http://blog.csdn.net/fulinus

前面在移植nand flash啟動時做了很多探索性的工作,但是後來發現在relocate.S檔案中呼叫的函式中有呼叫大部分的庫函式,牽扯到的檔案較多,很難將它們一一包含到前面4K空間中去。正在想其他方法時,突然意識到SPL功能。我初步瞭解了一下SPL的功能,簡而言之是一個將u-boot從nand flash拷貝到SDRAM中並執行的一個程式(u-boot-spl.bin),是u-boot在nand flash啟動這個情況下的bootloader。很有意思吧。

這篇博文不是我一邊探索一邊寫的,而是我經過N多天,反覆琢磨測試成功後,再把這其中的經驗整理出來分享給大家。移植成功的那一刻很開心,糾結於各種問題最終都一一化解了。後回頭看感覺很簡單,工作量也不大,哈哈。

1、make distclean #從一個乾淨的環境開始;

2、$ make menuconfig #簡單配置下;

Boot images  ---> 

[*] Enable SPL

Architecture select (ARM architecture)  --->

ARM architecture  --->

Target select (Support tq2440)  --->

儲存,退出

3、$make

編譯出錯:

Configuration file "spl/.config" not found!

這個恐怕是這個版本的SPL做的不是很好。不過不能因為這個以為就不可以了。同時在根目錄下生成spl/目錄。

4、$ cp .config spl/ #將根目錄下的.config拷貝到spl目錄中去;

5、$ make #再次編譯還是沒有通過;

6、$ make menuconfig #重新配置一下,取消SPL,儲存退出;

7、$make #再次編譯,再次因為沒有使能SPL選項可以正常編譯。總的來說前面的工作就是使其生成SPL目錄,並將.config拷貝其中。

8、$ make menuconfig #重新配置一下,使能SPL,儲存退出;

9、$make #這次編譯就可以了,有如下提示:

Support Denali NAND controller for SPL (SPL_NAND_DENALI) [N/y/?] (NEW) y

選擇y,就可以正常編譯了,並生成u-boot-spl.bin檔案:

 。。。

  LDS     u-boot.lds
  LD      u-boot
  OBJCOPY u-boot.srec
  OBJCOPY u-boot.bin #這裡是u-boot.bin檔案
  。。。
  LDS     spl/u-boot-spl.lds
  LD      spl/u-boot-spl #這裡是u-boot-spl.bin檔案
  OBJCOPY spl/u-boot-spl.bin

不過你在編譯u-boot-spl.bin檔案時,會有如下錯誤:

/home/fulinux/u-boot-2014.10/arch/arm/lib/crt0.S:99: undefined reference to `board_init_f'

在前面我們知道這個函式裡呼叫了很多C函式,而且我們的u-boot-spl.bin檔案不需要這個函式的功能,主要的工作是將nand flash中的u-boot拷貝出來,因此我們的arch/arm/lib/crt0.S檔案修改如下:

ENTRY(_main)

/*
 * Set up initial C runtime environment and call board_init_f(0).
 */

#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
        ldr     sp, =(CONFIG_SPL_STACK)
#else
        ldr     sp, =(CONFIG_SYS_INIT_SP_ADDR)
#endif
        bic     sp, sp, #7      /* 8-byte alignment for ABI compliance */
        mov     r2, sp
        sub     sp, sp, #GD_SIZE        /* allocate one GD above SP */
        bic     sp, sp, #7      /* 8-byte alignment for ABI compliance */
        mov     r9, sp          /* GD is above SP */
        mov     r1, sp
        mov     r0, #0
clr_gd:
        cmp     r1, r2                  /* while not at end of GD */
        strlo   r0, [r1]                /* clear 32-bit GD word */
        addlo   r1, r1, #4              /* move to next */
        blo     clr_gd
#if defined(CONFIG_SYS_MALLOC_F_LEN) && !defined(CONFIG_SPL_BUILD)
        sub     sp, sp, #CONFIG_SYS_MALLOC_F_LEN
        str     sp, [r9, #GD_MALLOC_BASE]
#endif

#if defined(CONFIG_SPL_BUILD)
#define LENGTH_UBOOT    0x40000
    /* Read u-boot from Nandflash to SDRAM address $CONFIG_SYS_TEXT_BASE */
    mov r0, #0x4000           /*nand_read_ll() 2nd argument*/
    ldr r1, =CONFIG_SYS_TEXT_BASE     /*nand_read_ll() 1st argument*/
    mov r2, #LENGTH_UBOOT  /*nand_read_ll() 3rd argument*/

    bl  copy_code_to_sdram

    tst r0, #0x0           /*Check nand_read_ll() return value*/
    bne infinite_loop     /*nand_read_ll() not return 0, then goto dead loop*/

    ldr pc, =CONFIG_SYS_TEXT_BASE

infinite_loop:
#define GPBDAT   0x56000014
    /* Turn on LED2 */
    ldr     r2, =GPBDAT
    ldr     r3, [r2]
    bic     r3, r3, #(1<<7)
    str     r3, [r2]
0:
    b   0b

#else
        /* mov r0, #0 not needed due to above code */
        bl      board_init_f
#endif

#if ! defined(CONFIG_SPL_BUILD)
/*
 * Set up intermediate environment (new sp and gd) and call
 * relocate_code(addr_moni). Trick here is that we'll return
 * 'here' but relocated.
 */

        ldr     sp, [r9, #GD_START_ADDR_SP]     /* sp = gd->start_addr_sp */
        bic     sp, sp, #7      /* 8-byte alignment for ABI compliance */
        ldr     r9, [r9, #GD_BD]                /* r9 = gd->bd */
        sub     r9, r9, #GD_SIZE                /* new GD is below bd */

        adr     lr, here
        ldr     r0, [r9, #GD_RELOC_OFF]         /* r0 = gd->reloc_off */
        add     lr, lr, r0
        ldr     r0, [r9, #GD_RELOCADDR]         /* r0 = gd->relocaddr */
        b       relocate_code
here:

/* Set up final (full) environment */

        bl      c_runtime_cpu_setup     /* we still call old routine here */

        ldr     r0, =__bss_start        /* this is auto-relocated! */
        ldr     r1, =__bss_end          /* this is auto-relocated! */

        mov     r2, #0x00000000         /* prepare zero to clear BSS */

clbss_l:cmp     r0, r1                  /* while not at end of BSS */
        strlo   r2, [r0]                /* clear 32-bit BSS word */
        addlo   r0, r0, #4              /* move to next */
        blo     clbss_l

        bl coloured_LED_init
        bl red_led_on

        /* call board_init_r(gd_t *id, ulong dest_addr) */
        mov     r0, r9                  /* gd_t */
        ldr     r1, [r9, #GD_RELOCADDR] /* dest_addr */
        /* call board_init_r */
        ldr     pc, =board_init_r       /* this is auto-relocated! */

        /* we should not return here. */

#endif

ENDPROC(_main)
上面設定了零時堆疊,copy_code_to_sdram函式用於將nand flash中的程式碼拷貝到SDRAM中,該函式有三個引數,第一個是u-boot.bin在nand flash中的起始地址,後面再燒錄u-boot.bin時,u-boot放置的起始位置就是0x4000,第二個是SDRAM中的地址,即目的地址(CONFIG_SYS_TEXT_BASE = 0x32000000),第3個引數是u-boot大小(LENGTH_UBOOT = 0x40000)。拷貝完成後,由下面的指令實現跳轉去執行u-boot:

ldr pc, =CONFIG_SYS_TEXT_BASE

copy_code_to_sdram函式定義在board/samsung/tq2440/nand_read.c檔案中:

#include <common.h>
#include <linux/mtd/nand.h>

#define __REGb(x)       (*(volatile unsigned char *)(x))
#define __REGw(x)       (*(volatile unsigned short *)(x))
#define __REGi(x)       (*(volatile unsigned int *)(x))
#define NF_BASE         0x4E000000
#if defined(CONFIG_S3C24100)
#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 NFSTAT_BUSY     1
#define nand_select()   (NFCONF &= ~0x800)
#define nand_deselect() (NFCONF |= 0x800)
#define nand_clear_RnB()        do {} while (0)
#elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
#define NFSTAT_BUSY     1
#define GPBDAT      __REGi(0x56000014)
#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 NFDATA16        __REGw(NF_BASE + 0x10)
#define NFSTAT          __REGb(NF_BASE + 0x20)
#define nand_select()   (NFCONT &= ~(1 << 1))
#define nand_deselect() (NFCONT |= (1 << 1))
#define nand_clear_RnB()        (NFSTAT |= (1 << 2))
#endif

static inline void nand_wait(void)
{
    int i;

    while (!(NFSTAT & NFSTAT_BUSY))
        for (i=0; i<10; i++);
}

struct boot_nand_t {
    int page_size;
    int block_size;
    int bad_block_offset;
    //  unsigned long size;
};

#ifdef CONFIG_S3C24x0_NAND_SKIP_BAD
static int is_bad_block(struct boot_nand_t * nand, unsigned long i)
{
    unsigned char data;
    unsigned long page_num;

    nand_clear_RnB();
    if (nand->page_size == 512) {
        NFCMD = NAND_CMD_READOOB; /* 0x50 */
        NFADDR = nand->bad_block_offset & 0xf;
        NFADDR = (i >> 9) & 0xff;
        NFADDR = (i >> 17) & 0xff;
        NFADDR = (i >> 25) & 0xff;
    } else if (nand->page_size == 2048) {
        page_num = i >> 11; /* addr / 2048 */
        NFCMD = NAND_CMD_READ0;
        NFADDR = nand->bad_block_offset & 0xff;
        NFADDR = (nand->bad_block_offset >> 8) & 0xff;
        NFADDR = page_num & 0xff;
        NFADDR = (page_num >> 8) & 0xff;
        NFADDR = (page_num >> 16) & 0xff;
        NFCMD = NAND_CMD_READSTART;
    } else {
        return -1;
    }
    nand_wait();
    data = (NFDATA & 0xff);
    if (data != 0xff)
        return 1;

    return 0;
}
#endif

static int nand_read_page_ll(struct boot_nand_t * nand, unsigned char *buf, unsigned long addr)
{
    unsigned short *ptr16 = (unsigned short *)buf;
    unsigned int i, page_num;

    nand_clear_RnB();

    NFCMD = NAND_CMD_READ0;

    if (nand->page_size == 512) {
        /* Write Address */
        NFADDR = addr & 0xff;
        NFADDR = (addr >> 9) & 0xff;
        NFADDR = (addr >> 17) & 0xff;
        NFADDR = (addr >> 25) & 0xff;
    } else if (nand->page_size == 2048) {
        page_num = addr >> 11; /* addr / 2048 */
        /* Write Address */
        NFADDR = 0;
        NFADDR = 0;
        NFADDR = page_num & 0xff;
        NFADDR = (page_num >> 8) & 0xff;
        NFADDR = (page_num >> 16) & 0xff;
        NFCMD = NAND_CMD_READSTART;
    } else {
        return -1;
    }
    nand_wait();

#if defined(CONFIG_S3C2410)
    for (i = 0; i < nand->page_size; i++) {
        *buf = (NFDATA & 0xff);
        buf++;
    }
#elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
    for (i = 0; i < (nand->page_size>>1); i++) {
        *ptr16 = NFDATA16;
        ptr16++;
    }
#endif

    return nand->page_size;
}

static unsigned short nand_read_id(void)
{
    unsigned short res = 0;
    NFCMD = NAND_CMD_READID;
    NFADDR = 0;
    res = NFDATA;
    res = (res << 8) | NFDATA;
    return res;
}

extern unsigned int dynpart_size[];

/* low level nand read function */
int copy_code_to_sdram(unsigned long start_addr, unsigned char *buf, int size)
{
    int i, j;
    unsigned short nand_id;
    struct boot_nand_t nand;

    /* chip Enable */
    nand_select();
    nand_clear_RnB();

    for (i = 0; i < 10; i++)
        ;
    nand_id = nand_read_id();

    if(nand_id == 0xec76 ||             /* Samsung K91208 */
            nand_id == 0xad76 ) {       /*Hynix HY27US08121A*/
        nand.page_size = 512;
        nand.block_size = 32 * nand.page_size; 
        nand.bad_block_offset = nand.page_size;

        GPBDAT &= ~(1<<6);

        //      nand.size = 0x4000000;
    }else if(nand_id == 0xecf1 ||       /* Samsung K9F1G08U0B */
            nand_id == 0xecda ||        /* Samsung K9F2G08U0B */
            nand_id == 0xecd3 ) { /* Samsung K9K8G08 */
        nand.page_size = 2048;
        nand.block_size = 128 * 1024;
        nand.bad_block_offset = nand.page_size;
        //      nand.size = 0x8000000;
    }else{
        return -1; // hang
    }

    if((start_addr & (nand.block_size-1)) 
            || (size & ((nand.block_size-1)))){
        return -1;      /* invalid alignment */
    }

    GPBDAT &= ~(1<<7);
    for (i=start_addr; i < (start_addr + size);) {
#ifdef CONFIG_S3C24x0_NAND_SKIP_BAD
        if (i & (nand.block_size-1)== 0) {
            if (is_bad_block(&nand, i) ||
                    is_bad_block(&nand, i + nand.page_size)) {
                /* Bad block */
                i += nand.block_size;
                size += nand.block_size;
                continue;
            }
        }
#endif
        j = nand_read_page_ll(&nand, buf, i);
        i += j;
        buf += j;
    }

    /* chip Disable */
    nand_deselect();

    GPBDAT &= ~(1<<8);

    return 0;
}
並修改board/samsung/tq2440/Makefile檔案如下:

obj-y   := tq2440.o
obj-y   += lowlevel_init.o
obj-$(CONFIG_SPL_BUILD) += nand_read.o

前面初始化時需要有Nand flash初始化工作,這個工作放在board/samsung/tq2440/lowlevel_init.S檔案中,如下所示:

/*
 * Memory Setup stuff - taken from blob memsetup.S
 *
 * Copyright (C) 1999 2000 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl) and
 *                     Jan-Derk Bakker (J.D.Bakker@its.tudelft.nl)
 *
 * Modified for the Samsung SMDK2410 by
 * (C) Copyright 2002
 * David Mueller, ELSOFT AG, <d.mueller@elsoft.ch>
 *
 * Modified for the friendly-arm SBC-2410X by
 * (C) Copyright 2005
 * JinHua Luo, GuangDong Linux Center, <luo.jinhua@gd-linux.com>
 *
 * See file CREDITS for list of people who contributed to this
 * project.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 */

#include <config.h>
#include <version.h>

/*
 * Taken from linux/arch/arm/boot/compressed/head-s3c2410.S
 *
 * Copyright (C) 2002 Samsung Electronics SW.LEE  <hitchcar@sec.samsung.com>
 */

#define BWSCON  0x48000000

/* BWSCON */
#define DW8                     (0x0)
#define DW16                    (0x1)
#define DW32                    (0x2)
#define WAIT                    (0x1<<2)
#define UBLB                    (0x1<<3)

#define B1_BWSCON               (DW16)
#define B2_BWSCON               (DW16)
#define B3_BWSCON               (DW16 + WAIT + UBLB)
#define B4_BWSCON               (DW16)
#define B5_BWSCON               (DW16)
#define B6_BWSCON               (DW32)
#define B7_BWSCON               (DW32)

#define B0_Tacs                 0x0
#define B0_Tcos                 0x0
#define B0_Tacc                 0x7
#define B0_Tcoh                 0x0
#define B0_Tah                  0x0
#define B0_Tacp                 0x0
#define B0_PMC                  0x0

#define B1_Tacs                 0x0
#define B1_Tcos                 0x0
#define B1_Tacc                 0x7
#define B1_Tcoh                 0x0
#define B1_Tah                  0x0
#define B1_Tacp                 0x0
#define B1_PMC                  0x0

#define B2_Tacs                 0x0
#define B2_Tcos                 0x0
#define B2_Tacc                 0x7
#define B2_Tcoh                 0x0
#define B2_Tah                  0x0
#define B2_Tacp                 0x0
#define B2_PMC                  0x0

#define B3_Tacs                 0xc
#define B3_Tcos                 0x7
#define B3_Tacc                 0xf
#define B3_Tcoh                 0x1
#define B3_Tah                  0x0
#define B3_Tacp                 0x0
#define B3_PMC                  0x0

#define B4_Tacs                 0x0
#define B4_Tcos                 0x0
#define B4_Tacc                 0x7
#define B4_Tcoh                 0x0
#define B4_Tah                  0x0
#define B4_Tacp                 0x0
#define B4_PMC                  0x0

#define B5_Tacs                 0xc
#define B5_Tcos                 0x7
#define B5_Tacc                 0xf
#define B5_Tcoh                 0x1
#define B5_Tah                  0x0
#define B5_Tacp                 0x0
#define B5_PMC                  0x0

#define B6_MT                   0x3     /* SDRAM */
#define B6_Trcd                 0x1
#define B6_SCAN                 0x1     /* 9bit */

#define B7_MT                   0x3     /* SDRAM */
#define B7_Trcd                 0x1     /* 3clk */
#define B7_SCAN                 0x1     /* 9bit */

/* REFRESH parameter */
#define REFEN                   0x1     /* Refresh enable */
#define TREFMD                  0x0     /* CBR(CAS before RAS)/Auto refresh */
#define Trc                     0x3     /* 7clk */
#define Tchr                    0x2     /* 3clk */

#if defined(CONFIG_S3C2440)
#define Trp         0x2 /* 4clk */
#define REFCNT          1012
#else
#define Trp         0x0 /* 2clk */
#define REFCNT                  0x0459
#endif
/**************************************/

#define S3C24X0_INTERRUPT_BASE      0x4A000000
#define S3C24X0_CLOCK_POWER_BASE    0x4C000000
#define S3C2410_NAND_BASE           0x4E000000
#define S3C24X0_WATCHDOG_BASE       0x53000000
#define S3C24X0_GPIO_BASE           0x56000000
#define GPBCON                      0x56000010
#define GPBDAT                      0x56000014
#define GPBUP                       0x56000018

#define INTMSK_OFFSET               0x08
#define INTSUBMSK_OFFSET            0x1c
#define MPLLCON_OFFSET              0x04
#define CLKDIVN_OFFSET              0x14
#define NFCONF_OFFSET               0x00
#define NFCONT_OFFSET               0x04
#define NFCMD_OFFSET                0x08
#define NFSTAT_OFFSET               0x20

#define MDIV_405                    0x7f << 12
#define PSDIV_405                   0x21        
#define MDIV_200                    0xa1 << 12 
#define PSDIV_200                   0x31        

.globl lowlevel_init
lowlevel_init:
    /****** Disable Watchdog ******/
    ldr r0, =S3C24X0_WATCHDOG_BASE
    mov r1, #0
    str r1, [r0]

    /****** Disable interrupt by mask all IRQ mask ******/
    ldr r0, =S3C24X0_INTERRUPT_BASE
    mvn r1, #0x0
    str r1, [r0, #INTMSK_OFFSET]
    str r1, [r0, #INTSUBMSK_OFFSET]

    /****** Initialize System Clock, FCLK:HCLK:PCLK = 1:4:8,default FCLK is 120MHz ******/
    ldr r0, =S3C24X0_CLOCK_POWER_BASE
    mov r1, #5
    str r1, [r0, #CLKDIVN_OFFSET]
    
    mrc p15, 0, r1, c1, c0, 0
    orr r1, r1, #0xc0000000
    mcr p15, 0, r1, c1, c0, 0

    mov r2, #MDIV_405
    add r2, r2, #PSDIV_405
    str r2, [r0, #MPLLCON_OFFSET]

   /***** Initialize Nandflash controller ******/
    mov r1, #S3C2410_NAND_BASE
    ldr r2, =( (7<<12)|(7<<8)|(7<<4)|(0<<0) )
    str r2, [r1, #NFCONF_OFFSET]

    ldr r2, =( (1<<4)|(0<<1)|(1<<0) )   @ Active low CE Control
    str r2, [r1, #NFCONT_OFFSET]
    
    ldr r2, =(0x6)                      @ RnB Clear
    str r2, [r1, #NFSTAT_OFFSET]

    mov r2, #0xff                       @ Reset Nandflash
    strb    r2, [r1, #NFCMD_OFFSET]
    
    mov r3, #0       @ Delay for a while
delay:
    add r3, r3, #0x1
    cmp r3, #0xa
    blt delay   

wait:
    ldr r2, [r1, #NFSTAT_OFFSET]  @ wait ready
    tst r2, #0x4
    beq wait

mem_init:
        /* 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, =mem_init
        sub     r0, r0, r1
    adr r3, mem_init       /* r3 <- current position of code   */
    add r0, r0, r3
        ldr     r1, =BWSCON     /* Bus Width Status Controller */
        add     r2, r0, #13*4
0:
        ldr     r3, [r0], #4
        str     r3, [r1], #4
        cmp     r2, r0
        bne     0b

    ldr r1, =GPBDAT
    ldr r2, [r1]
    bic r2, r2, #(1<<5)  
    str r2, [r1]

        /* everything is fine now */
        mov     pc, lr

        .ltorg
/* the literal pools origin */

SMRDATA:
    .word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28))
    .word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC))
    .word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC))
    .word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC))
    .word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC))
    .word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC))
    .word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC))
    .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 0xb2
    .word 0x30
    .word 0x30
為了避免系統在u-boot-spl.bin和u-boot.bin下重複出現初始化工作,上面這個檔案將arch/arm/cpu/arm920t/start.S檔案中的關看門狗,中斷遮蔽和時鐘設定等放在了上面,所以我們遮蔽掉arch/arm/cpu/arm920t/start.S檔案中的重複部分,並修改如下:

/*
 *  armboot - Startup Code for ARM920 CPU-core
 *
 *  Copyright (c) 2001  Marius Gr?ger <mag@sysgo.de>
 *  Copyright (c) 2002  Alex Züpke <azu@sysgo.de>
 *  Copyright (c) 2002  Gary Jennejohn <garyj@denx.de>
 *
 * SPDX-License-Identifier:     GPL-2.0+
 */

#include <asm-offsets.h>
#include <common.h>
#include <config.h>

/*
 *************************************************************************
 *
 * Startup Code (called from the ARM reset exception vector)
 *
 * do important init only if we don't start from memory!
 * relocate armboot to ram
 * setup stack
 * jump to second stage
 *
 *************************************************************************
 */

        .globl  reset

reset:
        /*
         * set the cpu to SVC32 mode
         */
        mrs     r0, cpsr
        bic     r0, r0, #0x1f
        orr     r0, r0, #0xd3
        msr     cpsr, r0

#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

#if 0
        /* turn off the watchdog */

# if defined(CONFIG_S3C2400)
#  define pWTCON        0x15300000
#  define INTMSK        0x14400008      /* Interrupt-Controller base addresses */
#  define CLKDIVN       0x14800014      /* clock divisor register */
#else
#  define pWTCON        0x53000000
#  define INTMSK        0x4A000008      /* Interrupt-Controller base addresses */
#  define INTSUBMSK     0x4A00001C
#  define CLKDIVN       0x4C000014      /* clock divisor register */
# endif

        ldr     r0, =pWTCON
        mov     r1, #0x0
        str     r1, [r0]

        /*
         * mask all IRQs by setting all bits in the INTMR - default
         */
        mov     r1, #0xffffffff
        ldr     r0, =INTMSK
        str     r1, [r0]
# if defined(CONFIG_S3C2410)
        ldr     r1, =0x3ff
        ldr     r0, =INTSUBMSK
        str     r1, [r0]
# elif defined(CONFIG_S3C2440)
    ldr r1, =0x7fff
    ldr r0, =INTSUBMSK
    str r1, [r0]
# endif

# if defined(CONFIG_S3C2440)

#  define MPLLCON 0x4C000004 /* 系統主頻配置暫存器 */
#  define UPLLCON 0x4C000008 /* USB頻率配置暫存器 */
#  define CAMDIVN 0x4C000018 /* CAMERA時鐘分頻暫存器 */
#  define MMDIV_405 (0x7f<<12)
#  define MPSDIV_405 0x21
#  define UMDIV_48 (0x38<<12)
#  define UPSDIV_48 0X22

    ldr r0, =CAMDIVN
    mov r1, #0
    str r1, [r0]

        /* FCLK:HCLK:PCLK = 1:2:4 */
        /* default FCLK is 120 MHz ! */
    ldr r0, =CLKDIVN
    mov r1, #0x05
    str r1, [r0]

    /* 如果HDIVN不等於0,CPU必須設定為非同步匯流排模式 */
    mrc p15, 0, r0, c1, c0, 0
    orr r0, r0, #0xC0000000
    mcr p15, 0, r0, c1, c0, 0

    ldr r0, =UPLLCON
    mov r1, #UMDIV_48 /* USB時鐘48MHz */
    add r1, r1, #UPSDIV_48
    str r1, [r0]
    /*
     * When you set MPLL&UPLL values, you have to set the UPLL
     * value first and then the MPLL value. (Needs intervals
     * approximately 7 NOP)
     */
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    ldr r0, =MPLLCON
    mov r1, #MMDIV_405 /* cpu時鐘 400MHz */
    add r1, r1, #MPSDIV_405
    str r1, [r0]

# else
        /* FCLK:HCLK:PCLK = 1:2:4 */
        /* default FCLK is 120 MHz ! */
        ldr     r0, =CLKDIVN
        mov     r1, #3
        str     r1, [r0]
#endif  /* CONFIG_S3C2440 */

#endif  /* CONFIG_S3C24X0 */

        /*
         * we do sys-critical inits only at reboot,
         * not when booting from ram!
         */
#if defined(CONFIG_SPL_BUILD)
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
        bl      cpu_init_crit
#endif
#endif

#define GPBCON   0x56000010
#define GPBDAT   0x56000014
#define GPBUP    0x56000018

    /* Set GPB5,GPB6,GPB7,GPB8 as GPIO OUTPUT mode */
    ldr     r0, =GPBCON
    ldr     r1, [r0]
    bic     r1, r1, #0x3Fc00      /* Set GPBCON for GPB5,GPB6,GPB7,GPB8 as 0x00 */
    orr     r1, r1, #0x15400      /* Set GPBCON for GPB5,GPB6,GPB7,GPB8 as GPIOOUT, 0x01 */
    str     r1, [r0]

    /* Set internal pullup resister */
    ldr     r0, =GPBUP
    ldr     r1, [r0]
    orr     r1, r1, #0x01E0     /* Set bit 5,6,7,8, disable pullup resister */
    @bic     r1, r1, #0x01E0    /* Clear bit 5,6,7,8, enable pullup resister */
    str     r1, [r0]


    /* Turn off LED0, LED1, LED2, LED3 */
    ldr     r2, =GPBDAT
    ldr     r3, [r2]
    orr     r3, r3, #0x01E0     /* Set bit 5,6,7,8 as high level */
    str     r3, [r2]

    /* Turn on LED0 */
    ldr     r2, =GPBDAT
    ldr     r3, [r2]
    bic     r3, r3, #(1<<5)  /* Clear bit 5, set GPB5 as low level */
    str     r3, [r2]

        bl      _main

/*------------------------------------------------------------------------------*/

        .globl  c_runtime_cpu_setup
c_runtime_cpu_setup:

        mov     pc, lr

/*
 *************************************************************************
 *
 * CPU_init_critical registers
 *
 * setup important registers
 * setup memory timing
 *
 *************************************************************************
 */


#ifndef CONFIG_SKIP_LOWLEVEL_INIT
cpu_init_crit:
        /*
         * flush v4 I/D caches
         */
        mov     r0, #0
        mcr     p15, 0, r0, c7, c7, 0   /* flush v3/v4 cache */
        mcr     p15, 0, r0, c8, c7, 0   /* flush v4 TLB */

        /*
         * disable MMU stuff and caches
         */
        mrc     p15, 0, r0, c1, c0, 0
        bic     r0, r0, #0x00002300     @ clear bits 13, 9:8 (--V- --RS)
        bic     r0, r0, #0x00000087     @ clear bits 7, 2:0 (B--- -CAM)
        orr     r0, r0, #0x00000002     @ set bit 2 (A) Align
        orr     r0, r0, #0x00001000     @ set bit 12 (I) I-Cache
        mcr     p15, 0, r0, c1, c0, 0

        /*
         * before relocating, we have to setup RAM timing
         * because memory timing is board-dependend, you will
         * find a lowlevel_init.S in your board directory.
         */
        mov     ip, lr

        bl      lowlevel_init

        mov     lr, ip
        mov     pc, lr
#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
上面#if 0到下面的#endif區域是遮蔽了的程式碼。
#if defined(CONFIG_SPL_BUILD)
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
        bl      cpu_init_crit
#endif
#endif

呼叫cpu_init_crit函式的前提是SPL編譯,且沒有定義CONFIG_SKIP_LOWLEVEL_INIT巨集。

前面使能的SPL功能時,會在.config檔案中有如下定義:

CONFIG_SPL=y

在spl/include/generated/autoconf.h標頭檔案中:

/*
 *
 * Automatically generated file; DO NOT EDIT.
 * U-Boot 2014.10 Configuration
 *
 */
#define CONFIG_SPL_NAND_DENALI 1
#define CONFIG_ARM 1
#define CONFIG_SYS_VENDOR "samsung"
#define CONFIG_TARGET_TQ2440 1
#define CONFIG_SYS_CPU "arm920t"
#define CONFIG_SYS_BOARD "tq2440"
#define CONFIG_SYS_CONFIG_NAME "tq2440"
#define CONFIG_SUPPORT_OF_CONTROL 1
#define CONFIG_SPL 1
#define CONFIG_SYS_ARCH "arm"
#define CONFIG_SYS_SOC "s3c24x0"
#define CONFIG_SPL_BUILD 1

所以不用在include/configs/tq2440.h標頭檔案中使能該巨集,如下:

#define CONFIG_SPL 1

上面還有一個CONFIG_SPL_BUILD巨集使能了。在上面的arch/arm/lib/crt0.S檔案中需要被編譯到u-boot.bin的程式碼都由CONFIG_SPL_BUILD巨集控制。


做完上面這些之後可以編譯了,並生成u-boot.bin和spl/u-boot-spl.bin檔案,通過下面兩條指令燒錄到nand flash中去:

nand erase 0 4000;tftp 32000000 u-boot-spl.bin;nand write 32000000 0 4000; #將u-boot-spl.bin檔案燒錄到nand flash的0起始地址處。

nand erase 4000 40000;tftp 32000000 u-boot.bin;nand write 32000000 4000 40000;reset; #將u-boot.bin檔案燒錄到nand flash的0x4000的起始地址處。

執行顯示:



U-Boot 2014.10 (Jan 15 2015 - 11:09:24)


CPUID: 32440001
FCLK:  405.600 MHz
HCLK:  101.400 MHz
PCLK:   50.700 MHz
DRAM:  64 MiB
fulinux
WARNING: Caches not enabled
Flash: *** failed ***
NAND:  64 MiB
*** Warning - bad CRC, using default environment


In:    serial
Out:   serial
Err:   serial
Net:   dm9000
Warning: dm9000 MAC addresses don't match:
Address in SROM is         ff:ff:ff:ff:ff:ff
Address in environment is  12:34:56:78:9a:bc


Warning: Your board does not use generic board. Please read
doc/README.generic-board and take action. Boards not
upgraded by the late 2014 may break or be removed.


這裡寫的很亂,後面我會寫的更加詳細一些。

明天繼續;



相關文章