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

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

Merge "msm: kgsl: Add GPU CX Ipeak client support"

parents 03135c71 6764d05c
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -113,6 +113,20 @@ Optional Properties:
- qcom,l2pc-cpu-mask-latency:
				The CPU mask latency in microseconds to avoid L2PC
				on masked CPUs.

- qcom,gpu-cx-ipeak:
				CX Ipeak is a mitigation scheme which throttles cDSP frequency
				if all the clients are running at their respective threshold
				frequencies to limit CX peak current.
				<phandle bit>
				phandle - phandle of CX Ipeak device node
				bit     - Every bit corresponds to a client of CX Ipeak
				driver in the relevant register.
- qcom, gpu-cx-ipeak-freq:
				GPU frequency threshold for CX Ipeak voting. GPU votes
				to CX Ipeak driver when GPU clock crosses this threshold.
				CX Ipeak can limit peak current based on voting from other clients.

- qcom,force-32bit:
				Force the GPU to use 32 bit data sizes even if
				it is capable of doing 64 bit.
+4 −0
Original line number Diff line number Diff line
@@ -1338,6 +1338,10 @@ static int adreno_probe(struct platform_device *pdev)
		device->mmu.va_padding = adreno_dev->gpucore->va_padding;
	}

	if (adreno_dev->gpucore->cx_ipeak_gpu_freq)
		device->pwrctrl.cx_ipeak_gpu_freq =
				adreno_dev->gpucore->cx_ipeak_gpu_freq;

	status = kgsl_device_platform_probe(device);
	if (status) {
		device->pdev = NULL;
+2 −0
Original line number Diff line number Diff line
@@ -390,6 +390,7 @@ struct adreno_device_private {
 * @gpmu_tsens: ID for the temporature sensor used by the GPMU
 * @max_power: Max possible power draw of a core, units elephant tail hairs
 * @va_padding: Size to pad allocations to, zero if not required
 * @cx_ipeak_gpu_freq : Default Cx Ipeak GPU frequency
 */
struct adreno_gpu_core {
	enum adreno_gpurev gpurev;
@@ -421,6 +422,7 @@ struct adreno_gpu_core {
	unsigned int gpmu_tsens;
	unsigned int max_power;
	uint64_t va_padding;
	unsigned int cx_ipeak_gpu_freq;
};


+78 −0
Original line number Diff line number Diff line
@@ -428,6 +428,28 @@ void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device,
		!test_bit(GMU_DCVS_REPLAY, &device->gmu_core.flags))
		return;

	if (pwr->gpu_cx_ipeak) {
		unsigned int old_freq = pwr->pwrlevels[old_level].gpu_freq;
		unsigned int new_freq = pwr->pwrlevels[new_level].gpu_freq;
		unsigned int ipeak_freq = pwr->cx_ipeak_gpu_freq;
		/*
		 * Set CX Ipeak vote for GPU if it tries to cross
		 * threshold frequency.
		 */
		if (old_freq < ipeak_freq && new_freq >= ipeak_freq) {
			int ret = cx_ipeak_update(pwr->gpu_cx_ipeak, true);
			/*
			 * Hardware damage is possible at peak current
			 * if mitigation not done to limit peak power.
			 */
			if (ret) {
				KGSL_PWR_ERR(device,
				"ipeak voting failed due to timeout %d\n", ret);
				return;
			}
		}
	}

	kgsl_pwrscale_update_stats(device);

	/*
@@ -492,6 +514,25 @@ void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device,

	/* Timestamp the frequency change */
	device->pwrscale.freq_change_time = ktime_to_ms(ktime_get());

	if (pwr->gpu_cx_ipeak) {
		unsigned int old_freq = pwr->pwrlevels[old_level].gpu_freq;
		unsigned int new_freq = pwr->pwrlevels[new_level].gpu_freq;
		unsigned int ipeak_freq = pwr->cx_ipeak_gpu_freq;
		/*
		 * Reset CX Ipeak vote for GPU if it goes below
		 * threshold frequency.
		 */
		if (old_freq >= ipeak_freq && new_freq < ipeak_freq) {
			int ret = cx_ipeak_update(pwr->gpu_cx_ipeak, false);

			/* Failed to withdraw the voting from ipeak driver */
			if (ret)
				KGSL_PWR_ERR(device,
				"Failed to withdraw votes from ipeak %d\n",
					ret);
		}
	}
}
EXPORT_SYMBOL(kgsl_pwrctrl_pwrlevel_change);

@@ -2414,8 +2455,43 @@ int kgsl_pwrctrl_init(struct kgsl_device *device)
	of_property_read_string(pdev->dev.of_node, "qcom,tzone-name",
		&pwr->tzone_name);

	/*
	 * Cx ipeak client support, default value of Cx Ipeak GPU freq
	 * is used if defined in GPU list and it is overridden by
	 * new frequency value if defined in dt.
	 */
	if (of_find_property(pdev->dev.of_node, "qcom,gpu-cx-ipeak", NULL)) {
		if (!of_property_read_u32(pdev->dev.of_node,
			"qcom,gpu-cx-ipeak-freq", &pwr->cx_ipeak_gpu_freq)
				|| pwr->cx_ipeak_gpu_freq) {
			pwr->gpu_cx_ipeak = cx_ipeak_register(pdev->dev.of_node,
					"qcom,gpu-cx-ipeak");
		} else {
			KGSL_PWR_ERR(device,
					"failed to get GPU-CX-Ipeak Frequency\n");
			result = -EINVAL;
			goto error_cleanup_pwr_limit;
		}

		if (IS_ERR(pwr->gpu_cx_ipeak)) {
			result = PTR_ERR(pwr->gpu_cx_ipeak);
			KGSL_PWR_ERR(device,
				"Failed to register client with CX Ipeak %d\n",
				result);
			goto error_cleanup_pwr_limit;
		}
	}
	return result;

error_cleanup_pwr_limit:
	pwr->power_flags = 0;

	if (!IS_ERR_OR_NULL(pwr->sysfs_pwr_limit)) {
		list_del(&pwr->sysfs_pwr_limit->node);
		kfree(pwr->sysfs_pwr_limit);
		pwr->sysfs_pwr_limit = NULL;
	}
	kfree(pwr->bus_ib);
error_cleanup_pcl:
	_close_pcl(pwr);
error_cleanup_ocmem_pcl:
@@ -2435,6 +2511,8 @@ void kgsl_pwrctrl_close(struct kgsl_device *device)

	KGSL_PWR_INFO(device, "close device %d\n", device->id);

	cx_ipeak_unregister(pwr->gpu_cx_ipeak);

	pwr->power_flags = 0;

	if (!IS_ERR_OR_NULL(pwr->sysfs_pwr_limit)) {
+5 −0
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
#define __KGSL_PWRCTRL_H

#include <linux/pm_qos.h>
#include <soc/qcom/cx_ipeak.h>

/*****************************************************************************
 * power flags
@@ -172,6 +173,8 @@ struct kgsl_regulator {
 * isense_clk_indx - index of isense clock, 0 if no isense
 * isense_clk_on_level - isense clock rate is XO rate below this level.
 * tzone_name - pointer to thermal zone name of GPU temperature sensor
 * gpu_cx_ipeak - pointer to CX Ipeak client used by GPU
 * cx_ipeak_gpu_freq - Value of GPU CX Ipeak frequency
 */

struct kgsl_pwrctrl {
@@ -229,6 +232,8 @@ struct kgsl_pwrctrl {
	unsigned int gpu_bimc_int_clk_freq;
	bool gpu_bimc_interface_enabled;
	const char *tzone_name;
	struct cx_ipeak_client *gpu_cx_ipeak;
	unsigned int cx_ipeak_gpu_freq;
};

int kgsl_pwrctrl_init(struct kgsl_device *device);