aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOlof Johansson <olof@lixom.net>2017-06-18 23:55:07 -0400
committerOlof Johansson <olof@lixom.net>2017-06-18 23:55:07 -0400
commit93c452f5d396175b4bfbc989e379c47761af7271 (patch)
tree726bd366e1af487a62e2c9dd3aba1cc6be166451
parent8c2f8a2fb1248d5b8eda6271f095e7703fd133dd (diff)
parentc0f2e21953324def9e2f8394406b557d7cb5af64 (diff)
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>
-rw-r--r--drivers/cpufreq/scpi-cpufreq.c38
-rw-r--r--drivers/firmware/arm_scpi.c63
-rw-r--r--include/linux/scpi_protocol.h3
3 files changed, 72 insertions, 32 deletions
diff --git a/drivers/cpufreq/scpi-cpufreq.c b/drivers/cpufreq/scpi-cpufreq.c
index ea7a4e1b68c2..8de2364b5995 100644
--- a/drivers/cpufreq/scpi-cpufreq.c
+++ b/drivers/cpufreq/scpi-cpufreq.c
@@ -30,46 +30,20 @@
30 30
31static struct scpi_ops *scpi_ops; 31static struct scpi_ops *scpi_ops;
32 32
33static struct scpi_dvfs_info *scpi_get_dvfs_info(struct device *cpu_dev)
34{
35 int domain = topology_physical_package_id(cpu_dev->id);
36
37 if (domain < 0)
38 return ERR_PTR(-EINVAL);
39 return scpi_ops->dvfs_get_info(domain);
40}
41
42static int scpi_get_transition_latency(struct device *cpu_dev) 33static int scpi_get_transition_latency(struct device *cpu_dev)
43{ 34{
44 struct scpi_dvfs_info *info = scpi_get_dvfs_info(cpu_dev); 35 return scpi_ops->get_transition_latency(cpu_dev);
45
46 if (IS_ERR(info))
47 return PTR_ERR(info);
48 return info->latency;
49} 36}
50 37
51static int scpi_init_opp_table(const struct cpumask *cpumask) 38static int scpi_init_opp_table(const struct cpumask *cpumask)
52{ 39{
53 int idx, ret; 40 int ret;
54 struct scpi_opp *opp;
55 struct device *cpu_dev = get_cpu_device(cpumask_first(cpumask)); 41 struct device *cpu_dev = get_cpu_device(cpumask_first(cpumask));
56 struct scpi_dvfs_info *info = scpi_get_dvfs_info(cpu_dev);
57
58 if (IS_ERR(info))
59 return PTR_ERR(info);
60
61 if (!info->opps)
62 return -EIO;
63 42
64 for (opp = info->opps, idx = 0; idx < info->count; idx++, opp++) { 43 ret = scpi_ops->add_opps_to_device(cpu_dev);
65 ret = dev_pm_opp_add(cpu_dev, opp->freq, opp->m_volt * 1000); 44 if (ret) {
66 if (ret) { 45 dev_warn(cpu_dev, "failed to add opps to the device\n");
67 dev_warn(cpu_dev, "failed to add opp %uHz %umV\n", 46 return ret;
68 opp->freq, opp->m_volt);
69 while (idx-- > 0)
70 dev_pm_opp_remove(cpu_dev, (--opp)->freq);
71 return ret;
72 }
73 } 47 }
74 48
75 ret = dev_pm_opp_set_sharing_cpus(cpu_dev, cpumask); 49 ret = dev_pm_opp_set_sharing_cpus(cpu_dev, cpumask);
diff --git a/drivers/firmware/arm_scpi.c b/drivers/firmware/arm_scpi.c
index f6cfc31d34c7..8043e51de897 100644
--- a/drivers/firmware/arm_scpi.c
+++ b/drivers/firmware/arm_scpi.c
@@ -39,6 +39,7 @@
39#include <linux/of_address.h> 39#include <linux/of_address.h>
40#include <linux/of_platform.h> 40#include <linux/of_platform.h>
41#include <linux/printk.h> 41#include <linux/printk.h>
42#include <linux/pm_opp.h>
42#include <linux/scpi_protocol.h> 43#include <linux/scpi_protocol.h>
43#include <linux/slab.h> 44#include <linux/slab.h>
44#include <linux/sort.h> 45#include <linux/sort.h>
@@ -684,6 +685,65 @@ static struct scpi_dvfs_info *scpi_dvfs_get_info(u8 domain)
684 return info; 685 return info;
685} 686}
686 687
688static int scpi_dev_domain_id(struct device *dev)
689{
690 struct of_phandle_args clkspec;
691
692 if (of_parse_phandle_with_args(dev->of_node, "clocks", "#clock-cells",
693 0, &clkspec))
694 return -EINVAL;
695
696 return clkspec.args[0];
697}
698
699static struct scpi_dvfs_info *scpi_dvfs_info(struct device *dev)
700{
701 int domain = scpi_dev_domain_id(dev);
702
703 if (domain < 0)
704 return ERR_PTR(domain);
705
706 return scpi_dvfs_get_info(domain);
707}
708
709static int scpi_dvfs_get_transition_latency(struct device *dev)
710{
711 struct scpi_dvfs_info *info = scpi_dvfs_info(dev);
712
713 if (IS_ERR(info))
714 return PTR_ERR(info);
715
716 if (!info->latency)
717 return 0;
718
719 return info->latency;
720}
721
722static int scpi_dvfs_add_opps_to_device(struct device *dev)
723{
724 int idx, ret;
725 struct scpi_opp *opp;
726 struct scpi_dvfs_info *info = scpi_dvfs_info(dev);
727
728 if (IS_ERR(info))
729 return PTR_ERR(info);
730
731 if (!info->opps)
732 return -EIO;
733
734 for (opp = info->opps, idx = 0; idx < info->count; idx++, opp++) {
735 ret = dev_pm_opp_add(dev, opp->freq, opp->m_volt * 1000);
736 if (ret) {
737 dev_warn(dev, "failed to add opp %uHz %umV\n",
738 opp->freq, opp->m_volt);
739 while (idx-- > 0)
740 dev_pm_opp_remove(dev, (--opp)->freq);
741 return ret;
742 }
743 }
744 return 0;
745}
746
687static int scpi_sensor_get_capability(u16 *sensors) 747static int scpi_sensor_get_capability(u16 *sensors)
688{ 748{
689 struct sensor_capabilities cap_buf; 749 struct sensor_capabilities cap_buf;
@@ -765,6 +825,9 @@ static struct scpi_ops scpi_ops = {
765 .dvfs_get_idx = scpi_dvfs_get_idx, 825 .dvfs_get_idx = scpi_dvfs_get_idx,
766 .dvfs_set_idx = scpi_dvfs_set_idx, 826 .dvfs_set_idx = scpi_dvfs_set_idx,
767 .dvfs_get_info = scpi_dvfs_get_info, 827 .dvfs_get_info = scpi_dvfs_get_info,
828 .device_domain_id = scpi_dev_domain_id,
829 .get_transition_latency = scpi_dvfs_get_transition_latency,
830 .add_opps_to_device = scpi_dvfs_add_opps_to_device,
768 .sensor_get_capability = scpi_sensor_get_capability, 831 .sensor_get_capability = scpi_sensor_get_capability,
769 .sensor_get_info = scpi_sensor_get_info, 832 .sensor_get_info = scpi_sensor_get_info,
770 .sensor_get_value = scpi_sensor_get_value, 833 .sensor_get_value = scpi_sensor_get_value,
diff --git a/include/linux/scpi_protocol.h b/include/linux/scpi_protocol.h
index dc5f989be226..327d65663dbf 100644
--- a/include/linux/scpi_protocol.h
+++ b/include/linux/scpi_protocol.h
@@ -67,6 +67,9 @@ struct scpi_ops {
67 int (*dvfs_get_idx)(u8); 67 int (*dvfs_get_idx)(u8);
68 int (*dvfs_set_idx)(u8, u8); 68 int (*dvfs_set_idx)(u8, u8);
69 struct scpi_dvfs_info *(*dvfs_get_info)(u8); 69 struct scpi_dvfs_info *(*dvfs_get_info)(u8);
70 int (*device_domain_id)(struct device *);
71 int (*get_transition_latency)(struct device *);
72 int (*add_opps_to_device)(struct device *);
70 int (*sensor_get_capability)(u16 *sensors); 73 int (*sensor_get_capability)(u16 *sensors);
71 int (*sensor_get_info)(u16 sensor_id, struct scpi_sensor_info *); 74 int (*sensor_get_info)(u16 sensor_id, struct scpi_sensor_info *);
72 int (*sensor_get_value)(u16, u64 *); 75 int (*sensor_get_value)(u16, u64 *);