Linux内核4.14版本——Nand子系统(1)——hisi504_nand.c分析
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分析相关推荐
- 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 ...
- 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_ ...
- Linux内核4.14版本——watchdog看门狗框架分析
目录 0 简介 1. 设备的注册 1.1 dw_wdt_drv_probe 1.2 watchdog_register_device 1.3 __watchdog_register_device 1. ...
- 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版本移植的,基 ...
- Linux内核4.14版本——alsa框架分析(1)—alsa简介
目录 一,ALSA声音编程介绍 二,ALSA历史 三,数字音频基础 四,ALSA基础 五,ALSA体系结构 六,设备命名 七,声音缓存和数据传输 八,Over and Under Run 九,一个典型 ...
- Linux内核4.14版本——drm框架分析(1)——drm简介
目录 1. DRM简介(Direct Rendering Manager) 1.1 DRM发展历史 1.2 DRM架构对比FB架构优势 1.3 DRM图形显示框架 1.4 DRM图形显示框架涉及元素 ...
- 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 ...
- 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 ...
- 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 总线 ...
最新文章
- webpack、rollup、parcel 它们的优劣?_尾货批发与正价批发优劣势,你有二者兼顾吗?...
- 3 ADO.NET跟踪日志
- java 反射 成员变量_java基础--反射(成员变量)
- codeforces 96A-C语言解题报告
- mysql 字符串 截取字母_MySQL字符串函数:字符串截取
- c语言做一个小程序报告,《C语言程序设计实践》课程报告30个小程序组合成一个大程序.doc...
- arcgis分隔图层重复出文件_【干货】ArcGIS不可或缺的制图技巧,处理好细节才能让图更专业!...
- 大数据治理会遇到哪些难题
- 【手写数字识别】基于matlab GUI BP神经网络手写数字识别【含Matlab源码 518期】
- 韦东山嵌入式Linux第一期视频-韦东山-专题视频课程
- idea 主题设计+网站
- xcode 5中调试技巧
- C# winform下的OxyPlot(安装2.0版本!!!!)
- @Primary注解在spring中的使用
- Kettle【实践 04】Java环境实现KJB和KTR脚本文件执行v9版本9.0.0.0-423相关依赖说明(云资源分享:依赖包+kjb+ktr+测试源码)
- 吉林大学邮箱smtp服务器,吉珠专属EDU邮箱上线,校友也可申请!除了发邮件,这个邮箱还能省钱!...
- Java多线程实现跑步比赛【比赛详解】
- 企业如何建立商业生态系统
- linux libuv,libuv queue的实现
- 江苏图采之证件照上传
热门文章
- 【蓝桥杯选拔赛真题02】python奇偶数 青少年组蓝桥杯python 选拔赛STEMA比赛真题解析
- 数据库技术与应用(SQL Server)——【SQL Server单表查询(二)】
- python-requests模拟浏览器登录实战
- python血条游戏代码_零基础快速学十二课Python完整游戏代码,使用「格式符%」来处理...
- 帮忙哥们选购笔记本电脑3000-4000
- linux proc cpuinfo,Linux下查看CPU信息[/proc/cpuinfo]
- 内核对象句柄泄漏检测
- 小程序公告php实现,小程序两种滚动公告栏的实现方法
- 可以骑驴找马,但不要虐待驴----徐小平老师
- Chrome浏览器地址栏显示完整网址 不隐藏http/https的设置方法 87版本可用