• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * Redistributions of source code must retain the above copyright notice, this
8  * list of conditions and the following disclaimer.
9  *
10  * Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  *
14  * Neither the name of ARM nor the names of its contributors may be used
15  * to endorse or promote products derived from this software without specific
16  * prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include <arch_helpers.h>
32 #include <platform.h>
33 #include "juno_def.h"
34 #include "mhu.h"
35 #include "scp_bootloader.h"
36 #include "scpi.h"
37 
38 /* Boot commands sent from AP -> SCP */
39 #define BOOT_CMD_START	0x01
40 #define BOOT_CMD_DATA	0x02
41 
42 typedef struct {
43 	uint32_t image_size;
44 } cmd_start_payload;
45 
46 typedef struct {
47 	uint32_t sequence_num;
48 	uint32_t offset;
49 	uint32_t size;
50 } cmd_data_payload;
51 
52 #define BOOT_DATA_MAX_SIZE  0x1000
53 
54 /* Boot commands sent from SCP -> AP */
55 #define BOOT_CMD_ACK	0x03
56 #define BOOT_CMD_NACK	0x04
57 
58 typedef struct {
59 	uint32_t sequence_num;
60 } cmd_ack_payload;
61 
62 /*
63  * Unlike the runtime protocol, the boot protocol uses the same memory region
64  * for both AP -> SCP and SCP -> AP transfers; define the address of this...
65  */
66 static void * const cmd_payload = (void *)(MHU_SECURE_BASE + 0x0080);
67 
scp_boot_message_start(void)68 static void *scp_boot_message_start(void)
69 {
70 	mhu_secure_message_start();
71 
72 	return cmd_payload;
73 }
74 
scp_boot_message_send(unsigned command,size_t size)75 static void scp_boot_message_send(unsigned command, size_t size)
76 {
77 	/* Make sure payload can be seen by SCP */
78 	if (MHU_PAYLOAD_CACHED)
79 		flush_dcache_range((unsigned long)cmd_payload, size);
80 
81 	/* Send command to SCP */
82 	mhu_secure_message_send(command | (size << 8));
83 }
84 
scp_boot_message_wait(size_t size)85 static uint32_t scp_boot_message_wait(size_t size)
86 {
87 	uint32_t response =  mhu_secure_message_wait();
88 
89 	/* Make sure we see the reply from the SCP and not any stale data */
90 	if (MHU_PAYLOAD_CACHED)
91 		inv_dcache_range((unsigned long)cmd_payload, size);
92 
93 	return response & 0xff;
94 }
95 
scp_boot_message_end(void)96 static void scp_boot_message_end(void)
97 {
98 	mhu_secure_message_end();
99 }
100 
transfer_block(uint32_t sequence_num,uint32_t offset,uint32_t size)101 static int transfer_block(uint32_t sequence_num, uint32_t offset, uint32_t size)
102 {
103 	cmd_data_payload *cmd_data = scp_boot_message_start();
104 	cmd_data->sequence_num = sequence_num;
105 	cmd_data->offset = offset;
106 	cmd_data->size = size;
107 
108 	scp_boot_message_send(BOOT_CMD_DATA, sizeof(*cmd_data));
109 
110 	cmd_ack_payload *cmd_ack = cmd_payload;
111 	int ok = scp_boot_message_wait(sizeof(*cmd_ack)) == BOOT_CMD_ACK
112 		 && cmd_ack->sequence_num == sequence_num;
113 
114 	scp_boot_message_end();
115 
116 	return ok;
117 }
118 
scp_bootloader_transfer(void * image,unsigned int image_size)119 int scp_bootloader_transfer(void *image, unsigned int image_size)
120 {
121 	uintptr_t offset = (uintptr_t)image - MHU_SECURE_BASE;
122 	uintptr_t end = offset + image_size;
123 	uint32_t response;
124 
125 	mhu_secure_init();
126 
127 	/* Initiate communications with SCP */
128 	do {
129 		cmd_start_payload *cmd_start = scp_boot_message_start();
130 		cmd_start->image_size = image_size;
131 
132 		scp_boot_message_send(BOOT_CMD_START, sizeof(*cmd_start));
133 
134 		response = scp_boot_message_wait(0);
135 
136 		scp_boot_message_end();
137 	} while (response != BOOT_CMD_ACK);
138 
139 	/* Transfer image to SCP a block at a time */
140 	uint32_t sequence_num = 1;
141 	size_t size;
142 	while ((size = end - offset) != 0) {
143 		if (size > BOOT_DATA_MAX_SIZE)
144 			size = BOOT_DATA_MAX_SIZE;
145 		while (!transfer_block(sequence_num, offset, size))
146 			; /* Retry forever */
147 		offset += size;
148 		sequence_num++;
149 	}
150 
151 	/* Wait for SCP to signal it's ready */
152 	return scpi_wait_ready();
153 }
154