mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 20:32:04 +09:00
soc: rockchip: add CONFIG_ROCKCHIP_OPP for rockchip_opp_select.c
Change-Id: I0cde56d1ad7482c8d4e8b518fc49cc028da6501b Signed-off-by: Jianqun Xu <jay.xu@rock-chips.com> Signed-off-by: Tao Huang <huangtao@rock-chips.com> Signed-off-by: Finley Xiao <finley.xiao@rock-chips.com>
This commit is contained in:
@@ -45,6 +45,13 @@ config ROCKCHIP_IPA
|
|||||||
|
|
||||||
If unsure, say N.
|
If unsure, say N.
|
||||||
|
|
||||||
|
config ROCKCHIP_OPP
|
||||||
|
bool "Rockchip OPP select support"
|
||||||
|
depends on PM_DEVFREQ
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
Say y here to enable rockchip OPP support.
|
||||||
|
|
||||||
config ROCKCHIP_PM_DOMAINS
|
config ROCKCHIP_PM_DOMAINS
|
||||||
bool "Rockchip generic power domain"
|
bool "Rockchip generic power domain"
|
||||||
depends on PM
|
depends on PM
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ obj-$(CONFIG_FIQ_DEBUGGER) += rk_fiq_debugger.o
|
|||||||
obj-$(CONFIG_MMC_DW_ROCKCHIP) += sdmmc_vendor_storage.o
|
obj-$(CONFIG_MMC_DW_ROCKCHIP) += sdmmc_vendor_storage.o
|
||||||
obj-$(CONFIG_RK_FLASH) += flash_vendor_storage.o
|
obj-$(CONFIG_RK_FLASH) += flash_vendor_storage.o
|
||||||
obj-$(CONFIG_ROCKCHIP_IPA) += rockchip_ipa.o
|
obj-$(CONFIG_ROCKCHIP_IPA) += rockchip_ipa.o
|
||||||
|
obj-$(CONFIG_ROCKCHIP_OPP) += rockchip_opp_select.o
|
||||||
obj-$(CONFIG_ROCKCHIP_PVTM) += rockchip_pvtm.o
|
obj-$(CONFIG_ROCKCHIP_PVTM) += rockchip_pvtm.o
|
||||||
obj-$(CONFIG_ROCKCHIP_SUSPEND_MODE) += rockchip_pm_config.o
|
obj-$(CONFIG_ROCKCHIP_SUSPEND_MODE) += rockchip_pm_config.o
|
||||||
|
|
||||||
|
|||||||
@@ -16,12 +16,14 @@
|
|||||||
#include <soc/rockchip/rockchip_opp_select.h>
|
#include <soc/rockchip/rockchip_opp_select.h>
|
||||||
|
|
||||||
#include "../../clk/rockchip/clk.h"
|
#include "../../clk/rockchip/clk.h"
|
||||||
#include "../../base/power/opp/opp.h"
|
#include "../../opp/opp.h"
|
||||||
#include "../../devfreq/governor.h"
|
#include "../../devfreq/governor.h"
|
||||||
|
|
||||||
#define MAX_PROP_NAME_LEN 6
|
#define MAX_PROP_NAME_LEN 6
|
||||||
#define SEL_TABLE_END ~1
|
#define SEL_TABLE_END ~1
|
||||||
#define LEAKAGE_INVALID 0xff
|
#define LEAKAGE_INVALID 0xff
|
||||||
|
#define AVS_DELETE_OPP 0
|
||||||
|
#define AVS_SCALING_RATE 1
|
||||||
|
|
||||||
#define to_thermal_opp_info(nb) container_of(nb, struct thermal_opp_info, \
|
#define to_thermal_opp_info(nb) container_of(nb, struct thermal_opp_info, \
|
||||||
thermal_nb)
|
thermal_nb)
|
||||||
@@ -573,9 +575,9 @@ void rockchip_get_scale_volt_sel(struct device *dev, char *lkg_name,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(rockchip_get_scale_volt_sel);
|
EXPORT_SYMBOL(rockchip_get_scale_volt_sel);
|
||||||
|
|
||||||
int rockchip_set_opp_info(struct device *dev, int process, int volt_sel)
|
struct opp_table *rockchip_set_opp_prop_name(struct device *dev, int process,
|
||||||
|
int volt_sel)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
|
||||||
char name[MAX_PROP_NAME_LEN];
|
char name[MAX_PROP_NAME_LEN];
|
||||||
|
|
||||||
if (process >= 0) {
|
if (process >= 0) {
|
||||||
@@ -587,90 +589,80 @@ int rockchip_set_opp_info(struct device *dev, int process, int volt_sel)
|
|||||||
} else if (volt_sel >= 0) {
|
} else if (volt_sel >= 0) {
|
||||||
snprintf(name, MAX_PROP_NAME_LEN, "L%d", volt_sel);
|
snprintf(name, MAX_PROP_NAME_LEN, "L%d", volt_sel);
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = dev_pm_opp_set_prop_name(dev, name);
|
return dev_pm_opp_set_prop_name(dev, name);
|
||||||
if (ret)
|
|
||||||
dev_err(dev, "Failed to set prop name\n");
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
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_sel(np, "rockchip,board-irdrop", rate / 1000000,
|
|
||||||
&irdrop);
|
|
||||||
return ret ? ret : irdrop;
|
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(rockchip_set_opp_prop_name);
|
||||||
|
|
||||||
static int rockchip_adjust_opp_by_irdrop(struct device *dev,
|
static int rockchip_adjust_opp_by_irdrop(struct device *dev,
|
||||||
struct device_node *np,
|
struct device_node *np,
|
||||||
unsigned long *safe_rate,
|
unsigned long *safe_rate,
|
||||||
unsigned long *max_rate)
|
unsigned long *max_rate)
|
||||||
{
|
{
|
||||||
struct dev_pm_opp *opp, *safe_opp = NULL;
|
struct sel_table *irdrop_table = NULL;
|
||||||
unsigned long rate;
|
struct opp_table *opp_table;
|
||||||
u32 max_volt = UINT_MAX;
|
struct dev_pm_opp *opp;
|
||||||
int evb_irdrop = 0, board_irdrop, delta_irdrop;
|
int evb_irdrop = 0, board_irdrop, delta_irdrop;
|
||||||
int i, count, ret = 0;
|
int tmp_safe_rate = 0, opp_rate, i, ret = 0;
|
||||||
|
u32 max_volt = UINT_MAX;
|
||||||
bool reach_max_volt = false;
|
bool reach_max_volt = false;
|
||||||
|
|
||||||
of_property_read_u32_index(np, "rockchip,max-volt", 0, &max_volt);
|
of_property_read_u32_index(np, "rockchip,max-volt", 0, &max_volt);
|
||||||
of_property_read_u32_index(np, "rockchip,evb-irdrop", 0, &evb_irdrop);
|
of_property_read_u32_index(np, "rockchip,evb-irdrop", 0, &evb_irdrop);
|
||||||
|
rockchip_get_sel_table(np, "rockchip,board-irdrop", &irdrop_table);
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)
|
opp_table = dev_pm_opp_get_opp_table(dev);
|
||||||
rcu_read_lock();
|
if (!opp_table) {
|
||||||
#endif
|
ret = -ENOMEM;
|
||||||
count = dev_pm_opp_get_opp_count(dev);
|
goto out;
|
||||||
if (count <= 0) {
|
|
||||||
ret = count ? count : -ENODATA;
|
|
||||||
goto unlock;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0, rate = 0; i < count; i++, rate++) {
|
mutex_lock(&opp_table->lock);
|
||||||
/* find next rate */
|
list_for_each_entry(opp, &opp_table->opp_list, node) {
|
||||||
opp = dev_pm_opp_find_freq_ceil(dev, &rate);
|
if (!irdrop_table) {
|
||||||
if (IS_ERR(opp)) {
|
|
||||||
ret = PTR_ERR(opp);
|
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
board_irdrop = rockchip_of_get_irdrop(np, opp->rate);
|
|
||||||
if (IS_ERR_VALUE(board_irdrop))
|
|
||||||
/* Assume it has the same IR-Drop as evb */
|
|
||||||
delta_irdrop = 0;
|
delta_irdrop = 0;
|
||||||
else
|
} else {
|
||||||
delta_irdrop = board_irdrop - evb_irdrop;
|
opp_rate = opp->rate / 1000;
|
||||||
if ((opp->u_volt + delta_irdrop) <= max_volt) {
|
board_irdrop = -EINVAL;
|
||||||
opp->u_volt += delta_irdrop;
|
for (i = 0; irdrop_table[i].sel != SEL_TABLE_END; i++) {
|
||||||
opp->u_volt_min += delta_irdrop;
|
if (opp_rate >= irdrop_table[i].min)
|
||||||
opp->u_volt_max += delta_irdrop;
|
board_irdrop = irdrop_table[i].sel;
|
||||||
|
}
|
||||||
|
if (board_irdrop == -EINVAL)
|
||||||
|
delta_irdrop = 0;
|
||||||
|
else
|
||||||
|
delta_irdrop = board_irdrop - evb_irdrop;
|
||||||
|
}
|
||||||
|
if ((opp->supplies[0].u_volt + delta_irdrop) <= max_volt) {
|
||||||
|
opp->supplies[0].u_volt += delta_irdrop;
|
||||||
|
opp->supplies[0].u_volt_min += delta_irdrop;
|
||||||
|
if (opp->supplies[0].u_volt_max + delta_irdrop <=
|
||||||
|
max_volt)
|
||||||
|
opp->supplies[0].u_volt_max += delta_irdrop;
|
||||||
|
else
|
||||||
|
opp->supplies[0].u_volt_max = max_volt;
|
||||||
if (!reach_max_volt)
|
if (!reach_max_volt)
|
||||||
safe_opp = opp;
|
tmp_safe_rate = opp->rate;
|
||||||
if (opp->u_volt == max_volt)
|
if (opp->supplies[0].u_volt == max_volt)
|
||||||
reach_max_volt = true;
|
reach_max_volt = true;
|
||||||
} else {
|
} else {
|
||||||
opp->u_volt = max_volt;
|
opp->supplies[0].u_volt = max_volt;
|
||||||
opp->u_volt_min = max_volt;
|
opp->supplies[0].u_volt_min = max_volt;
|
||||||
opp->u_volt_max = max_volt;
|
opp->supplies[0].u_volt_max = max_volt;
|
||||||
}
|
}
|
||||||
|
if (max_rate)
|
||||||
|
*max_rate = opp->rate;
|
||||||
|
if (safe_rate && tmp_safe_rate != opp->rate)
|
||||||
|
*safe_rate = tmp_safe_rate;
|
||||||
}
|
}
|
||||||
|
mutex_unlock(&opp_table->lock);
|
||||||
|
|
||||||
unlock:
|
dev_pm_opp_put_opp_table(opp_table);
|
||||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)
|
|
||||||
rcu_read_unlock();
|
|
||||||
#endif
|
|
||||||
if (ret)
|
|
||||||
goto out;
|
|
||||||
if (safe_opp && safe_opp != opp && safe_rate)
|
|
||||||
*safe_rate = safe_opp->rate;
|
|
||||||
if (max_rate)
|
|
||||||
*max_rate = opp->rate;
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
kfree(irdrop_table);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -681,9 +673,6 @@ static int rockchip_adjust_opp_table(struct device *dev,
|
|||||||
unsigned long rate;
|
unsigned long rate;
|
||||||
int i, count, ret = 0;
|
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);
|
count = dev_pm_opp_get_opp_count(dev);
|
||||||
if (count <= 0) {
|
if (count <= 0) {
|
||||||
ret = count ? count : -ENODATA;
|
ret = count ? count : -ENODATA;
|
||||||
@@ -699,11 +688,9 @@ static int rockchip_adjust_opp_table(struct device *dev,
|
|||||||
}
|
}
|
||||||
if (opp->rate > scale_rate)
|
if (opp->rate > scale_rate)
|
||||||
dev_pm_opp_remove(dev, opp->rate);
|
dev_pm_opp_remove(dev, opp->rate);
|
||||||
|
dev_pm_opp_put(opp);
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)
|
|
||||||
rcu_read_unlock();
|
|
||||||
#endif
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -730,24 +717,15 @@ int rockchip_adjust_power_scale(struct device *dev, int scale)
|
|||||||
dev_info(dev, "avs=%d\n", avs);
|
dev_info(dev, "avs=%d\n", avs);
|
||||||
clk = of_clk_get_by_name(np, NULL);
|
clk = of_clk_get_by_name(np, NULL);
|
||||||
if (IS_ERR(clk)) {
|
if (IS_ERR(clk)) {
|
||||||
if (avs == 1) {
|
|
||||||
avs = 0;
|
|
||||||
dev_err(dev, "Failed to get clk, set avs 0\n");
|
|
||||||
}
|
|
||||||
if (!safe_rate)
|
if (!safe_rate)
|
||||||
goto out_np;
|
goto out_np;
|
||||||
dev_info(dev, "safe_rate=%lu\n", safe_rate);
|
dev_dbg(dev, "Failed to get clk, safe_rate=%lu\n", safe_rate);
|
||||||
if (avs == 2) {
|
ret = rockchip_adjust_opp_table(dev, safe_rate);
|
||||||
ret = rockchip_cpufreq_set_scale_rate(dev, safe_rate);
|
if (ret)
|
||||||
if (ret)
|
dev_err(dev, "Failed to adjust opp table\n");
|
||||||
dev_err(dev, "Failed to set cpu scale rate\n");
|
|
||||||
} else {
|
|
||||||
ret = rockchip_adjust_opp_table(dev, safe_rate);
|
|
||||||
if (ret)
|
|
||||||
dev_err(dev, "Failed to adjust opp table\n");
|
|
||||||
}
|
|
||||||
goto out_np;
|
goto out_np;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (safe_rate)
|
if (safe_rate)
|
||||||
irdrop_scale = rockchip_pll_clk_rate_to_scale(clk, safe_rate);
|
irdrop_scale = rockchip_pll_clk_rate_to_scale(clk, safe_rate);
|
||||||
if (max_rate)
|
if (max_rate)
|
||||||
@@ -755,49 +733,42 @@ int rockchip_adjust_power_scale(struct device *dev, int scale)
|
|||||||
target_scale = max(irdrop_scale, scale);
|
target_scale = max(irdrop_scale, scale);
|
||||||
if (target_scale <= 0)
|
if (target_scale <= 0)
|
||||||
goto out_clk;
|
goto out_clk;
|
||||||
|
|
||||||
dev_dbg(dev, "target_scale=%d, irdrop_scale=%d, scale=%d\n",
|
dev_dbg(dev, "target_scale=%d, irdrop_scale=%d, scale=%d\n",
|
||||||
target_scale, irdrop_scale, scale);
|
target_scale, irdrop_scale, scale);
|
||||||
|
|
||||||
if (avs == 1) {
|
if (avs == AVS_SCALING_RATE) {
|
||||||
ret = rockchip_pll_clk_adaptive_scaling(clk, target_scale);
|
ret = rockchip_pll_clk_adaptive_scaling(clk, target_scale);
|
||||||
if (ret)
|
if (ret)
|
||||||
dev_err(dev, "Failed to adaptive scaling\n");
|
dev_err(dev, "Failed to adaptive scaling\n");
|
||||||
if (opp_scale < avs_scale) {
|
if (opp_scale >= avs_scale)
|
||||||
dev_info(dev, "avs-scale=%d, opp-scale=%d\n",
|
goto out_clk;
|
||||||
avs_scale, opp_scale);
|
dev_info(dev, "avs-scale=%d, opp-scale=%d\n", avs_scale,
|
||||||
scale_rate = rockchip_pll_clk_scale_to_rate(clk,
|
opp_scale);
|
||||||
avs_scale);
|
scale_rate = rockchip_pll_clk_scale_to_rate(clk, avs_scale);
|
||||||
if (scale_rate <= 0) {
|
if (scale_rate <= 0) {
|
||||||
dev_err(dev,
|
dev_err(dev, "Failed to get avs scale rate, %d\n",
|
||||||
"Failed to get avs scale rate, %d\n",
|
avs_scale);
|
||||||
avs_scale);
|
goto out_clk;
|
||||||
goto out_clk;
|
|
||||||
}
|
|
||||||
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 {
|
dev_dbg(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");
|
||||||
|
} else if (avs == AVS_DELETE_OPP) {
|
||||||
if (opp_scale >= target_scale)
|
if (opp_scale >= target_scale)
|
||||||
goto out_clk;
|
goto out_clk;
|
||||||
|
dev_info(dev, "target_scale=%d, opp-scale=%d\n", target_scale,
|
||||||
|
opp_scale);
|
||||||
scale_rate = rockchip_pll_clk_scale_to_rate(clk, target_scale);
|
scale_rate = rockchip_pll_clk_scale_to_rate(clk, target_scale);
|
||||||
if (scale_rate <= 0) {
|
if (scale_rate <= 0) {
|
||||||
dev_err(dev, "Failed to get scale rate, %d\n",
|
dev_err(dev, "Failed to get scale rate, %d\n",
|
||||||
target_scale);
|
target_scale);
|
||||||
goto out_clk;
|
goto out_clk;
|
||||||
}
|
}
|
||||||
dev_info(dev, "scale_rate=%lu\n", scale_rate);
|
dev_dbg(dev, "scale_rate=%lu\n", scale_rate);
|
||||||
if (avs == 2) {
|
ret = rockchip_adjust_opp_table(dev, scale_rate);
|
||||||
ret = rockchip_cpufreq_set_scale_rate(dev, scale_rate);
|
if (ret)
|
||||||
if (ret)
|
dev_err(dev, "Failed to adjust opp table\n");
|
||||||
dev_err(dev, "Failed to set cpu scale rate\n");
|
|
||||||
} else {
|
|
||||||
ret = rockchip_adjust_opp_table(dev, scale_rate);
|
|
||||||
if (ret)
|
|
||||||
dev_err(dev, "Failed to adjust opp table\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out_clk:
|
out_clk:
|
||||||
@@ -805,7 +776,7 @@ out_clk:
|
|||||||
out_np:
|
out_np:
|
||||||
of_node_put(np);
|
of_node_put(np);
|
||||||
|
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(rockchip_adjust_power_scale);
|
EXPORT_SYMBOL(rockchip_adjust_power_scale);
|
||||||
|
|
||||||
@@ -829,7 +800,7 @@ int rockchip_init_opp_table(struct device *dev,
|
|||||||
rockchip_get_soc_info(dev, matches, &bin, &process);
|
rockchip_get_soc_info(dev, matches, &bin, &process);
|
||||||
rockchip_get_scale_volt_sel(dev, lkg_name, reg_name, bin, process,
|
rockchip_get_scale_volt_sel(dev, lkg_name, reg_name, bin, process,
|
||||||
&scale, &volt_sel);
|
&scale, &volt_sel);
|
||||||
rockchip_set_opp_info(dev, process, volt_sel);
|
rockchip_set_opp_prop_name(dev, process, volt_sel);
|
||||||
ret = dev_pm_opp_of_add_table(dev);
|
ret = dev_pm_opp_of_add_table(dev);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "Invalid operating-points in device tree.\n");
|
dev_err(dev, "Invalid operating-points in device tree.\n");
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ void rockchip_get_soc_info(struct device *dev,
|
|||||||
void rockchip_get_scale_volt_sel(struct device *dev, char *lkg_name,
|
void rockchip_get_scale_volt_sel(struct device *dev, char *lkg_name,
|
||||||
char *reg_name, int bin, int process,
|
char *reg_name, int bin, int process,
|
||||||
int *scale, int *volt_sel);
|
int *scale, int *volt_sel);
|
||||||
int rockchip_set_opp_info(struct device *dev, int process, int volt_sel);
|
struct opp_table *rockchip_set_opp_prop_name(struct device *dev, int process,
|
||||||
|
int volt_sel);
|
||||||
int rockchip_adjust_power_scale(struct device *dev, int scale);
|
int rockchip_adjust_power_scale(struct device *dev, int scale);
|
||||||
int rockchip_init_opp_table(struct device *dev,
|
int rockchip_init_opp_table(struct device *dev,
|
||||||
const struct of_device_id *matches,
|
const struct of_device_id *matches,
|
||||||
@@ -75,8 +76,9 @@ static inline void rockchip_get_scale_volt_sel(struct device *dev,
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int rockchip_set_opp_info(struct device *dev, int process,
|
static inline struct opp_table *rockchip_set_opp_prop_name(struct device *dev,
|
||||||
int volt_sel)
|
int process,
|
||||||
|
int volt_sel)
|
||||||
{
|
{
|
||||||
return -ENOTSUPP;
|
return -ENOTSUPP;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user