summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorViresh Kumar <viresh.kumar@linaro.org>2017-10-05 17:33:22 +0530
committerViresh Kumar <viresh.kumar@linaro.org>2017-10-06 14:40:42 +0530
commitadc3d9479927f6a4e4c3ec3cf4d9523102de49bb (patch)
tree545b2375eab6a9e075c60d7384818d3cf059ea6e
parent776ef2b22b0b4ec92ab5c293e639267a5642f388 (diff)
downloadlinux-adc3d9479927f6a4e4c3ec3cf4d9523102de49bb.tar.gz
opp: qcom: rpmpd: Add support to set performance states of OPPs
The OPP core needs to know the performance state for each OPP that the device supports, if we want to update performance states of the device's PM domain. Add support for Qualcomm's rpmpd for the same. signed-off-by: Rajendra Nayak <rnayak@codeaurora.org> signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
-rw-r--r--drivers/opp/Makefile2
-rw-r--r--drivers/opp/qcom_rpmpd.c127
2 files changed, 129 insertions, 0 deletions
diff --git a/drivers/opp/Makefile b/drivers/opp/Makefile
index e70ceb4..af96900 100644
--- a/drivers/opp/Makefile
+++ b/drivers/opp/Makefile
@@ -2,3 +2,5 @@ ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
obj-y += core.o cpu.o
obj-$(CONFIG_OF) += of.o
obj-$(CONFIG_DEBUG_FS) += debugfs.o
+
+obj-$(CONFIG_QCOM_RPMPD) += qcom_rpmpd.o
diff --git a/drivers/opp/qcom_rpmpd.c b/drivers/opp/qcom_rpmpd.c
new file mode 100644
index 0000000..750dd45
--- /dev/null
+++ b/drivers/opp/qcom_rpmpd.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/pm_opp.h>
+
+struct device;
+
+enum rpmpd_levels {
+ NONE,
+ LOWER, /* SVS2 */
+ LOW, /* SVS */
+ NOMINAL, /* NOMINAL */
+ HIGH, /* Turbo */
+ MAX_LEVEL,
+};
+
+struct rpmpd_freq_map {
+ struct device *dev;
+ unsigned long freq[MAX_LEVEL];
+};
+
+enum msm8996_devices {
+ SDHCI,
+ UFS,
+ PCIE,
+ USB3,
+};
+
+static struct rpmpd_freq_map msm8996_rpmpd_freq_map[] = {
+ [SDHCI] = {
+ .freq[LOWER] = 19200000,
+ .freq[LOW] = 200000000,
+ .freq[NOMINAL] = 400000000,
+ },
+ [UFS] = {
+ .freq[LOWER] = 19200000,
+ .freq[LOW] = 100000000,
+ .freq[NOMINAL] = 200000000,
+ .freq[HIGH] = 240000000,
+ },
+ [PCIE] = {
+ .freq[LOWER] = 1011000,
+ },
+ [USB3] = {
+ .freq[LOWER] = 60000000,
+ .freq[LOW] = 120000000,
+ .freq[NOMINAL] = 150000000,
+ },
+};
+
+static int get_pstate(struct device *dev, unsigned long rate)
+{
+ int i, j;
+
+ for (i = 0; i < ARRAY_SIZE(msm8996_rpmpd_freq_map); i++) {
+ if (dev != msm8996_rpmpd_freq_map[i].dev)
+ continue;
+
+ for (j = 0; j < MAX_LEVEL; j++) {
+ if (msm8996_rpmpd_freq_map[i].freq[j] >= rate)
+ return j;
+ }
+
+ return MAX_LEVEL;
+ }
+
+ /* Bug */
+ WARN_ON(1);
+
+ return 0;
+}
+
+static const struct of_device_id devices[] = {
+ { .compatible = "qcom,sdhci-msm-v4", .data = (void *)SDHCI },
+ { .compatible = "qcom,ufshc", .data = (void *)UFS },
+ { .compatible = "qcom,pcie-msm8996", .data = (void *)PCIE },
+ { .compatible = "qcom,dwc3", .data = (void *)USB3 },
+ { }
+};
+
+static int __init rpmpd_get_performance(void)
+{
+ struct platform_device *pdev;
+ struct device_node *np;
+ int i, index;
+
+ if (!of_machine_is_compatible("qcom,msm8996-mtp"))
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(devices); i++) {
+ np = of_find_compatible_node(NULL, NULL, devices[i].compatible);
+ if (!np)
+ continue;
+
+ pdev = of_find_device_by_node(np);
+ if (!pdev)
+ pdev = of_platform_device_create(np, NULL, NULL);
+
+ of_node_put(np);
+
+ if (!pdev)
+ continue;
+
+ index = (enum msm8996_devices)(devices[i].data);
+ msm8996_rpmpd_freq_map[index].dev = &pdev->dev;
+
+ dev_pm_opp_register_get_pstate_helper(&pdev->dev, get_pstate);
+ }
+
+ return 0;
+}
+subsys_initcall(rpmpd_get_performance);