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

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
......@@ -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 */
......
......@@ -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
/*
* 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_BOOT_SLUMBER = 0,
/*
* Let the GMU know to not turn off any GPU registers while the CPU is in a
* critical section
*/
#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_GPU_SET,
/*
* Set a new power level for the GPU when the CPU is doing frequency scaling
*/
GMU_OOB_DCVS_SET,
/*
* Used to keep the GPU on for CPU-side reads of performance counters.
*/
GMU_OOB_PERFCOUNTER_SET,
};
void a6xx_hfi_init(struct a6xx_gmu *gmu);
int a6xx_hfi_start(struct a6xx_gmu *gmu, int boot_state);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment