1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (C) 2018 Marvell International Ltd. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu * https://spdx.org/licenses 6*91f16700Schasinglulu */ 7*91f16700Schasinglulu 8*91f16700Schasinglulu #include <assert.h> 9*91f16700Schasinglulu 10*91f16700Schasinglulu #include <platform_def.h> 11*91f16700Schasinglulu 12*91f16700Schasinglulu #include <arch_helpers.h> 13*91f16700Schasinglulu #include <common/debug.h> 14*91f16700Schasinglulu #include <drivers/delay_timer.h> 15*91f16700Schasinglulu #include <mg_conf_cm3/mg_conf_cm3.h> 16*91f16700Schasinglulu #include <lib/mmio.h> 17*91f16700Schasinglulu 18*91f16700Schasinglulu #include <plat_pm_trace.h> 19*91f16700Schasinglulu #include <mss_scp_bootloader.h> 20*91f16700Schasinglulu #include <mss_ipc_drv.h> 21*91f16700Schasinglulu #include <mss_mem.h> 22*91f16700Schasinglulu #include <mss_defs.h> 23*91f16700Schasinglulu #include <mss_scp_bl2_format.h> 24*91f16700Schasinglulu 25*91f16700Schasinglulu #define MSS_DMA_TIMEOUT 1000 26*91f16700Schasinglulu #define MSS_EXTERNAL_SPACE 0x50000000 27*91f16700Schasinglulu #define MSS_EXTERNAL_ADDR_MASK 0xfffffff 28*91f16700Schasinglulu #define MSS_INTERNAL_SPACE 0x40000000 29*91f16700Schasinglulu #define MSS_INTERNAL_ADDR_MASK 0x00ffffff 30*91f16700Schasinglulu 31*91f16700Schasinglulu #define DMA_SIZE 128 32*91f16700Schasinglulu 33*91f16700Schasinglulu #define MSS_HANDSHAKE_TIMEOUT 50 34*91f16700Schasinglulu 35*91f16700Schasinglulu static int mss_check_image_ready(volatile struct mss_pm_ctrl_block *mss_pm_crtl) 36*91f16700Schasinglulu { 37*91f16700Schasinglulu int timeout = MSS_HANDSHAKE_TIMEOUT; 38*91f16700Schasinglulu 39*91f16700Schasinglulu /* Wait for SCP to signal it's ready */ 40*91f16700Schasinglulu while ((mss_pm_crtl->handshake != MSS_ACKNOWLEDGMENT) && 41*91f16700Schasinglulu (timeout-- > 0)) 42*91f16700Schasinglulu mdelay(1); 43*91f16700Schasinglulu 44*91f16700Schasinglulu if (mss_pm_crtl->handshake != MSS_ACKNOWLEDGMENT) 45*91f16700Schasinglulu return -1; 46*91f16700Schasinglulu 47*91f16700Schasinglulu mss_pm_crtl->handshake = HOST_ACKNOWLEDGMENT; 48*91f16700Schasinglulu 49*91f16700Schasinglulu return 0; 50*91f16700Schasinglulu } 51*91f16700Schasinglulu 52*91f16700Schasinglulu static int mss_iram_dma_load(uint32_t src_addr, uint32_t size, 53*91f16700Schasinglulu uintptr_t mss_regs) 54*91f16700Schasinglulu { 55*91f16700Schasinglulu uint32_t i, loop_num, timeout; 56*91f16700Schasinglulu 57*91f16700Schasinglulu /* load image to MSS RAM using DMA */ 58*91f16700Schasinglulu loop_num = (size / DMA_SIZE) + !!(size % DMA_SIZE); 59*91f16700Schasinglulu for (i = 0; i < loop_num; i++) { 60*91f16700Schasinglulu /* write source address */ 61*91f16700Schasinglulu mmio_write_32(MSS_DMA_SRCBR(mss_regs), 62*91f16700Schasinglulu src_addr + (i * DMA_SIZE)); 63*91f16700Schasinglulu /* write destination address */ 64*91f16700Schasinglulu mmio_write_32(MSS_DMA_DSTBR(mss_regs), (i * DMA_SIZE)); 65*91f16700Schasinglulu /* make sure DMA data is ready before triggering it */ 66*91f16700Schasinglulu dsb(); 67*91f16700Schasinglulu /* set the DMA control register */ 68*91f16700Schasinglulu mmio_write_32(MSS_DMA_CTRLR(mss_regs), 69*91f16700Schasinglulu ((MSS_DMA_CTRLR_REQ_SET << 70*91f16700Schasinglulu MSS_DMA_CTRLR_REQ_OFFSET) | 71*91f16700Schasinglulu (DMA_SIZE << MSS_DMA_CTRLR_SIZE_OFFSET))); 72*91f16700Schasinglulu /* Poll DMA_ACK at MSS_DMACTLR until it is ready */ 73*91f16700Schasinglulu timeout = MSS_DMA_TIMEOUT; 74*91f16700Schasinglulu while (timeout > 0U) { 75*91f16700Schasinglulu if (((mmio_read_32(MSS_DMA_CTRLR(mss_regs)) >> 76*91f16700Schasinglulu MSS_DMA_CTRLR_ACK_OFFSET) & 77*91f16700Schasinglulu MSS_DMA_CTRLR_ACK_MASK) 78*91f16700Schasinglulu == MSS_DMA_CTRLR_ACK_READY) { 79*91f16700Schasinglulu break; 80*91f16700Schasinglulu } 81*91f16700Schasinglulu udelay(50); 82*91f16700Schasinglulu timeout--; 83*91f16700Schasinglulu } 84*91f16700Schasinglulu if (timeout == 0) { 85*91f16700Schasinglulu ERROR("\nMSS DMA failed (timeout)\n"); 86*91f16700Schasinglulu return 1; 87*91f16700Schasinglulu } 88*91f16700Schasinglulu } 89*91f16700Schasinglulu return 0; 90*91f16700Schasinglulu } 91*91f16700Schasinglulu 92*91f16700Schasinglulu static int mss_image_load(uint32_t src_addr, uint32_t size, 93*91f16700Schasinglulu uintptr_t mss_regs, uintptr_t sram) 94*91f16700Schasinglulu { 95*91f16700Schasinglulu uint32_t chunks = 1; /* !sram case */ 96*91f16700Schasinglulu uint32_t chunk_num; 97*91f16700Schasinglulu int ret; 98*91f16700Schasinglulu 99*91f16700Schasinglulu /* Check if the img size is not bigger than ID-RAM size of MSS CM3 */ 100*91f16700Schasinglulu if (size > MSS_IDRAM_SIZE) { 101*91f16700Schasinglulu ERROR("image is too big to fit into MSS CM3 memory\n"); 102*91f16700Schasinglulu return 1; 103*91f16700Schasinglulu } 104*91f16700Schasinglulu 105*91f16700Schasinglulu /* The CPx MSS DMA cannot access DRAM directly in secure boot mode 106*91f16700Schasinglulu * Copy the MSS FW image to MSS SRAM by the CPU first, then run 107*91f16700Schasinglulu * MSS DMA for SRAM to IRAM copy 108*91f16700Schasinglulu */ 109*91f16700Schasinglulu if (sram != 0) { 110*91f16700Schasinglulu chunks = size / MSS_SRAM_SIZE + !!(size % MSS_SRAM_SIZE); 111*91f16700Schasinglulu } 112*91f16700Schasinglulu 113*91f16700Schasinglulu NOTICE("%s Loading MSS FW from addr. 0x%x Size 0x%x to MSS at 0x%lx\n", 114*91f16700Schasinglulu sram == 0 ? "" : "SECURELY", src_addr, size, mss_regs); 115*91f16700Schasinglulu for (chunk_num = 0; chunk_num < chunks; chunk_num++) { 116*91f16700Schasinglulu size_t chunk_size = size; 117*91f16700Schasinglulu uint32_t img_src = MSS_EXTERNAL_SPACE | /* no SRAM */ 118*91f16700Schasinglulu (src_addr & MSS_EXTERNAL_ADDR_MASK); 119*91f16700Schasinglulu 120*91f16700Schasinglulu if (sram != 0) { 121*91f16700Schasinglulu uintptr_t chunk_source = 122*91f16700Schasinglulu src_addr + MSS_SRAM_SIZE * chunk_num; 123*91f16700Schasinglulu 124*91f16700Schasinglulu if (chunk_num != (size / MSS_SRAM_SIZE)) { 125*91f16700Schasinglulu chunk_size = MSS_SRAM_SIZE; 126*91f16700Schasinglulu } else { 127*91f16700Schasinglulu chunk_size = size % MSS_SRAM_SIZE; 128*91f16700Schasinglulu } 129*91f16700Schasinglulu 130*91f16700Schasinglulu if (chunk_size == 0) { 131*91f16700Schasinglulu break; 132*91f16700Schasinglulu } 133*91f16700Schasinglulu 134*91f16700Schasinglulu VERBOSE("Chunk %d -> SRAM 0x%lx from 0x%lx SZ 0x%lx\n", 135*91f16700Schasinglulu chunk_num, sram, chunk_source, chunk_size); 136*91f16700Schasinglulu memcpy((void *)sram, (void *)chunk_source, chunk_size); 137*91f16700Schasinglulu dsb(); 138*91f16700Schasinglulu img_src = MSS_INTERNAL_SPACE | 139*91f16700Schasinglulu (sram & MSS_INTERNAL_ADDR_MASK); 140*91f16700Schasinglulu } 141*91f16700Schasinglulu 142*91f16700Schasinglulu ret = mss_iram_dma_load(img_src, chunk_size, mss_regs); 143*91f16700Schasinglulu if (ret != 0) { 144*91f16700Schasinglulu ERROR("MSS FW chunk %d load failed\n", chunk_num); 145*91f16700Schasinglulu return ret; 146*91f16700Schasinglulu } 147*91f16700Schasinglulu } 148*91f16700Schasinglulu 149*91f16700Schasinglulu bl2_plat_configure_mss_windows(mss_regs); 150*91f16700Schasinglulu 151*91f16700Schasinglulu if (sram != 0) { 152*91f16700Schasinglulu /* Wipe the MSS SRAM after using it as copy buffer */ 153*91f16700Schasinglulu memset((void *)sram, 0, MSS_SRAM_SIZE); 154*91f16700Schasinglulu NOTICE("CP MSS startup is postponed\n"); 155*91f16700Schasinglulu /* FW loaded, but CPU startup postponed until final CP setup */ 156*91f16700Schasinglulu mmio_write_32(sram, MSS_FW_READY_MAGIC); 157*91f16700Schasinglulu dsb(); 158*91f16700Schasinglulu } else { 159*91f16700Schasinglulu /* Release M3 from reset */ 160*91f16700Schasinglulu mmio_write_32(MSS_M3_RSTCR(mss_regs), 161*91f16700Schasinglulu (MSS_M3_RSTCR_RST_OFF << 162*91f16700Schasinglulu MSS_M3_RSTCR_RST_OFFSET)); 163*91f16700Schasinglulu } 164*91f16700Schasinglulu 165*91f16700Schasinglulu NOTICE("Done\n"); 166*91f16700Schasinglulu 167*91f16700Schasinglulu return 0; 168*91f16700Schasinglulu } 169*91f16700Schasinglulu 170*91f16700Schasinglulu /* Load image to MSS AP and do PM related initialization 171*91f16700Schasinglulu * Note that this routine is different than other CM3 loading routines, because 172*91f16700Schasinglulu * firmware for AP is dedicated for PM and therefore some additional PM 173*91f16700Schasinglulu * initialization is required 174*91f16700Schasinglulu */ 175*91f16700Schasinglulu static int mss_ap_load_image(uintptr_t single_img, 176*91f16700Schasinglulu uint32_t image_size, uint32_t ap_idx) 177*91f16700Schasinglulu { 178*91f16700Schasinglulu volatile struct mss_pm_ctrl_block *mss_pm_crtl; 179*91f16700Schasinglulu int ret; 180*91f16700Schasinglulu 181*91f16700Schasinglulu /* TODO: add PM Control Info from platform */ 182*91f16700Schasinglulu mss_pm_crtl = (struct mss_pm_ctrl_block *)MSS_SRAM_PM_CONTROL_BASE; 183*91f16700Schasinglulu mss_pm_crtl->ipc_version = MV_PM_FW_IPC_VERSION; 184*91f16700Schasinglulu mss_pm_crtl->num_of_clusters = PLAT_MARVELL_CLUSTER_COUNT; 185*91f16700Schasinglulu mss_pm_crtl->num_of_cores_per_cluster = 186*91f16700Schasinglulu PLAT_MARVELL_CLUSTER_CORE_COUNT; 187*91f16700Schasinglulu mss_pm_crtl->num_of_cores = PLAT_MARVELL_CLUSTER_COUNT * 188*91f16700Schasinglulu PLAT_MARVELL_CLUSTER_CORE_COUNT; 189*91f16700Schasinglulu mss_pm_crtl->pm_trace_ctrl_base_address = AP_MSS_ATF_CORE_CTRL_BASE; 190*91f16700Schasinglulu mss_pm_crtl->pm_trace_info_base_address = AP_MSS_ATF_CORE_INFO_BASE; 191*91f16700Schasinglulu mss_pm_crtl->pm_trace_info_core_size = AP_MSS_ATF_CORE_INFO_SIZE; 192*91f16700Schasinglulu VERBOSE("MSS Control Block = 0x%x\n", MSS_SRAM_PM_CONTROL_BASE); 193*91f16700Schasinglulu VERBOSE("mss_pm_crtl->ipc_version = 0x%x\n", 194*91f16700Schasinglulu mss_pm_crtl->ipc_version); 195*91f16700Schasinglulu VERBOSE("mss_pm_crtl->num_of_cores = 0x%x\n", 196*91f16700Schasinglulu mss_pm_crtl->num_of_cores); 197*91f16700Schasinglulu VERBOSE("mss_pm_crtl->num_of_clusters = 0x%x\n", 198*91f16700Schasinglulu mss_pm_crtl->num_of_clusters); 199*91f16700Schasinglulu VERBOSE("mss_pm_crtl->num_of_cores_per_cluster = 0x%x\n", 200*91f16700Schasinglulu mss_pm_crtl->num_of_cores_per_cluster); 201*91f16700Schasinglulu VERBOSE("mss_pm_crtl->pm_trace_ctrl_base_address = 0x%x\n", 202*91f16700Schasinglulu mss_pm_crtl->pm_trace_ctrl_base_address); 203*91f16700Schasinglulu VERBOSE("mss_pm_crtl->pm_trace_info_base_address = 0x%x\n", 204*91f16700Schasinglulu mss_pm_crtl->pm_trace_info_base_address); 205*91f16700Schasinglulu VERBOSE("mss_pm_crtl->pm_trace_info_core_size = 0x%x\n", 206*91f16700Schasinglulu mss_pm_crtl->pm_trace_info_core_size); 207*91f16700Schasinglulu 208*91f16700Schasinglulu /* TODO: add checksum to image */ 209*91f16700Schasinglulu VERBOSE("Send info about the SCP_BL2 image to be transferred to SCP\n"); 210*91f16700Schasinglulu 211*91f16700Schasinglulu ret = mss_image_load(single_img, image_size, 212*91f16700Schasinglulu bl2_plat_get_ap_mss_regs(ap_idx), 0); 213*91f16700Schasinglulu if (ret != 0) { 214*91f16700Schasinglulu ERROR("SCP Image load failed\n"); 215*91f16700Schasinglulu return -1; 216*91f16700Schasinglulu } 217*91f16700Schasinglulu 218*91f16700Schasinglulu /* check that the image was loaded successfully */ 219*91f16700Schasinglulu ret = mss_check_image_ready(mss_pm_crtl); 220*91f16700Schasinglulu if (ret != 0) 221*91f16700Schasinglulu NOTICE("SCP Image doesn't contain PM firmware\n"); 222*91f16700Schasinglulu 223*91f16700Schasinglulu return 0; 224*91f16700Schasinglulu } 225*91f16700Schasinglulu 226*91f16700Schasinglulu /* Load CM3 image (single_img) to CM3 pointed by cm3_type */ 227*91f16700Schasinglulu static int load_img_to_cm3(enum cm3_t cm3_type, 228*91f16700Schasinglulu uintptr_t single_img, uint32_t image_size) 229*91f16700Schasinglulu { 230*91f16700Schasinglulu int ret, ap_idx, cp_index; 231*91f16700Schasinglulu uint32_t ap_count = bl2_plat_get_ap_count(); 232*91f16700Schasinglulu 233*91f16700Schasinglulu switch (cm3_type) { 234*91f16700Schasinglulu case MSS_AP: 235*91f16700Schasinglulu for (ap_idx = 0; ap_idx < ap_count; ap_idx++) { 236*91f16700Schasinglulu NOTICE("Load image to AP%d MSS\n", ap_idx); 237*91f16700Schasinglulu ret = mss_ap_load_image(single_img, image_size, ap_idx); 238*91f16700Schasinglulu if (ret != 0) 239*91f16700Schasinglulu return ret; 240*91f16700Schasinglulu } 241*91f16700Schasinglulu break; 242*91f16700Schasinglulu case MSS_CP0: 243*91f16700Schasinglulu case MSS_CP1: 244*91f16700Schasinglulu case MSS_CP2: 245*91f16700Schasinglulu case MSS_CP3: 246*91f16700Schasinglulu /* MSS_AP = 0 247*91f16700Schasinglulu * MSS_CP1 = 1 248*91f16700Schasinglulu * . 249*91f16700Schasinglulu * . 250*91f16700Schasinglulu * MSS_CP3 = 4 251*91f16700Schasinglulu * Actual CP index is MSS_CPX - 1 252*91f16700Schasinglulu */ 253*91f16700Schasinglulu cp_index = cm3_type - 1; 254*91f16700Schasinglulu for (ap_idx = 0; ap_idx < ap_count; ap_idx++) { 255*91f16700Schasinglulu /* Check if we should load this image 256*91f16700Schasinglulu * according to number of CPs 257*91f16700Schasinglulu */ 258*91f16700Schasinglulu if (bl2_plat_get_cp_count(ap_idx) <= cp_index) { 259*91f16700Schasinglulu NOTICE("Skipping MSS CP%d related image\n", 260*91f16700Schasinglulu cp_index); 261*91f16700Schasinglulu break; 262*91f16700Schasinglulu } 263*91f16700Schasinglulu 264*91f16700Schasinglulu NOTICE("Load image to CP%d MSS AP%d\n", 265*91f16700Schasinglulu cp_index, ap_idx); 266*91f16700Schasinglulu ret = mss_image_load(single_img, image_size, 267*91f16700Schasinglulu bl2_plat_get_cp_mss_regs( 268*91f16700Schasinglulu ap_idx, cp_index), 269*91f16700Schasinglulu bl2_plat_get_cp_mss_sram( 270*91f16700Schasinglulu ap_idx, cp_index)); 271*91f16700Schasinglulu if (ret != 0) { 272*91f16700Schasinglulu ERROR("SCP Image load failed\n"); 273*91f16700Schasinglulu return -1; 274*91f16700Schasinglulu } 275*91f16700Schasinglulu } 276*91f16700Schasinglulu break; 277*91f16700Schasinglulu case MG_CP0: 278*91f16700Schasinglulu case MG_CP1: 279*91f16700Schasinglulu case MG_CP2: 280*91f16700Schasinglulu cp_index = cm3_type - MG_CP0; 281*91f16700Schasinglulu if (bl2_plat_get_cp_count(0) <= cp_index) { 282*91f16700Schasinglulu NOTICE("Skipping MG CP%d related image\n", 283*91f16700Schasinglulu cp_index); 284*91f16700Schasinglulu break; 285*91f16700Schasinglulu } 286*91f16700Schasinglulu NOTICE("Load image to CP%d MG\n", cp_index); 287*91f16700Schasinglulu ret = mg_image_load(single_img, image_size, cp_index); 288*91f16700Schasinglulu if (ret != 0) { 289*91f16700Schasinglulu ERROR("SCP Image load failed\n"); 290*91f16700Schasinglulu return -1; 291*91f16700Schasinglulu } 292*91f16700Schasinglulu break; 293*91f16700Schasinglulu default: 294*91f16700Schasinglulu ERROR("SCP_BL2 wrong img format (cm3_type=%d)\n", cm3_type); 295*91f16700Schasinglulu break; 296*91f16700Schasinglulu } 297*91f16700Schasinglulu 298*91f16700Schasinglulu return 0; 299*91f16700Schasinglulu } 300*91f16700Schasinglulu 301*91f16700Schasinglulu /* The Armada 8K has 5 service CPUs and Armada 7K has 3. Therefore it was 302*91f16700Schasinglulu * required to provide a method for loading firmware to all of the service CPUs. 303*91f16700Schasinglulu * To achieve that, the scp_bl2 image in fact is file containing up to 5 304*91f16700Schasinglulu * concatenated firmwares and this routine splits concatenated image into single 305*91f16700Schasinglulu * images dedicated for appropriate service CPU and then load them. 306*91f16700Schasinglulu */ 307*91f16700Schasinglulu static int split_and_load_bl2_image(void *image) 308*91f16700Schasinglulu { 309*91f16700Schasinglulu file_header_t *file_hdr; 310*91f16700Schasinglulu img_header_t *img_hdr; 311*91f16700Schasinglulu uintptr_t single_img; 312*91f16700Schasinglulu int i; 313*91f16700Schasinglulu 314*91f16700Schasinglulu file_hdr = (file_header_t *)image; 315*91f16700Schasinglulu 316*91f16700Schasinglulu if (file_hdr->magic != FILE_MAGIC) { 317*91f16700Schasinglulu ERROR("SCP_BL2 wrong img format\n"); 318*91f16700Schasinglulu return -1; 319*91f16700Schasinglulu } 320*91f16700Schasinglulu 321*91f16700Schasinglulu if (file_hdr->nr_of_imgs > MAX_NR_OF_FILES) { 322*91f16700Schasinglulu ERROR("SCP_BL2 concatenated image contains too many images\n"); 323*91f16700Schasinglulu return -1; 324*91f16700Schasinglulu } 325*91f16700Schasinglulu 326*91f16700Schasinglulu img_hdr = (img_header_t *)((uintptr_t)image + sizeof(file_header_t)); 327*91f16700Schasinglulu single_img = (uintptr_t)image + sizeof(file_header_t) + 328*91f16700Schasinglulu sizeof(img_header_t) * file_hdr->nr_of_imgs; 329*91f16700Schasinglulu 330*91f16700Schasinglulu NOTICE("SCP_BL2 contains %d concatenated images\n", 331*91f16700Schasinglulu file_hdr->nr_of_imgs); 332*91f16700Schasinglulu for (i = 0; i < file_hdr->nr_of_imgs; i++) { 333*91f16700Schasinglulu 334*91f16700Schasinglulu /* Before loading make sanity check on header */ 335*91f16700Schasinglulu if (img_hdr->version != HEADER_VERSION) { 336*91f16700Schasinglulu ERROR("Wrong header, img corrupted exiting\n"); 337*91f16700Schasinglulu return -1; 338*91f16700Schasinglulu } 339*91f16700Schasinglulu 340*91f16700Schasinglulu load_img_to_cm3(img_hdr->type, single_img, img_hdr->length); 341*91f16700Schasinglulu 342*91f16700Schasinglulu /* Prepare offsets for next run */ 343*91f16700Schasinglulu single_img += img_hdr->length; 344*91f16700Schasinglulu img_hdr++; 345*91f16700Schasinglulu } 346*91f16700Schasinglulu 347*91f16700Schasinglulu return 0; 348*91f16700Schasinglulu } 349*91f16700Schasinglulu 350*91f16700Schasinglulu int scp_bootloader_transfer(void *image, unsigned int image_size) 351*91f16700Schasinglulu { 352*91f16700Schasinglulu #ifdef SCP_BL2_BASE 353*91f16700Schasinglulu assert((uintptr_t) image == SCP_BL2_BASE); 354*91f16700Schasinglulu #endif 355*91f16700Schasinglulu 356*91f16700Schasinglulu VERBOSE("Concatenated img size %d\n", image_size); 357*91f16700Schasinglulu 358*91f16700Schasinglulu if (image_size == 0) { 359*91f16700Schasinglulu ERROR("SCP_BL2 image size can't be 0 (current size = 0x%x)\n", 360*91f16700Schasinglulu image_size); 361*91f16700Schasinglulu return -1; 362*91f16700Schasinglulu } 363*91f16700Schasinglulu 364*91f16700Schasinglulu if (split_and_load_bl2_image(image)) 365*91f16700Schasinglulu return -1; 366*91f16700Schasinglulu 367*91f16700Schasinglulu return 0; 368*91f16700Schasinglulu } 369