MTD NAND 驱动编程接口

作者:

Thomas Gleixner

简介

通用 NAND 驱动程序支持几乎所有基于 NAND 和 AG-AND 的芯片,并将它们连接到 Linux 内核的内存技术设备 (MTD) 子系统。

本文档提供给想要实现适用于 NAND 设备的板级驱动程序或文件系统驱动程序的开发人员。

已知错误和假设

无。

文档提示

函数和结构文档是自动生成的。每个函数和结构成员都有一个简短的描述,并标有 [XXX] 标识符。以下章节解释了这些标识符的含义。

函数标识符 [XXX]

这些函数在简短的注释中用 [XXX] 标识符标记。这些标识符解释了函数的使用和范围。使用以下标识符

  • [MTD 接口]

    这些函数提供了 MTD 内核 API 的接口。它们不可替换,并提供完全独立于硬件的功能。

  • [NAND 接口]

    这些函数已导出,并提供 NAND 内核 API 的接口。

  • [GENERIC]

    通用函数不可替换,并提供完全独立于硬件的功能。

  • [DEFAULT]

    默认函数提供与硬件相关的功能,适用于大多数实现。如果需要,板级驱动程序可以替换这些函数。这些函数通过 NAND 芯片描述结构中的指针调用。板级驱动程序可以在调用 nand_scan() 之前设置应由板级相关函数替换的函数。如果在进入 nand_scan() 时函数指针为 NULL,则该指针将设置为适用于检测到的芯片类型的默认函数。

结构成员标识符 [XXX]

结构成员在注释中用 [XXX] 标识符标记。这些标识符解释了成员的使用和范围。使用以下标识符

  • [INTERN]

    这些成员仅供 NAND 驱动程序内部使用,不得修改。这些值中的大多数都是从芯片几何信息计算出来的,这些信息在 nand_scan() 期间进行评估。

  • [REPLACEABLE]

    可替换成员保存硬件相关函数,这些函数可由板级驱动程序提供。板级驱动程序可以在调用 nand_scan() 之前设置应由板级相关函数替换的函数。如果在进入 nand_scan() 时函数指针为 NULL,则该指针将设置为适用于检测到的芯片类型的默认函数。

  • [BOARDSPECIFIC]

    板级特定成员保存硬件相关信息,这些信息必须由板级驱动程序提供。板级驱动程序必须在调用 nand_scan() 之前设置函数指针和数据字段。

  • [OPTIONAL]

    可选成员可以保存与板级驱动程序相关的信息。通用 NAND 驱动程序代码不使用此信息。

基本板级驱动程序

对于大多数板,仅提供基本函数并填写 NAND 芯片描述结构中一些真正与板相关的成员就足够了。

基本定义

至少您必须提供一个 nand_chip 结构和一个用于存储 ioremap'ed 芯片地址的存储。您可以使用 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。

Init 函数

Init 函数分配内存并设置所有特定于板的参数和函数指针。当所有设置完成后,将调用 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);

Exit 函数

只有当驱动程序编译为模块时,才需要退出函数。它释放芯片驱动程序持有的所有资源,并取消注册 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 以启用表版本控制。强烈建议为带有写入支持的镜像表启用此功能。它可以确保将丢失坏块表信息的风险降低到丢失有关应标记为坏块的一个磨损块的信息。

  • 在写入时保存块内容

    如果保存坏块表的块确实包含其他有用信息,请设置选项 NAND_BBT_SAVECONTENT。写入坏块表时,会读取整个块,更新坏块表,擦除块,然后将所有内容写回。如果未设置此选项,则仅写入坏块表,并且忽略并擦除块中的所有其他内容。

  • 保留块数

    对于自动放置,必须为坏块表存储保留一些块。保留块的数量在坏块表描述结构的 maxblocks 成员中定义。为镜像表保留 4 个块应该是一个合理的数字。这也限制了扫描坏块表标识模式的块的数量。

备用区域(自动)放置

nand 驱动程序实现了在备用区域中放置文件系统数据的不同可能性,

  • 由 fs 驱动程序定义的放置

  • 自动放置

默认放置函数是自动放置。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} 条目终止。

由 fs 驱动程序定义的放置

调用函数提供指向定义 ecc 放置的 nand_oobinfo 结构的指针。对于写入,调用方必须提供备用区域缓冲区以及数据缓冲区。备用区域缓冲区大小为(页数)*(备用区域的大小)。对于读取,缓冲区大小为(页数)*((备用区域的大小)+(每页的 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 FLASH

  • nanddump:转储 NAND FLASH 分区的内容

这些工具了解 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 生成器(sw/hw)匹配。如果位翻转的数量超过 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 hw 错误

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

DQ[7:0] 从 CLK 的访问窗口

tAC_max

DQ[7:0] 从 CLK 的访问窗口

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

DQS 从 CLK 的访问窗口的开始

tDQSCK_max

DQS 从 CLK 的访问窗口的结束

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}

anonymous

timings.sdr

typeNAND_SDR_IFACE 时使用它。

timings.nvddr

typeNAND_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

如果 typeNAND_OP_CMD_INSTR,则使用它

ctx.addr

如果 typeNAND_OP_ADDR_INSTR,则使用它

ctx.data

如果 typeNAND_OP_DATA_IN_INSTRNAND_OP_DATA_OUT_INSTR,则使用它

ctx.waitrdy

如果 typeNAND_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_offlast_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_op_parser_exec_op() 尝试执行 NAND 操作(或尝试确定是否支持特定操作)时,它都会迭代该数组。

值得一提的是,将按照声明顺序测试模式,并且将采用第一个匹配项,因此重要的是适当排序模式,以便将简单/低效的模式放在列表的末尾。通常,这是放置单指令模式的地方。

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(ERASE、PROG 等)

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

在闪存 ID 和 MTD 字段(例如擦除大小、页面大小和 OOB 大小)设置完毕后,在 NAND 检测阶段之后调用此方法。如果 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

选择/取消选择特定的目标/裸片

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

data_buf 覆盖的 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 Flash 设备 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}

anonymous

{unnamed_struct}

anonymous

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 相同,也来自数据手册。例如,“每个 512Byte 的 4bit ECC”可以使用 NAND_ECC_INFO(4, 512) 设置。

int nand_opcode_8bits(unsigned int command)

检查操作码的地址是否仅应在低 8 位上发送

参数

unsigned int command

要检查的操作码

void *nand_get_data_buf(struct nand_chip *chip)

获取内部页面缓冲区

参数

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 的位数

描述

将位从一个内存区域复制到另一个内存区域(允许重叠)。

void nand_select_target(struct nand_chip *chip, unsigned int cs)

选择一个 NAND 目标(又名 die)

参数

struct nand_chip *chip

NAND 芯片对象

unsigned int cs

要选择的 CS 线。请注意,此 CS id 始终来自芯片 PoV,而不是控制器 PoV

描述

选择一个 NAND 目标,以便在 chip 上执行的进一步操作将转到所选的 NAND 目标。

void nand_deselect_target(struct nand_chip *chip)

取消选择当前选择的目标

参数

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,否则返回负错误代码。

int nand_prog_page_end_op(struct nand_chip *chip)

结束 PROG PAGE 操作

参数

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,否则返回负错误代码。

int nand_readid_op(struct nand_chip *chip, u8 addr, void *buf, unsigned int len)

执行 READID 操作

参数

struct nand_chip *chip

NAND 芯片

u8 addr

在READID命令之后要经过的地址周期数

void *buf

用于存储ID的缓冲区

unsigned int len

缓冲区长度

描述

此函数发送READID命令并读取NAND返回的ID。此函数不选择/取消选择CS线。

成功时返回 0,否则返回负错误代码。

int nand_status_op(struct nand_chip *chip, u8 *status)

执行STATUS操作

参数

struct nand_chip *chip

NAND 芯片

u8 *status

用于存储NAND状态的输出变量

描述

此函数发送STATUS命令并读取NAND返回的状态。此函数不选择/取消选择CS线。

成功时返回 0,否则返回负错误代码。

int nand_exit_status_op(struct nand_chip *chip)

退出STATUS操作

参数

struct nand_chip *chip

NAND 芯片

描述

此函数发送READ0命令以取消STATUS命令的效果,以避免仅读取状态,直到发送新的读取命令。

此函数不选择/取消选择CS线。

成功时返回 0,否则返回负错误代码。

int nand_erase_op(struct nand_chip *chip, unsigned int eraseblock)

执行擦除操作

参数

struct nand_chip *chip

NAND 芯片

unsigned int eraseblock

要擦除的块

描述

此函数发送ERASE命令并等待NAND准备就绪后返回。此函数不选择/取消选择CS线。

成功时返回 0,否则返回负错误代码。

int nand_reset_op(struct nand_chip *chip)

执行重置操作

参数

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 字段。这是错误的,因为数据指令可能会被分割。

返回要发送/接收的数据块的长度。

int nand_reset(struct nand_chip *chip, int chipnr)

重置和初始化NAND设备

参数

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

调用者需要将OOB数据读取到chip->oob_poi

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

调用者需要将OOB数据读取到chip->oob_poi

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页面读取,从OOB区域读取ECC数据

参数

struct nand_chip *chip

NAND芯片信息结构

uint8_t *buf

用于存储读取数据的缓冲区

int oob_required

调用者需要将OOB数据读取到chip->oob_poi

int page

要读取的页码

描述

用于大页面芯片的硬件ECC,需要从OOB中提取ECC数据,然后再读取实际数据。

int nand_read_oob_std(struct nand_chip *chip, int page)

[可替换] 最常用的OOB数据读取函数

参数

struct nand_chip *chip

NAND芯片信息结构

int page

要读取的页码

int nand_write_oob_std(struct nand_chip *chip, int page)

[可替换] 最常用的OOB数据写入函数

参数

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配置。

  1. 如果ECC步长和ECC强度都已设置(通常由DT设置),则检查此控制器是否支持。

  2. 如果用户提供了nand-ecc-maximize属性,则选择最大ECC强度。

  3. 否则,尝试使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

可选的Flash ID表

描述

这会用默认值填充所有未初始化的函数指针。 读取Flash ID,并用适当的值填充mtd/chip结构。

void nand_cleanup(struct nand_chip *chip)

[NAND接口] 释放NAND设备持有的资源

参数

struct nand_chip *chip

NAND 芯片对象

提供的内部函数

本章包含NAND驱动程序内部函数的自动生成文档。 每个函数都有一个简短的描述,并标有[XXX]标识符。 有关说明,请参见“文档提示”一章。 标有[DEFAULT]的函数可能与板驱动程序开发人员相关。

void nand_release_device(struct nand_chip *chip)

[通用] 释放芯片

参数

struct nand_chip *chip

NAND 芯片对象

描述

释放芯片锁并唤醒任何等待设备的人。

int nand_bbm_get_next_page(struct nand_chip *chip, int page)

获取坏块标记的下一页

参数

struct nand_chip *chip

NAND 芯片对象

int page

开始检查坏块标记使用的第一页

描述

返回一个整数,该整数对应于块内的页偏移量,用于存储坏块标记的页。 如果没有更多页面可用,则返回-EINVAL。

int nand_block_bad(struct nand_chip *chip, loff_t ofs)

[默认] 从芯片读取坏块标记

参数

struct nand_chip *chip

NAND 芯片对象

loff_t ofs

从设备起始位置的偏移量

描述

检查块是否损坏。

bool nand_region_is_secured(struct nand_chip *chip, loff_t offset, u64 size)

检查区域是否安全

参数

struct nand_chip *chip

NAND 芯片对象

loff_t offset

要检查的区域的偏移量

u64 size

要检查的区域的大小

描述

通过将偏移量和大小与从DT获得的受保护区域列表进行比较,来检查该区域是否受保护。 如果该区域受保护,则返回true,否则返回false。

void nand_get_device(struct nand_chip *chip)

[通用] 获取所选访问的芯片

参数

struct nand_chip *chip

NAND 芯片结构体

描述

锁定设备及其控制器以进行独占访问

int nand_check_wp(struct nand_chip *chip)

[通用] 检查芯片是否受到写保护

参数

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 ops结构

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写入带外。

int nand_default_block_markbad(struct nand_chip *chip, loff_t ofs)

[默认] 通过坏块标记将块标记为坏块

参数

struct nand_chip *chip

NAND 芯片对象

loff_t ofs

从设备起始位置的偏移量

描述

这是默认实现,可以由硬件特定的驱动程序覆盖。 它提供了将坏块标记写入块的详细信息。

int nand_markbad_bbm(struct nand_chip *chip, loff_t ofs)

通过更新BBM来标记块

参数

struct nand_chip *chip

NAND 芯片对象

loff_t ofs

要标记为坏块的块的偏移量

int nand_block_markbad_lowlevel(struct nand_chip *chip, loff_t ofs)

将块标记为坏块

参数

struct nand_chip *chip

NAND 芯片对象

loff_t ofs

从设备起始位置的偏移量

描述

此函数执行通用的NAND坏块标记步骤(即,坏块表和/或标记)。 我们只允许硬件驱动程序指定如何将坏块标记写入OOB(chip->legacy.block_markbad)。

我们按以下顺序尝试操作

  1. 擦除受影响的块,以允许干净地写入OOB标记

  2. 将坏块标记写入受影响块的OOB区域(除非存在标志NAND_BBT_NO_OOB_BBM)

  3. 更新BBT

请注意,我们保留在(2)或(3)中遇到的第一个错误,完成这些过程,并在最后转储该错误。

int nand_block_isreserved(struct mtd_info *mtd, loff_t ofs)

[通用] 检查块是否标记为保留。

