Arm SCMI updates for v6.5
Couple of main additions :- 1. Support for multiple SMC/HVC transports for SCMI: Some platforms need to support multiple SCMI instances within a platform(more commonly in a VM). The same SMC/HVC FID is used with all the instances. The platform or the hypervisor needs a way to distinguish among SMC/HVC calls made from different instances. This change adds support for passing shmem channel address as the parameters in the SMC/HVC call. The address is split into 4KB-page and offset for simiplicity. 2. Addition od SCMI v3.2 explicit powercap enable/disable support: SCMI v3.2 specification introduces support to disable powercapping as a whole on the desired zones. This change adds the needed support to the core SCMI powercap protocol, exposing enable/disable protocol operations and then wiring up the new operartions in the related powercap framework helpers. -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEunHlEgbzHrJD3ZPhAEG6vDF+4pgFAmSHCbQACgkQAEG6vDF+ 4phj9hAAjYYoJ9HvIqxJ68jRRh7BFnsdeCVqsGUzopeXbiWwr+uc0hko+oP8+hjz R/tHvqhKuUiKC+ROOVHSx0VdU5721v2Uhvn5gtp2ZzKN/Iw7Mm/6dMlGDF790MSw gkxJ5dog9H04HSGG1LvQIPKKY/BNUh7xvPkwoKlCO7DyNG+WQ5yyQT0v9DiZH8gg j5eKX29gDZJEuzr8TlkpYHATyDlzMNVD0/pX97DedhqEqzVnms/yAa1R6zu+M0sn 8xyR2gy0UJ0w3unT8KxEbbxdJcykYxTbyVqJIc28xtVYA1EOGkFwZLYcVvy4z0LC xny3PJSeL8g/pbrilbYNbYcqz9Qjb9eNU9XdDFa+Oy09skwnYr2uYje6XPBk/KFu cQ5xs9ChJezcIRPBq/iV4Aqe5WK05IPZ0Q0HKsuTmdOOMaCsPui5nMkkybrm3KOU uZ6z90Br854FI/pQqAqpwYY1Wqa1g6I4DFUwOtd04qD1V19s0CEDrx8uPtoKcSaP 0W+BeSv56Ukvn2rYPbu0teIzbk3s00kGqHcy1YKyq1rGmZSYrBf1bfmZkIJgfN/2 0cyzJAch4j4ggvnJQJPybWYjbmKfxE+A9hk3hjZ1mrew2wWeIsjevclu4wtNUCjc qT3wa8SOtjaUGTQmvEWBKeYrkMcOhx+vxSo8SjemW/X3WjYswdw= =uVB0 -----END PGP SIGNATURE----- gpgsig -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEiK/NIGsWEZVxh/FrYKtH/8kJUicFAmSUabgACgkQYKtH/8kJ UieE8A//Rvcl3hDpZgNa6pCvX7dH3m2JttmBgBmGbH4mVffjqhstYknp8Fb8Faxq 91cGvAJ0QTn0Kaox7ycHQQVxLK5u7UfTmCe6pGGIDWZqXQDj6TETZoeWmiBgnTeS 510Id9S/CsSnjErO1D575fogSx2AohgBzIIk4r0YxZ0HcQiGteS7fAFjd4JMoheF ZhUUmAu8Kp//grgeujvgQ59bCP4w6dqJ7KT/wnBZCy0CACpECA+LmYS1N/bnfPB2 rzxMo1GgUfSNEKxNx6T8UC9+LfUkitHNwfPyoe3av9GAGhozaTbGD9xll0DTj2iz yFyhbgyY9aCxNMAwzq6hnveZi90X/bC1hnIidH5oyQkqTNTgE1X1y7SA6+SSfBzF UlFafLq2xw+ENmDYOV6Lz4JREPhC2gFwjYqjn8teLQBriaCBIdtaedbGDnUVN0Ht Iiv4baGtrIqbwosO2o/mfCLAveY/zh5aINv3rY1bkdfdFUQqS8gDlNGTuKDN+H+3 v80eyP8XPU2pZ7NTzSxcnz5SHSZWagVcugnzDEdeX2ZBeSKY50PzFZEY7OSU5k9o iYjRyChHTTab/rG51GyhthVvszU9iKSQzmGco6OnaHd/vfCeXUfNKey98zVLbjUO V8xJOAIZ9NNU9SzIfupfe9vjfIPOTxEqbWV3M4pvkgyKjNEddr4= =Ze5+ -----END PGP SIGNATURE----- Merge tag 'scmi-updates-6.5' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux into soc/drivers Arm SCMI updates for v6.5 Couple of main additions :- 1. Support for multiple SMC/HVC transports for SCMI: Some platforms need to support multiple SCMI instances within a platform(more commonly in a VM). The same SMC/HVC FID is used with all the instances. The platform or the hypervisor needs a way to distinguish among SMC/HVC calls made from different instances. This change adds support for passing shmem channel address as the parameters in the SMC/HVC call. The address is split into 4KB-page and offset for simiplicity. 2. Addition od SCMI v3.2 explicit powercap enable/disable support: SCMI v3.2 specification introduces support to disable powercapping as a whole on the desired zones. This change adds the needed support to the core SCMI powercap protocol, exposing enable/disable protocol operations and then wiring up the new operartions in the related powercap framework helpers. * tag 'scmi-updates-6.5' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux: powercap: arm_scmi: Add support for disabling powercaps on a zone firmware: arm_scmi: Add Powercap protocol enable support firmware: arm_scmi: Refactor the internal powercap get/set helpers firmware: arm_scmi: Augment SMC/HVC to allow optional parameters dt-bindings: firmware: arm,scmi: support for parameter in smc/hvc call Link: https://lore.kernel.org/r/20230612121017.4108104-1-sudeep.holla@arm.com Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
commit
2d0d3a1004
|
@ -34,6 +34,10 @@ properties:
|
|||
- description: SCMI compliant firmware with ARM SMC/HVC transport
|
||||
items:
|
||||
- const: arm,scmi-smc
|
||||
- description: SCMI compliant firmware with ARM SMC/HVC transport
|
||||
with shmem address(4KB-page, offset) as parameters
|
||||
items:
|
||||
- const: arm,scmi-smc-param
|
||||
- description: SCMI compliant firmware with SCMI Virtio transport.
|
||||
The virtio transport only supports a single device.
|
||||
items:
|
||||
|
@ -299,7 +303,9 @@ else:
|
|||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: arm,scmi-smc
|
||||
enum:
|
||||
- arm,scmi-smc
|
||||
- arm,scmi-smc-param
|
||||
then:
|
||||
required:
|
||||
- arm,smc-id
|
||||
|
|
|
@ -2914,6 +2914,7 @@ static const struct of_device_id scmi_of_match[] = {
|
|||
#endif
|
||||
#ifdef CONFIG_ARM_SCMI_TRANSPORT_SMC
|
||||
{ .compatible = "arm,scmi-smc", .data = &scmi_smc_desc},
|
||||
{ .compatible = "arm,scmi-smc-param", .data = &scmi_smc_desc},
|
||||
#endif
|
||||
#ifdef CONFIG_ARM_SCMI_TRANSPORT_VIRTIO
|
||||
{ .compatible = "arm,scmi-virtio", .data = &scmi_virtio_desc},
|
||||
|
|
|
@ -108,6 +108,8 @@ struct scmi_powercap_meas_changed_notify_payld {
|
|||
};
|
||||
|
||||
struct scmi_powercap_state {
|
||||
bool enabled;
|
||||
u32 last_pcap;
|
||||
bool meas_notif_enabled;
|
||||
u64 thresholds;
|
||||
#define THRESH_LOW(p, id) \
|
||||
|
@ -313,24 +315,33 @@ static int scmi_powercap_xfer_cap_get(const struct scmi_protocol_handle *ph,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int scmi_powercap_cap_get(const struct scmi_protocol_handle *ph,
|
||||
u32 domain_id, u32 *power_cap)
|
||||
static int __scmi_powercap_cap_get(const struct scmi_protocol_handle *ph,
|
||||
const struct scmi_powercap_info *dom,
|
||||
u32 *power_cap)
|
||||
{
|
||||
struct scmi_powercap_info *dom;
|
||||
struct powercap_info *pi = ph->get_priv(ph);
|
||||
|
||||
if (!power_cap || domain_id >= pi->num_domains)
|
||||
return -EINVAL;
|
||||
|
||||
dom = pi->powercaps + domain_id;
|
||||
if (dom->fc_info && dom->fc_info[POWERCAP_FC_CAP].get_addr) {
|
||||
*power_cap = ioread32(dom->fc_info[POWERCAP_FC_CAP].get_addr);
|
||||
trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_CAP_GET,
|
||||
domain_id, *power_cap, 0);
|
||||
dom->id, *power_cap, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return scmi_powercap_xfer_cap_get(ph, domain_id, power_cap);
|
||||
return scmi_powercap_xfer_cap_get(ph, dom->id, power_cap);
|
||||
}
|
||||
|
||||
static int scmi_powercap_cap_get(const struct scmi_protocol_handle *ph,
|
||||
u32 domain_id, u32 *power_cap)
|
||||
{
|
||||
const struct scmi_powercap_info *dom;
|
||||
|
||||
if (!power_cap)
|
||||
return -EINVAL;
|
||||
|
||||
dom = scmi_powercap_dom_info_get(ph, domain_id);
|
||||
if (!dom)
|
||||
return -EINVAL;
|
||||
|
||||
return __scmi_powercap_cap_get(ph, dom, power_cap);
|
||||
}
|
||||
|
||||
static int scmi_powercap_xfer_cap_set(const struct scmi_protocol_handle *ph,
|
||||
|
@ -375,17 +386,20 @@ static int scmi_powercap_xfer_cap_set(const struct scmi_protocol_handle *ph,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int scmi_powercap_cap_set(const struct scmi_protocol_handle *ph,
|
||||
u32 domain_id, u32 power_cap,
|
||||
bool ignore_dresp)
|
||||
static int __scmi_powercap_cap_set(const struct scmi_protocol_handle *ph,
|
||||
struct powercap_info *pi, u32 domain_id,
|
||||
u32 power_cap, bool ignore_dresp)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
const struct scmi_powercap_info *pc;
|
||||
|
||||
pc = scmi_powercap_dom_info_get(ph, domain_id);
|
||||
if (!pc || !pc->powercap_cap_config || !power_cap ||
|
||||
power_cap < pc->min_power_cap ||
|
||||
power_cap > pc->max_power_cap)
|
||||
return -EINVAL;
|
||||
if (!pc || !pc->powercap_cap_config)
|
||||
return ret;
|
||||
|
||||
if (power_cap &&
|
||||
(power_cap < pc->min_power_cap || power_cap > pc->max_power_cap))
|
||||
return ret;
|
||||
|
||||
if (pc->fc_info && pc->fc_info[POWERCAP_FC_CAP].set_addr) {
|
||||
struct scmi_fc_info *fci = &pc->fc_info[POWERCAP_FC_CAP];
|
||||
|
@ -394,10 +408,41 @@ static int scmi_powercap_cap_set(const struct scmi_protocol_handle *ph,
|
|||
ph->hops->fastchannel_db_ring(fci->set_db);
|
||||
trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_CAP_SET,
|
||||
domain_id, power_cap, 0);
|
||||
ret = 0;
|
||||
} else {
|
||||
ret = scmi_powercap_xfer_cap_set(ph, pc, power_cap,
|
||||
ignore_dresp);
|
||||
}
|
||||
|
||||
/* Save the last explicitly set non-zero powercap value */
|
||||
if (PROTOCOL_REV_MAJOR(pi->version) >= 0x2 && !ret && power_cap)
|
||||
pi->states[domain_id].last_pcap = power_cap;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int scmi_powercap_cap_set(const struct scmi_protocol_handle *ph,
|
||||
u32 domain_id, u32 power_cap,
|
||||
bool ignore_dresp)
|
||||
{
|
||||
struct powercap_info *pi = ph->get_priv(ph);
|
||||
|
||||
/*
|
||||
* Disallow zero as a possible explicitly requested powercap:
|
||||
* there are enable/disable operations for this.
|
||||
*/
|
||||
if (!power_cap)
|
||||
return -EINVAL;
|
||||
|
||||
/* Just log the last set request if acting on a disabled domain */
|
||||
if (PROTOCOL_REV_MAJOR(pi->version) >= 0x2 &&
|
||||
!pi->states[domain_id].enabled) {
|
||||
pi->states[domain_id].last_pcap = power_cap;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return scmi_powercap_xfer_cap_set(ph, pc, power_cap, ignore_dresp);
|
||||
return __scmi_powercap_cap_set(ph, pi, domain_id,
|
||||
power_cap, ignore_dresp);
|
||||
}
|
||||
|
||||
static int scmi_powercap_xfer_pai_get(const struct scmi_protocol_handle *ph,
|
||||
|
@ -564,11 +609,78 @@ scmi_powercap_measurements_threshold_set(const struct scmi_protocol_handle *ph,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int scmi_powercap_cap_enable_set(const struct scmi_protocol_handle *ph,
|
||||
u32 domain_id, bool enable)
|
||||
{
|
||||
int ret;
|
||||
u32 power_cap;
|
||||
struct powercap_info *pi = ph->get_priv(ph);
|
||||
|
||||
if (PROTOCOL_REV_MAJOR(pi->version) < 0x2)
|
||||
return -EINVAL;
|
||||
|
||||
if (enable == pi->states[domain_id].enabled)
|
||||
return 0;
|
||||
|
||||
if (enable) {
|
||||
/* Cannot enable with a zero powercap. */
|
||||
if (!pi->states[domain_id].last_pcap)
|
||||
return -EINVAL;
|
||||
|
||||
ret = __scmi_powercap_cap_set(ph, pi, domain_id,
|
||||
pi->states[domain_id].last_pcap,
|
||||
true);
|
||||
} else {
|
||||
ret = __scmi_powercap_cap_set(ph, pi, domain_id, 0, true);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Update our internal state to reflect final platform state: the SCMI
|
||||
* server could have ignored a disable request and kept enforcing some
|
||||
* powercap limit requested by other agents.
|
||||
*/
|
||||
ret = scmi_powercap_cap_get(ph, domain_id, &power_cap);
|
||||
if (!ret)
|
||||
pi->states[domain_id].enabled = !!power_cap;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int scmi_powercap_cap_enable_get(const struct scmi_protocol_handle *ph,
|
||||
u32 domain_id, bool *enable)
|
||||
{
|
||||
int ret;
|
||||
u32 power_cap;
|
||||
struct powercap_info *pi = ph->get_priv(ph);
|
||||
|
||||
*enable = true;
|
||||
if (PROTOCOL_REV_MAJOR(pi->version) < 0x2)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Report always real platform state; platform could have ignored
|
||||
* a previous disable request. Default true on any error.
|
||||
*/
|
||||
ret = scmi_powercap_cap_get(ph, domain_id, &power_cap);
|
||||
if (!ret)
|
||||
*enable = !!power_cap;
|
||||
|
||||
/* Update internal state with current real platform state */
|
||||
pi->states[domain_id].enabled = *enable;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct scmi_powercap_proto_ops powercap_proto_ops = {
|
||||
.num_domains_get = scmi_powercap_num_domains_get,
|
||||
.info_get = scmi_powercap_dom_info_get,
|
||||
.cap_get = scmi_powercap_cap_get,
|
||||
.cap_set = scmi_powercap_cap_set,
|
||||
.cap_enable_set = scmi_powercap_cap_enable_set,
|
||||
.cap_enable_get = scmi_powercap_cap_enable_get,
|
||||
.pai_get = scmi_powercap_pai_get,
|
||||
.pai_set = scmi_powercap_pai_set,
|
||||
.measurements_get = scmi_powercap_measurements_get,
|
||||
|
@ -829,6 +941,11 @@ scmi_powercap_protocol_init(const struct scmi_protocol_handle *ph)
|
|||
if (!pinfo->powercaps)
|
||||
return -ENOMEM;
|
||||
|
||||
pinfo->states = devm_kcalloc(ph->dev, pinfo->num_domains,
|
||||
sizeof(*pinfo->states), GFP_KERNEL);
|
||||
if (!pinfo->states)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* Note that any failure in retrieving any domain attribute leads to
|
||||
* the whole Powercap protocol initialization failure: this way the
|
||||
|
@ -843,15 +960,21 @@ scmi_powercap_protocol_init(const struct scmi_protocol_handle *ph)
|
|||
if (pinfo->powercaps[domain].fastchannels)
|
||||
scmi_powercap_domain_init_fc(ph, domain,
|
||||
&pinfo->powercaps[domain].fc_info);
|
||||
|
||||
/* Grab initial state when disable is supported. */
|
||||
if (PROTOCOL_REV_MAJOR(version) >= 0x2) {
|
||||
ret = __scmi_powercap_cap_get(ph,
|
||||
&pinfo->powercaps[domain],
|
||||
&pinfo->states[domain].last_pcap);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pinfo->states[domain].enabled =
|
||||
!!pinfo->states[domain].last_pcap;
|
||||
}
|
||||
}
|
||||
|
||||
pinfo->states = devm_kcalloc(ph->dev, pinfo->num_domains,
|
||||
sizeof(*pinfo->states), GFP_KERNEL);
|
||||
if (!pinfo->states)
|
||||
return -ENOMEM;
|
||||
|
||||
pinfo->version = version;
|
||||
|
||||
return ph->set_priv(ph, pinfo);
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,23 @@
|
|||
|
||||
#include "common.h"
|
||||
|
||||
/*
|
||||
* The shmem address is split into 4K page and offset.
|
||||
* This is to make sure the parameters fit in 32bit arguments of the
|
||||
* smc/hvc call to keep it uniform across smc32/smc64 conventions.
|
||||
* This however limits the shmem address to 44 bit.
|
||||
*
|
||||
* These optional parameters can be used to distinguish among multiple
|
||||
* scmi instances that are using the same smc-id.
|
||||
* The page parameter is passed in r1/x1/w1 register and the offset parameter
|
||||
* is passed in r2/x2/w2 register.
|
||||
*/
|
||||
|
||||
#define SHMEM_SIZE (SZ_4K)
|
||||
#define SHMEM_SHIFT 12
|
||||
#define SHMEM_PAGE(x) (_UL((x) >> SHMEM_SHIFT))
|
||||
#define SHMEM_OFFSET(x) ((x) & (SHMEM_SIZE - 1))
|
||||
|
||||
/**
|
||||
* struct scmi_smc - Structure representing a SCMI smc transport
|
||||
*
|
||||
|
@ -30,6 +47,8 @@
|
|||
* @inflight: Atomic flag to protect access to Tx/Rx shared memory area.
|
||||
* Used when operating in atomic mode.
|
||||
* @func_id: smc/hvc call function id
|
||||
* @param_page: 4K page number of the shmem channel
|
||||
* @param_offset: Offset within the 4K page of the shmem channel
|
||||
*/
|
||||
|
||||
struct scmi_smc {
|
||||
|
@ -40,6 +59,8 @@ struct scmi_smc {
|
|||
#define INFLIGHT_NONE MSG_TOKEN_MAX
|
||||
atomic_t inflight;
|
||||
u32 func_id;
|
||||
u32 param_page;
|
||||
u32 param_offset;
|
||||
};
|
||||
|
||||
static irqreturn_t smc_msg_done_isr(int irq, void *data)
|
||||
|
@ -137,6 +158,10 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (of_device_is_compatible(dev->of_node, "arm,scmi-smc-param")) {
|
||||
scmi_info->param_page = SHMEM_PAGE(res.start);
|
||||
scmi_info->param_offset = SHMEM_OFFSET(res.start);
|
||||
}
|
||||
/*
|
||||
* If there is an interrupt named "a2p", then the service and
|
||||
* completion of a message is signaled by an interrupt rather than by
|
||||
|
@ -179,6 +204,8 @@ static int smc_send_message(struct scmi_chan_info *cinfo,
|
|||
{
|
||||
struct scmi_smc *scmi_info = cinfo->transport_info;
|
||||
struct arm_smccc_res res;
|
||||
unsigned long page = scmi_info->param_page;
|
||||
unsigned long offset = scmi_info->param_offset;
|
||||
|
||||
/*
|
||||
* Channel will be released only once response has been
|
||||
|
@ -188,7 +215,8 @@ static int smc_send_message(struct scmi_chan_info *cinfo,
|
|||
|
||||
shmem_tx_prepare(scmi_info->shmem, xfer, cinfo);
|
||||
|
||||
arm_smccc_1_1_invoke(scmi_info->func_id, 0, 0, 0, 0, 0, 0, 0, &res);
|
||||
arm_smccc_1_1_invoke(scmi_info->func_id, page, offset, 0, 0, 0, 0, 0,
|
||||
&res);
|
||||
|
||||
/* Only SMCCC_RET_NOT_SUPPORTED is valid error code */
|
||||
if (res.a0) {
|
||||
|
|
|
@ -70,10 +70,26 @@ static int scmi_powercap_get_power_uw(struct powercap_zone *pz,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int scmi_powercap_zone_enable_set(struct powercap_zone *pz, bool mode)
|
||||
{
|
||||
struct scmi_powercap_zone *spz = to_scmi_powercap_zone(pz);
|
||||
|
||||
return powercap_ops->cap_enable_set(spz->ph, spz->info->id, mode);
|
||||
}
|
||||
|
||||
static int scmi_powercap_zone_enable_get(struct powercap_zone *pz, bool *mode)
|
||||
{
|
||||
struct scmi_powercap_zone *spz = to_scmi_powercap_zone(pz);
|
||||
|
||||
return powercap_ops->cap_enable_get(spz->ph, spz->info->id, mode);
|
||||
}
|
||||
|
||||
static const struct powercap_zone_ops zone_ops = {
|
||||
.get_max_power_range_uw = scmi_powercap_get_max_power_range_uw,
|
||||
.get_power_uw = scmi_powercap_get_power_uw,
|
||||
.release = scmi_powercap_zone_release,
|
||||
.set_enable = scmi_powercap_zone_enable_set,
|
||||
.get_enable = scmi_powercap_zone_enable_get,
|
||||
};
|
||||
|
||||
static void scmi_powercap_normalize_cap(const struct scmi_powercap_zone *spz,
|
||||
|
|
|
@ -629,11 +629,25 @@ struct scmi_powercap_info {
|
|||
* @num_domains_get: get the count of powercap domains provided by SCMI.
|
||||
* @info_get: get the information for the specified domain.
|
||||
* @cap_get: get the current CAP value for the specified domain.
|
||||
* On SCMI platforms supporting powercap zone disabling, this could
|
||||
* report a zero value for a zone where powercapping is disabled.
|
||||
* @cap_set: set the CAP value for the specified domain to the provided value;
|
||||
* if the domain supports setting the CAP with an asynchronous command
|
||||
* this request will finally trigger an asynchronous transfer, but, if
|
||||
* @ignore_dresp here is set to true, this call will anyway return
|
||||
* immediately without waiting for the related delayed response.
|
||||
* Note that the powercap requested value must NOT be zero, even if
|
||||
* the platform supports disabling a powercap by setting its cap to
|
||||
* zero (since SCMI v3.2): there are dedicated operations that should
|
||||
* be used for that. (@cap_enable_set/get)
|
||||
* @cap_enable_set: enable or disable the powercapping on the specified domain,
|
||||
* if supported by the SCMI platform implementation.
|
||||
* Note that, by the SCMI specification, the platform can
|
||||
* silently ignore our disable request and decide to enforce
|
||||
* anyway some other powercap value requested by another agent
|
||||
* on the system: for this reason @cap_get and @cap_enable_get
|
||||
* will always report the final platform view of the powercaps.
|
||||
* @cap_enable_get: get the current CAP enable status for the specified domain.
|
||||
* @pai_get: get the current PAI value for the specified domain.
|
||||
* @pai_set: set the PAI value for the specified domain to the provided value.
|
||||
* @measurements_get: retrieve the current average power measurements for the
|
||||
|
@ -662,6 +676,10 @@ struct scmi_powercap_proto_ops {
|
|||
u32 *power_cap);
|
||||
int (*cap_set)(const struct scmi_protocol_handle *ph, u32 domain_id,
|
||||
u32 power_cap, bool ignore_dresp);
|
||||
int (*cap_enable_set)(const struct scmi_protocol_handle *ph,
|
||||
u32 domain_id, bool enable);
|
||||
int (*cap_enable_get)(const struct scmi_protocol_handle *ph,
|
||||
u32 domain_id, bool *enable);
|
||||
int (*pai_get)(const struct scmi_protocol_handle *ph, u32 domain_id,
|
||||
u32 *pai);
|
||||
int (*pai_set)(const struct scmi_protocol_handle *ph, u32 domain_id,
|
||||
|
|
Loading…
Reference in New Issue