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

Commit 16808973 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: kgsl: Bring in the GPU bandwidth governor"

parents e64d7841 07ba0273
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -10,8 +10,27 @@ config QCOM_KGSL
	  on QTI targets. This includes power management, memory management,
	  and scheduling for the Adreno GPUs.

config DEVFREQ_GOV_QCOM_ADRENO_TZ
	tristate "Qualcomm Technologies, Inc. GPU frequency governor"
	depends on PM_DEVFREQ && QCOM_KGSL
	help
	  GPU frequency governor for the Adreno GPU. Sets the frequency
	  using an "on demand" algorithm in conjunction with other
	  components on Adreno platforms. This is not useful for non-Adreno
	  devices.

config DEVFREQ_GOV_QCOM_GPUBW_MON
	tristate "Qualcomm Technologies, Inc. GPU bandwidth governor"
	depends on DEVFREQ_GOV_QCOM_ADRENO_TZ
	help
	  This governor works together with the Adreno GPU governor to
	  select bus frequency votes using an "on-demand" algorithm.
	  This governor will not be useful for non-Adreno based
	  targets.

config QCOM_ADRENO_DEFAULT_GOVERNOR
	string "devfreq governor for the adreno core"
	default "msm-adreno-tz" if DEVFREQ_GOV_QCOM_ADRENO_TZ
	default "simple_ondemand"
	depends on QCOM_KGSL

+3 −0
Original line number Diff line number Diff line
@@ -52,3 +52,6 @@ msm_kgsl-$(CONFIG_COMPAT) += adreno_compat.o
msm_kgsl-$(CONFIG_QCOM_KGSL_CORESIGHT) += adreno_coresight.o
msm_kgsl-$(CONFIG_DEBUG_FS) += adreno_debugfs.o adreno_profile.o
msm_kgsl-$(CONFIG_ARM_SMMU) += adreno_iommu.o

obj-$(CONFIG_DEVFREQ_GOV_QCOM_ADRENO_TZ) += governor_msm_adreno_tz.o
obj-$(CONFIG_DEVFREQ_GOV_QCOM_GPUBW_MON) += governor_gpubw_mon.o
+59 −14
Original line number Diff line number Diff line
@@ -842,7 +842,7 @@ static void adreno_of_get_ca_target_pwrlevel(struct adreno_device *adreno_dev,
	of_property_read_u32(node, "qcom,ca-target-pwrlevel",
		&ca_target_pwrlevel);

	if (ca_target_pwrlevel > device->pwrctrl.num_pwrlevels - 2)
	if (ca_target_pwrlevel >= device->pwrctrl.num_pwrlevels)
		ca_target_pwrlevel = 1;

	device->pwrscale.ctxt_aware_target_pwrlevel = ca_target_pwrlevel;
@@ -907,15 +907,27 @@ 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;
		unsigned int index, freq = 0;
		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;
		}

		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;
		}

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

		if (index >= KGSL_MAX_PWRLEVELS) {
			dev_err(device->dev,
				"%pOF: Pwrlevel index %d is out of range\n",
@@ -928,12 +940,7 @@ static int adreno_of_parse_pwrlevels(struct adreno_device *adreno_dev,

		level = &pwr->pwrlevels[index];

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

		of_property_read_u32(child, "qcom,acd-level",
			&level->acd_level);
@@ -944,6 +951,7 @@ static int adreno_of_parse_pwrlevels(struct adreno_device *adreno_dev,
			dev_err(device->dev,
				"%pOF: Couldn't read the bus frequency for power level %d\n",
				child, index);
			of_node_put(child);
			return ret;
		}

@@ -968,7 +976,7 @@ static void adreno_of_get_initial_pwrlevel(struct adreno_device *adreno_dev,

	of_property_read_u32(node, "qcom,initial-pwrlevel", &init_level);

	if (init_level < 0 || init_level > pwr->num_pwrlevels)
	if (init_level < 0 || init_level >= pwr->num_pwrlevels)
		init_level = 1;

	pwr->active_pwrlevel = init_level;
@@ -1613,6 +1621,43 @@ static int adreno_remove(struct platform_device *pdev)
	return 0;
}

static int adreno_pm_resume(struct device *dev)
{
	struct kgsl_device *device = dev_get_drvdata(dev);

	mutex_lock(&device->mutex);
	if (device->state == KGSL_STATE_SUSPEND) {
		adreno_dispatcher_unhalt(device);
		kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER);
	} else if (device->state != KGSL_STATE_INIT) {
		/*
		 * This is an error situation so wait for the device to idle and
		 * then put the device in SLUMBER state.  This will get us to
		 * the right place when we resume.
		 */
		if (device->state == KGSL_STATE_ACTIVE)
			adreno_idle(device);
		kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER);
		dev_err(device->dev, "resume invoked without a suspend\n");
	}
	mutex_unlock(&device->mutex);
	return 0;
}

static int adreno_pm_suspend(struct device *dev)
{
	struct kgsl_device *device = dev_get_drvdata(dev);
	int status;

	mutex_lock(&device->mutex);
	status = kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND);
	if (!status && device->state == KGSL_STATE_SUSPEND)
		adreno_dispatcher_halt(device);
	mutex_unlock(&device->mutex);

	return status;
}

