summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYe Li <ye.li@nxp.com>2022-07-29 18:52:44 +0800
committerYe Li <ye.li@nxp.com>2022-07-31 17:07:26 +0800
commita33d90b8b053a165e3d0d21d0d8620dcca0f1740 (patch)
tree440ae00aaac2a710ea649a3cf97b066e375f47c8
parent6ff9cc720071cee39afbb97dedb795ea6339d6fa (diff)
LFU-372-1 thermal: Add SCMI Sensor based thermal driver
Add SCMI Sensor protocol based thermal driver to get temperature from SCMI platform server. Signed-off-by: Ye Li <ye.li@nxp.com> Reviewed-by: Alice Guo <alice.guo@nxp.com>
-rw-r--r--drivers/firmware/scmi/scmi_agent-uclass.c4
-rw-r--r--drivers/thermal/Kconfig6
-rw-r--r--drivers/thermal/Makefile1
-rw-r--r--drivers/thermal/scmi_thermal.c176
-rw-r--r--include/scmi_protocols.h90
5 files changed, 277 insertions, 0 deletions
diff --git a/drivers/firmware/scmi/scmi_agent-uclass.c b/drivers/firmware/scmi/scmi_agent-uclass.c
index 7695b03509..78e16d9170 100644
--- a/drivers/firmware/scmi/scmi_agent-uclass.c
+++ b/drivers/firmware/scmi/scmi_agent-uclass.c
@@ -94,6 +94,10 @@ static int scmi_bind_protocols(struct udevice *dev)
if (IS_ENABLED(CONFIG_POWER_DOMAIN))
drv = DM_DRIVER_GET(scmi_power_domain);
break;
+ case SCMI_PROTOCOL_ID_SENSOR:
+ if (IS_ENABLED(CONFIG_DM_THERMAL))
+ drv = DM_DRIVER_GET(scmi_thermal);
+ break;
default:
break;
}
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index a21f8b838c..8666d67483 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -42,6 +42,12 @@ config IMX_PMC_TEMPERATURE
Enable PMC Temperature Sensor on NXP i.MX8ULP. The driver supports
reading CPU temperature.
+config SCMI_THERMAL
+ bool "SCMI Sensor based thermal driver"
+ select SCMI_FIRMWARE
+ help
+ Enable SCMI Sensor protocol based thermal driver to get temperature.
+
config TI_DRA7_THERMAL
bool "Temperature sensor driver for TI dra7xx SOCs"
help
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index a3b72418fc..779f7d9642 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_IMX_SCU_THERMAL) += imx_scu_thermal.o
obj-$(CONFIG_TI_DRA7_THERMAL) += ti-bandgap.o
obj-$(CONFIG_IMX_TMU) += imx_tmu.o
obj-$(CONFIG_IMX_PMC_TEMPERATURE) += imx_pmc_temperature.o
+obj-$(CONFIG_SCMI_THERMAL) += scmi_thermal.o
diff --git a/drivers/thermal/scmi_thermal.c b/drivers/thermal/scmi_thermal.c
new file mode 100644
index 0000000000..bccfd28c2f
--- /dev/null
+++ b/drivers/thermal/scmi_thermal.c
@@ -0,0 +1,176 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2022 NXP
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <thermal.h>
+#include <scmi_agent.h>
+#include <scmi_protocols.h>
+#include <asm/types.h>
+#include <dm/device-internal.h>
+#include <dm/device.h>
+
+struct scmi_thermal_priv {
+ s16 num_sensors;
+ s16 thermal_id;
+ struct scmi_sensor_descrition_get_p2a *desc_buf;
+ size_t desc_buf_size;
+};
+
+static int scmi_thermal_get_temp(struct udevice *dev, int *temp)
+{
+ struct scmi_thermal_priv *priv = dev_get_priv(dev);
+ struct scmi_sensor_reading_get_a2p in = { priv->thermal_id };
+ struct scmi_sensor_reading_get_p2a out = { 0 };
+ struct scmi_msg msg = {
+ .protocol_id = SCMI_PROTOCOL_ID_SENSOR,
+ .message_id = SCMI_SENSOR_READING_GET,
+ .in_msg = (u8 *)&in,
+ .in_msg_sz = sizeof(in),
+ .out_msg = (u8 *)&out,
+ .out_msg_sz = sizeof(out),
+ };
+ int ret;
+
+ ret = devm_scmi_process_msg(dev->parent, &msg);
+ if (ret)
+ return ret;
+
+ ret = scmi_to_linux_errno(out.status);
+ if (ret < 0)
+ return ret;
+
+ *temp = out.val.value_low;
+
+ return ret;
+}
+
+static int scmi_sensor_attributes_get(struct udevice *dev)
+{
+ struct scmi_protocol_attributes_p2a_sensor out = { 0 };
+ struct scmi_msg msg = {
+ .protocol_id = SCMI_PROTOCOL_ID_SENSOR,
+ .message_id = SCMI_PROTOCOL_ATTRIBUTES,
+ .in_msg = NULL,
+ .in_msg_sz = 0,
+ .out_msg = (u8 *)&out,
+ .out_msg_sz = sizeof(out),
+ };
+ int ret;
+ struct scmi_thermal_priv *priv = dev_get_priv(dev);
+
+ ret = devm_scmi_process_msg(dev->parent, &msg);
+ if (ret)
+ return ret;
+
+ ret = scmi_to_linux_errno(out.status);
+ if (ret < 0)
+ return ret;
+
+ priv->num_sensors = out.num_sensors;
+
+ dev_dbg(dev,"num_sensors %d\n", priv->num_sensors);
+
+ return 0;
+}
+
+static int scmi_sensor_description_get(struct udevice *dev, u32 start_ind,
+ struct scmi_sensor_descrition_get_p2a *desc_buf, size_t desc_buf_size)
+{
+ struct scmi_sensor_description_get_a2p in = { start_ind };
+ struct scmi_msg msg = {
+ .protocol_id = SCMI_PROTOCOL_ID_SENSOR,
+ .message_id = SCMI_SENSOR_DESCRIPTION_GET,
+ .in_msg = (u8 *)&in,
+ .in_msg_sz = sizeof(in),
+ .out_msg = (u8 *)desc_buf,
+ .out_msg_sz = desc_buf_size,
+ };
+ int ret;
+
+ ret = devm_scmi_process_msg(dev->parent, &msg);
+ if (ret)
+ return ret;
+
+ ret = scmi_to_linux_errno(desc_buf->status);
+ if (ret < 0)
+ return ret;
+
+ return ret;
+}
+
+static const struct dm_thermal_ops scmi_thermal_ops = {
+ .get_temp = scmi_thermal_get_temp,
+};
+
+static int scmi_thermal_probe(struct udevice *dev)
+{
+ int ret;
+ u16 num_returned, num_remaining, cnt;
+ u32 index = 0;
+ bool find = false;
+ struct scmi_sensor_desc *desc;
+ struct scmi_thermal_priv *priv = dev_get_priv(dev);
+
+ ret = scmi_sensor_attributes_get(dev);
+ if (ret){
+ dev_err(dev, "scmi_sensor_attributes_get failure %d\n", ret);
+ return ret;
+ }
+
+ priv->desc_buf_size = sizeof(struct scmi_sensor_descrition_get_p2a) +
+ (priv->num_sensors - 1) * sizeof(struct scmi_sensor_desc);
+ priv->desc_buf = (struct scmi_sensor_descrition_get_p2a *)calloc(1, priv->desc_buf_size);
+ if (!priv->desc_buf) {
+ dev_err(dev, "allocate desc_buffer failure\n");
+ return -ENOMEM;
+ }
+
+ do {
+ ret = scmi_sensor_description_get(dev, index, priv->desc_buf, priv->desc_buf_size);
+ if (ret){
+ dev_err(dev, "scmi_sensor_description_get failure %d\n", ret);
+ return ret;
+ }
+
+ num_returned = priv->desc_buf->num_sensor_flags & 0xffff;
+ num_remaining = (priv->desc_buf->num_sensor_flags >> 16) & 0xffff;
+
+ if (index + num_returned > priv->num_sensors) {
+ dev_err(dev, "Num of sensors can't exceed %d",
+ priv->num_sensors);
+ return -EINVAL;
+ }
+
+ for (cnt = 0; cnt < num_returned; cnt++) {
+ desc = &priv->desc_buf->desc[cnt];
+ if ((desc->attr_high & 0xff) == 0x2) {
+ priv->thermal_id = desc->id; /* Only get one thermal sensor */
+ dev_dbg(dev, "thermal id %u\n", priv->thermal_id);
+ find = true;
+ break;
+ }
+ }
+
+ index += num_returned;
+ } while (num_returned && num_remaining && !find);
+
+ if (!find) {
+ dev_err(dev, "Can't find thermal sensor device\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+U_BOOT_DRIVER(scmi_thermal) = {
+ .name = "scmi_thermal",
+ .id = UCLASS_THERMAL,
+ .ops = &scmi_thermal_ops,
+ .probe = scmi_thermal_probe,
+ .flags = DM_FLAG_PRE_RELOC,
+ .priv_auto = sizeof(struct scmi_thermal_priv),
+};
diff --git a/include/scmi_protocols.h b/include/scmi_protocols.h
index bcda4762d7..22b6a33a80 100644
--- a/include/scmi_protocols.h
+++ b/include/scmi_protocols.h
@@ -40,6 +40,12 @@ enum scmi_status_code {
SCMI_PROTOCOL_ERROR = -10,
};
+enum scmi_common_message_id {
+ SCMI_PROTOCOL_VERSION = 0x000,
+ SCMI_PROTOCOL_ATTRIBUTES = 0x001,
+ SCMI_PROTOCOL_MESSAGE_ATTRIBUTES = 0x002
+};
+
/*
* SCMI Clock Protocol
*/
@@ -323,4 +329,88 @@ struct scmi_power_get_state_out {
u32 state;
};
+/*
+ * SCMI Sensor protocol
+ */
+
+enum scmi_sensor_message_id {
+ SCMI_SENSOR_DESCRIPTION_GET = 0x3,
+ SCMI_SENSOR_TRIP_POINT_NOTIFY = 0x4,
+ SCMI_SENSOR_TRIP_POINT_CONFIG = 0x5,
+ SCMI_SENSOR_READING_GET = 0x6,
+ SCMI_SENSOR_AXIS_DESCRIPTION_GET = 0x7,
+ SCMI_SENSOR_LIST_UPDATE_INTERVALS = 0x8,
+ SCMI_SENSOR_CONFIG_GET = 0x9,
+ SCMI_SENSOR_CONFIG_SET = 0xA,
+ SCMI_SENSOR_CONTINUOUS_UPDATE_NOTIFY = 0xB,
+};
+
+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_MAX_STR_SIZE 16
+
+struct scmi_msg_resp_attrs {
+ s32 min_range_low;
+ s32 min_range_high;
+ s32 max_range_low;
+ s32 max_range_high;
+};
+
+struct scmi_sensor_desc {
+ u32 id;
+ u32 attr_low;
+ u32 attr_high;
+ u8 name[SCMI_MAX_STR_SIZE];
+ u32 power;
+ u32 resolution;
+ struct scmi_msg_resp_attrs scalar_attrs;
+};
+
+struct scmi_sensor_description_get_a2p {
+ uint32_t desc_index;
+};
+
+struct scmi_sensor_descrition_get_p2a {
+ int32_t status;
+ uint32_t num_sensor_flags;
+ struct scmi_sensor_desc desc[1];
+};
+
+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;
+};
+
#endif /* _SCMI_PROTOCOLS_H */