Commit 82b9c656 authored by Siarhei Siamashka's avatar Siarhei Siamashka
Browse files

fel: Make the SPL load address configurable instead of hardcoded 0x0



Add a new field 'spl_addr' to the SoC description structure and adjust
the code to honor it. This is needed for supporting Allwinner A80.

Tested on Allwinner A20 by changing the 'spl_addr' to 0x28000 in the
'fel' tool and using a custom build of U-Boot (CONFIG_SPL_TEXT_BASE
changed from 0x20 to 0x28020).
Signed-off-by: default avatarSiarhei Siamashka <siarhei.siamashka@gmail.com>
Acked-by: default avatarHans de Goede <hdegoede@redhat.com>
parent a69bbe96
......@@ -69,6 +69,7 @@ SWAPTBL .req r4
FULLSIZE .req r5
BUFSIZE .req r6
CHECKSUM .req r7
SPL_ADDR .req r8
entry_point:
b setup_stack
......@@ -87,7 +88,7 @@ stack_end:
/* A function, which walks the table and swaps all buffers */
swap_all_buffers:
adr SWAPTBL, swaptbl_start
adr SWAPTBL, appended_data + 4
swap_next_buffer:
ldr BUF1, [SWAPTBL], #4
ldr BUF2, [SWAPTBL], #4
......@@ -104,6 +105,7 @@ swap_next_word:
b swap_next_buffer
setup_stack: /* Save the original SP, LR and CPSR to stack */
ldr SPL_ADDR, appended_data
adr BUF1, stack_end
str sp, [BUF1, #-4]!
mov sp, BUF1
......@@ -125,7 +127,7 @@ setup_stack: /* Save the original SP, LR and CPSR to stack */
verify_checksum:
movw CHECKSUM, #0x6c39
movt CHECKSUM, #0x5f0a
mov BUF1, #0
mov BUF1, SPL_ADDR
ldr FULLSIZE, [BUF1, #16]
check_next_word:
ldr TMP1, [BUF1], #4
......@@ -133,39 +135,35 @@ check_next_word:
add CHECKSUM, CHECKSUM, TMP1
bne check_next_word
mov BUF1, #0
ldr TMP1, [BUF1, #12]
ldr TMP1, [SPL_ADDR, #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]
str TMP1, [SPL_ADDR, #8]
/* Call the SPL code */
dsb
isb
blx BUF1
blx SPL_ADDR
/* 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]
str TMP1, [SPL_ADDR, #8]
b return_to_fel_noswap
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]
str TMP1, [SPL_ADDR, #8]
return_to_fel:
bl swap_all_buffers
......@@ -175,4 +173,15 @@ return_to_fel_noswap:
ldr sp, [sp]
bx lr
swaptbl_start:
appended_data:
/*
* The appended data uses the following format:
*
* struct {
* uint32_t spl_addr;
* sram_swap_buffers swaptbl[];
* };
*
* More details about the 'spl_addr' variable and the 'sram_swap_buffers'
* struct can be found in the 'fel.c' source file.
*/
......@@ -8,7 +8,7 @@
0xe1a00000, /* 1c: nop */
0xe1a00000, /* 20: nop */
0xe1a00000, /* 24: nop */
0xe28f40e4, /* 28: add r4, pc, #228 */
0xe28f40dc, /* 28: add r4, pc, #220 */
0xe4940004, /* 2c: ldr r0, [r4], #4 */
0xe4941004, /* 30: ldr r1, [r4], #4 */
0xe4946004, /* 34: ldr r6, [r4], #4 */
......@@ -21,49 +21,46 @@
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] */
0xe59f80a4, /* 5c: ldr r8, [pc, #164] */
0xe24f0044, /* 60: sub r0, pc, #68 */
0xe520d004, /* 64: str sp, [r0, #-4]! */
0xe1a0d000, /* 68: mov sp, r0 */
0xe10f2000, /* 6c: mrs r2, CPSR */
0xe92d4004, /* 70: push {r2, lr} */
0xe38220c0, /* 74: orr r2, r2, #192 */
0xe121f002, /* 78: msr CPSR_c, r2 */
0xee112f10, /* 7c: mrc 15, 0, r2, cr1, cr0, {0} */
0xe3013004, /* 80: movw r3, #4100 */
0xe1120003, /* 84: tst r2, r3 */
0x1a000012, /* 88: bne d8 <cache_is_unsupported> */
0xebffffe5, /* 8c: bl 28 <swap_all_buffers> */
0xe3067c39, /* 90: movw r7, #27705 */
0xe3457f0a, /* 94: movt r7, #24330 */
0xe1a00008, /* 98: mov r0, r8 */
0xe5905010, /* 9c: ldr r5, [r0, #16] */
0xe4902004, /* a0: ldr r2, [r0], #4 */
0xe2555004, /* a4: subs r5, r5, #4 */
0xe0877002, /* a8: add r7, r7, r2 */
0x1afffffb, /* ac: bne a0 <check_next_word> */
0xe598200c, /* b0: ldr r2, [r8, #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] */
0xea000004, /* ec: b 104 <return_to_fel_noswap> */
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 */
0x1a00000a, /* b8: bne e8 <checksum_is_bad> */
0xe304262e, /* bc: movw r2, #17966 */
0xe3442c45, /* c0: movt r2, #19525 */
0xe5882008, /* c4: str r2, [r8, #8] */
0xf57ff04f, /* c8: dsb sy */
0xf57ff06f, /* cc: isb sy */
0xe12fff38, /* d0: blx r8 */
0xea000006, /* d4: b f4 <return_to_fel> */
0xe3032f2e, /* d8: movw r2, #16174 */
0xe3432f3f, /* dc: movt r2, #16191 */
0xe5882008, /* e0: str r2, [r8, #8] */
0xea000003, /* e4: b f8 <return_to_fel_noswap> */
0xe304222e, /* e8: movw r2, #16942 */
0xe3442441, /* ec: movt r2, #17473 */
0xe5882008, /* f0: str r2, [r8, #8] */
0xebffffcb, /* f4: bl 28 <swap_all_buffers> */
0xe8bd4004, /* f8: pop {r2, lr} */
0xe121f002, /* fc: msr CPSR_c, r2 */
0xe59dd000, /* 100: ldr sp, [sp] */
0xe12fff1e, /* 104: bx lr */
......@@ -349,6 +349,7 @@ typedef struct {
*/
typedef struct {
uint32_t soc_id; /* ID of the SoC */
uint32_t spl_addr; /* SPL load address */
uint32_t scratch_addr; /* A safe place to upload & run code */
uint32_t thunk_addr; /* Address of the thunk code */
uint32_t thunk_size; /* Maximal size of the thunk code */
......@@ -695,7 +696,7 @@ void aw_fel_write_and_execute_spl(libusb_device_handle *usb,
uint32_t sp, sp_irq;
uint32_t spl_checksum, spl_len, spl_len_limit = SPL_LEN_LIMIT;
uint32_t *buf32 = (uint32_t *)buf;
uint32_t written = 0;
uint32_t cur_addr = sram_info->spl_addr;
uint32_t *tt = NULL;
if (!sram_info || !sram_info->swap_buffers) {
......@@ -737,23 +738,24 @@ void aw_fel_write_and_execute_spl(libusb_device_handle *usb,
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 ((swap_buffers[i].buf2 >= sram_info->spl_addr) &&
(swap_buffers[i].buf2 < sram_info->spl_addr + spl_len_limit))
spl_len_limit = swap_buffers[i].buf2 - sram_info->spl_addr;
if (len > 0 && cur_addr < swap_buffers[i].buf1) {
uint32_t tmp = swap_buffers[i].buf1 - cur_addr;
if (tmp > len)
tmp = len;
aw_fel_write(usb, buf, written, tmp);
written += tmp;
aw_fel_write(usb, buf, cur_addr, tmp);
cur_addr += tmp;
buf += tmp;
len -= tmp;
}
if (len > 0 && written == swap_buffers[i].buf1) {
if (len > 0 && cur_addr == 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;
cur_addr += tmp;
buf += tmp;
len -= tmp;
}
......@@ -771,9 +773,10 @@ void aw_fel_write_and_execute_spl(libusb_device_handle *usb,
/* Write the remaining part of the SPL */
if (len > 0)
aw_fel_write(usb, buf, written, len);
aw_fel_write(usb, buf, cur_addr, len);
thunk_size = sizeof(fel_to_spl_thunk) + (i + 1) * sizeof(*swap_buffers);
thunk_size = sizeof(fel_to_spl_thunk) + sizeof(sram_info->spl_addr) +
(i + 1) * sizeof(*swap_buffers);
if (thunk_size > sram_info->thunk_size) {
fprintf(stderr, "SPL: bad thunk size (need %d, have %d)\n",
......@@ -784,6 +787,8 @@ void aw_fel_write_and_execute_spl(libusb_device_handle *usb,
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),
&sram_info->spl_addr, sizeof(sram_info->spl_addr));
memcpy(thunk_buf + sizeof(fel_to_spl_thunk) / sizeof(uint32_t) + 1,
swap_buffers, (i + 1) * sizeof(*swap_buffers));
for (i = 0; i < thunk_size / sizeof(uint32_t); i++)
......@@ -800,7 +805,7 @@ void aw_fel_write_and_execute_spl(libusb_device_handle *usb,
usleep(250000);
/* Read back the result and check if everything was fine */
aw_fel_read(usb, 4, header_signature, 8);
aw_fel_read(usb, sram_info->spl_addr + 4, header_signature, 8);
if (strcmp(header_signature, "eGON.FEL") != 0) {
fprintf(stderr, "SPL: failure code '%s'\n",
header_signature);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment