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 68 static void *scp_boot_message_start(void) 69 { 70 mhu_secure_message_start(); 71 72 return cmd_payload; 73 } 74 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 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 96 static void scp_boot_message_end(void) 97 { 98 mhu_secure_message_end(); 99 } 100 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 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