mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-18 22:14:16 +00:00
ARM cpufreq updates for 6.9
- General enhancements / cleanups to cpufreq drivers (tianyu2, Nícolas F. R. A. Prado, Erick Archer, Arnd Bergmann, Anastasia Belova). - Update cpufreq-dt-platdev to block/approve devices (Richard Acayan). - scmi: get transition delay from firmware (Pierre Gondois). -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEx73Crsp7f6M6scA70rkcPK6BEhwFAmXu2CMACgkQ0rkcPK6B EhxGMQ/+IBFDtHVRzPO6dQRWO1AFgUB3/XAWLPVjvVB3bhsBQS4BGFkkElyfUyfa vIQlZnerhgWbhw3pkLwbirN+yW9DWkBIgHwOtGaYaK9LeXEQfZ2+Yezc9uUe6syN HtHVLHntGetDP6FRQarTIeWYSE5FJOf1QhREIwBbXCmB4VvudcBuafAgykbKN92T p0bVHfKhaHlbYlOui3hJVBfRdDAgHlimawkqzOwqtugsoZ7rQcJDxO1OaE+ovH1E 5KlXTbugcDkct1g66SPOZxx6APQ4EeXFanlmBaQAmgT1unVRuqMQpLrkxgiFywcm ypMz7SGwXsh41J0aZAEhpRvwPu3pGLtdQOTK3Pwa24xKkn17I6yYlyLyCGseXiCY wZz4W+Y6WBP4wwUnYBB6TuwfROdY7wy9KTswxd/qWP4Q7LKXyangB6d0pXV6eSUc XPyZ21NiTw4BUCkzOzl5+4um2uF2t62sTWh1hg/KOKwnlAkBqnt8/BvkuoNYqRte sX3xiWjcF0sq1kZlkHtE8USFqiSioBgQm2KCjnuc5N5rsK9Qmc7fBHEe4sP975HV otHYlBai/Y5D5piTOJMVv92+Ghw9jjLPUmn1IUppt8QVLv0RY1nPmp1WSu2yh80/ 2a2d9bR5llDfyt1vh75X7Tdt1Bsf9LSJyYptfxJvge/L/7jrGhI= =Hu43 -----END PGP SIGNATURE----- Merge tag 'cpufreq-arm-updates-6.9' of git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm Merge ARM cpufreq updates for 6.9 from Viresh Kumar: "- General enhancements / cleanups to cpufreq drivers (tianyu2, Nícolas F. R. A. Prado, Erick Archer, Arnd Bergmann, Anastasia Belova). - Update cpufreq-dt-platdev to block/approve devices (Richard Acayan). - scmi: get transition delay from firmware (Pierre Gondois)." * tag 'cpufreq-arm-updates-6.9' of git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm: cpufreq: scmi: Set transition_delay_us firmware: arm_scmi: Populate fast channel rate_limit firmware: arm_scmi: Populate perf commands rate_limit cpufreq: qcom-hw: add CONFIG_COMMON_CLK dependency cpufreq: dt-platdev: block SDM670 in cpufreq-dt-platdev cpufreq: mediatek-hw: Don't error out if supply is not found Documentation: power: Use kcalloc() instead of kzalloc() cpufreq: mediatek-hw: Wait for CPU supplies before probing cpufreq: brcmstb-avs-cpufreq: add check for cpufreq_cpu_get's return value cpufreq: imx6: use regmap to read ocotp register
This commit is contained in:
commit
6b7195d305
13 changed files with 136 additions and 42 deletions
|
@ -305,7 +305,7 @@ dev_pm_opp_get_opp_count
|
||||||
{
|
{
|
||||||
/* Do things */
|
/* Do things */
|
||||||
num_available = dev_pm_opp_get_opp_count(dev);
|
num_available = dev_pm_opp_get_opp_count(dev);
|
||||||
speeds = kzalloc(sizeof(u32) * num_available, GFP_KERNEL);
|
speeds = kcalloc(num_available, sizeof(u32), GFP_KERNEL);
|
||||||
/* populate the table in increasing order */
|
/* populate the table in increasing order */
|
||||||
freq = 0;
|
freq = 0;
|
||||||
while (!IS_ERR(opp = dev_pm_opp_find_freq_ceil(dev, &freq))) {
|
while (!IS_ERR(opp = dev_pm_opp_find_freq_ceil(dev, &freq))) {
|
||||||
|
|
|
@ -274,7 +274,7 @@ dev_pm_opp_get_opp_count
|
||||||
{
|
{
|
||||||
/* 做一些事情 */
|
/* 做一些事情 */
|
||||||
num_available = dev_pm_opp_get_opp_count(dev);
|
num_available = dev_pm_opp_get_opp_count(dev);
|
||||||
speeds = kzalloc(sizeof(u32) * num_available, GFP_KERNEL);
|
speeds = kcalloc(num_available, sizeof(u32), GFP_KERNEL);
|
||||||
/* 按升序填充表 */
|
/* 按升序填充表 */
|
||||||
freq = 0;
|
freq = 0;
|
||||||
while (!IS_ERR(opp = dev_pm_opp_find_freq_ceil(dev, &freq))) {
|
while (!IS_ERR(opp = dev_pm_opp_find_freq_ceil(dev, &freq))) {
|
||||||
|
|
|
@ -173,6 +173,7 @@ config ARM_QCOM_CPUFREQ_NVMEM
|
||||||
config ARM_QCOM_CPUFREQ_HW
|
config ARM_QCOM_CPUFREQ_HW
|
||||||
tristate "QCOM CPUFreq HW driver"
|
tristate "QCOM CPUFreq HW driver"
|
||||||
depends on ARCH_QCOM || COMPILE_TEST
|
depends on ARCH_QCOM || COMPILE_TEST
|
||||||
|
depends on COMMON_CLK
|
||||||
help
|
help
|
||||||
Support for the CPUFreq HW driver.
|
Support for the CPUFreq HW driver.
|
||||||
Some QCOM chipsets have a HW engine to offload the steps
|
Some QCOM chipsets have a HW engine to offload the steps
|
||||||
|
|
|
@ -481,6 +481,8 @@ static bool brcm_avs_is_firmware_loaded(struct private_data *priv)
|
||||||
static unsigned int brcm_avs_cpufreq_get(unsigned int cpu)
|
static unsigned int brcm_avs_cpufreq_get(unsigned int cpu)
|
||||||
{
|
{
|
||||||
struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
|
struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
|
||||||
|
if (!policy)
|
||||||
|
return 0;
|
||||||
struct private_data *priv = policy->driver_data;
|
struct private_data *priv = policy->driver_data;
|
||||||
|
|
||||||
cpufreq_cpu_put(policy);
|
cpufreq_cpu_put(policy);
|
||||||
|
|
|
@ -156,6 +156,7 @@ static const struct of_device_id blocklist[] __initconst = {
|
||||||
{ .compatible = "qcom,sc7280", },
|
{ .compatible = "qcom,sc7280", },
|
||||||
{ .compatible = "qcom,sc8180x", },
|
{ .compatible = "qcom,sc8180x", },
|
||||||
{ .compatible = "qcom,sc8280xp", },
|
{ .compatible = "qcom,sc8280xp", },
|
||||||
|
{ .compatible = "qcom,sdm670", },
|
||||||
{ .compatible = "qcom,sdm845", },
|
{ .compatible = "qcom,sdm845", },
|
||||||
{ .compatible = "qcom,sdx75", },
|
{ .compatible = "qcom,sdx75", },
|
||||||
{ .compatible = "qcom,sm6115", },
|
{ .compatible = "qcom,sm6115", },
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
#include <linux/pm_opp.h>
|
#include <linux/pm_opp.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
|
#include <linux/mfd/syscon.h>
|
||||||
|
#include <linux/regmap.h>
|
||||||
|
|
||||||
#define PU_SOC_VOLTAGE_NORMAL 1250000
|
#define PU_SOC_VOLTAGE_NORMAL 1250000
|
||||||
#define PU_SOC_VOLTAGE_HIGH 1275000
|
#define PU_SOC_VOLTAGE_HIGH 1275000
|
||||||
|
@ -225,8 +227,6 @@ static void imx6x_disable_freq_in_opp(struct device *dev, unsigned long freq)
|
||||||
|
|
||||||
static int imx6q_opp_check_speed_grading(struct device *dev)
|
static int imx6q_opp_check_speed_grading(struct device *dev)
|
||||||
{
|
{
|
||||||
struct device_node *np;
|
|
||||||
void __iomem *base;
|
|
||||||
u32 val;
|
u32 val;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -235,16 +235,11 @@ static int imx6q_opp_check_speed_grading(struct device *dev)
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
} else {
|
} else {
|
||||||
np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-ocotp");
|
struct regmap *ocotp;
|
||||||
if (!np)
|
|
||||||
return -ENOENT;
|
|
||||||
|
|
||||||
base = of_iomap(np, 0);
|
ocotp = syscon_regmap_lookup_by_compatible("fsl,imx6q-ocotp");
|
||||||
of_node_put(np);
|
if (IS_ERR(ocotp))
|
||||||
if (!base) {
|
return -ENOENT;
|
||||||
dev_err(dev, "failed to map ocotp\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SPEED_GRADING[1:0] defines the max speed of ARM:
|
* SPEED_GRADING[1:0] defines the max speed of ARM:
|
||||||
|
@ -254,8 +249,7 @@ static int imx6q_opp_check_speed_grading(struct device *dev)
|
||||||
* 2b'00: 792000000Hz;
|
* 2b'00: 792000000Hz;
|
||||||
* We need to set the max speed of ARM according to fuse map.
|
* We need to set the max speed of ARM according to fuse map.
|
||||||
*/
|
*/
|
||||||
val = readl_relaxed(base + OCOTP_CFG3);
|
regmap_read(ocotp, OCOTP_CFG3, &val);
|
||||||
iounmap(base);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val >>= OCOTP_CFG3_SPEED_SHIFT;
|
val >>= OCOTP_CFG3_SPEED_SHIFT;
|
||||||
|
@ -290,25 +284,16 @@ static int imx6ul_opp_check_speed_grading(struct device *dev)
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
} else {
|
} else {
|
||||||
struct device_node *np;
|
struct regmap *ocotp;
|
||||||
void __iomem *base;
|
|
||||||
|
|
||||||
np = of_find_compatible_node(NULL, NULL, "fsl,imx6ul-ocotp");
|
ocotp = syscon_regmap_lookup_by_compatible("fsl,imx6ul-ocotp");
|
||||||
if (!np)
|
if (IS_ERR(ocotp))
|
||||||
np = of_find_compatible_node(NULL, NULL,
|
ocotp = syscon_regmap_lookup_by_compatible("fsl,imx6ull-ocotp");
|
||||||
"fsl,imx6ull-ocotp");
|
|
||||||
if (!np)
|
if (IS_ERR(ocotp))
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
base = of_iomap(np, 0);
|
regmap_read(ocotp, OCOTP_CFG3, &val);
|
||||||
of_node_put(np);
|
|
||||||
if (!base) {
|
|
||||||
dev_err(dev, "failed to map ocotp\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
val = readl_relaxed(base + OCOTP_CFG3);
|
|
||||||
iounmap(base);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_platform.h>
|
#include <linux/of_platform.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/regulator/consumer.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
|
||||||
#define LUT_MAX_ENTRIES 32U
|
#define LUT_MAX_ENTRIES 32U
|
||||||
|
@ -300,7 +301,23 @@ static struct cpufreq_driver cpufreq_mtk_hw_driver = {
|
||||||
static int mtk_cpufreq_hw_driver_probe(struct platform_device *pdev)
|
static int mtk_cpufreq_hw_driver_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
const void *data;
|
const void *data;
|
||||||
int ret;
|
int ret, cpu;
|
||||||
|
struct device *cpu_dev;
|
||||||
|
struct regulator *cpu_reg;
|
||||||
|
|
||||||
|
/* Make sure that all CPU supplies are available before proceeding. */
|
||||||
|
for_each_possible_cpu(cpu) {
|
||||||
|
cpu_dev = get_cpu_device(cpu);
|
||||||
|
if (!cpu_dev)
|
||||||
|
return dev_err_probe(&pdev->dev, -EPROBE_DEFER,
|
||||||
|
"Failed to get cpu%d device\n", cpu);
|
||||||
|
|
||||||
|
cpu_reg = devm_regulator_get(cpu_dev, "cpu");
|
||||||
|
if (IS_ERR(cpu_reg))
|
||||||
|
return dev_err_probe(&pdev->dev, PTR_ERR(cpu_reg),
|
||||||
|
"CPU%d regulator get failed\n", cpu);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
data = of_device_get_match_data(&pdev->dev);
|
data = of_device_get_match_data(&pdev->dev);
|
||||||
if (!data)
|
if (!data)
|
||||||
|
|
|
@ -144,6 +144,29 @@ scmi_get_cpu_power(struct device *cpu_dev, unsigned long *power,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
scmi_get_rate_limit(u32 domain, bool has_fast_switch)
|
||||||
|
{
|
||||||
|
int ret, rate_limit;
|
||||||
|
|
||||||
|
if (has_fast_switch) {
|
||||||
|
/*
|
||||||
|
* Fast channels are used whenever available,
|
||||||
|
* so use their rate_limit value if populated.
|
||||||
|
*/
|
||||||
|
ret = perf_ops->fast_switch_rate_limit(ph, domain,
|
||||||
|
&rate_limit);
|
||||||
|
if (!ret && rate_limit)
|
||||||
|
return rate_limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = perf_ops->rate_limit_get(ph, domain, &rate_limit);
|
||||||
|
if (ret)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return rate_limit;
|
||||||
|
}
|
||||||
|
|
||||||
static int scmi_cpufreq_init(struct cpufreq_policy *policy)
|
static int scmi_cpufreq_init(struct cpufreq_policy *policy)
|
||||||
{
|
{
|
||||||
int ret, nr_opp, domain;
|
int ret, nr_opp, domain;
|
||||||
|
@ -250,6 +273,9 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy)
|
||||||
policy->fast_switch_possible =
|
policy->fast_switch_possible =
|
||||||
perf_ops->fast_switch_possible(ph, domain);
|
perf_ops->fast_switch_possible(ph, domain);
|
||||||
|
|
||||||
|
policy->transition_delay_us =
|
||||||
|
scmi_get_rate_limit(domain, policy->fast_switch_possible);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_free_opp:
|
out_free_opp:
|
||||||
|
|
|
@ -1617,7 +1617,7 @@ static void
|
||||||
scmi_common_fastchannel_init(const struct scmi_protocol_handle *ph,
|
scmi_common_fastchannel_init(const struct scmi_protocol_handle *ph,
|
||||||
u8 describe_id, u32 message_id, u32 valid_size,
|
u8 describe_id, u32 message_id, u32 valid_size,
|
||||||
u32 domain, void __iomem **p_addr,
|
u32 domain, void __iomem **p_addr,
|
||||||
struct scmi_fc_db_info **p_db)
|
struct scmi_fc_db_info **p_db, u32 *rate_limit)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
u32 flags;
|
u32 flags;
|
||||||
|
@ -1661,6 +1661,9 @@ scmi_common_fastchannel_init(const struct scmi_protocol_handle *ph,
|
||||||
goto err_xfer;
|
goto err_xfer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rate_limit)
|
||||||
|
*rate_limit = le32_to_cpu(resp->rate_limit) & GENMASK(19, 0);
|
||||||
|
|
||||||
phys_addr = le32_to_cpu(resp->chan_addr_low);
|
phys_addr = le32_to_cpu(resp->chan_addr_low);
|
||||||
phys_addr |= (u64)le32_to_cpu(resp->chan_addr_high) << 32;
|
phys_addr |= (u64)le32_to_cpu(resp->chan_addr_high) << 32;
|
||||||
addr = devm_ioremap(ph->dev, phys_addr, size);
|
addr = devm_ioremap(ph->dev, phys_addr, size);
|
||||||
|
|
|
@ -153,6 +153,7 @@ struct perf_dom_info {
|
||||||
bool perf_fastchannels;
|
bool perf_fastchannels;
|
||||||
bool level_indexing_mode;
|
bool level_indexing_mode;
|
||||||
u32 opp_count;
|
u32 opp_count;
|
||||||
|
u32 rate_limit_us;
|
||||||
u32 sustained_freq_khz;
|
u32 sustained_freq_khz;
|
||||||
u32 sustained_perf_level;
|
u32 sustained_perf_level;
|
||||||
unsigned long mult_factor;
|
unsigned long mult_factor;
|
||||||
|
@ -266,6 +267,8 @@ scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph,
|
||||||
if (PROTOCOL_REV_MAJOR(version) >= 0x4)
|
if (PROTOCOL_REV_MAJOR(version) >= 0x4)
|
||||||
dom_info->level_indexing_mode =
|
dom_info->level_indexing_mode =
|
||||||
SUPPORTS_LEVEL_INDEXING(flags);
|
SUPPORTS_LEVEL_INDEXING(flags);
|
||||||
|
dom_info->rate_limit_us = le32_to_cpu(attr->rate_limit_us) &
|
||||||
|
GENMASK(19, 0);
|
||||||
dom_info->sustained_freq_khz =
|
dom_info->sustained_freq_khz =
|
||||||
le32_to_cpu(attr->sustained_freq_khz);
|
le32_to_cpu(attr->sustained_freq_khz);
|
||||||
dom_info->sustained_perf_level =
|
dom_info->sustained_perf_level =
|
||||||
|
@ -786,23 +789,27 @@ static void scmi_perf_domain_init_fc(const struct scmi_protocol_handle *ph,
|
||||||
|
|
||||||
ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL,
|
ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL,
|
||||||
PERF_LEVEL_GET, 4, dom->id,
|
PERF_LEVEL_GET, 4, dom->id,
|
||||||
&fc[PERF_FC_LEVEL].get_addr, NULL);
|
&fc[PERF_FC_LEVEL].get_addr, NULL,
|
||||||
|
&fc[PERF_FC_LEVEL].rate_limit);
|
||||||
|
|
||||||
ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL,
|
ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL,
|
||||||
PERF_LIMITS_GET, 8, dom->id,
|
PERF_LIMITS_GET, 8, dom->id,
|
||||||
&fc[PERF_FC_LIMIT].get_addr, NULL);
|
&fc[PERF_FC_LIMIT].get_addr, NULL,
|
||||||
|
&fc[PERF_FC_LIMIT].rate_limit);
|
||||||
|
|
||||||
if (dom->info.set_perf)
|
if (dom->info.set_perf)
|
||||||
ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL,
|
ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL,
|
||||||
PERF_LEVEL_SET, 4, dom->id,
|
PERF_LEVEL_SET, 4, dom->id,
|
||||||
&fc[PERF_FC_LEVEL].set_addr,
|
&fc[PERF_FC_LEVEL].set_addr,
|
||||||
&fc[PERF_FC_LEVEL].set_db);
|
&fc[PERF_FC_LEVEL].set_db,
|
||||||
|
&fc[PERF_FC_LEVEL].rate_limit);
|
||||||
|
|
||||||
if (dom->set_limits)
|
if (dom->set_limits)
|
||||||
ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL,
|
ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL,
|
||||||
PERF_LIMITS_SET, 8, dom->id,
|
PERF_LIMITS_SET, 8, dom->id,
|
||||||
&fc[PERF_FC_LIMIT].set_addr,
|
&fc[PERF_FC_LIMIT].set_addr,
|
||||||
&fc[PERF_FC_LIMIT].set_db);
|
&fc[PERF_FC_LIMIT].set_db,
|
||||||
|
&fc[PERF_FC_LIMIT].rate_limit);
|
||||||
|
|
||||||
dom->fc_info = fc;
|
dom->fc_info = fc;
|
||||||
}
|
}
|
||||||
|
@ -855,6 +862,23 @@ scmi_dvfs_transition_latency_get(const struct scmi_protocol_handle *ph,
|
||||||
return dom->opp[dom->opp_count - 1].trans_latency_us * 1000;
|
return dom->opp[dom->opp_count - 1].trans_latency_us * 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
scmi_dvfs_rate_limit_get(const struct scmi_protocol_handle *ph,
|
||||||
|
u32 domain, u32 *rate_limit)
|
||||||
|
{
|
||||||
|
struct perf_dom_info *dom;
|
||||||
|
|
||||||
|
if (!rate_limit)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
dom = scmi_perf_domain_lookup(ph, domain);
|
||||||
|
if (IS_ERR(dom))
|
||||||
|
return PTR_ERR(dom);
|
||||||
|
|
||||||
|
*rate_limit = dom->rate_limit_us;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int scmi_dvfs_freq_set(const struct scmi_protocol_handle *ph, u32 domain,
|
static int scmi_dvfs_freq_set(const struct scmi_protocol_handle *ph, u32 domain,
|
||||||
unsigned long freq, bool poll)
|
unsigned long freq, bool poll)
|
||||||
{
|
{
|
||||||
|
@ -954,6 +978,25 @@ static bool scmi_fast_switch_possible(const struct scmi_protocol_handle *ph,
|
||||||
return dom->fc_info && dom->fc_info[PERF_FC_LEVEL].set_addr;
|
return dom->fc_info && dom->fc_info[PERF_FC_LEVEL].set_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int scmi_fast_switch_rate_limit(const struct scmi_protocol_handle *ph,
|
||||||
|
u32 domain, u32 *rate_limit)
|
||||||
|
{
|
||||||
|
struct perf_dom_info *dom;
|
||||||
|
|
||||||
|
if (!rate_limit)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
dom = scmi_perf_domain_lookup(ph, domain);
|
||||||
|
if (IS_ERR(dom))
|
||||||
|
return PTR_ERR(dom);
|
||||||
|
|
||||||
|
if (!dom->fc_info)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
*rate_limit = dom->fc_info[PERF_FC_LEVEL].rate_limit;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static enum scmi_power_scale
|
static enum scmi_power_scale
|
||||||
scmi_power_scale_get(const struct scmi_protocol_handle *ph)
|
scmi_power_scale_get(const struct scmi_protocol_handle *ph)
|
||||||
{
|
{
|
||||||
|
@ -970,11 +1013,13 @@ static const struct scmi_perf_proto_ops perf_proto_ops = {
|
||||||
.level_set = scmi_perf_level_set,
|
.level_set = scmi_perf_level_set,
|
||||||
.level_get = scmi_perf_level_get,
|
.level_get = scmi_perf_level_get,
|
||||||
.transition_latency_get = scmi_dvfs_transition_latency_get,
|
.transition_latency_get = scmi_dvfs_transition_latency_get,
|
||||||
|
.rate_limit_get = scmi_dvfs_rate_limit_get,
|
||||||
.device_opps_add = scmi_dvfs_device_opps_add,
|
.device_opps_add = scmi_dvfs_device_opps_add,
|
||||||
.freq_set = scmi_dvfs_freq_set,
|
.freq_set = scmi_dvfs_freq_set,
|
||||||
.freq_get = scmi_dvfs_freq_get,
|
.freq_get = scmi_dvfs_freq_get,
|
||||||
.est_power_get = scmi_dvfs_est_power_get,
|
.est_power_get = scmi_dvfs_est_power_get,
|
||||||
.fast_switch_possible = scmi_fast_switch_possible,
|
.fast_switch_possible = scmi_fast_switch_possible,
|
||||||
|
.fast_switch_rate_limit = scmi_fast_switch_rate_limit,
|
||||||
.power_scale_get = scmi_power_scale_get,
|
.power_scale_get = scmi_power_scale_get,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -703,20 +703,24 @@ static void scmi_powercap_domain_init_fc(const struct scmi_protocol_handle *ph,
|
||||||
ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
|
ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
|
||||||
POWERCAP_CAP_SET, 4, domain,
|
POWERCAP_CAP_SET, 4, domain,
|
||||||
&fc[POWERCAP_FC_CAP].set_addr,
|
&fc[POWERCAP_FC_CAP].set_addr,
|
||||||
&fc[POWERCAP_FC_CAP].set_db);
|
&fc[POWERCAP_FC_CAP].set_db,
|
||||||
|
&fc[POWERCAP_FC_CAP].rate_limit);
|
||||||
|
|
||||||
ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
|
ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
|
||||||
POWERCAP_CAP_GET, 4, domain,
|
POWERCAP_CAP_GET, 4, domain,
|
||||||
&fc[POWERCAP_FC_CAP].get_addr, NULL);
|
&fc[POWERCAP_FC_CAP].get_addr, NULL,
|
||||||
|
&fc[POWERCAP_FC_CAP].rate_limit);
|
||||||
|
|
||||||
ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
|
ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
|
||||||
POWERCAP_PAI_SET, 4, domain,
|
POWERCAP_PAI_SET, 4, domain,
|
||||||
&fc[POWERCAP_FC_PAI].set_addr,
|
&fc[POWERCAP_FC_PAI].set_addr,
|
||||||
&fc[POWERCAP_FC_PAI].set_db);
|
&fc[POWERCAP_FC_PAI].set_db,
|
||||||
|
&fc[POWERCAP_FC_PAI].rate_limit);
|
||||||
|
|
||||||
ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
|
ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
|
||||||
POWERCAP_PAI_GET, 4, domain,
|
POWERCAP_PAI_GET, 4, domain,
|
||||||
&fc[POWERCAP_FC_PAI].get_addr, NULL);
|
&fc[POWERCAP_FC_PAI].get_addr, NULL,
|
||||||
|
&fc[POWERCAP_PAI_GET].rate_limit);
|
||||||
|
|
||||||
*p_fc = fc;
|
*p_fc = fc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -234,6 +234,7 @@ struct scmi_fc_info {
|
||||||
void __iomem *set_addr;
|
void __iomem *set_addr;
|
||||||
void __iomem *get_addr;
|
void __iomem *get_addr;
|
||||||
struct scmi_fc_db_info *set_db;
|
struct scmi_fc_db_info *set_db;
|
||||||
|
u32 rate_limit;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -268,7 +269,8 @@ struct scmi_proto_helpers_ops {
|
||||||
u8 describe_id, u32 message_id,
|
u8 describe_id, u32 message_id,
|
||||||
u32 valid_size, u32 domain,
|
u32 valid_size, u32 domain,
|
||||||
void __iomem **p_addr,
|
void __iomem **p_addr,
|
||||||
struct scmi_fc_db_info **p_db);
|
struct scmi_fc_db_info **p_db,
|
||||||
|
u32 *rate_limit);
|
||||||
void (*fastchannel_db_ring)(struct scmi_fc_db_info *db);
|
void (*fastchannel_db_ring)(struct scmi_fc_db_info *db);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -128,6 +128,8 @@ struct scmi_perf_domain_info {
|
||||||
* @level_set: sets the performance level of a domain
|
* @level_set: sets the performance level of a domain
|
||||||
* @level_get: gets the performance level of a domain
|
* @level_get: gets the performance level of a domain
|
||||||
* @transition_latency_get: gets the DVFS transition latency for a given device
|
* @transition_latency_get: gets the DVFS transition latency for a given device
|
||||||
|
* @rate_limit_get: gets the minimum time (us) required between successive
|
||||||
|
* requests
|
||||||
* @device_opps_add: adds all the OPPs for a given device
|
* @device_opps_add: adds all the OPPs for a given device
|
||||||
* @freq_set: sets the frequency for a given device using sustained frequency
|
* @freq_set: sets the frequency for a given device using sustained frequency
|
||||||
* to sustained performance level mapping
|
* to sustained performance level mapping
|
||||||
|
@ -137,6 +139,8 @@ struct scmi_perf_domain_info {
|
||||||
* at a given frequency
|
* at a given frequency
|
||||||
* @fast_switch_possible: indicates if fast DVFS switching is possible or not
|
* @fast_switch_possible: indicates if fast DVFS switching is possible or not
|
||||||
* for a given device
|
* for a given device
|
||||||
|
* @fast_switch_rate_limit: gets the minimum time (us) required between
|
||||||
|
* successive fast_switching requests
|
||||||
* @power_scale_mw_get: indicates if the power values provided are in milliWatts
|
* @power_scale_mw_get: indicates if the power values provided are in milliWatts
|
||||||
* or in some other (abstract) scale
|
* or in some other (abstract) scale
|
||||||
*/
|
*/
|
||||||
|
@ -154,6 +158,8 @@ struct scmi_perf_proto_ops {
|
||||||
u32 *level, bool poll);
|
u32 *level, bool poll);
|
||||||
int (*transition_latency_get)(const struct scmi_protocol_handle *ph,
|
int (*transition_latency_get)(const struct scmi_protocol_handle *ph,
|
||||||
u32 domain);
|
u32 domain);
|
||||||
|
int (*rate_limit_get)(const struct scmi_protocol_handle *ph,
|
||||||
|
u32 domain, u32 *rate_limit);
|
||||||
int (*device_opps_add)(const struct scmi_protocol_handle *ph,
|
int (*device_opps_add)(const struct scmi_protocol_handle *ph,
|
||||||
struct device *dev, u32 domain);
|
struct device *dev, u32 domain);
|
||||||
int (*freq_set)(const struct scmi_protocol_handle *ph, u32 domain,
|
int (*freq_set)(const struct scmi_protocol_handle *ph, u32 domain,
|
||||||
|
@ -164,6 +170,8 @@ struct scmi_perf_proto_ops {
|
||||||
unsigned long *rate, unsigned long *power);
|
unsigned long *rate, unsigned long *power);
|
||||||
bool (*fast_switch_possible)(const struct scmi_protocol_handle *ph,
|
bool (*fast_switch_possible)(const struct scmi_protocol_handle *ph,
|
||||||
u32 domain);
|
u32 domain);
|
||||||
|
int (*fast_switch_rate_limit)(const struct scmi_protocol_handle *ph,
|
||||||
|
u32 domain, u32 *rate_limit);
|
||||||
enum scmi_power_scale (*power_scale_get)(const struct scmi_protocol_handle *ph);
|
enum scmi_power_scale (*power_scale_get)(const struct scmi_protocol_handle *ph);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue