This patch adds support for multiple NAND chips connected to the
i.MX6. Linux already supports this configuration. So lets port
the missing features to the U-Boot driver to support more than
one NAND chip here as well.

The necessary changes in detail are:

- Only use DMA channel 0 for all NAND chips:
  Linux: a7c12d01 (mtd: gpmi: use DMA channel 0 for all the
                   nand chips)
         d159d8b7 (mtd: gpmi: decouple the chip select from
                   the DMA channel)
- On i.MX6 only use ready/busy pin for CS0:
  Linux: 7caa4fd2 (mtd: gpmi: imx6: fix the wrong method for
                   checking ready/busy)

To enable this feature the board needs to configure
CONFIG_SYS_NAND_MAX_CHIPS to 2 (or more).

With these changes I'm able to detect and acces 2 NAND chips:

=> nand device

Device 0: 2x nand0, sector size 128 KiB
  Page size      2048 b
  OOB size         64 b
  Erase size   131072 b

Please note that this is also needed to support a NAND chip with
multiple chips embedded in one die, e.g. Micron MT29F32G08QAA.

Tested on a i.MX6DL based board with 2 Micron MT29F4G08AB
chips.

Signed-off-by: Stefan Roese <s...@denx.de>
Cc: Marek Vasut <ma...@denx.de>
Cc: Stefano Babic <sba...@denx.de>
Cc: Fabio Estevam <fabio.este...@freescale.com>
Cc: Scott Wood <scottw...@freescale.com>
---
 drivers/mtd/nand/mxs_nand.c | 30 ++++++++++++++----------------
 1 file changed, 14 insertions(+), 16 deletions(-)

diff --git a/drivers/mtd/nand/mxs_nand.c b/drivers/mtd/nand/mxs_nand.c
index 7a064ab..5013246 100644
--- a/drivers/mtd/nand/mxs_nand.c
+++ b/drivers/mtd/nand/mxs_nand.c
@@ -263,7 +263,7 @@ static void mxs_nand_cmd_ctrl(struct mtd_info *mtd, int 
data, unsigned int ctrl)
        struct nand_chip *nand = mtd->priv;
        struct mxs_nand_info *nand_info = nand->priv;
        struct mxs_dma_desc *d;
-       uint32_t channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0 + nand_info->cur_chip;
+       uint32_t channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0;
        int ret;
 
        /*
@@ -340,13 +340,17 @@ static void mxs_nand_cmd_ctrl(struct mtd_info *mtd, int 
data, unsigned int ctrl)
 static int mxs_nand_device_ready(struct mtd_info *mtd)
 {
        struct nand_chip *chip = mtd->priv;
-       struct mxs_nand_info *nand_info = chip->priv;
+       __maybe_unused struct mxs_nand_info *nand_info = chip->priv;
        struct mxs_gpmi_regs *gpmi_regs =
                (struct mxs_gpmi_regs *)MXS_GPMI_BASE;
        uint32_t tmp;
 
        tmp = readl(&gpmi_regs->hw_gpmi_stat);
+#if defined(CONFIG_MX6)
+       tmp >>= (GPMI_STAT_READY_BUSY_OFFSET + 0);
+#else
        tmp >>= (GPMI_STAT_READY_BUSY_OFFSET + nand_info->cur_chip);
+#endif
 
        return tmp & 1;
 }
@@ -409,7 +413,7 @@ static void mxs_nand_read_buf(struct mtd_info *mtd, uint8_t 
*buf, int length)
        struct nand_chip *nand = mtd->priv;
        struct mxs_nand_info *nand_info = nand->priv;
        struct mxs_dma_desc *d;
-       uint32_t channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0 + nand_info->cur_chip;
+       uint32_t channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0;
        int ret;
 
        if (length > NAND_MAX_PAGESIZE) {
@@ -490,7 +494,7 @@ static void mxs_nand_write_buf(struct mtd_info *mtd, const 
uint8_t *buf,
        struct nand_chip *nand = mtd->priv;
        struct mxs_nand_info *nand_info = nand->priv;
        struct mxs_dma_desc *d;
-       uint32_t channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0 + nand_info->cur_chip;
+       uint32_t channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0;
        int ret;
 
        if (length > NAND_MAX_PAGESIZE) {
@@ -554,7 +558,7 @@ static int mxs_nand_ecc_read_page(struct mtd_info *mtd, 
struct nand_chip *nand,
 {
        struct mxs_nand_info *nand_info = nand->priv;
        struct mxs_dma_desc *d;
-       uint32_t channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0 + nand_info->cur_chip;
+       uint32_t channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0;
        uint32_t corrected = 0, failed = 0;
        uint8_t *status;
        int i, ret;
@@ -701,7 +705,7 @@ static int mxs_nand_ecc_write_page(struct mtd_info *mtd,
 {
        struct mxs_nand_info *nand_info = nand->priv;
        struct mxs_dma_desc *d;
-       uint32_t channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0 + nand_info->cur_chip;
+       uint32_t channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0;
        int ret;
 
        memcpy(nand_info->data_buf, buf, mtd->writesize);
@@ -1068,7 +1072,7 @@ int mxs_nand_init(struct mxs_nand_info *info)
                (struct mxs_gpmi_regs *)MXS_GPMI_BASE;
        struct mxs_bch_regs *bch_regs =
                (struct mxs_bch_regs *)MXS_BCH_BASE;
-       int i = 0, j;
+       int i = 0;
 
        info->desc = malloc(sizeof(struct mxs_dma_desc *) *
                                MXS_NAND_DMA_DESCRIPTOR_COUNT);
@@ -1083,11 +1087,8 @@ int mxs_nand_init(struct mxs_nand_info *info)
        }
 
        /* Init the DMA controller. */
-       for (j = MXS_DMA_CHANNEL_AHB_APBH_GPMI0;
-               j <= MXS_DMA_CHANNEL_AHB_APBH_GPMI7; j++) {
-               if (mxs_dma_init_channel(j))
-                       goto err3;
-       }
+       if (mxs_dma_init_channel(0))
+               goto err2;
 
        /* Reset the GPMI block. */
        mxs_reset_block(&gpmi_regs->hw_gpmi_ctrl0_reg);
@@ -1100,13 +1101,10 @@ int mxs_nand_init(struct mxs_nand_info *info)
        clrsetbits_le32(&gpmi_regs->hw_gpmi_ctrl1,
                        GPMI_CTRL1_GPMI_MODE,
                        GPMI_CTRL1_ATA_IRQRDY_POLARITY | GPMI_CTRL1_DEV_RESET |
-                       GPMI_CTRL1_BCH_MODE);
+                       GPMI_CTRL1_BCH_MODE | GPMI_CTRL1_DECOUPLE_CS);
 
        return 0;
 
-err3:
-       for (--j; j >= 0; j--)
-               mxs_dma_release(j);
 err2:
        free(info->desc);
 err1:
-- 
2.2.0

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to