diff --git a/drivers/scmi-msg/common.h b/drivers/scmi-msg/common.h index 62f3087df..6b186d07d 100644 --- a/drivers/scmi-msg/common.h +++ b/drivers/scmi-msg/common.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: BSD-3-Clause */ /* - * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved. * Copyright (c) 2019-2020, Linaro Limited */ #ifndef SCMI_MSG_COMMON_H @@ -15,6 +15,7 @@ #include "clock.h" #include "power_domain.h" #include "reset_domain.h" +#include "sensor.h" #define SCMI_VERSION 0x20000U #define SCMI_IMPL_VERSION 0U @@ -118,6 +119,13 @@ scmi_msg_handler_t scmi_msg_get_rstd_handler(struct scmi_msg *msg); */ scmi_msg_handler_t scmi_msg_get_pd_handler(struct scmi_msg *msg); +/* + * scmi_msg_get_sensor_handler - Return a handler for a sensor message + * @msg - message to process + * Return a function handler for the message or NULL + */ +scmi_msg_handler_t scmi_msg_get_sensor_handler(struct scmi_msg *msg); + /* * Process Read, process and write response for input SCMI message * diff --git a/drivers/scmi-msg/entry.c b/drivers/scmi-msg/entry.c index 399115c6d..5ac68e1e6 100644 --- a/drivers/scmi-msg/entry.c +++ b/drivers/scmi-msg/entry.c @@ -15,6 +15,7 @@ #pragma weak scmi_msg_get_rstd_handler #pragma weak scmi_msg_get_pd_handler #pragma weak scmi_msg_get_voltage_handler +#pragma weak scmi_msg_get_sensor_handler scmi_msg_handler_t scmi_msg_get_clock_handler(struct scmi_msg *msg __unused) { @@ -36,6 +37,11 @@ scmi_msg_handler_t scmi_msg_get_voltage_handler(struct scmi_msg *msg __unused) return NULL; } +scmi_msg_handler_t scmi_msg_get_sensor_handler(struct scmi_msg *msg __unused) +{ + return NULL; +} + void scmi_status_response(struct scmi_msg *msg, int32_t status) { assert(msg->out && msg->out_size >= sizeof(int32_t)); @@ -75,6 +81,9 @@ void scmi_process_message(struct scmi_msg *msg) case SCMI_PROTOCOL_ID_POWER_DOMAIN: handler = scmi_msg_get_pd_handler(msg); break; + case SCMI_PROTOCOL_ID_SENSOR: + handler = scmi_msg_get_sensor_handler(msg); + break; default: break; } diff --git a/drivers/scmi-msg/sensor.c b/drivers/scmi-msg/sensor.c new file mode 100644 index 000000000..a47018d88 --- /dev/null +++ b/drivers/scmi-msg/sensor.c @@ -0,0 +1,277 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright 2021-2024 NXP + */ + +#include +#include + +#include "common.h" + +#include +#include +#include + +static bool message_id_is_supported(size_t message_id); + +uint16_t plat_scmi_sensor_count(unsigned int agent_id __unused) +{ + if (sensor_ops.sensor_count != NULL) { + return sensor_ops.sensor_count(agent_id); + } + + return 0U; +} + +uint8_t plat_scmi_sensor_max_requests(unsigned int agent_id __unused) +{ + if (sensor_ops.sensor_max_request != NULL) { + return sensor_ops.sensor_max_request(agent_id); + } + + return 0U; +} + +uint32_t plat_scmi_sensor_reg(unsigned int agent_id __unused, + unsigned int *addr) +{ + if (sensor_ops.get_sensor_req != NULL) { + return sensor_ops.get_sensor_req(agent_id, addr); + } + + return 0U; +} + +int32_t plat_scmi_sensor_reading_get(uint32_t agent_id __unused, + uint16_t sensor_id __unused, + uint32_t *val __unused) +{ + if (sensor_ops.sensor_reading_get != NULL) { + return sensor_ops.sensor_reading_get(agent_id, sensor_id, val); + } + + return 0; +} + +uint32_t plat_scmi_sensor_description_get(uint32_t agent_id __unused, + uint16_t desc_index __unused, + struct scmi_sensor_desc *desc __unused) +{ + if (sensor_ops.sensor_description_get != NULL) { + return sensor_ops.sensor_description_get(agent_id, desc_index, desc); + } + + return 0U; +} + +uint32_t plat_scmi_sensor_update_interval(uint32_t agent_id __unused, + uint16_t sensor_id __unused) +{ + if (sensor_ops.sensor_update_interval != NULL) { + return sensor_ops.sensor_update_interval(agent_id, sensor_id); + } + + return 0U; +} + +uint32_t plat_scmi_sensor_state(uint32_t agent_id __unused, + uint16_t sensor_id __unused) +{ + if (sensor_ops.sensor_state != NULL) { + return sensor_ops.sensor_state(agent_id, sensor_id); + } + + return 0U; +} + +uint32_t plat_scmi_sensor_timestamped(uint32_t agent_id __unused, + uint16_t sensor_id __unused) +{ + if (sensor_ops.sensor_timestamped != NULL) { + return sensor_ops.sensor_timestamped(agent_id, sensor_id); + } + + return 0U; +} + +static void report_version(struct scmi_msg *msg) +{ + struct scmi_protocol_version_p2a return_values = { + .status = SCMI_SUCCESS, + .version = SCMI_PROTOCOL_VERSION_SENSOR, + }; + + if (msg->in_size != 0U) { + scmi_status_response(msg, SCMI_PROTOCOL_ERROR); + return; + } + + scmi_write_response(msg, &return_values, sizeof(return_values)); +} + +static void report_attributes(struct scmi_msg *msg) +{ + unsigned int addr[2]; + unsigned int len; + + struct scmi_protocol_attributes_p2a_sensor return_values = { + .status = SCMI_SUCCESS, + }; + + if (msg->in_size != 0U) { + scmi_status_response(msg, SCMI_PROTOCOL_ERROR); + return; + } + + return_values.num_sensors = plat_scmi_sensor_count(msg->agent_id); + return_values.max_reqs = plat_scmi_sensor_max_requests(msg->agent_id); + len = plat_scmi_sensor_reg(msg->agent_id, addr); + if (len != 0U) { + return_values.sensor_reg_low = addr[0]; + return_values.sensor_reg_high = addr[1]; + return_values.sensor_reg_len = len; + } + + scmi_write_response(msg, &return_values, sizeof(return_values)); +} + +static void report_message_attributes(struct scmi_msg *msg) +{ + struct scmi_protocol_message_attributes_a2p *in_args = (void *)msg->in; + struct scmi_protocol_message_attributes_p2a return_values = { + .status = SCMI_SUCCESS, + /* For this protocol, attributes shall be zero */ + .attributes = 0U, + }; + + if (msg->in_size != sizeof(*in_args)) { + scmi_status_response(msg, SCMI_PROTOCOL_ERROR); + return; + } + + if (!message_id_is_supported(in_args->message_id)) { + scmi_status_response(msg, SCMI_NOT_FOUND); + return; + } + + scmi_write_response(msg, &return_values, sizeof(return_values)); +} + +static void scmi_sensor_description_get(struct scmi_msg *msg) +{ + const struct scmi_sensor_description_get_a2p *in_args = (void *)msg->in; + struct scmi_sensor_description_get_p2a return_values = { + .status = SCMI_SUCCESS, + }; + struct scmi_sensor_desc desc; + unsigned int desc_index = 0U; + unsigned int num_sensor_flags; + + if (msg->in_size != sizeof(*in_args)) { + scmi_status_response(msg, SCMI_PROTOCOL_ERROR); + return; + } + + desc_index = SPECULATION_SAFE_VALUE(in_args->desc_index); + + num_sensor_flags = plat_scmi_sensor_description_get(msg->agent_id, desc_index, + &desc); + return_values.num_sensor_flags = num_sensor_flags; + + memcpy(msg->out, &return_values, sizeof(return_values)); + memcpy(msg->out + sizeof(return_values), &desc, sizeof(desc)); + msg->out_size_out = sizeof(return_values) + sizeof(struct scmi_sensor_desc); +} + +static void scmi_sensor_config_get(struct scmi_msg *msg) +{ + const struct scmi_sensor_config_get_a2p *in_args = (void *)msg->in; + struct scmi_sensor_config_get_p2a return_values = { + .status = SCMI_SUCCESS, + }; + unsigned int sensor_id = 0U; + uint32_t update_interval, state, timestamped; + + if (msg->in_size != sizeof(*in_args)) { + scmi_status_response(msg, SCMI_PROTOCOL_ERROR); + return; + } + + sensor_id = SPECULATION_SAFE_VALUE(in_args->sensor_id); + + if (sensor_id >= plat_scmi_sensor_count(msg->agent_id)) { + scmi_status_response(msg, SCMI_INVALID_PARAMETERS); + return; + } + + update_interval = plat_scmi_sensor_update_interval(msg->agent_id, sensor_id); + state = plat_scmi_sensor_state(msg->agent_id, sensor_id); + timestamped = plat_scmi_sensor_timestamped(msg->agent_id, sensor_id); + return_values.sensor_config = (update_interval << 11) | (timestamped << 1) | state; + + scmi_write_response(msg, &return_values, sizeof(return_values)); +} + +static void scmi_sensor_reading_get(struct scmi_msg *msg) +{ + const struct scmi_sensor_reading_get_a2p *in_args = (void *)msg->in; + struct scmi_sensor_reading_get_p2a return_values = { + .status = SCMI_SUCCESS, + }; + unsigned int sensor_id = 0U; + int32_t ret; + + if (msg->in_size != sizeof(*in_args)) { + scmi_status_response(msg, SCMI_PROTOCOL_ERROR); + return; + } + + sensor_id = SPECULATION_SAFE_VALUE(in_args->sensor_id); + + if (sensor_id >= plat_scmi_sensor_count(msg->agent_id)) { + scmi_status_response(msg, SCMI_INVALID_PARAMETERS); + return; + } + + ret = plat_scmi_sensor_reading_get(msg->agent_id, sensor_id, + (uint32_t *)&return_values.val); + if (ret) { + scmi_status_response(msg, SCMI_HARDWARE_ERROR); + return; + } + + scmi_write_response(msg, &return_values, sizeof(return_values)); +} + +static void scmi_sensor_list_update_intervals(struct scmi_msg *msg) +{ + /* TODO */ + scmi_status_response(msg, SCMI_NOT_SUPPORTED); +} + +static const scmi_msg_handler_t scmi_sensor_handler_table[SCMI_SENSOR_MAX] = { + [SCMI_PROTOCOL_VERSION] = report_version, + [SCMI_PROTOCOL_ATTRIBUTES] = report_attributes, + [SCMI_PROTOCOL_MESSAGE_ATTRIBUTES] = report_message_attributes, + [SCMI_SENSOR_DESCRIPTION_GET] = scmi_sensor_description_get, + [SCMI_SENSOR_CONFIG_GET] = scmi_sensor_config_get, + [SCMI_SENSOR_LIST_UPDATE_INTERVALS] = scmi_sensor_list_update_intervals, + [SCMI_SENSOR_READING_GET] = scmi_sensor_reading_get, +}; + +static bool message_id_is_supported(size_t message_id) +{ + return scmi_sensor_handler_table[message_id] != NULL; +} + +scmi_msg_handler_t scmi_msg_get_sensor_handler(struct scmi_msg *msg) +{ + unsigned int message_id = SPECULATION_SAFE_VALUE(msg->message_id); + + if (!message_id_is_supported(message_id)) { + VERBOSE("pd handle not found %u\n", msg->message_id); + return NULL; + } + + return scmi_sensor_handler_table[message_id]; +} diff --git a/drivers/scmi-msg/sensor.h b/drivers/scmi-msg/sensor.h new file mode 100644 index 000000000..28cbb1ed3 --- /dev/null +++ b/drivers/scmi-msg/sensor.h @@ -0,0 +1,125 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright 2023-2024 NXP + */ + +#ifndef SCMI_MSG_SENSOR_H +#define SCMI_MSG_SENSOR_H + +#include + +#include + +#define SCMI_PROTOCOL_VERSION_SENSOR 0x20000U + +/* + * Identifiers of the SCMI SENSOR Protocol commands + */ +enum scmi_sensor_command_id { + SCMI_SENSOR_DESCRIPTION_GET = 0x003, + SCMI_SENSOR_TRIP_POINT_NOTIFY = 0x004, + SCMI_SENSOR_TRIP_POINT_CONFIG = 0x005, + SCMI_SENSOR_READING_GET = 0x006, + SCMI_SENSOR_AXIS_DESCRIPTION_GET = 0x007, + SCMI_SENSOR_LIST_UPDATE_INTERVALS = 0x008, + SCMI_SENSOR_CONFIG_GET = 0x009, + SCMI_SENSOR_CONFIG_SET = 0x00A, + SCMI_SENSOR_CONTINUOUS_UPDATE_NOTIFY = 0x00B, + SCMI_SENSOR_MAX = 0x00C, +}; + +/* Protocol attributes */ +struct scmi_protocol_attributes_p2a_sensor { + int32_t status; + int16_t num_sensors; + uint8_t max_reqs; + uint8_t res; + uint32_t sensor_reg_low; + uint32_t sensor_reg_high; + uint32_t sensor_reg_len; +}; + +#define SCMI_SENSOR_NAME_LENGTH_MAX 16U + +struct scmi_sensor_desc { + uint32_t id; + uint32_t attr_low; + uint32_t attr_high; + uint8_t name[SCMI_SENSOR_NAME_LENGTH_MAX]; + uint32_t power; + uint32_t resolution; + int32_t min_range_low; + int32_t min_range_high; + int32_t max_range_low; + int32_t max_range_high; +}; + +struct scmi_sensor_description_get_a2p { + uint32_t desc_index; +}; + +struct scmi_sensor_description_get_p2a { + int32_t status; + uint32_t num_sensor_flags; +}; + +struct scmi_sensor_config_get_a2p { + uint32_t sensor_id; +}; + +struct scmi_sensor_config_get_p2a { + int32_t status; + uint32_t sensor_config; +}; + +/* + * Sensor Reading Get + */ +struct scmi_sensor_reading_get_a2p { + uint32_t sensor_id; + uint32_t flags; +}; + +struct scmi_sensor_val { + uint32_t value_low; + uint32_t value_high; + uint32_t timestap_low; + uint32_t timestap_high; +}; + +struct scmi_sensor_reading_get_p2a { + int32_t status; + struct scmi_sensor_val val; +}; + +typedef struct { + uint16_t (*sensor_count)(unsigned int agent_id); + uint8_t (*sensor_max_request)(unsigned int agent_id); + uint32_t (*get_sensor_req)(unsigned int agent_id, unsigned int *addr); + int32_t (*sensor_reading_get)(uint32_t agent_id, uint16_t sensor_id, + uint32_t *val); + uint32_t (*sensor_description_get)(unsigned int agent_id, uint16_t sensor_id, + struct scmi_sensor_desc *desc); + uint32_t (*sensor_update_interval)(uint32_t agent_id, uint16_t sensor_id); + uint32_t (*sensor_state)(uint32_t agent_id, uint16_t sensor_id); + uint16_t (*sensor_timestamped)(uint32_t agent_id, uint16_t sensor_id); +} plat_scmi_sensor_ops_t; + +#define REGISTER_SCMI_SENSOR_OPS(_sensor_count, _sensor_max_request, \ + _get_sensor_req, _sensor_reading_get, \ + _sensor_description_get, _sensor_update_interval, \ + _sensor_state, _sensor_timestamped) \ + const plat_scmi_sensor_ops_t sensor_ops = { \ + .sensor_count = _sensor_count, \ + .sensor_max_request = _sensor_max_request, \ + .get_sensor_req = _get_sensor_req, \ + .sensor_reading_get = _sensor_reading_get, \ + .sensor_description_get = _sensor_description_get, \ + .sensor_update_interval = _sensor_update_interval, \ + .sensor_state = _sensor_state, \ + .sensor_timestamped = _sensor_timestamped, \ + } + +extern const plat_scmi_sensor_ops_t sensor_ops; + +#endif /* SCMI_MSG_SENSOR_H */