diff options
author | Vikas Das <vdas@codeaurora.org> | 2014-09-22 17:49:56 -0700 |
---|---|---|
committer | Patrick Georgi <pgeorgi@google.com> | 2015-04-15 21:56:56 +0200 |
commit | 08f249e7d07e7742e202d08305822af2b3ddec78 (patch) | |
tree | ad7403d9915d06d309e1a7227b3af62a00e71dae /src/soc/qualcomm/ipq806x | |
parent | 239622677b3e3e20d1de8f79224edf1cc97d7083 (diff) |
ipq806x: Load TZBSP blob from coreboot ramstage
Read the TZBSP blob from CBFS and run it. A side effect of the blob
execution is switching the processor into User mode.
Starting TZBSP requires processor running in Supervisor mode, TZBSP
code is compiled for ARM. Coreboot is executing in System mode and is
compiled for Thumb. An assembler wrapper switches the execution mode
and interfaces between Thumb and ARM modes.
BUG=chrome-os-partner:34161
BRANCH=Storm
TEST=manual
With the preceeding patches the system successfully loads to
depthcharge in recovery mode.
Change-Id: I812b5cef95ba5562a005e005162d6391e502ecf8
Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Commit-Id: 7065cf3d17964a1d9038ec8906b469a08a79c6e2
Original-Change-Id: Ib14dbcbcbe489b595f4247d489d50f76a0e65948
Original-Signed-off-by: Varadarajan Narayanan <varada@qti.qualcomm.com>
Original-Signed-off-by: Vadim Bendebury <vbendeb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/229026
Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/9690
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Diffstat (limited to 'src/soc/qualcomm/ipq806x')
-rw-r--r-- | src/soc/qualcomm/ipq806x/Makefile.inc | 2 | ||||
-rw-r--r-- | src/soc/qualcomm/ipq806x/blobs_init.c | 55 | ||||
-rw-r--r-- | src/soc/qualcomm/ipq806x/include/soc/memlayout.ld | 4 | ||||
-rw-r--r-- | src/soc/qualcomm/ipq806x/include/soc/soc_services.h | 5 | ||||
-rw-r--r-- | src/soc/qualcomm/ipq806x/tz_wrapper.S | 106 |
5 files changed, 153 insertions, 19 deletions
diff --git a/src/soc/qualcomm/ipq806x/Makefile.inc b/src/soc/qualcomm/ipq806x/Makefile.inc index 7fb6290a42..e0f014af35 100644 --- a/src/soc/qualcomm/ipq806x/Makefile.inc +++ b/src/soc/qualcomm/ipq806x/Makefile.inc @@ -40,6 +40,7 @@ romstage-y += timer.c romstage-$(CONFIG_DRIVERS_UART) += uart.c romstage-y += cbmem.c +ramstage-y += blobs_init.c ramstage-y += cbmem.c ramstage-y += clock.c ramstage-y += gpio.c @@ -48,6 +49,7 @@ ramstage-$(CONFIG_SPI_FLASH) += spi.c ramstage-y += timer.c ramstage-$(CONFIG_DRIVERS_UART) += uart.c ramstage-y += usb.c +ramstage-y += tz_wrapper.S ifeq ($(CONFIG_USE_BLOBS),y) diff --git a/src/soc/qualcomm/ipq806x/blobs_init.c b/src/soc/qualcomm/ipq806x/blobs_init.c index 96a14dc40b..0f3a99a7cc 100644 --- a/src/soc/qualcomm/ipq806x/blobs_init.c +++ b/src/soc/qualcomm/ipq806x/blobs_init.c @@ -27,10 +27,11 @@ #include "mbn_header.h" -static struct mbn_header *map_ipq_blob(const char *file_name) +static void *load_ipq_blob(const char *file_name) { struct cbfs_file *blob_file; struct mbn_header *blob_mbn; + void *blob_dest; blob_file = cbfs_get_file(CBFS_DEFAULT_MEDIA, file_name); if (!blob_file) @@ -44,35 +45,55 @@ static struct mbn_header *map_ipq_blob(const char *file_name) (blob_mbn->mbn_total_size > ntohl(blob_file->len))) return NULL; - return blob_mbn; + blob_dest = (void *) blob_mbn->mbn_destination; + if (blob_mbn->mbn_destination) { + /* Copy the blob to the appropriate memory location. */ + memcpy(blob_dest, blob_mbn + 1, blob_mbn->mbn_total_size); + cache_sync_instructions(); + return blob_dest; + } + + /* + * The blob did not have to be relocated, return its address in CBFS + * cache. + */ + return blob_mbn + 1; } +#ifdef __PRE_RAM__ + int initialize_dram(void) { - struct mbn_header *cdt_mbn; - struct mbn_header *ddr_mbn; + void *cdt; int (*ddr_init_function)(void *cdt_header); - cdt_mbn = map_ipq_blob("cdt.mbn"); - ddr_mbn = map_ipq_blob("ddr.mbn"); + cdt = load_ipq_blob("cdt.mbn"); + ddr_init_function = load_ipq_blob("ddr.mbn"); - if (!cdt_mbn || !ddr_mbn) { - printk(BIOS_ERR, "cdt.mbn: %p, ddr.mbn: %p\n", - cdt_mbn, ddr_mbn); + if (!cdt || !ddr_init_function) { + printk(BIOS_ERR, "cdt: %p, ddr_init_function: %p\n", + cdt, ddr_init_function); die("could not find DDR initialization blobs\n"); } - /* Actual area where DDR init is going to be running */ - ddr_init_function = (int (*)(void *))ddr_mbn->mbn_destination; - - /* Copy core into the appropriate memory location. */ - memcpy(ddr_init_function, ddr_mbn + 1, ddr_mbn->mbn_total_size); - cache_sync_instructions(); - - if (ddr_init_function(cdt_mbn + 1) < 0) /* Skip mbn header. */ + if (ddr_init_function(cdt) < 0) die("Fail to Initialize DDR\n"); printk(BIOS_INFO, "DDR initialized\n"); return 0; } + +#else /* __PRE_RAM__ */ + +void start_tzbsp(void) +{ + void *tzbsp = load_ipq_blob("tz.mbn"); + + if (!tzbsp) + die("could not find or map TZBSP\n"); + + tz_init_wrapper(0, 0, tzbsp); +} + +#endif /* !__PRE_RAM__ */ diff --git a/src/soc/qualcomm/ipq806x/include/soc/memlayout.ld b/src/soc/qualcomm/ipq806x/include/soc/memlayout.ld index 873f61cb1e..6a0d6ad815 100644 --- a/src/soc/qualcomm/ipq806x/include/soc/memlayout.ld +++ b/src/soc/qualcomm/ipq806x/include/soc/memlayout.ld @@ -54,9 +54,9 @@ SECTIONS DRAM_START(0x40000000) RAMSTAGE(0x40640000, 128K) - SYMBOL(memlayout_cbmem_top, 0x59FA0000) + SYMBOL(memlayout_cbmem_top, 0x59F80000) #ifndef __PRE_RAM__ - CBFS_CACHE(0x59FA0000, 256K) + CBFS_CACHE(0x59F80000, 384K) #endif DMA_COHERENT(0x5A000000, 2M) } diff --git a/src/soc/qualcomm/ipq806x/include/soc/soc_services.h b/src/soc/qualcomm/ipq806x/include/soc/soc_services.h index 9e92bc71e3..b852d7f37e 100644 --- a/src/soc/qualcomm/ipq806x/include/soc/soc_services.h +++ b/src/soc/qualcomm/ipq806x/include/soc/soc_services.h @@ -27,4 +27,9 @@ extern u8 _memlayout_cbmem_top[]; /* Returns zero on success, nonzero on failure. */ int initialize_dram(void); +/* Loads and runs TZBSP, switches into user mode. */ +void start_tzbsp(void); + +int tz_init_wrapper(int, int, void *); + #endif diff --git a/src/soc/qualcomm/ipq806x/tz_wrapper.S b/src/soc/qualcomm/ipq806x/tz_wrapper.S new file mode 100644 index 0000000000..70cc170f64 --- /dev/null +++ b/src/soc/qualcomm/ipq806x/tz_wrapper.S @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +/* + * TZ expects the ARM core to be in 'ARM' mode. However, coreboot seems + * to be compiled in mixed thumb/arm mode. Hence create a glue function + * to invoke TZ. + */ + +#include <arch/asm.h> + +/* + * Force ARM mode. Else this gets assembled with mixed ARM and + * Thumb instructions. We set up everything and jump to TZBSP + * using the 'blx' instruction. For 'blx' if the last bit of the + * destination address is zero, it switches to ARM mode. Since, + * we are already in ARM mode, nothing to switch as such. + * + * However, when TZBSP returns, the CPU is still in ARM mode. + * If the assembler inserts Thumb instructions between the point + * of return from TZBSP to the 'bx' instruction we are hosed. + * Hence forcing ARM mode. + * + * Rest of the code can be compiled in mixed ARM/Thumb mode. + * Since tz_init_wrapper is being forced as an ARM symbol, + * callers will use 'blx' to come here forcing a switch to + * ARM mode. The wrapper does its job and returns back to the + * Thumb caller. + */ +.arm +/* + * int tz_init_wrapper(int, int, void *); + */ +ENTRY(tz_init_wrapper) + .global tz_init_wrapper + + /* + * r0 = tz_arg1 + * r1 = tz_arg2 + * r2 = tz_load_addr + */ + + /* + * Per the AAPCS + * r0, r1, r2, r3, r12 can be clobbered + * r4, r5, r6, r7, r8, r9, r10, r11 have to be preserved + * + * Following code clobbers + * r0 - Setting return value to zero + * r1 - For doing a thumb return + * r3 - Passing 'SP' from current mode to 'svc' mode + * r4 - To save & restore CPSR + * + * Per AAPCS, save and restore r4, rest are 'clobberable' :) + * The invoked code takes care of saving and restoring the other + * preserved registers (i.e. r5 - r11) + * + * Stack Usage: + * SP -> | LR | (Lower address) + * | r4 | + * | CPSR | + * |-------| + * | . | + * | . | + * | . | (Higher address) + */ + + sub sp, sp, #12 /* Allocate stack frame */ + str lr, [sp] /* Save return address */ + str r4, [sp, #4] /* Use r4 to hold the new CPSR value */ + + mov r3, sp /* Get current stack pointer */ + + mrs r4, CPSR /* save CPSR */ + str r4, [sp, #8] + + bic r4, r4, 0x1f /* Clear mode bits */ + orr r4, r4, 0x13 /* 'svc' mode */ + msr cpsr_cxf, r4 /* Switch to Supervisor mode. */ + mov sp, r3 /* Use the same stack as the previous mode */ + + blx r2 /* Jump to TZ in ARM mode */ + + nop /* back from TZ, in ARM mode */ + + ldr r4, [sp, #8] /* restore CPSR */ + msr cpsr_cxf, r4 + + ldr r4, [sp, #4] /* restore r4 */ + + ldr lr, [sp] /* saved return address */ + add sp, sp, #12 /* free stack frame */ + + bx lr /* back to thumb caller */ + +ENDPROC(tz_init_wrapper) |