Patchwork [U-Boot,v7,02/19] nand: mxc: Add support for i.MX5

login
register
mail settings
Submitter Benoît Thébaudeau
Date Feb. 15, 2013, 8:54 p.m.
Message ID <1360961665-10693-2-git-send-email-benoit.thebaudeau@advansee.com>
Download mbox | patch
Permalink /patch/220858/
State Superseded
Delegated to: Stefano Babic
Headers show

Comments

Benoît Thébaudeau - Feb. 15, 2013, 8:54 p.m.
Signed-off-by: Benoît Thébaudeau <benoit.thebaudeau@advansee.com>
---
Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3:
 - Separate code reformatting from behavioral changes.

Changes in v2: None

 arch/arm/include/asm/arch-mx5/imx-regs.h |    9 +++
 drivers/mtd/nand/mxc_nand.c              |  129 +++++++++++++++++++++++++++---
 include/fsl_nfc.h                        |   79 +++++++++++++++++-
 nand_spl/nand_boot_fsl_nfc.c             |   67 +++++++++++++++-
 4 files changed, 269 insertions(+), 15 deletions(-)
Fabio Estevam - Feb. 26, 2013, 3:33 p.m.
Benoit,

On Fri, Feb 15, 2013 at 6:54 PM, Benoît Thébaudeau
<benoit.thebaudeau@advansee.com> wrote:

> +#elif defined(CONFIG_MX51) || defined(CONFIG_MX53)
> +static int is_16bit_nand(void)
> +{
> +       struct src *src = (struct src *)SRC_BASE_ADDR;
> +
> +       if (readl(&src->sbmr) & SRC_SBMR_NF16B)
> +               return 1;
> +       else
> +               return 0;

This logic is not working on my tests with mx53ard and it results in:

NAND:  NAND device: Manufacturer ID: 0xec, Chip ID: 0xd5 (Samsung NAND 2GiB 3,3)
NAND bus width 16 instead 8 bit
No NAND device found!!!
0 MiB

I am using NAND, but not booting from it, so I don't think we should
use SBMR register to decide the NAND bus width.

If we are not booting from NAND, shouldn't we use a CONFIG_ option in
mx53ard.h to tell the NAND bus width?

Regards,

Fabio Estevam
Benoît Thébaudeau - Feb. 26, 2013, 4:08 p.m.
Hi Fabio,

On Tuesday, February 26, 2013 4:33:20 PM, Fabio Estevam wrote:
> Benoit,
> 
> On Fri, Feb 15, 2013 at 6:54 PM, Benoît Thébaudeau
> <benoit.thebaudeau@advansee.com> wrote:
> 
> > +#elif defined(CONFIG_MX51) || defined(CONFIG_MX53)
> > +static int is_16bit_nand(void)
> > +{
> > +       struct src *src = (struct src *)SRC_BASE_ADDR;
> > +
> > +       if (readl(&src->sbmr) & SRC_SBMR_NF16B)
> > +               return 1;
> > +       else
> > +               return 0;
> 
> This logic is not working on my tests with mx53ard and it results in:
> 
> NAND:  NAND device: Manufacturer ID: 0xec, Chip ID: 0xd5 (Samsung NAND 2GiB
> 3,3)
> NAND bus width 16 instead 8 bit
> No NAND device found!!!
> 0 MiB
> 
> I am using NAND, but not booting from it, so I don't think we should
> use SBMR register to decide the NAND bus width.
> 
> If we are not booting from NAND, shouldn't we use a CONFIG_ option in
> mx53ard.h to tell the NAND bus width?

This boot pin / fuse config has been used by this driver for all i.MX platforms
from the beginning. I don't think that we really need one more software config
here. This is hardware stuff, and the i.MX provides a dedicated hardware
configuration for it, so I think that we should use it, even if it's made for
NAND boot, since it's just describing the present hardware, just like DT would.

In the particular case of the mx53ard, there is a DIP switch that you can use to
fix this config to 8-bit NAND Flash. But if you have blown the fuses to override
the boot pin config, then of course we're doomed because a wrong NAND Flash
config has been blow.

Best regards,
Benoît
Fabio Estevam - Feb. 26, 2013, 4:35 p.m.
On Tue, Feb 26, 2013 at 1:08 PM, Benoît Thébaudeau
<benoit.thebaudeau@advansee.com> wrote:

> This boot pin / fuse config has been used by this driver for all i.MX platforms
> from the beginning. I don't think that we really need one more software config
> here. This is hardware stuff, and the i.MX provides a dedicated hardware
> configuration for it, so I think that we should use it, even if it's made for
> NAND boot, since it's just describing the present hardware, just like DT would.
>
> In the particular case of the mx53ard, there is a DIP switch that you can use to
> fix this config to 8-bit NAND Flash. But if you have blown the fuses to override
> the boot pin config, then of course we're doomed because a wrong NAND Flash
> config has been blow.

The boot config jumpers are correctly set to boot from MMC card and
this is what I am using as the boot media.

Why should we decide the NAND width via boot pins if I am not booting
from NAND at all?

I see that current mxc nand drivers are doing like this, but I don't
think this makes sense if we use NAND and does not boot from it.

I agree with this comment from tt01.h:

"/*
 * it's not 16 bit:
 * #define CONFIG_SYS_NAND_BUSWIDTH_16BIT
 *    the current u-boot mxc_nand.c tries to auto-detect, but this only
 *    reads the boot settings during reset (which might be wrong)
 */"

and we can also see the a workaround at board/davedenx/qong/qong.c in
order to tell the nand bus width is 8 bits:

void qong_nand_plat_init(void *chip)
{
	struct nand_chip *nand = (struct nand_chip *)chip;
	nand->chip_delay = 20;
	nand->select_chip = qong_nand_select_chip;
	nand->options &= ~NAND_BUSWIDTH_16;
	board_nand_setup();
}
Benoît Thébaudeau - Feb. 26, 2013, 4:49 p.m.
Hi Fabio,

On Tuesday, February 26, 2013 5:35:28 PM, Fabio Estevam wrote:
> On Tue, Feb 26, 2013 at 1:08 PM, Benoît Thébaudeau
> <benoit.thebaudeau@advansee.com> wrote:
> 
> > This boot pin / fuse config has been used by this driver for all i.MX
> > platforms
> > from the beginning. I don't think that we really need one more software
> > config
> > here. This is hardware stuff, and the i.MX provides a dedicated hardware
> > configuration for it, so I think that we should use it, even if it's made
> > for
> > NAND boot, since it's just describing the present hardware, just like DT
> > would.
> >
> > In the particular case of the mx53ard, there is a DIP switch that you can
> > use to
> > fix this config to 8-bit NAND Flash. But if you have blown the fuses to
> > override
> > the boot pin config, then of course we're doomed because a wrong NAND Flash
> > config has been blow.
> 
> The boot config jumpers are correctly set to boot from MMC card and
> this is what I am using as the boot media.

OK, then we don't have a choice.

> Why should we decide the NAND width via boot pins if I am not booting
> from NAND at all?
> 
> I see that current mxc nand drivers are doing like this, but I don't
> think this makes sense if we use NAND and does not boot from it.

If the NAND boot config for bus width is not used by the actuel boot config to
mean something else (which is not your case), then it's a handy way of
describing the NAND hardware setup without involving software. But anyway we're
not in this case, so we need a software config.

> I agree with this comment from tt01.h:
> 
> "/*
>  * it's not 16 bit:
>  * #define CONFIG_SYS_NAND_BUSWIDTH_16BIT
>  *    the current u-boot mxc_nand.c tries to auto-detect, but this only
>  *    reads the boot settings during reset (which might be wrong)
>  */"
> 
> and we can also see the a workaround at board/davedenx/qong/qong.c in
> order to tell the nand bus width is 8 bits:
> 
> void qong_nand_plat_init(void *chip)
> {
> 	struct nand_chip *nand = (struct nand_chip *)chip;
> 	nand->chip_delay = 20;
> 	nand->select_chip = qong_nand_select_chip;
> 	nand->options &= ~NAND_BUSWIDTH_16;
> 	board_nand_setup();
> }

OK, then let's use something like CONFIG_SYS_NAND_BUSWIDTH_16BIT for all boards
with mxc_nand enabled.

Best regards,
Benoît
Fabio Estevam - Feb. 26, 2013, 5:03 p.m.
On Tue, Feb 26, 2013 at 1:49 PM, Benoît Thébaudeau
<benoit.thebaudeau@advansee.com> wrote:
> Hi Fabio,
>
> On Tuesday, February 26, 2013 5:35:28 PM, Fabio Estevam wrote:
>> On Tue, Feb 26, 2013 at 1:08 PM, Benoît Thébaudeau
>> <benoit.thebaudeau@advansee.com> wrote:
>>
>> > This boot pin / fuse config has been used by this driver for all i.MX
>> > platforms
>> > from the beginning. I don't think that we really need one more software
>> > config
>> > here. This is hardware stuff, and the i.MX provides a dedicated hardware
>> > configuration for it, so I think that we should use it, even if it's made
>> > for
>> > NAND boot, since it's just describing the present hardware, just like DT
>> > would.
>> >
>> > In the particular case of the mx53ard, there is a DIP switch that you can
>> > use to
>> > fix this config to 8-bit NAND Flash. But if you have blown the fuses to
>> > override
>> > the boot pin config, then of course we're doomed because a wrong NAND Flash
>> > config has been blow.
>>
>> The boot config jumpers are correctly set to boot from MMC card and
>> this is what I am using as the boot media.
>
> OK, then we don't have a choice.
>
>> Why should we decide the NAND width via boot pins if I am not booting
>> from NAND at all?
>>
>> I see that current mxc nand drivers are doing like this, but I don't
>> think this makes sense if we use NAND and does not boot from it.
>
> If the NAND boot config for bus width is not used by the actuel boot config to
> mean something else (which is not your case), then it's a handy way of
> describing the NAND hardware setup without involving software. But anyway we're
> not in this case, so we need a software config.
>
>> I agree with this comment from tt01.h:
>>
>> "/*
>>  * it's not 16 bit:
>>  * #define CONFIG_SYS_NAND_BUSWIDTH_16BIT
>>  *    the current u-boot mxc_nand.c tries to auto-detect, but this only
>>  *    reads the boot settings during reset (which might be wrong)
>>  */"
>>
>> and we can also see the a workaround at board/davedenx/qong/qong.c in
>> order to tell the nand bus width is 8 bits:
>>
>> void qong_nand_plat_init(void *chip)
>> {
>>       struct nand_chip *nand = (struct nand_chip *)chip;
>>       nand->chip_delay = 20;
>>       nand->select_chip = qong_nand_select_chip;
>>       nand->options &= ~NAND_BUSWIDTH_16;
>>       board_nand_setup();
>> }
>
> OK, then let's use something like CONFIG_SYS_NAND_BUSWIDTH_16BIT for all boards
> with mxc_nand enabled.

Documentation/devicetree/bindings/mtd/nand.txt  says:

nand-bus-width : 8 or 16 bus width if not present 8

I think we could do the same here, ie, if
CONFIG_SYS_NAND_BUSWIDTH_16BIT is not defined in the board file, then
assume it is 8-bit nand.

I can send this as a separate patch.

Thanks,

Fabio Estevam
Benoît Thébaudeau - Feb. 26, 2013, 5:08 p.m.
Hi Fabio,

On Tuesday, February 26, 2013 6:03:56 PM, Fabio Estevam wrote:
> On Tue, Feb 26, 2013 at 1:49 PM, Benoît Thébaudeau
> <benoit.thebaudeau@advansee.com> wrote:
> > Hi Fabio,
> >
> > On Tuesday, February 26, 2013 5:35:28 PM, Fabio Estevam wrote:
> >> On Tue, Feb 26, 2013 at 1:08 PM, Benoît Thébaudeau
> >> <benoit.thebaudeau@advansee.com> wrote:
> >>
> >> > This boot pin / fuse config has been used by this driver for all i.MX
> >> > platforms
> >> > from the beginning. I don't think that we really need one more software
> >> > config
> >> > here. This is hardware stuff, and the i.MX provides a dedicated hardware
> >> > configuration for it, so I think that we should use it, even if it's
> >> > made
> >> > for
> >> > NAND boot, since it's just describing the present hardware, just like DT
> >> > would.
> >> >
> >> > In the particular case of the mx53ard, there is a DIP switch that you
> >> > can
> >> > use to
> >> > fix this config to 8-bit NAND Flash. But if you have blown the fuses to
> >> > override
> >> > the boot pin config, then of course we're doomed because a wrong NAND
> >> > Flash
> >> > config has been blow.
> >>
> >> The boot config jumpers are correctly set to boot from MMC card and
> >> this is what I am using as the boot media.
> >
> > OK, then we don't have a choice.
> >
> >> Why should we decide the NAND width via boot pins if I am not booting
> >> from NAND at all?
> >>
> >> I see that current mxc nand drivers are doing like this, but I don't
> >> think this makes sense if we use NAND and does not boot from it.
> >
> > If the NAND boot config for bus width is not used by the actuel boot config
> > to
> > mean something else (which is not your case), then it's a handy way of
> > describing the NAND hardware setup without involving software. But anyway
> > we're
> > not in this case, so we need a software config.
> >
> >> I agree with this comment from tt01.h:
> >>
> >> "/*
> >>  * it's not 16 bit:
> >>  * #define CONFIG_SYS_NAND_BUSWIDTH_16BIT
> >>  *    the current u-boot mxc_nand.c tries to auto-detect, but this only
> >>  *    reads the boot settings during reset (which might be wrong)
> >>  */"
> >>
> >> and we can also see the a workaround at board/davedenx/qong/qong.c in
> >> order to tell the nand bus width is 8 bits:
> >>
> >> void qong_nand_plat_init(void *chip)
> >> {
> >>       struct nand_chip *nand = (struct nand_chip *)chip;
> >>       nand->chip_delay = 20;
> >>       nand->select_chip = qong_nand_select_chip;
> >>       nand->options &= ~NAND_BUSWIDTH_16;
> >>       board_nand_setup();
> >> }
> >
> > OK, then let's use something like CONFIG_SYS_NAND_BUSWIDTH_16BIT for all
> > boards
> > with mxc_nand enabled.
> 
> Documentation/devicetree/bindings/mtd/nand.txt  says:
> 
> nand-bus-width : 8 or 16 bus width if not present 8
> 
> I think we could do the same here, ie, if
> CONFIG_SYS_NAND_BUSWIDTH_16BIT is not defined in the board file, then
> assume it is 8-bit nand.

I 100% agree. This should make your patch quite lite.

> I can send this as a separate patch.

OK, thanks.

Best regards,
Benoît

Patch

diff --git a/arch/arm/include/asm/arch-mx5/imx-regs.h b/arch/arm/include/asm/arch-mx5/imx-regs.h
index 249d15a..9aa0c6a 100644
--- a/arch/arm/include/asm/arch-mx5/imx-regs.h
+++ b/arch/arm/include/asm/arch-mx5/imx-regs.h
@@ -224,6 +224,15 @@ 
 #define CS0_32M_CS1_32M_CS2_32M_CS3_32M		3
 
 /*
+ * SRC register definitions
+ */
+#if defined(CONFIG_MX51)
+#define SRC_SBMR_NF16B		(1 << 2)
+#elif defined(CONFIG_MX53)
+#define SRC_SBMR_NF16B		(1 << 13)
+#endif
+
+/*
  * CSPI register definitions
  */
 #define MXC_ECSPI
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
index 045df49..cead757 100644
--- a/drivers/mtd/nand/mxc_nand.c
+++ b/drivers/mtd/nand/mxc_nand.c
@@ -22,7 +22,8 @@ 
 #include <nand.h>
 #include <linux/err.h>
 #include <asm/io.h>
-#if defined(CONFIG_MX25) || defined(CONFIG_MX27) || defined(CONFIG_MX35)
+#if defined(CONFIG_MX25) || defined(CONFIG_MX27) || defined(CONFIG_MX35) || \
+	defined(CONFIG_MX51) || defined(CONFIG_MX53)
 #include <asm/arch/imx-regs.h>
 #endif
 #include <fsl_nfc.h>
@@ -36,6 +37,9 @@  struct mxc_nand_host {
 	struct nand_chip		*nand;
 
 	struct fsl_nfc_regs __iomem	*regs;
+#ifdef MXC_NFC_V3_2
+	struct fsl_nfc_ip_regs __iomem	*ip_regs;
+#endif
 	int				spare_only;
 	int				status_request;
 	int				pagesize_2k;
@@ -77,7 +81,7 @@  static struct nand_ecclayout nand_hw_eccoob2k = {
 	.oobfree = { {2, 4}, {11, 11}, {27, 11}, {43, 11}, {59, 5} },
 };
 #endif
-#elif defined(MXC_NFC_V2_1)
+#elif defined(MXC_NFC_V2_1) || defined(MXC_NFC_V3_2)
 #ifndef CONFIG_SYS_NAND_LARGEPAGE
 static struct nand_ecclayout nand_hw_eccoob = {
 	.eccbytes = 9,
@@ -130,6 +134,16 @@  static int is_16bit_nand(void)
 	else
 		return 0;
 }
+#elif defined(CONFIG_MX51) || defined(CONFIG_MX53)
+static int is_16bit_nand(void)
+{
+	struct src *src = (struct src *)SRC_BASE_ADDR;
+
+	if (readl(&src->sbmr) & SRC_SBMR_NF16B)
+		return 1;
+	else
+		return 0;
+}
 #else
 #warning "8/16 bit NAND autodetection not supported"
 static int is_16bit_nand(void)
@@ -158,10 +172,17 @@  static void wait_op_done(struct mxc_nand_host *host, int max_retries,
 	uint32_t tmp;
 
 	while (max_retries-- > 0) {
+#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1)
 		tmp = readnfc(&host->regs->config2);
 		if (tmp & NFC_V1_V2_CONFIG2_INT) {
 			tmp &= ~NFC_V1_V2_CONFIG2_INT;
 			writenfc(tmp, &host->regs->config2);
+#elif defined(MXC_NFC_V3_2)
+		tmp = readnfc(&host->ip_regs->ipc);
+		if (tmp & NFC_V3_IPC_INT) {
+			tmp &= ~NFC_V3_IPC_INT;
+			writenfc(tmp, &host->ip_regs->ipc);
+#endif
 			break;
 		}
 		udelay(1);
@@ -213,7 +234,7 @@  static void send_prog_page(struct mxc_nand_host *host, uint8_t buf_id,
 	if (spare_only)
 		MTDDEBUG(MTD_DEBUG_LEVEL1, "send_prog_page (%d)\n", spare_only);
 
-	if (is_mxc_nfc_21()) {
+	if (is_mxc_nfc_21() || is_mxc_nfc_32()) {
 		int i;
 		/*
 		 *  The controller copies the 64 bytes of spare data from
@@ -229,11 +250,18 @@  static void send_prog_page(struct mxc_nand_host *host, uint8_t buf_id,
 		}
 	}
 
+#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1)
 	writenfc(buf_id, &host->regs->buf_addr);
+#elif defined(MXC_NFC_V3_2)
+	uint32_t tmp = readnfc(&host->regs->config1);
+	tmp &= ~NFC_V3_CONFIG1_RBA_MASK;
+	tmp |= NFC_V3_CONFIG1_RBA(buf_id);
+	writenfc(tmp, &host->regs->config1);
+#endif
 
 	/* Configure spare or page+spare access */
 	if (!host->pagesize_2k) {
-		uint16_t config1 = readnfc(&host->regs->config1);
+		uint32_t config1 = readnfc(&host->regs->config1);
 		if (spare_only)
 			config1 |= NFC_CONFIG1_SP_EN;
 		else
@@ -256,7 +284,14 @@  static void send_read_page(struct mxc_nand_host *host, uint8_t buf_id,
 {
 	MTDDEBUG(MTD_DEBUG_LEVEL3, "send_read_page (%d)\n", spare_only);
 
+#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1)
 	writenfc(buf_id, &host->regs->buf_addr);
+#elif defined(MXC_NFC_V3_2)
+	uint32_t tmp = readnfc(&host->regs->config1);
+	tmp &= ~NFC_V3_CONFIG1_RBA_MASK;
+	tmp |= NFC_V3_CONFIG1_RBA(buf_id);
+	writenfc(tmp, &host->regs->config1);
+#endif
 
 	/* Configure spare or page+spare access */
 	if (!host->pagesize_2k) {
@@ -273,7 +308,7 @@  static void send_read_page(struct mxc_nand_host *host, uint8_t buf_id,
 	/* Wait for operation to complete */
 	wait_op_done(host, TROP_US_DELAY, spare_only);
 
-	if (is_mxc_nfc_21()) {
+	if (is_mxc_nfc_21() || is_mxc_nfc_32()) {
 		int i;
 
 		/*
@@ -293,10 +328,16 @@  static void send_read_page(struct mxc_nand_host *host, uint8_t buf_id,
 /* Request the NANDFC to perform a read of the NAND device ID. */
 static void send_read_id(struct mxc_nand_host *host)
 {
-	uint16_t tmp;
+	uint32_t tmp;
 
+#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1)
 	/* NANDFC buffer 0 is used for device ID output */
 	writenfc(0x0, &host->regs->buf_addr);
+#elif defined(MXC_NFC_V3_2)
+	tmp = readnfc(&host->regs->config1);
+	tmp &= ~NFC_V3_CONFIG1_RBA_MASK;
+	writenfc(tmp, &host->regs->config1);
+#endif
 
 	/* Read ID into main buffer */
 	tmp = readnfc(&host->regs->config1);
@@ -315,15 +356,19 @@  static void send_read_id(struct mxc_nand_host *host)
  */
 static uint16_t get_dev_status(struct mxc_nand_host *host)
 {
+#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1)
 	void __iomem *main_buf = host->regs->main_area[1];
 	uint32_t store;
-	uint16_t ret, tmp;
+#endif
+	uint32_t ret, tmp;
 	/* Issue status request to NAND device */
 
+#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1)
 	/* store the main area1 first word, later do recovery */
 	store = readl(main_buf);
 	/* NANDFC buffer 1 is used for device status */
 	writenfc(1, &host->regs->buf_addr);
+#endif
 
 	/* Read status into main buffer */
 	tmp = readnfc(&host->regs->config1);
@@ -335,12 +380,16 @@  static uint16_t get_dev_status(struct mxc_nand_host *host)
 	/* Wait for operation to complete */
 	wait_op_done(host, TROP_US_DELAY, 0);
 
+#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1)
 	/*
 	 *  Status is placed in first word of main buffer
 	 * get status, then recovery area 1 data
 	 */
 	ret = readw(main_buf);
 	writel(store, main_buf);
+#elif defined(MXC_NFC_V3_2)
+	ret = readnfc(&host->regs->config1) >> 16;
+#endif
 
 	return ret;
 }
@@ -359,6 +408,7 @@  static void _mxc_nand_enable_hwecc(struct mtd_info *mtd, int on)
 {
 	struct nand_chip *nand_chip = mtd->priv;
 	struct mxc_nand_host *host = nand_chip->priv;
+#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1)
 	uint16_t tmp = readnfc(&host->regs->config1);
 
 	if (on)
@@ -366,6 +416,15 @@  static void _mxc_nand_enable_hwecc(struct mtd_info *mtd, int on)
 	else
 		tmp &= ~NFC_V1_V2_CONFIG1_ECC_EN;
 	writenfc(tmp, &host->regs->config1);
+#elif defined(MXC_NFC_V3_2)
+	uint32_t tmp = readnfc(&host->ip_regs->config2);
+
+	if (on)
+		tmp |= NFC_V3_CONFIG2_ECC_EN;
+	else
+		tmp &= ~NFC_V3_CONFIG2_ECC_EN;
+	writenfc(tmp, &host->ip_regs->config2);
+#endif
 }
 
 #ifdef CONFIG_MXC_NAND_HWECC
@@ -377,7 +436,7 @@  static void mxc_nand_enable_hwecc(struct mtd_info *mtd, int mode)
 	 */
 }
 
-#ifdef MXC_NFC_V2_1
+#if defined(MXC_NFC_V2_1) || defined(MXC_NFC_V3_2)
 static int mxc_nand_read_oob_syndrome(struct mtd_info *mtd,
 				      struct nand_chip *chip,
 				      int page, int sndcmd)
@@ -1167,8 +1226,8 @@  static struct nand_bbt_descr bbt_mirror_descr = {
 int board_nand_init(struct nand_chip *this)
 {
 	struct mtd_info *mtd;
-#ifdef MXC_NFC_V2_1
-	uint16_t tmp;
+#if defined(MXC_NFC_V2_1) || defined(MXC_NFC_V3_2)
+	uint32_t tmp;
 #endif
 
 #ifdef CONFIG_SYS_NAND_USE_FLASH_BBT
@@ -1196,13 +1255,17 @@  int board_nand_init(struct nand_chip *this)
 	this->verify_buf = mxc_nand_verify_buf;
 
 	host->regs = (struct fsl_nfc_regs __iomem *)CONFIG_MXC_NAND_REGS_BASE;
+#ifdef MXC_NFC_V3_2
+	host->ip_regs =
+		(struct fsl_nfc_ip_regs __iomem *)CONFIG_MXC_NAND_IP_REGS_BASE;
+#endif
 	host->clk_act = 1;
 
 #ifdef CONFIG_MXC_NAND_HWECC
 	this->ecc.calculate = mxc_nand_calculate_ecc;
 	this->ecc.hwctl = mxc_nand_enable_hwecc;
 	this->ecc.correct = mxc_nand_correct_data;
-	if (is_mxc_nfc_21()) {
+	if (is_mxc_nfc_21() || is_mxc_nfc_32()) {
 		this->ecc.mode = NAND_ECC_HW_SYNDROME;
 		this->ecc.read_page = mxc_nand_read_page_syndrome;
 		this->ecc.read_page_raw = mxc_nand_read_page_raw_syndrome;
@@ -1240,6 +1303,7 @@  int board_nand_init(struct nand_chip *this)
 	this->ecc.layout = &nand_hw_eccoob;
 #endif
 
+#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1)
 #ifdef MXC_NFC_V2_1
 	tmp = readnfc(&host->regs->config1);
 	tmp |= NFC_V2_CONFIG1_ONE_CYCLE;
@@ -1274,6 +1338,49 @@  int board_nand_init(struct nand_chip *this)
 
 	/* Unlock Block Command for given address range */
 	writenfc(0x4, &host->regs->wrprot);
+#elif defined(MXC_NFC_V3_2)
+	writenfc(NFC_V3_CONFIG1_RBA(0), &host->regs->config1);
+	writenfc(NFC_V3_IPC_CREQ, &host->ip_regs->ipc);
+
+	/* Unlock the internal RAM Buffer */
+	writenfc(NFC_V3_WRPROT_BLS_UNLOCK | NFC_V3_WRPROT_UNLOCK,
+			&host->ip_regs->wrprot);
+
+	/* Blocks to be unlocked */
+	for (tmp = 0; tmp < CONFIG_SYS_NAND_MAX_CHIPS; tmp++)
+		writenfc(0x0 | 0xFFFF << 16,
+				&host->ip_regs->wrprot_unlock_blkaddr[tmp]);
+
+	writenfc(0, &host->ip_regs->ipc);
+
+	tmp = readnfc(&host->ip_regs->config2);
+	tmp &= ~(NFC_V3_CONFIG2_SPAS_MASK | NFC_V3_CONFIG2_EDC_MASK |
+			NFC_V3_CONFIG2_ECC_MODE_8 | NFC_V3_CONFIG2_PS_MASK);
+	tmp |= NFC_V3_CONFIG2_ONE_CYCLE;
+
+	if (host->pagesize_2k) {
+		tmp |= NFC_V3_CONFIG2_SPAS(64/2);
+		tmp |= NFC_V3_CONFIG2_PS_2048;
+	} else {
+		tmp |= NFC_V3_CONFIG2_SPAS(16/2);
+		tmp |= NFC_V3_CONFIG2_PS_512;
+	}
+
+	writenfc(tmp, &host->ip_regs->config2);
+
+	tmp = NFC_V3_CONFIG3_NUM_OF_DEVS(0) |
+			NFC_V3_CONFIG3_NO_SDMA |
+			NFC_V3_CONFIG3_RBB_MODE |
+			NFC_V3_CONFIG3_SBB(6) | /* Reset default */
+			NFC_V3_CONFIG3_ADD_OP(0);
+
+	if (!(this->options & NAND_BUSWIDTH_16))
+		tmp |= NFC_V3_CONFIG3_FW8;
+
+	writenfc(tmp, &host->ip_regs->config3);
+
+	writenfc(0, &host->ip_regs->delay_line);
+#endif
 
 	return 0;
 }
diff --git a/include/fsl_nfc.h b/include/fsl_nfc.h
index 013e9e2..48a6448 100644
--- a/include/fsl_nfc.h
+++ b/include/fsl_nfc.h
@@ -33,7 +33,8 @@ 
  *	to support up to 2K byte pagesize nand.
  *	Reading or writing a 2K page requires 4 FDI/FDO cycles.
  *
- * MX25 and MX35 have version 2.1, which has:
+ * MX25 and MX35 have version 2.1, and MX51 and MX53 have version 3.2, which
+ * have:
  *	8 512-byte main buffers and
  *	8 64-byte spare buffers
  *	to support up to 4K byte pagesize nand.
@@ -44,20 +45,29 @@ 
 #define MXC_NFC_V1
 #define is_mxc_nfc_1()		1
 #define is_mxc_nfc_21()		0
+#define is_mxc_nfc_32()		0
 #elif defined(CONFIG_MX25) || defined(CONFIG_MX35)
 #define MXC_NFC_V2_1
 #define is_mxc_nfc_1()		0
 #define is_mxc_nfc_21()		1
+#define is_mxc_nfc_32()		0
+#elif defined(CONFIG_MX51) || defined(CONFIG_MX53)
+#define MXC_NFC_V3
+#define MXC_NFC_V3_2
+#define is_mxc_nfc_1()		0
+#define is_mxc_nfc_21()		0
+#define is_mxc_nfc_32()		1
 #else
 #error "MXC NFC implementation not supported"
 #endif
+#define is_mxc_nfc_3()		is_mxc_nfc_32()
 
 #if defined(MXC_NFC_V1)
 #define NAND_MXC_NR_BUFS		4
 #define NAND_MXC_SPARE_BUF_SIZE		16
 #define NAND_MXC_REG_OFFSET		0xe00
 #define NAND_MXC_2K_MULTI_CYCLE
-#elif defined(MXC_NFC_V2_1)
+#elif defined(MXC_NFC_V2_1) || defined(MXC_NFC_V3_2)
 #define NAND_MXC_NR_BUFS		8
 #define NAND_MXC_SPARE_BUF_SIZE		64
 #define NAND_MXC_REG_OFFSET		0x1e00
@@ -110,9 +120,28 @@  struct fsl_nfc_regs {
 	u16 unlockend_blkaddr2;
 	u16 unlockstart_blkaddr3;
 	u16 unlockend_blkaddr3;
+#elif defined(MXC_NFC_V3_2)
+	u32 flash_cmd;
+	u32 flash_addr[12];
+	u32 config1;
+	u32 ecc_status_result;
+	u32 status_sum;
+	u32 launch;
 #endif
 };
 
+#ifdef MXC_NFC_V3_2
+struct fsl_nfc_ip_regs {
+	u32 wrprot;
+	u32 wrprot_unlock_blkaddr[8];
+	u32 config2;
+	u32 config3;
+	u32 ipc;
+	u32 err_addr;
+	u32 delay_line;
+};
+#endif
+
 /* Set FCMD to 1, rest to 0 for Command operation */
 #define NFC_CMD				0x1
 
@@ -131,20 +160,66 @@  struct fsl_nfc_regs {
 /* Set FDO to 100, rest to 0 for Read Status operation */
 #define NFC_STATUS			0x20
 
+#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1)
 #define NFC_CONFIG1_SP_EN		(1 << 2)
 #define NFC_CONFIG1_RST			(1 << 6)
 #define NFC_CONFIG1_CE			(1 << 7)
+#elif defined(MXC_NFC_V3_2)
+#define NFC_CONFIG1_SP_EN		(1 << 0)
+#define NFC_CONFIG1_CE			(1 << 1)
+#define NFC_CONFIG1_RST			(1 << 2)
+#endif
 #define NFC_V1_V2_CONFIG1_ECC_EN	(1 << 3)
 #define NFC_V1_V2_CONFIG1_INT_MSK	(1 << 4)
 #define NFC_V1_V2_CONFIG1_BIG		(1 << 5)
 #define NFC_V2_CONFIG1_ECC_MODE_4	(1 << 0)
 #define NFC_V2_CONFIG1_ONE_CYCLE	(1 << 8)
 #define NFC_V2_CONFIG1_FP_INT		(1 << 11)
+#define NFC_V3_CONFIG1_RBA_MASK		(0x7 << 4)
+#define NFC_V3_CONFIG1_RBA(x)		(((x) & 0x7) << 4)
 
 #define NFC_V1_V2_CONFIG2_INT		(1 << 15)
+#define NFC_V3_CONFIG2_PS_MASK		(0x3 << 0)
+#define NFC_V3_CONFIG2_PS_512		(0 << 0)
+#define NFC_V3_CONFIG2_PS_2048		(1 << 0)
+#define NFC_V3_CONFIG2_PS_4096		(2 << 0)
+#define NFC_V3_CONFIG2_ONE_CYCLE	(1 << 2)
+#define NFC_V3_CONFIG2_ECC_EN		(1 << 3)
+#define NFC_V3_CONFIG2_2CMD_PHASES	(1 << 4)
+#define NFC_V3_CONFIG2_NUM_ADDR_PH0	(1 << 5)
+#define NFC_V3_CONFIG2_ECC_MODE_8	(1 << 6)
+#define NFC_V3_CONFIG2_PPB_MASK		(0x3 << 7)
+#define NFC_V3_CONFIG2_PPB(x)		(((x) & 0x3) << 7)
+#define NFC_V3_CONFIG2_EDC_MASK		(0x7 << 9)
+#define NFC_V3_CONFIG2_EDC(x)		(((x) & 0x7) << 9)
+#define NFC_V3_CONFIG2_NUM_ADDR_PH1(x)	(((x) & 0x3) << 12)
+#define NFC_V3_CONFIG2_INT_MSK		(1 << 15)
+#define NFC_V3_CONFIG2_SPAS_MASK	(0xff << 16)
+#define NFC_V3_CONFIG2_SPAS(x)		(((x) & 0xff) << 16)
+#define NFC_V3_CONFIG2_ST_CMD_MASK	(0xff << 24)
+#define NFC_V3_CONFIG2_ST_CMD(x)	(((x) & 0xff) << 24)
+
+#define NFC_V3_CONFIG3_ADD_OP(x)	(((x) & 0x3) << 0)
+#define NFC_V3_CONFIG3_FW8		(1 << 3)
+#define NFC_V3_CONFIG3_SBB(x)		(((x) & 0x7) << 8)
+#define NFC_V3_CONFIG3_NUM_OF_DEVS(x)	(((x) & 0x7) << 12)
+#define NFC_V3_CONFIG3_RBB_MODE		(1 << 15)
+#define NFC_V3_CONFIG3_NO_SDMA		(1 << 20)
 
+#define NFC_V3_WRPROT_UNLOCK		(1 << 2)
+#define NFC_V3_WRPROT_BLS_UNLOCK	(2 << 6)
+
+#define NFC_V3_IPC_CREQ			(1 << 0)
+#define NFC_V3_IPC_INT			(1 << 31)
+
+#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1)
 #define operation	config2
 #define readnfc		readw
 #define writenfc	writew
+#elif defined(MXC_NFC_V3_2)
+#define operation	launch
+#define readnfc		readl
+#define writenfc	writel
+#endif
 
 #endif /* __FSL_NFC_H */
diff --git a/nand_spl/nand_boot_fsl_nfc.c b/nand_spl/nand_boot_fsl_nfc.c
index 615e820..1096727 100644
--- a/nand_spl/nand_boot_fsl_nfc.c
+++ b/nand_spl/nand_boot_fsl_nfc.c
@@ -30,12 +30,18 @@ 
 #include <asm/io.h>
 #include <fsl_nfc.h>
 
+#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1)
 static struct fsl_nfc_regs *const nfc = (void *)NFC_BASE_ADDR;
+#elif defined(MXC_NFC_V3_2)
+static struct fsl_nfc_regs *const nfc = (void *)NFC_BASE_ADDR_AXI;
+static struct fsl_nfc_ip_regs *const nfc_ip = (void *)NFC_BASE_ADDR;
+#endif
 
 static void nfc_wait_ready(void)
 {
 	uint32_t tmp;
 
+#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1)
 	while (!(readnfc(&nfc->config2) & NFC_V1_V2_CONFIG2_INT))
 		;
 
@@ -43,11 +49,56 @@  static void nfc_wait_ready(void)
 	tmp = readnfc(&nfc->config2);
 	tmp &= ~NFC_V1_V2_CONFIG2_INT;
 	writenfc(tmp, &nfc->config2);
+#elif defined(MXC_NFC_V3_2)
+	while (!(readnfc(&nfc_ip->ipc) & NFC_V3_IPC_INT))
+		;
+
+	/* Reset interrupt flag */
+	tmp = readnfc(&nfc_ip->ipc);
+	tmp &= ~NFC_V3_IPC_INT;
+	writenfc(tmp, &nfc_ip->ipc);
+#endif
 }
 
 static void nfc_nand_init(void)
 {
-#if defined(MXC_NFC_V2_1)
+#if defined(MXC_NFC_V3_2)
+	int ecc_per_page = CONFIG_SYS_NAND_PAGE_SIZE / 512;
+	int tmp;
+
+	tmp = (readnfc(&nfc_ip->config2) & ~(NFC_V3_CONFIG2_SPAS_MASK |
+			NFC_V3_CONFIG2_EDC_MASK | NFC_V3_CONFIG2_PS_MASK)) |
+		NFC_V3_CONFIG2_SPAS(CONFIG_SYS_NAND_SPARE_SIZE / 2) |
+		NFC_V3_CONFIG2_INT_MSK | NFC_V3_CONFIG2_ECC_EN |
+		NFC_V3_CONFIG2_ONE_CYCLE;
+	if (CONFIG_SYS_NAND_PAGE_SIZE == 4096)
+		tmp |= NFC_V3_CONFIG2_PS_4096;
+	else if (CONFIG_SYS_NAND_PAGE_SIZE == 2048)
+		tmp |= NFC_V3_CONFIG2_PS_2048;
+	else if (CONFIG_SYS_NAND_PAGE_SIZE == 512)
+		tmp |= NFC_V3_CONFIG2_PS_512;
+	/*
+	 * if spare size is larger that 16 bytes per 512 byte hunk
+	 * then use 8 symbol correction instead of 4
+	 */
+	if (CONFIG_SYS_NAND_SPARE_SIZE / ecc_per_page > 16)
+		tmp |= NFC_V3_CONFIG2_ECC_MODE_8;
+	else
+		tmp &= ~NFC_V3_CONFIG2_ECC_MODE_8;
+	writenfc(tmp, &nfc_ip->config2);
+
+	tmp = NFC_V3_CONFIG3_NUM_OF_DEVS(0) |
+			NFC_V3_CONFIG3_NO_SDMA |
+			NFC_V3_CONFIG3_RBB_MODE |
+			NFC_V3_CONFIG3_SBB(6) | /* Reset default */
+			NFC_V3_CONFIG3_ADD_OP(0);
+#ifndef CONFIG_SYS_NAND_BUSWIDTH_16
+	tmp |= NFC_V3_CONFIG3_FW8;
+#endif
+	writenfc(tmp, &nfc_ip->config3);
+
+	writenfc(0, &nfc_ip->delay_line);
+#elif defined(MXC_NFC_V2_1)
 	int ecc_per_page = CONFIG_SYS_NAND_PAGE_SIZE / 512;
 	int config1;
 
@@ -123,7 +174,13 @@  static void nfc_nand_data_output(void)
 	int i;
 #endif
 
+#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1)
 	writenfc(0, &nfc->buf_addr);
+#elif defined(MXC_NFC_V3_2)
+	int config1 = readnfc(&nfc->config1);
+	config1 &= ~NFC_V3_CONFIG1_RBA_MASK;
+	writenfc(config1, &nfc->config1);
+#endif
 	writenfc(NFC_OUTPUT, &nfc->operation);
 	nfc_wait_ready();
 #ifdef NAND_MXC_2K_MULTI_CYCLE
@@ -144,7 +201,7 @@  static int nfc_nand_check_ecc(void)
 #if defined(MXC_NFC_V1)
 	u16 ecc_status = readw(&nfc->ecc_status_result);
 	return (ecc_status & 0x3) == 2 || (ecc_status >> 2) == 2;
-#elif defined(MXC_NFC_V2_1)
+#elif defined(MXC_NFC_V2_1) || defined(MXC_NFC_V3_2)
 	u32 ecc_status = readl(&nfc->ecc_status_result);
 	int ecc_per_page = CONFIG_SYS_NAND_PAGE_SIZE / 512;
 	int err_limit = CONFIG_SYS_NAND_SPARE_SIZE / ecc_per_page > 16 ? 8 : 4;
@@ -163,7 +220,13 @@  static int nfc_nand_check_ecc(void)
 static void nfc_nand_read_page(unsigned int page_address)
 {
 	/* read in first 0 buffer */
+#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1)
 	writenfc(0, &nfc->buf_addr);
+#elif defined(MXC_NFC_V3_2)
+	int config1 = readnfc(&nfc->config1);
+	config1 &= ~NFC_V3_CONFIG1_RBA_MASK;
+	writenfc(config1, &nfc->config1);
+#endif
 	nfc_nand_command(NAND_CMD_READ0);
 	nfc_nand_page_address(page_address);