]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/mtd/nand/gpmi-nand/gpmi-nand.c
Merge tag 'for-linus-3.5-20120601' of git://git.infradead.org/linux-mtd
[karo-tx-linux.git] / drivers / mtd / nand / gpmi-nand / gpmi-nand.c
index b68e04310bd8e5b14327ff142788180ba8680754..a05b7b444d4f1f8a92d6f0e10a2ee1db19d3c722 100644 (file)
@@ -25,6 +25,8 @@
 #include <linux/mtd/gpmi-nand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/pinctrl/consumer.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include "gpmi-nand.h"
 
 /* add our owner bbt descriptor */
@@ -387,7 +389,7 @@ static void release_bch_irq(struct gpmi_nand_data *this)
 static bool gpmi_dma_filter(struct dma_chan *chan, void *param)
 {
        struct gpmi_nand_data *this = param;
-       struct resource *r = this->private;
+       int dma_channel = (int)this->private;
 
        if (!mxs_dma_is_apbh(chan))
                return false;
@@ -399,7 +401,7 @@ static bool gpmi_dma_filter(struct dma_chan *chan, void *param)
         *      for mx28 :      MX28_DMA_GPMI0 ~ MX28_DMA_GPMI7
         *              (These eight channels share the same IRQ!)
         */
-       if (r->start <= chan->chan_id && chan->chan_id <= r->end) {
+       if (dma_channel == chan->chan_id) {
                chan->private = &this->dma_data;
                return true;
        }
@@ -419,57 +421,45 @@ static void release_dma_channels(struct gpmi_nand_data *this)
 static int __devinit acquire_dma_channels(struct gpmi_nand_data *this)
 {
        struct platform_device *pdev = this->pdev;
-       struct gpmi_nand_platform_data *pdata = this->pdata;
-       struct resources *res = &this->resources;
-       struct resource *r, *r_dma;
-       unsigned int i;
+       struct resource *r_dma;
+       struct device_node *dn;
+       int dma_channel;
+       unsigned int ret;
+       struct dma_chan *dma_chan;
+       dma_cap_mask_t mask;
+
+       /* dma channel, we only use the first one. */
+       dn = pdev->dev.of_node;
+       ret = of_property_read_u32(dn, "fsl,gpmi-dma-channel", &dma_channel);
+       if (ret) {
+               pr_err("unable to get DMA channel from dt.\n");
+               goto acquire_err;
+       }
+       this->private = (void *)dma_channel;
 
-       r = platform_get_resource_byname(pdev, IORESOURCE_DMA,
-                                       GPMI_NAND_DMA_CHANNELS_RES_NAME);
+       /* gpmi dma interrupt */
        r_dma = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
                                        GPMI_NAND_DMA_INTERRUPT_RES_NAME);
-       if (!r || !r_dma) {
+       if (!r_dma) {
                pr_err("Can't get resource for DMA\n");
-               return -ENXIO;
+               goto acquire_err;
        }
+       this->dma_data.chan_irq = r_dma->start;
 
-       /* used in gpmi_dma_filter() */
-       this->private = r;
-
-       for (i = r->start; i <= r->end; i++) {
-               struct dma_chan *dma_chan;
-               dma_cap_mask_t mask;
+       /* request dma channel */
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_SLAVE, mask);
 
-               if (i - r->start >= pdata->max_chip_count)
-                       break;
-
-               dma_cap_zero(mask);
-               dma_cap_set(DMA_SLAVE, mask);
-
-               /* get the DMA interrupt */
-               if (r_dma->start == r_dma->end) {
-                       /* only register the first. */
-                       if (i == r->start)
-                               this->dma_data.chan_irq = r_dma->start;
-                       else
-                               this->dma_data.chan_irq = NO_IRQ;
-               } else
-                       this->dma_data.chan_irq = r_dma->start + (i - r->start);
-
-               dma_chan = dma_request_channel(mask, gpmi_dma_filter, this);
-               if (!dma_chan)
-                       goto acquire_err;
-
-               /* fill the first empty item */
-               this->dma_chans[i - r->start] = dma_chan;
+       dma_chan = dma_request_channel(mask, gpmi_dma_filter, this);
+       if (!dma_chan) {
+               pr_err("dma_request_channel failed.\n");
+               goto acquire_err;
        }
 
-       res->dma_low_channel = r->start;
-       res->dma_high_channel = i;
+       this->dma_chans[0] = dma_chan;
        return 0;
 
 acquire_err:
-       pr_err("Can't acquire DMA channel %u\n", i);
        release_dma_channels(this);
        return -EINVAL;
 }
@@ -851,7 +841,7 @@ static void block_mark_swapping(struct gpmi_nand_data *this,
 }
 
 static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
-                               uint8_t *buf, int page)
+                               uint8_t *buf, int oob_required, int page)
 {
        struct gpmi_nand_data *this = chip->priv;
        struct bch_geometry *nfc_geo = &this->bch_geometry;
@@ -917,28 +907,31 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
                mtd->ecc_stats.corrected += corrected;
        }
 
-       /*
-        * It's time to deliver the OOB bytes. See gpmi_ecc_read_oob() for
-        * details about our policy for delivering the OOB.
-        *
-        * We fill the caller's buffer with set bits, and then copy the block
-        * mark to th caller's buffer. Note that, if block mark swapping was
-        * necessary, it has already been done, so we can rely on the first
-        * byte of the auxiliary buffer to contain the block mark.
-        */
-       memset(chip->oob_poi, ~0, mtd->oobsize);
-       chip->oob_poi[0] = ((uint8_t *) auxiliary_virt)[0];
+       if (oob_required) {
+               /*
+                * It's time to deliver the OOB bytes. See gpmi_ecc_read_oob()
+                * for details about our policy for delivering the OOB.
+                *
+                * We fill the caller's buffer with set bits, and then copy the
+                * block mark to th caller's buffer. Note that, if block mark
+                * swapping was necessary, it has already been done, so we can
+                * rely on the first byte of the auxiliary buffer to contain
+                * the block mark.
+                */
+               memset(chip->oob_poi, ~0, mtd->oobsize);
+               chip->oob_poi[0] = ((uint8_t *) auxiliary_virt)[0];
 
-       read_page_swap_end(this, buf, mtd->writesize,
-                       this->payload_virt, this->payload_phys,
-                       nfc_geo->payload_size,
-                       payload_virt, payload_phys);
+               read_page_swap_end(this, buf, mtd->writesize,
+                               this->payload_virt, this->payload_phys,
+                               nfc_geo->payload_size,
+                               payload_virt, payload_phys);
+       }
 exit_nfc:
        return ret;
 }
 
-static void gpmi_ecc_write_page(struct mtd_info *mtd,
-                               struct nand_chip *chip, const uint8_t *buf)
+static void gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+                               const uint8_t *buf, int oob_required)
 {
        struct gpmi_nand_data *this = chip->priv;
        struct bch_geometry *nfc_geo = &this->bch_geometry;
@@ -1077,7 +1070,7 @@ exit_auxiliary:
  * this driver.
  */
 static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
-                               int page, int sndcmd)
+                               int page)
 {
        struct gpmi_nand_data *this = chip->priv;
 
@@ -1100,11 +1093,7 @@ static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
                chip->oob_poi[0] = chip->read_byte(mtd);
        }
 
-       /*
-        * Return true, indicating that the next call to this function must send
-        * a command.
-        */
-       return true;
+       return 0;
 }
 
 static int
@@ -1318,7 +1307,7 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this)
                /* Write the first page of the current stride. */
                dev_dbg(dev, "Writing an NCB fingerprint in page 0x%x\n", page);
                chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
-               chip->ecc.write_page_raw(mtd, chip, buffer);
+               chip->ecc.write_page_raw(mtd, chip, buffer, 0);
                chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
 
                /* Wait for the write to finish. */
@@ -1444,6 +1433,10 @@ static int gpmi_pre_bbt_scan(struct gpmi_nand_data  *this)
        if (ret)
                return ret;
 
+       /* Adjust the ECC strength according to the chip. */
+       this->nand.ecc.strength = this->bch_geometry.ecc_strength;
+       this->mtd.ecc_strength = this->bch_geometry.ecc_strength;
+
        /* NAND boot init, depends on the gpmi_set_geometry(). */
        return nand_boot_init(this);
 }
