mirror of
https://github.com/u-boot/u-boot.git
synced 2025-01-21 10:14:05 +08:00
firmware: scmi: voltage regulator
Implement voltage regulators interfaced by the SCMI voltage domain protocol. The DT bindings are defined in the Linux kernel since SCMI voltage domain and regulators patches [1] and [2] integration in v5.11-rc7. Link: [1]0f80fcec08
Link: [2]2add5cacff
Signed-off-by: Etienne Carriere <etienne.carriere@linaro.org> Reviewed-by: Jaehoon Chung <jh80.chung@samsung.com>
This commit is contained in:
parent
d46933839f
commit
1f213ee4db
@ -62,6 +62,20 @@ Required properties:
|
||||
- #power-domain-cells : Should be 1. Contains the device or the power
|
||||
domain ID value used by SCMI commands.
|
||||
|
||||
Regulator bindings for the SCMI Regulator based on SCMI Message Protocol
|
||||
------------------------------------------------------------
|
||||
An SCMI Regulator is permanently bound to a well defined SCMI Voltage Domain,
|
||||
and should be always positioned as a root regulator.
|
||||
It does not support any current operation.
|
||||
|
||||
SCMI Regulators are grouped under a 'regulators' node which in turn is a child
|
||||
of the SCMI Voltage protocol node inside the desired SCMI instance node.
|
||||
|
||||
This binding uses the common regulator binding[6].
|
||||
|
||||
Required properties:
|
||||
- reg : shall identify an existent SCMI Voltage Domain.
|
||||
|
||||
Sensor bindings for the sensors based on SCMI Message Protocol
|
||||
--------------------------------------------------------------
|
||||
SCMI provides an API to access the various sensors on the SoC.
|
||||
@ -105,6 +119,7 @@ Required sub-node properties:
|
||||
[3] Documentation/devicetree/bindings/thermal/thermal.txt
|
||||
[4] Documentation/devicetree/bindings/sram/sram.yaml
|
||||
[5] Documentation/devicetree/bindings/reset/reset.txt
|
||||
[6] Documentation/devicetree/bindings/regulator/regulator.yaml
|
||||
|
||||
Example:
|
||||
|
||||
@ -169,6 +184,25 @@ firmware {
|
||||
reg = <0x16>;
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
|
||||
scmi_voltage: protocol@17 {
|
||||
reg = <0x17>;
|
||||
|
||||
regulators {
|
||||
regulator_devX: regulator@0 {
|
||||
reg = <0x0>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
};
|
||||
|
||||
regulator_devY: regulator@9 {
|
||||
reg = <0x9>;
|
||||
regulator-min-microvolt = <500000>;
|
||||
regulator-max-microvolt = <4200000>;
|
||||
};
|
||||
|
||||
...
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -80,6 +80,16 @@ static int scmi_bind_protocols(struct udevice *dev)
|
||||
if (IS_ENABLED(CONFIG_RESET_SCMI))
|
||||
drv = DM_DRIVER_GET(scmi_reset_domain);
|
||||
break;
|
||||
case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
|
||||
if (IS_ENABLED(CONFIG_DM_REGULATOR_SCMI)) {
|
||||
node = ofnode_find_subnode(node, "regulators");
|
||||
if (!ofnode_valid(node)) {
|
||||
dev_err(dev, "no regulators node\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
drv = DM_DRIVER_GET(scmi_voltage_domain);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -353,3 +353,11 @@ config DM_REGULATOR_TPS65941
|
||||
TPS65941 series of PMICs have 5 single phase BUCKs that can also
|
||||
be configured in multi phase modes & 4 LDOs. The driver implements
|
||||
get/set api for value and enable.
|
||||
|
||||
config DM_REGULATOR_SCMI
|
||||
bool "Enable driver for SCMI voltage domain regulators"
|
||||
depends on DM_REGULATOR
|
||||
select SCMI_AGENT
|
||||
help
|
||||
Enable this option if you want to support regulators exposed through
|
||||
the SCMI voltage domain protocol by a SCMI server.
|
||||
|
@ -30,3 +30,4 @@ obj-$(CONFIG_DM_REGULATOR_TPS65910) += tps65910_regulator.o
|
||||
obj-$(CONFIG_DM_REGULATOR_TPS62360) += tps62360_regulator.o
|
||||
obj-$(CONFIG_$(SPL_)DM_REGULATOR_STPMIC1) += stpmic1.o
|
||||
obj-$(CONFIG_DM_REGULATOR_TPS65941) += tps65941_regulator.o
|
||||
obj-$(CONFIG_DM_REGULATOR_SCMI) += scmi_regulator.o
|
||||
|
195
drivers/power/regulator/scmi_regulator.c
Normal file
195
drivers/power/regulator/scmi_regulator.c
Normal file
@ -0,0 +1,195 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2020-2021 Linaro Limited
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <scmi_agent.h>
|
||||
#include <scmi_protocols.h>
|
||||
#include <asm/types.h>
|
||||
#include <dm/device.h>
|
||||
#include <dm/device_compat.h>
|
||||
#include <dm/device-internal.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <power/regulator.h>
|
||||
|
||||
/**
|
||||
* struct scmi_regulator_platdata - Platform data for a scmi voltage domain regulator
|
||||
* @domain_id: ID representing the regulator for the related SCMI agent
|
||||
*/
|
||||
struct scmi_regulator_platdata {
|
||||
u32 domain_id;
|
||||
};
|
||||
|
||||
static int scmi_voltd_set_enable(struct udevice *dev, bool enable)
|
||||
{
|
||||
struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
|
||||
struct scmi_voltd_config_set_in in = {
|
||||
.domain_id = pdata->domain_id,
|
||||
.config = enable ? SCMI_VOLTD_CONFIG_ON : SCMI_VOLTD_CONFIG_OFF,
|
||||
};
|
||||
struct scmi_voltd_config_set_out out;
|
||||
struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN,
|
||||
SCMI_VOLTAGE_DOMAIN_CONFIG_SET,
|
||||
in, out);
|
||||
int ret;
|
||||
|
||||
ret = devm_scmi_process_msg(dev->parent->parent, &msg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = scmi_to_linux_errno(out.status);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int scmi_voltd_get_enable(struct udevice *dev)
|
||||
{
|
||||
struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
|
||||
struct scmi_voltd_config_get_in in = {
|
||||
.domain_id = pdata->domain_id,
|
||||
};
|
||||
struct scmi_voltd_config_get_out out;
|
||||
struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN,
|
||||
SCMI_VOLTAGE_DOMAIN_CONFIG_GET,
|
||||
in, out);
|
||||
int ret;
|
||||
|
||||
ret = devm_scmi_process_msg(dev->parent->parent, &msg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = scmi_to_linux_errno(out.status);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return out.config == SCMI_VOLTD_CONFIG_ON;
|
||||
}
|
||||
|
||||
static int scmi_voltd_set_voltage_level(struct udevice *dev, int uV)
|
||||
{
|
||||
struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
|
||||
struct scmi_voltd_level_set_in in = {
|
||||
.domain_id = pdata->domain_id,
|
||||
.voltage_level = uV,
|
||||
};
|
||||
struct scmi_voltd_level_set_out out;
|
||||
struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN,
|
||||
SCMI_VOLTAGE_DOMAIN_LEVEL_SET,
|
||||
in, out);
|
||||
int ret;
|
||||
|
||||
ret = devm_scmi_process_msg(dev->parent->parent, &msg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return scmi_to_linux_errno(out.status);
|
||||
}
|
||||
|
||||
static int scmi_voltd_get_voltage_level(struct udevice *dev)
|
||||
{
|
||||
struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
|
||||
struct scmi_voltd_level_get_in in = {
|
||||
.domain_id = pdata->domain_id,
|
||||
};
|
||||
struct scmi_voltd_level_get_out out;
|
||||
struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN,
|
||||
SCMI_VOLTAGE_DOMAIN_LEVEL_GET,
|
||||
in, out);
|
||||
int ret;
|
||||
|
||||
ret = devm_scmi_process_msg(dev->parent->parent, &msg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = scmi_to_linux_errno(out.status);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return out.voltage_level;
|
||||
}
|
||||
|
||||
static int scmi_regulator_of_to_plat(struct udevice *dev)
|
||||
{
|
||||
struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
|
||||
fdt_addr_t reg;
|
||||
|
||||
reg = dev_read_addr(dev);
|
||||
if (reg == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
pdata->domain_id = (u32)reg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scmi_regulator_probe(struct udevice *dev)
|
||||
{
|
||||
struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
|
||||
struct scmi_voltd_attr_in in = { 0 };
|
||||
struct scmi_voltd_attr_out out = { 0 };
|
||||
struct scmi_msg scmi_msg = {
|
||||
.protocol_id = SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN,
|
||||
.message_id = SCMI_VOLTAGE_DOMAIN_ATTRIBUTES,
|
||||
.in_msg = (u8 *)&in,
|
||||
.in_msg_sz = sizeof(in),
|
||||
.out_msg = (u8 *)&out,
|
||||
.out_msg_sz = sizeof(out),
|
||||
};
|
||||
int ret;
|
||||
|
||||
/* Check voltage domain is known from SCMI server */
|
||||
in.domain_id = pdata->domain_id;
|
||||
|
||||
ret = devm_scmi_process_msg(dev->parent->parent, &scmi_msg);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to query voltage domain %u: %d\n",
|
||||
pdata->domain_id, ret);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dm_regulator_ops scmi_voltd_ops = {
|
||||
.get_value = scmi_voltd_get_voltage_level,
|
||||
.set_value = scmi_voltd_set_voltage_level,
|
||||
.get_enable = scmi_voltd_get_enable,
|
||||
.set_enable = scmi_voltd_set_enable,
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(scmi_regulator) = {
|
||||
.name = "scmi_regulator",
|
||||
.id = UCLASS_REGULATOR,
|
||||
.ops = &scmi_voltd_ops,
|
||||
.probe = scmi_regulator_probe,
|
||||
.of_to_plat = scmi_regulator_of_to_plat,
|
||||
.plat_auto = sizeof(struct scmi_regulator_platdata),
|
||||
};
|
||||
|
||||
static int scmi_regulator_bind(struct udevice *dev)
|
||||
{
|
||||
struct driver *drv;
|
||||
ofnode node;
|
||||
int ret;
|
||||
|
||||
drv = DM_DRIVER_GET(scmi_regulator);
|
||||
|
||||
ofnode_for_each_subnode(node, dev_ofnode(dev)) {
|
||||
ret = device_bind(dev, drv, ofnode_get_name(node),
|
||||
NULL, node, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_DRIVER(scmi_voltage_domain) = {
|
||||
.name = "scmi_voltage_domain",
|
||||
.id = UCLASS_NOP,
|
||||
.bind = scmi_regulator_bind,
|
||||
};
|
@ -23,6 +23,7 @@ enum scmi_std_protocol {
|
||||
SCMI_PROTOCOL_ID_CLOCK = 0x14,
|
||||
SCMI_PROTOCOL_ID_SENSOR = 0x15,
|
||||
SCMI_PROTOCOL_ID_RESET_DOMAIN = 0x16,
|
||||
SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN = 0x17,
|
||||
};
|
||||
|
||||
enum scmi_status_code {
|
||||
@ -176,4 +177,116 @@ struct scmi_rd_reset_out {
|
||||
s32 status;
|
||||
};
|
||||
|
||||
/*
|
||||
* SCMI Voltage Domain Protocol
|
||||
*/
|
||||
|
||||
enum scmi_voltage_domain_message_id {
|
||||
SCMI_VOLTAGE_DOMAIN_ATTRIBUTES = 0x3,
|
||||
SCMI_VOLTAGE_DOMAIN_CONFIG_SET = 0x5,
|
||||
SCMI_VOLTAGE_DOMAIN_CONFIG_GET = 0x6,
|
||||
SCMI_VOLTAGE_DOMAIN_LEVEL_SET = 0x7,
|
||||
SCMI_VOLTAGE_DOMAIN_LEVEL_GET = 0x8,
|
||||
};
|
||||
|
||||
#define SCMI_VOLTD_NAME_LEN 16
|
||||
|
||||
#define SCMI_VOLTD_CONFIG_MASK GENMASK(3, 0)
|
||||
#define SCMI_VOLTD_CONFIG_OFF 0
|
||||
#define SCMI_VOLTD_CONFIG_ON 0x7
|
||||
|
||||
/**
|
||||
* struct scmi_voltd_attr_in - Payload for VOLTAGE_DOMAIN_ATTRIBUTES message
|
||||
* @domain_id: SCMI voltage domain ID
|
||||
*/
|
||||
struct scmi_voltd_attr_in {
|
||||
u32 domain_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct scmi_voltd_attr_out - Payload for VOLTAGE_DOMAIN_ATTRIBUTES response
|
||||
* @status: SCMI command status
|
||||
* @attributes: Retrieved attributes of the voltage domain
|
||||
* @name: Voltage domain name
|
||||
*/
|
||||
struct scmi_voltd_attr_out {
|
||||
s32 status;
|
||||
u32 attributes;
|
||||
char name[SCMI_VOLTD_NAME_LEN];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct scmi_voltd_config_set_in - Message payload for VOLTAGE_CONFIG_SET cmd
|
||||
* @domain_id: SCMI voltage domain ID
|
||||
* @config: Configuration data of the voltage domain
|
||||
*/
|
||||
struct scmi_voltd_config_set_in {
|
||||
u32 domain_id;
|
||||
u32 config;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct scmi_voltd_config_set_out - Response for VOLTAGE_CONFIG_SET command
|
||||
* @status: SCMI command status
|
||||
*/
|
||||
struct scmi_voltd_config_set_out {
|
||||
s32 status;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct scmi_voltd_config_get_in - Message payload for VOLTAGE_CONFIG_GET cmd
|
||||
* @domain_id: SCMI voltage domain ID
|
||||
*/
|
||||
struct scmi_voltd_config_get_in {
|
||||
u32 domain_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct scmi_voltd_config_get_out - Response for VOLTAGE_CONFIG_GET command
|
||||
* @status: SCMI command status
|
||||
* @config: Configuration data of the voltage domain
|
||||
*/
|
||||
struct scmi_voltd_config_get_out {
|
||||
s32 status;
|
||||
u32 config;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct scmi_voltd_level_set_in - Message payload for VOLTAGE_LEVEL_SET cmd
|
||||
* @domain_id: SCMI voltage domain ID
|
||||
* @flags: Parameter flags for configuring target level
|
||||
* @voltage_level: Target voltage level in microvolts (uV)
|
||||
*/
|
||||
struct scmi_voltd_level_set_in {
|
||||
u32 domain_id;
|
||||
u32 flags;
|
||||
s32 voltage_level;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct scmi_voltd_level_set_out - Response for VOLTAGE_LEVEL_SET command
|
||||
* @status: SCMI command status
|
||||
*/
|
||||
struct scmi_voltd_level_set_out {
|
||||
s32 status;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct scmi_voltd_level_get_in - Message payload for VOLTAGE_LEVEL_GET cmd
|
||||
* @domain_id: SCMI voltage domain ID
|
||||
*/
|
||||
struct scmi_voltd_level_get_in {
|
||||
u32 domain_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct scmi_voltd_level_get_out - Response for VOLTAGE_LEVEL_GET command
|
||||
* @status: SCMI command status
|
||||
* @voltage_level: Voltage level in microvolts (uV)
|
||||
*/
|
||||
struct scmi_voltd_level_get_out {
|
||||
s32 status;
|
||||
s32 voltage_level;
|
||||
};
|
||||
|
||||
#endif /* _SCMI_PROTOCOLS_H */
|
||||
|
Loading…
Reference in New Issue
Block a user