GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)

This commit is contained in:
lai
2026-09-06 03:52:57 +08:00
commit b1928b41c0
21813 changed files with 4413081 additions and 0 deletions
@@ -0,0 +1,168 @@
/*
* Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <platform_def.h>
#include <common/bl_common.h>
#include <common/desc_image_load.h>
#include <marvell_def.h>
#include <plat/common/platform.h>
/*******************************************************************************
* Following descriptor provides BL image/ep information that gets used
* by BL2 to load the images and also subset of this information is
* passed to next BL image. The image loading sequence is managed by
* populating the images in required loading order. The image execution
* sequence is managed by populating the `next_handoff_image_id` with
* the next executable image id.
******************************************************************************/
static bl_mem_params_node_t bl2_mem_params_descs[] = {
#ifdef SCP_BL2_BASE
/* Fill SCP_BL2 related information if it exists */
{
.image_id = SCP_BL2_IMAGE_ID,
SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY,
VERSION_2, entry_point_info_t, SECURE | NON_EXECUTABLE),
SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY,
VERSION_2, image_info_t, 0),
.image_info.image_base = SCP_BL2_BASE,
.image_info.image_max_size = SCP_BL2_SIZE,
.next_handoff_image_id = INVALID_IMAGE_ID,
},
#endif /* SCP_BL2_BASE */
#ifdef EL3_PAYLOAD_BASE
/* Fill EL3 payload related information (BL31 is EL3 payload)*/
{
.image_id = BL31_IMAGE_ID,
SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
VERSION_2, entry_point_info_t,
SECURE | EXECUTABLE | EP_FIRST_EXE),
.ep_info.pc = EL3_PAYLOAD_BASE,
.ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX,
DISABLE_ALL_EXCEPTIONS),
SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
VERSION_2, image_info_t,
IMAGE_ATTRIB_PLAT_SETUP | IMAGE_ATTRIB_SKIP_LOADING),
.next_handoff_image_id = INVALID_IMAGE_ID,
},
#else /* EL3_PAYLOAD_BASE */
/* Fill BL31 related information */
{
.image_id = BL31_IMAGE_ID,
SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
VERSION_2, entry_point_info_t,
SECURE | EXECUTABLE | EP_FIRST_EXE),
.ep_info.pc = BL31_BASE,
.ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX,
DISABLE_ALL_EXCEPTIONS),
#if DEBUG
.ep_info.args.arg3 = MARVELL_BL31_PLAT_PARAM_VAL,
#endif
SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
VERSION_2, image_info_t, IMAGE_ATTRIB_PLAT_SETUP),
.image_info.image_base = BL31_BASE,
.image_info.image_max_size = BL31_LIMIT - BL31_BASE,
# ifdef BL32_BASE
.next_handoff_image_id = BL32_IMAGE_ID,
# else
.next_handoff_image_id = BL33_IMAGE_ID,
# endif
},
# ifdef BL32_BASE
/* Fill BL32 related information */
{
.image_id = BL32_IMAGE_ID,
SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
VERSION_2, entry_point_info_t, SECURE | EXECUTABLE),
.ep_info.pc = BL32_BASE,
SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
VERSION_2, image_info_t, 0),
.image_info.image_base = BL32_BASE,
.image_info.image_max_size = BL32_LIMIT - BL32_BASE,
.next_handoff_image_id = BL33_IMAGE_ID,
},
/*
* Fill BL32 external 1 related information.
* A typical use for extra1 image is with OP-TEE
* where it is the pager image.
*/
{
.image_id = BL32_EXTRA1_IMAGE_ID,
SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
VERSION_2, entry_point_info_t, SECURE | NON_EXECUTABLE),
SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING),
.image_info.image_base = BL32_BASE,
.image_info.image_max_size = BL32_LIMIT - BL32_BASE,
.next_handoff_image_id = INVALID_IMAGE_ID,
},
/*
* Fill BL32 external 2 related information.
* A typical use for extra2 image is with OP-TEE,
* where it is the paged image.
*/
{
.image_id = BL32_EXTRA2_IMAGE_ID,
SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
VERSION_2, entry_point_info_t, SECURE | NON_EXECUTABLE),
SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING),
#ifdef SPD_opteed
.image_info.image_base = MARVELL_OPTEE_PAGEABLE_LOAD_BASE,
.image_info.image_max_size = MARVELL_OPTEE_PAGEABLE_LOAD_SIZE,
#endif
.next_handoff_image_id = INVALID_IMAGE_ID,
},
# endif /* BL32_BASE */
/* Fill BL33 related information */
{
.image_id = BL33_IMAGE_ID,
SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
VERSION_2, entry_point_info_t, NON_SECURE | EXECUTABLE),
# ifdef PRELOADED_BL33_BASE
.ep_info.pc = PRELOADED_BL33_BASE,
SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING),
# else
.ep_info.pc = MARVELL_DRAM_BASE,
SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
VERSION_2, image_info_t, 0),
.image_info.image_base = MARVELL_DRAM_BASE,
.image_info.image_max_size = MARVELL_DRAM_SIZE,
# endif /* PRELOADED_BL33_BASE */
.next_handoff_image_id = INVALID_IMAGE_ID,
}
#endif /* EL3_PAYLOAD_BASE */
};
REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs)
@@ -0,0 +1,137 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <assert.h>
#include <platform_def.h>
#include <arch.h>
#include <arch_helpers.h>
#include <common/debug.h>
#include <lib/mmio.h>
#include <lib/xlat_tables/xlat_tables_v2.h>
#include <plat_marvell.h>
/* Weak definitions may be overridden in specific ARM standard platform */
#pragma weak plat_get_ns_image_entrypoint
#pragma weak plat_marvell_get_mmap
/*
* Set up the page tables for the generic and platform-specific memory regions.
* The extents of the generic memory regions are specified by the function
* arguments and consist of:
* - Trusted SRAM seen by the BL image;
* - Code section;
* - Read-only data section;
* - Coherent memory region, if applicable.
*/
void marvell_setup_page_tables(uintptr_t total_base,
size_t total_size,
uintptr_t code_start,
uintptr_t code_limit,
uintptr_t rodata_start,
uintptr_t rodata_limit
#if USE_COHERENT_MEM
,
uintptr_t coh_start,
uintptr_t coh_limit
#endif
)
{
/*
* Map the Trusted SRAM with appropriate memory attributes.
* Subsequent mappings will adjust the attributes for specific regions.
*/
VERBOSE("Trusted SRAM seen by this BL image: %p - %p\n",
(void *) total_base, (void *) (total_base + total_size));
mmap_add_region(total_base, total_base,
total_size,
MT_MEMORY | MT_RW | MT_SECURE);
/* Re-map the code section */
VERBOSE("Code region: %p - %p\n",
(void *) code_start, (void *) code_limit);
mmap_add_region(code_start, code_start,
code_limit - code_start,
MT_CODE | MT_SECURE);
/* Re-map the read-only data section */
VERBOSE("Read-only data region: %p - %p\n",
(void *) rodata_start, (void *) rodata_limit);
mmap_add_region(rodata_start, rodata_start,
rodata_limit - rodata_start,
MT_RO_DATA | MT_SECURE);
#if USE_COHERENT_MEM
/* Re-map the coherent memory region */
VERBOSE("Coherent region: %p - %p\n",
(void *) coh_start, (void *) coh_limit);
mmap_add_region(coh_start, coh_start,
coh_limit - coh_start,
MT_DEVICE | MT_RW | MT_SECURE);
#endif
/* Now (re-)map the platform-specific memory regions */
mmap_add(plat_marvell_get_mmap());
/* Create the page tables to reflect the above mappings */
init_xlat_tables();
}
unsigned long plat_get_ns_image_entrypoint(void)
{
return PLAT_MARVELL_NS_IMAGE_OFFSET;
}
/*****************************************************************************
* Gets SPSR for BL32 entry
*****************************************************************************
*/
uint32_t marvell_get_spsr_for_bl32_entry(void)
{
/*
* The Secure Payload Dispatcher service is responsible for
* setting the SPSR prior to entry into the BL32 image.
*/
return 0;
}
/*****************************************************************************
* Gets SPSR for BL33 entry
*****************************************************************************
*/
uint32_t marvell_get_spsr_for_bl33_entry(void)
{
unsigned long el_status;
unsigned int mode;
uint32_t spsr;
/* Figure out what mode we enter the non-secure world in */
el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT;
el_status &= ID_AA64PFR0_ELX_MASK;
mode = (el_status) ? MODE_EL2 : MODE_EL1;
/*
* TODO: Consider the possibility of specifying the SPSR in
* the FIP ToC and allowing the platform to have a say as
* well.
*/
spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
return spsr;
}
/*****************************************************************************
* Returns ARM platform specific memory map regions.
*****************************************************************************
*/
const mmap_region_t *plat_marvell_get_mmap(void)
{
return plat_marvell_mmap;
}
@@ -0,0 +1,259 @@
/*
* Copyright (c) 2020, ARM Limited. All rights reserved.
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <asm_macros.S>
#include <cortex_a72.h>
#ifndef PLAT_a3700
#include <drivers/marvell/ccu.h>
#include <drivers/marvell/cache_llc.h>
#endif
#include <marvell_def.h>
#include <platform_def.h>
.weak plat_marvell_calc_core_pos
.weak plat_my_core_pos
.globl plat_crash_console_init
.globl plat_crash_console_putc
.globl plat_crash_console_flush
.globl platform_mem_init
.globl disable_mmu_dcache
.globl invalidate_tlb_all
.globl platform_unmap_sram
.globl disable_sram
.globl disable_icache
.globl invalidate_icache_all
.globl marvell_exit_bootrom
.globl ca72_l2_enable_unique_clean
/* -----------------------------------------------------
* unsigned int plat_my_core_pos(void)
* This function uses the plat_marvell_calc_core_pos()
* definition to get the index of the calling CPU.
* -----------------------------------------------------
*/
func plat_my_core_pos
mrs x0, mpidr_el1
b plat_marvell_calc_core_pos
endfunc plat_my_core_pos
/* -----------------------------------------------------
* unsigned int plat_marvell_calc_core_pos(uint64_t mpidr)
* Helper function to calculate the core position.
* With this function: CorePos = (ClusterId * 2) +
* CoreId
* -----------------------------------------------------
*/
func plat_marvell_calc_core_pos
and x1, x0, #MPIDR_CPU_MASK
and x0, x0, #MPIDR_CLUSTER_MASK
add x0, x1, x0, LSR #7
ret
endfunc plat_marvell_calc_core_pos
/* ---------------------------------------------
* int plat_crash_console_init(void)
* Function to initialize the crash console
* without a C Runtime to print crash report.
* Clobber list : x0, x1, x2
* ---------------------------------------------
*/
func plat_crash_console_init
#ifdef PLAT_a3700
mov x1, x30
bl get_ref_clk
mov x30, x1
mov_imm x1, 1000000
mul x1, x0, x1
#else
mov_imm x1, PLAT_MARVELL_UART_CLK_IN_HZ
#endif
mov_imm x0, PLAT_MARVELL_UART_BASE
mov_imm x2, MARVELL_CONSOLE_BAUDRATE
#ifdef PLAT_a3700
b console_a3700_core_init
#else
b console_16550_core_init
#endif
endfunc plat_crash_console_init
/* ---------------------------------------------
* int plat_crash_console_putc(int c)
* Function to print a character on the crash
* console without a C Runtime.
* Clobber list : x1, x2
* ---------------------------------------------
*/
func plat_crash_console_putc
mov_imm x1, PLAT_MARVELL_UART_BASE
#ifdef PLAT_a3700
b console_a3700_core_putc
#else
b console_16550_core_putc
#endif
endfunc plat_crash_console_putc
/* ---------------------------------------------
* void plat_crash_console_flush()
* Function to force a write of all buffered
* data that hasn't been output.
* Out : void.
* Clobber list : r0
* ---------------------------------------------
*/
func plat_crash_console_flush
mov_imm x0, PLAT_MARVELL_UART_BASE
#ifdef PLAT_a3700
b console_a3700_core_flush
#else
b console_16550_core_flush
#endif
endfunc plat_crash_console_flush
/* ---------------------------------------------------------------------
* We don't need to carry out any memory initialization on ARM
* platforms. The Secure RAM is accessible straight away.
* ---------------------------------------------------------------------
*/
func platform_mem_init
ret
endfunc platform_mem_init
/* -----------------------------------------------------
* Disable icache, dcache, and MMU
* -----------------------------------------------------
*/
func disable_mmu_dcache
mrs x0, sctlr_el3
bic x0, x0, 0x1 /* M bit - MMU */
bic x0, x0, 0x4 /* C bit - Dcache L1 & L2 */
msr sctlr_el3, x0
isb
b mmu_off
mmu_off:
ret
endfunc disable_mmu_dcache
/* -----------------------------------------------------
* Disable all TLB entries
* -----------------------------------------------------
*/
func invalidate_tlb_all
tlbi alle3
dsb sy
isb
ret
endfunc invalidate_tlb_all
/* -----------------------------------------------------
* Disable the i cache
* -----------------------------------------------------
*/
func disable_icache
mrs x0, sctlr_el3
bic x0, x0, 0x1000 /* I bit - Icache L1 & L2 */
msr sctlr_el3, x0
isb
ret
endfunc disable_icache
/* -----------------------------------------------------
* Disable all of the i caches
* -----------------------------------------------------
*/
func invalidate_icache_all
ic ialluis
isb sy
ret
endfunc invalidate_icache_all
/* -----------------------------------------------------
* Clear the SRAM enabling bit to unmap SRAM
* -----------------------------------------------------
*/
func platform_unmap_sram
ldr x0, =CCU_SRAM_WIN_CR
str wzr, [x0]
ret
endfunc platform_unmap_sram
/* -----------------------------------------------------
* Disable the SRAM
* -----------------------------------------------------
*/
func disable_sram
/* Disable the line lockings. They must be disabled expictly
* or the OS will have problems using the cache */
ldr x1, =MASTER_LLC_TC0_LOCK
str wzr, [x1]
/* Invalidate all ways */
ldr w1, =LLC_WAY_MASK
ldr x0, =MASTER_LLC_INV_WAY
str w1, [x0]
/* Finally disable LLC */
ldr x0, =MASTER_LLC_CTRL
str wzr, [x0]
ret
endfunc disable_sram
/* -----------------------------------------------------
* Operation when exit bootROM:
* Disable the MMU
* Disable and invalidate the dcache
* Unmap and disable the SRAM
* Disable and invalidate the icache
* -----------------------------------------------------
*/
func marvell_exit_bootrom
/* Save the system restore address */
mov x28, x0
/* Close the caches and MMU */
bl disable_mmu_dcache
/*
* There is nothing important in the caches now,
* so invalidate them instead of cleaning.
*/
adr x0, __RW_START__
adr x1, __RW_END__
sub x1, x1, x0
bl inv_dcache_range
bl invalidate_tlb_all
/*
* Clean the memory mapping of SRAM
* the DDR mapping will remain to enable boot image to execute
*/
bl platform_unmap_sram
/* Disable the SRAM */
bl disable_sram
/* Disable and invalidate icache */
bl disable_icache
bl invalidate_icache_all
mov x0, x28
br x0
endfunc marvell_exit_bootrom
/*
* Enable L2 UniqueClean evictions with data
*/
func ca72_l2_enable_unique_clean
mrs x0, CORTEX_A72_L2ACTLR_EL1
orr x0, x0, #CORTEX_A72_L2ACTLR_ENABLE_UNIQUE_CLEAN
msr CORTEX_A72_L2ACTLR_EL1, x0
ret
endfunc ca72_l2_enable_unique_clean
@@ -0,0 +1,105 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <platform_def.h>
#include <bl1/bl1.h>
#include <common/bl_common.h>
#include <common/debug.h>
#include <drivers/arm/sp805.h>
#include <drivers/console.h>
#include <plat/common/platform.h>
#include <plat_marvell.h>
/* Weak definitions may be overridden in specific Marvell standard platform */
#pragma weak bl1_early_platform_setup
#pragma weak bl1_plat_arch_setup
#pragma weak bl1_platform_setup
#pragma weak bl1_plat_sec_mem_layout
/* Data structure which holds the extents of the RAM for BL1*/
static meminfo_t bl1_ram_layout;
meminfo_t *bl1_plat_sec_mem_layout(void)
{
return &bl1_ram_layout;
}
/*
* BL1 specific platform actions shared between Marvell standard platforms.
*/
void marvell_bl1_early_platform_setup(void)
{
/* Initialize the console to provide early debug support */
marvell_console_boot_init();
/* Allow BL1 to see the whole Trusted RAM */
bl1_ram_layout.total_base = MARVELL_BL_RAM_BASE;
bl1_ram_layout.total_size = MARVELL_BL_RAM_SIZE;
}
void bl1_early_platform_setup(void)
{
marvell_bl1_early_platform_setup();
}
/*
* Perform the very early platform specific architecture setup shared between
* MARVELL standard platforms. This only does basic initialization. Later
* architectural setup (bl1_arch_setup()) does not do anything platform
* specific.
*/
void marvell_bl1_plat_arch_setup(void)
{
marvell_setup_page_tables(bl1_ram_layout.total_base,
bl1_ram_layout.total_size,
BL1_RO_BASE,
BL1_RO_LIMIT,
BL1_RO_DATA_BASE,
BL1_RO_DATA_END
#if USE_COHERENT_MEM
, BL_COHERENT_RAM_BASE,
BL_COHERENT_RAM_END
#endif
);
enable_mmu_el3(0);
}
void bl1_plat_arch_setup(void)
{
marvell_bl1_plat_arch_setup();
}
/*
* Perform the platform specific architecture setup shared between
* MARVELL standard platforms.
*/
void marvell_bl1_platform_setup(void)
{
/* Initialise the IO layer and register platform IO devices */
plat_marvell_io_setup();
}
void bl1_platform_setup(void)
{
marvell_bl1_platform_setup();
}
void bl1_plat_prepare_exit(entry_point_info_t *ep_info)
{
#ifdef EL3_PAYLOAD_BASE
/*
* Program the EL3 payload's entry point address into the CPUs mailbox
* in order to release secondary CPUs from their holding pen and make
* them jump there.
*/
marvell_program_trusted_mailbox(ep_info->pc);
dsbsy();
sev();
#endif
}
@@ -0,0 +1,158 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <assert.h>
#include <string.h>
#include <platform_def.h>
#include <arch_helpers.h>
#include <common/bl_common.h>
#include <common/debug.h>
#include <common/desc_image_load.h>
#include <drivers/console.h>
#include <lib/utils.h>
#ifdef SPD_opteed
#include <optee_utils.h>
#endif
#include <marvell_def.h>
#include <plat_marvell.h>
/* Data structure which holds the extents of the trusted SRAM for BL2 */
static meminfo_t bl2_tzram_layout __aligned(CACHE_WRITEBACK_GRANULE);
/* Weak definitions may be overridden in specific MARVELL standard platform */
#pragma weak bl2_early_platform_setup2
#pragma weak bl2_platform_setup
#pragma weak bl2_plat_arch_setup
#pragma weak bl2_plat_sec_mem_layout
meminfo_t *bl2_plat_sec_mem_layout(void)
{
return &bl2_tzram_layout;
}
/*****************************************************************************
* BL1 has passed the extents of the trusted SRAM that should be visible to BL2
* in x0. This memory layout is sitting at the base of the free trusted SRAM.
* Copy it to a safe location before its reclaimed by later BL2 functionality.
*****************************************************************************
*/
void marvell_bl2_early_platform_setup(meminfo_t *mem_layout)
{
/* Initialize the console to provide early debug support */
marvell_console_boot_init();
/* Setup the BL2 memory layout */
bl2_tzram_layout = *mem_layout;
/* Initialise the IO layer and register platform IO devices */
plat_marvell_io_setup();
}
void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1,
u_register_t arg2, u_register_t arg3)
{
struct meminfo *mem_layout = (struct meminfo *)arg1;
marvell_bl2_early_platform_setup(mem_layout);
}
void bl2_platform_setup(void)
{
/* Nothing to do */
}
/*****************************************************************************
* Perform the very early platform specific architectural setup here. At the
* moment this is only initializes the mmu in a quick and dirty way.
*****************************************************************************
*/
void marvell_bl2_plat_arch_setup(void)
{
marvell_setup_page_tables(bl2_tzram_layout.total_base,
bl2_tzram_layout.total_size,
BL_CODE_BASE,
BL_CODE_END,
BL_RO_DATA_BASE,
BL_RO_DATA_END
#if USE_COHERENT_MEM
, BL_COHERENT_RAM_BASE,
BL_COHERENT_RAM_END
#endif
);
enable_mmu_el1(0);
}
void bl2_plat_arch_setup(void)
{
marvell_bl2_plat_arch_setup();
}
int marvell_bl2_handle_post_image_load(unsigned int image_id)
{
int err = 0;
bl_mem_params_node_t *bl_mem_params = get_bl_mem_params_node(image_id);
#ifdef SPD_opteed
bl_mem_params_node_t *pager_mem_params = NULL;
bl_mem_params_node_t *paged_mem_params = NULL;
#endif /* SPD_opteed */
assert(bl_mem_params);
switch (image_id) {
case BL32_IMAGE_ID:
#ifdef SPD_opteed
pager_mem_params = get_bl_mem_params_node(BL32_EXTRA1_IMAGE_ID);
assert(pager_mem_params);
paged_mem_params = get_bl_mem_params_node(BL32_EXTRA2_IMAGE_ID);
assert(paged_mem_params);
err = parse_optee_header(&bl_mem_params->ep_info,
&pager_mem_params->image_info,
&paged_mem_params->image_info);
if (err != 0)
WARN("OPTEE header parse error.\n");
#endif /* SPD_opteed */
bl_mem_params->ep_info.spsr = marvell_get_spsr_for_bl32_entry();
break;
case BL33_IMAGE_ID:
/* BL33 expects to receive the primary CPU MPID (through r0) */
bl_mem_params->ep_info.args.arg0 = 0xffff & read_mpidr();
bl_mem_params->ep_info.spsr = marvell_get_spsr_for_bl33_entry();
break;
#ifdef SCP_BL2_BASE
case SCP_BL2_IMAGE_ID:
/* The subsequent handling of SCP_BL2 is platform specific */
err = bl2_plat_handle_scp_bl2(&bl_mem_params->image_info);
if (err) {
WARN("Failure in platform-specific handling of SCP_BL2 image.\n");
}
break;
#endif
default:
/* Do nothing in default case */
break;
}
return err;
}
/*******************************************************************************
* This function can be used by the platforms to update/use image
* information for given `image_id`.
******************************************************************************/
int bl2_plat_handle_post_image_load(unsigned int image_id)
{
return marvell_bl2_handle_post_image_load(image_id);
}
@@ -0,0 +1,237 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <assert.h>
#include <arch.h>
#include <common/bl_common.h>
#include <common/debug.h>
#ifdef USE_CCI
#include <drivers/arm/cci.h>
#endif
#include <drivers/console.h>
#include <plat/common/platform.h>
#include <marvell_def.h>
#include <marvell_plat_priv.h>
#include <plat_marvell.h>
/*
* Placeholder variables for copying the arguments that have been passed to
* BL31 from BL2.
*/
static entry_point_info_t bl32_image_ep_info;
static entry_point_info_t bl33_image_ep_info;
/* Weak definitions may be overridden in specific ARM standard platform */
#pragma weak bl31_early_platform_setup2
#pragma weak bl31_platform_setup
#pragma weak bl31_plat_arch_setup
#pragma weak bl31_plat_get_next_image_ep_info
#pragma weak plat_get_syscnt_freq2
/*****************************************************************************
* Return a pointer to the 'entry_point_info' structure of the next image for
* the security state specified. BL33 corresponds to the non-secure image type
* while BL32 corresponds to the secure image type. A NULL pointer is returned
* if the image does not exist.
*****************************************************************************
*/
entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
{
entry_point_info_t *next_image_info;
assert(sec_state_is_valid(type));
next_image_info = (type == NON_SECURE)
? &bl33_image_ep_info : &bl32_image_ep_info;
return next_image_info;
}
/*****************************************************************************
* Perform any BL31 early platform setup common to ARM standard platforms.
* Here is an opportunity to copy parameters passed by the calling EL (S-EL1
* in BL2 & EL3 in BL1) before they are lost (potentially). This needs to be
* done before the MMU is initialized so that the memory layout can be used
* while creating page tables. BL2 has flushed this information to memory, so
* we are guaranteed to pick up good data.
*****************************************************************************
*/
void marvell_bl31_early_platform_setup(void *from_bl2,
uintptr_t soc_fw_config,
uintptr_t hw_config,
void *plat_params_from_bl2)
{
/* Initialize the console to provide early debug support */
marvell_console_boot_init();
#if RESET_TO_BL31
/* There are no parameters from BL2 if BL31 is a reset vector */
assert(from_bl2 == NULL);
assert(plat_params_from_bl2 == NULL);
#ifdef BL32_BASE
/* Populate entry point information for BL32 */
SET_PARAM_HEAD(&bl32_image_ep_info,
PARAM_EP,
VERSION_1,
0);
SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE);
bl32_image_ep_info.pc = BL32_BASE;
bl32_image_ep_info.spsr = marvell_get_spsr_for_bl32_entry();
#endif /* BL32_BASE */
/* Populate entry point information for BL33 */
SET_PARAM_HEAD(&bl33_image_ep_info,
PARAM_EP,
VERSION_1,
0);
/*
* Tell BL31 where the non-trusted software image
* is located and the entry state information
*/
bl33_image_ep_info.pc = plat_get_ns_image_entrypoint();
bl33_image_ep_info.spsr = marvell_get_spsr_for_bl33_entry();
SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
#else
/*
* In debug builds, we pass a special value in 'plat_params_from_bl2'
* to verify platform parameters from BL2 to BL31.
* In release builds, it's not used.
*/
assert(((unsigned long long)plat_params_from_bl2) ==
MARVELL_BL31_PLAT_PARAM_VAL);
/*
* Check params passed from BL2 should not be NULL,
*/
bl_params_t *params_from_bl2 = (bl_params_t *)from_bl2;
assert(params_from_bl2 != NULL);
assert(params_from_bl2->h.type == PARAM_BL_PARAMS);
assert(params_from_bl2->h.version >= VERSION_2);
bl_params_node_t *bl_params = params_from_bl2->head;
/*
* Copy BL33 and BL32 (if present), entry point information.
* They are stored in Secure RAM, in BL2's address space.
*/
while (bl_params != NULL) {
if (bl_params->image_id == BL32_IMAGE_ID)
bl32_image_ep_info = *bl_params->ep_info;
if (bl_params->image_id == BL33_IMAGE_ID)
bl33_image_ep_info = *bl_params->ep_info;
bl_params = bl_params->next_params_info;
}
#endif
}
void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
u_register_t arg2, u_register_t arg3)
{
marvell_bl31_early_platform_setup((void *)arg0, arg1, arg2,
(void *)arg3);
#ifdef USE_CCI
/*
* Initialize CCI for this cluster during cold boot.
* No need for locks as no other CPU is active.
*/
plat_marvell_interconnect_init();
/*
* Enable CCI coherency for the primary CPU's cluster.
* Platform specific PSCI code will enable coherency for other
* clusters.
*/
plat_marvell_interconnect_enter_coherency();
#endif
}
/*****************************************************************************
* Perform any BL31 platform setup common to ARM standard platforms
*****************************************************************************
*/
void marvell_bl31_platform_setup(void)
{
/* Initialize the GIC driver, cpu and distributor interfaces */
plat_marvell_gic_driver_init();
plat_marvell_gic_init();
/* For Armada-8k-plus family, the SoC includes more than
* a single AP die, but the default die that boots is AP #0.
* For other families there is only one die (#0).
* Initialize psci arch from die 0
*/
marvell_psci_arch_init(0);
}
/*****************************************************************************
* Perform any BL31 platform runtime setup prior to BL31 exit common to ARM
* standard platforms
*****************************************************************************
*/
void marvell_bl31_plat_runtime_setup(void)
{
console_switch_state(CONSOLE_FLAG_RUNTIME);
/* Initialize the runtime console */
marvell_console_runtime_init();
}
void bl31_platform_setup(void)
{
marvell_bl31_platform_setup();
}
void bl31_plat_runtime_setup(void)
{
marvell_bl31_plat_runtime_setup();
}
/*****************************************************************************
* Perform the very early platform specific architectural setup shared between
* ARM standard platforms. This only does basic initialization. Later
* architectural setup (bl31_arch_setup()) does not do anything platform
* specific.
*****************************************************************************
*/
void marvell_bl31_plat_arch_setup(void)
{
marvell_setup_page_tables(BL31_BASE,
BL31_END - BL31_BASE,
BL_CODE_BASE,
BL_CODE_END,
BL_RO_DATA_BASE,
BL_RO_DATA_END
#if USE_COHERENT_MEM
, BL_COHERENT_RAM_BASE,
BL_COHERENT_RAM_END
#endif
);
#if BL31_CACHE_DISABLE
enable_mmu_el3(DISABLE_DCACHE);
INFO("Cache is disabled in BL3\n");
#else
enable_mmu_el3(0);
#endif
}
void bl31_plat_arch_setup(void)
{
marvell_bl31_plat_arch_setup();
}
unsigned int plat_get_syscnt_freq2(void)
{
return PLAT_REF_CLK_IN_HZ;
}
@@ -0,0 +1,52 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <drivers/arm/cci.h>
#include <plat_marvell.h>
static const int cci_map[] = {
PLAT_MARVELL_CCI_CLUSTER0_SL_IFACE_IX,
PLAT_MARVELL_CCI_CLUSTER1_SL_IFACE_IX
};
/****************************************************************************
* The following functions are defined as weak to allow a platform to override
* the way ARM CCI driver is initialised and used.
****************************************************************************
*/
#pragma weak plat_marvell_interconnect_init
#pragma weak plat_marvell_interconnect_enter_coherency
#pragma weak plat_marvell_interconnect_exit_coherency
/****************************************************************************
* Helper function to initialize ARM CCI driver.
****************************************************************************
*/
void plat_marvell_interconnect_init(void)
{
cci_init(PLAT_MARVELL_CCI_BASE, cci_map, ARRAY_SIZE(cci_map));
}
/****************************************************************************
* Helper function to place current master into coherency
****************************************************************************
*/
void plat_marvell_interconnect_enter_coherency(void)
{
cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
}
/****************************************************************************
* Helper function to remove current master from coherency
****************************************************************************
*/
void plat_marvell_interconnect_exit_coherency(void)
{
cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
}
@@ -0,0 +1,99 @@
# Copyright (C) 2018 Marvell International Ltd.
#
# SPDX-License-Identifier: BSD-3-Clause
# https://spdx.org/licenses
MARVELL_PLAT_BASE := plat/marvell/armada
MARVELL_PLAT_INCLUDE_BASE := include/plat/marvell/armada
SEPARATE_CODE_AND_RODATA := 1
# flag to switch from PLL to ARO
ARO_ENABLE := 0
$(eval $(call add_define,ARO_ENABLE))
# Convert LLC to secure SRAM
LLC_SRAM := 0
$(eval $(call add_define,LLC_SRAM))
# Enable/Disable LLC
LLC_ENABLE := 1
$(eval $(call add_define,LLC_ENABLE))
include lib/xlat_tables_v2/xlat_tables.mk
PLAT_INCLUDES += -I$(MARVELL_PLAT_INCLUDE_BASE)/common \
-I$(MARVELL_PLAT_INCLUDE_BASE)/common/aarch64
PLAT_BL_COMMON_SOURCES += ${XLAT_TABLES_LIB_SRCS} \
$(MARVELL_PLAT_BASE)/common/aarch64/marvell_common.c \
$(MARVELL_PLAT_BASE)/common/aarch64/marvell_helpers.S \
$(MARVELL_COMMON_BASE)/marvell_console.c
BL1_SOURCES += drivers/delay_timer/delay_timer.c \
drivers/io/io_fip.c \
drivers/io/io_memmap.c \
drivers/io/io_storage.c \
$(MARVELL_PLAT_BASE)/common/marvell_bl1_setup.c \
$(MARVELL_PLAT_BASE)/common/marvell_io_storage.c \
$(MARVELL_PLAT_BASE)/common/plat_delay_timer.c
ifdef EL3_PAYLOAD_BASE
# Need the arm_program_trusted_mailbox() function to release secondary CPUs from
# their holding pen
endif
BL2_SOURCES += drivers/io/io_fip.c \
drivers/io/io_memmap.c \
drivers/io/io_storage.c \
common/desc_image_load.c \
$(MARVELL_PLAT_BASE)/common/marvell_bl2_setup.c \
$(MARVELL_PLAT_BASE)/common/marvell_io_storage.c \
$(MARVELL_PLAT_BASE)/common/aarch64/marvell_bl2_mem_params_desc.c \
$(MARVELL_PLAT_BASE)/common/marvell_image_load.c
ifeq (${SPD},opteed)
PLAT_INCLUDES += -Iinclude/lib
BL2_SOURCES += lib/optee/optee_utils.c
endif
BL31_SOURCES += $(MARVELL_PLAT_BASE)/common/marvell_bl31_setup.c \
$(MARVELL_PLAT_BASE)/common/marvell_pm.c \
$(MARVELL_PLAT_BASE)/common/marvell_topology.c \
plat/common/plat_psci_common.c \
$(MARVELL_PLAT_BASE)/common/plat_delay_timer.c \
drivers/delay_timer/delay_timer.c
# PSCI functionality
$(eval $(call add_define,CONFIG_ARM64))
# Add the build options to pack Trusted OS Extra1 and Trusted OS Extra2 images
# in the FIP if the platform requires.
ifneq ($(BL32_EXTRA1),)
$(eval $(call TOOL_ADD_IMG,bl32_extra1,--tos-fw-extra1))
endif
ifneq ($(BL32_EXTRA2),)
$(eval $(call TOOL_ADD_IMG,bl32_extra2,--tos-fw-extra2))
endif
# MSS (SCP) build
ifeq (${MSS_SUPPORT}, 1)
include $(MARVELL_PLAT_BASE)/common/mss/mss_common.mk
endif
$(BUILD_PLAT)/$(BOOT_IMAGE): $(BUILD_PLAT)/bl1.bin $(BUILD_PLAT)/$(FIP_NAME)
$(if $(shell find $(BUILD_PLAT)/bl1.bin -type f -size +128k),$(error "Image '$(BUILD_PLAT)/bl1.bin' is bigger than 128kB"))
@cp $(BUILD_PLAT)/bl1.bin $(BUILD_PLAT)/$(BOOT_IMAGE) || { rm -f $(BUILD_PLAT)/$(BOOT_IMAGE); false; }
@truncate -s %128K $(BUILD_PLAT)/$(BOOT_IMAGE) || { rm -f $(BUILD_PLAT)/$(BOOT_IMAGE); false; }
@cat $(BUILD_PLAT)/$(FIP_NAME) >> $(BUILD_PLAT)/$(BOOT_IMAGE) || { rm -f $(BUILD_PLAT)/$(BOOT_IMAGE); false; }
@truncate -s %4 $(BUILD_PLAT)/$(BOOT_IMAGE) || { rm -f $(BUILD_PLAT)/$(BOOT_IMAGE); false; }
@$(ECHO_BLANK_LINE)
@echo "Built $@ successfully"
@$(ECHO_BLANK_LINE)
.PHONY: mrvl_bootimage
mrvl_bootimage: $(BUILD_PLAT)/$(BOOT_IMAGE)
.PHONY: mrvl_flash
mrvl_flash: $(BUILD_PLAT)/$(FLASH_IMAGE)
@@ -0,0 +1,77 @@
/*
* Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <platform_def.h>
#include <common/debug.h>
#include <drivers/console.h>
#include <plat_marvell.h>
#ifdef PLAT_a3700
#include <drivers/marvell/uart/a3700_console.h>
#define PLAT_MARVELL_UART_CLK_IN_HZ (get_ref_clk() * 1000000)
#define console_marvell_register console_a3700_register
#else
#include <drivers/ti/uart/uart_16550.h>
#define console_marvell_register console_16550_register
#endif
static console_t marvell_boot_console;
static console_t marvell_runtime_console;
/*******************************************************************************
* Functions that set up the console
******************************************************************************/
/* Initialize the console to provide early debug support */
void marvell_console_boot_init(void)
{
int rc =
console_marvell_register(PLAT_MARVELL_UART_BASE,
PLAT_MARVELL_UART_CLK_IN_HZ,
MARVELL_CONSOLE_BAUDRATE,
&marvell_boot_console);
if (rc == 0) {
/*
* The crash console doesn't use the multi console API, it uses
* the core console functions directly. It is safe to call panic
* and let it print debug information.
*/
panic();
}
console_set_scope(&marvell_boot_console, CONSOLE_FLAG_BOOT);
}
void marvell_console_boot_end(void)
{
console_flush();
(void)console_unregister(&marvell_boot_console);
}
/* Initialize the runtime console */
void marvell_console_runtime_init(void)
{
int rc =
console_marvell_register(PLAT_MARVELL_UART_BASE,
PLAT_MARVELL_UART_CLK_IN_HZ,
MARVELL_CONSOLE_BAUDRATE,
&marvell_runtime_console);
if (rc == 0)
panic();
console_set_scope(&marvell_runtime_console, CONSOLE_FLAG_RUNTIME);
}
void marvell_console_runtime_end(void)
{
console_flush();
(void)console_unregister(&marvell_runtime_console);
}
@@ -0,0 +1,112 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <platform_def.h>
#include <common/debug.h>
#include <lib/mmio.h>
#include <ddr_info.h>
#define DRAM_CH0_MMAP_LOW_REG(iface, cs, base) \
(base + DRAM_CH0_MMAP_LOW_OFFSET + (iface) * 0x10000 + (cs) * 0x8)
#define DRAM_CH0_MMAP_HIGH_REG(iface, cs, base) \
(DRAM_CH0_MMAP_LOW_REG(iface, cs, base) + 4)
#define DRAM_CS_VALID_ENABLED_MASK 0x1
#define DRAM_AREA_LENGTH_OFFS 16
#define DRAM_AREA_LENGTH_MASK (0x1f << DRAM_AREA_LENGTH_OFFS)
#define DRAM_START_ADDRESS_L_OFFS 23
#define DRAM_START_ADDRESS_L_MASK \
(0x1ff << DRAM_START_ADDRESS_L_OFFS)
#define DRAM_START_ADDR_HTOL_OFFS 32
#define DRAM_MAX_CS_NUM 2
#define DRAM_CS_ENABLED(iface, cs, base) \
(mmio_read_32(DRAM_CH0_MMAP_LOW_REG(iface, cs, base)) & \
DRAM_CS_VALID_ENABLED_MASK)
#define GET_DRAM_REGION_SIZE_CODE(iface, cs, base) \
(mmio_read_32(DRAM_CH0_MMAP_LOW_REG(iface, cs, base)) & \
DRAM_AREA_LENGTH_MASK) >> DRAM_AREA_LENGTH_OFFS
/* Mapping between DDR area length and real DDR size is specific and looks like
* bellow:
* 0 => 384 MB
* 1 => 768 MB
* 2 => 1536 MB
* 3 => 3 GB
* 4 => 6 GB
*
* 7 => 8 MB
* 8 => 16 MB
* 9 => 32 MB
* 10 => 64 MB
* 11 => 128 MB
* 12 => 256 MB
* 13 => 512 MB
* 14 => 1 GB
* 15 => 2 GB
* 16 => 4 GB
* 17 => 8 GB
* 18 => 16 GB
* 19 => 32 GB
* 20 => 64 GB
* 21 => 128 GB
* 22 => 256 GB
* 23 => 512 GB
* 24 => 1 TB
* 25 => 2 TB
* 26 => 4 TB
*
* to calculate real size we need to use two different formulas:
* -- GET_DRAM_REGION_SIZE_ODD for values 0-4 (DRAM_REGION_SIZE_ODD)
* -- GET_DRAM_REGION_SIZE_EVEN for values 7-26 (DRAM_REGION_SIZE_EVEN)
* using mentioned formulas we cover whole mapping between "Area length" value
* and real size (see above mapping).
*/
#define DRAM_REGION_SIZE_EVEN(C) (((C) >= 7) && ((C) <= 26))
#define GET_DRAM_REGION_SIZE_EVEN(C) ((uint64_t)1 << ((C) + 16))
#define DRAM_REGION_SIZE_ODD(C) ((C) <= 4)
#define GET_DRAM_REGION_SIZE_ODD(C) ((uint64_t)0x18000000 << (C))
uint64_t mvebu_get_dram_size(uint64_t ap_base_addr)
{
uint64_t mem_size = 0;
uint8_t region_code;
uint8_t cs, iface;
for (iface = 0; iface < DRAM_MAX_IFACE; iface++) {
for (cs = 0; cs < DRAM_MAX_CS_NUM; cs++) {
/* Exit loop on first disabled DRAM CS */
if (!DRAM_CS_ENABLED(iface, cs, ap_base_addr))
break;
/* Decode area length for current CS
* from register value
*/
region_code =
GET_DRAM_REGION_SIZE_CODE(iface, cs,
ap_base_addr);
if (DRAM_REGION_SIZE_EVEN(region_code)) {
mem_size +=
GET_DRAM_REGION_SIZE_EVEN(region_code);
} else if (DRAM_REGION_SIZE_ODD(region_code)) {
mem_size +=
GET_DRAM_REGION_SIZE_ODD(region_code);
} else {
WARN("%s: Invalid mem region (0x%x) CS#%d\n",
__func__, region_code, cs);
return 0;
}
}
}
return mem_size;
}
@@ -0,0 +1,148 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <platform_def.h>
#include <bl31/interrupt_mgmt.h>
#include <common/debug.h>
#include <drivers/arm/gicv2.h>
#include <lib/bakery_lock.h>
#include <lib/mmio.h>
#include <plat/common/platform.h>
#include <plat_marvell.h>
/*
* The following functions are defined as weak to allow a platform to override
* the way the GICv2 driver is initialised and used.
*/
#pragma weak plat_marvell_gic_driver_init
#pragma weak plat_marvell_gic_init
#define A7K8K_PIC_CAUSE_REG 0xf03f0100
#define A7K8K_PIC0_MASK_REG 0xf03f0108
#define A7K8K_PIC_PMUOF_IRQ_MASK (1 << 17)
#define A7K8K_PIC_MAX_IRQS 32
#define A7K8K_PIC_MAX_IRQ_MASK ((1UL << A7K8K_PIC_MAX_IRQS) - 1)
#define A7K8K_ODMIN_SET_REG 0xf0300040
#define A7K8K_ODMI_PMU_IRQ(idx) ((2 + idx) << 12)
#define A7K8K_ODMI_PMU_GIC_IRQ(idx) (130 + idx)
static DEFINE_BAKERY_LOCK(a7k8k_irq_lock);
/*
* On a GICv2 system, the Group 1 secure interrupts are treated as Group 0
* interrupts.
*/
static const interrupt_prop_t marvell_interrupt_props[] = {
PLAT_MARVELL_G1S_IRQ_PROPS(GICV2_INTR_GROUP0),
PLAT_MARVELL_G0_IRQ_PROPS(GICV2_INTR_GROUP0)
};
static unsigned int target_mask_array[PLATFORM_CORE_COUNT];
/*
* Ideally `marvell_gic_data` structure definition should be a `const` but it is
* kept as modifiable for overwriting with different GICD and GICC base when
* running on FVP with VE memory map.
*/
static gicv2_driver_data_t marvell_gic_data = {
.gicd_base = PLAT_MARVELL_GICD_BASE,
.gicc_base = PLAT_MARVELL_GICC_BASE,
.interrupt_props = marvell_interrupt_props,
.interrupt_props_num = ARRAY_SIZE(marvell_interrupt_props),
.target_masks = target_mask_array,
.target_masks_num = ARRAY_SIZE(target_mask_array),
};
/*
* ARM common helper to initialize the GICv2 only driver.
*/
void plat_marvell_gic_driver_init(void)
{
gicv2_driver_init(&marvell_gic_data);
}
static uint64_t a7k8k_pmu_interrupt_handler(uint32_t id,
uint32_t flags,
void *handle,
void *cookie)
{
unsigned int idx = plat_my_core_pos();
uint32_t irq;
bakery_lock_get(&a7k8k_irq_lock);
/* Acknowledge IRQ */
irq = plat_ic_acknowledge_interrupt();
plat_ic_end_of_interrupt(irq);
if (irq != MARVELL_IRQ_PIC0) {
bakery_lock_release(&a7k8k_irq_lock);
return 0;
}
/* Acknowledge PMU overflow IRQ in PIC0 */
mmio_setbits_32(A7K8K_PIC_CAUSE_REG, A7K8K_PIC_PMUOF_IRQ_MASK);
/* Trigger ODMI Frame IRQ */
mmio_write_32(A7K8K_ODMIN_SET_REG, A7K8K_ODMI_PMU_IRQ(idx));
bakery_lock_release(&a7k8k_irq_lock);
return 0;
}
void mvebu_pmu_interrupt_enable(void)
{
unsigned int idx;
uint32_t flags;
int32_t rc;
/* Reset PIC */
mmio_write_32(A7K8K_PIC_CAUSE_REG, A7K8K_PIC_MAX_IRQ_MASK);
/* Unmask PMU overflow IRQ in PIC0 */
mmio_clrbits_32(A7K8K_PIC0_MASK_REG, A7K8K_PIC_PMUOF_IRQ_MASK);
/* Configure ODMI Frame IRQs as edge triggered */
for (idx = 0; idx < PLATFORM_CORE_COUNT; idx++)
gicv2_interrupt_set_cfg(A7K8K_ODMI_PMU_GIC_IRQ(idx),
GIC_INTR_CFG_EDGE);
/*
* Register IRQ handler as INTR_TYPE_S_EL1 as its the only valid type
* for GICv2 in ARM-TF.
*/
flags = 0U;
set_interrupt_rm_flag((flags), (NON_SECURE));
rc = register_interrupt_type_handler(INTR_TYPE_S_EL1,
a7k8k_pmu_interrupt_handler,
flags);
if (rc != 0)
panic();
}
void mvebu_pmu_interrupt_disable(void)
{
/* Reset PIC */
mmio_write_32(A7K8K_PIC_CAUSE_REG, A7K8K_PIC_MAX_IRQ_MASK);
/* Mask PMU overflow IRQ in PIC0 */
mmio_setbits_32(A7K8K_PIC0_MASK_REG, A7K8K_PIC_PMUOF_IRQ_MASK);
}
void plat_marvell_gic_init(void)
{
gicv2_distif_init();
gicv2_pcpu_distif_init();
gicv2_set_pe_target_mask(plat_my_core_pos());
gicv2_cpuif_enable();
}
@@ -0,0 +1,210 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <platform_def.h>
#include <common/debug.h>
#include <common/interrupt_props.h>
#include <drivers/arm/gicv3.h>
#include <plat/common/platform.h>
#include <marvell_def.h>
#include <plat_marvell.h>
/******************************************************************************
* The following functions are defined as weak to allow a platform to override
* the way the GICv3 driver is initialised and used.
******************************************************************************
*/
#pragma weak plat_marvell_gic_driver_init
#pragma weak plat_marvell_gic_init
#pragma weak plat_marvell_gic_cpuif_enable
#pragma weak plat_marvell_gic_cpuif_disable
#pragma weak plat_marvell_gic_pcpu_init
/* The GICv3 driver only needs to be initialized in EL3 */
static uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT];
static const interrupt_prop_t marvell_interrupt_props[] = {
PLAT_MARVELL_G1S_IRQ_PROPS(INTR_GROUP1S),
PLAT_MARVELL_G0_IRQ_PROPS(INTR_GROUP0)
};
/*
* We save and restore the GICv3 context on system suspend. Allocate the
* data in the designated EL3 Secure carve-out memory
*/
static gicv3_redist_ctx_t rdist_ctx __section("arm_el3_tzc_dram");
static gicv3_dist_ctx_t dist_ctx __section("arm_el3_tzc_dram");
/*
* MPIDR hashing function for translating MPIDRs read from GICR_TYPER register
* to core position.
*
* Calculating core position is dependent on MPIDR_EL1.MT bit. However, affinity
* values read from GICR_TYPER don't have an MT field. To reuse the same
* translation used for CPUs, we insert MT bit read from the PE's MPIDR into
* that read from GICR_TYPER.
*
* Assumptions:
*
* - All CPUs implemented in the system have MPIDR_EL1.MT bit set;
* - No CPUs implemented in the system use affinity level 3.
*/
static unsigned int marvell_gicv3_mpidr_hash(u_register_t mpidr)
{
mpidr |= (read_mpidr_el1() & MPIDR_MT_MASK);
return plat_marvell_calc_core_pos(mpidr);
}
const gicv3_driver_data_t marvell_gic_data = {
.gicd_base = PLAT_MARVELL_GICD_BASE,
.gicr_base = PLAT_MARVELL_GICR_BASE,
.interrupt_props = marvell_interrupt_props,
.interrupt_props_num = ARRAY_SIZE(marvell_interrupt_props),
.rdistif_num = PLATFORM_CORE_COUNT,
.rdistif_base_addrs = rdistif_base_addrs,
.mpidr_to_core_pos = marvell_gicv3_mpidr_hash
};
void plat_marvell_gic_driver_init(void)
{
/*
* The GICv3 driver is initialized in EL3 and does not need
* to be initialized again in SEL1. This is because the S-EL1
* can use GIC system registers to manage interrupts and does
* not need GIC interface base addresses to be configured.
*/
#if IMAGE_BL31
gicv3_driver_init(&marvell_gic_data);
#endif
}
/******************************************************************************
* Marvell common helper to initialize the GIC. Only invoked by BL31
******************************************************************************
*/
void plat_marvell_gic_init(void)
{
/* Initialize GIC-600 Multi Chip feature,
* only if the maximum number of north bridges
* is more than 1 - otherwise no need for multi
* chip feature initialization
*/
#if (PLAT_MARVELL_NORTHB_COUNT > 1)
if (gic600_multi_chip_init())
ERROR("GIC-600 Multi Chip initialization failed\n");
#endif
gicv3_distif_init();
gicv3_rdistif_init(plat_my_core_pos());
gicv3_cpuif_enable(plat_my_core_pos());
}
/******************************************************************************
* Marvell common helper to enable the GIC CPU interface
******************************************************************************
*/
void plat_marvell_gic_cpuif_enable(void)
{
gicv3_cpuif_enable(plat_my_core_pos());
}
/******************************************************************************
* Marvell common helper to disable the GIC CPU interface
******************************************************************************
*/
void plat_marvell_gic_cpuif_disable(void)
{
gicv3_cpuif_disable(plat_my_core_pos());
}
/******************************************************************************
* Marvell common helper to init. the per-cpu redistributor interface in GICv3
******************************************************************************
*/
void plat_marvell_gic_pcpu_init(void)
{
gicv3_rdistif_init(plat_my_core_pos());
}
/******************************************************************************
* Marvell common helper to save SPI irq states in GICv3
******************************************************************************
*/
void plat_marvell_gic_irq_save(void)
{
/*
* If an ITS is available, save its context before
* the Redistributor using:
* gicv3_its_save_disable(gits_base, &its_ctx[i])
* Additionally, an implementation-defined sequence may
* be required to save the whole ITS state.
*/
/*
* Save the GIC Redistributors and ITS contexts before the
* Distributor context. As we only handle SYSTEM SUSPEND API,
* we only need to save the context of the CPU that is issuing
* the SYSTEM SUSPEND call, i.e. the current CPU.
*/
gicv3_rdistif_save(plat_my_core_pos(), &rdist_ctx);
/* Save the GIC Distributor context */
gicv3_distif_save(&dist_ctx);
/*
* From here, all the components of the GIC can be safely powered down
* as long as there is an alternate way to handle wakeup interrupt
* sources.
*/
}
/******************************************************************************
* Marvell common helper to restore SPI irq states in GICv3
******************************************************************************
*/
void plat_marvell_gic_irq_restore(void)
{
/* Restore the GIC Distributor context */
gicv3_distif_init_restore(&dist_ctx);
/*
* Restore the GIC Redistributor and ITS contexts after the
* Distributor context. As we only handle SYSTEM SUSPEND API,
* we only need to restore the context of the CPU that issued
* the SYSTEM SUSPEND call.
*/
gicv3_rdistif_init_restore(plat_my_core_pos(), &rdist_ctx);
/*
* If an ITS is available, restore its context after
* the Redistributor using:
* gicv3_its_restore(gits_base, &its_ctx[i])
* An implementation-defined sequence may be required to
* restore the whole ITS state. The ITS must also be
* re-enabled after this sequence has been executed.
*/
}
/******************************************************************************
* Marvell common helper to save per-cpu PPI irq states in GICv3
******************************************************************************
*/
void plat_marvell_gic_irq_pcpu_save(void)
{
gicv3_rdistif_save(plat_my_core_pos(), &rdist_ctx);
}
/******************************************************************************
* Marvell common helper to restore per-cpu PPI irq states in GICv3
******************************************************************************
*/
void plat_marvell_gic_irq_pcpu_restore(void)
{
gicv3_rdistif_init_restore(plat_my_core_pos(), &rdist_ctx);
}
@@ -0,0 +1,36 @@
/*
* Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <platform_def.h>
#include <common/bl_common.h>
#include <common/desc_image_load.h>
#include <plat/common/platform.h>
/*******************************************************************************
* This function flushes the data structures so that they are visible
* in memory for the next BL image.
******************************************************************************/
void plat_flush_next_bl_params(void)
{
flush_bl_params_desc();
}
/*******************************************************************************
* This function returns the list of loadable images.
******************************************************************************/
bl_load_info_t *plat_get_bl_image_load_info(void)
{
return get_bl_load_info_from_mem_params_desc();
}
/*******************************************************************************
* This function returns the list of executable images.
******************************************************************************/
bl_params_t *plat_get_next_bl_params(void)
{
return get_next_bl_params_from_mem_params_desc();
}
@@ -0,0 +1,227 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <assert.h>
#include <string.h>
#include <platform_def.h>
#include <common/bl_common.h>
#include <common/debug.h>
#include <drivers/io/io_driver.h>
#include <drivers/io/io_fip.h>
#include <drivers/io/io_memmap.h>
#include <drivers/io/io_storage.h>
#include <tools_share/firmware_image_package.h>
/* IO devices */
static const io_dev_connector_t *fip_dev_con;
static uintptr_t fip_dev_handle;
static const io_dev_connector_t *memmap_dev_con;
static uintptr_t memmap_dev_handle;
static const io_block_spec_t fip_block_spec = {
.offset = PLAT_MARVELL_FIP_BASE,
.length = PLAT_MARVELL_FIP_MAX_SIZE
};
static const io_uuid_spec_t bl2_uuid_spec = {
.uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2,
};
static const io_uuid_spec_t scp_bl2_uuid_spec = {
.uuid = UUID_SCP_FIRMWARE_SCP_BL2,
};
static const io_uuid_spec_t bl31_uuid_spec = {
.uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31,
};
static const io_uuid_spec_t bl32_uuid_spec = {
.uuid = UUID_SECURE_PAYLOAD_BL32,
};
static const io_uuid_spec_t bl32_extra1_uuid_spec = {
.uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA1,
};
static const io_uuid_spec_t bl32_extra2_uuid_spec = {
.uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA2,
};
static const io_uuid_spec_t bl33_uuid_spec = {
.uuid = UUID_NON_TRUSTED_FIRMWARE_BL33,
};
static int open_fip(const uintptr_t spec);
static int open_memmap(const uintptr_t spec);
struct plat_io_policy {
uintptr_t *dev_handle;
uintptr_t image_spec;
int (*check)(const uintptr_t spec);
};
/* By default, Marvell platforms load images from the FIP */
static const struct plat_io_policy policies[] = {
[FIP_IMAGE_ID] = {
&memmap_dev_handle,
(uintptr_t)&fip_block_spec,
open_memmap
},
[BL2_IMAGE_ID] = {
&fip_dev_handle,
(uintptr_t)&bl2_uuid_spec,
open_fip
},
[SCP_BL2_IMAGE_ID] = {
&fip_dev_handle,
(uintptr_t)&scp_bl2_uuid_spec,
open_fip
},
[BL31_IMAGE_ID] = {
&fip_dev_handle,
(uintptr_t)&bl31_uuid_spec,
open_fip
},
[BL32_IMAGE_ID] = {
&fip_dev_handle,
(uintptr_t)&bl32_uuid_spec,
open_fip
},
[BL32_EXTRA1_IMAGE_ID] = {
&fip_dev_handle,
(uintptr_t)&bl32_extra1_uuid_spec,
open_fip
},
[BL32_EXTRA2_IMAGE_ID] = {
&fip_dev_handle,
(uintptr_t)&bl32_extra2_uuid_spec,
open_fip
},
[BL33_IMAGE_ID] = {
&fip_dev_handle,
(uintptr_t)&bl33_uuid_spec,
open_fip
},
};
/* Weak definitions may be overridden in specific ARM standard platform */
#pragma weak plat_marvell_io_setup
#pragma weak plat_marvell_get_alt_image_source
static int open_fip(const uintptr_t spec)
{
int result;
uintptr_t local_image_handle;
/* See if a Firmware Image Package is available */
result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID);
if (result == 0) {
result = io_open(fip_dev_handle, spec, &local_image_handle);
if (result == 0) {
VERBOSE("Using FIP\n");
io_close(local_image_handle);
}
}
return result;
}
static int open_memmap(const uintptr_t spec)
{
int result;
uintptr_t local_image_handle;
result = io_dev_init(memmap_dev_handle, (uintptr_t)NULL);
if (result == 0) {
result = io_open(memmap_dev_handle, spec, &local_image_handle);
if (result == 0) {
VERBOSE("Using Memmap\n");
io_close(local_image_handle);
}
}
return result;
}
void marvell_io_setup(void)
{
int io_result;
io_result = register_io_dev_fip(&fip_dev_con);
assert(io_result == 0);
io_result = register_io_dev_memmap(&memmap_dev_con);
assert(io_result == 0);
/* Open connections to devices and cache the handles */
io_result = io_dev_open(fip_dev_con, (uintptr_t)NULL,
&fip_dev_handle);
assert(io_result == 0);
io_result = io_dev_open(memmap_dev_con, (uintptr_t)NULL,
&memmap_dev_handle);
assert(io_result == 0);
/* Ignore improbable errors in release builds */
(void)io_result;
}
void plat_marvell_io_setup(void)
{
marvell_io_setup();
}
int plat_marvell_get_alt_image_source(
unsigned int image_id __attribute__((unused)),
uintptr_t *dev_handle __attribute__((unused)),
uintptr_t *image_spec __attribute__((unused)))
{
/* By default do not try an alternative */
return -ENOENT;
}
/*
* Return an IO device handle and specification which can be used to access
* an image. Use this to enforce platform load policy
*/
int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle,
uintptr_t *image_spec)
{
int result;
const struct plat_io_policy *policy;
assert(image_id < ARRAY_SIZE(policies));
policy = &policies[image_id];
result = policy->check(policy->image_spec);
if (result == 0) {
*image_spec = policy->image_spec;
*dev_handle = *(policy->dev_handle);
} else {
VERBOSE("Trying alternative IO\n");
result = plat_marvell_get_alt_image_source(image_id, dev_handle,
image_spec);
}
return result;
}
/*
* See if a Firmware Image Package is available,
* by checking if TOC is valid or not.
*/
int marvell_io_is_toc_valid(void)
{
int result;
result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID);
return result == 0;
}
@@ -0,0 +1,60 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <assert.h>
#include <arch_helpers.h>
#include <lib/psci/psci.h>
#include <marvell_pm.h>
/* Standard ARM platforms are expected to export plat_arm_psci_pm_ops */
extern const plat_psci_ops_t plat_arm_psci_pm_ops;
/*****************************************************************************
* Private function to program the mailbox for a cpu before it is released
* from reset. This function assumes that the mail box base is within
* the MARVELL_SHARED_RAM region
*****************************************************************************
*/
void marvell_program_mailbox(uintptr_t address)
{
uintptr_t *mailbox = (void *)PLAT_MARVELL_MAILBOX_BASE;
/*
* Ensure that the PLAT_MARVELL_MAILBOX_BASE is within
* MARVELL_SHARED_RAM region.
*/
assert((PLAT_MARVELL_MAILBOX_BASE >= MARVELL_SHARED_RAM_BASE) &&
((PLAT_MARVELL_MAILBOX_BASE + sizeof(*mailbox)) <=
(MARVELL_SHARED_RAM_BASE + MARVELL_SHARED_RAM_SIZE)));
mailbox[MBOX_IDX_MAGIC] = MVEBU_MAILBOX_MAGIC_NUM;
mailbox[MBOX_IDX_SEC_ADDR] = address;
/* Flush data cache if the mail box shared RAM is cached */
#if PLAT_MARVELL_SHARED_RAM_CACHED
flush_dcache_range((uintptr_t)PLAT_MARVELL_MAILBOX_BASE +
8 * MBOX_IDX_MAGIC,
2 * sizeof(uint64_t));
#endif
}
/*****************************************************************************
* The ARM Standard platform definition of platform porting API
* `plat_setup_psci_ops`.
*****************************************************************************
*/
int plat_setup_psci_ops(uintptr_t sec_entrypoint,
const plat_psci_ops_t **psci_ops)
{
*psci_ops = &plat_arm_psci_pm_ops;
/* Setup mailbox with entry point. */
marvell_program_mailbox(sec_entrypoint);
return 0;
}
@@ -0,0 +1,84 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <plat_marvell.h>
/* The power domain tree descriptor */
unsigned char marvell_power_domain_tree_desc[PLAT_MARVELL_CLUSTER_COUNT + 1];
/*****************************************************************************
* This function dynamically constructs the topology according to
* PLAT_MARVELL_CLUSTER_COUNT and returns it.
*****************************************************************************
*/
const unsigned char *plat_get_power_domain_tree_desc(void)
{
int i;
/*
* The power domain tree does not have a single system level power
* domain i.e. a single root node. The first entry in the power domain
* descriptor specifies the number of power domains at the highest power
* level.
* For Marvell Platform this is the number of cluster power domains.
*/
marvell_power_domain_tree_desc[0] = PLAT_MARVELL_CLUSTER_COUNT;
for (i = 0; i < PLAT_MARVELL_CLUSTER_COUNT; i++)
marvell_power_domain_tree_desc[i + 1] =
PLAT_MARVELL_CLUSTER_CORE_COUNT;
return marvell_power_domain_tree_desc;
}
/*****************************************************************************
* This function validates an MPIDR by checking whether it falls within the
* acceptable bounds. An error code (-1) is returned if an incorrect mpidr
* is passed.
*****************************************************************************
*/
int marvell_check_mpidr(u_register_t mpidr)
{
unsigned int nb_id, cluster_id, cpu_id;
mpidr &= MPIDR_AFFINITY_MASK;
if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK |
MPIDR_AFFLVL_MASK << MPIDR_AFF2_SHIFT))
return -1;
/* Get north bridge ID */
nb_id = MPIDR_AFFLVL3_VAL(mpidr);
cluster_id = MPIDR_AFFLVL1_VAL(mpidr);
cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
if (nb_id >= PLAT_MARVELL_CLUSTER_COUNT)
return -1;
if (cluster_id >= PLAT_MARVELL_CLUSTER_COUNT)
return -1;
if (cpu_id >= PLAT_MARVELL_CLUSTER_CORE_COUNT)
return -1;
return 0;
}
/*****************************************************************************
* This function implements a part of the critical interface between the PSCI
* generic layer and the platform that allows the former to query the platform
* to convert an MPIDR to a unique linear index. An error code (-1) is returned
* in case the MPIDR is invalid.
*****************************************************************************
*/
int plat_core_pos_by_mpidr(u_register_t mpidr)
{
if (marvell_check_mpidr(mpidr) == -1)
return -1;
return plat_marvell_calc_core_pos(mpidr);
}
@@ -0,0 +1,188 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <common/debug.h>
#include <common/runtime_svc.h>
#include <drivers/marvell/cache_llc.h>
#include <drivers/marvell/mochi/ap_setup.h>
#include <drivers/rambus/trng_ip_76.h>
#include <lib/smccc.h>
#include <marvell_plat_priv.h>
#include <plat_marvell.h>
#include "comphy/phy-comphy-cp110.h"
#include "secure_dfx_access/dfx.h"
#include "ddr_phy_access.h"
#include <stdbool.h>
/* #define DEBUG_COMPHY */
#ifdef DEBUG_COMPHY
#define debug(format...) NOTICE(format)
#else
#define debug(format, arg...)
#endif
/* Comphy related FID's */
#define MV_SIP_COMPHY_POWER_ON 0x82000001
#define MV_SIP_COMPHY_POWER_OFF 0x82000002
#define MV_SIP_COMPHY_PLL_LOCK 0x82000003
#define MV_SIP_COMPHY_XFI_TRAIN 0x82000004
#define MV_SIP_COMPHY_DIG_RESET 0x82000005
/* Miscellaneous FID's' */
#define MV_SIP_DRAM_SIZE 0x82000010
#define MV_SIP_LLC_ENABLE 0x82000011
#define MV_SIP_PMU_IRQ_ENABLE 0x82000012
#define MV_SIP_PMU_IRQ_DISABLE 0x82000013
#define MV_SIP_DFX 0x82000014
#define MV_SIP_DDR_PHY_WRITE 0x82000015
#define MV_SIP_DDR_PHY_READ 0x82000016
/* TRNG */
#define MV_SIP_RNG_64 0xC200FF11
#define MAX_LANE_NR 6
#define MVEBU_COMPHY_OFFSET 0x441000
#define MVEBU_CP_BASE_MASK (~0xffffff)
/* Common PHY register */
#define COMPHY_TRX_TRAIN_CTRL_REG_0_OFFS 0x120a2c
/* This macro is used to identify COMPHY related calls from SMC function ID */
#define is_comphy_fid(fid) \
((fid) >= MV_SIP_COMPHY_POWER_ON && (fid) <= MV_SIP_COMPHY_DIG_RESET)
_Bool is_cp_range_valid(u_register_t *addr)
{
int cp_nr;
*addr &= MVEBU_CP_BASE_MASK;
for (cp_nr = 0; cp_nr < CP_NUM; cp_nr++) {
if (*addr == MVEBU_CP_REGS_BASE(cp_nr))
return true;
}
return false;
}
uintptr_t mrvl_sip_smc_handler(uint32_t smc_fid,
u_register_t x1,
u_register_t x2,
u_register_t x3,
u_register_t x4,
void *cookie,
void *handle,
u_register_t flags)
{
u_register_t ret, read, x5 = x1;
int i;
debug("%s: got SMC (0x%x) x1 0x%lx, x2 0x%lx, x3 0x%lx\n",
__func__, smc_fid, x1, x2, x3);
if (is_comphy_fid(smc_fid)) {
/* validate address passed via x1 */
if (!is_cp_range_valid(&x1)) {
ERROR("%s: Wrong smc (0x%x) address: %lx\n",
__func__, smc_fid, x1);
SMC_RET1(handle, SMC_UNK);
}
x5 = x1 + COMPHY_TRX_TRAIN_CTRL_REG_0_OFFS;
x1 += MVEBU_COMPHY_OFFSET;
if (x2 >= MAX_LANE_NR) {
ERROR("%s: Wrong smc (0x%x) lane nr: %lx\n",
__func__, smc_fid, x2);
SMC_RET1(handle, SMC_UNK);
}
}
switch (smc_fid) {
/* Comphy related FID's */
case MV_SIP_COMPHY_POWER_ON:
/* x1: comphy_base, x2: comphy_index, x3: comphy_mode */
ret = mvebu_cp110_comphy_power_on(x1, x2, x3, x5);
SMC_RET1(handle, ret);
case MV_SIP_COMPHY_POWER_OFF:
/* x1: comphy_base, x2: comphy_index */
ret = mvebu_cp110_comphy_power_off(x1, x2, x3);
SMC_RET1(handle, ret);
case MV_SIP_COMPHY_PLL_LOCK:
/* x1: comphy_base, x2: comphy_index */
ret = mvebu_cp110_comphy_is_pll_locked(x1, x2);
SMC_RET1(handle, ret);
case MV_SIP_COMPHY_XFI_TRAIN:
/* x1: comphy_base, x2: comphy_index */
ret = mvebu_cp110_comphy_xfi_rx_training(x1, x2);
SMC_RET1(handle, ret);
case MV_SIP_COMPHY_DIG_RESET:
/* x1: comphy_base, x2: comphy_index, x3: mode, x4: command */
ret = mvebu_cp110_comphy_digital_reset(x1, x2, x3, x4);
SMC_RET1(handle, ret);
/* Miscellaneous FID's' */
case MV_SIP_DRAM_SIZE:
ret = mvebu_get_dram_size(MVEBU_REGS_BASE);
SMC_RET1(handle, ret);
case MV_SIP_LLC_ENABLE:
for (i = 0; i < ap_get_count(); i++)
llc_runtime_enable(i);
SMC_RET1(handle, 0);
#ifdef MVEBU_PMU_IRQ_WA
case MV_SIP_PMU_IRQ_ENABLE:
mvebu_pmu_interrupt_enable();
SMC_RET1(handle, 0);
case MV_SIP_PMU_IRQ_DISABLE:
mvebu_pmu_interrupt_disable();
SMC_RET1(handle, 0);
#endif
case MV_SIP_DFX:
if (x1 >= MV_SIP_DFX_THERMAL_INIT &&
x1 <= MV_SIP_DFX_THERMAL_SEL_CHANNEL) {
ret = mvebu_dfx_thermal_handle(x1, &read, x2, x3);
SMC_RET2(handle, ret, read);
}
if (x1 >= MV_SIP_DFX_SREAD && x1 <= MV_SIP_DFX_SWRITE) {
ret = mvebu_dfx_misc_handle(x1, &read, x2, x3);
SMC_RET2(handle, ret, read);
}
SMC_RET1(handle, SMC_UNK);
case MV_SIP_DDR_PHY_WRITE:
ret = mvebu_ddr_phy_write(x1, x2);
SMC_RET1(handle, ret);
case MV_SIP_DDR_PHY_READ:
read = 0;
ret = mvebu_ddr_phy_read(x1, (uint16_t *)&read);
SMC_RET2(handle, ret, read);
case MV_SIP_RNG_64:
if ((x1 % 2 + 1) > sizeof(read)/4) {
ERROR("%s: Maximum %ld random bytes per SMC call\n",
__func__, sizeof(read));
SMC_RET1(handle, SMC_UNK);
}
ret = eip76_rng_get_random((uint8_t *)&read, 4 * (x1 % 2 + 1));
SMC_RET2(handle, ret, read);
default:
ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
SMC_RET1(handle, SMC_UNK);
}
}
/* Define a runtime service descriptor for fast SMC calls */
DECLARE_RT_SVC(
marvell_sip_svc,
OEN_SIP_START,
OEN_SIP_END,
SMC_TYPE_FAST,
NULL,
mrvl_sip_smc_handler
);
@@ -0,0 +1,20 @@
#
# Copyright (C) 2018 Marvell International Ltd.
#
# SPDX-License-Identifier: BSD-3-Clause
# https://spdx.org/licenses
#
PLAT_MARVELL := plat/marvell/armada
MSS_SOURCE := $(PLAT_MARVELL)/common/mss
BL2_SOURCES += $(MSS_SOURCE)/mss_scp_bootloader.c \
$(PLAT_MARVELL)/common/plat_delay_timer.c \
drivers/delay_timer/delay_timer.c \
$(MARVELL_DRV) \
$(BOARD_DIR)/board/marvell_plat_config.c
BL31_SOURCES += $(MSS_SOURCE)/mss_ipc_drv.c
PLAT_INCLUDES += -I$(MSS_SOURCE)
@@ -0,0 +1,113 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <string.h>
#include <common/debug.h>
#include <lib/mmio.h>
#include <plat_marvell.h>
#include <mss_ipc_drv.h>
#define IPC_MSG_BASE_MASK MVEBU_REGS_BASE_MASK
#define IPC_CH_NUM_OF_MSG (16)
#define IPC_CH_MSG_IDX (-1)
unsigned long mv_pm_ipc_msg_base;
unsigned int mv_pm_ipc_queue_size;
unsigned int msg_sync;
int msg_index = IPC_CH_MSG_IDX;
/******************************************************************************
* mss_pm_ipc_init
*
* DESCRIPTION: Initialize PM IPC infrastructure
******************************************************************************
*/
int mv_pm_ipc_init(unsigned long ipc_control_addr)
{
struct mss_pm_ipc_ctrl *ipc_control =
(struct mss_pm_ipc_ctrl *)ipc_control_addr;
/* Initialize PM IPC control block */
mv_pm_ipc_msg_base = ipc_control->msg_base_address |
IPC_MSG_BASE_MASK;
mv_pm_ipc_queue_size = ipc_control->queue_size;
return 0;
}
/******************************************************************************
* mv_pm_ipc_queue_addr_get
*
* DESCRIPTION: Returns the IPC queue address
******************************************************************************
*/
unsigned int mv_pm_ipc_queue_addr_get(void)
{
unsigned int addr;
inv_dcache_range((uint64_t)&msg_index, sizeof(msg_index));
msg_index = msg_index + 1;
if (msg_index >= IPC_CH_NUM_OF_MSG)
msg_index = 0;
addr = (unsigned int)(mv_pm_ipc_msg_base +
(msg_index * mv_pm_ipc_queue_size));
flush_dcache_range((uint64_t)&msg_index, sizeof(msg_index));
return addr;
}
/******************************************************************************
* mv_pm_ipc_msg_rx
*
* DESCRIPTION: Retrieve message from IPC channel
******************************************************************************
*/
int mv_pm_ipc_msg_rx(unsigned int channel_id, struct mss_pm_ipc_msg *msg)
{
unsigned int addr = mv_pm_ipc_queue_addr_get();
msg->msg_reply = mmio_read_32(addr + IPC_MSG_REPLY_LOC);
return 0;
}
/******************************************************************************
* mv_pm_ipc_msg_tx
*
* DESCRIPTION: Send message via IPC channel
******************************************************************************
*/
int mv_pm_ipc_msg_tx(unsigned int channel_id, unsigned int msg_id,
unsigned int cluster_power_state)
{
unsigned int addr = mv_pm_ipc_queue_addr_get();
/* Validate the entry for message placed by the host is free */
if (mmio_read_32(addr + IPC_MSG_STATE_LOC) == IPC_MSG_FREE) {
inv_dcache_range((uint64_t)&msg_sync, sizeof(msg_sync));
msg_sync = msg_sync + 1;
flush_dcache_range((uint64_t)&msg_sync, sizeof(msg_sync));
mmio_write_32(addr + IPC_MSG_SYNC_ID_LOC, msg_sync);
mmio_write_32(addr + IPC_MSG_ID_LOC, msg_id);
mmio_write_32(addr + IPC_MSG_CPU_ID_LOC, channel_id);
mmio_write_32(addr + IPC_MSG_POWER_STATE_LOC,
cluster_power_state);
mmio_write_32(addr + IPC_MSG_STATE_LOC, IPC_MSG_OCCUPY);
} else {
ERROR("%s: FAILED\n", __func__);
}
return 0;
}
@@ -0,0 +1,120 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#ifndef MSS_IPC_DRV_H
#define MSS_IPC_DRV_H
#include <lib/psci/psci.h>
#define MV_PM_FW_IPC_VERSION_MAGIC (0xCA530000) /* Do NOT change */
/* Increament for each version */
#define MV_PM_FW_IPC_VERSION_SEQ (0x00000001)
#define MV_PM_FW_IPC_VERSION (MV_PM_FW_IPC_VERSION_MAGIC | \
MV_PM_FW_IPC_VERSION_SEQ)
#define IPC_MSG_STATE_LOC (0x0)
#define IPC_MSG_SYNC_ID_LOC (0x4)
#define IPC_MSG_ID_LOC (0x8)
#define IPC_MSG_RET_CH_ID_LOC (0xC)
#define IPC_MSG_CPU_ID_LOC (0x10)
#define IPC_MSG_CLUSTER_ID_LOC (0x14)
#define IPC_MSG_SYSTEM_ID_LOC (0x18)
#define IPC_MSG_POWER_STATE_LOC (0x1C)
#define IPC_MSG_REPLY_LOC (0x20)
#define IPC_MSG_RESERVED_LOC (0x24)
/* IPC initialization state */
enum mss_pm_ipc_init_state {
IPC_UN_INITIALIZED = 1,
IPC_INITIALIZED = 2
};
/* IPC queue direction */
enum mss_pm_ipc_init_msg_dir {
IPC_MSG_TX = 0,
IPC_MSG_RX = 1
};
/* IPC message state */
enum mss_pm_ipc_msg_state {
IPC_MSG_FREE = 1,
IPC_MSG_OCCUPY = 2
};
/* IPC control block */
struct mss_pm_ipc_ctrl {
unsigned int ctrl_base_address;
unsigned int msg_base_address;
unsigned int num_of_channels;
unsigned int channel_size;
unsigned int queue_size;
};
/* IPC message types */
enum mss_pm_msg_id {
PM_IPC_MSG_CPU_SUSPEND = 1,
PM_IPC_MSG_CPU_OFF = 2,
PM_IPC_MSG_CPU_ON = 3,
PM_IPC_MSG_SYSTEM_RESET = 4,
PM_IPC_MSG_SYSTEM_SUSPEND = 5,
PM_IPC_MAX_MSG
};
struct mss_pm_ipc_msg {
unsigned int msg_sync_id; /*
* Sync number, validate message
* reply corresponding to message
* received
*/
unsigned int msg_id; /* Message Id */
unsigned int ret_channel_id; /* IPC channel reply */
unsigned int cpu_id; /* CPU Id */
unsigned int cluster_id; /* Cluster Id */
unsigned int system_id; /* System Id */
unsigned int power_state;
unsigned int msg_reply; /* Message reply */
};
/* IPC queue */
struct mss_pm_ipc_queue {
unsigned int state;
struct mss_pm_ipc_msg msg;
};
/* IPC channel */
struct mss_pm_ipc_ch {
struct mss_pm_ipc_queue *tx_queue;
struct mss_pm_ipc_queue *rx_queue;
};
/*****************************************************************************
* mv_pm_ipc_init
*
* DESCRIPTION: Initialize PM IPC infrastructure
*****************************************************************************
*/
int mv_pm_ipc_init(unsigned long ipc_control_addr);
/*****************************************************************************
* mv_pm_ipc_msg_rx
*
* DESCRIPTION: Retrieve message from IPC channel
*****************************************************************************
*/
int mv_pm_ipc_msg_rx(unsigned int channel_id, struct mss_pm_ipc_msg *msg);
/*****************************************************************************
* mv_pm_ipc_msg_tx
*
* DESCRIPTION: Send message via IPC channel
*****************************************************************************
*/
int mv_pm_ipc_msg_tx(unsigned int channel_id, unsigned int msg_id,
unsigned int cluster_power_state);
#endif /* MSS_IPC_DRV_H */
@@ -0,0 +1,60 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#ifndef MSS_MEM_H
#define MSS_MEM_H
/* MSS SRAM Memory base */
#define MSS_SRAM_PM_CONTROL_BASE (MVEBU_REGS_BASE + 0x520000)
enum mss_pm_ctrl_handshake {
MSS_UN_INITIALIZED = 0,
MSS_COMPATIBILITY_ERROR = 1,
MSS_ACKNOWLEDGMENT = 2,
HOST_ACKNOWLEDGMENT = 3
};
enum mss_pm_ctrl_rtos_env {
MSS_MULTI_PROCESS_ENV = 0,
MSS_SINGLE_PROCESS_ENV = 1,
MSS_MAX_PROCESS_ENV
};
struct mss_pm_ctrl_block {
/* This field is used to synchronize the Host
* and MSS initialization sequence
* Valid Values
* 0 - Un-Initialized
* 1 - Compatibility Error
* 2 - MSS Acknowledgment
* 3 - Host Acknowledgment
*/
unsigned int handshake;
/*
* This field include Host IPC version. Once received by the MSS
* It will be compared to MSS IPC version and set MSS Acknowledge to
* "compatibility error" in case there is no match
*/
unsigned int ipc_version;
unsigned int ipc_base_address;
unsigned int ipc_state;
/* Following fields defines firmware core architecture */
unsigned int num_of_cores;
unsigned int num_of_clusters;
unsigned int num_of_cores_per_cluster;
/* Following fields define pm trace debug base address */
unsigned int pm_trace_ctrl_base_address;
unsigned int pm_trace_info_base_address;
unsigned int pm_trace_info_core_size;
unsigned int ctrl_blk_size;
};
#endif /* MSS_MEM_H */
@@ -0,0 +1,45 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#ifndef MSS_SCP_BL2_FORMAT_H
#define MSS_SCP_BL2_FORMAT_H
#define MAX_NR_OF_FILES 8
#define FILE_MAGIC 0xddd01ff
#define HEADER_VERSION 0x1
#define MSS_IDRAM_SIZE 0x10000 /* 64KB */
#define MSS_SRAM_SIZE 0x8000 /* 32KB */
/* Types definitions */
typedef struct file_header {
/* Magic specific for concatenated file (used for validation) */
uint32_t magic;
uint32_t nr_of_imgs; /* Number of images concatenated */
} file_header_t;
/* Types definitions */
enum cm3_t {
MSS_AP,
MSS_CP0,
MSS_CP1,
MSS_CP2,
MSS_CP3,
MG_CP0,
MG_CP1,
MG_CP2,
};
typedef struct img_header {
uint32_t type; /* CM3 type, can be one of cm3_t */
uint32_t length; /* Image length */
uint32_t version; /* For sanity checks and future
* extended functionality
*/
} img_header_t;
#endif /* MSS_SCP_BL2_FORMAT_H */
@@ -0,0 +1,368 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <assert.h>
#include <platform_def.h>
#include <arch_helpers.h>
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <mg_conf_cm3/mg_conf_cm3.h>
#include <lib/mmio.h>
#include <plat_pm_trace.h>
#include <mss_scp_bootloader.h>
#include <mss_ipc_drv.h>
#include <mss_mem.h>
#include <mss_defs.h>
#include <mss_scp_bl2_format.h>
#define MSS_DMA_TIMEOUT 1000
#define MSS_EXTERNAL_SPACE 0x50000000
#define MSS_EXTERNAL_ADDR_MASK 0xfffffff
#define MSS_INTERNAL_SPACE 0x40000000
#define MSS_INTERNAL_ADDR_MASK 0x00ffffff
#define DMA_SIZE 128
#define MSS_HANDSHAKE_TIMEOUT 50
static int mss_check_image_ready(volatile struct mss_pm_ctrl_block *mss_pm_crtl)
{
int timeout = MSS_HANDSHAKE_TIMEOUT;
/* Wait for SCP to signal it's ready */
while ((mss_pm_crtl->handshake != MSS_ACKNOWLEDGMENT) &&
(timeout-- > 0))
mdelay(1);
if (mss_pm_crtl->handshake != MSS_ACKNOWLEDGMENT)
return -1;
mss_pm_crtl->handshake = HOST_ACKNOWLEDGMENT;
return 0;
}
static int mss_iram_dma_load(uint32_t src_addr, uint32_t size,
uintptr_t mss_regs)
{
uint32_t i, loop_num, timeout;
/* load image to MSS RAM using DMA */
loop_num = (size / DMA_SIZE) + !!(size % DMA_SIZE);
for (i = 0; i < loop_num; i++) {
/* write source address */
mmio_write_32(MSS_DMA_SRCBR(mss_regs),
src_addr + (i * DMA_SIZE));
/* write destination address */
mmio_write_32(MSS_DMA_DSTBR(mss_regs), (i * DMA_SIZE));
/* make sure DMA data is ready before triggering it */
dsb();
/* set the DMA control register */
mmio_write_32(MSS_DMA_CTRLR(mss_regs),
((MSS_DMA_CTRLR_REQ_SET <<
MSS_DMA_CTRLR_REQ_OFFSET) |
(DMA_SIZE << MSS_DMA_CTRLR_SIZE_OFFSET)));
/* Poll DMA_ACK at MSS_DMACTLR until it is ready */
timeout = MSS_DMA_TIMEOUT;
while (timeout > 0U) {
if (((mmio_read_32(MSS_DMA_CTRLR(mss_regs)) >>
MSS_DMA_CTRLR_ACK_OFFSET) &
MSS_DMA_CTRLR_ACK_MASK)
== MSS_DMA_CTRLR_ACK_READY) {
break;
}
udelay(50);
timeout--;
}
if (timeout == 0) {
ERROR("\nMSS DMA failed (timeout)\n");
return 1;
}
}
return 0;
}
static int mss_image_load(uint32_t src_addr, uint32_t size,
uintptr_t mss_regs, uintptr_t sram)
{
uint32_t chunks = 1; /* !sram case */
uint32_t chunk_num;
int ret;
/* Check if the img size is not bigger than ID-RAM size of MSS CM3 */
if (size > MSS_IDRAM_SIZE) {
ERROR("image is too big to fit into MSS CM3 memory\n");
return 1;
}
/* The CPx MSS DMA cannot access DRAM directly in secure boot mode
* Copy the MSS FW image to MSS SRAM by the CPU first, then run
* MSS DMA for SRAM to IRAM copy
*/
if (sram != 0) {
chunks = size / MSS_SRAM_SIZE + !!(size % MSS_SRAM_SIZE);
}
NOTICE("%s Loading MSS FW from addr. 0x%x Size 0x%x to MSS at 0x%lx\n",
sram == 0 ? "" : "SECURELY", src_addr, size, mss_regs);
for (chunk_num = 0; chunk_num < chunks; chunk_num++) {
size_t chunk_size = size;
uint32_t img_src = MSS_EXTERNAL_SPACE | /* no SRAM */
(src_addr & MSS_EXTERNAL_ADDR_MASK);
if (sram != 0) {
uintptr_t chunk_source =
src_addr + MSS_SRAM_SIZE * chunk_num;
if (chunk_num != (size / MSS_SRAM_SIZE)) {
chunk_size = MSS_SRAM_SIZE;
} else {
chunk_size = size % MSS_SRAM_SIZE;
}
if (chunk_size == 0) {
break;
}
VERBOSE("Chunk %d -> SRAM 0x%lx from 0x%lx SZ 0x%lx\n",
chunk_num, sram, chunk_source, chunk_size);
memcpy((void *)sram, (void *)chunk_source, chunk_size);
dsb();
img_src = MSS_INTERNAL_SPACE |
(sram & MSS_INTERNAL_ADDR_MASK);
}
ret = mss_iram_dma_load(img_src, chunk_size, mss_regs);
if (ret != 0) {
ERROR("MSS FW chunk %d load failed\n", chunk_num);
return ret;
}
}
bl2_plat_configure_mss_windows(mss_regs);
if (sram != 0) {
/* Wipe the MSS SRAM after using it as copy buffer */
memset((void *)sram, 0, MSS_SRAM_SIZE);
NOTICE("CP MSS startup is postponed\n");
/* FW loaded, but CPU startup postponed until final CP setup */
mmio_write_32(sram, MSS_FW_READY_MAGIC);
dsb();
} else {
/* Release M3 from reset */
mmio_write_32(MSS_M3_RSTCR(mss_regs),
(MSS_M3_RSTCR_RST_OFF <<
MSS_M3_RSTCR_RST_OFFSET));
}
NOTICE("Done\n");
return 0;
}
/* Load image to MSS AP and do PM related initialization
* Note that this routine is different than other CM3 loading routines, because
* firmware for AP is dedicated for PM and therefore some additional PM
* initialization is required
*/
static int mss_ap_load_image(uintptr_t single_img,
uint32_t image_size, uint32_t ap_idx)
{
volatile struct mss_pm_ctrl_block *mss_pm_crtl;
int ret;
/* TODO: add PM Control Info from platform */
mss_pm_crtl = (struct mss_pm_ctrl_block *)MSS_SRAM_PM_CONTROL_BASE;
mss_pm_crtl->ipc_version = MV_PM_FW_IPC_VERSION;
mss_pm_crtl->num_of_clusters = PLAT_MARVELL_CLUSTER_COUNT;
mss_pm_crtl->num_of_cores_per_cluster =
PLAT_MARVELL_CLUSTER_CORE_COUNT;
mss_pm_crtl->num_of_cores = PLAT_MARVELL_CLUSTER_COUNT *
PLAT_MARVELL_CLUSTER_CORE_COUNT;
mss_pm_crtl->pm_trace_ctrl_base_address = AP_MSS_ATF_CORE_CTRL_BASE;
mss_pm_crtl->pm_trace_info_base_address = AP_MSS_ATF_CORE_INFO_BASE;
mss_pm_crtl->pm_trace_info_core_size = AP_MSS_ATF_CORE_INFO_SIZE;
VERBOSE("MSS Control Block = 0x%x\n", MSS_SRAM_PM_CONTROL_BASE);
VERBOSE("mss_pm_crtl->ipc_version = 0x%x\n",
mss_pm_crtl->ipc_version);
VERBOSE("mss_pm_crtl->num_of_cores = 0x%x\n",
mss_pm_crtl->num_of_cores);
VERBOSE("mss_pm_crtl->num_of_clusters = 0x%x\n",
mss_pm_crtl->num_of_clusters);
VERBOSE("mss_pm_crtl->num_of_cores_per_cluster = 0x%x\n",
mss_pm_crtl->num_of_cores_per_cluster);
VERBOSE("mss_pm_crtl->pm_trace_ctrl_base_address = 0x%x\n",
mss_pm_crtl->pm_trace_ctrl_base_address);
VERBOSE("mss_pm_crtl->pm_trace_info_base_address = 0x%x\n",
mss_pm_crtl->pm_trace_info_base_address);
VERBOSE("mss_pm_crtl->pm_trace_info_core_size = 0x%x\n",
mss_pm_crtl->pm_trace_info_core_size);
/* TODO: add checksum to image */
VERBOSE("Send info about the SCP_BL2 image to be transferred to SCP\n");
ret = mss_image_load(single_img, image_size,
bl2_plat_get_ap_mss_regs(ap_idx), 0);
if (ret != 0) {
ERROR("SCP Image load failed\n");
return -1;
}
/* check that the image was loaded successfully */
ret = mss_check_image_ready(mss_pm_crtl);
if (ret != 0)
NOTICE("SCP Image doesn't contain PM firmware\n");
return 0;
}
/* Load CM3 image (single_img) to CM3 pointed by cm3_type */
static int load_img_to_cm3(enum cm3_t cm3_type,
uintptr_t single_img, uint32_t image_size)
{
int ret, ap_idx, cp_index;
uint32_t ap_count = bl2_plat_get_ap_count();
switch (cm3_type) {
case MSS_AP:
for (ap_idx = 0; ap_idx < ap_count; ap_idx++) {
NOTICE("Load image to AP%d MSS\n", ap_idx);
ret = mss_ap_load_image(single_img, image_size, ap_idx);
if (ret != 0)
return ret;
}
break;
case MSS_CP0:
case MSS_CP1:
case MSS_CP2:
case MSS_CP3:
/* MSS_AP = 0
* MSS_CP1 = 1
* .
* .
* MSS_CP3 = 4
* Actual CP index is MSS_CPX - 1
*/
cp_index = cm3_type - 1;
for (ap_idx = 0; ap_idx < ap_count; ap_idx++) {
/* Check if we should load this image
* according to number of CPs
*/
if (bl2_plat_get_cp_count(ap_idx) <= cp_index) {
NOTICE("Skipping MSS CP%d related image\n",
cp_index);
break;
}
NOTICE("Load image to CP%d MSS AP%d\n",
cp_index, ap_idx);
ret = mss_image_load(single_img, image_size,
bl2_plat_get_cp_mss_regs(
ap_idx, cp_index),
bl2_plat_get_cp_mss_sram(
ap_idx, cp_index));
if (ret != 0) {
ERROR("SCP Image load failed\n");
return -1;
}
}
break;
case MG_CP0:
case MG_CP1:
case MG_CP2:
cp_index = cm3_type - MG_CP0;
if (bl2_plat_get_cp_count(0) <= cp_index) {
NOTICE("Skipping MG CP%d related image\n",
cp_index);
break;
}
NOTICE("Load image to CP%d MG\n", cp_index);
ret = mg_image_load(single_img, image_size, cp_index);
if (ret != 0) {
ERROR("SCP Image load failed\n");
return -1;
}
break;
default:
ERROR("SCP_BL2 wrong img format (cm3_type=%d)\n", cm3_type);
break;
}
return 0;
}
/* The Armada 8K has 5 service CPUs and Armada 7K has 3. Therefore it was
* required to provide a method for loading firmware to all of the service CPUs.
* To achieve that, the scp_bl2 image in fact is file containing up to 5
* concatenated firmwares and this routine splits concatenated image into single
* images dedicated for appropriate service CPU and then load them.
*/
static int split_and_load_bl2_image(void *image)
{
file_header_t *file_hdr;
img_header_t *img_hdr;
uintptr_t single_img;
int i;
file_hdr = (file_header_t *)image;
if (file_hdr->magic != FILE_MAGIC) {
ERROR("SCP_BL2 wrong img format\n");
return -1;
}
if (file_hdr->nr_of_imgs > MAX_NR_OF_FILES) {
ERROR("SCP_BL2 concatenated image contains too many images\n");
return -1;
}
img_hdr = (img_header_t *)((uintptr_t)image + sizeof(file_header_t));
single_img = (uintptr_t)image + sizeof(file_header_t) +
sizeof(img_header_t) * file_hdr->nr_of_imgs;
NOTICE("SCP_BL2 contains %d concatenated images\n",
file_hdr->nr_of_imgs);
for (i = 0; i < file_hdr->nr_of_imgs; i++) {
/* Before loading make sanity check on header */
if (img_hdr->version != HEADER_VERSION) {
ERROR("Wrong header, img corrupted exiting\n");
return -1;
}
load_img_to_cm3(img_hdr->type, single_img, img_hdr->length);
/* Prepare offsets for next run */
single_img += img_hdr->length;
img_hdr++;
}
return 0;
}
int scp_bootloader_transfer(void *image, unsigned int image_size)
{
#ifdef SCP_BL2_BASE
assert((uintptr_t) image == SCP_BL2_BASE);
#endif
VERBOSE("Concatenated img size %d\n", image_size);
if (image_size == 0) {
ERROR("SCP_BL2 image size can't be 0 (current size = 0x%x)\n",
image_size);
return -1;
}
if (split_and_load_bl2_image(image))
return -1;
return 0;
}
@@ -0,0 +1,20 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#ifndef MSS_SCP_BOOTLOADER_H
#define MSS_SCP_BOOTLOADER_H
int scp_bootloader_transfer(void *image, unsigned int image_size);
uintptr_t bl2_plat_get_cp_mss_regs(int ap_idx, int cp_idx);
uintptr_t bl2_plat_get_cp_mss_sram(int ap_idx, int cp_idx);
uintptr_t bl2_plat_get_ap_mss_regs(int ap_idx);
uint32_t bl2_plat_get_cp_count(int ap_idx);
uint32_t bl2_plat_get_ap_count(void);
void bl2_plat_configure_mss_windows(uintptr_t mss_regs);
int bl2_plat_mss_check_image_ready(void);
#endif /* MSS_SCP_BOOTLOADER_H */
@@ -0,0 +1,34 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <arch_helpers.h>
#include <drivers/delay_timer.h>
#include <mvebu_def.h>
#define SYS_COUNTER_FREQ_IN_MHZ (COUNTER_FREQUENCY/1000000)
static uint32_t plat_get_timer_value(void)
{
/*
* Generic delay timer implementation expects the timer to be a down
* counter. We apply bitwise NOT operator to the tick values returned
* by read_cntpct_el0() to simulate the down counter.
*/
return (uint32_t)(~read_cntpct_el0());
}
static const timer_ops_t plat_timer_ops = {
.get_timer_value = plat_get_timer_value,
.clk_mult = 1,
.clk_div = SYS_COUNTER_FREQ_IN_MHZ
};
void plat_delay_timer_init(void)
{
timer_init(&plat_timer_ops);
}