mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-07 21:33:54 +00:00
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
This commit is contained in:
parent
13caddef46
commit
e63819f2bc
4 changed files with 420 additions and 1 deletions
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
277
drivers/scmi-msg/sensor.c
Normal file
277
drivers/scmi-msg/sensor.c
Normal file
|
@ -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];
|
||||
}
|
125
drivers/scmi-msg/sensor.h
Normal file
125
drivers/scmi-msg/sensor.h
Normal file
|
@ -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 */
|
Loading…
Add table
Reference in a new issue