static void adreno_fault_detect_init(struct adreno_device *adreno_dev)
{
	struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
@@ -3741,21 +3786,21 @@ static const struct kgsl_functable adreno_functable = {
	.clk_set_options = adreno_clk_set_options,
	.gpu_model = adreno_gpu_model,
	.stop_fault_timer = adreno_dispatcher_stop_fault_timer,
	.dispatcher_halt = adreno_dispatcher_halt,
	.dispatcher_unhalt = adreno_dispatcher_unhalt,
	.query_property_list = adreno_query_property_list,
	.is_hwcg_on = adreno_is_hwcg_on,
};

static const struct dev_pm_ops adreno_pm_ops = {
	SET_SYSTEM_SLEEP_PM_OPS(adreno_pm_suspend, adreno_pm_resume)
};

static struct platform_driver adreno_platform_driver = {
	.probe = adreno_probe,
	.remove = adreno_remove,
	.suspend = kgsl_suspend_driver,
	.resume = kgsl_resume_driver,
	.id_table = adreno_id_table,
	.driver = {
		.name = "kgsl-3d",
		.pm = &kgsl_pm_ops,
		.pm = &adreno_pm_ops,
		.of_match_table = adreno_match_table,
	}
};
+3 −4
Original line number Diff line number Diff line
@@ -934,14 +934,13 @@ static uint32_t _write_voltage_table(struct adreno_device *adreno_dev,
	const struct adreno_a5xx_core *a5xx_core = to_a5xx_core(adreno_dev);
	int i;
	struct dev_pm_opp *opp;
	int levels = pwr->num_pwrlevels - 1;
	unsigned int mvolt = 0;

	kgsl_regwrite(device, addr++, a5xx_core->max_power);
	kgsl_regwrite(device, addr++, levels);
	kgsl_regwrite(device, addr++, pwr->num_pwrlevels);

	/* Write voltage in mV and frequency in MHz */
	for (i = 0; i < levels; i++) {
	for (i = 0; i < pwr->num_pwrlevels; i++) {
		opp = dev_pm_opp_find_freq_exact(&device->pdev->dev,
				pwr->pwrlevels[i].gpu_freq, true);
		/* _opp_get returns uV, convert to mV */
@@ -953,7 +952,7 @@ static uint32_t _write_voltage_table(struct adreno_device *adreno_dev,
		kgsl_regwrite(device, addr++,
				pwr->pwrlevels[i].gpu_freq / 1000000);
	}
	return (levels * 2 + 2);
	return (pwr->num_pwrlevels * 2 + 2);
}

static uint32_t lm_limit(struct adreno_device *adreno_dev)
+2 −1
Original line number Diff line number Diff line
@@ -830,7 +830,8 @@ static int a6xx_gmu_gfx_rail_on(struct kgsl_device *device)
{
	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
	struct gmu_device *gmu = KGSL_GMU_DEVICE(device);
	unsigned int perf_idx = pwr->num_pwrlevels - pwr->default_pwrlevel - 1;
	unsigned int perf_idx = gmu->num_gpupwrlevels -
		pwr->default_pwrlevel - 1;
	uint32_t default_opp = gmu->rpmh_votes.gx_votes[perf_idx];

	gmu_core_regwrite(device, A6XX_GMU_BOOT_SLUMBER_OPTION,
Loading