视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
u-boot-06在mini2440上的移植
2025-10-03 03:58:16 责编:小OO
文档
u-boot-2010-06在mini2440上的移植

[日期:2011-03-16] 来源:Linux社区  作者:L_Backkom 

u-boot-2010-06在mini2440上的移植

[日期:2011-03-16]

来源:Linux社区  作者:L_Backkom

1.1 移植环境介绍

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

 
开发板配置选项中各项的含义如下:

armCPU 的类型(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)

 
1.6 在include/configs/中建立开发板配置文件

#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

出现错误了,会是什么原因呢?测试一下U-boot本身附带的配置:

[root@angel u-boot-2009.11]# make smdk2410_config

Configuring for smdk2410 board...

ln: 创建符号链接 “asm”: 不支持的操作

make: *** [smdk2410_config] 

错误 1

依然是这个错误,于是猜测错误原因不是在自己的配置上,上网查了下,发现错误原因是:在Windows分区使用此命令,Windows分区不支持linux上的链接。

恍然大悟啊,自己把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

三.添加对Nor Flash的支持

通常,在嵌入式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

然后添加对我们mini2440开发板上2M的Nor Flash(型号为SST39VF1601)的支持。在u-boot中对Nor Flash的操作分别有初始化、擦除和写入,所以我们主要修改与硬件密切相关的三个函数flash_init、flash_erase、write_hword,修改代码如下:

#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; 

    }

}

修改完后重新编译u-boot,下载到RAM中运行结果如下图:

上一页1234下一页  GO 

更多 

u-boot-2010-06在mini2440上的移植

[日期:2011-03-16]

来源:Linux社区  作者:L_Backkom

四.添加对Nand Flash的支持

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         //堆栈的长度大小

 

其次,修改cpu/arm920t/start.S这个文件,使u-boot从Nand Flash启动,在上一节中提过,u-boot默认是从Nor Flash启动的。修改部分如下:

#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 

再次,在board/samsung/mini2440/目录下新建一个nand_read.c文件,在该文件中来实现上面汇编中要调用的nand_read_ll函数,代码如下:

#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;

然后,在board/samsung/mini2440/Makefile中添加nand_read.c的编译选项,使他编译到u-boot中,如下:

COBJS    := mini2440.o flash.o nand_read.o
还有一个重要的地方要修改,在cpu/arm920t/u-boot.lds中,这个u-boot启动连接脚本文件决定了u-boot运行的入口地址,以及各个段的存储位置,这也是链接定位的作用。添加下面两行代码的主要目的是防止编译器把我们自己添加的用于nandboot的子函数放到4K之后,否则是无法启动的。如下:

.text :

{

    cpu/arm920t/start.o    (.text)

    board/samsung/mini2440/lowlevel_init.o (.text)

    board/samsung/mini440/nand_read.o (.text)

    *(.text)

}
最后编译u-boot,生成u-boot.bin文件。然后先将mini2440开发板调到Nor启动档,利用supervivi的a命令将u-boot.bin下载到开发板的Nand Flash中,再把开发板调到Nand启动档,打开电源就从Nand Flash启动了。

 

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函数等。

我们在u-boot提供的关于S3C2410的nand_flash驱动文件的基础上添加相关代码以支持S3C2440.

#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;

}

  在s3c24x0.h里添加S3C2440相关nand_flash的结构体,修改代码如下:

#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

  在mini2440.h里添加nand_flash相关宏定义

#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

    在mini2440.h里添加saveenv命令的支持

#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

编译下载,从Nand Flash启动,从出现的信息看出,此时已经支持Nand Flash了:

 

上一页1234  GO 下载本文

显示全文
专题