soc: rockchip: opp_select: Add support to get leakage for rv1126

The leakage value is a decimal on RV1126, let it multiply by 1000 for
changing voltage and frequency scale according to leakage. And round up to
the nearest whole number for calculating static power, it does not need
to be precise.

Signed-off-by: Finley Xiao <finley.xiao@rock-chips.com>
Change-Id: I8ae256eb8e725503c744be2011a5edc7275d47cc
This commit is contained in:
Finley Xiao 2020-10-13 21:13:24 +08:00 committed by Tao Huang
commit 3aa3abee3e

View file

@ -26,6 +26,10 @@
#define AVS_DELETE_OPP 0
#define AVS_SCALING_RATE 1
#define LEAKAGE_V1 1
#define LEAKAGE_V2 2
#define LEAKAGE_V3 3
#define to_thermal_opp_info(nb) container_of(nb, struct thermal_opp_info, \
thermal_nb)
@ -66,6 +70,7 @@ struct lkg_conversion_table {
#define frac_to_int(x) ((x) >> FRAC_BITS)
static int pvtm_value[PVTM_CH_MAX][PVTM_SUB_CH_MAX];
static int lkg_version;
/*
* temp = temp * 10
@ -509,18 +514,28 @@ next:
return 0;
}
int rockchip_of_get_leakage(struct device *dev, char *lkg_name, int *leakage)
static int rockchip_get_leakage_version(int *version)
{
if (*version)
return 0;
if (of_machine_is_compatible("rockchip,rk3368"))
*version = LEAKAGE_V2;
else if (of_machine_is_compatible("rockchip,rv1126") ||
of_machine_is_compatible("rockchip,rv1109"))
*version = LEAKAGE_V3;
else
*version = LEAKAGE_V1;
return 0;
}
static int rockchip_get_leakage_v1(struct device *dev, struct device_node *np,
char *lkg_name, int *leakage)
{
struct device_node *np;
struct nvmem_cell *cell;
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;
}
cell = of_nvmem_cell_get(np, "leakage");
if (IS_ERR(cell)) {
ret = rockchip_get_efuse_value(np, lkg_name, leakage);
@ -528,17 +543,79 @@ int rockchip_of_get_leakage(struct device *dev, char *lkg_name, int *leakage)
nvmem_cell_put(cell);
ret = rockchip_get_efuse_value(np, "leakage", leakage);
}
if (ret) {
if (ret)
dev_err(dev, "Failed to get %s\n", lkg_name);
ret = -EINVAL;
goto out;
return ret;
}
static int rockchip_get_leakage_v2(struct device *dev, struct device_node *np,
char *lkg_name, int *leakage)
{
int lkg = 0, ret = 0;
if (rockchip_get_leakage_v1(dev, np, lkg_name, &lkg))
return -EINVAL;
ret = rockchip_adjust_leakage(dev, np, &lkg);
if (ret)
dev_err(dev, "Failed to adjust leakage, value=%d\n", lkg);
else
*leakage = lkg;
return ret;
}
static int rockchip_get_leakage_v3(struct device *dev, struct device_node *np,
char *lkg_name, int *leakage)
{
int lkg = 0;
if (rockchip_get_leakage_v1(dev, np, lkg_name, &lkg))
return -EINVAL;
*leakage = (((lkg & 0xf8) >> 3) * 1000) + ((lkg & 0x7) * 125);
return 0;
}
int rockchip_of_get_leakage(struct device *dev, char *lkg_name, int *leakage)
{
struct device_node *np;
int ret = -EINVAL;
np = of_parse_phandle(dev->of_node, "operating-points-v2", 0);
if (!np) {
dev_warn(dev, "OPP-v2 not supported\n");
return -ENOENT;
}
ret = rockchip_adjust_leakage(dev, np, leakage);
if (ret)
dev_err(dev, "Failed to adjust leakage\n");
rockchip_get_leakage_version(&lkg_version);
switch (lkg_version) {
case LEAKAGE_V1:
ret = rockchip_get_leakage_v1(dev, np, lkg_name, leakage);
break;
case LEAKAGE_V2:
ret = rockchip_get_leakage_v2(dev, np, lkg_name, leakage);
break;
case LEAKAGE_V3:
ret = rockchip_get_leakage_v3(dev, np, lkg_name, leakage);
if (!ret) {
/*
* round up to the nearest whole number for calculating
* static power, it does not need to be precise.
*/
if (*leakage % 1000 > 500)
*leakage = *leakage / 1000 + 1;
else
*leakage = *leakage / 1000;
}
break;
default:
break;
}
out:
of_node_put(np);
return ret;
@ -550,30 +627,34 @@ void rockchip_of_get_lkg_sel(struct device *dev, struct device_node *np,
int *volt_sel, int *scale_sel)
{
struct property *prop = NULL;
struct nvmem_cell *cell;
int leakage = -EINVAL, ret;
int leakage = -EINVAL, ret = 0;
char name[NAME_MAX];
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");
rockchip_get_leakage_version(&lkg_version);
switch (lkg_version) {
case LEAKAGE_V1:
ret = rockchip_get_leakage_v1(dev, np, lkg_name, &leakage);
if (ret)
return;
dev_info(dev, "leakage=%d\n", leakage);
case LEAKAGE_V2:
ret = rockchip_get_leakage_v2(dev, np, lkg_name, &leakage);
if (ret)
return;
dev_info(dev, "leakage=%d\n", leakage);
break;
case LEAKAGE_V3:
ret = rockchip_get_leakage_v3(dev, np, lkg_name, &leakage);
if (ret)
return;
dev_info(dev, "leakage=%d.%d\n", leakage / 1000,
leakage % 1000);
break;
default:
return;
}
ret = rockchip_adjust_leakage(dev, np, &leakage);
if (ret) {
dev_err(dev, "Failed to adjust leakage\n");
return;
}
dev_info(dev, "leakage=%d\n", leakage);
if (!volt_sel)
goto next;
if (process >= 0) {