All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH] i.MX6 nand bootupdate, reworked
@ 2016-06-18 21:44 Sergey Kubushyn
  2016-09-28 16:34 ` Jagan Teki
  0 siblings, 1 reply; 6+ messages in thread
From: Sergey Kubushyn @ 2016-06-18 21:44 UTC (permalink / raw)
  To: u-boot

Here is yet another version, diff made against latest u-boot-imx master.

Actual code moved from drivers/mtd/nand to /arch/arm/imx-common, some
functions renamed. No other changes.

Signed-off-by: Sergey Kubushyn <ksi@koi8.net>
---
  arch/arm/imx-common/Makefile               |   3 +
  arch/arm/imx-common/cmd_nand_bootupdate.c  | 556 +++++++++++++++++++++++++++++
  arch/arm/include/asm/imx-common/mxs_nand.h |  37 ++
  cmd/nand.c                                 |  61 ++++
  drivers/mtd/nand/mxs_nand.c                |   7 +-
  5 files changed, 661 insertions(+), 3 deletions(-)

diff --git a/arch/arm/imx-common/Makefile b/arch/arm/imx-common/Makefile
index d34a784..b77c231 100644
--- a/arch/arm/imx-common/Makefile
+++ b/arch/arm/imx-common/Makefile
@@ -34,6 +34,9 @@ endif
  ifeq ($(SOC),$(filter $(SOC),vf610))
  obj-y += ddrmc-vf610.o
  endif
+ifeq ($(SOC),$(filter $(SOC),mx6))
+obj-$(CONFIG_CMD_NAND_BOOTUPDATE) += cmd_nand_bootupdate.o
+endif
  obj-$(CONFIG_CMD_BMODE) += cmd_bmode.o
  obj-$(CONFIG_CMD_HDMIDETECT) += cmd_hdmidet.o
  obj-$(CONFIG_CMD_DEKBLOB) += cmd_dek.o
diff --git a/arch/arm/imx-common/cmd_nand_bootupdate.c b/arch/arm/imx-common/cmd_nand_bootupdate.c
new file mode 100644
index 0000000..1dcb637
--- /dev/null
+++ b/arch/arm/imx-common/cmd_nand_bootupdate.c
@@ -0,0 +1,556 @@
+/*
+ * cmd_nand_bootupdate.c - write U-Boot to MXS NAND to make it bootable
+ *
+ * Copyright (c) 2016 Sergey Kubushyn <ksi@koi8.net>
+ *
+ * Most of the source shamelesly stolen from barebox.
+ *
+ * Here is the original copyright:
+ *
+ *=== Cut ===
+ * Copyright (C) 2014 Sascha Hauer, Pengutronix
+ *=== Cut ===
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ *
+ */
+
+#include <common.h>
+#include <linux/sizes.h>
+#include <linux/mtd/mtd.h>
+#include <linux/compat.h>
+#include <command.h>
+#include <console.h>
+#include <malloc.h>
+#include <asm/byteorder.h>
+#include <jffs2/jffs2.h>
+#include <nand.h>
+#include <errno.h>
+#include <asm/imx-common/mxs_nand.h>
+#include <asm/imx-common/imximage.cfg>
+
+
+#ifndef CONFIG_CMD_MTDPARTS
+#error "CONFIG_CMD_MTDPARTS is not set, mtd partition support missing"
+#endif
+
+static const char *uboot_tgt = "nand0,0";
+
+/* partition handling routines */
+int mtdparts_init(void);
+int id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *dev_num);
+int find_dev_and_part(const char *id, struct mtd_device **dev,
+		      u8 *part_num, struct part_info **part);
+
+struct dbbt_block {
+	uint32_t Checksum;	/* reserved on i.MX6 */
+	uint32_t FingerPrint;
+	uint32_t Version;
+	uint32_t numberBB;	/* reserved on i.MX6 */
+	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 */
+};
+
+struct fw_write_data {
+	int	fw1_blk;
+	int	fw2_blk;
+	int	part_blks;
+	void	*buf;
+	size_t	len;
+};
+
+#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 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->EccBlock0Size = 0x00000200;
+	fcb->EccBlockNSize = 0x00000200;
+	fcb->DataSetup = 80;
+	fcb->DataHold = 60;
+	fcb->AddressSetup = 25;
+	fcb->DSAMPLE_TIME = 6;
+	fcb->MetadataBytes = 10;
+
+	/* 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);
+
+	fcb->BBMarkerPhysicalOffset = mtd->writesize;
+
+	fcb->NumEccBlocksPerPage = mtd->writesize / fcb->EccBlock0Size - 1;
+
+	fcb->Checksum = calc_chksum((void *)fcb + 4, sizeof(*fcb) - 4);
+
+	return 0;
+}
+
+/* Erase entire U-Boot partition */
+static int imx_nand_uboot_erase(struct mtd_info *mtd, struct part_info *part)
+{
+	uint64_t		offset = 0;
+	struct erase_info	erase;
+	int			len = part->size;
+	int			ret;
+
+	while (len > 0) {
+		pr_debug("erasing at 0x%08llx\n", offset);
+		if (mtd_block_isbad(mtd, offset)) {
+			pr_debug("erase skip block @ 0x%08llx\n", offset);
+			offset += mtd->erasesize;
+			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;
+}
+
+/*
+ * Write the U-Boot proper (2 copies) to where it belongs.
+ * This is U-Boot binary image itself, no FCB/DBBT here yet.
+ */
+static int imx_nand_uboot_write_fw(struct mtd_info *mtd, struct fw_write_data *fw)
+{
+	uint64_t	offset;
+	int		ret;
+	int		blk;
+	size_t		dummy;
+	size_t		bytes_left;
+	int		chunk;
+	void		*p;
+
+	bytes_left = fw->len;
+	p = fw->buf;
+	blk = fw->fw1_blk;
+	offset = blk * mtd->erasesize;
+
+	while (bytes_left > 0) {
+		chunk = min(bytes_left, mtd->erasesize);
+
+		pr_debug("fw1: writing %p at 0x%08llx, left 0x%08x\n",
+				p, offset, bytes_left);
+
+		if (mtd_block_isbad(mtd, offset)) {
+			pr_debug("fw1: write skip block @ 0x%08llx\n", offset);
+			offset += mtd->erasesize;
+			blk++;
+			continue;
+		}
+
+		if (blk >= fw->fw2_blk)
+			return -ENOSPC;
+
+		ret = mtd_write(mtd, offset, chunk, &dummy, p);
+		if (ret)
+			return ret;
+
+		offset += chunk;
+		bytes_left -= chunk;
+		p += chunk;
+		blk++;
+	}
+
+	bytes_left = fw->len;
+	p = fw->buf;
+	blk = fw->fw2_blk;
+	offset = blk * mtd->erasesize;
+
+	while (bytes_left > 0) {
+		chunk = min(bytes_left, mtd->erasesize);
+
+		pr_debug("fw2: writing %p at 0x%08llx, left 0x%08x\n",
+				p, offset, bytes_left);
+
+		if (mtd_block_isbad(mtd, offset)) {
+			pr_debug("fw2: write skip block @ 0x%08llx\n", offset);
+			offset += mtd->erasesize;
+			blk++;
+			continue;
+		}
+
+		if (blk >= fw->part_blks)
+			return -ENOSPC;
+
+		ret = mtd_write(mtd, offset, chunk, &dummy, p);
+		if (ret)
+			return ret;
+
+		offset += chunk;
+		bytes_left -= chunk;
+		p += chunk;
+		blk++;
+	}
+
+	return 0;
+}
+
+static int dbbt_data_create(struct mtd_info *mtd, void *buf, int num_blocks)
+{
+	int		n;
+	int		n_bad_blocks = 0;
+	uint32_t	*bb = buf + 0x8;
+	uint32_t	*n_bad_blocksp = buf + 0x4;
+
+	for (n = 0; n < num_blocks; 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;
+}
+
+/*
+ * This is where it is all done. Takes pointer to a U-Boot image in
+ * RAM and image size, creates FCB/DBBT and writes everything where
+ * it belongs into NAND. Image must be an IMX image built for NAND.
+ */
+static int imx_nand_uboot_update(const void *img, size_t len)
+{
+	int 			i, ret;
+
+	size_t			dummy;
+	loff_t			offset = 0;
+
+	void 			*fcb_raw_page;
+	void			*dbbt_page;
+	void			*dbbt_data_page;
+	void			*ecc;
+
+	uint32_t 		num_blocks_fcb_dbbt;
+	uint32_t		num_blocks_fw;
+
+	struct mtd_info		*mtd;
+	struct fcb_block	*fcb;
+	struct dbbt_block	*dbbt;
+
+	struct mtd_device	*dev;
+	struct part_info	*part;
+	u8			pnum;
+
+	struct fw_write_data	fw;
+
+	if ((mtdparts_init() == 0) &&
+			(find_dev_and_part(uboot_tgt, &dev, &pnum, &part) == 0)) {
+		if (dev->id->type != MTD_DEV_TYPE_NAND) {
+			puts("Not a NAND device\n");
+			return -ENODEV;
+		}
+	}
+
+	nand_curr_device = dev->id->num;
+
+#ifdef CONFIG_SYS_NAND_SELECT_DEVICE
+	board_nand_select_device(nand_info[nand_curr_device].priv, nand_curr_device);
+#endif
+
+	/* Get a pointer to mtd_info for selected device */
+
+	mtd = get_mtd_device_nm("nand0");	/* We always boot off of nand0 */
+
+	if (IS_ERR(mtd)) {
+		/* Should not happen */
+		puts("No nand0 device...\n");
+		return -ENODEV;
+	}
+
+	put_mtd_device(mtd);
+
+	/* Quick and dirty check if we have 2Mbytes of good blocks in nand0,0 */
+
+	i = 0;
+	offset = 0;	/* It is the first partition so it starts at block 0 */
+
+	while (offset < part->size) {
+		if (!mtd_block_isbad(mtd, offset)) {
+			i += mtd->erasesize;
+		}
+		offset += mtd->erasesize;
+	}
+
+	if (i < SZ_2M) {
+		puts("Partition too small for U-Boot!\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * We will use 4 first blocks for FCB/DBBT copies.
+	 * The rest of partition is split in half and used
+	 * for two U-Boot copies. We don't care if those
+	 * start on good or bad block - bad blocks will be
+	 * skipped on write, ROM boot code will also skip
+	 * bad blocks on bootup when loading U-Boot image.
+	 */
+
+	fw.part_blks = part->size / mtd->erasesize;
+	num_blocks_fcb_dbbt = 4;
+	num_blocks_fw = (fw.part_blks - num_blocks_fcb_dbbt) / 2;
+	fw.fw1_blk = num_blocks_fcb_dbbt;
+	fw.fw2_blk = fw.fw1_blk + num_blocks_fw;
+
+	/* OK, now create FCB structure for bootROM NAND boot */
+
+	fcb_raw_page = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
+
+	fcb = fcb_raw_page + 12;
+	ecc = fcb_raw_page + 512 + 12;
+
+	dbbt_page = kzalloc(mtd->writesize, GFP_KERNEL);
+	dbbt_data_page = kzalloc(mtd->writesize, GFP_KERNEL);
+	dbbt = dbbt_page;
+
+	/*
+	 * Write one additional page to make the ROM happy.
+	 * Maybe the PagesInFirmwarex fields are really the
+	 * number of pages - 1. kobs-ng does the same.
+	 */
+
+	fw.len = ALIGN(len + FLASH_OFFSET_STANDARD + mtd->writesize, mtd->writesize);
+	fw.buf = kzalloc(fw.len, GFP_KERNEL);
+	memcpy(fw.buf + FLASH_OFFSET_STANDARD, img, len);
+
+	/* Erase entire partition */
+	ret = imx_nand_uboot_erase(mtd, part);
+	if (ret)
+		goto out;
+
+	/*
+	 * Now write 2 copies of the U-Boot proper to where they belong.
+	 * Headers (FCB, DBBT) will be generated and written after that.
+	 */
+	ret = imx_nand_uboot_write_fw(mtd, &fw);
+	if (ret < 0)
+		goto out;
+
+	/*
+	 * Create FCB, calculate ECC (we don't/can't use hardware ECC
+	 * here so we do it ourselves and then write _RAW_ pages.
+	 */
+
+	fcb->Firmware1_startingPage = fw.fw1_blk * mtd->erasesize / mtd->writesize;
+	fcb->Firmware2_startingPage = fw.fw2_blk * mtd->erasesize / mtd->writesize;
+	fcb->PagesInFirmware1 =
+		ALIGN(len + FLASH_OFFSET_STANDARD, 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.
+	 * We will _NOT_ mark a bad block as good -- we skip the bad blocks.
+	 */
+	memset(fcb_raw_page + mtd->writesize, 0xff, 2);
+
+	/* Now create DBBT */
+	dbbt->Checksum = 0;
+	dbbt->FingerPrint = 0x54424244;
+	dbbt->Version = 0x01000000;
+
+	if ((ret = dbbt_data_create(mtd, dbbt_data_page, fw.part_blks)) < 0)
+		goto out;
+
+	if (ret > 0)
+		dbbt->DBBTNumOfPages = 1;
+
+	offset = 0;
+
+	if (mtd_block_isbad(mtd, offset)) {
+		puts("Block 0 is bad, NAND unusable\n");
+		ret = -EIO;
+		goto out;
+	}
+
+	/*
+	 * Write FCB/DBBT to first 4 blocks. Skip bad blocks if any.
+	 * Less than 4 copies will be written if there were BBs !!!
+	 */
+
+	for (i = 0; i < 4; i++) {
+
+		if (mtd_block_isbad(mtd, offset)) {
+			pr_err("Block %d is bad, skipped\n", i);
+			continue;
+		}
+
+
+		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, &dummy, dbbt_page);
+		if (ret)
+			goto out;
+
+		/* DBBTNumOfPages == 0 if no bad blocks */
+		if (dbbt->DBBTNumOfPages > 0) {
+			ret = mtd_write(mtd, mtd->erasesize * i + mtd->writesize * 5,
+					mtd->writesize, &dummy, dbbt_data_page);
+			if (ret)
+				goto out;
+		}
+	}
+
+out:
+	kfree(dbbt_page);
+	kfree(dbbt_data_page);
+	kfree(fcb_raw_page);
+	kfree(fw.buf);
+
+	return ret;
+}
+
+
+int do_nand_bootupdate(ulong addr, size_t len)
+{
+	/* KSI: Unlock NAND first if it is locked... */
+
+	return imx_nand_uboot_update((const void *)addr, len);
+}
diff --git a/arch/arm/include/asm/imx-common/mxs_nand.h b/arch/arm/include/asm/imx-common/mxs_nand.h
new file mode 100644
index 0000000..7826a9f
--- /dev/null
+++ b/arch/arm/include/asm/imx-common/mxs_nand.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 PHYTEC Messtechnik GmbH,
+ * Author: Stefan Christ <s.christ@phytec.de>
+ *
+ * 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.
+ */
+
+#ifndef __NAND_MXS_H
+#define __NAND_MXS_H
+
+/*
+ * Functions are definied in drivers/mtd/nand/nand_mxs.c.  They are used to
+ * calculate the ECC Strength, BadBlockMarkerByte and BadBlockMarkerStartBit
+ * which are placed into the FCB structure. The i.MX6 ROM needs these
+ * parameters to read the firmware from NAND.
+ *
+ * The parameters depends on the pagesize and oobsize of NAND chips and are
+ * different for each combination. To avoid placing hardcoded values in the bbu
+ * update handler code, the generic calculation from the driver code is used.
+ */
+
+uint32_t mxs_nand_get_ecc_strength(uint32_t page_data_size,
+						uint32_t page_oob_size);
+
+uint32_t mxs_nand_mark_byte_offset(struct mtd_info *mtd);
+
+uint32_t mxs_nand_mark_bit_offset(struct mtd_info *mtd);
+
+#endif /* __NAND_MXS_H */
diff --git a/cmd/nand.c b/cmd/nand.c
index 583a18f..bea3032 100644
--- a/cmd/nand.c
+++ b/cmd/nand.c
@@ -38,6 +38,11 @@ int find_dev_and_part(const char *id, struct mtd_device **dev,
  		      u8 *part_num, struct part_info **part);
  #endif

+#ifdef CONFIG_CMD_NAND_BOOTUPDATE
+/* This comes from a separate file in arch/imx-common */
+int do_nand_bootupdate(ulong addr, size_t len);
+#endif
+
  static int nand_dump(struct mtd_info *mtd, ulong off, int only_oob,
  		     int repeat)
  {
@@ -373,6 +378,9 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  	loff_t off, size, maxsize;
  	char *cmd, *s;
  	struct mtd_info *mtd;
+#ifdef CONFIG_CMD_NAND_BOOTUPDATE
+	size_t cnt;
+#endif
  #ifdef CONFIG_SYS_NAND_QUIET
  	int quiet = CONFIG_SYS_NAND_QUIET;
  #else
@@ -745,6 +753,48 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  	}
  #endif

+#ifdef CONFIG_CMD_NAND_BOOTUPDATE
+	if (strncmp(cmd, "bootupdate", 10) == 0) {
+
+		if (argc < 3) {
+			/* All default values */
+			addr = getenv_ulong("fileaddr", 16, 0UL);
+			cnt = getenv_ulong("filesize", 16, 0UL);
+		}
+
+		if (argc == 3) {
+			/* 'addr' only, file size from environment */
+			if ((addr = simple_strtoul(argv[2], NULL, 16)) == 0UL)
+				addr = getenv_ulong("fileaddr", 16, 0UL);
+
+			cnt = getenv_ulong("filesize", 16, 0UL);
+		}
+
+		if (argc > 3) {
+			/* 'addr', 'size', and possibly more */
+			if ((addr = simple_strtoul(argv[2], NULL, 16)) == 0UL)
+				addr = getenv_ulong("fileaddr", 16, 0UL);
+
+			if ((cnt = simple_strtoul(argv[3], NULL, 16)) == 0UL)
+				cnt = getenv_ulong("filesize", 16, 0UL);
+		}
+
+
+		if (addr == 0 || cnt == 0) {
+			puts("Invalid arguments to nand bootupdate!\n");
+			return 1;
+		}
+
+		if (do_nand_bootupdate(addr, cnt)) {
+			puts("NAND bootupdate failed!\n");
+			return 1;
+		}
+
+		puts("NAND bootupdate successful\n");
+		return 0;
+	}
+#endif
+
  usage:
  	return CMD_RET_USAGE;
  }
@@ -766,6 +816,17 @@ static char nand_help_text[] =
  	"    'addr', skipping bad blocks and dropping any pages at the end\n"
  	"    of eraseblocks that contain only 0xFF\n"
  #endif
+#ifdef CONFIG_CMD_NAND_BOOTUPDATE
+	"nand bootupdate - [addr] [size]\n"
+	"    write U-Boot into NAND in board/SoC specific manner creating all\n"
+	"    required headers and other bits and pieces as required for the\n"
+	"    system to be able to boot off of NAND. 'addr' is the address\n"
+	"    where U-Boot image has been loaded at, 'size' is its size.\n"
+	"    If any of 'addr'/'size' is missing it is taken from environment\n"
+	"    for the last file loaded. U-Boot image must be of a proper type\n"
+	"    for the target platform (only IMX image supported at the moment)\n"
+	"    binary without U-Boot image headers (e.g. u-boot.imx file.)\n"
+#endif
  	"nand erase[.spread] [clean] off size - erase 'size' bytes "
  	"from offset 'off'\n"
  	"    With '.spread', erase enough for given file size, otherwise,\n"
diff --git a/drivers/mtd/nand/mxs_nand.c b/drivers/mtd/nand/mxs_nand.c
index c90a3a7..a7b90bf 100644
--- a/drivers/mtd/nand/mxs_nand.c
+++ b/drivers/mtd/nand/mxs_nand.c
@@ -26,6 +26,7 @@
  #include <asm/imx-common/regs-gpmi.h>
  #include <asm/arch/sys_proto.h>
  #include <asm/imx-common/dma.h>
+#include <asm/imx-common/mxs_nand.h>

  #define	MXS_NAND_DMA_DESCRIPTOR_COUNT		4

@@ -145,7 +146,7 @@ static uint32_t mxs_nand_aux_status_offset(void)
  	return (MXS_NAND_METADATA_SIZE + 0x3) & ~0x3;
  }

-static inline uint32_t mxs_nand_get_ecc_strength(uint32_t page_data_size,
+uint32_t mxs_nand_get_ecc_strength(uint32_t page_data_size,
  						uint32_t page_oob_size)
  {
  	int ecc_strength;
@@ -221,14 +222,14 @@ static inline uint32_t mxs_nand_get_mark_offset(uint32_t page_data_size,
  	return block_mark_bit_offset;
  }

-static uint32_t mxs_nand_mark_byte_offset(struct mtd_info *mtd)
+uint32_t mxs_nand_mark_byte_offset(struct mtd_info *mtd)
  {
  	uint32_t ecc_strength;
  	ecc_strength = mxs_nand_get_ecc_strength(mtd->writesize, mtd->oobsize);
  	return mxs_nand_get_mark_offset(mtd->writesize, ecc_strength) >> 3;
  }

-static uint32_t mxs_nand_mark_bit_offset(struct mtd_info *mtd)
+uint32_t mxs_nand_mark_bit_offset(struct mtd_info *mtd)
  {
  	uint32_t ecc_strength;
  	ecc_strength = mxs_nand_get_ecc_strength(mtd->writesize, mtd->oobsize);


---
******************************************************************
*  KSI at home    KOI8 Net  < >  The impossible we do immediately.  *
*  Las Vegas   NV, USA   < >  Miracles require 24-hour notice.   *
******************************************************************

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

* [U-Boot] [PATCH] i.MX6 nand bootupdate, reworked
  2016-06-18 21:44 [U-Boot] [PATCH] i.MX6 nand bootupdate, reworked Sergey Kubushyn
@ 2016-09-28 16:34 ` Jagan Teki
  2016-09-28 17:03   ` Jagan Teki
  2016-09-28 17:17   ` Sergey Kubushyn
  0 siblings, 2 replies; 6+ messages in thread
From: Jagan Teki @ 2016-09-28 16:34 UTC (permalink / raw)
  To: u-boot

On Sun, Jun 19, 2016 at 3:14 AM, Sergey Kubushyn <ksi@koi8.net> wrote:
> Here is yet another version, diff made against latest u-boot-imx master.
>
> Actual code moved from drivers/mtd/nand to /arch/arm/imx-common, some
> functions renamed. No other changes.


<snip>

>         return CMD_RET_USAGE;
>  }
> @@ -766,6 +816,17 @@ static char nand_help_text[] =
>         "    'addr', skipping bad blocks and dropping any pages at the
> end\n"
>         "    of eraseblocks that contain only 0xFF\n"
>  #endif
> +#ifdef CONFIG_CMD_NAND_BOOTUPDATE
> +       "nand bootupdate - [addr] [size]\n"

What is the addr here the nand offset or the ddr addr? I tried of
doing the same but unable to boot any help?

$ dd if=SPL of=SPL-new bs=512 seek=2
icorem6qdl> tftpboot ${loadaddr} SPL-new
Using FEC device
TFTP from server 192.168.2.96; our IP address is 192.168.2.75
Filename 'SPL-new'.
Load address: 0x12000000
Loading: #######
         1.4 MiB/s
done
Bytes transferred = 32768 (8000 hex)
icorem6qdl> nand bootupdate ${loadaddr} 0x8000
NAND bootupdate successful
icorem6qdl>

thanks!
-- 
Jagan Teki
Free Software Engineer | www.openedev.com
U-Boot, Linux | Upstream Maintainer
Hyderabad, India.

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

* [U-Boot] [PATCH] i.MX6 nand bootupdate, reworked
  2016-09-28 16:34 ` Jagan Teki
@ 2016-09-28 17:03   ` Jagan Teki
  2016-09-28 17:20     ` Sergey Kubushyn
  2016-09-28 17:17   ` Sergey Kubushyn
  1 sibling, 1 reply; 6+ messages in thread
From: Jagan Teki @ 2016-09-28 17:03 UTC (permalink / raw)
  To: u-boot

On Wed, Sep 28, 2016 at 10:04 PM, Jagan Teki <jagannadh.teki@gmail.com> wrote:
> On Sun, Jun 19, 2016 at 3:14 AM, Sergey Kubushyn <ksi@koi8.net> wrote:
>> Here is yet another version, diff made against latest u-boot-imx master.
>>
>> Actual code moved from drivers/mtd/nand to /arch/arm/imx-common, some
>> functions renamed. No other changes.
>
>
> <snip>
>
>>         return CMD_RET_USAGE;
>>  }
>> @@ -766,6 +816,17 @@ static char nand_help_text[] =
>>         "    'addr', skipping bad blocks and dropping any pages at the
>> end\n"
>>         "    of eraseblocks that contain only 0xFF\n"
>>  #endif
>> +#ifdef CONFIG_CMD_NAND_BOOTUPDATE
>> +       "nand bootupdate - [addr] [size]\n"
>
> What is the addr here the nand offset or the ddr addr? I tried of
> doing the same but unable to boot any help?
>
> $ dd if=SPL of=SPL-new bs=512 seek=2

Sorry it's work for me w/o seek hope this is doing inside your code, thanks!


-- 
Jagan Teki
Free Software Engineer | www.openedev.com
U-Boot, Linux | Upstream Maintainer
Hyderabad, India.

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

* [U-Boot] [PATCH] i.MX6 nand bootupdate, reworked
  2016-09-28 16:34 ` Jagan Teki
  2016-09-28 17:03   ` Jagan Teki
@ 2016-09-28 17:17   ` Sergey Kubushyn
  2016-09-28 18:52     ` Jagan Teki
  1 sibling, 1 reply; 6+ messages in thread
From: Sergey Kubushyn @ 2016-09-28 17:17 UTC (permalink / raw)
  To: u-boot

On Wed, 28 Sep 2016, Jagan Teki wrote:

> On Sun, Jun 19, 2016 at 3:14 AM, Sergey Kubushyn <ksi@koi8.net> wrote:
>> Here is yet another version, diff made against latest u-boot-imx master.
>>
>> Actual code moved from drivers/mtd/nand to /arch/arm/imx-common, some
>> functions renamed. No other changes.
>
>
> <snip>
>
>>         return CMD_RET_USAGE;
>>  }
>> @@ -766,6 +816,17 @@ static char nand_help_text[] =
>>         "    'addr', skipping bad blocks and dropping any pages at the
>> end\n"
>>         "    of eraseblocks that contain only 0xFF\n"
>>  #endif
>> +#ifdef CONFIG_CMD_NAND_BOOTUPDATE
>> +       "nand bootupdate - [addr] [size]\n"
>
> What is the addr here the nand offset or the ddr addr? I tried of
> doing the same but unable to boot any help?

It is where the actual U-Boot image is loaded in RAM. If "nand bootupdate"
is done right after reading U-Boot binary into RAM (e.g. with ext4load)
those can be both omitted.

As a matter of fact I'm finishing a bunch of changes to U-Boot, including
that bootupdate command and 2 new boards right now and going to submit all
that either tonight or tomorrow.

NAND bootupdate works like a charm here and we do actually use it in actual
production environment with both Linux and Android; firmware updates do
update U-Boot itself as a part of regular network (or OTA how it is called
in Android) updates.

Will try to write a small README file on that if times permitted.

Please note that it has been only tested on i.MX6 (don't have anything else
here; all our boards are i.MX6D/Q/DL.) We do not use SPL.

As of your case I'm not exactly sure what you are trying to achieve. That
entire NAND boot thing with all FCB/DBBT/whatever only applies to INITIAL
boot off of raw NAND device. It allows to boot either the full U-Boot or
SPL using i.MX6 NAND ROM boot routine that reads that FCB and whatever
else then loads actual binary (either U-Boot or SPL or whatever) according
to information in that FCB and runs it.

If you are booting your SPL off of some other media and then trying to load
second stage U-Boot from raw NAND you don't need all that FCB kabang. The
DCB part (if U-Boot is built as i.MX6 image) is also not needed so it can
be stripped or skipped. However your SPL must properly configure NAND
itself so it would be able to read from it and it should include all stuff
required to actually read data from NAND.

The FCB/DBBT stuff is only needed for initial boot off of raw NAND. If you
are going to boot off of NAND and want to have your U-Boot in NAND (that is
the only logical use of NAND for U-Boot) I can not see any reason for going
SPL road but you might have your own reasons that I don't know.

---
******************************************************************
*  KSI at home    KOI8 Net  < >  The impossible we do immediately.  *
*  Las Vegas   NV, USA   < >  Miracles require 24-hour notice.   *
******************************************************************

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

* [U-Boot] [PATCH] i.MX6 nand bootupdate, reworked
  2016-09-28 17:03   ` Jagan Teki
@ 2016-09-28 17:20     ` Sergey Kubushyn
  0 siblings, 0 replies; 6+ messages in thread
From: Sergey Kubushyn @ 2016-09-28 17:20 UTC (permalink / raw)
  To: u-boot

On Wed, 28 Sep 2016, Jagan Teki wrote:

> On Wed, Sep 28, 2016 at 10:04 PM, Jagan Teki <jagannadh.teki@gmail.com> wrote:
>> On Sun, Jun 19, 2016 at 3:14 AM, Sergey Kubushyn <ksi@koi8.net> wrote:
>>> Here is yet another version, diff made against latest u-boot-imx master.
>>>
>>> Actual code moved from drivers/mtd/nand to /arch/arm/imx-common, some
>>> functions renamed. No other changes.
>>
>>
>> <snip>
>>
>>>         return CMD_RET_USAGE;
>>>  }
>>> @@ -766,6 +816,17 @@ static char nand_help_text[] =
>>>         "    'addr', skipping bad blocks and dropping any pages at the
>>> end\n"
>>>         "    of eraseblocks that contain only 0xFF\n"
>>>  #endif
>>> +#ifdef CONFIG_CMD_NAND_BOOTUPDATE
>>> +       "nand bootupdate - [addr] [size]\n"
>>
>> What is the addr here the nand offset or the ddr addr? I tried of
>> doing the same but unable to boot any help?
>>
>> $ dd if=SPL of=SPL-new bs=512 seek=2
>
> Sorry it's work for me w/o seek hope this is doing inside your code, thanks!

Yep, it is taken care of inside nand bootupdate code -- it allows to
just load u-boot.imx image without bothering with offsets or skipping
that leading empty kilobyte yourself.

---
******************************************************************
*  KSI at home    KOI8 Net  < >  The impossible we do immediately.  *
*  Las Vegas   NV, USA   < >  Miracles require 24-hour notice.   *
******************************************************************

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

* [U-Boot] [PATCH] i.MX6 nand bootupdate, reworked
  2016-09-28 17:17   ` Sergey Kubushyn
@ 2016-09-28 18:52     ` Jagan Teki
  0 siblings, 0 replies; 6+ messages in thread
From: Jagan Teki @ 2016-09-28 18:52 UTC (permalink / raw)
  To: u-boot

On Wed, Sep 28, 2016 at 10:47 PM, Sergey Kubushyn <ksi@koi8.net> wrote:
> On Wed, 28 Sep 2016, Jagan Teki wrote:
>
>> On Sun, Jun 19, 2016 at 3:14 AM, Sergey Kubushyn <ksi@koi8.net> wrote:
>>>
>>> Here is yet another version, diff made against latest u-boot-imx master.
>>>
>>> Actual code moved from drivers/mtd/nand to /arch/arm/imx-common, some
>>> functions renamed. No other changes.
>>
>>
>>
>> <snip>
>>
>>>         return CMD_RET_USAGE;
>>>  }
>>> @@ -766,6 +816,17 @@ static char nand_help_text[] =
>>>         "    'addr', skipping bad blocks and dropping any pages at the
>>> end\n"
>>>         "    of eraseblocks that contain only 0xFF\n"
>>>  #endif
>>> +#ifdef CONFIG_CMD_NAND_BOOTUPDATE
>>> +       "nand bootupdate - [addr] [size]\n"
>>
>>
>> What is the addr here the nand offset or the ddr addr? I tried of
>> doing the same but unable to boot any help?
>
>
> It is where the actual U-Boot image is loaded in RAM. If "nand bootupdate"
> is done right after reading U-Boot binary into RAM (e.g. with ext4load)
> those can be both omitted.
>
> As a matter of fact I'm finishing a bunch of changes to U-Boot, including
> that bootupdate command and 2 new boards right now and going to submit all
> that either tonight or tomorrow.
>
> NAND bootupdate works like a charm here and we do actually use it in actual
> production environment with both Linux and Android; firmware updates do
> update U-Boot itself as a part of regular network (or OTA how it is called
> in Android) updates.
>
> Will try to write a small README file on that if times permitted.

True, good to have.

>
> Please note that it has been only tested on i.MX6 (don't have anything else
> here; all our boards are i.MX6D/Q/DL.) We do not use SPL.
>
> As of your case I'm not exactly sure what you are trying to achieve. That
> entire NAND boot thing with all FCB/DBBT/whatever only applies to INITIAL
> boot off of raw NAND device. It allows to boot either the full U-Boot or
> SPL using i.MX6 NAND ROM boot routine that reads that FCB and whatever
> else then loads actual binary (either U-Boot or SPL or whatever) according
> to information in that FCB and runs it.
>
> If you are booting your SPL off of some other media and then trying to load
> second stage U-Boot from raw NAND you don't need all that FCB kabang. The
> DCB part (if U-Boot is built as i.MX6 image) is also not needed so it can
> be stripped or skipped. However your SPL must properly configure NAND
> itself so it would be able to read from it and it should include all stuff
> required to actually read data from NAND.
>
> The FCB/DBBT stuff is only needed for initial boot off of raw NAND. If you
> are going to boot off of NAND and want to have your U-Boot in NAND (that is
> the only logical use of NAND for U-Boot) I can not see any reason for going
> SPL road but you might have your own reasons that I don't know.

Since ROM expects the FCB/DBBT this tool adding that so I updated SPL
and written u-boot-dtb.img using 'nand write'

thanks!
-- 
Jagan Teki
Free Software Engineer | www.openedev.com
U-Boot, Linux | Upstream Maintainer
Hyderabad, India.

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

end of thread, other threads:[~2016-09-28 18:52 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-06-18 21:44 [U-Boot] [PATCH] i.MX6 nand bootupdate, reworked Sergey Kubushyn
2016-09-28 16:34 ` Jagan Teki
2016-09-28 17:03   ` Jagan Teki
2016-09-28 17:20     ` Sergey Kubushyn
2016-09-28 17:17   ` Sergey Kubushyn
2016-09-28 18:52     ` Jagan Teki

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.