[PATCH 2/2] ARM i.MX: cleanup boot modes

Sascha Hauer s.hauer at pengutronix.de
Thu Feb 24 10:55:07 EST 2011


The i.MX Processors support two different boot modes, the internal
boot mode and the external boot mode. Traditionally the external
NAND boot mode is handled in drivers/mtd/nand and the internal
boot mode is handled in arch/arm/mach-imx. This patch consolidates
the handling of both boot modes in arch/arm/mach-imx so that
the user does not have to look in the mtd kconfig section for
booting from NAND. Also, selecting between internal and external
boot mode now is a clear choice.
The external NAND boot mode has been independent of the mtd nand
driver, but as the code was contained in the NAND driver it was
not possible to support booting from NAND without a mtd nand driver.
This is changed with this patch.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 arch/arm/mach-imx/Kconfig                 |   51 +++++
 arch/arm/mach-imx/Makefile                |    1 +
 arch/arm/mach-imx/include/mach/imx-nand.h |   56 +++++-
 arch/arm/mach-imx/internal-nand-boot.c    |  269 +++++++++++++++++++++++++
 drivers/mtd/nand/Kconfig                  |   21 --
 drivers/mtd/nand/nand_imx.c               |  307 -----------------------------
 6 files changed, 376 insertions(+), 329 deletions(-)
 create mode 100644 arch/arm/mach-imx/internal-nand-boot.c

diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 235f644..5454505 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -39,10 +39,35 @@ config BOARDINFO
 	default "Garz+Fricke Cupid" if MACH_GUF_CUPID
 	default "Ka-Ro tx25" if MACH_TX25
 
+choice
+	prompt "Select boot mode"
+	help
+	  i.MX processors support two different boot modes. With the internal
+	  boot mode the boot medium contains a header describing the image to
+	  load. The header also contains a register/value table which can be
+	  used to setup SDRAM. The internal ROM code then initializes SDRAM
+	  using the register/value table, loads the whole barebox image to
+	  SDRAM and starts it. The internal boot mode is available on newer
+	  i.MX processors (i.MX25, i.MX35 and i.MX51). and supports booting
+	  from NOR, NAND, MMC/SD and serial ROMs.
+	  The external boot mode only supports booting from NAND and NOR. With
+	  NOR flash the image is just started in NOR flash. With NAND flash
+	  the NAND controller loads the first 2kbyte from NAND into the NAND
+	  controllers internal SRAM where it is then started. It's the
+	  responsibility of these 2kbyte to load the rest of the boot image.
+	  The external boot mode is supported on older i.MX processors (i.MX1,
+	  i.MX21, i.MX25, i.MX27, i.MX21, i.MX35).
+
 config ARCH_IMX_INTERNAL_BOOT
 	bool "support internal boot mode"
 	depends on ARCH_IMX25 || ARCH_IMX35 || ARCH_IMX51
 
+config ARCH_IMX_EXTERNAL_BOOT
+	bool "support external boot mode"
+	depends on ARCH_IMX1 || ARCH_IMX21 || ARCH_IMX25 || ARCH_IMX27 || ARCH_IMX31 || ARCH_IMX35
+
+endchoice
+
 choice
 	depends on ARCH_IMX_INTERNAL_BOOT
 	prompt "Internal boot source"
@@ -64,6 +89,32 @@ config ARCH_IMX_INTERNAL_BOOT_ONENAND
 
 endchoice
 
+config NAND_IMX_BOOT
+	bool
+	depends on ARCH_IMX_EXTERNAL_BOOT_NAND
+	default y
+
+config ARCH_IMX_EXTERNAL_BOOT_NAND
+	bool
+	prompt "Support Starting barebox from NAND"
+	depends on ARCH_IMX_EXTERNAL_BOOT
+
+choice
+	depends on ARCH_IMX_EXTERNAL_BOOT_NAND
+	default NAND_IMX_BOOT_512_2K
+	prompt "select nand pagesize you want to support booting from"
+
+config NAND_IMX_BOOT_512
+	bool "512 byte page size"
+
+config NAND_IMX_BOOT_2K
+	bool "2048 byte page size"
+
+config NAND_IMX_BOOT_512_2K
+	bool "512 byte and 2048 byte pagesize"
+
+endchoice
+
 comment "Freescale i.MX System-on-Chip"
 
 choice
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index 3b2deaf..5fcaac9 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_ARCH_IMX51) += speed-imx51.o imx51.o iomux-v3.o
 obj-$(CONFIG_IMX_CLKO)	+= clko.o
 obj-$(CONFIG_IMX_IIM)	+= iim.o
 obj-$(CONFIG_NAND_IMX) += nand.o
+obj-$(CONFIG_ARCH_IMX_EXTERNAL_BOOT_NAND) += internal-nand-boot.o
 obj-y += speed.o
 obj-y += devices.o
 obj-y += boot.o
diff --git a/arch/arm/mach-imx/include/mach/imx-nand.h b/arch/arm/mach-imx/include/mach/imx-nand.h
index eb583a2..22462b2 100644
--- a/arch/arm/mach-imx/include/mach/imx-nand.h
+++ b/arch/arm/mach-imx/include/mach/imx-nand.h
@@ -11,5 +11,59 @@ struct imx_nand_platform_data {
 	unsigned int hw_ecc:1;
 	unsigned int flash_bbt:1;
 };
-#endif /* __ASM_ARCH_NAND_H */
 
+#define nfc_is_v21()		(cpu_is_mx25() || cpu_is_mx35())
+#define nfc_is_v1()		(cpu_is_mx31() || cpu_is_mx27() || cpu_is_mx21())
+#define nfc_is_v3_2()		cpu_is_mx51()
+#define nfc_is_v3()		nfc_is_v3_2()
+
+#define NFC_V1_ECC_STATUS_RESULT	0x0c
+#define NFC_V1_RSLTMAIN_AREA		0x0e
+#define NFC_V1_RSLTSPARE_AREA		0x10
+
+#define NFC_V2_ECC_STATUS_RESULT1	0x0c
+#define NFC_V2_ECC_STATUS_RESULT2	0x0e
+#define NFC_V2_SPAS			0x10
+
+#define NFC_V1_V2_BUF_SIZE		0x00
+#define NFC_V1_V2_BUF_ADDR		0x04
+#define NFC_V1_V2_FLASH_ADDR		0x06
+#define NFC_V1_V2_FLASH_CMD		0x08
+#define NFC_V1_V2_CONFIG		0x0a
+
+#define NFC_V1_V2_WRPROT		0x12
+#define NFC_V1_UNLOCKSTART_BLKADDR	0x14
+#define NFC_V1_UNLOCKEND_BLKADDR	0x16
+#define NFC_V21_UNLOCKSTART_BLKADDR	0x20
+#define NFC_V21_UNLOCKEND_BLKADDR	0x22
+#define NFC_V1_V2_NF_WRPRST		0x18
+#define NFC_V1_V2_CONFIG1		0x1a
+#define NFC_V1_V2_CONFIG2		0x1c
+
+#define NFC_V2_CONFIG1_ECC_MODE_4       (1 << 0)
+#define NFC_V1_V2_CONFIG1_SP_EN		(1 << 2)
+#define NFC_V1_V2_CONFIG1_ECC_EN	(1 << 3)
+#define NFC_V1_V2_CONFIG1_INT_MSK	(1 << 4)
+#define NFC_V1_V2_CONFIG1_BIG		(1 << 5)
+#define NFC_V1_V2_CONFIG1_RST		(1 << 6)
+#define NFC_V1_V2_CONFIG1_CE		(1 << 7)
+#define NFC_V1_V2_CONFIG1_ONE_CYCLE	(1 << 8)
+#define NFC_V2_CONFIG1_PPB(x)		(((x) & 0x3) << 9)
+#define NFC_V2_CONFIG1_FP_INT		(1 << 11)
+
+#define NFC_V1_V2_CONFIG2_INT		(1 << 15)
+
+#define NFC_V2_SPAS_SPARESIZE(spas)	((spas) >> 1)
+
+/*
+ * Operation modes for the NFC. Valid for v1, v2 and v3
+ * type controllers.
+ */
+#define NFC_CMD				(1 << 0)
+#define NFC_ADDR			(1 << 1)
+#define NFC_INPUT			(1 << 2)
+#define NFC_OUTPUT			(1 << 3)
+#define NFC_ID				(1 << 4)
+#define NFC_STATUS			(1 << 5)
+
+#endif /* __ASM_ARCH_NAND_H */
diff --git a/arch/arm/mach-imx/internal-nand-boot.c b/arch/arm/mach-imx/internal-nand-boot.c
new file mode 100644
index 0000000..0d71b99
--- /dev/null
+++ b/arch/arm/mach-imx/internal-nand-boot.c
@@ -0,0 +1,269 @@
+/*
+ * 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, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <init.h>
+#include <asm/io.h>
+#include <linux/mtd/nand.h>
+#include <mach/imx-nand.h>
+#include <mach/generic.h>
+#include <mach/imx-regs.h>
+
+static void __bare_init noinline imx_nandboot_wait_op_done(void *regs)
+{
+	u32 r;
+
+	while (1) {
+		r = readw(regs + NFC_V1_V2_CONFIG2);
+		if (r & NFC_V1_V2_CONFIG2_INT)
+			break;
+	};
+
+	r &= ~NFC_V1_V2_CONFIG2_INT;
+
+	writew(r, regs + NFC_V1_V2_CONFIG2);
+}
+
+/*
+ * This function issues the specified command to the NAND device and
+ * waits for completion.
+ *
+ * @param       cmd     command for NAND Flash
+ */
+static void __bare_init imx_nandboot_send_cmd(void *regs, u16 cmd)
+{
+	writew(cmd, regs + NFC_V1_V2_FLASH_CMD);
+	writew(NFC_CMD, regs + NFC_V1_V2_CONFIG2);
+
+	imx_nandboot_wait_op_done(regs);
+}
+
+/*
+ * This function sends an address (or partial address) to the
+ * NAND device.  The address is used to select the source/destination for
+ * a NAND command.
+ *
+ * @param       addr    address to be written to NFC.
+ * @param       islast  True if this is the last address cycle for command
+ */
+static void __bare_init noinline imx_nandboot_send_addr(void *regs, u16 addr)
+{
+	writew(addr, regs + NFC_V1_V2_FLASH_ADDR);
+	writew(NFC_ADDR, regs + NFC_V1_V2_CONFIG2);
+
+	/* Wait for operation to complete */
+	imx_nandboot_wait_op_done(regs);
+}
+
+static void __bare_init imx_nandboot_nfc_addr(void *regs, u32 offs, int pagesize_2k)
+{
+	imx_nandboot_send_addr(regs, offs & 0xff);
+
+	if (pagesize_2k) {
+		imx_nandboot_send_addr(regs, offs & 0xff);
+		imx_nandboot_send_addr(regs, (offs >> 11) & 0xff);
+		imx_nandboot_send_addr(regs, (offs >> 19) & 0xff);
+		imx_nandboot_send_addr(regs, (offs >> 27) & 0xff);
+		imx_nandboot_send_cmd(regs, NAND_CMD_READSTART);
+	} else {
+		imx_nandboot_send_addr(regs, (offs >> 9) & 0xff);
+		imx_nandboot_send_addr(regs, (offs >> 17) & 0xff);
+		imx_nandboot_send_addr(regs, (offs >> 25) & 0xff);
+	}
+}
+
+static void __bare_init imx_nandboot_send_page(void *regs,
+		unsigned int ops, int pagesize_2k)
+{
+	int bufs, i;
+
+	if (nfc_is_v1() && pagesize_2k)
+		bufs = 4;
+	else
+		bufs = 1;
+
+	for (i = 0; i < bufs; i++) {
+		/* NANDFC buffer 0 is used for page read/write */
+		writew(i, regs + NFC_V1_V2_BUF_ADDR);
+
+		writew(ops, regs + NFC_V1_V2_CONFIG2);
+
+		/* Wait for operation to complete */
+		imx_nandboot_wait_op_done(regs);
+	}
+}
+
+static void __bare_init __memcpy32(void *trg, const void *src, int size)
+{
+	int i;
+	unsigned int *t = trg;
+	unsigned const int *s = src;
+
+	for (i = 0; i < (size >> 2); i++)
+		*t++ = *s++;
+}
+
+static int __maybe_unused is_pagesize_2k(void)
+{
+#ifdef CONFIG_ARCH_IMX21
+	if (readl(IMX_SYSTEM_CTL_BASE + 0x14) & (1 << 5))
+		return 1;
+	else
+		return 0;
+#endif
+#ifdef CONFIG_ARCH_IMX27
+	if (readl(IMX_SYSTEM_CTL_BASE + 0x14) & (1 << 5))
+		return 1;
+	else
+		return 0;
+#endif
+#ifdef CONFIG_ARCH_IMX31
+	if (readl(IMX_CCM_BASE + CCM_RCSR) & RCSR_NFMS)
+		return 1;
+	else
+		return 0;
+#endif
+#if defined(CONFIG_ARCH_IMX35) || defined(CONFIG_ARCH_IMX25)
+	if (readl(IMX_CCM_BASE + CCM_RCSR) & (1 << 8))
+		return 1;
+	else
+		return 0;
+#endif
+}
+
+void __bare_init imx_nand_load_image(void *dest, int size)
+{
+	u32 tmp, page, block, blocksize, pagesize;
+	int pagesize_2k = 1;
+	void *regs, *base, *spare0;
+
+#if defined(CONFIG_NAND_IMX_BOOT_512)
+	pagesize_2k = 0;
+#elif defined(CONFIG_NAND_IMX_BOOT_2K)
+	pagesize_2k = 1;
+#else
+	pagesize_2k = is_pagesize_2k();
+#endif
+
+	if (pagesize_2k) {
+		pagesize = 2048;
+		blocksize = 128 * 1024;
+	} else {
+		pagesize = 512;
+		blocksize = 16 * 1024;
+	}
+
+	base = (void __iomem *)IMX_NFC_BASE;
+	if (nfc_is_v21()) {
+		regs = base + 0x1e00;
+		spare0 = base + 0x1000;
+	} else if (nfc_is_v1()) {
+		regs = base + 0xe00;
+		spare0 = base + 0x800;
+	}
+
+	imx_nandboot_send_cmd(regs, NAND_CMD_RESET);
+
+	/* preset operation */
+	/* Unlock the internal RAM Buffer */
+	writew(0x2, regs + NFC_V1_V2_CONFIG);
+
+	/* Unlock Block Command for given address range */
+	writew(0x4, regs + NFC_V1_V2_WRPROT);
+
+	tmp = readw(regs + NFC_V1_V2_CONFIG1);
+	tmp |= NFC_V1_V2_CONFIG1_ECC_EN;
+	if (nfc_is_v21())
+		/* currently no support for 218 byte OOB with stronger ECC */
+		tmp |= NFC_V2_CONFIG1_ECC_MODE_4;
+	tmp &= ~(NFC_V1_V2_CONFIG1_SP_EN | NFC_V1_V2_CONFIG1_INT_MSK);
+	writew(tmp, regs + NFC_V1_V2_CONFIG1);
+
+	if (nfc_is_v21()) {
+		if (pagesize_2k)
+			writew(NFC_V2_SPAS_SPARESIZE(64), regs + NFC_V2_SPAS);
+		else
+			writew(NFC_V2_SPAS_SPARESIZE(16), regs + NFC_V2_SPAS);
+	}
+
+	block = page = 0;
+
+	while (1) {
+		page = 0;
+		while (page * pagesize < blocksize) {
+			debug("page: %d block: %d dest: %p src "
+					"0x%08x\n",
+					page, block, dest,
+					block * blocksize +
+					page * pagesize);
+
+			imx_nandboot_send_cmd(regs, NAND_CMD_READ0);
+			imx_nandboot_nfc_addr(regs, block * blocksize +
+					page * pagesize, pagesize_2k);
+			imx_nandboot_send_page(regs, NFC_OUTPUT, pagesize_2k);
+			page++;
+
+			if (pagesize_2k) {
+				if ((readw(spare0) & 0xff) != 0xff)
+					continue;
+			} else {
+				if ((readw(spare0 + 4) & 0xff00) != 0xff00)
+					continue;
+			}
+
+			__memcpy32(dest, base, pagesize);
+			dest += pagesize;
+			size -= pagesize;
+
+			if (size <= 0)
+				return;
+		}
+		block++;
+	}
+}
+
+#define CONFIG_NAND_IMX_BOOT_DEBUG
+#ifdef CONFIG_NAND_IMX_BOOT_DEBUG
+#include <command.h>
+
+static int do_nand_boot_test(struct command *cmdtp, int argc, char *argv[])
+{
+	void *dest;
+	int size;
+
+	if (argc < 3)
+		return COMMAND_ERROR_USAGE;
+
+	dest = (void *)strtoul_suffix(argv[1], NULL, 0);
+	size = strtoul_suffix(argv[2], NULL, 0);
+
+	imx_nand_load_image(dest, size);
+
+	return 0;
+}
+
+static const __maybe_unused char cmd_nand_boot_test_help[] =
+"Usage: nand_boot_test <dest> <size>\n"
+"This command loads the booloader from the NAND memory like the reset\n"
+"routine does. Its intended for development tests only";
+
+BAREBOX_CMD_START(nand_boot_test)
+	.cmd		= do_nand_boot_test,
+	.usage		= "load bootloader from NAND",
+	BAREBOX_CMD_HELP(cmd_nand_boot_test_help)
+BAREBOX_CMD_END
+#endif
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 034bb6f..12e1237 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -13,27 +13,6 @@ config NAND_IMX
 	prompt "i.MX NAND driver"
 	depends on ARCH_IMX21 || ARCH_IMX27 || ARCH_IMX31 || ARCH_IMX35 || ARCH_IMX25 || ARCH_IMX51
 
-config NAND_IMX_BOOT
-	bool
-	prompt "Support Starting barebox from NAND"
-	depends on NAND_IMX && !ARCH_IMX51
-
-choice
-	depends on NAND_IMX_BOOT
-	default NAND_IMX_BOOT_512_2K
-	prompt "select nand pagesize you want to support booting from"
-
-config NAND_IMX_BOOT_512
-	bool "512 byte page size"
-
-config NAND_IMX_BOOT_2K
-	bool "2048 byte page size"
-
-config NAND_IMX_BOOT_512_2K
-	bool "512 byte and 2048 byte pagesize"
-
-endchoice
-
 config NAND_OMAP_GPMC
 	tristate "NAND Flash Support for GPMC based OMAP platforms"
 	depends on ((ARCH_OMAP2 || ARCH_OMAP3) && GPMC)
diff --git a/drivers/mtd/nand/nand_imx.c b/drivers/mtd/nand/nand_imx.c
index 9a15ab2..ca6e55b 100644
--- a/drivers/mtd/nand/nand_imx.c
+++ b/drivers/mtd/nand/nand_imx.c
@@ -30,60 +30,6 @@
 #include <asm/io.h>
 #include <errno.h>
 
-#define nfc_is_v21()		(cpu_is_mx25() || cpu_is_mx35())
-#define nfc_is_v1()		(cpu_is_mx31() || cpu_is_mx27() || cpu_is_mx21())
-#define nfc_is_v3_2()		cpu_is_mx51()
-#define nfc_is_v3()		nfc_is_v3_2()
-
-#define NFC_V1_ECC_STATUS_RESULT	0x0c
-#define NFC_V1_RSLTMAIN_AREA		0x0e
-#define NFC_V1_RSLTSPARE_AREA		0x10
-
-#define NFC_V2_ECC_STATUS_RESULT1	0x0c
-#define NFC_V2_ECC_STATUS_RESULT2	0x0e
-#define NFC_V2_SPAS			0x10
-
-#define NFC_V1_V2_BUF_SIZE		0x00
-#define NFC_V1_V2_BUF_ADDR		0x04
-#define NFC_V1_V2_FLASH_ADDR		0x06
-#define NFC_V1_V2_FLASH_CMD		0x08
-#define NFC_V1_V2_CONFIG		0x0a
-
-#define NFC_V1_V2_WRPROT		0x12
-#define NFC_V1_UNLOCKSTART_BLKADDR	0x14
-#define NFC_V1_UNLOCKEND_BLKADDR	0x16
-#define NFC_V21_UNLOCKSTART_BLKADDR	0x20
-#define NFC_V21_UNLOCKEND_BLKADDR	0x22
-#define NFC_V1_V2_NF_WRPRST		0x18
-#define NFC_V1_V2_CONFIG1		0x1a
-#define NFC_V1_V2_CONFIG2		0x1c
-
-#define NFC_V2_CONFIG1_ECC_MODE_4       (1 << 0)
-#define NFC_V1_V2_CONFIG1_SP_EN		(1 << 2)
-#define NFC_V1_V2_CONFIG1_ECC_EN	(1 << 3)
-#define NFC_V1_V2_CONFIG1_INT_MSK	(1 << 4)
-#define NFC_V1_V2_CONFIG1_BIG		(1 << 5)
-#define NFC_V1_V2_CONFIG1_RST		(1 << 6)
-#define NFC_V1_V2_CONFIG1_CE		(1 << 7)
-#define NFC_V1_V2_CONFIG1_ONE_CYCLE	(1 << 8)
-#define NFC_V2_CONFIG1_PPB(x)		(((x) & 0x3) << 9)
-#define NFC_V2_CONFIG1_FP_INT		(1 << 11)
-
-#define NFC_V1_V2_CONFIG2_INT		(1 << 15)
-
-#define NFC_V2_SPAS_SPARESIZE(spas)	((spas) >> 1)
-
-/*
- * Operation modes for the NFC. Valid for v1, v2 and v3
- * type controllers.
- */
-#define NFC_CMD				(1 << 0)
-#define NFC_ADDR			(1 << 1)
-#define NFC_INPUT			(1 << 2)
-#define NFC_OUTPUT			(1 << 3)
-#define NFC_ID				(1 << 4)
-#define NFC_STATUS			(1 << 5)
-
 #define NFC_V3_FLASH_CMD		(host->regs_axi + 0x00)
 #define NFC_V3_FLASH_ADDR0		(host->regs_axi + 0x04)
 
@@ -132,12 +78,6 @@
 
 #define NFC_V3_DELAY_LINE		(host->regs_ip + 0x34)
 
-#ifdef CONFIG_NAND_IMX_BOOT
-#define __nand_boot_init __bare_init
-#else
-#define __nand_boot_init
-#endif
-
 struct imx_nand_host {
 	struct mtd_info		mtd;		
 	struct nand_chip	nand;
@@ -1239,253 +1179,6 @@ static struct driver_d imx_nand_driver = {
 	.probe = imxnd_probe,
 };
 
-#ifdef CONFIG_NAND_IMX_BOOT
-static void __nand_boot_init noinline imx_nandboot_wait_op_done(void *regs)
-{
-	u32 r;
-
-	while (1) {
-		r = readw(regs + NFC_V1_V2_CONFIG2);
-		if (r & NFC_V1_V2_CONFIG2_INT)
-			break;
-	};
-
-	r &= ~NFC_V1_V2_CONFIG2_INT;
-
-	writew(r, regs + NFC_V1_V2_CONFIG2);
-}
-
-/*
- * This function issues the specified command to the NAND device and
- * waits for completion.
- *
- * @param       cmd     command for NAND Flash
- */
-static void __nand_boot_init imx_nandboot_send_cmd(void *regs, u16 cmd)
-{
-	writew(cmd, regs + NFC_V1_V2_FLASH_CMD);
-	writew(NFC_CMD, regs + NFC_V1_V2_CONFIG2);
-
-	imx_nandboot_wait_op_done(regs);
-}
-
-/*
- * This function sends an address (or partial address) to the
- * NAND device.  The address is used to select the source/destination for
- * a NAND command.
- *
- * @param       addr    address to be written to NFC.
- * @param       islast  True if this is the last address cycle for command
- */
-static void __nand_boot_init noinline imx_nandboot_send_addr(void *regs, u16 addr)
-{
-	writew(addr, regs + NFC_V1_V2_FLASH_ADDR);
-	writew(NFC_ADDR, regs + NFC_V1_V2_CONFIG2);
-
-	/* Wait for operation to complete */
-	imx_nandboot_wait_op_done(regs);
-}
-
-static void __nand_boot_init imx_nandboot_nfc_addr(void *regs, u32 offs, int pagesize_2k)
-{
-	imx_nandboot_send_addr(regs, offs & 0xff);
-
-	if (pagesize_2k) {
-		imx_nandboot_send_addr(regs, offs & 0xff);
-		imx_nandboot_send_addr(regs, (offs >> 11) & 0xff);
-		imx_nandboot_send_addr(regs, (offs >> 19) & 0xff);
-		imx_nandboot_send_addr(regs, (offs >> 27) & 0xff);
-		imx_nandboot_send_cmd(regs, NAND_CMD_READSTART);
-	} else {
-		imx_nandboot_send_addr(regs, (offs >> 9) & 0xff);
-		imx_nandboot_send_addr(regs, (offs >> 17) & 0xff);
-		imx_nandboot_send_addr(regs, (offs >> 25) & 0xff);
-	}
-}
-
-static void __nand_boot_init imx_nandboot_send_page(void *regs,
-		unsigned int ops, int pagesize_2k)
-{
-	int bufs, i;
-
-	if (nfc_is_v1() && pagesize_2k)
-		bufs = 4;
-	else
-		bufs = 1;
-
-	for (i = 0; i < bufs; i++) {
-		/* NANDFC buffer 0 is used for page read/write */
-		writew(i, regs + NFC_V1_V2_BUF_ADDR);
-
-		writew(ops, regs + NFC_V1_V2_CONFIG2);
-
-		/* Wait for operation to complete */
-		imx_nandboot_wait_op_done(regs);
-	}
-}
-
-static void __nand_boot_init __memcpy32(void *trg, const void *src, int size)
-{
-	int i;
-	unsigned int *t = trg;
-	unsigned const int *s = src;
-
-	for (i = 0; i < (size >> 2); i++)
-		*t++ = *s++;
-}
-
-static int __maybe_unused is_pagesize_2k(void)
-{
-#ifdef CONFIG_ARCH_IMX21
-	if (readl(IMX_SYSTEM_CTL_BASE + 0x14) & (1 << 5))
-		return 1;
-	else
-		return 0;
-#endif
-#ifdef CONFIG_ARCH_IMX27
-	if (readl(IMX_SYSTEM_CTL_BASE + 0x14) & (1 << 5))
-		return 1;
-	else
-		return 0;
-#endif
-#ifdef CONFIG_ARCH_IMX31
-	if (readl(IMX_CCM_BASE + CCM_RCSR) & RCSR_NFMS)
-		return 1;
-	else
-		return 0;
-#endif
-#if defined(CONFIG_ARCH_IMX35) || defined(CONFIG_ARCH_IMX25)
-	if (readl(IMX_CCM_BASE + CCM_RCSR) & (1 << 8))
-		return 1;
-	else
-		return 0;
-#endif
-}
-
-void __nand_boot_init imx_nand_load_image(void *dest, int size)
-{
-	u32 tmp, page, block, blocksize, pagesize;
-	int pagesize_2k = 1;
-	void *regs, *base, *spare0;
-
-#if defined(CONFIG_NAND_IMX_BOOT_512)
-	pagesize_2k = 0;
-#elif defined(CONFIG_NAND_IMX_BOOT_2K)
-	pagesize_2k = 1;
-#else
-	pagesize_2k = is_pagesize_2k();
-#endif
-
-	if (pagesize_2k) {
-		pagesize = 2048;
-		blocksize = 128 * 1024;
-	} else {
-		pagesize = 512;
-		blocksize = 16 * 1024;
-	}
-
-	base = (void __iomem *)IMX_NFC_BASE;
-	if (nfc_is_v21()) {
-		regs = base + 0x1e00;
-		spare0 = base + 0x1000;
-	} else if (nfc_is_v1()) {
-		regs = base + 0xe00;
-		spare0 = base + 0x800;
-	}
-
-	imx_nandboot_send_cmd(regs, NAND_CMD_RESET);
-
-	/* preset operation */
-	/* Unlock the internal RAM Buffer */
-	writew(0x2, regs + NFC_V1_V2_CONFIG);
-
-	/* Unlock Block Command for given address range */
-	writew(0x4, regs + NFC_V1_V2_WRPROT);
-
-	tmp = readw(regs + NFC_V1_V2_CONFIG1);
-	tmp |= NFC_V1_V2_CONFIG1_ECC_EN;
-	if (nfc_is_v21())
-		/* currently no support for 218 byte OOB with stronger ECC */
-		tmp |= NFC_V2_CONFIG1_ECC_MODE_4;
-	tmp &= ~(NFC_V1_V2_CONFIG1_SP_EN | NFC_V1_V2_CONFIG1_INT_MSK);
-	writew(tmp, regs + NFC_V1_V2_CONFIG1);
-
-	if (nfc_is_v21()) {
-		if (pagesize_2k)
-			writew(NFC_V2_SPAS_SPARESIZE(64), regs + NFC_V2_SPAS);
-		else
-			writew(NFC_V2_SPAS_SPARESIZE(16), regs + NFC_V2_SPAS);
-	}
-
-	block = page = 0;
-
-	while (1) {
-		page = 0;
-		while (page * pagesize < blocksize) {
-			debug("page: %d block: %d dest: %p src "
-					"0x%08x\n",
-					page, block, dest,
-					block * blocksize +
-					page * pagesize);
-
-			imx_nandboot_send_cmd(regs, NAND_CMD_READ0);
-			imx_nandboot_nfc_addr(regs, block * blocksize +
-					page * pagesize, pagesize_2k);
-			imx_nandboot_send_page(regs, NFC_OUTPUT, pagesize_2k);
-			page++;
-
-			if (pagesize_2k) {
-				if ((readw(spare0) & 0xff) != 0xff)
-					continue;
-			} else {
-				if ((readw(spare0 + 4) & 0xff00) != 0xff00)
-					continue;
-			}
-
-			__memcpy32(dest, base, pagesize);
-			dest += pagesize;
-			size -= pagesize;
-
-			if (size <= 0)
-				return;
-		}
-		block++;
-	}
-}
-#define CONFIG_NAND_IMX_BOOT_DEBUG
-#ifdef CONFIG_NAND_IMX_BOOT_DEBUG
-#include <command.h>
-
-static int do_nand_boot_test(struct command *cmdtp, int argc, char *argv[])
-{
-	void *dest;
-	int size;
-
-	if (argc < 3)
-		return COMMAND_ERROR_USAGE;
-
-	dest = (void *)strtoul_suffix(argv[1], NULL, 0);
-	size = strtoul_suffix(argv[2], NULL, 0);
-
-	imx_nand_load_image(dest, size);
-
-	return 0;
-}
-
-static const __maybe_unused char cmd_nand_boot_test_help[] =
-"Usage: nand_boot_test <dest> <size>\n"
-"This command loads the booloader from the NAND memory like the reset\n"
-"routine does. Its intended for development tests only";
-
-BAREBOX_CMD_START(nand_boot_test)
-	.cmd		= do_nand_boot_test,
-	.usage		= "load bootloader from NAND",
-	BAREBOX_CMD_HELP(cmd_nand_boot_test_help)
-BAREBOX_CMD_END
-#endif
-
-#endif /* CONFIG_NAND_IMX_BOOT */
-
 /*
  * Main initialization routine
  * @return  0 if successful; non-zero otherwise
-- 
1.7.2.3




More information about the barebox mailing list