diff options
author | David Collins <collinsd@codeaurora.org> | 2016-02-22 16:07:41 -0800 |
---|---|---|
committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 21:23:14 -0700 |
commit | d67ab7607c4c3f7eb04a599fc9098d70323b1a2d (patch) | |
tree | 8622ba4f69fb2c62b2cd9e807891c3b6e3b20609 | |
parent | 0514464b8eae8636f6c775cf975011e029ac3c09 (diff) |
regulator: cpr3-hmss-regulator: add support for CBF voltage offset fuses
Add support for the CBF open-loop/closed-loop voltage offset
fuses found on MSM8996-Pro chips. These fuses define independent
open-loop voltages and closed-loop target quotients for the power
cluster and CBF clock which share CPR hardware thread 0. This
independent fusing ensures optimal VDD supply voltage for all
power cluster, performance cluster, CBF corner combinations.
Change-Id: I2e309d683f853f8bd9fd4eb6d12b05c32c7aaf26
CRs-Fixed: 980901
Signed-off-by: David Collins <collinsd@codeaurora.org>
-rw-r--r-- | Documentation/devicetree/bindings/regulator/cpr3-hmss-regulator.txt | 8 | ||||
-rw-r--r-- | drivers/regulator/cpr3-hmss-regulator.c | 95 |
2 files changed, 103 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/regulator/cpr3-hmss-regulator.txt b/Documentation/devicetree/bindings/regulator/cpr3-hmss-regulator.txt index 47480abf5541..45a27d14c249 100644 --- a/Documentation/devicetree/bindings/regulator/cpr3-hmss-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/cpr3-hmss-regulator.txt @@ -209,6 +209,13 @@ HMSS specific properties: given regulator type. For HMSS the maximum supported value is 2. +- qcom,is-cbf-regulator + Usage: optional + Value type: <empty> + Definition: Boolean flag which indicates that the CPR3 regulator + corresponds to the CBF clock domain. Special fuses are + defined for the CBF CPR3 regulator on MSM8996-Pro chips. + - qcom,ldo-min-headroom-voltage Usage: required if vdd-threadN-ldo-supply is specified for the CPR3 thread containing this CPR3 regulator and this CPR3 @@ -418,6 +425,7 @@ apcc_cpr: cpr3-ctrl@99e8000 { regulator-name = "apc0_cbf_corner"; regulator-min-microvolt = <1>; regulator-max-microvolt = <10>; + qcom,is-cbf-regulator; qcom,cpr-pd-bypass-mask = <0x18>; qcom,cpr-fuse-corners = <5>; diff --git a/drivers/regulator/cpr3-hmss-regulator.c b/drivers/regulator/cpr3-hmss-regulator.c index 30c4115b4a9d..3fa594a9c517 100644 --- a/drivers/regulator/cpr3-hmss-regulator.c +++ b/drivers/regulator/cpr3-hmss-regulator.c @@ -51,6 +51,8 @@ * interpolation * @speed_bin: Application processor speed bin fuse parameter value for * the given chip + * @cbf_voltage_offset: Voltage margin offset for the CBF regulator used on + * MSM8996-Pro chips. * @cpr_fusing_rev: CPR fusing revision fuse parameter value * @redundant_fusing: Redundant fusing select fuse parameter value * @limitation: CPR limitation select fuse parameter value @@ -71,6 +73,7 @@ struct cpr3_msm8996_hmss_fuses { u64 init_voltage[MSM8996_HMSS_FUSE_CORNERS]; u64 target_quot[MSM8996_HMSS_FUSE_CORNERS]; u64 quot_offset[MSM8996_HMSS_FUSE_CORNERS]; + u64 cbf_voltage_offset[MSM8996_HMSS_FUSE_CORNERS]; u64 speed_bin; u64 cpr_fusing_rev; u64 redundant_fusing; @@ -324,6 +327,15 @@ msm8996_hmss_aging_init_quot_diff_param[] = { {}, }; +static const struct cpr3_fuse_param +msm8996pro_hmss_voltage_offset_param[MSM8996_HMSS_FUSE_CORNERS][4] = { + {{68, 50, 52}, {41, 63, 63}, {} }, + {{62, 30, 31}, {62, 63, 63}, {66, 45, 45}, {} }, + {{61, 35, 36}, {61, 62, 63}, {} }, + {{61, 26, 26}, {61, 32, 34}, {} }, + {{61, 22, 25}, {} }, +}; + #define MSM8996PRO_SOC_ID 4 /* @@ -391,6 +403,8 @@ static const int msm8996_vdd_mx_fuse_ret_volt[] = { #define MSM8996_HMSS_FUSE_STEP_VOLT 10000 #define MSM8996_HMSS_VOLTAGE_FUSE_SIZE 6 +#define MSM8996PRO_HMSS_CBF_FUSE_STEP_VOLT 10000 +#define MSM8996PRO_HMSS_CBF_VOLTAGE_FUSE_SIZE 4 #define MSM8996_HMSS_QUOT_OFFSET_SCALE 5 #define MSM8996_HMSS_AGING_INIT_QUOT_DIFF_SCALE 2 #define MSM8996_HMSS_AGING_INIT_QUOT_DIFF_SIZE 6 @@ -407,6 +421,23 @@ static const int msm8996_vdd_mx_fuse_ret_volt[] = { #define MSM8996_HMSS_AGING_BYPASS_MASK0 (GENMASK(7, 0) & ~BIT(3)) /** + * cpr3_msm8996_hmss_use_voltage_offset_fuse() - return if this part utilizes + * voltage offset fuses or not + * @vreg: Pointer to the CPR3 regulator + * + * Return: true if this part utilizes voltage offset fuses, else false + */ +static inline bool cpr3_msm8996_hmss_use_voltage_offset_fuse( + struct cpr3_regulator *vreg) +{ + struct cpr3_msm8996_hmss_fuses *fuse = vreg->platform_fuses; + + return vreg->thread->ctrl->soc_revision == MSM8996PRO_SOC_ID + && fuse->cpr_fusing_rev >= 2 + && of_property_read_bool(vreg->of_node, "qcom,is-cbf-regulator"); +} + +/** * cpr3_msm8996_hmss_read_fuse_data() - load HMSS specific fuse parameter values * @vreg: Pointer to the CPR3 regulator * @@ -570,6 +601,49 @@ static int cpr3_msm8996_hmss_read_fuse_data(struct cpr3_regulator *vreg) vreg->fuse_corner_count = MSM8996_HMSS_FUSE_CORNERS; vreg->platform_fuses = fuse; + if (cpr3_msm8996_hmss_use_voltage_offset_fuse(vreg)) { + for (i = 0; i < MSM8996_HMSS_FUSE_CORNERS; i++) { + rc = cpr3_read_fuse_param(base, + msm8996pro_hmss_voltage_offset_param[i], + &fuse->cbf_voltage_offset[i]); + if (rc) { + cpr3_err(vreg, "Unable to read fuse-corner %d CBF voltage offset fuse, rc=%d\n", + i, rc); + return rc; + } + } + } + + return 0; +} + +/** + * cpr3_hmss_apply_fused_voltage_offset() - adjust the fused voltages for each + * fuse corner according to voltage offset fuse values + * @vreg: Pointer to the CPR3 regulator + * @fuse_volt: Pointer to an array of the fused voltage values; must + * have length equal to vreg->fuse_corner_count + * + * Voltage values in fuse_volt are modified in place. + * + * Return: 0 on success, errno on failure + */ +static int cpr3_hmss_apply_fused_voltage_offset(struct cpr3_regulator *vreg, + int *fuse_volt) +{ + struct cpr3_msm8996_hmss_fuses *fuse = vreg->platform_fuses; + int i; + + if (!cpr3_msm8996_hmss_use_voltage_offset_fuse(vreg)) + return 0; + + for (i = 0; i < vreg->fuse_corner_count; i++) + fuse_volt[i] += cpr3_convert_open_loop_voltage_fuse( + 0, + MSM8996PRO_HMSS_CBF_FUSE_STEP_VOLT, + fuse->cbf_voltage_offset[i], + MSM8996PRO_HMSS_CBF_VOLTAGE_FUSE_SIZE); + return 0; } @@ -654,6 +728,20 @@ static int cpr3_msm8996_hmss_calculate_open_loop_voltages( fuse_volt[i]); } + if (cpr3_msm8996_hmss_use_voltage_offset_fuse(vreg)) { + rc = cpr3_hmss_apply_fused_voltage_offset(vreg, fuse_volt); + if (rc) { + cpr3_err(vreg, "could not apply CBF voltage offsets, rc=%d\n", + rc); + goto done; + } + + for (i = 0; i < vreg->fuse_corner_count; i++) + cpr3_info(vreg, "fused %6s: CBF offset open-loop=%7d uV\n", + cpr3_msm8996_hmss_fuse_corner_name[i], + fuse_volt[i]); + } + rc = cpr3_adjust_fused_open_loop_voltages(vreg, fuse_volt); if (rc) { cpr3_err(vreg, "fused open-loop voltage adjustment failed, rc=%d\n", @@ -865,6 +953,13 @@ static int cpr3_msm8996_hmss_calculate_target_quotients( goto done; } + rc = cpr3_hmss_apply_fused_voltage_offset(vreg, volt_adjust_fuse); + if (rc) { + cpr3_err(vreg, "could not apply CBF voltage offsets, rc=%d\n", + rc); + goto done; + } + if (!allow_interpolation) { /* Use fused target quotients for lower frequencies. */ return cpr3_msm8996_hmss_set_no_interpolation_quotients(vreg, |