mail archive of the barebox mailing list
 help / color / mirror / Atom feed
From: Sascha Hauer <s.hauer@pengutronix.de>
To: Barebox List <barebox@lists.infradead.org>
Subject: [PATCH 09/12] ARM: i.MX53: Implement NAND xload
Date: Wed, 14 Sep 2016 11:12:45 +0200	[thread overview]
Message-ID: <1473844368-13030-9-git-send-email-s.hauer@pengutronix.de> (raw)
In-Reply-To: <1473844368-13030-1-git-send-email-s.hauer@pengutronix.de>

Some i.MX53 want to setup the SDRAM from C code rather than
from DCD tables. The image size for these boards is limited
to the internal SRAM size. To overcome this limitation for
i.MX53 boards booting from NAND implement an xload mechanism
to load only the PBL to SRAM and let barebox load the rest
of the image itself after SDRAM has been initialized.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm/mach-imx/Makefile             |   2 +-
 arch/arm/mach-imx/include/mach/xload.h |   1 +
 arch/arm/mach-imx/xload-imx-nand.c     | 308 +++++++++++++++++++++++++++++++++
 3 files changed, 310 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/mach-imx/xload-imx-nand.c

diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index 0763944..a216c9b 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -25,4 +25,4 @@ obj-pbl-y += esdctl.o boot.o
 obj-$(CONFIG_BAREBOX_UPDATE) += imx-bbu-internal.o
 obj-$(CONFIG_BAREBOX_UPDATE_IMX_EXTERNAL_NAND) += imx-bbu-external-nand.o
 lwl-y += cpu_init.o
-pbl-y += xload-spi.o xload-esdhc.o xload-common.o
+pbl-y += xload-spi.o xload-esdhc.o xload-common.o xload-imx-nand.o
diff --git a/arch/arm/mach-imx/include/mach/xload.h b/arch/arm/mach-imx/include/mach/xload.h
index 997522e..3898d66 100644
--- a/arch/arm/mach-imx/include/mach/xload.h
+++ b/arch/arm/mach-imx/include/mach/xload.h
@@ -1,6 +1,7 @@
 #ifndef __MACH_XLOAD_H
 #define __MACH_XLOAD_H
 
+int imx53_nand_start_image(void);
 int imx6_spi_load_image(int instance, unsigned int flash_offset, void *buf, int len);
 int imx6_spi_start_image(int instance);
 int imx6_esdhc_load_image(int instance, void *buf, int len);
diff --git a/arch/arm/mach-imx/xload-imx-nand.c b/arch/arm/mach-imx/xload-imx-nand.c
new file mode 100644
index 0000000..22e41fa
--- /dev/null
+++ b/arch/arm/mach-imx/xload-imx-nand.c
@@ -0,0 +1,308 @@
+/*
+ * 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.
+ *
+ */
+#define pr_fmt(fmt)	"imx-nand-boot: " fmt
+
+#include <common.h>
+#include <init.h>
+#include <io.h>
+#include <linux/mtd/nand.h>
+#include <mach/imx-nand.h>
+#include <mach/generic.h>
+#include <mach/imx53-regs.h>
+#include <mach/xload.h>
+
+struct imx_nand {
+	void __iomem *base;
+	void __iomem *main_area0;
+	void __iomem *regs_ip;
+	void __iomem *regs_axi;
+	void *spare0;
+	int pagesize;
+	int v1;
+	int pages_per_block;
+};
+
+static void wait_op_done(struct imx_nand *host)
+{
+	u32 r;
+
+	while (1) {
+		r = readl(NFC_V3_IPC);
+		if (r & NFC_V3_IPC_INT)
+			break;
+	};
+
+	r &= ~NFC_V3_IPC_INT;
+
+	writel(r, NFC_V3_IPC);
+}
+
+/*
+ * This function issues the specified command to the NAND device and
+ * waits for completion.
+ *
+ * @param       cmd     command for NAND Flash
+ */
+static void imx_nandboot_send_cmd(struct imx_nand *host, u16 cmd)
+{
+	/* fill command */
+	writel(cmd, NFC_V3_FLASH_CMD);
+
+	/* send out command */
+	writel(NFC_CMD, NFC_V3_LAUNCH);
+
+	/* Wait for operation to complete */
+	wait_op_done(host);
+}
+
+/*
+ * 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 imx_nandboot_send_addr(struct imx_nand *host, u16 addr)
+{
+	/* fill address */
+	writel(addr, NFC_V3_FLASH_ADDR0);
+
+	/* send out address */
+	writel(NFC_ADDR, NFC_V3_LAUNCH);
+
+	wait_op_done(host);
+}
+
+static void imx_nandboot_nfc_addr(struct imx_nand *host, int page)
+{
+	imx_nandboot_send_addr(host, 0);
+
+	if (host->pagesize == 2048)
+		imx_nandboot_send_addr(host, 0);
+
+	imx_nandboot_send_addr(host, page & 0xff);
+	imx_nandboot_send_addr(host, (page >> 8) & 0xff);
+	imx_nandboot_send_addr(host, (page >> 16) & 0xff);
+
+	if (host->pagesize == 2048)
+		imx_nandboot_send_cmd(host, NAND_CMD_READSTART);
+}
+
+static void imx_nandboot_send_page(struct imx_nand *host, unsigned int ops)
+{
+	uint32_t tmp;
+
+	tmp = readl(NFC_V3_CONFIG1);
+	tmp &= ~(7 << 4);
+	writel(tmp, NFC_V3_CONFIG1);
+
+	/* transfer data from NFC ram to nand */
+	writel(ops, NFC_V3_LAUNCH);
+
+	wait_op_done(host);
+}
+
+static void __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 void imx_nandboot_get_page(struct imx_nand *host, unsigned int page)
+{
+	imx_nandboot_send_cmd(host, NAND_CMD_READ0);
+	imx_nandboot_nfc_addr(host, page);
+	imx_nandboot_send_page(host, NFC_OUTPUT);
+}
+
+static int imx_nandboot_read_page(struct imx_nand *host, unsigned int page,
+				   void *buf)
+{
+	int nsubpages;
+	u32 eccstat, err;
+
+	imx_nandboot_get_page(host, page);
+
+	__memcpy32(buf, host->main_area0, host->pagesize);
+
+	eccstat = readl(NFC_V3_ECC_STATUS_RESULT);
+	nsubpages = host->pagesize / 512;
+
+	do {
+		err = eccstat & 0xf;
+		if (err == 0xf)
+			return -EBADMSG;
+		eccstat >>= 4;
+	} while (--nsubpages);
+
+	return 0;
+}
+
+static int dbbt_block_is_bad(void *_dbbt, int block)
+{
+	int i;
+	u32 *dbbt = _dbbt;
+	int num_bad_blocks;
+
+	if (!_dbbt)
+		return false;
+
+	dbbt++; /* reserved */
+
+	num_bad_blocks = *dbbt++;
+
+	for (i = 0; i < num_bad_blocks; i++) {
+		if (*dbbt == block)
+			return true;
+		dbbt++;
+	}
+
+	return false;
+}
+
+static int read_firmware(struct imx_nand *host, void *dbbt, int page, void *buf,
+			 int npages)
+{
+	int ret;
+
+	if (dbbt_block_is_bad(dbbt, page / host->pages_per_block))
+		page = ALIGN(page, host->pages_per_block);
+
+	while (npages) {
+		if (!(page % host->pages_per_block)) {
+			if (dbbt_block_is_bad(NULL, page / host->pages_per_block)) {
+				page += host->pages_per_block;
+				continue;
+			}
+		}
+
+		ret = imx_nandboot_read_page(host, page, buf);
+		if (ret)
+			return ret;
+
+		buf += host->pagesize;
+		page++;
+		npages--;
+	}
+
+	return 0;
+}
+
+int imx53_nand_start_image(void)
+{
+	struct imx_nand host;
+	void *buf = IOMEM(MX53_CSD0_BASE_ADDR);
+	void *dbbt = NULL;
+	int page_firmware1, page_firmware2, page_dbbt, image_size, npages;
+	void (*firmware)(void);
+	int ret;
+	u32 cfg1 = readl(IOMEM(MX53_SRC_BASE_ADDR) + 0x4);
+
+	host.base = IOMEM(MX53_NFC_AXI_BASE_ADDR);
+	host.main_area0 = host.base;
+	host.regs_ip = IOMEM(MX53_NFC_BASE_ADDR);
+	host.regs_axi = host.base + 0x1e00;
+	host.spare0 = host.base + 0x1000;
+
+	switch ((cfg1 >> 14) & 0x3) {
+	case 0:
+		host.pagesize = 512;
+		break;
+	case 1:
+		host.pagesize = 2048;
+		break;
+	case 2:
+	case 3:
+		host.pagesize = 4096;
+		break;
+	}
+
+	switch ((cfg1 >> 17) & 0x3) {
+	case 0:
+		host.pages_per_block = 32;
+		break;
+	case 1:
+		host.pages_per_block = 64;
+		break;
+	case 2:
+		host.pages_per_block = 128;
+		break;
+	case 3:
+		host.pages_per_block = 256;
+		break;
+	}
+
+	pr_debug("Using pagesize %d, %d pages per block\n",
+		 host.pagesize, host.pages_per_block);
+
+	ret = imx_nandboot_read_page(&host, 0, buf);
+	if (ret)
+		return ret;
+
+	if (*(u32 *)(buf + 0x4) != 0x20424346) {
+		pr_err("No FCB Found on flash\n");
+		return -EINVAL;
+	}
+
+	page_firmware1 = *(u32 *)(buf + 0x68);
+	page_firmware2 = *(u32 *)(buf + 0x6c);
+	page_dbbt = *(u32 *)(buf + 0x78);
+
+	image_size = ALIGN(imx_image_size(), host.pagesize);
+	npages = image_size / host.pagesize;
+
+	if (page_dbbt) {
+		ret = imx_nandboot_read_page(&host, page_dbbt, buf);
+		if (!ret && *(u32 *)(buf + 0x4) == 0x44424254) {
+			ret = imx_nandboot_read_page(&host, page_dbbt + 4, buf);
+			if (!ret) {
+				pr_debug("Using DBBT from page %d\n", page_dbbt + 4);
+				dbbt = buf;
+				buf += host.pagesize;
+			}
+		}
+	}
+
+	pr_debug("Reading firmware from page %d, size %d\n",
+		 page_firmware1, image_size);
+
+	ret = read_firmware(&host, dbbt, page_firmware1, buf, npages);
+	if (ret) {
+		pr_debug("Reading primary firmware failed\n");
+		if (page_firmware2) {
+			pr_debug("Reading firmware from page %d, size %d\n",
+				 page_firmware2, image_size);
+			ret = read_firmware(&host, dbbt, page_firmware2, buf, npages);
+			if (ret) {
+				pr_err("Could not read firmware\n");
+				return -EINVAL;
+			}
+		} else {
+			pr_err("Reading primary firmware failed, no secondary firmware found\n");
+			return -EINVAL;
+		}
+	}
+
+	pr_debug("Firmware read, starting it\n");
+
+	firmware = buf;
+
+	firmware();
+
+	return 0;
+}
-- 
2.8.1


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

  parent reply	other threads:[~2016-09-14  9:13 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-09-14  9:12 [PATCH 01/12] ARM: i.MX53: Add uart5 clock support Sascha Hauer
2016-09-14  9:12 ` [PATCH 02/12] ARM: i.MX53 Vincell: Reset phy consistently from device tree Sascha Hauer
2016-09-14  9:12 ` [PATCH 03/12] ARM: i.MX53 Vincell: Adjust bbu handler partition size to real partition size Sascha Hauer
2016-09-14  9:12 ` [PATCH 04/12] ARM: i.MX53 Vincell: Add PBL console support Sascha Hauer
2016-09-14  9:24   ` Michael Grzeschik
2016-09-15  8:00     ` Sascha Hauer
2016-09-14  9:12 ` [PATCH 05/12] ARM: i.MX53: do not pass base address to imx*_boot_save_loc Sascha Hauer
2016-09-14  9:12 ` [PATCH 06/12] ARM: i.MX: Provide bootsource functions for early boot code Sascha Hauer
2016-09-14  9:12 ` [PATCH 07/12] ARM: i.MX53: Detect booting from USB Sascha Hauer
2016-09-14  9:12 ` [PATCH 08/12] mtd: imx-nand: Move v3 register definitions to include file Sascha Hauer
2016-09-14  9:12 ` Sascha Hauer [this message]
2016-09-14  9:12 ` [PATCH 10/12] ARM: i.MX53 Vincell: Add NAND xload support Sascha Hauer
2016-09-14  9:12 ` [PATCH 11/12] ARM: imx_v7_defconfig: Enable Vincell support Sascha Hauer
2016-09-14  9:12 ` [PATCH 12/12] ARM: vincell_defconfig: make smaller Sascha Hauer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1473844368-13030-9-git-send-email-s.hauer@pengutronix.de \
    --to=s.hauer@pengutronix.de \
    --cc=barebox@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox