Skip to content

Commit a27d774

Browse files
akhilpo-qcomRob Clark
authored andcommitted
drm/msm/adreno: Add fenced regwrite support
There are some special registers which are accessible even when GX power domain is collapsed during an IFPC sleep. Accessing these registers wakes up GPU from power collapse and allow programming these registers without additional handshake with GMU. This patch adds support for this special register write sequence. Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com> Patchwork: https://patchwork.freedesktop.org/patch/673368/ Signed-off-by: Rob Clark <robin.clark@oss.qualcomm.com>
1 parent ac9098b commit a27d774

3 files changed

Lines changed: 90 additions & 11 deletions

File tree

drivers/gpu/drm/msm/adreno/a6xx_gpu.c

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,84 @@
1616

1717
#define GPU_PAS_ID 13
1818

19+
static bool fence_status_check(struct msm_gpu *gpu, u32 offset, u32 value, u32 status, u32 mask)
20+
{
21+
/* Success if !writedropped0/1 */
22+
if (!(status & mask))
23+
return true;
24+
25+
udelay(10);
26+
27+
/* Try to update fenced register again */
28+
gpu_write(gpu, offset, value);
29+
30+
/* We can't do a posted write here because the power domain could be
31+
* in collapse state. So use the heaviest barrier instead
32+
*/
33+
mb();
34+
return false;
35+
}
36+
37+
static int fenced_write(struct a6xx_gpu *a6xx_gpu, u32 offset, u32 value, u32 mask)
38+
{
39+
struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
40+
struct msm_gpu *gpu = &adreno_gpu->base;
41+
struct a6xx_gmu *gmu = &a6xx_gpu->gmu;
42+
u32 status;
43+
44+
gpu_write(gpu, offset, value);
45+
46+
/* Nothing else to be done in the case of no-GMU */
47+
if (adreno_has_gmu_wrapper(adreno_gpu))
48+
return 0;
49+
50+
/* We can't do a posted write here because the power domain could be
51+
* in collapse state. So use the heaviest barrier instead
52+
*/
53+
mb();
54+
55+
if (!gmu_poll_timeout(gmu, REG_A6XX_GMU_AHB_FENCE_STATUS, status,
56+
fence_status_check(gpu, offset, value, status, mask), 0, 1000))
57+
return 0;
58+
59+
/* Try again for another 1ms before failing */
60+
gpu_write(gpu, offset, value);
61+
mb();
62+
63+
if (!gmu_poll_timeout(gmu, REG_A6XX_GMU_AHB_FENCE_STATUS, status,
64+
fence_status_check(gpu, offset, value, status, mask), 0, 1000)) {
65+
/*
66+
* The 'delay' warning is here because the pause to print this
67+
* warning will allow gpu to move to power collapse which
68+
* defeats the purpose of continuous polling for 2 ms
69+
*/
70+
dev_err_ratelimited(gmu->dev, "delay in fenced register write (0x%x)\n",
71+
offset);
72+
return 0;
73+
}
74+
75+
dev_err_ratelimited(gmu->dev, "fenced register write (0x%x) fail\n",
76+
offset);
77+
78+
return -ETIMEDOUT;
79+
}
80+
81+
int a6xx_fenced_write(struct a6xx_gpu *a6xx_gpu, u32 offset, u64 value, u32 mask, bool is_64b)
82+
{
83+
int ret;
84+
85+
ret = fenced_write(a6xx_gpu, offset, lower_32_bits(value), mask);
86+
if (ret)
87+
return ret;
88+
89+
if (!is_64b)
90+
return 0;
91+
92+
ret = fenced_write(a6xx_gpu, offset + 1, upper_32_bits(value), mask);
93+
94+
return ret;
95+
}
96+
1997
static inline bool _a6xx_check_idle(struct msm_gpu *gpu)
2098
{
2199
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
@@ -86,7 +164,7 @@ static void a6xx_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring)
86164
/* Update HW if this is the current ring and we are not in preempt*/
87165
if (!a6xx_in_preempt(a6xx_gpu)) {
88166
if (a6xx_gpu->cur_ring == ring)
89-
gpu_write(gpu, REG_A6XX_CP_RB_WPTR, wptr);
167+
a6xx_fenced_write(a6xx_gpu, REG_A6XX_CP_RB_WPTR, wptr, BIT(0), false);
90168
else
91169
ring->restore_wptr = true;
92170
} else {

drivers/gpu/drm/msm/adreno/a6xx_gpu.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,5 +295,6 @@ int a6xx_gpu_state_put(struct msm_gpu_state *state);
295295

296296
void a6xx_bus_clear_pending_transactions(struct adreno_gpu *adreno_gpu, bool gx_off);
297297
void a6xx_gpu_sw_reset(struct msm_gpu *gpu, bool assert);
298+
int a6xx_fenced_write(struct a6xx_gpu *gpu, u32 offset, u64 value, u32 mask, bool is_64b);
298299

299300
#endif /* __A6XX_GPU_H__ */

drivers/gpu/drm/msm/adreno/a6xx_preempt.c

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ static inline void set_preempt_state(struct a6xx_gpu *gpu,
4141
}
4242

4343
/* Write the most recent wptr for the given ring into the hardware */
44-
static inline void update_wptr(struct msm_gpu *gpu, struct msm_ringbuffer *ring)
44+
static inline void update_wptr(struct a6xx_gpu *a6xx_gpu, struct msm_ringbuffer *ring)
4545
{
4646
unsigned long flags;
4747
uint32_t wptr;
@@ -51,7 +51,7 @@ static inline void update_wptr(struct msm_gpu *gpu, struct msm_ringbuffer *ring)
5151
if (ring->restore_wptr) {
5252
wptr = get_wptr(ring);
5353

54-
gpu_write(gpu, REG_A6XX_CP_RB_WPTR, wptr);
54+
a6xx_fenced_write(a6xx_gpu, REG_A6XX_CP_RB_WPTR, wptr, BIT(0), false);
5555

5656
ring->restore_wptr = false;
5757
}
@@ -172,7 +172,7 @@ void a6xx_preempt_irq(struct msm_gpu *gpu)
172172

173173
set_preempt_state(a6xx_gpu, PREEMPT_FINISH);
174174

175-
update_wptr(gpu, a6xx_gpu->cur_ring);
175+
update_wptr(a6xx_gpu, a6xx_gpu->cur_ring);
176176

177177
set_preempt_state(a6xx_gpu, PREEMPT_NONE);
178178

@@ -268,7 +268,7 @@ void a6xx_preempt_trigger(struct msm_gpu *gpu)
268268
*/
269269
if (!ring || (a6xx_gpu->cur_ring == ring)) {
270270
set_preempt_state(a6xx_gpu, PREEMPT_FINISH);
271-
update_wptr(gpu, a6xx_gpu->cur_ring);
271+
update_wptr(a6xx_gpu, a6xx_gpu->cur_ring);
272272
set_preempt_state(a6xx_gpu, PREEMPT_NONE);
273273
spin_unlock_irqrestore(&a6xx_gpu->eval_lock, flags);
274274
return;
@@ -302,13 +302,13 @@ void a6xx_preempt_trigger(struct msm_gpu *gpu)
302302

303303
spin_unlock_irqrestore(&ring->preempt_lock, flags);
304304

305-
gpu_write64(gpu,
306-
REG_A6XX_CP_CONTEXT_SWITCH_SMMU_INFO,
307-
a6xx_gpu->preempt_smmu_iova[ring->id]);
305+
a6xx_fenced_write(a6xx_gpu,
306+
REG_A6XX_CP_CONTEXT_SWITCH_SMMU_INFO, a6xx_gpu->preempt_smmu_iova[ring->id],
307+
BIT(1), true);
308308

309-
gpu_write64(gpu,
309+
a6xx_fenced_write(a6xx_gpu,
310310
REG_A6XX_CP_CONTEXT_SWITCH_PRIV_NON_SECURE_RESTORE_ADDR,
311-
a6xx_gpu->preempt_iova[ring->id]);
311+
a6xx_gpu->preempt_iova[ring->id], BIT(1), true);
312312

313313
a6xx_gpu->next_ring = ring;
314314

@@ -328,7 +328,7 @@ void a6xx_preempt_trigger(struct msm_gpu *gpu)
328328
set_preempt_state(a6xx_gpu, PREEMPT_TRIGGERED);
329329

330330
/* Trigger the preemption */
331-
gpu_write(gpu, REG_A6XX_CP_CONTEXT_SWITCH_CNTL, cntl);
331+
a6xx_fenced_write(a6xx_gpu, REG_A6XX_CP_CONTEXT_SWITCH_CNTL, cntl, BIT(1), false);
332332
}
333333

334334
static int preempt_init_ring(struct a6xx_gpu *a6xx_gpu,

0 commit comments

Comments
 (0)