u-boot-2014.10移植第27天----nand flash啟動(五)

fulinux發表於2015-03-25

硬體平臺:tq2440

開發環境:Ubuntu-3.11

u-boot版本:2014.10

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


為實現nand flash啟動,最好的方法是使用u-boot自身提供的SPL方式,就是藉助另一個相對獨立的u-boot-spl.bin執行檔案,將u-boot.bin拷貝到SDRAM中去,再執行u-boot.bin。這樣一來u-boot就可以再次重定向。我們這裡首先嚐試用一個老方法。

1、首先關閉“位置無關”的編譯選項,在arch/arm/config.mk檔案中,註釋“pie”:

# needed for relocation
# LDFLAGS_u-boot += -pie

2、修改基地址,在include/configs/tq2440.h配置檔案中,修改CONFIG_SYS_TEXT_BASE:

#define CONFIG_SYS_TEXT_BASE 0x33F80000

3、在board/samsung/tq2440目錄下新增nand_read_ll.c檔案,nand_read_ll.c檔案內容如下:

/* NAND FLASH控制器 */

#define NFCONF  (*((volatile unsigned long *)0x4E000000))
#define NFCONT  (*((volatile unsigned long *)0x4E000004))
#define NFCMMD  (*((volatile unsigned long *)0x4E000008))
#define NFADDR  (*((volatile unsigned long *)0x4E00000C))
#define NFDATA  (*((volatile unsigned long *)0x4E000010))
#define NFSTAT  (*((volatile unsigned long *)0x4E000020))

static int is_boot_from_norflash(void)
{
    int val;
    volatile int *p = (volatile int *)0;

    val = *p;
    *p = 0x12345678;
    if(*p == 0x12345678){
        /* 寫成功,是nand flash啟動 */
        *p = val;
        return 0;
    }else{
        /* Nor flash 不能像記憶體一樣寫 */
        return 1;
    }
}

void nand_init_ll(void)
{
#define TACLS 0
#define TWRPH0  1
#define TWRPH1  0

    /* 設定時序 */
    NFCONT = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);

    /* 使能Nand flash 控制器,初始化ECC, 禁止片選 */
    NFCONT = (1<<4)|(1<<1)|(1<<0);
}

void clear_bss(void)
{
    extern int __bss_start, __bss_end;
    int *p = &__bss_start;

    for(; p < &__bss_end; p++){
        *p = 0;
    }
}

static void nand_select(void)
{
    NFCONT &= ~(1<<1);
}

static void nand_deselect(void)
{
    NFCONT |= (1<<1);
}

static void nand_cmd(unsigned char cmd)
{
    volatile int i;

    NFCMMD = cmd;

    for(i = 0; i < 10; i++);
}

static void nand_addr(unsigned int addr)
{
    volatile int i;
    unsigned int col = addr % 2048;
    unsigned int page = addr / 2048;

    NFADDR = col & 0xFF;
    
    for(i = 0; i < 10; i++);

    NFADDR = (col >> 8) & 0xFF;

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

    NFADDR = page & 0xFF;

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

    NFADDR = (page >> 8) & 0xFF;

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

    NFADDR = (page >> 16) & 0xFF;

    for(i = 0; i < 10; i++);
}

static void nand_wait_ready(void)
{
    while(!(NFSTAT & 1));
}

static unsigned char nand_data(void)
{
    return NFDATA;
}

static void nand_read_ll(unsigned int addr, unsigned char *buf, unsigned int len)
{
    int i = 0;
    int col = addr % 2048;

    /* 1.選中 */
    nand_select();

    while(i < len)
    {
        /* 2.發出讀命令:00h */
        nand_cmd(0x00);

        /* 3.發出地址指令 */
        nand_addr(addr);

        /* 4.發出讀命令:30h */
        nand_cmd(0x30);

        /* 5.判斷狀態 */
        nand_wait_ready();

        /* 6.讀資料 */
        for(; (col < 2048) && (i < len); col++){
            buf[i] = nand_data();
            i++;
            addr++;
        }

        col = 0;
    }

    /* 7.取消選中 */
    nand_deselect();
}

void copy_code_to_sdram(unsigned char *src, unsigned char *dest, unsigned int len)
{
    int i = 0;

    /* 如果是Nor flash 啟動 */
    if(is_boot_from_norflash()){
        while(i < len){
            dest[i] = src[i];
            i++;
        }
    }else{
        nand_init_ll();
        nand_read_ll((unsigned int)src, dest, len);
    }
}

4、修改board/samsung/tq2440目錄下的Makefile檔案:

obj-y   := tq2440.o
+ obj-y   += nand_read_ll.o
obj-y   += lowlevel_init.o


5、修改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 */


#if 1
__TEXT_BASE:
    .word CONFIG_SYS_TEXT_BASE
    
    mov r0, #0
    ldr r1, __TEXT_BASE


    ldr r2, __TEXT_BASE


    ldr r3, =__bss_end


    sub r2, r3, r2


    bl copy_code_to_sdram
    bl clear_bss


    ldr pc, =call_board_init_f


call_board_init_f:
    mov r0, #0
    bl board_init_f


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


    ldr r1, __TEXT_BASE
    bl board_init_r
#else


        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
        /* mov r0, #0 not needed due to above code */
        bl      board_init_f


#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
#endif


ENDPROC(_main)


6、修改arch/arm/lib/board.c 檔案中的board_init_f函式:

//void board_init_f(ulong bootflag)
unsigned int board_init_f(ulong bootflag)
。。。

    //addr -= gd->mon_len;
    //addr &= ~(4096 - 1);
    addr = CONFIG_SYS_TEXT_BASE;

。。。

    memcpy(id, (void *)gd, sizeof(gd_t));


    return (unsigned int)id;

7、同時修改include/common.h標頭檔案中board_init_f函式的宣告:

//void  board_init_f(ulong);
unsigned int board_init_f(ulong);


8、修改連線指令碼arch/arm/cpu/u-boot.lds檔案,將nand_read_ll.c檔案放在前4K位元組中:

    .text :
    {
        *(.__image_copy_start)
        *(.vectors)
        CPUDIR/start.o (.text*)
        board/samsung/tq2440/lowlevel_init.o(.text*)
        board/samsung/tq2440/nand_read_ll.o(.text*)

        *(.text*)                           
    }  

9、修改arch/arm/config.mk檔案,將checkarmreloc功能註釋掉:

# ALL-y += checkarmreloc

10、編譯

不成功,感覺這個方法很牽強,換一種;

明天繼續;

相關文章