📄 omap2.c
字号:
INIT_COMPLETION(c->dma_done); omap_start_dma(c->dma_channel); timeout = jiffies + msecs_to_jiffies(20); done = &c->dma_done.done; while (time_before(jiffies, timeout)) if (*done) break; dma_unmap_single(&c->pdev->dev, dma_dst, count, DMA_TO_DEVICE); if (!*done) { dev_err(&c->pdev->dev, "timeout waiting for DMA\n"); goto out_copy; } return 0;out_copy: memcpy(this->base + bram_offset, buf, count); return 0;}#elseint omap3_onenand_read_bufferram(struct mtd_info *mtd, int area, unsigned char *buffer, int offset, size_t count);int omap3_onenand_write_bufferram(struct mtd_info *mtd, int area, const unsigned char *buffer, int offset, size_t count);#endif#if defined(CONFIG_ARCH_OMAP2) || defined(MULTI_OMAP2)static int omap2_onenand_read_bufferram(struct mtd_info *mtd, int area, unsigned char *buffer, int offset, size_t count){ struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); struct onenand_chip *this = mtd->priv; dma_addr_t dma_src, dma_dst; int bram_offset; bram_offset = omap2_onenand_bufferram_offset(mtd, area) + area + offset; /* DMA is not used. Revisit PM requirements before enabling it. */ if (1 || (c->dma_channel < 0) || ((void *) buffer >= (void *) high_memory) || (bram_offset & 3) || (((unsigned int) buffer) & 3) || (count < 1024) || (count & 3)) { memcpy(buffer, (__force void *)(this->base + bram_offset), count); return 0; } dma_src = c->phys_base + bram_offset; dma_dst = dma_map_single(&c->pdev->dev, buffer, count, DMA_FROM_DEVICE); if (dma_mapping_error(&c->pdev->dev, dma_dst)) { dev_err(&c->pdev->dev, "Couldn't DMA map a %d byte buffer\n", count); return -1; } omap_set_dma_transfer_params(c->dma_channel, OMAP_DMA_DATA_TYPE_S32, count / 4, 1, 0, 0, 0); omap_set_dma_src_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC, dma_src, 0, 0); omap_set_dma_dest_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC, dma_dst, 0, 0); INIT_COMPLETION(c->dma_done); omap_start_dma(c->dma_channel); wait_for_completion(&c->dma_done); dma_unmap_single(&c->pdev->dev, dma_dst, count, DMA_FROM_DEVICE); return 0;}static int omap2_onenand_write_bufferram(struct mtd_info *mtd, int area, const unsigned char *buffer, int offset, size_t count){ struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); struct onenand_chip *this = mtd->priv; dma_addr_t dma_src, dma_dst; int bram_offset; bram_offset = omap2_onenand_bufferram_offset(mtd, area) + area + offset; /* DMA is not used. Revisit PM requirements before enabling it. */ if (1 || (c->dma_channel < 0) || ((void *) buffer >= (void *) high_memory) || (bram_offset & 3) || (((unsigned int) buffer) & 3) || (count < 1024) || (count & 3)) { memcpy((__force void *)(this->base + bram_offset), buffer, count); return 0; } dma_src = dma_map_single(&c->pdev->dev, (void *) buffer, count, DMA_TO_DEVICE); dma_dst = c->phys_base + bram_offset; if (dma_mapping_error(&c->pdev->dev, dma_dst)) { dev_err(&c->pdev->dev, "Couldn't DMA map a %d byte buffer\n", count); return -1; } omap_set_dma_transfer_params(c->dma_channel, OMAP_DMA_DATA_TYPE_S16, count / 2, 1, 0, 0, 0); omap_set_dma_src_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC, dma_src, 0, 0); omap_set_dma_dest_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC, dma_dst, 0, 0); INIT_COMPLETION(c->dma_done); omap_start_dma(c->dma_channel); wait_for_completion(&c->dma_done); dma_unmap_single(&c->pdev->dev, dma_dst, count, DMA_TO_DEVICE); return 0;}#elseint omap2_onenand_read_bufferram(struct mtd_info *mtd, int area, unsigned char *buffer, int offset, size_t count);int omap2_onenand_write_bufferram(struct mtd_info *mtd, int area, const unsigned char *buffer, int offset, size_t count);#endifstatic struct platform_driver omap2_onenand_driver;static int __adjust_timing(struct device *dev, void *data){ int ret = 0; struct omap2_onenand *c; c = dev_get_drvdata(dev); BUG_ON(c->setup == NULL); /* DMA is not in use so this is all that is needed */ /* Revisit for OMAP3! */ ret = c->setup(c->onenand.base, c->freq); return ret;}int omap2_onenand_rephase(void){ return driver_for_each_device(&omap2_onenand_driver.driver, NULL, NULL, __adjust_timing);}static void __devexit omap2_onenand_shutdown(struct platform_device *pdev){ struct omap2_onenand *c = dev_get_drvdata(&pdev->dev); /* With certain content in the buffer RAM, the OMAP boot ROM code * can recognize the flash chip incorrectly. Zero it out before * soft reset. */ memset((__force void *)c->onenand.base, 0, ONENAND_BUFRAM_SIZE);}static int __devinit omap2_onenand_probe(struct platform_device *pdev){ struct omap_onenand_platform_data *pdata; struct omap2_onenand *c; int r; pdata = pdev->dev.platform_data; if (pdata == NULL) { dev_err(&pdev->dev, "platform data missing\n"); return -ENODEV; } c = kzalloc(sizeof(struct omap2_onenand), GFP_KERNEL); if (!c) return -ENOMEM; init_completion(&c->irq_done); init_completion(&c->dma_done); c->gpmc_cs = pdata->cs; c->gpio_irq = pdata->gpio_irq; c->dma_channel = pdata->dma_channel; if (c->dma_channel < 0) { /* if -1, don't use DMA */ c->gpio_irq = 0; } r = gpmc_cs_request(c->gpmc_cs, ONENAND_IO_SIZE, &c->phys_base); if (r < 0) { dev_err(&pdev->dev, "Cannot request GPMC CS\n"); goto err_kfree; } if (request_mem_region(c->phys_base, ONENAND_IO_SIZE, pdev->dev.driver->name) == NULL) { dev_err(&pdev->dev, "Cannot reserve memory region at 0x%08lx, " "size: 0x%x\n", c->phys_base, ONENAND_IO_SIZE); r = -EBUSY; goto err_free_cs; } c->onenand.base = ioremap(c->phys_base, ONENAND_IO_SIZE); if (c->onenand.base == NULL) { r = -ENOMEM; goto err_release_mem_region; } if (pdata->onenand_setup != NULL) { r = pdata->onenand_setup(c->onenand.base, c->freq); if (r < 0) { dev_err(&pdev->dev, "Onenand platform setup failed: " "%d\n", r); goto err_iounmap; } c->setup = pdata->onenand_setup; } if (c->gpio_irq) { if ((r = omap_request_gpio(c->gpio_irq)) < 0) { dev_err(&pdev->dev, "Failed to request GPIO%d for " "OneNAND\n", c->gpio_irq); goto err_iounmap; } omap_set_gpio_direction(c->gpio_irq, 1); if ((r = request_irq(OMAP_GPIO_IRQ(c->gpio_irq), omap2_onenand_interrupt, IRQF_TRIGGER_RISING, pdev->dev.driver->name, c)) < 0) goto err_release_gpio; } if (c->dma_channel >= 0) { r = omap_request_dma(0, pdev->dev.driver->name, omap2_onenand_dma_cb, (void *) c, &c->dma_channel); if (r == 0) { omap_set_dma_write_mode(c->dma_channel, OMAP_DMA_WRITE_NON_POSTED); omap_set_dma_src_data_pack(c->dma_channel, 1); omap_set_dma_src_burst_mode(c->dma_channel, OMAP_DMA_DATA_BURST_8); omap_set_dma_dest_data_pack(c->dma_channel, 1); omap_set_dma_dest_burst_mode(c->dma_channel, OMAP_DMA_DATA_BURST_8); } else { dev_info(&pdev->dev, "failed to allocate DMA for OneNAND, " "using PIO instead\n"); c->dma_channel = -1; } } dev_info(&pdev->dev, "initializing on CS%d, phys base 0x%08lx, virtual " "base %p\n", c->gpmc_cs, c->phys_base, c->onenand.base); c->pdev = pdev; c->mtd.name = pdev->dev.bus_id; c->mtd.priv = &c->onenand; c->mtd.owner = THIS_MODULE; if (c->dma_channel >= 0) { struct onenand_chip *this = &c->onenand; this->wait = omap2_onenand_wait; if (cpu_is_omap34xx()) { this->read_bufferram = omap3_onenand_read_bufferram; this->write_bufferram = omap3_onenand_write_bufferram; } else { this->read_bufferram = omap2_onenand_read_bufferram; this->write_bufferram = omap2_onenand_write_bufferram; } } if ((r = onenand_scan(&c->mtd, 1)) < 0) goto err_release_dma; switch ((c->onenand.version_id >> 4) & 0xf) { case 0: c->freq = 40; break; case 1: c->freq = 54; break; case 2: c->freq = 66; break; case 3: c->freq = 83; break; }#ifdef CONFIG_MTD_PARTITIONS if (pdata->parts != NULL) r = add_mtd_partitions(&c->mtd, pdata->parts, pdata->nr_parts); else#endif r = add_mtd_device(&c->mtd); if (r < 0) goto err_release_onenand; platform_set_drvdata(pdev, c); return 0;err_release_onenand: onenand_release(&c->mtd);err_release_dma: if (c->dma_channel != -1) omap_free_dma(c->dma_channel); if (c->gpio_irq) free_irq(OMAP_GPIO_IRQ(c->gpio_irq), c);err_release_gpio: if (c->gpio_irq) omap_free_gpio(c->gpio_irq);err_iounmap: iounmap(c->onenand.base);err_release_mem_region: release_mem_region(c->phys_base, ONENAND_IO_SIZE);err_free_cs: gpmc_cs_free(c->gpmc_cs);err_kfree: kfree(c); return r;}static int __devexit omap2_onenand_remove(struct platform_device *pdev){ struct omap2_onenand *c = dev_get_drvdata(&pdev->dev); BUG_ON(c == NULL);#ifdef CONFIG_MTD_PARTITIONS if (c->parts) del_mtd_partitions(&c->mtd); else del_mtd_device(&c->mtd);#else del_mtd_device(&c->mtd);#endif onenand_release(&c->mtd); if (c->dma_channel != -1) omap_free_dma(c->dma_channel); omap2_onenand_shutdown(pdev); platform_set_drvdata(pdev, NULL); if (c->gpio_irq) { free_irq(OMAP_GPIO_IRQ(c->gpio_irq), c); omap_free_gpio(c->gpio_irq); } iounmap(c->onenand.base); release_mem_region(c->phys_base, ONENAND_IO_SIZE); kfree(c); return 0;}static struct platform_driver omap2_onenand_driver = { .probe = omap2_onenand_probe, .remove = omap2_onenand_remove, .shutdown = omap2_onenand_shutdown, .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, },};static int __init omap2_onenand_init(void){ printk(KERN_INFO "OneNAND driver initializing\n"); return platform_driver_register(&omap2_onenand_driver);}static void __exit omap2_onenand_exit(void){ platform_driver_unregister(&omap2_onenand_driver);}module_init(omap2_onenand_init);module_exit(omap2_onenand_exit);MODULE_ALIAS(DRIVER_NAME);MODULE_LICENSE("GPL");MODULE_AUTHOR("Jarkko Lavinen <jarkko.lavinen@nokia.com>");MODULE_DESCRIPTION("Glue layer for OneNAND flash on OMAP2 / OMAP3");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -