From mboxrd@z Thu Jan 1 00:00:00 1970 From: Kuo-Jung Su Date: Mon, 29 Jul 2013 13:51:51 +0800 Subject: [U-Boot] [PATCH v7 09/11] arm: add customized boot command for Faraday Images In-Reply-To: <1375077113-27251-1-git-send-email-dantesu@gmail.com> References: <1375077113-27251-1-git-send-email-dantesu@gmail.com> Message-ID: <1375077113-27251-10-git-send-email-dantesu@gmail.com> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de From: Kuo-Jung Su 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 CC: Albert Aribaud --- 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 + * + * 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 + * - boot from 'interface' with the firmware named as + * where 'interface' could be any one of + * + * 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 +#include + +#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 \n" + " - boot from 'interface' with the firmware named as \n" + " where 'interface' could be any one of \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", + " \n" + " - boot from 'interface' with the firmware named as \n" + " where 'interface' could be any one of \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 + * + * 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 + * + * 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 + 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