[U-Boot] [PATCH] mtd: nand: mxs: Add support for multiple NAND chips

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:

On Tuesday, December 02, 2014 at 02:26:14 PM, Stefan Roese wrote:
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
Shouldn't you see "Device 0" and "Device 1" ?
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
Looks pretty trivial, thanks!
Reviewed-by: Marek Vasut marex@denx.de
Best regards, Marek Vasut

On Sat, 2014-12-06 at 14:07 +0100, Marek Vasut wrote:
On Tuesday, December 02, 2014 at 02:26:14 PM, Stefan Roese wrote:
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
Shouldn't you see "Device 0" and "Device 1" ?
The "2x" indicates that there are two identical chips being treated as a single device (chip->numchips).
-Scott

On Sunday, December 07, 2014 at 12:45:30 AM, Scott Wood wrote:
On Sat, 2014-12-06 at 14:07 +0100, Marek Vasut wrote:
On Tuesday, December 02, 2014 at 02:26:14 PM, Stefan Roese wrote:
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
Shouldn't you see "Device 0" and "Device 1" ?
The "2x" indicates that there are two identical chips being treated as a single device (chip->numchips).
Is that correct ? What if I have two different NAND chips on this controller?
Best regards, Marek Vasut

On Sun, 2014-12-07 at 02:32 +0100, Marek Vasut wrote:
On Sunday, December 07, 2014 at 12:45:30 AM, Scott Wood wrote:
On Sat, 2014-12-06 at 14:07 +0100, Marek Vasut wrote:
On Tuesday, December 02, 2014 at 02:26:14 PM, Stefan Roese wrote:
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
Shouldn't you see "Device 0" and "Device 1" ?
The "2x" indicates that there are two identical chips being treated as a single device (chip->numchips).
Is that correct ? What if I have two different NAND chips on this controller?
Then they need to be represented as separate NAND devices, rather than multiple chips on one device.
-Scott

On Sunday, December 07, 2014 at 02:50:25 AM, Scott Wood wrote:
On Sun, 2014-12-07 at 02:32 +0100, Marek Vasut wrote:
On Sunday, December 07, 2014 at 12:45:30 AM, Scott Wood wrote:
On Sat, 2014-12-06 at 14:07 +0100, Marek Vasut wrote:
On Tuesday, December 02, 2014 at 02:26:14 PM, Stefan Roese wrote:
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
Shouldn't you see "Device 0" and "Device 1" ?
The "2x" indicates that there are two identical chips being treated as a single device (chip->numchips).
Is that correct ? What if I have two different NAND chips on this controller?
Then they need to be represented as separate NAND devices, rather than multiple chips on one device.
Gee, I wouldn't have though of that, really ;-)
So is this patch correct or not ?
Best regards, Marek Vasut

On Sun, 2014-12-07 at 06:26 +0100, Marek Vasut wrote:
On Sunday, December 07, 2014 at 02:50:25 AM, Scott Wood wrote:
On Sun, 2014-12-07 at 02:32 +0100, Marek Vasut wrote:
On Sunday, December 07, 2014 at 12:45:30 AM, Scott Wood wrote:
On Sat, 2014-12-06 at 14:07 +0100, Marek Vasut wrote:
On Tuesday, December 02, 2014 at 02:26:14 PM, Stefan Roese wrote:
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
Shouldn't you see "Device 0" and "Device 1" ?
The "2x" indicates that there are two identical chips being treated as a single device (chip->numchips).
Is that correct ? What if I have two different NAND chips on this controller?
Then they need to be represented as separate NAND devices, rather than multiple chips on one device.
Gee, I wouldn't have though of that, really ;-)
Well, you asked a vague question...
So is this patch correct or not ?
In all its details? I don't know, as I'm not familiar with the hardware. With regards to the question about non-identical devices, this patch doesn't add support for that. So it's a question of what the requirements are, and whether it's being used in the right circumstances. If you have non-identical NAND chips, make sure CONFIG_SYS_NAND_MAX_CHIPS is 1.
A better question might be, does this approach make sense, versus implementing support for multiple devices? What does Linux support?
-Scott

