MTD NAND 驱动编程接口¶
- 作者:
Thomas Gleixner
简介¶
通用 NAND 驱动程序支持几乎所有基于 NAND 和 AG-AND 的芯片,并将它们连接到 Linux 内核的内存技术设备 (MTD) 子系统。
本文档提供给想要实现适用于 NAND 设备的板驱动程序或文件系统驱动程序的开发人员。
已知错误和假设¶
无。
文档提示¶
函数和结构文档是自动生成的。每个函数和结构成员都有一个简短的描述,并用 [XXX] 标识符标记。以下章节解释这些标识符的含义。
函数标识符 [XXX]¶
函数在简短的注释中用 [XXX] 标识符标记。标识符解释函数的使用和范围。使用以下标识符
[MTD 接口]
这些函数提供 MTD 内核 API 的接口。它们不可替换,并提供完全独立于硬件的功能。
[NAND 接口]
这些函数被导出并提供 NAND 内核 API 的接口。
[通用]
通用函数不可替换,并提供完全独立于硬件的功能。
[默认]
默认函数提供适用于大多数实现的硬件相关功能。如有必要,板驱动程序可以替换这些函数。这些函数通过 NAND 芯片描述结构中的指针调用。板驱动程序可以在调用 nand_scan() 之前设置应由板相关函数替换的函数。如果 nand_scan() 入口处的函数指针为 NULL,则该指针将设置为适用于检测到的芯片类型的默认函数。
结构成员标识符 [XXX]¶
结构成员在注释中用 [XXX] 标识符标记。标识符解释成员的使用和范围。使用以下标识符
[内部]
这些成员仅供 NAND 驱动程序内部使用,不得修改。大多数这些值都是从芯片几何信息计算得出的,这些信息在 nand_scan() 期间进行评估。
[可替换]
可替换成员保存可由板驱动程序提供的硬件相关函数。板驱动程序可以在调用 nand_scan() 之前设置应由板相关函数替换的函数。如果 nand_scan() 入口处的函数指针为 NULL,则该指针将设置为适用于检测到的芯片类型的默认函数。
[板特定]
板特定成员保存必须由板驱动程序提供的硬件相关信息。板驱动程序必须在调用 nand_scan() 之前设置函数指针和数据字段。
[可选]
可选成员可以保存与板驱动程序相关的信息。通用 NAND 驱动程序代码不使用此信息。
基本板驱动程序¶
对于大多数板来说,仅提供基本函数并填写 NAND 芯片描述结构中一些真正依赖于板的成员就足够了。
基本定义¶
至少您必须提供一个 nand_chip 结构和一个用于存储 ioremap 芯片地址的存储空间。您可以使用 kmalloc 分配 nand_chip 结构,也可以静态分配它。NAND 芯片结构嵌入了一个 mtd 结构,该结构将注册到 MTD 子系统。您可以使用 nand_to_mtd() 帮助程序从 nand_chip 指针中提取指向 mtd 结构的指针。
基于 Kmalloc 的示例
static struct mtd_info *board_mtd;
static void __iomem *baseaddr;
静态示例
static struct nand_chip board_chip;
static void __iomem *baseaddr;
分区定义¶
如果要将设备划分为分区,则定义适合您板的分区方案。
#define NUM_PARTITIONS 2
static struct mtd_partition partition_info[] = {
{ .name = "Flash partition 1",
.offset = 0,
.size = 8 * 1024 * 1024 },
{ .name = "Flash partition 2",
.offset = MTDPART_OFS_NEXT,
.size = MTDPART_SIZ_FULL },
};
硬件控制函数¶
硬件控制函数提供对 NAND 芯片控制引脚的访问。访问可以通过 GPIO 引脚或地址线完成。如果使用地址线,请确保满足时序要求。
基于 GPIO 的示例
static void board_hwcontrol(struct mtd_info *mtd, int cmd)
{
switch(cmd){
case NAND_CTL_SETCLE: /* Set CLE pin high */ break;
case NAND_CTL_CLRCLE: /* Set CLE pin low */ break;
case NAND_CTL_SETALE: /* Set ALE pin high */ break;
case NAND_CTL_CLRALE: /* Set ALE pin low */ break;
case NAND_CTL_SETNCE: /* Set nCE pin low */ break;
case NAND_CTL_CLRNCE: /* Set nCE pin high */ break;
}
}
基于地址线的示例。 假设 nCE 引脚由芯片选择解码器驱动。
static void board_hwcontrol(struct mtd_info *mtd, int cmd)
{
struct nand_chip *this = mtd_to_nand(mtd);
switch(cmd){
case NAND_CTL_SETCLE: this->legacy.IO_ADDR_W |= CLE_ADRR_BIT; break;
case NAND_CTL_CLRCLE: this->legacy.IO_ADDR_W &= ~CLE_ADRR_BIT; break;
case NAND_CTL_SETALE: this->legacy.IO_ADDR_W |= ALE_ADRR_BIT; break;
case NAND_CTL_CLRALE: this->legacy.IO_ADDR_W &= ~ALE_ADRR_BIT; break;
}
}
设备就绪函数¶
如果硬件接口将 NAND 芯片的就绪忙引脚连接到 GPIO 或其他可访问的 I/O 引脚,则此函数用于读回引脚的状态。该函数没有参数,如果设备忙(R/B 引脚为低电平),则应返回 0,如果设备就绪(R/B 引脚为高电平),则应返回 1。如果硬件接口无法访问就绪忙引脚,则不能定义该函数,并且函数指针 this->legacy.dev_ready 设置为 NULL。
初始化函数¶
初始化函数分配内存并设置所有特定于板的参数和函数指针。设置好所有内容后,调用 nand_scan()。此函数尝试检测和识别芯片。如果找到芯片,则会相应地初始化所有内部数据字段。必须先将结构清零,然后再填写有关设备的必要信息。
static int __init board_init (void)
{
struct nand_chip *this;
int err = 0;
/* Allocate memory for MTD device structure and private data */
this = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
if (!this) {
printk ("Unable to allocate NAND MTD device structure.\n");
err = -ENOMEM;
goto out;
}
board_mtd = nand_to_mtd(this);
/* map physical address */
baseaddr = ioremap(CHIP_PHYSICAL_ADDRESS, 1024);
if (!baseaddr) {
printk("Ioremap to access NAND chip failed\n");
err = -EIO;
goto out_mtd;
}
/* Set address of NAND IO lines */
this->legacy.IO_ADDR_R = baseaddr;
this->legacy.IO_ADDR_W = baseaddr;
/* Reference hardware control function */
this->hwcontrol = board_hwcontrol;
/* Set command delay time, see datasheet for correct value */
this->legacy.chip_delay = CHIP_DEPENDEND_COMMAND_DELAY;
/* Assign the device ready function, if available */
this->legacy.dev_ready = board_dev_ready;
this->eccmode = NAND_ECC_SOFT;
/* Scan to find existence of the device */
if (nand_scan (this, 1)) {
err = -ENXIO;
goto out_ior;
}
add_mtd_partitions(board_mtd, partition_info, NUM_PARTITIONS);
goto out;
out_ior:
iounmap(baseaddr);
out_mtd:
kfree (this);
out:
return err;
}
module_init(board_init);
退出函数¶
仅当驱动程序编译为模块时,才需要退出函数。它释放芯片驱动程序拥有的所有资源,并在 MTD 层中取消注册分区。
#ifdef MODULE
static void __exit board_cleanup (void)
{
/* Unregister device */
WARN_ON(mtd_device_unregister(board_mtd));
/* Release resources */
nand_cleanup(mtd_to_nand(board_mtd));
/* unmap physical address */
iounmap(baseaddr);
/* Free the MTD device structure */
kfree (mtd_to_nand(board_mtd));
}
module_exit(board_cleanup);
#endif
高级板驱动程序函数¶
本章介绍 NAND 驱动程序的高级功能。有关板驱动程序可以覆盖的函数列表,请参阅 nand_chip 结构的文档。
多芯片控制¶
NAND 驱动程序可以控制芯片阵列。因此,板级驱动程序必须提供自己的 `select_chip` 函数。此函数必须(取消)选择请求的芯片。在调用 `nand_scan()` 之前,必须设置 `nand_chip` 结构中的函数指针。`nand_scan()` 的 `maxchip` 参数定义了要扫描的最大芯片数量。请确保 `select_chip` 函数可以处理请求的芯片数量。
NAND 驱动程序将这些芯片连接成一个虚拟芯片,并将此虚拟芯片提供给 MTD 层。
注意:该驱动程序只能处理大小相同的线性芯片阵列。不支持扩展总线宽度的并行阵列。
基于 GPIO 的示例
static void board_select_chip (struct mtd_info *mtd, int chip)
{
/* Deselect all chips, set all nCE pins high */
GPIO(BOARD_NAND_NCE) |= 0xff;
if (chip >= 0)
GPIO(BOARD_NAND_NCE) &= ~ (1 << chip);
}
基于地址线的示例。 假设 nCE 引脚连接到地址解码器。
static void board_select_chip (struct mtd_info *mtd, int chip)
{
struct nand_chip *this = mtd_to_nand(mtd);
/* Deselect all chips */
this->legacy.IO_ADDR_R &= ~BOARD_NAND_ADDR_MASK;
this->legacy.IO_ADDR_W &= ~BOARD_NAND_ADDR_MASK;
switch (chip) {
case 0:
this->legacy.IO_ADDR_R |= BOARD_NAND_ADDR_CHIP0;
this->legacy.IO_ADDR_W |= BOARD_NAND_ADDR_CHIP0;
break;
....
case n:
this->legacy.IO_ADDR_R |= BOARD_NAND_ADDR_CHIPn;
this->legacy.IO_ADDR_W |= BOARD_NAND_ADDR_CHIPn;
break;
}
}
硬件 ECC 支持¶
函数和常量¶
NAND 驱动程序支持三种不同类型的硬件 ECC。
NAND_ECC_HW3_256
硬件 ECC 生成器,每 256 字节提供 3 字节 ECC。
NAND_ECC_HW3_512
硬件 ECC 生成器,每 512 字节提供 3 字节 ECC。
NAND_ECC_HW6_512
硬件 ECC 生成器,每 512 字节提供 6 字节 ECC。
NAND_ECC_HW8_512
硬件 ECC 生成器,每 512 字节提供 8 字节 ECC。
如果您的硬件生成器具有不同的功能,请将其添加到 `nand_base.c` 中的适当位置。
板级驱动程序必须提供以下函数:
`enable_hwecc`
此函数在读取/写入芯片之前调用。在此函数中重置或初始化硬件生成器。调用该函数时会带有一个参数,该参数使您能够区分读取和写入操作。
`calculate_ecc`
此函数在从芯片读取/写入后调用。将 ECC 从硬件传输到缓冲区。如果设置了 `NAND_HWECC_SYNDROME` 选项,则该函数仅在写入时调用。请参见下文。
`correct_data`
如果出现 ECC 错误,则会调用此函数进行错误检测和纠正。如果错误可以纠正,则返回 1 或 2。如果错误无法纠正,则返回 -1。如果您的硬件生成器与 `nand_ecc` 软件生成器的默认算法匹配,则使用 `nand_ecc` 提供的纠正函数,而不是实现重复的代码。
带综合征计算的硬件 ECC¶
许多硬件 ECC 实现都提供 Reed-Solomon 代码,并在读取时计算错误综合征。在调用通用 Reed-Solomon 库中的错误纠正代码之前,必须将综合征转换为标准 Reed-Solomon 综合征。
ECC 字节必须紧接在数据字节之后放置,以便综合征生成器能够工作。这与软件 ECC 使用的通常布局相反。不再可能分离数据和带外区域。NAND 驱动程序代码处理此布局,并且 oob 区域中剩余的空闲字节由自动放置代码管理。在这种情况下,提供匹配的 oob 布局。有关实现参考,请参见 `rts_from4.c` 和 `diskonchip.c`。在这些情况下,我们还必须在 FLASH 上使用坏块表,因为 ECC 布局会干扰坏块标记位置。有关详细信息,请参见坏块表支持。
坏块表支持¶
大多数 NAND 芯片在备用区域的定义位置标记坏块。在任何情况下都不得擦除这些块,因为坏块信息将会丢失。可以通过读取块中第一页的备用区域来每次访问块时检查坏块标记。这很耗时,因此使用坏块表。
NAND 驱动程序支持各种类型的坏块表。
每个设备
坏块表包含设备的所有坏块信息,该设备可以由多个芯片组成。
每个芯片
每个芯片使用一个坏块表,其中包含此特定芯片的坏块信息。
固定偏移量
坏块表位于芯片(设备)中的固定偏移量处。这适用于各种 DiskOnChip 设备。
自动放置
坏块表自动放置并在芯片(设备)的末尾或开头检测到。
镜像表
坏块表在芯片(设备)上镜像,以便在不丢失数据的情况下更新坏块表。
`nand_scan()` 调用函数 `nand_default_bbt()`。`nand_default_bbt()` 根据 `nand_scan()` 检索的芯片信息选择适当的默认坏块表描述符。
标准策略是扫描设备以查找坏块,并构建一个基于 RAM 的坏块表,该表允许比始终在闪存芯片本身上检查坏块信息更快的访问速度。
基于闪存的表¶
可能需要或有必要将坏块表保存在 FLASH 中。对于 AG-AND 芯片,这是强制性的,因为它们没有出厂标记的坏块。它们具有出厂标记的好块。当擦除该块以重复使用时,会擦除标记模式。因此,如果在将模式写回芯片之前断电,则该块将丢失并添加到坏块中。因此,当第一次检测到芯片时,我们会扫描芯片以查找好块,并在擦除任何块之前将此信息存储在坏块表中。
存储表的块通过在内存坏块表中将其标记为坏块来防止意外访问。坏块表管理函数允许规避此保护。
激活基于 FLASH 的坏块表支持的最简单方法是在调用 `nand_scan()` 之前,在 nand 芯片结构的 `bbt_option` 字段中设置 `NAND_BBT_USE_FLASH` 选项。对于 AG-AND 芯片,默认情况下会这样做。这会激活 NAND 驱动程序的默认基于 FLASH 的坏块表功能。默认的坏块表选项为:
每个芯片存储坏块表
每个块使用 2 位
自动放置在芯片末尾
使用带有版本号的镜像表
在芯片末尾保留 4 个块
用户定义的表¶
用户定义的表是通过填写 `nand_bbt_descr` 结构并在调用 `nand_scan()` 之前将指针存储在 `nand_chip` 结构成员 `bbt_td` 中来创建的。如果需要镜像表,则必须创建第二个结构,并且必须将指向该结构的指针存储在 `nand_chip` 结构内的 `bbt_md` 中。如果将 `bbt_md` 成员设置为 NULL,则仅使用主表,并且不会扫描镜像表。
`nand_bbt_descr` 结构中最重要的是 `options` 字段。这些选项定义了表的大部分属性。使用 `rawnand.h` 中的预定义常量来定义选项。
每个块的位数
支持的位数是 1、2、4、8。
每个芯片的表
设置常量 `NAND_BBT_PERCHIP` 选择为芯片阵列中的每个芯片管理坏块表。如果未设置此选项,则使用每个设备的坏块表。
表位置是绝对的
使用选项常量 `NAND_BBT_ABSPAGE` 并在 `pages` 字段中定义坏块表开始的绝对页码。如果您选择了每个芯片的坏块表,并且您有一个多芯片阵列,则必须为芯片阵列中的每个芯片提供起始页。注意:不会执行表识别模式的扫描,因此可以使字段 `pattern`、`veroffs`、`offs` 和 `len` 保持未初始化状态。
表位置是自动检测到的
该表可以位于芯片(设备)的第一个或最后一个好块中。设置 `NAND_BBT_LASTBLOCK` 将坏块表放置在芯片(设备)的末尾。坏块表通过存储在块中第一页的备用区域中的模式进行标记和识别,该块保存坏块表。将指向模式的指针存储在 `pattern` 字段中。此外,模式的长度必须存储在 `len` 中,并且备用区域中的偏移量必须在 `nand_bbt_descr` 结构的 `offs` 成员中给出。对于镜像坏块表,不同的模式是强制性的。
表创建
如果在扫描期间找不到表,请设置 `NAND_BBT_CREATE` 选项以启用表创建。通常,这仅在新发现芯片时执行一次。
表写入支持
设置 `NAND_BBT_WRITE` 选项以启用表写入支持。这允许在由于磨损而必须将块标记为坏块时更新坏块表。MTD 接口函数 `block_markbad` 正在调用坏块表的更新函数。如果启用了写入支持,则会在 FLASH 上更新表。
注意:写入支持应仅为带有版本控制的镜像表启用。
表版本控制
设置 `NAND_BBT_VERSION` 选项以启用表版本控制。强烈建议对具有写入支持的镜像表启用此功能。它可以确保将丢失坏块表信息的风险降低到丢失应标记为坏块的一个磨损块的信息。版本存储在设备备用区域中的 4 个连续字节中。版本号的位置由坏块表描述符中的成员 `veroffs` 定义。
在写入时保存块内容
如果保存坏块表的块包含其他有用的信息,请设置选项 `NAND_BBT_SAVECONTENT`。当写入坏块表时,将读取整个块,更新坏块表,擦除该块,然后写回所有内容。如果未设置此选项,则仅写入坏块表,并且忽略和擦除该块中的其他所有内容。
保留块的数量
为了自动布局,必须为坏块表存储保留一些块。保留的块数在坏块表描述结构体的 maxblocks 成员中定义。为镜像表保留 4 个块应该是一个合理的数字。这也限制了扫描坏块表标识模式的块数。
备用区域(自动)布局¶
NAND 驱动程序实现了在备用区域中放置文件系统数据的不同可能性:
由文件系统驱动程序定义的布局
自动布局
默认布局函数是自动布局。NAND 驱动程序为各种芯片类型内置了默认布局方案。如果由于硬件 ECC 功能导致默认布局不适合,则板级驱动程序可以提供自己的布局方案。
文件系统驱动程序可以提供自己的布局方案,该方案将代替默认布局方案。
布局方案由 nand_oobinfo 结构体定义
struct nand_oobinfo {
int useecc;
int eccbytes;
int eccpos[24];
int oobfree[8][2];
};
useecc
useecc 成员控制 ECC 和布局函数。头文件 include/mtd/mtd-abi.h 包含用于选择 ECC 和布局的常量。MTD_NANDECC_OFF 完全关闭 ECC。不推荐这样做,仅用于测试和诊断。MTD_NANDECC_PLACE 选择调用者定义的布局,MTD_NANDECC_AUTOPLACE 选择自动布局。
eccbytes
eccbytes 成员定义每个页面的 ECC 字节数。
eccpos
eccpos 数组保存备用区域中放置 ECC 代码的字节偏移量。
oobfree
oobfree 数组定义备用区域中可用于自动布局的区域。信息以 {offset, size} 格式给出。offset 定义可用区域的起始位置,size 定义长度(以字节为单位)。可以定义多个区域。列表以 {0, 0} 条目结束。
由文件系统驱动程序定义的布局¶
调用函数提供一个指向 nand_oobinfo 结构的指针,该结构定义了 ECC 布局。对于写入操作,调用者必须提供一个备用区域缓冲区以及数据缓冲区。备用区域缓冲区大小为(页面数)*(备用区域大小)。对于读取操作,缓冲区大小为(页面数)*((备用区域大小)+(每个页面的 ECC 步数)* sizeof(int))。驱动程序将每个元组的 ECC 检查结果存储在备用缓冲区中。存储顺序为:
<spare data page 0><ecc result 0>...<ecc result n>
...
<spare data page n><ecc result 0>...<ecc result n>
这是 YAFFS1 使用的旧模式。
如果备用区域缓冲区为 NULL,则仅根据 nand_oobinfo 结构中给定的方案执行 ECC 布局。
自动布局¶
自动布局使用内置默认值将 ECC 字节放置在备用区域中。如果必须将文件系统数据存储/读取到备用区域,则调用函数必须提供一个缓冲区。每个页面的缓冲区大小由 nand_oobinfo 结构中的 oobfree 数组确定。
如果备用区域缓冲区为 NULL,则仅根据默认内置方案执行 ECC 布局。
备用区域自动布局默认方案¶
256 字节页面大小¶
偏移量 |
内容 |
注释 |
---|---|---|
0x00 |
ECC 字节 0 |
错误校正码字节 0 |
0x01 |
ECC 字节 1 |
错误校正码字节 1 |
0x02 |
ECC 字节 2 |
错误校正码字节 2 |
0x03 |
自动放置 0 |
|
0x04 |
自动放置 1 |
|
0x05 |
坏块标记 |
如果此字节中的任何位为零,则此块为坏块。这仅适用于块中的第一个页面。在其余页面中,此字节保留。 |
0x06 |
自动放置 2 |
|
0x07 |
自动放置 3 |
512 字节页面大小¶
偏移量 |
内容 |
注释 |
---|---|---|
0x00 |
ECC 字节 0 |
此页面中较低的 256 字节数据的错误校正码字节 0 |
0x01 |
ECC 字节 1 |
此页面中较低的 256 字节数据的错误校正码字节 1 |
0x02 |
ECC 字节 2 |
此页面中较低的 256 字节数据的错误校正码字节 2 |
0x03 |
ECC 字节 3 |
此页面中较高的 256 字节数据的错误校正码字节 0 |
0x04 |
保留 |
保留 |
0x05 |
坏块标记 |
如果此字节中的任何位为零,则此块为坏块。这仅适用于块中的第一个页面。在其余页面中,此字节保留。 |
0x06 |
ECC 字节 4 |
此页面中较高的 256 字节数据的错误校正码字节 1 |
0x07 |
ECC 字节 5 |
此页面中较高的 256 字节数据的错误校正码字节 2 |
0x08 - 0x0F |
自动放置 0 - 7 |
2048 字节页面大小¶
偏移量 |
内容 |
注释 |
---|---|---|
0x00 |
坏块标记 |
如果此字节中的任何位为零,则此块为坏块。这仅适用于块中的第一个页面。在其余页面中,此字节保留。 |
0x01 |
保留 |
保留 |
0x02-0x27 |
自动放置 0 - 37 |
|
0x28 |
ECC 字节 0 |
此页面中第一个 256 字节数据的错误校正码字节 0 |
0x29 |
ECC 字节 1 |
此页面中第一个 256 字节数据的错误校正码字节 1 |
0x2A |
ECC 字节 2 |
此页面中第一个 256 字节数据的错误校正码字节 2 |
0x2B |
ECC 字节 3 |
此页面中第二个 256 字节数据的错误校正码字节 0 |
0x2C |
ECC 字节 4 |
此页面中第二个 256 字节数据的错误校正码字节 1 |
0x2D |
ECC 字节 5 |
此页面中第二个 256 字节数据的错误校正码字节 2 |
0x2E |
ECC 字节 6 |
此页面中第三个 256 字节数据的错误校正码字节 0 |
0x2F |
ECC 字节 7 |
此页面中第三个 256 字节数据的错误校正码字节 1 |
0x30 |
ECC 字节 8 |
此页面中第三个 256 字节数据的错误校正码字节 2 |
0x31 |
ECC 字节 9 |
此页面中第四个 256 字节数据的错误校正码字节 0 |
0x32 |
ECC 字节 10 |
此页面中第四个 256 字节数据的错误校正码字节 1 |
0x33 |
ECC 字节 11 |
此页面中第四个 256 字节数据的错误校正码字节 2 |
0x34 |
ECC 字节 12 |
此页面中第五个 256 字节数据的错误校正码字节 0 |
0x35 |
ECC 字节 13 |
此页面中第五个 256 字节数据的错误校正码字节 1 |
0x36 |
ECC 字节 14 |
此页面中第五个 256 字节数据的错误校正码字节 2 |
0x37 |
ECC 字节 15 |
此页面中第六个 256 字节数据的错误校正码字节 0 |
0x38 |
ECC 字节 16 |
此页面中第六个 256 字节数据的错误校正码字节 1 |
0x39 |
ECC 字节 17 |
此页面中第六个 256 字节数据的错误校正码字节 2 |
0x3A |
ECC 字节 18 |
此页面中第七个 256 字节数据的错误校正码字节 0 |
0x3B |
ECC 字节 19 |
此页面中第七个 256 字节数据的错误校正码字节 1 |
0x3C |
ECC 字节 20 |
此页面中第七个 256 字节数据的错误校正码字节 2 |
0x3D |
ECC 字节 21 |
此页面中第八个 256 字节数据的错误校正码字节 0 |
0x3E |
ECC 字节 22 |
此页面中第八个 256 字节数据的错误校正码字节 1 |
0x3F |
ECC 字节 23 |
此页面中第八个 256 字节数据的错误校正码字节 2 |
文件系统支持¶
NAND 驱动程序通过 MTD 接口为文件系统提供所有必要的功能。
文件系统必须了解 NAND 的特性和限制。NAND 闪存的一个主要限制是,您不能像您希望的那样频繁地写入页面。在再次擦除之前,对页面的连续写入限制为 1-3 次,具体取决于制造商的规范。这同样适用于备用区域。
因此,NAND 感知文件系统必须以页面大小的块写入,或保持一个写入缓冲区以收集较小的写入,直到它们总和达到页面大小。可用的 NAND 感知文件系统:JFFS2、YAFFS。
用于存储文件系统数据的备用区域的使用由备用区域布局功能控制,该功能在前面的章节中进行了描述。
工具¶
MTD 项目提供了一些有用的工具来处理 NAND 闪存。
flasherase, flasheraseall:擦除和格式化 FLASH 分区
nandwrite:将文件系统映像写入 NAND 闪存
nanddump:转储 NAND 闪存分区的内容
这些工具了解 NAND 的限制。请使用这些工具,而不是抱怨由非 NAND 感知访问方法引起的错误。
常量¶
本章介绍可能与驱动程序开发人员相关的常量。
芯片选项常量¶
芯片 ID 表的常量¶
这些常量在 rawnand.h 中定义。它们被 OR 在一起以描述芯片功能
/* Buswitdh is 16 bit */
#define NAND_BUSWIDTH_16 0x00000002
/* Device supports partial programming without padding */
#define NAND_NO_PADDING 0x00000004
/* Chip has cache program function */
#define NAND_CACHEPRG 0x00000008
/* Chip has copy back function */
#define NAND_COPYBACK 0x00000010
/* AND Chip which has 4 banks and a confusing page / block
* assignment. See Renesas datasheet for further information */
#define NAND_IS_AND 0x00000020
/* Chip has a array of 4 pages which can be read without
* additional ready /busy waits */
#define NAND_4PAGE_ARRAY 0x00000040
运行时选项的常量¶
这些常量在 rawnand.h 中定义。它们被 OR 在一起以描述功能
/* The hw ecc generator provides a syndrome instead a ecc value on read
* This can only work if we have the ecc bytes directly behind the
* data bytes. Applies for DOC and AG-AND Renesas HW Reed Solomon generators */
#define NAND_HWECC_SYNDROME 0x00020000
ECC 选择常量¶
使用这些常量选择 ECC 算法
/* No ECC. Usage is not recommended ! */
#define NAND_ECC_NONE 0
/* Software ECC 3 byte ECC per 256 Byte data */
#define NAND_ECC_SOFT 1
/* Hardware ECC 3 byte ECC per 256 Byte data */
#define NAND_ECC_HW3_256 2
/* Hardware ECC 3 byte ECC per 512 Byte data */
#define NAND_ECC_HW3_512 3
/* Hardware ECC 6 byte ECC per 512 Byte data */
#define NAND_ECC_HW6_512 4
/* Hardware ECC 8 byte ECC per 512 Byte data */
#define NAND_ECC_HW8_512 6
结构体¶
本章包含 NAND 驱动程序中使用的结构体的自动生成文档,这些结构体可能与驱动程序开发人员相关。每个结构体成员都有一个简短的描述,并用 [XXX] 标识符标记。有关说明,请参阅“文档提示”一章。
-
struct nand_parameters¶
来自参数页面的 NAND 通用参数
定义:
struct nand_parameters {
const char *model;
bool supports_set_get_features;
bool supports_read_cache;
unsigned long set_feature_list[BITS_TO_LONGS(ONFI_FEATURE_NUMBER)];
unsigned long get_feature_list[BITS_TO_LONGS(ONFI_FEATURE_NUMBER)];
struct onfi_params *onfi;
};
成员
model
型号名称
supports_set_get_features
NAND 芯片支持设置/获取功能
supports_read_cache
NAND 芯片支持读取缓存操作
set_feature_list
可以设置的功能的位图
get_feature_list
可以获取的功能的位图
onfi
ONFI 特定参数
-
struct nand_id¶
NAND ID 结构体
定义:
struct nand_id {
u8 data[NAND_MAX_ID_LEN];
int len;
};
成员
data
包含 ID 字节的缓冲区。
len
ID 长度。
-
struct nand_ecc_step_info¶
ECC 引擎的 ECC 步进信息
定义:
struct nand_ecc_step_info {
int stepsize;
const int *strengths;
int nstrengths;
};
成员
stepsize
每个 ECC 步进的数据字节数
strengths
支持的强度数组
nstrengths
支持的强度数量
-
struct nand_ecc_caps¶
ECC 引擎的功能
定义:
struct nand_ecc_caps {
const struct nand_ecc_step_info *stepinfos;
int nstepinfos;
int (*calc_ecc_bytes)(int step_size, int strength);
};
成员
stepinfos
ECC 步进信息数组
nstepinfos
ECC 步进信息数量
calc_ecc_bytes
驱动程序用于计算每个步进 ECC 字节的回调函数
-
struct nand_ecc_ctrl¶
ECC 的控制结构
定义:
struct nand_ecc_ctrl {
enum nand_ecc_engine_type engine_type;
enum nand_ecc_placement placement;
enum nand_ecc_algo algo;
int steps;
int size;
int bytes;
int total;
int strength;
int prepad;
int postpad;
unsigned int options;
u8 *calc_buf;
u8 *code_buf;
void (*hwctl)(struct nand_chip *chip, int mode);
int (*calculate)(struct nand_chip *chip, const uint8_t *dat, uint8_t *ecc_code);
int (*correct)(struct nand_chip *chip, uint8_t *dat, uint8_t *read_ecc, uint8_t *calc_ecc);
int (*read_page_raw)(struct nand_chip *chip, uint8_t *buf, int oob_required, int page);
int (*write_page_raw)(struct nand_chip *chip, const uint8_t *buf, int oob_required, int page);
int (*read_page)(struct nand_chip *chip, uint8_t *buf, int oob_required, int page);
int (*read_subpage)(struct nand_chip *chip, uint32_t offs, uint32_t len, uint8_t *buf, int page);
int (*write_subpage)(struct nand_chip *chip, uint32_t offset,uint32_t data_len, const uint8_t *data_buf, int oob_required, int page);
int (*write_page)(struct nand_chip *chip, const uint8_t *buf, int oob_required, int page);
int (*write_oob_raw)(struct nand_chip *chip, int page);
int (*read_oob_raw)(struct nand_chip *chip, int page);
int (*read_oob)(struct nand_chip *chip, int page);
int (*write_oob)(struct nand_chip *chip, int page);
};
成员
engine_type
ECC 引擎类型
placement
OOB 字节放置
algo
ECC 算法
steps
每个页面的 ECC 步数
size
每个 ECC 步进的数据字节数
字节
每个步进的 ECC 字节数
total
每个页面的 ECC 字节总数
strength
每个 ECC 步进可纠正的最大位数
prepad
用于基于综合症的 ECC 生成器的填充信息
postpad
用于基于综合症的 ECC 生成器的填充信息
options
ECC 特定选项(请参阅上面定义的 NAND_ECC_XXX 标志)
calc_buf
用于计算 ECC 的缓冲区,大小为 oobsize。
code_buf
用于从闪存读取 ECC 的缓冲区,大小为 oobsize。
hwctl
控制硬件 ECC 生成器的函数。仅当硬件 ECC 可用时才必须提供
calculate
用于 ECC 计算或从 ECC 硬件读取的回调函数
correct
用于 ECC 校正的函数,与 ECC 生成器(软件/硬件)匹配。应返回一个正数,表示已校正的位翻转次数,如果位翻转次数超过 ECC 强度则返回 -EBADMSG,如果错误与校正没有直接关系则返回任何其他错误代码。如果返回 -EBADMSG,则应保持输入缓冲区不变。
read_page_raw
用于读取没有 ECC 的原始页面的函数。此函数应隐藏 ECC 控制器使用的特定布局,并且即使它们没有连续存储在 NAND 芯片上(例如,NAND_ECC_PLACEMENT_INTERLEAVED 交错带内和带外数据),也始终返回连续的带内和带外数据。
write_page_raw
用于写入没有 ECC 的原始页面的函数。此函数应隐藏 ECC 控制器使用的特定布局,并将传递的数据视为连续的带内和带外数据。ECC 控制器负责进行适当的转换以适应其特定布局(例如,NAND_ECC_PLACEMENT_INTERLEAVED 交错带内和带外数据)。
read_page
根据 ECC 生成器要求读取页面的函数;返回任何单个 ECC 步骤中校正的最大位翻转次数,-EIO 硬件错误
read_subpage
用于读取 ECC 覆盖的页面的部分的函数;返回与 read_page() 相同的值
write_subpage
用于写入 ECC 覆盖的页面的部分的函数。
write_page
根据 ECC 生成器要求写入页面的函数。
write_oob_raw
用于写入没有 ECC 的芯片 OOB 数据的函数
read_oob_raw
用于读取没有 ECC 的芯片 OOB 数据的函数
read_oob
用于读取芯片 OOB 数据的函数
write_oob
用于写入芯片 OOB 数据的函数
-
struct nand_sdr_timings¶
SDR NAND 芯片时序
定义:
struct nand_sdr_timings {
u64 tBERS_max;
u32 tCCS_min;
u64 tPROG_max;
u64 tR_max;
u32 tALH_min;
u32 tADL_min;
u32 tALS_min;
u32 tAR_min;
u32 tCEA_max;
u32 tCEH_min;
u32 tCH_min;
u32 tCHZ_max;
u32 tCLH_min;
u32 tCLR_min;
u32 tCLS_min;
u32 tCOH_min;
u32 tCS_min;
u32 tDH_min;
u32 tDS_min;
u32 tFEAT_max;
u32 tIR_min;
u32 tITC_max;
u32 tRC_min;
u32 tREA_max;
u32 tREH_min;
u32 tRHOH_min;
u32 tRHW_min;
u32 tRHZ_max;
u32 tRLOH_min;
u32 tRP_min;
u32 tRR_min;
u64 tRST_max;
u32 tWB_max;
u32 tWC_min;
u32 tWH_min;
u32 tWHR_min;
u32 tWP_min;
u32 tWW_min;
};
成员
tBERS_max
块擦除时间
tCCS_min
更改列设置时间
tPROG_max
页面编程时间
tR_max
页面读取时间
tALH_min
ALE 保持时间
tADL_min
ALE 到数据加载时间
tALS_min
ALE 设置时间
tAR_min
ALE 到 RE# 延迟
tCEA_max
CE# 访问时间
tCEH_min
CE# 高电平保持时间
tCH_min
CE# 保持时间
tCHZ_max
CE# 高电平到输出高阻抗
tCLH_min
CLE 保持时间
tCLR_min
CLE 到 RE# 延迟
tCLS_min
CLE 设置时间
tCOH_min
CE# 高电平到输出保持
tCS_min
CE# 设置时间
tDH_min
数据保持时间
tDS_min
数据设置时间
tFEAT_max
设置功能和获取功能的忙碌时间
tIR_min
输出高阻抗到 RE# 低电平
tITC_max
接口和定时模式更改时间
tRC_min
RE# 周期时间
tREA_max
RE# 访问时间
tREH_min
RE# 高电平保持时间
tRHOH_min
RE# 高电平到输出保持
tRHW_min
RE# 高电平到 WE# 低电平
tRHZ_max
RE# 高电平到输出高阻抗
tRLOH_min
RE# 低电平到输出保持
tRP_min
RE# 脉冲宽度
tRR_min
就绪到 RE# 低电平(仅限数据)
tRST_max
设备复位时间,从 R/B# 的下降沿到 R/B# 的上升沿测量。
tWB_max
WE# 高电平到 SR[6] 低电平
tWC_min
WE# 周期时间
tWH_min
WE# 高电平保持时间
tWHR_min
WE# 高电平到 RE# 低电平
tWP_min
WE# 脉冲宽度
tWW_min
WP# 过渡到 WE# 低电平
描述
此结构定义了 SDR NAND 芯片的时序要求。这些信息可以在每个 NAND 数据表中找到,并且时序的含义在 ONFI 规范中进行了描述:https://media-www.micron.com/-/media/client/onfi/specs/onfi_3_1_spec.pdf(第 4.15 章 时序参数)
所有这些时序均以皮秒表示。
-
struct nand_nvddr_timings¶
NV-DDR NAND 芯片时序
定义:
struct nand_nvddr_timings {
u64 tBERS_max;
u32 tCCS_min;
u64 tPROG_max;
u64 tR_max;
u32 tAC_min;
u32 tAC_max;
u32 tADL_min;
u32 tCAD_min;
u32 tCAH_min;
u32 tCALH_min;
u32 tCALS_min;
u32 tCAS_min;
u32 tCEH_min;
u32 tCH_min;
u32 tCK_min;
u32 tCS_min;
u32 tDH_min;
u32 tDQSCK_min;
u32 tDQSCK_max;
u32 tDQSD_min;
u32 tDQSD_max;
u32 tDQSHZ_max;
u32 tDQSQ_max;
u32 tDS_min;
u32 tDSC_min;
u32 tFEAT_max;
u32 tITC_max;
u32 tQHS_max;
u32 tRHW_min;
u32 tRR_min;
u32 tRST_max;
u32 tWB_max;
u32 tWHR_min;
u32 tWRCK_min;
u32 tWW_min;
};
成员
tBERS_max
块擦除时间
tCCS_min
更改列设置时间
tPROG_max
页面编程时间
tR_max
页面读取时间
tAC_min
从 CLK 开始的 DQ[7:0] 的访问窗口
tAC_max
从 CLK 开始的 DQ[7:0] 的访问窗口
tADL_min
ALE 到数据加载时间
tCAD_min
命令、地址、数据延迟
tCAH_min
命令/地址 DQ 保持时间
tCALH_min
W/R_n、CLE 和 ALE 保持时间
tCALS_min
W/R_n、CLE 和 ALE 设置时间
tCAS_min
命令/地址 DQ 设置时间
tCEH_min
CE# 高电平保持时间
tCH_min
CE# 保持时间
tCK_min
平均时钟周期时间
tCS_min
CE# 设置时间
tDH_min
数据保持时间
tDQSCK_min
从 CLK 开始的 DQS 的访问窗口开始
tDQSCK_max
从 CLK 开始的 DQS 的访问窗口结束
tDQSD_min
由设备驱动的最小 W/R_n 低电平到 DQS/DQ
tDQSD_max
由设备驱动的最大 W/R_n 低电平到 DQS/DQ
tDQSHZ_max
由设备驱动的 W/R_n 高电平到 DQS/DQ 三态
tDQSQ_max
DQS-DQ 偏移,DQS 到最后一个有效的 DQ,每次访问
tDS_min
数据设置时间
tDSC_min
DQS 周期时间
tFEAT_max
设置功能和获取功能的忙碌时间
tITC_max
接口和定时模式更改时间
tQHS_max
数据保持偏移系数
tRHW_min
数据输出周期到命令、地址或数据输入周期
tRR_min
就绪到 RE# 低电平(仅限数据)
tRST_max
设备复位时间,从 R/B# 的下降沿到 R/B# 的上升沿测量。
tWB_max
WE# 高电平到 SR[6] 低电平
tWHR_min
WE# 高电平到 RE# 低电平
tWRCK_min
W/R_n 低电平到数据输出周期
tWW_min
WP# 过渡到 WE# 低电平
描述
此结构定义了 NV-DDR NAND 数据接口的时序要求。这些信息可以在每个 NAND 数据表中找到,并且时序的含义在 ONFI 规范中进行了描述:https://media-www.micron.com/-/media/client/onfi/specs/onfi_4_1_gold.pdf(第 4.18.2 章 NV-DDR)
所有这些时序均以皮秒表示。
-
enum nand_interface_type¶
NAND 接口类型
常量
NAND_SDR_IFACE
单数据速率接口
NAND_NVDDR_IFACE
双倍数据速率接口
-
struct nand_interface_config¶
NAND 接口时序
定义:
struct nand_interface_config {
enum nand_interface_type type;
struct nand_timings {
unsigned int mode;
union {
struct nand_sdr_timings sdr;
struct nand_nvddr_timings nvddr;
};
} timings;
};
成员
type
时序类型
timings
时序信息
timings.mode
规范中定义的时序模式
{unnamed_union}
匿名
timings.sdr
当 type 为
NAND_SDR_IFACE
时使用它。timings.nvddr
当 type 为
NAND_NVDDR_IFACE
时使用它。
-
bool nand_interface_is_sdr(const struct nand_interface_config *conf)¶
获取接口类型
参数
const struct nand_interface_config *conf
数据接口
-
bool nand_interface_is_nvddr(const struct nand_interface_config *conf)¶
获取接口类型
参数
const struct nand_interface_config *conf
数据接口
-
const struct nand_sdr_timings *nand_get_sdr_timings(const struct nand_interface_config *conf)¶
从数据接口获取 SDR 时序
参数
const struct nand_interface_config *conf
数据接口
-
const struct nand_nvddr_timings *nand_get_nvddr_timings(const struct nand_interface_config *conf)¶
从数据接口获取 NV-DDR 时序
参数
const struct nand_interface_config *conf
数据接口
-
struct nand_op_cmd_instr¶
命令指令的定义
定义:
struct nand_op_cmd_instr {
u8 opcode;
};
成员
opcode
在一个周期内发出的命令
-
struct nand_op_addr_instr¶
地址指令的定义
定义:
struct nand_op_addr_instr {
unsigned int naddrs;
const u8 *addrs;
};
成员
naddrs
addrs 数组的长度
addrs
包含要发出的地址周期的数组
-
struct nand_op_data_instr¶
数据指令的定义
定义:
struct nand_op_data_instr {
unsigned int len;
union {
void *in;
const void *out;
} buf;
bool force_8bit;
};
成员
len
要移动的数据字节数
buf
要填充的缓冲区
buf.in
从 NAND 芯片读取时要填充的缓冲区
buf.out
写入 NAND 芯片时要读取的缓冲区
force_8bit
强制 8 位访问
描述
请注意,“in”和“out”与 ONFI 规范相反,是从控制器角度来看的,因此“in”是从 NAND 芯片读取,“out”是写入 NAND 芯片。
-
struct nand_op_waitrdy_instr¶
等待就绪指令的定义
定义:
struct nand_op_waitrdy_instr {
unsigned int timeout_ms;
};
成员
timeout_ms
等待就绪/忙引脚的最大延迟(以毫秒为单位)
-
enum nand_op_instr_type¶
所有指令类型的定义
常量
NAND_OP_CMD_INSTR
命令指令
NAND_OP_ADDR_INSTR
地址指令
NAND_OP_DATA_IN_INSTR
数据输入指令
NAND_OP_DATA_OUT_INSTR
数据输出指令
NAND_OP_WAITRDY_INSTR
等待就绪指令
-
struct nand_op_instr¶
指令对象
定义:
struct nand_op_instr {
enum nand_op_instr_type type;
union {
struct nand_op_cmd_instr cmd;
struct nand_op_addr_instr addr;
struct nand_op_data_instr data;
struct nand_op_waitrdy_instr waitrdy;
} ctx;
unsigned int delay_ns;
};
成员
type
指令类型
ctx
与指令关联的额外数据。您必须根据 **type** 使用适当的元素
ctx.cmd
如果 **type** 为
NAND_OP_CMD_INSTR
,则使用此项ctx.addr
如果 **type** 为
NAND_OP_ADDR_INSTR
,则使用此项ctx.data
如果 **type** 为
NAND_OP_DATA_IN_INSTR
或NAND_OP_DATA_OUT_INSTR
,则使用此项ctx.waitrdy
如果 **type** 为
NAND_OP_WAITRDY_INSTR
,则使用此项delay_ns
在总线上发出指令后,控制器应应用的延迟。大多数现代控制器都具有内部时序控制逻辑,在这种情况下,控制器驱动程序可以忽略此字段。
-
struct nand_subop¶
子操作
定义:
struct nand_subop {
unsigned int cs;
const struct nand_op_instr *instrs;
unsigned int ninstrs;
unsigned int first_instr_start_off;
unsigned int last_instr_end_off;
};
成员
cs
为此 NAND 子操作选择的 CS 线
instrs
指令数组
ninstrs
instrs 数组的长度
first_instr_start_off
子操作的第一条指令的起始偏移量
last_instr_end_off
子操作的最后一条指令的结束偏移量(不包括在内)
描述
**first_instr_start_off** 和 **last_instr_end_off** 仅适用于数据或地址指令。
当 NAND 控制器无法按原样处理操作时,解析器会将其拆分为子操作,并将子操作传递给控制器驱动程序。
-
struct nand_op_parser_addr_constraints¶
地址指令的约束
定义:
struct nand_op_parser_addr_constraints {
unsigned int maxcycles;
};
成员
maxcycles
控制器在单个步骤中可以发出的最大地址周期数
-
struct nand_op_parser_data_constraints¶
数据指令的约束
定义:
struct nand_op_parser_data_constraints {
unsigned int maxlen;
};
成员
maxlen
控制器在单个步骤中可以处理的最大数据长度
-
struct nand_op_parser_pattern_elem¶
模式的一个元素
定义:
struct nand_op_parser_pattern_elem {
enum nand_op_instr_type type;
bool optional;
union {
struct nand_op_parser_addr_constraints addr;
struct nand_op_parser_data_constraints data;
} ctx;
};
成员
type
指令类型
optional
模式的此元素是可选的还是强制的
ctx
地址或数据约束
ctx.addr
地址约束(周期数)
ctx.data
数据约束(数据长度)
-
struct nand_op_parser_pattern¶
NAND 子操作模式描述符
定义:
struct nand_op_parser_pattern {
const struct nand_op_parser_pattern_elem *elems;
unsigned int nelems;
int (*exec)(struct nand_chip *chip, const struct nand_subop *subop);
};
成员
elems
模式元素数组
nelems
elems 数组中模式元素的数量
exec
将发出子操作的函数
描述
模式是元素的列表,每个元素代表一条指令及其约束。模式本身由核心使用,以将 NAND 芯片操作与 NAND 控制器操作进行匹配。一旦找到 NAND 控制器操作模式和 NAND 芯片操作(或 NAND 操作的子集)之间的匹配项,则会调用 pattern ->exec() 钩子,以便控制器驱动程序可以在总线上发出操作。
控制器驱动程序应声明其支持的尽可能多的模式,并将此模式列表(在以下宏的帮助下创建)传递给 nand_op_parser_exec_op()
帮助程序。
-
struct nand_op_parser¶
NAND 控制器操作解析器描述符
定义:
struct nand_op_parser {
const struct nand_op_parser_pattern *patterns;
unsigned int npatterns;
};
成员
patterns
支持的模式数组
npatterns
patterns 数组的长度
描述
解析器描述符只是一个支持的模式数组,每次尝试执行 NAND 操作时(或尝试确定是否支持特定操作时),nand_op_parser_exec_op()
都会迭代该数组。
值得一提的是,将按照声明顺序测试模式,并将采用第一个匹配项,因此务必适当排序模式,以便将简单/低效的模式放在列表末尾。通常,这是放置单指令模式的位置。
-
struct nand_operation¶
NAND 操作描述符
定义:
struct nand_operation {
unsigned int cs;
bool deassert_wp;
const struct nand_op_instr *instrs;
unsigned int ninstrs;
};
成员
cs
为此 NAND 操作选择的 CS 线
deassert_wp
当操作需要取消置位 WP 引脚时设置为 true(擦除、编程等)
instrs
要执行的指令数组
ninstrs
instrs 数组的长度
描述
将传递给 chip->exec_op() 的实际操作结构。
-
struct nand_controller_ops¶
控制器操作
定义:
struct nand_controller_ops {
int (*attach_chip)(struct nand_chip *chip);
void (*detach_chip)(struct nand_chip *chip);
int (*exec_op)(struct nand_chip *chip,const struct nand_operation *op, bool check_only);
int (*setup_interface)(struct nand_chip *chip, int chipnr, const struct nand_interface_config *conf);
};
成员
attach_chip
此方法在 NAND 检测阶段之后,在设置了闪存 ID 和 MTD 字段(如擦除大小、页面大小和 OOB 大小)之后调用。如果 NAND 芯片或设备树提供了 ECC 要求,则可以使用。通常用于选择适当的 ECC 配置并分配关联的资源。此钩子是可选的。
detach_chip
释放 nand_controller_ops->attach_chip() 中分配/声明的所有资源。此钩子是可选的。
exec_op
执行 NAND 操作的特定于控制器的方法。此方法替换 chip->legacy.cmdfunc()、chip->legacy.{read,write}_{buf,byte,word}()、chip->legacy.dev_ready() 和 chip->legacy.waitfunc()。
setup_interface
设置数据接口和时序。如果 chipnr 设置为
NAND_DATA_IFACE_CHECK_ONLY
,则表示不应应用配置,而仅应进行检查。此挂钩是可选的。
-
struct nand_controller¶
用于描述 NAND 控制器的结构
定义:
struct nand_controller {
struct mutex lock;
const struct nand_controller_ops *ops;
struct {
unsigned int data_only_read: 1;
unsigned int cont_read: 1;
} supported_op;
bool controller_wp;
};
成员
lock
用于序列化对 NAND 控制器的访问的锁
ops
NAND 控制器操作。
supported_op
NAND 控制器已知支持的操作,仅在初始检查后由核心写入。
supported_op.data_only_read
控制器支持从总线上读取更多数据,而无需重新启动整个读取操作或更改列。
supported_op.cont_read
控制器支持顺序缓存读取。
controller_wp
控制器负责处理 WP 引脚。
-
struct nand_legacy¶
NAND 芯片的旧式字段/挂钩
定义:
struct nand_legacy {
void __iomem *IO_ADDR_R;
void __iomem *IO_ADDR_W;
void (*select_chip)(struct nand_chip *chip, int cs);
u8 (*read_byte)(struct nand_chip *chip);
void (*write_byte)(struct nand_chip *chip, u8 byte);
void (*write_buf)(struct nand_chip *chip, const u8 *buf, int len);
void (*read_buf)(struct nand_chip *chip, u8 *buf, int len);
void (*cmd_ctrl)(struct nand_chip *chip, int dat, unsigned int ctrl);
void (*cmdfunc)(struct nand_chip *chip, unsigned command, int column, int page_addr);
int (*dev_ready)(struct nand_chip *chip);
int (*waitfunc)(struct nand_chip *chip);
int (*block_bad)(struct nand_chip *chip, loff_t ofs);
int (*block_markbad)(struct nand_chip *chip, loff_t ofs);
int (*set_features)(struct nand_chip *chip, int feature_addr, u8 *subfeature_para);
int (*get_features)(struct nand_chip *chip, int feature_addr, u8 *subfeature_para);
int chip_delay;
struct nand_controller dummy_controller;
};
成员
IO_ADDR_R
读取闪存设备 8 条 I/O 线的地址
IO_ADDR_W
写入闪存设备 8 条 I/O 线的地址
select_chip
选择/取消选择特定的目标/die
read_byte
从芯片读取一个字节
write_byte
在低 8 条 I/O 线上向芯片写入单个字节
write_buf
将缓冲区中的数据写入芯片
read_buf
将数据从芯片读取到缓冲区中
cmd_ctrl
用于控制 ALE/CLE/nCE 的硬件特定功能。也用于写入命令和地址
cmdfunc
用于向芯片写入命令的硬件特定功能。
dev_ready
用于访问设备就绪/忙碌线的硬件特定功能。如果设置为 NULL,则无法访问就绪/忙碌信息,并且就绪/忙碌信息从芯片状态寄存器读取。
waitfunc
用于等待就绪的硬件特定功能。
block_bad
使用 OOB 标记检查块是否损坏
block_markbad
标记一个坏块
set_features
设置 NAND 芯片特性
get_features
获取 NAND 芯片特性
chip_delay
用于将数据从阵列传输到读取寄存器 (tR) 的芯片相关延迟。
dummy_controller
用于只能控制单个芯片的驱动程序的虚拟控制器实现
描述
如果你正在看这个结构,那你已经错了。这些字段/挂钩都已弃用。
-
struct nand_chip_ops¶
NAND 芯片操作
定义:
struct nand_chip_ops {
int (*suspend)(struct nand_chip *chip);
void (*resume)(struct nand_chip *chip);
int (*lock_area)(struct nand_chip *chip, loff_t ofs, uint64_t len);
int (*unlock_area)(struct nand_chip *chip, loff_t ofs, uint64_t len);
int (*setup_read_retry)(struct nand_chip *chip, int retry_mode);
int (*choose_interface_config)(struct nand_chip *chip, struct nand_interface_config *iface);
};
成员
suspend
挂起操作
resume
恢复操作
lock_area
锁定操作
unlock_area
解锁操作
setup_read_retry
设置读取重试模式(主要用于 MLC NAND)
choose_interface_config
选择最佳的接口配置
-
struct nand_manufacturer¶
NAND 制造商结构
定义:
struct nand_manufacturer {
const struct nand_manufacturer_desc *desc;
void *priv;
};
成员
desc
制造商描述
priv
制造商驱动程序的私有信息
-
struct nand_secure_region¶
NAND 安全区域结构
定义:
struct nand_secure_region {
u64 offset;
u64 size;
};
成员
offset
安全区域的起始偏移量
size
安全区域的大小
-
struct nand_chip¶
NAND 私有闪存芯片数据
定义:
struct nand_chip {
struct nand_device base;
struct nand_id id;
struct nand_parameters parameters;
struct nand_manufacturer manufacturer;
struct nand_chip_ops ops;
struct nand_legacy legacy;
unsigned int options;
const struct nand_interface_config *current_interface_config;
struct nand_interface_config *best_interface_config;
unsigned int bbt_erase_shift;
unsigned int bbt_options;
unsigned int badblockpos;
unsigned int badblockbits;
struct nand_bbt_descr *bbt_td;
struct nand_bbt_descr *bbt_md;
struct nand_bbt_descr *badblock_pattern;
u8 *bbt;
unsigned int page_shift;
unsigned int phys_erase_shift;
unsigned int chip_shift;
unsigned int pagemask;
unsigned int subpagesize;
u8 *data_buf;
u8 *oob_poi;
struct {
unsigned int bitflips;
int page;
} pagecache;
unsigned long buf_align;
struct mutex lock;
unsigned int suspended : 1;
wait_queue_head_t resume_wq;
int cur_cs;
int read_retries;
struct nand_secure_region *secure_regions;
u8 nr_secure_regions;
struct {
bool ongoing;
unsigned int first_page;
unsigned int pause_page;
unsigned int last_page;
} cont_read;
struct nand_controller *controller;
struct nand_ecc_ctrl ecc;
void *priv;
};
成员
base
继承自通用 NAND 设备
id
保存 NAND ID
parameters
以易于阅读的形式保存通用参数
manufacturer
制造商信息
ops
NAND 芯片操作
legacy
所有旧式字段/挂钩。如果你开发新的驱动程序,甚至不要尝试使用这些字段/挂钩,如果你正在修改使用这些字段/挂钩的现有驱动程序,你应该考虑重构该驱动程序并避免使用它们。
options
各种芯片选项。可以部分设置它们以通知 nand_scan 关于特殊功能。请参阅定义以了解更多说明。
current_interface_config
当前使用的 NAND 接口配置
best_interface_config
最适合 NAND 芯片和 NAND 控制器约束的最佳 NAND 接口配置。如果未设置,则必须使用默认的重置接口配置。
bbt_erase_shift
bbt 条目中的地址位数
bbt_options
坏块表特定选项。此处使用的所有选项都必须来自 bbm.h。默认情况下,这些选项将复制到相应的 nand_bbt_descr 中。
badblockpos
oob 区域中的坏块标记位置
badblockbits
良好块的坏块标记位置中的最小设置位数;即,当 badblockbits = 7 时,BBM = 11110111b 是好的
bbt_td
用于闪存查找的坏块表描述符
bbt_md
坏块表镜像描述符
badblock_pattern
用于初始坏块扫描的坏块扫描模式
bbt
坏块表指针
page_shift
页面中的地址位数(列地址位数)
phys_erase_shift
物理擦除块中的地址位数
chip_shift
一个芯片中的地址位数
pagemask
页面编号掩码 = (页面数 / 芯片数) - 1
subpagesize
保存子页面大小
data_buf
用于数据的缓冲区,大小为 (页面大小 + oobsize)
oob_poi
数据缓冲区覆盖的 OOB 区域的指针
pagecache
包含页面缓存相关字段的结构
pagecache.bitflips
缓存页面的位翻转次数
pagecache.page
当前缓存在缓存中的页面编号。-1 表示当前没有缓存页面
buf_align
平台所需的最小缓冲区对齐
lock
保护挂起字段的锁。也用于序列化对 NAND 设备的访问
suspended
当设备挂起时设置为 1,未挂起时设置为 0
resume_wq
如果 rawnand 处于挂起状态,则等待睡眠的等待队列。
cur_cs
当前选定的目标。-1 表示未选择任何目标,否则我们应该始终具有 cur_cs >= 0 && cur_cs < nanddev_ntargets()。NAND 控制器驱动程序不应修改此值,但允许读取它。
read_retries
支持的读取重试模式的数量
secure_regions
包含安全区域信息的结构
nr_secure_regions
安全区域的数量
cont_read
顺序页面读取内部
cont_read.ongoing
是否正在进行连续读取
cont_read.first_page
连续读取操作的开始
cont_read.pause_page
当前顺序缓存读取操作的结束
cont_read.last_page
连续读取操作的结束
controller
在多个独立设备之间共享的硬件控制器结构
ecc
ECC 控制器结构
priv
芯片私有数据
-
const struct nand_interface_config *nand_get_interface_config(struct nand_chip *chip)¶
检索 NAND 芯片的当前接口配置
参数
struct nand_chip *chip
NAND 芯片
-
struct nand_flash_dev¶
NAND 闪存设备 ID 结构
定义:
struct nand_flash_dev {
char *name;
union {
struct {
uint8_t mfr_id;
uint8_t dev_id;
};
uint8_t id[NAND_MAX_ID_LEN];
};
unsigned int pagesize;
unsigned int chipsize;
unsigned int erasesize;
unsigned int options;
uint16_t id_len;
uint16_t oobsize;
struct {
uint16_t strength_ds;
uint16_t step_ds;
} ecc;
};
成员
name
NAND 芯片的人可读名称
{unnamed_union}
匿名
{unnamed_struct}
匿名
mfr_id
完整芯片 ID 数组的制造商 ID 部分(与
id[0]
引用相同的内存地址)dev_id
完整芯片 ID 数组的设备 ID 部分(与
id[1]
引用相同的内存地址)id
完整设备 ID 数组
pagesize
NAND 页面的大小(以字节为单位);如果为 0,则实际页面大小(以及擦除块大小)由扩展 NAND 芯片 ID 数组确定)
chipsize
总芯片大小(以 MiB 为单位)
erasesize
擦除块大小(以字节为单位)(如果为 0,则从扩展 ID 确定)
options
存储各种芯片位选项
id_len
id 的有效长度。
oobsize
OOB 大小
ecc
来自数据手册的 ECC 可纠正性和步长信息。
ecc.strength_ds
来自数据手册的 ECC 可纠正性,与 nand_chip{} 中的 ecc_strength_ds 相同。
ecc.step_ds
ecc.strength_ds 所需的 ECC 步长,与 nand_chip{} 中的 ecc_step_ds 相同,也来自数据手册。例如,“每个 512 字节 4 位 ECC”可以使用 NAND_ECC_INFO(4, 512) 设置。
-
int nand_opcode_8bits(unsigned int command)¶
检查操作码的地址是否应该只在低 8 位上发送
参数
unsigned int command
要检查的操作码
参数
struct nand_chip *chip
NAND 芯片对象
描述
返回使缓存失效后预先分配的页面缓冲区。驱动程序不想分配自己的反弹缓冲区,并且仍然需要此类缓冲区进行特定操作(最常见的是仅读取 OOB 数据时),则应使用此函数。
请注意,永远不要在写入/write_oob 路径中调用此函数,因为核心可能已将要写出的数据放置在此缓冲区中。
返回
指向页面缓存缓冲区的指针
提供的公共函数¶
本章节包含导出的 NAND 内核 API 函数的自动生成文档。每个函数都有一个简短的描述,并用 [XXX] 标识符标记。有关说明,请参阅“文档提示”章节。
-
void nand_extract_bits(u8 *dst, unsigned int dst_off, const u8 *src, unsigned int src_off, unsigned int nbits)¶
将未对齐的位从一个缓冲区复制到另一个缓冲区
参数
u8 *dst
目标缓冲区
unsigned int dst_off
写入开始的位偏移量
const u8 *src
源缓冲区
unsigned int src_off
读取开始的位偏移量
unsigned int nbits
要从 src 复制到 dst 的位数
描述
将位从一个内存区域复制到另一个内存区域(允许重叠)。
参数
struct nand_chip *chip
NAND 芯片对象
unsigned int cs
要选择的 CS 线。请注意,此 CS ID 始终来自芯片的 PoV,而不是控制器的 PoV
描述
选择一个 NAND 目标,以便对 chip 执行的进一步操作转到所选的 NAND 目标。
参数
struct nand_chip *chip
NAND 芯片对象
描述
取消选择当前选定的 NAND 目标。在取消选择目标后对 chip 执行的操作的结果是未定义的。
-
int nand_soft_waitrdy(struct nand_chip *chip, unsigned long timeout_ms)¶
轮询 STATUS 寄存器,直到 RDY 位设置为 1
参数
struct nand_chip *chip
NAND 芯片结构
unsigned long timeout_ms
超时时间,以毫秒为单位
描述
使用 ->exec_op() 轮询 STATUS 寄存器,直到 RDY 位变为 1。如果未在指定的超时时间内发生,则返回 -ETIMEDOUT。
此助手旨在当控制器无法访问 NAND R/B 引脚时使用。
请注意,从 ->exec_op() 实现中调用此助手意味着 ->exec_op() 必须是可重入的。
如果 NAND 芯片准备就绪,则返回 0,否则返回负错误。
-
int nand_gpio_waitrdy(struct nand_chip *chip, struct gpio_desc *gpiod, unsigned long timeout_ms)¶
轮询 R/B GPIO 引脚,直到准备就绪
参数
struct nand_chip *chip
NAND 芯片结构
struct gpio_desc *gpiod
R/B 引脚的 GPIO 描述符
unsigned long timeout_ms
超时时间,以毫秒为单位
描述
轮询 R/B GPIO 引脚,直到它准备就绪。如果未在指定的超时时间内发生,则返回 -ETIMEDOUT。
此助手旨在当控制器通过 GPIO 访问 NAND R/B 引脚时使用。
如果 R/B 引脚指示芯片已准备就绪,则返回 0,否则返回负错误。
-
int nand_read_page_op(struct nand_chip *chip, unsigned int page, unsigned int offset_in_page, void *buf, unsigned int len)¶
执行 READ PAGE 操作
参数
struct nand_chip *chip
NAND 芯片
unsigned int page
要读取的页
unsigned int offset_in_page
页内的偏移量
void *buf
用于存储数据的缓冲区
unsigned int len
缓冲区的长度
描述
此函数发出 READ PAGE 操作。此函数不选择/取消选择 CS 线。
成功返回 0,否则返回负错误代码。
-
int nand_change_read_column_op(struct nand_chip *chip, unsigned int offset_in_page, void *buf, unsigned int len, bool force_8bit)¶
执行 CHANGE READ COLUMN 操作
参数
struct nand_chip *chip
NAND 芯片
unsigned int offset_in_page
页内的偏移量
void *buf
用于存储数据的缓冲区
unsigned int len
缓冲区的长度
bool force_8bit
强制 8 位总线访问
描述
此函数发出 CHANGE READ COLUMN 操作。此函数不选择/取消选择 CS 线。
成功返回 0,否则返回负错误代码。
-
int nand_read_oob_op(struct nand_chip *chip, unsigned int page, unsigned int offset_in_oob, void *buf, unsigned int len)¶
执行 READ OOB 操作
参数
struct nand_chip *chip
NAND 芯片
unsigned int page
要读取的页
unsigned int offset_in_oob
OOB 区域内的偏移量
void *buf
用于存储数据的缓冲区
unsigned int len
缓冲区的长度
描述
此函数发出 READ OOB 操作。此函数不选择/取消选择 CS 线。
成功返回 0,否则返回负错误代码。
-
int nand_prog_page_begin_op(struct nand_chip *chip, unsigned int page, unsigned int offset_in_page, const void *buf, unsigned int len)¶
启动 PROG PAGE 操作
参数
struct nand_chip *chip
NAND 芯片
unsigned int page
要写入的页
unsigned int offset_in_page
页内的偏移量
const void *buf
包含要写入页的数据的缓冲区
unsigned int len
缓冲区的长度
描述
此函数发出 PROG PAGE 操作的前半部分。此函数不选择/取消选择 CS 线。
成功返回 0,否则返回负错误代码。
参数
struct nand_chip *chip
NAND 芯片
描述
此函数发出 PROG PAGE 操作的后半部分。此函数不选择/取消选择 CS 线。
成功返回 0,否则返回负错误代码。
-
int nand_prog_page_op(struct nand_chip *chip, unsigned int page, unsigned int offset_in_page, const void *buf, unsigned int len)¶
执行完整的 PROG PAGE 操作
参数
struct nand_chip *chip
NAND 芯片
unsigned int page
要写入的页
unsigned int offset_in_page
页内的偏移量
const void *buf
包含要写入页的数据的缓冲区
unsigned int len
缓冲区的长度
描述
此函数执行完整的 PROG PAGE 操作。此函数不选择/取消选择 CS 线。
成功返回 0,否则返回负错误代码。
-
int nand_change_write_column_op(struct nand_chip *chip, unsigned int offset_in_page, const void *buf, unsigned int len, bool force_8bit)¶
执行 CHANGE WRITE COLUMN 操作
参数
struct nand_chip *chip
NAND 芯片
unsigned int offset_in_page
页内的偏移量
const void *buf
包含要发送到 NAND 的数据的缓冲区
unsigned int len
缓冲区的长度
bool force_8bit
强制 8 位总线访问
描述
此函数执行 CHANGE WRITE COLUMN 操作。此函数不选择/取消选择 CS 线。
成功返回 0,否则返回负错误代码。
参数
struct nand_chip *chip
NAND 芯片
u8 addr
在 READID 命令之后传递的地址周期
void *buf
用于存储 ID 的缓冲区
unsigned int len
缓冲区的长度
描述
此函数发送 READID 命令并读取 NAND 返回的 ID。此函数不选择/取消选择 CS 线。
成功返回 0,否则返回负错误代码。
参数
struct nand_chip *chip
NAND 芯片
u8 *status
用于存储 NAND 状态的输出变量
描述
此函数发送 STATUS 命令并读取 NAND 返回的状态。此函数不选择/取消选择 CS 线。
成功返回 0,否则返回负错误代码。
参数
struct nand_chip *chip
NAND 芯片
描述
此函数发送 READ0 命令以取消 STATUS 命令的效果,从而避免在发送新的读取命令之前只读取状态。
此函数不选择/取消选择 CS 线。
成功返回 0,否则返回负错误代码。
参数
struct nand_chip *chip
NAND 芯片
unsigned int eraseblock
要擦除的块
描述
此函数发送 ERASE 命令并等待 NAND 准备就绪后返回。此函数不选择/取消选择 CS 线。
成功返回 0,否则返回负错误代码。
参数
struct nand_chip *chip
NAND 芯片
描述
此函数发送 RESET 命令并等待 NAND 准备就绪后返回。此函数不选择/取消选择 CS 线。
成功返回 0,否则返回负错误代码。
-
int nand_read_data_op(struct nand_chip *chip, void *buf, unsigned int len, bool force_8bit, bool check_only)¶
从 NAND 读取数据
参数
struct nand_chip *chip
NAND 芯片
void *buf
用于存储数据的缓冲区
unsigned int len
缓冲区的长度
bool force_8bit
强制 8 位总线访问
bool check_only
不实际运行该命令,仅检查控制器驱动程序是否支持它
描述
此函数在总线上执行原始数据读取。通常在启动另一个 NAND 操作(如 nand_read_page_op()
)后使用。此函数不选择/取消选择 CS 线。
成功返回 0,否则返回负错误代码。
-
int nand_write_data_op(struct nand_chip *chip, const void *buf, unsigned int len, bool force_8bit)¶
从 NAND 写入数据
参数
struct nand_chip *chip
NAND 芯片
const void *buf
包含要在总线上发送的数据的缓冲区
unsigned int len
缓冲区的长度
bool force_8bit
强制 8 位总线访问
描述
此函数在总线上执行原始数据写入。通常在启动另一个 NAND 操作(如 nand_write_page_begin_op())后使用。此函数不选择/取消选择 CS 线。
成功返回 0,否则返回负错误代码。
-
int nand_op_parser_exec_op(struct nand_chip *chip, const struct nand_op_parser *parser, const struct nand_operation *op, bool check_only)¶
exec_op 解析器
参数
struct nand_chip *chip
NAND 芯片
const struct nand_op_parser *parser
控制器驱动程序提供的模式描述
const struct nand_operation *op
要处理的 NAND 操作
bool check_only
为 true 时,该函数仅检查是否可以处理 op,但不执行该操作
描述
辅助函数,旨在简化仅支持有限指令序列的 NAND 控制器驱动程序的集成。支持的序列在 parser 中描述,如果 check_only 设置为 false,则框架会负责将 op 拆分为多个子操作,并将其传递回匹配模式的 ->exec() 回调。
NAND 控制器驱动程序应从其自身的 ->exec_op() 实现中调用此函数。
成功时返回 0,否则返回负错误代码。失败可能是由于不支持的操作(没有一个支持的模式能够处理请求的操作),或者由匹配模式的 ->exec() 挂钩返回的错误引起的。
-
unsigned int nand_subop_get_addr_start_off(const struct nand_subop *subop, unsigned int instr_idx)¶
获取地址数组中的起始偏移量
参数
const struct nand_subop *subop
整个子操作
unsigned int instr_idx
子操作内部的指令索引
描述
在驱动程序开发过程中,可能会倾向于直接使用地址指令的 ->addr.addrs 字段。这是错误的,因为地址指令可能会被拆分。
给定一个地址指令,返回要发出的第一个周期的偏移量。
-
unsigned int nand_subop_get_num_addr_cyc(const struct nand_subop *subop, unsigned int instr_idx)¶
获取要断言的剩余地址周期数
参数
const struct nand_subop *subop
整个子操作
unsigned int instr_idx
子操作内部的指令索引
描述
在驱动程序开发过程中,可能会倾向于直接使用数据指令的 ->addr->naddrs 字段。这是错误的,因为指令可能会被拆分。
给定一个地址指令,返回要发出的地址周期数。
-
unsigned int nand_subop_get_data_start_off(const struct nand_subop *subop, unsigned int instr_idx)¶
获取数据数组中的起始偏移量
参数
const struct nand_subop *subop
整个子操作
unsigned int instr_idx
子操作内部的指令索引
描述
在驱动程序开发过程中,可能会倾向于直接使用数据指令的 ->data->buf.{in,out} 字段。这是错误的,因为数据指令可能会被拆分。
给定一个数据指令,返回要开始的偏移量。
-
unsigned int nand_subop_get_data_len(const struct nand_subop *subop, unsigned int instr_idx)¶
获取要检索的字节数
参数
const struct nand_subop *subop
整个子操作
unsigned int instr_idx
子操作内部的指令索引
描述
在驱动程序开发过程中,可能会倾向于直接使用数据指令的 ->data->len 字段。这是错误的,因为数据指令可能会被拆分。
返回要发送/接收的数据块的长度。
参数
struct nand_chip *chip
NAND 芯片
int chipnr
内部芯片 ID
描述
保存时序数据结构,然后应用 SDR 时序模式 0(有关详细信息,请参阅 nand_reset_interface),执行重置操作,然后恢复之前的时序。
成功返回 0,否则返回负错误代码。
-
int nand_check_erased_ecc_chunk(void *data, int datalen, void *ecc, int ecclen, void *extraoob, int extraooblen, int bitflips_threshold)¶
检查 ECC 块是否(几乎)只包含 0xff 数据
参数
void *data
要测试的数据缓冲区
int datalen
数据长度
void *ecc
ECC 缓冲区
int ecclen
ECC 长度
void *extraoob
额外的 OOB 缓冲区
int extraooblen
额外的 OOB 长度
int bitflips_threshold
最大位翻转数
描述
检查数据缓冲区及其关联的 ECC 和 OOB 数据是否仅包含 0xff 模式,这意味着底层区域已被擦除并准备好进行编程。 bitflips_threshold 指定将该区域视为未擦除之前的最大位翻转数。
返回小于或等于 bitflips_threshold 的正位翻转数,或超过阈值的位翻转数的 -ERROR_CODE。 如果成功,则用 0xff 填充传递的缓冲区。
注意
- 1/ ECC 算法在预定义的块大小上工作,这些块大小通常
与 NAND 页面大小不同。在修复位翻转时,ECC 引擎将报告每个块的错误数,并且 NAND 核心基础设施希望您返回整个页面的最大位翻转数。 这就是为什么您应该始终在单个块而不是整个页面上使用此函数的原因。在检查完每个块后,您应该相应地更新 max_bitflips 值。
- 2/ 在检查擦除页中的位翻转时,您不仅应该检查
有效负载数据,还应检查其关联的 ECC 数据,因为用户可能已将几乎所有位都编程为 1,但只有几个位除外。 在这种情况下,我们不应将该块视为已擦除,并且检查 ECC 字节可以防止这种情况。
- 3/ extraoob 参数是可选的,如果您的某些 OOB
数据受 ECC 引擎保护,则应使用此参数。 如果您支持子页面并希望将一些额外的 OOB 数据附加到 ECC 块,也可以使用此参数。
-
int nand_read_page_raw(struct nand_chip *chip, uint8_t *buf, int oob_required, int page)¶
[内部] 读取没有 ECC 的原始页面数据
参数
struct nand_chip *chip
nand 芯片信息结构
uint8_t *buf
存储读取数据的缓冲区
int oob_required
调用方需要读取到 chip->oob_poi 的 OOB 数据
int page
要读取的页码
描述
不适用于使用特殊 oob 布局的综合症计算 ECC 控制器。
-
int nand_monolithic_read_page_raw(struct nand_chip *chip, u8 *buf, int oob_required, int page)¶
原始模式下的整体页面读取
参数
struct nand_chip *chip
NAND 芯片信息结构
u8 *buf
存储读取数据的缓冲区
int oob_required
调用方需要读取到 chip->oob_poi 的 OOB 数据
int page
要读取的页码
描述
这是一个原始页面读取,即没有任何错误检测/纠正。单片式意味着我们请求将所有相关数据(主数据加上可能的 OOB 数据)加载到 NAND 缓存中,并以单个操作通过总线(从 NAND 芯片到 NAND 控制器)发送。 这是 nand_read_page_raw()
的替代方法,后者首先读取主数据,如果也请求了 OOB 数据,则在总线上读取更多数据。
-
int nand_read_page_hwecc_oob_first(struct nand_chip *chip, uint8_t *buf, int oob_required, int page)¶
硬件 ECC 页面读取,ECC 数据从 OOB 区域读取
参数
struct nand_chip *chip
nand 芯片信息结构
uint8_t *buf
存储读取数据的缓冲区
int oob_required
调用方需要读取到 chip->oob_poi 的 OOB 数据
int page
要读取的页码
描述
用于大页面芯片的硬件 ECC,它需要先从 OOB 中提取 ECC 数据,然后再读取实际数据。
参数
struct nand_chip *chip
nand 芯片信息结构
int page
要读取的页码
参数
struct nand_chip *chip
nand 芯片信息结构
int page
要写入的页码
-
int nand_write_page_raw(struct nand_chip *chip, const uint8_t *buf, int oob_required, int page)¶
[内部] 原始页面写入函数
参数
struct nand_chip *chip
nand 芯片信息结构
const uint8_t *buf
数据缓冲区
int oob_required
必须将 chip->oob_poi 写入 OOB
int page
要写入的页码
描述
不适用于使用特殊 oob 布局的综合症计算 ECC 控制器。
-
int nand_monolithic_write_page_raw(struct nand_chip *chip, const u8 *buf, int oob_required, int page)¶
原始模式下的单片式页面写入
参数
struct nand_chip *chip
NAND 芯片信息结构
const u8 *buf
要写入的数据缓冲区
int oob_required
必须将 chip->oob_poi 写入 OOB
int page
要写入的页码
描述
这是一个原始页面写入,即没有任何错误检测/纠正。单片式意味着我们请求将所有相关数据(主数据加上可能的 OOB 数据)通过总线发送,并在单个操作中有效地编程到 NAND 芯片阵列中。 这是 nand_write_page_raw()
的替代方法,后者首先发送主数据,然后通过在 NAND 总线上锁定更多数据周期来最终发送 OOB 数据,最后发送程序命令以同步 NAND 芯片缓存。
-
int rawnand_dt_parse_gpio_cs(struct device *dev, struct gpio_desc ***cs_array, unsigned int *ncs_array)¶
解析控制器的 gpio-cs 属性
参数
struct device *dev
要解析的设备。也用于管理分配。
struct gpio_desc ***cs_array
成功时分配的 GPIO 描述符指针数组
unsigned int *ncs_array
成功时更新的 cs_array 中的条目数。 成功时 返回 0,否则返回错误。
-
int nand_ecc_choose_conf(struct nand_chip *chip, const struct nand_ecc_caps *caps, int oobavail)¶
设置 ECC 强度和 ECC 步长
参数
struct nand_chip *chip
nand 芯片信息结构
const struct nand_ecc_caps *caps
ECC 引擎功能信息结构
int oobavail
ECC 引擎可以使用的 OOB 大小
描述
根据以下逻辑选择 ECC 配置。
如果 ECC 步长和 ECC 强度都已设置(通常由 DT 设置),则检查此控制器是否支持它。
如果用户提供了 nand-ecc-maximize 属性,则选择最大 ECC 强度。
否则,请尝试匹配与芯片要求最接近的 ECC 步长和 ECC 强度。如果可用的 OOB 大小不能满足芯片要求,则回退到最大 ECC 步长和 ECC 强度。
成功时,将设置选定的 ECC 设置。
-
int nand_scan_with_ids(struct nand_chip *chip, unsigned int maxchips, struct nand_flash_dev *ids)¶
[NAND 接口] 扫描 NAND 设备
参数
struct nand_chip *chip
NAND 芯片对象
unsigned int maxchips
要扫描的芯片数量。
struct nand_flash_dev *ids
可选的闪存 ID 表
描述
这将使用默认值填充所有未初始化的函数指针。读取闪存 ID,并用适当的值填充 mtd/芯片结构。
参数
struct nand_chip *chip
NAND 芯片对象
提供的内部函数¶
本章包含 NAND 驱动程序内部函数的自动生成文档。每个函数都有一个简短的描述,该描述标有 [XXX] 标识符。有关说明,请参阅“文档提示”一章。标有 [DEFAULT] 的函数可能与板驱动程序开发人员相关。
参数
struct nand_chip *chip
NAND 芯片对象
描述
释放芯片锁并唤醒等待设备上的任何人。
参数
struct nand_chip *chip
NAND 芯片对象
int page
开始检查坏块标记使用的第一页
描述
返回一个整数,该整数对应于块内页面偏移量,用于存储坏块标记的页面。如果没有更多页面可用,则返回 -EINVAL。
参数
struct nand_chip *chip
NAND 芯片对象
loff_t ofs
设备起始偏移量
描述
检查块是否为坏块。
参数
struct nand_chip *chip
NAND 芯片对象
loff_t offset
要检查的区域的偏移量
u64 size
要检查的区域的大小
描述
通过将偏移量和大小与从 DT 获取的安全区域列表进行比较来检查区域是否安全。如果区域安全则返回 true,否则返回 false。
参数
struct nand_chip *chip
NAND 芯片结构
描述
锁定设备及其控制器以进行独占访问
参数
struct nand_chip *chip
NAND 芯片对象
描述
检查设备是否写保护。该函数期望设备已被选中。
-
uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, size_t len, struct mtd_oob_ops *ops)¶
[内部] 将客户端缓冲区传输到 OOB
参数
struct nand_chip *chip
NAND 芯片对象
uint8_t *oob
OOB 数据缓冲区
size_t len
OOB 数据写入长度
struct mtd_oob_ops *ops
OOB 操作结构
-
int nand_do_write_oob(struct nand_chip *chip, loff_t to, struct mtd_oob_ops *ops)¶
[MTD 接口] NAND 写带外数据
参数
struct nand_chip *chip
NAND 芯片对象
loff_t to
要写入的偏移量
struct mtd_oob_ops *ops
OOB 操作描述结构
描述
NAND 写带外数据。
参数
struct nand_chip *chip
NAND 芯片对象
loff_t ofs
设备起始偏移量
描述
这是默认实现,可以被硬件特定的驱动程序覆盖。它提供了将坏块标记写入块的详细信息。
参数
struct nand_chip *chip
NAND 芯片对象
loff_t ofs
要标记为坏块的块的偏移量
参数
struct nand_chip *chip
NAND 芯片对象
loff_t ofs
设备起始偏移量
描述
此函数执行通用的 NAND 坏块标记步骤(即,坏块表和/或标记)。我们只允许硬件驱动程序指定如何将坏块标记写入 OOB (chip->legacy.block_markbad)。
我们按以下顺序尝试操作
擦除受影响的块,以允许干净地写入 OOB 标记
将坏块标记写入受影响块的 OOB 区域(除非存在标志 NAND_BBT_NO_OOB_BBM)
更新 BBT
请注意,我们保留在 (2) 或 (3) 中遇到的第一个错误,完成这些过程,并在最后转储错误。
-
int nand_block_isreserved(struct mtd_info *mtd, loff_t ofs)¶
[通用] 检查块是否标记为保留。
参数
struct mtd_info *mtd
MTD 设备结构
loff_t ofs
设备起始偏移量
描述
检查块是否标记为保留。
参数
struct nand_chip *chip
NAND 芯片对象
loff_t ofs
设备起始偏移量
int allowbbt
1,如果允许访问 bbt 区域
描述
检查块是否为坏块。通过读取坏块表或调用扫描函数。
参数
struct nand_chip *chip
NAND 芯片结构
unsigned long timeo
超时
描述
等待命令完成。这是在中断上下文中使用 nand_wait 的辅助函数。可能发生在 panic 状态,并且尝试通过 mtdoops 写入 oops 信息。
参数
struct nand_chip *chip
NAND 芯片
int chipnr
内部芯片 ID
描述
将数据接口和时序重置为 ONFI 模式 0。
成功返回 0,否则返回负错误代码。
参数
struct nand_chip *chip
NAND 芯片
int chipnr
内部芯片 ID
描述
配置芯片和驱动程序支持的最佳数据接口和 NAND 时序。
成功返回 0,否则返回负错误代码。
-
int nand_choose_best_sdr_timings(struct nand_chip *chip, struct nand_interface_config *iface, struct nand_sdr_timings *spec_timings)¶
选择 NAND 控制器和 NAND 芯片都支持的最佳 SDR 时序
参数
struct nand_chip *chip
NAND 芯片
struct nand_interface_config *iface
接口配置(最终可以更新)
struct nand_sdr_timings *spec_timings
特定时序,当不符合 ONFI 规范时使用
描述
如果提供了特定时序,则使用它们。否则,从 ONFI 信息中检索支持的时序模式。
-
int nand_choose_best_nvddr_timings(struct nand_chip *chip, struct nand_interface_config *iface, struct nand_nvddr_timings *spec_timings)¶
选择 NAND 控制器和 NAND 芯片都支持的最佳 NVDDR 时序
参数
struct nand_chip *chip
NAND 芯片
struct nand_interface_config *iface
接口配置(最终可以更新)
struct nand_nvddr_timings *spec_timings
特定时序,当不符合 ONFI 规范时使用
描述
如果提供了特定时序,则使用它们。否则,从 ONFI 信息中检索支持的时序模式。
-
int nand_choose_best_timings(struct nand_chip *chip, struct nand_interface_config *iface)¶
选择 NAND 控制器和 NAND 芯片都支持的最佳 NVDDR 或 SDR 时序
参数
struct nand_chip *chip
NAND 芯片
struct nand_interface_config *iface
接口配置(最终可以更新)
描述
如果提供了特定时序,则使用它们。否则,从 ONFI 信息中检索支持的时序模式。
参数
struct nand_chip *chip
NAND 芯片
描述
找到芯片和驱动程序支持的最佳数据接口和 NAND 时序。最终让 NAND 制造商驱动程序提出自己的一组时序。
在此函数之后,nand_chip->interface_config 将初始化为可用的最佳时序模式。
成功返回 0,否则返回负错误代码。
-
int nand_fill_column_cycles(struct nand_chip *chip, u8 *addrs, unsigned int offset_in_page)¶
填充地址的列周期
参数
struct nand_chip *chip
NAND 芯片
u8 *addrs
要填充的地址周期数组
unsigned int offset_in_page
页内的偏移量
描述
根据 NAND 总线宽度和页大小,填充 addrs 字段的第一个或前两个字节。
返回编码列所需的周期数,如果其中一个参数无效,则返回负错误代码。
-
int nand_read_param_page_op(struct nand_chip *chip, u8 page, void *buf, unsigned int len)¶
执行读取参数页操作
参数
struct nand_chip *chip
NAND 芯片
u8 page
要读取的参数页
void *buf
用于存储数据的缓冲区
unsigned int len
缓冲区的长度
描述
此函数发出读取参数页操作。此函数不选择/取消选择 CS 线。
成功返回 0,否则返回负错误代码。
参数
struct nand_chip *chip
NAND 芯片
u8 feature
特性 ID
const void *data
4 字节数据
描述
此函数发送设置特性命令,并等待 NAND 准备就绪后再返回。此函数不选择/取消选择 CS 线。
成功返回 0,否则返回负错误代码。
参数
struct nand_chip *chip
NAND 芯片
u8 feature
特性 ID
void *data
4 字节数据
描述
此函数发送获取特性命令,并等待 NAND 准备就绪后再返回。此函数不选择/取消选择 CS 线。
成功返回 0,否则返回负错误代码。
-
struct nand_op_parser_ctx¶
解析器使用的上下文
定义:
struct nand_op_parser_ctx {
const struct nand_op_instr *instrs;
unsigned int ninstrs;
struct nand_subop subop;
};
成员
instrs
必须处理的所有指令的数组
ninstrs
instrs 数组的长度
子操作
要传递给 NAND 控制器的子操作
描述
核心使用此结构将 NAND 操作拆分为可以由 NAND 控制器处理的子操作。
-
bool nand_op_parser_must_split_instr(const struct nand_op_parser_pattern_elem *pat, const struct nand_op_instr *instr, unsigned int *start_offset)¶
检查是否必须拆分指令
参数
const struct nand_op_parser_pattern_elem *pat
与 instr 匹配的解析器模式元素
const struct nand_op_instr *instr
指向要检查的指令的指针
unsigned int *start_offset
这是一个输入/输出参数。如果 instr 已经被拆分,则 start_offset 是开始的偏移量(地址周期或数据缓冲区中的偏移量)。相反,如果函数返回 true(即 instr 必须拆分),则此参数将更新以指向尚未处理的第一个数据/地址周期。
描述
一些 NAND 控制器是有限的,不能通过唯一的操作发送 X 个地址周期,也不能同时读取/写入超过 Y 个字节。在这种情况下,将不适合单个控制器操作的指令拆分为两个或多个块。
如果必须拆分指令,则返回 true,否则返回 false。 start_offset 参数也会更新为下一组指令必须开始的偏移量(如果是地址或数据指令)。
-
bool nand_op_parser_match_pat(const struct nand_op_parser_pattern *pat, struct nand_op_parser_ctx *ctx)¶
检查模式是否与解析器上下文中剩余的指令匹配
参数
const struct nand_op_parser_pattern *pat
要测试的模式
struct nand_op_parser_ctx *ctx
要与模式 pat 匹配的解析器上下文结构
描述
检查 pat 是否匹配 ctx 中剩余的指令集或子集。如果匹配,则返回 true,否则返回 false。当返回 true 时,ctx->subop 将更新为要传递给控制器驱动程序的指令集。
参数
struct nand_chip *chip
NAND 芯片信息结构
int addr
特性地址
u8 *subfeature_param
子特性参数,一个 4 字节的数组
描述
成功返回 0,否则返回负的错误码。 如果操作无法处理,则返回 -ENOTSUPP。
参数
struct nand_chip *chip
NAND 芯片信息结构
int addr
特性地址
u8 *subfeature_param
子特性参数,一个 4 字节的数组
描述
成功返回 0,否则返回负的错误码。 如果操作无法处理,则返回 -ENOTSUPP。
-
int nand_check_erased_buf(void *buf, int len, int bitflips_threshold)¶
检查缓冲区是否(几乎)只包含 0xff 数据
参数
void *buf
要测试的缓冲区
int len
缓冲区长度
int bitflips_threshold
最大位翻转数
描述
检查缓冲区是否只包含 0xff,这意味着底层区域已被擦除并准备好进行编程。 bitflips_threshold 指定在认为该区域未擦除之前允许的最大位翻转次数。 返回小于或等于 bitflips_threshold 的正数位翻转次数,或者对于超过阈值的位翻转返回 -ERROR_CODE。
注意
此函数的逻辑是从 memweight 实现中提取的,除了如果位翻转次数超过 bitflips_threshold 值,`nand_check_erased_buf` 函数会在测试整个缓冲区之前退出。
-
int nand_read_page_raw_notsupp(struct nand_chip *chip, u8 *buf, int oob_required, int page)¶
虚拟读取原始页函数
参数
struct nand_chip *chip
nand 芯片信息结构
u8 *buf
存储读取数据的缓冲区
int oob_required
调用方需要读取到 chip->oob_poi 的 OOB 数据
int page
要读取的页码
描述
无条件返回 -ENOTSUPP。
-
int nand_read_page_raw_syndrome(struct nand_chip *chip, uint8_t *buf, int oob_required, int page)¶
[内部] 读取没有 ECC 的原始页面数据
参数
struct nand_chip *chip
nand 芯片信息结构
uint8_t *buf
存储读取数据的缓冲区
int oob_required
调用方需要读取到 chip->oob_poi 的 OOB 数据
int page
要读取的页码
描述
即使不使用 OOB,我们也需要特殊的 oob 布局和处理。
-
int nand_read_page_swecc(struct nand_chip *chip, uint8_t *buf, int oob_required, int page)¶
[可替换] 基于软件 ECC 的页面读取函数
参数
struct nand_chip *chip
nand 芯片信息结构
uint8_t *buf
存储读取数据的缓冲区
int oob_required
调用方需要读取到 chip->oob_poi 的 OOB 数据
int page
要读取的页码
-
int nand_read_subpage(struct nand_chip *chip, uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi, int page)¶
[可替换] 基于 ECC 的子页读取函数
参数
struct nand_chip *chip
nand 芯片信息结构
uint32_t data_offs
请求数据在页面中的偏移量
uint32_t readlen
数据长度
uint8_t *bufpoi
存储读取数据的缓冲区
int page
要读取的页码
-
int nand_read_page_hwecc(struct nand_chip *chip, uint8_t *buf, int oob_required, int page)¶
[可替换] 基于硬件 ECC 的页面读取函数
参数
struct nand_chip *chip
nand 芯片信息结构
uint8_t *buf
存储读取数据的缓冲区
int oob_required
调用方需要读取到 chip->oob_poi 的 OOB 数据
int page
要读取的页码
描述
不适用于需要特殊 oob 布局的校验和计算 ECC 控制器。
-
int nand_read_page_syndrome(struct nand_chip *chip, uint8_t *buf, int oob_required, int page)¶
[可替换] 基于硬件 ECC 校验和的页面读取
参数
struct nand_chip *chip
nand 芯片信息结构
uint8_t *buf
存储读取数据的缓冲区
int oob_required
调用方需要读取到 chip->oob_poi 的 OOB 数据
int page
要读取的页码
描述
硬件生成器会自动计算错误校验和。 因此,我们需要特殊的 oob 布局和处理。
-
uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, struct mtd_oob_ops *ops, size_t len)¶
[内部] 将 oob 传输到客户端缓冲区
参数
struct nand_chip *chip
NAND 芯片对象
uint8_t *oob
oob 目标地址
struct mtd_oob_ops *ops
OOB 操作结构
size_t len
要传输的 oob 大小
参数
struct nand_chip *chip
NAND 芯片对象
int retry_mode
要使用的重试模式
描述
一些供应商提供了一个特殊的命令来移动 Vt 阈值,当页面中存在太多位翻转(即 ECC 错误)时使用。 设置新的阈值后,主机应重试读取该页面。
-
int nand_do_read_ops(struct nand_chip *chip, loff_t from, struct mtd_oob_ops *ops)¶
[内部] 使用 ECC 读取数据
参数
struct nand_chip *chip
NAND 芯片对象
loff_t from
读取起始偏移量
struct mtd_oob_ops *ops
OOB 操作结构
描述
内部函数。调用时需持有芯片锁。
参数
struct nand_chip *chip
nand 芯片信息结构
int page
要读取的页码
-
int nand_write_oob_syndrome(struct nand_chip *chip, int page)¶
[可替换] 用于带校验位的硬件 ECC 的 OOB 数据写入函数 - 仅用于大页闪存
参数
struct nand_chip *chip
nand 芯片信息结构
int page
要写入的页码
参数
struct nand_chip *chip
NAND 芯片对象
loff_t from
读取起始偏移量
struct mtd_oob_ops *ops
带外操作描述结构
描述
从备用区读取 NAND 带外数据。
-
int nand_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)¶
[MTD 接口] NAND 读取数据和/或带外数据
参数
struct mtd_info *mtd
MTD 设备结构
loff_t from
读取起始偏移量
struct mtd_oob_ops *ops
OOB 操作描述结构
描述
NAND 读取数据和/或带外数据。
-
int nand_write_page_raw_notsupp(struct nand_chip *chip, const u8 *buf, int oob_required, int page)¶
虚拟原始页写入函数
参数
struct nand_chip *chip
nand 芯片信息结构
const u8 *buf
数据缓冲区
int oob_required
必须将 chip->oob_poi 写入 OOB
int page
要写入的页码
描述
无条件返回 -ENOTSUPP。
-
int nand_write_page_raw_syndrome(struct nand_chip *chip, const uint8_t *buf, int oob_required, int page)¶
[内部] 原始页面写入函数
参数
struct nand_chip *chip
nand 芯片信息结构
const uint8_t *buf
数据缓冲区
int oob_required
必须将 chip->oob_poi 写入 OOB
int page
要写入的页码
描述
即使未检查 ECC,我们也需要特殊的 OOB 布局和处理。
-
int nand_write_page_swecc(struct nand_chip *chip, const uint8_t *buf, int oob_required, int page)¶
[可替换] 基于软件 ECC 的页写入函数
参数
struct nand_chip *chip
nand 芯片信息结构
const uint8_t *buf
数据缓冲区
int oob_required
必须将 chip->oob_poi 写入 OOB
int page
要写入的页码
-
int nand_write_page_hwecc(struct nand_chip *chip, const uint8_t *buf, int oob_required, int page)¶
[可替换] 基于硬件 ECC 的页写入函数
参数
struct nand_chip *chip
nand 芯片信息结构
const uint8_t *buf
数据缓冲区
int oob_required
必须将 chip->oob_poi 写入 OOB
int page
要写入的页码
-
int nand_write_subpage_hwecc(struct nand_chip *chip, uint32_t offset, uint32_t data_len, const uint8_t *buf, int oob_required, int page)¶
[可替换] 基于硬件 ECC 的子页写入
参数
struct nand_chip *chip
nand 芯片信息结构
uint32_t offset
页内子页的列地址
uint32_t data_len
数据长度
const uint8_t *buf
数据缓冲区
int oob_required
必须将 chip->oob_poi 写入 OOB
int page
要写入的页码
-
int nand_write_page_syndrome(struct nand_chip *chip, const uint8_t *buf, int oob_required, int page)¶
[可替换] 基于硬件 ECC 校验位的页写入
参数
struct nand_chip *chip
nand 芯片信息结构
const uint8_t *buf
数据缓冲区
int oob_required
必须将 chip->oob_poi 写入 OOB
int page
要写入的页码
描述
硬件生成器会自动计算错误校验和。 因此,我们需要特殊的 oob 布局和处理。
-
int nand_write_page(struct nand_chip *chip, uint32_t offset, int data_len, const uint8_t *buf, int oob_required, int page, int raw)¶
写入一页
参数
struct nand_chip *chip
NAND 芯片描述符
uint32_t offset
页内地址偏移量
int data_len
要写入的实际数据长度
const uint8_t *buf
要写入的数据
int oob_required
必须将 chip->oob_poi 写入 OOB
int page
要写入的页码
int raw
使用 write_page 的 _raw 版本
-
int nand_do_write_ops(struct nand_chip *chip, loff_t to, struct mtd_oob_ops *ops)¶
[内部] 带 ECC 的 NAND 写入
参数
struct nand_chip *chip
NAND 芯片对象
loff_t to
要写入的偏移量
struct mtd_oob_ops *ops
带外操作描述结构
描述
带 ECC 的 NAND 写入。
-
int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const uint8_t *buf)¶
[MTD 接口] 带 ECC 的 NAND 写入
参数
struct mtd_info *mtd
MTD 设备结构
loff_t to
要写入的偏移量
size_t len
要写入的字节数
size_t *retlen
指向用于存储写入字节数的变量的指针
const uint8_t *buf
要写入的数据
描述
带 ECC 的 NAND 写入。在中断上下文中执行写入时使用,例如,当在 panic 时写入 oops 时,可能会被 mtdoops 调用。
-
int nand_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops)¶
[MTD 接口] NAND 写入数据和/或带外数据
参数
struct mtd_info *mtd
MTD 设备结构
loff_t to
要写入的偏移量
struct mtd_oob_ops *ops
OOB 操作描述结构
-
int nand_erase(struct mtd_info *mtd, struct erase_info *instr)¶
[MTD 接口] 擦除块
参数
struct mtd_info *mtd
MTD 设备结构
struct erase_info *instr
擦除指令
描述
擦除一个或多个块。
参数
struct nand_chip *chip
NAND 芯片对象
struct erase_info *instr
擦除指令
int allowbbt
允许擦除 bbt 区域
描述
擦除一个或多个块。
-
void nand_sync(struct mtd_info *mtd)¶
[MTD 接口] 同步
参数
struct mtd_info *mtd
MTD 设备结构
描述
同步实际上是等待芯片就绪函数。
-
int nand_block_isbad(struct mtd_info *mtd, loff_t offs)¶
[MTD 接口] 检查偏移量处的块是否为坏块
参数
struct mtd_info *mtd
MTD 设备结构
loff_t offs
相对于 mtd 起始的偏移量
-
int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)¶
[MTD 接口] 将给定偏移量处的块标记为坏块
参数
struct mtd_info *mtd
MTD 设备结构
loff_t ofs
相对于 mtd 起始的偏移量
-
int nand_suspend(struct mtd_info *mtd)¶
[MTD 接口] 暂停 NAND 闪存
参数
struct mtd_info *mtd
MTD 设备结构
描述
成功返回 0,否则返回负错误代码。
-
void nand_resume(struct mtd_info *mtd)¶
[MTD 接口] 恢复 NAND 闪存
参数
struct mtd_info *mtd
MTD 设备结构
-
void nand_shutdown(struct mtd_info *mtd)¶
[MTD 接口] 完成当前的 NAND 操作并阻止进一步操作
参数
struct mtd_info *mtd
MTD 设备结构
-
int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)¶
[MTD 接口] 锁定 NAND 闪存
参数
struct mtd_info *mtd
MTD 设备结构
loff_t ofs
偏移量字节地址
uint64_t len
要锁定的字节数(必须是块/页大小的倍数)
-
int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)¶
[MTD 接口] 解锁 NAND 闪存
参数
struct mtd_info *mtd
MTD 设备结构
loff_t ofs
偏移量字节地址
uint64_t len
要解锁的字节数(必须是块/页大小的倍数)
-
int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips, struct nand_flash_dev *table)¶
扫描 NAND 设备
参数
struct nand_chip *chip
NAND 芯片对象
unsigned int maxchips
要扫描的芯片数量
struct nand_flash_dev *table
备用 NAND ID 表
描述
这是正常 nand_scan() 函数的第一阶段。它读取闪存 ID 并相应地设置 MTD 字段。
此辅助函数以前由需要调整一些与 ECC 相关的参数的控制器驱动程序直接调用,然后再调用 nand_scan_tail()
。这种分离阻止了在此阶段进行动态分配,这很不方便,并且为了方便 ->init_ecc()/cleanup_ecc() 钩子而被禁止。
-
int nand_check_ecc_caps(struct nand_chip *chip, const struct nand_ecc_caps *caps, int oobavail)¶
检查预设 ECC 设置的合理性
参数
struct nand_chip *chip
nand 芯片信息结构
const struct nand_ecc_caps *caps
ECC 容量信息结构
int oobavail
ECC 引擎可以使用的 OOB 大小
描述
当 ECC 步长和强度已经设置时,检查它们是否受控制器支持,以及计算出的 ECC 字节是否适合芯片的 OOB 区域。如果成功,则设置计算出的 ECC 字节数。
-
int nand_match_ecc_req(struct nand_chip *chip, const struct nand_ecc_caps *caps, int oobavail)¶
以最少的 ECC 字节满足芯片的要求
参数
struct nand_chip *chip
nand 芯片信息结构
const struct nand_ecc_caps *caps
ECC 引擎功能信息结构
int oobavail
ECC 引擎可以使用的 OOB 大小
描述
如果提供了芯片的 ECC 要求,则尝试以最少的 ECC 字节(即以最大的 OOB 可用字节)来满足它。如果成功,则设置选定的 ECC 设置。
-
int nand_maximize_ecc(struct nand_chip *chip, const struct nand_ecc_caps *caps, int oobavail)¶
选择可用的最大 ECC 强度
参数
struct nand_chip *chip
nand 芯片信息结构
const struct nand_ecc_caps *caps
ECC 引擎功能信息结构
int oobavail
ECC 引擎可以使用的 OOB 大小
描述
选择控制器支持且适合芯片 OOB 区域的最大 ECC 强度。如果成功,则设置选定的 ECC 设置。
参数
struct nand_chip *chip
NAND 芯片对象
描述
这是普通 nand_scan() 函数的第二阶段。它使用默认值填充所有未初始化的函数指针,并扫描坏块表(如果适用)。
-
int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td)¶
[通用] 检查缓冲区中是否存在某个模式
参数
uint8_t *buf
要搜索的缓冲区
int len
要搜索的缓冲区长度
int paglen
页长度
struct nand_bbt_descr *td
搜索模式描述符
描述
检查给定位置是否存在某种模式。用于搜索坏块表和好/坏块标识符。
-
int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td)¶
[通用] 检查缓冲区中是否存在某个模式
参数
uint8_t *buf
要搜索的缓冲区
struct nand_bbt_descr *td
搜索模式描述符
描述
检查给定位置是否存在某种模式。用于搜索坏块表和好/坏块标识符。与 check_pattern 相同,但没有可选的空检查。
-
u32 add_marker_len(struct nand_bbt_descr *td)¶
计算数据区域中标记的长度
参数
struct nand_bbt_descr *td
用于计算的 BBT 描述符
描述
如果标记位于 OOB 区域,则长度将为 0。
-
int read_bbt(struct nand_chip *this, uint8_t *buf, int page, int num, struct nand_bbt_descr *td, int offs)¶
[通用] 从页面开始读取坏块表
参数
struct nand_chip *this
NAND 芯片对象
uint8_t *buf
临时缓冲区
int page
起始页
int num
要读取的 bbt 描述符的数量
struct nand_bbt_descr *td
bbt 描述表
int offs
表中的块号偏移量
描述
从页面开始读取坏块表。
-
int read_abs_bbt(struct nand_chip *this, uint8_t *buf, struct nand_bbt_descr *td, int chip)¶
[通用] 从给定页面开始读取坏块表
参数
struct nand_chip *this
NAND 芯片对象
uint8_t *buf
临时缓冲区
struct nand_bbt_descr *td
坏块表的描述符
int chip
读取特定芯片的表,-1 读取所有芯片;仅当设置 NAND_BBT_PERCHIP 选项时才适用
描述
从给定页面开始读取所有芯片的坏块表。我们假设 bbt 位是连续排列的。
-
int scan_read_oob(struct nand_chip *this, uint8_t *buf, loff_t offs, size_t len)¶
[通用] 扫描数据+OOB 区域到缓冲区
参数
struct nand_chip *this
NAND 芯片对象
uint8_t *buf
临时缓冲区
loff_t offs
要扫描的偏移量
size_t len
要读取的数据区域的长度
描述
从数据+OOB 扫描读取数据。可能会遍历多个页面,在 buf 中交错页面、OOB、页面、OOB...。完成传输并返回“最强”的 ECC 条件(错误或位翻转)。可能会在第一个(非 ECC)错误时退出。
-
void read_abs_bbts(struct nand_chip *this, uint8_t *buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md)¶
[通用] 从给定页开始读取所有芯片的坏块表
参数
struct nand_chip *this
NAND 芯片对象
uint8_t *buf
临时缓冲区
struct nand_bbt_descr *td
坏块表的描述符
struct nand_bbt_descr *md
坏块表镜像的描述符
描述
从给定页开始读取所有芯片的坏块表。我们假设 bbt 位是连续的。
-
int create_bbt(struct nand_chip *this, uint8_t *buf, struct nand_bbt_descr *bd, int chip)¶
[通用] 通过扫描设备创建坏块表
参数
struct nand_chip *this
NAND 芯片对象
uint8_t *buf
临时缓冲区
struct nand_bbt_descr *bd
好/坏块搜索模式的描述符
int chip
为特定芯片创建表格,-1 读取所有芯片; 仅当设置了 NAND_BBT_PERCHIP 选项时才适用
描述
通过扫描设备以查找给定的好/坏块识别模式来创建坏块表。
参数
struct nand_chip *this
NAND 芯片对象
uint8_t *buf
临时缓冲区
struct nand_bbt_descr *td
坏块表的描述符
描述
通过搜索给定的标识模式来读取坏块表。搜索从设备的开头向上或从设备的结尾向下执行。搜索始终从块的开头开始。如果给出了 NAND_BBT_PERCHIP 选项,则为每个芯片搜索一个 bbt,其中包含该芯片的坏块信息。这是为某些 DOC 设备提供支持所必需的。
bbt 标识模式位于块中第一页的 oob 区域。
-
void search_read_bbts(struct nand_chip *this, uint8_t *buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md)¶
[通用] 扫描设备以查找坏块表
参数
struct nand_chip *this
NAND 芯片对象
uint8_t *buf
临时缓冲区
struct nand_bbt_descr *td
坏块表的描述符
struct nand_bbt_descr *md
坏块表镜像的描述符
描述
搜索并读取坏块表。
-
int get_bbt_block(struct nand_chip *this, struct nand_bbt_descr *td, struct nand_bbt_descr *md, int chip)¶
获取适合存储 BBT 的第一个有效擦除块
参数
struct nand_chip *this
NAND 设备
struct nand_bbt_descr *td
BBT 描述
struct nand_bbt_descr *md
镜像 BBT 描述符
int chip
芯片选择器
描述
此函数返回一个正的块号,该块号指向适合存储 BBT 的有效擦除块(即在为 BBT 保留的范围内),如果所有块都已使用或标记为坏块,则返回 -ENOSPC。如果 td->pages[chip] 已经指向一个有效的块,我们将重用它,否则我们将搜索下一个有效的块。
-
void mark_bbt_block_bad(struct nand_chip *this, struct nand_bbt_descr *td, int chip, int block)¶
将为 BBT 保留的块之一标记为坏块
参数
struct nand_chip *this
NAND 设备
struct nand_bbt_descr *td
BBT 描述
int chip
芯片选择器
int block
要标记的 BBT 块
描述
为 BBT 保留的块可能会变为坏块。此函数是一个辅助函数,用于将此类块标记为坏块。它负责更新内存中的 BBT,使用坏块标记将块标记为坏块,并使关联的 td->pages[] 条目无效。
-
int write_bbt(struct nand_chip *this, uint8_t *buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md, int chipsel)¶
[通用] (重新)写入坏块表
参数
struct nand_chip *this
NAND 芯片对象
uint8_t *buf
临时缓冲区
struct nand_bbt_descr *td
坏块表的描述符
struct nand_bbt_descr *md
坏块表镜像的描述符
int chipsel
特定芯片的选择器,-1 表示全部
描述
(重新)写入坏块表。
参数
struct nand_chip *this
NAND 芯片对象
struct nand_bbt_descr *bd
好/坏块搜索模式的描述符
描述
该函数通过扫描设备以查找制造商/软件标记的好/坏块来创建基于内存的 bbt。
-
int check_create(struct nand_chip *this, uint8_t *buf, struct nand_bbt_descr *bd)¶
[通用] 必要时创建并写入 bbt
参数
struct nand_chip *this
NAND 设备
uint8_t *buf
临时缓冲区
struct nand_bbt_descr *bd
好/坏块搜索模式的描述符
描述
该函数检查先前调用 read_bbt 的结果,并在必要时创建/更新 bbt。如果未找到芯片/设备的 bbt,则需要创建。如果缺少其中一个表或一个表的版本号小于另一个表,则需要更新。
参数
struct nand_chip *this
NAND 设备
loff_t offs
新标记的块的偏移量
描述
该函数更新坏块表。
参数
struct nand_chip *this
NAND 设备
struct nand_bbt_descr *td
坏块表描述符
描述
坏块表区域被标记为“坏”,以防止意外擦除/写入。这些区域由标记 0x02 标识。
参数
struct nand_chip *this
NAND 设备
struct nand_bbt_descr *bd
要验证的表。
描述
此函数对坏块描述表执行一些健全性检查。
参数
struct nand_chip *this
NAND 设备
struct nand_bbt_descr *bd
好/坏块搜索模式的描述符
描述
该函数检查是否已存在坏块表。如果不存在,它会扫描设备中由制造商标记的好/坏块,并将坏块表写入选定的位置。
坏块表内存在此处分配。必须通过调用 `nand_free_bbt` 函数来释放。
参数
struct nand_chip *this
要为其创建描述符的 NAND 芯片。
描述
此函数根据 this 的属性分配并初始化一个用于 BBM 检测的 `nand_bbt_descr`。新的描述符存储在 `this->badblock_pattern` 中。因此,传递给此函数时,`this->badblock_pattern` 应该为 NULL。
参数
struct nand_chip *this
NAND 芯片对象
loff_t offs
设备中的偏移量。
参数
struct nand_chip *this
NAND 芯片对象
loff_t offs
设备中的偏移量。
int allowbbt
允许访问坏块表区域。
参数
struct nand_chip *this
NAND 芯片对象
loff_t offs
坏块的偏移量。
贡献者¶
以下人员为 NAND 驱动程序做出了贡献
Steven J. Hillsjhill@realitydiluted.com
David Woodhousedwmw2@infradead.org
Thomas Gleixnertglx@linutronix.de
许多用户为测试提供了错误修复、改进和帮助。非常感谢。
以下人员为此文档做出了贡献
Thomas Gleixnertglx@linutronix.de