plat/marvell/armada/common/mss: use MSS SRAM in secure mode
The CP MSS IRAM is only accessible by CM3 CPU and MSS DMA.
In secure boot mode the MSS DMA is unable to directly load
the MSS FW image from DRAM to IRAM.
This patch adds support for using the MSS SRAM as intermediate
storage. The MSS FW image is loaded by application CPU into the
MSS SRAM first, then transferred to MSS IRAM by MSS DMA.
Such change allows the CP MSS image load in secure mode.
Change-Id: Iee7a51d157743a0bdf8acb668ee3d599f760a712
Signed-off-by: Konstantin Porotchkin <kostap@marvell.com>
Reviewed-by: Stefan Chulski <stefanc@marvell.com>
Reviewed-by: Grzegorz Jaszczyk <jaszczyk@marvell.com>
diff --git a/plat/marvell/armada/a8k/common/mss/mss_bl2_setup.c b/plat/marvell/armada/a8k/common/mss/mss_bl2_setup.c
index b919cb3..71fa2b8 100644
--- a/plat/marvell/armada/a8k/common/mss/mss_bl2_setup.c
+++ b/plat/marvell/armada/a8k/common/mss/mss_bl2_setup.c
@@ -30,6 +30,10 @@
#define MSS_EXTERNAL_ADDR_MASK 0xfffffff
#define MSS_INTERNAL_ACCESS_BIT 28
+#define MSS_AP_REGS_OFFSET 0x580000
+#define MSS_CP_SRAM_OFFSET 0x220000
+#define MSS_CP_REGS_OFFSET 0x280000
+
struct addr_map_win ccu_mem_map[] = {
{MVEBU_CP_REGS_BASE(0), 0x4000000, IO_0_TID}
};
@@ -121,12 +125,21 @@
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) + 0x280000;
+ if (is_secure()) {
+ return MVEBU_CP_REGS_BASE(cp_idx) + MSS_CP_SRAM_OFFSET;
+ }
+
+ return 0; /* SRAM will not be used */
}
uintptr_t bl2_plat_get_ap_mss_regs(int ap_idx)
{
- return MVEBU_REGS_BASE + 0x580000;
+ return MVEBU_REGS_BASE + MSS_AP_REGS_OFFSET;
}
uint32_t bl2_plat_get_cp_count(int ap_idx)
diff --git a/plat/marvell/armada/common/mss/mss_scp_bl2_format.h b/plat/marvell/armada/common/mss/mss_scp_bl2_format.h
index 74dddc6..90913b0 100644
--- a/plat/marvell/armada/common/mss/mss_scp_bl2_format.h
+++ b/plat/marvell/armada/common/mss/mss_scp_bl2_format.h
@@ -13,6 +13,7 @@
#define HEADER_VERSION 0x1
#define MSS_IDRAM_SIZE 0x10000 /* 64KB */
+#define MSS_SRAM_SIZE 0x8000 /* 32KB */
/* Types definitions */
typedef struct file_header {
diff --git a/plat/marvell/armada/common/mss/mss_scp_bootloader.c b/plat/marvell/armada/common/mss/mss_scp_bootloader.c
index adf570e..a16f4c7 100644
--- a/plat/marvell/armada/common/mss/mss_scp_bootloader.c
+++ b/plat/marvell/armada/common/mss/mss_scp_bootloader.c
@@ -38,6 +38,8 @@
#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
@@ -60,60 +62,108 @@
return 0;
}
-static int mss_image_load(uint32_t src_addr, uint32_t size, uintptr_t mss_regs)
+static int mss_iram_dma_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);
-
+ loop_num = (size / DMA_SIZE) + !!(size % DMA_SIZE);
for (i = 0; i < loop_num; i++) {
- /* write destination and source addresses */
+ /* write source address */
mmio_write_32(MSS_DMA_SRCBR(mss_regs),
- MSS_EXTERNAL_SPACE |
- ((src_addr & MSS_EXTERNAL_ADDR_MASK) +
- (i * DMA_SIZE)));
+ src_addr + (i * DMA_SIZE));
+ /* write destination address */
mmio_write_32(MSS_DMA_DSTBR(mss_regs), (i * DMA_SIZE));
-
- dsb(); /* make sure DMA data is ready before triggering it */
-
+ /* 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) |
+ 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) {
+ 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) {
+ (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");
+ 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);
/* Release M3 from reset */
- mmio_write_32(MSS_M3_RSTCR(mss_regs), (MSS_M3_RSTCR_RST_OFF <<
- MSS_M3_RSTCR_RST_OFFSET));
+ mmio_write_32(MSS_M3_RSTCR(mss_regs),
+ (MSS_M3_RSTCR_RST_OFF << MSS_M3_RSTCR_RST_OFFSET));
NOTICE("Done\n");
@@ -162,7 +212,7 @@
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));
+ bl2_plat_get_ap_mss_regs(ap_idx), 0);
if (ret != 0) {
ERROR("SCP Image load failed\n");
return -1;
@@ -218,6 +268,8 @@
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");
diff --git a/plat/marvell/armada/common/mss/mss_scp_bootloader.h b/plat/marvell/armada/common/mss/mss_scp_bootloader.h
index 4950d24..d65354a 100644
--- a/plat/marvell/armada/common/mss/mss_scp_bootloader.h
+++ b/plat/marvell/armada/common/mss/mss_scp_bootloader.h
@@ -10,6 +10,7 @@
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);