@@ -1471,9 +1464,9 @@ void gpmi_nfc_exit(struct gpmi_nand_data *this)
 
 static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this)
 {
-       struct gpmi_nand_platform_data *pdata = this->pdata;
        struct mtd_info  *mtd = &this->mtd;
        struct nand_chip *chip = &this->nand;
+       struct mtd_part_parser_data ppdata = {};
        int ret;
 
        /* init current chip */
@@ -1502,6 +1495,7 @@ static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this)
        chip->options           |= NAND_NO_SUBPAGE_WRITE;
        chip->ecc.mode          = NAND_ECC_HW;
        chip->ecc.size          = 1;
+       chip->ecc.strength      = 8;
        chip->ecc.layout        = &gpmi_hw_ecclayout;
 
        /* Allocate a temporary DMA buffer for reading ID in the nand_scan() */
@@ -1511,14 +1505,14 @@ static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this)
        if (ret)
                goto err_out;
 
-       ret = nand_scan(mtd, pdata->max_chip_count);
+       ret = nand_scan(mtd, 1);
        if (ret) {
                pr_err("Chip scan failed\n");
                goto err_out;
        }
 
-       ret = mtd_device_parse_register(mtd, NULL, NULL,
-                       pdata->partitions, pdata->partition_count);
+       ppdata.of_node = this->pdev->dev.of_node;
+       ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
        if (ret)
                goto err_out;
        return 0;
@@ -1528,12 +1522,41 @@ err_out:
        return ret;
 }
 
+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]
+       }, {
+               .compatible = "fsl,imx28-gpmi-nand",
+               .data = (void *)&gpmi_ids[IS_MX28]
+       }, {
+               .compatible = "fsl,imx6q-gpmi-nand",
+               .data = (void *)&gpmi_ids[IS_MX6Q]
+       }, {}
+};
+MODULE_DEVICE_TABLE(of, gpmi_nand_id_table);
+
 static int __devinit gpmi_nand_probe(struct platform_device *pdev)
 {
-       struct gpmi_nand_platform_data *pdata = pdev->dev.platform_data;
        struct gpmi_nand_data *this;
+       const struct of_device_id *of_id;
        int ret;
 
+       of_id = of_match_device(gpmi_nand_id_table, &pdev->dev);
+       if (of_id) {
+               pdev->id_entry = of_id->data;
+       } else {
+               pr_err("Failed to find the right device id.\n");
+               return -ENOMEM;
+       }
+
        this = kzalloc(sizeof(*this), GFP_KERNEL);
        if (!this) {
                pr_err("Failed to allocate per-device memory\n");
@@ -1543,13 +1566,6 @@ static int __devinit gpmi_nand_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, this);
        this->pdev  = pdev;
        this->dev   = &pdev->dev;
-       this->pdata = pdata;
-
-       if (pdata->platform_init) {
-               ret = pdata->platform_init();
-               if (ret)
-                       goto platform_init_error;
-       }
 
        ret = acquire_resources(this);
        if (ret)
@@ -1567,7 +1583,6 @@ static int __devinit gpmi_nand_probe(struct platform_device *pdev)
 
 exit_nfc_init:
        release_resources(this);
-platform_init_error:
 exit_acquire_resources:
        platform_set_drvdata(pdev, NULL);
        kfree(this);
@@ -1585,19 +1600,10 @@ static int __exit gpmi_nand_remove(struct platform_device *pdev)
        return 0;
 }
 
-static const struct platform_device_id gpmi_ids[] = {
-       {
-               .name = "imx23-gpmi-nand",
-               .driver_data = IS_MX23,
-       }, {
-               .name = "imx28-gpmi-nand",
-               .driver_data = IS_MX28,
-       }, {},
-};
-
 static struct platform_driver gpmi_nand_driver = {
        .driver = {
                .name = "gpmi-nand",
+               .of_match_table = gpmi_nand_id_table,
        },
        .probe   = gpmi_nand_probe,
        .remove  = __exit_p(gpmi_nand_remove),