1 /* 2 * Copyright (C) 2018 Marvell International Ltd. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 * https://spdx.org/licenses 6 */ 7 8 #include <platform_def.h> 9 10 #include <common/bl_common.h> 11 #include <common/debug.h> 12 #include <drivers/marvell/ccu.h> 13 #include <drivers/marvell/mochi/cp110_setup.h> 14 #include <lib/mmio.h> 15 16 #include <armada_common.h> 17 #include <marvell_plat_priv.h> /* timer functionality */ 18 19 #include "mss_scp_bootloader.h" 20 21 /* IO windows configuration */ 22 #define IOW_GCR_OFFSET (0x70) 23 24 /* MSS windows configuration */ 25 #define MSS_AEBR(base) (base + 0x160) 26 #define MSS_AIBR(base) (base + 0x164) 27 #define MSS_AEBR_MASK 0xFFF 28 #define MSS_AIBR_MASK 0xFFF 29 30 #define MSS_EXTERNAL_SPACE 0x50000000 31 #define MSS_EXTERNAL_ACCESS_BIT 28 32 #define MSS_EXTERNAL_ADDR_MASK 0xfffffff 33 #define MSS_INTERNAL_ACCESS_BIT 28 34 35 struct addr_map_win ccu_mem_map[] = { 36 {MVEBU_CP_REGS_BASE(0), 0x4000000, IO_0_TID} 37 }; 38 39 /* Since the scp_bl2 image can contain firmware for cp1 and cp0 coprocessors, 40 * the access to cp0 and cp1 need to be provided. More precisely it is 41 * required to: 42 * - get the information about device id which is stored in CP0 registers 43 * (to distinguish between cases where we have cp0 and cp1 or standalone cp0) 44 * - get the access to cp which is needed for loading fw for cp0/cp1 45 * coprocessors 46 * This function configures ccu windows accordingly. 47 * 48 * Note: there is no need to restore previous ccu configuration, since in next 49 * phase (BL31) the init_ccu will be called (via apn806_init/ 50 * bl31_plat_arch_setu) and therefore the ccu configuration will be overwritten. 51 */ 52 static int bl2_plat_mmap_init(void) 53 { 54 int cfg_num, win_id, cfg_idx; 55 56 cfg_num = ARRAY_SIZE(ccu_mem_map); 57 58 /* CCU window-0 should not be counted - it's already used */ 59 if (cfg_num > (MVEBU_CCU_MAX_WINS - 1)) { 60 ERROR("BL2: %s: trying to open too many windows\n", __func__); 61 return -1; 62 } 63 64 /* Enable required CCU windows 65 * Do not touch CCU window 0, 66 * it's used for the internal registers access 67 */ 68 for (cfg_idx = 0, win_id = 1; cfg_idx < cfg_num; cfg_idx++, win_id++) { 69 /* Enable required CCU windows */ 70 ccu_win_check(&ccu_mem_map[cfg_idx]); 71 ccu_enable_win(MVEBU_AP0, &ccu_mem_map[cfg_idx], win_id); 72 } 73 74 /* Set the default target id to PIDI */ 75 mmio_write_32(MVEBU_IO_WIN_BASE(MVEBU_AP0) + IOW_GCR_OFFSET, PIDI_TID); 76 77 /* Open AMB bridge required for MG access */ 78 cp110_amb_init(MVEBU_CP_REGS_BASE(0)); 79 80 if (CP_COUNT == 2) 81 cp110_amb_init(MVEBU_CP_REGS_BASE(1)); 82 83 return 0; 84 } 85 86 /***************************************************************************** 87 * Transfer SCP_BL2 from Trusted RAM using the SCP Download protocol. 88 * Return 0 on success, -1 otherwise. 89 ***************************************************************************** 90 */ 91 int bl2_plat_handle_scp_bl2(image_info_t *scp_bl2_image_info) 92 { 93 int ret; 94 95 INFO("BL2: Initiating SCP_BL2 transfer to SCP\n"); 96 97 /* initialize time (for delay functionality) */ 98 plat_delay_timer_init(); 99 100 ret = bl2_plat_mmap_init(); 101 if (ret != 0) 102 return ret; 103 104 ret = scp_bootloader_transfer((void *)scp_bl2_image_info->image_base, 105 scp_bl2_image_info->image_size); 106 107 if (ret == 0) 108 INFO("BL2: SCP_BL2 transferred to SCP\n"); 109 else 110 ERROR("BL2: SCP_BL2 transfer failure\n"); 111 112 return ret; 113 } 114 115 uintptr_t bl2_plat_get_cp_mss_regs(int ap_idx, int cp_idx) 116 { 117 return MVEBU_CP_REGS_BASE(cp_idx) + 0x280000; 118 } 119 120 uintptr_t bl2_plat_get_ap_mss_regs(int ap_idx) 121 { 122 return MVEBU_REGS_BASE + 0x580000; 123 } 124 125 uint32_t bl2_plat_get_cp_count(int ap_idx) 126 { 127 uint32_t revision = cp110_device_id_get(MVEBU_CP_REGS_BASE(0)); 128 /* A8040: two CPs. 129 * A7040: one CP. 130 */ 131 if (revision == MVEBU_80X0_DEV_ID || 132 revision == MVEBU_80X0_CP115_DEV_ID) 133 return 2; 134 else 135 return 1; 136 } 137 138 uint32_t bl2_plat_get_ap_count(void) 139 { 140 /* A8040 and A7040 have only one AP */ 141 return 1; 142 } 143 144 void bl2_plat_configure_mss_windows(uintptr_t mss_regs) 145 { 146 /* set AXI External and Internal Address Bus extension */ 147 mmio_write_32(MSS_AEBR(mss_regs), 148 ((0x0 >> MSS_EXTERNAL_ACCESS_BIT) & MSS_AEBR_MASK)); 149 mmio_write_32(MSS_AIBR(mss_regs), 150 ((mss_regs >> MSS_INTERNAL_ACCESS_BIT) & MSS_AIBR_MASK)); 151 } 152