... ...
【2】在上面添加的代码中有一个跳转:bl nand_read_ll ,它跳入是新增的C 语言文件board/samsung/mini2440/nand_read.c中的函数,这个文件原本是用vivi 的代码,后来经过openmoko 的修改,并支持不同的Nand Flash 芯片,我又这里多加了几个个芯片ID以支持所有mini2440 的Nand Flash。代码如下:
/* #include static inline void nand_wait(void) while (!(NFSTAT & NFSTAT_BUSY)) struct boot_nand_t { #if 0 /* compile time failure in case of an invalid configuration */ static int is_bad_block(struct boot_nand_t * nand, unsigned long i) nand_clear_RnB(); return 0; static int nand_read_page_ll(struct boot_nand_t * nand, unsigned char *buf, unsigned long addr) nand_clear_RnB(); NFCMD = NAND_CMD_READ0; if (nand->page_size == 512) { #if defined(CONFIG_S3C2410) return nand->page_size; static unsigned short nand_read_id(void) extern unsigned int dynpart_size[]; /* low level nand read function */ /* chip Enable */ if (nand_id == 0xec76 /* Samsung K91208 */ for (i=start_addr; i < (start_addr + size);) { if (is_bad_block(&nand, i) || /* chip Disable */ return 0; 然后保存为nand_read.c,还要记得路径是在board/samsung/mini2440/目录下。 注意:上面这段代码中对Nand进行寻址的部分,这跟具体的Nand Flash的寻址方式有关。根据我们开发板上的Nand Flash(K9F1G08U0C)数据手册得知,片内寻址是采用27位地址形式。从第0位开始分四次通过I/O0-I/O7进行传送,并进行片内寻址。具体含义和结构图如下(相关概念参考Nand数据手册): 0-11位:Y-Buffers偏移地址 12-27位:X-Buffers偏移地址 【3】在board/samsung/mini2440/Makefile中添加nand_read.c的编译选项,使他编译到u-boot中,修改后代码如下: #define CONFIG_S3C2410_NAND_SKIP_BAD 1 3.3,重新编译 从上面的运行结果看,显然现在的Nand还不能做任何事情,而且也没有显示有关Nand的任何信息,所以只能说明上面的这些步骤只是��成了Nand移植的Stage1部分。下面我们来添加我们开发板上的Nand Flash(K9F1G08U0B)的Stage2部分的有关操作支持。 【1】Nand Flash 相关代码的修改
* nand_read.c: Simple NAND read functions for booting from NAND
*
* This is used by cpu/arm920/start.S assembler code,
* and the board-specific linker script must make sure this
* file is linked within the first 4kB of NAND flash.
*
* Taken from GPLv2 licensed vivi bootloader,
* Copyright (C) 2002 MIZI Research, Inc.
*
* Author: Hwang, Chideok
* Date : $Date: 2004/02/04 10:37:37 $
*
* u-boot integration and bad-block skipping (C) 2006 by OpenMoko, Inc.
* Author: Harald Welte
*/
#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 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
{
int i;
for (i=0; i<10; i++);
}
int page_size;
int block_size;
int bad_block_offset;
// unsigned long size;
};
#if defined(CONFIG_S3C2410) || defined(CONFIG_MINI2440)
/* configuration for 2410 with 512byte sized flash */
#define NAND_PAGE_SIZE 512
#define BAD_BLOCK_OFFSET 5
#define NAND_BLOCK_MASK (NAND_PAGE_SIZE - 1)
#define NAND_BLOCK_SIZE 0x4000
#else
/* 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)
#endif
#if defined(CONFIG_S3C2410) && (NAND_PAGE_SIZE != 512)
#error 'S3C2410 does not support nand page size != 512'
#endif
#endif
{
unsigned char data;
unsigned long page_num;
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;
}
{
unsigned short *ptr16 = (unsigned short *)buf;
unsigned int i, page_num;
/* 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();
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
}
{
unsigned short res = 0;
NFCMD = NAND_CMD_READID;
NFADDR = 0;
res = NFDATA;
res = (res << 8) | NFDATA;
return res;
}
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;
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;
}
||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 */
#ifdef CONFIG_S3C2410_NAND_SKIP_BAD
//if (i & (nand.block_size-1)== 0) {//warning: suggest parentheses around comparison in operand of '&'
if ((i & (nand.block_size-1))== 0) {
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;
}
nand_deselect();
}
include $(TOPDIR)/config.mk
LIB = $(obj)lib$(BOARD).a
COBJS := nand_read.o mini2440.o flash.o
SOBJS := lowlevel_init.o
【4】在mini2440.h头文件中加入Nand要用到的宏和寄存器的定义。
用gedit打开include/configs/mini2440.h头文件,定位到文件末尾处加入下列代码:
/*-----------------------------------------------------------------------
* NAND flash settings
*/
【5】在cpu/arm920t/u-boot.lds中添加下面两行代码,主要目的是防止编译器把我们自己添加的用于nandboot的子函数放到4K之后,否则是无法启动的,修改后代码如下:
.text :
{
cpu/arm920t/start.o (.text)
board/samsung/mini2440/lowlevel_init.o (.text)
board/samsung/mini2440/nand_read.o (.text)
*(.text)
}
编译成功后生成u-boot.bin文件。下载时先将mini2440开发板调到Nor启动档,利用supervivi的a命令将u-boot.bin下载到开发板的Nand Flash中,再把开发板调到Nand启动档,打开电源就从Nand Flash启动了,启动结果如下:
... ...
Enter your selection: ?
U-Boot 2009.08 ( 5鏈?06 2011 - 14:17:44)
DRAM: 64 MB
Flash: 2 MB
*** Warning - bad CRC, using default environment
In: serial
Out: serial
Err: serial
[u-boot@MINI2440]#nand info
Unknown command nand' - try 'help'
[u-boot@MINI2440]#
3.4,在U-boot 启动的第一阶段,初始化了Nand Flash 控制器。但到第二阶段start_armboot函数还是会再次初始化Nand Flash 控制器。因为第二阶段和第一阶段的代码基本是独立的,第一阶段的代码基本只起到代码重定位的作用,到了第二阶段才是真正U-boot 的开始,以前的初始化过程还会重做一遍,比如始化Nand Flash 控制器、CPU 频率等。因为 S3C2440 和S3C2410 之间的很大差别就是:S3C2410 的Nand Flash 控制器只支持512B+16B 的Nand Flash,而S3C2440 还支持2KB+64B 的大容量Nand Flash。所以在Nand Flash 控制器上寄存器和控制流程上的差别很明显,底层驱动代码的修改也是必须的。具体的差别还是需要对比芯片数据手册的,下面我们结合代码来分析一下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函数等。
打开/drivers/mtd/nand/s3c2410_nand.c,定位到37行,修改如下:
#define __REGb(x) (*(volatile unsigned char *)(x))
#define __REGi(x) (*(volatile unsigned int *)(x))
#define NF_BASE 0x4e000000
#if defined(CONFIG_S3C2410)
#define NFCONF __REGi(NF_BASE + 0x0)
#define NFCMD __REGb(NF_BASE + 0x4)
... ...
#define S3C2410_ADDR_NALE 4
#define S3C2410_ADDR_NCLE 8
#endif
#if defined(CONFIG_S3C2440)
#define S3C2410_ADDR_NALE 0x08
#define S3C2410_ADDR_NCLE 0x0c
#define NFCONF __REGi(NF_BASE + 0x0)
#define NFCONT __REGb(NF_BASE + 0x4)
#define NFCMD __REGb(NF_BASE + 0x8)
#define NFADDR __REGb(NF_BASE + 0xc)
#define NFDATA __REGb(NF_BASE + 0x10)
#define NFMECCD0 __REGb(NF_BASE + 0x14)
#define NFMECCD1 __REGb(NF_BASE + 0x18)
#define NFSECCD __REGb(NF_BASE + 0x1c)
#define NFSTAT __REGb(NF_BASE + 0x20)
#define NFESTAT0 __REGb(NF_BASE + 0x24)
#define NFESTAT1 __REGb(NF_BASE + 0x28)
#define NFMECC0 __REGb(NF_BASE + 0x2c)
#define NFMECC1 __REGb(NF_BASE + 0x30)
#define NFSECC __REGb(NF_BASE + 0x34)
#define NFSBLK __REGb(NF_BASE + 0x38)
#define NFEBLK __REGb(NF_BASE + 0x3c)
#define NFECC0 __REGb(NF_BASE + 0x2c)
#define NFECC1 __REGb(NF_BASE + 0x2d)
#define NFECC2 __REGb(NF_BASE + 0x2e)
#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)
#endif
ulong IO_ADDR_W = NF_BASE;
static void s3c2410_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
//struct nand_chip *chip = mtd->priv;
DEBUGN('hwcontrol(): 0x%02x 0x%02xn', cmd, ctrl);
if (ctrl & NAND_CTRL_CHANGE) {
//ulong IO_ADDR_W = NF_BASE;//应注释掉这个局部变量否则找不到ID 'No NAND device found!!!'
IO_ADDR_W = NF_BASE;
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)
if (ctrl & NAND_NCE)
NFCONF &= ~S3C2410_NFCONF_nFCE;
else
NFCONF |= S3C2410_NFCONF_nFCE;
#endif
#if defined(CONFIG_S3C2440)
if (ctrl & NAND_NCE)
NFCONT &= ~S3C2410_NFCONT_nFCE;
else
NFCONT |= S3C2410_NFCONT_nFCE;
#endif
}
if (cmd != NAND_CMD_NONE)
//writeb(cmd, chip->IO_ADDR_W);
writeb(cmd, (void *)IO_ADDR_W);
}
... ...
#ifdef CONFIG_S3C2410_NAND_HWECC
void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)
{
DEBUGN('s3c2410_nand_enable_hwecc(%p, %d)n', mtd, mode);
#if defined(CONFIG_S3C2410)
NFCONF |= S3C2410_NFCONF_INITECC;
#endif
#if defined(CONFIG_S3C2440)
NFCONT |= S3C2410_NFCONT_INITECC;
#endif
}
... ...
#endif
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);
/* initialize hardware */
#if defined(CONFIG_S3C2410)
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);
NFCONF = cfg;
/* initialize nand_chip data structure */
nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)0x4e00000c;
#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);
NFCONF = cfg;
NFCONT = (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(0<<6)|(0<<5)|(1<<4)|(0<<1)|(1<<0);
/* initialize nand_chip data structure */
nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)0x4e000010;
#endif
/* read_buf and write_buf are default */
/* read_byte and write_byte are default */
上一篇:u-boot-2009.08在mini2440上的移植 增加nor flash功能
下一篇:u-boot-2009.08在mini2440上的移植 增加DM9000网卡驱动
推荐阅读最新更新时间:2024-11-13 16:46
设计资源 培训 开发板 精华推荐
- LT6656ACDC-2.5、2.5V 电压基准作为微功率稳压器的典型应用
- FLWMTRRFGW64FS、MC9S08GW64 流量计参考设计
- OP284FSZ-REEL7 具有限流功能的低压差稳压器的典型应用
- 【训练营】涂鸦智能RGB灯+333876C
- ADA4858-3ACPZ-RL钳位放大器典型应用电路
- 基于瑞萨R7FA2E1A72DFL芯片的开发板2.0
- 可爱小夜灯
- 使用 Richtek Technology Corporation 的 RT8560 的参考设计
- LTC2408 的典型应用 - 4 通道/8 通道 24 位功率无延迟 Delta-Sigma ADC
- LT1581 的典型应用 - 10A、极低压差稳压器
- 第三款5nm手机处理器:三星Exynos 1080问市,单核性能提升1.5倍
- 三星Exynos 1080旗舰芯片:5纳米EUV工艺
- 苹果M1芯片MacBook Pro跑分曝光:单核1714,多核6802
- Zepp将在11月18日凌晨发布全新旗舰智能腕表Zepp Z
- Redmi K40系列:小孔径OLED挖孔直屏 支持120Hz刷新率
- 总投资100亿元,成都偏光片“超级工厂”正式开工
- 为企业减负16亿元!宁波颁布降本减负新政策
- 越贵年轻人越爱? iPhone韩国正式发售 5成消费者是20多岁年轻
- 雷军盛赞小米MIX3相机:排名世界第三,将持续改进相机技术
- 火拼小米8与坚果R1,魅族16变相降价100元