mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* i.MX FCB NAND boot updates
@ 2015-06-12  6:35 Sascha Hauer
  2015-06-12  6:35 ` [PATCH 01/10] ARM: dts: Karo tx6: increase barebox partition to 4MB Sascha Hauer
                   ` (9 more replies)
  0 siblings, 10 replies; 11+ messages in thread
From: Sascha Hauer @ 2015-06-12  6:35 UTC (permalink / raw)
  To: Barebox List

The i.MX6 NAND boot update code can be used for i.MX28 aswell with
some modifications. This series makes the code available for i.MX28
and also has some optimizations like use of a partition to allow
for size checks.

Sascha

----------------------------------------------------------------
Sascha Hauer (10):
      ARM: dts: Karo tx6: increase barebox partition to 4MB
      mtd: partition: implement write_oob
      filetype: Add filetype for MXS bootstream
      ARM: i.MX6: bbu nand: Move to common place
      imx-bbu-nand-fcb: Fix debug messages
      imx-bbu-nand-fcb: Use barebox partition instead of whole device
      imx-bbu-nand-fcb: make available for i.MX28 aswell
      imx-bbu-nand-fcb: Let DBBT start at page 1
      imx-bbu-nand-fcb: Erase whole partition
      imx-bbu-nand-fcb: Split space for firmware in two equal regions

 arch/arm/dts/imx6dl-tx6u-801x.dts                  |   4 +-
 arch/arm/mach-imx/Kconfig                          |   9 -
 arch/arm/mach-imx/Makefile                         |   1 -
 arch/arm/mach-imx/include/mach/bbu.h               |   9 -
 common/Kconfig                                     |   8 +
 common/Makefile                                    |   1 +
 common/filetype.c                                  |   3 +
 .../imx6-bbu-nand.c => common/imx-bbu-nand-fcb.c   | 248 ++++++++++++++++-----
 drivers/mtd/partition.c                            |  13 ++
 include/bbu.h                                      |  14 ++
 include/filetype.h                                 |   1 +
 11 files changed, 239 insertions(+), 72 deletions(-)
 rename arch/arm/mach-imx/imx6-bbu-nand.c => common/imx-bbu-nand-fcb.c (69%)

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 01/10] ARM: dts: Karo tx6: increase barebox partition to 4MB
  2015-06-12  6:35 i.MX FCB NAND boot updates Sascha Hauer
@ 2015-06-12  6:35 ` Sascha Hauer
  2015-06-12  6:35 ` [PATCH 02/10] mtd: partition: implement write_oob Sascha Hauer
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Sascha Hauer @ 2015-06-12  6:35 UTC (permalink / raw)
  To: Barebox List

Due to the DBBT, multiple FCBs, two bootloaders and the possibility
of bad blocks the bootloader partition needs more space. Increase
it to 4MB.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm/dts/imx6dl-tx6u-801x.dts | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm/dts/imx6dl-tx6u-801x.dts b/arch/arm/dts/imx6dl-tx6u-801x.dts
index 43104b2..a480408 100644
--- a/arch/arm/dts/imx6dl-tx6u-801x.dts
+++ b/arch/arm/dts/imx6dl-tx6u-801x.dts
@@ -18,12 +18,12 @@
 &gpmi {
 	partition@0 {
 		label = "barebox";
-		reg = <0x0 0x100000>;
+		reg = <0x0 0x400000>;
 	};
 
 	partition@1 {
 		label = "barebox-environment";
-		reg = <0x100000 0x100000>;
+		reg = <0x400000 0x100000>;
 	};
 };
 
-- 
2.1.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 02/10] mtd: partition: implement write_oob
  2015-06-12  6:35 i.MX FCB NAND boot updates Sascha Hauer
  2015-06-12  6:35 ` [PATCH 01/10] ARM: dts: Karo tx6: increase barebox partition to 4MB Sascha Hauer
@ 2015-06-12  6:35 ` Sascha Hauer
  2015-06-12  6:35 ` [PATCH 03/10] filetype: Add filetype for MXS bootstream Sascha Hauer
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Sascha Hauer @ 2015-06-12  6:35 UTC (permalink / raw)
  To: Barebox List

To enable mtd_write_oob for partitions.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/mtd/partition.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/drivers/mtd/partition.c b/drivers/mtd/partition.c
index 98b9081..c11a3db 100644
--- a/drivers/mtd/partition.c
+++ b/drivers/mtd/partition.c
@@ -31,6 +31,16 @@ static int mtd_part_write(struct mtd_info *mtd, loff_t to, size_t len,
 					len, retlen, buf);
 }
 
+static int mtd_part_write_oob(struct mtd_info *mtd, loff_t to,
+		struct mtd_oob_ops *ops)
+{
+	if (to >= mtd->size)
+		return -EINVAL;
+	if (ops->datbuf && to + ops->len > mtd->size)
+		return -EINVAL;
+	return mtd->master->write_oob(mtd->master, to + mtd->master_offset, ops);
+}
+
 static int mtd_part_erase(struct mtd_info *mtd, struct erase_info *instr)
 {
 	int ret;
@@ -160,6 +170,9 @@ struct mtd_info *mtd_add_partition(struct mtd_info *mtd, off_t offset,
 		part->block_markbad = mtd->block_markbad ? mtd_part_block_markbad : NULL;
 	}
 
+	if (mtd->write_oob)
+		part->write_oob = mtd_part_write_oob;
+
 	part->block_isbad = mtd->block_isbad ? mtd_part_block_isbad : NULL;
 	part->size = size;
 	part->name = xstrdup(name);
-- 
2.1.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 03/10] filetype: Add filetype for MXS bootstream
  2015-06-12  6:35 i.MX FCB NAND boot updates Sascha Hauer
  2015-06-12  6:35 ` [PATCH 01/10] ARM: dts: Karo tx6: increase barebox partition to 4MB Sascha Hauer
  2015-06-12  6:35 ` [PATCH 02/10] mtd: partition: implement write_oob Sascha Hauer
@ 2015-06-12  6:35 ` Sascha Hauer
  2015-06-12  6:35 ` [PATCH 04/10] ARM: i.MX6: bbu nand: Move to common place Sascha Hauer
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Sascha Hauer @ 2015-06-12  6:35 UTC (permalink / raw)
  To: Barebox List

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 common/filetype.c  | 3 +++
 include/filetype.h | 1 +
 2 files changed, 4 insertions(+)

diff --git a/common/filetype.c b/common/filetype.c
index 25d9761..28a4b2c 100644
--- a/common/filetype.c
+++ b/common/filetype.c
@@ -60,6 +60,7 @@ static const struct filetype_str filetype_str[] = {
 			"TI OMAP CH boot image (big endian)", "ch-image-be" },
 	[filetype_xz_compressed] = { "XZ compressed", "xz" },
 	[filetype_exe] = { "MS-DOS executable", "exe" },
+	[filetype_mxs_bootstream] = { "Freescale MXS bootstream", "mxsbs" },
 };
 
 const char *file_type_to_string(enum filetype f)
@@ -292,6 +293,8 @@ enum filetype file_detect_type(const void *_buf, size_t bufsize)
 
 	if (buf8[0] == 'M' && buf8[1] == 'Z')
 		return filetype_exe;
+	if (le32_to_cpu(buf[5]) == 0x504d5453)
+		return filetype_mxs_bootstream;
 
 	if (is_barebox_arm_head(_buf))
 		return filetype_arm_barebox;
diff --git a/include/filetype.h b/include/filetype.h
index cca4dad..e452b7a 100644
--- a/include/filetype.h
+++ b/include/filetype.h
@@ -34,6 +34,7 @@ enum filetype {
 	filetype_ch_image_be,
 	filetype_exe,
 	filetype_xz_compressed,
+	filetype_mxs_bootstream,
 	filetype_max,
 };
 
-- 
2.1.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 04/10] ARM: i.MX6: bbu nand: Move to common place
  2015-06-12  6:35 i.MX FCB NAND boot updates Sascha Hauer
                   ` (2 preceding siblings ...)
  2015-06-12  6:35 ` [PATCH 03/10] filetype: Add filetype for MXS bootstream Sascha Hauer
@ 2015-06-12  6:35 ` Sascha Hauer
  2015-06-12  6:35 ` [PATCH 05/10] imx-bbu-nand-fcb: Fix debug messages Sascha Hauer
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Sascha Hauer @ 2015-06-12  6:35 UTC (permalink / raw)
  To: Barebox List

The code can be used on i.MX28 aswell, so move it to a common place.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm/mach-imx/Kconfig            |   9 -
 arch/arm/mach-imx/Makefile           |   1 -
 arch/arm/mach-imx/imx6-bbu-nand.c    | 491 -----------------------------------
 arch/arm/mach-imx/include/mach/bbu.h |   9 -
 common/Kconfig                       |   8 +
 common/Makefile                      |   1 +
 common/imx-bbu-nand-fcb.c            | 491 +++++++++++++++++++++++++++++++++++
 include/bbu.h                        |   9 +
 8 files changed, 509 insertions(+), 510 deletions(-)
 delete mode 100644 arch/arm/mach-imx/imx6-bbu-nand.c
 create mode 100644 common/imx-bbu-nand-fcb.c

diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index c713477..812a9f9 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -112,15 +112,6 @@ config BAREBOX_UPDATE_IMX_EXTERNAL_NAND
 	depends on MTD_WRITE
 	default y
 
-config BAREBOX_UPDATE_IMX6_NAND
-	bool
-	depends on ARCH_IMX6
-	depends on BAREBOX_UPDATE
-	depends on MTD
-	depends on MTD_WRITE
-	depends on NAND_MXS
-	default y
-
 comment "Freescale i.MX System-on-Chip"
 
 config ARCH_IMX1
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index ae953b1..0c8ca4b 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -21,6 +21,5 @@ obj-y += devices.o imx.o esdctl.o
 obj-y += boot.o
 obj-$(CONFIG_BAREBOX_UPDATE) += imx-bbu-internal.o
 obj-$(CONFIG_BAREBOX_UPDATE_IMX_EXTERNAL_NAND) += imx-bbu-external-nand.o
-obj-$(CONFIG_BAREBOX_UPDATE_IMX6_NAND) += imx6-bbu-nand.o
 pbl-y += esdctl.o
 lwl-y += cpu_init.o
diff --git a/arch/arm/mach-imx/imx6-bbu-nand.c b/arch/arm/mach-imx/imx6-bbu-nand.c
deleted file mode 100644
index d2bfedb..0000000
--- a/arch/arm/mach-imx/imx6-bbu-nand.c
+++ /dev/null
@@ -1,491 +0,0 @@
-/*
- * Copyright (C) 2014 Sascha Hauer, Pengutronix
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation.
- *
- */
-
-#define pr_fmt(fmt) "imx6-bbu-nand: " fmt
-
-#include <filetype.h>
-#include <common.h>
-#include <malloc.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <ioctl.h>
-#include <linux/sizes.h>
-#include <bbu.h>
-#include <fs.h>
-#include <mach/bbu.h>
-#include <linux/mtd/mtd-abi.h>
-#include <linux/mtd/nand_mxs.h>
-#include <linux/mtd/mtd.h>
-#include <linux/stat.h>
-
-struct dbbt_block {
-	uint32_t Checksum;
-	uint32_t FingerPrint;
-	uint32_t Version;
-	uint32_t reserved;
-	uint32_t DBBTNumOfPages;
-};
-
-struct fcb_block {
-	uint32_t Checksum;		/* First fingerprint in first byte */
-	uint32_t FingerPrint;		/* 2nd fingerprint at byte 4 */
-	uint32_t Version;		/* 3rd fingerprint at byte 8 */
-	uint8_t DataSetup;
-	uint8_t DataHold;
-	uint8_t AddressSetup;
-	uint8_t DSAMPLE_TIME;
-	/* These are for application use only and not for ROM. */
-	uint8_t NandTimingState;
-	uint8_t REA;
-	uint8_t RLOH;
-	uint8_t RHOH;
-	uint32_t PageDataSize;		/* 2048 for 2K pages, 4096 for 4K pages */
-	uint32_t TotalPageSize;		/* 2112 for 2K pages, 4314 for 4K pages */
-	uint32_t SectorsPerBlock;	/* Number of 2K sections per block */
-	uint32_t NumberOfNANDs;		/* Total Number of NANDs - not used by ROM */
-	uint32_t TotalInternalDie;	/* Number of separate chips in this NAND */
-	uint32_t CellType;		/* MLC or SLC */
-	uint32_t EccBlockNEccType;	/* Type of ECC, can be one of BCH-0-20 */
-	uint32_t EccBlock0Size;		/* Number of bytes for Block0 - BCH */
-	uint32_t EccBlockNSize;		/* Block size in bytes for all blocks other than Block0 - BCH */
-	uint32_t EccBlock0EccType;	/* Ecc level for Block 0 - BCH */
-	uint32_t MetadataBytes;		/* Metadata size - BCH */
-	uint32_t NumEccBlocksPerPage;	/* Number of blocks per page for ROM use - BCH */
-	uint32_t EccBlockNEccLevelSDK;	/* Type of ECC, can be one of BCH-0-20 */
-	uint32_t EccBlock0SizeSDK;	/* Number of bytes for Block0 - BCH */
-	uint32_t EccBlockNSizeSDK;	/* Block size in bytes for all blocks other than Block0 - BCH */
-	uint32_t EccBlock0EccLevelSDK;	/* Ecc level for Block 0 - BCH */
-	uint32_t NumEccBlocksPerPageSDK;/* Number of blocks per page for SDK use - BCH */
-	uint32_t MetadataBytesSDK;	/* Metadata size - BCH */
-	uint32_t EraseThreshold;	/* To set into BCH_MODE register */
-	uint32_t BootPatch;		/* 0 for normal boot and 1 to load patch starting next to FCB */
-	uint32_t PatchSectors;		/* Size of patch in sectors */
-	uint32_t Firmware1_startingPage;/* Firmware image starts on this sector */
-	uint32_t Firmware2_startingPage;/* Secondary FW Image starting Sector */
-	uint32_t PagesInFirmware1;	/* Number of sectors in firmware image */
-	uint32_t PagesInFirmware2;	/* Number of sector in secondary FW image */
-	uint32_t DBBTSearchAreaStartAddress; /* Page address where dbbt search area begins */
-	uint32_t BadBlockMarkerByte;	/* Byte in page data that have manufacturer marked bad block marker, */
-					/* this will be swapped with metadata[0] to complete page data. */
-	uint32_t BadBlockMarkerStartBit;/* For BCH ECC sizes other than 8 and 16 the bad block marker does not */
-					/* start at 0th bit of BadBlockMarkerByte. This field is used to get to */
-					/* the start bit of bad block marker byte with in BadBlockMarkerByte */
-	uint32_t BBMarkerPhysicalOffset;/* FCB value that gives byte offset for bad block marker on physical NAND page */
-	uint32_t BCHType;
-
-	uint32_t TMTiming2_ReadLatency;
-	uint32_t TMTiming2_PreambleDelay;
-	uint32_t TMTiming2_CEDelay;
-	uint32_t TMTiming2_PostambleDelay;
-	uint32_t TMTiming2_CmdAddPause;
-	uint32_t TMTiming2_DataPause;
-	uint32_t TMSpeed;
-	uint32_t TMTiming1_BusyTimeout;
-
-	uint32_t DISBBM;	/* the flag to enable (1)/disable(0) bi swap */
-	uint32_t BBMarkerPhysicalOffsetInSpareData; /* The swap position of main area in spare area */
-};
-
-#define BF_VAL(v, bf)		(((v) & bf##_MASK) >> bf##_OFFSET)
-#define GETBIT(v,n)	(((v) >> (n)) & 0x1)
-
-static uint8_t calculate_parity_13_8(uint8_t d)
-{
-	uint8_t p = 0;
-
-	p |= (GETBIT(d, 6) ^ GETBIT(d, 5) ^ GETBIT(d, 3) ^ GETBIT(d, 2))		 << 0;
-	p |= (GETBIT(d, 7) ^ GETBIT(d, 5) ^ GETBIT(d, 4) ^ GETBIT(d, 2) ^ GETBIT(d, 1)) << 1;
-	p |= (GETBIT(d, 7) ^ GETBIT(d, 6) ^ GETBIT(d, 5) ^ GETBIT(d, 1) ^ GETBIT(d, 0)) << 2;
-	p |= (GETBIT(d, 7) ^ GETBIT(d, 4) ^ GETBIT(d, 3) ^ GETBIT(d, 0))		 << 3;
-	p |= (GETBIT(d, 6) ^ GETBIT(d, 4) ^ GETBIT(d, 3) ^ GETBIT(d, 2) ^ GETBIT(d, 1) ^ GETBIT(d, 0)) << 4;
-	return p;
-}
-
-static void encode_hamming_13_8(void *_src, void *_ecc, size_t size)
-{
-	int i;
-	uint8_t *src = _src;
-	uint8_t *ecc = _ecc;
-
-	for (i = 0; i < size; i++)
-		ecc[i] = calculate_parity_13_8(src[i]);
-}
-
-static uint32_t calc_chksum(void *buf, size_t size)
-{
-	u32 chksum = 0;
-	u8 *bp = buf;
-	size_t i;
-
-	for (i = 0; i < size; i++)
-		chksum += bp[i];
-
-	return ~chksum;
-}
-
-static __maybe_unused void dump_fcb(void *buf)
-{
-	struct fcb_block *fcb = buf;
-
-	pr_debug("Checksum:                   0x%08x\n", fcb->Checksum);
-	pr_debug("FingerPrint:                0x%08x\n", fcb->FingerPrint);
-	pr_debug("Version:                    0x%08x\n", fcb->Version);
-	pr_debug("DataSetup:                  0x%02x\n", fcb->DataSetup);
-	pr_debug("DataHold:                   0x%02x\n", fcb->DataHold);
-	pr_debug("AddressSetup:               0x%02x\n", fcb->AddressSetup);
-	pr_debug("DSAMPLE_TIME:               0x%02x\n", fcb->DSAMPLE_TIME);
-	pr_debug("NandTimingState:            0x%02x\n", fcb->NandTimingState);
-	pr_debug("REA:                        0x%02x\n", fcb->REA);
-	pr_debug("RLOH:                       0x%02x\n", fcb->RLOH);
-	pr_debug("RHOH:                       0x%02x\n", fcb->RHOH);
-	pr_debug("PageDataSize:               0x%08x\n", fcb->PageDataSize);
-	pr_debug("TotalPageSize:              0x%08x\n", fcb->TotalPageSize);
-	pr_debug("SectorsPerBlock:            0x%08x\n", fcb->SectorsPerBlock);
-	pr_debug("NumberOfNANDs:              0x%08x\n", fcb->NumberOfNANDs);
-	pr_debug("TotalInternalDie:           0x%08x\n", fcb->TotalInternalDie);
-	pr_debug("CellType:                   0x%08x\n", fcb->CellType);
-	pr_debug("EccBlockNEccType:           0x%08x\n", fcb->EccBlockNEccType);
-	pr_debug("EccBlock0Size:              0x%08x\n", fcb->EccBlock0Size);
-	pr_debug("EccBlockNSize:              0x%08x\n", fcb->EccBlockNSize);
-	pr_debug("EccBlock0EccType:           0x%08x\n", fcb->EccBlock0EccType);
-	pr_debug("MetadataBytes:              0x%08x\n", fcb->MetadataBytes);
-	pr_debug("NumEccBlocksPerPage:        0x%08x\n", fcb->NumEccBlocksPerPage);
-	pr_debug("EccBlockNEccLevelSDK:       0x%08x\n", fcb->EccBlockNEccLevelSDK);
-	pr_debug("EccBlock0SizeSDK:           0x%08x\n", fcb->EccBlock0SizeSDK);
-	pr_debug("EccBlockNSizeSDK:           0x%08x\n", fcb->EccBlockNSizeSDK);
-	pr_debug("EccBlock0EccLevelSDK:       0x%08x\n", fcb->EccBlock0EccLevelSDK);
-	pr_debug("NumEccBlocksPerPageSDK:     0x%08x\n", fcb->NumEccBlocksPerPageSDK);
-	pr_debug("MetadataBytesSDK:           0x%08x\n", fcb->MetadataBytesSDK);
-	pr_debug("EraseThreshold:             0x%08x\n", fcb->EraseThreshold);
-	pr_debug("BootPatch:                  0x%08x\n", fcb->BootPatch);
-	pr_debug("PatchSectors:               0x%08x\n", fcb->PatchSectors);
-	pr_debug("Firmware1_startingPage:     0x%08x\n", fcb->Firmware1_startingPage);
-	pr_debug("Firmware2_startingPage:     0x%08x\n", fcb->Firmware2_startingPage);
-	pr_debug("PagesInFirmware1:           0x%08x\n", fcb->PagesInFirmware1);
-	pr_debug("PagesInFirmware2:           0x%08x\n", fcb->PagesInFirmware2);
-	pr_debug("DBBTSearchAreaStartAddress: 0x%08x\n", fcb->DBBTSearchAreaStartAddress);
-	pr_debug("BadBlockMarkerByte:         0x%08x\n", fcb->BadBlockMarkerByte);
-	pr_debug("BadBlockMarkerStartBit:     0x%08x\n", fcb->BadBlockMarkerStartBit);
-	pr_debug("BBMarkerPhysicalOffset:     0x%08x\n", fcb->BBMarkerPhysicalOffset);
-	pr_debug("BCHType:                    0x%08x\n", fcb->BCHType);
-	pr_debug("TMTiming2_ReadLatency:      0x%08x\n", fcb->TMTiming2_ReadLatency);
-	pr_debug("TMTiming2_PreambleDelay:    0x%08x\n", fcb->TMTiming2_PreambleDelay);
-	pr_debug("TMTiming2_CEDelay:          0x%08x\n", fcb->TMTiming2_CEDelay);
-	pr_debug("TMTiming2_PostambleDelay:   0x%08x\n", fcb->TMTiming2_PostambleDelay);
-	pr_debug("TMTiming2_CmdAddPause:      0x%08x\n", fcb->TMTiming2_CmdAddPause);
-	pr_debug("TMTiming2_DataPause:        0x%08x\n", fcb->TMTiming2_DataPause);
-	pr_debug("TMSpeed:                    0x%08x\n", fcb->TMSpeed);
-	pr_debug("TMTiming1_BusyTimeout:      0x%08x\n", fcb->TMTiming1_BusyTimeout);
-	pr_debug("DISBBM:                     0x%08x\n", fcb->DISBBM);
-	pr_debug("BBMarkerPhysOfsInSpareData: 0x%08x\n", fcb->BBMarkerPhysicalOffsetInSpareData);
-}
-
-static __maybe_unused ssize_t raw_read_page(struct mtd_info *mtd, void *dst, loff_t offset)
-{
-	struct mtd_oob_ops ops;
-	ssize_t ret;
-
-	ops.mode = MTD_OPS_RAW;
-	ops.ooboffs = 0;
-	ops.datbuf = dst;
-	ops.len = mtd->writesize;
-	ops.oobbuf = dst + mtd->writesize;
-	ops.ooblen = mtd->oobsize;
-	ret = mtd_read_oob(mtd, offset, &ops);
-
-        return ret;
-}
-
-static ssize_t raw_write_page(struct mtd_info *mtd, void *buf, loff_t offset)
-{
-	struct mtd_oob_ops ops;
-	ssize_t ret;
-
-	ops.mode = MTD_OPS_RAW;
-	ops.ooboffs = 0;
-	ops.datbuf = buf;
-	ops.len = mtd->writesize;
-	ops.oobbuf = buf + mtd->writesize;
-	ops.ooblen = mtd->oobsize;
-	ret = mtd_write_oob(mtd, offset, &ops);
-
-        return ret;
-}
-
-static int fcb_create(struct fcb_block *fcb, struct mtd_info *mtd)
-{
-	fcb->FingerPrint = 0x20424346;
-	fcb->Version = 0x01000000;
-	fcb->PageDataSize = mtd->writesize;
-	fcb->TotalPageSize = mtd->writesize + mtd->oobsize;
-	fcb->SectorsPerBlock = mtd->erasesize / mtd->writesize;
-
-	/* Divide ECC strength by two and save the value into FCB structure. */
-	fcb->EccBlock0EccType =
-		mxs_nand_get_ecc_strength(mtd->writesize, mtd->oobsize) >> 1;
-	fcb->EccBlockNEccType = fcb->EccBlock0EccType;
-
-	/* Also hardcoded in kobs-ng */
-	fcb->DataSetup = 80;
-	fcb->DataHold = 60;
-	fcb->AddressSetup = 25;
-	fcb->DSAMPLE_TIME = 6;
-	fcb->MetadataBytes = 0x0000000a;
-	fcb->EccBlock0Size = 0x00000200;
-	fcb->EccBlockNSize = 0x00000200;
-
-	fcb->NumEccBlocksPerPage = mtd->writesize / fcb->EccBlock0Size - 1;
-
-	/* DBBT search area starts at third block */
-	fcb->DBBTSearchAreaStartAddress = mtd->erasesize / mtd->writesize * 2;
-
-	fcb->BadBlockMarkerByte = mxs_nand_mark_byte_offset(mtd);
-	fcb->BadBlockMarkerStartBit = mxs_nand_mark_bit_offset(mtd);
-
-	fcb->BBMarkerPhysicalOffset = mtd->writesize;
-
-	fcb->Checksum = calc_chksum((void *)fcb + 4, sizeof(*fcb) - 4);
-
-	return 0;
-}
-
-static int imx6_bbu_erase(struct mtd_info *mtd)
-{
-	uint64_t offset = 0;
-	int len = SZ_2M;
-	struct erase_info erase;
-	int ret;
-
-	while (len > 0) {
-		pr_debug("erasing at 0x%08llx\n", offset);
-		if (mtd_block_isbad(mtd, offset)) {
-			offset += mtd->erasesize;
-			pr_debug("erase skip block @ 0x%08llx\n", offset);
-			continue;
-		}
-
-		memset(&erase, 0, sizeof(erase));
-		erase.addr = offset;
-		erase.len = mtd->erasesize;
-
-		ret = mtd_erase(mtd, &erase);
-		if (ret)
-			return ret;
-
-		offset += mtd->erasesize;
-		len -= mtd->erasesize;
-	}
-
-	return 0;
-}
-
-static int imx6_bbu_write_firmware(struct mtd_info *mtd, int block, void *buf, size_t len)
-{
-	uint64_t offset = block * mtd->erasesize;
-	int ret;
-	size_t written;
-
-	while (len > 0) {
-		int now = min(len, mtd->erasesize);
-
-		pr_debug("writing %p at 0x%08llx, left 0x%08x\n",
-				buf, offset, len);
-
-		if (mtd_block_isbad(mtd, offset)) {
-			offset += mtd->erasesize;
-			block++;
-			pr_debug("write skip block @ 0x%08llx\n", offset);
-			continue;
-		}
-
-		ret = mtd_write(mtd, offset, now, &written, buf);
-		if (ret)
-			return ret;
-
-		offset += now;
-		len -= now;
-		buf += now;
-		block++;
-	}
-
-	return block;
-}
-
-static int dbbt_data_create(struct mtd_info *mtd, void *buf, int block_last)
-{
-	int n;
-	int n_bad_blocks = 0;
-	uint32_t *bb = buf + 0x8;
-	uint32_t *n_bad_blocksp = buf + 0x4;
-
-	for (n = 0; n <= block_last; n++) {
-		loff_t offset = n * mtd->erasesize;
-		if (mtd_block_isbad(mtd, offset)) {
-			n_bad_blocks++;
-			*bb = n;
-			bb++;
-		}
-	}
-
-	*n_bad_blocksp = n_bad_blocks;
-
-	return n_bad_blocks;
-}
-
-static int imx6_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *data)
-{
-	struct cdev *bcb_cdev;
-	struct mtd_info *mtd;
-	int ret, block_fw1, block_fw2, block_last;
-	struct fcb_block *fcb;
-	struct dbbt_block *dbbt;
-	void *fcb_raw_page, *dbbt_page, *dbbt_data_page;
-	void *ecc;
-	int written;
-	void *fw;
-	unsigned fw_size;
-	int i;
-
-	if (file_detect_type(data->image, data->len) != filetype_arm_barebox &&
-			!bbu_force(data, "Not an ARM barebox image"))
-		return -EINVAL;
-
-	ret = bbu_confirm(data);
-	if (ret)
-		return ret;
-
-	bcb_cdev = cdev_by_name("nand0");
-	if (!bcb_cdev) {
-		pr_err("%s: No FCB device!\n", __func__);
-		return -ENODEV;
-	}
-
-	mtd = bcb_cdev->mtd;
-
-	fcb_raw_page = xzalloc(mtd->writesize + mtd->oobsize);
-
-	fcb = fcb_raw_page + 12;
-	ecc = fcb_raw_page + 512 + 12;
-
-	dbbt_page = xzalloc(mtd->writesize);
-	dbbt_data_page = xzalloc(mtd->writesize);
-	dbbt = dbbt_page;
-
-	/*
-	 * We have to write one additional page to make the ROM happy.
-	 * Maybe the PagesInFirmwarex fields are really the number of pages - 1.
-	 * kobs-ng has the same.
-	 */
-	fw_size = ALIGN(data->len + mtd->writesize, mtd->writesize);
-	fw = xzalloc(fw_size);
-	memcpy(fw, data->image, data->len);
-
-	block_fw1 = 4;
-
-	ret = imx6_bbu_erase(mtd);
-	if (ret)
-		goto out;
-
-	ret = imx6_bbu_write_firmware(mtd, block_fw1, fw, fw_size);
-	if (ret < 0)
-		goto out;
-
-	block_fw2 = ret;
-
-	ret = imx6_bbu_write_firmware(mtd, block_fw2, fw, fw_size);
-	if (ret < 0)
-		goto out;
-
-	block_last = ret;
-
-	fcb->Firmware1_startingPage = block_fw1 * mtd->erasesize / mtd->writesize;
-	fcb->Firmware2_startingPage = block_fw2 * mtd->erasesize / mtd->writesize;
-	fcb->PagesInFirmware1 = ALIGN(data->len, mtd->writesize) / mtd->writesize;
-	fcb->PagesInFirmware2 = fcb->PagesInFirmware1;
-
-	fcb_create(fcb, mtd);
-	encode_hamming_13_8(fcb, ecc, 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
-	 * the FCB is mostly written to the first page in a block, a scan for
-	 * factory bad blocks will detect these blocks as bad, e.g. when
-	 * function nand_scan_bbt() is executed to build a new bad block table.
-	 */
-	memset(fcb_raw_page + mtd->writesize, 0xFF, 2);
-
-	ret = raw_write_page(mtd, fcb_raw_page, 0);
-	if (ret)
-		goto out;
-
-	ret = raw_write_page(mtd, fcb_raw_page, mtd->erasesize);
-	if (ret)
-		goto out;
-
-	dbbt->Checksum = 0;
-	dbbt->FingerPrint = 0x54424244;
-	dbbt->Version = 0x01000000;
-
-	ret = dbbt_data_create(mtd, dbbt_data_page, block_last);
-	if (ret < 0)
-		goto out;
-
-	if (ret > 0)
-		dbbt->DBBTNumOfPages = 1;
-
-	for (i = 2; i < 4; i++) {
-		ret = mtd_write(mtd, mtd->erasesize * i, 2048, &written, dbbt_page);
-		if (ret)
-			goto out;
-
-		if (dbbt->DBBTNumOfPages > 0) {
-			ret = mtd_write(mtd, mtd->erasesize * i + mtd->writesize * 4,
-					2048, &written, dbbt_data_page);
-			if (ret)
-				goto out;
-		}
-	}
-
-out:
-	free(dbbt_page);
-	free(dbbt_data_page);
-	free(fcb_raw_page);
-	free(fw);
-
-	return ret;
-}
-
-int imx6_bbu_nand_register_handler(const char *name, unsigned long flags)
-{
-	struct bbu_handler *handler;
-	int ret;
-
-	handler = xzalloc(sizeof(*handler));
-	handler->devicefile = "/dev/nand0";
-	handler->name = name;
-	handler->flags = flags;
-	handler->handler = imx6_bbu_nand_update;
-
-	ret = bbu_register_handler(handler);
-	if (ret)
-		free(handler);
-
-	return ret;
-}
diff --git a/arch/arm/mach-imx/include/mach/bbu.h b/arch/arm/mach-imx/include/mach/bbu.h
index 5eb9a47..8039091 100644
--- a/arch/arm/mach-imx/include/mach/bbu.h
+++ b/arch/arm/mach-imx/include/mach/bbu.h
@@ -75,15 +75,6 @@ static inline int imx_bbu_external_nor_register_handler(const char *name, char *
 }
 #endif
 
-#if defined(CONFIG_BAREBOX_UPDATE_IMX6_NAND)
-int imx6_bbu_nand_register_handler(const char *name, unsigned long flags);
-#else
-static inline int imx6_bbu_nand_register_handler(const char *name, unsigned long flags)
-{
-	return -ENOSYS;
-}
-#endif
-
 #if defined(CONFIG_BAREBOX_UPDATE_IMX_EXTERNAL_NAND)
 int imx_bbu_external_nand_register_handler(const char *name, char *devicefile,
 		unsigned long flags);
diff --git a/common/Kconfig b/common/Kconfig
index 1c5d14c..0ebfe1e 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -94,6 +94,14 @@ config EFI_DEVICEPATH
 config FILE_LIST
 	bool
 
+config BAREBOX_UPDATE_IMX_NAND_FCB
+	bool
+	depends on ARCH_IMX6
+	depends on BAREBOX_UPDATE
+	depends on MTD_WRITE
+	depends on NAND_MXS
+	default y
+
 menu "General Settings"
 
 config LOCALVERSION
diff --git a/common/Makefile b/common/Makefile
index 2738238..74801f7 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -52,6 +52,7 @@ lwl-$(CONFIG_IMD)		+= imd-barebox.o
 obj-$(CONFIG_IMD)		+= imd.o
 obj-$(CONFIG_FILE_LIST)		+= file-list.o
 obj-$(CONFIG_FIRMWARE)		+= firmware.o
+obj-$(CONFIG_BAREBOX_UPDATE_IMX_NAND_FCB) += imx-bbu-nand-fcb.o
 
 quiet_cmd_pwd_h = PWDH    $@
 ifdef CONFIG_PASSWORD
diff --git a/common/imx-bbu-nand-fcb.c b/common/imx-bbu-nand-fcb.c
new file mode 100644
index 0000000..d2bfedb
--- /dev/null
+++ b/common/imx-bbu-nand-fcb.c
@@ -0,0 +1,491 @@
+/*
+ * Copyright (C) 2014 Sascha Hauer, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation.
+ *
+ */
+
+#define pr_fmt(fmt) "imx6-bbu-nand: " fmt
+
+#include <filetype.h>
+#include <common.h>
+#include <malloc.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <ioctl.h>
+#include <linux/sizes.h>
+#include <bbu.h>
+#include <fs.h>
+#include <mach/bbu.h>
+#include <linux/mtd/mtd-abi.h>
+#include <linux/mtd/nand_mxs.h>
+#include <linux/mtd/mtd.h>
+#include <linux/stat.h>
+
+struct dbbt_block {
+	uint32_t Checksum;
+	uint32_t FingerPrint;
+	uint32_t Version;
+	uint32_t reserved;
+	uint32_t DBBTNumOfPages;
+};
+
+struct fcb_block {
+	uint32_t Checksum;		/* First fingerprint in first byte */
+	uint32_t FingerPrint;		/* 2nd fingerprint at byte 4 */
+	uint32_t Version;		/* 3rd fingerprint at byte 8 */
+	uint8_t DataSetup;
+	uint8_t DataHold;
+	uint8_t AddressSetup;
+	uint8_t DSAMPLE_TIME;
+	/* These are for application use only and not for ROM. */
+	uint8_t NandTimingState;
+	uint8_t REA;
+	uint8_t RLOH;
+	uint8_t RHOH;
+	uint32_t PageDataSize;		/* 2048 for 2K pages, 4096 for 4K pages */
+	uint32_t TotalPageSize;		/* 2112 for 2K pages, 4314 for 4K pages */
+	uint32_t SectorsPerBlock;	/* Number of 2K sections per block */
+	uint32_t NumberOfNANDs;		/* Total Number of NANDs - not used by ROM */
+	uint32_t TotalInternalDie;	/* Number of separate chips in this NAND */
+	uint32_t CellType;		/* MLC or SLC */
+	uint32_t EccBlockNEccType;	/* Type of ECC, can be one of BCH-0-20 */
+	uint32_t EccBlock0Size;		/* Number of bytes for Block0 - BCH */
+	uint32_t EccBlockNSize;		/* Block size in bytes for all blocks other than Block0 - BCH */
+	uint32_t EccBlock0EccType;	/* Ecc level for Block 0 - BCH */
+	uint32_t MetadataBytes;		/* Metadata size - BCH */
+	uint32_t NumEccBlocksPerPage;	/* Number of blocks per page for ROM use - BCH */
+	uint32_t EccBlockNEccLevelSDK;	/* Type of ECC, can be one of BCH-0-20 */
+	uint32_t EccBlock0SizeSDK;	/* Number of bytes for Block0 - BCH */
+	uint32_t EccBlockNSizeSDK;	/* Block size in bytes for all blocks other than Block0 - BCH */
+	uint32_t EccBlock0EccLevelSDK;	/* Ecc level for Block 0 - BCH */
+	uint32_t NumEccBlocksPerPageSDK;/* Number of blocks per page for SDK use - BCH */
+	uint32_t MetadataBytesSDK;	/* Metadata size - BCH */
+	uint32_t EraseThreshold;	/* To set into BCH_MODE register */
+	uint32_t BootPatch;		/* 0 for normal boot and 1 to load patch starting next to FCB */
+	uint32_t PatchSectors;		/* Size of patch in sectors */
+	uint32_t Firmware1_startingPage;/* Firmware image starts on this sector */
+	uint32_t Firmware2_startingPage;/* Secondary FW Image starting Sector */
+	uint32_t PagesInFirmware1;	/* Number of sectors in firmware image */
+	uint32_t PagesInFirmware2;	/* Number of sector in secondary FW image */
+	uint32_t DBBTSearchAreaStartAddress; /* Page address where dbbt search area begins */
+	uint32_t BadBlockMarkerByte;	/* Byte in page data that have manufacturer marked bad block marker, */
+					/* this will be swapped with metadata[0] to complete page data. */
+	uint32_t BadBlockMarkerStartBit;/* For BCH ECC sizes other than 8 and 16 the bad block marker does not */
+					/* start at 0th bit of BadBlockMarkerByte. This field is used to get to */
+					/* the start bit of bad block marker byte with in BadBlockMarkerByte */
+	uint32_t BBMarkerPhysicalOffset;/* FCB value that gives byte offset for bad block marker on physical NAND page */
+	uint32_t BCHType;
+
+	uint32_t TMTiming2_ReadLatency;
+	uint32_t TMTiming2_PreambleDelay;
+	uint32_t TMTiming2_CEDelay;
+	uint32_t TMTiming2_PostambleDelay;
+	uint32_t TMTiming2_CmdAddPause;
+	uint32_t TMTiming2_DataPause;
+	uint32_t TMSpeed;
+	uint32_t TMTiming1_BusyTimeout;
+
+	uint32_t DISBBM;	/* the flag to enable (1)/disable(0) bi swap */
+	uint32_t BBMarkerPhysicalOffsetInSpareData; /* The swap position of main area in spare area */
+};
+
+#define BF_VAL(v, bf)		(((v) & bf##_MASK) >> bf##_OFFSET)
+#define GETBIT(v,n)	(((v) >> (n)) & 0x1)
+
+static uint8_t calculate_parity_13_8(uint8_t d)
+{
+	uint8_t p = 0;
+
+	p |= (GETBIT(d, 6) ^ GETBIT(d, 5) ^ GETBIT(d, 3) ^ GETBIT(d, 2))		 << 0;
+	p |= (GETBIT(d, 7) ^ GETBIT(d, 5) ^ GETBIT(d, 4) ^ GETBIT(d, 2) ^ GETBIT(d, 1)) << 1;
+	p |= (GETBIT(d, 7) ^ GETBIT(d, 6) ^ GETBIT(d, 5) ^ GETBIT(d, 1) ^ GETBIT(d, 0)) << 2;
+	p |= (GETBIT(d, 7) ^ GETBIT(d, 4) ^ GETBIT(d, 3) ^ GETBIT(d, 0))		 << 3;
+	p |= (GETBIT(d, 6) ^ GETBIT(d, 4) ^ GETBIT(d, 3) ^ GETBIT(d, 2) ^ GETBIT(d, 1) ^ GETBIT(d, 0)) << 4;
+	return p;
+}
+
+static void encode_hamming_13_8(void *_src, void *_ecc, size_t size)
+{
+	int i;
+	uint8_t *src = _src;
+	uint8_t *ecc = _ecc;
+
+	for (i = 0; i < size; i++)
+		ecc[i] = calculate_parity_13_8(src[i]);
+}
+
+static uint32_t calc_chksum(void *buf, size_t size)
+{
+	u32 chksum = 0;
+	u8 *bp = buf;
+	size_t i;
+
+	for (i = 0; i < size; i++)
+		chksum += bp[i];
+
+	return ~chksum;
+}
+
+static __maybe_unused void dump_fcb(void *buf)
+{
+	struct fcb_block *fcb = buf;
+
+	pr_debug("Checksum:                   0x%08x\n", fcb->Checksum);
+	pr_debug("FingerPrint:                0x%08x\n", fcb->FingerPrint);
+	pr_debug("Version:                    0x%08x\n", fcb->Version);
+	pr_debug("DataSetup:                  0x%02x\n", fcb->DataSetup);
+	pr_debug("DataHold:                   0x%02x\n", fcb->DataHold);
+	pr_debug("AddressSetup:               0x%02x\n", fcb->AddressSetup);
+	pr_debug("DSAMPLE_TIME:               0x%02x\n", fcb->DSAMPLE_TIME);
+	pr_debug("NandTimingState:            0x%02x\n", fcb->NandTimingState);
+	pr_debug("REA:                        0x%02x\n", fcb->REA);
+	pr_debug("RLOH:                       0x%02x\n", fcb->RLOH);
+	pr_debug("RHOH:                       0x%02x\n", fcb->RHOH);
+	pr_debug("PageDataSize:               0x%08x\n", fcb->PageDataSize);
+	pr_debug("TotalPageSize:              0x%08x\n", fcb->TotalPageSize);
+	pr_debug("SectorsPerBlock:            0x%08x\n", fcb->SectorsPerBlock);
+	pr_debug("NumberOfNANDs:              0x%08x\n", fcb->NumberOfNANDs);
+	pr_debug("TotalInternalDie:           0x%08x\n", fcb->TotalInternalDie);
+	pr_debug("CellType:                   0x%08x\n", fcb->CellType);
+	pr_debug("EccBlockNEccType:           0x%08x\n", fcb->EccBlockNEccType);
+	pr_debug("EccBlock0Size:              0x%08x\n", fcb->EccBlock0Size);
+	pr_debug("EccBlockNSize:              0x%08x\n", fcb->EccBlockNSize);
+	pr_debug("EccBlock0EccType:           0x%08x\n", fcb->EccBlock0EccType);
+	pr_debug("MetadataBytes:              0x%08x\n", fcb->MetadataBytes);
+	pr_debug("NumEccBlocksPerPage:        0x%08x\n", fcb->NumEccBlocksPerPage);
+	pr_debug("EccBlockNEccLevelSDK:       0x%08x\n", fcb->EccBlockNEccLevelSDK);
+	pr_debug("EccBlock0SizeSDK:           0x%08x\n", fcb->EccBlock0SizeSDK);
+	pr_debug("EccBlockNSizeSDK:           0x%08x\n", fcb->EccBlockNSizeSDK);
+	pr_debug("EccBlock0EccLevelSDK:       0x%08x\n", fcb->EccBlock0EccLevelSDK);
+	pr_debug("NumEccBlocksPerPageSDK:     0x%08x\n", fcb->NumEccBlocksPerPageSDK);
+	pr_debug("MetadataBytesSDK:           0x%08x\n", fcb->MetadataBytesSDK);
+	pr_debug("EraseThreshold:             0x%08x\n", fcb->EraseThreshold);
+	pr_debug("BootPatch:                  0x%08x\n", fcb->BootPatch);
+	pr_debug("PatchSectors:               0x%08x\n", fcb->PatchSectors);
+	pr_debug("Firmware1_startingPage:     0x%08x\n", fcb->Firmware1_startingPage);
+	pr_debug("Firmware2_startingPage:     0x%08x\n", fcb->Firmware2_startingPage);
+	pr_debug("PagesInFirmware1:           0x%08x\n", fcb->PagesInFirmware1);
+	pr_debug("PagesInFirmware2:           0x%08x\n", fcb->PagesInFirmware2);
+	pr_debug("DBBTSearchAreaStartAddress: 0x%08x\n", fcb->DBBTSearchAreaStartAddress);
+	pr_debug("BadBlockMarkerByte:         0x%08x\n", fcb->BadBlockMarkerByte);
+	pr_debug("BadBlockMarkerStartBit:     0x%08x\n", fcb->BadBlockMarkerStartBit);
+	pr_debug("BBMarkerPhysicalOffset:     0x%08x\n", fcb->BBMarkerPhysicalOffset);
+	pr_debug("BCHType:                    0x%08x\n", fcb->BCHType);
+	pr_debug("TMTiming2_ReadLatency:      0x%08x\n", fcb->TMTiming2_ReadLatency);
+	pr_debug("TMTiming2_PreambleDelay:    0x%08x\n", fcb->TMTiming2_PreambleDelay);
+	pr_debug("TMTiming2_CEDelay:          0x%08x\n", fcb->TMTiming2_CEDelay);
+	pr_debug("TMTiming2_PostambleDelay:   0x%08x\n", fcb->TMTiming2_PostambleDelay);
+	pr_debug("TMTiming2_CmdAddPause:      0x%08x\n", fcb->TMTiming2_CmdAddPause);
+	pr_debug("TMTiming2_DataPause:        0x%08x\n", fcb->TMTiming2_DataPause);
+	pr_debug("TMSpeed:                    0x%08x\n", fcb->TMSpeed);
+	pr_debug("TMTiming1_BusyTimeout:      0x%08x\n", fcb->TMTiming1_BusyTimeout);
+	pr_debug("DISBBM:                     0x%08x\n", fcb->DISBBM);
+	pr_debug("BBMarkerPhysOfsInSpareData: 0x%08x\n", fcb->BBMarkerPhysicalOffsetInSpareData);
+}
+
+static __maybe_unused ssize_t raw_read_page(struct mtd_info *mtd, void *dst, loff_t offset)
+{
+	struct mtd_oob_ops ops;
+	ssize_t ret;
+
+	ops.mode = MTD_OPS_RAW;
+	ops.ooboffs = 0;
+	ops.datbuf = dst;
+	ops.len = mtd->writesize;
+	ops.oobbuf = dst + mtd->writesize;
+	ops.ooblen = mtd->oobsize;
+	ret = mtd_read_oob(mtd, offset, &ops);
+
+        return ret;
+}
+
+static ssize_t raw_write_page(struct mtd_info *mtd, void *buf, loff_t offset)
+{
+	struct mtd_oob_ops ops;
+	ssize_t ret;
+
+	ops.mode = MTD_OPS_RAW;
+	ops.ooboffs = 0;
+	ops.datbuf = buf;
+	ops.len = mtd->writesize;
+	ops.oobbuf = buf + mtd->writesize;
+	ops.ooblen = mtd->oobsize;
+	ret = mtd_write_oob(mtd, offset, &ops);
+
+        return ret;
+}
+
+static int fcb_create(struct fcb_block *fcb, struct mtd_info *mtd)
+{
+	fcb->FingerPrint = 0x20424346;
+	fcb->Version = 0x01000000;
+	fcb->PageDataSize = mtd->writesize;
+	fcb->TotalPageSize = mtd->writesize + mtd->oobsize;
+	fcb->SectorsPerBlock = mtd->erasesize / mtd->writesize;
+
+	/* Divide ECC strength by two and save the value into FCB structure. */
+	fcb->EccBlock0EccType =
+		mxs_nand_get_ecc_strength(mtd->writesize, mtd->oobsize) >> 1;
+	fcb->EccBlockNEccType = fcb->EccBlock0EccType;
+
+	/* Also hardcoded in kobs-ng */
+	fcb->DataSetup = 80;
+	fcb->DataHold = 60;
+	fcb->AddressSetup = 25;
+	fcb->DSAMPLE_TIME = 6;
+	fcb->MetadataBytes = 0x0000000a;
+	fcb->EccBlock0Size = 0x00000200;
+	fcb->EccBlockNSize = 0x00000200;
+
+	fcb->NumEccBlocksPerPage = mtd->writesize / fcb->EccBlock0Size - 1;
+
+	/* DBBT search area starts at third block */
+	fcb->DBBTSearchAreaStartAddress = mtd->erasesize / mtd->writesize * 2;
+
+	fcb->BadBlockMarkerByte = mxs_nand_mark_byte_offset(mtd);
+	fcb->BadBlockMarkerStartBit = mxs_nand_mark_bit_offset(mtd);
+
+	fcb->BBMarkerPhysicalOffset = mtd->writesize;
+
+	fcb->Checksum = calc_chksum((void *)fcb + 4, sizeof(*fcb) - 4);
+
+	return 0;
+}
+
+static int imx6_bbu_erase(struct mtd_info *mtd)
+{
+	uint64_t offset = 0;
+	int len = SZ_2M;
+	struct erase_info erase;
+	int ret;
+
+	while (len > 0) {
+		pr_debug("erasing at 0x%08llx\n", offset);
+		if (mtd_block_isbad(mtd, offset)) {
+			offset += mtd->erasesize;
+			pr_debug("erase skip block @ 0x%08llx\n", offset);
+			continue;
+		}
+
+		memset(&erase, 0, sizeof(erase));
+		erase.addr = offset;
+		erase.len = mtd->erasesize;
+
+		ret = mtd_erase(mtd, &erase);
+		if (ret)
+			return ret;
+
+		offset += mtd->erasesize;
+		len -= mtd->erasesize;
+	}
+
+	return 0;
+}
+
+static int imx6_bbu_write_firmware(struct mtd_info *mtd, int block, void *buf, size_t len)
+{
+	uint64_t offset = block * mtd->erasesize;
+	int ret;
+	size_t written;
+
+	while (len > 0) {
+		int now = min(len, mtd->erasesize);
+
+		pr_debug("writing %p at 0x%08llx, left 0x%08x\n",
+				buf, offset, len);
+
+		if (mtd_block_isbad(mtd, offset)) {
+			offset += mtd->erasesize;
+			block++;
+			pr_debug("write skip block @ 0x%08llx\n", offset);
+			continue;
+		}
+
+		ret = mtd_write(mtd, offset, now, &written, buf);
+		if (ret)
+			return ret;
+
+		offset += now;
+		len -= now;
+		buf += now;
+		block++;
+	}
+
+	return block;
+}
+
+static int dbbt_data_create(struct mtd_info *mtd, void *buf, int block_last)
+{
+	int n;
+	int n_bad_blocks = 0;
+	uint32_t *bb = buf + 0x8;
+	uint32_t *n_bad_blocksp = buf + 0x4;
+
+	for (n = 0; n <= block_last; n++) {
+		loff_t offset = n * mtd->erasesize;
+		if (mtd_block_isbad(mtd, offset)) {
+			n_bad_blocks++;
+			*bb = n;
+			bb++;
+		}
+	}
+
+	*n_bad_blocksp = n_bad_blocks;
+
+	return n_bad_blocks;
+}
+
+static int imx6_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *data)
+{
+	struct cdev *bcb_cdev;
+	struct mtd_info *mtd;
+	int ret, block_fw1, block_fw2, block_last;
+	struct fcb_block *fcb;
+	struct dbbt_block *dbbt;
+	void *fcb_raw_page, *dbbt_page, *dbbt_data_page;
+	void *ecc;
+	int written;
+	void *fw;
+	unsigned fw_size;
+	int i;
+
+	if (file_detect_type(data->image, data->len) != filetype_arm_barebox &&
+			!bbu_force(data, "Not an ARM barebox image"))
+		return -EINVAL;
+
+	ret = bbu_confirm(data);
+	if (ret)
+		return ret;
+
+	bcb_cdev = cdev_by_name("nand0");
+	if (!bcb_cdev) {
+		pr_err("%s: No FCB device!\n", __func__);
+		return -ENODEV;
+	}
+
+	mtd = bcb_cdev->mtd;
+
+	fcb_raw_page = xzalloc(mtd->writesize + mtd->oobsize);
+
+	fcb = fcb_raw_page + 12;
+	ecc = fcb_raw_page + 512 + 12;
+
+	dbbt_page = xzalloc(mtd->writesize);
+	dbbt_data_page = xzalloc(mtd->writesize);
+	dbbt = dbbt_page;
+
+	/*
+	 * We have to write one additional page to make the ROM happy.
+	 * Maybe the PagesInFirmwarex fields are really the number of pages - 1.
+	 * kobs-ng has the same.
+	 */
+	fw_size = ALIGN(data->len + mtd->writesize, mtd->writesize);
+	fw = xzalloc(fw_size);
+	memcpy(fw, data->image, data->len);
+
+	block_fw1 = 4;
+
+	ret = imx6_bbu_erase(mtd);
+	if (ret)
+		goto out;
+
+	ret = imx6_bbu_write_firmware(mtd, block_fw1, fw, fw_size);
+	if (ret < 0)
+		goto out;
+
+	block_fw2 = ret;
+
+	ret = imx6_bbu_write_firmware(mtd, block_fw2, fw, fw_size);
+	if (ret < 0)
+		goto out;
+
+	block_last = ret;
+
+	fcb->Firmware1_startingPage = block_fw1 * mtd->erasesize / mtd->writesize;
+	fcb->Firmware2_startingPage = block_fw2 * mtd->erasesize / mtd->writesize;
+	fcb->PagesInFirmware1 = ALIGN(data->len, mtd->writesize) / mtd->writesize;
+	fcb->PagesInFirmware2 = fcb->PagesInFirmware1;
+
+	fcb_create(fcb, mtd);
+	encode_hamming_13_8(fcb, ecc, 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
+	 * the FCB is mostly written to the first page in a block, a scan for
+	 * factory bad blocks will detect these blocks as bad, e.g. when
+	 * function nand_scan_bbt() is executed to build a new bad block table.
+	 */
+	memset(fcb_raw_page + mtd->writesize, 0xFF, 2);
+
+	ret = raw_write_page(mtd, fcb_raw_page, 0);
+	if (ret)
+		goto out;
+
+	ret = raw_write_page(mtd, fcb_raw_page, mtd->erasesize);
+	if (ret)
+		goto out;
+
+	dbbt->Checksum = 0;
+	dbbt->FingerPrint = 0x54424244;
+	dbbt->Version = 0x01000000;
+
+	ret = dbbt_data_create(mtd, dbbt_data_page, block_last);
+	if (ret < 0)
+		goto out;
+
+	if (ret > 0)
+		dbbt->DBBTNumOfPages = 1;
+
+	for (i = 2; i < 4; i++) {
+		ret = mtd_write(mtd, mtd->erasesize * i, 2048, &written, dbbt_page);
+		if (ret)
+			goto out;
+
+		if (dbbt->DBBTNumOfPages > 0) {
+			ret = mtd_write(mtd, mtd->erasesize * i + mtd->writesize * 4,
+					2048, &written, dbbt_data_page);
+			if (ret)
+				goto out;
+		}
+	}
+
+out:
+	free(dbbt_page);
+	free(dbbt_data_page);
+	free(fcb_raw_page);
+	free(fw);
+
+	return ret;
+}
+
+int imx6_bbu_nand_register_handler(const char *name, unsigned long flags)
+{
+	struct bbu_handler *handler;
+	int ret;
+
+	handler = xzalloc(sizeof(*handler));
+	handler->devicefile = "/dev/nand0";
+	handler->name = name;
+	handler->flags = flags;
+	handler->handler = imx6_bbu_nand_update;
+
+	ret = bbu_register_handler(handler);
+	if (ret)
+		free(handler);
+
+	return ret;
+}
diff --git a/include/bbu.h b/include/bbu.h
index 4a3d35e..c5f22be 100644
--- a/include/bbu.h
+++ b/include/bbu.h
@@ -50,4 +50,13 @@ static inline int bbu_register_handler(struct bbu_handler *unused)
 
 #endif
 
+#if defined(CONFIG_BAREBOX_UPDATE_IMX_NAND_FCB)
+int imx6_bbu_nand_register_handler(const char *name, unsigned long flags);
+#else
+static inline int imx6_bbu_nand_register_handler(const char *name, unsigned long flags)
+{
+	return -ENOSYS;
+}
+#endif
+
 #endif /* __INCLUDE_BBU_H */
-- 
2.1.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 05/10] imx-bbu-nand-fcb: Fix debug messages
  2015-06-12  6:35 i.MX FCB NAND boot updates Sascha Hauer
                   ` (3 preceding siblings ...)
  2015-06-12  6:35 ` [PATCH 04/10] ARM: i.MX6: bbu nand: Move to common place Sascha Hauer
@ 2015-06-12  6:35 ` Sascha Hauer
  2015-06-12  6:35 ` [PATCH 06/10] imx-bbu-nand-fcb: Use barebox partition instead of whole device Sascha Hauer
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Sascha Hauer @ 2015-06-12  6:35 UTC (permalink / raw)
  To: Barebox List

We should print the block number before increasing it, not afterwards.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 common/imx-bbu-nand-fcb.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/common/imx-bbu-nand-fcb.c b/common/imx-bbu-nand-fcb.c
index d2bfedb..5b984d4 100644
--- a/common/imx-bbu-nand-fcb.c
+++ b/common/imx-bbu-nand-fcb.c
@@ -275,8 +275,8 @@ static int imx6_bbu_erase(struct mtd_info *mtd)
 	while (len > 0) {
 		pr_debug("erasing at 0x%08llx\n", offset);
 		if (mtd_block_isbad(mtd, offset)) {
-			offset += mtd->erasesize;
 			pr_debug("erase skip block @ 0x%08llx\n", offset);
+			offset += mtd->erasesize;
 			continue;
 		}
 
@@ -308,9 +308,9 @@ static int imx6_bbu_write_firmware(struct mtd_info *mtd, int block, void *buf, s
 				buf, offset, len);
 
 		if (mtd_block_isbad(mtd, offset)) {
+			pr_debug("write skip block @ 0x%08llx\n", offset);
 			offset += mtd->erasesize;
 			block++;
-			pr_debug("write skip block @ 0x%08llx\n", offset);
 			continue;
 		}
 
-- 
2.1.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 06/10] imx-bbu-nand-fcb: Use barebox partition instead of whole device
  2015-06-12  6:35 i.MX FCB NAND boot updates Sascha Hauer
                   ` (4 preceding siblings ...)
  2015-06-12  6:35 ` [PATCH 05/10] imx-bbu-nand-fcb: Fix debug messages Sascha Hauer
@ 2015-06-12  6:35 ` Sascha Hauer
  2015-06-12  6:35 ` [PATCH 07/10] imx-bbu-nand-fcb: make available for i.MX28 aswell Sascha Hauer
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Sascha Hauer @ 2015-06-12  6:35 UTC (permalink / raw)
  To: Barebox List

We used to use nand0 device for storing barebox and made the assumption
that there is enough space at the beginning of the first device. Instead,
use the barebox partition directly. This requires that the partition
where barebox should be stored is named 'barebox', that is the case for
all boards currently.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 common/imx-bbu-nand-fcb.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/common/imx-bbu-nand-fcb.c b/common/imx-bbu-nand-fcb.c
index 5b984d4..ca7df97 100644
--- a/common/imx-bbu-nand-fcb.c
+++ b/common/imx-bbu-nand-fcb.c
@@ -370,7 +370,7 @@ static int imx6_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *da
 	if (ret)
 		return ret;
 
-	bcb_cdev = cdev_by_name("nand0");
+	bcb_cdev = cdev_by_name(handler->devicefile);
 	if (!bcb_cdev) {
 		pr_err("%s: No FCB device!\n", __func__);
 		return -ENODEV;
@@ -478,7 +478,7 @@ int imx6_bbu_nand_register_handler(const char *name, unsigned long flags)
 	int ret;
 
 	handler = xzalloc(sizeof(*handler));
-	handler->devicefile = "/dev/nand0";
+	handler->devicefile = "nand0.barebox";
 	handler->name = name;
 	handler->flags = flags;
 	handler->handler = imx6_bbu_nand_update;
-- 
2.1.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 07/10] imx-bbu-nand-fcb: make available for i.MX28 aswell
  2015-06-12  6:35 i.MX FCB NAND boot updates Sascha Hauer
                   ` (5 preceding siblings ...)
  2015-06-12  6:35 ` [PATCH 06/10] imx-bbu-nand-fcb: Use barebox partition instead of whole device Sascha Hauer
@ 2015-06-12  6:35 ` Sascha Hauer
  2015-06-12  6:35 ` [PATCH 08/10] imx-bbu-nand-fcb: Let DBBT start at page 1 Sascha Hauer
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Sascha Hauer @ 2015-06-12  6:35 UTC (permalink / raw)
  To: Barebox List

The code can be used with slight modifications on i.MX28 aswell.
Add a i.MX28 registration function and move the differences to
function callbacks.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 common/Kconfig            |   2 +-
 common/imx-bbu-nand-fcb.c | 173 ++++++++++++++++++++++++++++++++++++++++------
 include/bbu.h             |   5 ++
 3 files changed, 157 insertions(+), 23 deletions(-)

diff --git a/common/Kconfig b/common/Kconfig
index 0ebfe1e..31944c5 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -96,7 +96,7 @@ config FILE_LIST
 
 config BAREBOX_UPDATE_IMX_NAND_FCB
 	bool
-	depends on ARCH_IMX6
+	depends on ARCH_IMX6 || ARCH_IMX28
 	depends on BAREBOX_UPDATE
 	depends on MTD_WRITE
 	depends on NAND_MXS
diff --git a/common/imx-bbu-nand-fcb.c b/common/imx-bbu-nand-fcb.c
index ca7df97..920b5a1 100644
--- a/common/imx-bbu-nand-fcb.c
+++ b/common/imx-bbu-nand-fcb.c
@@ -17,7 +17,7 @@
  *
  */
 
-#define pr_fmt(fmt) "imx6-bbu-nand: " fmt
+#define pr_fmt(fmt) "imx-bbu-nand-fcb: " fmt
 
 #include <filetype.h>
 #include <common.h>
@@ -28,17 +28,17 @@
 #include <linux/sizes.h>
 #include <bbu.h>
 #include <fs.h>
-#include <mach/bbu.h>
 #include <linux/mtd/mtd-abi.h>
 #include <linux/mtd/nand_mxs.h>
 #include <linux/mtd/mtd.h>
 #include <linux/stat.h>
+#include <io.h>
 
 struct dbbt_block {
 	uint32_t Checksum;
 	uint32_t FingerPrint;
 	uint32_t Version;
-	uint32_t reserved;
+	uint32_t numberBB; /* reserved on i.MX6 */
 	uint32_t DBBTNumOfPages;
 };
 
@@ -102,6 +102,16 @@ struct fcb_block {
 	uint32_t BBMarkerPhysicalOffsetInSpareData; /* The swap position of main area in spare area */
 };
 
+struct imx_nand_fcb_bbu_handler {
+	struct bbu_handler handler;
+
+	void (*fcb_create)(struct imx_nand_fcb_bbu_handler *imx_handler,
+		struct fcb_block *fcb, struct mtd_info *mtd);
+	void (*dbbt_create)(struct imx_nand_fcb_bbu_handler *imx_handler,
+		struct dbbt_block *dbbt, int num_bad_blocks);
+	enum filetype filetype;
+};
+
 #define BF_VAL(v, bf)		(((v) & bf##_MASK) >> bf##_OFFSET)
 #define GETBIT(v,n)	(((v) >> (n)) & 0x1)
 
@@ -228,7 +238,8 @@ static ssize_t raw_write_page(struct mtd_info *mtd, void *buf, loff_t offset)
         return ret;
 }
 
-static int fcb_create(struct fcb_block *fcb, struct mtd_info *mtd)
+static int fcb_create(struct imx_nand_fcb_bbu_handler *imx_handler,
+		struct fcb_block *fcb, struct mtd_info *mtd)
 {
 	fcb->FingerPrint = 0x20424346;
 	fcb->Version = 0x01000000;
@@ -241,12 +252,6 @@ static int fcb_create(struct fcb_block *fcb, struct mtd_info *mtd)
 		mxs_nand_get_ecc_strength(mtd->writesize, mtd->oobsize) >> 1;
 	fcb->EccBlockNEccType = fcb->EccBlock0EccType;
 
-	/* Also hardcoded in kobs-ng */
-	fcb->DataSetup = 80;
-	fcb->DataHold = 60;
-	fcb->AddressSetup = 25;
-	fcb->DSAMPLE_TIME = 6;
-	fcb->MetadataBytes = 0x0000000a;
 	fcb->EccBlock0Size = 0x00000200;
 	fcb->EccBlockNSize = 0x00000200;
 
@@ -260,12 +265,14 @@ static int fcb_create(struct fcb_block *fcb, struct mtd_info *mtd)
 
 	fcb->BBMarkerPhysicalOffset = mtd->writesize;
 
+	imx_handler->fcb_create(imx_handler, fcb, mtd);
+
 	fcb->Checksum = calc_chksum((void *)fcb + 4, sizeof(*fcb) - 4);
 
 	return 0;
 }
 
-static int imx6_bbu_erase(struct mtd_info *mtd)
+static int imx_bbu_erase(struct mtd_info *mtd)
 {
 	uint64_t offset = 0;
 	int len = SZ_2M;
@@ -295,7 +302,7 @@ static int imx6_bbu_erase(struct mtd_info *mtd)
 	return 0;
 }
 
-static int imx6_bbu_write_firmware(struct mtd_info *mtd, int block, void *buf, size_t len)
+static int imx_bbu_write_firmware(struct mtd_info *mtd, int block, void *buf, size_t len)
 {
 	uint64_t offset = block * mtd->erasesize;
 	int ret;
@@ -348,8 +355,10 @@ static int dbbt_data_create(struct mtd_info *mtd, void *buf, int block_last)
 	return n_bad_blocks;
 }
 
-static int imx6_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *data)
+static int imx_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *data)
 {
+	struct imx_nand_fcb_bbu_handler *imx_handler =
+		container_of(handler, struct imx_nand_fcb_bbu_handler, handler);
 	struct cdev *bcb_cdev;
 	struct mtd_info *mtd;
 	int ret, block_fw1, block_fw2, block_last;
@@ -361,9 +370,14 @@ static int imx6_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *da
 	void *fw;
 	unsigned fw_size;
 	int i;
+	enum filetype filetype;
 
-	if (file_detect_type(data->image, data->len) != filetype_arm_barebox &&
-			!bbu_force(data, "Not an ARM barebox image"))
+	filetype = file_detect_type(data->image, data->len);
+
+	if (filetype != imx_handler->filetype &&
+			!bbu_force(data, "Image is not of type %s but of type %s",
+				file_type_to_string(imx_handler->filetype),
+				file_type_to_string(filetype)))
 		return -EINVAL;
 
 	ret = bbu_confirm(data);
@@ -398,17 +412,17 @@ static int imx6_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *da
 
 	block_fw1 = 4;
 
-	ret = imx6_bbu_erase(mtd);
+	ret = imx_bbu_erase(mtd);
 	if (ret)
 		goto out;
 
-	ret = imx6_bbu_write_firmware(mtd, block_fw1, fw, fw_size);
+	ret = imx_bbu_write_firmware(mtd, block_fw1, fw, fw_size);
 	if (ret < 0)
 		goto out;
 
 	block_fw2 = ret;
 
-	ret = imx6_bbu_write_firmware(mtd, block_fw2, fw, fw_size);
+	ret = imx_bbu_write_firmware(mtd, block_fw2, fw, fw_size);
 	if (ret < 0)
 		goto out;
 
@@ -419,7 +433,7 @@ static int imx6_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *da
 	fcb->PagesInFirmware1 = ALIGN(data->len, mtd->writesize) / mtd->writesize;
 	fcb->PagesInFirmware2 = fcb->PagesInFirmware1;
 
-	fcb_create(fcb, mtd);
+	fcb_create(imx_handler, fcb, mtd);
 	encode_hamming_13_8(fcb, ecc, 512);
 
 	/*
@@ -447,8 +461,11 @@ static int imx6_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *da
 	if (ret < 0)
 		goto out;
 
-	if (ret > 0)
+	if (ret > 0) {
 		dbbt->DBBTNumOfPages = 1;
+		if (imx_handler->dbbt_create)
+			imx_handler->dbbt_create(imx_handler, dbbt, ret);
+	}
 
 	for (i = 2; i < 4; i++) {
 		ret = mtd_write(mtd, mtd->erasesize * i, 2048, &written, dbbt_page);
@@ -472,16 +489,127 @@ out:
 	return ret;
 }
 
+static void imx6_fcb_create(struct imx_nand_fcb_bbu_handler *imx_handler,
+		struct fcb_block *fcb, struct mtd_info *mtd)
+{
+	/* Also hardcoded in kobs-ng */
+	fcb->DataSetup = 80;
+	fcb->DataHold = 60;
+	fcb->AddressSetup = 25;
+	fcb->DSAMPLE_TIME = 6;
+	fcb->MetadataBytes = 10;
+}
+
 int imx6_bbu_nand_register_handler(const char *name, unsigned long flags)
 {
+	struct imx_nand_fcb_bbu_handler *imx_handler;
+	struct bbu_handler *handler;
+	int ret;
+
+	imx_handler = xzalloc(sizeof(*imx_handler));
+	imx_handler->fcb_create = imx6_fcb_create;
+	imx_handler->filetype = filetype_arm_barebox;
+
+	handler = &imx_handler->handler;
+	handler->devicefile = "nand0.barebox";
+	handler->name = name;
+	handler->flags = flags;
+	handler->handler = imx_bbu_nand_update;
+
+	ret = bbu_register_handler(handler);
+	if (ret)
+		free(handler);
+
+	return ret;
+}
+
+#ifdef CONFIG_ARCH_IMX28
+#include <mach/imx28-regs.h>
+
+#define GPMI_TIMING0				0x00000070
+#define	GPMI_TIMING0_ADDRESS_SETUP_MASK			(0xff << 16)
+#define	GPMI_TIMING0_ADDRESS_SETUP_OFFSET		16
+#define	GPMI_TIMING0_DATA_HOLD_MASK			(0xff << 8)
+#define	GPMI_TIMING0_DATA_HOLD_OFFSET			8
+#define	GPMI_TIMING0_DATA_SETUP_MASK			0xff
+#define	GPMI_TIMING0_DATA_SETUP_OFFSET			0
+
+#define GPMI_TIMING1				0x00000080
+
+#define BCH_MODE				0x00000020
+
+#define BCH_FLASH0LAYOUT0			0x00000080
+#define	BCH_FLASHLAYOUT0_NBLOCKS_MASK			(0xff << 24)
+#define	BCH_FLASHLAYOUT0_NBLOCKS_OFFSET			24
+#define	BCH_FLASHLAYOUT0_META_SIZE_MASK			(0xff << 16)
+#define	BCH_FLASHLAYOUT0_META_SIZE_OFFSET		16
+#define	BCH_FLASHLAYOUT0_ECC0_MASK			(0xf << 12)
+#define	BCH_FLASHLAYOUT0_ECC0_OFFSET			12
+#define	BCH_FLASHLAYOUT0_DATA0_SIZE_MASK		0xfff
+#define	BCH_FLASHLAYOUT0_DATA0_SIZE_OFFSET		0
+
+#define BCH_FLASH0LAYOUT1			0x00000090
+#define	BCH_FLASHLAYOUT1_PAGE_SIZE_MASK			(0xffff << 16)
+#define	BCH_FLASHLAYOUT1_PAGE_SIZE_OFFSET		16
+#define	BCH_FLASHLAYOUT1_ECCN_MASK			(0xf << 12)
+#define	BCH_FLASHLAYOUT1_ECCN_OFFSET			12
+#define	BCH_FLASHLAYOUT1_DATAN_SIZE_MASK		0xfff
+#define	BCH_FLASHLAYOUT1_DATAN_SIZE_OFFSET		0
+
+static void imx28_fcb_create(struct imx_nand_fcb_bbu_handler *imx_handler,
+		struct fcb_block *fcb, struct mtd_info *mtd)
+{
+	u32 fl0, fl1, t0;
+	void __iomem *bch_regs = (void *)MXS_BCH_BASE;
+	void __iomem *gpmi_regs = (void *)MXS_GPMI_BASE;
+
+	fl0 = readl(bch_regs + BCH_FLASH0LAYOUT0);
+	fl1 = readl(bch_regs + BCH_FLASH0LAYOUT1);
+	t0 = readl(gpmi_regs + GPMI_TIMING0);
+
+	fcb->MetadataBytes = BF_VAL(fl0, BCH_FLASHLAYOUT0_META_SIZE);
+	fcb->DataSetup = BF_VAL(t0, GPMI_TIMING0_DATA_SETUP);
+	fcb->DataHold = BF_VAL(t0, GPMI_TIMING0_DATA_HOLD);
+	fcb->AddressSetup = BF_VAL(t0, GPMI_TIMING0_ADDRESS_SETUP);
+	fcb->MetadataBytes = BF_VAL(fl0, BCH_FLASHLAYOUT0_META_SIZE);
+	fcb->NumEccBlocksPerPage = BF_VAL(fl0, BCH_FLASHLAYOUT0_NBLOCKS);
+	fcb->EraseThreshold = readl(bch_regs + BCH_MODE);
+}
+
+static void imx28_dbbt_create(struct imx_nand_fcb_bbu_handler *imx_handler,
+		struct dbbt_block *dbbt, int num_bad_blocks)
+{
+	uint32_t a = 0;
+	uint8_t *p = (void *)dbbt;
+	int i;
+
+	dbbt->numberBB = num_bad_blocks;
+
+	for (i = 4; i < 512; i++)
+		a += p[i];
+
+	a ^= 0xffffffff;
+
+	dbbt->Checksum = a;
+}
+
+int imx28_bbu_nand_register_handler(const char *name, unsigned long flags)
+{
+	struct imx_nand_fcb_bbu_handler *imx_handler;
 	struct bbu_handler *handler;
 	int ret;
 
-	handler = xzalloc(sizeof(*handler));
+	imx_handler = xzalloc(sizeof(*imx_handler));
+	imx_handler->fcb_create = imx28_fcb_create;
+	imx_handler->dbbt_create = imx28_dbbt_create;
+
+	imx_handler->filetype = filetype_mxs_bootstream;
+
+	handler = &imx_handler->handler;
 	handler->devicefile = "nand0.barebox";
 	handler->name = name;
 	handler->flags = flags;
-	handler->handler = imx6_bbu_nand_update;
+	handler->handler = imx_bbu_nand_update;
 
 	ret = bbu_register_handler(handler);
 	if (ret)
@@ -489,3 +617,4 @@ int imx6_bbu_nand_register_handler(const char *name, unsigned long flags)
 
 	return ret;
 }
+#endif
diff --git a/include/bbu.h b/include/bbu.h
index c5f22be..4cf97e1 100644
--- a/include/bbu.h
+++ b/include/bbu.h
@@ -52,11 +52,16 @@ static inline int bbu_register_handler(struct bbu_handler *unused)
 
 #if defined(CONFIG_BAREBOX_UPDATE_IMX_NAND_FCB)
 int imx6_bbu_nand_register_handler(const char *name, unsigned long flags);
+int imx28_bbu_nand_register_handler(const char *name, unsigned long flags);
 #else
 static inline int imx6_bbu_nand_register_handler(const char *name, unsigned long flags)
 {
 	return -ENOSYS;
 }
+static inline int imx28_bbu_nand_register_handler(const char *name, unsigned long flags)
+{
+	return -ENOSYS;
+}
 #endif
 
 #endif /* __INCLUDE_BBU_H */
-- 
2.1.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 08/10] imx-bbu-nand-fcb: Let DBBT start at page 1
  2015-06-12  6:35 i.MX FCB NAND boot updates Sascha Hauer
                   ` (6 preceding siblings ...)
  2015-06-12  6:35 ` [PATCH 07/10] imx-bbu-nand-fcb: make available for i.MX28 aswell Sascha Hauer
@ 2015-06-12  6:35 ` Sascha Hauer
  2015-06-12  6:35 ` [PATCH 09/10] imx-bbu-nand-fcb: Erase whole partition Sascha Hauer
  2015-06-12  6:35 ` [PATCH 10/10] imx-bbu-nand-fcb: Split space for firmware in two equal regions Sascha Hauer
  9 siblings, 0 replies; 11+ messages in thread
From: Sascha Hauer @ 2015-06-12  6:35 UTC (permalink / raw)
  To: Barebox List

We used to put the FCB in the first two NAND blocks and the DBBT
in the third and fourth block. It's much more space efficient to
put the FCB and DBBT together into the same eraseblock in different
pages. This way we can store four FCBs and four DBBTs instead of
two only.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 common/imx-bbu-nand-fcb.c | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/common/imx-bbu-nand-fcb.c b/common/imx-bbu-nand-fcb.c
index 920b5a1..d65b9cd 100644
--- a/common/imx-bbu-nand-fcb.c
+++ b/common/imx-bbu-nand-fcb.c
@@ -257,8 +257,8 @@ static int fcb_create(struct imx_nand_fcb_bbu_handler *imx_handler,
 
 	fcb->NumEccBlocksPerPage = mtd->writesize / fcb->EccBlock0Size - 1;
 
-	/* DBBT search area starts at third block */
-	fcb->DBBTSearchAreaStartAddress = mtd->erasesize / mtd->writesize * 2;
+	/* DBBT search area starts at second page on first block */
+	fcb->DBBTSearchAreaStartAddress = 1;
 
 	fcb->BadBlockMarkerByte = mxs_nand_mark_byte_offset(mtd);
 	fcb->BadBlockMarkerStartBit = mxs_nand_mark_bit_offset(mtd);
@@ -445,10 +445,6 @@ static int imx_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *dat
 	 */
 	memset(fcb_raw_page + mtd->writesize, 0xFF, 2);
 
-	ret = raw_write_page(mtd, fcb_raw_page, 0);
-	if (ret)
-		goto out;
-
 	ret = raw_write_page(mtd, fcb_raw_page, mtd->erasesize);
 	if (ret)
 		goto out;
@@ -467,14 +463,19 @@ static int imx_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *dat
 			imx_handler->dbbt_create(imx_handler, dbbt, ret);
 	}
 
-	for (i = 2; i < 4; i++) {
-		ret = mtd_write(mtd, mtd->erasesize * i, 2048, &written, dbbt_page);
+	for (i = 0; i < 4; i++) {
+		ret = raw_write_page(mtd, fcb_raw_page, mtd->erasesize * i);
+		if (ret)
+			goto out;
+
+		ret = mtd_write(mtd, mtd->erasesize * i + mtd->writesize,
+				mtd->writesize, &written, dbbt_page);
 		if (ret)
 			goto out;
 
 		if (dbbt->DBBTNumOfPages > 0) {
-			ret = mtd_write(mtd, mtd->erasesize * i + mtd->writesize * 4,
-					2048, &written, dbbt_data_page);
+			ret = mtd_write(mtd, mtd->erasesize * i + mtd->writesize * 5,
+					mtd->writesize, &written, dbbt_data_page);
 			if (ret)
 				goto out;
 		}
-- 
2.1.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 09/10] imx-bbu-nand-fcb: Erase whole partition
  2015-06-12  6:35 i.MX FCB NAND boot updates Sascha Hauer
                   ` (7 preceding siblings ...)
  2015-06-12  6:35 ` [PATCH 08/10] imx-bbu-nand-fcb: Let DBBT start at page 1 Sascha Hauer
@ 2015-06-12  6:35 ` Sascha Hauer
  2015-06-12  6:35 ` [PATCH 10/10] imx-bbu-nand-fcb: Split space for firmware in two equal regions Sascha Hauer
  9 siblings, 0 replies; 11+ messages in thread
From: Sascha Hauer @ 2015-06-12  6:35 UTC (permalink / raw)
  To: Barebox List

Now that we use a partition for the bootloader instead of
the whole NAND device we can erase it completely instead of
hardcoded 2MB.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 common/imx-bbu-nand-fcb.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/common/imx-bbu-nand-fcb.c b/common/imx-bbu-nand-fcb.c
index d65b9cd..c4f49b5 100644
--- a/common/imx-bbu-nand-fcb.c
+++ b/common/imx-bbu-nand-fcb.c
@@ -275,11 +275,10 @@ static int fcb_create(struct imx_nand_fcb_bbu_handler *imx_handler,
 static int imx_bbu_erase(struct mtd_info *mtd)
 {
 	uint64_t offset = 0;
-	int len = SZ_2M;
 	struct erase_info erase;
 	int ret;
 
-	while (len > 0) {
+	while (offset < mtd->size) {
 		pr_debug("erasing at 0x%08llx\n", offset);
 		if (mtd_block_isbad(mtd, offset)) {
 			pr_debug("erase skip block @ 0x%08llx\n", offset);
@@ -296,7 +295,6 @@ static int imx_bbu_erase(struct mtd_info *mtd)
 			return ret;
 
 		offset += mtd->erasesize;
-		len -= mtd->erasesize;
 	}
 
 	return 0;
-- 
2.1.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 10/10] imx-bbu-nand-fcb: Split space for firmware in two equal regions
  2015-06-12  6:35 i.MX FCB NAND boot updates Sascha Hauer
                   ` (8 preceding siblings ...)
  2015-06-12  6:35 ` [PATCH 09/10] imx-bbu-nand-fcb: Erase whole partition Sascha Hauer
@ 2015-06-12  6:35 ` Sascha Hauer
  9 siblings, 0 replies; 11+ messages in thread
From: Sascha Hauer @ 2015-06-12  6:35 UTC (permalink / raw)
  To: Barebox List

We used to write the second firmware right after the first
firmware. However, splitting the available space into two
equal regions has advantages: When we update barebox the next
time the generated FCB/DBBT blocks will be the same as with the
last update, so in case of power failure it is more likely that
we have valid data in one of the FCB/DBBT areas.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 common/imx-bbu-nand-fcb.c | 48 ++++++++++++++++++++++++++++++++---------------
 1 file changed, 33 insertions(+), 15 deletions(-)

diff --git a/common/imx-bbu-nand-fcb.c b/common/imx-bbu-nand-fcb.c
index c4f49b5..22031f5 100644
--- a/common/imx-bbu-nand-fcb.c
+++ b/common/imx-bbu-nand-fcb.c
@@ -300,7 +300,8 @@ static int imx_bbu_erase(struct mtd_info *mtd)
 	return 0;
 }
 
-static int imx_bbu_write_firmware(struct mtd_info *mtd, int block, void *buf, size_t len)
+static int imx_bbu_write_firmware(struct mtd_info *mtd, unsigned block,
+		unsigned num_blocks, void *buf, size_t len)
 {
 	uint64_t offset = block * mtd->erasesize;
 	int ret;
@@ -309,6 +310,9 @@ static int imx_bbu_write_firmware(struct mtd_info *mtd, int block, void *buf, si
 	while (len > 0) {
 		int now = min(len, mtd->erasesize);
 
+		if (!num_blocks)
+			return -ENOSPC;
+
 		pr_debug("writing %p at 0x%08llx, left 0x%08x\n",
 				buf, offset, len);
 
@@ -327,6 +331,7 @@ static int imx_bbu_write_firmware(struct mtd_info *mtd, int block, void *buf, si
 		len -= now;
 		buf += now;
 		block++;
+		num_blocks--;
 	}
 
 	return block;
@@ -359,16 +364,17 @@ static int imx_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *dat
 		container_of(handler, struct imx_nand_fcb_bbu_handler, handler);
 	struct cdev *bcb_cdev;
 	struct mtd_info *mtd;
-	int ret, block_fw1, block_fw2, block_last;
+	int ret, block_fw1, block_fw2;
 	struct fcb_block *fcb;
 	struct dbbt_block *dbbt;
 	void *fcb_raw_page, *dbbt_page, *dbbt_data_page;
 	void *ecc;
 	int written;
 	void *fw;
-	unsigned fw_size;
+	unsigned fw_size, partition_size;
 	int i;
 	enum filetype filetype;
+	unsigned num_blocks_fcb_dbbt, num_blocks, num_blocks_fw;
 
 	filetype = file_detect_type(data->image, data->len);
 
@@ -378,10 +384,6 @@ static int imx_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *dat
 				file_type_to_string(filetype)))
 		return -EINVAL;
 
-	ret = bbu_confirm(data);
-	if (ret)
-		return ret;
-
 	bcb_cdev = cdev_by_name(handler->devicefile);
 	if (!bcb_cdev) {
 		pr_err("%s: No FCB device!\n", __func__);
@@ -389,6 +391,7 @@ static int imx_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *dat
 	}
 
 	mtd = bcb_cdev->mtd;
+	partition_size = mtd->size;
 
 	fcb_raw_page = xzalloc(mtd->writesize + mtd->oobsize);
 
@@ -408,24 +411,39 @@ static int imx_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *dat
 	fw = xzalloc(fw_size);
 	memcpy(fw, data->image, data->len);
 
-	block_fw1 = 4;
+	num_blocks_fcb_dbbt = 4;
+	num_blocks = partition_size / mtd->erasesize;
+	num_blocks_fw = (num_blocks - num_blocks_fcb_dbbt) / 2;
+
+	block_fw1 = num_blocks_fcb_dbbt;
+	block_fw2 = num_blocks_fcb_dbbt + num_blocks_fw;
+
+	pr_info("writing first firmware to block %d (ofs 0x%08x)\n",
+			block_fw1, block_fw1 * mtd->erasesize);
+	pr_info("writing second firmware to block %d (ofs 0x%08x)\n",
+			block_fw2, block_fw2 * mtd->erasesize);
+	pr_info("maximum size per firmware: 0x%08x bytes\n",
+			num_blocks_fw * mtd->erasesize);
+
+	if (num_blocks_fw * mtd->erasesize < fw_size)
+		return -ENOSPC;
+
+	ret = bbu_confirm(data);
+	if (ret)
+		goto out;
 
 	ret = imx_bbu_erase(mtd);
 	if (ret)
 		goto out;
 
-	ret = imx_bbu_write_firmware(mtd, block_fw1, fw, fw_size);
+	ret = imx_bbu_write_firmware(mtd, block_fw1, num_blocks_fw, fw, fw_size);
 	if (ret < 0)
 		goto out;
 
-	block_fw2 = ret;
-
-	ret = imx_bbu_write_firmware(mtd, block_fw2, fw, fw_size);
+	ret = imx_bbu_write_firmware(mtd, block_fw2, num_blocks_fw, fw, fw_size);
 	if (ret < 0)
 		goto out;
 
-	block_last = ret;
-
 	fcb->Firmware1_startingPage = block_fw1 * mtd->erasesize / mtd->writesize;
 	fcb->Firmware2_startingPage = block_fw2 * mtd->erasesize / mtd->writesize;
 	fcb->PagesInFirmware1 = ALIGN(data->len, mtd->writesize) / mtd->writesize;
@@ -451,7 +469,7 @@ static int imx_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *dat
 	dbbt->FingerPrint = 0x54424244;
 	dbbt->Version = 0x01000000;
 
-	ret = dbbt_data_create(mtd, dbbt_data_page, block_last);
+	ret = dbbt_data_create(mtd, dbbt_data_page, block_fw2 + num_blocks_fw);
 	if (ret < 0)
 		goto out;
 
-- 
2.1.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2015-06-12  6:36 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-06-12  6:35 i.MX FCB NAND boot updates Sascha Hauer
2015-06-12  6:35 ` [PATCH 01/10] ARM: dts: Karo tx6: increase barebox partition to 4MB Sascha Hauer
2015-06-12  6:35 ` [PATCH 02/10] mtd: partition: implement write_oob Sascha Hauer
2015-06-12  6:35 ` [PATCH 03/10] filetype: Add filetype for MXS bootstream Sascha Hauer
2015-06-12  6:35 ` [PATCH 04/10] ARM: i.MX6: bbu nand: Move to common place Sascha Hauer
2015-06-12  6:35 ` [PATCH 05/10] imx-bbu-nand-fcb: Fix debug messages Sascha Hauer
2015-06-12  6:35 ` [PATCH 06/10] imx-bbu-nand-fcb: Use barebox partition instead of whole device Sascha Hauer
2015-06-12  6:35 ` [PATCH 07/10] imx-bbu-nand-fcb: make available for i.MX28 aswell Sascha Hauer
2015-06-12  6:35 ` [PATCH 08/10] imx-bbu-nand-fcb: Let DBBT start at page 1 Sascha Hauer
2015-06-12  6:35 ` [PATCH 09/10] imx-bbu-nand-fcb: Erase whole partition Sascha Hauer
2015-06-12  6:35 ` [PATCH 10/10] imx-bbu-nand-fcb: Split space for firmware in two equal regions Sascha Hauer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox