Loading Documentation/devicetree/bindings/regulator/cpr4-apss-regulator.txt +28 −0 Original line number Diff line number Diff line Loading @@ -348,6 +348,27 @@ APSS specific properties: regardless of the fuse combination and speed bin found on a given chip. - qcom,cpr-misc-fuse-voltage-adjustment Usage: optional Value type: <prop-encoded-array> Definition: A grouping of integer tuple lists where each tuple defines the voltage adjustments in microvolts for each voltage corner in order from lowest to highest. This adjustment is applied to both open-loop and closed-loop voltages. Each tuple list must contain a number of tuples equal to 2 to the power of the number of bits selected for misc voltage adj fuse definition. For MSMTITANIUM the tuple list must contain 2 tuples for the 1-bit misc fuse. Tuples in a list should be specified in ascending order according to the misc fuse value assuming that the fuse is treated like an unsigned integer. The tuple list grouping must contain qcom,cpr-speed-bins number of tuple lists in which case the lists are matched to speed bins 1-to-1 or exactly 1 list which is used regardless of the speed bin found on a given chip. ======= Example ======= Loading Loading @@ -422,6 +443,13 @@ apc_cpr: cpr4-ctrl@b018000 { 1689600000 1843200000 1958400000 2150400000 2208000000>; qcom,cpr-misc-fuse-voltage-adjustment = /* Speed bin 0; misc fuse 0..1 */ < 0 0 0 0 0 0 0 0>, < 0 0 30000 0 0 0 0 0>; qcom,allow-voltage-interpolation; qcom,allow-quotient-interpolation; qcom,cpr-scaled-open-loop-voltage-as-ceiling; Loading drivers/regulator/cpr4-apss-regulator.c +150 −1 Original line number Diff line number Diff line Loading @@ -66,6 +66,7 @@ struct cpr4_msmtitanium_apss_fuses { u64 cpr_fusing_rev; u64 boost_cfg; u64 boost_voltage; u64 misc; }; /* Loading Loading @@ -155,6 +156,17 @@ static const struct cpr3_fuse_param msmtitanium_apss_boost_fuse_volt_param[] = { {}, }; static const struct cpr3_fuse_param msmtitanium_misc_fuse_volt_adj_param[] = { {36, 54, 54}, {}, }; /* * The number of possible values for misc fuse is * 2^(#bits defined for misc fuse) */ #define MSMTITANIUM_MISC_FUSE_VAL_COUNT BIT(1) /* * Open loop voltage fuse reference voltages in microvolts for MSMTITANIUM */ Loading Loading @@ -231,6 +243,20 @@ static int cpr4_msmtitanium_apss_read_fuse_data(struct cpr3_regulator *vreg) } cpr3_info(vreg, "CPR fusing revision = %llu\n", fuse->cpr_fusing_rev); rc = cpr3_read_fuse_param(base, msmtitanium_misc_fuse_volt_adj_param, &fuse->misc); if (rc) { cpr3_err(vreg, "Unable to read misc voltage adjustment fuse, rc=%d\n", rc); return rc; } cpr3_info(vreg, "CPR misc fuse value = %llu\n", fuse->misc); if (fuse->misc >= MSMTITANIUM_MISC_FUSE_VAL_COUNT) { cpr3_err(vreg, "CPR misc fuse value = %llu, should be < %lu\n", fuse->misc, MSMTITANIUM_MISC_FUSE_VAL_COUNT); return -EINVAL; } for (i = 0; i < MSMTITANIUM_APSS_FUSE_CORNERS; i++) { rc = cpr3_read_fuse_param(base, msmtitanium_apss_init_voltage_param[i], Loading Loading @@ -324,6 +350,78 @@ static int cpr4_apss_parse_corner_data(struct cpr3_regulator *vreg) return rc; } /** * cpr4_apss_parse_misc_fuse_voltage_adjustments() - fill an array from a * portion of the voltage adjustments specified based on * miscellaneous fuse bits. * @vreg: Pointer to the CPR3 regulator * @volt_adjust: Voltage adjustment output data array which must be * of size vreg->corner_count * * cpr3_parse_common_corner_data() must be called for vreg before this function * is called so that speed bin size elements are initialized. * * Two formats are supported for the device tree property: * 1. Length == tuple_list_size * vreg->corner_count * (reading begins at index 0) * 2. Length == tuple_list_size * vreg->speed_bin_corner_sum * (reading begins at index tuple_list_size * vreg->speed_bin_offset) * * Here, tuple_list_size is the number of possible values for misc fuse. * All other property lengths are treated as errors. * * Return: 0 on success, errno on failure */ static int cpr4_apss_parse_misc_fuse_voltage_adjustments( struct cpr3_regulator *vreg, u32 *volt_adjust) { struct device_node *node = vreg->of_node; struct cpr4_msmtitanium_apss_fuses *fuse = vreg->platform_fuses; int tuple_list_size = MSMTITANIUM_MISC_FUSE_VAL_COUNT; int i, offset, rc, len = 0; const char *prop_name = "qcom,cpr-misc-fuse-voltage-adjustment"; if (!of_find_property(node, prop_name, &len)) { cpr3_err(vreg, "property %s is missing\n", prop_name); return -EINVAL; } if (len == tuple_list_size * vreg->corner_count * sizeof(u32)) { offset = 0; } else if (vreg->speed_bin_corner_sum > 0 && len == tuple_list_size * vreg->speed_bin_corner_sum * sizeof(u32)) { offset = tuple_list_size * vreg->speed_bin_offset + fuse->misc * vreg->corner_count; } else { if (vreg->speed_bin_corner_sum > 0) cpr3_err(vreg, "property %s has invalid length=%d, should be %zu or %zu\n", prop_name, len, tuple_list_size * vreg->corner_count * sizeof(u32), tuple_list_size * vreg->speed_bin_corner_sum * sizeof(u32)); else cpr3_err(vreg, "property %s has invalid length=%d, should be %zu\n", prop_name, len, tuple_list_size * vreg->corner_count * sizeof(u32)); return -EINVAL; } for (i = 0; i < vreg->corner_count; i++) { rc = of_property_read_u32_index(node, prop_name, offset + i, &volt_adjust[i]); if (rc) { cpr3_err(vreg, "error reading property %s, rc=%d\n", prop_name, rc); return rc; } } return 0; } /** * cpr4_msmtitanium_apss_calculate_open_loop_voltages() - calculate the open-loop * voltage for each corner of a CPR3 regulator Loading @@ -349,7 +447,7 @@ static int cpr4_msmtitanium_apss_calculate_open_loop_voltages( int i, j, rc = 0; bool allow_interpolation; u64 freq_low, volt_low, freq_high, volt_high; int *fuse_volt; int *fuse_volt, *misc_adj_volt; int *fmax_corner; fuse_volt = kcalloc(vreg->fuse_corner_count, sizeof(*fuse_volt), Loading Loading @@ -445,8 +543,34 @@ done: if (rc) cpr3_err(vreg, "open-loop voltage adjustment failed, rc=%d\n", rc); if (of_find_property(node, "qcom,cpr-misc-fuse-voltage-adjustment", NULL)) { misc_adj_volt = kcalloc(vreg->corner_count, sizeof(*misc_adj_volt), GFP_KERNEL); if (!misc_adj_volt) { rc = -ENOMEM; goto _exit; } rc = cpr4_apss_parse_misc_fuse_voltage_adjustments(vreg, misc_adj_volt); if (rc) { cpr3_err(vreg, "qcom,cpr-misc-fuse-voltage-adjustment reading failed, rc=%d\n", rc); kfree(misc_adj_volt); goto _exit; } for (i = 0; i < vreg->corner_count; i++) vreg->corner[i].open_loop_volt += misc_adj_volt[i]; kfree(misc_adj_volt); } } _exit: kfree(fuse_volt); kfree(fmax_corner); return rc; Loading Loading @@ -525,6 +649,7 @@ static int cpr4_msmtitanium_apss_calculate_target_quotients( int i, j, fuse_corner, quot_adjust; int *fmax_corner; int *volt_adjust, *volt_adjust_fuse, *ro_scale; int *voltage_adj_misc; /* Log fused quotient values for debugging purposes. */ cpr3_info(vreg, "fused LowSVS: quot[%2llu]=%4llu\n", Loading Loading @@ -567,6 +692,30 @@ static int cpr4_msmtitanium_apss_calculate_target_quotients( goto done; } if (of_find_property(vreg->of_node, "qcom,cpr-misc-fuse-voltage-adjustment", NULL)) { voltage_adj_misc = kcalloc(vreg->corner_count, sizeof(*voltage_adj_misc), GFP_KERNEL); if (!voltage_adj_misc) { rc = -ENOMEM; goto done; } rc = cpr4_apss_parse_misc_fuse_voltage_adjustments(vreg, voltage_adj_misc); if (rc) { cpr3_err(vreg, "qcom,cpr-misc-fuse-voltage-adjustment reading failed, rc=%d\n", rc); kfree(voltage_adj_misc); goto done; } for (i = 0; i < vreg->corner_count; i++) volt_adjust[i] += voltage_adj_misc[i]; kfree(voltage_adj_misc); } if (!allow_interpolation) { /* Use fused target quotients for lower frequencies. */ return cpr4_msmtitanium_apss_set_no_interpolation_quotients( Loading Loading
Documentation/devicetree/bindings/regulator/cpr4-apss-regulator.txt +28 −0 Original line number Diff line number Diff line Loading @@ -348,6 +348,27 @@ APSS specific properties: regardless of the fuse combination and speed bin found on a given chip. - qcom,cpr-misc-fuse-voltage-adjustment Usage: optional Value type: <prop-encoded-array> Definition: A grouping of integer tuple lists where each tuple defines the voltage adjustments in microvolts for each voltage corner in order from lowest to highest. This adjustment is applied to both open-loop and closed-loop voltages. Each tuple list must contain a number of tuples equal to 2 to the power of the number of bits selected for misc voltage adj fuse definition. For MSMTITANIUM the tuple list must contain 2 tuples for the 1-bit misc fuse. Tuples in a list should be specified in ascending order according to the misc fuse value assuming that the fuse is treated like an unsigned integer. The tuple list grouping must contain qcom,cpr-speed-bins number of tuple lists in which case the lists are matched to speed bins 1-to-1 or exactly 1 list which is used regardless of the speed bin found on a given chip. ======= Example ======= Loading Loading @@ -422,6 +443,13 @@ apc_cpr: cpr4-ctrl@b018000 { 1689600000 1843200000 1958400000 2150400000 2208000000>; qcom,cpr-misc-fuse-voltage-adjustment = /* Speed bin 0; misc fuse 0..1 */ < 0 0 0 0 0 0 0 0>, < 0 0 30000 0 0 0 0 0>; qcom,allow-voltage-interpolation; qcom,allow-quotient-interpolation; qcom,cpr-scaled-open-loop-voltage-as-ceiling; Loading
drivers/regulator/cpr4-apss-regulator.c +150 −1 Original line number Diff line number Diff line Loading @@ -66,6 +66,7 @@ struct cpr4_msmtitanium_apss_fuses { u64 cpr_fusing_rev; u64 boost_cfg; u64 boost_voltage; u64 misc; }; /* Loading Loading @@ -155,6 +156,17 @@ static const struct cpr3_fuse_param msmtitanium_apss_boost_fuse_volt_param[] = { {}, }; static const struct cpr3_fuse_param msmtitanium_misc_fuse_volt_adj_param[] = { {36, 54, 54}, {}, }; /* * The number of possible values for misc fuse is * 2^(#bits defined for misc fuse) */ #define MSMTITANIUM_MISC_FUSE_VAL_COUNT BIT(1) /* * Open loop voltage fuse reference voltages in microvolts for MSMTITANIUM */ Loading Loading @@ -231,6 +243,20 @@ static int cpr4_msmtitanium_apss_read_fuse_data(struct cpr3_regulator *vreg) } cpr3_info(vreg, "CPR fusing revision = %llu\n", fuse->cpr_fusing_rev); rc = cpr3_read_fuse_param(base, msmtitanium_misc_fuse_volt_adj_param, &fuse->misc); if (rc) { cpr3_err(vreg, "Unable to read misc voltage adjustment fuse, rc=%d\n", rc); return rc; } cpr3_info(vreg, "CPR misc fuse value = %llu\n", fuse->misc); if (fuse->misc >= MSMTITANIUM_MISC_FUSE_VAL_COUNT) { cpr3_err(vreg, "CPR misc fuse value = %llu, should be < %lu\n", fuse->misc, MSMTITANIUM_MISC_FUSE_VAL_COUNT); return -EINVAL; } for (i = 0; i < MSMTITANIUM_APSS_FUSE_CORNERS; i++) { rc = cpr3_read_fuse_param(base, msmtitanium_apss_init_voltage_param[i], Loading Loading @@ -324,6 +350,78 @@ static int cpr4_apss_parse_corner_data(struct cpr3_regulator *vreg) return rc; } /** * cpr4_apss_parse_misc_fuse_voltage_adjustments() - fill an array from a * portion of the voltage adjustments specified based on * miscellaneous fuse bits. * @vreg: Pointer to the CPR3 regulator * @volt_adjust: Voltage adjustment output data array which must be * of size vreg->corner_count * * cpr3_parse_common_corner_data() must be called for vreg before this function * is called so that speed bin size elements are initialized. * * Two formats are supported for the device tree property: * 1. Length == tuple_list_size * vreg->corner_count * (reading begins at index 0) * 2. Length == tuple_list_size * vreg->speed_bin_corner_sum * (reading begins at index tuple_list_size * vreg->speed_bin_offset) * * Here, tuple_list_size is the number of possible values for misc fuse. * All other property lengths are treated as errors. * * Return: 0 on success, errno on failure */ static int cpr4_apss_parse_misc_fuse_voltage_adjustments( struct cpr3_regulator *vreg, u32 *volt_adjust) { struct device_node *node = vreg->of_node; struct cpr4_msmtitanium_apss_fuses *fuse = vreg->platform_fuses; int tuple_list_size = MSMTITANIUM_MISC_FUSE_VAL_COUNT; int i, offset, rc, len = 0; const char *prop_name = "qcom,cpr-misc-fuse-voltage-adjustment"; if (!of_find_property(node, prop_name, &len)) { cpr3_err(vreg, "property %s is missing\n", prop_name); return -EINVAL; } if (len == tuple_list_size * vreg->corner_count * sizeof(u32)) { offset = 0; } else if (vreg->speed_bin_corner_sum > 0 && len == tuple_list_size * vreg->speed_bin_corner_sum * sizeof(u32)) { offset = tuple_list_size * vreg->speed_bin_offset + fuse->misc * vreg->corner_count; } else { if (vreg->speed_bin_corner_sum > 0) cpr3_err(vreg, "property %s has invalid length=%d, should be %zu or %zu\n", prop_name, len, tuple_list_size * vreg->corner_count * sizeof(u32), tuple_list_size * vreg->speed_bin_corner_sum * sizeof(u32)); else cpr3_err(vreg, "property %s has invalid length=%d, should be %zu\n", prop_name, len, tuple_list_size * vreg->corner_count * sizeof(u32)); return -EINVAL; } for (i = 0; i < vreg->corner_count; i++) { rc = of_property_read_u32_index(node, prop_name, offset + i, &volt_adjust[i]); if (rc) { cpr3_err(vreg, "error reading property %s, rc=%d\n", prop_name, rc); return rc; } } return 0; } /** * cpr4_msmtitanium_apss_calculate_open_loop_voltages() - calculate the open-loop * voltage for each corner of a CPR3 regulator Loading @@ -349,7 +447,7 @@ static int cpr4_msmtitanium_apss_calculate_open_loop_voltages( int i, j, rc = 0; bool allow_interpolation; u64 freq_low, volt_low, freq_high, volt_high; int *fuse_volt; int *fuse_volt, *misc_adj_volt; int *fmax_corner; fuse_volt = kcalloc(vreg->fuse_corner_count, sizeof(*fuse_volt), Loading Loading @@ -445,8 +543,34 @@ done: if (rc) cpr3_err(vreg, "open-loop voltage adjustment failed, rc=%d\n", rc); if (of_find_property(node, "qcom,cpr-misc-fuse-voltage-adjustment", NULL)) { misc_adj_volt = kcalloc(vreg->corner_count, sizeof(*misc_adj_volt), GFP_KERNEL); if (!misc_adj_volt) { rc = -ENOMEM; goto _exit; } rc = cpr4_apss_parse_misc_fuse_voltage_adjustments(vreg, misc_adj_volt); if (rc) { cpr3_err(vreg, "qcom,cpr-misc-fuse-voltage-adjustment reading failed, rc=%d\n", rc); kfree(misc_adj_volt); goto _exit; } for (i = 0; i < vreg->corner_count; i++) vreg->corner[i].open_loop_volt += misc_adj_volt[i]; kfree(misc_adj_volt); } } _exit: kfree(fuse_volt); kfree(fmax_corner); return rc; Loading Loading @@ -525,6 +649,7 @@ static int cpr4_msmtitanium_apss_calculate_target_quotients( int i, j, fuse_corner, quot_adjust; int *fmax_corner; int *volt_adjust, *volt_adjust_fuse, *ro_scale; int *voltage_adj_misc; /* Log fused quotient values for debugging purposes. */ cpr3_info(vreg, "fused LowSVS: quot[%2llu]=%4llu\n", Loading Loading @@ -567,6 +692,30 @@ static int cpr4_msmtitanium_apss_calculate_target_quotients( goto done; } if (of_find_property(vreg->of_node, "qcom,cpr-misc-fuse-voltage-adjustment", NULL)) { voltage_adj_misc = kcalloc(vreg->corner_count, sizeof(*voltage_adj_misc), GFP_KERNEL); if (!voltage_adj_misc) { rc = -ENOMEM; goto done; } rc = cpr4_apss_parse_misc_fuse_voltage_adjustments(vreg, voltage_adj_misc); if (rc) { cpr3_err(vreg, "qcom,cpr-misc-fuse-voltage-adjustment reading failed, rc=%d\n", rc); kfree(voltage_adj_misc); goto done; } for (i = 0; i < vreg->corner_count; i++) volt_adjust[i] += voltage_adj_misc[i]; kfree(voltage_adj_misc); } if (!allow_interpolation) { /* Use fused target quotients for lower frequencies. */ return cpr4_msmtitanium_apss_set_no_interpolation_quotients( Loading