世界简讯:开放NAND闪存接口ONFI介绍
本文转自公众号,欢迎关注
开放NAND闪存接口ONFI介绍 (qq.com)
一.前言ONFI即 Open NAND Flash Interface,开放NAND闪存接口.是一个由100多家制造、设计或启用NAND闪存的公司组成的行业工作组,主要是Intel和镁光。致力于简化NAND闪存集成到消费电子产品、计算平台和任何其他需要固态大容量存储的应用程序中。为NAND闪存定义标准化的组件级接口规范以及连接器和模块外形规格。使用开放接口标准加强了来自不同供应商的NAND设备的兼容性和互操作性。这增加了标准器件的供应基础,缩短了设计时间并加快了上市时间。
【资料图】
从软件的角度,主要是读取符合ONFI标准的参数,比如容量等信息,用以做驱动代码的兼容性设计。这部分信息一般放置在指定的参数PAGE中,描述芯片组织、功能、时序和其他行为参数的数据结构。
以下基于GD5F1GQ5xExxG详细介绍ONFI的参数页。
二.读取参数页参考《GD5F1GQ5xExxG DATASHEET》的8.11 ReadParameter Page (P27)
参数PAGE至少有三份参数副本存储在设备中,读PAGE到Cache(13h) 之后,从Cache读(03H/0BH)命令可用于读指定的数据,可以一次只读一份,如果校验错误再偏移读下一份。
操作过程如下:
1.配置B0寄存器的OTP_EN位为1
2.然后回读确认B0寄存器的OTP_EN位置1
3.使用(13h)指令加载地址24’h000004的PAGE到Cache中
4.读C0寄存器,等待OIP为0表示操作完
5.使用(03H/0BH)命令从Cache中读出指定数据。
如下是使用逻辑分析仪抓取的一次完整的操作
(1)先读B0寄存器,设置OTP_EN位为1(bit6), 然后回读确认OTP_EN置位
(2)使用(13h)指令加载地址24’h000004的PAGE到Cache中,第一次读C0寄存器为0x01即OIP=1还未完成,然后后面继续读OIP变为了0表示完成。
(3)03H指令读取整个PAGE的数据,可以看到256字节就重复了。
可以看到256字节重复了8遍,刚好2KB,最后还有128B的Spare区域
三.参数页数据结构Byte | O/M | Description | 3.3V/1.8V | 实际值(数据小端模式) |
0-3 | M | Parameter page signatureByte 0: 4FH, “O”Byte 1: 4EH, “N”Byte 2: 46H, “F”Byte 3: 49H, “I” | 4FH4EH46H49H | “ONFI” |
4-5 | M | Revision number0-15 Reserved (0) | 00H00H | |
6-7 | M | Features supported0-15 Reserved (0) | 00H00H | |
8-9 | M | Reserved (0) | 00H00H | |
10-31 | Reserved (0) | 00H…00H | ||
Manufacturer Information block | ||||
32-43 | M | Device manufacturer (12 ASCII characters)“GIGADEVICE ” | 47H49H47H41H44H45H56H49H43H45H20H20H | “GIGADEVICE ” |
44-63 | M | Device model (20 ASCII characters) “GD5F1GQ5U”x4 2.7v ~ 3.6v “GD5F1GQ5R”x4 1.7v ~ 2.0v | 47H44H35H46H31H47H51H35H55H/52H20H20H20H20H20H20H 20H 20H 20H 20H 20H | “GD5F1GQ5R” |
64 | M | JEDEC manufacturer ID“C8” | C8H | C8 |
65-66 | O | Date code | 00H00H | |
67-79 | Reserved | 00H00H00H | ||
Memory organization block | ||||
80-83 | M | Number of data bytes per page | 00H08H00H00H | PAGE数据大小 0x00000800=2KB |
84-85 | M | Number of spare bytes per page | 80H00H | PAGE的SPARE区域大小0x0080=128字节 |
86-89 | M | Number of data bytes per partial page | 00H02H00H00H | 分页大小0x0200=512字节 即一个PAGE分为4个小页 |
90-91 | M | Number of spare bytes per partial page | 20H00H | 每个分页SPARE区域大小0x0020=32字节 |
92-95 | M | Number of pages per block | 40H00H00H00H | 每个块的PAGE数0x00000040=64块 |
96-99 | M | Number of blocks per logical unit (LUN) | 00H04H00H00H | 每个逻辑单元的块数0x00000400=1024个 |
100 | M | Number of logical units (LUNs) | 01H | 逻辑单元数1 |
101 | M | Reserved | 00H | |
102 | M | Number of bits per cell | 01H | 每个存储单元的位数1,即SLC |
103-104 | M | Bad blocks maximum | 14H00H | 最大坏块数20 |
105-106 | M | Block endurance | 01H05H | 耐久性0x0501 (指的什么待查) |
107 | M | Guaranteed valid blocks at beginning of target | 01H | 保证存储开始的该块数在生命周期是有效的 |
108-109 | M | Block endurance for guaranteed valid blocks | 00H00H | 保证有效区块的耐久性 |
110 | M | Number of programs per page | 04H | 每页有4个可编程小页 |
111 | M | Partial programming attributes5-7 Reserved4 1 = partial page layout is partial page data followed by partial page spare1-3 Reserved0 1 = partial page programming has constraints | 00H | 部分页面编程无约束 小页连续放一起,SPARE区域连续放一起。 |
112 | M | Number of bits ECC correctability | 00H | |
113 | M | Number of interleaved address bits4-7 Reserved (0)0-3 Number of interleaved address bits | 00H | |
114 | O | Interleaved operation attributes4-7 Reserved (0)3 Address restrictions for program cache2 1 = program cache supported1 1 = no block address restrictions0 Overlapped / concurrent interleaving support | 00H | |
115-127 | Reserved | 00H…00H | ||
Electrical parameters block | ||||
128 | M | I/O capacitance | 08H | |
129-130 | M | IO clock support | 00H00H | |
131-132 | O | Reserved (0) | 00H00H | |
133-134 | M | tPROG Maximum page program time (us) | 58H02H | |
135-136 | M | tBERS Maximum block erase time (us) | 10H27H | |
137-138 | M | tR Maximum page read time (us) | 3CH00H | |
139-140 | M | Reserved | 00H00H | |
141-163 | Reserved | 00H | ||
Vendor block | ||||
164-165 | M | Vendor specificRevision number | 00H | |
166-253 | Vendor specific | 00H | ||
254-255 | M | Integrity CRC | Set on test | 0x3E80 |
Redundant parameter pages | ||||
256-511 | M | Value of bytes 0-255 | ||
512-767 | M | Value of bytes 0-255 | ||
768+ | O | Additional redundant parameter pages |
校验值如下
Device Model | ORGANIZATION | VCC RANGE | CRC value B254/B255 |
“GD5F1GQ5UxxG” | X4 | 2.7v ~ 3.6v | 58H/F3H |
“GD5F1GQ5RxxG” | X4 | 1.7v ~ 2.0v | 80H/3EH |
其中1.“O”代表可选,“M”代表强制
完整性CRC(循环冗余检查)字段用于验证参数页面的内容是否已正确传输到主机。有关详细信息,请参阅ONFI 1.0规范。CRC应使用以下16位生成器多项式计算:G(X)=X^16+X^15+X^2+1,此十六进制多项式可表示为8005h
CRC值应在计算开始前用4F4Eh的值进行初始化。在计算出最终CRC值之后,没有对其应用XOR。不存在数据字节或CRC计算值的反转。
四.关键代码读参数页的主要流程,相关底层接口这里不再贴出
int nand_read_param_page(uint8_t* buffer, uint16_t start, uint16_t len){ int res = 0; /* 设置OTP_EN = 1 */ res = nand_set_otp(NAND_B_OPT_ACCESS,NAND_REG_RETRY); if(res == 0) { /* 加载数据到Cache */ res = nand_read_page_to_cache(NAND_PARAM_PAGE_ADDR,NAND_PAGE_TO_CACHE_RETRY); if(res == 0) { /* 从Cache读数据 */ res = nand_read_from_cache(start, len, buffer); if(res == 0) { /* 成功 */ } else { res = -3; } } else { return -2; } } else { res = -1; } /* 切回正常模式 */ nand_set_otp(NAND_B_OPT_NORMAL,NAND_REG_RETRY); return res;}
五.uCFS的NAND FTL中使用ONFIfs_dev_nand_part_onfi.c
fs_dev_nand_part_onfi.h
函数FS_NAND_PartONFI_ParamPageParse根据参数页解释参数到FS_NAND_PART_DATA结构体
/*********************************************************************************************************** FS_NAND_PartONFI_ParamPageParse()** Description : Parse the ONFI parameter page.** Argument(s) : p_part_data Pointer to a NAND part data object.* ----------- Argument validated by caller.** p_err Pointer to variable that will receive return the error code from this function :* ----- Argument validated by caller.** FS_ERR_DEV_NAND_ONFI_INVALID_PARAM_PAGE Invalid parameter page.* FS_ERR_DEV_NAND_ONFI_VER_NOT_SUPPORTED ONFI version not supported.* FS_ERR_NONE Parameter page parsed successfully.** Return(s) : none.** Note(s) : none.**********************************************************************************************************/static void FS_NAND_PartONFI_ParamPageParse (FS_NAND_PART_DATA *p_part_data, FS_ERR *p_err){ CPU_BOOLEAN is_ver_supported; CPU_BOOLEAN has_ext_pp; CPU_BOOLEAN is_bus_16; CPU_BOOLEAN is_invalid; CPU_INT08U value; CPU_INT08U multiplier; CPU_INT08U lun_nbr; CPU_INT16U version; CPU_INT32U pg_size; CPU_INT32U max_size; CPU_INT32U nb_pg_per_blk; CPU_INT32U blk_cnt; CPU_INT64U max_blk_erase; CPU_DATA ix; *p_err = FS_ERR_NONE; /* -------------- REV INFO AND FEATURES --------------- */ /* Validate ONFI version. */ MEM_VAL_COPY_GET_INT16U_LITTLE(&version, &FS_NAND_PartONFI_ParamPg[4]); is_invalid = DEF_BIT_IS_SET(version, DEF_BIT_00); if (is_invalid == DEF_YES) { *p_err = FS_ERR_DEV_INVALID; return; } ix = 0; is_ver_supported = DEF_NO; while ((is_ver_supported != DEF_YES) && (ix < FS_NAND_PART_ONFI_V_QTY)){ is_ver_supported = DEF_BIT_IS_SET(version, FS_NAND_PartONFI_SupportedVersions[ix]); ix++; } if (is_ver_supported == DEF_YES) { version = FS_NAND_PartONFI_SupportedVersions[ix - 1u]; } else { FS_TRACE_DBG(("FS_NAND_PartONFI_ParamPageParse(): ONFI version not supported by this driver.rn")); *p_err = FS_ERR_DEV_INVALID; return; } /* Identify features. */ has_ext_pp = DEF_BIT_IS_SET(FS_NAND_PartONFI_ParamPg[6], FS_NAND_PART_ONFI_FEATURE_EX_PP); is_bus_16 = DEF_BIT_IS_SET(FS_NAND_PartONFI_ParamPg[6], FS_NAND_PART_ONFI_FEATURE_BUS_16); if (is_bus_16 == DEF_YES) { p_part_data->BusWidth = 16u; } else { p_part_data->BusWidth = 8u; } /* Extended parameter page length. */ if (has_ext_pp == DEF_YES) { FS_NAND_PartONFI_ExtParamPageLen = FS_NAND_PartONFI_ParamPg[12]; FS_NAND_PartONFI_ExtParamPageLen |= (CPU_INT16U)((CPU_INT16U)FS_NAND_PartONFI_ParamPg[13] << DEF_INT_08_NBR_BITS); FS_NAND_PartONFI_ExtParamPageLen *= 16u; } /* Number of parameter pages. */ if (version >= FS_NAND_PART_ONFI_V21) { FS_NAND_PartONFI_ParamPageCnt = FS_NAND_PartONFI_ParamPg[14]; } else { FS_NAND_PartONFI_ParamPageCnt = 3u; } /* ----------- IDENTIFY MEMORY ORGANIZATION ----------- */ /* Page size. */ MEM_VAL_COPY_GET_INT32U_LITTLE(&pg_size, &FS_NAND_PartONFI_ParamPg[80]); max_size = (FS_NAND_PG_SIZE) -1; if (pg_size > max_size) { FS_TRACE_DBG(("FS_NAND_PartONFI_ParamPageParse(): Page size does not fit in container type FS_NAND_PG_SIZE.rn")); *p_err = FS_ERR_DEV_INCOMPATIBLE_LOW_PARAMS; return; } p_part_data->PgSize = pg_size; /* Spare size. */ MEM_VAL_COPY_GET_INT16U_LITTLE(&(p_part_data->SpareSize), &FS_NAND_PartONFI_ParamPg[84]); /* Nb of pages per blk. */ MEM_VAL_COPY_GET_INT32U_LITTLE(&nb_pg_per_blk, &FS_NAND_PartONFI_ParamPg[92]); max_size = (FS_NAND_PG_PER_BLK_QTY) -1; if (nb_pg_per_blk > max_size) { FS_TRACE_DBG(("FS_NAND_PartONFI_ParamPageParse(): Nb of pages per blk does not fit in container type FS_NAND_PG_PER_BLK_QTY.rn")); *p_err = FS_ERR_DEV_INCOMPATIBLE_LOW_PARAMS; return; } p_part_data->PgPerBlk = nb_pg_per_blk; /* Nb of block per logical unit. */ MEM_VAL_COPY_GET_INT32U_LITTLE(&blk_cnt, &FS_NAND_PartONFI_ParamPg[96]); max_size = (FS_NAND_BLK_QTY) - 1; if (blk_cnt > max_size) { FS_TRACE_DBG(("FS_NAND_PartONFI_ParamPageParse(): Blk cnt does not fit in container type FS_NAND_BLK_QTY.rn")); *p_err = FS_ERR_DEV_INCOMPATIBLE_LOW_PARAMS; return; } /* Nb of logical units. */ lun_nbr = FS_NAND_PartONFI_ParamPg[100]; p_part_data->BlkCnt = blk_cnt * lun_nbr; /* Max nb of bad blocks per logical unit. */ MEM_VAL_COPY_GET_INT16U_LITTLE(&(p_part_data->MaxBadBlkCnt), &FS_NAND_PartONFI_ParamPg[103]); p_part_data->MaxBadBlkCnt *= lun_nbr; /* Max programming operations per block. */ value = FS_NAND_PartONFI_ParamPg[105]; multiplier = FS_NAND_PartONFI_ParamPg[106]; if (multiplier > 9u) { FS_TRACE_DBG(("FS_NAND_PartONFI_ParamPageParse: Max blk erase count larger than supported.rn")); *p_err = FS_ERR_DEV_INCOMPATIBLE_LOW_PARAMS; return; } max_blk_erase = value * FS_NAND_PartONFI_PowerOf10[multiplier]; max_size = (CPU_INT32U) - 1; if (max_blk_erase > max_size) { FS_TRACE_DBG(("FS_NAND_PartONFI_ParamPageParse(): Max blk erase cnt does not fit in container type CPU_INT32U.rn")); *p_err = FS_ERR_DEV_INCOMPATIBLE_LOW_PARAMS; return; } p_part_data->MaxBlkErase = max_blk_erase; /* Max nb of partial page programming. */ p_part_data->NbrPgmPerPg = FS_NAND_PartONFI_ParamPg[110]; /* ECC correction needed. */ p_part_data->ECC_NbrCorrBits = FS_NAND_PartONFI_ParamPg[112]; if (p_part_data->ECC_NbrCorrBits == 0xFFu) { p_part_data->ECC_CodewordSize = 0u; if (has_ext_pp == DEF_FALSE) { FS_TRACE_DBG(("FS_NAND_PartONFI_ParamPageParse(): ECC located in extended param pg, but dev does not have one.rn")); *p_err = FS_ERR_DEV_INVALID; return; } else { *p_err = FS_ERR_DEV_NAND_ONFI_EXT_PARAM_PAGE; } } else { p_part_data->ECC_CodewordSize = 528u; } /* Factory defect mark type. */ if (version >= FS_NAND_PART_ONFI_V21) { p_part_data->DefectMarkType = DEFECT_SPARE_L_1_PG_1_OR_N_ALL_0; } else { /* #### NAND drv not compatible with "any loc". */ p_part_data->DefectMarkType = DEFECT_SPARE_L_1_PG_1_OR_N_ALL_0; }}
六.参考https://www.onfi.org/specifications
最新版本是5.1
审核编辑黄宇
标签: