mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 02:50:49 +09:00
soc: rockchip: opp_select: Implements new opp APIs for kernel 6.1
Signed-off-by: Finley Xiao <finley.xiao@rock-chips.com> Change-Id: I3e1bef3d15d8ea290565fb3573d8e79b5bf18815
This commit is contained in:
@@ -83,6 +83,10 @@ struct otp_opp_info {
|
||||
static int pvtm_value[PVTM_CH_MAX][PVTM_SUB_CH_MAX];
|
||||
static int lkg_version;
|
||||
|
||||
static int rockchip_init_read_margin(struct device *dev,
|
||||
struct rockchip_opp_info *opp_info,
|
||||
const char *reg_name);
|
||||
|
||||
/*
|
||||
* temp = temp * 10
|
||||
* conv = exp(-ln(1.2) / 5 * (temp - 23)) * 100
|
||||
@@ -652,9 +656,9 @@ int rockchip_of_get_leakage(struct device *dev, char *lkg_name, int *leakage)
|
||||
}
|
||||
EXPORT_SYMBOL(rockchip_of_get_leakage);
|
||||
|
||||
void rockchip_of_get_lkg_sel(struct device *dev, struct device_node *np,
|
||||
char *lkg_name, int process,
|
||||
int *volt_sel, int *scale_sel)
|
||||
static 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 property *prop = NULL;
|
||||
int leakage = -EINVAL, ret = 0;
|
||||
@@ -713,7 +717,6 @@ next:
|
||||
if (!ret)
|
||||
dev_info(dev, "leakage-scale=%d\n", *scale_sel);
|
||||
}
|
||||
EXPORT_SYMBOL(rockchip_of_get_lkg_sel);
|
||||
|
||||
static unsigned long rockchip_pvtpll_get_rate(struct rockchip_opp_info *info)
|
||||
{
|
||||
@@ -804,7 +807,7 @@ static int rockchip_init_pvtpll_info(struct rockchip_opp_info *info)
|
||||
info->opp_table[i].u_volt_mem_min = opp->supplies[1].u_volt_min;
|
||||
info->opp_table[i].u_volt_mem_max = opp->supplies[1].u_volt_max;
|
||||
}
|
||||
info->opp_table[i++].rate = opp->rate;
|
||||
info->opp_table[i++].rate = opp->rates[0];
|
||||
}
|
||||
mutex_unlock(&opp_table->lock);
|
||||
|
||||
@@ -839,7 +842,7 @@ static int rockchip_pvtpll_set_clk(struct device *dev, struct clk *clk,
|
||||
return ret;
|
||||
}
|
||||
|
||||
void rockchip_pvtpll_calibrate_opp(struct rockchip_opp_info *info)
|
||||
static void rockchip_pvtpll_calibrate_opp(struct rockchip_opp_info *info)
|
||||
{
|
||||
struct opp_table *opp_table;
|
||||
struct dev_pm_opp *opp;
|
||||
@@ -866,6 +869,14 @@ void rockchip_pvtpll_calibrate_opp(struct rockchip_opp_info *info)
|
||||
if (!opp_table)
|
||||
return;
|
||||
|
||||
if (info->clocks) {
|
||||
ret = clk_bulk_prepare_enable(info->nclocks, info->clocks);
|
||||
if (ret) {
|
||||
dev_err(info->dev, "failed to enable opp clks\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ((!opp_table->regulators) || IS_ERR(opp_table->clk))
|
||||
goto out_put;
|
||||
|
||||
@@ -980,11 +991,12 @@ out:
|
||||
if (cur_rate < old_rate)
|
||||
rockchip_pvtpll_set_clk(info->dev, opp_table->clk, old_rate);
|
||||
out_put:
|
||||
if (info->clocks)
|
||||
clk_bulk_disable_unprepare(info->nclocks, info->clocks);
|
||||
dev_pm_opp_put_opp_table(opp_table);
|
||||
}
|
||||
EXPORT_SYMBOL(rockchip_pvtpll_calibrate_opp);
|
||||
|
||||
void rockchip_pvtpll_add_length(struct rockchip_opp_info *info)
|
||||
static void rockchip_pvtpll_add_length(struct rockchip_opp_info *info)
|
||||
{
|
||||
struct device_node *np;
|
||||
struct opp_table *opp_table;
|
||||
@@ -1018,13 +1030,13 @@ void rockchip_pvtpll_add_length(struct rockchip_opp_info *info)
|
||||
|
||||
mutex_lock(&opp_table->lock);
|
||||
list_for_each_entry(opp, &opp_table->opp_list, node) {
|
||||
if (opp->rate < min_rate * 1000 || opp->rate > max_rate * 1000)
|
||||
if (opp->rates[0] < min_rate * 1000 || opp->rates[0] > max_rate * 1000)
|
||||
continue;
|
||||
ret = clk_set_rate(opp_table->clk, opp->rate | opp_flag);
|
||||
ret = clk_set_rate(opp_table->clk, opp->rates[0] | opp_flag);
|
||||
if (ret) {
|
||||
dev_err(info->dev,
|
||||
"failed to change %lu len margin %d\n",
|
||||
opp->rate, margin);
|
||||
opp->rates[0], margin);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1034,10 +1046,9 @@ void rockchip_pvtpll_add_length(struct rockchip_opp_info *info)
|
||||
|
||||
dev_pm_opp_put_opp_table(opp_table);
|
||||
}
|
||||
EXPORT_SYMBOL(rockchip_pvtpll_add_length);
|
||||
|
||||
static int rockchip_get_pvtm_pvtpll(struct device *dev, struct device_node *np,
|
||||
char *reg_name)
|
||||
const char *reg_name)
|
||||
{
|
||||
struct regulator *reg;
|
||||
struct clk *clk;
|
||||
@@ -1118,7 +1129,7 @@ out:
|
||||
}
|
||||
|
||||
static int rockchip_get_pvtm(struct device *dev, struct device_node *np,
|
||||
char *reg_name)
|
||||
const char *reg_name)
|
||||
{
|
||||
struct regulator *reg;
|
||||
struct clk *clk;
|
||||
@@ -1164,9 +1175,9 @@ static int rockchip_get_pvtm(struct device *dev, struct device_node *np,
|
||||
return pvtm;
|
||||
}
|
||||
|
||||
void rockchip_of_get_pvtm_sel(struct device *dev, struct device_node *np,
|
||||
char *reg_name, int process,
|
||||
int *volt_sel, int *scale_sel)
|
||||
static void rockchip_of_get_pvtm_sel(struct device *dev, struct device_node *np,
|
||||
const char *reg_name, int process,
|
||||
int *volt_sel, int *scale_sel)
|
||||
{
|
||||
struct property *prop = NULL;
|
||||
char name[NAME_MAX];
|
||||
@@ -1206,10 +1217,9 @@ next:
|
||||
if (!ret)
|
||||
dev_info(dev, "pvtm-scale=%d\n", *scale_sel);
|
||||
}
|
||||
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)
|
||||
static void rockchip_of_get_bin_sel(struct device *dev, struct device_node *np,
|
||||
int bin, int *scale_sel)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
@@ -1221,10 +1231,9 @@ void rockchip_of_get_bin_sel(struct device *dev, struct device_node *np,
|
||||
if (!ret)
|
||||
dev_info(dev, "bin-scale=%d\n", *scale_sel);
|
||||
}
|
||||
EXPORT_SYMBOL(rockchip_of_get_bin_sel);
|
||||
|
||||
void rockchip_of_get_bin_volt_sel(struct device *dev, struct device_node *np,
|
||||
int bin, int *bin_volt_sel)
|
||||
static void rockchip_of_get_bin_volt_sel(struct device *dev, struct device_node *np,
|
||||
int bin, int *bin_volt_sel)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
@@ -1236,7 +1245,6 @@ void rockchip_of_get_bin_volt_sel(struct device *dev, struct device_node *np,
|
||||
if (!ret)
|
||||
dev_info(dev, "bin-volt-sel=%d\n", *bin_volt_sel);
|
||||
}
|
||||
EXPORT_SYMBOL(rockchip_of_get_bin_volt_sel);
|
||||
|
||||
void rockchip_get_opp_data(const struct of_device_id *matches,
|
||||
struct rockchip_opp_info *info)
|
||||
@@ -1252,8 +1260,8 @@ void rockchip_get_opp_data(const struct of_device_id *matches,
|
||||
}
|
||||
EXPORT_SYMBOL(rockchip_get_opp_data);
|
||||
|
||||
int rockchip_get_volt_rm_table(struct device *dev, struct device_node *np,
|
||||
char *porp_name, struct volt_rm_table **table)
|
||||
static int rockchip_get_volt_rm_table(struct device *dev, struct device_node *np,
|
||||
char *porp_name, struct volt_rm_table **table)
|
||||
{
|
||||
struct volt_rm_table *rm_table;
|
||||
const struct property *prop;
|
||||
@@ -1292,11 +1300,10 @@ int rockchip_get_volt_rm_table(struct device *dev, struct device_node *np,
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(rockchip_get_volt_rm_table);
|
||||
|
||||
void rockchip_get_scale_volt_sel(struct device *dev, char *lkg_name,
|
||||
char *reg_name, int bin, int process,
|
||||
int *scale, int *volt_sel)
|
||||
static void rockchip_get_scale_volt_sel(struct device *dev, char *lkg_name,
|
||||
const char *reg_name,
|
||||
struct rockchip_opp_info *info)
|
||||
{
|
||||
struct device_node *np;
|
||||
int lkg_scale = 0, pvtm_scale = 0, bin_scale = 0;
|
||||
@@ -1309,45 +1316,188 @@ void rockchip_get_scale_volt_sel(struct device *dev, char *lkg_name,
|
||||
return;
|
||||
}
|
||||
|
||||
rockchip_of_get_lkg_sel(dev, np, lkg_name, process,
|
||||
rockchip_of_get_lkg_sel(dev, np, lkg_name, info->process,
|
||||
&lkg_volt_sel, &lkg_scale);
|
||||
rockchip_of_get_pvtm_sel(dev, np, reg_name, process,
|
||||
rockchip_of_get_pvtm_sel(dev, np, reg_name, info->process,
|
||||
&pvtm_volt_sel, &pvtm_scale);
|
||||
rockchip_of_get_bin_sel(dev, np, bin, &bin_scale);
|
||||
rockchip_of_get_bin_volt_sel(dev, np, bin, &bin_volt_sel);
|
||||
if (scale)
|
||||
*scale = max3(lkg_scale, pvtm_scale, bin_scale);
|
||||
if (volt_sel) {
|
||||
if (bin_volt_sel >= 0)
|
||||
*volt_sel = bin_volt_sel;
|
||||
else
|
||||
*volt_sel = max(lkg_volt_sel, pvtm_volt_sel);
|
||||
}
|
||||
rockchip_of_get_bin_sel(dev, np, info->bin, &bin_scale);
|
||||
rockchip_of_get_bin_volt_sel(dev, np, info->bin, &bin_volt_sel);
|
||||
info->scale = max3(lkg_scale, pvtm_scale, bin_scale);
|
||||
if (bin_volt_sel >= 0)
|
||||
info->volt_sel = bin_volt_sel;
|
||||
else
|
||||
info->volt_sel = max(lkg_volt_sel, pvtm_volt_sel);
|
||||
|
||||
of_node_put(np);
|
||||
}
|
||||
EXPORT_SYMBOL(rockchip_get_scale_volt_sel);
|
||||
|
||||
struct opp_table *rockchip_set_opp_prop_name(struct device *dev, int process,
|
||||
int volt_sel)
|
||||
static int rockchip_opp_set_config(struct device *dev, struct rockchip_opp_info *info,
|
||||
const char *clk_name, const char *reg_name)
|
||||
{
|
||||
char name[MAX_PROP_NAME_LEN];
|
||||
struct dev_pm_opp_config config = {0};
|
||||
struct clk *clk = NULL;
|
||||
const char *reg_names[] = {NULL, NULL, NULL};
|
||||
const char *clk_names[] = {NULL, NULL, NULL};
|
||||
|
||||
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 NULL;
|
||||
if (clk_name) {
|
||||
clk = clk_get(dev, clk_name);
|
||||
if (!IS_ERR_OR_NULL(clk)) {
|
||||
if (strstr(__clk_get_name(clk), "scmi"))
|
||||
info->is_scmi_clk = true;
|
||||
clk_names[0] = clk_name;
|
||||
config.clk_names = clk_names;
|
||||
clk_put(clk);
|
||||
}
|
||||
if (info->data && info->data->config_clks)
|
||||
config.config_clks = info->data->config_clks;
|
||||
}
|
||||
|
||||
return dev_pm_opp_set_prop_name(dev, name);
|
||||
if (info->process >= 0) {
|
||||
if (info->volt_sel >= 0)
|
||||
snprintf(name, MAX_PROP_NAME_LEN, "P%d-L%d",
|
||||
info->process, info->volt_sel);
|
||||
else
|
||||
snprintf(name, MAX_PROP_NAME_LEN, "P%d", info->process);
|
||||
config.prop_name = name;
|
||||
} else if (info->volt_sel >= 0) {
|
||||
snprintf(name, MAX_PROP_NAME_LEN, "L%d", info->volt_sel);
|
||||
config.prop_name = name;
|
||||
}
|
||||
|
||||
if (info->data && info->data->config_regulators)
|
||||
config.config_regulators = info->data->config_regulators;
|
||||
|
||||
if (info->supported_hw[0] || info->supported_hw[1]) {
|
||||
config.supported_hw = kmemdup(info->supported_hw, 2 * sizeof(u32),
|
||||
GFP_KERNEL);
|
||||
config.supported_hw_count = 2;
|
||||
}
|
||||
|
||||
if (reg_name) {
|
||||
reg_names[0] = reg_name;
|
||||
if (of_find_property(dev->of_node, "mem-supply", NULL))
|
||||
reg_names[1] = "mem";
|
||||
config.regulator_names = reg_names;
|
||||
}
|
||||
|
||||
info->opp_token = dev_pm_opp_set_config(dev, &config);
|
||||
if (info->opp_token < 0) {
|
||||
dev_err(dev, "failed to set opp config\n");
|
||||
return info->opp_token;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(rockchip_set_opp_prop_name);
|
||||
|
||||
void rockchip_opp_dvfs_lock(struct rockchip_opp_info *info)
|
||||
{
|
||||
if (info)
|
||||
mutex_lock(&info->dvfs_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(rockchip_opp_dvfs_lock);
|
||||
|
||||
void rockchip_opp_dvfs_unlock(struct rockchip_opp_info *info)
|
||||
{
|
||||
if (info)
|
||||
mutex_unlock(&info->dvfs_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(rockchip_opp_dvfs_unlock);
|
||||
|
||||
int rockchip_init_opp_info(struct device *dev, struct rockchip_opp_info *info,
|
||||
char *clk_name, char *reg_name)
|
||||
{
|
||||
struct device_node *np;
|
||||
int ret = 0, nclocks = 0, i;
|
||||
u32 freq;
|
||||
|
||||
/* Get OPP descriptor node */
|
||||
np = of_parse_phandle(dev->of_node, "operating-points-v2", 0);
|
||||
if (!np) {
|
||||
dev_dbg(dev, "Failed to find operating-points-v2\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
info->dev = dev;
|
||||
info->bin = -EINVAL;
|
||||
info->process = -EINVAL;
|
||||
info->volt_sel = -EINVAL;
|
||||
info->is_runtime_active = true;
|
||||
mutex_init(&info->dvfs_mutex);
|
||||
|
||||
of_property_read_u32(np, "rockchip,init-freq", &info->init_freq);
|
||||
|
||||
info->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
|
||||
if (IS_ERR(info->grf))
|
||||
info->grf = NULL;
|
||||
info->dsu_grf = syscon_regmap_lookup_by_phandle(np, "rockchip,dsu-grf");
|
||||
if (IS_ERR(info->dsu_grf))
|
||||
info->dsu_grf = NULL;
|
||||
|
||||
nclocks = of_clk_get_parent_count(np);
|
||||
if (nclocks > 0) {
|
||||
info->clocks = devm_kcalloc(dev, nclocks, sizeof(*info->clocks),
|
||||
GFP_KERNEL);
|
||||
if (!info->clocks) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
for (i = 0; i < nclocks; i++) {
|
||||
info->clocks[i].clk = of_clk_get(np, i);
|
||||
if (IS_ERR(info->clocks[i].clk)) {
|
||||
ret = PTR_ERR(info->clocks[i].clk);
|
||||
dev_err(dev, "%s: failed to get clk %d\n",
|
||||
np->name, i);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
info->nclocks = nclocks;
|
||||
ret = clk_bulk_prepare_enable(info->nclocks, info->clocks);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to enable opp clks\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (info->data && info->data->set_read_margin) {
|
||||
info->current_rm = UINT_MAX;
|
||||
info->target_rm = UINT_MAX;
|
||||
rockchip_get_volt_rm_table(dev, np, "volt-mem-read-margin",
|
||||
&info->volt_rm_tbl);
|
||||
of_property_read_u32(np, "low-volt-mem-read-margin",
|
||||
&info->low_rm);
|
||||
if (!of_property_read_u32(np, "intermediate-threshold-freq",
|
||||
&freq))
|
||||
info->intermediate_threshold_freq = freq * 1000;
|
||||
rockchip_init_read_margin(dev, info, reg_name);
|
||||
}
|
||||
|
||||
if (info->data && info->data->get_soc_info)
|
||||
info->data->get_soc_info(dev, np, &info->bin, &info->process);
|
||||
|
||||
rockchip_get_scale_volt_sel(dev, "leakage", reg_name, info);
|
||||
|
||||
if (info && info->data && info->data->set_soc_info)
|
||||
info->data->set_soc_info(dev, np, info);
|
||||
|
||||
ret = rockchip_opp_set_config(dev, info, clk_name, reg_name);
|
||||
|
||||
if (info->clocks)
|
||||
clk_bulk_disable_unprepare(info->nclocks, info->clocks);
|
||||
out:
|
||||
of_node_put(np);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(rockchip_init_opp_info);
|
||||
|
||||
void rockchip_uninit_opp_info(struct device *dev, struct rockchip_opp_info *info)
|
||||
{
|
||||
dev_pm_opp_clear_config(info->opp_token);
|
||||
}
|
||||
EXPORT_SYMBOL(rockchip_uninit_opp_info);
|
||||
|
||||
static int rockchip_adjust_opp_by_irdrop(struct device *dev,
|
||||
struct device_node *np,
|
||||
@@ -1380,7 +1530,7 @@ static int rockchip_adjust_opp_by_irdrop(struct device *dev,
|
||||
if (!irdrop_table) {
|
||||
delta_irdrop = 0;
|
||||
} else {
|
||||
opp_rate = opp->rate / 1000000;
|
||||
opp_rate = opp->rates[0] / 1000000;
|
||||
board_irdrop = -EINVAL;
|
||||
for (i = 0; irdrop_table[i].sel != SEL_TABLE_END; i++) {
|
||||
if (opp_rate >= irdrop_table[i].min)
|
||||
@@ -1400,7 +1550,7 @@ static int rockchip_adjust_opp_by_irdrop(struct device *dev,
|
||||
else
|
||||
opp->supplies[0].u_volt_max = max_volt;
|
||||
if (!reach_max_volt)
|
||||
tmp_safe_rate = opp->rate;
|
||||
tmp_safe_rate = opp->rates[0];
|
||||
if (opp->supplies[0].u_volt == max_volt)
|
||||
reach_max_volt = true;
|
||||
} else {
|
||||
@@ -1409,8 +1559,8 @@ static int rockchip_adjust_opp_by_irdrop(struct device *dev,
|
||||
opp->supplies[0].u_volt_max = max_volt;
|
||||
}
|
||||
if (max_rate)
|
||||
*max_rate = opp->rate;
|
||||
if (safe_rate && tmp_safe_rate != opp->rate)
|
||||
*max_rate = opp->rates[0];
|
||||
if (safe_rate && tmp_safe_rate != opp->rates[0])
|
||||
*safe_rate = tmp_safe_rate;
|
||||
}
|
||||
mutex_unlock(&opp_table->lock);
|
||||
@@ -1479,9 +1629,9 @@ static void rockchip_adjust_opp_by_otp(struct device *dev,
|
||||
list_for_each_entry(opp, &opp_table->opp_list, node) {
|
||||
if (!opp->available)
|
||||
continue;
|
||||
if (opp->rate < opp_info.min_freq * 1000000)
|
||||
if (opp->rates[0] < opp_info.min_freq * 1000000)
|
||||
continue;
|
||||
if (opp->rate > opp_info.max_freq * 1000000)
|
||||
if (opp->rates[0] > opp_info.max_freq * 1000000)
|
||||
continue;
|
||||
|
||||
opp->supplies->u_volt += opp_info.volt * 1000;
|
||||
@@ -1493,8 +1643,8 @@ static void rockchip_adjust_opp_by_otp(struct device *dev,
|
||||
dev_pm_opp_put_opp_table(opp_table);
|
||||
}
|
||||
|
||||
static int rockchip_adjust_opp_table(struct device *dev,
|
||||
unsigned long scale_rate)
|
||||
static int rockchip_adjust_opp_by_scale(struct device *dev,
|
||||
unsigned long scale_rate)
|
||||
{
|
||||
struct dev_pm_opp *opp;
|
||||
unsigned long rate;
|
||||
@@ -1513,15 +1663,15 @@ static int rockchip_adjust_opp_table(struct device *dev,
|
||||
ret = PTR_ERR(opp);
|
||||
goto out;
|
||||
}
|
||||
if (opp->rate > scale_rate)
|
||||
dev_pm_opp_disable(dev, opp->rate);
|
||||
if (opp->rates[0] > scale_rate)
|
||||
dev_pm_opp_disable(dev, opp->rates[0]);
|
||||
dev_pm_opp_put(opp);
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rockchip_adjust_power_scale(struct device *dev, int scale)
|
||||
static int rockchip_adjust_power_scale(struct device *dev, struct rockchip_opp_info *info)
|
||||
{
|
||||
struct device_node *np;
|
||||
struct clk *clk;
|
||||
@@ -1549,7 +1699,7 @@ int rockchip_adjust_power_scale(struct device *dev, int scale)
|
||||
if (!safe_rate)
|
||||
goto out_np;
|
||||
dev_dbg(dev, "Failed to get clk, safe_rate=%lu\n", safe_rate);
|
||||
ret = rockchip_adjust_opp_table(dev, safe_rate);
|
||||
ret = rockchip_adjust_opp_by_scale(dev, safe_rate);
|
||||
if (ret)
|
||||
dev_err(dev, "Failed to adjust opp table\n");
|
||||
goto out_np;
|
||||
@@ -1559,11 +1709,11 @@ int rockchip_adjust_power_scale(struct device *dev, int scale)
|
||||
irdrop_scale = rockchip_pll_clk_rate_to_scale(clk, safe_rate);
|
||||
if (max_rate)
|
||||
opp_scale = rockchip_pll_clk_rate_to_scale(clk, max_rate);
|
||||
target_scale = max(irdrop_scale, scale);
|
||||
target_scale = max(irdrop_scale, info->scale);
|
||||
if (target_scale <= 0)
|
||||
goto out_clk;
|
||||
dev_dbg(dev, "target_scale=%d, irdrop_scale=%d, scale=%d\n",
|
||||
target_scale, irdrop_scale, scale);
|
||||
target_scale, irdrop_scale, info->scale);
|
||||
|
||||
if (avs == AVS_SCALING_RATE) {
|
||||
ret = rockchip_pll_clk_adaptive_scaling(clk, target_scale);
|
||||
@@ -1580,7 +1730,7 @@ int rockchip_adjust_power_scale(struct device *dev, int scale)
|
||||
goto out_clk;
|
||||
}
|
||||
dev_dbg(dev, "scale_rate=%lu\n", scale_rate);
|
||||
ret = rockchip_adjust_opp_table(dev, scale_rate);
|
||||
ret = rockchip_adjust_opp_by_scale(dev, scale_rate);
|
||||
if (ret)
|
||||
dev_err(dev, "Failed to adjust opp table\n");
|
||||
} else if (avs == AVS_DELETE_OPP) {
|
||||
@@ -1595,7 +1745,7 @@ int rockchip_adjust_power_scale(struct device *dev, int scale)
|
||||
goto out_clk;
|
||||
}
|
||||
dev_dbg(dev, "scale_rate=%lu\n", scale_rate);
|
||||
ret = rockchip_adjust_opp_table(dev, scale_rate);
|
||||
ret = rockchip_adjust_opp_by_scale(dev, scale_rate);
|
||||
if (ret)
|
||||
dev_err(dev, "Failed to adjust opp table\n");
|
||||
}
|
||||
@@ -1607,7 +1757,37 @@ out_np:
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(rockchip_adjust_power_scale);
|
||||
|
||||
static int rockchip_opp_parse_supplies(struct device *dev,
|
||||
struct rockchip_opp_info *info)
|
||||
{
|
||||
struct opp_table *opp_table;
|
||||
|
||||
opp_table = dev_pm_opp_get_opp_table(dev);
|
||||
if (IS_ERR(opp_table))
|
||||
return PTR_ERR(opp_table);
|
||||
|
||||
if (opp_table->clk)
|
||||
info->clk = opp_table->clk;
|
||||
if (opp_table->regulators)
|
||||
info->regulators = opp_table->regulators;
|
||||
info->regulator_count = opp_table->regulator_count;
|
||||
|
||||
dev_pm_opp_put_opp_table(opp_table);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rockchip_adjust_opp_table(struct device *dev, struct rockchip_opp_info *info)
|
||||
{
|
||||
rockchip_opp_parse_supplies(dev, info);
|
||||
rockchip_adjust_power_scale(dev, info);
|
||||
rockchip_pvtpll_calibrate_opp(info);
|
||||
rockchip_pvtpll_add_length(info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(rockchip_adjust_opp_table);
|
||||
|
||||
int rockchip_get_read_margin(struct device *dev,
|
||||
struct rockchip_opp_info *opp_info,
|
||||
@@ -1647,9 +1827,9 @@ int rockchip_set_read_margin(struct device *dev,
|
||||
}
|
||||
EXPORT_SYMBOL(rockchip_set_read_margin);
|
||||
|
||||
int rockchip_init_read_margin(struct device *dev,
|
||||
struct rockchip_opp_info *opp_info,
|
||||
char *reg_name)
|
||||
static int rockchip_init_read_margin(struct device *dev,
|
||||
struct rockchip_opp_info *opp_info,
|
||||
const char *reg_name)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct regulator *reg;
|
||||
@@ -1701,7 +1881,6 @@ out:
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(rockchip_init_read_margin);
|
||||
|
||||
int rockchip_set_intermediate_rate(struct device *dev,
|
||||
struct rockchip_opp_info *opp_info,
|
||||
@@ -1749,91 +1928,306 @@ int rockchip_set_intermediate_rate(struct device *dev,
|
||||
}
|
||||
EXPORT_SYMBOL(rockchip_set_intermediate_rate);
|
||||
|
||||
int rockchip_init_opp_table(struct device *dev, struct rockchip_opp_info *info,
|
||||
char *lkg_name, char *reg_name)
|
||||
static int rockchip_opp_set_volt(struct device *dev, struct regulator *reg,
|
||||
struct dev_pm_opp_supply *supply, char *reg_name)
|
||||
{
|
||||
struct device_node *np;
|
||||
int bin = -EINVAL, process = -EINVAL;
|
||||
int scale = 0, volt_sel = -EINVAL;
|
||||
int ret = 0, num_clks = 0, i;
|
||||
u32 freq;
|
||||
int ret = 0;
|
||||
|
||||
/* Get OPP descriptor node */
|
||||
np = of_parse_phandle(dev->of_node, "operating-points-v2", 0);
|
||||
if (!np) {
|
||||
dev_dbg(dev, "Failed to find operating-points-v2\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
if (!info)
|
||||
goto next;
|
||||
info->dev = dev;
|
||||
|
||||
num_clks = of_clk_get_parent_count(np);
|
||||
if (num_clks > 0) {
|
||||
info->clks = devm_kcalloc(dev, num_clks, sizeof(*info->clks),
|
||||
GFP_KERNEL);
|
||||
if (!info->clks) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
for (i = 0; i < num_clks; i++) {
|
||||
info->clks[i].clk = of_clk_get(np, i);
|
||||
if (IS_ERR(info->clks[i].clk)) {
|
||||
ret = PTR_ERR(info->clks[i].clk);
|
||||
dev_err(dev, "%s: failed to get clk %d\n",
|
||||
np->name, i);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
info->num_clks = num_clks;
|
||||
ret = clk_bulk_prepare_enable(info->num_clks, info->clks);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to enable opp clks\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (info->data && info->data->set_read_margin) {
|
||||
info->current_rm = UINT_MAX;
|
||||
info->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
|
||||
if (IS_ERR(info->grf))
|
||||
info->grf = NULL;
|
||||
rockchip_get_volt_rm_table(dev, np, "volt-mem-read-margin",
|
||||
&info->volt_rm_tbl);
|
||||
of_property_read_u32(np, "low-volt-mem-read-margin",
|
||||
&info->low_rm);
|
||||
if (!of_property_read_u32(np, "intermediate-threshold-freq",
|
||||
&freq))
|
||||
info->intermediate_threshold_freq = freq * 1000;
|
||||
rockchip_init_read_margin(dev, info, reg_name);
|
||||
}
|
||||
if (info->data && info->data->get_soc_info)
|
||||
info->data->get_soc_info(dev, np, &bin, &process);
|
||||
|
||||
next:
|
||||
rockchip_get_scale_volt_sel(dev, lkg_name, reg_name, bin, process,
|
||||
&scale, &volt_sel);
|
||||
if (info && info->data && info->data->set_soc_info)
|
||||
info->data->set_soc_info(dev, np, bin, process, volt_sel);
|
||||
rockchip_set_opp_prop_name(dev, process, volt_sel);
|
||||
ret = dev_pm_opp_of_add_table(dev);
|
||||
if (ret) {
|
||||
dev_err(dev, "Invalid operating-points in device tree.\n");
|
||||
goto dis_opp_clk;
|
||||
}
|
||||
rockchip_adjust_power_scale(dev, scale);
|
||||
rockchip_pvtpll_calibrate_opp(info);
|
||||
rockchip_pvtpll_add_length(info);
|
||||
|
||||
dis_opp_clk:
|
||||
if (info && info->clks)
|
||||
clk_bulk_disable_unprepare(info->num_clks, info->clks);
|
||||
out:
|
||||
of_node_put(np);
|
||||
ret = regulator_set_voltage_triplet(reg, supply->u_volt_min,
|
||||
supply->u_volt, supply->u_volt_max);
|
||||
if (ret)
|
||||
dev_err(dev, "%s: failed to set voltage (%lu %lu %lu uV): %d\n",
|
||||
reg_name, supply->u_volt_min, supply->u_volt,
|
||||
supply->u_volt_max, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rockchip_opp_config_regulators(struct device *dev,
|
||||
struct dev_pm_opp *old_opp,
|
||||
struct dev_pm_opp *new_opp,
|
||||
struct regulator **regulators,
|
||||
unsigned int count,
|
||||
struct rockchip_opp_info *info)
|
||||
{
|
||||
struct regulator *vdd_reg = regulators[0];
|
||||
struct regulator *mem_reg;
|
||||
struct dev_pm_opp_supply old_supplies[2] = { 0 };
|
||||
struct dev_pm_opp_supply new_supplies[2] = { 0 };
|
||||
unsigned long old_freq, freq;
|
||||
u32 target_rm = UINT_MAX;
|
||||
int ret = 0;
|
||||
|
||||
if (count > 1)
|
||||
mem_reg = regulators[1];
|
||||
|
||||
ret = dev_pm_opp_get_supplies(new_opp, new_supplies);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = dev_pm_opp_get_supplies(old_opp, old_supplies);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_bulk_prepare_enable(info->nclocks, info->clocks);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to enable opp clks\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
rockchip_get_read_margin(dev, info, new_supplies[0].u_volt, &target_rm);
|
||||
|
||||
old_freq = dev_pm_opp_get_freq(old_opp);
|
||||
freq = dev_pm_opp_get_freq(new_opp);
|
||||
|
||||
if (count > 1)
|
||||
dev_dbg(dev, "%lu %lu -> %lu %lu (uV)\n",
|
||||
old_supplies[0].u_volt, old_supplies[1].u_volt,
|
||||
new_supplies[0].u_volt, new_supplies[1].u_volt);
|
||||
else
|
||||
dev_dbg(dev, "%lu -> %lu (uV)\n", old_supplies[0].u_volt,
|
||||
new_supplies[0].u_volt);
|
||||
|
||||
if (freq > old_freq) {
|
||||
if (count > 1) {
|
||||
ret = rockchip_opp_set_volt(dev, mem_reg, &new_supplies[1], "mem");
|
||||
if (ret)
|
||||
goto restore_voltage;
|
||||
}
|
||||
ret = rockchip_opp_set_volt(dev, vdd_reg, &new_supplies[0], "vdd");
|
||||
if (ret)
|
||||
goto restore_voltage;
|
||||
rockchip_set_read_margin(dev, info, target_rm, info->is_runtime_active);
|
||||
} else {
|
||||
rockchip_set_read_margin(dev, info, target_rm, info->is_runtime_active);
|
||||
ret = rockchip_opp_set_volt(dev, vdd_reg, &new_supplies[0], "vdd");
|
||||
if (ret)
|
||||
goto restore_voltage;
|
||||
if (count > 1) {
|
||||
ret = rockchip_opp_set_volt(dev, mem_reg, &new_supplies[1], "mem");
|
||||
if (ret)
|
||||
goto restore_voltage;
|
||||
}
|
||||
}
|
||||
|
||||
clk_bulk_disable_unprepare(info->nclocks, info->clocks);
|
||||
|
||||
return 0;
|
||||
|
||||
restore_voltage:
|
||||
rockchip_get_read_margin(dev, info, old_supplies[0].u_volt, &target_rm);
|
||||
rockchip_set_read_margin(dev, info, target_rm, info->is_runtime_active);
|
||||
|
||||
if (old_supplies[0].u_volt) {
|
||||
if (count > 1 && old_supplies[1].u_volt) {
|
||||
ret = rockchip_opp_set_volt(dev, mem_reg, &old_supplies[1], "mem");
|
||||
if (ret)
|
||||
goto dis_clks;
|
||||
}
|
||||
ret = rockchip_opp_set_volt(dev, vdd_reg, &old_supplies[0], "vdd");
|
||||
if (ret)
|
||||
goto dis_clks;
|
||||
}
|
||||
|
||||
dis_clks:
|
||||
clk_bulk_disable_unprepare(info->nclocks, info->clocks);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(rockchip_opp_config_regulators);
|
||||
|
||||
int rockchip_opp_config_clks(struct device *dev, struct opp_table *opp_table,
|
||||
struct dev_pm_opp *opp, void *data,
|
||||
bool scaling_down, struct rockchip_opp_info *info)
|
||||
{
|
||||
unsigned long *target = data;
|
||||
int ret;
|
||||
|
||||
if (!info->is_runtime_active)
|
||||
return 0;
|
||||
|
||||
dev_dbg(dev, "%lu -> %lu (Hz)\n", opp_table->rate_clk_single, *target);
|
||||
ret = clk_set_rate(opp_table->clk, *target);
|
||||
if (ret)
|
||||
dev_err(dev, "failed to set clock rate: %lu\n", *target);
|
||||
else
|
||||
opp_table->rate_clk_single = *target;
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(rockchip_opp_config_clks);
|
||||
|
||||
int rockchip_opp_check_rate_volt(struct device *dev, struct rockchip_opp_info *info)
|
||||
{
|
||||
struct regulator *vdd_reg = NULL;
|
||||
struct regulator *mem_reg = NULL;
|
||||
struct dev_pm_opp *opp;
|
||||
unsigned long old_rate = 0, new_rate = 0;
|
||||
unsigned long new_volt = 0, new_volt_mem = 0;
|
||||
int old_volt = 0, old_volt_mem = 0;
|
||||
u32 target_rm = UINT_MAX;
|
||||
bool is_set_clk = true;
|
||||
bool is_set_rm = false;
|
||||
int ret = 0;
|
||||
|
||||
if (!info->regulators || !info->clk)
|
||||
return 0;
|
||||
|
||||
vdd_reg = info->regulators[0];
|
||||
old_rate = clk_get_rate(info->clk);
|
||||
old_volt = regulator_get_voltage(vdd_reg);
|
||||
if (info->regulator_count > 1) {
|
||||
mem_reg = info->regulators[1];
|
||||
old_volt_mem = regulator_get_voltage(mem_reg);
|
||||
}
|
||||
|
||||
if (info->init_freq) {
|
||||
new_rate = info->init_freq * 1000;
|
||||
info->init_freq = 0;
|
||||
} else {
|
||||
new_rate = old_rate;
|
||||
}
|
||||
opp = dev_pm_opp_find_freq_ceil(dev, &new_rate);
|
||||
if (IS_ERR(opp)) {
|
||||
opp = dev_pm_opp_find_freq_floor(dev, &new_rate);
|
||||
if (IS_ERR(opp))
|
||||
return PTR_ERR(opp);
|
||||
}
|
||||
new_volt = opp->supplies[0].u_volt;
|
||||
if (info->regulator_count > 1)
|
||||
new_volt_mem = opp->supplies[1].u_volt;
|
||||
dev_pm_opp_put(opp);
|
||||
|
||||
if (old_rate == new_rate && info->is_rate_volt_checked) {
|
||||
if (info->regulator_count > 1) {
|
||||
if (old_volt == new_volt &&
|
||||
new_volt_mem == old_volt_mem)
|
||||
return 0;
|
||||
} else if (old_volt == new_volt) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (!new_volt || (info->regulator_count > 1 && !new_volt_mem))
|
||||
return 0;
|
||||
|
||||
ret = clk_bulk_prepare_enable(info->nclocks, info->clocks);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to enable opp clks\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (info->is_scmi_clk && !info->is_runtime_active)
|
||||
is_set_clk = false;
|
||||
if (info->data && info->data->set_read_margin && info->is_runtime_active)
|
||||
is_set_rm = true;
|
||||
|
||||
rockchip_get_read_margin(dev, info, new_volt, &target_rm);
|
||||
|
||||
dev_dbg(dev, "%s: %lu Hz --> %lu Hz, %lu %lu uV\n", __func__,
|
||||
old_rate, new_rate, new_volt, new_volt_mem);
|
||||
if (new_rate >= old_rate) {
|
||||
if (info->regulator_count > 1) {
|
||||
ret = regulator_set_voltage(mem_reg, new_volt_mem,
|
||||
INT_MAX);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: failed to set volt: %lu\n",
|
||||
__func__, new_volt_mem);
|
||||
goto disable_clk;
|
||||
}
|
||||
}
|
||||
ret = regulator_set_voltage(vdd_reg, new_volt, INT_MAX);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: failed to set volt: %lu\n",
|
||||
__func__, new_volt);
|
||||
goto restore_voltage;
|
||||
}
|
||||
rockchip_set_read_margin(dev, info, target_rm, is_set_rm);
|
||||
if (new_rate == old_rate)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (is_set_clk) {
|
||||
ret = clk_set_rate(info->clk, new_rate);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: failed to set clock rate: %lu\n",
|
||||
__func__, new_rate);
|
||||
goto restore_rm;
|
||||
}
|
||||
}
|
||||
|
||||
if (new_rate < old_rate) {
|
||||
rockchip_set_read_margin(dev, info, target_rm, is_set_rm);
|
||||
ret = regulator_set_voltage(vdd_reg, new_volt,
|
||||
INT_MAX);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: failed to set volt: %lu\n",
|
||||
__func__, new_volt);
|
||||
goto restore_freq;
|
||||
}
|
||||
if (info->regulator_count > 1) {
|
||||
ret = regulator_set_voltage(mem_reg, new_volt_mem,
|
||||
INT_MAX);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: failed to set volt: %lu\n",
|
||||
__func__, new_volt_mem);
|
||||
goto restore_freq;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
clk_bulk_disable_unprepare(info->nclocks, info->clocks);
|
||||
|
||||
return 0;
|
||||
|
||||
restore_freq:
|
||||
if (is_set_clk && clk_set_rate(info->clk, old_rate))
|
||||
dev_err(dev, "%s: failed to restore old-freq (%lu Hz)\n",
|
||||
__func__, old_rate);
|
||||
restore_rm:
|
||||
rockchip_get_read_margin(dev, info, old_volt, &target_rm);
|
||||
rockchip_set_read_margin(dev, info, target_rm, is_set_rm);
|
||||
restore_voltage:
|
||||
if (info->regulator_count > 1)
|
||||
regulator_set_voltage(mem_reg, old_volt_mem, INT_MAX);
|
||||
regulator_set_voltage(vdd_reg, old_volt, INT_MAX);
|
||||
disable_clk:
|
||||
clk_bulk_disable_unprepare(info->nclocks, info->clocks);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(rockchip_opp_check_rate_volt);
|
||||
|
||||
int rockchip_init_opp_table(struct device *dev, struct rockchip_opp_info *info,
|
||||
char *clk_name, char *reg_name)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = rockchip_init_opp_info(dev, info, clk_name, reg_name);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to init opp info\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = dev_pm_opp_of_add_table(dev);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to add opp table\n");
|
||||
rockchip_uninit_opp_info(dev, info);
|
||||
return ret;
|
||||
}
|
||||
|
||||
rockchip_adjust_opp_table(dev, info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(rockchip_init_opp_table);
|
||||
|
||||
void rockchip_uninit_opp_table(struct device *dev, struct rockchip_opp_info *info)
|
||||
{
|
||||
rockchip_uninit_opp_info(dev, info);
|
||||
dev_pm_opp_of_remove_table(dev);
|
||||
}
|
||||
EXPORT_SYMBOL(rockchip_uninit_opp_table);
|
||||
|
||||
MODULE_DESCRIPTION("ROCKCHIP OPP Select");
|
||||
MODULE_AUTHOR("Finley Xiao <finley.xiao@rock-chips.com>, Liang Chen <cl@rock-chips.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#ifndef __SOC_ROCKCHIP_OPP_SELECT_H
|
||||
#define __SOC_ROCKCHIP_OPP_SELECT_H
|
||||
|
||||
#include <linux/pm_opp.h>
|
||||
|
||||
#define VOLT_RM_TABLE_END ~1
|
||||
|
||||
/*
|
||||
@@ -40,12 +42,15 @@ struct volt_rm_table {
|
||||
};
|
||||
|
||||
struct rockchip_opp_data {
|
||||
config_clks_t config_clks;
|
||||
config_regulators_t config_regulators;
|
||||
|
||||
int (*get_soc_info)(struct device *dev, struct device_node *np,
|
||||
int *bin, int *process);
|
||||
int (*set_soc_info)(struct device *dev, struct device_node *np,
|
||||
int bin, int process, int volt_sel);
|
||||
struct rockchip_opp_info *info);
|
||||
int (*set_read_margin)(struct device *dev,
|
||||
struct rockchip_opp_info *opp_info,
|
||||
struct rockchip_opp_info *info,
|
||||
u32 rm);
|
||||
};
|
||||
|
||||
@@ -59,72 +64,112 @@ struct pvtpll_opp_table {
|
||||
unsigned long u_volt_mem_max;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct rockchip_opp_info - Rockchip opp info structure
|
||||
* @dev: The device.
|
||||
* @dvfs_mutex: Mutex to protect changing volage and scmi clock rate.
|
||||
* @data: Device-specific opp data.
|
||||
* @opp_table: Temporary opp table only used when enable pvtpll calibration.
|
||||
* @pvtpll_avg_offset: Register offset of pvtm value.
|
||||
* @pvtpll_min_rate: Minimum frequency which needs calibration.
|
||||
* @pvtpll_volt_step: Voltage step of pvtpll calibration.
|
||||
* @volt_rm_tbl: Pointer to voltage to memory read margin conversion table.
|
||||
* @grf: General Register Files regmap.
|
||||
* @dsu_grf: DSU General Register Files regmap.
|
||||
* @clocks: Pvtpll clocks.
|
||||
* @nclocks: Number of pvtpll clock.
|
||||
* @intermediate_threshold_freq: The frequency threshold of intermediate rate.
|
||||
* @low_rm: The read margin threshold of intermediate rate.
|
||||
* @current_rm: Current memory read margin.
|
||||
* @target_rm: Target memory read margin.
|
||||
* @is_runtime_active: Marks if device's pd is power on.
|
||||
* @opp_token: Integer replacement for opp_table.
|
||||
* @scale: Frequency scale.
|
||||
* @bin: Soc version.
|
||||
* @process: Process version.
|
||||
* @volt_sel: Speed grade.
|
||||
* @supported_hw: Array of version number to support.
|
||||
* @clk: Device's clock handle.
|
||||
* @is_scmi_clk: Marks if device's clock is scmi clock.
|
||||
* @regulators: Supply regulators.
|
||||
* @regulator_count: Number of power supply regulators.
|
||||
* @init_freq: Set the initial frequency when init opp table.
|
||||
* @is_rate_volt_checked: Marks if device has checked initial rate and voltage.
|
||||
*/
|
||||
struct rockchip_opp_info {
|
||||
struct device *dev;
|
||||
struct pvtpll_opp_table *opp_table;
|
||||
struct mutex dvfs_mutex;
|
||||
const struct rockchip_opp_data *data;
|
||||
struct volt_rm_table *volt_rm_tbl;
|
||||
struct regmap *grf;
|
||||
struct regmap *dsu_grf;
|
||||
struct clk_bulk_data *clks;
|
||||
struct clk *scmi_clk;
|
||||
/* The threshold frequency for set intermediate rate */
|
||||
unsigned long intermediate_threshold_freq;
|
||||
struct pvtpll_opp_table *opp_table;
|
||||
unsigned int pvtpll_avg_offset;
|
||||
unsigned int pvtpll_min_rate;
|
||||
unsigned int pvtpll_volt_step;
|
||||
int num_clks;
|
||||
/* The read margin for low voltage */
|
||||
|
||||
struct volt_rm_table *volt_rm_tbl;
|
||||
struct regmap *grf;
|
||||
struct regmap *dsu_grf;
|
||||
struct clk_bulk_data *clocks;
|
||||
int nclocks;
|
||||
unsigned long intermediate_threshold_freq;
|
||||
u32 low_rm;
|
||||
u32 current_rm;
|
||||
u32 target_rm;
|
||||
bool is_runtime_active;
|
||||
|
||||
int opp_token;
|
||||
int scale;
|
||||
int bin;
|
||||
int process;
|
||||
int volt_sel;
|
||||
u32 supported_hw[2];
|
||||
|
||||
struct clk *clk;
|
||||
bool is_scmi_clk;
|
||||
struct regulator **regulators;
|
||||
int regulator_count;
|
||||
unsigned int init_freq;
|
||||
bool is_rate_volt_checked;
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_ROCKCHIP_OPP)
|
||||
int rockchip_of_get_leakage(struct device *dev, char *lkg_name, int *leakage);
|
||||
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_pvtpll_calibrate_opp(struct rockchip_opp_info *info);
|
||||
void rockchip_pvtpll_add_length(struct rockchip_opp_info *info);
|
||||
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);
|
||||
void rockchip_of_get_bin_volt_sel(struct device *dev, struct device_node *np,
|
||||
int bin, int *bin_volt_sel);
|
||||
int rockchip_nvmem_cell_read_u8(struct device_node *np, const char *cell_id,
|
||||
u8 *val);
|
||||
int rockchip_nvmem_cell_read_u16(struct device_node *np, const char *cell_id,
|
||||
u16 *val);
|
||||
int rockchip_get_volt_rm_table(struct device *dev, struct device_node *np,
|
||||
char *porp_name, struct volt_rm_table **table);
|
||||
void rockchip_get_opp_data(const struct of_device_id *matches,
|
||||
struct rockchip_opp_info *info);
|
||||
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 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);
|
||||
void rockchip_opp_dvfs_lock(struct rockchip_opp_info *info);
|
||||
void rockchip_opp_dvfs_unlock(struct rockchip_opp_info *info);
|
||||
int rockchip_init_opp_info(struct device *dev, struct rockchip_opp_info *info,
|
||||
char *clk_name, char *reg_name);
|
||||
void rockchip_uninit_opp_info(struct device *dev, struct rockchip_opp_info *info);
|
||||
int rockchip_adjust_opp_table(struct device *dev, struct rockchip_opp_info *info);
|
||||
int rockchip_get_read_margin(struct device *dev,
|
||||
struct rockchip_opp_info *opp_info,
|
||||
struct rockchip_opp_info *info,
|
||||
unsigned long volt, u32 *target_rm);
|
||||
int rockchip_set_read_margin(struct device *dev,
|
||||
struct rockchip_opp_info *opp_info, u32 rm,
|
||||
struct rockchip_opp_info *info, u32 rm,
|
||||
bool is_set_rm);
|
||||
int rockchip_init_read_margin(struct device *dev,
|
||||
struct rockchip_opp_info *opp_info,
|
||||
char *reg_name);
|
||||
int rockchip_set_intermediate_rate(struct device *dev,
|
||||
struct rockchip_opp_info *opp_info,
|
||||
struct rockchip_opp_info *info,
|
||||
struct clk *clk, unsigned long old_freq,
|
||||
unsigned long new_freq, bool is_scaling_up,
|
||||
bool is_set_clk);
|
||||
int rockchip_init_opp_table(struct device *dev,
|
||||
struct rockchip_opp_info *info,
|
||||
char *lkg_name, char *reg_name);
|
||||
int rockchip_opp_config_regulators(struct device *dev,
|
||||
struct dev_pm_opp *old_opp,
|
||||
struct dev_pm_opp *new_opp,
|
||||
struct regulator **regulators,
|
||||
unsigned int count,
|
||||
struct rockchip_opp_info *info);
|
||||
int rockchip_opp_config_clks(struct device *dev, struct opp_table *opp_table,
|
||||
struct dev_pm_opp *opp, void *data,
|
||||
bool scaling_down, struct rockchip_opp_info *info);
|
||||
int rockchip_opp_check_rate_volt(struct device *dev, struct rockchip_opp_info *info);
|
||||
int rockchip_init_opp_table(struct device *dev, struct rockchip_opp_info *info,
|
||||
char *clk_name, char *reg_name);
|
||||
void rockchip_uninit_opp_table(struct device *dev,
|
||||
struct rockchip_opp_info *info);
|
||||
#else
|
||||
static inline int rockchip_of_get_leakage(struct device *dev, char *lkg_name,
|
||||
int *leakage)
|
||||
@@ -132,40 +177,6 @@ static inline int rockchip_of_get_leakage(struct device *dev, char *lkg_name,
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline void rockchip_of_get_lkg_sel(struct device *dev,
|
||||
struct device_node *np,
|
||||
char *lkg_name, int process,
|
||||
int *volt_sel, int *scale_sel)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void rockchip_pvtpll_calibrate_opp(struct rockchip_opp_info *info)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void rockchip_pvtpll_add_length(struct rockchip_opp_info *info)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void rockchip_of_get_pvtm_sel(struct device *dev,
|
||||
struct device_node *np,
|
||||
char *reg_name, int process,
|
||||
int *volt_sel, int *scale_sel)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void rockchip_of_get_bin_sel(struct device *dev,
|
||||
struct device_node *np, int bin,
|
||||
int *scale_sel)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void rockchip_of_get_bin_volt_sel(struct device *dev,
|
||||
struct device_node *np,
|
||||
int bin, int *bin_volt_sel)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int rockchip_nvmem_cell_read_u8(struct device_node *np,
|
||||
const char *cell_id, u8 *val)
|
||||
{
|
||||
@@ -178,59 +189,50 @@ static inline int rockchip_nvmem_cell_read_u16(struct device_node *np,
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int rockchip_get_volt_rm_table(struct device *dev,
|
||||
struct device_node *np,
|
||||
char *porp_name,
|
||||
struct volt_rm_table **table)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
}
|
||||
|
||||
static inline void rockchip_get_opp_data(const struct of_device_id *matches,
|
||||
struct rockchip_opp_info *info)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void rockchip_get_scale_volt_sel(struct device *dev,
|
||||
char *lkg_name, char *reg_name,
|
||||
int bin, int process, int *scale,
|
||||
int *volt_sel)
|
||||
static inline void rockchip_opp_dvfs_lock(struct rockchip_opp_info *info)
|
||||
{
|
||||
}
|
||||
|
||||
static inline struct opp_table *rockchip_set_opp_prop_name(struct device *dev,
|
||||
int process,
|
||||
int volt_sel)
|
||||
static inline void rockchip_opp_dvfs_unlock(struct rockchip_opp_info *info)
|
||||
{
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
static inline int rockchip_adjust_power_scale(struct device *dev, int scale)
|
||||
static inline int
|
||||
rockchip_init_opp_info(struct device *dev, struct rockchip_opp_info *info,
|
||||
char *clk_name, char *reg_name)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline void
|
||||
rockchip_uninit_opp_info(struct device *dev, struct rockchip_opp_info *info)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int
|
||||
rockchip_adjust_opp_table(struct device *dev, struct rockchip_opp_info *info)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int rockchip_get_read_margin(struct device *dev,
|
||||
struct rockchip_opp_info *opp_info,
|
||||
struct rockchip_opp_info *info,
|
||||
unsigned long volt, u32 *target_rm)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
static inline int rockchip_set_read_margin(struct device *dev,
|
||||
struct rockchip_opp_info *opp_info,
|
||||
struct rockchip_opp_info *info,
|
||||
u32 rm, bool is_set_rm)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int rockchip_init_read_margin(struct device *dev,
|
||||
struct rockchip_opp_info *opp_info,
|
||||
char *reg_name)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int
|
||||
rockchip_set_intermediate_rate(struct device *dev,
|
||||
struct rockchip_opp_info *opp_info,
|
||||
@@ -241,13 +243,44 @@ rockchip_set_intermediate_rate(struct device *dev,
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int rockchip_init_opp_table(struct device *dev,
|
||||
struct rockchip_opp_info *info,
|
||||
char *lkg_name, char *reg_name)
|
||||
static inline int
|
||||
rockchip_opp_config_regulators(struct device *dev,
|
||||
struct dev_pm_opp *old_opp,
|
||||
struct dev_pm_opp *new_opp,
|
||||
struct regulator **regulators,
|
||||
unsigned int count,
|
||||
struct rockchip_opp_info *info)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int rockchip_opp_config_clks(struct device *dev,
|
||||
struct opp_table *opp_table,
|
||||
struct dev_pm_opp *opp, void *data,
|
||||
bool scaling_down,
|
||||
struct rockchip_opp_info *info)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int rockchip_opp_check_rate_volt(struct device *dev,
|
||||
struct rockchip_opp_info *info)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int
|
||||
rockchip_init_opp_table(struct device *dev, struct rockchip_opp_info *info,
|
||||
char *clk_name, char *reg_name)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline void rockchip_uninit_opp_table(struct device *dev,
|
||||
struct rockchip_opp_info *info)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_ROCKCHIP_OPP */
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user