硬件平台: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区域是屏蔽了的代码。
调用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移植第29天----nand flash的SPL启动(一)
原文地址:http://blog.csdn.net/fulinus/article/details/42738641