From dbb3122b7794902eb35f30131afe24c27dd7fd28 Mon Sep 17 00:00:00 2001 From: Sandy Huang Date: Wed, 14 Apr 2021 10:43:38 +0800 Subject: [PATCH] drm/rockchip: vop2: add consider three display pending done bit Change-Id: I9e2fe62cff31153a1b16faaaa11f9a49b8051975 Signed-off-by: Sandy Huang --- drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 102 +++++++++++++++---- 1 file changed, 82 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 0ee9b37f1b7c..9787fcc84735 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -684,6 +684,12 @@ static inline void vop2_mask_write(struct vop2 *vop2, uint32_t offset, writel(v, vop2->regs + offset); } +static inline u32 vop2_line_to_time(struct drm_display_mode *mode, int line) +{ + /* us */ + return 1000000 / mode->crtc_clock * mode->crtc_htotal / 1000 * line; +} + static bool vop2_soc_is_rk3566(void) { return soc_is_rk3566(); @@ -891,7 +897,7 @@ static void vop2_wait_for_fs_by_raw_status(struct vop2_video_port *vp) * has take effect. */ ret = readx_poll_timeout_atomic(vop2_fs_raw_status_pending, vp, pending, - pending, 0, 10 * 1000); + pending, 0, 50 * 1000); if (ret) DRM_DEV_ERROR(vop2->dev, "wait vp%d raw fs statu timeout\n", vp->id); @@ -912,7 +918,7 @@ static void vop2_wait_for_port_mux_done(struct vop2 *vop2) * is done. */ ret = readx_poll_timeout_atomic(vop2_read_port_mux, vop2, port_mux_cfg, - port_mux_cfg == vop2->port_mux_cfg, 0, 20 * 1000); + port_mux_cfg == vop2->port_mux_cfg, 0, 50 * 1000); if (ret) DRM_DEV_ERROR(vop2->dev, "wait port_mux done timeout: 0x%x--0x%x\n", port_mux_cfg, vop2->port_mux_cfg); @@ -923,29 +929,85 @@ static int32_t vop2_pending_done_bits(struct vop2_video_port *vp) struct vop2 *vop2 = vp->vop2; struct drm_display_mode *adjusted_mode; struct vop2_video_port *done_vp; - uint32_t done_bits; + uint32_t done_bits, done_bits_bak; uint32_t vp_id; uint32_t vcnt; done_bits = vop2_readl(vop2, RK3568_REG_CFG_DONE) & 0x7; - /* we have some vp wait for config done take effect */ - if (done_bits) { - vp_id = ffs(done_bits) - 1; - /* no need to wait for same vp */ - if (vp_id != vp->id) { - done_vp = &vop2->vps[vp_id]; - adjusted_mode = &done_vp->crtc.state->adjusted_mode; - vcnt = vop2_read_vcnt(done_vp); - if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) - vcnt >>= 1; - /* if close to the last 1/8 frame, wait to next frame */ - if (vcnt > (adjusted_mode->crtc_vtotal * 7 >> 3)) { - vop2_wait_for_fs_by_raw_status(done_vp); - done_bits = 0; - } - } - } + done_bits_bak = done_bits; + /* no done bit, so no need to wait config done take effect */ + if (done_bits == 0) + return 0; + + vp_id = ffs(done_bits) - 1; + /* done bit is same with current vp config done, so no need to wait */ + if (hweight32(done_bits) == 1 && vp_id == vp->id) + return 0; + + /* have the other one different vp, wait for config done take effect */ + if (hweight32(done_bits) == 1 || + (hweight32(done_bits) == 2 && (done_bits & BIT(vp->id)))) { + /* two done bit, clear current vp done bit and find the other done bit vp */ + if (done_bits & BIT(vp->id)) + done_bits &= ~BIT(vp->id); + vp_id = ffs(done_bits) - 1; + done_vp = &vop2->vps[vp_id]; + adjusted_mode = &done_vp->crtc.state->adjusted_mode; + vcnt = vop2_read_vcnt(done_vp); + if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) + vcnt >>= 1; + /* if close to the last 1/8 frame, wait to next frame */ + if (vcnt > (adjusted_mode->crtc_vtotal * 7 >> 3)) { + vop2_wait_for_fs_by_raw_status(done_vp); + done_bits = 0; + } + } else { /* exist the other two vp done bit */ + struct drm_display_mode *first_mode, *second_mode; + struct vop2_video_port *first_done_vp, *second_done_vp, *wait_vp; + uint32_t first_vp_id, second_vp_id; + uint32_t first_vp_vcnt, second_vp_vcnt; + uint32_t first_vp_left_vcnt, second_vp_left_vcnt; + uint32_t first_vp_left_time, second_vp_left_time; + uint32_t first_vp_safe_time, second_vp_safe_time; + + first_vp_id = ffs(done_bits) - 1; + first_done_vp = &vop2->vps[first_vp_id]; + first_mode = &first_done_vp->crtc.state->adjusted_mode; + /* set last 1/8 frame time as safe section */ + first_vp_safe_time = 1000000 / first_mode->vrefresh >> 3; + + done_bits &= ~BIT(first_vp_id); + second_vp_id = ffs(done_bits) - 1; + second_done_vp = &vop2->vps[second_vp_id]; + second_mode = &second_done_vp->crtc.state->adjusted_mode; + /* set last 1/8 frame time as safe section */ + second_vp_safe_time = 1000000 / second_mode->vrefresh >> 3; + + first_vp_vcnt = vop2_read_vcnt(first_done_vp); + if (first_mode->flags & DRM_MODE_FLAG_INTERLACE) + first_vp_vcnt >>= 1; + second_vp_vcnt = vop2_read_vcnt(second_done_vp); + if (second_mode->flags & DRM_MODE_FLAG_INTERLACE) + second_vp_vcnt >>= 1; + + first_vp_left_vcnt = first_mode->crtc_vtotal - first_vp_vcnt; + second_vp_left_vcnt = second_mode->crtc_vtotal - second_vp_vcnt; + first_vp_left_time = vop2_line_to_time(first_mode, first_vp_left_vcnt); + second_vp_left_time = vop2_line_to_time(second_mode, second_vp_left_vcnt); + + /* if the two vp both at safe section, no need to wait */ + if (first_vp_left_time > first_vp_safe_time && + second_vp_left_time > second_vp_safe_time) + return done_bits_bak; + if (first_vp_left_time > second_vp_left_time) + wait_vp = first_done_vp; + else + wait_vp = second_done_vp; + + vop2_wait_for_fs_by_raw_status(wait_vp); + done_bits = 0; + } return done_bits; }