diff options
author | Ye Li <ye.li@nxp.com> | 2022-07-29 18:52:44 +0800 |
---|---|---|
committer | Ye Li <ye.li@nxp.com> | 2022-07-31 17:07:26 +0800 |
commit | a33d90b8b053a165e3d0d21d0d8620dcca0f1740 (patch) | |
tree | 440ae00aaac2a710ea649a3cf97b066e375f47c8 | |
parent | 6ff9cc720071cee39afbb97dedb795ea6339d6fa (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.c | 4 | ||||
-rw-r--r-- | drivers/thermal/Kconfig | 6 | ||||
-rw-r--r-- | drivers/thermal/Makefile | 1 | ||||
-rw-r--r-- | drivers/thermal/scmi_thermal.c | 176 | ||||
-rw-r--r-- | include/scmi_protocols.h | 90 |
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 */ |