Home | History | Annotate | Download | only in juno
      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