准备分析
资源工具
着手写程序
start.S中的代码拷贝很重要,Makefile中的链接地址很重要。
/*
* $Id: nand_cp.c,v 1.1 2008/11/20 01:08:36 boyko Exp $
*
* (C) Copyright 2006 Samsung Electronics
*
* See file CREDITS for list of people who contributed to this
* project.
*
* 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
*/
/*
* You must make sure that all functions in this file are designed
* to load only U-Boot image.
*
* So, DO NOT USE in common read.
*
* By scsuh.
*/
/*
* Standard NAND flash commands
*/
#define NAND_CMD_READ0 0
#define NAND_CMD_READ1 1
#define NAND_CMD_RNDOUT 5
#define NAND_CMD_PAGEPROG 0x10
#define NAND_CMD_READOOB 0x50
#define NAND_CMD_ERASE1 0x60
#define NAND_CMD_STATUS 0x70
#define NAND_CMD_STATUS_MULTI 0x71
#define NAND_CMD_SEQIN 0x80
#define NAND_CMD_RNDIN 0x85
#define NAND_CMD_READID 0x90
#define NAND_CMD_PARAM 0xec
#define NAND_CMD_ERASE2 0xd0
#define NAND_CMD_RESET 0xff
/* Extended commands for large page devices */
#define NAND_CMD_READSTART 0x30
#define NAND_CMD_RNDOUTSTART 0xE0
#define NAND_CMD_CACHEDPROG 0x15
#define NAND_DISABLE_CE() (NFCONT_REG |= (1 << 1))
#define NAND_ENABLE_CE() (NFCONT_REG &= ~(1 << 1))
#define NF_TRANSRnB() do { while(!(NFSTAT_REG & (1 << 0))); } while(0)
//#include <asm/io.h>
//#include <linux/mtd/nand.h>
#include "s5pc110.h"
#define COPY_BL2_SIZE 0x80000
#define NAND_CONTROL_ENABLE() (NFCONT_REG |= (1 << 0))
/*
* address format
* 17 16 9 8 0
* --------------------------------------------
* | block(12bit) | page(5bit) | offset(9bit) |
* --------------------------------------------
*/
static int nandll_read_page (uchar *buf, ulong addr, int large_block)
{
int i;
int page_size = 512;
if (1 == large_block)
page_size = 2048;
else if (2 == large_block)
page_size = 8192;
NAND_ENABLE_CE();
NFCMD_REG = NAND_CMD_READ0;
/* Write Address */
NFADDR_REG = 0;
if (large_block)
NFADDR_REG = 0;
NFADDR_REG = (addr) & 0xff;
NFADDR_REG = (addr >> 8) & 0xff;
NFADDR_REG = (addr >> 16) & 0xff;
if (large_block)
NFCMD_REG = NAND_CMD_READSTART;
NF_TRANSRnB();
/* for compatibility(2460). u32 cannot be used. by scsuh */
for(i=0; i < page_size; i++) {
*buf++ = NFDATA8_REG;
}
NAND_DISABLE_CE();
return 0;
}
/*
* Read data from NAND.
*/
static int nandll_read_blocks (ulong dst_addr, ulong size, int large_block)
{
uchar *buf = (uchar *)dst_addr;
int i;
uint page_shift = 9;
if (1 == large_block)
{
page_shift = 11;
/* Read pages */
for (i = (0x6000>>page_shift); i < (size>>page_shift); i++, buf+=(1<<page_shift))
{
nandll_read_page(buf, i, large_block);
}
}
else if(2 == large_block)
{
page_shift = 12;
for (i = 0; i < (size>>page_shift); i++, buf+=(1<<(page_shift-1)))
{
nandll_read_page(buf, i, large_block);
}
}
return 0;
}
int copy_uboot_to_ram_nand (void)
{
int large_block = 0;
int i;
vu_char id;
NAND_CONTROL_ENABLE();
NAND_ENABLE_CE();
NFCMD_REG = NAND_CMD_READID;
NFADDR_REG = 0x00;
/* wait for a while */
for (i=0; i<200; i++);
id = NFDATA8_REG;
id = NFDATA8_REG;
if (id > 0x80)
large_block = 1;
if(id == 0xd5)
{
large_block = 2;
}
/* read NAND Block.
* 128KB ->240KB because of U-Boot size increase. by scsuh
* So, read 0x3c000 bytes not 0x20000(128KB).
*/
//return nandll_read_blocks(CONFIG_SYS_TEXT_BASE, COPY_BL2_SIZE, large_block);
return nandll_read_blocks(0xd0024000, 0x4000, large_block);
}
void board_init_f_nand(unsigned long bootflag)
{
__attribute__((noreturn)) void (*uboot)(void);
copy_uboot_to_ram_nand();
/* Jump to U-Boot image */
uboot = (void *)0xd024010;
(*uboot)();
/* Never returns Here */
}
@******************************************************************************
@ File:start.S
@ 功能:启动代码,设置栈,拷贝16k到0xd0020000处
@******************************************************************************
.text
.global _start
_start:
ldr sp, =0xD0037D80 @ 设置栈,以便调用c函数
adr r0, _start @ 重定位
@ _start当前所位于的地址:0xd0020010 (前边放有16bit的头信息)
ldr r1, =_start @ _start的链接地址:0xd0024010
ldr r2, =0xd0028000 @ 0xd0028000 = 0xd0024000 + 0x4000(16k)
cmp r0, r1
beq run_on_dram
bl nand_asm_init
bl copy_uboot_to_ram_nand
run_on_dram:
ldr pc, =main @ 跳转
halt:
b halt
led_debug:
ldr R0,=0xE0200280 @ R0设为GPJ2CON寄存器。此寄存器
@ 用于选择端口J各引脚的功能:
@ 是输出、是输入、还是其他
mov R1,#0x00000001
str R1,[R0] @ 设置GPJ2_0为输出口, 位[10:9]=0b01
ldr R0,=0xE0200284 @ R0设为GPJ2DAT寄存器。此寄存器
@ 用于读/写端口GPJ2各引脚的数据
mov R1,#0x00000000 @ 此值改为0x00000001,
@ 可让LED1熄灭
str R1,[R0] @ GPJ2_0输出0,LED1点亮
mov pc, lr
/* Setting GPIO for NAND */
/* This setting is NAND initialze code at booting time in iROM. */
nand_asm_init:
/*
* Nand Interface Init for SMDKC110
*/
#define ELFIN_GPIO_BASE 0xE0200000
#define ELFIN_NAND_BASE 0xB0E00000
#define NFCONF_VAL (7<<12)|(7<<8)|(7<<4)|(0<<3)|(0<<2)|(1<<1)|(0<<0)
#define NFCONT_VAL (0x1<<23)|(0x1<<22)|(0<<18)|(0<<17)|(0<<16)|(0<<10)|(0<<9)|(0<<8)|(0<<7)|(0<<6)|(0x2<<1)|(1<<0)
#define MP01CON_OFFSET 0x2E0
#define MP01PUD_OFFSET 0x2E8
#define MP03CON_OFFSET 0x320
#define MP03PUD_OFFSET 0x328
#define NFCONF_OFFSET 0x00
#define NFCONT_OFFSET 0x04
ldr r0, =ELFIN_GPIO_BASE
ldr r1, [r0, #MP01CON_OFFSET]
bic r1, r1, #(0xf<<8)
orr r1, r1, #(0x3<<8)
str r1, [r0, #MP01CON_OFFSET]
ldr r1, [r0, #MP01PUD_OFFSET]
bic r1, r1, #(0x3<<4)
str r1, [r0, #MP01PUD_OFFSET]
ldr r1, [r0, #MP03CON_OFFSET]
bic r1, r1, #0xFFFFFF
ldr r2, =0x22222222
orr r1, r1, r2
str r1, [r0, #MP03CON_OFFSET]
ldr r1, [r0, #MP03PUD_OFFSET]
ldr r2, =0x3fff
bic r1, r1, r2
str r1, [r0, #MP03PUD_OFFSET]
ldr r0, =ELFIN_NAND_BASE
ldr r1, [r0, #NFCONF_OFFSET]
ldr r2, =0x777F
bic r1, r1, r2
ldr r2, =NFCONF_VAL
orr r1, r1, r2
str r1, [r0, #NFCONF_OFFSET]
ldr r1, [r0, #NFCONT_OFFSET]
ldr r2, =0x707C7
bic r1, r1, r2
ldr r2, =NFCONT_VAL
orr r1, r1, r2
str r1, [r0, #NFCONT_OFFSET]
ldr r1, [r0, #NFCONF_OFFSET]
orr r1, r1, #0x70
orr r1, r1, #0x7700
str r1, [r0, #NFCONF_OFFSET]
ldr r1, [r0, #NFCONT_OFFSET]
orr r1, r1, #0x03
str r1, [r0, #NFCONT_OFFSET]
mov pc, lr
main.c
#define GPJ2CON (*(volatile unsigned long *) 0xE0200280)
#define GPJ2DAT (*(volatile unsigned long *) 0xE0200284)
// 延时函数
void delay(unsigned long count)
{
volatile unsigned long i = count;
while (i--)
;
}
void main() //LED 闪烁
{
GPJ2CON = 0x00001111; // 配置引脚
while(1) // 闪烁
{
GPJ2DAT = 0; // LED on
delay(0x100000);
GPJ2DAT = 0xf; // LED off
delay(0x100000);
}
}
下载运行
同《
S5PV210的LED应用(一)》
运行调试
一开始以为程序会很难,应该MLC的,这样的NandFlash涉及到了ECC校验,颇为麻烦,但是细想,只实现读操作,会少许简单一些。最后发现读的时候问题并不多。也并不是那么困难。nand_asm_init和nand_cp.c提取于u-boot,并加以移植。
遗留问题
1.无