[U-Boot] [PATCH v7 09/11] arm: add customized boot command for Faraday Images

Kuo-Jung Su dantesu at gmail.com
Mon Jul 29 07:51:51 CEST 2013


From: Kuo-Jung Su <dantesu at faraday-tech.com>

At the time of writting, none of Faraday NAND & SPI controllers
supports XIP (eXecute In Place), and the 1st stage bootstrap
stored in embedded ROM is not compatible to U-Boot design.

So this patch is added to support booting from Faraday Images.

Signed-off-by: Kuo-Jung Su <dantesu at faraday-tech.com>
CC: Albert Aribaud <albert.u.boot at aribaud.net>
---
Changes for v7:
   - Update license to use SPDX identifiers.

Changes for v6:
   - Fix compiler warnning
   - Use shorter paragraph in commit message, and move the
     original statement into the top of cmd_bootfa.c.

Changes for v5:
   - Rename from 'arm: add Faraday firmware image utility'
     into 'arm: add Faraday specific boot command'
   - Add missing CRC check to the command 'bootfa'.
   - Add rationale to the command 'bootfa'.

Changes for v4:
   - Coding Style cleanup.
   - Break up from [arm: add Faraday A36x SoC platform support]

Changes for v3:
   - Coding Style cleanup.
   - Always insert a blank line between declarations and code.

Changes for v2:
   - Coding Style cleanup.

 arch/arm/cpu/faraday/Makefile     |    2 +-
 arch/arm/cpu/faraday/cmd_bootfa.c |  267 +++++++++++++++++++++++++++++++++++++
 arch/arm/cpu/faraday/fwimage.h    |   35 +++++
 arch/arm/cpu/faraday/fwimage2.h   |   55 ++++++++
 arch/arm/cpu/u-boot.lds           |   11 ++
 5 files changed, 369 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/cpu/faraday/cmd_bootfa.c
 create mode 100644 arch/arm/cpu/faraday/fwimage.h
 create mode 100644 arch/arm/cpu/faraday/fwimage2.h

diff --git a/arch/arm/cpu/faraday/Makefile b/arch/arm/cpu/faraday/Makefile
index 715bb5d..289823c 100644
--- a/arch/arm/cpu/faraday/Makefile
+++ b/arch/arm/cpu/faraday/Makefile
@@ -9,7 +9,7 @@ include $(TOPDIR)/config.mk

 LIB	= $(obj)lib$(CPU).o

-src-y  := cpu.o
+src-y  := cpu.o cmd_bootfa.o
 src-$(CONFIG_FTINTC020)   += ftintc020.o
 src-$(CONFIG_FTTMR010)    += fttmr010.o
 src-$(CONFIG_FTPWMTMR010) += ftpwmtmr010.o
diff --git a/arch/arm/cpu/faraday/cmd_bootfa.c b/arch/arm/cpu/faraday/cmd_bootfa.c
new file mode 100644
index 0000000..fa1f7df
--- /dev/null
+++ b/arch/arm/cpu/faraday/cmd_bootfa.c
@@ -0,0 +1,267 @@
+/*
+ * arch/arm/cpu/faraday/cmd_bootfa.c
+ *
+ * This command is used to boot faraday firmware from MMC/USB/SPI/NAND/NOR
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu at faraday-tech.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+/*
+ * At the time of writting, none of Faraday NAND & SPI controllers
+ * supports XIP (eXecute In Place). So the Faraday A360/A369 SoC has
+ * to implement a 1st level bootstrap code stored in the embedded ROM
+ * inside the SoC.
+ *
+ * After power-on, the ROM code (1st level bootstrap code) would load
+ * the 2nd bootstrap code into SRAM without any SDRAM initialization.
+ *
+ * The 2nd bootstrap code would then initialize SDRAM and load the
+ * generic firmware (u-boot/linux) into SDRAM, and finally make
+ * a long-jump to the firmware.
+ *
+ * Which means the SPL design of U-boot would never fit to A360/A369,
+ * since it's usually not possible to alter a embedded ROM code.
+ * And because both the 1st & 2nd level bootstrap code use the private
+ * Faraday Firmware Image Format, it would be better to drop U-boot
+ * image support to simplify the design.
+ *
+ * The Faraday Firmware Image Format uses a 1 KB (1024 Bytes) header:
+ *
+ * +----------------+ 0x0000
+ * | MAGIC          | Magic number
+ * +----------------+ 0x0004
+ * | HDR LENGTH     | The size of this header
+ * +----------------+ 0x0008
+ * |                |
+ * | SYS PARAMETERS | A set of (addr, data) for 32-bit register write,
+ * |                | which is for SDRAM initialization and timing control.
+ * +----------------+ 0x0108
+ * |                |
+ * | PART TABLE     | A partition table with max. 10 entries.
+ * |                |
+ * +----------------+ 0x03D8
+ * | HDR CHECKSUM   | Header Checksum (CRC32)
+ * +----------------+ 0x03DC
+ * | HDR REVISION   | Header Revision ID
+ * +----------------+ 0x03E0
+ * | HDR TIMESTAMP  | Header Creation Timestamp
+ * +----------------+ 0x03E4
+ * | RESERVED       |
+ * +----------------+ 0x0400
+ *
+ * The entry of partitoin table is:
+ *
+ * +----------------+ 0x0000
+ * | NAME           | The name of the partition
+ * +----------------+ 0x0020
+ * | OFFSET         | The offset address of the flash memory.
+ * +----------------+ 0x0024
+ * | LENGTH         | The data length of the partition.
+ * +----------------+ 0x0028
+ * | Load Address   | The address in SDRAM to store the firmware.
+ * +----------------+ 0x002C
+ * | Quick CRC      | An optional CRC32 agains 256KB of TOP & BUTTOM.
+ * +----------------+ 0x0030
+ * | FLAGS          | The flags/attribute of the partition
+ * +----------------+ 0x0034
+ * | RESERVED       |
+ * +----------------+ 0x0040
+ * | MAGIC=0x1000   | It's always a 0x1000.
+ * +----------------+ 0x0044
+ * | MAGIC=0x0001   | It's always a 0x0001.
+ * +----------------+ 0x0048
+ *
+ * The usage of the command 'bootfa' is:
+ *
+ * bootfa <interface> <fw_name>
+ * - boot from 'interface' with the firmware named as <fw_name>
+ *   where 'interface' could be any one of <usb | mmc | nand | sf>
+ *
+ * ex: bootfa usb linux
+ *
+ * The rationale is:
+ *
+ * 1. If 'interface' is either 'usb' or 'mmc/sd', then jumps to 2-a;
+ *    else jumps to 2-b.
+ * 2-a. Translate 'fw_name' to 'filename' from the built-in rules
+ *      (i.e. 'linux' -> 'zimage'), jumps to 3-a.
+ * 2-b. Use 'nand' or 'sf' or 'cp' to load image header into SDRAM,
+ *      and the looking for the 'fw_name' in the partition table.
+ *      If part->name equals 'fw_name', then jumps to 3-b;
+ *      else report an error and exit.
+ * 3-a. Use 'fatload' to load the firmware into SDRAM by filename,
+ *      and then jumps to 4.
+ * 3-b. Use 'nand' or 'sf' or 'cp' to load the firmware into SDRAM
+ *      by .offset & .length of the corresponding partition info,
+ *      and then jumps to 4.
+ * 4. Use 'go' to shift control to the loaded firmware.
+ */
+#include <common.h>
+#include <command.h>
+
+#include "fwimage2.h"
+
+#undef  ROUNDUP
+#define ROUNDUP(len, blksz) \
+	((len) % (blksz)) ? ((len) + (blksz) - ((len) % (blksz))) : (len)
+
+static int hdr_invalid(struct fwimage2 *img)
+{
+	uint32_t cksum_old, cksum_new;
+
+	if (le32_to_cpu(img->revision) != FWIMAGE2_REVISION)
+		return 0;
+
+	cksum_old = le32_to_cpu(img->hcrc);
+	img->hcrc = 0;
+	cksum_new = crc32_no_comp(0xffffffff, (const uint8_t *)img,
+		sizeof(struct fwimage2));
+	img->hcrc = cpu_to_le32(cksum_old);
+
+	return (cksum_new != cksum_old);
+}
+
+static int part_invalid(struct fwpart *part, uint8_t *buf)
+{
+	uint32_t len = le32_to_cpu(part->length);
+	uint32_t cksum = 0xFFFFFFFF;
+
+	if (len <= SZ_512K) {
+		cksum = crc32_no_comp(cksum, buf, len);
+	} else {
+		cksum = crc32_no_comp(cksum, buf, SZ_256K);
+		cksum = crc32_no_comp(cksum, buf + len - SZ_256K, SZ_256K);
+	}
+
+	return (cksum != le32_to_cpu(part->qcrc));
+}
+
+static struct fwpart *part_lookup(struct fwimage2 *hdr, char *name)
+{
+	int i;
+	struct fwpart *ppart = hdr->part;
+	static struct fwpart part_local;
+
+	if (hdr_invalid(hdr)) {
+		printf("part_lookup: bad header\n");
+		return NULL;
+	}
+
+	for (i = 0; ppart[i].length > 0 && i < 10; ++i) {
+		if (!strcmp(name, ppart[i].name)) {
+			printf("part_lookup: name=%s, offset=0x%x, size=0x%x\n",
+				ppart[i].name,
+				ppart[i].offset,
+				ppart[i].length);
+
+			memcpy(&part_local, &ppart[i], sizeof(struct fwpart));
+			return &part_local;
+		}
+	}
+
+	return NULL;
+}
+
+static int do_bootfa(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	char *inf, *name , cmd[256];
+	struct fwpart *part = NULL;
+
+	if (argc < 3) {
+#ifdef CONFIG_SYS_LONGHELP
+		printf("Usage:\n"
+			"%s %s\n", argv[0], cmdtp->help);
+#else
+		printf("Usage:\n"
+			"bootfa <interface> <fw_name>\n"
+			"    - boot from 'interface' with the firmware named as <fw_name>\n"
+			"      where 'interface' could be any one of <usb | mmc | nand | sf>\n"
+			"ex: bootfa usb linux");
+#endif
+		return 1;
+	}
+
+	inf  = argv[1];
+	name = argv[2];
+
+	if (!strcmp(inf, "usb")) {
+		if (!strcmp(name, "linux"))
+			name = "zimage";
+		else if (!strcmp(name, "wince"))
+			name = "nk.nb0";
+		sprintf(cmd, "usb start;fatload usb 0 0x%x %s",
+			CONFIG_SYS_LOAD_ADDR, name);
+		run_command(cmd, 0);
+	} else if (!strcmp(inf, "mmc") || !strcmp(inf, "sd")) {
+		if (!strcmp(name, "linux"))
+			name = "zimage";
+		else if (!strcmp(name, "wince"))
+			name = "nk.nb0";
+		sprintf(cmd, "mmcinfo;fatload mmc 0 0x%x %s",
+			CONFIG_SYS_LOAD_ADDR, name);
+		run_command(cmd, 0);
+#ifdef CONFIG_SYS_FLASH_BASE
+	} else if (!strcmp(inf, "nor")) {
+		sprintf(cmd, "cp.l 0x%x 0x%x 0x400",
+			CONFIG_SYS_FLASH_BASE,
+			CONFIG_SYS_LOAD_ADDR);
+		run_command(cmd, 0);
+		part = part_lookup((void *)CONFIG_SYS_LOAD_ADDR, name);
+		if (!part) {
+			printf("firmware not found!\n");
+			return 1;
+		}
+		sprintf(cmd, "cp.l 0x%x 0x%x 0x%x",
+			CONFIG_SYS_FLASH_BASE + part->offset,
+			CONFIG_SYS_LOAD_ADDR, part->length);
+		run_command(cmd, 0);
+#endif
+	} else if (!strcmp(inf, "nand")) {
+		sprintf(cmd, "nand read 0x%x 0 0x400", CONFIG_SYS_LOAD_ADDR);
+		run_command(cmd, 0);
+		part = part_lookup((void *)CONFIG_SYS_LOAD_ADDR, name);
+		if (!part) {
+			printf("firmware not found!\n");
+			return 1;
+		}
+		sprintf(cmd, "nand read 0x%x 0x%x 0x%x",
+			CONFIG_SYS_LOAD_ADDR,
+			part->offset, part->length);
+		run_command(cmd, 0);
+	} else if (!strcmp(inf, "sf")) {
+		sprintf(cmd, "sf probe 0:0 25000000;sf read 0x%x 0 0x400",
+			CONFIG_SYS_LOAD_ADDR);
+		run_command(cmd, 0);
+		part = part_lookup((void *)CONFIG_SYS_LOAD_ADDR, name);
+		if (!part) {
+			printf("firmware not found!\n");
+			return 1;
+		}
+		sprintf(cmd, "sf read 0x%x 0x%x 0x%x",
+			CONFIG_SYS_LOAD_ADDR,
+			part->offset, part->length);
+		run_command(cmd, 0);
+	}
+
+	if (part && part_invalid(part, (void *)CONFIG_SYS_LOAD_ADDR)) {
+		printf("bad partition!\n");
+		return 1;
+	}
+
+	sprintf(cmd, "go 0x%x", CONFIG_SYS_LOAD_ADDR);
+	run_command(cmd, 0);
+
+	return 1;
+}
+
+U_BOOT_CMD(
+	bootfa,    3,    1,    do_bootfa,
+	"boot faraday firmware image",
+	"<interface> <fw_name>\n"
+	"    - boot from 'interface' with the firmware named as <fw_name>\n"
+	"      where 'interface' could be any one of <usb | mmc | nand | sf>\n"
+	"ex: bootfa usb linux"
+);
diff --git a/arch/arm/cpu/faraday/fwimage.h b/arch/arm/cpu/faraday/fwimage.h
new file mode 100644
index 0000000..c01799b
--- /dev/null
+++ b/arch/arm/cpu/faraday/fwimage.h
@@ -0,0 +1,35 @@
+/*
+ * linux/arch/arm/plat-faraday/fwimage.h
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu at faraday-tech.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef _ARCH_ARM_PLAT_FARADAY_FWIMAGE_H
+#define _ARCH_ARM_PLAT_FARADAY_FWIMAGE_H
+
+struct fwparam {
+	uint32_t count;
+	uint32_t version; /* ycmo100525: for firmware image version */
+	uint32_t addr[31];
+	uint32_t data[31];
+};
+
+struct fwfile {
+	char name[64];
+	uint32_t size;
+};
+
+struct fwimage {
+	uint32_t magic; /* Image Header Magic */
+	uint32_t length;/* Image Header Length */
+
+	/* 256 bytes, embedded paramters area */
+	struct fwparam param;
+
+	struct fwfile  file[1];
+};
+
+#endif /* _ARCH_ARM_PLAT_FARADAY_FWIMAGE_H */
diff --git a/arch/arm/cpu/faraday/fwimage2.h b/arch/arm/cpu/faraday/fwimage2.h
new file mode 100644
index 0000000..6a33111
--- /dev/null
+++ b/arch/arm/cpu/faraday/fwimage2.h
@@ -0,0 +1,55 @@
+/*
+ * linux/arch/arm/plat-faraday/fwimage2.h
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu at faraday-tech.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef _ARCH_ARM_PLAT_FARADAY_FWIMAGE2_H
+#define _ARCH_ARM_PLAT_FARADAY_FWIMAGE2_H
+
+#include "fwimage.h"
+
+struct fwpart {
+	char name[32];
+
+	uint32_t offset;
+	uint32_t length;
+
+	uint32_t load;
+	uint32_t qcrc; /* Quick checksum againsts 256KB of TOP & BOTTOM */
+
+	uint32_t flags;
+#define FWIMAGE2_PART_FILESYSTEM    0x80000000 /* Is a filesystem ? */
+
+	uint32_t rsvd[3];
+	uint32_t magic1000; /* It's always 0x1000 */
+	uint32_t magic0001; /* It's always 0x0001 */
+}; /* size = 72 bytes */
+
+struct fwimage2 {
+	uint32_t magic; /* Image Header Magic */
+#define FWIMAGE2_MAGIC  0x00484946 /* "FIH\0" */
+
+	uint32_t hlen;  /* Image Header Length */
+
+	/* 256 bytes, 32-bit memory write */
+	struct {
+		uint32_t addr;
+		uint32_t data;
+	} mw32[32];
+
+	/* 720 bytes, partition table */
+	struct fwpart part[10];
+
+	uint32_t hcrc;     /* Image Header Checksum (CRC32) */
+	uint32_t revision; /* Image Format Revision ID */
+#define FWIMAGE2_REVISION   0x00000202 /* v2.2 */
+
+	uint32_t time;     /* Image Creation Timestamp */
+	uint32_t rsvd[7];
+}; /* size = 1024 bytes */
+
+#endif /* _ARCH_ARM_PLAT_FARADAY_FWIMAGE2_H */
diff --git a/arch/arm/cpu/u-boot.lds b/arch/arm/cpu/u-boot.lds
index 490aed2..f3ea681 100644
--- a/arch/arm/cpu/u-boot.lds
+++ b/arch/arm/cpu/u-boot.lds
@@ -7,6 +7,8 @@
  * SPDX-License-Identifier:	GPL-2.0+
  */

+#include <config.h>
+
 OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
 OUTPUT_ARCH(arm)
 ENTRY(_start)
@@ -19,6 +21,15 @@ SECTIONS
 	{
 		*(.__image_copy_start)
 		CPUDIR/start.o (.text*)
+#ifdef CONFIG_FARADAY
+		/*
+		 * Dante Su 2012.10.09:
+		 * Reserved for the faimage v2.1.
+		 * 1. CPUDIR/start.o: It shall never be > 4KB.
+		 * 2. faimage header: It shall always be stored at 0x1000, and <= 1KB.
+		 */
+		. = 0x00001400;
+#endif
 		*(.text*)
 	}

--
1.7.9.5



More information about the U-Boot mailing list