Commit 486f868b authored by Konstantin Porotchkin's avatar Konstantin Porotchkin
Browse files

plat: marvell: Add common ARMADA platform components



Add common Marvell ARMADA platform components.
This patch also includes common components for Marvell
ARMADA 8K platforms.

Change-Id: I42192fdc6525a42e46b3ac2ad63c83db9bcbfeaf
Signed-off-by: default avatarHanna Hawa <hannah@marvell.com>
Signed-off-by: default avatarKonstantin Porotchkin <kostap@marvell.com>
parent 939e0856
/*
* 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);
}
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <ap_setup.h>
#include <cache_llc.h>
#include <debug.h>
#include <marvell_plat_priv.h>
#include <runtime_svc.h>
#include <smcc.h>
#include "comphy/phy-comphy-cp110.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 MAX_LANE_NR 6
#define MVEBU_COMPHY_OFFSET 0x441000
#define MVEBU_SD_OFFSET 0x120000
/* 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)
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;
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)) {
/* some systems passes SD phys address instead of COMPHY phys
* address - convert it
*/
if (x1 & MVEBU_SD_OFFSET)
x1 = (x1 & ~0xffffff) + MVEBU_COMPHY_OFFSET;
if ((x1 & 0xffffff) != MVEBU_COMPHY_OFFSET) {
ERROR("%s: Wrong smc (0x%x) address: %lx\n",
__func__, smc_fid, x1);
SMC_RET1(handle, SMC_UNK);
}
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);
SMC_RET1(handle, ret);
case MV_SIP_COMPHY_POWER_OFF:
/* x1: comphy_base, x2: comphy_index */
ret = mvebu_cp110_comphy_power_off(x1, x2);
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:
/* x1: ap_base_addr */
ret = mvebu_get_dram_size(x1);
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);
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
);
#
# Copyright (C) 2018 Marvell International Ltd.
#
# SPDX-License-Identifier: BSD-3-Clause
# https://spdx.org/licenses
#
PLAT_MARVELL := plat/marvell
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) \
$(PLAT_FAMILY_BASE)/$(PLAT)/board/marvell_plat_config.c
BL31_SOURCES += $(MSS_SOURCE)/mss_ipc_drv.c
PLAT_INCLUDES += -I$(MSS_SOURCE)
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <plat_marvell.h>
#include <debug.h>
#include <string.h>
#include <mss_ipc_drv.h>
#include <mmio.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;
}
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#ifndef __PM_IPC_DRV_H
#define __PM_IPC_DRV_H
#include <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 /* __PM_IPC_DRV_H */
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#ifndef __MSS_PM_MEM_H
#define __MSS_PM_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_PM_MEM_H */
/*
* 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 5
#define FILE_MAGIC 0xddd01ff
#define HEADER_VERSION 0x1
#define MSS_IDRAM_SIZE 0x10000 /* 64KB */
#define MG_SRAM_SIZE 0x20000 /* 128KB */
/* 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,
};
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 */
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <assert.h>
#include <debug.h>
#include <mmio.h>
#include <arch_helpers.h> /* for cache maintanance operations */
#include <platform_def.h>
#include <delay_timer.h>
#include <plat_pm_trace.h>
#include <mss_scp_bootloader.h>
#include <mss_ipc_drv.h>
#include <mss_mem.h>
#include <mss_scp_bl2_format.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_DMA_TIMEOUT 1000
#define MSS_EXTERNAL_SPACE 0x50000000
#define MSS_EXTERNAL_ADDR_MASK 0xfffffff
#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_image_load(uint32_t src_addr, uint32_t size, uintptr_t mss_regs)
{
uint32_t i, loop_num, timeout;
/* 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;
}
NOTICE("Loading MSS image from addr. 0x%x Size 0x%x to MSS at 0x%lx\n",
src_addr, size, mss_regs);
/* load image to MSS RAM using DMA */
loop_num = (size / DMA_SIZE) + (((size & (DMA_SIZE - 1)) == 0) ? 0 : 1);
for (i = 0; i < loop_num; i++) {
/* write destination and source addresses */
mmio_write_32(MSS_DMA_SRCBR(mss_regs),
MSS_EXTERNAL_SPACE |
((src_addr & MSS_EXTERNAL_ADDR_MASK) +
(i * DMA_SIZE)));
mmio_write_32(MSS_DMA_DSTBR(mss_regs), (i * DMA_SIZE));
dsb(); /* make sure DMA data is ready before triggering it */
/* 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) {
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("\nDMA failed to load MSS image\n");
return 1;
}
}
bl2_plat_configure_mss_windows(mss_regs);
/* 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));
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));
if (ret != 0) {
ERROR("SCP Image load failed\n");
return -1;
}
}
break;
case MG_CP0:
/* TODO: */
NOTICE("Load image to CP0 MG not supported\n");
break;
case MG_CP1:
/* TODO: */
NOTICE("Load image to CP1 MG not supported\n");
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 to 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;
}
/*
* 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_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__ */
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <arch_helpers.h>
#include <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);
}
# Copyright (C) 2018 Marvell International Ltd.
#
# SPDX-License-Identifier: BSD-3-Clause
# https://spdx.org/licenses
# Marvell images
BOOT_IMAGE := boot-image.bin
BOOT_ENC_IMAGE := boot-image-enc.bin
FLASH_IMAGE := flash-image.bin
# Make non-trusted image by default
MARVELL_SECURE_BOOT := 0
$(eval $(call add_define,MARVELL_SECURE_BOOT))
# Enable compilation for Palladium emulation platform
PALLADIUM := 0
$(eval $(call add_define,PALLADIUM))
ifeq (${MARVELL_SECURE_BOOT},1)
DOIMAGE_SEC_FLAGS := -c $(DOIMAGE_SEC)
DOIMAGE_LIBS_CHECK = \
if ! [ -d "/usr/include/mbedtls" ]; then \
echo "****************************************" >&2; \
echo "Missing mbedTLS installation! " >&2; \
echo "Please download it from \"tls.mbed.org\"" >&2; \
echo "Alternatively on Debian/Ubuntu system install" >&2; \
echo "\"libmbedtls-dev\" package" >&2; \
echo "Make sure to use version 2.1.0 or later" >&2; \
echo "****************************************" >&2; \
exit 1; \
else if ! [ -f "/usr/include/libconfig.h" ]; then \
echo "********************************************************" >&2; \
echo "Missing Libconfig installation!" >&2; \
echo "Please download it from \"www.hyperrealm.com/libconfig/\"" >&2; \
echo "Alternatively on Debian/Ubuntu system install packages" >&2; \
echo "\"libconfig8\" and \"libconfig8-dev\"" >&2; \
echo "********************************************************" >&2; \
exit 1; \
fi \
fi
else #MARVELL_SECURE_BOOT
DOIMAGE_LIBS_CHECK =
DOIMAGE_SEC_FLAGS =
endif #MARVELL_SECURE_BOOT
mrvl_clean:
@echo " Doimage CLEAN"
${Q}${MAKE} PLAT=${PLAT} --no-print-directory -C ${DOIMAGEPATH} clean
${DOIMAGETOOL}: mrvl_clean
${Q}${MAKE} --no-print-directory -C ${DOIMAGEPATH} WTMI_IMG=$(WTMI_IMG)
SUBVERSION = devel-18.08.0
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment