drm/rockchip: vop2: Fix no signal when switch YUV420 to RGB/YUV444 in hdmi frl mode

The timing of YUV420 at the same resolution is different from other
color formats. Therefore, if timing switch of vop is later than the
switching process of hdmi, hdmi timing will be abnormal.

In hdmi frl mode, input ipi clk is different from output link clk
frequency, which makes it difficult to restore after the timing
error.

Therefore, it is necessary to ensure that the output mode of
vop is switched before hdmi switch to ensure the correct timing

Change-Id: I4633670f13a28975eb37a68ad597956d87a159c3
Signed-off-by: Algea Cao <algea.cao@rock-chips.com>
This commit is contained in:
Algea Cao
2024-03-22 09:30:05 +08:00
committed by Tao Huang
parent 3133279020
commit 19bc7529b9

View File

@@ -8553,6 +8553,41 @@ static void vop3_setup_pipe_dly(struct vop2_video_port *vp, const struct vop2_zp
}
}
static void vop2_crtc_setup_output_mode(struct drm_crtc *crtc)
{
uint8_t out_mode;
struct vop2_video_port *vp = to_vop2_video_port(crtc);
struct vop2 *vop2 = vp->vop2;
const struct vop2_data *vop2_data = vop2->data;
const struct vop2_video_port_data *vp_data = &vop2_data->vp[vp->id];
struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
if ((vcstate->output_mode == ROCKCHIP_OUT_MODE_AAAA &&
!(vp_data->feature & VOP_FEATURE_OUTPUT_10BIT)) ||
vcstate->output_if & VOP_OUTPUT_IF_BT656)
out_mode = ROCKCHIP_OUT_MODE_P888;
else
out_mode = vcstate->output_mode;
if (out_mode == ROCKCHIP_OUT_MODE_YUV420) {
if (vop2->version == VOP_VERSION_RK3588 && output_if_is_dp(vcstate->output_if))
out_mode = RK3588_DP_OUT_MODE_YUV420;
} else if (out_mode == ROCKCHIP_OUT_MODE_YUV422) {
if (vop2->version == VOP_VERSION_RK3576 && output_if_is_edp(vcstate->output_if))
out_mode = RK3576_EDP_OUT_MODE_YUV422;
else if (vop2->version == VOP_VERSION_RK3588 &&
output_if_is_edp(vcstate->output_if))
out_mode = RK3588_EDP_OUTPUT_MODE_YUV422;
else if (vop2->version == VOP_VERSION_RK3576 &&
output_if_is_hdmi(vcstate->output_if))
out_mode = RK3576_HDMI_OUT_MODE_YUV422;
else if (output_if_is_dp(vcstate->output_if))
out_mode = RK3588_DP_OUT_MODE_YUV422;
}
VOP_MODULE_SET(vop2, vp, out_mode, out_mode);
}
static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state)
{
struct vop2_video_port *vp = to_vop2_video_port(crtc);
@@ -8988,6 +9023,8 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_sta
vop3_setup_pipe_dly(vp, NULL);
vop2_crtc_csu_set_rate(crtc);
vop2_crtc_setup_output_mode(crtc);
vop2_cfg_done(crtc);
/*
@@ -11019,33 +11056,9 @@ static void vop2_cfg_update(struct drm_crtc *crtc,
struct vop2_video_port *splice_vp = &vop2->vps[vp_data->splice_vp_id];
uint32_t val;
uint32_t r, g, b;
uint8_t out_mode;
spin_lock(&vop2->reg_lock);
if ((vcstate->output_mode == ROCKCHIP_OUT_MODE_AAAA &&
!(vp_data->feature & VOP_FEATURE_OUTPUT_10BIT)) ||
vcstate->output_if & VOP_OUTPUT_IF_BT656)
out_mode = ROCKCHIP_OUT_MODE_P888;
else
out_mode = vcstate->output_mode;
if (out_mode == ROCKCHIP_OUT_MODE_YUV420) {
if (vop2->version == VOP_VERSION_RK3588 && output_if_is_dp(vcstate->output_if))
out_mode = RK3588_DP_OUT_MODE_YUV420;
} else if (out_mode == ROCKCHIP_OUT_MODE_YUV422) {
if (vop2->version == VOP_VERSION_RK3576 && output_if_is_edp(vcstate->output_if))
out_mode = RK3576_EDP_OUT_MODE_YUV422;
else if (vop2->version == VOP_VERSION_RK3588 && output_if_is_edp(vcstate->output_if))
out_mode = RK3588_EDP_OUTPUT_MODE_YUV422;
else if (vop2->version == VOP_VERSION_RK3576 && output_if_is_hdmi(vcstate->output_if))
out_mode = RK3576_HDMI_OUT_MODE_YUV422;
else if (output_if_is_dp(vcstate->output_if))
out_mode = RK3588_DP_OUT_MODE_YUV422;
}
VOP_MODULE_SET(vop2, vp, out_mode, out_mode);
vop2_post_color_swap(crtc);
vop2_dither_setup(vcstate, crtc);
@@ -11183,6 +11196,14 @@ static void vop2_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_stat
vop2_wait_for_scan_timing_from_the_assigned_line(vp, current_line, vtotal >> 3);
}
/*
* In some cases(such as seamless hdr switching) the crtc
* atomic enable will not be run, but vop output mode may
* also be modified. So vop2_crtc_setup_output_mode must
* be call in crtc atomic flush
*/
vop2_crtc_setup_output_mode(crtc);
vop2_cfg_update(crtc, old_cstate);
if (!vop2->is_iommu_enabled && vop2->is_iommu_needed) {