scp的全称是System Control and Management Interface ,其对应的源码为
https://github.com/ARM-software/SCP-firmware
其主要功能如下:
Initialization of the system to enable application core boot
Runtime services:
Power domain management
System power management
Performance domain management (Dynamic voltage and frequency scaling)
Clock management
Sensor management
System Control and Management Interface (SCMI, platform-side)
Support for the GNU Arm Embedded and Arm Compiler 6 toolchains
Support for platforms with several control processors
linux中的接口函数为/drivers/firmware/arm_scpi.c
这个是一个ko 文件,目前看只支持dts,还不支持ACPI
static struct platform_driver scpi_driver = {
.driver = {
.name = "scpi_protocol",
.of_match_table = scpi_of_match,
},
.probe = scpi_probe,
.remove = scpi_remove,
};
module_platform_driver(scpi_driver);
目前看scp中支持两类命令。其中一个是legacy
static int legacy_hpriority_cmds[] = {
LEGACY_SCPI_CMD_GET_CSS_PWR_STATE,
LEGACY_SCPI_CMD_CFG_PWR_STATE_STAT,
LEGACY_SCPI_CMD_GET_PWR_STATE_STAT,
LEGACY_SCPI_CMD_SET_DVFS,
LEGACY_SCPI_CMD_GET_DVFS,
LEGACY_SCPI_CMD_SET_RTC,
LEGACY_SCPI_CMD_GET_RTC,
LEGACY_SCPI_CMD_SET_CLOCK_INDEX,
LEGACY_SCPI_CMD_SET_CLOCK_VALUE,
LEGACY_SCPI_CMD_GET_CLOCK_VALUE,
LEGACY_SCPI_CMD_SET_PSU,
LEGACY_SCPI_CMD_GET_PSU,
LEGACY_SCPI_CMD_SENSOR_CFG_PERIODIC,
LEGACY_SCPI_CMD_SENSOR_CFG_BOUNDS,
};
另外一直就是正常的命令
enum scpi_drv_cmds {
CMD_SCPI_CAPABILITIES = 0,
CMD_GET_CLOCK_INFO,
CMD_GET_CLOCK_VALUE,
CMD_SET_CLOCK_VALUE,
CMD_GET_DVFS,
CMD_SET_DVFS,
CMD_GET_DVFS_INFO,
CMD_SENSOR_CAPABILITIES,
CMD_SENSOR_INFO,
CMD_SENSOR_VALUE,
CMD_SET_DEVICE_PWR_STATE,
CMD_GET_DEVICE_PWR_STATE,
CMD_MAX_COUNT,
};
这些命令的名字就是表示支持的功能,也就是命令就是设计
从这些命名看scp的功能大概分为4类
第一类是和clock相关的:
CMD_GET_CLOCK_INFO,
CMD_GET_CLOCK_VALUE,
CMD_SET_CLOCK_VALUE,
第二类是和dvfs相关的:
CMD_GET_DVFS,
CMD_SET_DVFS,
CMD_GET_DVFS_INFO,
第三类是和sensor相关的:
CMD_SENSOR_CAPABILITIES,
CMD_SENSOR_INFO,
CMD_SENSOR_VALUE,
第四类适合device power相关的:
CMD_SET_DEVICE_PWR_STATE,
CMD_GET_DEVICE_PWR_STATE,
目前看scp 有两个版本
static const struct of_device_id scpi_of_match[] = {
{.compatible = "arm,scpi"},
{.compatible = "arm,scpi-pre-1.0"},
{},
};
scp在kernel中的入口函数为:
static int scpi_probe(struct platform_device *pdev)
{
int count, idx, ret;
struct resource res;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
scpi_info = devm_kzalloc(dev, sizeof(*scpi_info), GFP_KERNEL);
if (!scpi_info)
return -ENOMEM;
#判断是否是legacy 如果是的话,则设置is_legacy = true
if (of_match_device(legacy_scpi_of_match, &pdev->dev))
scpi_info->is_legacy = true;
#计算mbox的个数,可见linux和scp之间是通过mbox来通信的
count = of_count_phandle_with_args(np, "mboxes", "#mbox-cells");
if (count < 0) {
dev_err(dev, "no mboxes property in '%pOF'\n", np);
return -ENODEV;
}
scpi_info->channels = devm_kcalloc(dev, count, sizeof(struct scpi_chan),
GFP_KERNEL);
if (!scpi_info->channels)
return -ENOMEM;
ret = devm_add_action(dev, scpi_free_channels, scpi_info);
if (ret)
return ret;
ret = scpi_init_versions(scpi_info);
if (ret) {
dev_err(dev, "incorrect or no SCP firmware found\n");
return ret;
}
#如果是能的scp的话,可以再开机log中看到下面的log
if (scpi_info->is_legacy && !scpi_info->protocol_version &&
!scpi_info->firmware_version)
dev_info(dev, "SCP Protocol legacy pre-1.0 firmware\n");
else
dev_info(dev, "SCP Protocol %lu.%lu Firmware %lu.%lu.%lu version\n",
FIELD_GET(PROTO_REV_MAJOR_MASK,
scpi_info->protocol_version),
FIELD_GET(PROTO_REV_MINOR_MASK,
scpi_info->protocol_version),
FIELD_GET(FW_REV_MAJOR_MASK,
scpi_info->firmware_version),
FIELD_GET(FW_REV_MINOR_MASK,
scpi_info->firmware_version),
FIELD_GET(FW_REV_PATCH_MASK,
scpi_info->firmware_version));
scpi_info->scpi_ops = &scpi_ops;
ret = devm_device_add_groups(dev, versions_groups);
if (ret)
dev_err(dev, "unable to create sysfs version group\n");
return devm_of_platform_populate(dev);
}