The IPUv3 display driver rounds up hactive to 8-pixel alignment in mode_set_nofb(), stealing pixels from the front porch. ipu_src_rect_width() applies the same rounding to the IDMAC read width. While this keeps the DC and IDMAC in sync, it causes the display to receive more active pixels than the mode specifies.
On fixed-pixel displays whose native width is not 8-pixel aligned (e.g. 854x480), the extra pixels cause visible skewing: each scanline is offset, making vertical lines lean. Remove both alignment overrides. The IDMAC and DC now use the exact mode width. The DMA burst size is already adapted to arbitrary widths by ipu_calculate_bursts(), so no alignment is required at the pixel level. Demote the DC warning about non-8-aligned hactive to dev_dbg, since it is informational rather than indicative of a problem. Signed-off-by: Magnus Hörlin <[email protected]> --- drivers/gpu/drm/imx/ipuv3/ipuv3-crtc.c | 9 --------- drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c | 9 ++++++++- drivers/gpu/ipu-v3/ipu-dc.c | 5 +++-- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/imx/ipuv3/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3/ipuv3-crtc.c index a18b9d1a6..47b88f29a 100644 --- a/drivers/gpu/drm/imx/ipuv3/ipuv3-crtc.c +++ b/drivers/gpu/drm/imx/ipuv3/ipuv3-crtc.c @@ -304,15 +304,6 @@ static void ipu_crtc_mode_set_nofb(struct drm_crtc *crtc) sig_cfg.vsync_pin = imx_crtc_state->di_vsync_pin; drm_display_mode_to_videomode(mode, &sig_cfg.mode); - if (!IS_ALIGNED(sig_cfg.mode.hactive, 8)) { - unsigned int new_hactive = ALIGN(sig_cfg.mode.hactive, 8); - - dev_warn(ipu_crtc->dev, "8-pixel align hactive %d -> %d\n", - sig_cfg.mode.hactive, new_hactive); - - sig_cfg.mode.hfront_porch -= new_hactive - sig_cfg.mode.hactive; - sig_cfg.mode.hactive = new_hactive; - } ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di, mode->flags & DRM_MODE_FLAG_INTERLACE, diff --git a/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c index c1c7be4e2..58e7853e6 100644 --- a/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c +++ b/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c @@ -34,7 +34,14 @@ to_ipu_plane_state(struct drm_plane_state *p) static unsigned int ipu_src_rect_width(const struct drm_plane_state *state) { - return ALIGN(drm_rect_width(&state->src) >> 16, 8); + /* + * Do not align width to 8 pixels here. The IDMAC read width + * must match the DC/DI hactive exactly, otherwise the DMFC + * FIFO overflows or underflows causing IDMAC timeouts or + * display corruption. The DMA burst size is adapted to the + * actual width by ipu_calculate_bursts(). + */ + return drm_rect_width(&state->src) >> 16; } static inline struct ipu_plane *to_ipu_plane(struct drm_plane *p) diff --git a/drivers/gpu/ipu-v3/ipu-dc.c b/drivers/gpu/ipu-v3/ipu-dc.c index b038a6d73..f5990e3dc 100644 --- a/drivers/gpu/ipu-v3/ipu-dc.c +++ b/drivers/gpu/ipu-v3/ipu-dc.c @@ -168,8 +168,9 @@ int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced, dc->di = ipu_di_get_num(di); if (!IS_ALIGNED(width, 8)) { - dev_warn(priv->dev, - "%s: hactive does not align to 8 byte\n", __func__); + dev_dbg(priv->dev, + "%s: hactive %u is not 8-pixel aligned\n", + __func__, width); } map = ipu_bus_format_to_map(bus_format); -- 2.39.5
