u-boot移植(七)支持nand启动
来源:互联网 发布:unity3d培训机构那个好 编辑:程序博客网 时间:2024/05/17 21:39
1、 从nand启动
添加nandflash启动,网络上有很多资料介绍自动识别从哪种方式启动,原理主要是nand启动时,内存同时映射到0地址和40000000地址,所以通过改变其中一个,去检测另一个是否改变来确定是nor启动,还是nand启动。此程序较简单,需要注意的是如果nand启动完了一定把改变的值复原。代码如下
ldr r1, =( (4<<28)|(3<<4)|(3<<2) ) /* address of Internal SRAM 0x4000003C*/
mov r0, #0 /* r0 = 0 */
str r0, [r1]
mov r1, #0x3c /* address of 0x0000003C*/
ldr r0, [r1]
cmp r0, #0 /*判断0x0000003C所指向的4个字节是否被清0*/
bne relocate /*没有被清0,就是在Nor Flash中启动,则跳到Nor Flash的重定向代码处relocate*/
/* recovery */
ldr r0, =(0xdeadbeef) /*被清0,就是在Nand Flash中启动*/
ldr r1, =( (4<<28)|(3<<4)|(3<<2) ) /*恢复0x4000003C指向的4字节的数据0xdeadbeef*
str r0, [r1]
从nand启动代码,定义u-boot在Nand flash中存放的长度为#define LENGTH_UBOOT 0x100000,可以方便修改u-boot因为裁剪和增添大小的改变而占的长度。 首先检测代码位置,如果在内存中,就设置堆栈,然后跳到c语言执行,否则就进行初始化nandflash,然后搬运代码
#define LENGTH_UBOOT 0x100000
#define NAND_CTL_BASE 0x4E000000
#ifdef CONFIG_S3C2440
/* Offset */
#define oNFCONF 0x00
#define oNFCONT 0x04
#define oNFCMD 0x08
#define oNFSTAT 0x20
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
mov r1, #0x0
mov r2, #LENGTH_UBOOT
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
添加nand_read_ll函数:
#include <common.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
#define nand_select() (NFCONT &= ~(1 << 1))
#define nand_deselect() (NFCONT |= (1 << 1))
#define nand_clear_RnB() (NFSTAT |= (1 << 2))
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();
for (i = 0; i < (nand->page_size>>1); i++) {
*ptr16 = NFDATA16;
ptr16++;
}
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;
}
添加把环境变量设置在nand中
#if !defined(CONFIG_NAND_BOOT)
{
#define CONFIG_ENV_IS_IN_FLASH 1
#define CONFIG_ENV_SIZE 0x10000 /* Total Size of Environment Sector */
}
#if defined(CONFIG_NAND_BOOT)
{
#define CONFIG_ENV_IS_IN_NAND 1
#define CONFIG_ENV_OFFSET 0x100000
#define CONFIG_ENV_SIZE 0x20000
}
- u-boot移植(七)支持nand启动
- 移植u-boot-2012.04----支持nand启动
- U-boot-2010.09移植(六)NAND Flash启动支持
- u-boot-2011.03在mini2440/micro2440上的移植(七)——支持Nand Flash启动
- TQ2440 u-boot-2012.10移植二支持NAND启动
- TQ2440 u-boot-2012.04.01移植二支持NAND启动
- TQ2440 u-boot-2012.10移植二支持NAND启动
- u-boot-2010.12移植到2440(四,支持nand flash启动)
- 【转】u-boot-2010.12移植到2440(四,支持nand flash启动)
- fl2440的U-boot-2010.09移植(六)NAND Flash启动支持
- [s3c2416x移植u-boot-2015.10] 让u-boot-2015.10支持spl nand的启动
- u-boot移植(四)使支持NAND FLASH
- 【Linux 移植 】——4、移植 u-boot-2012.04.01 之 支持NAND启动
- 06-S3C2440学习之移植2012u-boot到S3C2440(移植过程二)支持NAND启动
- 移植U-Boot S3C2440超值版支持NAND启动,支持YAFFS文件系统
- S5PV210:支持NAND启动u-boot
- 移植u-boot-2011.03到S3C2440(utu2440)的方法与步骤###7.NAND FLASH部分移植和支持NAND FLASH启动和读写
- U-boot移植 (v2012.04.1 S3C2440平台) (二) Nand flash 启动支持
- 如何在ASP.NET消息框中换行
- 用汇编的眼光看C++(开篇)
- deb包管理系统及实例讲解apt使用方法
- 如何将二维数组作为函数的参数传递
- ubuntu中useradd和adduser究竟怎么用—用户管理一
- u-boot移植(七)支持nand启动
- Notification详细用法
- ubuntu中添加了新用户的后续操作—用户管理二
- 搭建嵌入式Linux开发环境二
- Notification简介
- 设计模式之我见
- u-boot移植(八)支持yaffs
- 用汇编的眼光看C++ (之x86汇编)
- 获取jsp checkbox 复选框