[U-Boot] [PATCH v6 10/12] arm: add customized boot command for Faraday Images

Kuo-Jung Su
2013-07-04T03:40:42Z

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@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
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 | 279 +++++++++++++++++++++++++++++++++++++
arch/arm/cpu/faraday/fwimage.h | 47 +++++++
arch/arm/cpu/faraday/fwimage2.h | 67 +++++++++
arch/arm/cpu/u-boot.lds | 11 ++
5 files changed, 405 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 6b96e32..ef6a72e 100644
--- a/arch/arm/cpu/faraday/Makefile
+++ b/arch/arm/cpu/faraday/Makefile
@@ -25,7 +25,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..1645661
--- /dev/null
+++ b/arch/arm/cpu/faraday/cmd_bootfa.c
@@ -0,0 +1,279 @@
+/*
+ * 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@faraday-tech.com>
+ *
+ * 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
+ */
+
+/*
+ * 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..c6a3e80
--- /dev/null
+++ b/arch/arm/cpu/faraday/fwimage.h
@@ -0,0 +1,47 @@
+/*
+ * linux/arch/arm/plat-faraday/fwimage.h
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * 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
+ */
+
+#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..52e0b94
--- /dev/null
+++ b/arch/arm/cpu/faraday/fwimage2.h
@@ -0,0 +1,67 @@
+/*
+ * linux/arch/arm/plat-faraday/fwimage2.h
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * 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
+ */
+
+#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 3037885..032018f 100644
--- a/arch/arm/cpu/u-boot.lds
+++ b/arch/arm/cpu/u-boot.lds
@@ -23,6 +23,8 @@
* MA 02111-1307 USA
*/

+#include <config.h>
+
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
@@ -35,6 +37,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