Commit 555c50a4 authored by Eric Anholt's avatar Eric Anholt Committed by Rob Clark
Browse files

drm/msm: Clean up GMU OOB set/clear handling.



Now that the bug is fixed in the minimal way for stable, go make the
code table-driven.

Signed-off-by: default avatarEric Anholt <eric@anholt.net>
Reviewed-by: default avatarJordan Crouse <jcrouse@codeaurora.org>
Signed-off-by: default avatarRob Clark <robdclark@chromium.org>
parent 5f98b33b
Loading
Loading
Loading
Loading
+62 −62
Original line number Diff line number Diff line
@@ -245,48 +245,67 @@ static int a6xx_gmu_hfi_start(struct a6xx_gmu *gmu)
	return ret;
}

struct a6xx_gmu_oob_bits {
	int set, ack, set_new, ack_new;
	const char *name;
};

/* These are the interrupt / ack bits for each OOB request that are set
 * in a6xx_gmu_set_oob and a6xx_clear_oob
 */
static const struct a6xx_gmu_oob_bits a6xx_gmu_oob_bits[] = {
	[GMU_OOB_GPU_SET] = {
		.name = "GPU_SET",
		.set = 16,
		.ack = 24,
		.set_new = 30,
		.ack_new = 31,
	},

	[GMU_OOB_PERFCOUNTER_SET] = {
		.name = "PERFCOUNTER",
		.set = 17,
		.ack = 25,
		.set_new = 28,
		.ack_new = 30,
	},

	[GMU_OOB_BOOT_SLUMBER] = {
		.name = "BOOT_SLUMBER",
		.set = 22,
		.ack = 30,
	},

	[GMU_OOB_DCVS_SET] = {
		.name = "GPU_DCVS",
		.set = 23,
		.ack = 31,
	},
};

/* Trigger a OOB (out of band) request to the GMU */
int a6xx_gmu_set_oob(struct a6xx_gmu *gmu, enum a6xx_gmu_oob_state state)
{
	int ret;
	u32 val;
	int request, ack;
	const char *name;

	switch (state) {
	case GMU_OOB_GPU_SET:
		if (gmu->legacy) {
			request = GMU_OOB_GPU_SET_REQUEST;
			ack = GMU_OOB_GPU_SET_ACK;
		} else {
			request = GMU_OOB_GPU_SET_REQUEST_NEW;
			ack = GMU_OOB_GPU_SET_ACK_NEW;
		}
		name = "GPU_SET";
		break;
	case GMU_OOB_PERFCOUNTER_SET:
	if (state >= ARRAY_SIZE(a6xx_gmu_oob_bits))
		return -EINVAL;

	if (gmu->legacy) {
			request = GMU_OOB_PERFCOUNTER_REQUEST;
			ack = GMU_OOB_PERFCOUNTER_ACK;
		request = a6xx_gmu_oob_bits[state].set;
		ack = a6xx_gmu_oob_bits[state].ack;
	} else {
			request = GMU_OOB_PERFCOUNTER_REQUEST_NEW;
			ack = GMU_OOB_PERFCOUNTER_ACK_NEW;
		}
		name = "PERFCOUNTER";
		break;
	case GMU_OOB_BOOT_SLUMBER:
		request = GMU_OOB_BOOT_SLUMBER_REQUEST;
		ack = GMU_OOB_BOOT_SLUMBER_ACK;
		name = "BOOT_SLUMBER";
		break;
	case GMU_OOB_DCVS_SET:
		request = GMU_OOB_DCVS_REQUEST;
		ack = GMU_OOB_DCVS_ACK;
		name = "GPU_DCVS";
		break;
	default:
		request = a6xx_gmu_oob_bits[state].set_new;
		ack = a6xx_gmu_oob_bits[state].ack_new;
		if (!request || !ack) {
			DRM_DEV_ERROR(gmu->dev,
				      "Invalid non-legacy GMU request %s\n",
				      a6xx_gmu_oob_bits[state].name);
			return -EINVAL;
		}
	}

	/* Trigger the equested OOB operation */
	gmu_write(gmu, REG_A6XX_GMU_HOST2GMU_INTR_SET, 1 << request);
@@ -298,7 +317,7 @@ int a6xx_gmu_set_oob(struct a6xx_gmu *gmu, enum a6xx_gmu_oob_state state)
	if (ret)
		DRM_DEV_ERROR(gmu->dev,
			"Timeout waiting for GMU OOB set %s: 0x%x\n",
				name,
				a6xx_gmu_oob_bits[state].name,
				gmu_read(gmu, REG_A6XX_GMU_GMU2HOST_INTR_INFO));

	/* Clear the acknowledge interrupt */
@@ -310,36 +329,17 @@ int a6xx_gmu_set_oob(struct a6xx_gmu *gmu, enum a6xx_gmu_oob_state state)
/* Clear a pending OOB state in the GMU */
void a6xx_gmu_clear_oob(struct a6xx_gmu *gmu, enum a6xx_gmu_oob_state state)
{
	if (!gmu->legacy) {
		if (state == GMU_OOB_GPU_SET) {
			gmu_write(gmu, REG_A6XX_GMU_HOST2GMU_INTR_SET,
				1 << GMU_OOB_GPU_SET_CLEAR_NEW);
		} else {
			WARN_ON(state != GMU_OOB_PERFCOUNTER_SET);
			gmu_write(gmu, REG_A6XX_GMU_HOST2GMU_INTR_SET,
				1 << GMU_OOB_PERFCOUNTER_CLEAR_NEW);
		}
	int bit;

	if (state >= ARRAY_SIZE(a6xx_gmu_oob_bits))
		return;
	}

	switch (state) {
	case GMU_OOB_GPU_SET:
		gmu_write(gmu, REG_A6XX_GMU_HOST2GMU_INTR_SET,
			1 << GMU_OOB_GPU_SET_CLEAR);
		break;
	case GMU_OOB_PERFCOUNTER_SET:
		gmu_write(gmu, REG_A6XX_GMU_HOST2GMU_INTR_SET,
			1 << GMU_OOB_PERFCOUNTER_CLEAR);
		break;
	case GMU_OOB_BOOT_SLUMBER:
		gmu_write(gmu, REG_A6XX_GMU_HOST2GMU_INTR_SET,
			1 << GMU_OOB_BOOT_SLUMBER_CLEAR);
		break;
	case GMU_OOB_DCVS_SET:
		gmu_write(gmu, REG_A6XX_GMU_HOST2GMU_INTR_SET,
			1 << GMU_OOB_DCVS_CLEAR);
		break;
	}
	if (gmu->legacy)
		bit = a6xx_gmu_oob_bits[state].ack;
	else
		bit = a6xx_gmu_oob_bits[state].ack_new;

	gmu_write(gmu, REG_A6XX_GMU_HOST2GMU_INTR_SET, bit);
}

/* Enable CPU control of SPTP power power collapse */
+15 −40
Original line number Diff line number Diff line
@@ -153,51 +153,26 @@ static inline void gmu_write_rscc(struct a6xx_gmu *gmu, u32 offset, u32 value)
 */

enum a6xx_gmu_oob_state {
	GMU_OOB_BOOT_SLUMBER = 0,
	GMU_OOB_GPU_SET,
	GMU_OOB_DCVS_SET,
	GMU_OOB_PERFCOUNTER_SET,
};

/* These are the interrupt / ack bits for each OOB request that are set
 * in a6xx_gmu_set_oob and a6xx_clear_oob
 */

	/*
	 * Let the GMU know that a boot or slumber operation has started. The value in
	 * REG_A6XX_GMU_BOOT_SLUMBER_OPTION lets the GMU know which operation we are
	 * doing
	 */
#define GMU_OOB_BOOT_SLUMBER_REQUEST	22
#define GMU_OOB_BOOT_SLUMBER_ACK	30
#define GMU_OOB_BOOT_SLUMBER_CLEAR	30

	GMU_OOB_BOOT_SLUMBER = 0,
	/*
	 * Let the GMU know to not turn off any GPU registers while the CPU is in a
	 * critical section
	 */
	GMU_OOB_GPU_SET,
	/*
	 * Set a new power level for the GPU when the CPU is doing frequency scaling
	 */
#define GMU_OOB_DCVS_REQUEST	23
#define GMU_OOB_DCVS_ACK	31
#define GMU_OOB_DCVS_CLEAR	31

	GMU_OOB_DCVS_SET,
	/*
 * Let the GMU know to not turn off any GPU registers while the CPU is in a
 * critical section
	 * Used to keep the GPU on for CPU-side reads of performance counters.
	 */
#define GMU_OOB_GPU_SET_REQUEST	16
#define GMU_OOB_GPU_SET_ACK	24
#define GMU_OOB_GPU_SET_CLEAR	24

#define GMU_OOB_GPU_SET_REQUEST_NEW	30
#define GMU_OOB_GPU_SET_ACK_NEW		31
#define GMU_OOB_GPU_SET_CLEAR_NEW	31

#define GMU_OOB_PERFCOUNTER_REQUEST	17
#define GMU_OOB_PERFCOUNTER_ACK		25
#define GMU_OOB_PERFCOUNTER_CLEAR	25

#define GMU_OOB_PERFCOUNTER_REQUEST_NEW	28
#define GMU_OOB_PERFCOUNTER_ACK_NEW	30
#define GMU_OOB_PERFCOUNTER_CLEAR_NEW	30
	GMU_OOB_PERFCOUNTER_SET,
};

void a6xx_hfi_init(struct a6xx_gmu *gmu);
int a6xx_hfi_start(struct a6xx_gmu *gmu, int boot_state);