Skip to content

Commit eb8c888

Browse files
committed
drm/imx: add deferred plane disabling
The DP (display processor) channel disable code tried to busy wait for the DP sync flow end interrupt status bit when disabling the partial plane without a full modeset. That never worked reliably, and it was disabled completely by the recent "gpu: ipu-v3: remove IRQ dance on DC channel disable" patch, causing ipu_wait_interrupt to always time out after 50 ms, which in turn would trigger a timeout in drm_atomic_helper_wait_for_vblanks. This patch changes ipu_plane_atomic_disable to only queue a DP channel register update at the next frame boundary and set a flag, which can be done without any waiting whatsoever. The imx_drm_atomic_commit_tail then calls a new ipu_plane_disable_deferred function that does the actual IDMAC teardown of the planes that are flagged for deferred disabling, after waiting for the vblank. Signed-off-by: Philipp Zabel <[email protected]> Reviewed-by: Lucas Stach <[email protected]>
1 parent cf92fef commit eb8c888

File tree

5 files changed

+62
-11
lines changed

5 files changed

+62
-11
lines changed

drivers/gpu/drm/imx/imx-drm-core.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <video/imx-ipu-v3.h>
3131

3232
#include "imx-drm.h"
33+
#include "ipuv3-plane.h"
3334

3435
#define MAX_CRTC 4
3536

@@ -122,6 +123,10 @@ static const struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
122123
static void imx_drm_atomic_commit_tail(struct drm_atomic_state *state)
123124
{
124125
struct drm_device *dev = state->dev;
126+
struct drm_plane *plane;
127+
struct drm_plane_state *old_plane_state;
128+
bool plane_disabling = false;
129+
int i;
125130

126131
drm_atomic_helper_commit_modeset_disables(dev, state);
127132

@@ -131,6 +136,19 @@ static void imx_drm_atomic_commit_tail(struct drm_atomic_state *state)
131136

132137
drm_atomic_helper_commit_modeset_enables(dev, state);
133138

139+
for_each_plane_in_state(state, plane, old_plane_state, i) {
140+
if (drm_atomic_plane_disabling(old_plane_state, plane->state))
141+
plane_disabling = true;
142+
}
143+
144+
if (plane_disabling) {
145+
drm_atomic_helper_wait_for_vblanks(dev, state);
146+
147+
for_each_plane_in_state(state, plane, old_plane_state, i)
148+
ipu_plane_disable_deferred(plane);
149+
150+
}
151+
134152
drm_atomic_helper_commit_hw_done(state);
135153
}
136154

drivers/gpu/drm/imx/ipuv3-crtc.c

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,26 @@ static void ipu_crtc_enable(struct drm_crtc *crtc)
6060
ipu_di_enable(ipu_crtc->di);
6161
}
6262

63+
static void ipu_crtc_disable_planes(struct ipu_crtc *ipu_crtc,
64+
struct drm_crtc_state *old_crtc_state)
65+
{
66+
bool disable_partial = false;
67+
bool disable_full = false;
68+
struct drm_plane *plane;
69+
70+
drm_atomic_crtc_state_for_each_plane(plane, old_crtc_state) {
71+
if (plane == &ipu_crtc->plane[0]->base)
72+
disable_full = true;
73+
if (&ipu_crtc->plane[1] && plane == &ipu_crtc->plane[1]->base)
74+
disable_partial = true;
75+
}
76+
77+
if (disable_partial)
78+
ipu_plane_disable(ipu_crtc->plane[1], true);
79+
if (disable_full)
80+
ipu_plane_disable(ipu_crtc->plane[0], false);
81+
}
82+
6383
static void ipu_crtc_atomic_disable(struct drm_crtc *crtc,
6484
struct drm_crtc_state *old_crtc_state)
6585
{
@@ -73,7 +93,7 @@ static void ipu_crtc_atomic_disable(struct drm_crtc *crtc,
7393
* attached IDMACs will be left in undefined state, possibly hanging
7494
* the IPU or even system.
7595
*/
76-
drm_atomic_helper_disable_planes_on_crtc(old_crtc_state, false);
96+
ipu_crtc_disable_planes(ipu_crtc, old_crtc_state);
7797
ipu_dc_disable(ipu);
7898

7999
spin_lock_irq(&crtc->dev->event_lock);

drivers/gpu/drm/imx/ipuv3-plane.c

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -172,23 +172,30 @@ static void ipu_plane_enable(struct ipu_plane *ipu_plane)
172172
ipu_dp_enable_channel(ipu_plane->dp);
173173
}
174174

175-
static int ipu_disable_plane(struct drm_plane *plane)
175+
void ipu_plane_disable(struct ipu_plane *ipu_plane, bool disable_dp_channel)
176176
{
177-
struct ipu_plane *ipu_plane = to_ipu_plane(plane);
178-
179177
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
180178

181179
ipu_idmac_wait_busy(ipu_plane->ipu_ch, 50);
182180

183-
if (ipu_plane->dp)
184-
ipu_dp_disable_channel(ipu_plane->dp, true);
181+
if (ipu_plane->dp && disable_dp_channel)
182+
ipu_dp_disable_channel(ipu_plane->dp, false);
185183
ipu_idmac_disable_channel(ipu_plane->ipu_ch);
186184
ipu_dmfc_disable_channel(ipu_plane->dmfc);
187185
if (ipu_plane->dp)
188186
ipu_dp_disable(ipu_plane->ipu);
187+
}
189188

190-
return 0;
189+
void ipu_plane_disable_deferred(struct drm_plane *plane)
190+
{
191+
struct ipu_plane *ipu_plane = to_ipu_plane(plane);
192+
193+
if (ipu_plane->disabling) {
194+
ipu_plane->disabling = false;
195+
ipu_plane_disable(ipu_plane, false);
196+
}
191197
}
198+
EXPORT_SYMBOL_GPL(ipu_plane_disable_deferred);
192199

193200
static void ipu_plane_destroy(struct drm_plane *plane)
194201
{
@@ -356,7 +363,11 @@ static int ipu_plane_atomic_check(struct drm_plane *plane,
356363
static void ipu_plane_atomic_disable(struct drm_plane *plane,
357364
struct drm_plane_state *old_state)
358365
{
359-
ipu_disable_plane(plane);
366+
struct ipu_plane *ipu_plane = to_ipu_plane(plane);
367+
368+
if (ipu_plane->dp)
369+
ipu_dp_disable_channel(ipu_plane->dp, true);
370+
ipu_plane->disabling = true;
360371
}
361372

362373
static void ipu_plane_atomic_update(struct drm_plane *plane,

drivers/gpu/drm/imx/ipuv3-plane.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ struct ipu_plane {
2323

2424
int dma;
2525
int dp_flow;
26+
27+
bool disabling;
2628
};
2729

2830
struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
@@ -42,4 +44,7 @@ void ipu_plane_put_resources(struct ipu_plane *plane);
4244

4345
int ipu_plane_irq(struct ipu_plane *plane);
4446

47+
void ipu_plane_disable(struct ipu_plane *ipu_plane, bool disable_dp_channel);
48+
void ipu_plane_disable_deferred(struct drm_plane *plane);
49+
4550
#endif

drivers/gpu/ipu-v3/ipu-dp.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -277,9 +277,6 @@ void ipu_dp_disable_channel(struct ipu_dp *dp, bool sync)
277277
writel(0, flow->base + DP_FG_POS);
278278
ipu_srm_dp_update(priv->ipu, sync);
279279

280-
if (ipu_idmac_channel_busy(priv->ipu, IPUV3_CHANNEL_MEM_BG_SYNC))
281-
ipu_wait_interrupt(priv->ipu, IPU_IRQ_DP_SF_END, 50);
282-
283280
mutex_unlock(&priv->mutex);
284281
}
285282
EXPORT_SYMBOL_GPL(ipu_dp_disable_channel);

0 commit comments

Comments
 (0)