1. 简介

2. DTS

3. hisi_nfc_probe函数

3.1 获取dts中的资源

3.2 设置nand-chip结构体中必要的字段

3.3 nand_scan_ident扫描识别nand控制器

3.4 设置DMA相关的东西

3.5 ecc相关的配置

3.6 构造mtd结构体,并注册

4. nand_scan_tail

6. 参考文件


1. 简介

我们以drivers\mtd\nand\hisi504_nand.c来分析nand flash的驱动。

通过前文spi-nor子系统的研究,我们struct spi_nor结构体代表一个spi-nor的控制器设备。在nand的研究中,Linux使用struct nand_chip结构体来抽象nand control。

/*** struct nand_chip - NAND Private Flash Chip Data* @mtd:     MTD device registered to the MTD framework* @IO_ADDR_R:        [BOARDSPECIFIC] address to read the 8 I/O lines of the*         flash device* @IO_ADDR_W:      [BOARDSPECIFIC] address to write the 8 I/O lines of the*            flash device.* @read_byte:     [REPLACEABLE] read one byte from the chip* @read_word:     [REPLACEABLE] read one word from the chip* @write_byte:        [REPLACEABLE] write a single byte to the chip on the*           low 8 I/O lines* @write_buf:       [REPLACEABLE] write data from the buffer to the chip* @read_buf:       [REPLACEABLE] read data from the chip into the buffer* @select_chip:   [REPLACEABLE] select chip nr* @block_bad:      [REPLACEABLE] check if a block is bad, using OOB markers* @block_markbad:  [REPLACEABLE] mark a block bad* @cmd_ctrl:     [BOARDSPECIFIC] hardwarespecific function for controlling*          ALE/CLE/nCE. Also used to write command and address* @dev_ready:       [BOARDSPECIFIC] hardwarespecific function for accessing*            device ready/busy line. If set to NULL no access to*            ready/busy is available and the ready/busy information*         is read from the chip status register.* @cmdfunc:      [REPLACEABLE] hardwarespecific function for writing*            commands to the chip.* @waitfunc:      [REPLACEABLE] hardwarespecific function for wait on*            ready.* @setup_read_retry: [FLASHSPECIFIC] flash (vendor) specific function for*           setting the read-retry mode. Mostly needed for MLC NAND.* @ecc:        [BOARDSPECIFIC] ECC control structure* @buffers:       buffer structure for read/write* @buf_align:       minimum buffer alignment required by a platform* @hwcontrol:       platform-specific hardware control structure* @erase:      [REPLACEABLE] erase function* @scan_bbt:       [REPLACEABLE] function to scan bad block table* @chip_delay:       [BOARDSPECIFIC] chip dependent delay for transferring*          data from array to read regs (tR).* @state:        [INTERN] the current state of the NAND device* @oob_poi:       "poison value buffer," used for laying out OOB data*          before writing* @page_shift:       [INTERN] number of address bits in a page (column*          address bits).* @phys_erase_shift: [INTERN] number of address bits in a physical eraseblock* @bbt_erase_shift:    [INTERN] number of address bits in a bbt entry* @chip_shift:       [INTERN] number of address bits in one chip* @options:     [BOARDSPECIFIC] various chip options. They can partly*          be set to inform nand_scan about special functionality.*            See the defines for further explanation.* @bbt_options:    [INTERN] bad block specific options. All options used*          here must come from bbm.h. By default, these options*           will be copied to the appropriate nand_bbt_descr's.* @badblockpos:    [INTERN] position of the bad block marker in the oob*           area.* @badblockbits:  [INTERN] minimum number of set bits in a good block's*         bad block marker position; i.e., BBM == 11110111b is*         not bad when badblockbits == 7* @bits_per_cell:  [INTERN] number of bits per cell. i.e., 1 means SLC.* @ecc_strength_ds:    [INTERN] ECC correctability from the datasheet.*            Minimum amount of bit errors per @ecc_step_ds guaranteed*          to be correctable. If unknown, set to zero.* @ecc_step_ds: [INTERN] ECC step required by the @ecc_strength_ds,*           also from the datasheet. It is the recommended ECC step*            size, if known; if unknown, set to zero.* @onfi_timing_mode_default: [INTERN] default ONFI timing mode. This field is*               set to the actually used ONFI mode if the chip is*                  ONFI compliant or deduced from the datasheet if*                the NAND chip is not ONFI compliant.* @numchips:     [INTERN] number of physical chips* @chipsize:      [INTERN] the size of one chip for multichip arrays* @pagemask:     [INTERN] page number mask = number of (pages / chip) - 1* @pagebuf:       [INTERN] holds the pagenumber which is currently in*            data_buf.* @pagebuf_bitflips:  [INTERN] holds the bitflip count for the page which is*         currently in data_buf.* @subpagesize:  [INTERN] holds the subpagesize* @id:           [INTERN] holds NAND ID* @onfi_version: [INTERN] holds the chip ONFI version (BCD encoded),*            non 0 if ONFI supported.* @jedec_version:  [INTERN] holds the chip JEDEC version (BCD encoded),*           non 0 if JEDEC supported.* @onfi_params:   [INTERN] holds the ONFI page parameter when ONFI is*            supported, 0 otherwise.* @jedec_params:    [INTERN] holds the JEDEC parameter page when JEDEC is*          supported, 0 otherwise.* @max_bb_per_die:  [INTERN] the max number of bad blocks each die of a*            this nand device will encounter their life times.* @blocks_per_die:    [INTERN] The number of PEBs in a die* @data_interface: [INTERN] NAND interface timing information* @read_retries: [INTERN] the number of read retry modes supported* @onfi_set_features: [REPLACEABLE] set the features for ONFI nand* @onfi_get_features:  [REPLACEABLE] get the features for ONFI nand* @setup_data_interface: [OPTIONAL] setup the data interface and timing. If*             chipnr is set to %NAND_DATA_IFACE_CHECK_ONLY this*              means the configuration should not be applied but*              only checked.* @bbt:     [INTERN] bad block table pointer* @bbt_td:     [REPLACEABLE] bad block table descriptor for flash*         lookup.* @bbt_md:      [REPLACEABLE] bad block table mirror descriptor* @badblock_pattern:    [REPLACEABLE] bad block scan pattern used for initial*          bad block scan.* @controller:      [REPLACEABLE] a pointer to a hardware controller*           structure which is shared among multiple independent*           devices.* @priv:       [OPTIONAL] pointer to private chip data* @manufacturer:    [INTERN] Contains manufacturer information*/struct nand_chip {struct mtd_info mtd;void __iomem *IO_ADDR_R;void __iomem *IO_ADDR_W;uint8_t (*read_byte)(struct mtd_info *mtd);u16 (*read_word)(struct mtd_info *mtd);void (*write_byte)(struct mtd_info *mtd, uint8_t byte);void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);void (*select_chip)(struct mtd_info *mtd, int chip);int (*block_bad)(struct mtd_info *mtd, loff_t ofs);int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl);int (*dev_ready)(struct mtd_info *mtd);void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column,int page_addr);int(*waitfunc)(struct mtd_info *mtd, struct nand_chip *this);int (*erase)(struct mtd_info *mtd, int page);int (*scan_bbt)(struct mtd_info *mtd);int (*onfi_set_features)(struct mtd_info *mtd, struct nand_chip *chip,int feature_addr, uint8_t *subfeature_para);int (*onfi_get_features)(struct mtd_info *mtd, struct nand_chip *chip,int feature_addr, uint8_t *subfeature_para);int (*setup_read_retry)(struct mtd_info *mtd, int retry_mode);int (*setup_data_interface)(struct mtd_info *mtd, int chipnr,const struct nand_data_interface *conf);int chip_delay;unsigned int options;unsigned int bbt_options;int page_shift;int phys_erase_shift;int bbt_erase_shift;int chip_shift;int numchips;uint64_t chipsize;int pagemask;int pagebuf;unsigned int pagebuf_bitflips;int subpagesize;uint8_t bits_per_cell;uint16_t ecc_strength_ds;uint16_t ecc_step_ds;int onfi_timing_mode_default;int badblockpos;int badblockbits;struct nand_id id;int onfi_version;int jedec_version;union {struct nand_onfi_params  onfi_params;struct nand_jedec_params jedec_params;};u16 max_bb_per_die;u32 blocks_per_die;struct nand_data_interface *data_interface;int read_retries;flstate_t state;uint8_t *oob_poi;struct nand_hw_control *controller;struct nand_ecc_ctrl ecc;struct nand_buffers *buffers;unsigned long buf_align;struct nand_hw_control hwcontrol;uint8_t *bbt;struct nand_bbt_descr *bbt_td;struct nand_bbt_descr *bbt_md;struct nand_bbt_descr *badblock_pattern;void *priv;struct {const struct nand_manufacturer *desc;void *priv;} manufacturer;
};

2. DTS

 nand: nand@4020000 { compatible = "hisilicon,504-nfc";reg = <0x4020000 0x10000>, <0x5000000 0x1000>;interrupts = <0 379 4>;nand-bus-width = <8>;nand-ecc-mode = "hw";nand-ecc-strength = <16>;nand-ecc-step-size = <1024>;#address-cells = <1>;#size-cells = <1>;partition@0 { label = "nand_text";reg = <0x00000000 0x00400000>; };...}; 

3. hisi_nfc_probe函数

3.1 获取dts中的资源

static int hisi_nfc_probe(struct platform_device *pdev)
{int ret = 0, irq, flag, max_chips = HINFC504_MAX_CHIP;struct device *dev = &pdev->dev;struct hinfc_host *host;struct nand_chip  *chip;struct mtd_info   *mtd;struct resource   *res;struct device_node *np = dev->of_node;host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);if (!host)return -ENOMEM;host->dev = dev;platform_set_drvdata(pdev, host);chip = &host->chip;mtd  = nand_to_mtd(chip);irq = platform_get_irq(pdev, 0);if (irq < 0) {dev_err(dev, "no IRQ resource defined\n");ret = -ENXIO;goto err_res;}res = platform_get_resource(pdev, IORESOURCE_MEM, 0);host->iobase = devm_ioremap_resource(dev, res);if (IS_ERR(host->iobase)) {ret = PTR_ERR(host->iobase);goto err_res;}res = platform_get_resource(pdev, IORESOURCE_MEM, 1);host->mmio = devm_ioremap_resource(dev, res);if (IS_ERR(host->mmio)) {ret = PTR_ERR(host->mmio);dev_err(dev, "devm_ioremap_resource[1] fail\n");goto err_res;}.......
}

3.2 设置nand-chip结构体中必要的字段

static int hisi_nfc_probe(struct platform_device *pdev)
{int ret = 0, irq, flag, max_chips = HINFC504_MAX_CHIP;struct device *dev = &pdev->dev;struct hinfc_host *host;struct nand_chip  *chip;......nand_set_controller_data(chip, host);nand_set_flash_node(chip, np);chip->cmdfunc      = hisi_nfc_cmdfunc;chip->select_chip    = hisi_nfc_select_chip;chip->read_byte      = hisi_nfc_read_byte;chip->read_word        = hisi_nfc_read_word;chip->write_buf        = hisi_nfc_write_buf;chip->read_buf     = hisi_nfc_read_buf;chip->chip_delay    = HINFC504_CHIP_DELAY;chip->onfi_set_features   = nand_onfi_get_set_features_notsupp;chip->onfi_get_features    = nand_onfi_get_set_features_notsupp;hisi_nfc_host_init(host);..........
}

设置nand-chip结构体中必要的字段,hisi_nfc_host_init初始化nand flash控制器。

3.3 nand_scan_ident扫描识别nand控制器

static int hisi_nfc_probe(struct platform_device *pdev)
{.............ret = nand_scan_ident(mtd, max_chips, NULL);if (ret)goto err_res;............
}

3.4 设置DMA相关的东西

static int hisi_nfc_probe(struct platform_device *pdev)
{.............ret = nand_scan_ident(mtd, max_chips, NULL);if (ret)goto err_res;host->buffer = dmam_alloc_coherent(dev, mtd->writesize + mtd->oobsize,&host->dma_buffer, GFP_KERNEL);if (!host->buffer) {ret = -ENOMEM;goto err_res;}host->dma_oob = host->dma_buffer + mtd->writesize;memset(host->buffer, 0xff, mtd->writesize + mtd->oobsize);................
}

3.5 ecc相关的配置

static int hisi_nfc_probe(struct platform_device *pdev)
{..........if (chip->ecc.mode == NAND_ECC_HW)hisi_nfc_ecc_probe(host);..........
}

3.6 构造mtd结构体,并注册

static int hisi_nfc_probe(struct platform_device *pdev)
{............ret = nand_scan_tail(mtd);if (ret) {dev_err(dev, "nand_scan_tail failed: %d\n", ret);goto err_res;}ret = mtd_device_register(mtd, NULL, 0);if (ret) {dev_err(dev, "Err MTD partition=%d\n", ret);goto err_mtd;}return 0;err_mtd:nand_release(chip);
err_res:return ret;
}

从第3节中,我们知道nand control的主要内容是:

1. 填充nand-chip结构体。
    2. 初始化nand control控制器。
    3. 识别nand flash。
    4. 设置DMA相关的东西
    5. ecc相关的配置
    6. 填充mtd结构体,并注册mtd结构体。

下面我们主要讲填充mtd结构体的函数nand_scan_tail。

4. nand_scan_tail

我们假设ecc的mode是NAND_ECC_HW来分析这个函数。

/*** nand_scan_tail - [NAND Interface] Scan for the NAND device* @mtd: MTD device structure** This is the second phase of the normal nand_scan() function. It fills out* all the uninitialized function pointers with the defaults and scans for a* bad block table if appropriate.*/
int nand_scan_tail(struct mtd_info *mtd)
{struct nand_chip *chip = mtd_to_nand(mtd);struct nand_ecc_ctrl *ecc = &chip->ecc;struct nand_buffers *nbuf = NULL;.........../** FIXME: some NAND manufacturer drivers expect the first die to be* selected when manufacturer->init() is called. They should be fixed* to explictly select the relevant die when interacting with the NAND* chip.*/chip->select_chip(mtd, 0);ret = nand_manufacturer_init(chip);chip->select_chip(mtd, -1);if (ret)goto err_free_nbuf;........../** Check ECC mode, default to software if 3byte/512byte hardware ECC is* selected and we have 256 byte pagesize fallback to software ECC*/MTD_OPS_RAWswitch (ecc->mode) {......case NAND_ECC_HW:/* Use standard hwecc read page function? */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->hwctl && ecc->calculate)ecc->write_subpage = nand_write_subpage_hwecc;..........}.........../* Fill in remaining MTD driver data */mtd->type = nand_is_slc(chip) ? MTD_NANDFLASH : MTD_MLCNANDFLASH;mtd->flags = (chip->options & NAND_ROM) ? MTD_CAP_ROM :MTD_CAP_NANDFLASH;mtd->_erase = nand_erase;mtd->_point = NULL;mtd->_unpoint = NULL;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->_suspend = nand_suspend;mtd->_resume = nand_resume;mtd->_reboot = nand_shutdown;mtd->_block_isreserved = nand_block_isreserved;mtd->_block_isbad = nand_block_isbad;mtd->_block_markbad = nand_block_markbad;mtd->_max_bad_blocks = nand_max_bad_blocks;mtd->writebufsize = mtd->writesize;......return ret;
}

主要是设置struct nand_chip结构体中eec相关的内容,以及填充mtd结构体。mtd结构体最终被注册。

6. 参考文件

mtd子系统_IT利刃出鞘的博客-CSDN博客

NANDFLASH原理分析_大江的专栏-CSDN博客
Linux NAND FLASH驱动框架分析---mtd-linuxDOS-ChinaUnix博客

【驱动】linux系统下nand flash驱动程序框架 - Leo.cheng - 博客园

