mirror of
https://github.com/u-boot/u-boot.git
synced 2025-04-11 07:24:46 +00:00
power: domain: add SCMI driver
Add power domain driver based on SCMI power domain management protocol. Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
This commit is contained in:
parent
fc358b1a76
commit
c1d2ed0c63
5 changed files with 213 additions and 0 deletions
|
@ -86,6 +86,9 @@ struct udevice *scmi_get_protocol(struct udevice *dev,
|
|||
case SCMI_PROTOCOL_ID_BASE:
|
||||
proto = priv->base_dev;
|
||||
break;
|
||||
case SCMI_PROTOCOL_ID_POWER_DOMAIN:
|
||||
proto = priv->pwdom_dev;
|
||||
break;
|
||||
case SCMI_PROTOCOL_ID_CLOCK:
|
||||
proto = priv->clock_dev;
|
||||
break;
|
||||
|
@ -133,6 +136,9 @@ static int scmi_add_protocol(struct udevice *dev,
|
|||
case SCMI_PROTOCOL_ID_BASE:
|
||||
priv->base_dev = proto;
|
||||
break;
|
||||
case SCMI_PROTOCOL_ID_POWER_DOMAIN:
|
||||
priv->pwdom_dev = proto;
|
||||
break;
|
||||
case SCMI_PROTOCOL_ID_CLOCK:
|
||||
priv->clock_dev = proto;
|
||||
break;
|
||||
|
@ -405,6 +411,11 @@ static int scmi_bind_protocols(struct udevice *dev)
|
|||
drv = NULL;
|
||||
name = ofnode_get_name(node);
|
||||
switch (protocol_id) {
|
||||
case SCMI_PROTOCOL_ID_POWER_DOMAIN:
|
||||
if (CONFIG_IS_ENABLED(SCMI_POWER_DOMAIN) &&
|
||||
scmi_protocol_is_supported(dev, protocol_id))
|
||||
drv = DM_DRIVER_GET(scmi_power_domain);
|
||||
break;
|
||||
case SCMI_PROTOCOL_ID_CLOCK:
|
||||
if (CONFIG_IS_ENABLED(CLK_SCMI) &&
|
||||
scmi_protocol_is_supported(dev, protocol_id))
|
||||
|
|
|
@ -83,6 +83,13 @@ config SANDBOX_POWER_DOMAIN
|
|||
simply accepts requests to power on/off various HW modules without
|
||||
actually doing anything beyond a little error checking.
|
||||
|
||||
config SCMI_POWER_DOMAIN
|
||||
bool "Enable SCMI power domain driver"
|
||||
depends on POWER_DOMAIN && SCMI_FIRMWARE
|
||||
help
|
||||
Enable power domain implementation based on SCMI power domain
|
||||
management protocol.
|
||||
|
||||
config TEGRA186_POWER_DOMAIN
|
||||
bool "Enable Tegra186 BPMP-based power domain driver"
|
||||
depends on TEGRA186_BPMP
|
||||
|
|
|
@ -15,6 +15,7 @@ obj-$(CONFIG_MESON_EE_POWER_DOMAIN) += meson-ee-pwrc.o
|
|||
obj-$(CONFIG_MESON_SECURE_POWER_DOMAIN) += meson-secure-pwrc.o
|
||||
obj-$(CONFIG_SANDBOX_POWER_DOMAIN) += sandbox-power-domain.o
|
||||
obj-$(CONFIG_SANDBOX_POWER_DOMAIN) += sandbox-power-domain-test.o
|
||||
obj-$(CONFIG_SCMI_POWER_DOMAIN) += scmi-power-domain.o
|
||||
obj-$(CONFIG_TEGRA186_POWER_DOMAIN) += tegra186-power-domain.o
|
||||
obj-$(CONFIG_TI_SCI_POWER_DOMAIN) += ti-sci-power-domain.o
|
||||
obj-$(CONFIG_TI_POWER_DOMAIN) += ti-power-domain.o
|
||||
|
|
192
drivers/power/domain/scmi-power-domain.c
Normal file
192
drivers/power/domain/scmi-power-domain.c
Normal file
|
@ -0,0 +1,192 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* SCMI Power domain driver
|
||||
*
|
||||
* Copyright (C) 2023 Linaro Limited
|
||||
* author: AKASHI Takahiro <takahiro.akashi@linaro.org>
|
||||
*/
|
||||
|
||||
#include <dm.h>
|
||||
#include <malloc.h>
|
||||
#include <power-domain.h>
|
||||
#include <power-domain-uclass.h>
|
||||
#include <scmi_agent.h>
|
||||
#include <scmi_protocols.h>
|
||||
#include <dm/device_compat.h>
|
||||
|
||||
/**
|
||||
* struct scmi_pwd_properties
|
||||
* @attributes: Power domain attributes
|
||||
* @name: Name of the domain
|
||||
*/
|
||||
struct scmi_pwd_properties {
|
||||
u32 attributes;
|
||||
u8 *name; /* not used now */
|
||||
};
|
||||
|
||||
/**
|
||||
* struct scmi_power_domain_priv
|
||||
* @num_pwdoms: Number of power domains
|
||||
* @prop: Pointer to domain's properties
|
||||
* @stats_addr: Address of statistics memory region
|
||||
* @stats_len: Length of statistics memory region
|
||||
*/
|
||||
struct scmi_power_domain_priv {
|
||||
int num_pwdoms;
|
||||
struct scmi_pwd_properties *prop;
|
||||
u64 stats_addr;
|
||||
size_t stats_len;
|
||||
};
|
||||
|
||||
/**
|
||||
* async_is_supported - check asynchronous transition
|
||||
* @attributes: Power domain attributes
|
||||
*
|
||||
* Determine if the power transition can be done asynchronously.
|
||||
*
|
||||
* Return: true if supported, false if not
|
||||
*/
|
||||
static bool async_is_supported(u32 attributes)
|
||||
{
|
||||
if (attributes & SCMI_PWD_ATTR_PSTATE_ASYNC)
|
||||
return true;
|
||||
|
||||
/* TODO: check attributes && SCMI_PWD_ATTR_PSTATE_SYNC */
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* scmi_power_domain_on - Enable the power domain
|
||||
* @power_domain: Power domain
|
||||
*
|
||||
* Turn on the power domain.
|
||||
*
|
||||
* Return: 0 on success, error code on failure
|
||||
*/
|
||||
static int scmi_power_domain_on(struct power_domain *power_domain)
|
||||
{
|
||||
struct scmi_power_domain_priv *priv = dev_get_priv(power_domain->dev);
|
||||
u32 flags, pstate;
|
||||
int ret;
|
||||
|
||||
if (power_domain->id > priv->num_pwdoms)
|
||||
return -EINVAL;
|
||||
|
||||
if (async_is_supported(priv->prop[power_domain->id].attributes))
|
||||
flags = SCMI_PWD_SET_FLAGS_ASYNC;
|
||||
else
|
||||
flags = 0;
|
||||
|
||||
/* ON */
|
||||
pstate = 0;
|
||||
|
||||
ret = scmi_pwd_state_set(power_domain->dev, flags, power_domain->id,
|
||||
pstate);
|
||||
if (ret) {
|
||||
dev_err(power_domain->dev, "failed to set the state on (%d)\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* scmi_power_domain_off - Disable the power domain
|
||||
* @power_domain: Power domain
|
||||
*
|
||||
* Turn off the power domain.
|
||||
*
|
||||
* Return: 0 on success, error code on failure
|
||||
*/
|
||||
static int scmi_power_domain_off(struct power_domain *power_domain)
|
||||
{
|
||||
struct scmi_power_domain_priv *priv = dev_get_priv(power_domain->dev);
|
||||
u32 flags, pstate;
|
||||
int ret;
|
||||
|
||||
if (power_domain->id > priv->num_pwdoms)
|
||||
return -EINVAL;
|
||||
|
||||
if (async_is_supported(priv->prop[power_domain->id].attributes))
|
||||
flags = SCMI_PWD_SET_FLAGS_ASYNC;
|
||||
else
|
||||
flags = 0;
|
||||
|
||||
/* OFF */
|
||||
pstate = SCMI_PWD_PSTATE_TYPE_LOST;
|
||||
|
||||
ret = scmi_pwd_state_set(power_domain->dev, flags, power_domain->id,
|
||||
pstate);
|
||||
if (ret) {
|
||||
dev_err(power_domain->dev, "failed to set the state off (%d)\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* scmi_power_domain_probe - Probe the power domain
|
||||
* @dev: Power domain device
|
||||
*
|
||||
* Probe the power domain and initialize the properties.
|
||||
*
|
||||
* Return: 0 on success, error code on failure
|
||||
*/
|
||||
static int scmi_power_domain_probe(struct udevice *dev)
|
||||
{
|
||||
struct scmi_power_domain_priv *priv = dev_get_priv(dev);
|
||||
u32 version;
|
||||
int i, ret;
|
||||
|
||||
ret = devm_scmi_of_get_channel(dev);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to get channel (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = scmi_generic_protocol_version(dev, SCMI_PROTOCOL_ID_POWER_DOMAIN,
|
||||
&version);
|
||||
|
||||
ret = scmi_pwd_protocol_attrs(dev, &priv->num_pwdoms, &priv->stats_addr,
|
||||
&priv->stats_len);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to get protocol attributes (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
priv->prop = calloc(sizeof(*priv->prop), priv->num_pwdoms);
|
||||
if (!priv->prop)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < priv->num_pwdoms; i++) {
|
||||
ret = scmi_pwd_attrs(dev, i, &priv->prop[i].attributes,
|
||||
&priv->prop[i].name);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to get attributes pwd:%d (%d)\n",
|
||||
i, ret);
|
||||
for (i--; i >= 0; i--)
|
||||
free(priv->prop[i].name);
|
||||
free(priv->prop);
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct power_domain_ops scmi_power_domain_ops = {
|
||||
.on = scmi_power_domain_on,
|
||||
.off = scmi_power_domain_off,
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(scmi_power_domain) = {
|
||||
.name = "scmi_power_domain",
|
||||
.id = UCLASS_POWER_DOMAIN,
|
||||
.ops = &scmi_power_domain_ops,
|
||||
.probe = scmi_power_domain_probe,
|
||||
.priv_auto = sizeof(struct scmi_power_domain_priv),
|
||||
};
|
|
@ -23,6 +23,7 @@ struct scmi_channel;
|
|||
* @agent_name: Agent name
|
||||
* @agent_id: Identifier of agent
|
||||
* @base_dev: SCMI base protocol device
|
||||
* @pwdom_dev: SCMI power domain management protocol device
|
||||
* @clock_dev: SCMI clock protocol device
|
||||
* @resetdom_dev: SCMI reset domain protocol device
|
||||
* @voltagedom_dev: SCMI voltage domain protocol device
|
||||
|
@ -38,6 +39,7 @@ struct scmi_agent_priv {
|
|||
u8 *agent_name;
|
||||
u32 agent_id;
|
||||
struct udevice *base_dev;
|
||||
struct udevice *pwdom_dev;
|
||||
struct udevice *clock_dev;
|
||||
struct udevice *resetdom_dev;
|
||||
struct udevice *voltagedom_dev;
|
||||
|
|
Loading…
Add table
Reference in a new issue