硬件平台: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
#include
#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 ([email protected]) and
* Jan-Derk Bakker ([email protected])
*
* Modified for the Samsung SMDK2410 by
* (C) Copyright 2002
* David Mueller, ELSOFT AG,
*
* Modified for the friendly-arm SBC-2410X by
* (C) Copyright 2005
* JinHua Luo, GuangDong Linux Center,
*
* 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
#include
/*
* Taken from linux/arch/arm/boot/compressed/head-s3c2410.S
*
* Copyright (C) 2002 Samsung Electronics SW.LEE
*/
#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
* Copyright (c) 2002 Alex Züpke
* Copyright (c) 2002 Gary Jennejohn
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include
#include
#include
/*
*************************************************************************
*
* 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区域是屏蔽了的代码。
调用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.
这里写的很乱,后面我会写的更加详细一些。
明天继续;