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 不过你在编译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,#GD_SIZE /* allocate one GD above SP */ bic 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,#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,#GD_START_ADDR_SP] /* sp = gd->start_addr_sp */ bic sp,#7 /* 8-byte alignment for ABI compliance */ ldr r9,#GD_BD] /* r9 = gd->bd */ sub r9,r9,#GD_SIZE /* new GD is below bd */ adr lr,here ldr r0,#GD_RELOC_OFF] /* r0 = gd->reloc_off */ add lr,lr,r0 ldr r0,#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,#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,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 前面初始化时需要有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,#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,#CLKDIVN_OFFSET] mrc p15,c1,c0,0 orr r1,#0xc0000000 mcr p15,0 mov r2,#MDIV_405 add r2,r2,#PSDIV_405 str r2,#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,#NFCONT_OFFSET] ldr r2,=(0x6) @ RnB Clear str r2,#NFSTAT_OFFSET] mov r2,#0xff @ Reset Nandflash strb r2,#NFCMD_OFFSET] mov r3,#0 @ Delay for a while delay: add r3,#0x1 cmp r3,#0xa blt delay wait: ldr r2,#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,r1 adr r3,mem_init /* r3 <- current position of code */ add r0,r3 ldr r1,=BWSCON /* Bus Width Status Controller */ add r2,#13*4 0: ldr r3,[r0],#4 str r3,[r1],#4 cmp r2,r0 bne 0b ldr r1,=GPBDAT ldr r2,[r1] bic 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,#0x1f orr 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,#1 ldr r3,#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,[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 orr r0,#0xC0000000 mcr p15,0 ldr r0,=UPLLCON mov r1,#UMDIV_48 /* USB时钟48MHz */ add 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,#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,#0x3Fc00 /* Set GPBCON for GPB5,GPB8 as 0x00 */ orr r1,#0x15400 /* Set GPBCON for GPB5,GPB8 as GPIOOUT,0x01 */ str r1,[r0] /* Set internal pullup resister */ ldr r0,=GPBUP ldr r1,[r0] orr r1,#0x01E0 /* Set bit 5,6,7,8,disable pullup resister */ @bic r1,#0x01E0 /* Clear bit 5,enable pullup resister */ str r1,[r0] /* Turn off LED0,LED1,LED2,LED3 */ ldr r2,[r2] orr r3,8 as high level */ str r3,[r2] /* Turn on LED0 */ ldr r2,#(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,c7,0 /* flush v3/v4 cache */ mcr p15,c8,0 /* flush v4 TLB */ /* * disable MMU stuff and caches */ mrc p15,0 bic r0,#0x00002300 @ clear bits 13,9:8 (--V- --RS) bic r0,#0x00000087 @ clear bits 7,2:0 (B--- -CAM) orr r0,#0x00000002 @ set bit 2 (A) Align orr r0,#0x00001000 @ set bit 12 (I) I-Cache mcr p15,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的起始地址处。 运行显示:
这里写的很乱,后面我会写的更加详细一些。 明天继续; (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |