diff options
Diffstat (limited to '')
-rw-r--r-- | plat/marvell/armada/a8k/common/mss/mss_a8k.mk | 22 | ||||
-rw-r--r-- | plat/marvell/armada/a8k/common/mss/mss_bl2_setup.c | 165 | ||||
-rw-r--r-- | plat/marvell/armada/a8k/common/mss/mss_bl31_setup.c | 37 | ||||
-rw-r--r-- | plat/marvell/armada/a8k/common/mss/mss_defs.h | 33 | ||||
-rw-r--r-- | plat/marvell/armada/a8k/common/mss/mss_pm_ipc.c | 85 | ||||
-rw-r--r-- | plat/marvell/armada/a8k/common/mss/mss_pm_ipc.h | 35 |
6 files changed, 377 insertions, 0 deletions
diff --git a/plat/marvell/armada/a8k/common/mss/mss_a8k.mk b/plat/marvell/armada/a8k/common/mss/mss_a8k.mk new file mode 100644 index 0000000..315fc87 --- /dev/null +++ b/plat/marvell/armada/a8k/common/mss/mss_a8k.mk @@ -0,0 +1,22 @@ +# +# Copyright (C) 2018 Marvell International Ltd. +# +# SPDX-License-Identifier: BSD-3-Clause +# https://spdx.org/licenses +# + +PLAT_MARVELL := plat/marvell/armada +A8K_MSS_SOURCE := $(PLAT_MARVELL)/a8k/common/mss + +BL2_SOURCES += $(A8K_MSS_SOURCE)/mss_bl2_setup.c \ + $(MARVELL_MOCHI_DRV) + +BL31_SOURCES += $(A8K_MSS_SOURCE)/mss_pm_ipc.c \ + $(A8K_MSS_SOURCE)/mss_bl31_setup.c + +PLAT_INCLUDES += -I$(A8K_MSS_SOURCE) + +ifneq (${SCP_BL2},) +# This define is used to inidcate the SCP image is present +$(eval $(call add_define,SCP_IMAGE)) +endif 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)); +} diff --git a/plat/marvell/armada/a8k/common/mss/mss_bl31_setup.c b/plat/marvell/armada/a8k/common/mss/mss_bl31_setup.c new file mode 100644 index 0000000..52a8929 --- /dev/null +++ b/plat/marvell/armada/a8k/common/mss/mss_bl31_setup.c @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2021 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 <lib/mmio.h> + +#include <armada_common.h> + +#include "mss_defs.h" + +void mss_start_cp_cm3(int cp) +{ + uint32_t magic; + uintptr_t sram = MVEBU_CP_REGS_BASE(cp) + MSS_CP_SRAM_OFFSET; + uintptr_t regs = MVEBU_CP_REGS_BASE(cp) + MSS_CP_REGS_OFFSET; + + magic = mmio_read_32(sram); + + /* Make sure the FW was loaded */ + if (magic != MSS_FW_READY_MAGIC) { + return; + } + + NOTICE("Starting CP%d MSS CPU\n", cp); + /* remove the magic */ + mmio_write_32(sram, 0); + /* Release M3 from reset */ + mmio_write_32(MSS_M3_RSTCR(regs), + (MSS_M3_RSTCR_RST_OFF << MSS_M3_RSTCR_RST_OFFSET)); +} diff --git a/plat/marvell/armada/a8k/common/mss/mss_defs.h b/plat/marvell/armada/a8k/common/mss/mss_defs.h new file mode 100644 index 0000000..6956461 --- /dev/null +++ b/plat/marvell/armada/a8k/common/mss/mss_defs.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2021 Marvell International Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + * https://spdx.org/licenses + */ + +#ifndef MSS_DEFS_H +#define MSS_DEFS_H + +#define MSS_DMA_SRCBR(base) (base + 0xC0) +#define MSS_DMA_DSTBR(base) (base + 0xC4) +#define MSS_DMA_CTRLR(base) (base + 0xC8) +#define MSS_M3_RSTCR(base) (base + 0xFC) + +#define MSS_DMA_CTRLR_SIZE_OFFSET (0) +#define MSS_DMA_CTRLR_REQ_OFFSET (15) +#define MSS_DMA_CTRLR_REQ_SET (1) +#define MSS_DMA_CTRLR_ACK_OFFSET (12) +#define MSS_DMA_CTRLR_ACK_MASK (0x1) +#define MSS_DMA_CTRLR_ACK_READY (1) +#define MSS_M3_RSTCR_RST_OFFSET (0) +#define MSS_M3_RSTCR_RST_OFF (1) + +#define MSS_FW_READY_MAGIC 0x46575144 /* FWRD */ + +#define MSS_AP_REGS_OFFSET 0x00580000 +#define MSS_CP_SRAM_OFFSET 0x00220000 +#define MSS_CP_REGS_OFFSET 0x00280000 + +void mss_start_cp_cm3(int cp); + +#endif /* MSS_DEFS_H */ diff --git a/plat/marvell/armada/a8k/common/mss/mss_pm_ipc.c b/plat/marvell/armada/a8k/common/mss/mss_pm_ipc.c new file mode 100644 index 0000000..a070583 --- /dev/null +++ b/plat/marvell/armada/a8k/common/mss/mss_pm_ipc.c @@ -0,0 +1,85 @@ +/* + * 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/psci/psci.h> +#include <lib/mmio.h> + +#include <mss_pm_ipc.h> + +/* + * SISR is 32 bit interrupt register representing 32 interrupts + * + * +======+=============+=============+ + * + Bits + 31 + 30 - 00 + + * +======+=============+=============+ + * + Desc + MSS Msg Int + Reserved + + * +======+=============+=============+ + */ +#define MSS_SISR (MVEBU_REGS_BASE + 0x5800D0) +#define MSS_SISTR (MVEBU_REGS_BASE + 0x5800D8) + +#define MSS_MSG_INT_MASK (0x80000000) +#define MSS_TIMER_BASE (MVEBU_REGS_BASE_MASK + 0x580110) +#define MSS_TRIGGER_TIMEOUT (2000) + +/***************************************************************************** + * mss_pm_ipc_msg_send + * + * DESCRIPTION: create and transmit IPC message + ***************************************************************************** + */ +int mss_pm_ipc_msg_send(unsigned int channel_id, unsigned int msg_id, + const psci_power_state_t *target_state) +{ + /* Transmit IPC message */ +#ifndef DISABLE_CLUSTER_LEVEL + mv_pm_ipc_msg_tx(channel_id, msg_id, + (unsigned int)target_state->pwr_domain_state[ + MPIDR_AFFLVL1]); +#else + mv_pm_ipc_msg_tx(channel_id, msg_id, 0); +#endif + + return 0; +} + +/***************************************************************************** + * mss_pm_ipc_msg_trigger + * + * DESCRIPTION: Trigger IPC message interrupt to MSS + ***************************************************************************** + */ +int mss_pm_ipc_msg_trigger(void) +{ + unsigned int timeout; + unsigned int t_end; + unsigned int t_start = mmio_read_32(MSS_TIMER_BASE); + + mmio_write_32(MSS_SISR, MSS_MSG_INT_MASK); + + do { + /* wait while SCP process incoming interrupt */ + if (mmio_read_32(MSS_SISTR) != MSS_MSG_INT_MASK) + break; + + /* check timeout */ + t_end = mmio_read_32(MSS_TIMER_BASE); + + timeout = ((t_start > t_end) ? + (t_start - t_end) : (t_end - t_start)); + if (timeout > MSS_TRIGGER_TIMEOUT) { + ERROR("PM MSG Trigger Timeout\n"); + break; + } + + } while (1); + + return 0; +} diff --git a/plat/marvell/armada/a8k/common/mss/mss_pm_ipc.h b/plat/marvell/armada/a8k/common/mss/mss_pm_ipc.h new file mode 100644 index 0000000..1dfa9fa --- /dev/null +++ b/plat/marvell/armada/a8k/common/mss/mss_pm_ipc.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2018 Marvell International Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + * https://spdx.org/licenses + */ + +#ifndef MSS_PM_IPC_H +#define MSS_PM_IPC_H + +#include <mss_ipc_drv.h> + +/* Currently MSS does not support Cluster level Power Down */ +#define DISABLE_CLUSTER_LEVEL + + +/***************************************************************************** + * mss_pm_ipc_msg_send + * + * DESCRIPTION: create and transmit IPC message + ***************************************************************************** + */ +int mss_pm_ipc_msg_send(unsigned int channel_id, unsigned int msg_id, + const psci_power_state_t *target_state); + +/***************************************************************************** + * mss_pm_ipc_msg_trigger + * + * DESCRIPTION: Trigger IPC message interrupt to MSS + ***************************************************************************** + */ +int mss_pm_ipc_msg_trigger(void); + + +#endif /* MSS_PM_IPC_H */ |