Linux内核4.14版本——Nand子系统(1)——hisi504_nand.c分析相关推荐

  1. Linux内核4.14版本——GPIO子系统(1)——gpiolib分析

    目录 1.简述 2.Gpiolib 相关数据结构分析 2.1 gpio_chip 结构 2.2 gpio_desc 结构 2.3 gpio_device 结构 3 Gpiolib 对接芯片底层 3.1 ...

  2. Linux内核4.14版本:ARM64的内核启动过程(二)——start_kernel

    目录 1. rest_init 2. init 进程(kernel_init) 2.1 kernel_init_freeable 2.1.1 do_basic_setup 2.1.2 prepare_ ...

  3. Linux内核4.14版本——watchdog看门狗框架分析

    目录 0 简介 1. 设备的注册 1.1 dw_wdt_drv_probe 1.2 watchdog_register_device 1.3 __watchdog_register_device 1. ...

  4. Linux内核4.14版本——DMA Engine框架分析(6)-实战(测试dma驱动)

    1. dw-axi-dmac驱动 2. dma的测试程序 2.1 内核程序 2.2 用户测试程序 1. dw-axi-dmac驱动 dw-axi-dmac驱动4.14版本没有,是从5.4版本移植的,基 ...

  5. Linux内核4.14版本——alsa框架分析(1)—alsa简介

    目录 一,ALSA声音编程介绍 二,ALSA历史 三,数字音频基础 四,ALSA基础 五,ALSA体系结构 六,设备命名 七,声音缓存和数据传输 八,Over and Under Run 九,一个典型 ...

  6. Linux内核4.14版本——drm框架分析(1)——drm简介

    目录 1. DRM简介(Direct Rendering Manager) 1.1 DRM发展历史 1.2 DRM架构对比FB架构优势 1.3 DRM图形显示框架 1.4 DRM图形显示框架涉及元素 ...

  7. Linux内核4.14版本——SPI NOR子系统(2)——spi-nor.c分析

    1. 简介 2. spi_nor_scan 2.1 检查结构体struct spi_nor是否合格,匹配支持的nor flash ID得到info 2.1.1 spi_nor_check 2.1.2 ...

  8. Linux内核4.14版本——SPI NOR子系统(3)——cadence-quadspi.c分析

    目录 1. 芯片简介 1.1 模块与接口 1.2 访问模式 2. DTS 2.1 reg 2.2 cdns,trigger-address 2.3 匹配DTS的驱动程序入口 3. cqspi_prob ...

  9. Linux内核4.14版本——mmc core(3)——host模块

    1. 前言 2. MMC host驱动介绍 3. 主要数据结构 3.1 struct mmc_host 3.2 struct mmc_host_ops 3.2.1 数据传输有关的函数 3.2.2 总线 ...

最新文章

  1. webpack、rollup、parcel 它们的优劣?_尾货批发与正价批发优劣势,你有二者兼顾吗?...
  2. 3 ADO.NET跟踪日志
  3. java 反射 成员变量_java基础--反射(成员变量)
  4. codeforces 96A-C语言解题报告
  5. mysql 字符串 截取字母_MySQL字符串函数:字符串截取
  6. c语言做一个小程序报告,《C语言程序设计实践》课程报告30个小程序组合成一个大程序.doc...
  7. arcgis分隔图层重复出文件_【干货】ArcGIS不可或缺的制图技巧,处理好细节才能让图更专业!...
  8. 大数据治理会遇到哪些难题
  9. 【手写数字识别】基于matlab GUI BP神经网络手写数字识别【含Matlab源码 518期】
  10. 韦东山嵌入式Linux第一期视频-韦东山-专题视频课程
  11. idea 主题设计+网站
  12. xcode 5中调试技巧
  13. C# winform下的OxyPlot(安装2.0版本!!!!)
  14. @Primary注解在spring中的使用
  15. Kettle【实践 04】Java环境实现KJB和KTR脚本文件执行v9版本9.0.0.0-423相关依赖说明(云资源分享:依赖包+kjb+ktr+测试源码)
  16. 吉林大学邮箱smtp服务器,吉珠专属EDU邮箱上线,校友也可申请!除了发邮件,这个邮箱还能省钱!...
  17. Java多线程实现跑步比赛【比赛详解】
  18. 企业如何建立商业生态系统
  19. linux libuv,libuv queue的实现
  20. 江苏图采之证件照上传

热门文章

  1. 【蓝桥杯选拔赛真题02】python奇偶数 青少年组蓝桥杯python 选拔赛STEMA比赛真题解析
  2. 数据库技术与应用(SQL Server)——【SQL Server单表查询(二)】
  3. python-requests模拟浏览器登录实战
  4. python血条游戏代码_零基础快速学十二课Python完整游戏代码,使用「格式符%」来处理...
  5. 帮忙哥们选购笔记本电脑3000-4000
  6. linux proc cpuinfo,Linux下查看CPU信息[/proc/cpuinfo]
  7. 内核对象句柄泄漏检测
  8. 小程序公告php实现,小程序两种滚动公告栏的实现方法
  9. 可以骑驴找马,但不要虐待驴----徐小平老师
  10. Chrome浏览器地址栏显示完整网址 不隐藏http/https的设置方法 87版本可用