Commit 273c4176 authored by Mateusz Kwiatkowski's avatar Mateusz Kwiatkowski Committed by Maxime Ripard

drm/vc4: crtc: Fix timings for VEC modes

This commit fixes vertical timings of the VEC (composite output) modes
to accurately represent the 525-line ("NTSC") and 625-line ("PAL") ITU-R
standards.

Previous timings were actually defined as 502 and 601 lines, resulting
in non-standard 62.69 Hz and 52 Hz signals being generated,
respectively.

Changes to vc4_crtc.c have also been made, to make the PixelValve
vertical timings accurately correspond to the DRM modeline in interlaced
modes. The resulting VERTA/VERTB register values have been verified
against the reference values set by the Raspberry Pi firmware.
Signed-off-by: default avatarMateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
Link: https://lore.kernel.org/r/20221207-rpi-hvs-crtc-misc-v1-13-1f8e0770798b@cerno.techSigned-off-by: default avatarMaxime Ripard <maxime@cerno.tech>
parent 6c37c9c6
...@@ -335,8 +335,14 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_encoder *encode ...@@ -335,8 +335,14 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_encoder *encode
bool is_dsi = (vc4_encoder->type == VC4_ENCODER_TYPE_DSI0 || bool is_dsi = (vc4_encoder->type == VC4_ENCODER_TYPE_DSI0 ||
vc4_encoder->type == VC4_ENCODER_TYPE_DSI1); vc4_encoder->type == VC4_ENCODER_TYPE_DSI1);
bool is_dsi1 = vc4_encoder->type == VC4_ENCODER_TYPE_DSI1; bool is_dsi1 = vc4_encoder->type == VC4_ENCODER_TYPE_DSI1;
bool is_vec = vc4_encoder->type == VC4_ENCODER_TYPE_VEC;
u32 format = is_dsi1 ? PV_CONTROL_FORMAT_DSIV_24 : PV_CONTROL_FORMAT_24; u32 format = is_dsi1 ? PV_CONTROL_FORMAT_DSIV_24 : PV_CONTROL_FORMAT_24;
u8 ppc = pv_data->pixels_per_clock; u8 ppc = pv_data->pixels_per_clock;
u16 vert_bp = mode->crtc_vtotal - mode->crtc_vsync_end;
u16 vert_sync = mode->crtc_vsync_end - mode->crtc_vsync_start;
u16 vert_fp = mode->crtc_vsync_start - mode->crtc_vdisplay;
bool debug_dump_regs = false; bool debug_dump_regs = false;
int idx; int idx;
...@@ -364,49 +370,60 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_encoder *encode ...@@ -364,49 +370,60 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_encoder *encode
VC4_SET_FIELD(mode->hdisplay * pixel_rep / ppc, VC4_SET_FIELD(mode->hdisplay * pixel_rep / ppc,
PV_HORZB_HACTIVE)); PV_HORZB_HACTIVE));
CRTC_WRITE(PV_VERTA,
VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end +
interlace,
PV_VERTA_VBP) |
VC4_SET_FIELD(mode->crtc_vsync_end - mode->crtc_vsync_start,
PV_VERTA_VSYNC));
CRTC_WRITE(PV_VERTB,
VC4_SET_FIELD(mode->crtc_vsync_start - mode->crtc_vdisplay,
PV_VERTB_VFP) |
VC4_SET_FIELD(mode->crtc_vdisplay, PV_VERTB_VACTIVE));
if (interlace) { if (interlace) {
bool odd_field_first = false;
u32 field_delay = mode->htotal * pixel_rep / (2 * ppc);
u16 vert_bp_even = vert_bp;
u16 vert_fp_even = vert_fp;
if (is_vec) {
/* VEC (composite output) */
++field_delay;
if (mode->htotal == 858) {
/* 525-line mode (NTSC or PAL-M) */
odd_field_first = true;
}
}
if (odd_field_first)
++vert_fp_even;
else
++vert_bp;
CRTC_WRITE(PV_VERTA_EVEN, CRTC_WRITE(PV_VERTA_EVEN,
VC4_SET_FIELD(mode->crtc_vtotal - VC4_SET_FIELD(vert_bp_even, PV_VERTA_VBP) |
mode->crtc_vsync_end, VC4_SET_FIELD(vert_sync, PV_VERTA_VSYNC));
PV_VERTA_VBP) |
VC4_SET_FIELD(mode->crtc_vsync_end -
mode->crtc_vsync_start,
PV_VERTA_VSYNC));
CRTC_WRITE(PV_VERTB_EVEN, CRTC_WRITE(PV_VERTB_EVEN,
VC4_SET_FIELD(mode->crtc_vsync_start - VC4_SET_FIELD(vert_fp_even, PV_VERTB_VFP) |
mode->crtc_vdisplay,
PV_VERTB_VFP) |
VC4_SET_FIELD(mode->crtc_vdisplay, PV_VERTB_VACTIVE)); VC4_SET_FIELD(mode->crtc_vdisplay, PV_VERTB_VACTIVE));
/* We set up first field even mode for HDMI. VEC's /* We set up first field even mode for HDMI and VEC's PAL.
* NTSC mode would want first field odd instead, once * For NTSC, we need first field odd.
* we support it (to do so, set ODD_FIRST and put the
* delay in VSYNCD_EVEN instead).
*/ */
CRTC_WRITE(PV_V_CONTROL, CRTC_WRITE(PV_V_CONTROL,
PV_VCONTROL_CONTINUOUS | PV_VCONTROL_CONTINUOUS |
(is_dsi ? PV_VCONTROL_DSI : 0) | (is_dsi ? PV_VCONTROL_DSI : 0) |
PV_VCONTROL_INTERLACE | PV_VCONTROL_INTERLACE |
VC4_SET_FIELD(mode->htotal * pixel_rep / (2 * ppc), (odd_field_first
PV_VCONTROL_ODD_DELAY)); ? PV_VCONTROL_ODD_FIRST
CRTC_WRITE(PV_VSYNCD_EVEN, 0); : VC4_SET_FIELD(field_delay,
PV_VCONTROL_ODD_DELAY)));
CRTC_WRITE(PV_VSYNCD_EVEN,
(odd_field_first ? field_delay : 0));
} else { } else {
CRTC_WRITE(PV_V_CONTROL, CRTC_WRITE(PV_V_CONTROL,
PV_VCONTROL_CONTINUOUS | PV_VCONTROL_CONTINUOUS |
(is_dsi ? PV_VCONTROL_DSI : 0)); (is_dsi ? PV_VCONTROL_DSI : 0));
CRTC_WRITE(PV_VSYNCD_EVEN, 0);
} }
CRTC_WRITE(PV_VERTA,
VC4_SET_FIELD(vert_bp, PV_VERTA_VBP) |
VC4_SET_FIELD(vert_sync, PV_VERTA_VSYNC));
CRTC_WRITE(PV_VERTB,
VC4_SET_FIELD(vert_fp, PV_VERTB_VFP) |
VC4_SET_FIELD(mode->crtc_vdisplay, PV_VERTB_VACTIVE));
if (is_dsi) if (is_dsi)
CRTC_WRITE(PV_HACT_ACT, mode->hdisplay * pixel_rep); CRTC_WRITE(PV_HACT_ACT, mode->hdisplay * pixel_rep);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment