Loading Documentation/devicetree/bindings/regulator/cpr4-apss-regulator.txt +27 −1 Original line number Diff line number Diff line Loading @@ -165,7 +165,7 @@ APSS specific properties: and Turbo. - qcom,cpr-fuse-combos Usage: required Usage: optional Value type: <u32> Definition: Specifies the number of fuse combinations being supported by the device. This value is utilized by several other Loading @@ -178,6 +178,11 @@ APSS specific properties: The last 8 fuse combos correspond to speed bin fuse value 7 along with CPR revision fuse values 0 to 7. This property must be specified unless qcom,cpr-fuse-combo-map is present. In that case, qcom,cpr-fuse-combos is implicitly assumed to have a value equal to the number of tuple lists (rows) found in the qcom,cpr-fuse-combo-map property. - qcom,cpr-speed-bins Usage: optional Value type: <u32> Loading Loading @@ -368,6 +373,27 @@ APSS specific properties: speed bins 1-to-1 or exactly 1 list which is used regardless of the speed bin found on a given chip. - qcom,cpr-fuse-combo-map Usage: optional Value type: <prop-encoded-array> Definition: A grouping of integer tuple lists where each tuple list (row) defines a mapping from combinations of fuse parameter ranges to fuse combo ID (i.e., map row index). Each tuple defines the beginning and ending fuse parameter value that matches. The number of tuples in each row is equal to the number of selection fuse parameters used in fuse combo logic. For MSM8953, the fuse parameters are "speed-bin", "cpr fuse revision", and "foundry id". The tuples in each row correspond to the fuses in order: "speed-bin", "cpr fuse revision" and "foundry id". An example entry for speed-bin '3', cpr fuse revisions >= '2', and foundry '2' is as shown below: <3 3>, <2 7>, <2 2> The number of rows in the property is arbitrary but used to size other properties. qcom,cpr-fuse-combos must be set to the number of rows specified in this property. For msm8953, the maximum number of rows for this property is 512 (8 * 8 * 8). ======= Example ======= Loading drivers/regulator/cpr3-regulator.h +8 −0 Original line number Diff line number Diff line Loading @@ -863,6 +863,8 @@ int cpr4_parse_core_count_temp_voltage_adj(struct cpr3_regulator *vreg, bool use_corner_band); int cpr3_apm_init(struct cpr3_controller *ctrl); int cpr3_mem_acc_init(struct cpr3_regulator *vreg); int cpr3_parse_fuse_combo_map(struct cpr3_regulator *vreg, u64 *fuse_val, int fuse_count); #else Loading Loading @@ -1035,6 +1037,12 @@ static inline int cpr3_mem_acc_init(struct cpr3_regulator *vreg) return 0; } static int cpr3_parse_fuse_combo_map(struct cpr3_regulator *vreg, u64 *fuse_val, int fuse_count) { return -EPERM; } #endif /* CONFIG_REGULATOR_CPR3 */ #endif /* __REGULATOR_CPR_REGULATOR_H__ */ drivers/regulator/cpr3-util.c +104 −22 Original line number Diff line number Diff line Loading @@ -562,6 +562,14 @@ int cpr3_parse_common_corner_data(struct cpr3_regulator *vreg) return -EINVAL; } /* * Check if CPR3 regulator's fuse_combos_supported element is already * populated by fuse-combo-map logic. If not populated, then parse the * qcom,cpr-fuse-combos property. */ if (vreg->fuse_combos_supported) max_fuse_combos = vreg->fuse_combos_supported; else { rc = of_property_read_u32(node, "qcom,cpr-fuse-combos", &max_fuse_combos); if (rc) { Loading @@ -571,8 +579,8 @@ int cpr3_parse_common_corner_data(struct cpr3_regulator *vreg) } /* * Sanity check against arbitrarily large value to avoid excessive * memory allocation. * Sanity check against arbitrarily large value to avoid * excessive memory allocation. */ if (max_fuse_combos > 100 || max_fuse_combos == 0) { cpr3_err(vreg, "qcom,cpr-fuse-combos is invalid: %u\n", Loading @@ -588,6 +596,7 @@ int cpr3_parse_common_corner_data(struct cpr3_regulator *vreg) } vreg->fuse_combos_supported = max_fuse_combos; } of_property_read_u32(node, "qcom,cpr-speed-bins", &max_speed_bins); Loading Loading @@ -1974,3 +1983,76 @@ done: return rc; } /** * cpr3_parse_fuse_combo_map() - parse fuse combo map data for a CPR3 regulator * from device tree. * @vreg: Pointer to the CPR3 regulator * @fuse_val: Array of selection fuse parameter values * @fuse_count: Number of selection fuse parameters used in fuse combo * map * * This function reads the qcom,cpr-fuse-combo-map device tree property and * populates the fuse_combo element of CPR3 regulator with the row number of * fuse combo map data that matches with the data in fuse_val input array. * * Return: 0 on success, -ENODEV if qcom,cpr-fuse-combo-map property is not * specified in device node, other errno on failure */ int cpr3_parse_fuse_combo_map(struct cpr3_regulator *vreg, u64 *fuse_val, int fuse_count) { struct device_node *node = vreg->of_node; int i, j, len, num_fuse_combos, row_size, rc = 0; u32 *tmp; if (!of_find_property(node, "qcom,cpr-fuse-combo-map", &len)) { /* property not specified */ return -ENODEV; } row_size = fuse_count * 2; if (len == 0 || len % (sizeof(u32) * row_size)) { cpr3_err(vreg, "qcom,cpr-fuse-combo-map length=%d is invalid\n", len); return -EINVAL; } num_fuse_combos = len / (sizeof(u32) * row_size); vreg->fuse_combos_supported = num_fuse_combos; tmp = kzalloc(len, GFP_KERNEL); if (!tmp) return -ENOMEM; rc = of_property_read_u32_array(node, "qcom,cpr-fuse-combo-map", tmp, num_fuse_combos * row_size); if (rc) { cpr3_err(vreg, "could not read qcom,cpr-fuse-combo-map, rc=%d\n", rc); goto done; } for (i = 0; i < num_fuse_combos; i++) { for (j = 0; j < fuse_count; j++) { if (tmp[i * row_size + j * 2] > fuse_val[j] || tmp[i * row_size + j * 2 + 1] < fuse_val[j]) break; } if (j == fuse_count) { vreg->fuse_combo = i; break; } } if (i >= num_fuse_combos) { cpr3_err(vreg, "No matching CPR fuse combo found!\n"); BUG_ON(1); rc = -EINVAL; goto done; } done: kfree(tmp); return rc; } drivers/regulator/cpr4-apss-regulator.c +84 −0 Original line number Diff line number Diff line Loading @@ -51,6 +51,8 @@ * @speed_bin: Application processor speed bin fuse parameter value for * the given chip * @cpr_fusing_rev: CPR fusing revision fuse parameter value * @foundry_id: Foundry identifier fuse parameter value for the given * chip * @boost_cfg: CPR boost configuration fuse parameter value * @boost_voltage: CPR boost voltage fuse parameter value (raw, not * converted to a voltage) Loading @@ -66,6 +68,7 @@ struct cpr4_msm8953_apss_fuses { u64 quot_offset[MSM8953_APSS_FUSE_CORNERS]; u64 speed_bin; u64 cpr_fusing_rev; u64 foundry_id; u64 boost_cfg; u64 boost_voltage; u64 misc; Loading Loading @@ -149,6 +152,11 @@ static const struct cpr3_fuse_param msm8953_apss_speed_bin_param[] = { {}, }; static const struct cpr3_fuse_param msm8953_apss_foundry_id_param[] = { {37, 40, 42}, {}, }; static const struct cpr3_fuse_param msm8953_cpr_boost_fuse_cfg_param[] = { {36, 43, 45}, {}, Loading @@ -170,6 +178,15 @@ static const struct cpr3_fuse_param msm8953_apss_aging_init_quot_diff_param[] {}, }; /* * The maximum number of fuse combinations possible for the selected fuse * parameters in fuse combo map logic. * Here, possible speed-bin values = 8, fuse revision values = 8, and foundry * identifier values = 8. Total number of combinations = 512 (i.e., 8 * 8 * 8) */ #define CPR4_MSM8953_APSS_FUSE_COMBO_MAP_MAX_COUNT 512 /* * The number of possible values for misc fuse is * 2^(#bits defined for misc fuse) Loading Loading @@ -260,6 +277,14 @@ static int cpr4_msm8953_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, msm8953_apss_foundry_id_param, &fuse->foundry_id); if (rc) { cpr3_err(vreg, "Unable to read foundry id fuse, rc=%d\n", rc); return rc; } cpr3_info(vreg, "foundry id = %llu\n", fuse->foundry_id); rc = cpr3_read_fuse_param(base, msm8953_misc_fuse_volt_adj_param, &fuse->misc); if (rc) { Loading Loading @@ -1145,6 +1170,58 @@ done: return rc; } /* * Constants which define the selection fuse parameters used in fuse combo map * logic. */ enum cpr4_msm8953_apss_fuse_combo_parameters { MSM8953_APSS_SPEED_BIN = 0, MSM8953_APSS_CPR_FUSE_REV, MSM8953_APSS_FOUNDRY_ID, MSM8953_APSS_FUSE_COMBO_PARAM_COUNT, }; /** * cpr4_parse_fuse_combo_map() - parse APSS fuse combo map data from device tree * properties of the CPR3 regulator's device node * @vreg: Pointer to the CPR3 regulator * * Return: 0 on success, errno on failure */ static int cpr4_parse_fuse_combo_map(struct cpr3_regulator *vreg) { struct cpr4_msm8953_apss_fuses *fuse = vreg->platform_fuses; u64 *fuse_val; int rc; fuse_val = kcalloc(MSM8953_APSS_FUSE_COMBO_PARAM_COUNT, sizeof(*fuse_val), GFP_KERNEL); if (!fuse_val) return -ENOMEM; fuse_val[MSM8953_APSS_SPEED_BIN] = fuse->speed_bin; fuse_val[MSM8953_APSS_CPR_FUSE_REV] = fuse->cpr_fusing_rev; fuse_val[MSM8953_APSS_FOUNDRY_ID] = fuse->foundry_id; rc = cpr3_parse_fuse_combo_map(vreg, fuse_val, MSM8953_APSS_FUSE_COMBO_PARAM_COUNT); if (rc == -ENODEV) { cpr3_debug(vreg, "using legacy fuse combo logic, rc=%d\n", rc); rc = 0; } else if (rc < 0) { cpr3_err(vreg, "error reading fuse combo map data, rc=%d\n", rc); } else if (vreg->fuse_combo >= CPR4_MSM8953_APSS_FUSE_COMBO_MAP_MAX_COUNT) { cpr3_err(vreg, "invalid CPR fuse combo = %d found\n", vreg->fuse_combo); rc = -EINVAL; } kfree(fuse_val); return rc; } /** * cpr4_apss_init_regulator() - perform all steps necessary to initialize the * configuration data for a CPR3 regulator Loading @@ -1165,6 +1242,13 @@ static int cpr4_apss_init_regulator(struct cpr3_regulator *vreg) fuse = vreg->platform_fuses; rc = cpr4_parse_fuse_combo_map(vreg); if (rc) { cpr3_err(vreg, "error while parsing fuse combo map, rc=%d\n", rc); return rc; } rc = cpr4_apss_parse_corner_data(vreg); if (rc) { cpr3_err(vreg, "unable to read CPR corner data from device tree, rc=%d\n", Loading Loading
Documentation/devicetree/bindings/regulator/cpr4-apss-regulator.txt +27 −1 Original line number Diff line number Diff line Loading @@ -165,7 +165,7 @@ APSS specific properties: and Turbo. - qcom,cpr-fuse-combos Usage: required Usage: optional Value type: <u32> Definition: Specifies the number of fuse combinations being supported by the device. This value is utilized by several other Loading @@ -178,6 +178,11 @@ APSS specific properties: The last 8 fuse combos correspond to speed bin fuse value 7 along with CPR revision fuse values 0 to 7. This property must be specified unless qcom,cpr-fuse-combo-map is present. In that case, qcom,cpr-fuse-combos is implicitly assumed to have a value equal to the number of tuple lists (rows) found in the qcom,cpr-fuse-combo-map property. - qcom,cpr-speed-bins Usage: optional Value type: <u32> Loading Loading @@ -368,6 +373,27 @@ APSS specific properties: speed bins 1-to-1 or exactly 1 list which is used regardless of the speed bin found on a given chip. - qcom,cpr-fuse-combo-map Usage: optional Value type: <prop-encoded-array> Definition: A grouping of integer tuple lists where each tuple list (row) defines a mapping from combinations of fuse parameter ranges to fuse combo ID (i.e., map row index). Each tuple defines the beginning and ending fuse parameter value that matches. The number of tuples in each row is equal to the number of selection fuse parameters used in fuse combo logic. For MSM8953, the fuse parameters are "speed-bin", "cpr fuse revision", and "foundry id". The tuples in each row correspond to the fuses in order: "speed-bin", "cpr fuse revision" and "foundry id". An example entry for speed-bin '3', cpr fuse revisions >= '2', and foundry '2' is as shown below: <3 3>, <2 7>, <2 2> The number of rows in the property is arbitrary but used to size other properties. qcom,cpr-fuse-combos must be set to the number of rows specified in this property. For msm8953, the maximum number of rows for this property is 512 (8 * 8 * 8). ======= Example ======= Loading
drivers/regulator/cpr3-regulator.h +8 −0 Original line number Diff line number Diff line Loading @@ -863,6 +863,8 @@ int cpr4_parse_core_count_temp_voltage_adj(struct cpr3_regulator *vreg, bool use_corner_band); int cpr3_apm_init(struct cpr3_controller *ctrl); int cpr3_mem_acc_init(struct cpr3_regulator *vreg); int cpr3_parse_fuse_combo_map(struct cpr3_regulator *vreg, u64 *fuse_val, int fuse_count); #else Loading Loading @@ -1035,6 +1037,12 @@ static inline int cpr3_mem_acc_init(struct cpr3_regulator *vreg) return 0; } static int cpr3_parse_fuse_combo_map(struct cpr3_regulator *vreg, u64 *fuse_val, int fuse_count) { return -EPERM; } #endif /* CONFIG_REGULATOR_CPR3 */ #endif /* __REGULATOR_CPR_REGULATOR_H__ */
drivers/regulator/cpr3-util.c +104 −22 Original line number Diff line number Diff line Loading @@ -562,6 +562,14 @@ int cpr3_parse_common_corner_data(struct cpr3_regulator *vreg) return -EINVAL; } /* * Check if CPR3 regulator's fuse_combos_supported element is already * populated by fuse-combo-map logic. If not populated, then parse the * qcom,cpr-fuse-combos property. */ if (vreg->fuse_combos_supported) max_fuse_combos = vreg->fuse_combos_supported; else { rc = of_property_read_u32(node, "qcom,cpr-fuse-combos", &max_fuse_combos); if (rc) { Loading @@ -571,8 +579,8 @@ int cpr3_parse_common_corner_data(struct cpr3_regulator *vreg) } /* * Sanity check against arbitrarily large value to avoid excessive * memory allocation. * Sanity check against arbitrarily large value to avoid * excessive memory allocation. */ if (max_fuse_combos > 100 || max_fuse_combos == 0) { cpr3_err(vreg, "qcom,cpr-fuse-combos is invalid: %u\n", Loading @@ -588,6 +596,7 @@ int cpr3_parse_common_corner_data(struct cpr3_regulator *vreg) } vreg->fuse_combos_supported = max_fuse_combos; } of_property_read_u32(node, "qcom,cpr-speed-bins", &max_speed_bins); Loading Loading @@ -1974,3 +1983,76 @@ done: return rc; } /** * cpr3_parse_fuse_combo_map() - parse fuse combo map data for a CPR3 regulator * from device tree. * @vreg: Pointer to the CPR3 regulator * @fuse_val: Array of selection fuse parameter values * @fuse_count: Number of selection fuse parameters used in fuse combo * map * * This function reads the qcom,cpr-fuse-combo-map device tree property and * populates the fuse_combo element of CPR3 regulator with the row number of * fuse combo map data that matches with the data in fuse_val input array. * * Return: 0 on success, -ENODEV if qcom,cpr-fuse-combo-map property is not * specified in device node, other errno on failure */ int cpr3_parse_fuse_combo_map(struct cpr3_regulator *vreg, u64 *fuse_val, int fuse_count) { struct device_node *node = vreg->of_node; int i, j, len, num_fuse_combos, row_size, rc = 0; u32 *tmp; if (!of_find_property(node, "qcom,cpr-fuse-combo-map", &len)) { /* property not specified */ return -ENODEV; } row_size = fuse_count * 2; if (len == 0 || len % (sizeof(u32) * row_size)) { cpr3_err(vreg, "qcom,cpr-fuse-combo-map length=%d is invalid\n", len); return -EINVAL; } num_fuse_combos = len / (sizeof(u32) * row_size); vreg->fuse_combos_supported = num_fuse_combos; tmp = kzalloc(len, GFP_KERNEL); if (!tmp) return -ENOMEM; rc = of_property_read_u32_array(node, "qcom,cpr-fuse-combo-map", tmp, num_fuse_combos * row_size); if (rc) { cpr3_err(vreg, "could not read qcom,cpr-fuse-combo-map, rc=%d\n", rc); goto done; } for (i = 0; i < num_fuse_combos; i++) { for (j = 0; j < fuse_count; j++) { if (tmp[i * row_size + j * 2] > fuse_val[j] || tmp[i * row_size + j * 2 + 1] < fuse_val[j]) break; } if (j == fuse_count) { vreg->fuse_combo = i; break; } } if (i >= num_fuse_combos) { cpr3_err(vreg, "No matching CPR fuse combo found!\n"); BUG_ON(1); rc = -EINVAL; goto done; } done: kfree(tmp); return rc; }
drivers/regulator/cpr4-apss-regulator.c +84 −0 Original line number Diff line number Diff line Loading @@ -51,6 +51,8 @@ * @speed_bin: Application processor speed bin fuse parameter value for * the given chip * @cpr_fusing_rev: CPR fusing revision fuse parameter value * @foundry_id: Foundry identifier fuse parameter value for the given * chip * @boost_cfg: CPR boost configuration fuse parameter value * @boost_voltage: CPR boost voltage fuse parameter value (raw, not * converted to a voltage) Loading @@ -66,6 +68,7 @@ struct cpr4_msm8953_apss_fuses { u64 quot_offset[MSM8953_APSS_FUSE_CORNERS]; u64 speed_bin; u64 cpr_fusing_rev; u64 foundry_id; u64 boost_cfg; u64 boost_voltage; u64 misc; Loading Loading @@ -149,6 +152,11 @@ static const struct cpr3_fuse_param msm8953_apss_speed_bin_param[] = { {}, }; static const struct cpr3_fuse_param msm8953_apss_foundry_id_param[] = { {37, 40, 42}, {}, }; static const struct cpr3_fuse_param msm8953_cpr_boost_fuse_cfg_param[] = { {36, 43, 45}, {}, Loading @@ -170,6 +178,15 @@ static const struct cpr3_fuse_param msm8953_apss_aging_init_quot_diff_param[] {}, }; /* * The maximum number of fuse combinations possible for the selected fuse * parameters in fuse combo map logic. * Here, possible speed-bin values = 8, fuse revision values = 8, and foundry * identifier values = 8. Total number of combinations = 512 (i.e., 8 * 8 * 8) */ #define CPR4_MSM8953_APSS_FUSE_COMBO_MAP_MAX_COUNT 512 /* * The number of possible values for misc fuse is * 2^(#bits defined for misc fuse) Loading Loading @@ -260,6 +277,14 @@ static int cpr4_msm8953_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, msm8953_apss_foundry_id_param, &fuse->foundry_id); if (rc) { cpr3_err(vreg, "Unable to read foundry id fuse, rc=%d\n", rc); return rc; } cpr3_info(vreg, "foundry id = %llu\n", fuse->foundry_id); rc = cpr3_read_fuse_param(base, msm8953_misc_fuse_volt_adj_param, &fuse->misc); if (rc) { Loading Loading @@ -1145,6 +1170,58 @@ done: return rc; } /* * Constants which define the selection fuse parameters used in fuse combo map * logic. */ enum cpr4_msm8953_apss_fuse_combo_parameters { MSM8953_APSS_SPEED_BIN = 0, MSM8953_APSS_CPR_FUSE_REV, MSM8953_APSS_FOUNDRY_ID, MSM8953_APSS_FUSE_COMBO_PARAM_COUNT, }; /** * cpr4_parse_fuse_combo_map() - parse APSS fuse combo map data from device tree * properties of the CPR3 regulator's device node * @vreg: Pointer to the CPR3 regulator * * Return: 0 on success, errno on failure */ static int cpr4_parse_fuse_combo_map(struct cpr3_regulator *vreg) { struct cpr4_msm8953_apss_fuses *fuse = vreg->platform_fuses; u64 *fuse_val; int rc; fuse_val = kcalloc(MSM8953_APSS_FUSE_COMBO_PARAM_COUNT, sizeof(*fuse_val), GFP_KERNEL); if (!fuse_val) return -ENOMEM; fuse_val[MSM8953_APSS_SPEED_BIN] = fuse->speed_bin; fuse_val[MSM8953_APSS_CPR_FUSE_REV] = fuse->cpr_fusing_rev; fuse_val[MSM8953_APSS_FOUNDRY_ID] = fuse->foundry_id; rc = cpr3_parse_fuse_combo_map(vreg, fuse_val, MSM8953_APSS_FUSE_COMBO_PARAM_COUNT); if (rc == -ENODEV) { cpr3_debug(vreg, "using legacy fuse combo logic, rc=%d\n", rc); rc = 0; } else if (rc < 0) { cpr3_err(vreg, "error reading fuse combo map data, rc=%d\n", rc); } else if (vreg->fuse_combo >= CPR4_MSM8953_APSS_FUSE_COMBO_MAP_MAX_COUNT) { cpr3_err(vreg, "invalid CPR fuse combo = %d found\n", vreg->fuse_combo); rc = -EINVAL; } kfree(fuse_val); return rc; } /** * cpr4_apss_init_regulator() - perform all steps necessary to initialize the * configuration data for a CPR3 regulator Loading @@ -1165,6 +1242,13 @@ static int cpr4_apss_init_regulator(struct cpr3_regulator *vreg) fuse = vreg->platform_fuses; rc = cpr4_parse_fuse_combo_map(vreg); if (rc) { cpr3_err(vreg, "error while parsing fuse combo map, rc=%d\n", rc); return rc; } rc = cpr4_apss_parse_corner_data(vreg); if (rc) { cpr3_err(vreg, "unable to read CPR corner data from device tree, rc=%d\n", Loading