diff options
Diffstat (limited to 'plat/marvell/armada/a8k/common/mss/mss_bl2_setup.c')
-rw-r--r-- | plat/marvell/armada/a8k/common/mss/mss_bl2_setup.c | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/plat/marvell/armada/a8k/common/mss/mss_bl2_setup.c b/plat/marvell/armada/a8k/common/mss/mss_bl2_setup.c new file mode 100644 index 0000000..dee2d5b --- /dev/null +++ b/plat/marvell/armada/a8k/common/mss/mss_bl2_setup.c @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2018 Marvell International Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + * https://spdx.org/licenses + */ + +#include <platform_def.h> + +#include <common/bl_common.h> +#include <common/debug.h> +#include <drivers/marvell/ccu.h> +#include <drivers/marvell/mochi/ap_setup.h> +#include <drivers/marvell/mochi/cp110_setup.h> +#include <lib/mmio.h> + +#include <armada_common.h> +#include <marvell_plat_priv.h> /* timer functionality */ +#include "mss_defs.h" +#include "mss_scp_bootloader.h" + +/* MSS windows configuration */ +#define MSS_AEBR(base) (base + 0x160) +#define MSS_AIBR(base) (base + 0x164) +#define MSS_AEBR_MASK 0xFFF +#define MSS_AIBR_MASK 0xFFF + +#define MSS_EXTERNAL_SPACE 0x50000000 +#define MSS_EXTERNAL_ACCESS_BIT 28 +#define MSS_EXTERNAL_ADDR_MASK 0xfffffff +#define MSS_INTERNAL_ACCESS_BIT 28 + +struct addr_map_win ccu_mem_map[] = { + {MVEBU_CP_REGS_BASE(0), 0x4000000, IO_0_TID} +}; + +/* Since the scp_bl2 image can contain firmware for cp1 and cp0 coprocessors, + * the access to cp0 and cp1 need to be provided. More precisely it is + * required to: + * - get the information about device id which is stored in CP0 registers + * (to distinguish between cases where we have cp0 and cp1 or standalone cp0) + * - get the access to cp which is needed for loading fw for cp0/cp1 + * coprocessors + * This function configures ccu windows accordingly. + * + * Note: there is no need to restore previous ccu configuration, since in next + * phase (BL31) the init_ccu will be called (via apn806_init/ + * bl31_plat_arch_setu) and therefore the ccu configuration will be overwritten. + */ +static int bl2_plat_mmap_init(void) +{ + int cfg_num, win_id, cfg_idx, cp; + + cfg_num = ARRAY_SIZE(ccu_mem_map); + + /* CCU window-0 should not be counted - it's already used */ + if (cfg_num > (MVEBU_CCU_MAX_WINS - 1)) { + ERROR("BL2: %s: trying to open too many windows\n", __func__); + return -1; + } + + /* Enable required CCU windows + * Do not touch CCU window 0, + * it's used for the internal registers access + */ + for (cfg_idx = 0, win_id = 1; + (win_id < MVEBU_CCU_MAX_WINS) && (cfg_idx < cfg_num); win_id++) { + /* Skip already enabled CCU windows */ + if (ccu_is_win_enabled(MVEBU_AP0, win_id)) + continue; + /* Enable required CCU windows */ + ccu_win_check(&ccu_mem_map[cfg_idx]); + ccu_enable_win(MVEBU_AP0, &ccu_mem_map[cfg_idx], win_id); + cfg_idx++; + } + + /* Config address for each cp other than cp0 */ + for (cp = 1; cp < CP_COUNT; cp++) + update_cp110_default_win(cp); + + /* There is need to configure IO_WIN windows again to overwrite + * temporary configuration done during update_cp110_default_win + */ + init_io_win(MVEBU_AP0); + + /* Open AMB bridge required for MG access */ + for (cp = 0; cp < CP_COUNT; cp++) + cp110_amb_init(MVEBU_CP_REGS_BASE(cp)); + + return 0; +} + +/***************************************************************************** + * Transfer SCP_BL2 from Trusted RAM using the SCP Download protocol. + * Return 0 on success, -1 otherwise. + ***************************************************************************** + */ +int bl2_plat_handle_scp_bl2(image_info_t *scp_bl2_image_info) +{ + int ret; + + INFO("BL2: Initiating SCP_BL2 transfer to SCP\n"); + + /* initialize time (for delay functionality) */ + plat_delay_timer_init(); + + ret = bl2_plat_mmap_init(); + if (ret != 0) + return ret; + + ret = scp_bootloader_transfer((void *)scp_bl2_image_info->image_base, + scp_bl2_image_info->image_size); + + if (ret == 0) + INFO("BL2: SCP_BL2 transferred to SCP\n"); + else + ERROR("BL2: SCP_BL2 transfer failure\n"); + + return ret; +} + +uintptr_t bl2_plat_get_cp_mss_regs(int ap_idx, int cp_idx) +{ + return MVEBU_CP_REGS_BASE(cp_idx) + MSS_CP_REGS_OFFSET; +} + +uintptr_t bl2_plat_get_cp_mss_sram(int ap_idx, int cp_idx) +{ + return MVEBU_CP_REGS_BASE(cp_idx) + MSS_CP_SRAM_OFFSET; +} + +uintptr_t bl2_plat_get_ap_mss_regs(int ap_idx) +{ + return MVEBU_REGS_BASE + MSS_AP_REGS_OFFSET; +} + +uint32_t bl2_plat_get_cp_count(int ap_idx) +{ + uint32_t revision = cp110_device_id_get(MVEBU_CP_REGS_BASE(0)); + /* A8040: two CPs. + * A7040: one CP. + */ + if (revision == MVEBU_80X0_DEV_ID || + revision == MVEBU_80X0_CP115_DEV_ID) + return 2; + else if (revision == MVEBU_CN9130_DEV_ID) + return CP_COUNT; + else + return 1; +} + +uint32_t bl2_plat_get_ap_count(void) +{ + /* A8040 and A7040 have only one AP */ + return 1; +} + +void bl2_plat_configure_mss_windows(uintptr_t mss_regs) +{ + /* set AXI External and Internal Address Bus extension */ + mmio_write_32(MSS_AEBR(mss_regs), + ((0x0 >> MSS_EXTERNAL_ACCESS_BIT) & MSS_AEBR_MASK)); + mmio_write_32(MSS_AIBR(mss_regs), + ((mss_regs >> MSS_INTERNAL_ACCESS_BIT) & MSS_AIBR_MASK)); +} |