summaryrefslogtreecommitdiff
path: root/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/nand/gpmi-nand/gpmi-nand.c')
-rw-r--r--drivers/mtd/nand/gpmi-nand/gpmi-nand.c66
1 files changed, 29 insertions, 37 deletions
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
index dabbc14..a9830ff 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
@@ -45,10 +45,7 @@ static struct nand_bbt_descr gpmi_bbt_descr = {
.pattern = scan_ff_pattern
};
-/*
- * We may change the layout if we can get the ECC info from the datasheet,
- * else we will use all the (page + OOB).
- */
+/* We will use all the (page + OOB). */
static struct nand_ecclayout gpmi_hw_ecclayout = {
.eccbytes = 0,
.eccpos = { 0, },
@@ -357,8 +354,9 @@ int common_nfc_set_geometry(struct gpmi_nand_data *this)
struct dma_chan *get_dma_chan(struct gpmi_nand_data *this)
{
- /* We use the DMA channel 0 to access all the nand chips. */
- return this->dma_chans[0];
+ int chipnr = this->current_chip;
+
+ return this->dma_chans[chipnr];
}
/* Can we use the upper's buffer directly for DMA? */
@@ -394,6 +392,8 @@ static void dma_irq_callback(void *param)
struct gpmi_nand_data *this = param;
struct completion *dma_c = &this->dma_done;
+ complete(dma_c);
+
switch (this->dma_type) {
case DMA_FOR_COMMAND:
dma_unmap_sg(this->dev, &this->cmd_sgl, 1, DMA_TO_DEVICE);
@@ -418,8 +418,6 @@ static void dma_irq_callback(void *param)
default:
pr_err("in wrong DMA operation.\n");
}
-
- complete(dma_c);
}
int start_dma_without_bch_irq(struct gpmi_nand_data *this,
@@ -1265,22 +1263,14 @@ static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
static int
gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page)
{
- struct nand_oobfree *of = mtd->ecclayout->oobfree;
- int status = 0;
-
- /* Do we have available oob area? */
- if (!of->length)
- return -EPERM;
-
- if (!nand_is_slc(chip))
- return -EPERM;
-
- chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize + of->offset, page);
- chip->write_buf(mtd, chip->oob_poi + of->offset, of->length);
- chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
-
- status = chip->waitfunc(mtd, chip);
- return status & NAND_STATUS_FAIL ? -EIO : 0;
+ /*
+ * The BCH will use all the (page + oob).
+ * Our gpmi_hw_ecclayout can only prohibit the JFFS2 to write the oob.
+ * But it can not stop some ioctls such MEMWRITEOOB which uses
+ * MTD_OPS_PLACE_OOB. So We have to implement this function to prohibit
+ * these ioctls too.
+ */
+ return -EPERM;
}
static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs)
@@ -1578,6 +1568,8 @@ static int gpmi_set_geometry(struct gpmi_nand_data *this)
static int gpmi_pre_bbt_scan(struct gpmi_nand_data *this)
{
+ int ret;
+
/* Set up swap_block_mark, must be set before the gpmi_set_geometry() */
if (GPMI_IS_MX23(this))
this->swap_block_mark = false;
@@ -1585,8 +1577,12 @@ static int gpmi_pre_bbt_scan(struct gpmi_nand_data *this)
this->swap_block_mark = true;
/* Set up the medium geometry */
- return gpmi_set_geometry(this);
+ ret = gpmi_set_geometry(this);
+ if (ret)
+ return ret;
+ /* NAND boot init, depends on the gpmi_set_geometry(). */
+ return nand_boot_init(this);
}
static void gpmi_nfc_exit(struct gpmi_nand_data *this)
@@ -1668,7 +1664,7 @@ static int gpmi_nfc_init(struct gpmi_nand_data *this)
if (ret)
goto err_out;
- ret = nand_scan_ident(mtd, GPMI_IS_MX6Q(this) ? 2 : 1, NULL);
+ ret = nand_scan_ident(mtd, 1, NULL);
if (ret)
goto err_out;
@@ -1676,16 +1672,10 @@ static int gpmi_nfc_init(struct gpmi_nand_data *this)
if (ret)
goto err_out;
- chip->options |= NAND_SKIP_BBTSCAN;
ret = nand_scan_tail(mtd);
if (ret)
goto err_out;
- ret = nand_boot_init(this);
- if (ret)
- goto err_out;
- chip->scan_bbt(mtd);
-
ppdata.of_node = this->pdev->dev.of_node;
ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
if (ret)
@@ -1701,19 +1691,19 @@ static const struct platform_device_id gpmi_ids[] = {
{ .name = "imx23-gpmi-nand", .driver_data = IS_MX23, },
{ .name = "imx28-gpmi-nand", .driver_data = IS_MX28, },
{ .name = "imx6q-gpmi-nand", .driver_data = IS_MX6Q, },
- {}
+ {},
};
static const struct of_device_id gpmi_nand_id_table[] = {
{
.compatible = "fsl,imx23-gpmi-nand",
- .data = (void *)&gpmi_ids[IS_MX23],
+ .data = (void *)&gpmi_ids[IS_MX23]
}, {
.compatible = "fsl,imx28-gpmi-nand",
- .data = (void *)&gpmi_ids[IS_MX28],
+ .data = (void *)&gpmi_ids[IS_MX28]
}, {
.compatible = "fsl,imx6q-gpmi-nand",
- .data = (void *)&gpmi_ids[IS_MX6Q],
+ .data = (void *)&gpmi_ids[IS_MX6Q]
}, {}
};
MODULE_DEVICE_TABLE(of, gpmi_nand_id_table);
@@ -1732,7 +1722,7 @@ static int gpmi_nand_probe(struct platform_device *pdev)
return -ENODEV;
}
- this = devm_kzalloc(&pdev->dev, sizeof(*this), GFP_KERNEL);
+ this = kzalloc(sizeof(*this), GFP_KERNEL);
if (!this) {
pr_err("Failed to allocate per-device memory\n");
return -ENOMEM;
@@ -1762,6 +1752,7 @@ exit_nfc_init:
release_resources(this);
exit_acquire_resources:
dev_err(this->dev, "driver registration failed: %d\n", ret);
+ kfree(this);
return ret;
}
@@ -1772,6 +1763,7 @@ static int gpmi_nand_remove(struct platform_device *pdev)
gpmi_nfc_exit(this);
release_resources(this);
+ kfree(this);
return 0;
}