summaryrefslogtreecommitdiff
path: root/src/soc
diff options
context:
space:
mode:
Diffstat (limited to 'src/soc')
-rw-r--r--src/soc/qualcomm/ipq806x/Makefile.inc2
-rw-r--r--src/soc/qualcomm/ipq806x/blobs_init.c55
-rw-r--r--src/soc/qualcomm/ipq806x/include/soc/memlayout.ld4
-rw-r--r--src/soc/qualcomm/ipq806x/include/soc/soc_services.h5
-rw-r--r--src/soc/qualcomm/ipq806x/tz_wrapper.S106
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)