* [PATCH 0/3] Support CPR on msm8939
@ 2020-09-30 6:26 Jun Nie
2020-09-30 6:26 ` [PATCH 1/3] cpufreq: qcom: Add support for msm8939 Jun Nie
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Jun Nie @ 2020-09-30 6:26 UTC (permalink / raw)
To: nks, linux-pm, linux-arm-msm; +Cc: shawn.guo, Jun Nie
Support CPR on msm8939 with adding corner adjustments.
Jun Nie (3):
cpufreq: qcom: Add support for msm8939
dt-bindings: power: avs: CPR: Add corner adjust properties
power: avs: qcom-cpr: add support to msm8939
.../bindings/power/avs/qcom,cpr.txt | 38 +-
drivers/cpufreq/cpufreq-dt-platdev.c | 1 +
drivers/cpufreq/qcom-cpufreq-nvmem.c | 1 +
drivers/power/avs/qcom-cpr.c | 366 ++++++++++++++++--
4 files changed, 382 insertions(+), 24 deletions(-)
--
2.17.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 1/3] cpufreq: qcom: Add support for msm8939
2020-09-30 6:26 [PATCH 0/3] Support CPR on msm8939 Jun Nie
@ 2020-09-30 6:26 ` Jun Nie
2020-09-30 6:26 ` [PATCH 2/3] dt-bindings: power: avs: CPR: Add corner adjust properties Jun Nie
2020-09-30 6:26 ` [PATCH 3/3] power: avs: qcom-cpr: add support to msm8939 Jun Nie
2 siblings, 0 replies; 6+ messages in thread
From: Jun Nie @ 2020-09-30 6:26 UTC (permalink / raw)
To: nks, linux-pm, linux-arm-msm; +Cc: shawn.guo, Jun Nie
Add qcom-cpufreq-nvmem support for msm8939.
Also add msm8939 to cpufreq-dt-platdev blacklist to avoid
conflict.
Signed-off-by: Jun Nie <jun.nie@linaro.org>
---
drivers/cpufreq/cpufreq-dt-platdev.c | 1 +
drivers/cpufreq/qcom-cpufreq-nvmem.c | 1 +
2 files changed, 2 insertions(+)
diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c
index 7d01df7bfa6c..b6eeb8ef9c11 100644
--- a/drivers/cpufreq/cpufreq-dt-platdev.c
+++ b/drivers/cpufreq/cpufreq-dt-platdev.c
@@ -130,6 +130,7 @@ static const struct of_device_id blacklist[] __initconst = {
{ .compatible = "nvidia,tegra210", },
{ .compatible = "qcom,apq8096", },
+ { .compatible = "qcom,msm8939", },
{ .compatible = "qcom,msm8996", },
{ .compatible = "qcom,qcs404", },
{ .compatible = "qcom,sc7180", },
diff --git a/drivers/cpufreq/qcom-cpufreq-nvmem.c b/drivers/cpufreq/qcom-cpufreq-nvmem.c
index d06b37822c3d..d88060330497 100644
--- a/drivers/cpufreq/qcom-cpufreq-nvmem.c
+++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c
@@ -458,6 +458,7 @@ static const struct of_device_id qcom_cpufreq_match_list[] __initconst = {
{ .compatible = "qcom,apq8096", .data = &match_data_kryo },
{ .compatible = "qcom,msm8996", .data = &match_data_kryo },
{ .compatible = "qcom,qcs404", .data = &match_data_qcs404 },
+ { .compatible = "qcom,msm8939", .data = &match_data_qcs404 },
{ .compatible = "qcom,ipq8064", .data = &match_data_krait },
{ .compatible = "qcom,apq8064", .data = &match_data_krait },
{ .compatible = "qcom,msm8974", .data = &match_data_krait },
--
2.17.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 2/3] dt-bindings: power: avs: CPR: Add corner adjust properties
2020-09-30 6:26 [PATCH 0/3] Support CPR on msm8939 Jun Nie
2020-09-30 6:26 ` [PATCH 1/3] cpufreq: qcom: Add support for msm8939 Jun Nie
@ 2020-09-30 6:26 ` Jun Nie
2020-09-30 6:26 ` [PATCH 3/3] power: avs: qcom-cpr: add support to msm8939 Jun Nie
2 siblings, 0 replies; 6+ messages in thread
From: Jun Nie @ 2020-09-30 6:26 UTC (permalink / raw)
To: nks, linux-pm, linux-arm-msm; +Cc: shawn.guo, Jun Nie
Add corner adjust properties for both corner and virtual corner.
Signed-off-by: Jun Nie <jun.nie@linaro.org>
---
.../bindings/power/avs/qcom,cpr.txt | 38 ++++++++++++++++++-
1 file changed, 37 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/power/avs/qcom,cpr.txt b/Documentation/devicetree/bindings/power/avs/qcom,cpr.txt
index ab0d5ebbad4e..4f4108730dc3 100644
--- a/Documentation/devicetree/bindings/power/avs/qcom,cpr.txt
+++ b/Documentation/devicetree/bindings/power/avs/qcom,cpr.txt
@@ -10,7 +10,9 @@ and meet silicon characteristic requirements.
- compatible:
Usage: required
Value type: <string>
- Definition: should be "qcom,qcs404-cpr", "qcom,cpr" for qcs404
+ enum:
+ - qcom,qcs404-cpr
+ - qcom,msm8939-cpr
- reg:
Usage: required
@@ -70,6 +72,40 @@ and meet silicon characteristic requirements.
"cpr_quotient2", "cpr_quotient3", "cpr_ring_osc1",
"cpr_ring_osc2", "cpr_ring_osc3", "cpr_fuse_revision"
for qcs404.
+ should be: "cpr_speedbin" "cpr_init_voltage1",
+ "cpr_init_voltage2", "cpr_init_voltage3", "cpr_quotient1",
+ "cpr_quotient2", "cpr_quotient3", "cpr_ring_osc1",
+ "cpr_ring_osc2", "cpr_ring_osc3", "cpr_fuse_revision"
+ "cpr_fuse_revision_high", "cpr_pvs_version" and
+ "cpr_pvs_version_high" for msm8939.
+
+
+- fuse-version-map:
+ Usage: optional
+ Value type: <prop-encoded-array>
+ Definition: fuse map table to search for entry index that for below
+ properties lookup table. Based on SoC's speedbin, pvs_version
+ and cpr revision.
+
+- init-voltage-adjustment:
+ Usage: optional
+ Value type: <prop-encoded-array>
+ Definition: Adjustment to initial voltage that read from fuse.
+
+- quotient-adjustment:
+ Usage: optional
+ Value type: <prop-encoded-array>
+ Definition: Adjustment to quotient that read from fuse.
+
+ - virtual-corner-quotient-adjustment:
+ Usage: optional
+ Value type: <prop-encoded-array>
+ Definition: Adjustment to virtual corners' quotient.
+
+ - voltage-floor-override:
+ Usage: optional
+ Value type: <prop-encoded-array>
+ Definition: Value to override virtual corners' floor voltage.
Example:
--
2.17.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 3/3] power: avs: qcom-cpr: add support to msm8939
2020-09-30 6:26 [PATCH 0/3] Support CPR on msm8939 Jun Nie
2020-09-30 6:26 ` [PATCH 1/3] cpufreq: qcom: Add support for msm8939 Jun Nie
2020-09-30 6:26 ` [PATCH 2/3] dt-bindings: power: avs: CPR: Add corner adjust properties Jun Nie
@ 2020-09-30 6:26 ` Jun Nie
2020-10-01 0:59 ` kernel test robot
2 siblings, 1 reply; 6+ messages in thread
From: Jun Nie @ 2020-09-30 6:26 UTC (permalink / raw)
To: nks, linux-pm, linux-arm-msm; +Cc: shawn.guo, Jun Nie
Memory power supply voltage should be higher than CPU voltage on
msm8939, so add the memory voltage control in cpr.
quot_offset_scale is missing on msm8939, no scaling is expected
in this case and do not try to read related fuse.
Corner adjustments support is added.
Signed-off-by: Jun Nie <jun.nie@linaro.org>
---
drivers/power/avs/qcom-cpr.c | 366 ++++++++++++++++++++++++++++++++---
1 file changed, 343 insertions(+), 23 deletions(-)
diff --git a/drivers/power/avs/qcom-cpr.c b/drivers/power/avs/qcom-cpr.c
index bd7c3e48b386..1d9989636fa5 100644
--- a/drivers/power/avs/qcom-cpr.c
+++ b/drivers/power/avs/qcom-cpr.c
@@ -122,7 +122,7 @@
#define CPR_FUSE_MIN_QUOT_DIFF 50
-#define FUSE_REVISION_UNKNOWN (-1)
+#define FUSE_MATCH_ANY (-1)
enum voltage_change_dir {
NO_CHANGE,
@@ -150,6 +150,7 @@ struct fuse_corner_data {
/* fuse quot_offset */
int quot_offset_scale;
int quot_offset_adjust;
+ u32 min_diff_quot;
};
struct cpr_fuses {
@@ -165,7 +166,6 @@ struct corner_data {
struct cpr_desc {
unsigned int num_fuse_corners;
- int min_diff_quot;
int *step_quot;
unsigned int timer_delay_us;
@@ -182,6 +182,7 @@ struct cpr_desc {
struct cpr_fuses cpr_fuses;
bool reduce_to_fuse_uV;
bool reduce_to_corner_uV;
+ unsigned int *mx_level; /* memory voltage level */
};
struct acc_desc {
@@ -207,6 +208,7 @@ struct fuse_corner {
const struct reg_sequence *accs;
int num_accs;
unsigned long max_freq;
+ unsigned int mx_level;
u8 ring_osc_idx;
};
@@ -247,6 +249,8 @@ struct cpr_drv {
const struct cpr_fuse *cpr_fuses;
struct dentry *debugfs;
+ u16 cpr_fuse_map_count;
+ u16 cpr_fuse_map_match;
};
static bool cpr_is_allowed(struct cpr_drv *drv)
@@ -411,6 +415,10 @@ static int cpr_pre_voltage(struct cpr_drv *drv,
{
struct fuse_corner *prev_fuse_corner = drv->corner->fuse_corner;
+ if (drv->desc->mx_level && dir == UP)
+ dev_pm_genpd_set_performance_state(drv->dev,
+ fuse_corner->mx_level);
+
if (drv->tcsr && dir == DOWN)
cpr_set_acc(drv->tcsr, prev_fuse_corner, fuse_corner);
@@ -426,6 +434,10 @@ static int cpr_post_voltage(struct cpr_drv *drv,
if (drv->tcsr && dir == UP)
cpr_set_acc(drv->tcsr, prev_fuse_corner, fuse_corner);
+ if (drv->desc->mx_level && dir == DOWN)
+ dev_pm_genpd_set_performance_state(drv->dev,
+ fuse_corner->mx_level);
+
return 0;
}
@@ -439,7 +451,7 @@ static int cpr_scale_voltage(struct cpr_drv *drv, struct corner *corner,
if (ret)
return ret;
- ret = regulator_set_voltage(drv->vdd_apc, new_uV, new_uV);
+ ret = regulator_set_voltage(drv->vdd_apc, new_uV, fuse_corner->max_uV);
if (ret) {
dev_err_ratelimited(drv->dev, "failed to set apc voltage %d\n",
new_uV);
@@ -884,6 +896,48 @@ static int cpr_read_fuse_uV(const struct cpr_desc *desc,
return DIV_ROUND_UP(uV, step_volt) * step_volt;
}
+static int cpr_corner_get_adjust(struct cpr_drv *drv, char *pname,
+ unsigned int num_corners, u16 array_num,
+ u32 **adjust, u32 *pp_valid)
+{
+ struct property *pp;
+ int i, len, index, size;
+ u32 *ptr;
+
+ *pp_valid = 0;
+ pp = of_find_property(drv->dev->of_node, pname, &len);
+ if (!pp)
+ return 0;
+
+ size = num_corners * array_num * sizeof(u32);
+ if (len != size) {
+ dev_err(drv->dev, "prop %s length %d is invalid, %d expected\n",
+ pname, len, size);
+ return -EINVAL;
+ }
+
+ /* use 1st vector if there is only one property array */
+ if (array_num == 1)
+ index = 0;
+ else
+ index = drv->cpr_fuse_map_match * num_corners;
+
+ *adjust = kzalloc(sizeof(u32) * num_corners,
+ GFP_KERNEL);
+ if (!*adjust)
+ return -ENOMEM;
+
+ ptr = *adjust;
+ for (i = 0; i < num_corners; i++, ptr++) {
+ of_property_read_u32_index(drv->dev->of_node,
+ pname, index + i, ptr);
+ dev_dbg(drv->dev, "use %s[%d]: %d\n", pname, i, *ptr);
+ }
+ *pp_valid = 1;
+
+ return 0;
+}
+
static int cpr_fuse_corner_init(struct cpr_drv *drv)
{
const struct cpr_desc *desc = drv->desc;
@@ -893,16 +947,35 @@ static int cpr_fuse_corner_init(struct cpr_drv *drv)
unsigned int step_volt;
struct fuse_corner_data *fdata;
struct fuse_corner *fuse, *end;
- int uV;
+ int uV, *mx_level;
const struct reg_sequence *accs;
int ret;
+ char *quot_pp_name = "quotient-adjustment";
+ char *int_volt_pp_name = "init-voltage-adjustment";
+ u32 *quot_adjust, quot_pp_valid;
+ u32 *init_volt_adjust, volt_pp_valid;
accs = acc_desc->settings;
+ mx_level = desc->mx_level;
step_volt = regulator_get_linear_step(drv->vdd_apc);
if (!step_volt)
return -EINVAL;
+ ret = cpr_corner_get_adjust(drv, quot_pp_name,
+ desc->num_fuse_corners,
+ drv->cpr_fuse_map_count,
+ "_adjust, "_pp_valid);
+ if (ret)
+ return ret;
+
+ ret = cpr_corner_get_adjust(drv, int_volt_pp_name,
+ desc->num_fuse_corners,
+ drv->cpr_fuse_map_count,
+ &init_volt_adjust, &volt_pp_valid);
+ if (ret)
+ goto free_quot_pp;
+
/* Populate fuse_corner members */
fuse = drv->fuse_corners;
end = &fuse[desc->num_fuse_corners - 1];
@@ -920,9 +993,13 @@ static int cpr_fuse_corner_init(struct cpr_drv *drv)
/* Populate uV */
uV = cpr_read_fuse_uV(desc, fdata, fuses->init_voltage,
step_volt, drv);
- if (uV < 0)
- return uV;
+ if (uV < 0) {
+ ret = uV;
+ goto free_quot_pp;
+ }
+ if (volt_pp_valid)
+ uV += init_volt_adjust[i];
fuse->min_uV = fdata->min_uV;
fuse->max_uV = fdata->max_uV;
fuse->uV = clamp(uV, fuse->min_uV, fuse->max_uV);
@@ -940,17 +1017,24 @@ static int cpr_fuse_corner_init(struct cpr_drv *drv)
/* Populate target quotient by scaling */
ret = cpr_read_efuse(drv->dev, fuses->quotient, &fuse->quot);
if (ret)
- return ret;
+ goto free_volt_adjust;
fuse->quot *= fdata->quot_scale;
fuse->quot += fdata->quot_offset;
- fuse->quot += fdata->quot_adjust;
+ if (quot_pp_valid)
+ fuse->quot += quot_adjust[i];
+ else
+ fuse->quot += fdata->quot_adjust;
fuse->step_quot = desc->step_quot[fuse->ring_osc_idx];
/* Populate acc settings */
fuse->accs = accs;
fuse->num_accs = acc_desc->num_regs_per_fuse;
accs += acc_desc->num_regs_per_fuse;
+
+ /* Populate memory power supply settings */
+ if (mx_level)
+ fuse->mx_level = mx_level[i];
}
/*
@@ -970,7 +1054,8 @@ static int cpr_fuse_corner_init(struct cpr_drv *drv)
dev_err(drv->dev,
"min uV: %d (fuse corner: %d) not supported by regulator\n",
fuse->min_uV, i);
- return -EINVAL;
+ ret = -EINVAL;
+ goto free_volt_adjust;
}
ret = regulator_is_supported_voltage(drv->vdd_apc,
@@ -980,8 +1065,10 @@ static int cpr_fuse_corner_init(struct cpr_drv *drv)
dev_err(drv->dev,
"max uV: %d (fuse corner: %d) not supported by regulator\n",
fuse->max_uV, i);
- return -EINVAL;
+ ret = -EINVAL;
+ goto free_quot_pp;
}
+ ret = 0;
dev_dbg(drv->dev,
"fuse corner %d: [%d %d %d] RO%hhu quot %d squot %d\n",
@@ -989,7 +1076,13 @@ static int cpr_fuse_corner_init(struct cpr_drv *drv)
fuse->ring_osc_idx, fuse->quot, fuse->step_quot);
}
- return 0;
+free_volt_adjust:
+ if (volt_pp_valid)
+ kfree(init_volt_adjust);
+free_quot_pp:
+ if (quot_pp_valid)
+ kfree(quot_adjust);
+ return ret;
}
static int cpr_calculate_scaling(const char *quot_offset,
@@ -1006,7 +1099,7 @@ static int cpr_calculate_scaling(const char *quot_offset,
fuse = corner->fuse_corner;
prev_fuse = fuse - 1;
- if (quot_offset) {
+ if (quot_offset && fdata->quot_offset_scale) {
ret = cpr_read_efuse(drv->dev, quot_offset, "_diff);
if (ret)
return ret;
@@ -1015,6 +1108,7 @@ static int cpr_calculate_scaling(const char *quot_offset,
quot_diff += fdata->quot_offset_adjust;
} else {
quot_diff = fuse->quot - prev_fuse->quot;
+ quot_diff = max(quot_diff, fdata->min_diff_quot);
}
freq_diff = fuse->max_freq - prev_fuse->max_freq;
@@ -1031,6 +1125,9 @@ static int cpr_interpolate(const struct corner *corner, int step_volt,
u64 temp, temp_limit;
const struct fuse_corner *fuse, *prev_fuse;
+ if (!fdata->max_volt_scale)
+ return corner->uV;
+
fuse = corner->fuse_corner;
prev_fuse = fuse - 1;
@@ -1085,6 +1182,7 @@ static unsigned long cpr_get_opp_hz_for_req(struct dev_pm_opp *ref,
struct device_node *desc_np;
struct device_node *child_np = NULL;
struct device_node *child_req_np = NULL;
+ int ret;
desc_np = dev_pm_opp_of_get_opp_desc_node(cpu_dev);
if (!desc_np)
@@ -1094,6 +1192,14 @@ static unsigned long cpr_get_opp_hz_for_req(struct dev_pm_opp *ref,
if (!ref_np)
goto out_ref;
+ /* freq in cpr_opp is only used to calculate virtual corner quot, may
+ * not identical with freq in cpu_opp.
+ */
+ ret = of_property_read_u64(ref_np, "opp-hz", &rate);
+ if (!ret)
+ goto hz_done;
+
+ /* Support dtb that does not fill freq to cpr_opp */
do {
of_node_put(child_req_np);
child_np = of_get_next_available_child(desc_np, child_np);
@@ -1105,6 +1211,7 @@ static unsigned long cpr_get_opp_hz_for_req(struct dev_pm_opp *ref,
of_node_put(child_req_np);
of_node_put(child_np);
+hz_done:
of_node_put(ref_np);
out_ref:
of_node_put(desc_np);
@@ -1116,7 +1223,7 @@ static int cpr_corner_init(struct cpr_drv *drv)
{
const struct cpr_desc *desc = drv->desc;
const struct cpr_fuse *fuses = drv->cpr_fuses;
- int i, level, scaling = 0;
+ int ret, i, level, scaling = 0;
unsigned int fnum, fc;
const char *quot_offset;
struct fuse_corner *fuse, *prev_fuse;
@@ -1128,6 +1235,10 @@ static int cpr_corner_init(struct cpr_drv *drv)
unsigned long freq;
int step_volt = regulator_get_linear_step(drv->vdd_apc);
struct dev_pm_opp *opp;
+ u32 *vc_min_uV, vc_min_uV_valid;
+ u32 *vc_quot_adjust, vc_quot_pp_valid;
+ char *quot_pp_name = "virtual-corner-quotient-adjustment";
+ char *min_uV_pp_name = "voltage-floor-override";
if (!step_volt)
return -EINVAL;
@@ -1141,14 +1252,30 @@ static int cpr_corner_init(struct cpr_drv *drv)
if (!cdata)
return -ENOMEM;
+ ret = cpr_corner_get_adjust(drv, quot_pp_name,
+ drv->num_corners, 1,
+ &vc_quot_adjust, &vc_quot_pp_valid);
+ if (ret)
+ goto free_cdata;
+
+ ret = cpr_corner_get_adjust(drv, min_uV_pp_name,
+ drv->num_corners, 1,
+ &vc_min_uV, &vc_min_uV_valid);
+ if (ret)
+ goto free_vc_quot_pp;
+
/*
* Store maximum frequency for each fuse corner based on the frequency
* plan
*/
for (level = 1; level <= drv->num_corners; level++) {
opp = dev_pm_opp_find_level_exact(&drv->pd.dev, level);
- if (IS_ERR(opp))
- return -EINVAL;
+ if (IS_ERR(opp)) {
+ ret = -EINVAL;
+ dev_err(drv->dev, "Fail to find cpu opp for level %d\n",
+ level);
+ goto free_vc_min_uV_pp;
+ }
fc = cpr_get_fuse_corner(opp);
if (!fc) {
dev_pm_opp_put(opp);
@@ -1158,8 +1285,10 @@ static int cpr_corner_init(struct cpr_drv *drv)
freq = cpr_get_opp_hz_for_req(opp, drv->attached_cpu_dev);
if (!freq) {
dev_pm_opp_put(opp);
- return -EINVAL;
+ ret = -EINVAL;
+ goto free_vc_min_uV_pp;
}
+
cdata[level - 1].fuse_corner = fnum;
cdata[level - 1].freq = freq;
@@ -1227,8 +1356,10 @@ static int cpr_corner_init(struct cpr_drv *drv)
if (prev_fuse && cdata[i - 1].freq == prev_fuse->max_freq) {
scaling = cpr_calculate_scaling(quot_offset, drv,
fdata, corner);
- if (scaling < 0)
- return scaling;
+ if (scaling < 0) {
+ ret = scaling;
+ goto free_vc_min_uV_pp;
+ }
apply_scaling = true;
} else if (corner->freq == fuse->max_freq) {
@@ -1243,9 +1374,15 @@ static int cpr_corner_init(struct cpr_drv *drv)
corner->uV = cpr_interpolate(corner, step_volt, fdata);
}
+ if (vc_quot_pp_valid)
+ corner->quot_adjust -= vc_quot_adjust[i];
+
+ if (vc_min_uV_valid)
+ corner->min_uV = max(fuse->min_uV, (int)vc_min_uV[i]);
+ else
+ corner->min_uV = fuse->min_uV;
corner->max_uV = fuse->max_uV;
- corner->min_uV = fuse->min_uV;
corner->uV = clamp(corner->uV, corner->min_uV, corner->max_uV);
corner->last_uV = corner->uV;
@@ -1260,7 +1397,15 @@ static int cpr_corner_init(struct cpr_drv *drv)
fuse->quot - corner->quot_adjust);
}
- return 0;
+free_vc_min_uV_pp:
+ if (vc_min_uV_valid)
+ kfree(vc_min_uV);
+free_vc_quot_pp:
+ if (vc_quot_pp_valid)
+ kfree(vc_quot_adjust);
+free_cdata:
+ devm_kfree(drv->dev, cdata);
+ return ret;
}
static const struct cpr_fuse *cpr_get_fuses(struct cpr_drv *drv)
@@ -1294,6 +1439,9 @@ static const struct cpr_fuse *cpr_get_fuses(struct cpr_drv *drv)
if (!fuses[i].quotient)
return ERR_PTR(-ENOMEM);
+ if (!desc->cpr_fuses.fuse_corner_data[i].quot_offset_scale)
+ continue;
+
snprintf(tbuf, 32, "cpr_quotient_offset%d", i + 1);
fuses[i].quotient_offset = devm_kstrdup(drv->dev, tbuf,
GFP_KERNEL);
@@ -1385,7 +1533,6 @@ static int cpr_find_initial_corner(struct cpr_drv *drv)
static const struct cpr_desc qcs404_cpr_desc = {
.num_fuse_corners = 3,
- .min_diff_quot = CPR_FUSE_MIN_QUOT_DIFF,
.step_quot = (int []){ 25, 25, 25, },
.timer_delay_us = 5000,
.timer_cons_up = 0,
@@ -1396,6 +1543,7 @@ static const struct cpr_desc qcs404_cpr_desc = {
.gcnt_us = 1,
.vdd_apc_step_up_limit = 1,
.vdd_apc_step_down_limit = 1,
+ .mx_level = NULL,
.cpr_fuses = {
.init_voltage_step = 8000,
.init_voltage_width = 6,
@@ -1412,6 +1560,7 @@ static const struct cpr_desc qcs404_cpr_desc = {
.quot_adjust = 0,
.quot_offset_scale = 5,
.quot_offset_adjust = 0,
+ .min_diff_quot = CPR_FUSE_MIN_QUOT_DIFF,
},
/* fuse corner 1 */
{
@@ -1425,6 +1574,7 @@ static const struct cpr_desc qcs404_cpr_desc = {
.quot_adjust = -20,
.quot_offset_scale = 5,
.quot_offset_adjust = 0,
+ .min_diff_quot = CPR_FUSE_MIN_QUOT_DIFF,
},
/* fuse corner 2 */
{
@@ -1438,6 +1588,7 @@ static const struct cpr_desc qcs404_cpr_desc = {
.quot_adjust = 0,
.quot_offset_scale = 5,
.quot_offset_adjust = 0,
+ .min_diff_quot = CPR_FUSE_MIN_QUOT_DIFF,
},
},
},
@@ -1464,6 +1615,86 @@ static const struct cpr_acc_desc qcs404_cpr_acc_desc = {
.acc_desc = &qcs404_acc_desc,
};
+static const struct cpr_desc msm8939_cpr_desc = {
+ .num_fuse_corners = 3,
+ .step_quot = (int []){ 13, 13, 13, },
+ .timer_delay_us = 5000,
+ .timer_cons_up = 0,
+ .timer_cons_down = 2,
+ .up_threshold = 0,
+ .down_threshold = 8,
+ .idle_clocks = 15,
+ .gcnt_us = 1,
+ .vdd_apc_step_up_limit = 1,
+ .vdd_apc_step_down_limit = 1,
+ .mx_level = (unsigned int[]){3, 4, 6},
+ .cpr_fuses = {
+ .init_voltage_step = 10000,
+ .init_voltage_width = 6,
+ .fuse_corner_data = (struct fuse_corner_data[]){
+ /* fuse corner 0 */
+ {
+ .ref_uV = 1050000,
+ .max_uV = 1050000,
+ .min_uV = 1050000,
+ .max_volt_scale = 0,
+ .max_quot_scale = 0,
+ .quot_offset = 0,
+ .quot_scale = 1,
+ .quot_adjust = 0,
+ .quot_offset_scale = 0,
+ .quot_offset_adjust = 0,
+ .min_diff_quot = 0,
+ },
+ /* fuse corner 1 */
+ {
+ .ref_uV = 1150000,
+ .max_uV = 1150000,
+ .min_uV = 1050000,
+ .max_volt_scale = 0,
+ .max_quot_scale = 0,
+ .quot_offset = 0,
+ .quot_scale = 1,
+ .quot_adjust = -41,
+ .quot_offset_scale = 0,
+ .quot_offset_adjust = 0,
+ .min_diff_quot = 0,
+ },
+ /* fuse corner 2 */
+ {
+ .ref_uV = 1350000,
+ .max_uV = 1350000,
+ .min_uV = 1137500,
+ .max_volt_scale = 0,
+ .max_quot_scale = 900,
+ .quot_offset = 0,
+ .quot_scale = 1,
+ .quot_adjust = 0,
+ .quot_offset_scale = 0,
+ .quot_offset_adjust = 0,
+ .min_diff_quot = 40,
+ },
+ },
+ },
+};
+
+static const struct acc_desc msm8939_acc_desc = {
+ .settings = (struct reg_sequence[]){
+ { 0xb130, 0},
+ { 0xb124, 0},
+ { 0xb130, 0},
+ { 0xb124, 0},
+ { 0xb130, 1},
+ { 0xb124, 0x3000},
+ },
+ .num_regs_per_fuse = 2,
+};
+
+static const struct cpr_acc_desc msm8939_cpr_acc_desc = {
+ .cpr_desc = &msm8939_cpr_desc,
+ .acc_desc = &msm8939_acc_desc,
+};
+
static unsigned int cpr_get_performance_state(struct generic_pm_domain *genpd,
struct dev_pm_opp *opp)
{
@@ -1540,6 +1771,7 @@ static int cpr_pd_attach_dev(struct generic_pm_domain *domain,
goto unlock;
}
drv->num_corners = ret;
+ dev_dbg(drv->dev, "has %d virtual corners.\n", ret);
if (drv->num_corners < 2) {
dev_err(drv->dev, "need at least 2 OPPs to use CPR\n");
@@ -1651,6 +1883,94 @@ static void cpr_debugfs_init(struct cpr_drv *drv)
drv, &cpr_debug_info_fops);
}
+/* Match with map table to find out entry index that to retrieve adjustment
+ * array from properties lookup table.
+ */
+#define FUSE_MATCH_TUPLE_SIZE 3
+static int cpr_fuse_match_tuple(struct device *dev, struct cpr_drv *drv)
+{
+ u32 cpr_rev, cpr_rev_high;
+ u32 pvs_ver, pvs_ver_high;
+ struct property *pp;
+ int i, tuple_size = FUSE_MATCH_TUPLE_SIZE;
+ int ret, len;
+ u32 *tmp, speedbin;
+
+ drv->cpr_fuse_map_match = FUSE_MATCH_ANY;
+ ret = cpr_read_efuse(dev, "cpr_fuse_revision", &cpr_rev);
+ if (ret)
+ return ret;
+
+ ret = cpr_read_efuse(dev, "cpr_fuse_revision_high", &cpr_rev_high);
+ if (!ret)
+ cpr_rev |= cpr_rev_high << 1;
+
+ dev_info(dev, "fuse revision %d\n", cpr_rev);
+
+ pp = of_find_property(dev->of_node, "fuse-version-map", &len);
+ if (!pp)
+ return 0;
+
+ ret = cpr_read_efuse(dev, "cpr_pvs_version", &pvs_ver);
+ if (ret)
+ return ret;
+
+ ret = cpr_read_efuse(dev, "cpr_pvs_version_high", &pvs_ver_high);
+ if (!ret)
+ pvs_ver |= pvs_ver_high << 1;
+
+ ret = cpr_read_efuse(dev, "cpr_speedbin", &speedbin);
+
+ dev_info(dev, "pvs_version %d, speed_bin %d\n", pvs_ver, speedbin);
+
+ drv->cpr_fuse_map_count = len / (sizeof(u32) * tuple_size);
+
+ if (len == 0 || len % (sizeof(u32) * tuple_size)) {
+ dev_err(dev, "fuse-version-map length=%d is invalid\n",
+ len);
+ return -EINVAL;
+ }
+
+ tmp = kzalloc(len, GFP_KERNEL);
+ if (!tmp)
+ return -ENOMEM;
+
+ ret = of_property_read_u32_array(dev->of_node, "fuse-version-map",
+ tmp, drv->cpr_fuse_map_count * tuple_size);
+ if (ret) {
+ dev_err(dev, "could not read fuse-version-map, rc=%d\n",
+ ret);
+ return ret;
+ }
+
+ /*
+ * fuse-version-map tuple format:
+ * <speed_bin, pvs_version, cpr_fuse_revision
+ */
+ for (i = 0; i < drv->cpr_fuse_map_count; i++) {
+ if (tmp[i * tuple_size] != speedbin
+ && tmp[i * tuple_size] != FUSE_MATCH_ANY)
+ continue;
+ if (tmp[i * tuple_size + 1] != pvs_ver
+ && tmp[i * tuple_size + 1] != FUSE_MATCH_ANY)
+ continue;
+ if (tmp[i * tuple_size + 2] != cpr_rev
+ && tmp[i * tuple_size + 2] != FUSE_MATCH_ANY)
+ continue;
+ drv->cpr_fuse_map_match = i;
+ break;
+ }
+ if (drv->cpr_fuse_map_match != FUSE_MATCH_ANY) {
+ dev_info(dev, "fuse map tuple match found: %d\n",
+ drv->cpr_fuse_map_match);
+ } else {
+ dev_warn(dev, "fuse map tuple match not found\n");
+ drv->cpr_fuse_map_match = 0;
+ drv->cpr_fuse_map_count = 1;
+ }
+ return 0;
+}
+
static int cpr_probe(struct platform_device *pdev)
{
struct resource *res;
@@ -1659,7 +1979,6 @@ static int cpr_probe(struct platform_device *pdev)
int irq, ret;
const struct cpr_acc_desc *data;
struct device_node *np;
- u32 cpr_rev = FUSE_REVISION_UNKNOWN;
data = of_device_get_match_data(dev);
if (!data || !data->cpr_desc || !data->acc_desc)
@@ -1707,7 +2026,7 @@ static int cpr_probe(struct platform_device *pdev)
* initialized after attaching to the power domain,
* since it depends on the CPU's OPP table.
*/
- ret = cpr_read_efuse(dev, "cpr_fuse_revision", &cpr_rev);
+ ret = cpr_fuse_match_tuple(dev, drv);
if (ret)
return ret;
@@ -1776,6 +2095,7 @@ static int cpr_remove(struct platform_device *pdev)
static const struct of_device_id cpr_match_table[] = {
{ .compatible = "qcom,qcs404-cpr", .data = &qcs404_cpr_acc_desc },
+ { .compatible = "qcom,msm8939-cpr", .data = &msm8939_cpr_acc_desc },
{ }
};
MODULE_DEVICE_TABLE(of, cpr_match_table);
--
2.17.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH 3/3] power: avs: qcom-cpr: add support to msm8939
2020-09-30 6:26 ` [PATCH 3/3] power: avs: qcom-cpr: add support to msm8939 Jun Nie
@ 2020-10-01 0:59 ` kernel test robot
2020-10-07 3:22 ` Jun Nie
0 siblings, 1 reply; 6+ messages in thread
From: kernel test robot @ 2020-10-01 0:59 UTC (permalink / raw)
To: Jun Nie, nks, linux-pm, linux-arm-msm; +Cc: kbuild-all, shawn.guo, Jun Nie
[-- Attachment #1: Type: text/plain, Size: 4063 bytes --]
Hi Jun,
I love your patch! Perhaps something to improve:
[auto build test WARNING on pm/linux-next]
[also build test WARNING on robh/for-next linus/master v5.9-rc7 next-20200930]
[cannot apply to battery/master]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Jun-Nie/Support-CPR-on-msm8939/20200930-142825
base: https://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git linux-next
config: x86_64-randconfig-m031-20200930 (attached as .config)
compiler: gcc-9 (Debian 9.3.0-15) 9.3.0
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
smatch warnings:
drivers/power/avs/qcom-cpr.c:1957 cpr_fuse_match_tuple() warn: always true condition '(drv->cpr_fuse_map_match != (-1)) => (0-u16max != (-1))'
vim +1957 drivers/power/avs/qcom-cpr.c
1879
1880 /* Match with map table to find out entry index that to retrieve adjustment
1881 * array from properties lookup table.
1882 */
1883 #define FUSE_MATCH_TUPLE_SIZE 3
1884 static int cpr_fuse_match_tuple(struct device *dev, struct cpr_drv *drv)
1885 {
1886 u32 cpr_rev, cpr_rev_high;
1887 u32 pvs_ver, pvs_ver_high;
1888 struct property *pp;
1889 int i, tuple_size = FUSE_MATCH_TUPLE_SIZE;
1890 int ret, len;
1891 u32 *tmp, speedbin;
1892
1893 drv->cpr_fuse_map_match = FUSE_MATCH_ANY;
1894 ret = cpr_read_efuse(dev, "cpr_fuse_revision", &cpr_rev);
1895 if (ret)
1896 return ret;
1897
1898 ret = cpr_read_efuse(dev, "cpr_fuse_revision_high", &cpr_rev_high);
1899 if (!ret)
1900 cpr_rev |= cpr_rev_high << 1;
1901
1902 dev_info(dev, "fuse revision %d\n", cpr_rev);
1903
1904 pp = of_find_property(dev->of_node, "fuse-version-map", &len);
1905 if (!pp)
1906 return 0;
1907
1908 ret = cpr_read_efuse(dev, "cpr_pvs_version", &pvs_ver);
1909 if (ret)
1910 return ret;
1911
1912 ret = cpr_read_efuse(dev, "cpr_pvs_version_high", &pvs_ver_high);
1913 if (!ret)
1914 pvs_ver |= pvs_ver_high << 1;
1915
1916 ret = cpr_read_efuse(dev, "cpr_speedbin", &speedbin);
1917
1918 dev_info(dev, "pvs_version %d, speed_bin %d\n", pvs_ver, speedbin);
1919
1920 drv->cpr_fuse_map_count = len / (sizeof(u32) * tuple_size);
1921
1922 if (len == 0 || len % (sizeof(u32) * tuple_size)) {
1923 dev_err(dev, "fuse-version-map length=%d is invalid\n",
1924 len);
1925 return -EINVAL;
1926 }
1927
1928 tmp = kzalloc(len, GFP_KERNEL);
1929 if (!tmp)
1930 return -ENOMEM;
1931
1932 ret = of_property_read_u32_array(dev->of_node, "fuse-version-map",
1933 tmp, drv->cpr_fuse_map_count * tuple_size);
1934 if (ret) {
1935 dev_err(dev, "could not read fuse-version-map, rc=%d\n",
1936 ret);
1937 return ret;
1938 }
1939
1940 /*
1941 * fuse-version-map tuple format:
1942 * <speed_bin, pvs_version, cpr_fuse_revision
1943 */
1944 for (i = 0; i < drv->cpr_fuse_map_count; i++) {
1945 if (tmp[i * tuple_size] != speedbin
1946 && tmp[i * tuple_size] != FUSE_MATCH_ANY)
1947 continue;
1948 if (tmp[i * tuple_size + 1] != pvs_ver
1949 && tmp[i * tuple_size + 1] != FUSE_MATCH_ANY)
1950 continue;
1951 if (tmp[i * tuple_size + 2] != cpr_rev
1952 && tmp[i * tuple_size + 2] != FUSE_MATCH_ANY)
1953 continue;
1954 drv->cpr_fuse_map_match = i;
1955 break;
1956 }
> 1957 if (drv->cpr_fuse_map_match != FUSE_MATCH_ANY) {
1958 dev_info(dev, "fuse map tuple match found: %d\n",
1959 drv->cpr_fuse_map_match);
1960 } else {
1961 dev_warn(dev, "fuse map tuple match not found\n");
1962 drv->cpr_fuse_map_match = 0;
1963 drv->cpr_fuse_map_count = 1;
1964 }
1965 return 0;
1966 }
1967
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 33293 bytes --]
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 3/3] power: avs: qcom-cpr: add support to msm8939
2020-10-01 0:59 ` kernel test robot
@ 2020-10-07 3:22 ` Jun Nie
0 siblings, 0 replies; 6+ messages in thread
From: Jun Nie @ 2020-10-07 3:22 UTC (permalink / raw)
To: kernel test robot
Cc: Niklas Cassel, linux-pm, linux-arm-msm, kbuild-all, Shawn Guo
kernel test robot <lkp@intel.com> 于2020年10月1日周四 上午9:00写道:
>
> Hi Jun,
>
> I love your patch! Perhaps something to improve:
>
> [auto build test WARNING on pm/linux-next]
> [also build test WARNING on robh/for-next linus/master v5.9-rc7 next-20200930]
> [cannot apply to battery/master]
> [If your patch is applied to the wrong git tree, kindly drop us a note.
> And when submitting patch, we suggest to use '--base' as documented in
> https://git-scm.com/docs/git-format-patch]
>
> url: https://github.com/0day-ci/linux/commits/Jun-Nie/Support-CPR-on-msm8939/20200930-142825
> base: https://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git linux-next
> config: x86_64-randconfig-m031-20200930 (attached as .config)
> compiler: gcc-9 (Debian 9.3.0-15) 9.3.0
>
> If you fix the issue, kindly add following tag as appropriate
> Reported-by: kernel test robot <lkp@intel.com>
>
> smatch warnings:
> drivers/power/avs/qcom-cpr.c:1957 cpr_fuse_match_tuple() warn: always true condition '(drv->cpr_fuse_map_match != (-1)) => (0-u16max != (-1))'
>
> vim +1957 drivers/power/avs/qcom-cpr.c
>
Rob,
Thanks for your precious comments! I will fix these issue soon after holiday.
Regards,
Jun
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2020-10-07 3:22 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-09-30 6:26 [PATCH 0/3] Support CPR on msm8939 Jun Nie
2020-09-30 6:26 ` [PATCH 1/3] cpufreq: qcom: Add support for msm8939 Jun Nie
2020-09-30 6:26 ` [PATCH 2/3] dt-bindings: power: avs: CPR: Add corner adjust properties Jun Nie
2020-09-30 6:26 ` [PATCH 3/3] power: avs: qcom-cpr: add support to msm8939 Jun Nie
2020-10-01 0:59 ` kernel test robot
2020-10-07 3:22 ` Jun Nie
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).