Loading Documentation/devicetree/bindings/regulator/cpr3-hmss-regulator.txt +28 −0 Original line number Original line Diff line number Diff line Loading @@ -250,6 +250,8 @@ apcc_cpr: cpr3-ctrl@99e8000 { qcom,cpr-hw-closed-loop; qcom,cpr-hw-closed-loop; qcom,cpr-clock-throttling = <0x20>; qcom,cpr-clock-throttling = <0x20>; qcom,cpr-aging-ref-voltage = <905000>; thread@0 { thread@0 { qcom,cpr-thread-id = <0>; qcom,cpr-thread-id = <0>; qcom,cpr-consecutive-up = <0>; qcom,cpr-consecutive-up = <0>; Loading Loading @@ -311,6 +313,15 @@ apcc_cpr: cpr3-ctrl@99e8000 { qcom,allow-voltage-interpolation; qcom,allow-voltage-interpolation; qcom,allow-quotient-interpolation; qcom,allow-quotient-interpolation; qcom,cpr-scaled-open-loop-voltage-as-ceiling; qcom,cpr-scaled-open-loop-voltage-as-ceiling; qcom,cpr-aging-max-voltage-adjustment = <25000>; qcom,cpr-aging-ref-corner = <11>; qcom,cpr-aging-ro-scaling-factor = <3200>; qcom,cpr-aging-derate = <1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000>; qcom,allow-aging-voltage-adjustment = <1>; }; }; apc0_cbf_vreg: regulator-cbf { apc0_cbf_vreg: regulator-cbf { Loading Loading @@ -358,6 +369,14 @@ apcc_cpr: cpr3-ctrl@99e8000 { qcom,allow-voltage-interpolation; qcom,allow-voltage-interpolation; qcom,allow-quotient-interpolation; qcom,allow-quotient-interpolation; qcom,cpr-scaled-open-loop-voltage-as-ceiling; qcom,cpr-scaled-open-loop-voltage-as-ceiling; qcom,cpr-aging-max-voltage-adjustment = <25000>; qcom,cpr-aging-ref-corner = <9>; qcom,cpr-aging-ro-scaling-factor = <3200>; qcom,cpr-aging-derate = <1000 1000 1000 1000 1000 1000 1000 1000 1000 1000>; qcom,allow-aging-voltage-adjustment = <1>; }; }; }; }; Loading Loading @@ -422,6 +441,15 @@ apcc_cpr: cpr3-ctrl@99e8000 { qcom,allow-voltage-interpolation; qcom,allow-voltage-interpolation; qcom,allow-quotient-interpolation; qcom,allow-quotient-interpolation; qcom,cpr-scaled-open-loop-voltage-as-ceiling; qcom,cpr-scaled-open-loop-voltage-as-ceiling; qcom,cpr-aging-max-voltage-adjustment = <25000>; qcom,cpr-aging-ref-corner = <11>; qcom,cpr-aging-ro-scaling-factor = <3200>; qcom,cpr-aging-derate = <1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000>; qcom,allow-aging-voltage-adjustment = <1>; }; }; }; }; }; }; Documentation/devicetree/bindings/regulator/cpr3-mmss-regulator.txt +9 −0 Original line number Original line Diff line number Diff line Loading @@ -140,6 +140,8 @@ gfx_cpr: cpr3-ctrl@838000 { qcom,cpr-enable; qcom,cpr-enable; qcom,cpr-aging-ref-voltage = <905000>; thread@0 { thread@0 { qcom,cpr-thread-id = <0>; qcom,cpr-thread-id = <0>; qcom,cpr-consecutive-up = <0>; qcom,cpr-consecutive-up = <0>; Loading Loading @@ -194,6 +196,13 @@ gfx_cpr: cpr3-ctrl@838000 { qcom,allow-voltage-interpolation; qcom,allow-voltage-interpolation; qcom,cpr-scaled-open-loop-voltage-as-ceiling; qcom,cpr-scaled-open-loop-voltage-as-ceiling; qcom,cpr-aging-max-voltage-adjustment = <25000>; qcom,cpr-aging-ref-corner = <3>; qcom,cpr-aging-ro-scaling-factor = <2950>; qcom,cpr-aging-derate = <1000 1000 1000 1000>; qcom,allow-aging-voltage-adjustment = <1>; }; }; }; }; }; }; Documentation/devicetree/bindings/regulator/cpr3-regulator.txt +86 −2 Original line number Original line Diff line number Diff line Loading @@ -159,6 +159,14 @@ Platform independent properties: enabled) as opposed to open-loop mode (i.e. CPR sensing loop enabled) as opposed to open-loop mode (i.e. CPR sensing loop disabled) by default. disabled) by default. - qcom,cpr-aging-ref-voltage Usage: required if qcom,allow-aging-voltage-adjustment is specified for any third level nodes Value type: <u32> Definition: Specifies the CPR aging reference voltage in microvolts. This is the voltage that vdd-supply must be set to when performing an aging measurement. ================================================= ================================================= Second Level Nodes - CPR Threads for a Controller Second Level Nodes - CPR Threads for a Controller ================================================= ================================================= Loading Loading @@ -460,8 +468,9 @@ Platform independent properties: order to utilize this property. order to utilize this property. - qcom,cpr-ro-scaling-factor - qcom,cpr-ro-scaling-factor Usage: required if qcom,cpr-closed-loop-voltage-fuse-adjustment Usage: required if qcom,cpr-closed-loop-voltage-fuse-adjustment, or qcom,cpr-closed-loop-voltage-adjustment is specified qcom,cpr-closed-loop-voltage-adjustment, or qcom,allow-aging-voltage-adjustment is specified Value type: <prop-encoded-array> Value type: <prop-encoded-array> Definition: A grouping of integer tuple lists. Each tuple defines the Definition: A grouping of integer tuple lists. Each tuple defines the CPR ring oscillator (RO) scaling factor with units of QUOT/V CPR ring oscillator (RO) scaling factor with units of QUOT/V Loading @@ -488,6 +497,81 @@ Platform independent properties: qcom,cpr-closed-loop-voltage-adjustment by the relevant RO qcom,cpr-closed-loop-voltage-adjustment by the relevant RO scaling factor in this property. scaling factor in this property. - qcom,allow-aging-voltage-adjustment Usage: optional Value type: <prop-encoded-array> Definition: A list of integers which specifies if CPR aging adjustment should be performed for each fuse combination. Supported per-combo element values: 0 - do not perform CPR aging adjustment 1 - perform CPR aging adjustment The list must contain either qcom,cpr-fuse-combos number of elements in which case the elements are applied to fuse combinations 1-to-1 or the list must contain exactly 1 element which is used regardless of the fuse combination found on a given chip. - qcom,cpr-aging-max-voltage-adjustment Usage: required if qcom,allow-aging-voltage-adjustment is specified Value type: <prop-encoded-array> Definition: A list of integers which defines the maximum CPR aging voltage margin adjustment in microvolts that may be added for each fuse combination. If this property is specified and the adjustment specified is greater than 0, then aging adjustments are required for this regulator. The list must contain either qcom,cpr-fuse-combos number of elements in which case the max adjustments are applied to fuse combinations 1-to-1 or the list must contain exactly 1 element which is used regardless of the fuse combination found on a given chip. - qcom,cpr-aging-ref-corner Usage: required if qcom,allow-aging-voltage-adjustment is specified Value type: <prop-encoded-array> Definition: A list of integers which defines the CPR reference corner for this regulator to use during aging measurements for each fuse combination. The list must contain either qcom,cpr-fuse-combos number of elements in which case the max adjustments are applied to fuse combinations 1-to-1 or the list must contain exactly 1 element which is used regardless of the fuse combination found on a given chip. - qcom,cpr-aging-ro-scaling-factor Usage: required if qcom,allow-aging-voltage-adjustment is specified Value type: <prop-encoded-array> Definition: A list of integers which defines the CPR aging ring oscillator (RO) scaling factor with units of QUOT/V to use during aging measurements for each fuse combination. The list must contain either qcom,cpr-fuse-combos number of elements in which case the scaling factors are applied to fuse combinations 1-to-1 or the list must contain exactly 1 element which is used regardless of the fuse combination found on a given chip. - qcom,cpr-aging-derate Usage: optional, though only meaningful if qcom,allow-aging-voltage-adjustment is specified Value type: <prop-encoded-array> Definition: A list of integer tuples which each define the CPR aging derating scaling factor to apply to the closed-loop voltage margin adjustment for each corner. The individual scaling factors have units of uV/mV and are ordered from lowest to highest corner per tuple. For example, a value of 900 specifies that the voltage adjustment for the corner should be 90% (900/1000) of that for the reference corner. The list and tuples must meet the same size requirements as those specified for qcom,cpr-voltage-ceiling above. If this property is not specified, then it is assumed that no corners require derating (i.e. the scaling factor would be 1000). All properties specified within the core regulator framework can also be used in All properties specified within the core regulator framework can also be used in third level nodes. These bindings can be found in: third level nodes. These bindings can be found in: Documentation/devicetree/bindings/regulator/regulator.txt. Documentation/devicetree/bindings/regulator/regulator.txt. Loading drivers/regulator/cpr3-hmss-regulator.c +102 −1 Original line number Original line Diff line number Diff line Loading @@ -58,6 +58,8 @@ * limitations found on a given chip * limitations found on a given chip * @vdd_mx_ret_fuse: Defines the logic retention voltage of VDD_MX * @vdd_mx_ret_fuse: Defines the logic retention voltage of VDD_MX * @vdd_apcc_ret_fuse: Defines the logic retention voltage of VDD_APCC * @vdd_apcc_ret_fuse: Defines the logic retention voltage of VDD_APCC * @aging_init_quot_diff: Initial quotient difference between CPR aging * min and max sensors measured at time of manufacturing * * * This struct holds the values for all of the fuses read from memory. The * This struct holds the values for all of the fuses read from memory. The * values for ro_sel, init_voltage, target_quot, and quot_offset come from * values for ro_sel, init_voltage, target_quot, and quot_offset come from Loading @@ -76,6 +78,7 @@ struct cpr3_msm8996_hmss_fuses { u64 partial_binning; u64 partial_binning; u64 vdd_mx_ret_fuse; u64 vdd_mx_ret_fuse; u64 vdd_apcc_ret_fuse; u64 vdd_apcc_ret_fuse; u64 aging_init_quot_diff; }; }; /** /** Loading Loading @@ -337,6 +340,12 @@ static const struct cpr3_fuse_param msm8996_cpr_partial_binning_param[] = { {}, {}, }; }; static const struct cpr3_fuse_param msm8996_hmss_aging_init_quot_diff_param[] = { {68, 14, 19}, {}, }; /* /* * Some initial msm8996 parts cannot be used in a meaningful way by software. * Some initial msm8996 parts cannot be used in a meaningful way by software. * Other parts can only be used when operating with CPR disabled (i.e. at the * Other parts can only be used when operating with CPR disabled (i.e. at the Loading Loading @@ -390,6 +399,8 @@ static const int msm8996_vdd_mx_fuse_ret_volt[] = { #define MSM8996_HMSS_FUSE_STEP_VOLT 10000 #define MSM8996_HMSS_FUSE_STEP_VOLT 10000 #define MSM8996_HMSS_VOLTAGE_FUSE_SIZE 6 #define MSM8996_HMSS_VOLTAGE_FUSE_SIZE 6 #define MSM8996_HMSS_QUOT_OFFSET_SCALE 5 #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 #define MSM8996_HMSS_CPR_SENSOR_COUNT 25 #define MSM8996_HMSS_CPR_SENSOR_COUNT 25 #define MSM8996_HMSS_THREAD0_SENSOR_MIN 0 #define MSM8996_HMSS_THREAD0_SENSOR_MIN 0 Loading @@ -399,6 +410,9 @@ static const int msm8996_vdd_mx_fuse_ret_volt[] = { #define MSM8996_HMSS_CPR_CLOCK_RATE 19200000 #define MSM8996_HMSS_CPR_CLOCK_RATE 19200000 #define MSM8996_HMSS_AGING_SENSOR_ID 11 #define MSM8996_HMSS_AGING_BYPASS_MASK0 (GENMASK(7, 0) & ~BIT(3)) /** /** * cpr3_msm8996_hmss_read_fuse_data() - load HMSS specific fuse parameter values * cpr3_msm8996_hmss_read_fuse_data() - load HMSS specific fuse parameter values * @vreg: Pointer to the CPR3 regulator * @vreg: Pointer to the CPR3 regulator Loading Loading @@ -495,6 +509,14 @@ static int cpr3_msm8996_hmss_read_fuse_data(struct cpr3_regulator *vreg) cpr3_info(vreg, "Retention voltage fuses: VDD_MX = %llu, VDD_APCC = %llu\n", cpr3_info(vreg, "Retention voltage fuses: VDD_MX = %llu, VDD_APCC = %llu\n", fuse->vdd_mx_ret_fuse, fuse->vdd_apcc_ret_fuse); fuse->vdd_mx_ret_fuse, fuse->vdd_apcc_ret_fuse); rc = cpr3_read_fuse_param(base, msm8996_hmss_aging_init_quot_diff_param, &fuse->aging_init_quot_diff); if (rc) { cpr3_err(vreg, "Unable to read aging initial quotient difference fuse, rc=%d\n", rc); return rc; } id = vreg->thread->thread_id; id = vreg->thread->thread_id; for (i = 0; i < MSM8996_HMSS_FUSE_CORNERS; i++) { for (i = 0; i < MSM8996_HMSS_FUSE_CORNERS; i++) { Loading Loading @@ -845,7 +867,8 @@ static int cpr3_hmss_parse_closed_loop_voltage_adjustments( if (!of_find_property(vreg->of_node, if (!of_find_property(vreg->of_node, "qcom,cpr-closed-loop-voltage-adjustment", NULL) "qcom,cpr-closed-loop-voltage-adjustment", NULL) && !of_find_property(vreg->of_node, && !of_find_property(vreg->of_node, "qcom,cpr-closed-loop-voltage-fuse-adjustment", NULL)) { "qcom,cpr-closed-loop-voltage-fuse-adjustment", NULL) && !vreg->aging_allowed) { /* No adjustment required. */ /* No adjustment required. */ return 0; return 0; } else if (!of_find_property(vreg->of_node, } else if (!of_find_property(vreg->of_node, Loading Loading @@ -874,6 +897,11 @@ static int cpr3_hmss_parse_closed_loop_voltage_adjustments( for (i = 0; i < vreg->fuse_corner_count; i++) for (i = 0; i < vreg->fuse_corner_count; i++) ro_scale[i] = ro_all_scale[i * CPR3_RO_COUNT + fuse->ro_sel[i]]; ro_scale[i] = ro_all_scale[i * CPR3_RO_COUNT + fuse->ro_sel[i]]; for (i = 0; i < vreg->corner_count; i++) memcpy(vreg->corner[i].ro_scale, &ro_all_scale[vreg->corner[i].cpr_fuse_corner * CPR3_RO_COUNT], sizeof(*ro_all_scale) * CPR3_RO_COUNT); if (of_find_property(vreg->of_node, if (of_find_property(vreg->of_node, "qcom,cpr-closed-loop-voltage-fuse-adjustment", NULL)) { "qcom,cpr-closed-loop-voltage-fuse-adjustment", NULL)) { rc = cpr3_parse_array_property(vreg, rc = cpr3_parse_array_property(vreg, Loading Loading @@ -1518,6 +1546,72 @@ static int cpr3_hmss_apm_init(struct cpr3_controller *ctrl) return 0; return 0; } } /** * cpr3_hmss_init_aging() - perform HMSS CPR3 controller specific * aging initializations * @ctrl: Pointer to the CPR3 controller * * Return: 0 on success, errno on failure */ static int cpr3_hmss_init_aging(struct cpr3_controller *ctrl) { struct cpr3_msm8996_hmss_fuses *fuse = NULL; struct cpr3_regulator *vreg; u32 aging_ro_scale; int i, j, rc; for (i = 0; i < ctrl->thread_count; i++) { for (j = 0; j < ctrl->thread[i].vreg_count; j++) { if (ctrl->thread[i].vreg[j].aging_allowed) { ctrl->aging_required = true; vreg = &ctrl->thread[i].vreg[j]; fuse = vreg->platform_fuses; break; } } } if (!ctrl->aging_required || !fuse) return 0; rc = cpr3_parse_array_property(vreg, "qcom,cpr-aging-ro-scaling-factor", 1, vreg->fuse_combos_supported, vreg->fuse_combo, &aging_ro_scale); if (rc) return rc; if (aging_ro_scale == 0) { cpr3_err(ctrl, "aging RO scaling factor is invalid: %u\n", aging_ro_scale); return -EINVAL; } ctrl->aging_vdd_mode = REGULATOR_MODE_NORMAL; ctrl->aging_complete_vdd_mode = REGULATOR_MODE_IDLE; ctrl->aging_sensor_count = 1; ctrl->aging_sensor = kzalloc(sizeof(*ctrl->aging_sensor), GFP_KERNEL); if (!ctrl->aging_sensor) return -ENOMEM; ctrl->aging_sensor->sensor_id = MSM8996_HMSS_AGING_SENSOR_ID; ctrl->aging_sensor->bypass_mask[0] = MSM8996_HMSS_AGING_BYPASS_MASK0; ctrl->aging_sensor->ro_scale = aging_ro_scale; ctrl->aging_sensor->init_quot_diff = cpr3_convert_open_loop_voltage_fuse(0, MSM8996_HMSS_AGING_INIT_QUOT_DIFF_SCALE, fuse->aging_init_quot_diff, MSM8996_HMSS_AGING_INIT_QUOT_DIFF_SIZE); cpr3_debug(ctrl, "sensor %u aging init quotient diff = %d, aging RO scale = %u QUOT/V\n", ctrl->aging_sensor->sensor_id, ctrl->aging_sensor->init_quot_diff, ctrl->aging_sensor->ro_scale); return 0; } /** /** * cpr3_hmss_init_controller() - perform HMSS CPR3 controller specific * cpr3_hmss_init_controller() - perform HMSS CPR3 controller specific * initializations * initializations Loading Loading @@ -1708,6 +1802,13 @@ static int cpr3_hmss_regulator_probe(struct platform_device *pdev) } } } } rc = cpr3_hmss_init_aging(ctrl); if (rc) { cpr3_err(ctrl, "failed to initialize aging configurations, rc=%d\n", rc); return rc; } platform_set_drvdata(pdev, ctrl); platform_set_drvdata(pdev, ctrl); return cpr3_regulator_register(pdev, ctrl); return cpr3_regulator_register(pdev, ctrl); Loading drivers/regulator/cpr3-mmss-regulator.c +150 −38 Original line number Original line Diff line number Diff line Loading @@ -43,6 +43,8 @@ * for each fuse corner (raw, not converted to a voltage) * for each fuse corner (raw, not converted to a voltage) * @cpr_fusing_rev: CPR fusing revision fuse parameter value * @cpr_fusing_rev: CPR fusing revision fuse parameter value * @limitation: CPR limitation select fuse parameter value * @limitation: CPR limitation select fuse parameter value * @aging_init_quot_diff: Initial quotient difference between CPR aging * min and max sensors measured at time of manufacturing * * * This struct holds the values for all of the fuses read from memory. * This struct holds the values for all of the fuses read from memory. */ */ Loading @@ -50,6 +52,7 @@ struct cpr3_msm8996_mmss_fuses { u64 init_voltage[MSM8996_MMSS_FUSE_CORNERS]; u64 init_voltage[MSM8996_MMSS_FUSE_CORNERS]; u64 cpr_fusing_rev; u64 cpr_fusing_rev; u64 limitation; u64 limitation; u64 aging_init_quot_diff; }; }; /** /** Loading Loading @@ -110,6 +113,12 @@ static const struct cpr3_fuse_param msm8996_cpr_limitation_param[] = { {}, {}, }; }; static const struct cpr3_fuse_param msm8996_mmss_aging_init_quot_diff_param[] = { {68, 26, 31}, {}, }; /* /* * Some initial msm8996 parts cannot be used in a meaningful way by software. * Some initial msm8996 parts cannot be used in a meaningful way by software. * Other parts can only be used when operating with CPR disabled (i.e. at the * Other parts can only be used when operating with CPR disabled (i.e. at the Loading @@ -134,11 +143,16 @@ static const int msm8996_mmss_fuse_ref_volt[MSM8996_MMSS_FUSE_CORNERS] = { #define MSM8996_MMSS_FUSE_STEP_VOLT 10000 #define MSM8996_MMSS_FUSE_STEP_VOLT 10000 #define MSM8996_MMSS_VOLTAGE_FUSE_SIZE 5 #define MSM8996_MMSS_VOLTAGE_FUSE_SIZE 5 #define MSM8996_MMSS_AGING_INIT_QUOT_DIFF_SCALE 2 #define MSM8996_MMSS_AGING_INIT_QUOT_DIFF_SIZE 6 #define MSM8996_MMSS_CPR_SENSOR_COUNT 35 #define MSM8996_MMSS_CPR_SENSOR_COUNT 35 #define MSM8996_MMSS_CPR_CLOCK_RATE 19200000 #define MSM8996_MMSS_CPR_CLOCK_RATE 19200000 #define MSM8996_MMSS_AGING_SENSOR_ID 29 #define MSM8996_MMSS_AGING_BYPASS_MASK0 (GENMASK(23, 0)) /** /** * cpr3_msm8996_mmss_read_fuse_data() - load MMSS specific fuse parameter values * cpr3_msm8996_mmss_read_fuse_data() - load MMSS specific fuse parameter values * @vreg: Pointer to the CPR3 regulator * @vreg: Pointer to the CPR3 regulator Loading Loading @@ -181,6 +195,14 @@ static int cpr3_msm8996_mmss_read_fuse_data(struct cpr3_regulator *vreg) == MSM8996_CPR_LIMITATION_NO_CPR_OR_INTERPOLATION == MSM8996_CPR_LIMITATION_NO_CPR_OR_INTERPOLATION ? "CPR disabled and no interpolation" : "none"); ? "CPR disabled and no interpolation" : "none"); rc = cpr3_read_fuse_param(base, msm8996_mmss_aging_init_quot_diff_param, &fuse->aging_init_quot_diff); if (rc) { cpr3_err(vreg, "Unable to read aging initial quotient difference fuse, rc=%d\n", rc); return rc; } for (i = 0; i < MSM8996_MMSS_FUSE_CORNERS; i++) { for (i = 0; i < MSM8996_MMSS_FUSE_CORNERS; i++) { rc = cpr3_read_fuse_param(base, rc = cpr3_read_fuse_param(base, msm8996_mmss_init_voltage_param[i], msm8996_mmss_init_voltage_param[i], Loading Loading @@ -267,10 +289,13 @@ static int cpr3_mmss_adjust_target_quotients(struct cpr3_regulator *vreg, { { int i, j, rc, quot_adjust; int i, j, rc, quot_adjust; int *volt_adjust, *ro_scale; int *volt_adjust, *ro_scale; bool explicit_adjustment; u32 prev_quot; u32 prev_quot; if (!of_find_property(vreg->of_node, explicit_adjustment = of_find_property(vreg->of_node, "qcom,cpr-closed-loop-voltage-adjustment", NULL)) { "qcom,cpr-closed-loop-voltage-adjustment", NULL); if (!explicit_adjustment && !vreg->aging_allowed) { /* No adjustment required. */ /* No adjustment required. */ return 0; return 0; } else if (!of_find_property(vreg->of_node, } else if (!of_find_property(vreg->of_node, Loading @@ -288,15 +313,6 @@ static int cpr3_mmss_adjust_target_quotients(struct cpr3_regulator *vreg, goto done; goto done; } } rc = cpr3_parse_array_property(vreg, "qcom,cpr-closed-loop-voltage-adjustment", vreg->corner_count, corner_sum, combo_offset, volt_adjust); if (rc) { cpr3_err(vreg, "could not load closed-loop voltage adjustments, rc=%d\n", rc); goto done; } rc = cpr3_parse_array_property(vreg, "qcom,cpr-ro-scaling-factor", rc = cpr3_parse_array_property(vreg, "qcom,cpr-ro-scaling-factor", vreg->corner_count * CPR3_RO_COUNT, vreg->corner_count * CPR3_RO_COUNT, corner_sum * CPR3_RO_COUNT, corner_sum * CPR3_RO_COUNT, Loading @@ -308,6 +324,25 @@ static int cpr3_mmss_adjust_target_quotients(struct cpr3_regulator *vreg, goto done; goto done; } } for (i = 0; i < vreg->corner_count; i++) memcpy(vreg->corner[i].ro_scale, &ro_scale[i * CPR3_RO_COUNT], sizeof(*ro_scale) * CPR3_RO_COUNT); if (explicit_adjustment) { rc = cpr3_parse_array_property(vreg, "qcom,cpr-closed-loop-voltage-adjustment", vreg->corner_count, corner_sum, combo_offset, volt_adjust); if (rc) { cpr3_err(vreg, "could not load closed-loop voltage adjustments, rc=%d\n", rc); goto done; } /* * Adjust the target quotients for each corner according to * device tree adjustment values. */ for (i = 0; i < vreg->corner_count; i++) { for (i = 0; i < vreg->corner_count; i++) { for (j = 0; j < CPR3_RO_COUNT; j++) { for (j = 0; j < CPR3_RO_COUNT; j++) { if (vreg->corner[i].target_quot[j]) { if (vreg->corner[i].target_quot[j]) { Loading @@ -315,35 +350,45 @@ static int cpr3_mmss_adjust_target_quotients(struct cpr3_regulator *vreg, ro_scale[i * CPR3_RO_COUNT + j], ro_scale[i * CPR3_RO_COUNT + j], volt_adjust[i]); volt_adjust[i]); if (quot_adjust) { if (quot_adjust) { prev_quot prev_quot = vreg->corner[i]. = vreg->corner[i].target_quot[j]; target_quot[j]; vreg->corner[i].target_quot[j] vreg->corner[i].target_quot[j] += quot_adjust; += quot_adjust; cpr3_info(vreg, "adjusted corner %d RO%d target quot: %u --> %u (%d uV)\n", cpr3_info(vreg, "adjusted corner %d RO%d target quot: %u --> %u (%d uV)\n", i, j, prev_quot, i, j, prev_quot, vreg->corner[i].target_quot[j], vreg->corner[i]. target_quot[j], volt_adjust[i]); volt_adjust[i]); } } } } } } } } /* Ensure that target quotients increase monotonically */ /* * Ensure that target quotients increase monotonically from * lower to higher corners after being adjusted based upon * device tree adjustment values. */ for (i = 1; i < vreg->corner_count; i++) { for (i = 1; i < vreg->corner_count; i++) { for (j = 0; j < CPR3_RO_COUNT; j++) { for (j = 0; j < CPR3_RO_COUNT; j++) { if (vreg->corner[i].target_quot[j] if (vreg->corner[i].target_quot[j] && vreg->corner[i].target_quot[j] && vreg->corner[i].target_quot[j] < vreg->corner[i - 1].target_quot[j]) { < vreg->corner[i - 1].target_quot[j]) { cpr3_info(vreg, "adjusted corner %d RO%u target quot=%u < adjusted corner %d RO%u target quot=%u; overriding: corner %d RO%u target quot=%u\n", cpr3_info(vreg, "adjusted corner %d RO%u target quot=%u < adjusted corner %d RO%u target quot=%u; overriding: corner %d RO%u target quot=%u\n", i, j, vreg->corner[i].target_quot[j], i, j, vreg->corner[i].target_quot[j], i - 1, j, i - 1, j, vreg->corner[i - 1].target_quot[j], i, vreg->corner[i - 1]. j, vreg->corner[i - 1].target_quot[j]); target_quot[j], i, j, vreg->corner[i - 1]. target_quot[j]); vreg->corner[i].target_quot[j] vreg->corner[i].target_quot[j] = vreg->corner[i - 1].target_quot[j]; = vreg->corner[i - 1].target_quot[j]; } } } } } } } done: done: kfree(volt_adjust); kfree(volt_adjust); Loading Loading @@ -504,6 +549,66 @@ static void cpr3_mmss_print_settings(struct cpr3_regulator *vreg) } } } } /** * cpr3_mmss_init_aging() - perform MMSS CPR3 controller specific * aging initializations * @ctrl: Pointer to the CPR3 controller * * Return: 0 on success, errno on failure */ static int cpr3_mmss_init_aging(struct cpr3_controller *ctrl) { struct cpr3_msm8996_mmss_fuses *fuse; struct cpr3_regulator *vreg; u32 aging_ro_scale; int rc; vreg = &ctrl->thread[0].vreg[0]; ctrl->aging_required = vreg->aging_allowed; fuse = vreg->platform_fuses; if (!ctrl->aging_required || !fuse) return 0; rc = cpr3_parse_array_property(vreg, "qcom,cpr-aging-ro-scaling-factor", 1, vreg->fuse_combos_supported, vreg->fuse_combo, &aging_ro_scale); if (rc) return rc; if (aging_ro_scale == 0) { cpr3_err(ctrl, "aging RO scaling factor is invalid: %u\n", aging_ro_scale); return -EINVAL; } ctrl->aging_vdd_mode = REGULATOR_MODE_NORMAL; ctrl->aging_complete_vdd_mode = REGULATOR_MODE_IDLE; ctrl->aging_sensor_count = 1; ctrl->aging_sensor = kzalloc(sizeof(*ctrl->aging_sensor), GFP_KERNEL); if (!ctrl->aging_sensor) return -ENOMEM; ctrl->aging_sensor->sensor_id = MSM8996_MMSS_AGING_SENSOR_ID; ctrl->aging_sensor->bypass_mask[0] = MSM8996_MMSS_AGING_BYPASS_MASK0; ctrl->aging_sensor->ro_scale = aging_ro_scale; ctrl->aging_sensor->init_quot_diff = cpr3_convert_open_loop_voltage_fuse(0, MSM8996_MMSS_AGING_INIT_QUOT_DIFF_SCALE, fuse->aging_init_quot_diff, MSM8996_MMSS_AGING_INIT_QUOT_DIFF_SIZE); cpr3_debug(ctrl, "sensor %u aging init quotient diff = %d, aging RO scale = %u QUOT/V\n", ctrl->aging_sensor->sensor_id, ctrl->aging_sensor->init_quot_diff, ctrl->aging_sensor->ro_scale); return 0; } /** /** * cpr3_mmss_init_thread() - perform all steps necessary to initialize the * cpr3_mmss_init_thread() - perform all steps necessary to initialize the * configuration data for a CPR3 thread * configuration data for a CPR3 thread Loading Loading @@ -721,6 +826,13 @@ static int cpr3_mmss_regulator_probe(struct platform_device *pdev) return rc; return rc; } } rc = cpr3_mmss_init_aging(ctrl); if (rc) { cpr3_err(ctrl, "failed to initialize aging configurations, rc=%d\n", rc); return rc; } platform_set_drvdata(pdev, ctrl); platform_set_drvdata(pdev, ctrl); return cpr3_regulator_register(pdev, ctrl); return cpr3_regulator_register(pdev, ctrl); Loading Loading
Documentation/devicetree/bindings/regulator/cpr3-hmss-regulator.txt +28 −0 Original line number Original line Diff line number Diff line Loading @@ -250,6 +250,8 @@ apcc_cpr: cpr3-ctrl@99e8000 { qcom,cpr-hw-closed-loop; qcom,cpr-hw-closed-loop; qcom,cpr-clock-throttling = <0x20>; qcom,cpr-clock-throttling = <0x20>; qcom,cpr-aging-ref-voltage = <905000>; thread@0 { thread@0 { qcom,cpr-thread-id = <0>; qcom,cpr-thread-id = <0>; qcom,cpr-consecutive-up = <0>; qcom,cpr-consecutive-up = <0>; Loading Loading @@ -311,6 +313,15 @@ apcc_cpr: cpr3-ctrl@99e8000 { qcom,allow-voltage-interpolation; qcom,allow-voltage-interpolation; qcom,allow-quotient-interpolation; qcom,allow-quotient-interpolation; qcom,cpr-scaled-open-loop-voltage-as-ceiling; qcom,cpr-scaled-open-loop-voltage-as-ceiling; qcom,cpr-aging-max-voltage-adjustment = <25000>; qcom,cpr-aging-ref-corner = <11>; qcom,cpr-aging-ro-scaling-factor = <3200>; qcom,cpr-aging-derate = <1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000>; qcom,allow-aging-voltage-adjustment = <1>; }; }; apc0_cbf_vreg: regulator-cbf { apc0_cbf_vreg: regulator-cbf { Loading Loading @@ -358,6 +369,14 @@ apcc_cpr: cpr3-ctrl@99e8000 { qcom,allow-voltage-interpolation; qcom,allow-voltage-interpolation; qcom,allow-quotient-interpolation; qcom,allow-quotient-interpolation; qcom,cpr-scaled-open-loop-voltage-as-ceiling; qcom,cpr-scaled-open-loop-voltage-as-ceiling; qcom,cpr-aging-max-voltage-adjustment = <25000>; qcom,cpr-aging-ref-corner = <9>; qcom,cpr-aging-ro-scaling-factor = <3200>; qcom,cpr-aging-derate = <1000 1000 1000 1000 1000 1000 1000 1000 1000 1000>; qcom,allow-aging-voltage-adjustment = <1>; }; }; }; }; Loading Loading @@ -422,6 +441,15 @@ apcc_cpr: cpr3-ctrl@99e8000 { qcom,allow-voltage-interpolation; qcom,allow-voltage-interpolation; qcom,allow-quotient-interpolation; qcom,allow-quotient-interpolation; qcom,cpr-scaled-open-loop-voltage-as-ceiling; qcom,cpr-scaled-open-loop-voltage-as-ceiling; qcom,cpr-aging-max-voltage-adjustment = <25000>; qcom,cpr-aging-ref-corner = <11>; qcom,cpr-aging-ro-scaling-factor = <3200>; qcom,cpr-aging-derate = <1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000>; qcom,allow-aging-voltage-adjustment = <1>; }; }; }; }; }; };
Documentation/devicetree/bindings/regulator/cpr3-mmss-regulator.txt +9 −0 Original line number Original line Diff line number Diff line Loading @@ -140,6 +140,8 @@ gfx_cpr: cpr3-ctrl@838000 { qcom,cpr-enable; qcom,cpr-enable; qcom,cpr-aging-ref-voltage = <905000>; thread@0 { thread@0 { qcom,cpr-thread-id = <0>; qcom,cpr-thread-id = <0>; qcom,cpr-consecutive-up = <0>; qcom,cpr-consecutive-up = <0>; Loading Loading @@ -194,6 +196,13 @@ gfx_cpr: cpr3-ctrl@838000 { qcom,allow-voltage-interpolation; qcom,allow-voltage-interpolation; qcom,cpr-scaled-open-loop-voltage-as-ceiling; qcom,cpr-scaled-open-loop-voltage-as-ceiling; qcom,cpr-aging-max-voltage-adjustment = <25000>; qcom,cpr-aging-ref-corner = <3>; qcom,cpr-aging-ro-scaling-factor = <2950>; qcom,cpr-aging-derate = <1000 1000 1000 1000>; qcom,allow-aging-voltage-adjustment = <1>; }; }; }; }; }; };
Documentation/devicetree/bindings/regulator/cpr3-regulator.txt +86 −2 Original line number Original line Diff line number Diff line Loading @@ -159,6 +159,14 @@ Platform independent properties: enabled) as opposed to open-loop mode (i.e. CPR sensing loop enabled) as opposed to open-loop mode (i.e. CPR sensing loop disabled) by default. disabled) by default. - qcom,cpr-aging-ref-voltage Usage: required if qcom,allow-aging-voltage-adjustment is specified for any third level nodes Value type: <u32> Definition: Specifies the CPR aging reference voltage in microvolts. This is the voltage that vdd-supply must be set to when performing an aging measurement. ================================================= ================================================= Second Level Nodes - CPR Threads for a Controller Second Level Nodes - CPR Threads for a Controller ================================================= ================================================= Loading Loading @@ -460,8 +468,9 @@ Platform independent properties: order to utilize this property. order to utilize this property. - qcom,cpr-ro-scaling-factor - qcom,cpr-ro-scaling-factor Usage: required if qcom,cpr-closed-loop-voltage-fuse-adjustment Usage: required if qcom,cpr-closed-loop-voltage-fuse-adjustment, or qcom,cpr-closed-loop-voltage-adjustment is specified qcom,cpr-closed-loop-voltage-adjustment, or qcom,allow-aging-voltage-adjustment is specified Value type: <prop-encoded-array> Value type: <prop-encoded-array> Definition: A grouping of integer tuple lists. Each tuple defines the Definition: A grouping of integer tuple lists. Each tuple defines the CPR ring oscillator (RO) scaling factor with units of QUOT/V CPR ring oscillator (RO) scaling factor with units of QUOT/V Loading @@ -488,6 +497,81 @@ Platform independent properties: qcom,cpr-closed-loop-voltage-adjustment by the relevant RO qcom,cpr-closed-loop-voltage-adjustment by the relevant RO scaling factor in this property. scaling factor in this property. - qcom,allow-aging-voltage-adjustment Usage: optional Value type: <prop-encoded-array> Definition: A list of integers which specifies if CPR aging adjustment should be performed for each fuse combination. Supported per-combo element values: 0 - do not perform CPR aging adjustment 1 - perform CPR aging adjustment The list must contain either qcom,cpr-fuse-combos number of elements in which case the elements are applied to fuse combinations 1-to-1 or the list must contain exactly 1 element which is used regardless of the fuse combination found on a given chip. - qcom,cpr-aging-max-voltage-adjustment Usage: required if qcom,allow-aging-voltage-adjustment is specified Value type: <prop-encoded-array> Definition: A list of integers which defines the maximum CPR aging voltage margin adjustment in microvolts that may be added for each fuse combination. If this property is specified and the adjustment specified is greater than 0, then aging adjustments are required for this regulator. The list must contain either qcom,cpr-fuse-combos number of elements in which case the max adjustments are applied to fuse combinations 1-to-1 or the list must contain exactly 1 element which is used regardless of the fuse combination found on a given chip. - qcom,cpr-aging-ref-corner Usage: required if qcom,allow-aging-voltage-adjustment is specified Value type: <prop-encoded-array> Definition: A list of integers which defines the CPR reference corner for this regulator to use during aging measurements for each fuse combination. The list must contain either qcom,cpr-fuse-combos number of elements in which case the max adjustments are applied to fuse combinations 1-to-1 or the list must contain exactly 1 element which is used regardless of the fuse combination found on a given chip. - qcom,cpr-aging-ro-scaling-factor Usage: required if qcom,allow-aging-voltage-adjustment is specified Value type: <prop-encoded-array> Definition: A list of integers which defines the CPR aging ring oscillator (RO) scaling factor with units of QUOT/V to use during aging measurements for each fuse combination. The list must contain either qcom,cpr-fuse-combos number of elements in which case the scaling factors are applied to fuse combinations 1-to-1 or the list must contain exactly 1 element which is used regardless of the fuse combination found on a given chip. - qcom,cpr-aging-derate Usage: optional, though only meaningful if qcom,allow-aging-voltage-adjustment is specified Value type: <prop-encoded-array> Definition: A list of integer tuples which each define the CPR aging derating scaling factor to apply to the closed-loop voltage margin adjustment for each corner. The individual scaling factors have units of uV/mV and are ordered from lowest to highest corner per tuple. For example, a value of 900 specifies that the voltage adjustment for the corner should be 90% (900/1000) of that for the reference corner. The list and tuples must meet the same size requirements as those specified for qcom,cpr-voltage-ceiling above. If this property is not specified, then it is assumed that no corners require derating (i.e. the scaling factor would be 1000). All properties specified within the core regulator framework can also be used in All properties specified within the core regulator framework can also be used in third level nodes. These bindings can be found in: third level nodes. These bindings can be found in: Documentation/devicetree/bindings/regulator/regulator.txt. Documentation/devicetree/bindings/regulator/regulator.txt. Loading
drivers/regulator/cpr3-hmss-regulator.c +102 −1 Original line number Original line Diff line number Diff line Loading @@ -58,6 +58,8 @@ * limitations found on a given chip * limitations found on a given chip * @vdd_mx_ret_fuse: Defines the logic retention voltage of VDD_MX * @vdd_mx_ret_fuse: Defines the logic retention voltage of VDD_MX * @vdd_apcc_ret_fuse: Defines the logic retention voltage of VDD_APCC * @vdd_apcc_ret_fuse: Defines the logic retention voltage of VDD_APCC * @aging_init_quot_diff: Initial quotient difference between CPR aging * min and max sensors measured at time of manufacturing * * * This struct holds the values for all of the fuses read from memory. The * This struct holds the values for all of the fuses read from memory. The * values for ro_sel, init_voltage, target_quot, and quot_offset come from * values for ro_sel, init_voltage, target_quot, and quot_offset come from Loading @@ -76,6 +78,7 @@ struct cpr3_msm8996_hmss_fuses { u64 partial_binning; u64 partial_binning; u64 vdd_mx_ret_fuse; u64 vdd_mx_ret_fuse; u64 vdd_apcc_ret_fuse; u64 vdd_apcc_ret_fuse; u64 aging_init_quot_diff; }; }; /** /** Loading Loading @@ -337,6 +340,12 @@ static const struct cpr3_fuse_param msm8996_cpr_partial_binning_param[] = { {}, {}, }; }; static const struct cpr3_fuse_param msm8996_hmss_aging_init_quot_diff_param[] = { {68, 14, 19}, {}, }; /* /* * Some initial msm8996 parts cannot be used in a meaningful way by software. * Some initial msm8996 parts cannot be used in a meaningful way by software. * Other parts can only be used when operating with CPR disabled (i.e. at the * Other parts can only be used when operating with CPR disabled (i.e. at the Loading Loading @@ -390,6 +399,8 @@ static const int msm8996_vdd_mx_fuse_ret_volt[] = { #define MSM8996_HMSS_FUSE_STEP_VOLT 10000 #define MSM8996_HMSS_FUSE_STEP_VOLT 10000 #define MSM8996_HMSS_VOLTAGE_FUSE_SIZE 6 #define MSM8996_HMSS_VOLTAGE_FUSE_SIZE 6 #define MSM8996_HMSS_QUOT_OFFSET_SCALE 5 #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 #define MSM8996_HMSS_CPR_SENSOR_COUNT 25 #define MSM8996_HMSS_CPR_SENSOR_COUNT 25 #define MSM8996_HMSS_THREAD0_SENSOR_MIN 0 #define MSM8996_HMSS_THREAD0_SENSOR_MIN 0 Loading @@ -399,6 +410,9 @@ static const int msm8996_vdd_mx_fuse_ret_volt[] = { #define MSM8996_HMSS_CPR_CLOCK_RATE 19200000 #define MSM8996_HMSS_CPR_CLOCK_RATE 19200000 #define MSM8996_HMSS_AGING_SENSOR_ID 11 #define MSM8996_HMSS_AGING_BYPASS_MASK0 (GENMASK(7, 0) & ~BIT(3)) /** /** * cpr3_msm8996_hmss_read_fuse_data() - load HMSS specific fuse parameter values * cpr3_msm8996_hmss_read_fuse_data() - load HMSS specific fuse parameter values * @vreg: Pointer to the CPR3 regulator * @vreg: Pointer to the CPR3 regulator Loading Loading @@ -495,6 +509,14 @@ static int cpr3_msm8996_hmss_read_fuse_data(struct cpr3_regulator *vreg) cpr3_info(vreg, "Retention voltage fuses: VDD_MX = %llu, VDD_APCC = %llu\n", cpr3_info(vreg, "Retention voltage fuses: VDD_MX = %llu, VDD_APCC = %llu\n", fuse->vdd_mx_ret_fuse, fuse->vdd_apcc_ret_fuse); fuse->vdd_mx_ret_fuse, fuse->vdd_apcc_ret_fuse); rc = cpr3_read_fuse_param(base, msm8996_hmss_aging_init_quot_diff_param, &fuse->aging_init_quot_diff); if (rc) { cpr3_err(vreg, "Unable to read aging initial quotient difference fuse, rc=%d\n", rc); return rc; } id = vreg->thread->thread_id; id = vreg->thread->thread_id; for (i = 0; i < MSM8996_HMSS_FUSE_CORNERS; i++) { for (i = 0; i < MSM8996_HMSS_FUSE_CORNERS; i++) { Loading Loading @@ -845,7 +867,8 @@ static int cpr3_hmss_parse_closed_loop_voltage_adjustments( if (!of_find_property(vreg->of_node, if (!of_find_property(vreg->of_node, "qcom,cpr-closed-loop-voltage-adjustment", NULL) "qcom,cpr-closed-loop-voltage-adjustment", NULL) && !of_find_property(vreg->of_node, && !of_find_property(vreg->of_node, "qcom,cpr-closed-loop-voltage-fuse-adjustment", NULL)) { "qcom,cpr-closed-loop-voltage-fuse-adjustment", NULL) && !vreg->aging_allowed) { /* No adjustment required. */ /* No adjustment required. */ return 0; return 0; } else if (!of_find_property(vreg->of_node, } else if (!of_find_property(vreg->of_node, Loading Loading @@ -874,6 +897,11 @@ static int cpr3_hmss_parse_closed_loop_voltage_adjustments( for (i = 0; i < vreg->fuse_corner_count; i++) for (i = 0; i < vreg->fuse_corner_count; i++) ro_scale[i] = ro_all_scale[i * CPR3_RO_COUNT + fuse->ro_sel[i]]; ro_scale[i] = ro_all_scale[i * CPR3_RO_COUNT + fuse->ro_sel[i]]; for (i = 0; i < vreg->corner_count; i++) memcpy(vreg->corner[i].ro_scale, &ro_all_scale[vreg->corner[i].cpr_fuse_corner * CPR3_RO_COUNT], sizeof(*ro_all_scale) * CPR3_RO_COUNT); if (of_find_property(vreg->of_node, if (of_find_property(vreg->of_node, "qcom,cpr-closed-loop-voltage-fuse-adjustment", NULL)) { "qcom,cpr-closed-loop-voltage-fuse-adjustment", NULL)) { rc = cpr3_parse_array_property(vreg, rc = cpr3_parse_array_property(vreg, Loading Loading @@ -1518,6 +1546,72 @@ static int cpr3_hmss_apm_init(struct cpr3_controller *ctrl) return 0; return 0; } } /** * cpr3_hmss_init_aging() - perform HMSS CPR3 controller specific * aging initializations * @ctrl: Pointer to the CPR3 controller * * Return: 0 on success, errno on failure */ static int cpr3_hmss_init_aging(struct cpr3_controller *ctrl) { struct cpr3_msm8996_hmss_fuses *fuse = NULL; struct cpr3_regulator *vreg; u32 aging_ro_scale; int i, j, rc; for (i = 0; i < ctrl->thread_count; i++) { for (j = 0; j < ctrl->thread[i].vreg_count; j++) { if (ctrl->thread[i].vreg[j].aging_allowed) { ctrl->aging_required = true; vreg = &ctrl->thread[i].vreg[j]; fuse = vreg->platform_fuses; break; } } } if (!ctrl->aging_required || !fuse) return 0; rc = cpr3_parse_array_property(vreg, "qcom,cpr-aging-ro-scaling-factor", 1, vreg->fuse_combos_supported, vreg->fuse_combo, &aging_ro_scale); if (rc) return rc; if (aging_ro_scale == 0) { cpr3_err(ctrl, "aging RO scaling factor is invalid: %u\n", aging_ro_scale); return -EINVAL; } ctrl->aging_vdd_mode = REGULATOR_MODE_NORMAL; ctrl->aging_complete_vdd_mode = REGULATOR_MODE_IDLE; ctrl->aging_sensor_count = 1; ctrl->aging_sensor = kzalloc(sizeof(*ctrl->aging_sensor), GFP_KERNEL); if (!ctrl->aging_sensor) return -ENOMEM; ctrl->aging_sensor->sensor_id = MSM8996_HMSS_AGING_SENSOR_ID; ctrl->aging_sensor->bypass_mask[0] = MSM8996_HMSS_AGING_BYPASS_MASK0; ctrl->aging_sensor->ro_scale = aging_ro_scale; ctrl->aging_sensor->init_quot_diff = cpr3_convert_open_loop_voltage_fuse(0, MSM8996_HMSS_AGING_INIT_QUOT_DIFF_SCALE, fuse->aging_init_quot_diff, MSM8996_HMSS_AGING_INIT_QUOT_DIFF_SIZE); cpr3_debug(ctrl, "sensor %u aging init quotient diff = %d, aging RO scale = %u QUOT/V\n", ctrl->aging_sensor->sensor_id, ctrl->aging_sensor->init_quot_diff, ctrl->aging_sensor->ro_scale); return 0; } /** /** * cpr3_hmss_init_controller() - perform HMSS CPR3 controller specific * cpr3_hmss_init_controller() - perform HMSS CPR3 controller specific * initializations * initializations Loading Loading @@ -1708,6 +1802,13 @@ static int cpr3_hmss_regulator_probe(struct platform_device *pdev) } } } } rc = cpr3_hmss_init_aging(ctrl); if (rc) { cpr3_err(ctrl, "failed to initialize aging configurations, rc=%d\n", rc); return rc; } platform_set_drvdata(pdev, ctrl); platform_set_drvdata(pdev, ctrl); return cpr3_regulator_register(pdev, ctrl); return cpr3_regulator_register(pdev, ctrl); Loading
drivers/regulator/cpr3-mmss-regulator.c +150 −38 Original line number Original line Diff line number Diff line Loading @@ -43,6 +43,8 @@ * for each fuse corner (raw, not converted to a voltage) * for each fuse corner (raw, not converted to a voltage) * @cpr_fusing_rev: CPR fusing revision fuse parameter value * @cpr_fusing_rev: CPR fusing revision fuse parameter value * @limitation: CPR limitation select fuse parameter value * @limitation: CPR limitation select fuse parameter value * @aging_init_quot_diff: Initial quotient difference between CPR aging * min and max sensors measured at time of manufacturing * * * This struct holds the values for all of the fuses read from memory. * This struct holds the values for all of the fuses read from memory. */ */ Loading @@ -50,6 +52,7 @@ struct cpr3_msm8996_mmss_fuses { u64 init_voltage[MSM8996_MMSS_FUSE_CORNERS]; u64 init_voltage[MSM8996_MMSS_FUSE_CORNERS]; u64 cpr_fusing_rev; u64 cpr_fusing_rev; u64 limitation; u64 limitation; u64 aging_init_quot_diff; }; }; /** /** Loading Loading @@ -110,6 +113,12 @@ static const struct cpr3_fuse_param msm8996_cpr_limitation_param[] = { {}, {}, }; }; static const struct cpr3_fuse_param msm8996_mmss_aging_init_quot_diff_param[] = { {68, 26, 31}, {}, }; /* /* * Some initial msm8996 parts cannot be used in a meaningful way by software. * Some initial msm8996 parts cannot be used in a meaningful way by software. * Other parts can only be used when operating with CPR disabled (i.e. at the * Other parts can only be used when operating with CPR disabled (i.e. at the Loading @@ -134,11 +143,16 @@ static const int msm8996_mmss_fuse_ref_volt[MSM8996_MMSS_FUSE_CORNERS] = { #define MSM8996_MMSS_FUSE_STEP_VOLT 10000 #define MSM8996_MMSS_FUSE_STEP_VOLT 10000 #define MSM8996_MMSS_VOLTAGE_FUSE_SIZE 5 #define MSM8996_MMSS_VOLTAGE_FUSE_SIZE 5 #define MSM8996_MMSS_AGING_INIT_QUOT_DIFF_SCALE 2 #define MSM8996_MMSS_AGING_INIT_QUOT_DIFF_SIZE 6 #define MSM8996_MMSS_CPR_SENSOR_COUNT 35 #define MSM8996_MMSS_CPR_SENSOR_COUNT 35 #define MSM8996_MMSS_CPR_CLOCK_RATE 19200000 #define MSM8996_MMSS_CPR_CLOCK_RATE 19200000 #define MSM8996_MMSS_AGING_SENSOR_ID 29 #define MSM8996_MMSS_AGING_BYPASS_MASK0 (GENMASK(23, 0)) /** /** * cpr3_msm8996_mmss_read_fuse_data() - load MMSS specific fuse parameter values * cpr3_msm8996_mmss_read_fuse_data() - load MMSS specific fuse parameter values * @vreg: Pointer to the CPR3 regulator * @vreg: Pointer to the CPR3 regulator Loading Loading @@ -181,6 +195,14 @@ static int cpr3_msm8996_mmss_read_fuse_data(struct cpr3_regulator *vreg) == MSM8996_CPR_LIMITATION_NO_CPR_OR_INTERPOLATION == MSM8996_CPR_LIMITATION_NO_CPR_OR_INTERPOLATION ? "CPR disabled and no interpolation" : "none"); ? "CPR disabled and no interpolation" : "none"); rc = cpr3_read_fuse_param(base, msm8996_mmss_aging_init_quot_diff_param, &fuse->aging_init_quot_diff); if (rc) { cpr3_err(vreg, "Unable to read aging initial quotient difference fuse, rc=%d\n", rc); return rc; } for (i = 0; i < MSM8996_MMSS_FUSE_CORNERS; i++) { for (i = 0; i < MSM8996_MMSS_FUSE_CORNERS; i++) { rc = cpr3_read_fuse_param(base, rc = cpr3_read_fuse_param(base, msm8996_mmss_init_voltage_param[i], msm8996_mmss_init_voltage_param[i], Loading Loading @@ -267,10 +289,13 @@ static int cpr3_mmss_adjust_target_quotients(struct cpr3_regulator *vreg, { { int i, j, rc, quot_adjust; int i, j, rc, quot_adjust; int *volt_adjust, *ro_scale; int *volt_adjust, *ro_scale; bool explicit_adjustment; u32 prev_quot; u32 prev_quot; if (!of_find_property(vreg->of_node, explicit_adjustment = of_find_property(vreg->of_node, "qcom,cpr-closed-loop-voltage-adjustment", NULL)) { "qcom,cpr-closed-loop-voltage-adjustment", NULL); if (!explicit_adjustment && !vreg->aging_allowed) { /* No adjustment required. */ /* No adjustment required. */ return 0; return 0; } else if (!of_find_property(vreg->of_node, } else if (!of_find_property(vreg->of_node, Loading @@ -288,15 +313,6 @@ static int cpr3_mmss_adjust_target_quotients(struct cpr3_regulator *vreg, goto done; goto done; } } rc = cpr3_parse_array_property(vreg, "qcom,cpr-closed-loop-voltage-adjustment", vreg->corner_count, corner_sum, combo_offset, volt_adjust); if (rc) { cpr3_err(vreg, "could not load closed-loop voltage adjustments, rc=%d\n", rc); goto done; } rc = cpr3_parse_array_property(vreg, "qcom,cpr-ro-scaling-factor", rc = cpr3_parse_array_property(vreg, "qcom,cpr-ro-scaling-factor", vreg->corner_count * CPR3_RO_COUNT, vreg->corner_count * CPR3_RO_COUNT, corner_sum * CPR3_RO_COUNT, corner_sum * CPR3_RO_COUNT, Loading @@ -308,6 +324,25 @@ static int cpr3_mmss_adjust_target_quotients(struct cpr3_regulator *vreg, goto done; goto done; } } for (i = 0; i < vreg->corner_count; i++) memcpy(vreg->corner[i].ro_scale, &ro_scale[i * CPR3_RO_COUNT], sizeof(*ro_scale) * CPR3_RO_COUNT); if (explicit_adjustment) { rc = cpr3_parse_array_property(vreg, "qcom,cpr-closed-loop-voltage-adjustment", vreg->corner_count, corner_sum, combo_offset, volt_adjust); if (rc) { cpr3_err(vreg, "could not load closed-loop voltage adjustments, rc=%d\n", rc); goto done; } /* * Adjust the target quotients for each corner according to * device tree adjustment values. */ for (i = 0; i < vreg->corner_count; i++) { for (i = 0; i < vreg->corner_count; i++) { for (j = 0; j < CPR3_RO_COUNT; j++) { for (j = 0; j < CPR3_RO_COUNT; j++) { if (vreg->corner[i].target_quot[j]) { if (vreg->corner[i].target_quot[j]) { Loading @@ -315,35 +350,45 @@ static int cpr3_mmss_adjust_target_quotients(struct cpr3_regulator *vreg, ro_scale[i * CPR3_RO_COUNT + j], ro_scale[i * CPR3_RO_COUNT + j], volt_adjust[i]); volt_adjust[i]); if (quot_adjust) { if (quot_adjust) { prev_quot prev_quot = vreg->corner[i]. = vreg->corner[i].target_quot[j]; target_quot[j]; vreg->corner[i].target_quot[j] vreg->corner[i].target_quot[j] += quot_adjust; += quot_adjust; cpr3_info(vreg, "adjusted corner %d RO%d target quot: %u --> %u (%d uV)\n", cpr3_info(vreg, "adjusted corner %d RO%d target quot: %u --> %u (%d uV)\n", i, j, prev_quot, i, j, prev_quot, vreg->corner[i].target_quot[j], vreg->corner[i]. target_quot[j], volt_adjust[i]); volt_adjust[i]); } } } } } } } } /* Ensure that target quotients increase monotonically */ /* * Ensure that target quotients increase monotonically from * lower to higher corners after being adjusted based upon * device tree adjustment values. */ for (i = 1; i < vreg->corner_count; i++) { for (i = 1; i < vreg->corner_count; i++) { for (j = 0; j < CPR3_RO_COUNT; j++) { for (j = 0; j < CPR3_RO_COUNT; j++) { if (vreg->corner[i].target_quot[j] if (vreg->corner[i].target_quot[j] && vreg->corner[i].target_quot[j] && vreg->corner[i].target_quot[j] < vreg->corner[i - 1].target_quot[j]) { < vreg->corner[i - 1].target_quot[j]) { cpr3_info(vreg, "adjusted corner %d RO%u target quot=%u < adjusted corner %d RO%u target quot=%u; overriding: corner %d RO%u target quot=%u\n", cpr3_info(vreg, "adjusted corner %d RO%u target quot=%u < adjusted corner %d RO%u target quot=%u; overriding: corner %d RO%u target quot=%u\n", i, j, vreg->corner[i].target_quot[j], i, j, vreg->corner[i].target_quot[j], i - 1, j, i - 1, j, vreg->corner[i - 1].target_quot[j], i, vreg->corner[i - 1]. j, vreg->corner[i - 1].target_quot[j]); target_quot[j], i, j, vreg->corner[i - 1]. target_quot[j]); vreg->corner[i].target_quot[j] vreg->corner[i].target_quot[j] = vreg->corner[i - 1].target_quot[j]; = vreg->corner[i - 1].target_quot[j]; } } } } } } } done: done: kfree(volt_adjust); kfree(volt_adjust); Loading Loading @@ -504,6 +549,66 @@ static void cpr3_mmss_print_settings(struct cpr3_regulator *vreg) } } } } /** * cpr3_mmss_init_aging() - perform MMSS CPR3 controller specific * aging initializations * @ctrl: Pointer to the CPR3 controller * * Return: 0 on success, errno on failure */ static int cpr3_mmss_init_aging(struct cpr3_controller *ctrl) { struct cpr3_msm8996_mmss_fuses *fuse; struct cpr3_regulator *vreg; u32 aging_ro_scale; int rc; vreg = &ctrl->thread[0].vreg[0]; ctrl->aging_required = vreg->aging_allowed; fuse = vreg->platform_fuses; if (!ctrl->aging_required || !fuse) return 0; rc = cpr3_parse_array_property(vreg, "qcom,cpr-aging-ro-scaling-factor", 1, vreg->fuse_combos_supported, vreg->fuse_combo, &aging_ro_scale); if (rc) return rc; if (aging_ro_scale == 0) { cpr3_err(ctrl, "aging RO scaling factor is invalid: %u\n", aging_ro_scale); return -EINVAL; } ctrl->aging_vdd_mode = REGULATOR_MODE_NORMAL; ctrl->aging_complete_vdd_mode = REGULATOR_MODE_IDLE; ctrl->aging_sensor_count = 1; ctrl->aging_sensor = kzalloc(sizeof(*ctrl->aging_sensor), GFP_KERNEL); if (!ctrl->aging_sensor) return -ENOMEM; ctrl->aging_sensor->sensor_id = MSM8996_MMSS_AGING_SENSOR_ID; ctrl->aging_sensor->bypass_mask[0] = MSM8996_MMSS_AGING_BYPASS_MASK0; ctrl->aging_sensor->ro_scale = aging_ro_scale; ctrl->aging_sensor->init_quot_diff = cpr3_convert_open_loop_voltage_fuse(0, MSM8996_MMSS_AGING_INIT_QUOT_DIFF_SCALE, fuse->aging_init_quot_diff, MSM8996_MMSS_AGING_INIT_QUOT_DIFF_SIZE); cpr3_debug(ctrl, "sensor %u aging init quotient diff = %d, aging RO scale = %u QUOT/V\n", ctrl->aging_sensor->sensor_id, ctrl->aging_sensor->init_quot_diff, ctrl->aging_sensor->ro_scale); return 0; } /** /** * cpr3_mmss_init_thread() - perform all steps necessary to initialize the * cpr3_mmss_init_thread() - perform all steps necessary to initialize the * configuration data for a CPR3 thread * configuration data for a CPR3 thread Loading Loading @@ -721,6 +826,13 @@ static int cpr3_mmss_regulator_probe(struct platform_device *pdev) return rc; return rc; } } rc = cpr3_mmss_init_aging(ctrl); if (rc) { cpr3_err(ctrl, "failed to initialize aging configurations, rc=%d\n", rc); return rc; } platform_set_drvdata(pdev, ctrl); platform_set_drvdata(pdev, ctrl); return cpr3_regulator_register(pdev, ctrl); return cpr3_regulator_register(pdev, ctrl); Loading