123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368 |
- /*
- * Copyright (C) 2018 Marvell International Ltd.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- * https://spdx.org/licenses
- */
- #include <assert.h>
- #include <platform_def.h>
- #include <arch_helpers.h>
- #include <common/debug.h>
- #include <drivers/delay_timer.h>
- #include <mg_conf_cm3/mg_conf_cm3.h>
- #include <lib/mmio.h>
- #include <plat_pm_trace.h>
- #include <mss_scp_bootloader.h>
- #include <mss_ipc_drv.h>
- #include <mss_mem.h>
- #include <mss_defs.h>
- #include <mss_scp_bl2_format.h>
- #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
- #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_iram_dma_load(uint32_t src_addr, uint32_t size,
- uintptr_t mss_regs)
- {
- uint32_t i, loop_num, timeout;
- /* load image to MSS RAM using DMA */
- loop_num = (size / DMA_SIZE) + !!(size % DMA_SIZE);
- for (i = 0; i < loop_num; i++) {
- /* write source address */
- mmio_write_32(MSS_DMA_SRCBR(mss_regs),
- src_addr + (i * DMA_SIZE));
- /* write destination address */
- mmio_write_32(MSS_DMA_DSTBR(mss_regs), (i * DMA_SIZE));
- /* 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) |
- (DMA_SIZE << MSS_DMA_CTRLR_SIZE_OFFSET)));
- /* Poll DMA_ACK at MSS_DMACTLR until it is ready */
- timeout = MSS_DMA_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) {
- break;
- }
- udelay(50);
- timeout--;
- }
- if (timeout == 0) {
- 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);
- if (sram != 0) {
- /* Wipe the MSS SRAM after using it as copy buffer */
- memset((void *)sram, 0, MSS_SRAM_SIZE);
- NOTICE("CP MSS startup is postponed\n");
- /* FW loaded, but CPU startup postponed until final CP setup */
- mmio_write_32(sram, MSS_FW_READY_MAGIC);
- dsb();
- } else {
- /* 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), 0);
- 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),
- bl2_plat_get_cp_mss_sram(
- ap_idx, cp_index));
- if (ret != 0) {
- ERROR("SCP Image load failed\n");
- return -1;
- }
- }
- break;
- case MG_CP0:
- case MG_CP1:
- case MG_CP2:
- cp_index = cm3_type - MG_CP0;
- if (bl2_plat_get_cp_count(0) <= cp_index) {
- NOTICE("Skipping MG CP%d related image\n",
- cp_index);
- break;
- }
- NOTICE("Load image to CP%d MG\n", cp_index);
- ret = mg_image_load(single_img, image_size, cp_index);
- if (ret != 0) {
- ERROR("SCP Image load failed\n");
- return -1;
- }
- 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 too 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;
- }
|