Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f19b503f authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "regulator: mem-acc: Remove skip L1 memory ACC configuration logic"

parents e1af5f9d b22f3aac
Loading
Loading
Loading
Loading
+51 −48
Original line number Diff line number Diff line
@@ -53,21 +53,6 @@ Optional properties:
				defined by the qcom,acc-sel-l2-bit-size
				property.  This N-bit value specifies the corner
				value used by the accelerator for the L2 cache.
- qcom,l1-config-skip-fuse-sel:	Array of 5 elements to indicate where to read the bits, what value to
				compare with in order to decide whether to
				skip configuring the L1 accelerator or not while changing the APC corner
				and method to read fuse row, using SCM to read or read register directly.
				The 5 elements with index [0..4] are:
				  [0] => the fuse row number of the selector
				  [1] => LSB bit position of the bits
				  [2] => number of bits
				  [3] => the value to select skip L1 config logic
				  [4] => fuse reading method, 0 for direct reading or 1 for SCM reading
				When the value of the fuse bits specified by first 3 elements equals to
				the value in 4th element, L1 accelerator
				configuration logic is skipped. Otherwise, the original configuration sent
				from corner map should be applied. If the 5th element is 0, read the fuse row
				from register directly. Otherwise, read it through SCM.
- qcom,l1-acc-custom-data:	Array which maps APC corner values to L1 ACC custom data values.
				The corresponding custom data is written into the custom register
				while switching between APC corners. The custom register address
@@ -78,39 +63,50 @@ Optional properties:
				while switching between APC corners. The custom register address
				is specified by "acc-l2-custom" reg-property. The length of the array
				should be equal to number of APC corners.
- qcom,override-acc-fuse-sel:	Array of 5 elements to indicate where to read the bits, what value to
				compare with in order to decide whether to
				apply override acc-map and custom data or not
				and method to read fuse row, using SCM to read or read register directly.
				The 5 elements with index [0..4] are:
- qcom,override-acc-fuse-sel:	Array of 4 elements which specify the way to read the override fuse.
				The override fuse value is used by the qcom,override-fuse-version-map
				to identify the correct set of override properties.
				The 4 elements with index [0..4] are:
				  [0] => the fuse row number of the selector
				  [1] => LSB bit position of the bits
				  [2] => number of bits
				  [3] => the value to select override ACC configuration
				  [4] => fuse reading method, 0 for direct reading or 1 for SCM reading
				When the value of the fuse bits specified by first 3 elements equals to the value
				in 4th element, overridden accelerator configuration logic is applied.
				Otherwise, the original configuration should be applied. If the 5th element is 0,
				read the fuse row from register directly. Otherwise, read it through SCM.
- qcom,override-corner-acc-map:	Array which overrides the existing acc-corner map (specified by qcom,corner-acc-map)
				with corner values specified in this property.
				[0] maps APC SVS corner (1) to accelerator SVS corner
				[1] maps APC NOMINAL corner (2) to accelerator NOMINAL corner
				[2] maps APC TURBO corner (3) to accelerator TURBO corner
- qcom,override-l1-acc-custom-data:	Array which overrides the existing l1-acc-custom data
				  [3] => fuse reading method, 0 for direct reading or 1 for SCM reading
- qcom,override-fuse-version-map: Array of integers which each match to a override fuse value.
				Any element in a tuple may use the value 0xffffffff as a wildcard.
				The index of the first value (in the array) which matches the override fuse
				is used to select the right tuples from the other override properties.
- qcom,override-corner-acc-map:	Array of tuples which overrides the existing acc-corner map
				(specified by qcom,corner-acc-map) with corner values selected
				from this property. "qcom,override-corner-acc-map" must contain the
				same number of tuples as "qcom,override-fuse-version-map". These tuples
				are then mapped one-to-one in the order specified. If the
				"qcom,override-fuse-version-map" property is not specified, then
				"qcom,override-corner-acc-map" must contain a single tuple which is then
				applied unconditionally.
- qcom,override-l1-acc-custom-data:	Array of tuples of which overrides the existing l1-acc-custom data
				(specified by qcom,l1-acc-custom-data), with values specified in this property.
				The corresponding custom data is written into the custom register
				while switching between APC corners. The custom register address
				is specified by "acc-11-custom" reg-property. The length of the array
				should be equal to number of APC corners.
				This property can only be specified if the "qcom,l1-acc-custom-data" is already defined.
- qcom,override-l2-acc-custom-data:	Array which overrides the existing l2-acc-custom data
				(specified by qcom,l2-acc-custom-data) with values specified in this property.
				The corresponding custom data is written into the custom register
				while switching between APC corners. The custom register address
				is specified by "acc-l2-custom" reg-property. The length of the array
				should be equal to number of APC corners.
				This property can only be specified if the " qcom,l2-acc-custom-data" is already defined.
				The corresponding custom data is written into the custom register while
				switching between APC corners. The custom register address is specified by
				"acc-11-custom" reg-property. This property can only be specified if the
				"qcom,l1-acc-custom-data" is already defined. If the
				"qcom,override-fuse-version-map" property is specified, then
				qcom,override-l1-acc-custom-data must contain the same number of tuples
				as "qcom,override-fuse-version-map". These tuples are then mapped one-to-one
				in the order specified. If the qcom,override-fuse-version-map property is
				not specified, then "qcom,override-l1-acc-custom-data" must contain a single
				tuple which is then applied unconditionally.
- qcom,override-l2-acc-custom-data:	Array of tuples of which overrides the existing l1-acc-custom data
				(specified by qcom,l2-acc-custom-data), with values specified in this property.
				The corresponding custom data is written into the custom register while
				switching between APC corners. The custom register address is specified by
				"acc-12-custom" reg-property. This property can only be specified if the
				"qcom,l2-acc-custom-data" is already defined. If the
				"qcom,override-fuse-version-map" property is specified, then
				"qcom,override-l2-acc-custom-data" must contain the same number of tuples
				as "qcom,override-fuse-version-map". These tuples are then mapped one-to-one
				in the order specified. If the qcom,override-fuse-version-map property is
				not specified, then "qcom,override-l2-acc-custom-data" must contain a single
				tuple which is then applied unconditionally.
- qcom,mem-acc-type1:		Array which specifies the value to be written to the mem acc type1 register for each fuse
				corner, from the lowest fuse corner to the highest fuse corner. The length of the array
				must be equal to the number of APC fuse corners. This property must be present if reg names
@@ -139,11 +135,18 @@ mem_acc_vreg_corner: regulator@fd4aa044 {
	qcom,acc-sel-l1-bit-size = <2>;
	qcom,acc-sel-l2-bit-size = <2>;
	qcom,corner-acc-map = <0 1 3>;
	qcom,l1-config-skip-fuse-sel = <0 52 1 1 0>;
	qcom,l2-acc-custom-data = <0x0 0x3000 0x3000>;
	qcom,override-acc-fuse-sel = <0 52 1 1 0>;
	qcom,override-corner-acc-map = <0 0 1>;
	qcom,overide-l2-acc-custom-data = <0x0 0x0 0x3000>;

	qcom,override-acc-fuse-sel = <0 52 2 0>;
	qcom,override-fuse-version-map = <0>,
					 <2>,
					 <(-1)>;
	qcom,override-corner-acc-map =	<0 0 1>,
					<0 1 2>,
					<0 1 1>;
	qcom,overide-l2-acc-custom-data = <0x0	0x0	0x3000>,
					  <0x0	0x3000	0x3000>,
					  <0x0	0x0	0x0>;
	qcom,mem-acc-type1 = <0x02 0x02 0x00>;
	qcom,mem-acc-type2 = <0x02 0x02 0x00>;
	qcom,mem-acc-type3 = <0x02 0x02 0x00>;
+16 −4
Original line number Diff line number Diff line
@@ -308,15 +308,26 @@
&soc {
	mem_acc_vreg_corner: regulator@01942130 {
		compatible = "qcom,mem-acc-regulator";
		reg = <0x1942130 0x4>;
		reg-names = "acc-sel-l1";
		reg = <0x1942130 0x4>, <0x5c000 0x1000>;
		reg-names = "acc-sel-l1", "efuse_addr";
		regulator-name = "mem_acc_corner";
		regulator-min-microvolt = <1>;
		regulator-max-microvolt = <3>;
		regulator-max-microvolt = <4>;

		qcom,acc-sel-l1-bit-pos = <0>;
		qcom,acc-sel-l1-bit-size = <16>;
		qcom,corner-acc-map = <0x0 0x5555 0x5555>;
		qcom,corner-acc-map = <0x0 0x5454 0x5555 0xFFFF>;

		qcom,override-acc-fuse-sel = <29 43 2 0>;
		qcom,override-fuse-version-map = <0>,
						 <1>,
						 <2>,
						 <3>;
		qcom,override-corner-acc-map =
					<0x0    0x5454  0x5555  0xFFFF>,
					<0x0    0x5400  0x5555  0xFFFF>,
					<0x0    0x0054  0x5555  0xFFFF>,
					<0x0    0x0     0x5555  0xFFFF>;
	};

	apc_vreg_corner: regulator@b018000 {
@@ -356,6 +367,7 @@
					 <RPM_SMD_REGULATOR_LEVEL_TURBO>;

		mem-acc-supply = <&mem_acc_vreg_corner>;
		qcom,mem-acc-corner-map = <1 2 2 2 3 4 4 4>;

		qcom,cpr-ref-clk = <19200>;
		qcom,cpr-timer-delay = <5000>;
+154 −87
Original line number Diff line number Diff line
@@ -32,8 +32,8 @@
#define BYTES_PER_FUSE_ROW		8

/* mem-acc config flags */
#define MEM_ACC_SKIP_L1_CONFIG		BIT(0)
#define MEM_ACC_OVERRIDE_CONFIG		BIT(1)
#define FUSE_MAP_NO_MATCH		(-1)
#define FUSE_PARAM_MATCH_ANY		(-1)

enum {
	MEMORY_L1,
@@ -60,6 +60,10 @@ struct mem_acc_regulator {
	u32			num_acc_en;
	u32			*corner_acc_map;
	u32			num_corners;
	u32			override_fuse_value;
	int			override_map_match;
	int			override_map_count;


	void __iomem		*acc_sel_base[MEMORY_MAX];
	void __iomem		*acc_en_base;
@@ -129,28 +133,6 @@ static u64 mem_acc_read_efuse_row(struct mem_acc_regulator *mem_acc_vreg,
	return efuse_bits;
}

static int mem_acc_fuse_is_setting_expected(
		struct mem_acc_regulator *mem_acc_vreg, u32 sel_array[5])
{
	u64 fuse_bits;
	u32 ret;

	fuse_bits = mem_acc_read_efuse_row(mem_acc_vreg, sel_array[0],
							sel_array[4]);
	ret = (fuse_bits >> sel_array[1]) & ((1 << sel_array[2]) - 1);
	if (ret == sel_array[3])
		ret = 1;
	else
		ret = 0;

	pr_info("[row:%d] = 0x%llx @%d:%d == %d ?: %s\n",
			sel_array[0], fuse_bits,
			sel_array[1], sel_array[2],
			sel_array[3],
			(ret == 1) ? "yes" : "no");
	return ret;
}

static inline u32 apc_to_acc_corner(struct mem_acc_regulator *mem_acc_vreg,
								int corner)
{
@@ -166,14 +148,6 @@ static void __update_acc_sel(struct mem_acc_regulator *mem_acc_vreg,
{
	u32 acc_data, acc_data_old, i, bit, acc_corner;

	/*
	 * Do not configure the L1 ACC corner if the the corresponding flag is
	 * set.
	 */
	if ((mem_type == MEMORY_L1)
			&& (mem_acc_vreg->flags & MEM_ACC_SKIP_L1_CONFIG))
		return;

	acc_data = readl_relaxed(mem_acc_vreg->acc_sel_base[mem_type]);
	acc_data_old = acc_data;
	for (i = 0; i < mem_acc_vreg->num_acc_sel[mem_type]; i++) {
@@ -422,8 +396,7 @@ static int mem_acc_efuse_init(struct platform_device *pdev,
				 struct mem_acc_regulator *mem_acc_vreg)
{
	struct resource *res;
	int len, rc = 0;
	u32 l1_config_skip_fuse_sel[5];
	int len;

	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "efuse_addr");
	if (!res || !res->start) {
@@ -445,24 +418,6 @@ static int mem_acc_efuse_init(struct platform_device *pdev,
		return -EINVAL;
	}

	if (of_find_property(mem_acc_vreg->dev->of_node,
				"qcom,l1-config-skip-fuse-sel", NULL)) {
		rc = of_property_read_u32_array(mem_acc_vreg->dev->of_node,
					"qcom,l1-config-skip-fuse-sel",
					l1_config_skip_fuse_sel, 5);
		if (rc < 0) {
			pr_err("Read failed - qcom,l1-config-skip-fuse-sel rc=%d\n",
					rc);
			return rc;
		}

		if (mem_acc_fuse_is_setting_expected(mem_acc_vreg,
						l1_config_skip_fuse_sel)) {
			mem_acc_vreg->flags |= MEM_ACC_SKIP_L1_CONFIG;
			pr_debug("Skip L1 configuration enabled\n");
		}
	}

	return 0;
}

@@ -532,7 +487,9 @@ static int override_mem_acc_custom_data(struct platform_device *pdev,
				 int mem_type)
{
	char *custom_apc_data_str;
	int len, rc = 0;
	int len, rc = 0, i;
	int tuple_count, tuple_match;
	u32 index = 0, value = 0;

	switch (mem_type) {
	case MEMORY_L1:
@@ -547,37 +504,148 @@ static int override_mem_acc_custom_data(struct platform_device *pdev,
	}

	if (!of_find_property(mem_acc_vreg->dev->of_node,
				custom_apc_data_str, NULL)) {
				custom_apc_data_str, &len)) {
		pr_debug("%s not specified\n", custom_apc_data_str);
		return 0;
	}

	/* Free old custom data */
	devm_kfree(&pdev->dev, mem_acc_vreg->acc_custom_data[mem_type]);
	if (mem_acc_vreg->override_map_count) {
		if (mem_acc_vreg->override_map_match == FUSE_MAP_NO_MATCH)
			return 0;
		tuple_count = mem_acc_vreg->override_map_count;
		tuple_match = mem_acc_vreg->override_map_match;
	} else {
		tuple_count = 1;
		tuple_match = 0;
	}

	/* Populate override custom data */
	rc = populate_acc_data(mem_acc_vreg, custom_apc_data_str,
				&mem_acc_vreg->acc_custom_data[mem_type], &len);
	if (len != mem_acc_vreg->num_corners * tuple_count * sizeof(u32)) {
		pr_err("%s length=%d is invalid\n", custom_apc_data_str, len);
		return -EINVAL;
	}

	for (i = 0; i < mem_acc_vreg->num_corners; i++) {
		index = (tuple_match * mem_acc_vreg->num_corners) + i;
		rc = of_property_read_u32_index(mem_acc_vreg->dev->of_node,
					custom_apc_data_str, index, &value);
		if (rc) {
		pr_err("Unable to find %s rc=%d\n", custom_apc_data_str, rc);
			pr_err("Unable read %s index %u, rc=%d\n",
					custom_apc_data_str, index, rc);
			return rc;
		}
		mem_acc_vreg->acc_custom_data[mem_type][i] = value;
	}

	if (mem_acc_vreg->num_corners != len) {
		pr_err("Override custom data is not present for all the corners\n");
	return 0;
}

static int mem_acc_override_corner_map(struct mem_acc_regulator *mem_acc_vreg)
{
	int len = 0, i, rc;
	int tuple_count, tuple_match;
	u32 index = 0, value = 0;
	char *prop_str = "qcom,override-corner-acc-map";

	if (!of_find_property(mem_acc_vreg->dev->of_node, prop_str, &len))
		return 0;

	if (mem_acc_vreg->override_map_count) {
		if (mem_acc_vreg->override_map_match ==	FUSE_MAP_NO_MATCH)
			return 0;
		tuple_count = mem_acc_vreg->override_map_count;
		tuple_match = mem_acc_vreg->override_map_match;
	} else {
		tuple_count = 1;
		tuple_match = 0;
	}

	if (len != mem_acc_vreg->num_corners * tuple_count * sizeof(u32)) {
		pr_err("%s length=%d is invalid\n", prop_str, len);
		return -EINVAL;
	}

	for (i = 0; i < mem_acc_vreg->num_corners; i++) {
		index = (tuple_match * mem_acc_vreg->num_corners) + i;
		rc = of_property_read_u32_index(mem_acc_vreg->dev->of_node,
						prop_str, index, &value);
		if (rc) {
			pr_err("Unable read %s index %u, rc=%d\n",
						prop_str, index, rc);
			return rc;
		}
		mem_acc_vreg->corner_acc_map[i] = value;
	}

	return 0;

}

static int mem_acc_find_override_map_match(struct platform_device *pdev,
				 struct mem_acc_regulator *mem_acc_vreg)
{
	struct device_node *of_node = pdev->dev.of_node;
	int i, rc, tuple_size;
	int len = 0;
	u32 *tmp;
	char *prop_str = "qcom,override-fuse-version-map";

	/* Specify default no match case. */
	mem_acc_vreg->override_map_match = FUSE_MAP_NO_MATCH;
	mem_acc_vreg->override_map_count = 0;

	if (!of_find_property(of_node, prop_str, &len)) {
		/* No mapping present. */
		return 0;
	}

	tuple_size = 1;
	mem_acc_vreg->override_map_count = len / (sizeof(u32) * tuple_size);

	if (len == 0 || len % (sizeof(u32) * tuple_size)) {
		pr_err("%s length=%d is invalid\n", prop_str, len);
		return -EINVAL;
	}

	tmp = kzalloc(len, GFP_KERNEL);
	if (!tmp)
		return -ENOMEM;

	rc = of_property_read_u32_array(of_node, prop_str, tmp,
			mem_acc_vreg->override_map_count * tuple_size);
	if (rc) {
		pr_err("could not read %s rc=%d\n", prop_str, rc);
		goto done;
	}

	for (i = 0; i < mem_acc_vreg->override_map_count; i++) {
		if (tmp[i * tuple_size] != mem_acc_vreg->override_fuse_value
		    && tmp[i * tuple_size] != FUSE_PARAM_MATCH_ANY) {
			continue;
		} else {
			mem_acc_vreg->override_map_match = i;
			break;
		}
	}

	if (mem_acc_vreg->override_map_match != FUSE_MAP_NO_MATCH)
		pr_debug("%s tuple match found: %d\n", prop_str,
				mem_acc_vreg->override_map_match);
	else
		pr_err("%s tuple match not found\n", prop_str);

done:
	kfree(tmp);
	return rc;
}

#define MEM_TYPE_STRING_LEN	20
static int mem_acc_init(struct platform_device *pdev,
		struct mem_acc_regulator *mem_acc_vreg)
{
	struct resource *res;
	int len, rc, i, j;
	u32 override_acc_fuse_sel[5];
	u32 fuse_sel[4];
	u64 fuse_bits;
	bool acc_type_present = false;
	char tmps[MEM_TYPE_STRING_LEN];

@@ -692,38 +760,37 @@ static int mem_acc_init(struct platform_device *pdev,
	if (of_find_property(mem_acc_vreg->dev->of_node,
				"qcom,override-acc-fuse-sel", NULL)) {
		rc = of_property_read_u32_array(mem_acc_vreg->dev->of_node,
					"qcom,override-acc-fuse-sel",
					override_acc_fuse_sel, 5);
			"qcom,override-acc-fuse-sel", fuse_sel, 4);
		if (rc < 0) {
			pr_err("Read failed - qcom,override-acc-fuse-sel rc=%d\n",
					rc);
			return rc;
		}

		if (mem_acc_fuse_is_setting_expected(mem_acc_vreg,
						override_acc_fuse_sel)) {
			mem_acc_vreg->flags |= MEM_ACC_OVERRIDE_CONFIG;
			pr_debug("Apply ACC override configuration\n");
		}
		fuse_bits = mem_acc_read_efuse_row(mem_acc_vreg, fuse_sel[0],
								fuse_sel[3]);
		/*
		 * fuse_sel[1] = LSB position in row (shift)
		 * fuse_sel[2] = num of bits (mask)
		 */
		mem_acc_vreg->override_fuse_value = (fuse_bits >> fuse_sel[1]) &
						((1 << fuse_sel[2]) - 1);

		rc = mem_acc_find_override_map_match(pdev, mem_acc_vreg);
		if (rc) {
			pr_err("Unable to find fuse map match rc=%d\n", rc);
			return rc;
		}

	if (mem_acc_vreg->flags & MEM_ACC_OVERRIDE_CONFIG) {
		if (of_find_property(mem_acc_vreg->dev->of_node,
				"qcom,override-corner-acc-map", NULL)) {
			/* Free old corner-acc-map */
			devm_kfree(&pdev->dev, mem_acc_vreg->corner_acc_map);
		pr_debug("override_fuse_val=%d override_map_match=%d\n",
					mem_acc_vreg->override_fuse_value,
					mem_acc_vreg->override_map_match);

			/* Populate override corner acc map */
			rc = populate_acc_data(mem_acc_vreg,
						"qcom,override-corner-acc-map",
						&mem_acc_vreg->corner_acc_map,
						&mem_acc_vreg->num_corners);
		rc = mem_acc_override_corner_map(mem_acc_vreg);
		if (rc) {
				pr_err("Unable to find 'qcom,overrie-corner-acc-map' rc=%d\n",
					rc);
			pr_err("Unable to override corner map rc=%d\n", rc);
			return rc;
		}
		}

		for (i = 0; i < MEMORY_MAX; i++) {
			rc = override_mem_acc_custom_data(pdev,