您的位置:首页 > 运维架构 > Linux

最详尽的ARM+LINUX移植攻略 linux2.6.30.4内核+yaffs2文件系统+uboot 2009.08

2014-10-18 19:05 751 查看
转载地址:http://bbs.witech.com.cn/thread-4094-1-1.html

平台:

虚拟机:VirtualBox Ubuntu 9.10

文件传输工具:SSHSecureShellClient-3.2.9

交叉编译环境:arm-linux-gcc-4.3.2

与开发板通信:tftp

Uboot移植步骤一:

建立交叉编译环境:arm-linux-gcc-4.3.2

1.将arm-linux-gcc-4.3.2.tgz复制到任意路径下;

2.确保安装了标准C开发环境,sudo apt-get install build-essential libncurses5-dev;

3.在终端进入arm-linux-gcc-4.3.2.tgz存放目录,再sudo tar -zxvf arm-linux-gcc-4.3.2.tgz -C /(注意大写C字母后留一个空格),这样会自动解压到/usr/local/4.3.2目录下);

4.修改环境变量,使交叉编译环境生效。

vim ~/.profile

在这个文件最后添加上自己的环境变量:export PATH=$PATH:/usr/local/arm/4.3.2/bin

然后在终端执行source ~/.profile ,即可立即生效。

5. arm-linux-gcc -v

Using built-in specs.

Target: arm-none-linux-gnueabi

Configured with: /scratch/julian/lite-respin/linux/src/gcc-4.3/configure --build=i686-pc-linux-gnu --host=i686-pc-linux-gnu --target=arm-none-linux-gnueabi
--enable-threads --disable-libmudflap --disable-libssp --disable-libstdcxx-pch --with-gnu-as --with-gnu-ld --enable-languages=c,c++ --enable-shared --enable-symvers=gnu --enable-__cxa_atexit --with-pkgversion='Sourcery G++ Lite 2008q3-72' --with-bugurl=https://support.codesourcery.com/GNUToolchain/
--disable-nls --prefix=/opt/codesourcery --with-sysroot=/opt/codesourcery/arm-none-linux-gnueabi/libc --with-build-sysroot=/scratch/julian/lite-respin/linux/install/arm-none-linux-gnueabi/libc --with-gmp=/scratch/julian/lite-respin/linux/obj/host-libs-2008q3-72-arm-none-linux-gnueabi-i686-pc-linux-gnu/usr
--with-mpfr=/scratch/julian/lite-respin/linux/obj/host-libs-2008q3-72-arm-none-linux-gnueabi-i686-pc-linux-gnu/usr --disable-libgomp --enable-poison-system-directories --with-build-time-tools=/scratch/julian/lite-respin/linux/install/arm-none-linux-gnueabi/bin
--with-build-time-tools=/scratch/julian/lite-respin/linux/install/arm-none-linux-gnueabi/bin

Thread model: posix

gcc version 4.3.2 (Sourcery G++ Lite 2008q3-72)

U-boot-2009.08移植TE2440II开发板--在SDRAM中运行

因为串口的波特率问题纠结了我2天,嘿嘿。

1.首先创建自己板子的目录

cd u-boot-2009.08

mkdir board/samsung/TE2440II

cp board/samsung/smdk2410/* board/samsung/TE2440II/

mv board/samsung/TE2440II/smdk2410.c board/samsung/TE2440II/TE2440II.c

2.添加配置文件

cp include/configs/smdk2410.h include/configs/TE2440II.h

在include/configs/smdk2410.h include/configs/TE2440II.h中添加

#define CONFIG_SKIP_LOWLEVEL_INIT 1

因为是先在SDRAM中运行,所以要跳过底层的初始化。暂时没有添加CONFIG_2440,用原来的CONFIG_2410,以提高移植速度。

注意暂时不要添加#define CONFIG_SKIP_RELOCATE_UBOOT 1

否则就要更改你的下载地址为0x33f80000,让他去搬运代码吧

3.修改board/samsung/TE2440II/ 目录下的Makefile,把COBJS := 修改为

COBJS := TE2440II.o flash.o

4.修改顶层Makefile

TE2440II_config : unconfig

@$(MKCONFIG) $(@:_config=) arm arm920t TE2440II samsung s3c24x0

注意有个Tab键

5. 修改顶层Makefile文件,在CROSS_COMPILE ?=后面添加自己的交叉编译工具。

CROSS_COMPILE ?= /usr/local/arm/4.3.2/bin/arm-linux-

6.完成这几步后编译一下

make TE2440II_config

make

下到SDRAM中,终端应该没有任何信息,需要设置波特率。

1. 修改TE2440II.c文件

#elif FCLK_SPEED==1 /* Fout = 405MHz */

#define M_MDIV 0x7f

#define M_PDIV 0x2

#define M_SDIV 0x1

#endif

2. 修改cpu/arm920t/start.S

外部晶振为12MHz,通过MPLLCON设置MPLL为405M

#if defined(CONFIG_S3C2410)

#define MPLLCON 0x4C000004

#define UPLLCON 0x4c000008

#define LOCKTIME 0x4C000000

#define CAMDIVN 0x4C000018

ldr r0,=LOCKTIME

ldr r1,=0xffffffff

str r1,[r0]

//清除摄像头分频寄存器的值

ldr r0,=CAMDIVN

mov r1,#0

str r1,[r0]

ldr r0, =CLKDIVN

mov r1, #5

str r1,[r0]

//手册说HDIVN不为0,加这个

mrc p15, 0, r1, c1, c0, 0 //read ctrl register

orr r1, r1, #0xc0000000 //Asynchronous

mcr p15, 0, r1, c1, c0, 0 //write ctrl register

ldr r0, =UPLLCON //同时修改UPLLCON和MPLLCON需要先修

ldr r1, =0x00038022 //改UPLLCON,且之间要间隔至少7个nop

str r1,[r0] //手册有些

nop

nop

nop

nop

nop

nop

nop

nop

ldr r0, =MPLLCON

ldr r1, =0x0007f021

str r1,[r0]

#endif

3. 修改cpu/arm920t/s3c24x0/speed.c

由于S3C2440和S3C2410的MPLL计算公式改变了,所以要改一下。

get_PLLCLK改成这样

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 (pllreg == MPLL) //MPLL的算法和UPLL是不同的。这里m=2*m

{

m <<= 1;

}

p = ((r & 0x003F0) >> 4) + 2;

s = r & 0x3;

return ((CONFIG_SYS_CLK_FREQ * m) / (p << s));

}

get_HCLK改成这样

/* return HCLK frequency */

ulong get_HCLK(void)

{

S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();

return get_FCLK()/4;

//return((clk_power->CLKDIVN & 0x2) ? get_FCLK()/2 : get_FCLK());

}

get_PCLK改成这样

/* return PCLK frequency */

ulong get_PCLK(void)

{

S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();

return get_HCLK()/2;

//return((clk_power->CLKDIVN & 0x1) ? get_HCLK()/2 : get_HCLK());

}

4. 我出问题的地方是串口,显示的基本跟正常的一样,但是显示为乱码,是串口波特率的问题。在drivers/serial/serial_s3c24x0.c中,修改

uart->UBRDIV = 27;

我直接设定了,不用鸟u-boot再鸟算了,他自己怎么也算不对,我帮他。

5. make TE2440II_config

make

下载到SDRAM中,哈哈。

U-boot-2009.08移植TE2440II开发板--支持Norflash

TE2440II开发板使用的Norflash是INTEL的JS28F320J3D75,4M,32个block,每个128KB。本文添加对Norflash的支持,使Uboot可以烧录到Norflash,从Norflash启动,并执行Norflash下的命令。

这样需要注释掉 /include/configs/TE2440II.h中的

#define CONFIG_SKIP_LOWLEVEL_INIT 1

//#define CONFIG_SKIP_RELOCATE_UBOOT 1

把include/configs/TE2440II.h的Physical Memory Map和FLASH and environment organization修改为,这里添加了/board/cmi/flash.c中部份变量的宏定义。FLASH and environment organization这里的sector指的是手册中的bank,所以大小是128KB,为32块。#define
CONFIG_ENV_ADDR (CONFIG_SYS_FLASH_BASE + 0x40000),这个偏移是自己定的,是放环境变量的,只要不在uboot的代码区就可以。

CONFIG_SYS_FLASH_ERASE_TOUT和CONFIG_SYS_FLASH_WRITE_TOUT是超时的时间,如果小了,自己改大些。cpu/arm920t/s3c24x0/timer.c中讲述了怎么获得时间的。

/*-----------------------------------------------------------------------

* 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 CONFIG_SYS_FLASH_BASE PHYS_FLASH_1

#define FLASH_BASE0_PRELIM PHYS_FLASH_1

#define CONFIG_SYS_MONITOR_BASE TEXT_BASE

/*-----------------------------------------------------------------------

* FLASH and environment organization

*/

#define CONFIG_SYS_MAX_FLASH_BANKS 1 /* max number of memory banks */

#define CONFIG_INTEL_JS28F320 1

#define PHYS_FLASH_SIZE 0x400000 /* 4M */

#define CONFIG_SYS_MAX_FLASH_SECT 32

#define CONFIG_ENV_ADDR (CONFIG_SYS_FLASH_BASE + 0x40000)

/* timeout values are in ticks */

#define CONFIG_SYS_FLASH_ERASE_TOUT (2*CONFIG_SYS_HZ) /* Timeout for Flash Erase */

#define CONFIG_SYS_FLASH_WRITE_TOUT (2*CONFIG_SYS_HZ) /* Timeout for Flash Write */

#define CONFIG_ENV_IS_IN_FLASH 1

#define CONFIG_ENV_SIZE 0x20000 /* Total Size of Environment Sector */

#endif /* __CONFIG_H */

用board/cmi/下的flash.c文件替换board/samsung/TE2440II/下的flash.c,因为cmi目录下的正好是JS28F320J3D75的驱动文件。删除这个write_short函数的申明和定 义、删除write_buff函数。替换成下面的两个函数:

/******************************************************************************************************

* Copy memory to flash.

*/

int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)

{

ulong cp, wp;

ushort data;

int l;

int i, rc;

wp = (addr & ~1); /* get lower word aligned address */

/*

* handle unaligned start bytes

*/

if ((l = addr - wp) != 0)

{

data = 0;

for (i=0, cp=wp; i<l; ++i, ++cp) {

data = (data >> 8) | (*(uchar *)cp << 8);

}

for (; i<2 && cnt>0; ++i) {

data = (data >> 8) | (*src++ << 8);

--cnt;

++cp;

}

for (; cnt==0 && i<2; ++i, ++cp) {

data = (data >> 8) | (*(uchar *)cp << 8);

}

if ((rc = write_word(info, wp, data)) != 0) {

return (rc);

}

wp += 2;

}

/*

* handle word aligned part

*/

while (cnt >= 2) {

data = *((vu_short*)src);

if ((rc = write_word(info, wp, data)) != 0) {

return (rc);

}

src += 2;

wp += 2;

cnt -= 2;

}

if (cnt == 0) {

return ERR_OK;

}

/*

* handle unaligned tail bytes

*/

data = 0;

for (i=0, cp=wp; i<2 && cnt>0; ++i, ++cp) {

data = (data >> 8) | (*src++ << 8);

--cnt;

}

for (; i<2; ++i, ++cp) {

data = (data >> 8) | (*(uchar *)cp << 8);

}

return write_word(info, wp, data);

}

/******************************************************************************************************

* Copy memory to flash.

*/

static int write_word (flash_info_t *info, ulong dest, ushort data)

{

vu_short *addr = (vu_short *)dest, val;

int rc = ERR_OK;

int flag;

/* Check if Flash is (sufficiently) erased , fix by kavin*/

if ((*addr & data) != data)

return ERR_NOT_ERASED;

/*

* Disable interrupts which might cause a timeout

* here. Remember that our exception vectors are

* at address 0 in the flash, and we don't want a

* (ticker) exception to happen while the flash

* chip is in programming mode.

*/

flag = disable_interrupts();

/* clear status register command */

*addr = 0x50;

/* program set-up command */

*addr = 0x40;

/* latch address/data */

*addr = data;

/* arm simple, non interrupt dependent timer */

reset_timer_masked();

/* wait while polling the status register */

while(((val = *addr) & 0x80) != 0x80)

{

if (get_timer_masked() > CONFIG_SYS_FLASH_WRITE_TOUT) {

rc = ERR_TIMOUT;

/* suspend program command */

*addr = 0xB0;

goto outahere;

}

}

if(val & 0x1A) { /* check for error */

printf("\nFlash write error %02x at address %08lx\n",

(int)val, (unsigned long)dest);

if(val & (1<<3)) {

printf("Voltage range error.\n");

rc = ERR_PROG_ERROR;

goto outahere;

}

if(val & (1<<1)) {

printf("Device protect error.\n");

rc = ERR_PROTECTED;

goto outahere;

}

if(val & (1<<4)) {

printf("Programming error.\n");

rc = ERR_PROG_ERROR;

goto outahere;

}

rc = ERR_PROG_ERROR;

goto outahere;

}

outahere:

/* read array command */

*addr = 0xFF;

if (flag)

enable_interrupts();

return rc;

}

修改flash.c文件中的一个宏定义:

把:

#define FLASH_BLOCK_SIZE 0x00010000

改为:

#define FLASH_BLOCK_SIZE 0x00020000

修改开发板目录下的lowlevel_init.S文件中SDARM刷新参数为:

#define REFCNT 1258 /* period=7.8125us, HCLK=405/4 Mhz, (2048+1-7.8125*405/4) */

Lowlevel_init.S中对SDRAM进行了初始化,因为我们要把第二阶段的代码搬运到SDRAM中,REFCNT是刷新计数器,这个在移植的时候是一定要修改的。手册上有公式:Refresh period = (2^11-refresh_count+1)/HCLK,我使用的这款芯片在datasheet写着8192Refresh
cycle/64ms,所以一个刷新周期为64ms/8192=7.8125us。目前公认的标准是,存储体中电容中数据有效保存期上限是64ms,也就是说每一行刷新的循环周期是64ms,这样刷新的速度就是:行数量/64ms。我的理解是CPU并不知道你用的SDRAM的刷新速度是多少,特殊功能寄存器也没有直接传递刷新速度的位,但是有一个刷新计数器,可以通过刷新计数器间接获得刷新速度,所以要设定刷新计数器。

然后就可以烧录Norflash了。

支持DM9000A

今天看了Nandflash部分,感觉不是一时半会儿能搞定的,所以先避实就虚呵呵,搞定了网卡。飞凌TE24440II使用的是双网卡,CS8900和DM9000A。已经有很好的网卡驱动代码,我们只要根据自己的板子适当修改一下就行,所以难度比Nandflash低得多。废话少说,看看怎么改。

