drm/rockchip: vop2: add consider three display pending done bit

Change-Id: I9e2fe62cff31153a1b16faaaa11f9a49b8051975
Signed-off-by: Sandy Huang <hjc@rock-chips.com>
This commit is contained in:
Sandy Huang
2021-04-14 10:43:38 +08:00
parent a103f1595b
commit dbb3122b77

View File

@@ -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;
}