From patchwork Mon Jul 29 05:51:51 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kuo-Jung Su X-Patchwork-Id: 262689 X-Patchwork-Delegate: albert.aribaud@free.fr Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 48D6E2C0098 for ; Mon, 29 Jul 2013 15:54:32 +1000 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id F005A4A02C; Mon, 29 Jul 2013 07:54:18 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id MOmMZjRELRZp; Mon, 29 Jul 2013 07:54:18 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 5B7F34A050; Mon, 29 Jul 2013 07:53:23 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 32E784A026 for ; Mon, 29 Jul 2013 07:53:09 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id z-pbRm8EIAOO for ; Mon, 29 Jul 2013 07:53:04 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 BL_NJABL=ERR(-1.5) (only DNSBL check requested) Received: from mail-pb0-f43.google.com (mail-pb0-f43.google.com [209.85.160.43]) by theia.denx.de (Postfix) with ESMTPS id 795174A048 for ; Mon, 29 Jul 2013 07:52:24 +0200 (CEST) Received: by mail-pb0-f43.google.com with SMTP id md12so4201605pbc.2 for ; Sun, 28 Jul 2013 22:52:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references :in-reply-to:references; bh=ys0dHD7RKFKuEnKy3Uq2slI0+M3ro/ZqZTgN3UTkuwE=; b=KMcp9DvpPKTSEF4n7CqfLfvPt1NvpNR3oyxVJjuIs3pAp019Ye23cr834oYhSeYwYR JdCiUCLCcJfUSEhBR193PWYXnsuPoqZzi/wRaVZVzyTfa9x2pCow9AUWBVk7UVEGpTrO xrcxX2hKAmnet9cxp1Ybc2fP3VijuE7bOp4mgLKHiBLM5crS98EiXkA4IXl5au82Gyhf OD2Xphu4uat5mkJd2izXSgmF079I1jE6AAwZ5rTwieG5jL/6gfg3U/A8L6qE5S16nl4o v6S/Eou0m15TzdkjVoVzG4hDYH21gFdbmZVRO6Kvb5lCZF3n6FssEwRTl3wgd31Zfd/O KYRg== X-Received: by 10.68.137.8 with SMTP id qe8mr66504381pbb.100.1375077143316; Sun, 28 Jul 2013 22:52:23 -0700 (PDT) Received: from localhost.localdomain (114-35-170-161.HINET-IP.hinet.net. [114.35.170.161]) by mx.google.com with ESMTPSA id wf7sm18602287pac.20.2013.07.28.22.52.21 for (version=TLSv1 cipher=DES-CBC3-SHA bits=168/168); Sun, 28 Jul 2013 22:52:22 -0700 (PDT) From: Kuo-Jung Su To: u-boot@lists.denx.de Date: Mon, 29 Jul 2013 13:51:51 +0800 Message-Id: <1375077113-27251-10-git-send-email-dantesu@gmail.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1375077113-27251-1-git-send-email-dantesu@gmail.com> References: <1375077113-27251-1-git-send-email-dantesu@gmail.com> In-Reply-To: <1364540788-13943-1-git-send-email-dantesu@gmail.com> References: <1364540788-13943-1-git-send-email-dantesu@gmail.com> Cc: Kuo-Jung Su Subject: [U-Boot] [PATCH v7 09/11] arm: add customized boot command for Faraday Images X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.11 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@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 -- 1.7.9.5 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*) }