首先注释掉跟CS8900有关的部分

//#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 */

在include/configs/TE2440II.h中添加

#define CONFIG_DRIVER_DM9000 1

#define CONFIG_NET_MULTI 1

#define CONFIG_DM9000_NO_SROM 1

#define CONFIG_DM9000_BASE 0x20000000 //网卡片选地址

#define DM9000_IO CONFIG_DM9000_BASE //网卡命令端口

#define DM9000_DATA (CONFIG_DM9000_BASE+4) //网卡数据端口

//增加ping命令

#define CONFIG_CMD_PING

//MAC地址

#define CONFIG_ETHADDR 08:00:3e:26:0a:5b

#define CONFIG_NETMASK 255.255.255.0

//开发板的IP地址

#define CONFIG_IPADDR 192.168.1.105

//Linux主机的IP地址

#define CONFIG_SERVERIP 192.168.1.103

注释掉以前跟这个重复的。

添加网卡初始化代码: 修改board/samsung/TE2440II/TE2440II.c

#include <net.h>

#include <netdev.h>

#ifdef CONFIG_DRIVER_DM9000

int board_eth_init(bd_t *bis)

{

return dm9000_initialize(bis);

}

#endif

在drivers/net/dm9000x.c中修改(屏蔽掉dm9000_init中的这一部分,不然使用网卡的时候会报“could not establish link”的错误)

#if 0

i = 0;

while (!(phy_read(1) & 0x20)) { /* autonegation complete bit */

udelay(1000);

i++;

if (i == 10000) {

printf("could not establish link\n");

return 0;

}

}

#endif

修改drivers/net/dm9000x.c。屏蔽掉dm9000_halt函数中的内容,否则ping不通。

/*

Stop the interface.

The interface is stopped when it is brought.

*/

static void dm9000_halt(struct eth_device *netdev)

{

//DM9000_DBG("%sn", __func__);

///* RESET devie */

//phy_write(0, 0x8000); /* PHY RESET */

//DM9000_iow(DM9000_GPR, 0x01); /* Power-Down PHY */

//DM9000_iow(DM9000_IMR, 0x80); /* Disable all interrupt */

//DM9000_iow(DM9000_RCR, 0x00); /* Disable RX */

}

重新编译烧录到Norflash就可以了。

这里需要注意的是#define CONFIG_DM9000_BASE 0x20000000 //网卡片选地址。而不是0x20003000,这个是DM9000,而我们使用的是DM9000A。因为CMD接在ADDR2上所以#define DM9000_DATA (CONFIG_DM9000_BASE+4)。因为DM9000A的地址信号和数据信号复用,CMD引脚决定传输的是地址信号还是数据信号。数据手册上说CMD为0时是地址信号所以DM9000_IO
CONFIG_DM9000_BASE,CMD为1时,是数据信号,所以#define DM9000_DATA (CONFIG_DM9000_BASE+4)。DM9000A内部有一个4K Dword SRAM,因为数据线和地址线是复用的,所以如果这部分用地址线进行寻址,范围是16KB,所以在 0x20000000~0x20000000+16KB范围内都可以的。所以0x20003000是碰巧在这里的。第一次ping不同,第二次开始就可以ping通了,这个是正常现象。

支持Nandflash操作

分析了一下Uboot中Nandflash的驱动,u-boot-2009.08使用的是和Linux内核一样的MTD(内存技术设备)架构。在Uboot下对Nand的支持体现在命令行下实现对nand flash的操作,为:nand info,nand device,nand read,nand
write,nand erease,nand bad。用到的主要数据结构有:struct nand_flash_dev,struct nand_chip。前者包括主要的芯片型号,存储容量,设备ID,I/O总线宽度等信息;后者是具体对nand flash进行操作时用到的信息。

对Nandflash驱动代码的分析:

1)lib_arm/board.c中start_armboot()函数中调用了nand_init()。

2)nand_init()函数定义在drivers/mtd/nand/Nand.c文件中,调用了同文件下的nand_init_chip()函数和board_nand_select_device()函数,并累加Nandflash的总大小。

3)nand_init_chip()函数初始化了IO_ADDR_R和IO_ADDR_W,调用board_nand_init()和nand_scan()。(在drivers/mtd/nand/S3c2410_nand.c中)

4)board_nand_init()函数在drivers/mtd/nand/S3c2410_nand.c中,初始化NFCONF配置寄存器。主要对struct nand_chip结构体的函数指针赋值,让他们指向自己为nand驱动编写的一些函数,该数据结构在include/linux/mtd/nand.h中定义。

5)nand_scan()函数在drivers/mtd/nand/Nand_base.c文件中定义,并调用了nand_scan_ident()和nand_scan_tail()函数。

6)nand_scan_ident()调用了同文件下的nand_set_defaults()和nand_get_flash_type(),nand_set_defaults()函数对struct nand_chip结构体的函数指针进行了赋值。在此函数中cmdfunc映射到了nand_command,nand_get_flash_type()读取了厂商和设备ID,并对struct
nand_chip结构体的变量和mtd_info进行初始化操作。

7)nand_scan_tail()进行了ECC的设置和剩下的MTD驱动函数的初始化。

8)nand_select_device()函数用来打开或关闭nand芯片,-1是打开,0是关闭。chip->cmd_ctrl映射到hwcontrol(在drivers/mtd/nand/S3c2410_nand.c的board_nand_init()函数中)。

9)返回nand_init(),这样nand的初始化就完成了。

移植Nandflash驱动,主要是修改S3c2410_nand.c。

看一个Read操作的例子:

以common/env_nand.c里读取Nandflash的环境变量为例,

env_nand.c中调用了nand_read(&nand_info[0], offset, &len, char_ptr);

nand_read在include/nand.h中定义。

static inline int nand_read(nand_info_t *info, loff_t ofs, size_t *len, u_char *buf)

{

return info->read(info, ofs, *len, (size_t *)len, buf);

}

nand_read又调用info->read,即mtd_info的read,mtd_info与nand_info_t同名。

mtd_info的read函数在drivers/nand/nand_base.c中的nand_scan_tail函数中被映射到nand_read(),在nand_read()中调用nand_do_read_ops()。这是最后一层,通过调用nand_chip中的函数完成带ECC的读操作。

现在进行移植:

修改include/configs/TE2440II.h如下

/*

* Command line configuration.

*/

#include <config_cmd_default.h>

#define CONFIG_CMD_CACHE

#define CONFIG_CMD_DATE

#define CONFIG_CMD_ELF

#define CONFIG_CMD_NAND

#define CONFIG_CMDLINE_EDITING

#ifdef CONFIG_CMDLINE_EDITING

#undef CONFIG_AUTO_COMPLETE

#else

#define CONFIG_AUTO_COMLETE

#endif

/*

* NAND flash setting

*/

#if defined(CONFIG_CMD_NAND)

#define CONFIG_SYS_NAND_BASE 0x4e000000

#define CONFIG_SYS_MAX_NAND_DEVICE 1

#define CONFIG_MTD_NAND_VERIFY_WRITE 1

#define NAND_SAMSUNG_LP_OPTIONS 1

#define CONFIG_NAND_S3C2440 1

#endif

环境变量那部分修改:

//#define CONFIG_ENV_IS_IN_FLASH 1

#define CONFIG_ENV_IS_IN_NAND 1 /*环境变量的保存位置*/

在drivers/mtd/nand/Makefile文件中添加:

COBJS-y += s3c2440_nand.o

COBJS-$(CONFIG_NAND_S3C2440) += s3c2440_nand.o

我们最重要的是修改s3c2410_nand.c,把它复制重命名为s3c2440_nand.c,因为s3c2410和s3c2440在nand控制器方面有很多不同,所以要进行移植。

修改s3c2440_nand.c为:

#define NF_BASE 0x4e000000

#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 NFMECCD0 __REGi(NF_BASE + 0x14)

#define NFMECCD1 __REGi(NF_BASE + 0x18)

#define NFSECCD __REGi(NF_BASE + 0x1C)

#define NFSTAT __REGb(NF_BASE + 0x20)

#define NFSTAT0 __REGi(NF_BASE + 0x24)

#define NFSTAT1 __REGi(NF_BASE + 0x28)

#define NFMECC0 __REGi(NF_BASE + 0x2C)

#define NFMECC1 __REGi(NF_BASE + 0x30)

#define NFSECC __REGi(NF_BASE + 0x34)

#define NFSBLK __REGi(NF_BASE + 0x38)

#define NFEBLK __REGi(NF_BASE + 0x3c)

#define S3C2440_NFCONT_nCE (1<<1)

#define S3C2440_ADDR_NALE 0x0c

#define S3C2440_ADDR_NCLE 0x08

ulong IO_ADDR_W = NF_BASE;

static void s3c2440_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)

{

struct nand_chip *chip = mtd->priv;

DEBUGN("hwcontrol(): 0x%02x 0x%02x\n", cmd, ctrl);

if (ctrl & NAND_CTRL_CHANGE) {

IO_ADDR_W = NF_BASE;

if (!(ctrl & NAND_CLE)) //要写的是地址

{

IO_ADDR_W |= S3C2440_ADDR_NALE;}

if (!(ctrl & NAND_ALE)) //要写的是命令

{

IO_ADDR_W |= S3C2440_ADDR_NCLE;}

if (ctrl & NAND_NCE)

{NFCONT &= ~S3C2440_NFCONT_nCE; //使能nand flash

//DEBUGN("NFCONT is 0x%x ",NFCONT);

//DEBUGN("nand Enable ");

}

else

{NFCONT |= S3C2440_NFCONT_nCE; //禁止nand flash

//DEBUGN("nand disable ");

}

}

if (cmd != NAND_CMD_NONE)

writeb(cmd,(void *)IO_ADDR_W);

}

static int s3c2440_dev_ready(struct mtd_info *mtd)

{

DEBUGN("dev_ready\n");

return (NFSTAT & 0x01);

}

/******************************************************************************************/

int board_nand_init(struct nand_chip *nand)

{

u_int32_t cfg;

u_int8_t tacls, twrph0, twrph1;

S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();

DEBUGN("board_nand_init()\n");

clk_power->CLKCON |= (1 << 4);

DEBUGN("CONFIG_S3C2440\n");

twrph0 = 4; twrph1 = 2; tacls = 0;

cfg = (tacls<<12)|(twrph0<<8)|(twrph1<<4);

NFCONF = cfg;

//DEBUGN("cfg is %x\n",cfg);

//DEBUGN("NFCONF is %lx\n",NFCONF);

cfg = (1<<6)|(1<<4)|(0<<1)|(1<<0);

NFCONT = cfg;

//DEBUGN("cfg is %lx\n",cfg);

//DEBUGN("NFCONT is %x\n",NFCONT);

/* initialize nand_chip data structure */

nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)0x4e000010;

/* read_buf and write_buf are default */

/* read_byte and write_byte are default */

/* hwcontrol always must be implemented */

nand->cmd_ctrl = s3c2440_hwcontrol;

nand->dev_ready = s3c2440_dev_ready;

return 0;

}

s3c2440_hwcontrol函数主要控制是写命令还是写地址。

我遇到的问题,由于board_nand_init()函数我没有添加return 0,导致后面的判断没法进行,结果读出的NAND为0MiB,所以移植一定要仔细阅读源码,还有个问题就是uboot的打印信息中出现NAND_ECC_NONE selected by board driver. This
is not recommended!!,这根ECC的校验模式有关,有人说“据说vivi或uboot通过软件算法产生的ecc校验码于S3C2410 NAND Flash 控制器产生的ecc校验码不一致”,所以我就没改什么,我把那个打印信息注释掉了。

支持Nandflash启动

从nandflash启动最关键的部分是rellocated,即代码重定位。s3c2440数据手册有这么一段,所以代码重定位是由nandflash控制器自动完成的,而不是一些人说的由CPU完成的。

在include/configs/TE2440II.h中添加nandflash控制器的定义:

/*

* NAND flash setting

*/

#if defined(CONFIG_CMD_NAND)

#define CONFIG_SYS_NAND_BASE 0x4e000000

#define CONFIG_SYS_MAX_NAND_DEVICE 1

#define CONFIG_MTD_NAND_VERIFY_WRITE 1

#define NAND_SAMSUNG_LP_OPTIONS 1 //大页要添加这个

#define CONFIG_NAND_S3C2440 1

#define CONFIG_S3C2440_NAND_BOOT 1

#define NAND_CTL_BASE 0x4E000000

#define oNFCONF 0x00

#define oNFCONT 0x04

#define oNFADDR 0x0c

#define oNFDATA 0x10

#define oNFCMD 0x08

#define oNFSTAT 0x20

#define oNFECC 0x2c

#endif



/*

* Command line configuration.

*/

下添加

#define CONFIG_CMD_NAND

修改环境变量那部分

//#undef CONFIG_ENV_IS_IN_FLASH 1

#define CONFIG_ENV_IS_IN_NAND 1

其次,修改cpu/arm920t/start.S这个文件,使u-boot从Nand Flash启动

为了让他自动识别是从norflash还是从nandflash启动添加,BWSCON的第2,1为即OM1,OM0。为00时是从nandflash启动,其他为从norflash启动,判断OM1和OM0,就可以让uboot自动识别启动方式。

#define BWSCON 0x48000000

ldr r0, =BWSCON

ldr r1,[r0]

ands r1, r1, #0x6

beq nand_boot

nor_boot:

#ifndef CONFIG_SKIP_RELOCATE_UBOOT

添加nandflash的启动代码,核心是relocated部分。首先设置nandflash控制器,然后将nandflash中从0开始的uboot复制到SDRAM中的TEXT_BASE处,TEXT_BASE在config.mk中定义,值为0x33f80000。复制好后,比较nandflash和SDRAM中的数据,如果前4K相同,表示搬移成功。下面的汇编代码注意ATPC标准规定r0~r3,用于参数传递和返回值。

/********************************************************/

//#define CONFIG_S3C2440_NAND_BOOT 1

nand_boot:

#define CONFIG_S3C2440_NAND_BOOT 1

#define NAND_CTL_BASE 0x4E000000

/* Offset */

#define oNFCONF 0x00

#define oNFCONT 0x04

#define oNFCMD 0x08

#define oNFSTAT 0x20

#define LENGTH_UBOOT 0x40000

@ reset NAND

mov r1, #NAND_CTL_BASE

ldr r2, =( (7<<12)|(7<<8)|(7<<4)|(0<<0) )

str r2, [r1, #oNFCONF]

ldr r2, [r1, #oNFCONF]

ldr r2, =((1<<4)|(0<<1)|(1<<0) ) @ Active low CE Control

str r2, [r1, #oNFCONT]

ldr r2, [r1, #oNFCONT]

ldr r2, =(0x6) @ RnB Clear

str r2, [r1, #oNFSTAT]

ldr r2, [r1, #oNFSTAT]

mov r2, #0xff @ RESET command

strb r2, [r1, #oNFCMD]

mov r3, #0 @ wait

nand1:

add r3, r3, #0x1

cmp r3, #0xa

blt nand1

nand2:

ldr r2, [r1, #oNFSTAT] @ wait ready

tst r2, #0x4

beq nand2

ldr r2, [r1, #oNFCONT]

orr r2, r2, #0x2 @ Flash Memory Chip Disable

str r2, [r1, #oNFCONT]

@ get read to call C functions (for nand_read())

ldr sp, DW_STACK_START @ setup stack pointer

mov fp, #0 @ no previous frame, so 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的长度大小

/**********************************************************/

/************************************************************/

bl nand_read_ll

tst r0, #0x0

beq ok_nand_read

bad_nand_read:

loop2:

b loop2 @ infinite loop

ok_nand_read:

@ verify

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

/* Set up the stack */

stack_setup:

ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */

sub r0, r0, #CONFIG_SYS_MALLOC_LEN /* malloc area */

sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE /* bdinfo */

#ifdef CONFIG_USE_IRQ

sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)

#endif

sub sp, r0, #12 /* leave 3 words for abort-stack */

clear_bss:

ldr r0, _bss_start /* find start of bss segment */

ldr r1, _bss_end /* stop here */

mov r2, #0x00000000 /* clear */

clbss_l:str r2, [r0] /* clear loop... */

add r0, r0, #4

cmp r0, r1

ble clbss_l

ldr pc, _start_armboot

_start_armboot: .word start_armboot

#define STACK_BASE 0x33ff8000

#define STACK_SIZE 0x10000

.align 2

DW_STACK_START: .word STACK_BASE+STACK_SIZE-4

在board/samsung/TE2440II/目录下添加nand_read.c文件,内容如下,在K9F2G08的datasheet中有这么一段

所以地址由5个周期传完。前两个周期用来寻页内地址。后三个周期是页间寻址。1device=2048block=2048*64page=2048*64*(2k+64)Bytes

#include <config.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

#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 << 2)

#define nand_select() (NFCONT &= ~(1 << 1))

#define nand_deselect() (NFCONT |= (1 << 1))

#define nand_clear_RnB() (NFSTAT |= NFSTAT_BUSY)

static inline void nand_wait(void)

{

int i;

while (!(NFSTAT & NFSTAT_BUSY))

for (i=0; i<10; i++);

}

/* configuration for 2440 with 2048byte sized flash */

#define NAND_5_ADDR_CYCLE

#define NAND_PAGE_SIZE 2048

#define BAD_BLOCK_OFFSET NAND_PAGE_SIZE

#define NAND_BLOCK_MASK (NAND_PAGE_SIZE - 1)

#define NAND_BLOCK_SIZE (NAND_PAGE_SIZE * 64)

static int nand_read_page_ll(unsigned char *buf, unsigned long addr)

{

unsigned int i, page_num;

nand_clear_RnB();

NFCMD = NAND_CMD_READ0;

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;

nand_wait();

for (i = 0; i < NAND_PAGE_SIZE; i++)

{

*buf = (NFDATA & 0xff);

buf++;

}

return NAND_PAGE_SIZE;

}

/* low level nand read function */

int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)

{

int i, j;

if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK))

{

return -1; /* invalid alignment */

}

/* chip Enable */

nand_select();

nand_clear_RnB();

for (i=0; i<10; i++);

for (i=start_addr; i < (start_addr + size);)

{

j = nand_read_page_ll(buf, i);

i += j;

buf += j;

}

/* chip Disable */

nand_deselect();

return 0;

}

然后在Makefile中添加

COBJS := my2440.o flash.o nand_read.o

修改TE2440II下的链接脚本u-boot.lds,使初始化和重定位代码被链接到前4KB。

.text :

{

cpu/arm920t/start.o (.text)

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

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

*(.text)

}

支持东华
3.5寸LCD输出console信息和BMP图片、logo

由于linux启动代码,仍然出现乱码,而我将启动信息输出到lcd就没有乱码。暂时这个问题还没有解决,lcd其实早已完成,今天整理下,再解决那个问题。

下面是我绘制的主要的lcd驱动调用流程图。start_armboot()在lib_arm/board.c中,stdio_init()在common/stdio.cdrv_video_init(),video_init(),video_logo (),video_fb_address()在drivers/video/cfb_console.c中,video_hw_init()在drivers/video/s3c2410_fb.c中,board_video_init()在board/samsung/TE2440II/TE2440II.c。

最终调用了board_video_init()函数,这个函数由我们自己来编写,由于以前写过裸机的lcd程序,所以时序就可以直接拿来用,不用调了,哈哈。在这个函数中主要还是对那5个lcd的控制寄存器进行初始化。这里要注意根据不同的屏,进行x,y的调整,我用的是东华WXCAT35-TG3#001,主要就是初始化一个GraphicDevice
*pGD结构体。

view plaincopy to clipboardprint?

#define MVAL (0)

#define MVAL_USED (0) //0=each frame 1=rate by MVAL

#define INVVDEN (0) //0=normal 1=inverted

#define BSWP (0) //Byte swap control

#define HWSWP (0) //Half word swap control

//TFT 240320

#define LCD_XSIZE_TFT_240320 (320)

#define LCD_YSIZE_TFT_240320 (240)

//TFT240320

#define HOZVAL_TFT_240320 (LCD_XSIZE_TFT_240320-1)

#define LINEVAL_TFT_240320 (LCD_YSIZE_TFT_240320-1)

//Timing parameter for WXCAT35-TG3#001"

#define VBPD_240320 (3)

#define VFPD_240320 (5)

#define VSPW_240320 (15)

#define HBPD_240320 (58)

#define HFPD_240320 (15)

#define HSPW_240320_WXCAT35 (8) //Adjust the horizontal displacement of the screen

#define CLKVAL_TFT_240320 (7)

//FCLK=405MHz,HCLK=101.25MHz,VCLK=4602272Hz

void board_video_init(GraphicDevice *pGD)

{

S3C24X0_LCD * const lcd = S3C24X0_GetBase_LCD();

S3C2410_NAND * const nand = S3C2410_GetBase_NAND();

/* FIXME: select LCM type by env variable */

/* Configuration for GTA01 LCM on QT2410 */

lcd->LCDCON1 = 0x00000778; /* CLKVAL=7, BPPMODE=16bpp, TFT, ENVID=0 */

lcd->LCDCON2 = (VBPD_240320<<24)|(LINEVAL_TFT_240320<<14)|(VFPD_240320<<6)|(VSPW_240320);

lcd->LCDCON3 = (HBPD_240320<<19)|(HOZVAL_TFT_240320<<8)|(HFPD_240320);

lcd->LCDCON4 = (MVAL<<8)|(HSPW_240320_WXCAT35);

lcd->LCDCON5 = 0x00000f09;

lcd->LPCSEL = 0x00000000;

}

明白上边的流程后一切变得很简单,只要根据自己的屏调整好时序就行了。添加一个驱动文件这个是一个外国的牛人已经写好的。在drivers/video/下添加s3c2410_fb.c。代码如下:

view plaincopy to clipboardprint?

/*

* (C) Copyright 2006 by OpenMoko, Inc.

* Author: Harald Welte <laforge@openmoko.org>

*

* 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 <common.h>

#if defined(CONFIG_VIDEO_S3C2410)

#include <video_fb.h>

#include "videomodes.h"

#include <s3c2410.h>

/*

* Export Graphic Device

*/

GraphicDevice smi;

#define VIDEO_MEM_SIZE 0x200000 /* 240x320x16bit = 0x25800 bytes */

extern void board_video_init(GraphicDevice *pGD);

/*******************************************************************************

*

* Init video chip with common Linux graphic modes (lilo)

*/

void *video_hw_init (void)

{

S3C24X0_LCD * const lcd = S3C24X0_GetBase_LCD();

GraphicDevice *pGD = (GraphicDevice *)&smi;

int videomode;

unsigned long t1, hsynch, vsynch;

char *penv;

int tmp, i, bits_per_pixel;

struct ctfb_res_modes *res_mode;

struct ctfb_res_modes var_mode;

// unsigned char videoout;

/* Search for video chip */

printf("Video: ");

tmp = 0;

videomode = CFG_SYS_DEFAULT_VIDEO_MODE;

/* get video mode via environment */

if ((penv = getenv ("videomode")) != NULL) {

/* deceide if it is a string */

if (penv[0] <= '9') {

videomode = (int) simple_strtoul (penv, NULL, 16);

tmp = 1;

}

} else {

tmp = 1;

}

if (tmp) {

/* parameter are vesa modes */

/* search params */

for (i = 0; i < VESA_MODES_COUNT; i++) {

if (vesa_modes.vesanr
== videomode)

break;

}

if (i == VESA_MODES_COUNT) {

printf ("no VESA Mode found, switching to mode 0x%x ",

CFG_SYS_DEFAULT_VIDEO_MODE);

i = 0;

}

res_mode =

(struct ctfb_res_modes *) &res_mode_init[vesa_modes.

resindex];

bits_per_pixel = vesa_modes.bits_per_pixel;

}

else {

res_mode = (struct ctfb_res_modes *) &var_mode;

bits_per_pixel = video_get_params (res_mode, penv);

}

/* calculate hsynch and vsynch freq (info only) */

t1 = (res_mode->left_margin + res_mode->xres +

res_mode->right_margin + res_mode->hsync_len) / 8;

t1 *= 8;

t1 *= res_mode->pixclock;

t1 /= 1000;

hsynch = 1000000000L / t1;

t1 *=

(res_mode->upper_margin + res_mode->yres +

res_mode->lower_margin + res_mode->vsync_len);

t1 /= 1000;

vsynch = 1000000000L / t1;

/* fill in Graphic device struct */

sprintf (pGD->modeIdent, "%dx%dx%d %ldkHz %ldHz", res_mode->xres,

res_mode->yres, bits_per_pixel, (hsynch / 1000),

(vsynch / 1000));

printf ("%s\n", pGD->modeIdent);

pGD->winSizeX = res_mode->xres;

pGD->winSizeY = res_mode->yres;

pGD->plnSizeX = res_mode->xres;

pGD->plnSizeY = res_mode->yres;

switch (bits_per_pixel) {

case 8:

pGD->gdfBytesPP = 1;

pGD->gdfIndex = GDF__8BIT_INDEX;

break;

case 15:

pGD->gdfBytesPP = 2;

pGD->gdfIndex = GDF_15BIT_555RGB;

break;

case 16:

pGD->gdfBytesPP = 2;

pGD->gdfIndex = GDF_16BIT_565RGB;

break;

case 24:

pGD->gdfBytesPP = 3;

pGD->gdfIndex = GDF_24BIT_888RGB;

break;

}

/* statically configure settings */

pGD->winSizeX = pGD->plnSizeX = 320;

pGD->winSizeY = pGD->plnSizeY = 240;

pGD->gdfBytesPP = 2;

pGD->gdfIndex = GDF_16BIT_565RGB;

pGD->frameAdrs = LCD_VIDEO_ADDR;

pGD->memSize = VIDEO_MEM_SIZE;

board_video_init(pGD);

lcd->LCDSADDR1 = pGD->frameAdrs >> 1;

/* This marks the end of the frame buffer. */

lcd->LCDSADDR2 = (lcd->LCDSADDR1&0x1fffff) + (pGD->winSizeX+0) * pGD->winSizeY;

lcd->LCDSADDR3 = (pGD->winSizeX & 0x7ff);

/* Clear video memory */

memset((void *)pGD->frameAdrs, 0, pGD->memSize);

/* Enable Display */

lcd->LCDCON1 |= 0x01; /* ENVID = 1 */

return ((void*)&smi);

}

void

video_set_lut (unsigned int index, /* color number */

unsigned char r, /* red */

unsigned char g, /* green */

unsigned char b /* blue */

)

{

}

#endif /* CONFIG_VIDEO_S3C2410 */

在你的配置头文件中添加如下宏定义:

view plaincopy to clipboardprint?

#define CONFIG_CMD_BMP

#define CONFIG_VIDEO

#define CONFIG_VIDEO_S3C2410

#define CONFIG_VIDEO_LOGO

#define VIDEO_FB_16BPP_PIXEL_SWAP

#define CONFIG_VIDEO_SW_CURSOR

#define CONFIG_VIDEO_BMP_LOGO

这样就基本完成了,重新启动一下是不是就显示出samsung的logo了。如果先改成自己喜欢的图片,修改tools/logos/denx.bmp,记住一定是是8bpp的bmp图,修改Makefile文件,修改/tools目录下的Makefile文件,大约是44~46行,

view plaincopy to clipboardprint?

ifeq ($(LOGO_BMP),)

LOGO_BMP= logos/denx.bmp

endif

把 denx.bmp 替换为你需要显示的logo图片的文件名,保存退出,重新编译uboot。图片的转化方法,在终端输入命令:

jpegtopnm $1 | ppmquant 31 | ppmtobmp -bpp 8 > $2

使用方法: (脚本名) ( 待处理的JPG图片名) (输出文件名)

这样就可以显示出你自己喜欢的logo图片了。

如果想将串口的打印信息显示在lcd上,添加环境变量。

view plaincopy to clipboardprint?

#define CONFIG_EXTRA_ENV_SETTINGS \

"stdin=serial\0" \

"stdout=vga" \

"stderr=serial\0" \

只要让stdout等于vga就可以了。在lib_arm/board.c文件中可以看到console_init初始化两次,我们修改的影响第二次的初始化,第一次的不影响,所以还会有部分输出信息显示在串口上的。Lcd就到这里,有什么问题我再及时改正吧。

Linux
2.6.30.4移植TE2440II开发板

宿主机:ubuntu9.10

目标机:s3c2440

交叉编译器:arm-linux-gcc-4.3.2

交叉编译器路径:/usr/local/arm/4.3.2

要移植的内核版本:linux-2.6.30.4

文件系统类型: yaffs2

步骤包括:

1)给linux内核打上yaffs2补丁

2)修改机器码

3)修改目标板的arch和编译器路径,

4)增加devfs文件管理器支持

5)修改晶振频率

6)修改MTD分区

7)关闭ECC校验

8)修改nandflash驱动

9)配置内核

首先,从官网上下载linux-2.6.30.4的内核。

ftp://ftp.kernel.org/pub/linux/kernel/v2.6/可以找到。

新建目录mkdir /home/haker,将内核源码包解压到hacker/目录下

tar –zxvf linux-2.6.30.4.tar.gz

1)给内核打jaffs2补丁

下载最新的驱动http://www.aleph1.co.uk/cgi-bin/ ...
fs2.tar.gz?view=tar

解压到/home/hacker/下

tar –zxvf yaffs2.tar.gz

进入目录

cd yaffs2

给内核打补丁

./patch-ker.sh c /home/hacker/linux-2.6.30.4

加上c 他会自动解压到后面的目录中

成功后会打印信息:

Updating /home/hacker/linux-2.6.30.4/fs/Kconfig

Updating /home/hacker/linux-2.6.30.4/fs/Makefile

2)修改机器码

暂时我使用的是飞凌的boot,自己的boot还没有完全做好,飞凌boot的默认机器码是193,修改arch/arm/tools/mach-types,将

s3c2410 ARCH_S3C2410 S3C2410 193 删掉

然后将

s3c2440 ARCH_S3C2440 S3C2440 362

修改为

s3c2440 ARCH_S3C2440 S3C2440 193

