All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH sunxi-tools v2 0/2] Support unified u-boot SPL for SD cards and FEL mode
@ 2015-02-09  2:37 Siarhei Siamashka
  2015-02-09  2:37 ` [U-Boot] [PATCH sunxi-tools v2 1/2] fel: Split 'aw_fel_get_version' into 'get' and 'print' variants Siarhei Siamashka
                   ` (3 more replies)
  0 siblings, 4 replies; 7+ messages in thread
From: Siarhei Siamashka @ 2015-02-09  2:37 UTC (permalink / raw)
  To: u-boot

An updated variant of the older patch
    http://lists.denx.de/pipermail/u-boot/2015-February/204024.html

These patches are not for the u-boot code (unless u-boot decides to
cannibalize the 'fel' tool later) but still provide a glue layer
between the Allwinner BROM code and the u-boot SPL code. And need
to play nice with both of them.

The updated 'fel' tool is supposed to be used together with u-boot
v2015.04 and provide support for booting regular u-boot SPL binaries
over USB via FEL mode. So that a special u-boot sunxi FEL configuration
can be eventually dropped in the future.

The usage instructions are in the 'New method of booting u-boot over USB
(u-boot v2015.04 and later versions)' section of the linux-sunxi wiki page
    http://linux-sunxi.org/index.php?title=FEL/USBBoot&oldid=12979

It temporarily moves the BROM data from the first 32 KiB of SRAM into
a different SRAM section before calling the SPL code. And then moves
it back before returning from the SPL back to the FEL code in BROM.
This provides a contiguous 32 KiB block in the beginning of SRAM for
use by the SPL. And in the case if an extra SRAM section is not
available, we can at least "defragmemnt" the free memory areas
and still provide a contiguous ~21 KiB block to the SPL in the
beginning of SRAM.

This code is also available in the following branch:
    https://github.com/ssvb/sunxi-tools/commits/20150206-fel-large-spl-support

Siarhei Siamashka (2):
  fel: Split 'aw_fel_get_version' into 'get' and 'print' variants
  fel: New command for loading U-Boot SPL binaries in eGON format

 fel-to-spl-thunk.S | 172 +++++++++++++++++++++++++++++++
 fel-to-spl-thunk.h |  69 +++++++++++++
 fel.c              | 291 +++++++++++++++++++++++++++++++++++++++++++++++++----
 3 files changed, 510 insertions(+), 22 deletions(-)
 create mode 100644 fel-to-spl-thunk.S
 create mode 100644 fel-to-spl-thunk.h

-- 
2.0.5

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [U-Boot] [PATCH sunxi-tools v2 1/2] fel: Split 'aw_fel_get_version' into 'get' and 'print' variants
  2015-02-09  2:37 [U-Boot] [PATCH sunxi-tools v2 0/2] Support unified u-boot SPL for SD cards and FEL mode Siarhei Siamashka
@ 2015-02-09  2:37 ` Siarhei Siamashka
  2015-02-09  2:37 ` [U-Boot] [PATCH sunxi-tools v2 2/2] fel: New command for loading U-Boot SPL binaries in eGON format Siarhei Siamashka
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 7+ messages in thread
From: Siarhei Siamashka @ 2015-02-09  2:37 UTC (permalink / raw)
  To: u-boot

Now aw_fel_get_version() can get the SoC ID for internal usage
from the other functions. And aw_fel_print_version() is used
to print the formatted string to stdout.

Signed-off-by: Siarhei Siamashka <siarhei.siamashka@gmail.com>
---
Changes in v2:
 - This code has been isolated into a separate patch. No other changes.

 fel.c | 53 +++++++++++++++++++++++++++++++----------------------
 1 file changed, 31 insertions(+), 22 deletions(-)

diff --git a/fel.c b/fel.c
index c21d6ec..542bf4b 100644
--- a/fel.c
+++ b/fel.c
@@ -41,6 +41,17 @@ struct  aw_usb_request {
 	char	pad[10];
 }  __attribute__((packed));
 
+struct aw_fel_version {
+	char signature[8];
+	uint32_t soc_id;	/* 0x00162300 */
+	uint32_t unknown_0a;	/* 1 */
+	uint16_t protocol;	/* 1 */
+	uint8_t  unknown_12;	/* 0x44 */
+	uint8_t  unknown_13;	/* 0x08 */
+	uint32_t scratchpad;	/* 0x7e00 */
+	uint32_t pad[2];	/* unused */
+} __attribute__((packed));
+
 static const int AW_USB_READ = 0x11;
 static const int AW_USB_WRITE = 0x12;
 
@@ -136,32 +147,27 @@ void aw_read_fel_status(libusb_device_handle *usb)
 	aw_usb_read(usb, &buf, sizeof(buf));
 }
 
-void aw_fel_get_version(libusb_device_handle *usb)
+void aw_fel_get_version(libusb_device_handle *usb, struct aw_fel_version *buf)
 {
-	struct aw_fel_version {
-		char signature[8];
-		uint32_t soc_id;	/* 0x00162300 */
-		uint32_t unknown_0a;	/* 1 */
-		uint16_t protocol;	/* 1 */
-		uint8_t  unknown_12;	/* 0x44 */
-		uint8_t  unknown_13;	/* 0x08 */
-		uint32_t scratchpad;	/* 0x7e00 */
-		uint32_t pad[2];	/* unused */
-	} __attribute__((packed)) buf;
-
 	aw_send_fel_request(usb, AW_FEL_VERSION, 0, 0);
-	aw_usb_read(usb, &buf, sizeof(buf));
+	aw_usb_read(usb, buf, sizeof(*buf));
 	aw_read_fel_status(usb);
 
-	buf.soc_id = le32toh(buf.soc_id);
-	buf.unknown_0a = le32toh(buf.unknown_0a);
-	buf.protocol = le32toh(buf.protocol);
-	buf.scratchpad = le16toh(buf.scratchpad);
-	buf.pad[0] = le32toh(buf.pad[0]);
-	buf.pad[1] = le32toh(buf.pad[1]);
+	buf->soc_id = (le32toh(buf->soc_id) >> 8) & 0xFFFF;
+	buf->unknown_0a = le32toh(buf->unknown_0a);
+	buf->protocol = le32toh(buf->protocol);
+	buf->scratchpad = le16toh(buf->scratchpad);
+	buf->pad[0] = le32toh(buf->pad[0]);
+	buf->pad[1] = le32toh(buf->pad[1]);
+}
+
+void aw_fel_print_version(libusb_device_handle *usb)
+{
+	struct aw_fel_version buf;
+	aw_fel_get_version(usb, &buf);
 
 	const char *soc_name="unknown";
-	switch ((buf.soc_id >> 8) & 0xFFFF) {
+	switch (buf.soc_id) {
 	case 0x1623: soc_name="A10";break;
 	case 0x1625: soc_name="A13";break;
 	case 0x1633: soc_name="A31";break;
@@ -170,7 +176,10 @@ void aw_fel_get_version(libusb_device_handle *usb)
 	case 0x1639: soc_name="A80";break;
 	}
 
-	printf("%.8s soc=%08x(%s) %08x ver=%04x %02x %02x scratchpad=%08x %08x %08x\n", buf.signature, buf.soc_id, soc_name, buf.unknown_0a, buf.protocol, buf.unknown_12, buf.unknown_13, buf.scratchpad, buf.pad[0], buf.pad[1]);
+	printf("%.8s soc=%08x(%s) %08x ver=%04x %02x %02x scratchpad=%08x %08x %08x\n",
+		buf.signature, buf.soc_id, soc_name, buf.unknown_0a,
+		buf.protocol, buf.unknown_12, buf.unknown_13,
+		buf.scratchpad, buf.pad[0], buf.pad[1]);
 }
 
 void aw_fel_read(libusb_device_handle *usb, uint32_t offset, void *buf, size_t len)
@@ -387,7 +396,7 @@ int main(int argc, char **argv)
 			aw_fel_execute(handle, strtoul(argv[2], NULL, 0));
 			skip=3;
 		} else if (strncmp(argv[1], "ver", 3) == 0 && argc > 1) {
-			aw_fel_get_version(handle);
+			aw_fel_print_version(handle);
 			skip=1;
 		} else if (strcmp(argv[1], "write") == 0 && argc > 3) {
 			size_t size;
-- 
2.0.5

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [U-Boot] [PATCH sunxi-tools v2 2/2] fel: New command for loading U-Boot SPL binaries in eGON format
  2015-02-09  2:37 [U-Boot] [PATCH sunxi-tools v2 0/2] Support unified u-boot SPL for SD cards and FEL mode Siarhei Siamashka
  2015-02-09  2:37 ` [U-Boot] [PATCH sunxi-tools v2 1/2] fel: Split 'aw_fel_get_version' into 'get' and 'print' variants Siarhei Siamashka
@ 2015-02-09  2:37 ` Siarhei Siamashka
  2015-02-09 22:14 ` [U-Boot] [PATCH sunxi-tools v2 0/2] Support unified u-boot SPL for SD cards and FEL mode Simon Glass
  2015-02-10  8:21 ` Hans de Goede
  3 siblings, 0 replies; 7+ messages in thread
From: Siarhei Siamashka @ 2015-02-09  2:37 UTC (permalink / raw)
  To: u-boot

Now it is possible to load and execute the same U-Boot SPL,
as used for booting from SD cards. Just a different delivery
method (a USB OTG cable instead of an SD card) for handling
exactly the same content.

The only argument for this new command is the name of the SPL
binary file (with a eGON header generated by the 'mksunxiboot'
tool). Now the 'fel' tool can be run as:

    fel spl u-boot-sunxi-with-spl.bin

Before this change, the SPL was only able to use the memory between
addresses 0x2000 and ~0x5D00, totalling to something like ~15 KiB.
This is the biggest contiguous area in SRAM, which is not used
by the FEL code from the BROM. Unfortunately, it is rather small.
And also the unusual starting offset was making it difficult to
use the same SPL binary for booting from the SD card and via FEL.

There are surely more unused parts of SRAM, but they are scattered
across multiple locations, primarily because the FEL code from the
BROM sets up two stacks at inconvenient locations (the IRQ handler
stack at 0x2000, and a regular stack at 0x7000). Essentially, the
problem to solve here is to ensure a sufficiently large and consistent
SRAM address space for the SPL without any potentially SoC specific
holes in the case of booting over USB via FEL.

This is achieved by injecting special entry/exit thunk code, which
is moving the data in SRAM to provide a contiguous space for the SPL
at the beginning of SRAM, while still preserving the the data from
the BROM elsewhere. When the SPL tries to return control back to the
FEL code in the BROM, the thunk code moves the data back to its
original place. Additionally, the eGON checksum is verified to
ensure that no data corruption has happened due to some unexpected
clash with the FEL protocol code from the BROM.

So the thunk code takes care of the address space allocation uglyness
and provides the U-Boot SPL with a somewhat nicer abstraction.
Now the FEL booted SPL on A10/A13/A20/A31 can use up to 32 KiB of
SRAM because the BROM data is saved to different SRAM section.
There is also generic code, which does not rely on extra SRAM
sections, but just glues together the unused free space from
both BROM FEL stacks to provide something like ~21 KiB to the SPL.

Signed-off-by: Siarhei Siamashka <siarhei.siamashka@gmail.com>
---
Changes in v2:
 - Return to the BROM FEL code instead of trying to re-start it
   by jumping to the 0xffff0020 address. The USB connection
   re-initialization is too unreliable in practice.
 - Detect if the cache is enabled and refuse to work in this case
 - Overwrite the "eGON.BT0" signature in memory with "eGON.FEL"
   if everything is fine. And overwrite it with "eGON.BAD" if a
   checksum error had been detected.

 fel-to-spl-thunk.S | 172 ++++++++++++++++++++++++++++++++++++++
 fel-to-spl-thunk.h |  69 ++++++++++++++++
 fel.c              | 238 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 479 insertions(+)
 create mode 100644 fel-to-spl-thunk.S
 create mode 100644 fel-to-spl-thunk.h

diff --git a/fel-to-spl-thunk.S b/fel-to-spl-thunk.S
new file mode 100644
index 0000000..93350b3
--- /dev/null
+++ b/fel-to-spl-thunk.S
@@ -0,0 +1,172 @@
+/*
+ * Copyright ? 2015 Siarhei Siamashka <siarhei.siamashka@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/*************************************************************************/
+/* Usage instructions: "ruby -x fel-to-spl-thunk.S > fel-to-spl-thunk.h" */
+/*************************************************************************/
+
+#if 0 
+#!/usr/bin/env ruby
+
+def tool_exists(tool_name)
+    `which #{tool_name} > /dev/null 2>&1`
+    return $?.to_i == 0
+end
+
+toolchains = [
+  "arm-none-eabi-",
+  "arm-linux-gnueabihf-",
+  "arm-none-linux-gnueabi-",
+  "armv7a-hardfloat-linux-gnueabi-",
+]
+
+toolchain = toolchains.find { |toolchain| tool_exists("#{toolchain}gcc") }
+abort "Can't find any ARM crosscompiler\n" unless toolchain
+
+system("#{toolchain}gcc -o #{$PROGRAM_NAME}.o -c #{$PROGRAM_NAME}")
+exit($?.to_i) if $?.to_i != 0
+
+`#{toolchain}objdump -d #{$PROGRAM_NAME}.o`.each_line {|l|
+    next unless l =~ /(\h+)\:\s+(\h+)\s+(\S+)\s+([^;]*)/
+    printf("\t0x%s, /* %8s:    %-10s %-28s */\n", $2, $1, $3, $4.strip)
+}
+
+__END__
+#endif
+
+/*************************************************************************/
+
+BUF1		.req	r0
+BUF2		.req	r1
+TMP1		.req	r2
+TMP2		.req	r3
+SWAPTBL		.req	r4
+FULLSIZE	.req	r5
+BUFSIZE		.req	r6
+CHECKSUM	.req	r7
+
+entry_point:
+	b	setup_stack
+
+stack_begin:
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+stack_end:
+	nop
+
+	/* A function, which walks the table and swaps all buffers */
+swap_all_buffers:
+	adr	SWAPTBL,   swaptbl_start
+swap_next_buffer:
+	ldr	BUF1,      [SWAPTBL],  #4
+	ldr	BUF2,      [SWAPTBL],  #4
+	ldr	BUFSIZE,   [SWAPTBL],  #4
+	cmp	BUFSIZE,   #0
+	bxeq    lr
+swap_next_word:
+	ldr	TMP1,      [BUF1]
+	ldr	TMP2,      [BUF2]
+	subs	BUFSIZE,   BUFSIZE,    #4
+	str	TMP1,      [BUF2],     #4
+	str	TMP2,      [BUF1],     #4
+	bne	swap_next_word
+	b	swap_next_buffer
+
+setup_stack: /* Save the original SP, LR and CPSR to stack */
+	adr	BUF1,      stack_end
+	str	sp,        [BUF1, #-4]!
+	mov	sp,        BUF1
+	mrs	TMP1,      cpsr
+	push	{TMP1, lr}
+
+	/* Disable IRQ and FIQ */
+	orr	TMP1,      #0xc0
+	msr	cpsr_c,    TMP1
+
+	/* Check if the instructions or data cache is enabled */
+	mrc	p15, 0, TMP1, c1, c0, 0
+	movw	TMP2,      #((1 << 12) | (1 << 2))
+	tst	TMP1,      TMP2
+	bne	cache_is_unsupported
+
+	bl	swap_all_buffers
+
+verify_checksum:
+	movw	CHECKSUM,  #0x6c39
+	movt	CHECKSUM,  #0x5f0a
+	mov	BUF1,      #0
+	ldr     FULLSIZE,  [BUF1, #16]
+check_next_word:
+	ldr	TMP1,      [BUF1],   #4
+	subs	FULLSIZE,  FULLSIZE, #4
+	add	CHECKSUM,  CHECKSUM, TMP1
+	bne	check_next_word
+
+	mov	BUF1,      #0
+	ldr	TMP1,      [BUF1, #12]
+	subs	CHECKSUM,  CHECKSUM, TMP1, lsl #1
+	bne	checksum_is_bad
+
+	/* Change 'eGON.BT0' -> 'eGON.FEL' */
+	mov	BUF1,      #0
+	movw	TMP1,      (('F' << 8) + '.')
+	movt	TMP1,      (('L' << 8) + 'E')
+	str	TMP1,      [BUF1, #8]
+
+	/* Call the SPL code */
+	dsb
+	isb
+	blx	BUF1
+
+	/* Return back to FEL */
+	b	return_to_fel
+
+cache_is_unsupported:
+	/* Bail out if cache is enabled and change 'eGON.BT0' -> 'eGON.???' */
+	mov	BUF1,      #0
+	movw	TMP1,      (('?' << 8) + '.')
+	movt	TMP1,      (('?' << 8) + '?')
+	str	TMP1,      [BUF1, #8]
+	b	return_to_fel
+
+checksum_is_bad:
+	/* The checksum test failed, so change 'eGON.BT0' -> 'eGON.BAD' */
+	mov	BUF1,      #0
+	movw	TMP1,      (('B' << 8) + '.')
+	movt	TMP1,      (('D' << 8) + 'A')
+	str	TMP1,      [BUF1, #8]
+
+return_to_fel:
+	bl	swap_all_buffers
+	pop	{TMP1, lr}
+	msr	cpsr_c,    TMP1 /* Restore the original CPSR */
+	ldr     sp,        [sp]
+	bx	lr
+
+swaptbl_start:
diff --git a/fel-to-spl-thunk.h b/fel-to-spl-thunk.h
new file mode 100644
index 0000000..08e90e7
--- /dev/null
+++ b/fel-to-spl-thunk.h
@@ -0,0 +1,69 @@
+	0xea000015, /*        0:    b          5c <setup_stack>             */
+	0xe1a00000, /*        4:    nop                                     */
+	0xe1a00000, /*        8:    nop                                     */
+	0xe1a00000, /*        c:    nop                                     */
+	0xe1a00000, /*       10:    nop                                     */
+	0xe1a00000, /*       14:    nop                                     */
+	0xe1a00000, /*       18:    nop                                     */
+	0xe1a00000, /*       1c:    nop                                     */
+	0xe1a00000, /*       20:    nop                                     */
+	0xe1a00000, /*       24:    nop                                     */
+	0xe28f40e4, /*       28:    add        r4, pc, #228                 */
+	0xe4940004, /*       2c:    ldr        r0, [r4], #4                 */
+	0xe4941004, /*       30:    ldr        r1, [r4], #4                 */
+	0xe4946004, /*       34:    ldr        r6, [r4], #4                 */
+	0xe3560000, /*       38:    cmp        r6, #0                       */
+	0x012fff1e, /*       3c:    bxeq       lr                           */
+	0xe5902000, /*       40:    ldr        r2, [r0]                     */
+	0xe5913000, /*       44:    ldr        r3, [r1]                     */
+	0xe2566004, /*       48:    subs       r6, r6, #4                   */
+	0xe4812004, /*       4c:    str        r2, [r1], #4                 */
+	0xe4803004, /*       50:    str        r3, [r0], #4                 */
+	0x1afffff9, /*       54:    bne        40 <swap_next_word>          */
+	0xeafffff3, /*       58:    b          2c <swap_next_buffer>        */
+	0xe24f0040, /*       5c:    sub        r0, pc, #64                  */
+	0xe520d004, /*       60:    str        sp, [r0, #-4]!               */
+	0xe1a0d000, /*       64:    mov        sp, r0                       */
+	0xe10f2000, /*       68:    mrs        r2, CPSR                     */
+	0xe92d4004, /*       6c:    push       {r2, lr}                     */
+	0xe38220c0, /*       70:    orr        r2, r2, #192                 */
+	0xe121f002, /*       74:    msr        CPSR_c, r2                   */
+	0xee112f10, /*       78:    mrc        15, 0, r2, cr1, cr0, {0}     */
+	0xe3013004, /*       7c:    movw       r3, #4100                    */
+	0xe1120003, /*       80:    tst        r2, r3                       */
+	0x1a000014, /*       84:    bne        dc <cache_is_unsupported>    */
+	0xebffffe6, /*       88:    bl         28 <swap_all_buffers>        */
+	0xe3067c39, /*       8c:    movw       r7, #27705                   */
+	0xe3457f0a, /*       90:    movt       r7, #24330                   */
+	0xe3a00000, /*       94:    mov        r0, #0                       */
+	0xe5905010, /*       98:    ldr        r5, [r0, #16]                */
+	0xe4902004, /*       9c:    ldr        r2, [r0], #4                 */
+	0xe2555004, /*       a0:    subs       r5, r5, #4                   */
+	0xe0877002, /*       a4:    add        r7, r7, r2                   */
+	0x1afffffb, /*       a8:    bne        9c <check_next_word>         */
+	0xe3a00000, /*       ac:    mov        r0, #0                       */
+	0xe590200c, /*       b0:    ldr        r2, [r0, #12]                */
+	0xe0577082, /*       b4:    subs       r7, r7, r2, lsl #1           */
+	0x1a00000c, /*       b8:    bne        f0 <checksum_is_bad>         */
+	0xe3a00000, /*       bc:    mov        r0, #0                       */
+	0xe304262e, /*       c0:    movw       r2, #17966                   */
+	0xe3442c45, /*       c4:    movt       r2, #19525                   */
+	0xe5802008, /*       c8:    str        r2, [r0, #8]                 */
+	0xf57ff04f, /*       cc:    dsb        sy                           */
+	0xf57ff06f, /*       d0:    isb        sy                           */
+	0xe12fff30, /*       d4:    blx        r0                           */
+	0xea000008, /*       d8:    b          100 <return_to_fel>          */
+	0xe3a00000, /*       dc:    mov        r0, #0                       */
+	0xe3032f2e, /*       e0:    movw       r2, #16174                   */
+	0xe3432f3f, /*       e4:    movt       r2, #16191                   */
+	0xe5802008, /*       e8:    str        r2, [r0, #8]                 */
+	0xea000003, /*       ec:    b          100 <return_to_fel>          */
+	0xe3a00000, /*       f0:    mov        r0, #0                       */
+	0xe304222e, /*       f4:    movw       r2, #16942                   */
+	0xe3442441, /*       f8:    movt       r2, #17473                   */
+	0xe5802008, /*       fc:    str        r2, [r0, #8]                 */
+	0xebffffc8, /*      100:    bl         28 <swap_all_buffers>        */
+	0xe8bd4004, /*      104:    pop        {r2, lr}                     */
+	0xe121f002, /*      108:    msr        CPSR_c, r2                   */
+	0xe59dd000, /*      10c:    ldr        sp, [sp]                     */
+	0xe12fff1e, /*      110:    bx         lr                           */
diff --git a/fel.c b/fel.c
index 542bf4b..d18a1d8 100644
--- a/fel.c
+++ b/fel.c
@@ -29,6 +29,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <errno.h>
+#include <unistd.h>
 
 #include "endian_compat.h"
 
@@ -294,6 +295,237 @@ void aw_fel_fill(libusb_device_handle *usb, uint32_t offset, size_t size, unsign
 	aw_fel_write(usb, buf, offset, size);
 }
 
+/*
+ * The 'sram_swap_buffers' structure is used to describe information about
+ * two buffers in SRAM, the content of which needs to be exchanged before
+ * calling the U-Boot SPL code and then exchanged again before returning
+ * control back to the FEL code from the BROM.
+ */
+
+typedef struct {
+	uint32_t buf1; /* BROM buffer */
+	uint32_t buf2; /* backup storage location */
+	uint32_t size; /* buffer size */
+} sram_swap_buffers;
+
+/*
+ * Each SoC variant may have its own list of memory buffers to be exchanged
+ * and the information about the placement of the thunk code, which handles
+ * the transition of execution from the BROM FEL code to the U-Boot SPL and
+ * back.
+ *
+ * Note: the entries in the 'swap_buffers' tables need to be sorted by 'buf1'
+ * addresses. And the 'buf1' addresses are the BROM data buffers, while 'buf2'
+ * addresses are the intended backup locations.
+ */
+typedef struct {
+	uint32_t           soc_id;     /* ID of the SoC */
+	uint32_t           thunk_addr; /* Address of the thunk code */
+	uint32_t           thunk_size; /* Maximal size of the thunk code */
+	sram_swap_buffers *swap_buffers;
+} soc_sram_info;
+
+/*
+ * The FEL code from BROM in A10/A13/A20 sets up two stacks for itself. One
+ * at 0x2000 (and growing down) for the IRQ handler. And another one at 0x7000
+ * (and also growing down) for the regular code. In order to use the whole
+ * 32 KiB in the A1/A2 sections of SRAM, we need to temporarily move these
+ * stacks elsewhere. And the addresses above 0x7000 are also a bit suspicious,
+ * so it might be safer to backup the 0x7000-0x8000 area too. On A10/A13/A20
+ * we can use the SRAM section A3 (0x8000) for this purpose.
+ */
+sram_swap_buffers a10_a13_a20_sram_swap_buffers[] = {
+	{ .buf1 = 0x01800, .buf2 = 0x8000, .size = 0x800 },
+	{ .buf1 = 0x05C00, .buf2 = 0x8800, .size = 0x8000 - 0x5C00 },
+	{ 0 }  /* End of the table */
+};
+
+/*
+ * A31 is very similar to A10/A13/A20, except that it has no SRAM at 0x8000.
+ * So we use the SRAM section at 0x44000 instead. This is the memory, which
+ * is normally shared with the OpenRISC core (should we do an extra check to
+ * ensure that this core is powered off and can't interfere?).
+ */
+sram_swap_buffers a31_sram_swap_buffers[] = {
+	{ .buf1 = 0x01800, .buf2 = 0x44000, .size = 0x800 },
+	{ .buf1 = 0x05C00, .buf2 = 0x44800, .size = 0x8000 - 0x5C00 },
+	{ 0 }  /* End of the table */
+};
+
+soc_sram_info soc_sram_info_table[] = {
+	{
+		.soc_id       = 0x1623, /* Allwinner A10 */
+		.thunk_addr   = 0xAE00, .thunk_size = 0x200,
+		.swap_buffers = a10_a13_a20_sram_swap_buffers,
+	},
+	{
+		.soc_id       = 0x1625, /* Allwinner A13 */
+		.thunk_addr   = 0xAE00, .thunk_size = 0x200,
+		.swap_buffers = a10_a13_a20_sram_swap_buffers,
+	},
+	{
+		.soc_id       = 0x1651, /* Allwinner A20 */
+		.thunk_addr   = 0xAE00, .thunk_size = 0x200,
+		.swap_buffers = a10_a13_a20_sram_swap_buffers,
+	},
+	{
+		.soc_id       = 0x1633, /* Allwinner A31 */
+		.thunk_addr   = 0x46E00, .thunk_size = 0x200,
+		.swap_buffers = a31_sram_swap_buffers,
+	},
+	{ 0 } /* End of the table */
+};
+
+/*
+ * This generic record assumes BROM with similar properties to A10/A13/A20/A31,
+ * but no extra SRAM sections beyond 0x8000. It also assumes that the IRQ
+ * handler stack usage never exceeds 0x400 bytes.
+ *
+ * The users may or may not hope that the 0x7000-0x8000 area is also unused
+ * by the BROM and re-purpose it for the SPL stack.
+ *
+ * The size limit for the ".text + .data" sections is ~21 KiB.
+ */
+sram_swap_buffers generic_sram_swap_buffers[] = {
+	{ .buf1 = 0x01C00, .buf2 = 0x5800, .size = 0x400 },
+	{ 0 }  /* End of the table */
+};
+
+soc_sram_info generic_sram_info = {
+	.thunk_addr   = 0x5680, .thunk_size = 0x180,
+	.swap_buffers = generic_sram_swap_buffers,
+};
+
+soc_sram_info *aw_fel_get_sram_info(libusb_device_handle *usb)
+{
+	int i;
+	struct aw_fel_version buf;
+
+	aw_fel_get_version(usb, &buf);
+
+	for (i = 0; soc_sram_info_table[i].swap_buffers; i++)
+		if (soc_sram_info_table[i].soc_id == buf.soc_id)
+			return &soc_sram_info_table[i];
+
+	printf("Warning: no 'soc_sram_info' data for your SoC (id=%04X)\n",
+	       buf.soc_id);
+	return &generic_sram_info;
+}
+
+static uint32_t fel_to_spl_thunk[] = {
+	#include "fel-to-spl-thunk.h"
+};
+
+void aw_fel_write_and_execute_spl(libusb_device_handle *usb,
+				  uint8_t *buf, size_t len)
+{
+	soc_sram_info *sram_info = aw_fel_get_sram_info(usb);
+	sram_swap_buffers *swap_buffers;
+	char header_signature[9] = { 0 };
+	size_t i, thunk_size;
+	uint32_t *thunk_buf;
+	uint32_t spl_checksum, spl_len, spl_len_limit = 0x8000;
+	uint32_t *buf32 = (uint32_t *)buf;
+	uint32_t written = 0;
+
+	if (!sram_info || !sram_info->swap_buffers) {
+		fprintf(stderr, "SPL: Unsupported SoC type\n");
+		exit(1);
+	}
+
+	if (len < 32 || memcmp(buf + 4, "eGON.BT0", 8) != 0) {
+		fprintf(stderr, "SPL: eGON header is not found\n");
+		exit(1);
+	}
+
+	spl_checksum = 2 * le32toh(buf32[3]) - 0x5F0A6C39;
+	spl_len = le32toh(buf32[4]);
+
+	if (spl_len > len || (spl_len % 4) != 0) {
+		fprintf(stderr, "SPL: bad length in the eGON header\n");
+		exit(1);
+	}
+
+	len = spl_len;
+	for (i = 0; i < len / 4; i++)
+		spl_checksum -= le32toh(buf32[i]);
+
+	if (spl_checksum != 0) {
+		fprintf(stderr, "SPL: checksum check failed\n");
+		exit(1);
+	}
+
+	swap_buffers = sram_info->swap_buffers;
+	for (i = 0; swap_buffers[i].size; i++) {
+		if (swap_buffers[i].buf2 < spl_len_limit)
+			spl_len_limit = swap_buffers[i].buf2;
+		if (len > 0 && written < swap_buffers[i].buf1) {
+			uint32_t tmp = swap_buffers[i].buf1 - written;
+			if (tmp > len)
+				tmp = len;
+			aw_fel_write(usb, buf, written, tmp);
+			written += tmp;
+			buf += tmp;
+			len -= tmp;
+		}
+		if (len > 0 && written == swap_buffers[i].buf1) {
+			uint32_t tmp = swap_buffers[i].size;
+			if (tmp > len)
+				tmp = len;
+			aw_fel_write(usb, buf, swap_buffers[i].buf2, tmp);
+			written += tmp;
+			buf += tmp;
+			len -= tmp;
+		}
+	}
+
+	/* Clarify the SPL size limitations, and bail out if they are not met */
+	if (sram_info->thunk_addr < spl_len_limit)
+		spl_len_limit = sram_info->thunk_addr;
+
+	if (spl_len > spl_len_limit) {
+		fprintf(stderr, "SPL: too large (need %d, have %d)\n",
+			(int)spl_len, (int)spl_len_limit);
+		exit(1);
+	}
+
+	/* Write the remaining part of the SPL */
+	if (len > 0)
+		aw_fel_write(usb, buf, written, len);
+
+	thunk_size = sizeof(fel_to_spl_thunk) + (i + 1) * sizeof(*swap_buffers);
+
+	if (thunk_size > sram_info->thunk_size) {
+		fprintf(stderr, "SPL: bad thunk size (need %d, have %d)\n",
+			(int)sizeof(fel_to_spl_thunk), sram_info->thunk_size);
+		exit(1);
+	}
+
+	thunk_buf = malloc(thunk_size);
+	memcpy(thunk_buf, fel_to_spl_thunk, sizeof(fel_to_spl_thunk));
+	memcpy(thunk_buf + sizeof(fel_to_spl_thunk) / sizeof(uint32_t),
+	       swap_buffers, (i + 1) * sizeof(*swap_buffers));
+
+	for (i = 0; i < thunk_size / sizeof(uint32_t); i++)
+		thunk_buf[i] = htole32(thunk_buf[i]);
+
+	aw_fel_write(usb, thunk_buf, sram_info->thunk_addr, thunk_size);
+	aw_fel_execute(usb, sram_info->thunk_addr);
+
+	free(thunk_buf);
+
+	/* TODO: Try to find and fix the bug, which needs this workaround */
+	usleep(250000);
+
+	/* Read back the result and check if everything was fine */
+	aw_fel_read(usb, 4, header_signature, 8);
+	if (strcmp(header_signature, "eGON.FEL") != 0) {
+		fprintf(stderr, "SPL: failure code '%s'\n",
+			header_signature);
+		exit(1);
+	}
+}
+
 static int aw_fel_get_endpoint(libusb_device_handle *usb)
 {
 	struct libusb_device *dev = libusb_get_device(usb);
@@ -352,6 +584,7 @@ int main(int argc, char **argv)
 			"	ver[sion]			Show BROM version\n"
 			"	clear address length		Clear memory\n"
 			"	fill address length value	Fill memory\n"
+			"	spl file			Load and execute U-Boot SPL\n"
 			, argv[0]
 		);
 	}
@@ -417,6 +650,11 @@ int main(int argc, char **argv)
 		} else if (strcmp(argv[1], "fill") == 0 && argc > 3) {
 			aw_fel_fill(handle, strtoul(argv[2], NULL, 0), strtoul(argv[3], NULL, 0), (unsigned char)strtoul(argv[4], NULL, 0));
 			skip=4;
+		} else if (strcmp(argv[1], "spl") == 0 && argc > 2) {
+			size_t size;
+			uint8_t *buf = load_file(argv[2], &size);
+			aw_fel_write_and_execute_spl(handle, buf, size);
+			skip=2;
 		} else {
 			fprintf(stderr,"Invalid command %s\n", argv[1]);
 			exit(1);
-- 
2.0.5

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [U-Boot] [PATCH sunxi-tools v2 0/2] Support unified u-boot SPL for SD cards and FEL mode
  2015-02-09  2:37 [U-Boot] [PATCH sunxi-tools v2 0/2] Support unified u-boot SPL for SD cards and FEL mode Siarhei Siamashka
  2015-02-09  2:37 ` [U-Boot] [PATCH sunxi-tools v2 1/2] fel: Split 'aw_fel_get_version' into 'get' and 'print' variants Siarhei Siamashka
  2015-02-09  2:37 ` [U-Boot] [PATCH sunxi-tools v2 2/2] fel: New command for loading U-Boot SPL binaries in eGON format Siarhei Siamashka
@ 2015-02-09 22:14 ` Simon Glass
  2015-02-11  3:01   ` Siarhei Siamashka
  2015-02-10  8:21 ` Hans de Goede
  3 siblings, 1 reply; 7+ messages in thread
From: Simon Glass @ 2015-02-09 22:14 UTC (permalink / raw)
  To: u-boot

Hi Siarhei,

On 8 February 2015 at 19:37, Siarhei Siamashka
<siarhei.siamashka@gmail.com> wrote:
> An updated variant of the older patch
>     http://lists.denx.de/pipermail/u-boot/2015-February/204024.html
>
> These patches are not for the u-boot code (unless u-boot decides to
> cannibalize the 'fel' tool later) but still provide a glue layer
> between the Allwinner BROM code and the u-boot SPL code. And need
> to play nice with both of them.

It's an interesting idea actually - I wonder what people think about
putting these tools in the source tree. I suspect it could get a bit
out of hand? But it would make it easier to keep things in sync,

[snip]

Regards,
Simon

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [U-Boot] [PATCH sunxi-tools v2 0/2] Support unified u-boot SPL for SD cards and FEL mode
  2015-02-09  2:37 [U-Boot] [PATCH sunxi-tools v2 0/2] Support unified u-boot SPL for SD cards and FEL mode Siarhei Siamashka
                   ` (2 preceding siblings ...)
  2015-02-09 22:14 ` [U-Boot] [PATCH sunxi-tools v2 0/2] Support unified u-boot SPL for SD cards and FEL mode Simon Glass
@ 2015-02-10  8:21 ` Hans de Goede
  2015-02-11  3:06   ` Siarhei Siamashka
  3 siblings, 1 reply; 7+ messages in thread
From: Hans de Goede @ 2015-02-10  8:21 UTC (permalink / raw)
  To: u-boot

Hi,

On 09-02-15 03:37, Siarhei Siamashka wrote:
> An updated variant of the older patch
>      http://lists.denx.de/pipermail/u-boot/2015-February/204024.html
>
> These patches are not for the u-boot code (unless u-boot decides to
> cannibalize the 'fel' tool later) but still provide a glue layerHi,
> between the Allwinner BROM code and the u-boot SPL code. And need
> to play nice with both of them.
>
> The updated 'fel' tool is supposed to be used together with u-boot
> v2015.04 and provide support for booting regular u-boot SPL binaries
> over USB via FEL mode. So that a special u-boot sunxi FEL configuration
> can be eventually dropped in the future.
>
> The usage instructions are in the 'New method of booting u-boot over USB
> (u-boot v2015.04 and later versions)' section of the linux-sunxi wiki page
>      http://linux-sunxi.org/index.php?title=FEL/USBBoot&oldid=12979
>
> It temporarily moves the BROM data from the first 32 KiB of SRAM into
> a different SRAM section before calling the SPL code. And then moves
> it back before returning from the SPL back to the FEL code in BROM.
> This provides a contiguous 32 KiB block in the beginning of SRAM for
> use by the SPL. And in the case if an extra SRAM section is not
> available, we can at least "defragmemnt" the free memory areas
> and still provide a contiguous ~21 KiB block to the SPL in the
> beginning of SRAM.
>
> This code is also available in the following branch:
>      https://github.com/ssvb/sunxi-tools/commits/20150206-fel-large-spl-support
>
> Siarhei Siamashka (2):
>    fel: Split 'aw_fel_get_version' into 'get' and 'print' variants
>    fel: New command for loading U-Boot SPL binaries in eGON format
>
>   fel-to-spl-thunk.S | 172 +++++++++++++++++++++++++++++++
>   fel-to-spl-thunk.h |  69 +++++++++++++
>   fel.c              | 291 +++++++++++++++++++++++++++++++++++++++++++++++++----
>   3 files changed, 510 insertions(+), 22 deletions(-)
>   create mode 100644 fel-to-spl-thunk.S
>   create mode 100644 fel-to-spl-thunk.h

Thanks for your work on this, ACK to both patches, feel free to push them.

One question, the new wiki instructions say that for the latest upstream u-boot
_felconfig is no longer necessary, but Simon's patches to fix FEL support upstream
contain some #ifdef FEL in start.S to skip some lowlevel init when in FEL mode,
does that mean that skipping this is no longer necessary ?

Regards,

Hans

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [U-Boot] [PATCH sunxi-tools v2 0/2] Support unified u-boot SPL for SD cards and FEL mode
  2015-02-09 22:14 ` [U-Boot] [PATCH sunxi-tools v2 0/2] Support unified u-boot SPL for SD cards and FEL mode Simon Glass
@ 2015-02-11  3:01   ` Siarhei Siamashka
  0 siblings, 0 replies; 7+ messages in thread
From: Siarhei Siamashka @ 2015-02-11  3:01 UTC (permalink / raw)
  To: u-boot

On Mon, 9 Feb 2015 15:14:51 -0700
Simon Glass <sjg@chromium.org> wrote:

> Hi Siarhei,
> 
> On 8 February 2015 at 19:37, Siarhei Siamashka
> <siarhei.siamashka@gmail.com> wrote:
> > An updated variant of the older patch
> >     http://lists.denx.de/pipermail/u-boot/2015-February/204024.html
> >
> > These patches are not for the u-boot code (unless u-boot decides to
> > cannibalize the 'fel' tool later) but still provide a glue layer
> > between the Allwinner BROM code and the u-boot SPL code. And need
> > to play nice with both of them.
> 
> It's an interesting idea actually - I wonder what people think about
> putting these tools in the source tree. I suspect it could get a bit
> out of hand? But it would make it easier to keep things in sync,

Yes, keeping it is sync with the mksunxiboot program would be easier
in this case.

But I searched a bit, and can see that sunxi-tools is already packaged
in some linux distributions, for example:

    https://packages.debian.org/search?keywords=sunxi-tools

Maybe it's better to keep the 'fel' tool in the 'sunxi-tools' package
and just make sure that it gets reasonably well supported in linux
distributions.

In addition, there might be other bootloaders or "bare metal" users.
I have found this very cool project, which relies on the FEL mode
and allows to run code on the OpenRISC core in Allwinner A31:

    https://github.com/skristiansson/ar100-info

What's particularly interesting is that it apparently had the DRAM
controller support for A31 (sun6i) even before this was implemented
in u-boot :)

-- 
Best regards,
Siarhei Siamashka

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [U-Boot] [PATCH sunxi-tools v2 0/2] Support unified u-boot SPL for SD cards and FEL mode
  2015-02-10  8:21 ` Hans de Goede
@ 2015-02-11  3:06   ` Siarhei Siamashka
  0 siblings, 0 replies; 7+ messages in thread
From: Siarhei Siamashka @ 2015-02-11  3:06 UTC (permalink / raw)
  To: u-boot

On Tue, 10 Feb 2015 09:21:59 +0100
Hans de Goede <hdegoede@redhat.com> wrote:

> Hi,
> 
> On 09-02-15 03:37, Siarhei Siamashka wrote:
> > An updated variant of the older patch
> >      http://lists.denx.de/pipermail/u-boot/2015-February/204024.html
> >
> > These patches are not for the u-boot code (unless u-boot decides to
> > cannibalize the 'fel' tool later) but still provide a glue layerHi,
> > between the Allwinner BROM code and the u-boot SPL code. And need
> > to play nice with both of them.
> >
> > The updated 'fel' tool is supposed to be used together with u-boot
> > v2015.04 and provide support for booting regular u-boot SPL binaries
> > over USB via FEL mode. So that a special u-boot sunxi FEL configuration
> > can be eventually dropped in the future.
> >
> > The usage instructions are in the 'New method of booting u-boot over USB
> > (u-boot v2015.04 and later versions)' section of the linux-sunxi wiki page
> >      http://linux-sunxi.org/index.php?title=FEL/USBBoot&oldid=12979
> >
> > It temporarily moves the BROM data from the first 32 KiB of SRAM into
> > a different SRAM section before calling the SPL code. And then moves
> > it back before returning from the SPL back to the FEL code in BROM.
> > This provides a contiguous 32 KiB block in the beginning of SRAM for
> > use by the SPL. And in the case if an extra SRAM section is not
> > available, we can at least "defragmemnt" the free memory areas
> > and still provide a contiguous ~21 KiB block to the SPL in the
> > beginning of SRAM.
> >
> > This code is also available in the following branch:
> >      https://github.com/ssvb/sunxi-tools/commits/20150206-fel-large-spl-support
> >
> > Siarhei Siamashka (2):
> >    fel: Split 'aw_fel_get_version' into 'get' and 'print' variants
> >    fel: New command for loading U-Boot SPL binaries in eGON format
> >
> >   fel-to-spl-thunk.S | 172 +++++++++++++++++++++++++++++++
> >   fel-to-spl-thunk.h |  69 +++++++++++++
> >   fel.c              | 291 +++++++++++++++++++++++++++++++++++++++++++++++++----
> >   3 files changed, 510 insertions(+), 22 deletions(-)
> >   create mode 100644 fel-to-spl-thunk.S
> >   create mode 100644 fel-to-spl-thunk.h
> 
> Thanks for your work on this, ACK to both patches, feel free to push them.

Thanks, pushed to sunxi-tool

> One question, the new wiki instructions say that for the latest upstream u-boot
> _felconfig is no longer necessary, but Simon's patches to fix FEL support upstream
> contain some #ifdef FEL in start.S to skip some lowlevel init when in FEL mode,
> does that mean that skipping this is no longer necessary ?

Skipping is not necessary if we save/restore some additional registers
instead. I'm just applying extra changes on top of Simon's patches,
and it works (the wiki page links to the git branch with these
changes). This is discussed at

    http://lists.denx.de/pipermail/u-boot/2015-February/204361.html

-- 
Best regards,
Siarhei Siamashka

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2015-02-11  3:06 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-02-09  2:37 [U-Boot] [PATCH sunxi-tools v2 0/2] Support unified u-boot SPL for SD cards and FEL mode Siarhei Siamashka
2015-02-09  2:37 ` [U-Boot] [PATCH sunxi-tools v2 1/2] fel: Split 'aw_fel_get_version' into 'get' and 'print' variants Siarhei Siamashka
2015-02-09  2:37 ` [U-Boot] [PATCH sunxi-tools v2 2/2] fel: New command for loading U-Boot SPL binaries in eGON format Siarhei Siamashka
2015-02-09 22:14 ` [U-Boot] [PATCH sunxi-tools v2 0/2] Support unified u-boot SPL for SD cards and FEL mode Simon Glass
2015-02-11  3:01   ` Siarhei Siamashka
2015-02-10  8:21 ` Hans de Goede
2015-02-11  3:06   ` Siarhei Siamashka

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.