feat(scmi): add scmi sensor support

LF-4715-1 drivers: scmi-msg: add sensor support

Add scmi sensor support

Signed-off-by: Peng Fan <peng.fan@nxp.com>
Signed-off-by: Jacky Bai <ping.bai@nxp.com>
Change-Id: I810e270b138bf5486b32df121056bfa5103c129f
diff --git a/drivers/scmi-msg/common.h b/drivers/scmi-msg/common.h
index 62f3087..6b186d0 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
@@ -119,6 +120,13 @@
 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
  *
  * @msg: SCMI message context
diff --git a/drivers/scmi-msg/entry.c b/drivers/scmi-msg/entry.c
index 399115c..5ac68e1 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 @@
 	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 @@
 	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 0000000..a47018d
--- /dev/null
+++ b/drivers/scmi-msg/sensor.c
@@ -0,0 +1,277 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright 2021-2024 NXP
+ */
+
+#include <cdefs.h>
+#include <string.h>
+
+#include "common.h"
+
+#include <drivers/scmi-msg.h>
+#include <drivers/scmi.h>
+#include <lib/utils_def.h>
+
+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 0000000..28cbb1e
--- /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 <stdint.h>
+
+#include <lib/utils_def.h>
+
+#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 */