diff --git a/drivers/soc/rockchip/rockchip_opp_select.c b/drivers/soc/rockchip/rockchip_opp_select.c index 2f2b69a8fcdc..4e20d0911d35 100644 --- a/drivers/soc/rockchip/rockchip_opp_select.c +++ b/drivers/soc/rockchip/rockchip_opp_select.c @@ -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) {