zoukankan      html  css  js  c++  java
  • (四)支持 Nand Flash

    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左右行添加:

    1. #define S3C24X0_LCD_BASE  0x4D000000  
    2. #define S3C2410_NAND_BASE 0x4E000000  
    3. #define S3C2440_NAND_BASE 0x4E000000           定义nand Flash寄存器基地址
    第107行左右添加:
    1. static inline struct s3c2410_nand *s3c2410_get_base_nand(void)  
    2. {  
    3. return (struct s3c2410_nand *)S3C2410_NAND_BASE;  
    4. }  
    5. static inline struct s3c2410_nand *s3c2440_get_base_nand(void)  
    6. {  
    7. return (struct s3c2410_nand *)S3C2440_NAND_BASE;  
    修改arch/rm/include/asm/arch-s3c24x0/s3c24x0.h
    第162行添加:
    1. struct s3c2410_nand {  
    2. u32 NFCONF;  
    3. u32 NFCMD;  
    4. u32 NFADDR;  
    5. u32 NFDATA;  
    6. u32 NFSTAT;  
    7. u32 NFECC;  
    8. };  
    9. struct s3c2440_nand {                     定义用到的变量
    10. u32 NFCONF;  
    11. u32 NFCONT;  
    12. u32 NFCMD;  
    13. u32 NFADDR;  
    14. u32 NFDATA;  
    15. u32 NFMECCD0;  
    16. u32 NFMECCD1;  
    17. u32 NFSECCD;  
    18. u32 NFSTAT;  
    19. u32 NFESTAT0;  
    20. u32 NFESTAT1;  
    21. u32 NFMECC0;  
    22. u32 NFMECC1;  
    23. u32 NFSECC;  
    24. u32 NFSBLK;  
    25. u32 NFEBLK;  
    26. };
    修改drivers/mtd/nand/Makefile
    第35行添加
    1. COBJS-y += nand_ids.o  
    2. COBJS-y += nand_util.o  
    3. COBJS-y += s3c2440_nand.o 

     第49行修改为:

    1. COBJS-$(CONFIG_NAND_NDFC) += ndfc.o  
    2. COBJS-$(CONFIG_NAND_NOMADIK) += nomadik.o  
    3. COBJS-$(CONFIG_NAND_S3C2410) += s3c2440_nand.o
    修改/include/configs/mini2440.h
    添加代码如下
    1. #define CONFIG_CMD_NAND  
    2. /* NAND flash settings */  
    3. #if defined(CONFIG_CMD_NAND)  
    4. #define CONFIG_SYS_NAND_BASE 0x4E000000 //Nand配置寄存器基地址  
    5. #define CONFIG_SYS_MAX_NAND_DEVICE 1  
    6. #define CONFIG_MTD_NAND_VERIFY_WRITE 1  
    7. #endif

     为了能够用saveenv命令时将环境变量保存在Nand Flash中,修改代码为:

    1. #define CONFIG_SYS_FLASH_ERASE_TOUT  (5*CONFIG_SYS_HZ) /* Timeout for Flash Erase */  
    2. #define CONFIG_SYS_FLASH_WRITE_TOUT  (5*CONFIG_SYS_HZ) /* Timeout for Flash Write */  
    3. //#define  CONFIG_ENV_IS_IN_FLASH 1  
    4. //#define CONFIG_ENV_SIZE  0x10000  /* Total Size of Environment Sector */  
    5. #define CONFIG_ENV_IS_IN_NAND 1  
    6. #define CONFIG_ENV_OFFSET 0x100000      定义偏移量
    7. #define CONFIG_ENV_SIZE  0x20000  /* Total Size of Environment Sector */  定义扇区大小
    还有一个重要的地方要修改,在arch/arm/cpu/arm920t/u-boot.lds 中,这个u-boot 启动连接脚本文件决定了u-boot运行的入口地址,以及各个段的存储位置,这也是链接定位的作用。添加下面两行代码的主要目的是防止编译器把我们自己添加的用于运行的入口地址,以及各个段的存储位置,这也是链接定位的作用。添加下面两行代码的主要目的是防止编译器把我们自己添加的用于nandboot 的子函数放到4K之后, 否则是无法启动的。如下
    1. .text :  
    2. {  
    3. arch/arm/cpu/arm920t/start.o (.text)  
    4. board/samsung/mini2440/lowlevel_init.o  (.text)  
    5. board/samsung/mini2440/nand_read.o (.text)  
    6. *(.text)  
    7. }
    修改board/samsung/TX2440/ lowlevel_init.S
    第54和58行修改如下
    1. #define B1_BWSCON  (DW16)  
    2. #define B2_BWSCON  (DW16)  
    3. #define B3_BWSCON  (DW16 + WAIT + UBLB)  
    4. #define B4_BWSCON  (DW16)  
    5. #define B5_BWSCON  (DW8)  
    6. #define B6_BWSCON  (DW32)  
    7. #define B7_BWSCON  (DW32)

     第123和126行修改如下:

    1. #define REFEN 0x1 /* Refresh enable */  
    2. #define TREFMD  0x0 /* CBR(CAS before RAS)/Auto refresh */  
    3. #define Trp 0x2 /* 4clk */  
    4. #define Trc 0x3 /* 7clk */  
    5. #define Tchr 0x2 /* 3clk */  
    6. #define REFCNT  1012 /* period=15.6us, HCLK=60Mhz, (2048+1-15.6*60) */ 

     再次编译,建议每次编译前都清除一下上次编译留下的中间代码:

    #make clean
    #make mini2440_config
    #make

     nand_read.c

    1. /* 
    2. * nand_read.c: Simple NAND read functions for booting from NAND 
    3. * 
    4. * This is used by cpu/arm920/start.S assembler code, 
    5. * and the board-specific linker script must make sure this 
    6. * file is linked within the first 4kB of NAND flash. 
    7. * 
    8. * Taken from GPLv2 licensed vivi bootloader, 
    9. * Copyright (C) 2002 MIZI Research, Inc. 
    10. * 
    11. * Author: Hwang, Chideok <hwang@mizi.com> 
    12. * Date : $Date: 2004/02/04 10:37:37 $ 
    13. * 
    14. * u-boot integration and bad-block skipping (C) 2006 by OpenMoko, Inc. 
    15. * Author: Harald Welte <laforge@openmoko.org> 
    16. */  
    17. #include <common.h>  
    18. #include <linux/mtd/nand.h>  
    19. #define __REGb(x) (*(volatile unsigned char *)(x))    字符型指针中取值
    20. #define __REGw(x) (*(volatile unsigned short *)(x))   短整型指针中取值
    21. #define __REGi(x) (*(volatile unsigned int *)(x))    无符整形指针取值
    22. #define NF_BASE  0x4e000000                     nand寄存器基地址
    23. #define NFCONF  __REGi(NF_BASE + 0x0)           配置
    24. #define NFCONT  __REGi(NF_BASE + 0x4)           控制
    25. #define NFCMD __REGb(NF_BASE + 0x8)             指令
    26. #define NFADDR  __REGb(NF_BASE + 0xc)           地址集
    27. #define NFDATA  __REGb(NF_BASE + 0x10)          数据
    28. #define NFDATA16 __REGw(NF_BASE + 0x10)        16位数据
    29. #define NFSTAT  __REGb(NF_BASE + 0x20)          状态
    30. #define NFSTAT_BUSY 1                        nand忙碌标识
    31. #define nand_select() (NFCONT &= ~(1 << 1))    使能片选
    32. #define nand_deselect() (NFCONT |= (1 << 1))   禁止片选
    33. #define nand_clear_RnB()  (NFSTAT |= (1 << 2))  清除传输中断位
    34. static inline void nand_wait(void)  
    35. {  
    36. int i;  
    37. while (!(NFSTAT & NFSTAT_BUSY))  
    38. for (i=0; i<10; i++);  
    39. }  
    40. struct boot_nand_t {  
    41. int page_size;     页大小
    42. int block_size;    块大小
    43. int bad_block_offset;     坏块偏移
    44. //  unsigned long size;  
    45. };  
    46. static int is_bad_block(struct boot_nand_t * nand, unsigned long i)     坏块检测
    47. {  
    48. unsigned char data;      
    49. unsigned long page_num;  
    50. nand_clear_RnB();       清除传输中断位
    51. if (nand->page_size == 512) {          适用于512B的小页检测
    52. NFCMD = NAND_CMD_READOOB; /* 0x50 */   读OOB命令
    53. NFADDR = nand->bad_block_offset & 0xf;  
    54. NFADDR = (i >> 9) & 0xff;  
    55. NFADDR = (i >> 17) & 0xff;  
    56. NFADDR = (i >> 25) & 0xff;  
    57. else if (nand->page_size == 2048) {  适用于2048B的大页检测
    58. page_num = i >> 11; /* addr / 2048 */  
    59. NFCMD = NAND_CMD_READ0;                 读OOB命令
    60. NFADDR = nand->bad_block_offset & 0xff;  
    61. NFADDR = (nand->bad_block_offset >> 8) & 0xff;  
    62. NFADDR = page_num & 0xff;  
    63. NFADDR = (page_num >> 8) & 0xff;  
    64. NFADDR = (page_num >> 16) & 0xff;  
    65. NFCMD = NAND_CMD_READSTART;  
    66. else {  
    67. return -1;  
    68. }  
    69. nand_wait();  
    70. data = (NFDATA & 0xff);  
    71. if (data != 0xff)  
    72. return 1;  
    73. return 0;  
    74. }  
    75. static int nand_read_page_ll(struct boot_nand_t * nand, unsigned char *buf, unsigned long addr)    nand读取函数
    76. {  
    77. unsigned short *ptr16 = (unsigned short *)buf;  
    78. unsigned int i, page_num;  
    79. nand_clear_RnB();      清除传输中断位  清除RnB信号
    80. NFCMD = NAND_CMD_READ0;      页读命令周期
    81. if (nand->page_size == 512) {  
    82. /* Write Address */  
    83. NFADDR = addr & 0xff;  
    84. NFADDR = (addr >> 9) & 0xff;  
    85. NFADDR = (addr >> 17) & 0xff;  
    86. NFADDR = (addr >> 25) & 0xff;  
    87. else if (nand->page_size == 2048) {     2K页
    88. page_num = addr >> 11; /* addr / 2048 */  取出页地址
    89. /* Write Address */  
    90. NFADDR = 0;                                 列地址A0~A7
    91. NFADDR = 0;               列地址A8~A11
    92. NFADDR = page_num & 0xff;       行地址A12~A19
    93. NFADDR = (page_num >> 8) & 0xff;       行地址A20~A27
    94. NFADDR = (page_num >> 16) & 0xff;           行地址A28
    95. NFCMD = NAND_CMD_READSTART;  
    96. else {  
    97. return -1;  
    98. }  
    99. nand_wait();  
    100. for (i = 0; i < (nand->page_size>>1); i++) {  
    101. *ptr16 = NFDATA16;  
    102. ptr16++;  
    103. }  
    104. return nand->page_size;  
    105. }  
    106. static unsigned short nand_read_id()  
    107. {  
    108. unsigned short res = 0;  
    109. NFCMD = NAND_CMD_READID;  
    110. NFADDR = 0;  
    111. res = NFDATA;  
    112. res = (res << 8) | NFDATA;  
    113. return res;  
    114. }  
    115. extern unsigned int dynpart_size[];  
    116. /* low level nand read function */  
    117. int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)  
    118. {  
    119. int i, j;  
    120. unsigned short nand_id;  
    121. struct boot_nand_t nand;  
    122. /* chip Enable */  
    123. nand_select();  
    124. nand_clear_RnB();  
    125. for (i = 0; i < 10; i++)  
    126. ;  
    127. nand_id = nand_read_id();  
    128. if (0) { /* dirty little hack to detect if nand id is misread */  
    129. unsigned short * nid = (unsigned short *)0x31fffff0;  
    130. *nid = nand_id;  
    131. }   
    132. if (nand_id == 0xec76 || /* Samsung K91208 */  
    133. nand_id == 0xad76 ) { /*Hynix HY27US08121A*/  
    134. nand.page_size = 512;  
    135. nand.block_size = 16 * 1024;  
    136. nand.bad_block_offset = 5;  
    137. //  nand.size = 0x4000000;  
    138. else if (nand_id == 0xecf1 || /* Samsung K9F1G08U0B */  
    139. nand_id == 0xecda || /* Samsung K9F2G08U0B */  
    140. nand_id == 0xecd3 ) { /* Samsung K9K8G08 */  
    141. nand.page_size = 2048;  
    142. nand.block_size = 128 * 1024;  
    143. nand.bad_block_offset = nand.page_size;  
    144. //  nand.size = 0x8000000;  
    145. else {  
    146. return -1; // hang  
    147. }  
    148. if ((start_addr & (nand.block_size-1)) || (size & ((nand.block_size-1))))  
    149. return -1;  /* invalid alignment */  
    150. for (i=start_addr; i < (start_addr + size);) {  
    151. #ifdef CONFIG_S3C2410_NAND_SKIP_BAD  
    152. if (i & (nand.block_size-1)== 0) {  
    153. if (is_bad_block(&nand, i) ||  
    154. is_bad_block(&nand, i + nand.page_size)) {  
    155. /* Bad block */  
    156. i += nand.block_size;  
    157. size += nand.block_size;  
    158. continue;  
    159. }  
    160. }  
    161. #endif  
    162. j = nand_read_page_ll(&nand, buf, i);  
    163. i += j;  
    164. buf += j;  
    165. }  
    166. /* chip Disable */  
    167. nand_deselect();  
    168. return 0;  
    169. }

    s3c2440_nand.c

    1. /* 
    2. * (C) Copyright 2006 OpenMoko, Inc. 
    3. * Author: Harald Welte <laforge@openmoko.org> 
    4. * 
    5. * This program is free software; you can redistribute it and/or 
    6. * modify it under the terms of the GNU General Public License as 
    7. * published by the Free Software Foundation; either version 2 of 
    8. * the License, or (at your option) any later version. 
    9. * 
    10. * This program is distributed in the hope that it will be useful, 
    11. * but WITHOUT ANY WARRANTY; without even the implied warranty of 
    12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
    13. * GNU General Public License for more details. 
    14. * 
    15. * You should have received a copy of the GNU General Public License 
    16. * along with this program; if not, write to the Free Software 
    17. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
    18. * MA 02111-1307 USA 
    19. */  
    20. #include <common.h>  
    21. #if 0  
    22. #define DEBUGN printf  
    23. #else  
    24. #define DEBUGN(x,args ...){}  
    25. #endif  
    26. #include <nand.h>  
    27. #include <asm/arch/s3c24x0_cpu.h>  
    28. #include <asm/arch/s3c2410.h>  
    29. #include <asm/io.h>  
    30. #define __REGb(x) (*(volatile unsigned char *)(x))  
    31. #define __REGi(x) (*(volatile unsigned int *)(x))  
    32. #define NF_BASE 0x4e000000  
    33. #define NFCONF __REGi(NF_BASE + 0x0)  
    34. #define NFCONT __REGi(NF_BASE + 0x4)  
    35. #define NFCMD __REGb(NF_BASE + 0x8)  
    36. #define NFADDR __REGb(NF_BASE + 0xc)  
    37. #define NFDATA __REGb(NF_BASE + 0x10)  
    38. #define NFMECCD0 __REGi(NF_BASE + 0x14)  
    39. #define NFMECCD1 __REGi(NF_BASE + 0x18)  
    40. #define NFSECCD __REGi(NF_BASE + 0x1C)  
    41. #define NFSTAT __REGb(NF_BASE + 0x20)  
    42. #define NFSTAT0 __REGi(NF_BASE + 0x24)  
    43. #define NFSTAT1 __REGi(NF_BASE + 0x28)  
    44. #define NFMECC0 __REGi(NF_BASE + 0x2C)  
    45. #define NFMECC1 __REGi(NF_BASE + 0x30)  
    46. #define NFSECC __REGi(NF_BASE + 0x34)  
    47. #define NFSBLK __REGi(NF_BASE + 0x38)  
    48. #define NFEBLK __REGi(NF_BASE + 0x3C)  
    49. #define S3C2440_NFCONT_nCE (1<<1)  
    50. #define S3C2440_ADDR_NALE 0x08  
    51. #define S3C2440_ADDR_NCLE 0x0c  
    52. #ifdef CONFIG_NAND_SPL  
    53. /* in the early stage of NAND flash booting, printf() is not available */  
    54. #define printf(fmt, args...)  
    55. static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)  
    56. {  
    57. int i;  
    58. struct nand_chip *this = mtd->priv;  
    59. for (i = 0; i < len; i++)  
    60. buf[i] = readb(this->IO_ADDR_R);  
    61. }  
    62. #endif  
    63. ulong IO_ADDR_W = NF_BASE;  
    64. static void s3c2440_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)  
    65. {  
    66. struct nand_chip *chip = mtd->priv;  
    67. DEBUGN("hwcontrol(): 0x%02x 0x%02x ", cmd, ctrl);  
    68. if (ctrl & NAND_CTRL_CHANGE) {  
    69. IO_ADDR_W = NF_BASE;  
    70. if (!(ctrl & NAND_CLE))  
    71. IO_ADDR_W |= S3C2440_ADDR_NCLE;  
    72. if (!(ctrl & NAND_ALE))  
    73. IO_ADDR_W |= S3C2440_ADDR_NALE;  
    74. if (ctrl & NAND_NCE)  
    75. NFCONT &= ~ S3C2440_NFCONT_nCE;  
    76. else  
    77. NFCONT |= S3C2440_NFCONT_nCE;  
    78. }  
    79. if (cmd != NAND_CMD_NONE)  
    80. writeb(cmd, (void *)IO_ADDR_W);  
    81. }  
    82. static int s3c2440_dev_ready(struct mtd_info *mtd)  
    83. {  
    84. DEBUGN("dev_ready ");  
    85. return(NFSTAT & 0x01);  
    86. }  
    87. #ifdef CONFIG_S3C2410_NAND_HWECC  
    88. void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)  
    89. {  
    90. struct s3c2410_nand *nand = s3c2410_get_base_nand();  
    91. debugX(1, "s3c2410_nand_enable_hwecc(%p, %d) ", mtd, mode);  
    92. writel(readl(&nand->NFCONF) | S3C2410_NFCONF_INITECC, &nand->NFCONF);  
    93. }  
    94. static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,  
    95. u_char *ecc_code)  
    96. {  
    97. struct s3c2410_nand *nand = s3c2410_get_base_nand();  
    98. ecc_code[0] = readb(&nand->NFECC);  
    99. ecc_code[1] = readb(&nand->NFECC + 1);  
    100. ecc_code[2] = readb(&nand->NFECC + 2);  
    101. debugX(1, "s3c2410_nand_calculate_hwecc(%p,): 0x%02x 0x%02x 0x%02x ",  
    102. mtd , ecc_code[0], ecc_code[1], ecc_code[2]);  
    103. return 0;  
    104. }  
    105. static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,  
    106. u_char *read_ecc, u_char *calc_ecc)  
    107. {  
    108. if (read_ecc[0] == calc_ecc[0] &&  
    109. read_ecc[1] == calc_ecc[1] &&  
    110. read_ecc[2] == calc_ecc[2])  
    111. return 0;  
    112. printf("s3c2410_nand_correct_data: not implemented ");  
    113. return -1;  
    114. }  
    115. #endif  
    116. int board_nand_init(struct nand_chip *nand)  
    117. {  
    118. u_int32_t cfg;  
    119. u_int8_t tacls, twrph0, twrph1;  
    120. struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power();  
    121. DEBUGN("board_nand_init() ");  
    122. writel(readl(&clk_power->CLKCON) | (1 << 4), &clk_power->CLKCON);  
    123. /* initialize hardware */  
    124. twrph0 = 4;  
    125. twrph1 =2;  
    126. tacls = 0;  
    127. cfg = ((tacls<<12)|(twrph0<<8)|(twrph1<<4));  
    128. NFCONF=cfg;  
    129. cfg = ((1<<6)|(1<<4)|(0<<1)|(1<<0));  
    130. NFCONT=cfg;  
    131. /* initialize nand_chip data structure */  
    132. nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)0x4e000010;  
    133. /* read_buf and write_buf are default */  
    134. /* read_byte and write_byte are default */  
    135. /* hwcontrol always must be implemented */  
    136. nand->cmd_ctrl = s3c2440_hwcontrol;  
    137. nand->dev_ready = s3c2440_dev_ready;  
    138. nand->ecc.mode = NAND_ECC_SOFT;  
    139. DEBUGN("end of nand_init ");  
    140. return 0;  
    141. }  
  • 相关阅读:
    UML 结构图之类图 总结
    UML 结构图之包图 总结
    UML 行为图之用例图 总结
    一位36岁程序员的困惑(转)
    某程序员转行前的感慨 告别程序员生涯
    PHP有前途吗?
    使用d3制作上下结构的股权穿透图
    elementUI实现动态拖拽表头、可拖拽列
    使用iview框架,如何进行输入框或者按钮的关联验证
    iview的Modal组件点击确定按钮如何阻止弹窗的关闭
  • 原文地址:https://www.cnblogs.com/liuchengchuxiao/p/4210577.html
Copyright © 2011-2022 走看看