
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 sr@denx.de Cc: Marek Vasut marex@denx.de Cc: Stefano Babic sbabic@denx.de Cc: Fabio Estevam fabio.estevam@freescale.com Cc: Scott Wood scottwood@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: