从零移植uboot 2017 到nuc970(第十九天)

来源:互联网 发布:origin画图for mac 编辑:程序博客网 时间:2024/06/06 01:40
隔了一段時間,重拾起來,幸好有記錄,不然也不知道到那裏了
CONFIG_SPL_NAND_BASEInclude nand_base.c in the SPL.  RequiresCONFIG_SPL_NAND_DRIVERS.CONFIG_SPL_NAND_DRIVERSSPL uses normal NAND drivers, not minimal drivers.CONFIG_SPL_NAND_ECCInclude standard software ECC in the SPLCONFIG_SPL_NAND_SIMPLESupport for NAND boot using simple NAND drivers thatexpose the cmd_ctrl() interface.
readme可以找到的一些解釋

先看正常版本的非spl的

NORMAL_DRIVERS=yobj-y += nand.oobj-y += nand_bbt.oobj-y += nand_ids.oobj-y += nand_util.oobj-y += nand_ecc.oobj-y += nand_base.oobj-y += nand_timings.o

這些文件,都會編譯

位於nand.c中的nand_init是解析的開始

void nand_init(void){#ifdef CONFIG_SYS_NAND_SELF_INITboard_nand_init();#elseint i;for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++)nand_init_chip(i);#endifprintf("%lu MiB\n", total_nand_size / 1024);#ifdef CONFIG_SYS_NAND_SELECT_DEVICE/* * Select the chip in the board/cpu specific driver */board_nand_select_device(mtd_to_nand(nand_info[nand_curr_device]), nand_curr_device);#endifcreate_mtd_concat();}
實際上直接進行nand_init_chip,而不去採取直接board_nand_init();
static void nand_init_chip(int i){struct nand_chip *nand = &nand_chip[i];struct mtd_info *mtd = nand_to_mtd(nand);ulong base_addr = base_address[i];int maxchips = CONFIG_SYS_NAND_MAX_CHIPS;if (maxchips < 1)maxchips = 1;nand->IO_ADDR_R = nand->IO_ADDR_W = (void  __iomem *)base_addr;if (board_nand_init(nand))return;if (nand_scan(mtd, maxchips))return;nand_register(i, mtd);}
這裏直接分析nand_chip 和mtd info的關係

這個直接來自kernel的定義,用到什麼地方再詳細分析

首先就是nand to mtd

static inline struct mtd_info *nand_to_mtd(struct nand_chip *chip){return &chip->mtd;}
也就是實際上返回了最初全局變量&nand_chip[0]->mtd的首地址,nand_chip包含了mtd_info的結構體
 * @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.
nand->IO_ADDR_R = nand->IO_ADDR_W = (void  __iomem *)base_addr;//nand控制器的基地址
這裏穿插下,Nuc970的芯片特性

The Flash Memory Interface (FMI) of this Chip has DMA unit and FMI unit. The DMA unitprovides a DMA (Direct Memory Access) function for FMI to exchange data between systemmemory (ex. SDRAM) and shared buffer (128 bytes), and the FMI unit control the interface ofeMMC or NAND flash. The interface controller can support eMMC and NAND-type flash andthe FMI is cooperated with DMAC to provide a fast data transfer between system memoryand cards.

其中DMA支持hardware Scatter-Gather特性,但是目前來說並沒有使用,關於是否是slc或者mlc通過讀取chip id獲得


  不過這都是作爲最底層的實現的時候的參考,但是可以稍微看下。繼續mtd的框架 ,後面的:

board_nand_init(nand)
  由我們自己根據芯片手冊,和自己使用的nand芯片,做個初始化硬件配置,nand_chip結構體子項的初始賦值,重點是解析

if (nand_scan(mtd, maxchips))
位於mtd/nand/nand_base.c

/** * nand_scan - [NAND Interface] Scan for the NAND device * @mtd: MTD device structure * @maxchips: number of chips to scan for * * This fills out all the uninitialized function pointers with the defaults. * The flash ID is read and the mtd/chip structures are filled with the * appropriate values. *///初始化上一步board_nand_init沒有涉及的函數,和成員 int nand_scan(struct mtd_info *mtd, int maxchips){int ret;ret = nand_scan_ident(mtd, maxchips, NULL);if (!ret)ret = nand_scan_tail(mtd);return ret;}
/** * nand_scan_ident - [NAND Interface] Scan for the NAND device * @mtd: MTD device structure * @maxchips: number of chips to scan for * @table: alternative NAND ID table * * This is the first phase of the normal nand_scan() function. It reads the * flash ID and sets up MTD fields accordingly. * */int nand_scan_ident(struct mtd_info *mtd, int maxchips,    struct nand_flash_dev *table){int i, nand_maf_id, nand_dev_id;struct nand_chip *chip = mtd_to_nand(mtd); //這裏具體的宏函數就不拓展了,使用了相對地址,用mtd的位置倒推出nand_chip的首地址struct nand_flash_dev *type; //用到那個成員再看int ret;if (chip->flash_node)     // 唯獨comment沒有解釋的地方,不過因爲沒有使用相關定義素以爲空函數        {ret = nand_dt_init(mtd, chip, chip->flash_node);//if (ret)return ret;}/* Set the default functions */nand_set_defaults(chip, chip->options & NAND_BUSWIDTH_16); //單獨列出來/* Read the flash type */type = nand_get_flash_type(mtd, chip, &nand_maf_id,   &nand_dev_id, table);if (IS_ERR(type)) {if (!(chip->options & NAND_SCAN_SILENT_NODEV))pr_warn("No NAND device found\n");//這裏就要添加你的nand信息否則會檢測失敗chip->select_chip(mtd, -1);return PTR_ERR(type);}chip->select_chip(mtd, -1);/* Check for a chip array */for (i = 1; i < maxchips; i++) {chip->select_chip(mtd, i);/* See comment in nand_get_flash_type for reset */chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);/* Send the command for reading device ID */chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);/* Read manufacturer and device IDs */if (nand_maf_id != chip->read_byte(mtd) ||    nand_dev_id != chip->read_byte(mtd)) {chip->select_chip(mtd, -1);break;}chip->select_chip(mtd, -1);}//再次檢查#ifdef DEBUGif (i > 1)pr_info("%d chips detected\n", i);#endif/* Store the number of chips and calc total size for mtd */chip->numchips = i;mtd->size = i * chip->chipsize;return 0;}
/* Set default functions */static void nand_set_defaults(struct nand_chip *chip, int busw){                   //整體上都是沒有指定的情況下,會使用默認的,但是那些需要自己去指定呢?後面會分析/* check for proper chip_delay setup, set 20us if not */if (!chip->chip_delay)chip->chip_delay = 20;/* 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;/* set for ONFI nand */if (!chip->onfi_set_features)chip->onfi_set_features = nand_onfi_set_features;if (!chip->onfi_get_features)chip->onfi_get_features = nand_onfi_get_features;/* 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;if (!chip->controller) {chip->controller = &chip->hwcontrol;spin_lock_init(&chip->controller->lock);init_waitqueue_head(&chip->controller->wq);}}
/** * nand_command_lp - [DEFAULT] Send command to NAND large page device * @mtd: MTD device structure * @command: the command to be sent * @column: the column address for this command, -1 if none * @page_addr: the page address for this command, -1 if none * * Send command to NAND device. This is the version for the new large page * devices. We don't have the separate regions as we have in the small page * devices. We must emulate NAND_CMD_READOOB to keep the code compatible. */static void nand_command_lp(struct mtd_info *mtd, unsigned int command,    int column, int page_addr){register struct nand_chip *chip = mtd_to_nand(mtd);/* Emulate NAND_CMD_READOOB */if (command == NAND_CMD_READOOB) {column += mtd->writesize;//nand寫的大小爲一頁command = NAND_CMD_READ0; //標準nand寫命令再nand.h定義 一般都相同,不需要修改,除非你的nand比較特殊}//如果讀取的是oob則直接column+一頁的大小,單位爲byte                                                   /* Command latch cycle */chip->cmd_ctrl(mtd, command, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);//這裏就調用了chip結構體的成員,所以mtd函數會使用chip中的    //函數,而該函數則是我們需要自己定義的實現的最底層函數,這是通過代碼解析的結論,第一個我們需要自己實現的,起作用操作ale,cle,nce 寫命令或者地址    //這裏給命令寄存器寫command                if (column != -1 || page_addr != -1)                {int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;/* Serially input address */if (column != -1)                 {/* Adjust columns for 16 bit buswidth */ //我使用的nand_control是8位的if (chip->options & NAND_BUSWIDTH_16 &&!nand_opcode_8bits(command))column >>= 1; //chip_option這裏起碼知道可以指定buswithdth,且我的nandk9f1908與標準nand命令有出入chip->cmd_ctrl(mtd, column, ctrl); //地址寄存器寫列地址,mtd爲從上傳下來的。ctrl &= ~NAND_CTRL_CHANGE;chip->cmd_ctrl(mtd, column >> 8, ctrl);//不轉化寄存器,繼續寫列地址高8位}if (page_addr != -1) {chip->cmd_ctrl(mtd, page_addr, ctrl); //寫頁地址chip->cmd_ctrl(mtd, page_addr >> 8,       NAND_NCE | NAND_ALE); //寫頁地址高8位/* One more address cycle for devices > 128MiB */if (chip->chipsize > (128 << 20))chip->cmd_ctrl(mtd, page_addr >> 16,       NAND_NCE | NAND_ALE); //如果128m以上 會有第5個週期,頁地址最高的8位}}chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);//給基地址寄存器寫none/* * Program and erase have their own busy handlers status, sequential * in and status need no delay. */switch (command) {case NAND_CMD_CACHEDPROG:case NAND_CMD_PAGEPROG:case NAND_CMD_ERASE1:case NAND_CMD_ERASE2:case NAND_CMD_SEQIN:case NAND_CMD_RNDIN:case NAND_CMD_STATUS:return;        //以上的命令直接退出,不在該函數處理case NAND_CMD_RESET:if (chip->dev_ready)break;udelay(chip->chip_delay);chip->cmd_ctrl(mtd, NAND_CMD_STATUS,       NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);chip->cmd_ctrl(mtd, NAND_CMD_NONE,       NAND_NCE | NAND_CTRL_CHANGE);/* EZ-NAND can take upto 250ms as per ONFi v4.0 */nand_wait_status_ready(mtd, 250);return;case NAND_CMD_RNDOUT:/* No ready / busy check necessary */chip->cmd_ctrl(mtd, NAND_CMD_RNDOUTSTART,       NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);chip->cmd_ctrl(mtd, NAND_CMD_NONE,       NAND_NCE | NAND_CTRL_CHANGE);return;case NAND_CMD_READ0:chip->cmd_ctrl(mtd, NAND_CMD_READSTART,       NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);chip->cmd_ctrl(mtd, NAND_CMD_NONE,       NAND_NCE | NAND_CTRL_CHANGE);/* This applies to read commands */default:/* * If we don't have access to the busy pin, we apply the given * command delay. */if (!chip->dev_ready) {udelay(chip->chip_delay);return;}}/* * Apply this short delay always to ensure that we do wait tWB in * any case on any machine. */ndelay(100);nand_wait_ready(mtd);}

一些命令是組合型的,看數據手冊就可得知,而此函數對與不需要data的命令做了處理
爲了方便解析,看一個cmd_ctrl的實現,取自s3c2410

static void s3c24x0_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl){       struct nand_chip *chip = mtd_to_nand(mtd); struct s3c24x0_nand *nand = s3c24x0_get_base_nand();//爲三星芯片的nand_controller                                                  debug("hwcontrol(): 0x%02x 0x%02x\n", cmd, ctrl);         //爲了方便解析,特意下了s3c2410的數據手冊來對應下if (ctrl & NAND_CTRL_CHANGE)//這個宏其實就是變化操作寄存器的地址,其實是編程的技巧         {ulong IO_ADDR_W = (ulong)nand;if (!(ctrl & NAND_CLE))IO_ADDR_W |= S3C2410_ADDR_NCLE;//此時對應地址寄存器if (!(ctrl & NAND_ALE))IO_ADDR_W |= S3C2410_ADDR_NALE; //此時對應命令寄存器                  //這裏並沒有說反,我確認了下,但怎麼解釋都不通,這裏應該的目的是 nand_cle選擇command寄存器,總之安裝順着的邏輯來chip->IO_ADDR_W = (void *)IO_ADDR_W;if (ctrl & NAND_NCE)writel(readl(&nand->nfconf) & ~S3C2410_NFCONF_nFCE,       &nand->nfconf);//始能片選信號elsewritel(readl(&nand->nfconf) | S3C2410_NFCONF_nFCE,       &nand->nfconf);//失能啦}if (cmd != NAND_CMD_NONE)writeb(cmd, chip->IO_ADDR_W);//相應寄存器寫入命令}

模仿了這個,可以寫出來自己的底層函數,mtd----chip->cmdfunc----chip->cmd_ctrl-----your own function繼續

read_buffer,write_buffer的實現較爲簡單,不做解析,且chip->nand_write_byte------chip->nand_write_buffer

chip->read_buffer 與 chip->read_byte/word實現方式不同都很簡單,但都沒有綜合成一個完整的寫或者讀命令,

較爲底層

/** * nand_default_block_markbad - [DEFAULT] mark a block bad via bad block marker * @mtd: MTD device structure * @ofs: offset from device start * * This is the default implementation, which can be overridden by a hardware * specific driver. It provides the details for writing a bad block marker to a * block. */static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs){struct nand_chip *chip = mtd_to_nand(mtd);struct mtd_oob_ops ops;uint8_t buf[2] = { 0, 0 };int ret = 0, res, i = 0;memset(&ops, 0, sizeof(ops));ops.oobbuf = buf;ops.ooboffs = chip->badblockpos;if (chip->options & NAND_BUSWIDTH_16) {ops.ooboffs &= ~0x01;ops.len = ops.ooblen = 2;} else {ops.len = ops.ooblen = 1;}ops.mode = MTD_OPS_PLACE_OOB;/* Write to first/last page(s) if necessary */if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)ofs += mtd->erasesize - mtd->writesize;//切換到最後一頁do {res = nand_do_write_oob(mtd, ofs, &ops);//ofs實際是第一頁的相對位置,也就是2k+xx(64)if (!ret)ret = res;i++;ofs += mtd->writesize;//加上一頁} while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2);//一般在第一頁,除非有特殊要求會寫第二頁,根據芯片來說return ret;}

/** * nand_do_write_oob - [MTD Interface] NAND write out-of-band * @mtd: MTD device structure * @to: offset to write to * @ops: oob operation description structure * * NAND write out-of-band. */static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,     struct mtd_oob_ops *ops){int chipnr, page, status, len;struct nand_chip *chip = mtd_to_nand(mtd);pr_debug("%s: to = 0x%08x, len = %i\n", __func__, (unsigned int)to, (int)ops->ooblen);len = mtd_oobavail(mtd, ops);//根據oob的模式返回長度 per block,這裏的per block讓人無法理解下面的代碼/* Do not allow write past end of page */if ((ops->ooboffs + ops->ooblen) > len) {pr_debug("%s: attempt to write past end of page\n",__func__);return -EINVAL;}if (unlikely(ops->ooboffs >= len)) {pr_debug("%s: attempt to start write outside oob\n",__func__);return -EINVAL;}/* Do not allow write past end of device */if (unlikely(to >= mtd->size ||     ops->ooboffs + ops->ooblen >((mtd->size >> chip->page_shift) - (to >> chip->page_shift)) * len)) {pr_debug("%s: attempt to write beyond end of device\n",__func__);return -EINVAL;}//這裏需要分析下,首先to>mtd->size 返回,然後ops->ooboffs + ops->ooblen >((mtd->size >> chip->page_shift)      // -(to >> chip->page_shift)) * len))這裏有點不太理解,當然這裏不是重點        chipnr = (int)(to >> chip->chip_shift);//chip的指針chip->select_chip(mtd, chipnr);//始能第幾快chip/* Shift to get page */page = (int)(to >> chip->page_shift);//得到相對的頁數,多塊是連續存儲/* * Reset the chip. Some chips (like the Toshiba TC5832DC found in one * of my DiskOnChip 2000 test units) will clear the whole data page too * if we don't do this. I have no clue why, but I seem to have 'fixed' * it in the doc2000 driver in August 1999.  dwmw2. */chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);/* Check, if it is write protected */if (nand_check_wp(mtd)) {chip->select_chip(mtd, -1);return -EROFS;}/* Invalidate the page cache, if we write to the cached page */if (page == chip->pagebuf)chip->pagebuf = -1;nand_fill_oob(mtd, ops->oobbuf, ops->ooblen, ops);//這裏ops->oobbuf爲兩個字節,ooblen爲1       //        if (ops->mode == MTD_OPS_RAW)status = chip->ecc.write_oob_raw(mtd, chip, page & chip->pagemask);elsestatus = chip->ecc.write_oob(mtd, chip, page & chip->pagemask);//這裏就是個人實現的函數了                chip->select_chip(mtd, -1);if (status)return status;ops->oobretlen = ops->ooblen;        return 0;}

/** * nand_fill_oob - [INTERN] Transfer client buffer to oob * @mtd: MTD device structure * @oob: oob data buffer * @len: oob data write length * @ops: oob ops structure */static uint8_t *nand_fill_oob(struct mtd_info *mtd, uint8_t *oob, size_t len,      struct mtd_oob_ops *ops){struct nand_chip *chip = mtd_to_nand(mtd);/* * Initialise to all 0xFF, to avoid the possibility of left over OOB * data from a previous OOB read. */memset(chip->oob_poi, 0xff, mtd->oobsize);//重置buff區,這個buffer是個人指定的switch (ops->mode) {case MTD_OPS_PLACE_OOB:case MTD_OPS_RAW:memcpy(chip->oob_poi + ops->ooboffs, oob, len);return oob + len; case MTD_OPS_AUTO_OOB: {struct nand_oobfree *free = chip->ecc.layout->oobfree;uint32_t boffs = 0, woffs = ops->ooboffs;size_t bytes = 0;for (; free->length && len; free++, len -= bytes) {/* Write request not from offset 0? */if (unlikely(woffs)) {if (woffs >= free->length) {woffs -= free->length;continue;}boffs = free->offset + woffs;bytes = min_t(size_t, len,      (free->length - woffs));woffs = 0;} else {bytes = min_t(size_t, len, free->length);boffs = free->offset;}memcpy(chip->oob_poi + boffs, oob, bytes);oob += bytes;}return oob;}default:BUG();}return NULL;}

下面按照調用的關係區分析
/* * Get the flash and manufacturer id and lookup if the type is supported. */static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,  struct nand_chip *chip,  int *maf_id, int *dev_id,  struct nand_flash_dev *type)//該函數沒什麼好解析的,和comment描述的一樣,剛開始讀了id然後和存儲的support list進行對比

int nand_scan_tail(struct mtd_info *mtd){int i;struct nand_chip *chip = mtd_to_nand(mtd);struct nand_ecc_ctrl *ecc = &chip->ecc;struct nand_buffers *nbuf;/* New bad blocks should be marked in OOB, flash-based BBT, or both */BUG_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) &&!(chip->bbt_options & NAND_BBT_USE_FLASH));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 */chip->oob_poi = chip->buffers->databuf + mtd->writesize;/* * If no default placement scheme is given, select an appropriate one. */if (!ecc->layout && (ecc->mode != NAND_ECC_SOFT_BCH)) {switch (mtd->oobsize) {case 8:ecc->layout = &nand_oob_8;break;case 16:ecc->layout = &nand_oob_16;break;case 64:ecc->layout = &nand_oob_64;break;case 128:ecc->layout = &nand_oob_128;break;default:pr_warn("No oob scheme defined for oobsize %d\n",   mtd->oobsize);BUG();}}//這個時候就是layout存儲了ecc字節數,位置,free位置 字節數,可用的oobsize將通過其他幾項推導出來if (!chip->write_page)chip->write_page = nand_write_page; //這個函數調用了ecc.write_page需要我們自己實現/* * Check ECC mode, default to software if 3byte/512byte hardware ECC is * selected and we have 256 byte pagesize fallback to software ECC */switch (ecc->mode) {case NAND_ECC_HW_OOB_FIRST:/* Similar to NAND_ECC_HW, but a separate read_page handle */if (!ecc->calculate || !ecc->correct || !ecc->hwctl) {pr_warn("No ECC functions supplied; hardware ECC not possible\n");BUG();}if (!ecc->read_page)ecc->read_page = nand_read_page_hwecc_oob_first;//k9f1g08並不支持50h所以這裏不解析case NAND_ECC_HW://實際上使用的是這種模式,着重解析這裏/* Use standard hwecc read page function? */if (!ecc->read_page)ecc->read_page = nand_read_page_hwecc; //其中ecc.hwctl,read_buf,calculate,correct需要自己指定if (!ecc->write_page)ecc->write_page = nand_write_page_hwecc;//write_buf需要自己指定,且先寫data后寫oobif (!ecc->read_page_raw)ecc->read_page_raw = nand_read_page_raw;//沒有ecc的讀if (!ecc->write_page_raw)ecc->write_page_raw = nand_write_page_raw;//沒有ecc的寫if (!ecc->read_oob)ecc->read_oob = nand_read_oob_std; //我使用的nand不支持if (!ecc->write_oob)ecc->write_oob = nand_write_oob_std;//我使用的nand不支持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;              //刪除不會執行的代碼         default:pr_warn("Invalid NAND_ECC_MODE %d\n", ecc->mode);BUG();}/* 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;/* * The number of bytes available for a client to place data into * the out of band area. */mtd->oobavail = 0;if (ecc->layout) {for (i = 0; ecc->layout->oobfree[i].length; i++)mtd->oobavail += ecc->layout->oobfree[i].length;}/* ECC sanity check: warn if it's too weak */if (!nand_ecc_strength_good(mtd))pr_warn("WARNING: %s: the ECC used on your system is too weak compared to the one required by the NAND chip\n",mtd->name);/* * Set the number of read / write steps for one page depending on ECC * mode. */ecc->steps = mtd->writesize / ecc->size;if (ecc->steps * ecc->size != mtd->writesize) {pr_warn("Invalid ECC parameters\n");BUG();}ecc->total = ecc->steps * ecc->bytes;/* Allow subpage writes up to ecc.steps. Not possible for MLC flash */if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && nand_is_slc(chip)) {switch (ecc->steps) {case 2:mtd->subpage_sft = 1;break;case 4:case 8:case 16:mtd->subpage_sft = 2;break;}}chip->subpagesize = mtd->writesize >> mtd->subpage_sft;/* Initialize state */chip->state = FL_READY;/* Invalidate the pagebuffer reference */chip->pagebuf = -1;/* Large page NAND with SOFT_ECC should support subpage reads */switch (ecc->mode) {case NAND_ECC_SOFT:case NAND_ECC_SOFT_BCH:if (chip->page_shift > 9)chip->options |= NAND_SUBPAGE_READ;break;default:break;}/* 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->_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;/* propagate ecc info to mtd_info */mtd->ecclayout = ecc->layout;mtd->ecc_strength = ecc->strength;mtd->ecc_step_size = ecc->size;/* * Initialize bitflip_threshold to its default prior scan_bbt() call. * scan_bbt() might invoke mtd_read(), thus bitflip_threshold must be * properly set. */if (!mtd->bitflip_threshold)mtd->bitflip_threshold = DIV_ROUND_UP(mtd->ecc_strength * 3, 4);return 0;}
函數非常的多,但是大體上最上面的函數封裝應該爲mtd的函數,而mtd調用chip的函數,chip的有關函數可能調用chip->ecc.的函數,所以ecc和部分chip函數爲最底層的函數這樣看起來整體比較清楚,今天就到這裏,再看一小會。明天根據老代碼,解析修改,然後調整到2017的mtd框架下面
0 0
原创粉丝点击