regulator: cpr3-regulator: add support for CPRh aging adjustment
Add support to perform a CPR aging measurement and subsequent target quotient and open-loop voltage adjustments for CPRh controllers at registration time. Change-Id: I3a48a912fb9dea37a6197c1a13c2b41454d2dcff CRs-Fixed: 1048890 Signed-off-by: David Collins <collinsd@codeaurora.org>
This commit is contained in:
parent
0b3886773c
commit
f49fa83627
2 changed files with 160 additions and 12 deletions
|
@ -1264,6 +1264,8 @@ static void cprh_controller_program_sdelta(
|
|||
mb();
|
||||
}
|
||||
|
||||
static int cprh_regulator_aging_adjust(struct cpr3_controller *ctrl);
|
||||
|
||||
/**
|
||||
* cpr3_regulator_init_cprh() - performs hardware initialization at the
|
||||
* controller and thread level required for CPRh operation.
|
||||
|
@ -1290,6 +1292,16 @@ static int cpr3_regulator_init_cprh(struct cpr3_controller *ctrl)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = cprh_regulator_aging_adjust(ctrl);
|
||||
if (rc && rc != -ETIMEDOUT) {
|
||||
/*
|
||||
* Don't fail initialization if the CPR aging measurement
|
||||
* timed out due to sensors not being available.
|
||||
*/
|
||||
cpr3_err(ctrl, "CPR aging adjustment failed, rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
cprh_controller_program_sdelta(ctrl);
|
||||
|
||||
rc = cpr3_regulator_init_cprh_corners(&ctrl->thread[0].vreg[0]);
|
||||
|
@ -3346,7 +3358,7 @@ static int cpr3_regulator_measure_aging(struct cpr3_controller *ctrl,
|
|||
u32 mask, reg, result, quot_min, quot_max, sel_min, sel_max;
|
||||
u32 quot_min_scaled, quot_max_scaled;
|
||||
u32 gcnt, gcnt_ref, gcnt0_restore, gcnt1_restore, irq_restore;
|
||||
u32 cont_dly_restore, up_down_dly_restore = 0;
|
||||
u32 ro_mask_restore, cont_dly_restore, up_down_dly_restore = 0;
|
||||
int quot_delta, quot_delta_scaled, quot_delta_scaled_sum;
|
||||
int *quot_delta_results;
|
||||
int rc, rc2, i, aging_measurement_count, filtered_count;
|
||||
|
@ -3379,7 +3391,8 @@ static int cpr3_regulator_measure_aging(struct cpr3_controller *ctrl,
|
|||
|
||||
/* Switch from HW to SW closed-loop if necessary */
|
||||
if (ctrl->supports_hw_closed_loop) {
|
||||
if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4) {
|
||||
if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4 ||
|
||||
ctrl->ctrl_type == CPR_CTRL_TYPE_CPRH) {
|
||||
cpr3_masked_write(ctrl, CPR4_REG_MARGIN_ADJ_CTL,
|
||||
CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_EN_MASK,
|
||||
CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_DISABLE);
|
||||
|
@ -3397,6 +3410,10 @@ static int cpr3_regulator_measure_aging(struct cpr3_controller *ctrl,
|
|||
cpr3_write(ctrl, CPR3_REG_GCNT(0), gcnt);
|
||||
cpr3_write(ctrl, CPR3_REG_GCNT(1), gcnt);
|
||||
|
||||
/* Unmask all RO's */
|
||||
ro_mask_restore = cpr3_read(ctrl, CPR3_REG_RO_MASK(0));
|
||||
cpr3_write(ctrl, CPR3_REG_RO_MASK(0), 0);
|
||||
|
||||
/*
|
||||
* Mask all sensors except for the one to measure and bypass all
|
||||
* sensors in collapsible domains.
|
||||
|
@ -3535,6 +3552,8 @@ cleanup:
|
|||
|
||||
cpr3_write(ctrl, CPR3_REG_IRQ_EN, irq_restore);
|
||||
|
||||
cpr3_write(ctrl, CPR3_REG_RO_MASK(0), ro_mask_restore);
|
||||
|
||||
cpr3_write(ctrl, CPR3_REG_GCNT(0), gcnt0_restore);
|
||||
cpr3_write(ctrl, CPR3_REG_GCNT(1), gcnt1_restore);
|
||||
|
||||
|
@ -3565,7 +3584,8 @@ cleanup:
|
|||
CPR3_IRQ_UP | CPR3_IRQ_DOWN | CPR3_IRQ_MID);
|
||||
|
||||
if (ctrl->supports_hw_closed_loop) {
|
||||
if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4) {
|
||||
if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPR4 ||
|
||||
ctrl->ctrl_type == CPR_CTRL_TYPE_CPRH) {
|
||||
cpr3_masked_write(ctrl, CPR4_REG_MARGIN_ADJ_CTL,
|
||||
CPR4_MARGIN_ADJ_CTL_HW_CLOSED_LOOP_EN_MASK,
|
||||
ctrl->use_hw_closed_loop
|
||||
|
@ -3866,6 +3886,126 @@ cleanup:
|
|||
return rc ? rc : rc2;
|
||||
}
|
||||
|
||||
/**
|
||||
* cprh_regulator_aging_adjust() - adjust the target quotients and open-loop
|
||||
* voltages for CPRh regulators based on the output of CPR aging
|
||||
* sensors
|
||||
* @ctrl: Pointer to the CPR3 controller
|
||||
*
|
||||
* Return: 0 on success, errno on failure
|
||||
*/
|
||||
static int cprh_regulator_aging_adjust(struct cpr3_controller *ctrl)
|
||||
{
|
||||
int i, j, id, rc, rc2, aging_volt, init_volt;
|
||||
int max_aging_volt = 0;
|
||||
u32 reg;
|
||||
|
||||
if (!ctrl->aging_required || !ctrl->cpr_enabled)
|
||||
return 0;
|
||||
|
||||
if (!ctrl->vdd_regulator) {
|
||||
cpr3_err(ctrl, "vdd-supply regulator missing\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
init_volt = regulator_get_voltage(ctrl->vdd_regulator);
|
||||
if (init_volt < 0) {
|
||||
cpr3_err(ctrl, "could not get vdd-supply voltage, rc=%d\n",
|
||||
init_volt);
|
||||
return init_volt;
|
||||
}
|
||||
|
||||
if (init_volt > ctrl->aging_ref_volt) {
|
||||
cpr3_info(ctrl, "unable to perform CPR aging measurement as vdd=%d uV > aging voltage=%d uV\n",
|
||||
init_volt, ctrl->aging_ref_volt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Verify that none of the aging sensors are currently masked. */
|
||||
for (i = 0; i < ctrl->aging_sensor_count; i++) {
|
||||
id = ctrl->aging_sensor[i].sensor_id;
|
||||
reg = cpr3_read(ctrl, CPR3_REG_SENSOR_MASK_READ(id));
|
||||
if (reg & BIT(id % 32)) {
|
||||
cpr3_info(ctrl, "unable to perform CPR aging measurement as CPR sensor %d is masked\n",
|
||||
id);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
rc = regulator_set_voltage(ctrl->vdd_regulator, ctrl->aging_ref_volt,
|
||||
INT_MAX);
|
||||
if (rc) {
|
||||
cpr3_err(ctrl, "unable to set vdd-supply to aging voltage=%d uV, rc=%d\n",
|
||||
ctrl->aging_ref_volt, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (ctrl->aging_vdd_mode) {
|
||||
rc = regulator_set_mode(ctrl->vdd_regulator,
|
||||
ctrl->aging_vdd_mode);
|
||||
if (rc) {
|
||||
cpr3_err(ctrl, "unable to configure vdd-supply for mode=%u, rc=%d\n",
|
||||
ctrl->aging_vdd_mode, rc);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
/* Perform aging measurement on all aging sensors */
|
||||
for (i = 0; i < ctrl->aging_sensor_count; i++) {
|
||||
for (j = 0; j < CPR3_AGING_RETRY_COUNT; j++) {
|
||||
rc = cpr3_regulator_measure_aging(ctrl,
|
||||
&ctrl->aging_sensor[i]);
|
||||
if (!rc)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!rc) {
|
||||
aging_volt =
|
||||
cpr3_voltage_adjustment(
|
||||
ctrl->aging_sensor[i].ro_scale,
|
||||
ctrl->aging_sensor[i].measured_quot_diff
|
||||
- ctrl->aging_sensor[i].init_quot_diff);
|
||||
max_aging_volt = max(max_aging_volt, aging_volt);
|
||||
} else {
|
||||
cpr3_err(ctrl, "CPR aging measurement failed after %d tries, rc=%d\n",
|
||||
j, rc);
|
||||
ctrl->aging_failed = true;
|
||||
ctrl->aging_required = false;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
/* Adjust the CPR target quotients according to the aging measurement */
|
||||
if (!rc) {
|
||||
cpr3_regulator_set_aging_ref_adjustment(ctrl, max_aging_volt);
|
||||
|
||||
cpr3_info(ctrl, "aging measurement successful; aging reference adjustment voltage=%d uV\n",
|
||||
ctrl->aging_ref_adjust_volt);
|
||||
ctrl->aging_succeeded = true;
|
||||
ctrl->aging_required = false;
|
||||
}
|
||||
|
||||
rc2 = regulator_set_voltage(ctrl->vdd_regulator, init_volt, INT_MAX);
|
||||
if (rc2) {
|
||||
cpr3_err(ctrl, "unable to reset vdd-supply to initial voltage=%d uV, rc=%d\n",
|
||||
init_volt, rc2);
|
||||
return rc2;
|
||||
}
|
||||
|
||||
if (ctrl->aging_complete_vdd_mode) {
|
||||
rc2 = regulator_set_mode(ctrl->vdd_regulator,
|
||||
ctrl->aging_complete_vdd_mode);
|
||||
if (rc2) {
|
||||
cpr3_err(ctrl, "unable to configure vdd-supply for mode=%u, rc=%d\n",
|
||||
ctrl->aging_complete_vdd_mode, rc2);
|
||||
return rc2;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* cpr3_regulator_update_ctrl_state() - update the state of the CPR controller
|
||||
* to reflect the corners used by all CPR3 regulators as well as
|
||||
|
|
|
@ -1202,6 +1202,23 @@ int cpr3_parse_common_ctrl_data(struct cpr3_controller *ctrl)
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
ctrl->vdd_regulator = devm_regulator_get(ctrl->dev, "vdd");
|
||||
if (IS_ERR(ctrl->vdd_regulator)) {
|
||||
rc = PTR_ERR(ctrl->vdd_regulator);
|
||||
if (rc != -EPROBE_DEFER) {
|
||||
/* vdd-supply is optional for CPRh controllers. */
|
||||
if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPRH) {
|
||||
cpr3_debug(ctrl, "unable to request vdd regulator, rc=%d\n",
|
||||
rc);
|
||||
ctrl->vdd_regulator = NULL;
|
||||
return 0;
|
||||
}
|
||||
cpr3_err(ctrl, "unable to request vdd regulator, rc=%d\n",
|
||||
rc);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Regulator device handles are not necessary for CPRh controllers
|
||||
* since communication with the regulators is completely managed
|
||||
|
@ -1210,15 +1227,6 @@ int cpr3_parse_common_ctrl_data(struct cpr3_controller *ctrl)
|
|||
if (ctrl->ctrl_type == CPR_CTRL_TYPE_CPRH)
|
||||
return rc;
|
||||
|
||||
ctrl->vdd_regulator = devm_regulator_get(ctrl->dev, "vdd");
|
||||
if (IS_ERR(ctrl->vdd_regulator)) {
|
||||
rc = PTR_ERR(ctrl->vdd_regulator);
|
||||
if (rc != -EPROBE_DEFER)
|
||||
cpr3_err(ctrl, "unable request vdd regulator, rc=%d\n",
|
||||
rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
ctrl->system_regulator = devm_regulator_get_optional(ctrl->dev,
|
||||
"system");
|
||||
if (IS_ERR(ctrl->system_regulator)) {
|
||||
|
|
Loading…
Add table
Reference in a new issue