SCPI update for v4.13
Adds support to get DVFS transition latency and OPP for any device whose DVFS are managed by SCPI. This avoids code duplication in both cpufreq and devfreq SCPI drivers. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABCAAGBQJZQmv9AAoJEABBurwxfuKYerEP/jaBOlgvAomhBreaERMX5Oud He+7VIj2qjuapptE3Su2+t+IKCyebc2hTPSi+PhFNn4Upqk/ZchE5X+dbvXNG3nf eZzBCSsvGPJoIXVeU3ACB5rT+Apv0qm0PSYUPnu9ZyCl46/qGZFECVufDJN1TdQc FEdYZDi7mQotYL27Mx7q4i7vay8Z6MkJs9EH86BnB9M6dZa3C5kFY3jkm2tu1Rca 1ythsWMoy/Wrc7kHex8Dk90hbHBJ7RhJIYYxxv2IJ+67SkIdTd/+HpBcdLDpqVNt e9ElLAw9t4ym1PdgGcQjDcHlpqRkxucgOJhSticrxTNdGThTH6hx7HZhz+CqCJ7k e9my66sfKFH+wzz0C8agd1H9sMbaqoVoHUucj2kR6PR/rO/VQ9ugTDnaZfkRoPvh +87XEv+d7Gf/B4jfEUwxsfcLSDe1vpghSt02FM4BrYtdoTZFse9koPMt0jKGNnjO 5jzk7VQVoKLpB5Xg8X9ePv808GWlUWTaxuPYfZMqThPdNHPsnAJrWe47s42Yogqw ZswExEDY/MdixtgzZssi96r5m69QVycSCvs+QiBNDPFqRgsuwTC1CDtvF4/3vZks mLtIxQ9vPXgHY7SfPGVZH3RuE07YC3QA+0m22xBCytogeriuMtxsyzHAkB3z2YFf xSNL5FIu5jOGQRVZ+PKQ =8QF6 -----END PGP SIGNATURE----- Merge tag 'scpi-updates-4.13' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux into next/drivers SCPI update for v4.13 Adds support to get DVFS transition latency and OPP for any device whose DVFS are managed by SCPI. This avoids code duplication in both cpufreq and devfreq SCPI drivers. * tag 'scpi-updates-4.13' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux: cpufreq: scpi: use new scpi_ops functions to remove duplicate code firmware: arm_scpi: add support to populate OPPs and get transition latency Signed-off-by: Olof Johansson <olof@lixom.net>
This commit is contained in:
commit
93c452f5d3
@ -30,46 +30,20 @@
|
||||
|
||||
static struct scpi_ops *scpi_ops;
|
||||
|
||||
static struct scpi_dvfs_info *scpi_get_dvfs_info(struct device *cpu_dev)
|
||||
{
|
||||
int domain = topology_physical_package_id(cpu_dev->id);
|
||||
|
||||
if (domain < 0)
|
||||
return ERR_PTR(-EINVAL);
|
||||
return scpi_ops->dvfs_get_info(domain);
|
||||
}
|
||||
|
||||
static int scpi_get_transition_latency(struct device *cpu_dev)
|
||||
{
|
||||
struct scpi_dvfs_info *info = scpi_get_dvfs_info(cpu_dev);
|
||||
|
||||
if (IS_ERR(info))
|
||||
return PTR_ERR(info);
|
||||
return info->latency;
|
||||
return scpi_ops->get_transition_latency(cpu_dev);
|
||||
}
|
||||
|
||||
static int scpi_init_opp_table(const struct cpumask *cpumask)
|
||||
{
|
||||
int idx, ret;
|
||||
struct scpi_opp *opp;
|
||||
int ret;
|
||||
struct device *cpu_dev = get_cpu_device(cpumask_first(cpumask));
|
||||
struct scpi_dvfs_info *info = scpi_get_dvfs_info(cpu_dev);
|
||||
|
||||
if (IS_ERR(info))
|
||||
return PTR_ERR(info);
|
||||
|
||||
if (!info->opps)
|
||||
return -EIO;
|
||||
|
||||
for (opp = info->opps, idx = 0; idx < info->count; idx++, opp++) {
|
||||
ret = dev_pm_opp_add(cpu_dev, opp->freq, opp->m_volt * 1000);
|
||||
if (ret) {
|
||||
dev_warn(cpu_dev, "failed to add opp %uHz %umV\n",
|
||||
opp->freq, opp->m_volt);
|
||||
while (idx-- > 0)
|
||||
dev_pm_opp_remove(cpu_dev, (--opp)->freq);
|
||||
return ret;
|
||||
}
|
||||
ret = scpi_ops->add_opps_to_device(cpu_dev);
|
||||
if (ret) {
|
||||
dev_warn(cpu_dev, "failed to add opps to the device\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = dev_pm_opp_set_sharing_cpus(cpu_dev, cpumask);
|
||||
|
||||
@ -39,6 +39,7 @@
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/pm_opp.h>
|
||||
#include <linux/scpi_protocol.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sort.h>
|
||||
@ -684,6 +685,65 @@ static struct scpi_dvfs_info *scpi_dvfs_get_info(u8 domain)
|
||||
return info;
|
||||
}
|
||||
|
||||
static int scpi_dev_domain_id(struct device *dev)
|
||||
{
|
||||
struct of_phandle_args clkspec;
|
||||
|
||||
if (of_parse_phandle_with_args(dev->of_node, "clocks", "#clock-cells",
|
||||
0, &clkspec))
|
||||
return -EINVAL;
|
||||
|
||||
return clkspec.args[0];
|
||||
}
|
||||
|
||||
static struct scpi_dvfs_info *scpi_dvfs_info(struct device *dev)
|
||||
{
|
||||
int domain = scpi_dev_domain_id(dev);
|
||||
|
||||
if (domain < 0)
|
||||
return ERR_PTR(domain);
|
||||
|
||||
return scpi_dvfs_get_info(domain);
|
||||
}
|
||||
|
||||
static int scpi_dvfs_get_transition_latency(struct device *dev)
|
||||
{
|
||||
struct scpi_dvfs_info *info = scpi_dvfs_info(dev);
|
||||
|
||||
if (IS_ERR(info))
|
||||
return PTR_ERR(info);
|
||||
|
||||
if (!info->latency)
|
||||
return 0;
|
||||
|
||||
return info->latency;
|
||||
}
|
||||
|
||||
static int scpi_dvfs_add_opps_to_device(struct device *dev)
|
||||
{
|
||||
int idx, ret;
|
||||
struct scpi_opp *opp;
|
||||
struct scpi_dvfs_info *info = scpi_dvfs_info(dev);
|
||||
|
||||
if (IS_ERR(info))
|
||||
return PTR_ERR(info);
|
||||
|
||||
if (!info->opps)
|
||||
return -EIO;
|
||||
|
||||
for (opp = info->opps, idx = 0; idx < info->count; idx++, opp++) {
|
||||
ret = dev_pm_opp_add(dev, opp->freq, opp->m_volt * 1000);
|
||||
if (ret) {
|
||||
dev_warn(dev, "failed to add opp %uHz %umV\n",
|
||||
opp->freq, opp->m_volt);
|
||||
while (idx-- > 0)
|
||||
dev_pm_opp_remove(dev, (--opp)->freq);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scpi_sensor_get_capability(u16 *sensors)
|
||||
{
|
||||
struct sensor_capabilities cap_buf;
|
||||
@ -765,6 +825,9 @@ static struct scpi_ops scpi_ops = {
|
||||
.dvfs_get_idx = scpi_dvfs_get_idx,
|
||||
.dvfs_set_idx = scpi_dvfs_set_idx,
|
||||
.dvfs_get_info = scpi_dvfs_get_info,
|
||||
.device_domain_id = scpi_dev_domain_id,
|
||||
.get_transition_latency = scpi_dvfs_get_transition_latency,
|
||||
.add_opps_to_device = scpi_dvfs_add_opps_to_device,
|
||||
.sensor_get_capability = scpi_sensor_get_capability,
|
||||
.sensor_get_info = scpi_sensor_get_info,
|
||||
.sensor_get_value = scpi_sensor_get_value,
|
||||
|
||||
@ -67,6 +67,9 @@ struct scpi_ops {
|
||||
int (*dvfs_get_idx)(u8);
|
||||
int (*dvfs_set_idx)(u8, u8);
|
||||
struct scpi_dvfs_info *(*dvfs_get_info)(u8);
|
||||
int (*device_domain_id)(struct device *);
|
||||
int (*get_transition_latency)(struct device *);
|
||||
int (*add_opps_to_device)(struct device *);
|
||||
int (*sensor_get_capability)(u16 *sensors);
|
||||
int (*sensor_get_info)(u16 sensor_id, struct scpi_sensor_info *);
|
||||
int (*sensor_get_value)(u16, u64 *);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user