soc: rockchip: opp_select: adjust opp-table by pvtm and mbist_vmin

1. support get pvtm from otp.
2. adjust opp-table by mbist_vmit which is get from otp.

Change-Id: Ie3703873880b65b2af03ae474065d541c7f9d605
Signed-off-by: Liang Chen <cl@rock-chips.com>
This commit is contained in:
Liang Chen
2021-05-28 08:38:06 +08:00
committed by Tao Huang
parent a0b1f8c7ae
commit 79d32ab7d4

View File

@@ -149,6 +149,49 @@ int rockchip_get_efuse_value(struct device_node *np, char *porp_name,
}
EXPORT_SYMBOL(rockchip_get_efuse_value);
static int rockchip_nvmem_cell_read_common(struct device_node *np,
const char *cell_id,
void *val, size_t count)
{
struct nvmem_cell *cell;
void *buf;
size_t len;
cell = of_nvmem_cell_get(np, cell_id);
if (IS_ERR(cell))
return PTR_ERR(cell);
buf = nvmem_cell_read(cell, &len);
if (IS_ERR(buf)) {
nvmem_cell_put(cell);
return PTR_ERR(buf);
}
if (len != count) {
kfree(buf);
nvmem_cell_put(cell);
return -EINVAL;
}
memcpy(val, buf, count);
kfree(buf);
nvmem_cell_put(cell);
return 0;
}
static int rockchip_nvmem_cell_read_u8(struct device_node *np,
const char *cell_id,
u8 *val)
{
return rockchip_nvmem_cell_read_common(np, cell_id, val, sizeof(*val));
}
static int rockchip_nvmem_cell_read_u16(struct device_node *np,
const char *cell_id,
u16 *val)
{
return rockchip_nvmem_cell_read_common(np, cell_id, val, sizeof(*val));
}
static int rockchip_get_sel_table(struct device_node *np, char *porp_name,
struct sel_table **table)
{
@@ -326,23 +369,12 @@ static int rockchip_get_pvtm_specific_value(struct device *dev,
{
struct pvtm_config *pvtm;
unsigned long old_freq;
unsigned int old_volt, ch[2];
unsigned int old_volt;
int cur_temp, diff_temp;
int cur_value, total_value, avg_value, diff_value;
int min_value, max_value;
int ret = 0, i = 0, retry = 2;
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)
return -EINVAL;
if (pvtm_value[ch[0]][ch[1]]) {
*target_value = pvtm_value[ch[0]][ch[1]];
return 0;
}
pvtm = kzalloc(sizeof(*pvtm), GFP_KERNEL);
if (!pvtm)
return -ENOMEM;
@@ -689,33 +721,65 @@ next:
}
EXPORT_SYMBOL(rockchip_of_get_lkg_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)
static int rockchip_get_pvtm(struct device *dev, struct device_node *np,
char *reg_name)
{
struct property *prop = NULL;
struct regulator *reg;
struct clk *clk;
int pvtm = -EINVAL, ret;
char name[NAME_MAX];
unsigned int ch[2];
int pvtm = 0;
u16 tmp = 0;
if (!rockchip_nvmem_cell_read_u16(np, "pvtm", &tmp) && tmp) {
pvtm = 10 * tmp;
dev_info(dev, "pvtm = %d, from nvmem\n", pvtm);
return pvtm;
}
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)
return -EINVAL;
if (pvtm_value[ch[0]][ch[1]]) {
dev_info(dev, "pvtm = %d, form pvtm_value\n", pvtm_value[ch[0]][ch[1]]);
return pvtm_value[ch[0]][ch[1]];
}
clk = clk_get(dev, NULL);
if (IS_ERR_OR_NULL(clk)) {
dev_warn(dev, "Failed to get clk\n");
return;
return PTR_ERR_OR_ZERO(clk);
}
reg = regulator_get_optional(dev, reg_name);
if (IS_ERR_OR_NULL(reg)) {
dev_warn(dev, "Failed to get reg\n");
goto clk_err;
clk_put(clk);
return PTR_ERR_OR_ZERO(reg);
}
ret = rockchip_get_pvtm_specific_value(dev, np, clk, reg, &pvtm);
if (ret) {
dev_err(dev, "Failed to get pvtm\n");
goto out;
}
rockchip_get_pvtm_specific_value(dev, np, clk, reg, &pvtm);
regulator_put(reg);
clk_put(clk);
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)
{
struct property *prop = NULL;
char name[NAME_MAX];
int pvtm, ret;
pvtm = rockchip_get_pvtm(dev, np, reg_name);
if (pvtm <= 0)
return;
if (!volt_sel)
goto next;
@@ -732,7 +796,7 @@ void rockchip_of_get_pvtm_sel(struct device *dev, struct device_node *np,
next:
if (!scale_sel)
goto out;
return;
if (process >= 0) {
snprintf(name, sizeof(name),
"rockchip,p%d-pvtm-scaling-sel", process);
@@ -743,11 +807,6 @@ next:
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);
@@ -940,6 +999,37 @@ out:
return ret;
}
static void rockchip_adjust_opp_by_mbist_vmin(struct device *dev,
struct device_node *np)
{
struct opp_table *opp_table;
struct dev_pm_opp *opp;
u32 vmin = 0;
u8 index = 0;
if (rockchip_nvmem_cell_read_u8(np, "mbist-vmin", &index))
return;
if (!index)
return;
if (of_property_read_u32_index(np, "mbist-vmin", index-1, &vmin))
return;
opp_table = dev_pm_opp_get_opp_table(dev);
if (!opp_table)
return;
mutex_lock(&opp_table->lock);
list_for_each_entry(opp, &opp_table->opp_list, node) {
if (opp->supplies->u_volt < vmin) {
opp->supplies->u_volt = vmin;
opp->supplies->u_volt_min = vmin;
}
}
mutex_unlock(&opp_table->lock);
}
static int rockchip_adjust_opp_table(struct device *dev,
unsigned long scale_rate)
{
@@ -986,6 +1076,7 @@ int rockchip_adjust_power_scale(struct device *dev, int scale)
of_property_read_u32(np, "rockchip,avs-enable", &avs);
of_property_read_u32(np, "rockchip,avs", &avs);
of_property_read_u32(np, "rockchip,avs-scale", &avs_scale);
rockchip_adjust_opp_by_mbist_vmin(dev, np);
rockchip_adjust_opp_by_irdrop(dev, np, &safe_rate, &max_rate);
dev_info(dev, "avs=%d\n", avs);