diff options
Diffstat (limited to 'drivers/mtd/nand/gpmi-nand/gpmi-nand.c')
-rw-r--r-- | drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 207 |
1 files changed, 76 insertions, 131 deletions
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index dabbc14db563..ca6369fe91ff 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -18,9 +18,6 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include <linux/clk.h> #include <linux/slab.h> #include <linux/interrupt.h> @@ -352,6 +349,9 @@ static int legacy_set_geometry(struct gpmi_nand_data *this) int common_nfc_set_geometry(struct gpmi_nand_data *this) { + if (of_property_read_bool(this->dev->of_node, "fsl,use-minimum-ecc") + && set_geometry_by_ecc_info(this)) + return 0; return legacy_set_geometry(this); } @@ -367,25 +367,28 @@ void prepare_data_dma(struct gpmi_nand_data *this, enum dma_data_direction dr) struct scatterlist *sgl = &this->data_sgl; int ret; - this->direct_dma_map_ok = true; - /* first try to map the upper buffer directly */ - sg_init_one(sgl, this->upper_buf, this->upper_len); - ret = dma_map_sg(this->dev, sgl, 1, dr); - if (ret == 0) { - /* We have to use our own DMA buffer. */ - sg_init_one(sgl, this->data_buffer_dma, PAGE_SIZE); - - if (dr == DMA_TO_DEVICE) - memcpy(this->data_buffer_dma, this->upper_buf, - this->upper_len); - + if (virt_addr_valid(this->upper_buf) && + !object_is_on_stack(this->upper_buf)) { + sg_init_one(sgl, this->upper_buf, this->upper_len); ret = dma_map_sg(this->dev, sgl, 1, dr); if (ret == 0) - pr_err("DMA mapping failed.\n"); + goto map_fail; - this->direct_dma_map_ok = false; + this->direct_dma_map_ok = true; + return; } + +map_fail: + /* We have to use our own DMA buffer. */ + sg_init_one(sgl, this->data_buffer_dma, this->upper_len); + + if (dr == DMA_TO_DEVICE) + memcpy(this->data_buffer_dma, this->upper_buf, this->upper_len); + + dma_map_sg(this->dev, sgl, 1, dr); + + this->direct_dma_map_ok = false; } /* This will be called after the DMA operation is finished. */ @@ -416,7 +419,7 @@ static void dma_irq_callback(void *param) break; default: - pr_err("in wrong DMA operation.\n"); + dev_err(this->dev, "in wrong DMA operation.\n"); } complete(dma_c); @@ -438,7 +441,8 @@ int start_dma_without_bch_irq(struct gpmi_nand_data *this, /* Wait for the interrupt from the DMA block. */ err = wait_for_completion_timeout(dma_c, msecs_to_jiffies(1000)); if (!err) { - pr_err("DMA timeout, last DMA :%d\n", this->last_dma_type); + dev_err(this->dev, "DMA timeout, last DMA :%d\n", + this->last_dma_type); gpmi_dump_info(this); return -ETIMEDOUT; } @@ -467,7 +471,8 @@ int start_dma_with_bch_irq(struct gpmi_nand_data *this, /* Wait for the interrupt from the BCH block. */ err = wait_for_completion_timeout(bch_c, msecs_to_jiffies(1000)); if (!err) { - pr_err("BCH timeout, last DMA :%d\n", this->last_dma_type); + dev_err(this->dev, "BCH timeout, last DMA :%d\n", + this->last_dma_type); gpmi_dump_info(this); return -ETIMEDOUT; } @@ -483,70 +488,38 @@ static int acquire_register_block(struct gpmi_nand_data *this, void __iomem *p; r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res_name); - if (!r) { - pr_err("Can't get resource for %s\n", res_name); - return -ENODEV; - } - - p = ioremap(r->start, resource_size(r)); - if (!p) { - pr_err("Can't remap %s\n", res_name); - return -ENOMEM; - } + p = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(p)) + return PTR_ERR(p); if (!strcmp(res_name, GPMI_NAND_GPMI_REGS_ADDR_RES_NAME)) res->gpmi_regs = p; else if (!strcmp(res_name, GPMI_NAND_BCH_REGS_ADDR_RES_NAME)) res->bch_regs = p; else - pr_err("unknown resource name : %s\n", res_name); + dev_err(this->dev, "unknown resource name : %s\n", res_name); return 0; } -static void release_register_block(struct gpmi_nand_data *this) -{ - struct resources *res = &this->resources; - if (res->gpmi_regs) - iounmap(res->gpmi_regs); - if (res->bch_regs) - iounmap(res->bch_regs); - res->gpmi_regs = NULL; - res->bch_regs = NULL; -} - static int acquire_bch_irq(struct gpmi_nand_data *this, irq_handler_t irq_h) { struct platform_device *pdev = this->pdev; - struct resources *res = &this->resources; const char *res_name = GPMI_NAND_BCH_INTERRUPT_RES_NAME; struct resource *r; int err; r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res_name); if (!r) { - pr_err("Can't get resource for %s\n", res_name); + dev_err(this->dev, "Can't get resource for %s\n", res_name); return -ENODEV; } - err = request_irq(r->start, irq_h, 0, res_name, this); - if (err) { - pr_err("Can't own %s\n", res_name); - return err; - } - - res->bch_low_interrupt = r->start; - res->bch_high_interrupt = r->end; - return 0; -} - -static void release_bch_irq(struct gpmi_nand_data *this) -{ - struct resources *res = &this->resources; - int i = res->bch_low_interrupt; + err = devm_request_irq(this->dev, r->start, irq_h, 0, res_name, this); + if (err) + dev_err(this->dev, "error requesting BCH IRQ\n"); - for (; i <= res->bch_high_interrupt; i++) - free_irq(i, this); + return err; } static void release_dma_channels(struct gpmi_nand_data *this) @@ -567,7 +540,7 @@ static int acquire_dma_channels(struct gpmi_nand_data *this) /* request dma channel */ dma_chan = dma_request_slave_channel(&pdev->dev, "rx-tx"); if (!dma_chan) { - pr_err("Failed to request DMA channel.\n"); + dev_err(this->dev, "Failed to request DMA channel.\n"); goto acquire_err; } @@ -579,21 +552,6 @@ acquire_err: return -EINVAL; } -static void gpmi_put_clks(struct gpmi_nand_data *this) -{ - struct resources *r = &this->resources; - struct clk *clk; - int i; - - for (i = 0; i < GPMI_CLK_MAX; i++) { - clk = r->clock[i]; - if (clk) { - clk_put(clk); - r->clock[i] = NULL; - } - } -} - static char *extra_clks_for_mx6q[GPMI_CLK_MAX] = { "gpmi_apb", "gpmi_bch", "gpmi_bch_apb", "per1_bch", }; @@ -606,7 +564,7 @@ static int gpmi_get_clks(struct gpmi_nand_data *this) int err, i; /* The main clock is stored in the first. */ - r->clock[0] = clk_get(this->dev, "gpmi_io"); + r->clock[0] = devm_clk_get(this->dev, "gpmi_io"); if (IS_ERR(r->clock[0])) { err = PTR_ERR(r->clock[0]); goto err_clock; @@ -622,7 +580,7 @@ static int gpmi_get_clks(struct gpmi_nand_data *this) if (extra_clks[i - 1] == NULL) break; - clk = clk_get(this->dev, extra_clks[i - 1]); + clk = devm_clk_get(this->dev, extra_clks[i - 1]); if (IS_ERR(clk)) { err = PTR_ERR(clk); goto err_clock; @@ -644,7 +602,6 @@ static int gpmi_get_clks(struct gpmi_nand_data *this) err_clock: dev_dbg(this->dev, "failed in finding the clocks.\n"); - gpmi_put_clks(this); return err; } @@ -666,7 +623,7 @@ static int acquire_resources(struct gpmi_nand_data *this) ret = acquire_dma_channels(this); if (ret) - goto exit_dma_channels; + goto exit_regs; ret = gpmi_get_clks(this); if (ret) @@ -675,18 +632,12 @@ static int acquire_resources(struct gpmi_nand_data *this) exit_clock: release_dma_channels(this); -exit_dma_channels: - release_bch_irq(this); exit_regs: - release_register_block(this); return ret; } static void release_resources(struct gpmi_nand_data *this) { - gpmi_put_clks(this); - release_register_block(this); - release_bch_irq(this); release_dma_channels(this); } @@ -732,8 +683,7 @@ static int read_page_prepare(struct gpmi_nand_data *this, length, DMA_FROM_DEVICE); if (dma_mapping_error(dev, dest_phys)) { if (alt_size < length) { - pr_err("%s, Alternate buffer is too small\n", - __func__); + dev_err(dev, "Alternate buffer is too small\n"); return -ENOMEM; } goto map_failed; @@ -783,8 +733,7 @@ static int send_page_prepare(struct gpmi_nand_data *this, DMA_TO_DEVICE); if (dma_mapping_error(dev, source_phys)) { if (alt_size < length) { - pr_err("%s, Alternate buffer is too small\n", - __func__); + dev_err(dev, "Alternate buffer is too small\n"); return -ENOMEM; } goto map_failed; @@ -837,14 +786,23 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this) { struct bch_geometry *geo = &this->bch_geometry; struct device *dev = this->dev; + struct mtd_info *mtd = &this->mtd; /* [1] Allocate a command buffer. PAGE_SIZE is enough. */ this->cmd_buffer = kzalloc(PAGE_SIZE, GFP_DMA | GFP_KERNEL); if (this->cmd_buffer == NULL) goto error_alloc; - /* [2] Allocate a read/write data buffer. PAGE_SIZE is enough. */ - this->data_buffer_dma = kzalloc(PAGE_SIZE, GFP_DMA | GFP_KERNEL); + /* + * [2] Allocate a read/write data buffer. + * The gpmi_alloc_dma_buffer can be called twice. + * We allocate a PAGE_SIZE length buffer if gpmi_alloc_dma_buffer + * is called before the nand_scan_ident; and we allocate a buffer + * of the real NAND page size when the gpmi_alloc_dma_buffer is + * called after the nand_scan_ident. + */ + this->data_buffer_dma = kzalloc(mtd->writesize ?: PAGE_SIZE, + GFP_DMA | GFP_KERNEL); if (this->data_buffer_dma == NULL) goto error_alloc; @@ -872,7 +830,6 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this) error_alloc: gpmi_free_dma_buffer(this); - pr_err("Error allocating DMA buffers!\n"); return -ENOMEM; } @@ -904,7 +861,8 @@ static void gpmi_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl) ret = gpmi_send_command(this); if (ret) - pr_err("Chip: %u, Error %d\n", this->current_chip, ret); + dev_err(this->dev, "Chip: %u, Error %d\n", + this->current_chip, ret); this->command_length = 0; } @@ -935,7 +893,7 @@ static void gpmi_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) struct nand_chip *chip = mtd->priv; struct gpmi_nand_data *this = chip->priv; - pr_debug("len is %d\n", len); + dev_dbg(this->dev, "len is %d\n", len); this->upper_buf = buf; this->upper_len = len; @@ -947,7 +905,7 @@ static void gpmi_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) struct nand_chip *chip = mtd->priv; struct gpmi_nand_data *this = chip->priv; - pr_debug("len is %d\n", len); + dev_dbg(this->dev, "len is %d\n", len); this->upper_buf = (uint8_t *)buf; this->upper_len = len; @@ -1026,13 +984,13 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip, unsigned int max_bitflips = 0; int ret; - pr_debug("page number is : %d\n", page); + dev_dbg(this->dev, "page number is : %d\n", page); ret = read_page_prepare(this, buf, mtd->writesize, this->payload_virt, this->payload_phys, nfc_geo->payload_size, &payload_virt, &payload_phys); if (ret) { - pr_err("Inadequate DMA buffer\n"); + dev_err(this->dev, "Inadequate DMA buffer\n"); ret = -ENOMEM; return ret; } @@ -1046,7 +1004,7 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip, nfc_geo->payload_size, payload_virt, payload_phys); if (ret) { - pr_err("Error in ECC-based read: %d\n", ret); + dev_err(this->dev, "Error in ECC-based read: %d\n", ret); return ret; } @@ -1102,7 +1060,7 @@ static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip, dma_addr_t auxiliary_phys; int ret; - pr_debug("ecc write page.\n"); + dev_dbg(this->dev, "ecc write page.\n"); if (this->swap_block_mark) { /* * If control arrives here, we're doing block mark swapping. @@ -1132,7 +1090,7 @@ static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip, nfc_geo->payload_size, &payload_virt, &payload_phys); if (ret) { - pr_err("Inadequate payload DMA buffer\n"); + dev_err(this->dev, "Inadequate payload DMA buffer\n"); return 0; } @@ -1142,7 +1100,7 @@ static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip, nfc_geo->auxiliary_size, &auxiliary_virt, &auxiliary_phys); if (ret) { - pr_err("Inadequate auxiliary DMA buffer\n"); + dev_err(this->dev, "Inadequate auxiliary DMA buffer\n"); goto exit_auxiliary; } } @@ -1150,7 +1108,7 @@ static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip, /* Ask the NFC. */ ret = gpmi_send_page(this, payload_phys, auxiliary_phys); if (ret) - pr_err("Error in ECC-based write: %d\n", ret); + dev_err(this->dev, "Error in ECC-based write: %d\n", ret); if (!this->swap_block_mark) { send_page_end(this, chip->oob_poi, mtd->oobsize, @@ -1240,7 +1198,7 @@ static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, { struct gpmi_nand_data *this = chip->priv; - pr_debug("page number is %d\n", page); + dev_dbg(this->dev, "page number is %d\n", page); /* clear the OOB buffer */ memset(chip->oob_poi, ~0, mtd->oobsize); @@ -1453,7 +1411,6 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this) /* Write the NCB fingerprint into the page buffer. */ memset(buffer, ~0, mtd->writesize); - memset(chip->oob_poi, ~0, mtd->oobsize); memcpy(buffer + 12, fingerprint, strlen(fingerprint)); /* Loop through the first search area, writing NCB fingerprints. */ @@ -1568,7 +1525,7 @@ static int gpmi_set_geometry(struct gpmi_nand_data *this) /* Set up the NFC geometry which is used by BCH. */ ret = bch_set_geometry(this); if (ret) { - pr_err("Error setting BCH geometry : %d\n", ret); + dev_err(this->dev, "Error setting BCH geometry : %d\n", ret); return ret; } @@ -1576,20 +1533,7 @@ static int gpmi_set_geometry(struct gpmi_nand_data *this) return gpmi_alloc_dma_buffer(this); } -static int gpmi_pre_bbt_scan(struct gpmi_nand_data *this) -{ - /* Set up swap_block_mark, must be set before the gpmi_set_geometry() */ - if (GPMI_IS_MX23(this)) - this->swap_block_mark = false; - else - this->swap_block_mark = true; - - /* Set up the medium geometry */ - return gpmi_set_geometry(this); - -} - -static void gpmi_nfc_exit(struct gpmi_nand_data *this) +static void gpmi_nand_exit(struct gpmi_nand_data *this) { nand_release(&this->mtd); gpmi_free_dma_buffer(this); @@ -1603,8 +1547,11 @@ static int gpmi_init_last(struct gpmi_nand_data *this) struct bch_geometry *bch_geo = &this->bch_geometry; int ret; - /* Prepare for the BBT scan. */ - ret = gpmi_pre_bbt_scan(this); + /* Set up swap_block_mark, must be set before the gpmi_set_geometry() */ + this->swap_block_mark = !GPMI_IS_MX23(this); + + /* Set up the medium geometry */ + ret = gpmi_set_geometry(this); if (ret) return ret; @@ -1629,7 +1576,7 @@ static int gpmi_init_last(struct gpmi_nand_data *this) return 0; } -static int gpmi_nfc_init(struct gpmi_nand_data *this) +static int gpmi_nand_init(struct gpmi_nand_data *this) { struct mtd_info *mtd = &this->mtd; struct nand_chip *chip = &this->nand; @@ -1693,7 +1640,7 @@ static int gpmi_nfc_init(struct gpmi_nand_data *this) return 0; err_out: - gpmi_nfc_exit(this); + gpmi_nand_exit(this); return ret; } @@ -1728,15 +1675,13 @@ static int gpmi_nand_probe(struct platform_device *pdev) if (of_id) { pdev->id_entry = of_id->data; } else { - pr_err("Failed to find the right device id.\n"); + dev_err(&pdev->dev, "Failed to find the right device id.\n"); return -ENODEV; } this = devm_kzalloc(&pdev->dev, sizeof(*this), GFP_KERNEL); - if (!this) { - pr_err("Failed to allocate per-device memory\n"); + if (!this) return -ENOMEM; - } platform_set_drvdata(pdev, this); this->pdev = pdev; @@ -1750,7 +1695,7 @@ static int gpmi_nand_probe(struct platform_device *pdev) if (ret) goto exit_nfc_init; - ret = gpmi_nfc_init(this); + ret = gpmi_nand_init(this); if (ret) goto exit_nfc_init; @@ -1770,7 +1715,7 @@ static int gpmi_nand_remove(struct platform_device *pdev) { struct gpmi_nand_data *this = platform_get_drvdata(pdev); - gpmi_nfc_exit(this); + gpmi_nand_exit(this); release_resources(this); return 0; } |