1b7ad0444SSumit Garg /* 2b7ad0444SSumit Garg * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. 3b7ad0444SSumit Garg * 4b7ad0444SSumit Garg * SPDX-License-Identifier: BSD-3-Clause 5b7ad0444SSumit Garg */ 6b7ad0444SSumit Garg 7b7ad0444SSumit Garg #include <arch_helpers.h> 8b7ad0444SSumit Garg #include <assert.h> 9b7ad0444SSumit Garg #include <platform_def.h> 10b7ad0444SSumit Garg #include <sq_common.h> 11b7ad0444SSumit Garg #include <debug.h> 12b7ad0444SSumit Garg #include <string.h> 13b7ad0444SSumit Garg #include "sq_mhu.h" 14b7ad0444SSumit Garg #include "sq_scpi.h" 15b7ad0444SSumit Garg 16b7ad0444SSumit Garg #define SCPI_SHARED_MEM_SCP_TO_AP PLAT_SQ_SCP_COM_SHARED_MEM_BASE 17b7ad0444SSumit Garg #define SCPI_SHARED_MEM_AP_TO_SCP (PLAT_SQ_SCP_COM_SHARED_MEM_BASE \ 18b7ad0444SSumit Garg + 0x100) 19b7ad0444SSumit Garg 20b7ad0444SSumit Garg #define SCPI_CMD_HEADER_AP_TO_SCP \ 21b7ad0444SSumit Garg ((scpi_cmd_t *) SCPI_SHARED_MEM_AP_TO_SCP) 22b7ad0444SSumit Garg #define SCPI_CMD_PAYLOAD_AP_TO_SCP \ 23b7ad0444SSumit Garg ((void *) (SCPI_SHARED_MEM_AP_TO_SCP + sizeof(scpi_cmd_t))) 24b7ad0444SSumit Garg 25b7ad0444SSumit Garg /* ID of the MHU slot used for the SCPI protocol */ 26b7ad0444SSumit Garg #define SCPI_MHU_SLOT_ID 0 27b7ad0444SSumit Garg 28b7ad0444SSumit Garg static void scpi_secure_message_start(void) 29b7ad0444SSumit Garg { 30b7ad0444SSumit Garg mhu_secure_message_start(SCPI_MHU_SLOT_ID); 31b7ad0444SSumit Garg } 32b7ad0444SSumit Garg 33b7ad0444SSumit Garg static void scpi_secure_message_send(size_t payload_size) 34b7ad0444SSumit Garg { 35b7ad0444SSumit Garg /* 36b7ad0444SSumit Garg * Ensure that any write to the SCPI payload area is seen by SCP before 37b7ad0444SSumit Garg * we write to the MHU register. If these 2 writes were reordered by 38b7ad0444SSumit Garg * the CPU then SCP would read stale payload data 39b7ad0444SSumit Garg */ 40b7ad0444SSumit Garg dmbst(); 41b7ad0444SSumit Garg 42b7ad0444SSumit Garg mhu_secure_message_send(SCPI_MHU_SLOT_ID); 43b7ad0444SSumit Garg } 44b7ad0444SSumit Garg 45b7ad0444SSumit Garg static void scpi_secure_message_receive(scpi_cmd_t *cmd) 46b7ad0444SSumit Garg { 47b7ad0444SSumit Garg uint32_t mhu_status; 48b7ad0444SSumit Garg 49b7ad0444SSumit Garg assert(cmd != NULL); 50b7ad0444SSumit Garg 51b7ad0444SSumit Garg mhu_status = mhu_secure_message_wait(); 52b7ad0444SSumit Garg 53b7ad0444SSumit Garg /* Expect an SCPI message, reject any other protocol */ 54b7ad0444SSumit Garg if (mhu_status != (1 << SCPI_MHU_SLOT_ID)) { 55b7ad0444SSumit Garg ERROR("MHU: Unexpected protocol (MHU status: 0x%x)\n", 56b7ad0444SSumit Garg mhu_status); 57b7ad0444SSumit Garg panic(); 58b7ad0444SSumit Garg } 59b7ad0444SSumit Garg 60b7ad0444SSumit Garg /* 61b7ad0444SSumit Garg * Ensure that any read to the SCPI payload area is done after reading 62b7ad0444SSumit Garg * the MHU register. If these 2 reads were reordered then the CPU would 63b7ad0444SSumit Garg * read invalid payload data 64b7ad0444SSumit Garg */ 65b7ad0444SSumit Garg dmbld(); 66b7ad0444SSumit Garg 67b7ad0444SSumit Garg memcpy(cmd, (void *) SCPI_SHARED_MEM_SCP_TO_AP, sizeof(*cmd)); 68b7ad0444SSumit Garg } 69b7ad0444SSumit Garg 70b7ad0444SSumit Garg static void scpi_secure_message_end(void) 71b7ad0444SSumit Garg { 72b7ad0444SSumit Garg mhu_secure_message_end(SCPI_MHU_SLOT_ID); 73b7ad0444SSumit Garg } 74b7ad0444SSumit Garg 75b7ad0444SSumit Garg int scpi_wait_ready(void) 76b7ad0444SSumit Garg { 77b7ad0444SSumit Garg scpi_cmd_t scpi_cmd; 78b7ad0444SSumit Garg scpi_status_t status = SCP_OK; 79b7ad0444SSumit Garg 80b7ad0444SSumit Garg VERBOSE("Waiting for SCP_READY command...\n"); 81b7ad0444SSumit Garg 82b7ad0444SSumit Garg /* Get a message from the SCP */ 83b7ad0444SSumit Garg scpi_secure_message_start(); 84b7ad0444SSumit Garg scpi_secure_message_receive(&scpi_cmd); 85b7ad0444SSumit Garg scpi_secure_message_end(); 86b7ad0444SSumit Garg 87b7ad0444SSumit Garg /* We are expecting 'SCP Ready', produce correct error if it's not */ 88b7ad0444SSumit Garg if (scpi_cmd.id != SCPI_CMD_SCP_READY) { 89b7ad0444SSumit Garg ERROR("Unexpected SCP command: expected command #%u," 90b7ad0444SSumit Garg "got command #%u\n", SCPI_CMD_SCP_READY, scpi_cmd.id); 91b7ad0444SSumit Garg status = SCP_E_SUPPORT; 92b7ad0444SSumit Garg } else if (scpi_cmd.size != 0) { 93b7ad0444SSumit Garg ERROR("SCP_READY command has incorrect size: expected 0," 94b7ad0444SSumit Garg "got %u\n", scpi_cmd.size); 95b7ad0444SSumit Garg status = SCP_E_SIZE; 96b7ad0444SSumit Garg } 97b7ad0444SSumit Garg 98b7ad0444SSumit Garg VERBOSE("Sending response for SCP_READY command\n"); 99b7ad0444SSumit Garg 100b7ad0444SSumit Garg /* 101b7ad0444SSumit Garg * Send our response back to SCP. 102b7ad0444SSumit Garg * We are using the same SCPI header, just update the status field. 103b7ad0444SSumit Garg */ 104b7ad0444SSumit Garg scpi_cmd.status = status; 105b7ad0444SSumit Garg scpi_secure_message_start(); 106b7ad0444SSumit Garg memcpy((void *) SCPI_SHARED_MEM_AP_TO_SCP, &scpi_cmd, sizeof(scpi_cmd)); 107b7ad0444SSumit Garg scpi_secure_message_send(0); 108b7ad0444SSumit Garg scpi_secure_message_end(); 109b7ad0444SSumit Garg 110b7ad0444SSumit Garg return status == SCP_OK ? 0 : -1; 111b7ad0444SSumit Garg } 112b7ad0444SSumit Garg 113b7ad0444SSumit Garg void scpi_set_sq_power_state(unsigned int mpidr, scpi_power_state_t cpu_state, 114b7ad0444SSumit Garg scpi_power_state_t cluster_state, scpi_power_state_t sq_state) 115b7ad0444SSumit Garg { 116b7ad0444SSumit Garg scpi_cmd_t *cmd; 117b7ad0444SSumit Garg uint32_t state = 0; 118b7ad0444SSumit Garg uint32_t *payload_addr; 119b7ad0444SSumit Garg 120b7ad0444SSumit Garg state |= mpidr & 0x0f; /* CPU ID */ 121b7ad0444SSumit Garg state |= (mpidr & 0xf00) >> 4; /* Cluster ID */ 122b7ad0444SSumit Garg state |= cpu_state << 8; 123b7ad0444SSumit Garg state |= cluster_state << 12; 124b7ad0444SSumit Garg state |= sq_state << 16; 125b7ad0444SSumit Garg 126b7ad0444SSumit Garg scpi_secure_message_start(); 127b7ad0444SSumit Garg 128b7ad0444SSumit Garg /* Populate the command header */ 129b7ad0444SSumit Garg cmd = SCPI_CMD_HEADER_AP_TO_SCP; 130b7ad0444SSumit Garg cmd->id = SCPI_CMD_SET_POWER_STATE; 131b7ad0444SSumit Garg cmd->set = SCPI_SET_NORMAL; 132b7ad0444SSumit Garg cmd->sender = 0; 133b7ad0444SSumit Garg cmd->size = sizeof(state); 134b7ad0444SSumit Garg /* Populate the command payload */ 135b7ad0444SSumit Garg payload_addr = SCPI_CMD_PAYLOAD_AP_TO_SCP; 136b7ad0444SSumit Garg *payload_addr = state; 137b7ad0444SSumit Garg scpi_secure_message_send(sizeof(state)); 138b7ad0444SSumit Garg 139b7ad0444SSumit Garg /* 140b7ad0444SSumit Garg * SCP does not reply to this command in order to avoid MHU interrupts 141b7ad0444SSumit Garg * from the sender, which could interfere with its power state request. 142b7ad0444SSumit Garg */ 143b7ad0444SSumit Garg scpi_secure_message_end(); 144b7ad0444SSumit Garg } 145b7ad0444SSumit Garg 146b7ad0444SSumit Garg uint32_t scpi_sys_power_state(scpi_system_state_t system_state) 147b7ad0444SSumit Garg { 148b7ad0444SSumit Garg scpi_cmd_t *cmd; 149b7ad0444SSumit Garg uint8_t *payload_addr; 150b7ad0444SSumit Garg scpi_cmd_t response; 151b7ad0444SSumit Garg 152b7ad0444SSumit Garg scpi_secure_message_start(); 153b7ad0444SSumit Garg 154b7ad0444SSumit Garg /* Populate the command header */ 155b7ad0444SSumit Garg cmd = SCPI_CMD_HEADER_AP_TO_SCP; 156b7ad0444SSumit Garg cmd->id = SCPI_CMD_SYS_POWER_STATE; 157b7ad0444SSumit Garg cmd->set = 0; 158b7ad0444SSumit Garg cmd->sender = 0; 159b7ad0444SSumit Garg cmd->size = sizeof(*payload_addr); 160b7ad0444SSumit Garg /* Populate the command payload */ 161b7ad0444SSumit Garg payload_addr = SCPI_CMD_PAYLOAD_AP_TO_SCP; 162b7ad0444SSumit Garg *payload_addr = system_state & 0xff; 163b7ad0444SSumit Garg scpi_secure_message_send(sizeof(*payload_addr)); 164b7ad0444SSumit Garg 165b7ad0444SSumit Garg scpi_secure_message_receive(&response); 166b7ad0444SSumit Garg 167b7ad0444SSumit Garg scpi_secure_message_end(); 168b7ad0444SSumit Garg 169b7ad0444SSumit Garg return response.status; 170b7ad0444SSumit Garg } 171*cfe19f85SArd Biesheuvel 172*cfe19f85SArd Biesheuvel uint32_t scpi_get_draminfo(struct draminfo *info) 173*cfe19f85SArd Biesheuvel { 174*cfe19f85SArd Biesheuvel scpi_cmd_t *cmd; 175*cfe19f85SArd Biesheuvel struct { 176*cfe19f85SArd Biesheuvel scpi_cmd_t cmd; 177*cfe19f85SArd Biesheuvel struct draminfo info; 178*cfe19f85SArd Biesheuvel } response; 179*cfe19f85SArd Biesheuvel uint32_t mhu_status; 180*cfe19f85SArd Biesheuvel 181*cfe19f85SArd Biesheuvel scpi_secure_message_start(); 182*cfe19f85SArd Biesheuvel 183*cfe19f85SArd Biesheuvel /* Populate the command header */ 184*cfe19f85SArd Biesheuvel cmd = SCPI_CMD_HEADER_AP_TO_SCP; 185*cfe19f85SArd Biesheuvel cmd->id = SCPI_CMD_GET_DRAMINFO; 186*cfe19f85SArd Biesheuvel cmd->set = SCPI_SET_EXTENDED; 187*cfe19f85SArd Biesheuvel cmd->sender = 0; 188*cfe19f85SArd Biesheuvel cmd->size = 0; 189*cfe19f85SArd Biesheuvel 190*cfe19f85SArd Biesheuvel scpi_secure_message_send(0); 191*cfe19f85SArd Biesheuvel 192*cfe19f85SArd Biesheuvel mhu_status = mhu_secure_message_wait(); 193*cfe19f85SArd Biesheuvel 194*cfe19f85SArd Biesheuvel /* Expect an SCPI message, reject any other protocol */ 195*cfe19f85SArd Biesheuvel if (mhu_status != (1 << SCPI_MHU_SLOT_ID)) { 196*cfe19f85SArd Biesheuvel ERROR("MHU: Unexpected protocol (MHU status: 0x%x)\n", 197*cfe19f85SArd Biesheuvel mhu_status); 198*cfe19f85SArd Biesheuvel panic(); 199*cfe19f85SArd Biesheuvel } 200*cfe19f85SArd Biesheuvel 201*cfe19f85SArd Biesheuvel /* 202*cfe19f85SArd Biesheuvel * Ensure that any read to the SCPI payload area is done after reading 203*cfe19f85SArd Biesheuvel * the MHU register. If these 2 reads were reordered then the CPU would 204*cfe19f85SArd Biesheuvel * read invalid payload data 205*cfe19f85SArd Biesheuvel */ 206*cfe19f85SArd Biesheuvel dmbld(); 207*cfe19f85SArd Biesheuvel 208*cfe19f85SArd Biesheuvel memcpy(&response, (void *)SCPI_SHARED_MEM_SCP_TO_AP, sizeof(response)); 209*cfe19f85SArd Biesheuvel 210*cfe19f85SArd Biesheuvel scpi_secure_message_end(); 211*cfe19f85SArd Biesheuvel 212*cfe19f85SArd Biesheuvel if (response.cmd.status == SCP_OK) 213*cfe19f85SArd Biesheuvel *info = response.info; 214*cfe19f85SArd Biesheuvel 215*cfe19f85SArd Biesheuvel return response.cmd.status; 216*cfe19f85SArd Biesheuvel } 217