[日期:2011-03-16] 来源:Linux社区 作者:L_Backkom
u-boot-2010-06在mini2440上的移植
| [日期:2011-03-16] | 来源:Linux社区 作者:L_Backkom |
U-boot版本:u-boot 2010-6
Linux平台:虚拟机下fedora 13
交叉编译工具:gcc-4.4.3
arm开发板:mini2440(CPU:S3C2440 ,SDRAM:M,Nor Flash:2M,Nand Flash:256M,网卡:DM9000EP)
1.2 删减u-boot文件
删除arch目录下除arm目录以外的所有目录,arm\\cpu目录下除arm920tmulu以外的所有目录,arch\\arm\\cpu\\arm920t录下除s3c24x0目录以外的所有目录(该目录下的文件不要删),arch\\arm\\include\\asm目录下除arch‐s3c24x0目录以外的所有arch‐xxxx目录(该目录下的文件不要删) 删除board目录下除samsung目录以外的所有目录,board\\samsung目录下除smdk2410目录以外的所有目录 删除include\\configs目录下除smdk2410.h文件以外的所有头文件。
1.3 修改顶层Makefile文件
# set default to nothing for native builds
ifeq ($(HOSTARCH),$(ARCH))
#CROSS_COMPILE ?=
#=========指定交叉编译工具========
CROSS_COMPILE ?= arm-linux-gcc
Endif
smdk2410_config : unconfig
@$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 samsung s3c24x0
#仿照smdk2410,配置自己的开发板
mini2440_config : unconfig
@$(MKCONFIG) $(@:_config=) arm arm920t mini2440 s3c24x0
| arm | CPU 的类型(CPU) |
| arm920t | 其对应于cpu/arm920t 子目录 |
| zcrarm | 开发者/或经销商(vender),对应于board/zcrarm目录 |
| mini2440 | 开发板的型号(BOARD),对应于board/ zcrarm /mini2440 目录 |
| s3c24x0 | 片上系统(SOC)定义 |
1.4 在/board 中建立mini2440 目录和文件
#cd board
#mkdir -p mini2440
#cp -arf samsung/smdk2410/* samsung/mini2440/
#cd mini2440/
| #mv smdk2410.c mini2440.c |
1.5 修改mini2440 目录下的Makefile文件
LIB = $(obj)lib$(BOARD).a
#COBJS := sbc2410x.o flash.o
COBJS := mini2440.o flash.o
SOBJS := lowlevel_init.o
SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)
| #cp include/configs/smdk2410.h include/configs/mini2440.h |
1.7 测试编译环境(此问题在以前移植u-boot时出现)
至此,最基本的配置已经完成。
[root@angel u-boot-2009.11]# make mini2440_config
Configuring for mini2440 board...
ln: 创建符号链接 “asm”: 不支持的操作
make: *** [mini2440_config]
| 错误 1 |
[root@angel u-boot-2009.11]# make smdk2410_config
Configuring for smdk2410 board...
ln: 创建符号链接 “asm”: 不支持的操作
make: *** [smdk2410_config]
| 错误 1 |
恍然大悟啊,自己把U-boot解压在虚拟机的共享文件夹下了,修改文件夹路径,编译……OK.
1234下一页 GO
二.基本功能实现
2.1 mini2440开发板u-boot的stage1阶段的硬件设备初始化
由于在u-boot启动代码处有两行是AT91RM9200DK的LED初始代码,但我们mini2440上的LED资源与该开发板的不一致,所以我们要删除或屏蔽该处代码,再加上mini2440的LED驱动代码(注:添加my2440 LED功能只是用于表示u-boot运行的状态,给调试带来方便,可将该段代码放到任何你想调试的地方),代码如下:
#gedit cpu/arm920t/start.S
/*bl coloured_LED_init //这两行是AT91RM9200DK开发板的LED初始化,注释掉
bl red_LED_on*/
#if defined(CONFIG_S3C2440) //区别与其他开发板
//根据mini2440原理图可知LED分别由S3C2440的PB5、6、7、8口来控制,以下是PB端口寄存器基地址(查2440的DataSheet得知)
#define GPBCON 0x56000010
#define GPBDAT 0x56000014
#define GPBUP 0x56000018
//以下对寄存器的操作参照S3C2440的DataSheet进行操作
ldr r0, =GPBUP
ldr r1, =0x7FF //即:二进制11111111111,关闭PB口上拉
str r1, [r0]
ldr r0, =GPBCON //配置PB5、6、7、8为输出口,对应PBCON寄存器的第10-17位
ldr r1, =0x154FD //即:二进制010*********
str r1, [r0]
ldr r0, =GPBDAT
ldr r1, =0x1C0 //即:二进制111000000,PB5设为低电平,6、7、8为高电平
str r1, [r0]
#endif
//此段代码使u-boot启动后,点亮开发板上的LED1,LED2、LED3、LED4不亮
在include/configs/mini2440.h头文件中添加CONFIG_S3C2440宏
#gedit include/configs/mini2440.h
#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 */
#define CONFIG_S3C2440 1 /* in a SAMSUNG S3C2440 SoC */
现在编译u-boot,在根目录下会生成一个u-boot.bin文件。然后我们利用mini2440原有的supervivi把u-boot.bin下载到RAM中运行测试(注意:我们使用supervivi进行下载时已经对CPU、RAM进行了初始化,所以我们在u-boot中要屏蔽掉对CPU、RAM的初始化),如下:
/*#ifndef CONFIG_SKIP_LOWLEVEL_INIT //在start.S文件中屏蔽u-boot对CPU、RAM的初始
bl cpu_init_crit //化
#endif*/
#make my2440_config
#make
2.2 在u-boot中添加对S3C2440一些寄存器的支持、添加中断禁止部分和时钟设置部分。
由于2410和2440的寄存器及地址大部分是一致的,所以这里就直接在2410的基础上再加上对2440的支持即可,代码如下:
#gedit cpu/arm920t/start.S
#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440)
/* turn off the watchdog */
# if defined(CONFIG_S3C2400)
# define pWTCON 0x15300000
# define INTMSK 0x14400008 /* Interupt-Controller base addresses */
# define CLKDIVN 0x14800014 /* clock divisor register */
#else //下面2410和2440的寄存器地址是一致的
# define pWTCON 0x53000000
# define INTMSK 0x4A000008 /* Interupt-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]
# endif
# if defined(CONFIG_S3C2440) //添加s3c2440的中断禁止部分
ldr r1, =0x7fff //根据2440芯片手册,INTSUBMSK寄存器有15位可用
ldr r0, =INTSUBMSK
str r1, [r0]
# endif
# if defined(CONFIG_S3C2440) //添加s3c2440的时钟部分
#define MPLLCON 0x4C000004 //系统主频配置寄存器基地址
#define UPLLCON 0x4C000008 //USB时钟频率配置寄存器基地址
ldr r0, =CLKDIVN //设置分频系数FCLK:HCLK:PCLK = 1:4:8
mov r1, #5
str r1, [r0]
ldr r0, =MPLLCON //设置系统主频为405MHz
ldr r1, =0x7F021 //这个值参考芯片手册“PLL VALUE SELECTION TABLE”部分
str r1, [r0]
ldr r0, =UPLLCON //设置USB时钟频率为48MHz
ldr r1, =0x38022 //这个值参考芯片手册“PLL VALUE SELECTION TABLE”部分
str r1, [r0]
# else //其他开发板的时钟部分,这里就不用管了,我们现在是做2440的
/* FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
# endif
#endif /* CONFIG_S3C2400 || CONFIG_S3C2410 || CONFIG_S3C2440 */
S3C2440的时钟部分除了在start.S中添加外,还要分别在board/samsung/mini2440/mini2440.c和arch/arm/cpu/arm920t/s3c24x0/speed.c中修改或添加部分代码,如下:
#gedit board/samsung/mini2440/mini2440.c //设置主频和USB时钟频率参数与start.S中的一致
#define FCLK_SPEED 2 //设置默认等于2,即下面红色代码部分有效
#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
#elif FCLK_SPEED==2 /* Fout = 405MHz */
#define M_MDIV 0x7F //这三个值根据S3C2440芯片手册“PLL VALUE SELECTION //TABLE”部分进行设置
#define M_PDIV 0x2
#define M_SDIV 0x1
#endif
#define USB_CLOCK 2 //设置默认等于2,即下面红色代码部分有效
#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
#elif USB_CLOCK==2 /* Fout = 48MHz */
#define U_M_MDIV 0x38 //这三个值根据S3C2440芯片手册“PLL VALUE SELECTION //TABLE”部分进行设置
#define U_M_PDIV 0x2
#define U_M_SDIV 0x2
#endif
#gedit cpu/arm920t/s3c24x0/speed.c //根据设置的分频系数FCLK:HCLK:PCLK = 1:4:8修改获取时
//频率的函数
static ulong get_PLLCLK(int pllreg)
{
S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
ulong r, m, p, s;
if (pllreg == MPLL)
r = clk_power->MPLLCON;
else if (pllreg == UPLL)
r = clk_power->UPLLCON;
else
hang();
m = ((r & 0xFF000) >> 12) + 8;
p = ((r & 0x003F0) >> 4) + 2;
s = r & 0x3;
#if defined(CONFIG_S3C2440)
if(pllreg == MPLL)
{ //参考S3C2440芯片手册上的公式:PLL=(2 * m * Fin)/(p * 2s)
return((CONFIG_SYS_CLK_FREQ * m * 2) / (p << s));
}
#endif
return((CONFIG_SYS_CLK_FREQ * m) / (p << s));
}
/* return HCLK frequency */
ulong get_HCLK(void)
{
S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
#if defined(CONFIG_S3C2440)
return(get_FCLK()/4);
#endif
return((clk_power->CLKDIVN & 0x2) ? get_FCLK()/2 : get_FCLK());
}
修改完毕后我们再重新编译u-boot,然后再下载到RAM中运行测试。结果终端有输出信息并且出现类似Shell的命令行,这说明这一部分移植完成。示意图如下:
上一页1234下一页 GO
本篇文章来源于 Linux公社网站(www.linuxidc.com) 原文链接:file:///C:/Documents%20and%20Settings/Administrator/桌面/201006/u-boot-2010-06在mini2440上的移植_Page2_Linux编程_Linux公社-Linux系统门户网站.mht
u-boot-2010-06在mini2440上的移植
| [日期:2011-03-16] | 来源:Linux社区 作者:L_Backkom |
通常,在嵌入式bootloader中,有两种方式来引导启动内核:从Nor Flash启动和从Nand Flash启动。u-boot中默认是从Nor Flash启动,再从上一节这个运行结果图中看,还发现几个问题:第一,我开发板的Nor Flash是2M的,而这里显示的是512kB;第二,出现Warning - bad CRC, using default environment的警告信息。不是u-boot默认是从Nor Flash启动的吗?为什么会有这些错误信息呢?这是因为我们还没有添加对我们自己的Nor Flash的支持,u-boot默认的是其他型号的Nor Flash,而我们的Nor Flash的型号是SST39VF1601。
下面我们一一来解决这些问题,让u-boot完全对我们Nor Flash的支持。首先我们修改头文件代码如下:
| #gedit include/configs/mini2440.h //修改命令行前的名字和Nor Flash参数部分的定义 |
| #define CONFIG_SYS_PROMPT "[Backkom@2440]#"
/*----------------------------------------------------------------------- * FLASH and environment organization */ #if 0 //注释掉下面两个类型的Nor Flash设置,因为不是我们所使用的型号 #define CONFIG_AMD_LV400 1 /* uncomment this if you have a LV400 flash */ #define CONFIG_AMD_LV800 1 /* uncomment this if you have a LV800 flash */ #endif #define CONFIG_SYS_MAX_FLASH_BANKS 1 /* max number of memory banks */ #define CONFIG_SST_39VF1601 1 #ifdef CONFIG_AMD_LV800 #define PHYS_FLASH_SIZE 0x00100000 /* 1MB */ #define CONFIG_SYS_MAX_FLASH_SECT (19) /* max number of sectors on one chip */ #define CONFIG_ENV_ADDR (CONFIG_SYS_FLASH_BASE + 0x0F0000) // addr of environment #endif #ifdef CONFIG_AMD_LV400 #define PHYS_FLASH_SIZE 0x00080000 /* 512KB */ #define CONFIG_SYS_MAX_FLASH_SECT (11) /* max number of sectors on one chip */ #define CONFIG_ENV_ADDR (CONFIG_SYS_FLASH_BASE + 0x070000) //addr of environment #endif #ifdef CONFIG_SST_39VF1601 //添加mini2440开发板Nor Flash设置 #define PHYS_FLASH_SIZE 0x200000 //我们开发板的Nor Flash是2M #define CONFIG_SYS_MAX_FLASH_SECT (512) //根据SST39VF1601的芯片手册描述,对其//进行操作有两种方式:块方式和扇区方式。现采用扇区方式(sector),1 sector = 2Kword = 4Kbyte,//所以2M的Nor Flash共有512个sector #define CONFIG_ENV_ADDR (CONFIG_SYS_FLASH_BASE + 0x040000) //暂设置环境变量的 //地址为0x040000(即:256Kb) #endif |
| #gedit board/samsung/my2440/flash.c |
| //修改定义部分如下: //#define MAIN_SECT_SIZE 0x10000 #define MAIN_SECT_SIZE 0x1000 //定义为4k,刚好是一个扇区的大小
//#define MEM_FLASH_ADDR1 (*(volatile u16 *)(CONFIG_SYS_FLASH_BASE + (0x00000555 << 1))) //#define MEM_FLASH_ADDR2 (*(volatile u16 *)(CONFIG_SYS_FLASH_BASE + (0x000002AA << 1))) #define MEM_FLASH_ADDR1 (*(volatile u16 *)(CONFIG_SYS_FLASH_BASE + (0x00005555 << 1))) //这两个参数看SST39VF1601手册 #define MEM_FLASH_ADDR2 (*(volatile u16 *)(CONFIG_SYS_FLASH_BASE + (0x00002AAA << 1)))
//修改flash_init函数如下: #elif defined(CONFIG_AMD_LV800) (AMD_MANUFACT & FLASH_VENDMASK) | (AMD_ID_LV800B & FLASH_TYPEMASK); #elif defined(CONFIG_SST_39VF1601) //在CONFIG_AMD_LV800后面添加CONFIG_SST_39VF1601 (SST_MANUFACT & FLASH_VENDMASK) | (SST_ID_xF1601 & FLASH_TYPEMASK);
for (j = 0; j < flash_info[i].sector_count; j++) { //if (j <= 3) { // /* 1st one is 16 KB */ // if (j == 0) { // flash_info[i].start[j] = flashbase + 0; // }
// /* 2nd and 3rd are both 8 KB */ // if ((j == 1) || (j == 2)) { // flash_info[i].start[j] = flashbase + 0x4000 + (j - 1) * 0x2000; // }
// /* 4th 32 KB */ // if (j == 3) { // flash_info[i].start[j] = flashbase + 0x8000; // } //} else { // flash_info[i].start[j] = flashbase + (j - 3) * MAIN_SECT_SIZE; //}
flash_info[i].start[j] = flashbase + j * MAIN_SECT_SIZE; }
//修改flash_print_info函数如下: case (AMD_MANUFACT & FLASH_VENDMASK): printf ("AMD: "); break; case (SST_MANUFACT & FLASH_VENDMASK): //添加SST39VF1601的 printf ("SST: "); break;
case (AMD_ID_LV800B & FLASH_TYPEMASK): printf ("1x Amd29LV800BB (8Mbit)\\n"); break; case (SST_ID_xF1601 & FLASH_TYPEMASK): //添加SST39VF1601的 printf ("1x SST39VF1610 (16Mbit)\\n"); break;
//修改flash_erase函数如下: //if ((info->flash_id & FLASH_VENDMASK) != // (AMD_MANUFACT & FLASH_VENDMASK)) { // return ERR_UNKNOWN_FLASH_VENDOR; //} if ((info->flash_id & FLASH_VENDMASK) != (SST_MANUFACT & FLASH_VENDMASK)) { return ERR_UNKNOWN_FLASH_VENDOR; }
///* wait until flash is ready */ //chip = 0; //do { // result = *addr; // /* check timeout */ // if (get_timer_masked () > // CONFIG_SYS_FLASH_ERASE_TOUT) { // MEM_FLASH_ADDR1 = CMD_READ_ARRAY; // chip = TMO; // break; // }
// if (!chip // && (result & 0xFFFF) & BIT_ERASE_DONE) // chip = READY;
// if (!chip // && (result & 0xFFFF) & BIT_PROGRAM_ERROR) // chip = ERR; //} while (!chip);
//MEM_FLASH_ADDR1 = CMD_READ_ARRAY;
//if (chip == ERR) { // rc = ERR_PROG_ERROR; // goto outahere; //}
//if (chip == TMO) { // rc = ERR_TIMOUT; // goto outahere; //} while (1) { if ((*addr & 0x40) != (*addr & 0x40)) continue; if (*addr & 0x80) { rc = ERR_OK; break; } } //修改write_hword函数如下: MEM_FLASH_ADDR1 = CMD_UNLOCK1; MEM_FLASH_ADDR2 = CMD_UNLOCK2; //MEM_FLASH_ADDR1 = CMD_UNLOCK_BYPASS; MEM_FLASH_ADDR1 = CMD_PROGRAM; //*addr = CMD_PROGRAM; *addr = data;
///* wait until flash is ready */ //chip = 0; //do { // result = *addr; // /* check timeout */ // if (get_timer_masked () > CONFIG_SYS_FLASH_ERASE_TOUT) { // chip = ERR | TMO; // break; // }
// if (!chip && ((result & 0x80) == (data & 0x80))) // chip = READY;
// if (!chip && ((result & 0xFFFF) & BIT_PROGRAM_ERROR)) { // result = *addr; // if ((result & 0x80) == (data & 0x80)) // chip = READY; // else // chip = ERR; // } //} while (!chip);
//*addr = CMD_READ_ARRAY;
//if (chip == ERR || *addr != data) // rc = ERR_PROG_ERROR; while (1) { if ((*addr & 0x40) != (*addr & 0x40)) continue;
if ((*addr & 0x80) == (data & 0x80)) { rc = ERR_OK; break; } } |
上一页1234下一页 GO
更多
u-boot-2010-06在mini2440上的移植
| [日期:2011-03-16] | 来源:Linux社区 作者:L_Backkom |
4.1 支持u-boot从Nand flash启动
目前u-boot中还没有对2440上Nand Flash的支持,也就是说要想u-boot从Nand Flash上启动得自己去实现了。
首先,在include/configs/mini2440.h头文件中定义Nand要用到的宏和寄存器,如下:
| #gedit include/configs/my2440.h //在文件末尾加入以下Nand Flash相关定义 |
| /* * Nand flash register and envionment variables */ #define CONFIG_S3C2440_NAND_BOOT 1 #define NAND_CTL_BASE 0x4E000000 //Nand Flash配置寄存器基地址,查2440手册可得知 #define bINT_CTL(Nb) __REG(INT_CTL_BASE+(Nb)) #define UBOOT_RAM_BASE 0x33f80000 #define STACK_BASE 0x33F00000 //定义堆栈的地址 #define STACK_SIZE 0x8000 //堆栈的长度大小
|
| #gedit cpu/arm920t/start.S |
| /*注意:在上一篇Nor Flash启动中,我们为了把u-boot用supervivi下载到内存中运行而屏蔽掉这段有关CPU初始化的代码。而现在我们要把u-boot下载到Nand Flash中,从Nand Flash启动,所以现在要恢复这段代码。*/
#ifndef CONFIG_SKIP_LOWLEVEL_INIT bl cpu_init_crit #endif
#if 0 //屏蔽掉u-boot中的从Nor Flash启动部分 #ifndef CONFIG_SKIP_RELOCATE_UBOOT relocate: /* relocate U-Boot to RAM */ adr r0, _start /* r0 <- current position of code */ ldr r1, _TEXT_BASE /* test if we run from flash or RAM */ cmp r0, r1 /* don't reloc during debug */ beq stack_setup
ldr r2, _armboot_start ldr r3, _bss_start sub r2, r3, r2 /* r2 <- size of armboot */ add r2, r0, r2 /* r2 <- source end address */
copy_loop: ldmia r0!, {r3-r10} /* copy from source address [r0] */ stmia r1!, {r3-r10} /* copy to target address [r1] */ cmp r0, r2 /* until source end addreee [r2] */ ble copy_loop #endif /* CONFIG_SKIP_RELOCATE_UBOOT */ #endif
//下面添加2440中u-boot从Nand Flash启动
#ifdef CONFIG_S3C2440_NAND_BOOT
#define oNFCONF 0x00 #define oNFCONT 0x04 #define oNFCMD 0x08 #define oNFSTAT 0x20 #define LENGTH_UBOOT 0x60000
mov r1, #NAND_CTL_BASE //复位Nand Flash ldr r2, =( (7<<12)|(7<<8)|(7<<4)|(0<<0) ) str r2, [r1, #oNFCONF] //设置配置寄存器的初始值,参考s3c2440手册 ldr r2, [r1, #oNFCONF]
ldr r2, =( (1<<4)|(0<<1)|(1<<0) ) str r2, [r1, #oNFCONT] //设置控制寄存器 ldr r2, [r1, #oNFCONT]
ldr r2, =(0x6) //RnB Clear str r2, [r1, #oNFSTAT] ldr r2, [r1, #oNFSTAT]
mov r2, #0xff //复位command strb r2, [r1, #oNFCMD] mov r3, #0 //等待 nand1: add r3, r3, #0x1 cmp r3, #0xa blt nand1
nand2: ldr r2, [r1, #oNFSTAT] //等待就绪 tst r2, #0x4 beq nand2
ldr r2, [r1, #oNFCONT] orr r2, r2, #0x2 //取消片选 str r2, [r1, #oNFCONT]
//get read to call C functions (for nand_read()) ldr sp, DW_STACK_START //为C代码准备堆栈,DW_STACK_START定义在下面 mov fp, #0
//copy U-Boot to RAM ldr r0, =TEXT_BASE//传递给C代码的第一个参数:u-boot在RAM中的起始地址 mov r1, #0x0 //传递给C代码的第二个参数:Nand Flash的起始地址 mov r2, # LENGTH_UBOOT //传递给C代码的第三个参数:u-boot的长度大小(128k) bl nand_read_ll //此处调用C代码中读Nand的函数,现在还没有要自己编写实现 tst r0, #0x0 beq ok_nand_read
bad_nand_read: loop2: b loop2 //infinite loop
ok_nand_read: //检查搬移后的数据,如果前4k完全相同,表示搬移成功 mov r0, #0 ldr r1, =TEXT_BASE mov r2, #0x400 //4 bytes * 1024 = 4K-bytes go_next: ldr r3, [r0], #4 ldr r4, [r1], #4 teq r3, r4 bne notmatch subs r2, r2, #4 beq stack_setup bne go_next
notmatch: loop3: b loop3 //infinite loop #endif //CONFIG_S3C2440_NAND_BOOT
_start_armboot: .word start_armboot //在这一句的下面加上DW_STACK_START的定义
.align 2 DW_STACK_START: .word STACK_BASE+STACK_SIZE-4 |
| #gedit board/samsung/mini2440/nand_read.c //新建一个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_S3C2410) && !define (CONFIG_S3C2440) #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 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 NFSTAT_BUSY 1 #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; }; 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; } 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)&& !define (CONFIG_S3C2440) 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() { 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 nand_read_ll(unsigned char *buf, 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 (0) { /* dirty little hack to detect if nand id is misread */ unsigned short * nid = (unsigned short *)0x31fffff0; *nid = nand_id; } if (nand_id == 0xec76 || /* Samsung K91208 */ nand_id == 0xad76 ) { /*Hynix HY27US08121A*/ nand.page_size = 512; nand.block_size = 16 * 1024; nand.bad_block_offset = 5; // 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 */ for (i=start_addr; i < (start_addr + size);) { #ifdef CONFIG_S3C2410_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(); return 0; } |
| COBJS := mini2440.o flash.o nand_read.o |
.text :
{
cpu/arm920t/start.o (.text)
board/samsung/mini2440/lowlevel_init.o (.text)
board/samsung/mini440/nand_read.o (.text)
*(.text)
| } |
4.2 添加Nand Flash(K9F2g08U0C)的有关操作支持
在上一节中我们说过,通常在嵌入式bootloader中,有两种方式来引导启动内核:从Nor Flash启动和从Nand Flash启动,但不管是从Nor启动或者从Nand启动,进入第二阶段以后,两者的执行流程是相同的。
现在的u-boot-2010-06版本对Nand的初始化、读写实现是基于最近的Linux内核的MTD架构,删除了以前传统的执行方法,使移植没有以前那样复杂了,实现Nand的操作和基本命令都直接在drivers/mtd/nand目录下(在doc/README.nand中讲得很清楚)。下面我们结合代码来分析一下u-boot在第二阶段的执行流程:
1.lib_arm/board.c文件中的start_armboot函数调用了drivers/mtd/nand/nand.c文件中的nand_init函数,如下:
#if defined(CONFIG_CMD_NAND) //可以看到CONFIG_CMD_NAND宏决定了Nand的初始化
puts ("NAND: ");
nand_init();
#endif
2.nand_init调用了同文件下的nand_init_chip函数;
3.nand_init_chip函数调用drivers/mtd/nand/s3c2410_nand.c文件下的board_nand_init函数,然后再调用drivers/mtd/nand/nand_base.c函数中的nand_scan函数;
| 4.nand_scan函数调用了同文件下的nand_scan_ident函数等。 |
| #gedit driver/mtd/nand/s3c2410_nand.c |
| #include #include #include #include #define NF_BASE 0x4e000000 #if defined(CONFIG_S3C2410)&&!define(CONFIG_S3C2440) #define S3C2410_NFCONF_EN (1<<15) #define S3C2410_NFCONF_512BYTE (1<<14) #define S3C2410_NFCONF_4STEP (1<<13) #define S3C2410_NFCONF_INITECC (1<<12) #define S3C2410_NFCONF_nFCE (1<<11) #define S3C2410_NFCONF_TACLS(x) ((x)<<8) #define S3C2410_NFCONF_TWRPH0(x) ((x)<<4) #define S3C2410_NFCONF_TWRPH1(x) ((x)<<0) #define S3C2410_ADDR_NALE 4 #define S3C2410_ADDR_NCLE 8 #endif #if defined(CONFIG_S3C2440) #define S3C2410_NFCONT_EN (1<<0) #define S3C2410_NFCONT_INITECC (1<<4) #define S3C2410_NFCONT_nFCE (1<<1) #define S3C2410_NFCONT_MAINECCLOCK (1<<5) #define S3C2410_NFCONF_TACLS(x) ((x)<<12) #define S3C2410_NFCONF_TWRPH0(x) ((x)<<8) #define S3C2410_NFCONF_TWRPH1(x) ((x)<<4) #define S3C2410_ADDR_NALE 0x08 #define S3C2410_ADDR_NCLE 0x0c #endif ulong IO_ADDR_W = NF_BASE; #ifdef CONFIG_NAND_SPL /* in the early stage of NAND flash booting, printf() is not available */ #define printf(fmt, args...) static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) { int i; struct nand_chip *this = mtd->priv; for (i = 0; i < len; i++) buf[i] = readb(this->IO_ADDR_R); } #endif static void s3c2410_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) { // struct nand_chip *chip = mtd->priv; struct s3c2410_nand *nand = s3c2410_get_base_nand(); debugX(1, "hwcontrol(): 0x%02x 0x%02x\\n", cmd, ctrl); if (ctrl & NAND_CTRL_CHANGE) { // ulong IO_ADDR_W = (ulong) nand; IO_ADDR_W = (ulong)nand; if (!(ctrl & NAND_CLE)) IO_ADDR_W |= S3C2410_ADDR_NCLE; if (!(ctrl & NAND_ALE)) IO_ADDR_W |= S3C2410_ADDR_NALE; // chip->IO_ADDR_W = (void *)IO_ADDR_W; #if defined(CONFIG_S3C2410)&& !define(CONFIG_S3C2440) if (ctrl & NAND_NCE) writel(readl(&nand->NFCONF) & ~S3C2410_NFCONF_nFCE, &nand->NFCONF); else writel(readl(&nand->NFCONF) | S3C2410_NFCONF_nFCE, &nand->NFCONF); } #endif #if defined(CONFIG_S3C2440) if (ctrl & NAND_NCE) writel(readl(&nand->NFCONT) & ~S3C2410_NFCONT_nFCE, &nand->NFCONT); else writel(readl(&nand->NFCONT) | S3C2410_NFCONT_nFCE, &nand->NFCONT); } #endif if (cmd != NAND_CMD_NONE) // writeb(cmd, chip->IO_ADDR_W); writeb(cmd, (void *)IO_ADDR_W); } static int s3c2410_dev_ready(struct mtd_info *mtd) { struct s3c2410_nand *nand = s3c2410_get_base_nand(); debugX(1, "dev_ready\\n"); return readl(&nand->NFSTAT) & 0x01; } #ifdef CONFIG_S3C2410_NAND_HWECC void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode) { struct s3c2410_nand *nand = s3c2410_get_base_nand(); debugX(1, "s3c2410_nand_enable_hwecc(%p, %d)\\n", mtd, mode); #if defined(CONFIG_S3C2410)&& !define(CONFIG_S3C2440) writel(readl(&nand->NFCONF) | S3C2410_NFCONF_INITECC, &nand->NFCONF); #endif #if defined(CONFIG_S3C2440) writel(readl(&nand->NFCONT) | S3C2410_NFCONT_INITECC, &nand->NFCONT); #endif } static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code) { struct s3c2410_nand *nand = s3c2410_get_base_nand(); ecc_code[0] = readb(&nand->NFECC); ecc_code[1] = readb(&nand->NFECC + 1); ecc_code[2] = readb(&nand->NFECC + 2); debugX(1, "s3c2410_nand_calculate_hwecc(%p,): 0x%02x 0x%02x 0x%02x\\n mtd , ecc_code[0], ecc_code[1], ecc_code[2]); return 0; } static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc) { if (read_ecc[0] == calc_ecc[0] && read_ecc[1] == calc_ecc[1] && read_ecc[2] == calc_ecc[2]) return 0; printf("s3c2410_nand_correct_data: not implemented\\n"); return -1; } #endif int board_nand_init(struct nand_chip *nand) { u_int32_t cfg; u_int8_t tacls, twrph0, twrph1; struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power(); struct s3c2410_nand *nand_reg = s3c2410_get_base_nand(); debugX(1, "board_nand_init()\\n"); writel(readl(&clk_power->CLKCON) | (1 << 4), &clk_power->CLKCON); #if defined(CONFIG_S3C2410)&& !define(CONFIG_S3C2440) /* initialize hardware */ twrph0 = 3; twrph1 = 0; tacls = 0; cfg = S3C2410_NFCONF_EN; cfg |= S3C2410_NFCONF_TACLS(tacls - 1); cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1); cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1); writel(cfg, &nand_reg->NFCONF); /* initialize nand_chip data structure */ nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)&nand_reg->NFDATA; #endif #if defined(CONFIG_S3C2440) twrph0 = 4; twrph1 = 2; tacls = 0; cfg = 0; cfg |= S3C2410_NFCONF_TACLS(tacls - 1); cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1); cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1); writel(cfg, &nand_reg->NFCONF); cfg = (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(0<<6)|(0<<5)|(1<<4)|(0<<1)|(1<<0); writel(cfg, &nand_reg->NFCONT); /* initialize nand_chip data structure */ nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)&nand_reg->NFDATA; #endif nand->select_chip = NULL; /* read_buf and write_buf are default */ /* read_byte and write_byte are default */ #ifdef CONFIG_NAND_SPL nand->read_buf = nand_read_buf; #endif /* hwcontrol always must be implemented */ nand->cmd_ctrl = s3c2410_hwcontrol; nand->dev_ready = s3c2410_dev_ready; #ifdef CONFIG_S3C2410_NAND_HWECC nand->ecc.hwctl = s3c2410_nand_enable_hwecc; nand->ecc.calculate = s3c2410_nand_calculate_ecc; nand->ecc.correct = s3c2410_nand_correct_data; nand->ecc.mode = NAND_ECC_HW; nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE; nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES; #else nand->ecc.mode = NAND_ECC_SOFT; #endif #ifdef CONFIG_S3C2410_NAND_BBT nand->options = NAND_USE_FLASH_BBT; #else nand->options = 0; #endif debugX(1, "end of nand_init\\n"); return 0; } |
| #gedit include/asm/arch-s3c24x0/s3c24x0.h |
| #if defined(CONFIG_S3C2440) struct s3c2410_nand { u32 NFCONF; u32 NFCONT; u32 NFCMD; u32 NFADDR; u32 NFDATA; u32 NFMECCD0; u32 NFMECCD1; u32 NFSECCD; u32 NFSTAT; u32 NFESTAT0; u32 NFESTAT1; u32 NFMECC0; u32 NFMECC1; u32 NFSECC; u32 NFSBLK; u32 NFEBLK; }; #endif #if defined(CONFIG_S3C2410)&& !define(CONFIG_S3C2440) /* NAND FLASH (see S3C2410 manual chapter 6) */ struct s3c2410_nand { u32 NFCONF; u32 NFCMD; u32 NFADDR; u32 NFDATA; u32 NFSTAT; u32 NFECC; }; #endif |
| #gedit include/configs/mini2440.h |
| #define CONFIG_CMD_NAND /* NAND flash settings */ #if defined(CONFIG_CMD_NAND) #define CONFIG_NAND_S3C2410 #define CONFIG_SYS_NAND_BASE 0x4E000000 //Nand配置寄存器基地址 #define CONFIG_SYS_MAX_NAND_DEVICE 1 #define CONFIG_MTD_NAND_VERIFY_WRITE 1 //#define NAND_SAMSUNG_LP_OPTIONS 1 //注意:我们这里是M的Nand Flash,所以不、//用,如果是M的大块Nand Flash,则需加上 #endif |
| #gedit include/configs/mini2440.h |
| //#define CONFIG_ENV_IS_IN_FLASH 1 /*屏蔽Nor Flash saveenv相关宏定义*/ //#define CONFIG_ENV_SIZE 0x10000 /* Total Size of Environment Sector */ #define CONFIG_ENV_IS_IN_NAND 1 #define CONFIG_ENV_OFFSET 0x60000 #define CONFIG_ENV_SIZE 0x20000 #define CONFIG_CMD_SAVEENV |
上一页1234 GO 下载本文