u-boot-2014.10移植第29天----nand flash的SPL啟動(一)
硬體平臺: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.
這裡寫的很亂,後面我會寫的更加詳細一些。
明天繼續;
相關文章
- u-boot-2014.10移植第30天----nand flash的SPL啟動(二)bootNaN
- u-boot-2014.10移植第23天----nand flash啟動(一)bootNaN
- u-boot-2014.10移植第28天----nand flash啟動(六)bootNaN
- u-boot-2014.10移植第27天----nand flash啟動(五)bootNaN
- u-boot-2014.10移植第25天----nand flash啟動(三)bootNaN
- u-boot-2014.10移植第26天----nand flash啟動(四)bootNaN
- u-boot-2014.10移植第24天----nand flash啟動(二)bootNaN
- u-boot-2014.10移植第19天----新增nand flash命令支援(一)bootNaN
- u-boot-2014.10移植第16天----Nor flash啟動boot
- u-boot-2014.10移植第21天----新增nand flash命令支援(三)bootNaN
- u-boot-2014.10移植第22天----新增nand flash命令支援(四)bootNaN
- u-boot-2014.10移植第20天----新增nand flash命令支援(二)bootNaN
- u-boot-2014.10移植第31天----核心啟動(一)boot
- u-boot-2014.10移植第15天----nor flash操作boot
- S3C2440從NAND Flash啟動和NOR FLASH啟動的問題S3NaN
- ZYNQ FLASH+EMMC手動移植LINUX啟動Linux
- NAND FlashNaN
- NAND Flash和NOR Flash的區別NaN
- NAND FLASH的介面控制設計NaN
- u-boot-2014.10移植第17天----新增DM9000網路卡支援(一)boot
- Mini2440 64M Nand Flash 更改為128M Nand FlashNaN
- NAND FLASH系統的權衡利弊NaN
- nor flash 和nand flash 傻傻分不清楚NaN
- 關於NAND FLASH解釦的認識NaN
- NAND Flash是如何生產出來的?NaN
- 宏旺半導體科普SPI NAND Flash和SPI NOR Flash的區別NaN
- u-boot-2014.10移植第18天----新增DM9000網路卡支援(二)boot
- Nand Flash結構及錯誤機制NaN
- ARM學習之Nand FLash控制器NaN
- 怎麼看時序圖--nand flash的讀操作詳解時序圖NaN
- 你的第一個Solana SPL
- uboot1: 啟動流程和移植框架boot框架
- Nand Flash基礎知識與壞塊管理機制的研究NaN
- (轉)關於NAND flash的MTD分割槽與uboot中分割槽的理解NaNboot
- TrendForce:2024年第一季全球NAND Flash產業營收季增28.1%NaN產業營收
- 東芝停工、NAND Flash又要漲價了?宏旺半導體:國產替代來臨NaN
- Flash Cs4安裝之後打不開(啟動介面一閃而過)
- PHP的SPL擴充套件庫(一)資料結構PHP套件資料結構