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

Commit 679abd9d authored by Kyle Piefer's avatar Kyle Piefer Committed by Gerrit - the friendly Code Review server
Browse files

msm: kgsl: Add support for Limits Management on A640



For Limits Management (LM) to be enabled on A640, the
feature control HFI message for LM must be sent to the GMU.
Additionally, the throttled cycles must be taken into
account for DCVS.

Change-Id: Ib6520a4bb211db2ffc0ac66d88acdad545c1303a
Signed-off-by: default avatarKyle Piefer <kpiefer@codeaurora.org>
parent b5ca255f
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -3574,7 +3574,7 @@ static void adreno_power_stats(struct kgsl_device *device,
	struct adreno_gpudev *gpudev  = ADRENO_GPU_DEVICE(adreno_dev);
	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
	struct adreno_busy_data *busy = &adreno_dev->busy_data;
	uint64_t adj = 0;
	int64_t adj = 0;

	memset(stats, 0, sizeof(*stats));

@@ -3587,6 +3587,9 @@ static void adreno_power_stats(struct kgsl_device *device,

		if (gpudev->read_throttling_counters) {
			adj = gpudev->read_throttling_counters(adreno_dev);
			if (adj < 0 && -adj > gpu_busy)
				adj = -gpu_busy;

			gpu_busy += adj;
		}

+1 −1
Original line number Diff line number Diff line
@@ -969,7 +969,7 @@ struct adreno_gpudev {
	void (*pwrlevel_change_settings)(struct adreno_device *,
				unsigned int prelevel, unsigned int postlevel,
				bool post);
	uint64_t (*read_throttling_counters)(struct adreno_device *);
	int64_t (*read_throttling_counters)(struct adreno_device *);
	void (*count_throttles)(struct adreno_device *, uint64_t adj);
	int (*enable_pwr_counters)(struct adreno_device *,
				unsigned int counter);
+3 −2
Original line number Diff line number Diff line
@@ -1688,9 +1688,10 @@ static int a5xx_enable_pwr_counters(struct adreno_device *adreno_dev,
/* number of cycles when clock is throttle by less than 50% (CRC) */
#define CRC_LESS50PCT 3

static uint64_t a5xx_read_throttling_counters(struct adreno_device *adreno_dev)
static int64_t a5xx_read_throttling_counters(struct adreno_device *adreno_dev)
{
	int i, adj;
	int i;
	int64_t adj;
	uint32_t th[ADRENO_GPMU_THROTTLE_COUNTERS];
	struct adreno_busy_data *busy = &adreno_dev->busy_data;

+32 −0
Original line number Diff line number Diff line
@@ -1414,6 +1414,37 @@ static int a6xx_soft_reset(struct adreno_device *adreno_dev)
	return 0;
}

static int64_t a6xx_read_throttling_counters(struct adreno_device *adreno_dev)
{
	int i;
	int64_t adj = 0;
	uint32_t counts[ADRENO_GPMU_THROTTLE_COUNTERS];
	struct adreno_busy_data *busy = &adreno_dev->busy_data;

	for (i = 0; i < ARRAY_SIZE(counts); i++) {
		if (!adreno_dev->gpmu_throttle_counters[i])
			counts[i] = 0;
		else
			counts[i] = counter_delta(KGSL_DEVICE(adreno_dev),
					adreno_dev->gpmu_throttle_counters[i],
					&busy->throttle_cycles[i]);
	}

	/*
	 * The adjustment is the number of cycles lost to throttling, which
	 * is calculated as a weighted average of the cycles throttled
	 * at 10%, 50%, and 90%. The adjustment is negative because in A6XX,
	 * the busy count includes the throttled cycles. Therefore, we want
	 * to remove them to prevent appearing to be busier than
	 * we actually are.
	 */
	adj = -((counts[0] * 1) + (counts[1] * 5) + (counts[2] * 9)) / 10;

	trace_kgsl_clock_throttling(0, counts[1], counts[2],
			counts[0], adj);
	return adj;
}

static void a6xx_count_throttles(struct adreno_device *adreno_dev,
	uint64_t adj)
{
@@ -2952,6 +2983,7 @@ struct adreno_gpudev adreno_a6xx_gpudev = {
	.regulator_disable = a6xx_sptprac_disable,
	.perfcounters = &a6xx_perfcounters,
	.enable_pwr_counters = a6xx_enable_pwr_counters,
	.read_throttling_counters = a6xx_read_throttling_counters,
	.count_throttles = a6xx_count_throttles,
	.microcode_read = a6xx_microcode_read,
	.enable_64bit = a6xx_enable_64bit,
+37 −0
Original line number Diff line number Diff line
@@ -1259,6 +1259,37 @@ static uint32_t lm_limit(struct adreno_device *adreno_dev)
	return adreno_dev->lm_limit;
}

static int a640_throttling_counters[ADRENO_GPMU_THROTTLE_COUNTERS] = {
	0x11, 0x15, 0x19
};

static void _setup_throttling_counters(struct adreno_device *adreno_dev)
{
	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
	struct gmu_device *gmu = KGSL_GMU_DEVICE(device);
	int i, ret;

	for (i = 0; i < ARRAY_SIZE(a640_throttling_counters); i++) {
		adreno_dev->busy_data.throttle_cycles[i] = 0;

		if (!a640_throttling_counters[i])
			continue;
		if (adreno_dev->gpmu_throttle_counters[i])
			continue;

		ret = adreno_perfcounter_get(adreno_dev,
				KGSL_PERFCOUNTER_GROUP_GPMU_PWR,
				a640_throttling_counters[i],
				&adreno_dev->gpmu_throttle_counters[i],
				NULL,
				PERFCOUNTER_FLAG_KERNEL);
		if (ret)
			dev_err_once(&gmu->pdev->dev,
				"Unable to get counter for LM: GPMU_PWR %d\n",
				a640_throttling_counters[i]);
	}
}

#define LIMITS_CONFIG(t, s, c, i, a) ( \
		(t & 0xF) | \
		((s & 0xF) << 4) | \
@@ -1278,6 +1309,12 @@ void a6xx_gmu_enable_lm(struct kgsl_device *device)
			!test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag))
		return;

	/* a640 only needs to set up throttling counters for DCVS */
	if (adreno_is_a640(adreno_dev)) {
		_setup_throttling_counters(adreno_dev);
		return;
	}

	gmu_core_regwrite(device, A6XX_GPU_GMU_CX_GMU_PWR_THRESHOLD,
		GPU_LIMIT_THRESHOLD_ENABLE | lm_limit(adreno_dev));
	gmu_core_regwrite(device, A6XX_GMU_AO_SPARE_CNTL, 1);
Loading