当前位置: 首页 > news >正文

青海旭云网络做网站需要多少钱全国信用企业信息查询系统

青海旭云网络做网站需要多少钱,全国信用企业信息查询系统,只做网站的人员工资,北京建网站找哪个公司文章目录 1. 前言2. NAND 初始化3. 访问 NAND 设备3.1 查看 NAND 设备信息3.1.1 查看 NAND 设备基本信息3.1.2 查看 NAND 设备 MTD 分区3.1.3 查看 NAND 设备坏块 3.2 NAND 擦除操作3.3 NAND 写操作3.4 NAND 读操作3.5 其它 NAND 操作 1. 前言 限于作者能力水平,本…

文章目录

  • 1. 前言
  • 2. NAND 初始化
  • 3. 访问 NAND 设备
    • 3.1 查看 NAND 设备信息
      • 3.1.1 查看 NAND 设备基本信息
      • 3.1.2 查看 NAND 设备 MTD 分区
      • 3.1.3 查看 NAND 设备坏块
    • 3.2 NAND 擦除操作
    • 3.3 NAND 写操作
    • 3.4 NAND 读操作
    • 3.5 其它 NAND 操作

1. 前言

限于作者能力水平,本文可能存在谬误,因此而给读者带来的损失,作者不做任何承诺。

2. NAND 初始化

下面以 Micron MT29F2G08AAD 型号的 Nand Flash 为例,说明 ARMv7 架构下 U-BootNand Flash 设备的初始化过程。首先,可以将相关代码划分为 U-Boot NAND 驱动硬件无关通用部分硬件相关的 NAND FLASH 以及其 控制器 驱动 两部分。另外,抽象层次上,U-BootNor Flash,Nand Flash 等类型设备,统一抽象为 MTD(Memory Technology Device) 类型设备,对这些类型设备的访问,都是通过 MTD 接口来间接进行。

board_init_r() /* common/board_r.c *//* 特定 板型 初始化:这里重点关注 NAND 控制器 的 初始化 */board_init() /* board/myirtech/myd_c335x/myd_c335x.c */...gpmc_init();/* putting a blanket check on GPMC based on ZeBu for now */gpmc_cfg = (struct gpmc *)GPMC_BASE;/* NAND 控制器 的一些寄存器配置 */...initr_nand()nand_init() /* drivers/mtd/nand/nand.c */nand_init_chip()struct mtd_info *mtd;#ifndef CONFIG_DM_NANDstruct nand_chip *nand = &nand_chip[i];ulong base_addr = base_address[i];#endif...mtd = &nand_info[i]; /* NAND 设备 的 MTD 数据对象 */mtd->priv = nand; /* MTD NAND 设备数据 */nand->IO_ADDR_R = nand->IO_ADDR_W = (void  __iomem *)base_addr; /* NAND 设备 IO 地址空间 *//* 1. 特定 板型 的 NAND 初始化 */if (board_nand_init(nand)) /* drivers/mtd/nand/omap_gpmc.c */return;/* 2. 扫描识别并配置 NAND 控制器 上 挂接的 NAND 设备 */if (nand_scan(mtd, maxchips))return;/* 3. 注册 扫描到的、挂接在 NAND 控制器 上 NAND 设备 */nand_register(i);/* 1. 特定 板型 的 NAND 初始化 */
board_nand_init(nand).../** xloader/Uboot's gpmc configuration would have configured GPMC for* nand type of memory. The following logic scans and latches on to the* first CS with NAND type memory.* TBD: need to make this logic generic to handle multiple CS NAND* devices.*/while (cs < GPMC_MAX_CS) {/* Check if NAND type is set */if ((readl(&gpmc_cfg->cs[cs].config1) & 0xC00) == 0x800) {/* Found it!! */break;}cs++;}...nand->IO_ADDR_R = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat;nand->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd;...nand->priv = &omap_nand_info[cs];nand->cmd_ctrl = omap_nand_hwcontrol;nand->options |= NAND_NO_PADDING | NAND_CACHEPRG;nand->chip_delay = 100;nand->ecc.layout = &omap_ecclayout; /* NAND ECC 数据 layout */...nand->options &= ~NAND_BUSWIDTH_16; /* 8 位数据宽度 */.../* select ECC scheme */
#if defined(CONFIG_NAND_OMAP_ECCSCHEME)/* NAND ECC 模式选择 */err = omap_select_ecc_scheme(nand, CONFIG_NAND_OMAP_ECCSCHEME,CONFIG_SYS_NAND_PAGE_SIZE, CONFIG_SYS_NAND_OOBSIZE);...switch (ecc_scheme) {...case OMAP_ECC_BCH8_CODE_HW: /* ECC 使用 硬件 BCH8 码 */#ifdef CONFIG_NAND_OMAP_ELM.../* intialize ELM for ECC error detection */elm_init(); /* ECC 错误检测硬件模块 ELM 初始化 */.../* populate ecc specific fields */nand->ecc.mode  = NAND_ECC_HW; /* 硬件 ECC */nand->ecc.strength = 8;nand->ecc.size  = SECTOR_BYTES;nand->ecc.bytes  = 14;/* ECC 操作接口 */nand->ecc.hwctl  = omap_enable_hwecc;nand->ecc.correct = omap_correct_data_bch;nand->ecc.calculate = omap_calculate_ecc;nand->ecc.read_page = omap_read_page_bch;...#else...#endif...}...info->ecc_scheme = ecc_scheme; /* OMAP_ECC_BCH8_CODE_HW */return 0;
#else...
#endif#ifdef CONFIG_NAND_OMAP_GPMC_PREFETCHnand->read_buf = omap_nand_read_prefetch;
#else...
#endifnand->dev_ready = omap_dev_ready;return 0;/* 2. 扫描识别并配置 NAND 控制器 上 挂接的 NAND 设备 */
nand_scan(mtd, maxchips) /* drivers/mtd/nand/nand_base.c */.../* 扫描识别 NAND 设备 和 参数, 设置操作接口 等 */ret = nand_scan_ident(mtd, maxchips, NULL);...struct nand_chip *chip = mtd->priv;struct nand_flash_dev *type;/* Set the default functions */nand_set_defaults(chip, chip->options & NAND_BUSWIDTH_16); /* 设置 NAND 设备缺省操作接口(读写等) */.../* check, if a user supplied command function given */if (chip->cmdfunc == NULL)chip->cmdfunc = nand_command;/* check, if a user supplied wait function given */if (chip->waitfunc == NULL)chip->waitfunc = nand_wait;if (!chip->select_chip)chip->select_chip = nand_select_chip;.../* If called twice, pointers that depend on busw may need to be reset */if (!chip->read_byte || chip->read_byte == nand_read_byte)chip->read_byte = busw ? nand_read_byte16 : nand_read_byte;if (!chip->read_word)chip->read_word = nand_read_word;if (!chip->block_bad)chip->block_bad = nand_block_bad; /* 坏块 判定接口 */if (!chip->block_markbad)chip->block_markbad = nand_default_block_markbad;if (!chip->write_buf || chip->write_buf == nand_write_buf)chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;if (!chip->write_byte || chip->write_byte == nand_write_byte)chip->write_byte = busw ? nand_write_byte16 : nand_write_byte;if (!chip->read_buf || chip->read_buf == nand_read_buf)chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;if (!chip->scan_bbt)chip->scan_bbt = nand_default_bbt; /* 坏块 选择/建立 接口 */.../* Read the flash type *//* 识别 NAND 设备类型 */type = nand_get_flash_type(mtd, chip, &nand_maf_id,&nand_dev_id, table);...u8 id_data[8];/* Select the device */chip->select_chip(mtd, 0);/** Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)* after power-up.*/chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); /* 复位 NAND 设备 ID *//* Send the command for reading device ID */chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); /* 发送读取 NAND 设备 ID 命令 *//* Read manufacturer and device IDs */*maf_id = chip->read_byte(mtd); /* 读取 NAND 设备 制造商 ID */*dev_id = chip->read_byte(mtd); /* 读取 NAND 设备 ID */chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); /* 读取 NAND 芯片 ID *//* Read entire ID string */for (i = 0; i < 8; i++)id_data[i] = chip->read_byte(mtd);...if (!type)type = nand_flash_ids; /* 预定义的 NAND 设备列表: drivers/mtd/nand/nand_ids.c *//** 对比 读取到的 NAND 设备 ID 和 预定义表 nand_flash_ids[], * 看是否能找到匹配的表项.*/for (; type->name != NULL; type++) {if (is_full_id_nand(type)) { /* 对于 全 ID 标识的设备, 进行全 ID 匹配 */if (find_full_id_nand(mtd, chip, type, id_data, &busw)) /* 如果 是 设备全 ID 匹配, */goto ident_done; /* 完成识别工作 */} else if (*dev_id == type->dev_id) { /* 如果 不是 设备全 ID 匹配, 而是 设备 ID 匹配 */break; /* 做进一步的识别工作(如符合 ONFI/JEDEC 规范的设备匹配工作) */}}/* 可能满足 ONFI/JEDEC 规范 的 设备 识别 */chip->onfi_version = 0;if (!type->name || !type->pagesize) {/* Check if the chip is ONFI compliant */if (nand_flash_detect_onfi(mtd, chip, &busw)) /* 识别到 符合 ONFI 接口规范 的 NAND 设备 */goto ident_done; /* 完成识别工作 *//* Check if the chip is JEDEC compliant */if (nand_flash_detect_jedec(mtd, chip, &busw)) /* 识别到 符合 JEDEC 接口规范 的 NAND 设备 */goto ident_done;}/* * 目前无法识别设备:* . 无法从预定义 NAND 芯片列表 nand_flash_ids[] 匹配设备* . 设备不符合 ONFI/JEDEC 接口规范*/if (!type->name)return ERR_PTR(-ENODEV);if (!mtd->name)mtd->name = type->name; /* 设置 MTD NAND 设备名称 *//* 设置 NAND 设备容量 */chip->chipsize = (uint64_t)type->chipsize << 20;/* 设置 NAND 的 page size, OOB size, erase size */if (!type->pagesize && chip->init_size) {/* Set the pagesize, oobsize, erasesize by the driver */busw = chip->init_size(mtd, chip, id_data);} else if (!type->pagesize) {/* Decode parameters from extended ID */nand_decode_ext_id(mtd, chip, id_data, &busw);} else {nand_decode_id(mtd, chip, type, id_data, &busw);}/* Get chip options */chip->options |= type->options; /* 设置 NAND 设备选项 */...ident_done:.../* 坏块管理相关配置 */nand_decode_bbm_options(mtd, chip, id_data);int maf_id = id_data[0];/* Set the bad block position */if (mtd->writesize > 512 || (chip->options & NAND_BUSWIDTH_16))chip->badblockpos = NAND_LARGE_BADBLOCK_POS;elsechip->badblockpos = NAND_SMALL_BADBLOCK_POS;/** Bad block marker is stored in the last page of each block on Samsung* and Hynix MLC devices; stored in first two pages of each block on* Micron devices with 2KiB pages and on SLC Samsung, Hynix, Toshiba,* AMD/Spansion, and Macronix.  All others scan only the first page.*/if (!nand_is_slc(chip) &&(maf_id == NAND_MFR_SAMSUNG ||maf_id == NAND_MFR_HYNIX))/* 三星 和 海力士 的 非 SLC 类型设备, 坏块标记存储在每个 block 的最后一个 page */chip->bbt_options |= NAND_BBT_SCANLASTPAGE;else if ((nand_is_slc(chip) &&(maf_id == NAND_MFR_SAMSUNG ||maf_id == NAND_MFR_HYNIX ||maf_id == NAND_MFR_TOSHIBA ||maf_id == NAND_MFR_AMD ||maf_id == NAND_MFR_MACRONIX)) ||(mtd->writesize == 2048 &&maf_id == NAND_MFR_MICRON))/* 一些厂家的 SLC 类型设备,坏块标记存储在 block 的 第1 和 第2 个 page */chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;...chip->badblockbits = 8;chip->erase = single_erase; /* 设置 擦除 接口 *//* Do not replace user supplied command function! */if (mtd->writesize > 512 && chip->cmdfunc == nand_command)chip->cmdfunc = nand_command_lp; /* 覆盖命令为 大 page 接口 *//* 报告设备信息 (需要开启 CONFIG_MTD_DEBUG) */pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",*maf_id, *dev_id);...pr_info("%d MiB, %s, erase size: %d KiB, page size: %d, OOB size: %d\n",(int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC",mtd->erasesize >> 10, mtd->writesize, mtd->oobsize);return type; /* 返回是被的 NAND 设备类型 *//* 通过 NAND 控制器,选择 NAND 芯片 */chip->select_chip(mtd, -1);/* Store the number of chips and calc total size for mtd */chip->numchips = i;mtd->size = i * chip->chipsize; /* 记录 MTD NAND 设备容量 */return 0;if (!ret)/** 扫描识别收尾工作: * 从 前面 扫描识别到的 NAND 设备 和 参数,* 为 NAND 设备建立缓冲,设置 NAND 设备对应的 MTD NAND 设备对象。*/ret = nand_scan_tail(mtd);int i;struct nand_chip *chip = mtd->priv;struct nand_ecc_ctrl *ecc = &chip->ecc;struct nand_buffers *nbuf;/* 为 NAND 设备 创建 缓冲: ECC, 数据 */if (!(chip->options & NAND_OWN_BUFFERS)) {nbuf = kzalloc(sizeof(struct nand_buffers), GFP_KERNEL);chip->buffers = nbuf;} else {if (!chip->buffers)return -ENOMEM;}/* Set the internal oob buffer location, just after the page data *//* 和 NAND 页面存储一样, OOB 缓冲 紧邻 page 缓冲之后 */chip->oob_poi = chip->buffers->databuf + mtd->writesize;...switch (ecc->mode) {...case NAND_ECC_HW: /* 设置没有配置的 ECC 接口 */if (!ecc->read_page)ecc->read_page = nand_read_page_hwecc;if (!ecc->write_page)ecc->write_page = nand_write_page_hwecc;if (!ecc->read_page_raw)ecc->read_page_raw = nand_read_page_raw;if (!ecc->write_page_raw)ecc->write_page_raw = nand_write_page_raw;if (!ecc->read_oob)ecc->read_oob = nand_read_oob_std;if (!ecc->write_oob)ecc->write_oob = nand_write_oob_std;if (!ecc->read_subpage)ecc->read_subpage = nand_read_subpage;if (!ecc->write_subpage)ecc->write_subpage = nand_write_subpage_hwecc;...}/* For many systems, the standard OOB write also works for raw */if (!ecc->read_oob_raw)ecc->read_oob_raw = ecc->read_oob;if (!ecc->write_oob_raw)ecc->write_oob_raw = ecc->write_oob;// 一些其它 ECC 相关配置.../* Initialize state */chip->state = FL_READY; /* NAND 设备标记为 READY 状态 */.../* Fill in remaining MTD driver data */mtd->type = nand_is_slc(chip) ? MTD_NANDFLASH : MTD_MLCNANDFLASH; /* 设置 MTD NAND 设备类型: SLC 或 MLC */mtd->flags = (chip->options & NAND_ROM) ? MTD_CAP_ROM :MTD_CAP_NANDFLASH; /* MTD NAND 读写属性设置:只读、可读写 *//* 设置 MTD NAND 设备接口: 调用 NAND 设备接口 */mtd->_erase = nand_erase;mtd->_read = nand_read;mtd->_write = nand_write;mtd->_panic_write = panic_nand_write;mtd->_read_oob = nand_read_oob;mtd->_write_oob = nand_write_oob;mtd->_sync = nand_sync;mtd->_lock = NULL;mtd->_unlock = NULL;mtd->_block_isreserved = nand_block_isreserved;mtd->_block_isbad = nand_block_isbad;mtd->_block_markbad = nand_block_markbad;mtd->writebufsize = mtd->writesize;// MTD NAND ECC 相关设置...return 0;return ret;/* 3. 注册 扫描到的、挂接在 NAND 控制器 上 NAND 设备 */
nand_register(i);struct mtd_info *mtd;mtd = get_nand_dev_by_index(devnum);sprintf(dev_name[devnum], "nand%d", devnum);mtd->name = dev_name[devnum];#ifdef CONFIG_MTD_DEVICE/** Add MTD device so that we can reference it later* via the mtdcore infrastructure (e.g. ubi).*/add_mtd_device(mtd);
#endiftotal_nand_size += mtd->size / 1024;if (nand_curr_device == -1)nand_curr_device = devnum; /* 设置当前 NAND 设备编号 */return 0;

3. 访问 NAND 设备

3.1 查看 NAND 设备信息

3.1.1 查看 NAND 设备基本信息

U-Boot 提供一些 nand info 命令,可以查看 NAND 设备信息:

# nand infoDevice 0: nand0, sector size 128 KiBPage size       2048 bOOB size          64 bErase size    131072 bsubpagesize      512 boptions     0x4000000cbbt options 0x    8000

从上面看到,Nand Flash 设备:

o page 是 2KB 大小
o page 后跟的 OOB(Spare area)64 Bytes
o 擦除 size 是 128KB,也就是 block size

3.1.2 查看 NAND 设备 MTD 分区

前面有说过,U-Boot 将 NAND 抽象为 MTD 设备进行访问,通过 mtdparts 命令,可以查看 NAND 设备的分区信息:

# mtdpartsdevice nand0 <nand.0>, # parts = 11#: name                size            offset          mask_flags0: NAND.SPL            0x00020000      0x00000000      01: NAND.SPL.backup1    0x00020000      0x00020000      02: NAND.SPL.backup2    0x00020000      0x00040000      03: NAND.SPL.backup3    0x00020000      0x00060000      04: NAND.u-boot-spl-os  0x00040000      0x00080000      05: NAND.u-boot         0x00100000      0x000c0000      06: NAND.u-boot-env     0x00020000      0x001c0000      07: NAND.u-boot-env.backup10x00020000   0x001e0000      08: NAND.kernel         0x00800000      0x00200000      09: NAND.rootfs         0x0d600000      0x00a00000      0
10: NAND.userdata       0x02000000      0x0e000000      0active partition: nand0,0 - (NAND.SPL) 0x00020000 @ 0x00000000defaults:
mtdids  : nand0=nand.0
mtdparts: mtdparts=nand.0:128k(NAND.SPL),128k(NAND.SPL.backup1),128k(NAND.SPL.backup2),128k(NAND.SPL.backup3),256k(NAND.u-boot-spl-os),1m(NAND.u-boot),128k(NAND.u-boot-env),128k(NAND.u-boot-env.backup1),8m(NAND.kernel),214m(NAND.rootfs),-(NAND.userdata)

3.1.3 查看 NAND 设备坏块

# nand badDevice 0 bad blocks:03e40000086c0000

发现了两个坏块,数据标记了它们的字节偏移位置。

3.2 NAND 擦除操作

通过 nand erase 命令,可以对 NAND 发起对 NAND 的擦除操作:

# nand erase c0000 100000

其中参数 c0000要擦除的起始位置,相对于 NAND 设备开始位置的字节偏移100000要擦除的长度字节数。这两个参数都是十六进制数字。来看一下擦除过程的具体实现:

do_nand() /* cmd/nand.c */...nand_info_t *nand;...int dev = nand_curr_device; /* 默认选择当前 NAND 设备进行操作 */......cmd = argv[1]; /* "erase" */...nand = get_nand_dev_by_index(dev); /* 获取 NAND 设备 */if (strncmp(cmd, "erase", 5) == 0 || strncmp(cmd, "scrub", 5) == 0) {nand_erase_options_t opts;......printf("\nNAND %s: ", cmd); /* "NAND erase: " *//* 解析 擦除起始位置 和 长度 参数 到 @off 和 @size */if (mtd_arg_off_size(argc - o, argv + o, &dev, &off, &size,&maxsize, MTD_DEV_TYPE_NAND,nand->size) != 0)return 1;/* 切换到 要操作 的 目标 NAND 设备 */if (set_dev(dev))return 1;nand = get_nand_dev_by_index(dev);memset(&opts, 0, sizeof(opts));opts.offset = off;opts.length = size;...ret = nand_erase_opts(nand, &opts); /* 擦除操作 */...}ret = nand_erase_opts(nand, &opts); /* drivers/mtd/nand/nand_util.c */.../** @erase_length:要擦除的 block 数目* @erased_length: 已经擦除的 block 数目*/unsigned long erase_length, erased_length; /* in blocks */...erase_length = lldiv(opts->length + meminfo->erasesize - 1,meminfo->erasesize); /* 向上对齐到 erase size (block 大小) */...for (erased_length = 0;erased_length < erase_length;erase.addr += meminfo->erasesize) {...if (!opts->scrub) {/* 检查位于 @ofs 位置的 block 是不是坏块 */int ret = mtd_block_isbad(meminfo, erase.addr);if (ret > 0) { /* 坏块 */...if (!opts->spread)erased_length++; /* 非 nand erase.spread 命令, 坏块也计入擦除 block 数目 */continue; /* 跳过坏块: 坏块不做擦除动作,擦除坏块是非法操作 */}}erased_length++; /* 已擦除 block 数目 +1 */result = mtd_erase(meminfo, &erase); /* 擦除当前块 */...return mtd->_erase(mtd, instr);nand_erase()return nand_erase_nand(mtd, instr, 0);...struct nand_chip *chip = mtd->priv; /* MTD 转入 NAND 层操作 */.../* Grab the lock and see if the device is available */nand_get_device(mtd, FL_ERASING);/* Shift to get first page */page = (int)(instr->addr >> chip->page_shift); /* 擦除位置转换为 page 位置 */chipnr = (int)(instr->addr >> chip->chip_shift);/* Calculate pages in each block */pages_per_block = 1 << (chip->phys_erase_shift - chip->page_shift);/* Select the NAND device */chip->select_chip(mtd, chipnr);/* Loop through the pages */len = instr->len;instr->state = MTD_ERASING;while (len) {...status = chip->erase(mtd, page & chip->pagemask);single_erase()struct nand_chip *chip = mtd->priv;/* Send commands to erase a block *//* 发送 page 擦除操作命令 */chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);/* 等待擦除操作完成 */return chip->waitfunc(mtd, chip);/* Increment page address and decrement length *//* 移向下一个 page */len -= (1ULL << chip->phys_erase_shift);page += pages_per_block;...}instr->state = MTD_ERASE_DONE;...}

3.3 NAND 写操作

假定以命令 nand write 0x82000000 c0000 ${filesize} 发起写操作写操作基本流程和擦除操作差不多,来看细节:

do_nand()...if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) {...addr = (ulong)simple_strtoul(argv[2], NULL, 16); // 0x82000000read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */printf("\nNAND %s: ", read ? "read" : "write");s = strchr(cmd, '.');if (s && !strcmp(s, ".raw")) { // nand write.raw...}  else {// @off  = 0xc0000// @size = ${filesize}if (mtd_arg_off_size(argc - 3, argv + 3, &dev, &off,&size, &maxsize,MTD_DEV_TYPE_NAND,nand->size) != 0)return 1;if (set_dev(dev))return 1;...rwsize = size;if (!s || !strcmp(s, ".jffs2") ||!strcmp(s, ".e") || !strcmp(s, ".i")) {if (read)ret = nand_read_skip_bad(nand, off, &rwsize,NULL, maxsize,(u_char *)addr); /* 读取,会自动跳过坏块 */elseret = nand_write_skip_bad(nand, off, &rwsize,NULL, maxsize,(u_char *)addr,WITH_WR_VERIFY); /* 写入,会自动跳过坏块 */}}nand = get_nand_dev_by_index(dev);}nand_write_skip_bad()...size_t left_to_write = *length; /* 要写入的长度, 字节数 */...int need_skip;blocksize = nand->erasesize;/* 检查写入过程中, 要跳过的坏块数目 */need_skip = check_skip_len(nand, offset, *length, &used_for_write);...while (left_to_write > 0) {size_t block_offset = offset & (nand->erasesize - 1); /* 计算 block 内偏移 */.../* 写入时跳过坏块 */if (nand_block_isbad(nand, offset & ~(nand->erasesize - 1))) {printf("Skip bad block 0x%08llx\n",offset & ~(nand->erasesize - 1));offset += nand->erasesize - block_offset;continue;}/* 调整 写入 大小 */if (left_to_write < (blocksize - block_offset))write_size = left_to_write;elsewrite_size = blocksize - block_offset;/* 写入 block *//* * 注意前后的两个 nand_write() 不是同一个函数: * . 前一个 nand_write() 是 MTD 驱动层的 接口* . 后一个是 NAND 驱动层的 接口*/rval = nand_write(nand, offset, &truncated_write_size, p_buffer); /* drivers/mtd/mtcore.c */mtd_write()mtd->_write(mtd, to, len, retlen, buf);nand_write() /* drivers/mtd/nand/nand_base.c */struct mtd_oob_ops ops;nand_get_device(mtd, FL_WRITING);memset(&ops, 0, sizeof(ops));ops.len = len;ops.datbuf = (uint8_t *)buf;ops.mode = MTD_OPS_PLACE_OOB;ret = nand_do_write_ops(mtd, to, &ops); /* NAND 设备写操作 */*retlen = ops.retlen;nand_release_device(mtd);return ret;/* 写入后,再读回来验证一下数据是否正确 */if ((flags & WITH_WR_VERIFY) && !rval)rval = nand_verify(nand, offset,truncated_write_size, p_buffer);offset += write_size;p_buffer += write_size;...left_to_write -= write_size;}ret = nand_do_write_ops(mtd, to, &ops); /* NAND 设备写操作 */...struct nand_chip *chip = mtd->priv;uint32_t writelen = ops->len;......while (1) {int bytes = mtd->writesize; /* 按 page 写入 */...uint8_t *wbuf = buf; /* 数据 */...if (unlikely(oob)) {...} else {/* We still need to erase leftover OOB data */memset(chip->oob_poi, 0xff, mtd->oobsize); /* 没有指定 OOB 数据, 则将 Spare area 全部填充 0xff */}ret = chip->write_page(mtd, chip, column, bytes, wbuf,oob_required, page, cached,(ops->mode == MTD_OPS_RAW)); /* 写入一个 page 的数据 */nand_write_page()...chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);if (unlikely(raw))status = chip->ecc.write_page_raw(mtd, chip, buf, oob_required);else if (subpage)status = chip->ecc.write_subpage(mtd, chip, offset, data_len, buf, oob_required);else /* 这里只考虑这一种情形 */status = chip->ecc.write_page(mtd, chip, buf, oob_required);nand_write_page_hwecc()int i, eccsize = chip->ecc.size;int eccbytes = chip->ecc.bytes;int eccsteps = chip->ecc.steps;uint8_t *ecc_calc = chip->buffers->ecccalc;const uint8_t *p = buf; /* 要写入的数据 */uint32_t *eccpos = chip->ecc.layout->eccpos;/* 写数据到 NAND, 每次写 @eccsize 个字节 (@eccsize 是计算 ECC 的单元) */for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {chip->ecc.hwctl(mtd, NAND_ECC_WRITE);chip->write_buf(mtd, p, eccsize); /* 将数据写入到 NAND */chip->ecc.calculate(mtd, p, &ecc_calc[i]); /* 计算数据 @p 的 ECC, 记录到 ecc_calc[i] */}for (i = 0; i < chip->ecc.total; i++)chip->oob_poi[eccpos[i]] = ecc_calc[i];chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); /* 将 ECC 数据写入到 Spare area */return 0;/* 写完一个 page */cached = 0;if (!cached || !NAND_HAS_CACHEPROG(chip)) {chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);status = chip->waitfunc(mtd, chip);} else  {...}return 0;...writelen -= bytes;if (!writelen)break;...}...

3.4 NAND 读操作

可以通过 nand read 0x82000000 200000 800000 发起对 NAND 的操作:将 NAND 从 0x200000 位置开始的 0x800000 个字节,读取到内存地址 0x82000000 开始的位置。NAND 读操作入口函数为 nand_read_skip_bad() ,其逻辑和 nand_write_skip_bad() 非常相似,在此不再赘述。值得一提的是,nand_read_skip_bad() 读操作,会跳过坏块。

3.5 其它 NAND 操作

nand device // 输出当前 NAND 设备信息
nand device <dev> // 切换到 NAND 设备 dev
nand dump[.oob] <offset> // 导出 NAND page 和 OOB, 带 .oob 后缀仅导出 OOB
......
http://www.yayakq.cn/news/723790/

相关文章:

  • 建网站比较好出入青岛最新通知今天
  • 北京最大的网站建设有限公司3000ok新开传奇网站公益服
  • 做特效的网站百度百家模板wordpress
  • 无锡网站制作专业服务公司徐州公共资源建设交易平台
  • 江苏炒股配资网站开发国外建站网
  • 八年级信息网站怎么做华为网站建设方案模板
  • 宝塔网站建设计算机学习网站
  • 北大学风建设网站wdcp 快速迁移网站
  • 手机微网站怎么制作的家里笔记本做网站 怎么解析
  • 推进网站集约化建设的作用网站制作项目执行
  • 上海网站公司做t-shirt素材网站
  • 博客网站建设设计报告自己架设网站备案
  • 集思吧网站怎么做问卷平面设计的素材网站
  • 漯河哪里做网站网站制作网址
  • linux wordpress 建站教程免费企业名录数据
  • 网站管理权限怎么进去甘肃省城乡城乡建设厅网站首页
  • 网站开发 html手机网站 案例
  • 旅游网站设计开题报告电子商城网站开发合同
  • 南京网站制作步骤页面效果图
  • 衡水商城网站建设免费发布房源的平台
  • 做视频网站赚做视频网站赚学校网站规划方案
  • 做网站的哪里好网站建设中备案
  • 行业网站作用论坛详情页模板下载
  • 郑州做网站公司有多少钱天津网站建设58
  • 网站分页js中国菲律宾铁路项目
  • 专业设计服务网站公司网站建设费用科目
  • 广州网站设计公司兴田德润活动泉州企业免费建站
  • 增城区建设局网站莱芜网站建设案例
  • 做酒业网站的要求wordpress从哪里登录密码
  • 广州做网站哪个平台好南通企业网站排名