从nand启动的uboot


所属类别:Linux

文章作者:cbqcgq

特别推荐:免费发布信息 承包关键词~~抢爆了!HOT!


我的开发板只有nand flash,但uboot不支持从nand flash启动,要移植uboot到自己的开发板上,需要对源码做一些修改,这里先来分析一下《ARM嵌入式linux系统开发从入门到精通》中给出的代码,虽然按照这个步骤编译出的二进制文件还有一些问题,但分析一下有助于之后对uboot的调试。由于uboot不支持从nand flash启动,所以将程序复制到DRAM里面去需要新加代码实现,一般通过copy_myself函数来实现。 首先看一下对start.S的修改:在ldr pc, _start_armboot前添加下面内容。#ifdef CONFIG_S3C2410_NAND_BOOTbl copy_myself@ jump to ramldr r1, =on_the_ramadd pc, r1, #0nopnop1: b 1b @ infinite loopon_the_ram:#endif在http://blog.chinaunix.net/u/29387/showart_244343.html中提到注释掉一部分relocate代码,但似乎注释的又不彻底,保留了清BSS段的代码。一个疑问是:注释掉这些内容是必须的吗?不过从出发点来说,这段代码确实是没有什么用了。下面我们来看一下copy_myself都做了哪些事情。此处参考了vivi的copy_myself代码,一些变量的定义需要添加,后面会给出,这里直接给出这些变量或宏所表达的意义。#ifdef CONFIG_S3C2410_NAND_BOOTcopy_myself:mov r10, lr @r10保存返回地址@ reset NAND @初始化nand,主要是设置相关的控制器mov r1, #NAND_CTL_BASE @NAND_CTL_BASE=0x4e000000,它是和nand相关的特殊寄存器组的基地址ldr r2, =0xf830 @ initial value 0x1111,1000,0011,0000,enable nand flash controller Initialize ECCstr r2, [r1, #oNFCONF]ldr r2, [r1, #oNFCONF]bic r2, r2, #0x800 @ enable chip,屏蔽[11],0 : NAND flash nFCE = L (active),NFCE是2410的管脚,与nandstr r2, [r1, #oNFCONF] @的NFCE相连mov r2, #0xff @ RESET commandstrb r2, [r1, #oNFCMD] @ 只传送一个字节到oNFCMDmov r3, #0 @ wait1: add r3, r3, #0x1cmp r3, #0xablt 1b @ 延时10个指令周期2: ldr r2, [r1, #oNFSTAT] @ wait ready,oNFSTAT的位[0]标志nand flash的状态,只读,取决于R/nB管脚。tst r2, #0x1 @1 = NAND Flash memory ready to operatebeq 2bldr r2, [r1, #oNFCONF]orr r2, r2, #0x800 @ disable chipstr r2, [r1, #oNFCONF]@ get read to call C functions (for nand_read())ldr sp, DW_STACK_START @ setup stack pointer, DW_STACK_START: .word STACK_BASE+STACK_SIZE-4mov fp, #0 @ no previous frame, so fp=0????????????????@ copy UBOOT to RAMldr r0, =UBOOT_RAM_BASE @UBOOT_RAM_BASE=0x33f00000 mov r1, #0x0mov r2, #0x30000 @ 0x30000=192K bl nand_read_ll @此处nand_read_ll没有给出传递参数,这里猜想其参数依次是r0~r2种的值,这也是最合理的解释tst r0, #0x0 @此处猜想汇编调用C函数的返回值赋给r0。关于汇编调用C函数的问题,有待考证。 beq ok_nand_read#ifdef CONFIG_DEBUG_LLbad_nand_read: ldr r0, STR_FAILldr r1, SerBase bl PrintWord1: b 1b @ infinite loop#endifok_nand_read:#ifdef CONFIG_DEBUG_LLldr r0, STR_OKldr r1, SerBasebl PrintWord#endif @ 此段代码打印调试信息,前提是定义了CONFIG_DEBUG_LL,我们没有定义它,跳过!@ verify mov r0, #0ldr r1, =UBOOT_RAM_BASE mov r2, #0x400 @ 4 bytes * 1024 = 4K-bytes,只验证前4K的内容,一点启示,这里只验证了前4k,并且根据go_next: @要求我们应该把所有搬运代码的代码段包含在这前 @4k之 中,代码本身并没有问题,关键是所调用ldr r3, [r0], #4 @的C函数以及相关头文件是否包含在了其中 ldr r4, [r1], #4teq r3, r4 bne notmatchsubs r2, r2, #4 @S标志着根据结果更新N和Z,beq done_nand_readbne go_nextnotmatch: @问题会是出在这儿吗?这儿有一个死循环!#ifdef CONFIG_DEBUG_LLsub r0, r0, #4ldr r1, SerBase bl PrintHexWordldr r0, STR_FAIL ldr r1, SerBasebl PrintWord#endif1: b 1bdone_nand_read:#ifdef CONFIG_DEBUG_LLldr r0, STR_OKldr r1, SerBase bl PrintWord#endifmov pc, r10@ clear memory@ r0: start address@ r1: lengthmem_clear:mov r2, #0 mov r3, r2mov r4, r2mov r5, r2mov r6, r2mov r7, r2mov r8, r2 mov r9, r2clear_loop:stmia r0!, {r2-r9}subs r1, r1, #(8 * 4)bne clear_loopmov pc, lr#endif @ CONFIG_S3C2410_NAND_BOOT还要在start.S中添加以下内容,用于定义栈地址变量。#ifdef CONFIG_S3C2410_NAND_BOOT.align 2DW_STACK_START: .word STACK_BASE+STACK_SIZE-4#endif在start.S中,我们调用了nand_read_ll函数,它在nand_read.c中实现,该文件是由我们在/board/mike2410目录下新建的#include #define __REGb(x) (*(volatile unsigned char *)(x))#define __REGi(x) (*(volatile unsigned int *)(x))#define NF_BASE 0x4e000000#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) @定义了NF相关寄存器#define BUSY 1 @这个BUSY有啥用呢???困惑!呵呵,屏蔽掉NFSTAT的前31位,只inline void wait_idle(void) { @保留最后一位 int i; while(!(NFSTAT & BUSY)) @如果忙,就延时一会儿 for(i=0; i<10; i++);}#define NAND_SECTOR_SIZE 512#define NAND_BLOCK_MASK (NAND_SECTOR_SIZE - 1)/* low level nand read function */intnand_read_ll(unsigned char *buf, unsigned long start_addr, int size){ @功能:将以start_addr为起始地址,大小为size的数据段copy到以buf int i, j; @为起始地址的内存中 if ((start_addr & NAND_BLOCK_MASK) (size & NAND_BLOCK_MASK)) { return -1; /* invalid alignment */ } /* chip Enable */ NFCONF &= ~0x800; for(i=0; i<10; i++); for(i=start_addr; i < (start_addr + size);) { /* READ0 */ NFCMD = 0; @开始读数据 /* Write Address */ NFADDR = i & 0xff; NFADDR = (i >> 9) & 0xff; NFADDR = (i >> 17) & 0xff; NFADDR = (i >> 25) & 0xff; @对此处的理解要参考K9S1208的手册,i 对应了一个32位地址,但k9s1208只有date/addr/cmd @共用的八根地址线,要分批次发送到nand flash。 wait_idle(); for(j=0; j < NAND_SECTOR_SIZE; j++, i++) {*buf = (NFDATA & 0xff);buf++; @数据以字节为单位传送到buf中 } } /* chip Disable */ NFCONF = 0x800; /* chip disable */ return 0;}修改makefile, COBJS:=mike2410.o flash.o改为COBJS:=mike2410.o flash.o nand_read.o。然后我们在board/mike2410目录下添加nandflash.h文件,它定义了nand flash的一些芯片配置参数。#include #if (CONFIG_COMMANDS & CFG_CMD_NAND)typedef enum {NFCE_LOW,NFCE_HIGH} NFCE_STATE; /*可以用NFCE_STATE声明一个枚举类型*/static inline void NF_Conf(u16 conf){S3C2410_NAND * const nand = S3C2410_GetBase_NAND();/*定义了一个指向S3C2410_NAND结构体(定义于s3c24x0.h)的指针nand,基地址是S3C2410_NAND_BASE(定义于S3C2410.h)*/nand->NFCONF = conf;}static inline void NF_Cmd(u8 cmd){S3C2410_NAND * const nand = S3C2410_GetBase_NAND();nand->NFCMD = cmd;}static inline void NF_CmdW(u8 cmd){NF_Cmd(cmd);udelay(1);}static inline void NF_Addr(u8 addr){S3C2410_NAND * const nand = S3C2410_GetBase_NAND();nand->NFADDR = addr;}static inline void NF_SetCE(NFCE_STATE s) //传递参数时s只能取NFCE_LOW或NFCE_HIGH{S3C2410_NAND * const nand = S3C2410_GetBase_NAND();switch (s) { case NFCE_LOW: nand->NFCONF &= ~(1<<11); //chip enable break; case NFCE_HIGH: nand->NFCONF = (1<<11); //chip disable break;}}static inline void NF_WaitRB(void){S3C2410_NAND * const nand = S3C2410_GetBase_NAND();while (!(nand->NFSTAT & (1<<0)));}static inline void NF_Write(u8 data){S3C2410_NAND * const nand = S3C2410_GetBase_NAND();nand->NFDATA = data;}static inline u8 NF_Read(void){S3C2410_NAND * const nand = S3C2410_GetBase_NAND();return(nand->NFDATA);}static inline void NF_Init_ECC(void){S3C2410_NAND * const nand = S3C2410_GetBase_NAND();nand->NFCONF = (1<<12);}static inline u32 NF_Read_ECC(void){S3C2410_NAND * const nand = S3C2410_GetBase_NAND();return(nand->NFECC);}#endif该头文件中定义的函数在修改的smdk2410.c中用到。下面是对mike2410.c的修改:主要是对nand的初始化。#include #include #include "nandflash.h"/* ------------------------------------------------------------------------- */#define FCLK_SPEED 1#if FCLK_SPEED==0 /* Fout = 203MHz, Fin = 12MHz for Audio */#define M_MDIV 0xC3#define M_PDIV 0x4#define M_SDIV 0x1#elif FCLK_SPEED==1 /* Fout = 202.8MHz */#define M_MDIV 0xA1#define M_PDIV 0x3#define M_SDIV 0x1 /*s3c2410.pdf 7-20*/#endif#define USB_CLOCK 1#if USB_CLOCK==0#define U_M_MDIV 0xA1#define U_M_PDIV 0x3#define U_M_SDIV 0x1#elif USB_CLOCK==1#define U_M_MDIV 0x48#define U_M_PDIV 0x3#define U_M_SDIV 0x2#endifstatic inline void delay (unsigned long loops){__asm__ volatile ("1:\n" "subs %0, %1, #1\n" "bne 1b":"=r" (loops):"0" (loops));}/** Miscellaneous platform dependent initialisations*/int board_init (void){DECLARE_GLOBAL_DATA_PTR;S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();/* to reduce PLL lock time, adjust the LOCKTIME register */clk_power->LOCKTIME = 0xFFFFFF;/* configure MPLL */clk_power->MPLLCON = ((M_MDIV << 12) + (M_PDIV << 4) + M_SDIV);/* some delay between MPLL and UPLL */delay (4000);/* configure UPLL */clk_power->UPLLCON = ((U_M_MDIV << 12) + (U_M_PDIV << 4) + U_M_SDIV);/* some delay between MPLL and UPLL */delay (8000);/* set up the I/O ports */gpio->GPACON = 0x007FFFFF;gpio->GPBCON = 0x00044555; /*针对我的板子此处应做相应的修改*,=0xBEAAF查看手册P268*/gpio->GPBUP = 0x000007FF; /* 1: The pull-up function is disabled.GPB[10:0]*/gpio->GPCCON = 0xAAAAAAAA; /*根据开发板,改为0xAABFFEAB*/gpio->GPCUP = 0x0000FFFF;gpio->GPDCON = 0xAAAAAAAA; /*改为=0xAABFAAAB*/gpio->GPDUP = 0x0000FFFF;gpio->GPECON = 0xAAAAAAAA;gpio->GPEUP = 0x0000FFFF;gpio->GPFCON = 0x000055AA; /*改为=0x7DEE*/gpio->GPFUP = 0x000000FF;gpio->GPGCON = 0xFF95FFBA; /*=FFAFFFFA*/gpio->GPGUP = 0x0000FFFF;gpio->GPHCON = 0x002AFAAA; /*0x3[10??]AAAA*/gpio->GPHUP = 0x000007FF;/* select USB port to be support for host or device */gpio->MISCCR = (1<<3);gpio->MISCCR &= ~((1<<12)(1<<13)); /*关于usb的normal和suspend???*//* arch number of SMDK2410-Board */gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;/* adress of boot parameters */gd->bd->bi_boot_params = 0x30000100;icache_enable();dcache_enable();return 0;}/** NAND flash initialization.*/#if (CONFIG_COMMANDS & CFG_CMD_NAND)extern ulong nand_probe(ulong physadr);static inline void NF_Reset(void){int i;NF_SetCE(NFCE_LOW);NF_Cmd(0xFF); /* reset command */for(i = 0; i < 10; i++); /* tWB = 100ns. */NF_WaitRB(); /* wait 200~500us; */NF_SetCE(NFCE_HIGH);}static inline void NF_Init(void){#if 0 /* a little bit too optimistic */#define TACLS 0#define TWRPH0 3#define TWRPH1 0#else#define TACLS 0#define TWRPH0 4#define TWRPH1 2#endifNF_Conf((1<<15)(0<<14)(0<<13)(1<<12)(1<<11)(TACLS<<8)(TWRPH0<<4)(TWRPH1<<0));}void nand_init(void){S3C2410_NAND * const nand = S3C2410_GetBase_NAND();NF_Init();#ifdef DEBUGprintf("NAND flash probing at 0x%.8lX\n", (ulong)nand);#endifprintf ("%4lu KB\n", nand_probe((ulong)nand) >> 10);}#endifint dram_init (void){DECLARE_GLOBAL_DATA_PTR;gd->bd->bi_dram[0].start = PHYS_SDRAM_1; /*定义见smdk2410.h*/gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;return 0;}对smdk2410.h的修改:#ifndef __CONFIG_H#define __CONFIG_H/** High Level Configuration Options* (easy to change)*/#define CONFIG_ARM920T 1 /* This is an ARM920T Core */#define CONFIG_S3C2410 1 /* in a SAMSUNG S3C2410 SoC */#define CONFIG_SMDK2410 1 /* on a SAMSUNG SMDK2410 Board *//* input clock of PLL */#define CONFIG_SYS_CLK_FREQ 12000000/* the SMDK2410 has 12MHz input clock */#define USE_920T_MMU 1#undef CONFIG_USE_IRQ /* we don't need IRQ/FIQ stuff */#define CONFIG_CMDLINE_TAG 1 /* enable passing of ATAGS */#define CONFIG_SETUP_MEMORY_TAGS 1#define CONFIG_INITRD_TAG 1/** Size of malloc() pool*/#define CFG_MALLOC_LEN (CFG_ENV_SIZE + 128*1024)#define CFG_GBL_DATA_SIZE 128 /* size in bytes reserved for initial data *//** Hardware drivers*/#define CONFIG_DRIVER_CS8900 1 /* we have a CS8900 on-board */#define CS8900_BASE 0x19000300#define CS8900_BUS16 1 /* the Linux driver does accesses as shorts *//** select serial console configuration*/#define CONFIG_SERIAL1 1 /* we use SERIAL 1 on SMDK2410 *//************************************************************* RTC************************************************************/#define CONFIG_RTC_S3C24X0 1/* allow to overwrite serial and ethaddr */#define CONFIG_ENV_OVERWRITE#define CONFIG_BAUDRATE 115200/************************************************************ Command definition***********************************************************/#define CONFIG_COMMANDS \ (CONFIG_CMD_DFL \ CFG_CMD_CACHE \CFG_CMD_ENV \ CFG_CMD_PING \ CFG_CMD_NAND \ /*CFG_CMD_EEPROM */ \ /*CFG_CMD_I2C */ \ CFG_CMD_REGINFO \ CFG_CMD_ELF)/* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */#include #define CONFIG_BOOTDELAY 3/*#define CONFIG_BOOTARGS "root=ramfs devfs=mount console=ttySA0,9600" *//*#define CONFIG_ETHADDR 08:00:3e:26:0a:5b */#define CONFIG_NETMASK 255.255.255.0#define CONFIG_IPADDR 192.168.1.10#define CONFIG_SERVERIP 192.168.1.1/*#define CONFIG_BOOTFILE "elinos-lart" *//*#define CONFIG_BOOTCOMMAND "tftp; bootm" */#if (CONFIG_COMMANDS & CFG_CMD_KGDB)#define CONFIG_KGDB_BAUDRATE 115200 /* speed to run kgdb serial port *//* what's this ? it's not used anywhere */#define CONFIG_KGDB_SER_INDEX 1 /* which serial port to use */#endif/** Miscellaneous configurable options*/#define CFG_LONGHELP /* undef to save memory */#define CFG_PROMPT "MIKE2410# " /* Monitor Command Prompt */#define CFG_CBSIZE 256 /* Console I/O Buffer Size */#define CFG_PBSIZE (CFG_CBSIZE+sizeof(CFG_PROMPT)+16) /* Print Buffer Size */#define CFG_MAXARGS 16 /* max number of command args */#define CFG_BARGSIZE CFG_CBSIZE /* Boot Argument Buffer Size */#define CFG_MEMTEST_START 0x30000000 /* memtest works on */#define CFG_MEMTEST_END 0x33F00000 /* 63 MB in DRAM */#undef CFG_CLKS_IN_HZ /* everything, incl board info, in Hz */#define CFG_LOAD_ADDR 0x30008000 /* default load address *//* the PWM TImer 4 uses a counter of 15625 for 10 ms, so we need *//* it to wrap 100 times (total 1562500) to get 1 sec. */#define CFG_HZ 1562500/* valid baudrates */#define CFG_BAUDRATE_TABLE { 9600, 19200, 38400, 57600, 115200 }/*-----------------------------------------------------------------------* Stack sizes** The stack sizes are set up in start.S using the settings below*/#define CONFIG_STACKSIZE (128*1024) /* regular stack */#ifdef CONFIG_USE_IRQ#define CONFIG_STACKSIZE_IRQ (4*1024) /* IRQ stack */#define CONFIG_STACKSIZE_FIQ (4*1024) /* FIQ stack */#endif/*-----------------------------------------------------------------------* Physical Memory Map*/#define CONFIG_NR_DRAM_BANKS 1 /* we have 1 bank of DRAM */#define PHYS_SDRAM_1 0x30000000 /* SDRAM Bank #1 */#define PHYS_SDRAM_1_SIZE 0x04000000 /* 64 MB */#define PHYS_FLASH_1 0x00000000 /* Flash Bank #1 */#define CFG_FLASH_BASE PHYS_FLASH_1/*-----------------------------------------------------------------------* FLASH and environment organization*/#define CONFIG_AMD_LV400 1 /* uncomment this if you have a LV400 flash */#if 0#define CONFIG_AMD_LV800 1 /* uncomment this if you have a LV800 flash */#endif#define CFG_MAX_FLASH_BANKS 1 /* max number of memory banks */#ifdef CONFIG_AMD_LV800#define PHYS_FLASH_SIZE 0x00100000 /* 1MB */#define CFG_MAX_FLASH_SECT (19) /* max number of sectors on one chip */#define CFG_ENV_ADDR (CFG_FLASH_BASE + 0x0F0000) /* addr of environment */#endif#ifdef CONFIG_AMD_LV400#define PHYS_FLASH_SIZE 0x00080000 /* 512KB */#define CFG_MAX_FLASH_SECT (11) /* max number of sectors on one chip */#define CFG_ENV_ADDR (CFG_FLASH_BASE + 0x070000) /* addr of environment */#endif/* timeout values are in ticks */#define CFG_FLASH_ERASE_TOUT (5*CFG_HZ) /* Timeout for Flash Erase */#define CFG_FLASH_WRITE_TOUT (5*CFG_HZ) /* Timeout for Flash Write */#define CFG_ENV_IS_IN_NAND 1#define CFG_ENV_OFFSET 0x30000#define CFG_ENV_SIZE 0x10000 /* Total Size of Environment Sector *//*-----------------------------------------------------------------------* * NAND flash settings* */#if (CONFIG_COMMANDS & CFG_CMD_NAND)#define CFG_MAX_NAND_DEVICE 1 /* Max number of NAND devices */#define SECTORSIZE 512#define ADDR_COLUMN 1#define ADDR_PAGE 2#define ADDR_COLUMN_PAGE 3#define NAND_ChipID_UNKNOWN 0x00#define NAND_MAX_FLOORS 1#define NAND_MAX_CHIPS 1#define NAND_WAIT_READY(nand) NF_WaitRB()#define NAND_DISABLE_CE(nand) NF_SetCE(NFCE_HIGH)#define NAND_ENABLE_CE(nand) NF_SetCE(NFCE_LOW)#define WRITE_NAND_COMMAND(d, adr) NF_Cmd(d)#define WRITE_NAND_COMMANDW(d, adr) NF_CmdW(d)#define WRITE_NAND_ADDRESS(d, adr) NF_Addr(d)#define WRITE_NAND(d, adr) NF_Write(d)#define READ_NAND(adr) NF_Read()/* the following functions are NOP's because S3C24X0 handles this in hardware */#define NAND_CTL_CLRALE(nandptr)#define NAND_CTL_SETALE(nandptr)#define NAND_CTL_CLRCLE(nandptr)#define NAND_CTL_SETCLE(nandptr)#define CONFIG_MTD_NAND_VERIFY_WRITE 1#define CONFIG_MTD_NAND_ECC_JFFS2 1#endif /* CONFIG_COMMANDS & CFG_CMD_NAND *//** * Nandflash Boot* */#if (CONFIG_COMMANDS & CFG_CMD_NAND) #define CONFIG_S3C2410_NAND_BOOT 1#define STACK_BASE 0x33f00000#define STACK_SIZE 0x8000#define UBOOT_RAM_BASE 0x33f80000#define NAND_CTL_BASE 0x4E000000#define bINT_CTL(Nb) __REG(INT_CTL_BASE + (Nb))#define oNFCONF 0x00#define oNFCMD 0x04#define oNFADDR 0x08#define oNFDATA 0x0c#define oNFSTAT 0x10#define oNFECC 0x14#endif#endif /* __CONFIG_H */有一个问题:LV800和LV400的选择上,并不清楚自己的板子是哪种????下一步要看看uboot命令了,我们可以先从SDRAM中调试uboot,调试成功后再移植。而这需要用到一些uboot命令,趁此机会把uboot命令熟悉一下,早晚都要学的。

相关信息

· PPT制作动感按钮跟我来

· 轻松解决:mysql数据库连接过多的错误

· I finally found the URL for ms vs2005 including MSDN for2005 终于找到MSDN2005

· VisualStudio.net中的XML注释(1)








....

32890 50071