From 7751fcdc185fc49740597807b2f820861fca34c2 Mon Sep 17 00:00:00 2001 From: Sandy Huang Date: Fri, 23 Jul 2021 10:21:50 +0800 Subject: [PATCH] drm/rockchip: vop: Deal with display area out of display mode Some linux display framework will set display area out of display mode, this is incorrect config and will lead vop iommu pagefault, we add this commit to avoid vop pagefault and output error info. Signed-off-by: Sandy Huang Change-Id: I50f9c93d807858b8939038aae9915b4895fe35e2 --- drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 27 ++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 6b84508a5339..a0d0cd4c1c1b 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -1767,10 +1767,11 @@ static void vop_plane_atomic_update(struct drm_plane *plane, struct drm_display_mode *mode = NULL; struct vop_win *win = to_vop_win(plane); struct vop_plane_state *vop_plane_state = to_vop_plane_state(state); + struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode; struct rockchip_crtc_state *s; struct vop *vop = to_vop(state->crtc); struct drm_framebuffer *fb = state->fb; - unsigned int actual_w, actual_h; + unsigned int actual_w, actual_h, dsp_w, dsp_h; unsigned int dsp_stx, dsp_sty; uint32_t act_info, dsp_info, dsp_st; struct drm_rect *src = &vop_plane_state->src; @@ -1823,10 +1824,30 @@ static void vop_plane_atomic_update(struct drm_plane *plane, mode = &crtc->state->adjusted_mode; actual_w = drm_rect_width(src) >> 16; actual_h = drm_rect_height(src) >> 16; + + dsp_w = drm_rect_width(dest); + if (dest->x1 + dsp_w > adjusted_mode->hdisplay) { + DRM_ERROR("%s win%d dest->x1[%d] + dsp_w[%d] exceed mode hdisplay[%d]\n", + crtc->name, win->win_id, dest->x1, dsp_w, adjusted_mode->hdisplay); + dsp_w = adjusted_mode->hdisplay - dest->x1; + if (dsp_w < 4) + dsp_w = 4; + actual_w = dsp_w * actual_w / drm_rect_width(dest); + } + dsp_h = drm_rect_height(dest); + if (dest->y1 + dsp_h > adjusted_mode->vdisplay) { + DRM_ERROR("%s win%d dest->y1[%d] + dsp_h[%d] exceed mode vdisplay[%d]\n", + crtc->name, win->win_id, dest->y1, dsp_h, adjusted_mode->vdisplay); + dsp_h = adjusted_mode->vdisplay - dest->y1; + if (dsp_h < 4) + dsp_h = 4; + actual_h = dsp_h * actual_h / drm_rect_height(dest); + } + act_info = (actual_h - 1) << 16 | ((actual_w - 1) & 0xffff); - dsp_info = (drm_rect_height(dest) - 1) << 16; - dsp_info |= (drm_rect_width(dest) - 1) & 0xffff; + dsp_info = (dsp_h - 1) << 16; + dsp_info |= (dsp_w - 1) & 0xffff; dsp_stx = dest->x1 + mode->crtc_htotal - mode->crtc_hsync_start; dsp_sty = dest->y1 + mode->crtc_vtotal - mode->crtc_vsync_start;