diff mbox series

[U-Boot,1/2] i.MX6: nand: extend nandbcb command for imx6UL(L)

Message ID 20190718115537.2096227-1-pn@denx.de
State Superseded
Delegated to: Stefano Babic
Headers show
Series [U-Boot,1/2] i.MX6: nand: extend nandbcb command for imx6UL(L) | expand

Commit Message

Parthiban Nallathambi July 18, 2019, 11:55 a.m. UTC
Firmware Configuration Block(FCB) for imx6ul(l) needs to be
BCH encoded. This patch depends on [1].

[1]: https://patchwork.ozlabs.org/project/uboot/list/?series=113810

Signed-off-by: Parthiban Nallathambi <pn@denx.de>
---
 arch/arm/mach-imx/Kconfig       |  1 +
 arch/arm/mach-imx/cmd_nandbcb.c | 72 ++++++++++++++++++++++++++++++++-
 2 files changed, 71 insertions(+), 2 deletions(-)

Comments

Shyam Saini Aug. 13, 2019, 1:40 p.m. UTC | #1
Hi Parthiban,

Thanks a lot for working on this.

Please see comments below.

> Firmware Configuration Block(FCB) for imx6ul(l) needs to be
> BCH encoded. This patch depends on [1].
>
> [1]: https://patchwork.ozlabs.org/project/uboot/list/?series=113810
>
> Signed-off-by: Parthiban Nallathambi <pn@denx.de>
> ---
>  arch/arm/mach-imx/Kconfig       |  1 +
>  arch/arm/mach-imx/cmd_nandbcb.c | 72 ++++++++++++++++++++++++++++++++-
>  2 files changed, 71 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
> index aeb5493488..175bed601e 100644
> --- a/arch/arm/mach-imx/Kconfig
> +++ b/arch/arm/mach-imx/Kconfig
> @@ -74,6 +74,7 @@ config CMD_HDMIDETECT
>  config CMD_NANDBCB
>         bool "i.MX6 NAND Boot Control Block(BCB) command"
>         depends on NAND && CMD_MTDPARTS
> +       select BCH if MX6UL || MX6ULL
>         default y if ARCH_MX6 && NAND_MXS
>         help
>           Unlike normal 'nand write/erase' commands, this command update
> diff --git a/arch/arm/mach-imx/cmd_nandbcb.c b/arch/arm/mach-imx/cmd_nandbcb.c
> index 065b814b2e..34176ee6e4 100644
> --- a/arch/arm/mach-imx/cmd_nandbcb.c
> +++ b/arch/arm/mach-imx/cmd_nandbcb.c
> @@ -14,8 +14,10 @@
>
>  #include <asm/io.h>
>  #include <jffs2/jffs2.h>
> +#include <linux/bch.h>
>  #include <linux/mtd/mtd.h>
>
> +#include <asm/arch/sys_proto.h>
>  #include <asm/mach-imx/imx-nandbcb.h>
>  #include <asm/mach-imx/imximage.cfg>
>  #include <mxs_nand.h>
> @@ -25,6 +27,66 @@
>  #define BF_VAL(v, bf)          (((v) & bf##_MASK) >> bf##_OFFSET)
>  #define GETBIT(v, n)           (((v) >> (n)) & 0x1)
>
> +static uint8_t reverse_bit(uint8_t b)
> +{
> +       b = (b & 0xf0) >> 4 | (b & 0x0f) << 4;
> +       b = (b & 0xcc) >> 2 | (b & 0x33) << 2;
> +       b = (b & 0xaa) >> 1 | (b & 0x55) << 1;
> +
> +       return b;
> +}
> +
> +static void encode_bch_ecc(void *buf, struct fcb_block *fcb, int eccbits)
> +{
> +       int i, j, m = 13;
> +       int blocksize = 128;
> +       int numblocks = 8;
> +       int ecc_buf_size = (m * eccbits + 7) / 8;
> +       struct bch_control *bch = init_bch(m, eccbits, 0);
> +       u8 *ecc_buf = kzalloc(ecc_buf_size, GFP_KERNEL);
> +       u8 *tmp_buf = kzalloc(blocksize * numblocks, GFP_KERNEL);
> +       u8 *psrc, *pdst;
> +
> +       /*
> +        * The blocks here are bit aligned. If eccbits is a multiple of 8,
> +        * we just can copy bytes. Otherwiese we must move the blocks to
> +        * the next free bit position.
> +        */
> +       WARN_ON(eccbits % 8);
> +
> +       memcpy(tmp_buf, fcb, sizeof(*fcb));
> +
> +       for (i = 0; i < numblocks; i++) {
> +               memset(ecc_buf, 0, ecc_buf_size);
> +               psrc = tmp_buf + i * blocksize;
> +               pdst = buf + i * (blocksize + ecc_buf_size);
> +
> +               /* copy data byte aligned to destination buf */
> +               memcpy(pdst, psrc, blocksize);
> +
> +               /*
> +                * imx-kobs use a modified encode_bch which reverse the
> +                * bit order of the data before calculating bch.
> +                * Do this in the buffer and use the bch lib here.
> +                */
> +               for (j = 0; j < blocksize; j++)
> +                       psrc[j] = reverse_bit(psrc[j]);
> +
> +               encode_bch(bch, psrc, blocksize, ecc_buf);
> +
> +               /* reverse ecc bit */
> +               for (j = 0; j < ecc_buf_size; j++)
> +                       ecc_buf[j] = reverse_bit(ecc_buf[j]);
> +
> +               /* Here eccbuf is byte aligned and we can just copy it */
> +               memcpy(pdst + blocksize, ecc_buf, ecc_buf_size);
> +       }
> +
> +       free(ecc_buf);
> +       free(tmp_buf);
> +       free_bch(bch);

I have used kfree() instead of free() in entire nand bcb code
So, I think for consistency reason it should be kfree here.

Could you please resend this patch with above mentioned changes.
Other than this,

>
>  static u8 calculate_parity_13_8(u8 d)
>  {
>         u8 p = 0;
> @@ -231,8 +293,14 @@ static int nandbcb_update(struct mtd_info *mtd, loff_t off, size_t size,
>                 goto dbbt_data_page_err;
>         }
>
> -       memcpy(fcb_raw_page + 12, fcb, sizeof(struct fcb_block));
> -       encode_hamming_13_8(fcb_raw_page + 12, fcb_raw_page + 12 + 512, 512);
> +       if (is_mx6ul() || is_mx6ull()) {
> +               /* 40 bit BCH, for i.MX6UL(L) */
> +               encode_bch_ecc(fcb_raw_page + 32, fcb, 40);
> +       } else {
> +               memcpy(fcb_raw_page + 12, fcb, sizeof(struct fcb_block));
> +               encode_hamming_13_8(fcb_raw_page + 12,
> +                                   fcb_raw_page + 12 + 512, 512);
> +       }
>         /*
>          * Set the first and second byte of OOB data to 0xFF, not 0x00. These
>          * bytes are used as the Manufacturers Bad Block Marker (MBBM). Since

Acked-by: Shyam Saini <shyam.saini@amarulasolutions.com>
Parthiban Nallathambi Aug. 13, 2019, 1:54 p.m. UTC | #2
Hi Shyam,

On 8/13/19 3:40 PM, Shyam Saini wrote:
> Hi Parthiban,
> 
> Thanks a lot for working on this.

Still enabling SECURE_BOOT fails to boot. Am yet to figure out this.
Do you have secure boot working from NAND?

> 
> Please see comments below.
> 
>> Firmware Configuration Block(FCB) for imx6ul(l) needs to be
>> BCH encoded. This patch depends on [1].
>>
>> [1]: https://patchwork.ozlabs.org/project/uboot/list/?series=113810
>>
>> Signed-off-by: Parthiban Nallathambi <pn@denx.de>
>> ---
>>   arch/arm/mach-imx/Kconfig       |  1 +
>>   arch/arm/mach-imx/cmd_nandbcb.c | 72 ++++++++++++++++++++++++++++++++-
>>   2 files changed, 71 insertions(+), 2 deletions(-)
>>
>> diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
>> index aeb5493488..175bed601e 100644
>> --- a/arch/arm/mach-imx/Kconfig
>> +++ b/arch/arm/mach-imx/Kconfig
>> @@ -74,6 +74,7 @@ config CMD_HDMIDETECT
>>   config CMD_NANDBCB
>>          bool "i.MX6 NAND Boot Control Block(BCB) command"
>>          depends on NAND && CMD_MTDPARTS
>> +       select BCH if MX6UL || MX6ULL
>>          default y if ARCH_MX6 && NAND_MXS
>>          help
>>            Unlike normal 'nand write/erase' commands, this command update
>> diff --git a/arch/arm/mach-imx/cmd_nandbcb.c b/arch/arm/mach-imx/cmd_nandbcb.c
>> index 065b814b2e..34176ee6e4 100644
>> --- a/arch/arm/mach-imx/cmd_nandbcb.c
>> +++ b/arch/arm/mach-imx/cmd_nandbcb.c
>> @@ -14,8 +14,10 @@
>>
>>   #include <asm/io.h>
>>   #include <jffs2/jffs2.h>
>> +#include <linux/bch.h>
>>   #include <linux/mtd/mtd.h>
>>
>> +#include <asm/arch/sys_proto.h>
>>   #include <asm/mach-imx/imx-nandbcb.h>
>>   #include <asm/mach-imx/imximage.cfg>
>>   #include <mxs_nand.h>
>> @@ -25,6 +27,66 @@
>>   #define BF_VAL(v, bf)          (((v) & bf##_MASK) >> bf##_OFFSET)
>>   #define GETBIT(v, n)           (((v) >> (n)) & 0x1)
>>
>> +static uint8_t reverse_bit(uint8_t b)
>> +{
>> +       b = (b & 0xf0) >> 4 | (b & 0x0f) << 4;
>> +       b = (b & 0xcc) >> 2 | (b & 0x33) << 2;
>> +       b = (b & 0xaa) >> 1 | (b & 0x55) << 1;
>> +
>> +       return b;
>> +}
>> +
>> +static void encode_bch_ecc(void *buf, struct fcb_block *fcb, int eccbits)
>> +{
>> +       int i, j, m = 13;
>> +       int blocksize = 128;
>> +       int numblocks = 8;
>> +       int ecc_buf_size = (m * eccbits + 7) / 8;
>> +       struct bch_control *bch = init_bch(m, eccbits, 0);
>> +       u8 *ecc_buf = kzalloc(ecc_buf_size, GFP_KERNEL);
>> +       u8 *tmp_buf = kzalloc(blocksize * numblocks, GFP_KERNEL);
>> +       u8 *psrc, *pdst;
>> +
>> +       /*
>> +        * The blocks here are bit aligned. If eccbits is a multiple of 8,
>> +        * we just can copy bytes. Otherwiese we must move the blocks to
>> +        * the next free bit position.
>> +        */
>> +       WARN_ON(eccbits % 8);
>> +
>> +       memcpy(tmp_buf, fcb, sizeof(*fcb));
>> +
>> +       for (i = 0; i < numblocks; i++) {
>> +               memset(ecc_buf, 0, ecc_buf_size);
>> +               psrc = tmp_buf + i * blocksize;
>> +               pdst = buf + i * (blocksize + ecc_buf_size);
>> +
>> +               /* copy data byte aligned to destination buf */
>> +               memcpy(pdst, psrc, blocksize);
>> +
>> +               /*
>> +                * imx-kobs use a modified encode_bch which reverse the
>> +                * bit order of the data before calculating bch.
>> +                * Do this in the buffer and use the bch lib here.
>> +                */
>> +               for (j = 0; j < blocksize; j++)
>> +                       psrc[j] = reverse_bit(psrc[j]);
>> +
>> +               encode_bch(bch, psrc, blocksize, ecc_buf);
>> +
>> +               /* reverse ecc bit */
>> +               for (j = 0; j < ecc_buf_size; j++)
>> +                       ecc_buf[j] = reverse_bit(ecc_buf[j]);
>> +
>> +               /* Here eccbuf is byte aligned and we can just copy it */
>> +               memcpy(pdst + blocksize, ecc_buf, ecc_buf_size);
>> +       }
>> +
>> +       free(ecc_buf);
>> +       free(tmp_buf);
>> +       free_bch(bch);
> 
> I have used kfree() instead of free() in entire nand bcb code
> So, I think for consistency reason it should be kfree here.
> 
> Could you please resend this patch with above mentioned changes.
> Other than this,

Thanks, will change it to kfree in v2.

> 
>>
>>   static u8 calculate_parity_13_8(u8 d)
>>   {
>>          u8 p = 0;
>> @@ -231,8 +293,14 @@ static int nandbcb_update(struct mtd_info *mtd, loff_t off, size_t size,
>>                  goto dbbt_data_page_err;
>>          }
>>
>> -       memcpy(fcb_raw_page + 12, fcb, sizeof(struct fcb_block));
>> -       encode_hamming_13_8(fcb_raw_page + 12, fcb_raw_page + 12 + 512, 512);
>> +       if (is_mx6ul() || is_mx6ull()) {
>> +               /* 40 bit BCH, for i.MX6UL(L) */
>> +               encode_bch_ecc(fcb_raw_page + 32, fcb, 40);
>> +       } else {
>> +               memcpy(fcb_raw_page + 12, fcb, sizeof(struct fcb_block));
>> +               encode_hamming_13_8(fcb_raw_page + 12,
>> +                                   fcb_raw_page + 12 + 512, 512);
>> +       }
>>          /*
>>           * Set the first and second byte of OOB data to 0xFF, not 0x00. These
>>           * bytes are used as the Manufacturers Bad Block Marker (MBBM). Since
> 
> Acked-by: Shyam Saini <shyam.saini@amarulasolutions.com>
>
Shyam Saini Aug. 14, 2019, 5:34 a.m. UTC | #3
> Hi Shyam,
>
> On 8/13/19 3:40 PM, Shyam Saini wrote:
> > Hi Parthiban,
> >
> > Thanks a lot for working on this.
>
> Still enabling SECURE_BOOT fails to boot. Am yet to figure out this.
> Do you have secure boot working from NAND?

I haven't tried secure boot with nand and our imx6ul board has some other nand
boot issues so couldn't test it soon.

>
> >
> > Please see comments below.
> >
> >> Firmware Configuration Block(FCB) for imx6ul(l) needs to be
> >> BCH encoded. This patch depends on [1].
> >>
> >> [1]: https://patchwork.ozlabs.org/project/uboot/list/?series=113810
> >>
> >> Signed-off-by: Parthiban Nallathambi <pn@denx.de>
> >> ---
> >>   arch/arm/mach-imx/Kconfig       |  1 +
> >>   arch/arm/mach-imx/cmd_nandbcb.c | 72 ++++++++++++++++++++++++++++++++-
> >>   2 files changed, 71 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
> >> index aeb5493488..175bed601e 100644
> >> --- a/arch/arm/mach-imx/Kconfig
> >> +++ b/arch/arm/mach-imx/Kconfig
> >> @@ -74,6 +74,7 @@ config CMD_HDMIDETECT
> >>   config CMD_NANDBCB
> >>          bool "i.MX6 NAND Boot Control Block(BCB) command"
> >>          depends on NAND && CMD_MTDPARTS
> >> +       select BCH if MX6UL || MX6ULL
> >>          default y if ARCH_MX6 && NAND_MXS
> >>          help
> >>            Unlike normal 'nand write/erase' commands, this command update
> >> diff --git a/arch/arm/mach-imx/cmd_nandbcb.c b/arch/arm/mach-imx/cmd_nandbcb.c
> >> index 065b814b2e..34176ee6e4 100644
> >> --- a/arch/arm/mach-imx/cmd_nandbcb.c
> >> +++ b/arch/arm/mach-imx/cmd_nandbcb.c
> >> @@ -14,8 +14,10 @@
> >>
> >>   #include <asm/io.h>
> >>   #include <jffs2/jffs2.h>
> >> +#include <linux/bch.h>
> >>   #include <linux/mtd/mtd.h>
> >>
> >> +#include <asm/arch/sys_proto.h>
> >>   #include <asm/mach-imx/imx-nandbcb.h>
> >>   #include <asm/mach-imx/imximage.cfg>
> >>   #include <mxs_nand.h>
> >> @@ -25,6 +27,66 @@
> >>   #define BF_VAL(v, bf)          (((v) & bf##_MASK) >> bf##_OFFSET)
> >>   #define GETBIT(v, n)           (((v) >> (n)) & 0x1)
> >>
> >> +static uint8_t reverse_bit(uint8_t b)
> >> +{
> >> +       b = (b & 0xf0) >> 4 | (b & 0x0f) << 4;
> >> +       b = (b & 0xcc) >> 2 | (b & 0x33) << 2;
> >> +       b = (b & 0xaa) >> 1 | (b & 0x55) << 1;
> >> +
> >> +       return b;
> >> +}
> >> +
> >> +static void encode_bch_ecc(void *buf, struct fcb_block *fcb, int eccbits)
> >> +{
> >> +       int i, j, m = 13;
> >> +       int blocksize = 128;
> >> +       int numblocks = 8;
> >> +       int ecc_buf_size = (m * eccbits + 7) / 8;
> >> +       struct bch_control *bch = init_bch(m, eccbits, 0);
> >> +       u8 *ecc_buf = kzalloc(ecc_buf_size, GFP_KERNEL);
> >> +       u8 *tmp_buf = kzalloc(blocksize * numblocks, GFP_KERNEL);
> >> +       u8 *psrc, *pdst;
> >> +
> >> +       /*
> >> +        * The blocks here are bit aligned. If eccbits is a multiple of 8,
> >> +        * we just can copy bytes. Otherwiese we must move the blocks to
> >> +        * the next free bit position.
> >> +        */
> >> +       WARN_ON(eccbits % 8);
> >> +
> >> +       memcpy(tmp_buf, fcb, sizeof(*fcb));
> >> +
> >> +       for (i = 0; i < numblocks; i++) {
> >> +               memset(ecc_buf, 0, ecc_buf_size);
> >> +               psrc = tmp_buf + i * blocksize;
> >> +               pdst = buf + i * (blocksize + ecc_buf_size);
> >> +
> >> +               /* copy data byte aligned to destination buf */
> >> +               memcpy(pdst, psrc, blocksize);
> >> +
> >> +               /*
> >> +                * imx-kobs use a modified encode_bch which reverse the
> >> +                * bit order of the data before calculating bch.
> >> +                * Do this in the buffer and use the bch lib here.
> >> +                */
> >> +               for (j = 0; j < blocksize; j++)
> >> +                       psrc[j] = reverse_bit(psrc[j]);
> >> +
> >> +               encode_bch(bch, psrc, blocksize, ecc_buf);
> >> +
> >> +               /* reverse ecc bit */
> >> +               for (j = 0; j < ecc_buf_size; j++)
> >> +                       ecc_buf[j] = reverse_bit(ecc_buf[j]);
> >> +
> >> +               /* Here eccbuf is byte aligned and we can just copy it */
> >> +               memcpy(pdst + blocksize, ecc_buf, ecc_buf_size);
> >> +       }
> >> +
> >> +       free(ecc_buf);
> >> +       free(tmp_buf);
> >> +       free_bch(bch);
> >
> > I have used kfree() instead of free() in entire nand bcb code
> > So, I think for consistency reason it should be kfree here.
> >
> > Could you please resend this patch with above mentioned changes.
> > Other than this,
>
> Thanks, will change it to kfree in v2.
>
> >
> >>
> >>   static u8 calculate_parity_13_8(u8 d)
> >>   {
> >>          u8 p = 0;
> >> @@ -231,8 +293,14 @@ static int nandbcb_update(struct mtd_info *mtd, loff_t off, size_t size,
> >>                  goto dbbt_data_page_err;
> >>          }
> >>
> >> -       memcpy(fcb_raw_page + 12, fcb, sizeof(struct fcb_block));
> >> -       encode_hamming_13_8(fcb_raw_page + 12, fcb_raw_page + 12 + 512, 512);
> >> +       if (is_mx6ul() || is_mx6ull()) {
> >> +               /* 40 bit BCH, for i.MX6UL(L) */
> >> +               encode_bch_ecc(fcb_raw_page + 32, fcb, 40);
> >> +       } else {
> >> +               memcpy(fcb_raw_page + 12, fcb, sizeof(struct fcb_block));
> >> +               encode_hamming_13_8(fcb_raw_page + 12,
> >> +                                   fcb_raw_page + 12 + 512, 512);
> >> +       }
> >>          /*
> >>           * Set the first and second byte of OOB data to 0xFF, not 0x00. These
> >>           * bytes are used as the Manufacturers Bad Block Marker (MBBM). Since
> >
> > Acked-by: Shyam Saini <shyam.saini@amarulasolutions.com>
> >
>
> --
> Thanks,
> Parthiban N
>
> DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
> Phone: (+49)-8142-66989-22 Fax: (+49)-8142-66989-80 Email: pn@denx.de
diff mbox series

Patch

diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index aeb5493488..175bed601e 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -74,6 +74,7 @@  config CMD_HDMIDETECT
 config CMD_NANDBCB
 	bool "i.MX6 NAND Boot Control Block(BCB) command"
 	depends on NAND && CMD_MTDPARTS
+	select BCH if MX6UL || MX6ULL
 	default y if ARCH_MX6 && NAND_MXS
 	help
 	  Unlike normal 'nand write/erase' commands, this command update
diff --git a/arch/arm/mach-imx/cmd_nandbcb.c b/arch/arm/mach-imx/cmd_nandbcb.c
index 065b814b2e..34176ee6e4 100644
--- a/arch/arm/mach-imx/cmd_nandbcb.c
+++ b/arch/arm/mach-imx/cmd_nandbcb.c
@@ -14,8 +14,10 @@ 
 
 #include <asm/io.h>
 #include <jffs2/jffs2.h>
+#include <linux/bch.h>
 #include <linux/mtd/mtd.h>
 
+#include <asm/arch/sys_proto.h>
 #include <asm/mach-imx/imx-nandbcb.h>
 #include <asm/mach-imx/imximage.cfg>
 #include <mxs_nand.h>
@@ -25,6 +27,66 @@ 
 #define BF_VAL(v, bf)		(((v) & bf##_MASK) >> bf##_OFFSET)
 #define GETBIT(v, n)		(((v) >> (n)) & 0x1)
 
+static uint8_t reverse_bit(uint8_t b)
+{
+	b = (b & 0xf0) >> 4 | (b & 0x0f) << 4;
+	b = (b & 0xcc) >> 2 | (b & 0x33) << 2;
+	b = (b & 0xaa) >> 1 | (b & 0x55) << 1;
+
+	return b;
+}
+
+static void encode_bch_ecc(void *buf, struct fcb_block *fcb, int eccbits)
+{
+	int i, j, m = 13;
+	int blocksize = 128;
+	int numblocks = 8;
+	int ecc_buf_size = (m * eccbits + 7) / 8;
+	struct bch_control *bch = init_bch(m, eccbits, 0);
+	u8 *ecc_buf = kzalloc(ecc_buf_size, GFP_KERNEL);
+	u8 *tmp_buf = kzalloc(blocksize * numblocks, GFP_KERNEL);
+	u8 *psrc, *pdst;
+
+	/*
+	 * The blocks here are bit aligned. If eccbits is a multiple of 8,
+	 * we just can copy bytes. Otherwiese we must move the blocks to
+	 * the next free bit position.
+	 */
+	WARN_ON(eccbits % 8);
+
+	memcpy(tmp_buf, fcb, sizeof(*fcb));
+
+	for (i = 0; i < numblocks; i++) {
+		memset(ecc_buf, 0, ecc_buf_size);
+		psrc = tmp_buf + i * blocksize;
+		pdst = buf + i * (blocksize + ecc_buf_size);
+
+		/* copy data byte aligned to destination buf */
+		memcpy(pdst, psrc, blocksize);
+
+		/*
+		 * imx-kobs use a modified encode_bch which reverse the
+		 * bit order of the data before calculating bch.
+		 * Do this in the buffer and use the bch lib here.
+		 */
+		for (j = 0; j < blocksize; j++)
+			psrc[j] = reverse_bit(psrc[j]);
+
+		encode_bch(bch, psrc, blocksize, ecc_buf);
+
+		/* reverse ecc bit */
+		for (j = 0; j < ecc_buf_size; j++)
+			ecc_buf[j] = reverse_bit(ecc_buf[j]);
+
+		/* Here eccbuf is byte aligned and we can just copy it */
+		memcpy(pdst + blocksize, ecc_buf, ecc_buf_size);
+	}
+
+	free(ecc_buf);
+	free(tmp_buf);
+	free_bch(bch);
+}
+
 static u8 calculate_parity_13_8(u8 d)
 {
 	u8 p = 0;
@@ -231,8 +293,14 @@  static int nandbcb_update(struct mtd_info *mtd, loff_t off, size_t size,
 		goto dbbt_data_page_err;
 	}
 
-	memcpy(fcb_raw_page + 12, fcb, sizeof(struct fcb_block));
-	encode_hamming_13_8(fcb_raw_page + 12, fcb_raw_page + 12 + 512, 512);
+	if (is_mx6ul() || is_mx6ull()) {
+		/* 40 bit BCH, for i.MX6UL(L) */
+		encode_bch_ecc(fcb_raw_page + 32, fcb, 40);
+	} else {
+		memcpy(fcb_raw_page + 12, fcb, sizeof(struct fcb_block));
+		encode_hamming_13_8(fcb_raw_page + 12,
+				    fcb_raw_page + 12 + 512, 512);
+	}
 	/*
 	 * Set the first and second byte of OOB data to 0xFF, not 0x00. These
 	 * bytes are used as the Manufacturers Bad Block Marker (MBBM). Since