GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)
This commit is contained in:
+168
@@ -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)
|
||||
+137
@@ -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;
|
||||
}
|
||||
|
||||
+259
@@ -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
|
||||
+105
@@ -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
|
||||
}
|
||||
+158
@@ -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);
|
||||
}
|
||||
|
||||
+237
@@ -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;
|
||||
}
|
||||
+52
@@ -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()));
|
||||
}
|
||||
+99
@@ -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)
|
||||
+77
@@ -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);
|
||||
}
|
||||
+112
@@ -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;
|
||||
}
|
||||
+148
@@ -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();
|
||||
}
|
||||
+210
@@ -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);
|
||||
}
|
||||
+36
@@ -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();
|
||||
}
|
||||
+227
@@ -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;
|
||||
}
|
||||
+60
@@ -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;
|
||||
}
|
||||
+84
@@ -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);
|
||||
}
|
||||
+188
@@ -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
|
||||
);
|
||||
+20
@@ -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)
|
||||
+113
@@ -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;
|
||||
}
|
||||
+120
@@ -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 */
|
||||
+60
@@ -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 */
|
||||
+45
@@ -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 */
|
||||
+368
@@ -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;
|
||||
}
|
||||
+20
@@ -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 */
|
||||
+34
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user