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