From 3aa3abee3ef21296ea97518d2bf45b9a7ff2df49 Mon Sep 17 00:00:00 2001 From: Finley Xiao Date: Tue, 13 Oct 2020 21:13:24 +0800 Subject: [PATCH] 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 Change-Id: I8ae256eb8e725503c744be2011a5edc7275d47cc --- drivers/soc/rockchip/rockchip_opp_select.c | 149 ++++++++++++++++----- 1 file changed, 115 insertions(+), 34 deletions(-) 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) {