summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/boot/dts/rk3288-android.dtsi1
-rw-r--r--arch/arm/boot/dts/rk3288.dtsi1
-rw-r--r--arch/arm64/boot/dts/rockchip/px30-android.dtsi4
-rw-r--r--arch/arm64/boot/dts/rockchip/px30.dtsi1
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3368-android.dtsi4
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3368.dtsi1
-rw-r--r--drivers/clk/rockchip/clk-pll.c35
-rw-r--r--drivers/clk/rockchip/clk.h3
-rw-r--r--drivers/cpufreq/cpufreq-dt.c5
-rw-r--r--drivers/cpufreq/rockchip-cpufreq.c154
-rw-r--r--drivers/devfreq/rockchip_dmc.c22
-rw-r--r--drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_devfreq.h2
-rw-r--r--drivers/gpu/arm/bifrost/mali_kbase_core_linux.c17
-rwxr-xr-xdrivers/gpu/arm/bifrost/platform/rk/mali_kbase_config_rk.c22
-rwxr-xr-xdrivers/gpu/arm/mali400/mali/linux/mali_kernel_linux.c22
-rw-r--r--drivers/gpu/arm/mali400/mali/platform/rk/rk.c6
-rw-r--r--drivers/gpu/arm/midgard/mali_kbase_core_linux.c16
-rw-r--r--drivers/gpu/arm/midgard/platform/mali_kbase_platform_common.h2
-rw-r--r--drivers/gpu/arm/midgard/platform/rk/mali_kbase_config_rk.c22
-rw-r--r--drivers/soc/rockchip/rockchip_opp_select.c537
-rw-r--r--drivers/video/rockchip/vcodec/vcodec_service.c22
-rw-r--r--include/linux/cpufreq.h6
-rw-r--r--include/soc/rockchip/rockchip_opp_select.h27
23 files changed, 560 insertions, 372 deletions
diff --git a/arch/arm/boot/dts/rk3288-android.dtsi b/arch/arm/boot/dts/rk3288-android.dtsi
index 02938b0cbe92..a63cb6955559 100644
--- a/arch/arm/boot/dts/rk3288-android.dtsi
+++ b/arch/arm/boot/dts/rk3288-android.dtsi
@@ -394,6 +394,7 @@
};
&cpu0_opp_table {
+ rockchip,avs-enable = <1>;
clocks = <&cru PLL_APLL>;
leakage-scaling-sel = <0 254 25>;
diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
index e6ca69ba8ee1..6b075ef68157 100644
--- a/arch/arm/boot/dts/rk3288.dtsi
+++ b/arch/arm/boot/dts/rk3288.dtsi
@@ -131,6 +131,7 @@
compatible = "operating-points-v2";
opp-shared;
+ rockchip,avs-scale = <17>;
nvmem-cells = <&cpu_leakage>;
nvmem-cell-names = "cpu_leakage";
diff --git a/arch/arm64/boot/dts/rockchip/px30-android.dtsi b/arch/arm64/boot/dts/rockchip/px30-android.dtsi
index 8c9c92e2cd3c..71d4cc489ff1 100644
--- a/arch/arm64/boot/dts/rockchip/px30-android.dtsi
+++ b/arch/arm64/boot/dts/rockchip/px30-android.dtsi
@@ -71,6 +71,10 @@
};
};
+&cpu0_opp_table {
+ rockchip,avs-enable = <1>;
+};
+
&display_subsystem {
status = "disabled";
ports = <&vopb_out>, <&vopl_out>;
diff --git a/arch/arm64/boot/dts/rockchip/px30.dtsi b/arch/arm64/boot/dts/rockchip/px30.dtsi
index 96808ba408f6..d4254f0b4359 100644
--- a/arch/arm64/boot/dts/rockchip/px30.dtsi
+++ b/arch/arm64/boot/dts/rockchip/px30.dtsi
@@ -109,6 +109,7 @@
opp-shared;
clocks = <&cru PLL_APLL>;
+ rockchip,avs-scale = <4>;
rockchip,max-volt = <1350000>;
rockchip,evb-irdrop = <25000>;
nvmem-cells = <&cpu_leakage>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3368-android.dtsi b/arch/arm64/boot/dts/rockchip/rk3368-android.dtsi
index fb5d64950d81..b7a8ab6971f4 100644
--- a/arch/arm64/boot/dts/rockchip/rk3368-android.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3368-android.dtsi
@@ -173,6 +173,10 @@
};
};
+&cluster1_opp {
+ rockchip,avs-enable = <1>;
+};
+
&display_subsystem {
status = "okay";
diff --git a/arch/arm64/boot/dts/rockchip/rk3368.dtsi b/arch/arm64/boot/dts/rockchip/rk3368.dtsi
index a880a393bf0c..c5277499125e 100644
--- a/arch/arm64/boot/dts/rockchip/rk3368.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3368.dtsi
@@ -275,6 +275,7 @@
cluster1_opp: opp_table1 {
compatible = "operating-points-v2";
opp-shared;
+ rockchip,avs-sclae = <36>;
rockchip,leakage-scaling-sel = <
1 24 36
25 254 0
diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c
index da7221078b33..dea6ce39cb04 100644
--- a/drivers/clk/rockchip/clk-pll.c
+++ b/drivers/clk/rockchip/clk-pll.c
@@ -114,12 +114,12 @@ int rockchip_pll_clk_adaptive_scaling(struct clk *clk, int sel)
return 0;
}
-int rockchip_pll_clk_adaptive_rate(struct clk *clk, unsigned long rate)
+int rockchip_pll_clk_rate_to_scale(struct clk *clk, unsigned long rate)
{
const struct rockchip_pll_rate_table *rate_table;
struct clk *parent = clk_get_parent(clk);
struct rockchip_clk_pll *pll;
- int i;
+ unsigned int i;
if (IS_ERR_OR_NULL(parent))
return -EINVAL;
@@ -130,13 +130,34 @@ int rockchip_pll_clk_adaptive_rate(struct clk *clk, unsigned long rate)
rate_table = pll->rate_table;
for (i = 0; i < pll->rate_count; i++) {
- if (rate >= rate_table[i].rate) {
- pll->sel = i;
- break;
- }
+ if (rate >= rate_table[i].rate)
+ return i;
}
- return 0;
+ return -EINVAL;
+}
+
+int rockchip_pll_clk_scale_to_rate(struct clk *clk, unsigned int scale)
+{
+ const struct rockchip_pll_rate_table *rate_table;
+ struct clk *parent = clk_get_parent(clk);
+ struct rockchip_clk_pll *pll;
+ unsigned int i;
+
+ if (IS_ERR_OR_NULL(parent))
+ return -EINVAL;
+
+ pll = to_rockchip_clk_pll(__clk_get_hw(parent));
+ if (!pll)
+ return -EINVAL;
+
+ rate_table = pll->rate_table;
+ for (i = 0; i < pll->rate_count; i++) {
+ if (i == scale)
+ return rate_table[i].rate;
+ }
+
+ return -EINVAL;
}
static struct rockchip_pll_rate_table *rk_pll_rate_table_get(void)
diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h
index 779497c5512b..e4bcd2a5abb1 100644
--- a/drivers/clk/rockchip/clk.h
+++ b/drivers/clk/rockchip/clk.h
@@ -781,7 +781,8 @@ void rockchip_clk_register_armclk(struct rockchip_clk_provider *ctx,
int nrates);
void rockchip_clk_protect_critical(const char *const clocks[], int nclocks);
int rockchip_pll_clk_adaptive_scaling(struct clk *clk, int sel);
-int rockchip_pll_clk_adaptive_rate(struct clk *clk, unsigned long rate);
+int rockchip_pll_clk_rate_to_scale(struct clk *clk, unsigned long rate);
+int rockchip_pll_clk_scale_to_rate(struct clk *clk, unsigned int scale);
void rockchip_register_restart_notifier(struct rockchip_clk_provider *ctx,
unsigned int reg, void (*cb)(void));
diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c
index b785a328adc5..f07774f96a14 100644
--- a/drivers/cpufreq/cpufreq-dt.c
+++ b/drivers/cpufreq/cpufreq-dt.c
@@ -161,7 +161,7 @@ static int cpufreq_init(struct cpufreq_policy *policy)
unsigned long cur_freq;
bool opp_v1 = false;
const char *name;
- int ret;
+ int ret, scale;
static int check_init;
cpu_dev = get_cpu_device(policy->cpu);
@@ -227,7 +227,8 @@ static int cpufreq_init(struct cpufreq_policy *policy)
dev_pm_opp_of_remove_table(cpu_dev);
}
}
- rockchip_adjust_opp_by_irdrop(cpu_dev);
+ scale = rockchip_cpufreq_get_scale(policy->cpu);
+ rockchip_adjust_power_scale(cpu_dev, scale);
#else
dev_pm_opp_of_cpumask_add_table(policy->cpus);
#endif
diff --git a/drivers/cpufreq/rockchip-cpufreq.c b/drivers/cpufreq/rockchip-cpufreq.c
index bcd8e59303f9..35ad89aa417b 100644
--- a/drivers/cpufreq/rockchip-cpufreq.c
+++ b/drivers/cpufreq/rockchip-cpufreq.c
@@ -33,7 +33,6 @@
#include "../clk/rockchip/clk.h"
-#define MAX_PROP_NAME_LEN 3
#define LEAKAGE_INVALID 0xff
#define REBOOT_FREQ 816000 /* kHz */
@@ -42,10 +41,9 @@ struct cluster_info {
cpumask_t cpus;
unsigned int reboot_freq;
unsigned int threshold_freq;
- int leakage;
- int pvtm;
int volt_sel;
- int soc_version;
+ int scale;
+ int process;
bool offline;
bool rebooting;
bool freq_limit;
@@ -64,68 +62,27 @@ static struct cluster_info *rockchip_cluster_info_lookup(int cpu)
return NULL;
}
-static int rockchip_get_efuse_value(struct device_node *np, char *porp_name,
- int *value)
+int rockchip_cpufreq_get_scale(int cpu)
{
- struct nvmem_cell *cell;
- unsigned char *buf;
- size_t len;
-
- cell = of_nvmem_cell_get(np, porp_name);
- if (IS_ERR(cell))
- return PTR_ERR(cell);
-
- buf = (unsigned char *)nvmem_cell_read(cell, &len);
-
- nvmem_cell_put(cell);
-
- if (IS_ERR(buf))
- return PTR_ERR(buf);
-
- if (buf[0] == LEAKAGE_INVALID)
- return -EINVAL;
-
- *value = buf[0];
-
- kfree(buf);
-
- return 0;
-}
-
-static int rk3399_get_soc_version(struct device_node *np, int *soc_version)
-{
- int ret, version;
+ struct cluster_info *cluster;
- if (of_property_match_string(np, "nvmem-cell-names",
- "soc_version") < 0)
+ cluster = rockchip_cluster_info_lookup(cpu);
+ if (!cluster)
return 0;
-
- ret = rockchip_get_efuse_value(np, "soc_version", &version);
- if (ret)
- return ret;
-
- *soc_version = (version & 0xf0) >> 4;
-
- return 0;
+ else
+ return cluster->scale;
}
-
-static const struct of_device_id rockchip_cpufreq_of_match[] = {
- {
- .compatible = "rockchip,rk3399",
- .data = (void *)&rk3399_get_soc_version,
- },
- {},
-};
+EXPORT_SYMBOL_GPL(rockchip_cpufreq_get_scale);
static int rockchip_cpufreq_cluster_init(int cpu, struct cluster_info *cluster)
{
- int (*get_soc_version)(struct device_node *np, int *soc_version);
- const struct of_device_id *match;
- struct device_node *node, *np;
- struct clk *clk;
+ struct device_node *np;
struct device *dev;
- int lkg_volt_sel, pvtm_volt_sel, lkg_scale_sel;
- int ret;
+ int ret = 0, bin = -EINVAL;
+
+ cluster->process = -EINVAL;
+ cluster->volt_sel = -EINVAL;
+ cluster->scale = 0;
dev = get_cpu_device(cpu);
if (!dev)
@@ -138,19 +95,9 @@ static int rockchip_cpufreq_cluster_init(int cpu, struct cluster_info *cluster)
}
ret = dev_pm_opp_of_get_sharing_cpus(dev, &cluster->cpus);
- if (ret)
- return ret;
-
- cluster->soc_version = -1;
- node = of_find_node_by_path("/");
- match = of_match_node(rockchip_cpufreq_of_match, node);
- if (match && match->data) {
- get_soc_version = match->data;
- ret = get_soc_version(np, &cluster->soc_version);
- if (ret) {
- dev_err(dev, "Failed to get chip_version\n");
- return ret;
- }
+ if (ret) {
+ dev_err(dev, "Failed to get sharing cpus\n");
+ goto np_err;
}
if (of_property_read_u32(np, "rockchip,reboot-freq",
@@ -160,68 +107,23 @@ static int rockchip_cpufreq_cluster_init(int cpu, struct cluster_info *cluster)
&cluster->threshold_freq);
cluster->freq_limit = of_property_read_bool(np, "rockchip,freq-limit");
- lkg_scale_sel = rockchip_of_get_lkg_scale_sel(dev, "cpu_leakage");
- if (lkg_scale_sel > 0) {
- clk = of_clk_get_by_name(np, NULL);
- if (IS_ERR(clk)) {
- dev_err(dev, "Failed to get opp clk");
- return PTR_ERR(clk);
- }
- ret = rockchip_pll_clk_adaptive_scaling(clk,
- lkg_scale_sel);
- if (ret) {
- dev_err(dev, "Failed to adaptive scaling\n");
- return ret;
- }
- }
-
- lkg_volt_sel = rockchip_of_get_lkg_volt_sel(dev, "cpu_leakage");
- pvtm_volt_sel = rockchip_of_get_pvtm_volt_sel(dev, NULL, "cpu");
-
- cluster->volt_sel = max(lkg_volt_sel, pvtm_volt_sel);
-
- return 0;
+ rockchip_get_soc_info(dev, NULL, &bin, &cluster->process);
+ rockchip_get_scale_volt_sel(dev, "cpu_leakage", "cpu",
+ bin, cluster->process,
+ &cluster->scale, &cluster->volt_sel);
+np_err:
+ of_node_put(np);
+ return ret;
}
static int rockchip_cpufreq_set_opp_info(int cpu, struct cluster_info *cluster)
{
- struct device *dev;
- char name[MAX_PROP_NAME_LEN];
- int ret, version;
+ struct device *dev = get_cpu_device(cpu);
- dev = get_cpu_device(cpu);
if (!dev)
return -ENODEV;
-
- if (cluster->soc_version >= 0) {
- if (cluster->volt_sel >= 0)
- snprintf(name, MAX_PROP_NAME_LEN, "S%d-L%d",
- cluster->soc_version, cluster->volt_sel);
- else
- snprintf(name, MAX_PROP_NAME_LEN, "S%d",
- cluster->soc_version);
- } else if (cluster->volt_sel >= 0) {
- snprintf(name, MAX_PROP_NAME_LEN, "L%d", cluster->volt_sel);
- } else {
- return 0;
- }
-
- ret = dev_pm_opp_set_prop_name(dev, name);
- if (ret) {
- dev_err(dev, "Failed to set prop name\n");
- return ret;
- }
-
- if (cluster->soc_version >= 0) {
- version = BIT(cluster->soc_version);
- ret = dev_pm_opp_set_supported_hw(dev, &version, 1);
- if (ret) {
- dev_err(dev, "Failed to set supported hardware\n");
- return ret;
- }
- }
-
- return 0;
+ return rockchip_set_opp_info(dev, cluster->process,
+ cluster->volt_sel);
}
static int rockchip_hotcpu_notifier(struct notifier_block *nb,
diff --git a/drivers/devfreq/rockchip_dmc.c b/drivers/devfreq/rockchip_dmc.c
index 3dd5c69953ed..3f03b81400b7 100644
--- a/drivers/devfreq/rockchip_dmc.c
+++ b/drivers/devfreq/rockchip_dmc.c
@@ -2933,10 +2933,7 @@ static int rockchip_dmcfreq_probe(struct platform_device *pdev)
int (*init)(struct platform_device *pdev,
struct rockchip_dmcfreq *data);
unsigned long opp_rate, opp_volt;
-#define MAX_PROP_NAME_LEN 3
- char name[MAX_PROP_NAME_LEN];
bool is_events_available = false;
- int lkg_volt_sel, pvtm_volt_sel, volt_sel;
int ret;
data = devm_kzalloc(dev, sizeof(struct rockchip_dmcfreq), GFP_KERNEL);
@@ -2987,22 +2984,11 @@ static int rockchip_dmcfreq_probe(struct platform_device *pdev)
* We add a devfreq driver to our parent since it has a device tree node
* with operating points.
*/
- lkg_volt_sel = rockchip_of_get_lkg_volt_sel(dev, "ddr_leakage");
- pvtm_volt_sel = rockchip_of_get_pvtm_volt_sel(dev, NULL, "center");
-
- volt_sel = max(lkg_volt_sel, pvtm_volt_sel);
- if (volt_sel >= 0) {
- snprintf(name, MAX_PROP_NAME_LEN, "L%d", volt_sel);
- ret = dev_pm_opp_set_prop_name(dev, name);
- if (ret)
- dev_err(dev, "Failed to set prop name\n");
- }
-
- if (dev_pm_opp_of_add_table(dev)) {
- dev_err(dev, "Invalid operating-points in device tree.\n");
- return -EINVAL;
+ ret = rockchip_init_opp_table(dev, NULL, "ddr_leakage", "center");
+ if (ret) {
+ dev_err(dev, "Failed to init_opp_table (%d)\n", ret);
+ return ret;
}
- rockchip_adjust_opp_by_irdrop(dev);
if (rockchip_dmcfreq_init_freq_table(dev, devp))
return -EFAULT;
diff --git a/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_devfreq.h b/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_devfreq.h
index 7493ce900fd7..ed484366db24 100644
--- a/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_devfreq.h
+++ b/drivers/gpu/arm/bifrost/backend/gpu/mali_kbase_devfreq.h
@@ -25,6 +25,6 @@
int kbase_devfreq_init(struct kbase_device *kbdev);
void kbase_devfreq_term(struct kbase_device *kbdev);
-void kbase_platform_rk_set_opp_info(struct kbase_device *kbdev);
+int kbase_platform_rk_init_opp_table(struct kbase_device *kbdev);
#endif /* _BASE_DEVFREQ_H_ */
diff --git a/drivers/gpu/arm/bifrost/mali_kbase_core_linux.c b/drivers/gpu/arm/bifrost/mali_kbase_core_linux.c
index 7df2e39c45dd..0a744c35ae1d 100644
--- a/drivers/gpu/arm/bifrost/mali_kbase_core_linux.c
+++ b/drivers/gpu/arm/bifrost/mali_kbase_core_linux.c
@@ -3254,22 +3254,9 @@ static int power_control_init(struct platform_device *pdev)
}
}
- kbase_platform_rk_set_opp_info(kbdev);
-
-#if defined(CONFIG_OF) && defined(CONFIG_PM_OPP)
- /* Register the OPPs if they are available in device tree */
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) \
- || defined(LSK_OPPV2_BACKPORT)
- err = dev_pm_opp_of_add_table(kbdev->dev);
- rockchip_adjust_opp_by_irdrop(kbdev->dev);
-#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
- err = of_init_opp_table(kbdev->dev);
-#else
- err = 0;
-#endif /* LINUX_VERSION_CODE */
+ err = kbase_platform_rk_init_opp_table(kbdev);
if (err)
- dev_dbg(kbdev->dev, "OPP table not found\n");
-#endif /* CONFIG_OF && CONFIG_PM_OPP */
+ dev_err(kbdev->dev, "Failed to init_opp_table (%d)\n", err);
return 0;
diff --git a/drivers/gpu/arm/bifrost/platform/rk/mali_kbase_config_rk.c b/drivers/gpu/arm/bifrost/platform/rk/mali_kbase_config_rk.c
index f9607d6fdf09..e7fa0c84dc91 100755
--- a/drivers/gpu/arm/bifrost/platform/rk/mali_kbase_config_rk.c
+++ b/drivers/gpu/arm/bifrost/platform/rk/mali_kbase_config_rk.c
@@ -433,24 +433,8 @@ static void kbase_platform_rk_remove_sysfs_files(struct device *dev)
device_remove_file(dev, &dev_attr_utilisation);
}
-void kbase_platform_rk_set_opp_info(struct kbase_device *kbdev)
+int kbase_platform_rk_init_opp_table(struct kbase_device *kbdev)
{
-#define MAX_PROP_NAME_LEN 3
- char name[MAX_PROP_NAME_LEN];
- int lkg_volt_sel, pvtm_volt_sel, volt_sel;
- int err = 0;
-
- if (!kbdev)
- return;
-
- lkg_volt_sel = rockchip_of_get_lkg_volt_sel(kbdev->dev, "gpu_leakage");
- pvtm_volt_sel = rockchip_of_get_pvtm_volt_sel(kbdev->dev, NULL, "mali");
-
- volt_sel = max(lkg_volt_sel, pvtm_volt_sel);
- if (volt_sel >= 0) {
- snprintf(name, MAX_PROP_NAME_LEN, "L%d", volt_sel);
- err = dev_pm_opp_set_prop_name(kbdev->dev, name);
- if (err)
- dev_err(kbdev->dev, "Failed to set prop name\n");
- }
+ return rockchip_init_opp_table(kbdev->dev, NULL,
+ "gpu_leakage", "mali");
}
diff --git a/drivers/gpu/arm/mali400/mali/linux/mali_kernel_linux.c b/drivers/gpu/arm/mali400/mali/linux/mali_kernel_linux.c
index ecfd5c3456bd..08df33df5d21 100755
--- a/drivers/gpu/arm/mali400/mali/linux/mali_kernel_linux.c
+++ b/drivers/gpu/arm/mali400/mali/linux/mali_kernel_linux.c
@@ -205,6 +205,8 @@ extern int mali_platform_device_unregister(void);
#endif
#endif
+extern int rk_platform_init_opp_table(struct device *dev);
+
/* Linux power management operations provided by the Mali device driver */
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29))
struct pm_ext_ops mali_dev_ext_pm_ops = {
@@ -518,10 +520,7 @@ static int mali_probe(struct platform_device *pdev)
{
int err;
#ifdef CONFIG_MALI_DEVFREQ
-#define MAX_PROP_NAME_LEN 3
struct mali_device *mdev;
- char name[MAX_PROP_NAME_LEN];
- int lkg_volt_sel;
#endif
MALI_DEBUG_PRINT(2, ("mali_probe(): Called for platform device %s\n", pdev->name));
@@ -567,14 +566,6 @@ static int mali_probe(struct platform_device *pdev)
mdev->dev = &pdev->dev;
dev_set_drvdata(mdev->dev, mdev);
- lkg_volt_sel = rockchip_of_get_lkg_volt_sel(mdev->dev, "gpu_leakage");
- if (lkg_volt_sel >= 0) {
- snprintf(name, MAX_PROP_NAME_LEN, "L%d", lkg_volt_sel);
- err = dev_pm_opp_set_prop_name(mdev->dev, name);
- if (err)
- dev_err(mdev->dev, "Failed to set prop name\n");
- }
-
/*Initilization clock and regulator*/
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) && defined(CONFIG_OF) \
&& defined(CONFIG_REGULATOR)
@@ -586,12 +577,9 @@ static int mali_probe(struct platform_device *pdev)
}
#endif /* LINUX_VERSION_CODE >= 3, 12, 0 */
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) && defined(CONFIG_OF) \
- && defined(CONFIG_PM_OPP)
- /* Register the OPPs if they are available in device tree */
- if (dev_pm_opp_of_add_table(mdev->dev) < 0)
- MALI_DEBUG_PRINT(3, ("OPP table not found\n"));
-#endif
+ err = rk_platform_init_opp_table(mdev->dev);
+ if (err)
+ MALI_DEBUG_PRINT(3, ("Failed to init_opp_table\n"));
/* Need to name the gpu clock "clk_mali" in the device tree */
mdev->clock = clk_get(mdev->dev, "clk_mali");
diff --git a/drivers/gpu/arm/mali400/mali/platform/rk/rk.c b/drivers/gpu/arm/mali400/mali/platform/rk/rk.c
index 46a8ba8901bb..80eadf12a70f 100644
--- a/drivers/gpu/arm/mali400/mali/platform/rk/rk.c
+++ b/drivers/gpu/arm/mali400/mali/platform/rk/rk.c
@@ -35,6 +35,7 @@
#include <linux/pm_runtime.h>
#include <linux/delay.h>
#include <linux/rockchip/cpu.h>
+#include <soc/rockchip/rockchip_opp_select.h>
#include <linux/mali/mali_utgard.h>
#include "mali_kernel_common.h"
@@ -444,6 +445,11 @@ static void rk_platform_power_off_gpu(struct device *dev)
rk_platform_disable_gpu_regulator(dev);
}
+int rk_platform_init_opp_table(struct device *dev)
+{
+ return rockchip_init_opp_table(dev, NULL, "gpu_leakage", "mali");
+}
+
static int mali_runtime_suspend(struct device *device)
{
int ret = 0;
diff --git a/drivers/gpu/arm/midgard/mali_kbase_core_linux.c b/drivers/gpu/arm/midgard/mali_kbase_core_linux.c
index 65b2045a35b7..3a6e5aae0bce 100644
--- a/drivers/gpu/arm/midgard/mali_kbase_core_linux.c
+++ b/drivers/gpu/arm/midgard/mali_kbase_core_linux.c
@@ -3880,21 +3880,9 @@ static int power_control_init(struct platform_device *pdev)
}
}
- kbase_platform_rk_set_opp_info(kbdev);
-
-#if defined(CONFIG_OF) && defined(CONFIG_PM_OPP)
- /* Register the OPPs if they are available in device tree */
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) \
- || defined(LSK_OPPV2_BACKPORT)
- err = dev_pm_opp_of_add_table(kbdev->dev);
-#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
- err = of_init_opp_table(kbdev->dev);
-#else
- err = 0;
-#endif /* LINUX_VERSION_CODE */
+ err = kbase_platform_rk_init_opp_table(kbdev);
if (err)
- dev_dbg(kbdev->dev, "OPP table not found\n");
-#endif /* CONFIG_OF && CONFIG_PM_OPP */
+ dev_err(kbdev->dev, "Failed to init_opp_table (%d)\n", err);
return 0;
diff --git a/drivers/gpu/arm/midgard/platform/mali_kbase_platform_common.h b/drivers/gpu/arm/midgard/platform/mali_kbase_platform_common.h
index a9569e808fb8..c11085af5f24 100644
--- a/drivers/gpu/arm/midgard/platform/mali_kbase_platform_common.h
+++ b/drivers/gpu/arm/midgard/platform/mali_kbase_platform_common.h
@@ -25,4 +25,4 @@
* @return Zero to indicate success non-zero for failure.
*/
int kbase_platform_early_init(void);
-void kbase_platform_rk_set_opp_info(struct kbase_device *kbdev);
+int kbase_platform_rk_init_opp_table(struct kbase_device *kbdev);
diff --git a/drivers/gpu/arm/midgard/platform/rk/mali_kbase_config_rk.c b/drivers/gpu/arm/midgard/platform/rk/mali_kbase_config_rk.c
index 402e984b5dd6..3b223a44a44c 100644
--- a/drivers/gpu/arm/midgard/platform/rk/mali_kbase_config_rk.c
+++ b/drivers/gpu/arm/midgard/platform/rk/mali_kbase_config_rk.c
@@ -430,24 +430,8 @@ static void kbase_platform_rk_remove_sysfs_files(struct device *dev)
device_remove_file(dev, &dev_attr_utilisation);
}
-void kbase_platform_rk_set_opp_info(struct kbase_device *kbdev)
+int kbase_platform_rk_init_opp_table(struct kbase_device *kbdev)
{
-#define MAX_PROP_NAME_LEN 3
- char name[MAX_PROP_NAME_LEN];
- int lkg_volt_sel, pvtm_volt_sel, volt_sel;
- int err = 0;
-
- if (!kbdev)
- return;
-
- lkg_volt_sel = rockchip_of_get_lkg_volt_sel(kbdev->dev, "gpu_leakage");
- pvtm_volt_sel = rockchip_of_get_pvtm_volt_sel(kbdev->dev, NULL, "mali");
-
- volt_sel = max(lkg_volt_sel, pvtm_volt_sel);
- if (volt_sel >= 0) {
- snprintf(name, MAX_PROP_NAME_LEN, "L%d", volt_sel);
- err = dev_pm_opp_set_prop_name(kbdev->dev, name);
- if (err)
- dev_err(kbdev->dev, "Failed to set prop name\n");
- }
+ return rockchip_init_opp_table(kbdev->dev, NULL,
+ "gpu_leakage", "mali");
}
diff --git a/drivers/soc/rockchip/rockchip_opp_select.c b/drivers/soc/rockchip/rockchip_opp_select.c
index 8bf81739ceea..88e746b687a5 100644
--- a/drivers/soc/rockchip/rockchip_opp_select.c
+++ b/drivers/soc/rockchip/rockchip_opp_select.c
@@ -16,15 +16,21 @@
#include "../../clk/rockchip/clk.h"
#include "../../base/power/opp/opp.h"
-#define LEAKAGE_TABLE_END ~1
+#define MAX_PROP_NAME_LEN 6
+#define SEL_TABLE_END ~1
#define LEAKAGE_INVALID 0xff
-struct volt_sel_table {
+struct sel_table {
int min;
int max;
int sel;
};
+struct bin_sel_table {
+ int bin;
+ int sel;
+};
+
struct pvtm_config {
unsigned int freq;
unsigned int volt;
@@ -42,8 +48,8 @@ struct pvtm_config {
#define PVTM_SUB_CH_MAX 8
static int pvtm_value[PVTM_CH_MAX][PVTM_SUB_CH_MAX];
-static int rockchip_get_efuse_value(struct device_node *np, char *porp_name,
- int *value)
+int rockchip_get_efuse_value(struct device_node *np, char *porp_name,
+ int *value)
{
struct nvmem_cell *cell;
unsigned char *buf;
@@ -69,11 +75,12 @@ static int rockchip_get_efuse_value(struct device_node *np, char *porp_name,
return 0;
}
+EXPORT_SYMBOL(rockchip_get_efuse_value);
-static int rockchip_get_volt_sel_table(struct device_node *np, char *porp_name,
- struct volt_sel_table **table)
+static int rockchip_get_sel_table(struct device_node *np, char *porp_name,
+ struct sel_table **table)
{
- struct volt_sel_table *sel_table;
+ struct sel_table *sel_table;
const struct property *prop;
int count, i;
@@ -105,32 +112,95 @@ static int rockchip_get_volt_sel_table(struct device_node *np, char *porp_name,
}
sel_table[i].min = 0;
sel_table[i].max = 0;
- sel_table[i].sel = LEAKAGE_TABLE_END;
+ sel_table[i].sel = SEL_TABLE_END;
*table = sel_table;
return 0;
}
-static int rockchip_get_volt_sel(struct device_node *np, char *name,
- int value, int *sel)
+static int rockchip_get_bin_sel_table(struct device_node *np, char *porp_name,
+ struct bin_sel_table **table)
{
- struct volt_sel_table *table;
- int i, j = -1, ret;
+ struct bin_sel_table *sel_table;
+ const struct property *prop;
+ int count, i;
- ret = rockchip_get_volt_sel_table(np, name, &table);
- if (ret)
+ prop = of_find_property(np, porp_name, NULL);
+ if (!prop)
+ return -EINVAL;
+
+ if (!prop->value)
+ return -ENODATA;
+
+ count = of_property_count_u32_elems(np, porp_name);
+ if (count < 0)
+ return -EINVAL;
+
+ if (count % 2)
return -EINVAL;
- for (i = 0; table[i].sel != LEAKAGE_TABLE_END; i++) {
- if (value >= table[i].min)
- j = i;
+ sel_table = kzalloc(sizeof(*sel_table) * (count / 2 + 1), GFP_KERNEL);
+ if (!sel_table)
+ return -ENOMEM;
+
+ for (i = 0; i < count / 2; i++) {
+ of_property_read_u32_index(np, porp_name, 2 * i,
+ &sel_table[i].bin);
+ of_property_read_u32_index(np, porp_name, 2 * i + 1,
+ &sel_table[i].sel);
}
- if (j != -1)
- *sel = table[j].sel;
- else
- ret = -EINVAL;
+ sel_table[i].bin = 0;
+ sel_table[i].sel = SEL_TABLE_END;
+
+ *table = sel_table;
+
+ return 0;
+}
+
+static int rockchip_get_sel(struct device_node *np, char *name,
+ int value, int *sel)
+{
+ struct sel_table *table = NULL;
+ int i, ret = -EINVAL;
+
+ if (!sel)
+ return -EINVAL;
+
+ if (rockchip_get_sel_table(np, name, &table))
+ return -EINVAL;
+
+ for (i = 0; table[i].sel != SEL_TABLE_END; i++) {
+ if (value >= table[i].min) {
+ *sel = table[i].sel;
+ ret = 0;
+ }
+ }
+ kfree(table);
+
+ return ret;
+}
+
+static int rockchip_get_bin_sel(struct device_node *np, char *name,
+ int value, int *sel)
+{
+ struct bin_sel_table *table = NULL;
+ int i, ret = -EINVAL;
+
+ if (!sel)
+ return -EINVAL;
+
+ if (rockchip_get_bin_sel_table(np, name, &table))
+ return -EINVAL;
+
+ for (i = 0; table[i].sel != SEL_TABLE_END; i++) {
+ if (value == table[i].bin) {
+ *sel = table[i].sel;
+ ret = 0;
+ break;
+ }
+ }
kfree(table);
return ret;
@@ -147,7 +217,7 @@ static int rockchip_parse_pvtm_config(struct device_node *np,
return -EINVAL;
if (of_property_read_u32_array(np, "rockchip,pvtm-ch", pvtm->ch, 2))
return -EINVAL;
- if (pvtm->ch[0] > PVTM_CH_MAX || pvtm->ch[1] > PVTM_SUB_CH_MAX)
+ if (pvtm->ch[0] >= PVTM_CH_MAX || pvtm->ch[1] >= PVTM_SUB_CH_MAX)
return -EINVAL;
if (of_property_read_u32(np, "rockchip,pvtm-sample-time",
&pvtm->sample_time))
@@ -190,7 +260,7 @@ static int rockchip_get_pvtm_specific_value(struct device *dev,
if (of_property_read_u32_array(np, "rockchip,pvtm-ch", ch, 2))
return -EINVAL;
- if (ch[0] > PVTM_CH_MAX || ch[1] > PVTM_SUB_CH_MAX)
+ if (ch[0] >= PVTM_CH_MAX || ch[1] >= PVTM_SUB_CH_MAX)
return -EINVAL;
if (pvtm_value[ch[0]][ch[1]]) {
@@ -273,134 +343,243 @@ pvtm_value_out:
return ret;
}
-int rockchip_of_get_lkg_scale_sel(struct device *dev, char *name)
+void rockchip_of_get_lkg_sel(struct device *dev, struct device_node *np,
+ char *lkg_name, int process,
+ int *volt_sel, int *scale_sel)
{
- struct device_node *np;
- int leakage, volt_sel;
- int ret;
+ struct property *prop = NULL;
+ struct nvmem_cell *cell;
+ int leakage = -EINVAL, ret;
+ char name[NAME_MAX];
- np = of_parse_phandle(dev->of_node, "operating-points-v2", 0);
- if (!np) {
- dev_warn(dev, "OPP-v2 not supported\n");
- return -ENOENT;
+ cell = of_nvmem_cell_get(np, "leakage");
+ if (IS_ERR(cell)) {
+ ret = rockchip_get_efuse_value(np, lkg_name, &leakage);
+ } else {
+ nvmem_cell_put(cell);
+ ret = rockchip_get_efuse_value(np, "leakage", &leakage);
+ }
+ if (ret) {
+ dev_err(dev, "Failed to get leakage\n");
+ return;
}
+ dev_info(dev, "leakage=%d\n", leakage);
+
+ if (!volt_sel)
+ goto next;
+ if (process >= 0) {
+ snprintf(name, sizeof(name),
+ "rockchip,p%d-leakage-voltage-sel", process);
+ prop = of_find_property(np, name, NULL);
+ }
+ if (!prop)
+ sprintf(name, "rockchip,leakage-voltage-sel");
+ ret = rockchip_get_sel(np, name, leakage, volt_sel);
+ if (!ret)
+ dev_info(dev, "leakage-volt-sel=%d\n", *volt_sel);
+
+next:
+ if (!scale_sel)
+ return;
+ if (process >= 0) {
+ snprintf(name, sizeof(name),
+ "rockchip,p%d-leakage-scaling-sel", process);
+ prop = of_find_property(np, name, NULL);
+ }
+ if (!prop)
+ sprintf(name, "rockchip,leakage-scaling-sel");
+ ret = rockchip_get_sel(np, name, leakage, scale_sel);
+ if (!ret)
+ dev_info(dev, "leakage-scale=%d\n", *scale_sel);
+}
+EXPORT_SYMBOL(rockchip_of_get_lkg_sel);
- ret = rockchip_get_efuse_value(np, name, &leakage);
- if (!ret) {
- dev_info(dev, "%s=%d\n", name, leakage);
- ret = rockchip_get_volt_sel(np, "rockchip,leakage-scaling-sel",
- leakage, &volt_sel);
- if (!ret) {
- dev_info(dev, "%s-scale-sel=%d\n", name, volt_sel);
- return volt_sel;
- }
- } else {
- dev_info(dev, "get %s fail\n", name);
- ret = rockchip_get_volt_sel(np, "rockchip,leakage-scaling-sel",
- 0, &volt_sel);
- if (!ret) {
- dev_info(dev, "%s-scale-sel=%d\n", name, volt_sel);
- return volt_sel;
- }
+void rockchip_of_get_pvtm_sel(struct device *dev, struct device_node *np,
+ char *reg_name, int process,
+ int *volt_sel, int *scale_sel)
+{
+ struct property *prop = NULL;
+ struct regulator *reg;
+ struct clk *clk;
+ int pvtm = -EINVAL, ret;
+ char name[NAME_MAX];
+
+ clk = clk_get(dev, NULL);
+ if (IS_ERR_OR_NULL(clk)) {
+ dev_warn(dev, "Failed to get clk\n");
+ return;
}
- return ret;
+ reg = regulator_get_optional(dev, reg_name);
+ if (IS_ERR_OR_NULL(reg)) {
+ dev_warn(dev, "Failed to get reg\n");
+ goto clk_err;
+ }
+
+ ret = rockchip_get_pvtm_specific_value(dev, np, clk, reg, &pvtm);
+ if (ret) {
+ dev_err(dev, "Failed to get pvtm\n");
+ goto out;
+ }
+
+ if (!volt_sel)
+ goto next;
+ if (process >= 0) {
+ snprintf(name, sizeof(name),
+ "rockchip,p%d-pvtm-voltage-sel", process);
+ prop = of_find_property(np, name, NULL);
+ }
+ if (!prop)
+ sprintf(name, "rockchip,pvtm-voltage-sel");
+ ret = rockchip_get_sel(np, name, pvtm, volt_sel);
+ if (!ret && volt_sel)
+ dev_info(dev, "pvtm-volt-sel=%d\n", *volt_sel);
+
+next:
+ if (!scale_sel)
+ goto out;
+ if (process >= 0) {
+ snprintf(name, sizeof(name),
+ "rockchip,p%d-pvtm-scaling-sel", process);
+ prop = of_find_property(np, name, NULL);
+ }
+ if (!prop)
+ sprintf(name, "rockchip,pvtm-scaling-sel");
+ ret = rockchip_get_sel(np, name, pvtm, scale_sel);
+ if (!ret)
+ dev_info(dev, "pvtm-scale=%d\n", *scale_sel);
+
+out:
+ regulator_put(reg);
+clk_err:
+ clk_put(clk);
+}
+EXPORT_SYMBOL(rockchip_of_get_pvtm_sel);
+
+void rockchip_of_get_bin_sel(struct device *dev, struct device_node *np,
+ int bin, int *scale_sel)
+{
+ int ret = 0;
+
+ if (!scale_sel || bin < 0)
+ return;
+
+ ret = rockchip_get_bin_sel(np, "rockchip,bin-scaling-sel",
+ bin, scale_sel);
+ if (!ret)
+ dev_info(dev, "bin-scale=%d\n", *scale_sel);
}
-EXPORT_SYMBOL(rockchip_of_get_lkg_scale_sel);
+EXPORT_SYMBOL(rockchip_of_get_bin_sel);
-int rockchip_of_get_lkg_volt_sel(struct device *dev, char *name)
+void rockchip_get_soc_info(struct device *dev,
+ const struct of_device_id *matches,
+ int *bin, int *process)
{
+ const struct of_device_id *match;
struct device_node *np;
- int leakage, volt_sel;
- int ret;
+ struct device_node *node;
+ int (*get_soc_info)(struct device *dev, struct device_node *np,
+ int *bin, int *process);
+ int ret = 0;
+
+ if (!matches)
+ return;
np = of_parse_phandle(dev->of_node, "operating-points-v2", 0);
if (!np) {
dev_warn(dev, "OPP-v2 not supported\n");
- return -ENOENT;
+ return;
}
- ret = rockchip_get_efuse_value(np, name, &leakage);
- if (!ret) {
- dev_info(dev, "%s=%d\n", name, leakage);
- ret = rockchip_get_volt_sel(np, "rockchip,leakage-voltage-sel",
- leakage, &volt_sel);
- if (!ret) {
- dev_info(dev, "%s-volt-sel=%d\n", name, volt_sel);
- return volt_sel;
- }
+ node = of_find_node_by_path("/");
+ match = of_match_node(matches, node);
+ if (match && match->data) {
+ get_soc_info = match->data;
+ ret = get_soc_info(dev, np, bin, process);
+ if (ret)
+ dev_err(dev, "Failed to get soc info\n");
}
- return ret;
+ of_node_put(node);
+ of_node_put(np);
}
-EXPORT_SYMBOL(rockchip_of_get_lkg_volt_sel);
+EXPORT_SYMBOL(rockchip_get_soc_info);
-int rockchip_of_get_pvtm_volt_sel(struct device *dev,
- char *clk_name,
- char *reg_name)
+void rockchip_get_scale_volt_sel(struct device *dev, char *lkg_name,
+ char *reg_name, int bin, int process,
+ int *scale, int *volt_sel)
{
struct device_node *np;
- struct regulator *reg;
- struct clk *clk;
- int pvtm, volt_sel;
- int ret;
+ int lkg_scale = 0, pvtm_scale = 0, bin_scale = 0;
+ int lkg_volt_sel = -EINVAL, pvtm_volt_sel = -EINVAL;
np = of_parse_phandle(dev->of_node, "operating-points-v2", 0);
if (!np) {
dev_warn(dev, "OPP-v2 not supported\n");
- return -ENOENT;
+ return;
}
- clk = clk_get(dev, clk_name);
- if (IS_ERR_OR_NULL(clk)) {
- dev_err(dev, "Failed to get clk\n");
- return PTR_ERR(clk);
- }
+ rockchip_of_get_lkg_sel(dev, np, lkg_name, process,
+ &lkg_volt_sel, &lkg_scale);
+ rockchip_of_get_pvtm_sel(dev, np, reg_name, process,
+ &pvtm_volt_sel, &pvtm_scale);
+ rockchip_of_get_bin_sel(dev, np, bin, &bin_scale);
+ if (scale)
+ *scale = max3(lkg_scale, pvtm_scale, bin_scale);
+ if (volt_sel)
+ *volt_sel = max(lkg_volt_sel, pvtm_volt_sel);
- reg = regulator_get_optional(dev, reg_name);
- if (IS_ERR_OR_NULL(reg)) {
- dev_err(dev, "Failed to get reg\n");
- clk_put(clk);
- return PTR_ERR(reg);
- }
+ of_node_put(np);
+}
+EXPORT_SYMBOL(rockchip_get_scale_volt_sel);
- ret = rockchip_get_pvtm_specific_value(dev, np, clk, reg, &pvtm);
- if (!ret)
- ret = rockchip_get_volt_sel(np, "rockchip,pvtm-voltage-sel",
- pvtm, &volt_sel);
+int rockchip_set_opp_info(struct device *dev, int process, int volt_sel)
+{
+ int ret = 0;
+ char name[MAX_PROP_NAME_LEN];
- regulator_put(reg);
- clk_put(clk);
+ if (process >= 0) {
+ if (volt_sel >= 0)
+ snprintf(name, MAX_PROP_NAME_LEN, "P%d-L%d",
+ process, volt_sel);
+ else
+ snprintf(name, MAX_PROP_NAME_LEN, "P%d", process);
+ } else if (volt_sel >= 0) {
+ snprintf(name, MAX_PROP_NAME_LEN, "L%d", volt_sel);
+ } else {
+ return 0;
+ }
+
+ ret = dev_pm_opp_set_prop_name(dev, name);
+ if (ret)
+ dev_err(dev, "Failed to set prop name\n");
- return ret ? ret : volt_sel;
+ return ret;
}
-EXPORT_SYMBOL(rockchip_of_get_pvtm_volt_sel);
+EXPORT_SYMBOL(rockchip_set_opp_info);
static int rockchip_of_get_irdrop(struct device_node *np, unsigned long rate)
{
int irdrop, ret;
- ret = rockchip_get_volt_sel(np, "rockchip,board-irdrop",
- rate / 1000000, &irdrop);
+ ret = rockchip_get_sel(np, "rockchip,board-irdrop", rate / 1000000,
+ &irdrop);
return ret ? ret : irdrop;
}
-int rockchip_adjust_opp_by_irdrop(struct device *dev)
+static int rockchip_adjust_opp_by_irdrop(struct device *dev,
+ struct device_node *np,
+ int *irdrop_scale,
+ int *opp_scale)
{
struct dev_pm_opp *opp, *safe_opp = NULL;
- struct device_node *np;
+ struct clk *clk;
unsigned long rate;
u32 max_volt = UINT_MAX;
int evb_irdrop = 0, board_irdrop, delta_irdrop;
int i, count, ret = 0;
bool reach_max_volt = false;
- np = of_parse_phandle(dev->of_node, "operating-points-v2", 0);
- if (!np) {
- dev_warn(dev, "OPP-v2 not supported\n");
- return -ENOENT;
- }
-
of_property_read_u32_index(np, "rockchip,max-volt", 0, &max_volt);
of_property_read_u32_index(np, "rockchip,evb-irdrop", 0, &evb_irdrop);
@@ -441,19 +620,159 @@ int rockchip_adjust_opp_by_irdrop(struct device *dev)
}
}
- if (safe_opp && safe_opp != opp) {
- struct clk *clk = of_clk_get_by_name(np, NULL);
+ clk = of_clk_get_by_name(np, NULL);
+ if (IS_ERR(clk))
+ goto out;
+ if (safe_opp && safe_opp != opp && irdrop_scale) {
+ *irdrop_scale = rockchip_pll_clk_rate_to_scale(clk,
+ safe_opp->rate);
+ dev_info(dev, "irdrop-scale=%d\n", *irdrop_scale);
+ }
+ if (opp_scale)
+ *opp_scale = rockchip_pll_clk_rate_to_scale(clk, opp->rate);
+ clk_put(clk);
+
+out:
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)
+ rcu_read_unlock();
+#endif
+ return ret;
+}
+
+static int rockchip_adjust_opp_table(struct device *dev,
+ unsigned long scale_rate)
+{
+ struct dev_pm_opp *opp;
+ unsigned long rate;
+ int i, count, ret = 0;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)
+ rcu_read_lock();
+#endif
+ count = dev_pm_opp_get_opp_count(dev);
+ if (count <= 0) {
+ ret = count ? count : -ENODATA;
+ goto out;
+ }
- if (!IS_ERR(clk)) {
- rockchip_pll_clk_adaptive_rate(clk, safe_opp->rate);
- clk_put(clk);
+ for (i = 0, rate = 0; i < count; i++, rate++) {
+ /* find next rate */
+ opp = dev_pm_opp_find_freq_ceil(dev, &rate);
+ if (IS_ERR(opp)) {
+ ret = PTR_ERR(opp);
+ goto out;
}
+ if (opp->rate > scale_rate)
+ dev_pm_opp_remove(dev, opp->rate);
}
out:
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)
rcu_read_unlock();
#endif
- of_node_put(np);
return ret;
}
-EXPORT_SYMBOL(rockchip_adjust_opp_by_irdrop);
+
+int rockchip_adjust_power_scale(struct device *dev, int scale)
+{
+ struct device_node *np;
+ struct clk *clk;
+ int irdrop_scale = 0, opp_scale = 0;
+ u32 target_scale, avs_enable = 0, avs_scale = 0;
+ long scale_rate = 0;
+ int ret = 0;
+
+ np = of_parse_phandle(dev->of_node, "operating-points-v2", 0);
+ if (!np) {
+ dev_warn(dev, "OPP-v2 not supported\n");
+ return -ENOENT;
+ }
+ of_property_read_u32(np, "rockchip,avs-enable", &avs_enable);
+ of_property_read_u32(np, "rockchip,avs-scale", &avs_scale);
+
+ rockchip_adjust_opp_by_irdrop(dev, np, &irdrop_scale, &opp_scale);
+ target_scale = max(irdrop_scale, scale);
+ if (target_scale <= 0)
+ return 0;
+ dev_info(dev, "target-scale=%d\n", target_scale);
+
+ clk = of_clk_get_by_name(np, NULL);
+ if (IS_ERR(clk)) {
+ dev_err(dev, "Failed to get opp clk\n");
+ goto np_err;
+ }
+
+ if (avs_enable) {
+ ret = rockchip_pll_clk_adaptive_scaling(clk, target_scale);
+ if (ret)
+ dev_err(dev, "Failed to adaptive scaling\n");
+ if (opp_scale < avs_scale) {
+ dev_info(dev, "avs-scale=%d, opp-scale=%d\n",
+ avs_scale, opp_scale);
+ scale_rate = rockchip_pll_clk_scale_to_rate(clk,
+ avs_scale);
+ if (scale_rate <= 0) {
+ dev_err(dev,
+ "Failed to get avs scale rate, %d\n",
+ avs_scale);
+ goto clk_err;
+ }
+ dev_info(dev, "avs scale_rate=%lu\n", scale_rate);
+ ret = rockchip_adjust_opp_table(dev, scale_rate);
+ if (ret)
+ dev_err(dev, "Failed to adjust opp table\n");
+ }
+ } else {
+ if (opp_scale >= target_scale)
+ goto clk_err;
+ scale_rate = rockchip_pll_clk_scale_to_rate(clk, target_scale);
+ if (scale_rate <= 0) {
+ dev_err(dev, "Failed to get scale rate, %d\n",
+ target_scale);
+ goto clk_err;
+ }
+ dev_info(dev, "scale_rate=%lu\n", scale_rate);
+ ret = rockchip_adjust_opp_table(dev, scale_rate);
+ if (ret)
+ dev_err(dev, "Failed to adjust opp table\n");
+ }
+
+clk_err:
+ clk_put(clk);
+np_err:
+ of_node_put(np);
+
+ return 0;
+}
+EXPORT_SYMBOL(rockchip_adjust_power_scale);
+
+int rockchip_init_opp_table(struct device *dev,
+ const struct of_device_id *matches,
+ char *lkg_name, char *reg_name)
+{
+ struct device_node *np;
+ int bin = -EINVAL, process = -EINVAL;
+ int scale = 0, volt_sel = -EINVAL;
+ int ret = 0;
+
+ /* Get OPP descriptor node */
+ np = _of_get_opp_desc_node(dev);
+ if (!np) {
+ dev_dbg(dev, "Failed to find operating-points-v2\n");
+ return -ENOENT;
+ }
+ of_node_put(np);
+
+ rockchip_get_soc_info(dev, NULL, &bin, &process);
+ rockchip_get_scale_volt_sel(dev, lkg_name, reg_name, bin, process,
+ &scale, &volt_sel);
+ rockchip_set_opp_info(dev, process, volt_sel);
+ ret = dev_pm_opp_of_add_table(dev);
+ if (ret) {
+ dev_err(dev, "Invalid operating-points in device tree.\n");
+ return ret;
+ }
+ rockchip_adjust_power_scale(dev, scale);
+
+ return 0;
+}
+EXPORT_SYMBOL(rockchip_init_opp_table);
diff --git a/drivers/video/rockchip/vcodec/vcodec_service.c b/drivers/video/rockchip/vcodec/vcodec_service.c
index 3036bdc0ab79..e18693586972 100644
--- a/drivers/video/rockchip/vcodec/vcodec_service.c
+++ b/drivers/video/rockchip/vcodec/vcodec_service.c
@@ -3289,9 +3289,6 @@ static int vcodec_probe(struct platform_device *pdev)
struct devfreq_dev_status *stat;
struct vpu_service_info *pservice = NULL;
struct vpu_session *session = NULL;
-#define MAX_PROP_NAME_LEN 3
- char name[MAX_PROP_NAME_LEN];
- int lkg_volt_sel;
pservice = devm_kzalloc(dev, sizeof(struct vpu_service_info),
GFP_KERNEL);
@@ -3385,21 +3382,12 @@ static int vcodec_probe(struct platform_device *pdev)
goto err;
if (!IS_ERR(pservice->vdd_vcodec)) {
- lkg_volt_sel = rockchip_of_get_lkg_volt_sel(dev,
- "rkvdec_leakage");
- if (lkg_volt_sel >= 0) {
- snprintf(name, MAX_PROP_NAME_LEN, "L%d", lkg_volt_sel);
- ret = dev_pm_opp_set_prop_name(dev, name);
- if (ret)
- dev_err(dev, "Failed to set prop name\n");
- }
-
- if (dev_pm_opp_of_add_table(dev)) {
- dev_err(dev, "Invalid operating-points\n");
- ret = -EINVAL;
- goto err;
+ ret = rockchip_init_opp_table(dev, NULL,
+ "rkvdec_leakage", "vcodec");
+ if (ret) {
+ dev_err(dev, "Failed to init_opp_table (%d)\n", ret);
+ return ret;
}
-
pservice->devfreq = devm_devfreq_add_device(dev, devp,
"userspace", NULL);
if (IS_ERR(pservice->devfreq)) {
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index c39c964bbaed..e1eb0967feef 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -697,11 +697,17 @@ unsigned long cpufreq_scale_freq_capacity(struct sched_domain *sd, int cpu);
unsigned long cpufreq_scale_max_freq_capacity(int cpu);
#ifdef CONFIG_ARM_ROCKCHIP_CPUFREQ
unsigned int rockchip_cpufreq_adjust_target(int cpu, unsigned int freq);
+int rockchip_cpufreq_get_scale(int cpu);
#else
static inline unsigned int rockchip_cpufreq_adjust_target(int cpu,
unsigned int freq)
{
return freq;
}
+
+int rockchip_cpufreq_get_scale(int cpu)
+{
+ return -EINVAL;
+}
#endif
#endif /* _LINUX_CPUFREQ_H */
diff --git a/include/soc/rockchip/rockchip_opp_select.h b/include/soc/rockchip/rockchip_opp_select.h
index b4317d030bd9..5d3d37b442ea 100644
--- a/include/soc/rockchip/rockchip_opp_select.h
+++ b/include/soc/rockchip/rockchip_opp_select.h
@@ -6,11 +6,26 @@
#ifndef __SOC_ROCKCHIP_OPP_SELECT_H
#define __SOC_ROCKCHIP_OPP_SELECT_H
-int rockchip_of_get_lkg_scale_sel(struct device *dev, char *name);
-int rockchip_of_get_lkg_volt_sel(struct device *dev, char *name);
-int rockchip_of_get_pvtm_volt_sel(struct device *dev,
- char *clk_name,
- char *reg_name);
-int rockchip_adjust_opp_by_irdrop(struct device *dev);
+void rockchip_of_get_lkg_sel(struct device *dev, struct device_node *np,
+ char *lkg_name, int process,
+ int *volt_sel, int *scale_sel);
+void rockchip_of_get_pvtm_sel(struct device *dev, struct device_node *np,
+ char *reg_name, int process,
+ int *volt_sel, int *scale_sel);
+void rockchip_of_get_bin_sel(struct device *dev, struct device_node *np,
+ int bin, int *scale_sel);
+int rockchip_get_efuse_value(struct device_node *np, char *porp_name,
+ int *value);
+void rockchip_get_soc_info(struct device *dev,
+ const struct of_device_id *matches,
+ int *bin, int *process);
+void rockchip_get_scale_volt_sel(struct device *dev, char *lkg_name,
+ char *reg_name, int bin, int process,
+ int *scale, int *volt_sel);
+int rockchip_set_opp_info(struct device *dev, int process, int volt_sel);
+int rockchip_adjust_power_scale(struct device *dev, int scale);
+int rockchip_init_opp_table(struct device *dev,
+ const struct of_device_id *matches,
+ char *lkg_name, char *reg_name);
#endif