添加 一个nandflash 需要修改的地方

在已有8bit NANDFlash控制器驱动的基础上,添加16bit NANDFlash需要关注board.c中.name和.id的更新,以及nand_flash_ids[]表的配置。启动时,kernel通过nand_scan()来识别和配置新添加的NANDFlash,该函数会根据bus宽度和maf_id进行操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

已经有nandflash controller的驱动了,但是要添加一个新的nandflash,尤其是本来是8bit, 新加的是16bit时,需要注意如下:

1. board.c 中:

static struct platform_nand_data cartesio_nand_mlc_data = {
        .chip = {
                .nr_chips       = 1,    /* 1 NAND chip per FSMC NAND-Flash slot */
                .chip_offset    = 0,    /* using FSMC PC-Card/NAND-Flash slot 0 */
                .nr_partitions  = ARRAY_SIZE(cartesio_nand_mlc_partitions),
                .partitions     = cartesio_nand_mlc_partitions,
                .ecclayout      = &cartesio_nand_mlc_ecclayout,
                .chip_delay     = 20,
                .options        = NAND_BUSWIDTH_16,   //这里8bit时是0,使用16bit时,应该修改 
        },
#ifdef CONFIG_CARTESIO_NAND_DMA
        .ctrl = {
                .priv = &cartesio_dma_nand,
        }
#endif
};
这里的 chip->option 需要注意.

同时需要注意下面的 .name 和 .id, nand_base.c 中的驱动会用到。

static struct platform_device cartesio_nand_mlc_flash = {
        .name           = "CARTESIO-NAND", // 这个会用来判断是不是NULL
        .id             = 0,                // id会用来比较 chip id
        .dev = {
                .platform_data = &cartesio_nand_mlc_data,
                .parent = &fsmc_device.dev,
        },
        .num_resources  = ARRAY_SIZE(cartesio_nand_mlc_resource),
        .resource       = cartesio_nand_mlc_resource,
};
2. drivers/mtd/nand/nand_ids.c

这里有个表 nand_flash_ids[], 定义如下:

/*
*       Chip ID list
*
*       Name. ID code, pagesize, chipsize in MegaByte, eraseblock size,
*       options
*
*       Pagesize; 0, 256, 512
*       0       get this information from the extended chip ID
+       256     256 Byte page size
*       512     512 Byte page size
*/
struct nand_flash_dev nand_flash_ids[] = {

#ifdef CONFIG_MTD_NAND_MUSEUM_IDS
        {"NAND 1MiB 5V 8-bit",          0x6e, 256, 1, 0x1000, 0},
        {"NAND 2MiB 5V 8-bit",          0x64, 256, 2, 0x1000, 0},
        {"NAND 4MiB 5V 8-bit",          0x6b, 512, 4, 0x2000, 0},
        {"NAND 1MiB 3,3V 8-bit",        0xe8, 256, 1, 0x1000, 0},
        {"NAND 1MiB 3,3V 8-bit",        0xec, 256, 1, 0x1000, 0},
        {"NAND 2MiB 3,3V 8-bit",        0xea, 256, 2, 0x1000, 0},
        {"NAND 4MiB 3,3V 8-bit",        0xd5, 512, 4, 0x2000, 0},
        {"NAND 4MiB 3,3V 8-bit",        0xe3, 512, 4, 0x2000, 0},
        {"NAND 4MiB 3,3V 8-bit",        0xe5, 512, 4, 0x2000, 0},
        {"NAND 8MiB 3,3V 8-bit",        0xd6, 512, 8, 0x2000, 0},

        {"NAND 8MiB 1,8V 8-bit",        0x39, 512, 8, 0x2000, 0},
        {"NAND 8MiB 3,3V 8-bit",        0xe6, 512, 8, 0x2000, 0},
        {"NAND 8MiB 1,8V 16-bit",       0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16},
        {"NAND 8MiB 3,3V 16-bit",       0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16},
#endif

        {"NAND 16MiB 1,8V 8-bit",       0x33, 512, 16, 0x4000, 0},
        {"NAND 16MiB 3,3V 8-bit",       0x73, 512, 16, 0x4000, 0},
        {"NAND 16MiB 1,8V 16-bit",      0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16},
        {"NAND 16MiB 3,3V 16-bit",      0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16},

        {"NAND 32MiB 1,8V 8-bit",       0x35, 512, 32, 0x4000, 0},
        {"NAND 32MiB 3,3V 8-bit",       0x75, 512, 32, 0x4000, 0},
        {"NAND 32MiB 1,8V 16-bit",      0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16},
        {"NAND 32MiB 3,3V 16-bit",      0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16},

        {"NAND 64MiB 1,8V 8-bit",       0x36, 512, 64, 0x4000, 0},
        {"NAND 64MiB 3,3V 8-bit",       0x76, 512, 64, 0x4000, 0},
        {"NAND 64MiB 1,8V 16-bit",      0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16},
        {"NAND 64MiB 3,3V 16-bit",      0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16},

        {"NAND 128MiB 1,8V 8-bit",      0x78, 512, 128, 0x4000, 0},
        {"NAND 128MiB 1,8V 8-bit",      0x39, 512, 128, 0x4000, 0},
        {"NAND 128MiB 3,3V 8-bit",      0x79, 512, 128, 0x4000, 0},
        {"NAND 128MiB 1,8V 16-bit",     0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16},
        {"NAND 128MiB 1,8V 16-bit",     0x49, 512, 128, 0x4000, NAND_BUSWIDTH_16},
        {"NAND 128MiB 3,3V 16-bit",     0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16},
        {"NAND 128MiB 3,3V 16-bit",     0x59, 512, 128, 0x4000, NAND_BUSWIDTH_16},

        {"NAND 256MiB 3,3V 8-bit",      0x71, 512, 256, 0x4000, 0},

        /*
         * These are the new chips with large page size. The pagesize and the
         * erasesize is determined from the extended id bytes
         */
#define LP_OPTIONS (NAND_SAMSUNG_LP_OPTIONS | NAND_NO_READRDY | NAND_NO_AUTOINCR)
#define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16)

        /*512 Megabit */
        {"NAND 64MiB 1,8V 8-bit",       0xA2, 0,  64, 0, LP_OPTIONS},
        {"NAND 64MiB 3,3V 8-bit",       0xF2, 0,  64, 0, LP_OPTIONS},
        {"NAND 64MiB 1,8V 16-bit",      0xB2, 0,  64, 0, LP_OPTIONS16},
        {"NAND 64MiB 3,3V 16-bit",      0xC2, 0,  64, 0, LP_OPTIONS16},

        /* 1 Gigabit */
        {"NAND 128MiB 1,8V 8-bit",      0xA1, 0, 128, 0, LP_OPTIONS},
        {"NAND 128MiB 3,3V 8-bit",      0xF1, 0, 128, 0, LP_OPTIONS},
        {"NAND 128MiB 1,8V 16-bit",     0xB1, 0, 128, 0, LP_OPTIONS16},
        {"NAND 128MiB 3,3V 16-bit",     0xC1, 0, 128, 0, LP_OPTIONS16},

        /* 2 Gigabit */
        {"NAND 256MiB 1,8V 8-bit",      0xAA, 0, 256, 0, LP_OPTIONS},
        {"NAND 256MiB 3,3V 8-bit",      0xDA, 0, 256, 0, LP_OPTIONS},
        {"NAND 256MiB 1,8V 16-bit",     0xBA, 0, 256, 0, LP_OPTIONS16},
        {"NAND 256MiB 3,3V 16-bit",     0xCA, 0, 256, 0, LP_OPTIONS16},

        /* 4 Gigabit */
        {"NAND 512MiB 1,8V 8-bit",      0xAC, 0, 512, 0, LP_OPTIONS},
        {"NAND 512MiB 3,3V 8-bit",      0xDC, 0, 512, 0, LP_OPTIONS},
        {"NAND 512MiB 1,8V 16-bit",     0xBC, 0, 512, 0, LP_OPTIONS16},
        {"NAND 512MiB 3,3V 16-bit",     0xCC, 0, 512, 0, LP_OPTIONS16},

        /* 8 Gigabit */
        {"NAND 1GiB 1,8V 8-bit",        0xA3, 0, 1024, 0, LP_OPTIONS},
        {"NAND 1GiB 3,3V 8-bit",        0xD3, 0, 1024, 0, LP_OPTIONS},
        {"NAND 1GiB 1,8V 16-bit",       0xB3, 0, 1024, 0, LP_OPTIONS16},
        {"NAND 1GiB 3,3V 16-bit",       0xC3, 0, 1024, 0, LP_OPTIONS16},

        /* 16 Gigabit */
        {"NAND 2GiB 1,8V 8-bit",        0xA5, 0, 2048, 0, LP_OPTIONS},
        {"NAND 2GiB 3,3V 8-bit",        0xD5, 0, 2048, 0, LP_OPTIONS},
        {"NAND 2GiB 1,8V 16-bit",       0xB5, 0, 2048, 0, LP_OPTIONS16},
        {"NAND 2GiB 3,3V 16-bit",       0xC5, 0, 2048, 0, LP_OPTIONS16},
/*Board specific ifdef for mlc nand onfi standard support*/
#ifdef CONFIG_BCH_8
        {"NAND 2GiB 3,3V 8-bit",        0x48, 4096, 2048, 0x100000, 0},
        {"NAND 256MiB 3,3V 16-bit",     0x90, 1024, 256, 0x20000, NAND_BUSWIDTH_16},
#endif

        /*
         * Renesas AND 1 Gigabit. Those chips do not support extended id and
         * have a strange page/block layout !  The chosen minimum erasesize is
         * 4 * 2 * 2048 = 16384 Byte, as those chips have an array of 4 page
         * planes 1 block = 2 pages, but due to plane arrangement the blocks
         * 0-3 consists of page 0 + 4,1 + 5, 2 + 6, 3 + 7 Anyway JFFS2 would
         * increase the eraseblock size so we chose a combined one which can be
         * erased in one go There are more speed improvements for reads and
         * writes possible, but not implemented now
         */
        {"AND 128MiB 3,3V 8-bit",       0x01, 2048, 128, 0x4000,
         NAND_IS_AND | NAND_NO_AUTOINCR |NAND_NO_READRDY | NAND_4PAGE_ARRAY |
         BBT_AUTO_REFRESH
        },

        {NULL,}
};
struct nand_flash_dev 定义如下, 在include/linux/mtd/nand.h 中:

/**
 * struct nand_flash_dev - NAND Flash Device ID Structure
 * @name:       Identify the device type
 * @id:         device ID code
 * @pagesize:   Pagesize in bytes. Either 256 or 512 or 0
 *              If the pagesize is 0, then the real pagesize
 *              and the eraseize are determined from the
 *              extended id bytes in the chip
 * @erasesize:  Size of an erase block in the flash device.
 * @chipsize:   Total chipsize in Mega Bytes
 * @options:    Bitfield to store chip relevant options
 */
struct nand_flash_dev {
        char *name;
        int id;
        unsigned long pagesize;   //页大小
        unsigned long chipsize;   //nand整个大小
        unsigned long erasesize;   //擦写大小,基本就是指块(block)大小
        unsigned long options;     //bus width, 
};
3. nand_base.c

kernel 启动后,加载nandflash时, 首先调用 nand_scan()

/**
 * 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.
 * The mtd->owner field must be set to the module of the caller
 *
 */
int nand_scan(struct mtd_info *mtd, int maxchips)
{
        int ret;

        /* Many callers got this wrong, so check for it for a while... */
        if (!mtd->owner && caller_is_module()) {
                printk(KERN_CRIT "%s called with NULL mtd->owner!\n",
                                __func__);
                BUG();
        }

        ret = nand_scan_ident(mtd, maxchips);   //这里主要是调用这函数
        if (!ret)
                ret = nand_scan_tail(mtd);
        return ret;
}
int nand_scan_ident(struct mtd_info *mtd, int maxchips) 定义如下:
/**
 * nand_scan_ident - [NAND Interface] Scan for the NAND device
 * @mtd:             MTD device structure
 * @maxchips:        Number of chips to scan for
 *
 * This is the first phase of the normal nand_scan() function. It
 * reads the flash ID and sets up MTD fields accordingly.
 *
 * The mtd->owner field must be set to the module of the caller.
 */
int nand_scan_ident(struct mtd_info *mtd, int maxchips)
{
        int i, busw, nand_maf_id;
        struct nand_chip *chip = mtd->priv;
        struct nand_flash_dev *type;

        /* Get buswidth to select the correct functions */
        busw = chip->options & NAND_BUSWIDTH_16;
        /* Set the default functions */
        nand_set_defaults(chip, busw);

        /* Read the flash type */
        type = nand_get_flash_type(mtd, chip, busw, &nand_maf_id);  //这里主要是调用这个函数,识别nand的类型,如果没识别,则下面返回 No NAND..

        if (IS_ERR(type)) {
                if (!(chip->options & NAND_SCAN_SILENT_NODEV))
                        printk(KERN_WARNING "No NAND device found.\n");  //这里如果没有探测到nand, 会打印这个log
                chip->select_chip(mtd, -1);
                return PTR_ERR(type);
        }

        /* 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) ||
                    type->id != chip->read_byte(mtd))
                        break;
        }
        if (i > 1)
                printk(KERN_INFO "%d NAND chips detected\n", i);    //如果多个nand探测到,会打印这个log
        /* Store the number of chips and calc total size for mtd */
        chip->numchips = i;
        mtd->size = i * chip->chipsize;

        return 0;
}
static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
                                                  struct nand_chip *chip,

                                                  int busw, int *maf_id)

定义如下:

/*
 * 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 busw, int *maf_id)
{
        struct nand_flash_dev *type = NULL;
        int i, dev_id, maf_idx;
        int tmp_id, tmp_manf;

        /* 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);

        /* Send the command for reading device ID */
        chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);

        /* Read manufacturer and device IDs */
        *maf_id = chip->read_byte(mtd);
        dev_id = chip->read_byte(mtd);                  //这里获得 dev_id 设备ID。

        /* Try again to make sure, as some systems the bus-hold or other
         * interface concerns can cause random data which looks like a
         * possibly credible NAND flash to appear. If the two results do
         * not match, ignore the device completely.
         */

        chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);

        /* Read manufacturer and device IDs */

        tmp_manf = chip->read_byte(mtd);
        tmp_id = chip->read_byte(mtd);

        if (tmp_manf != *maf_id || tmp_id != dev_id) {
                printk(KERN_INFO "%s: second ID read did not match "
                       "%02x,%02x against %02x,%02x\n", __func__,
                       *maf_id, dev_id, tmp_manf, tmp_id);
                return ERR_PTR(-ENODEV);
        }

        printk(KERN_INFO "dev_id = 0x%x", dev_id);              //这是我添加的打印,为了打印出设备id
        /* Lookup the flash id */
        for (i = 0; nand_flash_ids[i].name != NULL; i++) {       //这里如果board.c 中有定义nand设备,且.name != NULL,
                if (dev_id == nand_flash_ids[i].id) {            //就会开始遍历 nand_flash_ids[] 设备表,进行匹配,如果有设备id相同
                        type =  &nand_flash_ids[i];              //就是给type进行赋值
                        break;
                }
        }

        if (!type)
                return ERR_PTR(-ENODEV);

        if (!mtd->name)
                mtd->name = type->name;

        chip->chipsize = (uint64_t)type->chipsize << 20;

        /* Newer devices have all the information in additional id bytes */
        if (!type->pagesize) {
                int extid;
                /* The 3rd id byte holds MLC / multichip data */
                chip->cellinfo = chip->read_byte(mtd);
                /* The 4th id byte is the important one */
                extid = chip->read_byte(mtd);
                /* Calc pagesize */
                mtd->writesize = 1024 << (extid & 0x3);
                extid >>= 2;
                /* Calc oobsize */
                mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9);
                extid >>= 2;
                /* Calc blocksize. Blocksize is multiples of 64KiB */
                mtd->erasesize = (64 * 1024) << (extid & 0x03);
                extid >>= 2;
                /* Get buswidth information */
                busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;

        } else {
                /*
                 * Old devices have chip data hardcoded in the device id table
                 */
                mtd->erasesize = type->erasesize;
                mtd->writesize = type->pagesize;
                /*Board specific ifdef for greater than 128 oobsize*/
#ifdef CONFIG_BCH_8
                mtd->oobsize = 224;
#else
                mtd->oobsize = mtd->writesize / 32;
#endif
                busw = type->options & NAND_BUSWIDTH_16;
        }

        /* Try to identify manufacturer */
        for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) {
                if (nand_manuf_ids[maf_idx].id == *maf_id)
                        break;
        }

        /*
         * Check, if buswidth is correct. Hardware drivers should set
         * chip correct !
         */

        if (busw != (chip->options & NAND_BUSWIDTH_16)) {             //如果 buswidth 不对,会打印如下log
                printk(KERN_INFO "NAND device: Manufacturer ID:"
                       " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id,
                       dev_id, nand_manuf_ids[maf_idx].name, mtd->name);
                printk(KERN_WARNING "NAND bus width %d instead %d bit\n",
                       (chip->options & NAND_BUSWIDTH_16) ? 16 : 8,
                       busw ? 16 : 8);
                return ERR_PTR(-EINVAL);
        }

        /* Calculate the address shift from the page size */
        chip->page_shift = ffs(mtd->writesize) - 1;
        /* Convert chipsize to number of pages per chip -1. */
        chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;

        chip->bbt_erase_shift = chip->phys_erase_shift =
                ffs(mtd->erasesize) - 1;
        if (chip->chipsize & 0xffffffff)
                chip->chip_shift = ffs((unsigned)chip->chipsize) - 1;
        else
                chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)) + 32 - 1;

        /* Set the bad block position */
        chip->badblockpos = mtd->writesize > 512 ?
                NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;

        /* Get chip options, preserve non chip based options */
        chip->options &= ~NAND_CHIPOPTIONS_MSK;
        chip->options |= type->options & NAND_CHIPOPTIONS_MSK;

        /*
         * Set chip as a default. Board drivers can override it, if necessary
         */
        chip->options |= NAND_NO_AUTOINCR;

        /* Check if chip is a not a samsung device. Do not clear the
         * options for chips which are not having an extended id.
         */
        if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)
                chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;

        /* Check for AND chips with 4 page planes */
        if (chip->options & NAND_4PAGE_ARRAY)
                chip->erase_cmd = multi_erase_cmd;
        else
                chip->erase_cmd = single_erase_cmd;

        /* Do not replace user supplied command function ! */
        if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
                chip->cmdfunc = nand_command_lp;

        printk(KERN_INFO "NAND device: Manufacturer ID:"                     //如果最终探测出nandflash,会打印这个
               " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, dev_id,
               nand_manuf_ids[maf_idx].name, type->name);

        return type;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值