On 08.12.2014 23:53, Scott Wood wrote:
> => nand device > > Device 0: 2x nand0, sector size 128 KiB > > Page size 2048 b > OOB size 64 b > Erase size 131072 b
Shouldn't you see "Device 0" and "Device 1" ?
The "2x" indicates that there are two identical chips being treated as a single device (chip->numchips).
Is that correct ? What if I have two different NAND chips on this controller?
Then they need to be represented as separate NAND devices, rather than multiple chips on one device.
Gee, I wouldn't have though of that, really ;-)
Well, you asked a vague question...
So is this patch correct or not ?
In all its details? I don't know, as I'm not familiar with the hardware. With regards to the question about non-identical devices, this patch doesn't add support for that. So it's a question of what the requirements are, and whether it's being used in the right circumstances. If you have non-identical NAND chips, make sure CONFIG_SYS_NAND_MAX_CHIPS is 1.
Correct. Using CONFIG_SYS_NAND_MAX_CHIPS support identical chips. This is exactly what I need in my case. And is also needed for NAND devices that have multiple NAND chips embedded on one die. You then need this possibility to support multiple chips. Otherwise not the whole device can be accessed.
A better question might be, does this approach make sense, versus implementing support for multiple devices? What does Linux support?
Linux does it exactly in the same way:
[ 1.089439] nand: device found, Manufacturer ID: 0x2c, Chip ID: 0xdc [ 1.095864] nand: Micron MT29F4G08ABADAH4 [ 1.099896] nand: 512MiB, SLC, page size: 2048, OOB size: 64 [ 1.105871] nand: 2 chips detected ...
And exposes those 2 chips as one NAND device. By using this patch we also use the same MTD partitioning in U-Boot and Linux (mtdparts environment).
I hope now all is clear.
Thanks, Stefan

On Tuesday, December 09, 2014 at 08:20:51 AM, Stefan Roese wrote:
On 08.12.2014 23:53, Scott Wood wrote:
>> => nand device >> >> Device 0: 2x nand0, sector size 128 KiB >> >> Page size 2048 b >> OOB size 64 b >> Erase size 131072 b > > Shouldn't you see "Device 0" and "Device 1" ?
The "2x" indicates that there are two identical chips being treated as a single device (chip->numchips).
Is that correct ? What if I have two different NAND chips on this controller?
Then they need to be represented as separate NAND devices, rather than multiple chips on one device.
Gee, I wouldn't have though of that, really ;-)
Well, you asked a vague question...
So is this patch correct or not ?
In all its details? I don't know, as I'm not familiar with the hardware. With regards to the question about non-identical devices, this patch doesn't add support for that. So it's a question of what the requirements are, and whether it's being used in the right circumstances. If you have non-identical NAND chips, make sure CONFIG_SYS_NAND_MAX_CHIPS is 1.
Correct. Using CONFIG_SYS_NAND_MAX_CHIPS support identical chips. This is exactly what I need in my case. And is also needed for NAND devices that have multiple NAND chips embedded on one die. You then need this possibility to support multiple chips. Otherwise not the whole device can be accessed.
A better question might be, does this approach make sense, versus implementing support for multiple devices? What does Linux support?
Linux does it exactly in the same way:
[ 1.089439] nand: device found, Manufacturer ID: 0x2c, Chip ID: 0xdc [ 1.095864] nand: Micron MT29F4G08ABADAH4 [ 1.099896] nand: 512MiB, SLC, page size: 2048, OOB size: 64 [ 1.105871] nand: 2 chips detected ...
And exposes those 2 chips as one NAND device. By using this patch we also use the same MTD partitioning in U-Boot and Linux (mtdparts environment).
I hope now all is clear.
Yes, it is now. Thank you both for the detailed explanation!
Acked-by: Marek Vasut marex@denx.de
Best regards, Marek Vasut
participants (3)
-
Marek Vasut
-
Scott Wood
-
Stefan Roese