163 lines
4.4 KiB
C
163 lines
4.4 KiB
C
/* Copyright(c) 2021 Intel Corporation. All rights reserved.
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
|
|
#include <zephyr/devicetree.h>
|
|
#include <zephyr/kernel.h>
|
|
#include <zephyr/init.h>
|
|
#include <soc_util.h>
|
|
#include <zephyr/cache.h>
|
|
#include <adsp_shim.h>
|
|
#include <adsp_memory.h>
|
|
#include <cpu_init.h>
|
|
#include "manifest.h"
|
|
|
|
/* Important note about linkage:
|
|
*
|
|
* The C code here, starting from boot_core0(), is running entirely in
|
|
* IMR memory. The sram banks are not initialized yet and the Zephyr
|
|
* code is not yet copied there. No use of this memory is legal until
|
|
* after parse_manifest() returns. This means that all symbols in
|
|
* this file must be flagged "__imr" or "__imrdata" (or be guaranteed
|
|
* to inline via ALWAYS_INLINE, normal gcc "inline" is only a hint)!
|
|
*
|
|
* There's a similar note with Xtensa register windows: the Zephyr
|
|
* exception handles for window overflow are not present in IMR.
|
|
* While on existing systems, we start running with a VECBASE pointing
|
|
* to ROM handlers (that seem to work), it seems unsafe to rely on
|
|
* that. It's not possible to hit an overflow until at least four
|
|
* nested function calls, so this is mostly theoretical. Nonetheless
|
|
* care should be taken here to make sure the function tree remains
|
|
* shallow until SRAM initialization is finished.
|
|
*/
|
|
|
|
/* Various cAVS platform dependencies needed by the bootloader code.
|
|
* These probably want to migrate to devicetree.
|
|
*/
|
|
|
|
|
|
#define HOST_PAGE_SIZE 4096
|
|
#define MANIFEST_SEGMENT_COUNT 3
|
|
|
|
/* FIXME: Use Kconfig or some other means */
|
|
#if !defined(CONFIG_SOC_SERIES_INTEL_ACE)
|
|
#define RESET_MEMORY_HOLE
|
|
#endif
|
|
|
|
/* Initial/true entry point. Does nothing but jump to
|
|
* z_boot_asm_entry (which cannot be here, because it needs to be able
|
|
* to reference immediates which must link before it)
|
|
*/
|
|
__asm__(".pushsection .boot_entry.text, \"ax\" \n\t"
|
|
".global rom_entry \n\t"
|
|
"rom_entry: \n\t"
|
|
" j z_boot_asm_entry \n\t"
|
|
".popsection \n\t");
|
|
|
|
/* Entry stub. Sets up register windows and stack such that we can
|
|
* enter C code successfully, and calls boot_core0()
|
|
*/
|
|
#define STRINGIFY_MACRO(x) Z_STRINGIFY(x)
|
|
#define IMRSTACK STRINGIFY_MACRO(IMR_BOOT_LDR_MANIFEST_BASE)
|
|
__asm__(".section .imr.z_boot_asm_entry, \"x\" \n\t"
|
|
".align 4 \n\t"
|
|
"z_boot_asm_entry: \n\t"
|
|
" movi a0, 0x4002f \n\t"
|
|
" wsr a0, PS \n\t"
|
|
" movi a0, 0 \n\t"
|
|
" wsr a0, WINDOWBASE \n\t"
|
|
" movi a0, 1 \n\t"
|
|
" wsr a0, WINDOWSTART \n\t"
|
|
" rsync \n\t"
|
|
" movi a1, " IMRSTACK "\n\t"
|
|
" call4 boot_core0 \n\t");
|
|
|
|
static __imr void parse_module(struct sof_man_fw_header *hdr,
|
|
struct sof_man_module *mod)
|
|
{
|
|
int i;
|
|
uint32_t bias;
|
|
|
|
/* each module has 3 segments */
|
|
for (i = 0; i < MANIFEST_SEGMENT_COUNT; i++) {
|
|
|
|
switch (mod->segment[i].flags.r.type) {
|
|
case SOF_MAN_SEGMENT_TEXT:
|
|
case SOF_MAN_SEGMENT_DATA:
|
|
if (mod->segment[i].flags.r.load == 0) {
|
|
continue;
|
|
}
|
|
|
|
bias = mod->segment[i].file_offset -
|
|
SOF_MAN_ELF_TEXT_OFFSET;
|
|
|
|
/* copy from IMR to SRAM */
|
|
bmemcpy((void *)mod->segment[i].v_base_addr,
|
|
(uint8_t *)hdr + bias,
|
|
mod->segment[i].flags.r.length *
|
|
HOST_PAGE_SIZE);
|
|
break;
|
|
case SOF_MAN_SEGMENT_BSS:
|
|
/* already bbzero'd by sram init */
|
|
break;
|
|
default:
|
|
/* ignore */
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
#define MAN_SKIP_ENTRIES 1
|
|
|
|
/* parse FW manifest and copy modules */
|
|
__imr void parse_manifest(void)
|
|
{
|
|
struct sof_man_fw_desc *desc =
|
|
(struct sof_man_fw_desc *)IMR_BOOT_LDR_MANIFEST_BASE;
|
|
struct sof_man_fw_header *hdr = &desc->header;
|
|
struct sof_man_module *mod;
|
|
int i;
|
|
|
|
sys_cache_data_invd_range(hdr, sizeof(*hdr));
|
|
|
|
/* copy module to SRAM - skip bootloader module */
|
|
for (i = MAN_SKIP_ENTRIES; i < hdr->num_module_entries; i++) {
|
|
mod = desc->man_module + i;
|
|
|
|
sys_cache_data_invd_range(mod, sizeof(*mod));
|
|
parse_module(hdr, mod);
|
|
}
|
|
}
|
|
|
|
extern void hp_sram_init(uint32_t memory_size);
|
|
extern void lp_sram_init(void);
|
|
|
|
__imr void boot_core0(void)
|
|
{
|
|
cpu_early_init();
|
|
|
|
#ifdef CONFIG_ADSP_DISABLE_L2CACHE_AT_BOOT
|
|
ADSP_L2PCFG_REG = 0;
|
|
#endif
|
|
|
|
#ifdef RESET_MEMORY_HOLE
|
|
/* reset memory hole */
|
|
CAVS_SHIM.l2mecs = 0;
|
|
#endif
|
|
|
|
hp_sram_init(L2_SRAM_SIZE);
|
|
lp_sram_init();
|
|
parse_manifest();
|
|
sys_cache_data_flush_all();
|
|
|
|
xtensa_vecbase_lock();
|
|
|
|
/* Zephyr! */
|
|
extern FUNC_NORETURN void z_cstart(void);
|
|
z_cstart();
|
|
}
|