start.S 中Nand Boot 需要nand_read_ll 函数, 在board/samsung/mini2440 下新建文件nand_read.c
修改board/samsung/TX2440/Makefile 文件28 行, 将nand_read.c 编译进u-boot :
COBJS := TX2440.o nand_read.o flash.o
在Nand Flash 驱动drivers/mtd/nand 目录下新建s3c2440_nand.c 文件
修改arch/rm/include/asm/arch-s3c24x0/s3c2410.h
第55左右行添加:
- #define S3C24X0_LCD_BASE 0x4D000000
- #define S3C2410_NAND_BASE 0x4E000000
- #define S3C2440_NAND_BASE 0x4E000000 定义nand Flash寄存器基地址
第107行左右添加:
- static inline struct s3c2410_nand *s3c2410_get_base_nand(void)
- {
- return (struct s3c2410_nand *)S3C2410_NAND_BASE;
- }
- static inline struct s3c2410_nand *s3c2440_get_base_nand(void)
- {
- return (struct s3c2410_nand *)S3C2440_NAND_BASE;
- }
修改arch/rm/include/asm/arch-s3c24x0/s3c24x0.h
第162行添加:
- struct s3c2410_nand {
- u32 NFCONF;
- u32 NFCMD;
- u32 NFADDR;
- u32 NFDATA;
- u32 NFSTAT;
- u32 NFECC;
- };
- struct s3c2440_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;
- };
修改drivers/mtd/nand/Makefile
第35行添加
- COBJS-y += nand_ids.o
- COBJS-y += nand_util.o
- COBJS-y += s3c2440_nand.o
第49行修改为:
- COBJS-$(CONFIG_NAND_NDFC) += ndfc.o
- COBJS-$(CONFIG_NAND_NOMADIK) += nomadik.o
- COBJS-$(CONFIG_NAND_S3C2410) += s3c2440_nand.o
修改/include/configs/mini2440.h
添加代码如下
- #define CONFIG_CMD_NAND
- /* NAND flash settings */
- #if defined(CONFIG_CMD_NAND)
- #define CONFIG_SYS_NAND_BASE 0x4E000000 //Nand配置寄存器基地址
- #define CONFIG_SYS_MAX_NAND_DEVICE 1
- #define CONFIG_MTD_NAND_VERIFY_WRITE 1
- #endif
为了能够用saveenv命令时将环境变量保存在Nand Flash中,修改代码为:
- #define CONFIG_SYS_FLASH_ERASE_TOUT (5*CONFIG_SYS_HZ) /* Timeout for Flash Erase */
- #define CONFIG_SYS_FLASH_WRITE_TOUT (5*CONFIG_SYS_HZ) /* Timeout for Flash Write */
- //#define CONFIG_ENV_IS_IN_FLASH 1
- //#define CONFIG_ENV_SIZE 0x10000 /* Total Size of Environment Sector */
- #define CONFIG_ENV_IS_IN_NAND 1
- #define CONFIG_ENV_OFFSET 0x100000 定义偏移量
- #define CONFIG_ENV_SIZE 0x20000 /* Total Size of Environment Sector */ 定义扇区大小
还有一个重要的地方要修改,在arch/arm/cpu/arm920t/u-boot.lds 中,这个u-boot 启动连接脚本文件决定了u-boot运行的入口地址,以及各个段的存储位置,这也是链接定位的作用。添加下面两行代码的主要目的是防止编译器把我们自己添加的用于运行的入口地址,以及各个段的存储位置,这也是链接定位的作用。添加下面两行代码的主要目的是防止编译器把我们自己添加的用于nandboot 的子函数放到4K之后, 否则是无法启动的。如下
- .text :
- {
- arch/arm/cpu/arm920t/start.o (.text)
- board/samsung/mini2440/lowlevel_init.o (.text)
- board/samsung/mini2440/nand_read.o (.text)
- *(.text)
- }
修改board/samsung/TX2440/ lowlevel_init.S :
第54和58行修改如下
- #define B1_BWSCON (DW16)
- #define B2_BWSCON (DW16)
- #define B3_BWSCON (DW16 + WAIT + UBLB)
- #define B4_BWSCON (DW16)
- #define B5_BWSCON (DW8)
- #define B6_BWSCON (DW32)
- #define B7_BWSCON (DW32)
第123和126行修改如下:
- #define REFEN 0x1 /* Refresh enable */
- #define TREFMD 0x0 /* CBR(CAS before RAS)/Auto refresh */
- #define Trp 0x2 /* 4clk */
- #define Trc 0x3 /* 7clk */
- #define Tchr 0x2 /* 3clk */
- #define REFCNT 1012 /* period=15.6us, HCLK=60Mhz, (2048+1-15.6*60) */
再次编译,建议每次编译前都清除一下上次编译留下的中间代码:
#make clean
#make mini2440_config
#make
nand_read.c
- /*
- * 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 <hwang@mizi.com>
- * Date : $Date: 2004/02/04 10:37:37 $
- *
- * u-boot integration and bad-block skipping (C) 2006 by OpenMoko, Inc.
- * Author: Harald Welte <laforge@openmoko.org>
- */
- #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 nand寄存器基地址
- #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) 16位数据
- #define NFSTAT __REGb(NF_BASE + 0x20) 状态
- #define NFSTAT_BUSY 1 nand忙碌标识
- #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) { 适用于512B的小页检测
- NFCMD = NAND_CMD_READOOB; /* 0x50 */ 读OOB命令
- NFADDR = nand->bad_block_offset & 0xf;
- NFADDR = (i >> 9) & 0xff;
- NFADDR = (i >> 17) & 0xff;
- NFADDR = (i >> 25) & 0xff;
- } else if (nand->page_size == 2048) { 适用于2048B的大页检测
- page_num = i >> 11; /* addr / 2048 */
- NFCMD = NAND_CMD_READ0; 读OOB命令
- 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) nand读取函数
- {
- unsigned short *ptr16 = (unsigned short *)buf;
- unsigned int i, page_num;
- nand_clear_RnB(); 清除传输中断位 清除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) { 2K页
- page_num = addr >> 11; /* addr / 2048 */ 取出页地址
- /* Write Address */
- NFADDR = 0; 列地址A0~A7
- NFADDR = 0; 列地址A8~A11
- NFADDR = page_num & 0xff; 行地址A12~A19
- NFADDR = (page_num >> 8) & 0xff; 行地址A20~A27
- NFADDR = (page_num >> 16) & 0xff; 行地址A28
- 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;
- }
s3c2440_nand.c
- /*
- * (C) Copyright 2006 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 0
- #define DEBUGN printf
- #else
- #define DEBUGN(x,args ...){}
- #endif
- #include <nand.h>
- #include <asm/arch/s3c24x0_cpu.h>
- #include <asm/arch/s3c2410.h>
- #include <asm/io.h>
- #define __REGb(x) (*(volatile unsigned char *)(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 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 0x08
- #define S3C2440_ADDR_NCLE 0x0c
- #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
- 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 ", cmd, ctrl);
- if (ctrl & NAND_CTRL_CHANGE) {
- IO_ADDR_W = NF_BASE;
- if (!(ctrl & NAND_CLE))
- IO_ADDR_W |= S3C2440_ADDR_NCLE;
- if (!(ctrl & NAND_ALE))
- IO_ADDR_W |= S3C2440_ADDR_NALE;
- if (ctrl & NAND_NCE)
- NFCONT &= ~ S3C2440_NFCONT_nCE;
- else
- NFCONT |= S3C2440_NFCONT_nCE;
- }
- if (cmd != NAND_CMD_NONE)
- writeb(cmd, (void *)IO_ADDR_W);
- }
- static int s3c2440_dev_ready(struct mtd_info *mtd)
- {
- DEBUGN("dev_ready ");
- return(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) ", mtd, mode);
- writel(readl(&nand->NFCONF) | S3C2410_NFCONF_INITECC, &nand->NFCONF);
- }
- 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 ",
- 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 ");
- 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();
- DEBUGN("board_nand_init() ");
- writel(readl(&clk_power->CLKCON) | (1 << 4), &clk_power->CLKCON);
- /* initialize hardware */
- twrph0 = 4;
- twrph1 =2;
- tacls = 0;
- cfg = ((tacls<<12)|(twrph0<<8)|(twrph1<<4));
- NFCONF=cfg;
- cfg = ((1<<6)|(1<<4)|(0<<1)|(1<<0));
- NFCONT=cfg;
- /* 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;
- nand->ecc.mode = NAND_ECC_SOFT;
- DEBUGN("end of nand_init ");
- return 0;
- }