diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:13:47 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:13:47 +0000 |
commit | 102b0d2daa97dae68d3eed54d8fe37a9cc38a892 (patch) | |
tree | bcf648efac40ca6139842707f0eba5a4496a6dd2 /drivers/arm/css/scmi | |
parent | Initial commit. (diff) | |
download | arm-trusted-firmware-102b0d2daa97dae68d3eed54d8fe37a9cc38a892.tar.xz arm-trusted-firmware-102b0d2daa97dae68d3eed54d8fe37a9cc38a892.zip |
Adding upstream version 2.8.0+dfsg.upstream/2.8.0+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/arm/css/scmi')
-rw-r--r-- | drivers/arm/css/scmi/scmi_ap_core_proto.c | 81 | ||||
-rw-r--r-- | drivers/arm/css/scmi/scmi_common.c | 210 | ||||
-rw-r--r-- | drivers/arm/css/scmi/scmi_private.h | 160 | ||||
-rw-r--r-- | drivers/arm/css/scmi/scmi_pwr_dmn_proto.c | 88 | ||||
-rw-r--r-- | drivers/arm/css/scmi/scmi_sys_pwr_proto.c | 78 | ||||
-rw-r--r-- | drivers/arm/css/scmi/vendor/scmi_sq.c | 62 | ||||
-rw-r--r-- | drivers/arm/css/scmi/vendor/scmi_sq.h | 25 |
7 files changed, 704 insertions, 0 deletions
diff --git a/drivers/arm/css/scmi/scmi_ap_core_proto.c b/drivers/arm/css/scmi/scmi_ap_core_proto.c new file mode 100644 index 0000000..5941b87 --- /dev/null +++ b/drivers/arm/css/scmi/scmi_ap_core_proto.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> + +#include <arch_helpers.h> +#include <common/debug.h> +#include <drivers/arm/css/scmi.h> + +#include "scmi_private.h" + +/* + * API to set the SCMI AP core reset address and attributes + */ +int scmi_ap_core_set_reset_addr(void *p, uint64_t reset_addr, uint32_t attr) +{ + mailbox_mem_t *mbx_mem; + unsigned int token = 0; + int ret; + scmi_channel_t *ch = (scmi_channel_t *)p; + + validate_scmi_channel(ch); + + scmi_get_channel(ch); + + mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem); + mbx_mem->msg_header = SCMI_MSG_CREATE(SCMI_AP_CORE_PROTO_ID, + SCMI_AP_CORE_RESET_ADDR_SET_MSG, token); + mbx_mem->len = SCMI_AP_CORE_RESET_ADDR_SET_MSG_LEN; + mbx_mem->flags = SCMI_FLAG_RESP_POLL; + SCMI_PAYLOAD_ARG3(mbx_mem->payload, reset_addr & 0xffffffff, + reset_addr >> 32, attr); + + scmi_send_sync_command(ch); + + /* Get the return values */ + SCMI_PAYLOAD_RET_VAL1(mbx_mem->payload, ret); + assert(mbx_mem->len == SCMI_AP_CORE_RESET_ADDR_SET_RESP_LEN); + assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header)); + + scmi_put_channel(ch); + + return ret; +} + +/* + * API to get the SCMI AP core reset address and attributes + */ +int scmi_ap_core_get_reset_addr(void *p, uint64_t *reset_addr, uint32_t *attr) +{ + mailbox_mem_t *mbx_mem; + unsigned int token = 0; + int ret; + scmi_channel_t *ch = (scmi_channel_t *)p; + uint32_t lo_addr, hi_addr; + + validate_scmi_channel(ch); + + scmi_get_channel(ch); + + mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem); + mbx_mem->msg_header = SCMI_MSG_CREATE(SCMI_AP_CORE_PROTO_ID, + SCMI_AP_CORE_RESET_ADDR_GET_MSG, token); + mbx_mem->len = SCMI_AP_CORE_RESET_ADDR_GET_MSG_LEN; + mbx_mem->flags = SCMI_FLAG_RESP_POLL; + + scmi_send_sync_command(ch); + + /* Get the return values */ + SCMI_PAYLOAD_RET_VAL4(mbx_mem->payload, ret, lo_addr, hi_addr, *attr); + *reset_addr = lo_addr | (uint64_t)hi_addr << 32; + assert(mbx_mem->len == SCMI_AP_CORE_RESET_ADDR_GET_RESP_LEN); + assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header)); + + scmi_put_channel(ch); + + return ret; +} diff --git a/drivers/arm/css/scmi/scmi_common.c b/drivers/arm/css/scmi/scmi_common.c new file mode 100644 index 0000000..ec749fb --- /dev/null +++ b/drivers/arm/css/scmi/scmi_common.c @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> + +#include <arch_helpers.h> +#include <common/debug.h> +#include <drivers/arm/css/scmi.h> + +#include "scmi_private.h" + +#if HW_ASSISTED_COHERENCY +#define scmi_lock_init(lock) +#define scmi_lock_get(lock) spin_lock(lock) +#define scmi_lock_release(lock) spin_unlock(lock) +#else +#define scmi_lock_init(lock) bakery_lock_init(lock) +#define scmi_lock_get(lock) bakery_lock_get(lock) +#define scmi_lock_release(lock) bakery_lock_release(lock) +#endif + + +/* + * Private helper function to get exclusive access to SCMI channel. + */ +void scmi_get_channel(scmi_channel_t *ch) +{ + assert(ch->lock); + scmi_lock_get(ch->lock); + + /* Make sure any previous command has finished */ + assert(SCMI_IS_CHANNEL_FREE( + ((mailbox_mem_t *)(ch->info->scmi_mbx_mem))->status)); +} + +/* + * Private helper function to transfer ownership of channel from AP to SCP. + */ +void scmi_send_sync_command(scmi_channel_t *ch) +{ + mailbox_mem_t *mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem); + + SCMI_MARK_CHANNEL_BUSY(mbx_mem->status); + + /* + * Ensure that any write to the SCMI payload area is seen by SCP before + * we write to the doorbell register. If these 2 writes were reordered + * by the CPU then SCP would read stale payload data + */ + dmbst(); + + ch->info->ring_doorbell(ch->info); + /* + * Ensure that the write to the doorbell register is ordered prior to + * checking whether the channel is free. + */ + dmbsy(); + + /* Wait for channel to be free */ + while (!SCMI_IS_CHANNEL_FREE(mbx_mem->status)) + ; + + /* + * Ensure that any read to the SCMI payload area is done after reading + * mailbox status. If these 2 reads were reordered then the CPU would + * read invalid payload data + */ + dmbld(); +} + +/* + * Private helper function to release exclusive access to SCMI channel. + */ +void scmi_put_channel(scmi_channel_t *ch) +{ + /* Make sure any previous command has finished */ + assert(SCMI_IS_CHANNEL_FREE( + ((mailbox_mem_t *)(ch->info->scmi_mbx_mem))->status)); + + assert(ch->lock); + scmi_lock_release(ch->lock); +} + +/* + * API to query the SCMI protocol version. + */ +int scmi_proto_version(void *p, uint32_t proto_id, uint32_t *version) +{ + mailbox_mem_t *mbx_mem; + unsigned int token = 0; + int ret; + scmi_channel_t *ch = (scmi_channel_t *)p; + + validate_scmi_channel(ch); + + scmi_get_channel(ch); + + mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem); + mbx_mem->msg_header = SCMI_MSG_CREATE(proto_id, SCMI_PROTO_VERSION_MSG, + token); + mbx_mem->len = SCMI_PROTO_VERSION_MSG_LEN; + mbx_mem->flags = SCMI_FLAG_RESP_POLL; + + scmi_send_sync_command(ch); + + /* Get the return values */ + SCMI_PAYLOAD_RET_VAL2(mbx_mem->payload, ret, *version); + assert(mbx_mem->len == SCMI_PROTO_VERSION_RESP_LEN); + assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header)); + + scmi_put_channel(ch); + + return ret; +} + +/* + * API to query the protocol message attributes for a SCMI protocol. + */ +int scmi_proto_msg_attr(void *p, uint32_t proto_id, + uint32_t command_id, uint32_t *attr) +{ + mailbox_mem_t *mbx_mem; + unsigned int token = 0; + int ret; + scmi_channel_t *ch = (scmi_channel_t *)p; + + validate_scmi_channel(ch); + + scmi_get_channel(ch); + + mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem); + mbx_mem->msg_header = SCMI_MSG_CREATE(proto_id, + SCMI_PROTO_MSG_ATTR_MSG, token); + mbx_mem->len = SCMI_PROTO_MSG_ATTR_MSG_LEN; + mbx_mem->flags = SCMI_FLAG_RESP_POLL; + SCMI_PAYLOAD_ARG1(mbx_mem->payload, command_id); + + scmi_send_sync_command(ch); + + /* Get the return values */ + SCMI_PAYLOAD_RET_VAL2(mbx_mem->payload, ret, *attr); + assert(mbx_mem->len == SCMI_PROTO_MSG_ATTR_RESP_LEN); + assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header)); + + scmi_put_channel(ch); + + return ret; +} + +/* + * SCMI Driver initialization API. Returns initialized channel on success + * or NULL on error. The return type is an opaque void pointer. + */ +void *scmi_init(scmi_channel_t *ch) +{ + uint32_t version; + int ret; + + assert(ch && ch->info); + assert(ch->info->db_reg_addr); + assert(ch->info->db_modify_mask); + assert(ch->info->db_preserve_mask); + assert(ch->info->ring_doorbell != NULL); + + assert(ch->lock); + + scmi_lock_init(ch->lock); + + ch->is_initialized = 1; + + ret = scmi_proto_version(ch, SCMI_PWR_DMN_PROTO_ID, &version); + if (ret != SCMI_E_SUCCESS) { + WARN("SCMI power domain protocol version message failed\n"); + goto error; + } + + if (!is_scmi_version_compatible(SCMI_PWR_DMN_PROTO_VER, version)) { + WARN("SCMI power domain protocol version 0x%x incompatible with driver version 0x%x\n", + version, SCMI_PWR_DMN_PROTO_VER); + goto error; + } + + VERBOSE("SCMI power domain protocol version 0x%x detected\n", version); + + ret = scmi_proto_version(ch, SCMI_SYS_PWR_PROTO_ID, &version); + if ((ret != SCMI_E_SUCCESS)) { + WARN("SCMI system power protocol version message failed\n"); + goto error; + } + + if (!is_scmi_version_compatible(SCMI_SYS_PWR_PROTO_VER, version)) { + WARN("SCMI system power management protocol version 0x%x incompatible with driver version 0x%x\n", + version, SCMI_SYS_PWR_PROTO_VER); + goto error; + } + + VERBOSE("SCMI system power management protocol version 0x%x detected\n", + version); + + INFO("SCMI driver initialized\n"); + + return (void *)ch; + +error: + ch->is_initialized = 0; + return NULL; +} diff --git a/drivers/arm/css/scmi/scmi_private.h b/drivers/arm/css/scmi/scmi_private.h new file mode 100644 index 0000000..a684ca5 --- /dev/null +++ b/drivers/arm/css/scmi/scmi_private.h @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef SCMI_PRIVATE_H +#define SCMI_PRIVATE_H + +#include <lib/mmio.h> + +/* + * SCMI power domain management protocol message and response lengths. It is + * calculated as sum of length in bytes of the message header (4) and payload + * area (the number of bytes of parameters or return values in the payload). + */ +#define SCMI_PROTO_VERSION_MSG_LEN 4 +#define SCMI_PROTO_VERSION_RESP_LEN 12 + +#define SCMI_PROTO_MSG_ATTR_MSG_LEN 8 +#define SCMI_PROTO_MSG_ATTR_RESP_LEN 12 + +#define SCMI_AP_CORE_RESET_ADDR_SET_MSG_LEN 16 +#define SCMI_AP_CORE_RESET_ADDR_SET_RESP_LEN 8 + +#define SCMI_AP_CORE_RESET_ADDR_GET_MSG_LEN 4 +#define SCMI_AP_CORE_RESET_ADDR_GET_RESP_LEN 20 + +#define SCMI_PWR_STATE_SET_MSG_LEN 16 +#define SCMI_PWR_STATE_SET_RESP_LEN 8 + +#define SCMI_PWR_STATE_GET_MSG_LEN 8 +#define SCMI_PWR_STATE_GET_RESP_LEN 12 + +#define SCMI_SYS_PWR_STATE_SET_MSG_LEN 12 +#define SCMI_SYS_PWR_STATE_SET_RESP_LEN 8 + +#define SCMI_SYS_PWR_STATE_GET_MSG_LEN 4 +#define SCMI_SYS_PWR_STATE_GET_RESP_LEN 12 + +/* SCMI message header format bit field */ +#define SCMI_MSG_ID_SHIFT 0 +#define SCMI_MSG_ID_WIDTH 8 +#define SCMI_MSG_ID_MASK ((1 << SCMI_MSG_ID_WIDTH) - 1) + +#define SCMI_MSG_TYPE_SHIFT 8 +#define SCMI_MSG_TYPE_WIDTH 2 +#define SCMI_MSG_TYPE_MASK ((1 << SCMI_MSG_TYPE_WIDTH) - 1) + +#define SCMI_MSG_PROTO_ID_SHIFT 10 +#define SCMI_MSG_PROTO_ID_WIDTH 8 +#define SCMI_MSG_PROTO_ID_MASK ((1 << SCMI_MSG_PROTO_ID_WIDTH) - 1) + +#define SCMI_MSG_TOKEN_SHIFT 18 +#define SCMI_MSG_TOKEN_WIDTH 10 +#define SCMI_MSG_TOKEN_MASK ((1 << SCMI_MSG_TOKEN_WIDTH) - 1) + + +/* SCMI mailbox flags */ +#define SCMI_FLAG_RESP_POLL 0 +#define SCMI_FLAG_RESP_INT 1 + +/* SCMI power domain protocol `POWER_STATE_SET` message flags */ +#define SCMI_PWR_STATE_SET_FLAG_SYNC 0 +#define SCMI_PWR_STATE_SET_FLAG_ASYNC 1 + +/* + * Helper macro to create an SCMI message header given protocol, message id + * and token. + */ +#define SCMI_MSG_CREATE(_protocol, _msg_id, _token) \ + ((((_protocol) & SCMI_MSG_PROTO_ID_MASK) << SCMI_MSG_PROTO_ID_SHIFT) | \ + (((_msg_id) & SCMI_MSG_ID_MASK) << SCMI_MSG_ID_SHIFT) | \ + (((_token) & SCMI_MSG_TOKEN_MASK) << SCMI_MSG_TOKEN_SHIFT)) + +/* Helper macro to get the token from a SCMI message header */ +#define SCMI_MSG_GET_TOKEN(_msg) \ + (((_msg) >> SCMI_MSG_TOKEN_SHIFT) & SCMI_MSG_TOKEN_MASK) + +/* SCMI Channel Status bit fields */ +#define SCMI_CH_STATUS_RES0_MASK 0xFFFFFFFE +#define SCMI_CH_STATUS_FREE_SHIFT 0 +#define SCMI_CH_STATUS_FREE_WIDTH 1 +#define SCMI_CH_STATUS_FREE_MASK ((1 << SCMI_CH_STATUS_FREE_WIDTH) - 1) + +/* Helper macros to check and write the channel status */ +#define SCMI_IS_CHANNEL_FREE(status) \ + (!!(((status) >> SCMI_CH_STATUS_FREE_SHIFT) & SCMI_CH_STATUS_FREE_MASK)) + +#define SCMI_MARK_CHANNEL_BUSY(status) do { \ + assert(SCMI_IS_CHANNEL_FREE(status)); \ + (status) &= ~(SCMI_CH_STATUS_FREE_MASK << \ + SCMI_CH_STATUS_FREE_SHIFT); \ + } while (0) + +/* Helper macros to copy arguments to the mailbox payload */ +#define SCMI_PAYLOAD_ARG1(payld_arr, arg1) \ + mmio_write_32((uintptr_t)&payld_arr[0], arg1) + +#define SCMI_PAYLOAD_ARG2(payld_arr, arg1, arg2) do { \ + SCMI_PAYLOAD_ARG1(payld_arr, arg1); \ + mmio_write_32((uintptr_t)&payld_arr[1], arg2); \ + } while (0) + +#define SCMI_PAYLOAD_ARG3(payld_arr, arg1, arg2, arg3) do { \ + SCMI_PAYLOAD_ARG2(payld_arr, arg1, arg2); \ + mmio_write_32((uintptr_t)&payld_arr[2], arg3); \ + } while (0) + +/* Helper macros to read return values from the mailbox payload */ +#define SCMI_PAYLOAD_RET_VAL1(payld_arr, val1) \ + (val1) = mmio_read_32((uintptr_t)&payld_arr[0]) + +#define SCMI_PAYLOAD_RET_VAL2(payld_arr, val1, val2) do { \ + SCMI_PAYLOAD_RET_VAL1(payld_arr, val1); \ + (val2) = mmio_read_32((uintptr_t)&payld_arr[1]); \ + } while (0) + +#define SCMI_PAYLOAD_RET_VAL3(payld_arr, val1, val2, val3) do { \ + SCMI_PAYLOAD_RET_VAL2(payld_arr, val1, val2); \ + (val3) = mmio_read_32((uintptr_t)&payld_arr[2]); \ + } while (0) + +#define SCMI_PAYLOAD_RET_VAL4(payld_arr, val1, val2, val3, val4) do { \ + SCMI_PAYLOAD_RET_VAL3(payld_arr, val1, val2, val3); \ + (val4) = mmio_read_32((uintptr_t)&payld_arr[3]); \ + } while (0) + +/* + * Private data structure for representing the mailbox memory layout. Refer + * the SCMI specification for more details. + */ +typedef struct mailbox_mem { + uint32_t res_a; /* Reserved */ + volatile uint32_t status; + uint64_t res_b; /* Reserved */ + uint32_t flags; + volatile uint32_t len; + volatile uint32_t msg_header; + uint32_t payload[]; +} mailbox_mem_t; + + +/* Private APIs for use within SCMI driver */ +void scmi_get_channel(scmi_channel_t *ch); +void scmi_send_sync_command(scmi_channel_t *ch); +void scmi_put_channel(scmi_channel_t *ch); + +static inline void validate_scmi_channel(scmi_channel_t *ch) +{ + assert(ch && ch->is_initialized); + assert(ch->info && ch->info->scmi_mbx_mem); +} + +/* + * SCMI vendor specific protocol + */ +#define SCMI_SYS_VENDOR_EXT_PROTO_ID 0x80 + +#endif /* SCMI_PRIVATE_H */ diff --git a/drivers/arm/css/scmi/scmi_pwr_dmn_proto.c b/drivers/arm/css/scmi/scmi_pwr_dmn_proto.c new file mode 100644 index 0000000..a342aa8 --- /dev/null +++ b/drivers/arm/css/scmi/scmi_pwr_dmn_proto.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> + +#include <arch_helpers.h> +#include <common/debug.h> +#include <drivers/arm/css/scmi.h> + +#include "scmi_private.h" + +/* + * API to set the SCMI power domain power state. + */ +int scmi_pwr_state_set(void *p, uint32_t domain_id, + uint32_t scmi_pwr_state) +{ + mailbox_mem_t *mbx_mem; + unsigned int token = 0; + int ret; + + /* + * Only asynchronous mode of `set power state` command is allowed on + * application processors. + */ + uint32_t pwr_state_set_msg_flag = SCMI_PWR_STATE_SET_FLAG_ASYNC; + scmi_channel_t *ch = (scmi_channel_t *)p; + + validate_scmi_channel(ch); + + scmi_get_channel(ch); + + mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem); + mbx_mem->msg_header = SCMI_MSG_CREATE(SCMI_PWR_DMN_PROTO_ID, + SCMI_PWR_STATE_SET_MSG, token); + mbx_mem->len = SCMI_PWR_STATE_SET_MSG_LEN; + mbx_mem->flags = SCMI_FLAG_RESP_POLL; + SCMI_PAYLOAD_ARG3(mbx_mem->payload, pwr_state_set_msg_flag, + domain_id, scmi_pwr_state); + + scmi_send_sync_command(ch); + + /* Get the return values */ + SCMI_PAYLOAD_RET_VAL1(mbx_mem->payload, ret); + assert(mbx_mem->len == SCMI_PWR_STATE_SET_RESP_LEN); + assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header)); + + scmi_put_channel(ch); + + return ret; +} + +/* + * API to get the SCMI power domain power state. + */ +int scmi_pwr_state_get(void *p, uint32_t domain_id, + uint32_t *scmi_pwr_state) +{ + mailbox_mem_t *mbx_mem; + unsigned int token = 0; + int ret; + scmi_channel_t *ch = (scmi_channel_t *)p; + + validate_scmi_channel(ch); + + scmi_get_channel(ch); + + mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem); + mbx_mem->msg_header = SCMI_MSG_CREATE(SCMI_PWR_DMN_PROTO_ID, + SCMI_PWR_STATE_GET_MSG, token); + mbx_mem->len = SCMI_PWR_STATE_GET_MSG_LEN; + mbx_mem->flags = SCMI_FLAG_RESP_POLL; + SCMI_PAYLOAD_ARG1(mbx_mem->payload, domain_id); + + scmi_send_sync_command(ch); + + /* Get the return values */ + SCMI_PAYLOAD_RET_VAL2(mbx_mem->payload, ret, *scmi_pwr_state); + assert(mbx_mem->len == SCMI_PWR_STATE_GET_RESP_LEN); + assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header)); + + scmi_put_channel(ch); + + return ret; +} diff --git a/drivers/arm/css/scmi/scmi_sys_pwr_proto.c b/drivers/arm/css/scmi/scmi_sys_pwr_proto.c new file mode 100644 index 0000000..c8e62d1 --- /dev/null +++ b/drivers/arm/css/scmi/scmi_sys_pwr_proto.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> + +#include <arch_helpers.h> +#include <common/debug.h> +#include <drivers/arm/css/scmi.h> + +#include "scmi_private.h" + +/* + * API to set the SCMI system power state + */ +int scmi_sys_pwr_state_set(void *p, uint32_t flags, uint32_t system_state) +{ + mailbox_mem_t *mbx_mem; + unsigned int token = 0; + int ret; + scmi_channel_t *ch = (scmi_channel_t *)p; + + validate_scmi_channel(ch); + + scmi_get_channel(ch); + + mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem); + mbx_mem->msg_header = SCMI_MSG_CREATE(SCMI_SYS_PWR_PROTO_ID, + SCMI_SYS_PWR_STATE_SET_MSG, token); + mbx_mem->len = SCMI_SYS_PWR_STATE_SET_MSG_LEN; + mbx_mem->flags = SCMI_FLAG_RESP_POLL; + SCMI_PAYLOAD_ARG2(mbx_mem->payload, flags, system_state); + + scmi_send_sync_command(ch); + + /* Get the return values */ + SCMI_PAYLOAD_RET_VAL1(mbx_mem->payload, ret); + assert(mbx_mem->len == SCMI_SYS_PWR_STATE_SET_RESP_LEN); + assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header)); + + scmi_put_channel(ch); + + return ret; +} + +/* + * API to get the SCMI system power state + */ +int scmi_sys_pwr_state_get(void *p, uint32_t *system_state) +{ + mailbox_mem_t *mbx_mem; + unsigned int token = 0; + int ret; + scmi_channel_t *ch = (scmi_channel_t *)p; + + validate_scmi_channel(ch); + + scmi_get_channel(ch); + + mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem); + mbx_mem->msg_header = SCMI_MSG_CREATE(SCMI_SYS_PWR_PROTO_ID, + SCMI_SYS_PWR_STATE_GET_MSG, token); + mbx_mem->len = SCMI_SYS_PWR_STATE_GET_MSG_LEN; + mbx_mem->flags = SCMI_FLAG_RESP_POLL; + + scmi_send_sync_command(ch); + + /* Get the return values */ + SCMI_PAYLOAD_RET_VAL2(mbx_mem->payload, ret, *system_state); + assert(mbx_mem->len == SCMI_SYS_PWR_STATE_GET_RESP_LEN); + assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header)); + + scmi_put_channel(ch); + + return ret; +} diff --git a/drivers/arm/css/scmi/vendor/scmi_sq.c b/drivers/arm/css/scmi/vendor/scmi_sq.c new file mode 100644 index 0000000..f185424 --- /dev/null +++ b/drivers/arm/css/scmi/vendor/scmi_sq.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> + +#include <arch_helpers.h> +#include <common/debug.h> +#include <drivers/arm/css/scmi.h> + +#include "scmi_private.h" +#include "scmi_sq.h" + +#include <sq_common.h> + +/* SCMI messge ID to get the available DRAM region */ +#define SCMI_VENDOR_EXT_MEMINFO_GET_MSG 0x3 + +#define SCMI_VENDOR_EXT_MEMINFO_GET_MSG_LEN 4 + +/* + * API to get the available DRAM region + */ +int scmi_get_draminfo(void *p, struct draminfo *info) +{ + mailbox_mem_t *mbx_mem; + int token = 0, ret; + scmi_channel_t *ch = (scmi_channel_t *)p; + struct dram_info_resp response; + + validate_scmi_channel(ch); + + scmi_get_channel(ch); + + mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem); + mbx_mem->msg_header = SCMI_MSG_CREATE(SCMI_SYS_VENDOR_EXT_PROTO_ID, + SCMI_VENDOR_EXT_MEMINFO_GET_MSG, token); + mbx_mem->len = SCMI_VENDOR_EXT_MEMINFO_GET_MSG_LEN; + mbx_mem->flags = SCMI_FLAG_RESP_POLL; + + scmi_send_sync_command(ch); + + /* + * Ensure that any read to the SCPI payload area is done after reading + * the MHU register. If these 2 reads were reordered then the CPU would + * read invalid payload data + */ + dmbld(); + + /* Get the return values */ + SCMI_PAYLOAD_RET_VAL1(mbx_mem->payload, ret); + + memcpy(&response, (void *)mbx_mem->payload, sizeof(response)); + + scmi_put_channel(ch); + + *info = response.info; + + return ret; +} diff --git a/drivers/arm/css/scmi/vendor/scmi_sq.h b/drivers/arm/css/scmi/vendor/scmi_sq.h new file mode 100644 index 0000000..aee1a3a --- /dev/null +++ b/drivers/arm/css/scmi/vendor/scmi_sq.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef SCMI_SQ_H +#define SCMI_SQ_H + +#include <stddef.h> +#include <stdint.h> + +#include <sq_common.h> + +/* Structure to represent available DRAM region */ +struct dram_info_resp { + int status; + int reserved; + struct draminfo info; +}; + +/* API to get the available DRAM region */ +int scmi_get_draminfo(void *p, struct draminfo *info); + +#endif /* SCMI_SQ_H */ |