参数

struct mtd_info *mtd

MTD设备结构

loff_t ofs

从设备起始位置的偏移量

描述

检查该块是否标记为保留。

int nand_block_checkbad(struct nand_chip *chip, loff_t ofs, int allowbbt)

[通用] 检查块是否标记为坏块

参数

struct nand_chip *chip

NAND 芯片对象

loff_t ofs

从设备起始位置的偏移量

int allowbbt

1,如果允许访问 bbt 区域

描述

检查块是否损坏。可以通过读取坏块表或调用扫描函数来检查。

void panic_nand_wait(struct nand_chip *chip, unsigned long timeo)

[通用] 等待命令完成

参数

struct nand_chip *chip

NAND 芯片结构体

unsigned long timeo

超时

描述

等待命令完成。这是 nand_wait 的辅助函数,用于在中断上下文中调用。当发生 panic 并尝试通过 mtdoops 写入 oops 时可能会发生这种情况。

int nand_reset_interface(struct nand_chip *chip, int chipnr)

重置数据接口和时序

参数

struct nand_chip *chip

NAND 芯片

int chipnr

内部芯片ID

描述

将数据接口和时序重置为 ONFI 模式 0。

成功返回 0,否则返回负错误代码。

int nand_setup_interface(struct nand_chip *chip, int chipnr)

设置最佳数据接口和时序

参数

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 信息中检索支持的时序模式。

int nand_choose_interface_config(struct nand_chip *chip)

查找最佳数据接口和时序

参数

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)

执行 READ PARAMETER PAGE 操作

参数

struct nand_chip *chip

NAND 芯片

u8 page

要读取的参数页

void *buf

用于存储数据的缓冲区

unsigned int len

缓冲区长度

描述

此函数发出 READ PARAMETER PAGE 操作。此函数不选择/取消选择 CS 线。

成功时返回 0,否则返回负错误代码。

int nand_set_features_op(struct nand_chip *chip, u8 feature, const void *data)

执行 SET FEATURES 操作

参数

struct nand_chip *chip

NAND 芯片

u8 feature

功能 ID

const void *data

4 字节数据

描述

此函数发送 SET FEATURES 命令并等待 NAND 准备就绪后再返回。此函数不选择/取消选择 CS 线。

成功时返回 0,否则返回负错误代码。

int nand_get_features_op(struct nand_chip *chip, u8 feature, void *data)

执行 GET FEATURES 操作

参数

struct nand_chip *chip

NAND 芯片

u8 feature

功能 ID

void *data

4 字节数据

描述

此函数发送 GET FEATURES 命令并等待 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** 将更新为要传递给控制器驱动程序的指令集。

int nand_get_features(struct nand_chip *chip, int addr, u8 *subfeature_param)

执行 GET_FEATURE 的包装器

参数

struct nand_chip *chip

NAND芯片信息结构

int addr

功能地址

u8 *subfeature_param

子功能参数,一个四字节数组

描述

成功返回 0,否则返回负错误。如果操作无法处理,则返回 -ENOTSUPP。

int nand_set_features(struct nand_chip *chip, int addr, u8 *subfeature_param)

执行 SET_FEATURE 的包装器

参数

struct nand_chip *chip

NAND芯片信息结构

int addr

功能地址

u8 *subfeature_param

子功能参数,一个四字节数组

描述

成功返回 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 实现中提取的,只是 nand_check_erased_buf 函数会在位翻转次数超过 bitflips_threshold 值时在测试整个缓冲区之前退出。

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

调用者需要将OOB数据读取到chip->oob_poi

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

调用者需要将OOB数据读取到chip->oob_poi

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

调用者需要将OOB数据读取到chip->oob_poi

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

调用者需要将OOB数据读取到chip->oob_poi

int page

要读取的页码

描述

不适用于需要特殊 oob 布局的 syndrome 计算 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

调用者需要将OOB数据读取到chip->oob_poi

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 ops结构

size_t len

要传输的 oob 的大小

int nand_setup_read_retry(struct nand_chip *chip, int retry_mode)

[内部] 设置 READ RETRY 模式

参数

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 ops结构

描述

内部函数。在持有 chip 的情况下调用。

int nand_read_oob_syndrome(struct nand_chip *chip, int page)

[可替换] 用于带有校验位的 HW ECC 的 OOB 数据读取函数

参数

struct nand_chip *chip

NAND芯片信息结构

int page

要读取的页码

int nand_write_oob_syndrome(struct nand_chip *chip, int page)

[可替换] 用于带有校验位的 HW ECC 的 OOB 数据写入函数 - 仅适用于大页面闪存

参数

struct nand_chip *chip

NAND芯片信息结构

int page

要写入的页码

int nand_do_read_oob(struct nand_chip *chip, loff_t from, struct mtd_oob_ops *ops)

[内部] NAND 读取带外数据

参数

struct nand_chip *chip

NAND 芯片对象

loff_t from

读取的偏移量

struct mtd_oob_ops *ops

oob 操作描述结构

描述

从备用区域读取 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

oob 操作描述结构

描述

使用 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

擦除指令

描述

擦除一个或多个块。

int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr, int allowbbt)

[内部] 擦除块

参数

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 字段。

这个辅助函数曾经直接从控制器驱动程序调用,这些驱动程序需要在 nand_scan_tail() 之前调整一些与 ECC 相关的参数。 这种分离阻止了在此阶段进行动态分配,这很不方便,并且为了 ->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 设置。

int nand_scan_tail(struct nand_chip *chip)

扫描 NAND 设备

参数

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

坏块表镜像的描述符

描述

从给定页开始读取所有芯片的坏块表。我们假设坏块位是连续的。

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 选项时适用

描述

通过扫描设备以寻找给定的好/坏块识别模式来创建坏块表。

int search_bbt(struct nand_chip *this, uint8_t *buf, struct nand_bbt_descr *td)

[通用] 扫描设备以寻找特定的坏块表

参数

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

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

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 表示全部

描述

(重新)写入坏块表。

int nand_memory_bbt(struct nand_chip *this, struct nand_bbt_descr *bd)

[通用] 创建基于内存的坏块表

参数

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,则需要创建。 如果缺少一个表或一个表的版本号小于另一个表,则需要更新。

int nand_update_bbt(struct nand_chip *this, loff_t offs)

更新坏块表

参数

struct nand_chip *this

NAND 设备

loff_t offs

新标记的块的偏移量

描述

该函数更新坏块表。

void mark_bbt_region(struct nand_chip *this, struct nand_bbt_descr *td)

[通用] 标记坏块表区域

参数

struct nand_chip *this

NAND 设备

struct nand_bbt_descr *td

坏块表描述符

描述

坏块表区域被标记为“坏”以防止意外擦除/写入。 这些区域由标记 0x02 标识。

void verify_bbt_descr(struct nand_chip *this, struct nand_bbt_descr *bd)

验证坏块描述

参数

struct nand_chip *this

NAND 设备

struct nand_bbt_descr *bd

要验证的表

描述

此函数对坏块描述表执行一些健全性检查。

int nand_scan_bbt(struct nand_chip *this, struct nand_bbt_descr *bd)

[NAND 接口] 扫描,查找,读取并可能创建坏块表

参数

struct nand_chip *this

NAND 设备

struct nand_bbt_descr *bd

好/坏块搜索模式的描述符

描述

该函数检查是否已存在坏块表。 如果没有,它会扫描设备以查找制造商标记的好/坏块,并将坏块表写入选定的位置。

坏块表内存在这里分配。 必须通过调用 nand_free_bbt 函数来释放它。

int nand_create_badblock_pattern(struct nand_chip *this)

[内部] 创建 BBT 描述符结构

参数

struct nand_chip *this

要为其创建描述符的 NAND 芯片

描述

此函数基于 **this** 的属性,分配并初始化一个用于 BBM 检测的 nand_bbt_descr。 新的描述符存储在 this->badblock_pattern 中。 因此,传递给此函数时,this->badblock_pattern 应为 NULL。

int nand_isreserved_bbt(struct nand_chip *this, loff_t offs)

[NAND 接口] 检查一个块是否被保留

参数

struct nand_chip *this

NAND 芯片对象

loff_t offs

设备中的偏移量

int nand_isbad_bbt(struct nand_chip *this, loff_t offs, int allowbbt)

[NAND 接口] 检查一个块是否为坏块

参数

struct nand_chip *this

NAND 芯片对象

loff_t offs

设备中的偏移量

int allowbbt

允许访问坏块表区域

int nand_markbad_bbt(struct nand_chip *this, loff_t offs)

[NAND 接口] 在 BBT 中将一个块标记为坏块

参数

struct nand_chip *this

NAND 芯片对象

loff_t offs

坏块的偏移量

致谢

以下人员为 NAND 驱动程序做出了贡献

  1. Steven J. Hillsjhill@realitydiluted.com

  2. David Woodhousedwmw2@infradead.org

  3. Thomas Gleixnertglx@linutronix.de

许多用户提供了错误修复,改进和帮助进行测试。非常感谢。

以下人员为本文档做出了贡献

  1. Thomas Gleixnertglx@linutronix.de