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.pswp.cn/news/287761.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/287761.shtml
英文地址,請注明出處:http://en.pswp.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; …