OK335xS GPMC nand device register hacking

/**********************************************************************************              OK335xS GPMC nand device register hacking*  说明:*      由于最近遇到No NAND device found这个内核错误,在网络上也没找到很好的*  解决办法,于是只能自己去跟踪整个设备、驱动的注册流程,试着去理解整个系统*  的运作流程。**                                        2015-9-2 雨 深圳 南山平山村 曾剑锋********************************************************************************/cat arch/arm/mach-omap2/board-am335xevm.c
MACHINE_START(AM335XEVM, "am335xevm")/* Maintainer: Texas Instruments */.atag_offset    = 0x100,.map_io     = am335x_evm_map_io,.init_early = am33xx_init_early,.init_irq   = ti81xx_init_irq,.handle_irq     = omap3_intc_handle_irq,.timer      = &omap3_am33xx_timer,.init_machine   = am335x_evm_init,          -------------------+
MACHINE_END                                                        ||
MACHINE_START(AM335XIAEVM, "am335xiaevm")                          |/* Maintainer: Texas Instruments */                            |.atag_offset    = 0x100,                                       |.map_io     = am335x_evm_map_io,                               |.init_irq   = ti81xx_init_irq,                                 |.init_early = am33xx_init_early,                               |.timer      = &omap3_am33xx_timer,                             |.init_machine   = am335x_evm_init,          -------------------+
MACHINE_END                                                        ||
static void __init am335x_evm_init(void)        <------------------+
{......setup_ok335xs();              --------+......                                |
}                                         ||
/* ok335xs */                             |
static void setup_ok335xs(void)   <-------+
{pr_info("The board is a ok335xs.\n");/* Starter Kit has Micro-SD slot which doesn't have Write Protect pin */am335x_mmc[0].gpio_wp = -EINVAL;_configure_device(EVM_SK, ok335xs_dev_cfg, PROFILE_NONE);  ------------------+|am33xx_cpsw_init(AM33XX_CPSW_MODE_RGMII, NULL, NULL);                        |/* Atheros Tx Clk delay Phy fixup */                                         |phy_register_fixup_for_uid(AM335X_EVM_PHY_ID, AM335X_EVM_PHY_MASK,           |am33xx_evm_tx_clk_dly_phy_fixup);                             |
}                                                                                ||
/*ok335xs*/                                                                      |
static struct evm_dev_cfg ok335xs_dev_cfg[] = {               <------------------+......{evm_nand_init, DEV_ON_BASEBOARD, PROFILE_ALL},           ------------+{NULL, 0, 0},                                                         |
};                                                                        ||
static void evm_nand_init(int evm_id, int profile)            <-----------+
{struct omap_nand_platform_data *pdata;struct gpmc_devices_info gpmc_device[2] = {{ NULL, 0 },{ NULL, 0 },};setup_pin_mux(nand_pin_mux);pdata = omap_nand_init(am335x_nand_partitions,ARRAY_SIZE(am335x_nand_partitions), 0, 0,&am335x_nand_timings);if (!pdata)return;
//    pdata->ecc_opt =OMAP_ECC_BCH8_CODE_HW;pdata->ecc_opt =OMAP_ECC_HAMMING_CODE_DEFAULT;pdata->elm_used = true;gpmc_device[0].pdata = pdata;gpmc_device[0].flag = GPMC_DEVICE_NAND;     ------------------------------------+|omap_init_gpmc(gpmc_device, sizeof(gpmc_device));         --------------------+ |omap_init_elm();                                                              | |
}                                                                                 | || |
int __init omap_init_gpmc(struct gpmc_devices_info *pdata, int pdata_len)   <-----+ |
{                                                                                   |struct omap_hwmod *oh;                                                          |struct platform_device *pdev;                                                   |char *name = "omap-gpmc";       -----------------------------------------+      |char *oh_name = "gpmc";                                                  |      ||      |oh = omap_hwmod_lookup(oh_name);                                         |      |if (!oh) {                                                               |      |pr_err("Could not look up %s\n", oh_name);                           |      |return -ENODEV;                                                      |      |}                                                                        |      ||      |pdev = omap_device_build(name, -1, oh, pdata,                            |      |pdata_len, NULL, 0, 0);                                  |      |if (IS_ERR(pdev)) {                                                      |      |WARN(1, "Can't build omap_device for %s:%s.\n",                      |      |name, oh->name);                                     |      |return PTR_ERR(pdev);                                                |      |}                                                                        |      ||      |return 0;                                                                |      |
}                                                                            |      ||      ||      ||      |
cat arch/arm/mach-omap2/gpmc.c                                               |      |
static struct platform_driver gpmc_driver = {                                |      |.probe      = gpmc_probe,                         --------------+        |      |.remove     = __devexit_p(gpmc_remove),                         |        |      |.driver     = {                                                 |        |      |.name   = DRIVER_NAME,       ----------+                    |        |      |.owner  = THIS_MODULE,                 |                    |        |      |},                                         |                    |        |      |
};                                             |                    |        |      ||                    |        |      |
module_platform_driver(gpmc_driver);           |                    |        |      ||                    |        |      |
#define    DRIVER_NAME    "omap-gpmc"   <------+--------------------*--------+      ||               |
static int __devinit gpmc_probe(struct platform_device *pdev)  <----+               |
{                                                                                   |u32 l;                                                                          |int ret = -EINVAL;                                                              |struct resource *res = NULL;                                                    |struct gpmc_devices_info *gpmc_device = pdev->dev.platform_data;                |void *p;                                                                        ||/* XXX: This should go away with HWMOD & runtime PM adaptation */               |gpmc_clk_init(&pdev->dev);                                                      ||gpmc_dev = &pdev->dev;                                                          ||gpmc = devm_kzalloc(&pdev->dev, sizeof(struct gpmc), GFP_KERNEL);               |if (!gpmc)                                                                      |return -ENOMEM;                                                             ||gpmc->dev = &pdev->dev;                                                         ||res = platform_get_resource(pdev, IORESOURCE_MEM, 0);                           |if (!res) {                                                                     |ret = -ENOENT;                                                              |dev_err(gpmc->dev, "Failed to get resource: memory\n");                     |goto err_res;                                                               |}                                                                               |gpmc->phys_base = res->start;                                                   |gpmc->memsize = resource_size(res);                                             ||if (request_mem_region(gpmc->phys_base,                                         |gpmc->memsize, DRIVER_NAME) == NULL) {                                      |ret = -ENOMEM;                                                              |dev_err(gpmc->dev, "Failed to request memory region\n");                    |goto err_mem;                                                               |}                                                                               ||gpmc->io_base = ioremap(gpmc->phys_base, gpmc->memsize);                        |if (!gpmc->io_base) {                                                           |ret = -ENOMEM;                                                              |dev_err(gpmc->dev, "Failed to ioremap memory\n");                           |goto err_remap;                                                             |}                                                                               ||gpmc->ecc_used = -EINVAL;                                                       |spin_lock_init(&gpmc->mem_lock);                                                |platform_set_drvdata(pdev, gpmc);                                               ||l = gpmc_read_reg(GPMC_REVISION);                                               |dev_info(gpmc->dev, "GPMC revision %d.%d\n", (l >> 4) & 0x0f, l & 0x0f);        ||gpmc_mem_init();                                                                ||for (p = gpmc_device->pdata; p; gpmc_device++, p = gpmc_device->pdata)          |if (gpmc_device->flag & GPMC_DEVICE_NAND)                   <---------------+gpmc_nand_init((struct omap_nand_platform_data *) p);   ----------------+return 0;                                                                       ||
err_remap:                                                                          |release_mem_region(gpmc->phys_base, gpmc->memsize);                             |
err_mem:                                                                            |
err_res:                                                                            |devm_kfree(&pdev->dev, gpmc);                                                   |return ret;                                                                     |
}                                                                                   ||
int __devinit gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data)  <-----+
{int err    = 0;u8 cs = 0;struct device *dev = &gpmc_nand_device.dev;/* if cs not provided, find out the chip-select on which NAND exist */if (gpmc_nand_data->cs > GPMC_CS_NUM)while (cs < GPMC_CS_NUM) {u32 ret = 0;ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);if ((ret & 0xC00) == 0x800) {printk(KERN_INFO "Found NAND on CS%d\n", cs);gpmc_nand_data->cs = cs;break;}cs++;}if (gpmc_nand_data->cs > GPMC_CS_NUM) {printk(KERN_INFO "NAND: Unable to find configuration ""in GPMC\n ");return -ENODEV;}gpmc_nand_device.dev.platform_data = gpmc_nand_data;gpmc_nand_data->ctrlr_suspend    = gpmc_suspend;gpmc_nand_data->ctrlr_resume    = gpmc_resume;printk(KERN_INFO "Registering NAND on CS%d\n", gpmc_nand_data->cs);err = gpmc_cs_request(gpmc_nand_data->cs, NAND_IO_SIZE,&gpmc_nand_data->phys_base);if (err < 0) {dev_err(dev, "Cannot request GPMC CS\n");return err;}/* Set timings in GPMC */err = omap2_nand_gpmc_retime(gpmc_nand_data);                   ------------------+if (err < 0) {                                                                    |dev_err(dev, "Unable to set gpmc timings: %d\n", err);                        |return err;                                                                   |}                                                                                 ||/* Enable RD PIN Monitoring Reg */                                                |if (gpmc_nand_data->dev_ready) {                                                  |gpmc_cs_configure(gpmc_nand_data->cs, GPMC_CONFIG_RDY_BSY, 1);                |}                                                                                 ||err = platform_device_register(&gpmc_nand_device);     ---------------------------*-+if (err < 0) {                                                                    | |dev_err(dev, "Unable to register NAND device\n");                             | |goto out_free_cs;                                                             | |}                                                                                 | || |return 0;                                                                         | || |
out_free_cs:                                                                          | |gpmc_cs_free(gpmc_nand_data->cs);                                                 | || |return err;                                                                       | |
}                                                                                     | || |
static int omap2_nand_gpmc_retime(struct omap_nand_platform_data *gpmc_nand_data)  <--+ |
{                                                                                       |struct gpmc_timings t;                                                              |int err;                                                                            ||if (!gpmc_nand_data->gpmc_t)                                                        |return 0;                                                                       ||memset(&t, 0, sizeof(t));                                                           |t.sync_clk = gpmc_nand_data->gpmc_t->sync_clk;                                      |t.cs_on = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->cs_on);                    |t.adv_on = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->adv_on);                  ||/* Read */                                                                          |t.adv_rd_off = gpmc_round_ns_to_ticks(                                              |gpmc_nand_data->gpmc_t->adv_rd_off);                                    |t.oe_on  = t.adv_on;                                                                |t.access = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->access);                  |t.oe_off = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->oe_off);                  |t.cs_rd_off = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->cs_rd_off);            |t.rd_cycle  = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->rd_cycle);             ||/* Write */                                                                         |t.adv_wr_off = gpmc_round_ns_to_ticks(                                              |gpmc_nand_data->gpmc_t->adv_wr_off);                                    |t.we_on  = t.oe_on;                                                                 |if (cpu_is_omap34xx()) {                                                            |t.wr_data_mux_bus =    gpmc_round_ns_to_ticks(                                  |gpmc_nand_data->gpmc_t->wr_data_mux_bus);                               |t.wr_access = gpmc_round_ns_to_ticks(                                           |gpmc_nand_data->gpmc_t->wr_access);                                     |}                                                                                   |t.we_off = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->we_off);                  |t.cs_wr_off = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->cs_wr_off);            |t.wr_cycle  = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->wr_cycle);   --+       ||       |/* Configure GPMC */                                                        |       |if (gpmc_nand_data->devsize == NAND_BUSWIDTH_16)                            |       |gpmc_cs_configure(gpmc_nand_data->cs, GPMC_CONFIG_DEV_SIZE, 1);         |       |else                                                                        |       |gpmc_cs_configure(gpmc_nand_data->cs, GPMC_CONFIG_DEV_SIZE, 0);         |       |gpmc_cs_configure(gpmc_nand_data->cs,                                       |       |GPMC_CONFIG_DEV_TYPE, GPMC_DEVICETYPE_NAND);                        |       |err = gpmc_cs_set_timings(gpmc_nand_data->cs, &t);                          |       |if (err)                                                                    |       |return err;                                                             |       ||       |return 0;                                                                   |       |
}                                                                               |       ||       |
unsigned int gpmc_round_ns_to_ticks(unsigned int time_ns)           <-----------+       |
{                                                                                       |unsigned long ticks = gpmc_ns_to_ticks(time_ns);          ----------+               ||               |return ticks * gpmc_get_fclk_period() / 1000;                       |               |
}                                                                       |               ||               |
unsigned int gpmc_ns_to_ticks(unsigned int time_ns)           <---------+               |
{                                                                                       |unsigned long tick_ps;                                                              ||/* Calculate in picosecs to yield more exact results */                             |tick_ps = gpmc_get_fclk_period();                         ----------+               ||               |return (time_ns * 1000 + tick_ps - 1) / tick_ps;                    |               |
}                                                                       |               ||               |
unsigned long gpmc_get_fclk_period(void)                      <---------+               |
{                                                                                       |unsigned long rate = clk_get_rate(gpmc_l3_clk);                                     ||if (rate == 0) {                                                                    |printk(KERN_WARNING "gpmc_l3_clk not enabled\n");                               |return 0;                                                                       |}                                                                                   ||rate /= 1000;                                                                       |rate = 1000000000 / rate;    /* In picoseconds */                                   ||return rate;                                                                        |
}                                                                                       ||
static struct platform_device gpmc_nand_device = {       <------------------------------+.name        = "omap2-nand",               ------------------------+.id        = 0,                                                    |.num_resources    = 1,                                             |.resource    = &gpmc_nand_resource,        ---------+              |
};                                                      |              ||              |
static struct resource gpmc_nand_resource = {  <--------+              |.flags        = IORESOURCE_MEM,            ---------+              |
};                                                      |              ||              |
#define IORESOURCE_MEM        0x00000200       <--------+              ||||
cat drivers/mtd/nand/omap2.c                                           |
#define    DRIVER_NAME    "omap2-nand"         <-----------------------+
static struct platform_driver omap_nand_driver = {   <-----+.probe        = omap_nand_probe,             ----------*-----------+.remove        = omap_nand_remove,                     |           |
#ifdef CONFIG_PM                                           |           |.suspend    = omap_nand_suspend,                       |           |.resume        = omap_nand_resume,                     |           |
#endif                                                     |           |.driver        = {                                     |           |.name    = DRIVER_NAME,                            |           |.owner    = THIS_MODULE,                           |           |},                                                     |           |
};                                                         |           ||           |
static int __init omap_nand_init(void)          <--------+ |           |
{                                                        | |           |pr_info("%s driver initializing\n", DRIVER_NAME);    | |           || |           |return platform_driver_register(&omap_nand_driver); -*-+           |
}                                                        |             ||             |
static void __exit omap_nand_exit(void)                  |             |
{                                                        |             |platform_driver_unregister(&omap_nand_driver);       |             |
}                                                        |             ||             |
module_init(omap_nand_init);                    ---------+             |
module_exit(omap_nand_exit);                                           ||
static int __devinit omap_nand_probe(struct platform_device *pdev) <---+
{struct omap_nand_info        *info;struct omap_nand_platform_data    *pdata;int                err;int                i, offset;pdata = pdev->dev.platform_data;if (pdata == NULL) {dev_err(&pdev->dev, "platform data missing\n");return -ENODEV;}info = kzalloc(sizeof(struct omap_nand_info), GFP_KERNEL);if (!info)return -ENOMEM;platform_set_drvdata(pdev, info);spin_lock_init(&info->controller.lock);init_waitqueue_head(&info->controller.wq);info->pdev = pdev;info->gpmc_cs        = pdata->cs;info->phys_base        = pdata->phys_base;info->mtd.priv        = &info->nand;info->mtd.name        = dev_name(&pdev->dev);info->mtd.owner        = THIS_MODULE;info->ecc_opt        = pdata->ecc_opt;info->nand.options    = pdata->devsize;info->nand.options    |= NAND_SKIP_BBTSCAN;/** If ELM feature is used in OMAP NAND driver, then configure it*/if (pdata->elm_used) {if (pdata->ecc_opt == OMAP_ECC_BCH8_CODE_HW)omap_configure_elm(&info->mtd, OMAP_BCH8_ECC);}if (pdata->ctrlr_suspend)info->ctrlr_suspend = pdata->ctrlr_suspend;if (pdata->ctrlr_resume)info->ctrlr_resume = pdata->ctrlr_resume;/* NAND write protect off */gpmc_cs_configure(info->gpmc_cs, GPMC_CONFIG_WP, 0);if (!request_mem_region(info->phys_base, NAND_IO_SIZE,pdev->dev.driver->name)) {err = -EBUSY;goto out_free_info;}info->nand.IO_ADDR_R = ioremap(info->phys_base, NAND_IO_SIZE);if (!info->nand.IO_ADDR_R) {err = -ENOMEM;goto out_release_mem_region;}info->nand.controller = &info->controller;info->nand.IO_ADDR_W = info->nand.IO_ADDR_R;info->nand.cmd_ctrl  = omap_hwcontrol;/** If RDY/BSY line is connected to OMAP then use the omap ready* funcrtion and the generic nand_wait function which reads the status* register after monitoring the RDY/BSY line.Otherwise use a standard* chip delay which is slightly more than tR (AC Timing) of the NAND* device and read status register until you get a failure or success*/if (pdata->dev_ready) {info->nand.dev_ready = omap_dev_ready;info->nand.chip_delay = 0;} else {info->nand.waitfunc = omap_wait;info->nand.chip_delay = 50;}switch (pdata->xfer_type) {case NAND_OMAP_PREFETCH_POLLED:info->nand.read_buf   = omap_read_buf_pref;info->nand.write_buf  = omap_write_buf_pref;break;case NAND_OMAP_POLLED:if (info->nand.options & NAND_BUSWIDTH_16) {info->nand.read_buf   = omap_read_buf16;info->nand.write_buf  = omap_write_buf16;} else {info->nand.read_buf   = omap_read_buf8;info->nand.write_buf  = omap_write_buf8;}break;case NAND_OMAP_PREFETCH_DMA:err = omap_request_dma(OMAP24XX_DMA_GPMC, "NAND",omap_nand_dma_cb, &info->comp, &info->dma_ch);if (err < 0) {info->dma_ch = -1;dev_err(&pdev->dev, "DMA request failed!\n");goto out_release_mem_region;} else {omap_set_dma_dest_burst_mode(info->dma_ch,OMAP_DMA_DATA_BURST_16);omap_set_dma_src_burst_mode(info->dma_ch,OMAP_DMA_DATA_BURST_16);info->nand.read_buf   = omap_read_buf_dma_pref;info->nand.write_buf  = omap_write_buf_dma_pref;}break;case NAND_OMAP_PREFETCH_IRQ:err = request_irq(pdata->gpmc_irq,omap_nand_irq, IRQF_SHARED, "gpmc-nand", info);if (err) {dev_err(&pdev->dev, "requesting irq(%d) error:%d",pdata->gpmc_irq, err);goto out_release_mem_region;} else {info->gpmc_irq         = pdata->gpmc_irq;info->nand.read_buf  = omap_read_buf_irq_pref;info->nand.write_buf = omap_write_buf_irq_pref;}break;default:dev_err(&pdev->dev,"xfer_type(%d) not supported!\n", pdata->xfer_type);err = -EINVAL;goto out_release_mem_region;}info->nand.verify_buf = omap_verify_buf;/* selsect the ecc type */if (pdata->ecc_opt == OMAP_ECC_HAMMING_CODE_DEFAULT)info->nand.ecc.mode = NAND_ECC_SOFT;else {if (pdata->ecc_opt == OMAP_ECC_BCH4_CODE_HW) {info->nand.ecc.bytes    = 4*7;info->nand.ecc.size     = 4*512;} else if (pdata->ecc_opt == OMAP_ECC_BCH8_CODE_HW) {info->nand.ecc.bytes     = OMAP_BCH8_ECC_SECT_BYTES;info->nand.ecc.size      = 512;info->nand.ecc.read_page = omap_read_page_bch;} else {info->nand.ecc.bytes    = 3;info->nand.ecc.size     = 512;}info->nand.ecc.calculate        = omap_calculate_ecc;info->nand.ecc.hwctl            = omap_enable_hwecc;info->nand.ecc.correct          = omap_correct_data;info->nand.ecc.mode             = NAND_ECC_HW;}/* DIP switches on some boards change between 8 and 16 bit* bus widths for flash.  Try the other width if the first try fails.*/if (nand_scan_ident(&info->mtd, 1, NULL)) {                    --------+info->nand.options ^= NAND_BUSWIDTH_16;                            |if (nand_scan_ident(&info->mtd, 1, NULL)) {                        |err = -ENXIO;                                                  |goto out_release_mem_region;                                   |}                                                                  |}                                                                      ||/* select ecc lyout */                                                 |if (info->nand.ecc.mode != NAND_ECC_SOFT) {                            ||if (!(info->nand.options & NAND_BUSWIDTH_16))                      |info->nand.badblock_pattern = &bb_descrip_flashbased;          ||offset = JFFS2_CLEAN_MARKER_OFFSET;                                ||omap_oobinfo.eccbytes = info->nand.ecc.bytes *                     |info->mtd.writesize / info->nand.ecc.size;                     ||if (pdata->ecc_opt == OMAP_ECC_HAMMING_CODE_HW_ROMCODE) {          |omap_oobinfo.oobfree->offset =                                 |offset + omap_oobinfo.eccbytes;                    |omap_oobinfo.oobfree->length = info->mtd.oobsize -             |(offset + omap_oobinfo.eccbytes);                          |} else if (pdata->ecc_opt == OMAP_ECC_BCH8_CODE_HW) {              |offset = BCH_ECC_POS; /* Synchronize with U-boot */            ||omap_oobinfo.oobfree->offset = offset +                        |omap_oobinfo.eccbytes;                                     ||omap_oobinfo.oobfree->length = info->mtd.oobsize -             |offset - omap_oobinfo.eccbytes;                    |} else {                                                           |omap_oobinfo.oobfree->offset = offset;                         |omap_oobinfo.oobfree->length = info->mtd.oobsize -             |offset - omap_oobinfo.eccbytes;                    |/*                                                             |offset is calculated considering the following :               |1) 12 bytes ECC for 512 byte access and 24 bytes ECC for       |256 byte access in OOB_64 can be supported                     |2)Ecc bytes lie to the end of OOB area.                        |3)Ecc layout must match with u-boot's ECC layout.              |*/                                                             |offset = info->mtd.oobsize - MAX_HWECC_BYTES_OOB_64;           |}                                                                  ||for (i = 0; i < omap_oobinfo.eccbytes; i++)                        |omap_oobinfo.eccpos[i] = i+offset;                             ||info->nand.ecc.layout = &omap_oobinfo;                             |}                                                                      ||/* second phase scan */                                                |if (nand_scan_tail(&info->mtd)) {                                      |err = -ENXIO;                                                      |goto out_release_mem_region;                                       |}                                                                      ||/* Fix sub page size to page size for HW ECC */                        |if (info->nand.ecc.mode == NAND_ECC_HW) {                              |/*                                                                 |* For HW ECC, subpage size set to page size                       |* as subpage operations not supporting.                           |*/                                                                |info->mtd.subpage_sft = 0;                                         |info->nand.subpagesize = info->mtd.writesize >>                    |info->mtd.subpage_sft;                                         |}                                                                      ||mtd_device_parse_register(&info->mtd, NULL, 0,                         |pdata->parts, pdata->nr_parts);                                ||platform_set_drvdata(pdev, &info->mtd);                                ||return 0;                                                              ||
out_release_mem_region:                                                    |release_mem_region(info->phys_base, NAND_IO_SIZE);                     |
out_free_info:                                                             |kfree(info);                                                           ||return err;                                                            |
}                                                                          ||
int nand_scan_ident(struct mtd_info *mtd, int maxchips,      <-------------+struct nand_flash_dev *table)
{int i, busw, nand_maf_id, nand_dev_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_dev_id, table);                   |       ||       |if (IS_ERR(type)) {                                               |       |if (!(chip->options & NAND_SCAN_SILENT_NODEV))                |       |pr_warn("No NAND device found\n"); // get the target      |       |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) ||                    |  |    |nand_dev_id != chip->read_byte(mtd))                      |  |    |break;                                                    |  |    |}                                                                 |  |    |if (i > 1)                                                        |  |    |pr_info("%d NAND chips detected\n", i);                       |  |    ||  |    |/* Store the number of chips and calc total size for mtd */       |  |    |chip->numchips = i;                                               |  |    |mtd->size = i * chip->chipsize;                                   |  |    ||  |    |return 0;                                                         |  |    |
}                                                                     |  |    |
EXPORT_SYMBOL(nand_scan_ident);                                       |  |    ||  |    |
/* 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;                                 |if (!chip->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 = busw ? nand_write_buf16 : nand_write_buf;           |if (!chip->read_buf)                                                      |chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;              |if (!chip->verify_buf)                                                    |chip->verify_buf = busw ? nand_verify_buf16 : nand_verify_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);                           |}                                                                         ||
}                                                                             ||
static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, <-----+struct nand_chip *chip,int busw,int *maf_id, int *dev_id,struct nand_flash_dev *type)
{int i, maf_idx;u8 id_data[8];int ret;/* 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);/** 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);for (i = 0; i < 2; i++)id_data[i] = chip->read_byte(mtd);if (id_data[0] != *maf_id || id_data[1] != *dev_id) {pr_info("%s: second ID read did not match ""%02x,%02x against %02x,%02x\n", __func__,*maf_id, *dev_id, id_data[0], id_data[1]);return ERR_PTR(-ENODEV);}if (!type)type = nand_flash_ids;for (; type->name != NULL; type++)if (*dev_id == type->id)break;chip->onfi_version = 0;if (!type->name || !type->pagesize) {/* Check is chip is ONFI compliant */ret = nand_flash_detect_onfi(mtd, chip, &busw);if (ret)goto ident_done;}chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);/* Read entire ID string */for (i = 0; i < 8; i++)id_data[i] = chip->read_byte(mtd);if (!type->name)return ERR_PTR(-ENODEV);if (!mtd->name)mtd->name = type->name;chip->chipsize = (uint64_t)type->chipsize << 20;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) {int extid;/* The 3rd id byte holds MLC / multichip data */chip->cellinfo = id_data[2];/* The 4th id byte is the important one */extid = id_data[3];/** Field definitions are in the following datasheets:* Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32)* New style   (6 byte ID): Samsung K9GBG08U0M (p.40)** Check for wraparound + Samsung ID + nonzero 6th byte* to decide what to do.*/if (id_data[0] == id_data[6] && id_data[1] == id_data[7] &&id_data[0] == NAND_MFR_SAMSUNG &&(chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&id_data[5] != 0x00) {/* Calc pagesize */mtd->writesize = 2048 << (extid & 0x03);extid >>= 2;/* Calc oobsize */switch (extid & 0x03) {case 1:mtd->oobsize = 128;break;case 2:mtd->oobsize = 218;break;case 3:mtd->oobsize = 400;break;default:mtd->oobsize = 436;break;}extid >>= 2;/* Calc blocksize */mtd->erasesize = (128 * 1024) <<(((extid >> 1) & 0x04) | (extid & 0x03));busw = 0;} else {/* Calc pagesize */mtd->writesize = 1024 << (extid & 0x03);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;mtd->oobsize = mtd->writesize / 32;busw = type->options & NAND_BUSWIDTH_16;/** Check for Spansion/AMD ID + repeating 5th, 6th byte since* some Spansion chips have erasesize that conflicts with size* listed in nand_ids table.* Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39)*/if (*maf_id == NAND_MFR_AMD && id_data[4] != 0x00 &&id_data[5] == 0x00 && id_data[6] == 0x00 &&id_data[7] == 0x00 && mtd->writesize == 512) {mtd->erasesize = 128 * 1024;mtd->erasesize <<= ((id_data[3] & 0x03) << 1);}}/* Get chip options, preserve non chip based options */chip->options &= ~NAND_CHIPOPTIONS_MSK;chip->options |= type->options & NAND_CHIPOPTIONS_MSK;/** Check if chip is not a Samsung device. Do not clear the* options for chips which do not have an extended id.*/if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;
ident_done:/** Set chip as a default. Board drivers can override it, if necessary.*/chip->options |= NAND_NO_AUTOINCR;/* 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)) {pr_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);pr_warn("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));chip->chip_shift += 32 - 1;}chip->badblockbits = 8;/* Set the bad block position */if (mtd->writesize > 512 || (busw & 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 and AMD/Spansion. All others scan* only the first page.*/if ((chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&(*maf_id == NAND_MFR_SAMSUNG ||*maf_id == NAND_MFR_HYNIX))chip->bbt_options |= NAND_BBT_SCANLASTPAGE;else if ((!(chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&(*maf_id == NAND_MFR_SAMSUNG ||*maf_id == NAND_MFR_HYNIX ||*maf_id == NAND_MFR_TOSHIBA ||*maf_id == NAND_MFR_AMD)) ||(mtd->writesize == 2048 &&*maf_id == NAND_MFR_MICRON))chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;/* Check for AND chips with 4 page planes */if (chip->options & NAND_4PAGE_ARRAY)chip->erase_cmd = multi_erase_cmd;elsechip->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;pr_info("NAND device: Manufacturer ID:"" 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, *dev_id,nand_manuf_ids[maf_idx].name,chip->onfi_version ? chip->onfi_params.model : type->name);return type;
}

 

转载于:https://www.cnblogs.com/zengjfgit/p/4779333.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/287761.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Blazor University (19)使用 RenderFragments 模板化组件 —— 数据传递

原文链接&#xff1a;https://blazor-university.com/templating-components-with-renderfragements/passing-data-to-a-renderfragement/将数据传递给 RenderFragment源代码[1]到目前为止&#xff0c;我们使用了仅包含子标记的 RenderFragments&#xff0c;然后在渲染组件时按…

一头扎进Node(三) - File System

file.open:异步模式打开文件 fs.open(path, flags[, mode], callback) 案例代码如下&#xff1a; var fs require(fs);/*** 参数说明&#xff1a;* 1.path&#xff1a;要打开的文件的文件路径* 2.flags&#xff1a;打开文件的方式 读/写* r&#xff1a;只读方式打开文件…

《零基础看得懂的C语言入门教程 》——(十二)原来结构体是这么回事

一、学习目标 了解C语言的结构体的使用方法了解C语言结构体的结构的赋值了解多种C语言结构体变量的赋值方法和取值方法 目录 C语言真的很难吗&#xff1f;那是你没看这张图&#xff0c;化整为零轻松学习C语言。 第一篇&#xff1a;&#xff08;一&#xff09;脱离学习误区 第…

【学生选课系统经典】C#与SQLSERVER连接:Windows应用工程案例

实验任务描述 1 用C#访问SQLSERVER数据库(两种安全模式); 2 用C#完成数据库指定表上的数据显示; 3 用C#完成数据库指定表上的数据插入、删除和更新; 4 用C#完成数据库用户验证。 注意,由于C#语言的强大功能,下面的代码适用于SQLSERVER2000、也适合于SQLSERVER2005。区别仅…

Java精选笔记_JDBC

JDBC概述 什么是JDBC JDBC全称是Java数据库连接&#xff08;Java Database Connectivity&#xff09;&#xff0c;应用程序可通过这套API连接到关系数据库&#xff0c;并使用SQL语句来完成对数据库中数据的查询、更新和删除等操作。是一套用于执行SQL语句的Java API。Java的数据…

mysql关系数据库引擎_MySQL数据库引擎详解

作为Java程序员&#xff0c;MySQL数据库大家平时应该都没少使用吧&#xff0c;对MySQL数据库的引擎应该也有所了解&#xff0c;这篇文章就让我详细的说说MySQL数据库的Innodb和MyIASM两种引擎以及其索引结构。也来巩固一下自己对这块知识的掌握。Innodb引擎Innodb引擎提供了对数…

Java之synchronized的JVM底层实现原理精简理解

1 synchronized的JVM底层原理实现的精简理解 Java 虚拟机中的synchronized基于进入和退出Monitor对象&#xff08;也称为管程或监视器锁&#xff09;实现&#xff0c; 无论是显式同步(synchronized作用在同步代码块&#xff0c;有明确的 monitorenter 和 monitorexit 指令) 还是…

三分钟掌握Actor和CSP模型

点击上方蓝字进行关注前文传送门&#xff1a;《三分钟掌握共享内存模型和 Actor模型》&#xff0c; 一直想比较Actor模型与golang的CSP模型&#xff0c;经过一段时间的实战记录了本文。Actor vs CSP模型• 传统多线程的的共享内存&#xff08;ShareMemory&#xff09;模型使用l…

DateTimeToUnix/UnixToDateTime 对接时间转换

问题&#xff0c;通过毫秒数来解析出时间&#xff1a;&#xff08;很多对接的时候经常需要用到&#xff09; <?php $MyJson {"jingdong_vas_subscribe_get_responce":{"code":"0","item_code":"FW_GOODS-2236-1","…

【学生选课系统经典】VB与SQLSERVER连接:Windows应用工程案例

实验任务描述 1 用VB6访问SQLSERVER数据库(两种安全模式); 2 用VB6完成数据库指定表上的数据显示; 3 用VB6完成数据库指定表上的数据插入、删除和更新; 4 用VB6完成SQLSERVER2008数据库用户验证。 一、数据库系统 该实验中,所要求的数据库名称为SCHOOL,总共涉及以下表:

丢失api-ms-win-crt-runtime-l1-1-0.dll

运行Cmder的时候提示&#xff1a;丢失api-ms-win-crt-runtime-l1-1-0.dll在网上找了一些方法&#xff0c;基本解决方法都是装VC2015的运行时&#xff0c;但是我安装的时候出错&#xff0c;大家可以先试试。接着我就去解决安装出错这问题没&#xff0c;折腾了半天也没成功。后来…

《假如编程是魔法之零基础看得懂的Python入门教程 》——(二)魔法实习生第一步了解魔杖的使用

学习目标 了解什么是开发环境了解python语言的环境安装了解python语言编程的编辑器工具 目录 第一篇&#xff1a;《假如编程是魔法之零基础看得懂的Python入门教程 》——&#xff08;一&#xff09;既然你选择了这系列教程那么我就要让你听得懂 第三篇&#xff1a;《假如编…

Java之synchronized可重入性的理解

1 synchronized可重入性的理解 当一个线程试图操作一个由其他线程持有的对象锁的临界资源时&#xff0c;将会处于阻塞状态&#xff0c;但当一个线程再次请求自己持有对象锁的临界资源时&#xff0c;如果当前锁是重入性&#xff0c;会请求将会成功&#xff0c;如果当前锁不是可…

onmouseover-onmouseout

<input type"checkbox" value"autoLogin" οnmοuseοver"block()" οnmοuseοut"none()">两周内自动登录 <div id"div1">为了您的信息安全请不要在网吧或公共电脑勾选此项</div> <script> functi…

mysql5.7 only_full_group_by_Mysql5.7及以上版本 ONLY_FULL_GROUP_BY报错的解决方法

近期在开发过程中&#xff0c;因为项目开发环境连接的mysql数据库是阿里云的数据库&#xff0c;而阿里云的数据库版本是5.6的。而测试环境的mysql是自己安装的5.7。因此在开发过程中有小伙伴不注意写了有关group by的sql语句。在开发环境中运行是正常的&#xff0c;而到了测试环…

一款高速的NET版的离线免费OCR

PaddleOCR.Onnx一款基于Paddle的OCR&#xff0c;项目使用ONNX模型&#xff0c;速度更快。本项目同时支持X64和X86的CPU上使用。本项目是一个基于PaddleOCR的C代码修改并封装的.NET的工具类库。包含文本识别、文本检测、基于文本检测结果的统计分析的表格识别功能&#xff0c;同…

spring 注解简单使用

一、通用注解 1、项目结构&#xff1a; 2、新建Person类&#xff0c;注解Component未指明id&#xff0c;则后期使用spring获取实例对象时使用默认id"person"方式获取或使用类方式获取 package hjp.spring.annotation.commen;import org.springframework.stereotype.C…

selenium+python笔记3

#!/usr/bin/env python # -*- coding: utf-8 -*- """ desc:学习unittest的用法 注意setUp/setUpClass&#xff0c;tearDown/tearDownClass的区别 ① setUp():每个测试函数运行前运行 ② tearDown():每个测试函数运行完后执行 ③ setUpClass():必须使用classmeth…

【学生选课系统经典】C#与SQLSERVER连接:ASP.NET网站(服务器端,IIS发布)

实验任务描述 1 用C#访问SQLSERVER数据库(两种安全模式); 2 用C#完成数据库指定表上的数据显示; 3 用C#完成数据库指定表上的数据插入、删除和更新; 4 用C#完成数据库用户验证。 此处使用ASP.NET工程来完成这个项目,和Windows应用不同的是:这个项目是在服务器上、依靠IIS服…

TCP包头、UDP包头、IP包头、和MAC帧包头详细字段和包头大小

1 TCP头 TCP是一种可靠的、面向连接的字节流服务,头部定义如下。 /*TCP头定义,共20个字节*/ typedef struct _TCP_HEADER {short m_sSourPort;       // 源端口号16bitshort m_sDestPort;       // 目的端口号16bitunsigned int m_uiSequNum; …