xref: /arm-trusted-firmware/plat/marvell/armada/common/mss/mss_scp_bootloader.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
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