Browse Source
Add SCMI power domain protocol, with POWER_STATE_NOTIFY and POWER_STATE_CHANGE_REQUESTED_NOTIFY not implemented. Reviewed-by: Jacky Bai <ping.bai@nxp.com> Signed-off-by: Peng Fan <peng.fan@nxp.com> Change-Id: Ia7c4db57c4c702667f8eaa630c924016e4a8bde0pull/1943/head
Peng Fan
3 years ago
4 changed files with 322 additions and 0 deletions
@ -0,0 +1,239 @@ |
|||
// SPDX-License-Identifier: BSD-3-Clause
|
|||
/*
|
|||
* Copyright (c) 2015-2020, Arm Limited and Contributors. All rights reserved. |
|||
* Copyright (c) 2019-2020, Linaro Limited |
|||
*/ |
|||
#include <cdefs.h> |
|||
#include <string.h> |
|||
|
|||
#include <drivers/scmi-msg.h> |
|||
#include <drivers/scmi.h> |
|||
#include <lib/utils_def.h> |
|||
|
|||
#include "common.h" |
|||
|
|||
#pragma weak plat_scmi_pd_count |
|||
#pragma weak plat_scmi_pd_get_name |
|||
#pragma weak plat_scmi_pd_get_state |
|||
#pragma weak plat_scmi_pd_set_state |
|||
#pragma weak plat_scmi_pd_statistics |
|||
#pragma weak plat_scmi_pd_get_attributes |
|||
|
|||
static bool message_id_is_supported(size_t message_id); |
|||
|
|||
size_t plat_scmi_pd_count(unsigned int agent_id __unused) |
|||
{ |
|||
return 0U; |
|||
} |
|||
|
|||
const char *plat_scmi_pd_get_name(unsigned int agent_id __unused, |
|||
unsigned int pd_id __unused) |
|||
{ |
|||
return NULL; |
|||
} |
|||
|
|||
unsigned int plat_scmi_pd_statistics(unsigned int agent_id __unused, |
|||
unsigned long *pd_id __unused) |
|||
{ |
|||
return 0U; |
|||
} |
|||
|
|||
unsigned int plat_scmi_pd_get_attributes(unsigned int agent_id __unused, |
|||
unsigned int pd_id __unused) |
|||
{ |
|||
return 0U; |
|||
} |
|||
|
|||
unsigned int plat_scmi_pd_get_state(unsigned int agent_id __unused, |
|||
unsigned int pd_id __unused) |
|||
{ |
|||
return 0U; |
|||
} |
|||
|
|||
int32_t plat_scmi_pd_set_state(unsigned int agent_id __unused, |
|||
unsigned int flags __unused, |
|||
unsigned int pd_id __unused, |
|||
unsigned int state __unused) |
|||
{ |
|||
return SCMI_NOT_SUPPORTED; |
|||
} |
|||
|
|||
static void report_version(struct scmi_msg *msg) |
|||
{ |
|||
struct scmi_protocol_version_p2a return_values = { |
|||
.status = SCMI_SUCCESS, |
|||
.version = SCMI_PROTOCOL_VERSION_PD, |
|||
}; |
|||
|
|||
if (msg->in_size != 0) { |
|||
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 long addr = 0UL; |
|||
unsigned int len; |
|||
|
|||
struct scmi_protocol_attributes_p2a_pd return_values = { |
|||
.status = SCMI_SUCCESS, |
|||
}; |
|||
|
|||
if (msg->in_size != 0) { |
|||
scmi_status_response(msg, SCMI_PROTOCOL_ERROR); |
|||
return; |
|||
} |
|||
|
|||
return_values.attributes = plat_scmi_pd_count(msg->agent_id); |
|||
len = plat_scmi_pd_statistics(msg->agent_id, &addr); |
|||
if (len != 0U) { |
|||
return_values.statistics_addr_low = (unsigned int)addr; |
|||
return_values.statistics_addr_high = (uint32_t)(addr >> 32); |
|||
return_values.statistics_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_pd_attributes(struct scmi_msg *msg) |
|||
{ |
|||
const struct scmi_pd_attributes_a2p *in_args = (void *)msg->in; |
|||
struct scmi_pd_attributes_p2a return_values = { |
|||
.status = SCMI_SUCCESS, |
|||
}; |
|||
const char *name = NULL; |
|||
unsigned int pd_id = 0U; |
|||
|
|||
if (msg->in_size != sizeof(*in_args)) { |
|||
scmi_status_response(msg, SCMI_PROTOCOL_ERROR); |
|||
return; |
|||
} |
|||
|
|||
pd_id = SPECULATION_SAFE_VALUE(in_args->pd_id); |
|||
|
|||
if (pd_id >= plat_scmi_pd_count(msg->agent_id)) { |
|||
scmi_status_response(msg, SCMI_INVALID_PARAMETERS); |
|||
return; |
|||
} |
|||
|
|||
name = plat_scmi_pd_get_name(msg->agent_id, pd_id); |
|||
if (name == NULL) { |
|||
scmi_status_response(msg, SCMI_NOT_FOUND); |
|||
return; |
|||
} |
|||
|
|||
COPY_NAME_IDENTIFIER(return_values.pd_name, name); |
|||
|
|||
return_values.attributes = plat_scmi_pd_get_attributes(msg->agent_id, pd_id); |
|||
|
|||
scmi_write_response(msg, &return_values, sizeof(return_values)); |
|||
} |
|||
|
|||
static void scmi_pd_state_get(struct scmi_msg *msg) |
|||
{ |
|||
const struct scmi_pd_state_get_a2p *in_args = (void *)msg->in; |
|||
unsigned int state = 0U; |
|||
struct scmi_pd_state_get_p2a return_values = { |
|||
.status = SCMI_SUCCESS, |
|||
}; |
|||
unsigned int pd_id = 0U; |
|||
|
|||
if (msg->in_size != sizeof(*in_args)) { |
|||
scmi_status_response(msg, SCMI_PROTOCOL_ERROR); |
|||
return; |
|||
} |
|||
|
|||
pd_id = SPECULATION_SAFE_VALUE(in_args->pd_id); |
|||
|
|||
if (pd_id >= plat_scmi_pd_count(msg->agent_id)) { |
|||
scmi_status_response(msg, SCMI_INVALID_PARAMETERS); |
|||
return; |
|||
} |
|||
|
|||
state = plat_scmi_pd_get_state(msg->agent_id, pd_id); |
|||
|
|||
return_values.power_state = state; |
|||
|
|||
scmi_write_response(msg, &return_values, sizeof(return_values)); |
|||
} |
|||
|
|||
static void scmi_pd_state_set(struct scmi_msg *msg) |
|||
{ |
|||
const struct scmi_pd_state_set_a2p *in_args = (void *)msg->in; |
|||
unsigned int flags = 0U; |
|||
int32_t status = 0; |
|||
unsigned int pd_id = 0U; |
|||
unsigned int state = 0U; |
|||
|
|||
if (msg->in_size != sizeof(*in_args)) { |
|||
scmi_status_response(msg, SCMI_PROTOCOL_ERROR); |
|||
return; |
|||
} |
|||
|
|||
pd_id = SPECULATION_SAFE_VALUE(in_args->pd_id); |
|||
|
|||
if (pd_id >= plat_scmi_pd_count(msg->agent_id)) { |
|||
scmi_status_response(msg, SCMI_INVALID_PARAMETERS); |
|||
return; |
|||
} |
|||
|
|||
flags = SPECULATION_SAFE_VALUE(in_args->flags); |
|||
state = SPECULATION_SAFE_VALUE(in_args->power_state); |
|||
|
|||
status = plat_scmi_pd_set_state(msg->agent_id, flags, pd_id, state); |
|||
|
|||
scmi_status_response(msg, status); |
|||
} |
|||
|
|||
static const scmi_msg_handler_t scmi_pd_handler_table[] = { |
|||
[SCMI_PROTOCOL_VERSION] = report_version, |
|||
[SCMI_PROTOCOL_ATTRIBUTES] = report_attributes, |
|||
[SCMI_PROTOCOL_MESSAGE_ATTRIBUTES] = report_message_attributes, |
|||
[SCMI_PD_ATTRIBUTES] = scmi_pd_attributes, |
|||
[SCMI_PD_STATE_SET] = scmi_pd_state_set, |
|||
[SCMI_PD_STATE_GET] = scmi_pd_state_get, |
|||
}; |
|||
|
|||
static bool message_id_is_supported(size_t message_id) |
|||
{ |
|||
return (message_id < ARRAY_SIZE(scmi_pd_handler_table)) && |
|||
(scmi_pd_handler_table[message_id] != NULL); |
|||
} |
|||
|
|||
scmi_msg_handler_t scmi_msg_get_pd_handler(struct scmi_msg *msg) |
|||
{ |
|||
const size_t array_size = ARRAY_SIZE(scmi_pd_handler_table); |
|||
unsigned int message_id = SPECULATION_SAFE_VALUE(msg->message_id); |
|||
|
|||
if (message_id >= array_size) { |
|||
VERBOSE("pd handle not found %u", msg->message_id); |
|||
return NULL; |
|||
} |
|||
|
|||
return scmi_pd_handler_table[message_id]; |
|||
} |
@ -0,0 +1,72 @@ |
|||
/* SPDX-License-Identifier: BSD-3-Clause */ |
|||
/*
|
|||
* Copyright 2021 NXP |
|||
*/ |
|||
|
|||
#ifndef SCMI_MSG_PD_H |
|||
#define SCMI_MSG_PD_H |
|||
|
|||
#include <stdint.h> |
|||
|
|||
#include <lib/utils_def.h> |
|||
|
|||
#define SCMI_PROTOCOL_VERSION_PD 0x21000U |
|||
|
|||
/*
|
|||
* Identifiers of the SCMI POWER DOMAIN Protocol commands |
|||
*/ |
|||
enum scmi_pd_command_id { |
|||
SCMI_PD_ATTRIBUTES = 0x003, |
|||
SCMI_PD_STATE_SET = 0x004, |
|||
SCMI_PD_STATE_GET = 0x005, |
|||
}; |
|||
|
|||
/* Protocol attributes */ |
|||
struct scmi_pd_attributes_a2p { |
|||
uint32_t pd_id; |
|||
}; |
|||
|
|||
struct scmi_protocol_attributes_p2a_pd { |
|||
int32_t status; |
|||
uint32_t attributes; |
|||
uint32_t statistics_addr_low; |
|||
uint32_t statistics_addr_high; |
|||
uint32_t statistics_len; |
|||
}; |
|||
|
|||
#define SCMI_PD_NAME_LENGTH_MAX 16U |
|||
|
|||
struct scmi_pd_attributes_p2a { |
|||
int32_t status; |
|||
uint32_t attributes; |
|||
char pd_name[SCMI_PD_NAME_LENGTH_MAX]; |
|||
}; |
|||
|
|||
/*
|
|||
* Power Domain State Get |
|||
*/ |
|||
|
|||
struct scmi_pd_state_get_a2p { |
|||
uint32_t pd_id; |
|||
}; |
|||
|
|||
struct scmi_pd_state_get_p2a { |
|||
int32_t status; |
|||
uint32_t power_state; |
|||
}; |
|||
|
|||
/*
|
|||
* Power domain State Set |
|||
*/ |
|||
|
|||
struct scmi_pd_state_set_a2p { |
|||
uint32_t flags; |
|||
uint32_t pd_id; |
|||
uint32_t power_state; |
|||
}; |
|||
|
|||
struct scmi_pd_state_set_p2a { |
|||
int32_t status; |
|||
}; |
|||
|
|||
#endif /* SCMI_MSG_PD_H */ |
Loading…
Reference in new issue