3)修改目标板的arch和编译器路径

修改linux/2.6.30.4下的Makefile将

ARCH ?= $(SUBARCH)

CROSS_COMPILE ?=

修改成

ARCH ?= arm

CROSS_COMPILE ?= /usr/local/arm/4.3.2/bin/arm-linux-

4)增加devfs文件管理器支持

修改fs/Kconfig,找到

menu “Pseudo filesystems”

添加

config DEVFS_FS

bool “/dev file system support (OBSOLETE)”

default y

config DEVFS_MOUNT

bool “Automatially mount at bool”

default

depends on DEVFS_FS

5)修改晶振频率

arch/arm/mach-s3c2440/mach-smdk2440.c

/*s3c24xx_init_clocks(16934400);*/ s3c24xx_init_clocks(12000000);

6)修改MTD分区,由于自己的uboot还没有完全做好,暂时用飞凌的boot的分区,

修改文件arch/arm/plat-s3c24xx/common-smdk.c

static struct mtd_partition smdk_default_nand_part[] = {

[0] = {

.name = "Boot",

.size = 0x00100000,

.offset = 0

},

[1] = {

.name = "MyApp",

.size = 0x003c0000,

.offset = 0x00140000,

},

[2] = {

.name = "Kernel",

.size = 0x00300000,

.offset = 0x00500000,

},

[3] = {

.name = "fs_yaffs",

.size = 0x03c00000, //60M

.offset = 0x00800000,

},

[4] = {

.name = "WINCE",

.size = 0x03c00000,

.offset = 0x04400000,

}

};

7)关闭ECC校验

文件drivers/mtd/nand/s3c2410.c

函数:s3c2410_nand_init_chip

/*chip->ecc.mode = NAND_ECC_SOFT; */ chip->ecc.mode = NAND_ECC_NONE;

这个有两个 软件校验和硬件校验都要关掉

8)修改nandflash驱动,修改drivers/mtd/nand下面的nand_bbt.c文件:

static struct nand_bbt_descr largepage_memorybased = {

.options = 0,

.offs = 0,

.len = 1, // 原数值为2,支持2K每页的flash修改为1。K9F1G08,K9F2G08是2k每页的flash

.pattern = scan_ff_pattern

};

static struct nand_bbt_descr largepage_flashbased = {

.options = NAND_BBT_SCAN2NDPAGE,

.offs = 0,

.len = 1, //原数值为2,支持2K每页的flash修改为1。K9F1G08,K9F2G08是2k每页的flash

.pattern = scan_ff_pattern

};

9)配置内核

make menuconfig

首先加载s3c24xx系列的通用配置,然后在此基础上修改

配置完后将配置文件保存为.config,这样方便下次make menuconfig时默认加载上次配置过的文件

交叉编译内核

make zImage

如果没有任何错误,编译出来的内核在arch/arm/boot/目录下,文件zImage即是。

基于busybox1.15.0的yaffs2文件系统移植TE2440II开发板

首先说一下各个知识点:

使用的busybox是1.15.0。什么是busybox呢,busybox是很多标准linux一个单个可执行实现,很多标准linux工具都可以共享很多共同的元素。例如,很多基于文件的元素(比如grep和find)都需要在文件中搜索文件的代码。当这些工具被合并到一个可执行程序中时,他们就可以共享这些相同的元素,这样可以产生更小的可执行程序。实际上,busybox可以将大约3.5M的工具包装成大约200KB大小。这就为引导盘和嵌入式linux设备提供了更多的工具。我们可以对2.4或2.6版本的linux内核使用这个工具。

几个常用的make选项:

make clean 清除源代码树

make distclean 彻底清除源代码树

make menuconfig N-curses(基于菜单的)配置工具

make defconfig 启用默认的(通用)配置

make config 基于菜单的配置工具

uClibc与glibc。CC的标准就是glibc这个库,里边有GCC各种标准函数的实现,使用uClibc,这是一个对大小进行优化过的C库,它为嵌入式系统开发。

根文件系统前面加一个“根”字,说明它是加载其他文件系统的根,既然是根,那么如果没有这个根,其他文件系统就没法加载。他包括系统引导和其他文件系统挂载所必须的文件,根文件系统包括Linux启动所必须的目录和关键性的文件,例如Linux启动时都需要有init目录下的相关文件,在Linux挂载分区时Linux一定会找到/etc/fstab这个挂载文件等,根文件系统还包括了应用程序bin目录等。

1)Jffs2

JFFS嵌入式系统文件系统最早是由瑞典 Axis Communications公司基于Linux2.0的内核为嵌入式系统开发的文件系统。JFFS2是RedHat公司基于JFFS开发的闪存文件系统,最初是针对RedHat公司的嵌入式产品eCos开发的嵌入式文件系统,所以JFFS也可以用于Linux,uCLinux中。

Jffs2:日志闪存嵌入式系统文件系统版本2(Journalling Flash FileSystem v2)主要用于NOR型闪存,基于MTD驱动层,特点是,可读写的,支持数据压缩的,基于哈希表的日志型文件系统,并提供了崩溃/掉电安全保护,提供“写平衡”支持等。缺点主要是当文件系统已经满或接近满时,因为垃圾收集的关系而使jffs2的运行速度大大放慢。

2)Yaffs Yet Another Flash File System

Yaffs/yaffs2是专门为嵌入式系统使用NAND型闪存而设计的一种日志型文件系统。与jffs2相比,它减少一些功能(例如不支持数据压缩),所以速度更快,挂载时间更短,对内存的占用较小。另外他是跨平台的文件系统,除了Linux和eCos,还支持WinCE,pSOS和ThreadX等。

Yaffs/yaffs自带NAND芯片驱动,并且为嵌入式提供了直接访问文件系统的API,用于可以不使用Linux中的MTD与VFS,直接对文件系统操作。

3)Cramfs

Cramfs是Linux的创始人Linux Torvalds参与开发的一种只读的压缩文件系统。他也基于MTD驱动程序。在cramfs文件系统中,每一页(4KB)被压缩,可以随机页访问,其压缩比高达2:1,为嵌入式系统节省了大量的Flash存储空间,使系统可通过更低容量的FLASH存储相同的文件,从而降低系统成本。Cramfs文件系统以压缩方式存储,在运行时解压缩。

4)NFS

NFS是由Sun开发并发展起来的一项不同机器,不同操作系统之间通过网络共享文件的技术

然后开始操作:

一.

给内核打上补丁,使内核对yaffs2文件系统支持。

下载最新的驱动http://www.aleph1.co.uk/cgi-bin/ ...
fs2.tar.gz?view=tar

解压:

tar zxvf yaffs2.tar.gz

cd yaffs2

./patch-ker.sh c /home/hacker/linux-2.6.30.4

成功后打印信息:

1. Updating /file/fl/linux-2.6.33/fs/Kconfig

2. Updating /file/fl/linux-2.6.33/fs/Makefile

进入linux-2.6.30.4目录,把s3c2410的默认配置写入config文件。

1. make s3c2410_defconfig

配置文件系统选项

配置yaffs2文件系统

修改配置如下:

1. File systems --->

2.

Miscellaneous filesystems --->

3. <*> YAFFS2 file system support

4. -*- 512 byte / page devices

5. -*- 2048 byte (or larger) / page devices

6.

Autoselect yaffs2 format

7.

Cache short names in RAM

二:

编译busybox生成文件系统所需要的应用程序

1.解压busybox源码,修改Makefile使之编译成ARM平台:

#tar -jxvf busybox-1.15.0.tar.tar

#cd busybox-1.15.0

#gedit Makefile

修改CROSS_COMPILE ?= arm-linux- ARCH = arm

2.配置busybox,下面是一个人配置的busybox 1.13.0,借来参考,基本差不多。

make menuconfig

Busybox Settings --->

General Configuration --->

Buffer allocation policy (Allocate with Malloc) --->

Show verbose applet usage messages

Store applet usage messages in compressed form

Support --install [-s] to install applet links at runtime

Enable locale support (system needs locale for this to work)

Support for --long-options

Use the devpts filesystem for Unix98 PTYs

Support writing pidfiles

Runtime SUID/SGID configuration via /etc/busybox.conf

Suppress warning message if /etc/busybox.conf is not readable

(/proc/self/exe) Path to BusyBox executable

Build Options --->

Build BusyBox as a static binary (no shared libs)

Build with Large File Support (for accessing files > 2 GB)

Installation Options --->

[ ] Don't use /usr

Applets links (as soft-links) --->

(./_install) BusyBox installation prefix

Busybox Library Tuning --->

(6) Minimum password length

(2) MD5: Trade Bytes for Speed

Faster /proc scanning code (+100 bytes)

Command line editing

(1024) Maximum length of input

vi-style line editing commands

(15) History size

History saving

Tab completion

Fancy shell prompts

(4) Copy buffer size, in kilobytes

Use ioctl names rather than hex values in error messages

Support infiniband HW

Linux Module Utilities --->

(/lib/modules) Default directory containing modules

(modules.dep) Default name of modules.dep

insmod

rmmod

lsmod

modprobe

--- Options common to multiple modutils

[ ] Support version 2.2/2.4 Linux kernels

Support tainted module checking with new kernels

Support for module.aliases file

Support for module.symbols fileLinux System Utilities --->

3.编译和安装busybox:

make;make install

安装好后会在busybox-1.15.0/_install/目录下生成:bin,linuxrc,sbin,usr。

4.开始构建文件系统

1)创建一个root_2.6.30.4目录,把busybox-1.15.0/_install/目录下的复制过来,并在该目录下创建文件系统所需要的其他目录。

#mkdir root-2.6.30.4

#cp -rf busybox-1.15.0/_install/* root-2.6.30.4/

#cd root-2.6.30.4/

#mkdir dev etc home lib mnt opt proc tmp var

2)添加必须的文件,文件和文件夹都用chmod 777 xxx,修改权限

"dev"目录,创建两个设备文件:

#mknod console c 5 1

#mknod null c 1 3

etc"目录,创建各种配置文件并向里面添加内容,没有列出的就不用添加:

group: 系统用户组配置文件,内容如下:

root:*:0:

daemon:*:1:

bin:*:2:

sys:*:3:

adm:*:4:

tty:*:5:

disk:*:6:

lp:*:7:lp

mail:*:8:

news:*:9:

uucp:*:10:

proxy:*:13:

kmem:*:15:

dialout:*:20:

fax:*:21:

voice:*:22:

cdrom:*:24:

floppy:*:25:

tape:*:26:

sudo:*:27:

audio:*:29:

ppp:x:99:

500:x:500:plg

501:x:501:fa

inittab: 系统init进程配置文件,内容如下:

# /etc/inittab

::sysinit:/etc/init.d/rcS

console::askfirst:-/bin/sh

::ctrlaltdel:/sbin/reboot

::shutdown:/bin/umount -a –r

passwd: 系统密码文件,内容如下:

root::0:0:root:/:/bin/sh

ftp::14:50:FTP User:/var/ftp:

bin:*:1:1:bin:/bin:

daemon:*:2:2:daemon:/sbin:

nobody:*:99:99:Nobody:/:

hacker::502:502:Linux User,,,:/home/hacker:/bin/sh

sysconfig/HOSTNAME: 主机名称文件,内容如下:

TE2440II

注意HOSTNAME是文件名,TE2440II是文件中的内容。

fstab: 系统挂载文件系统列表,内容如下:

# device mount-point type options dump fsck order

none /proc proc defaults 0 0

none /dev/pts devpts mode=0622 0 0

tmpfs /dev/shm tmpfs defaults 0 0

init.d/rcS: 系统启动加载项,内容如下:

#!/bin/sh

PATH=/sbin:/bin:/usr/sbin:/usr/bin

runlevel=S

prevlevel=N

umask 022

export PATH runlevel prevlevel

#

# Trap CTRL-C &c only in this shell so we can interrupt subprocesses.

#

/bin/mount -t proc none /proc

/bin/mount -t tmpfs none /tmp

/bin/mount -t tmpfs none /var

/bin/mkdir -p /var/log

/bin/hostname -F /etc/sysconfig/HOSTNAME

profile: 用户环境配置文件,内容如下:

# Ash profile

# vim: syntax=sh

# No core files by default

#ulimit -S -c 0 > /dev/null 2>&1

USER="`id -un`"

LOGNAME=$USER

PS1='[\u@\h \W]\# '

PATH=$PATH:/usr/local/bin

LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib

HOSTNAME=`/bin/hostname`

export USER LOGNAME PS1 PATH LD_LIBRARY_PATH

resolv.conf: DNS配置文件,内容如下:

nameserver 61.144.56.100

"home"目录:创建一个hacker目录,与etc目录passwd文件中的hacker相对应

"lib"目录:这个里面放的都是库文件,直接从交叉编译器的库文件目录中拷贝过来:

#cp -f /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/armv4t/lib/*so* lib/ -a

6. 使用yaffs制作工具编译构建好的文件系统。使用mkyaffs2image,复制到/usr/sbin/目录下,给予777权限。

然后mkyaffs2image root-2.6.30.4 root-2.6.30.4.bin

注意一个路径是这样的 /etc/init.d/rcS, rcS是文件

Kernel panic - not syncing: Attempted to kill init!

上网搜索了一些相关信息,找到了解决问题的途径。 原因在于:编译内核和busybox使用的编译器是arm-linux-gcc 4.3.2,而这个编译器默认是打开“EABI选项”的,这样编译出来的busybox就是EABI的。但是内核编译的时候,默认是把“EABI选项”关掉的。所以busybox和内核无法正常配合。把“EABI选项”打开,重新编译内核后,一切正常。

Kernel Features --->

Use the ARM EABI to compile the kernel

Allow old ABI binaries to run with this kernel (EXPERIMENTAL) (NEW)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