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