| /* SPDX-License-Identifier: GPL-2.0-only */ |
| |
| #include <arch/cache.h> |
| #include <device/mmio.h> |
| #include <cbfs.h> |
| #include <console/console.h> |
| #include <string.h> |
| #include <timer.h> |
| |
| #include <soc/iomap.h> |
| #include <soc/soc_services.h> |
| |
| #include "mbn_header.h" |
| |
| static void *load_ipq_blob(const char *file_name) |
| { |
| struct mbn_header *blob_mbn; |
| void *blob_dest; |
| size_t blob_size; |
| |
| blob_mbn = cbfs_map(file_name, &blob_size); |
| if (!blob_mbn) |
| return NULL; |
| |
| /* some sanity checks on the headers */ |
| if ((blob_mbn->mbn_version != 3) || |
| (blob_mbn->mbn_total_size > blob_size)) |
| return NULL; |
| |
| 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; |
| } |
| |
| #define DDR_VERSION() ((const char *)0x2a03f600) |
| #define MAX_DDR_VERSION_SIZE 48 |
| |
| int initialize_dram(void) |
| { |
| void *cdt; |
| int (*ddr_init_function)(void *cdt_header); |
| |
| cdt = load_ipq_blob("cdt.mbn"); |
| ddr_init_function = load_ipq_blob("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"); |
| } |
| |
| if (ddr_init_function(cdt) < 0) |
| die("Fail to Initialize DDR\n"); |
| |
| /* |
| * Once DDR initializer finished, its version can be found at a fixed |
| * address in SRAM. |
| */ |
| printk(BIOS_INFO, "DDR version %.*s initialized\n", |
| MAX_DDR_VERSION_SIZE, DDR_VERSION()); |
| |
| return 0; |
| } |
| |
| void start_tzbsp(void) |
| { |
| void *tzbsp = load_ipq_blob("tz.mbn"); |
| |
| if (!tzbsp) |
| die("could not find or map TZBSP\n"); |
| |
| printk(BIOS_INFO, "Starting TZBSP\n"); |
| |
| tz_init_wrapper(0, 0, tzbsp); |
| } |
| |
| /* RPM version is encoded in a 32 bit word at the fixed address */ |
| #define RPM_VERSION() (*((u32 *)(0x00108008))) |
| void start_rpm(void) |
| { |
| u32 load_addr; |
| u32 ready_mask = 1 << 10; |
| u32 rpm_version; |
| |
| struct stopwatch sw; |
| |
| if (read32(RPM_SIGNAL_COOKIE) == RPM_FW_MAGIC_NUM) { |
| printk(BIOS_INFO, "RPM appears to have already started\n"); |
| return; |
| } |
| |
| load_addr = (u32)load_ipq_blob("rpm.mbn"); |
| if (!load_addr) |
| die("could not find or map RPM code\n"); |
| |
| printk(BIOS_INFO, "Starting RPM\n"); |
| |
| /* Clear 'ready' indication. */ |
| /* |
| * RPM_INT_ACK is clear-on-write type register, |
| * read-modify-write is not recommended. |
| */ |
| write32(RPM_INT_ACK, ready_mask); |
| |
| /* Set RPM entry address */ |
| write32(RPM_SIGNAL_ENTRY, load_addr); |
| /* Set cookie */ |
| write32(RPM_SIGNAL_COOKIE, RPM_FW_MAGIC_NUM); |
| |
| /* Wait for RPM start indication, up to 100ms. */ |
| stopwatch_init_usecs_expire(&sw, 100000); |
| while (!(read32(RPM_INT) & ready_mask)) |
| if (stopwatch_expired(&sw)) |
| die("RPM Initialization failed\n"); |
| |
| /* Acknowledge RPM initialization */ |
| write32(RPM_INT_ACK, ready_mask); |
| |
| /* Report RPM version, it is encoded in a 32 bit value. */ |
| rpm_version = RPM_VERSION(); |
| printk(BIOS_INFO, "Started RPM version %d.%d.%d\n", |
| rpm_version >> 24, |
| (rpm_version >> 16) & 0xff, |
| rpm_version & 0xffff); |
| } |