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