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

Commit 2cb2a114 authored by Jordan Crouse's avatar Jordan Crouse
Browse files

msm: kgsl: Move voltage levels to the GPU specific powerlevels



There are only two reasons for us to define a OPP table these days, and
one of them is to define the voltage levels that we send to the GMU.
That is silly because we have a perfectly good power level definition
already handy. Move the levels to the GPU definition and use them
accordingly.

Change-Id: Ic0dedbad2d3c84a2de7cda5311ff99e96434b9e5
Signed-off-by: default avatarJordan Crouse <jcrouse@codeaurora.org>
parent 55dccd62
Loading
Loading
Loading
Loading
+34 −24
Original line number Diff line number Diff line
@@ -907,30 +907,45 @@ static int adreno_of_parse_pwrlevels(struct adreno_device *adreno_dev,
	pwr->num_pwrlevels = 0;

	for_each_child_of_node(node, child) {
		unsigned int index, freq = 0;
		u32 index, freq = 0, voltage, bus;
		struct kgsl_pwrlevel *level;

		if (of_property_read_u32(child, "reg", &index)) {
			dev_err(device->dev,
				"%pOF: powerlevel index not found\n", child);
			of_node_put(child);
			return -EINVAL;
		ret = of_property_read_u32(child, "reg", &index);
		if (ret) {
			dev_err(device->dev, "%pOF: powerlevel index not found\n",
				child);
			goto out;
		}

		if (of_property_read_u32(child, "qcom,gpu-freq", &freq)) {
			dev_err(device->dev,
				"%pOF: Unable to read qcom,gpu-freq\n", child);
			of_node_put(child);
			return -EINVAL;
		ret = of_property_read_u32(child, "qcom,gpu-freq", &freq);
		if (ret) {
			dev_err(device->dev, "%pOF: Unable to read qcom,gpu-freq\n",
				child);
			goto out;
		}

		/* Ignore "zero" powerlevels */
		if (!freq)
			continue;

		ret = of_property_read_u32(child, "qcom,level", &voltage);
		if (ret) {
			dev_err(device->dev, "%pOF: Unable to read qcom,level\n",
				child);
			goto out;
		}

		ret = kgsl_of_property_read_ddrtype(child, "qcom,bus-freq",
			&bus);
		if (ret) {
			dev_err(device->dev, "%pOF:Unable to read qcom,bus-freq\n",
				child);
			goto out;
		}


		if (index >= KGSL_MAX_PWRLEVELS) {
			dev_err(device->dev,
				"%pOF: Pwrlevel index %d is out of range\n",
			dev_err(device->dev, "%pOF: Pwrlevel index %d is out of range\n",
				child, index);
			continue;
		}
@@ -941,20 +956,12 @@ static int adreno_of_parse_pwrlevels(struct adreno_device *adreno_dev,
		level = &pwr->pwrlevels[index];

		level->gpu_freq = freq;
		level->bus_freq = bus;
		level->voltage_level = voltage;

		of_property_read_u32(child, "qcom,acd-level",
			&level->acd_level);

		ret = kgsl_of_property_read_ddrtype(child,
			"qcom,bus-freq", &level->bus_freq);
		if (ret) {
			dev_err(device->dev,
				"%pOF: Couldn't read the bus frequency for power level %d\n",
				child, index);
			of_node_put(child);
			return ret;
		}

		level->bus_min = level->bus_freq;
		kgsl_of_property_read_ddrtype(child,
			"qcom,bus-min", &level->bus_min);
@@ -965,6 +972,9 @@ static int adreno_of_parse_pwrlevels(struct adreno_device *adreno_dev,
	}

	return 0;
out:
	of_node_put(child);
	return ret;
}

static void adreno_of_get_initial_pwrlevel(struct adreno_device *adreno_dev,
+17 −31
Original line number Diff line number Diff line
@@ -690,45 +690,22 @@ static int rpmh_arc_votes_init(struct kgsl_device *device,
{
	unsigned int num_freqs;
	u16 vlvl_tbl[MAX_GX_LEVELS];
	unsigned int *freq_tbl;
	int i;
	struct dev_pm_opp *opp;

	if (type == GMU_ARC_VOTE)
		return rpmh_gmu_arc_votes_init(gmu, pri_rail, sec_rail);

	num_freqs = gmu->num_gpupwrlevels;
	freq_tbl = gmu->gpu_freqs;

	if (num_freqs > pri_rail->num || num_freqs > MAX_GX_LEVELS) {
	if (num_freqs > pri_rail->num) {
		dev_err(&gmu->pdev->dev,
			"Defined more GPU DCVS levels than RPMh can support\n");
		return -EINVAL;
	}

	memset(vlvl_tbl, 0, sizeof(vlvl_tbl));

	/* Get the values from OPP API */
	for (i = 0; i < num_freqs; i++) {
		/* Hardcode VLVL 0 because it is not present in OPP */
		if (freq_tbl[i] == 0) {
			vlvl_tbl[i] = 0;
			continue;
		}

		opp = dev_pm_opp_find_freq_exact(&device->pdev->dev,
			freq_tbl[i], true);

		if (IS_ERR(opp)) {
			dev_err(&gmu->pdev->dev,
				"Failed to find opp freq %d for GPU\n",
				freq_tbl[i]);
			return PTR_ERR(opp);
		}

		vlvl_tbl[i] = dev_pm_opp_get_voltage(opp);
		dev_pm_opp_put(opp);
	}
	for (i = 0; i < num_freqs; i++)
		vlvl_tbl[i] = gmu->pwrlevels[i].level;

	return setup_volt_dependency_tbl(gmu->rpmh_votes.gx_votes, pri_rail,
						sec_rail, vlvl_tbl, num_freqs);
@@ -1205,7 +1182,7 @@ static int gmu_probe(struct kgsl_device *device, struct device_node *node)
	struct kgsl_hfi *hfi;
	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	int i = 0, ret = -ENXIO, index = 0;
	int i = 0, ret = -ENXIO, index;

	gmu = kzalloc(sizeof(struct gmu_device), GFP_KERNEL);

@@ -1275,12 +1252,21 @@ static int gmu_probe(struct kgsl_device *device, struct device_node *node)
	tasklet_init(&hfi->tasklet, hfi_receiver, (unsigned long) gmu);
	hfi->kgsldev = device;

	/* Add a dummy level for "off" that the GMU expects */
	gmu->gpu_freqs[index++] = 0;
	if (WARN(pwr->num_pwrlevels + 1 > ARRAY_SIZE(gmu->pwrlevels),
		"Too many GPU powerlevels for the GMU HFI\n")) {
		ret = -EINVAL;
		goto error;
	}

	/* Add a dummy level for "off" because the GMU expects it */
	gmu->pwrlevels[0].freq = 0;
	gmu->pwrlevels[0].level = 0;

	/* GMU power levels are in ascending order */
	for (i = pwr->num_pwrlevels - 1; i >= 0; i--)
		gmu->gpu_freqs[index++] = pwr->pwrlevels[i].gpu_freq;
	for (index = 1, i = pwr->num_pwrlevels - 1; i >= 0; i--, index++) {
		gmu->pwrlevels[index].freq = pwr->pwrlevels[i].gpu_freq;
		gmu->pwrlevels[index].level = pwr->pwrlevels[i].voltage_level;
	}

	gmu->num_gpupwrlevels = pwr->num_pwrlevels + 1;

+7 −2
Original line number Diff line number Diff line
@@ -158,7 +158,6 @@ struct icc_path;
 * @dump_mem: pointer to GMU debug dump memory
 * @gmu_log: gmu event log memory
 * @hfi: HFI controller
 * @gpu_freqs: GPU frequency table with lowest freq at index 0
 * @num_gpupwrlevels: number GPU frequencies in GPU freq table
 * @num_bwlevel: number of GPU BW levels
 * @num_cnocbwlevel: number CNOC BW levels
@@ -194,7 +193,13 @@ struct gmu_device {
	struct gmu_memdesc *dump_mem;
	struct gmu_memdesc *gmu_log;
	struct kgsl_hfi hfi;
	unsigned int gpu_freqs[MAX_GX_LEVELS];
	/** @pwrlevels: Array of GMU power levels */
	struct {
		/** @freq: GPU frequency */
		unsigned long freq;
		/** @level: Voltage level */
		u32 level;
	} pwrlevels[MAX_GX_LEVELS];
	unsigned int num_gpupwrlevels;
	unsigned int num_bwlevels;
	unsigned int num_cnocbwlevels;
+2 −2
Original line number Diff line number Diff line
@@ -437,7 +437,7 @@ static int hfi_send_dcvstbl_v1(struct gmu_device *gmu)
	for (i = 0; i < gmu->num_gpupwrlevels; i++) {
		cmd.gx_votes[i].vote = gmu->rpmh_votes.gx_votes[i];
		/* Divide by 1000 to convert to kHz */
		cmd.gx_votes[i].freq = gmu->gpu_freqs[i] / 1000;
		cmd.gx_votes[i].freq = gmu->pwrlevels[i].freq / 1000;
	}

	cmd.cx_votes[0].vote = gmu->rpmh_votes.cx_votes[0];
@@ -483,7 +483,7 @@ static int hfi_send_dcvstbl(struct gmu_device *gmu)
		/* Hardcode this to the max threshold since it is not used */
		cmd.gx_votes[i].acd = 0xFFFFFFFF;
		/* Divide by 1000 to convert to kHz */
		cmd.gx_votes[i].freq = gmu->gpu_freqs[i] / 1000;
		cmd.gx_votes[i].freq = gmu->pwrlevels[i].freq / 1000;
	}

	cmd.cx_votes[0].vote = gmu->rpmh_votes.cx_votes[0];
+2 −0
Original line number Diff line number Diff line
@@ -69,6 +69,8 @@ struct kgsl_pwrlevel {
	unsigned int bus_min;
	unsigned int bus_max;
	unsigned int acd_level;
	/** @voltage_level: Voltage level used by the GMU to vote RPMh */
	u32 voltage_level;
};

/**