drm/rockchip: add support interlace mode output

add interlace timing config for hdmi/cvbs interlace output mode

Change-Id: Ic0bb06667a5c56d81f5229b7ef87baef9e0e5f32
Signed-off-by: Sandy Huang <hjc@rock-chips.com>
(Cherry pick from commit 3452c2ff12f80f249bc54d28bc3c52d089f76a8a)
This commit is contained in:
Sandy Huang 2017-12-13 19:35:59 +08:00 committed by Kever Yang
parent 79feefb115
commit ccd843b928
3 changed files with 149 additions and 16 deletions

View File

@ -311,6 +311,87 @@ static int display_get_timing_from_dts(struct panel_state *panel_state,
return 0;
}
/**
* drm_mode_set_crtcinfo - set CRTC modesetting timing parameters
* @p: mode
* @adjust_flags: a combination of adjustment flags
*
* Setup the CRTC modesetting timing parameters for @p, adjusting if necessary.
*
* - The CRTC_INTERLACE_HALVE_V flag can be used to halve vertical timings of
* interlaced modes.
* - The CRTC_STEREO_DOUBLE flag can be used to compute the timings for
* buffers containing two eyes (only adjust the timings when needed, eg. for
* "frame packing" or "side by side full").
* - The CRTC_NO_DBLSCAN and CRTC_NO_VSCAN flags request that adjustment *not*
* be performed for doublescan and vscan > 1 modes respectively.
*/
void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags)
{
if ((p == NULL) || ((p->type & DRM_MODE_TYPE_CRTC_C) == DRM_MODE_TYPE_BUILTIN))
return;
if (p->flags & DRM_MODE_FLAG_DBLCLK)
p->crtc_clock = 2 * p->clock;
else
p->crtc_clock = p->clock;
p->crtc_hdisplay = p->hdisplay;
p->crtc_hsync_start = p->hsync_start;
p->crtc_hsync_end = p->hsync_end;
p->crtc_htotal = p->htotal;
p->crtc_hskew = p->hskew;
p->crtc_vdisplay = p->vdisplay;
p->crtc_vsync_start = p->vsync_start;
p->crtc_vsync_end = p->vsync_end;
p->crtc_vtotal = p->vtotal;
if (p->flags & DRM_MODE_FLAG_INTERLACE) {
if (adjust_flags & CRTC_INTERLACE_HALVE_V) {
p->crtc_vdisplay /= 2;
p->crtc_vsync_start /= 2;
p->crtc_vsync_end /= 2;
p->crtc_vtotal /= 2;
}
}
if (!(adjust_flags & CRTC_NO_DBLSCAN)) {
if (p->flags & DRM_MODE_FLAG_DBLSCAN) {
p->crtc_vdisplay *= 2;
p->crtc_vsync_start *= 2;
p->crtc_vsync_end *= 2;
p->crtc_vtotal *= 2;
}
}
if (!(adjust_flags & CRTC_NO_VSCAN)) {
if (p->vscan > 1) {
p->crtc_vdisplay *= p->vscan;
p->crtc_vsync_start *= p->vscan;
p->crtc_vsync_end *= p->vscan;
p->crtc_vtotal *= p->vscan;
}
}
if (adjust_flags & CRTC_STEREO_DOUBLE) {
unsigned int layout = p->flags & DRM_MODE_FLAG_3D_MASK;
switch (layout) {
case DRM_MODE_FLAG_3D_FRAME_PACKING:
p->crtc_clock *= 2;
p->crtc_vdisplay += p->crtc_vtotal;
p->crtc_vsync_start += p->crtc_vtotal;
p->crtc_vsync_end += p->crtc_vtotal;
p->crtc_vtotal += p->crtc_vtotal;
break;
}
}
p->crtc_vblank_start = min(p->crtc_vsync_start, p->crtc_vdisplay);
p->crtc_vblank_end = max(p->crtc_vsync_end, p->crtc_vtotal);
p->crtc_hblank_start = min(p->crtc_hsync_start, p->crtc_hdisplay);
p->crtc_hblank_end = max(p->crtc_hsync_end, p->crtc_htotal);
}
static int display_get_timing(struct display_state *state)
{
struct connector_state *conn_state = &state->conn_state;
@ -372,6 +453,7 @@ static int display_init(struct display_state *state)
struct crtc_state *crtc_state = &state->crtc_state;
const struct rockchip_crtc *crtc = crtc_state->crtc;
const struct rockchip_crtc_funcs *crtc_funcs = crtc->funcs;
struct drm_display_mode *mode = &conn_state->mode;
int ret = 0;
if (state->is_init)
@ -405,6 +487,7 @@ static int display_init(struct display_state *state)
if (ret)
goto deinit;
}
drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
if (crtc_funcs->init) {
ret = crtc_funcs->init(state);

View File

@ -140,15 +140,15 @@ static int rockchip_vop_init(struct display_state *state)
const struct rockchip_crtc *crtc = crtc_state->crtc;
const struct vop_data *vop_data = crtc->data;
struct vop *vop;
u16 hsync_len = mode->hsync_end - mode->hsync_start;
u16 hdisplay = mode->hdisplay;
u16 htotal = mode->htotal;
u16 hact_st = mode->htotal - mode->hsync_start;
u16 hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start;
u16 hdisplay = mode->crtc_hdisplay;
u16 htotal = mode->crtc_htotal;
u16 hact_st = mode->crtc_htotal - mode->crtc_hsync_start;
u16 hact_end = hact_st + hdisplay;
u16 vdisplay = mode->vdisplay;
u16 vtotal = mode->vtotal;
u16 vsync_len = mode->vsync_end - mode->vsync_start;
u16 vact_st = mode->vtotal - mode->vsync_start;
u16 vdisplay = mode->crtc_vdisplay;
u16 vtotal = mode->crtc_vtotal;
u16 vsync_len = mode->crtc_vsync_end - mode->crtc_vsync_start;
u16 vact_st = mode->crtc_vtotal - mode->crtc_vsync_start;
u16 vact_end = vact_st + vdisplay;
struct clk dclk, aclk;
u32 val;
@ -312,11 +312,31 @@ static int rockchip_vop_init(struct display_state *state)
val |= hact_end;
VOP_CTRL_SET(vop, hact_st_end, val);
VOP_CTRL_SET(vop, hpost_st_end, val);
VOP_CTRL_SET(vop, vtotal_pw, (vtotal << 16) | vsync_len);
val = vact_st << 16;
val |= vact_end;
VOP_CTRL_SET(vop, vact_st_end, val);
VOP_CTRL_SET(vop, vpost_st_end, val);
if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
u16 vact_st_f1 = vtotal + vact_st + 1;
u16 vact_end_f1 = vact_st_f1 + vdisplay;
val = vact_st_f1 << 16 | vact_end_f1;
VOP_CTRL_SET(vop, vact_st_end_f1, val);
VOP_CTRL_SET(vop, vpost_st_end_f1, val);
val = vtotal << 16 | (vtotal + vsync_len);
VOP_CTRL_SET(vop, vs_st_end_f1, val);
VOP_CTRL_SET(vop, dsp_interlace, 1);
VOP_CTRL_SET(vop, p2i_en, 1);
vtotal += vtotal + 1;
} else {
VOP_CTRL_SET(vop, dsp_interlace, 0);
VOP_CTRL_SET(vop, p2i_en, 0);
}
VOP_CTRL_SET(vop, vtotal_pw, (vtotal << 16) | vsync_len);
VOP_CTRL_SET(vop, core_dclk_div,
!!(mode->flags & DRM_MODE_FLAG_DBLCLK));
VOP_CTRL_SET(vop, standby, 1);
VOP_LINE_FLAG_SET(vop, line_flag_num[0], vact_end - 3);
VOP_LINE_FLAG_SET(vop, line_flag_num[1],

View File

@ -7,13 +7,18 @@
#ifndef _DRM_MODES_H
#define _DRM_MODES_H
#define DRM_MODE_TYPE_BUILTIN BIT(0)
#define DRM_MODE_TYPE_CLOCK_C (BIT(1) | DRM_MODE_TYPE_BUILTIN)
#define DRM_MODE_TYPE_CRTC_C (BIT(2) | DRM_MODE_TYPE_BUILTIN)
#define DRM_MODE_TYPE_PREFERRED BIT(3)
#define DRM_MODE_TYPE_DEFAULT BIT(4)
#define DRM_MODE_TYPE_USERDEF BIT(5)
#define DRM_MODE_TYPE_DRIVER BIT(6)
#define DRM_DISPLAY_INFO_LEN 32
#define DRM_CONNECTOR_NAME_LEN 32
#define DRM_DISPLAY_MODE_LEN 32
#define DRM_PROP_NAME_LEN 32
#define DRM_MODE_TYPE_BUILTIN (1<<0)
#define DRM_MODE_TYPE_CLOCK_C ((1<<1) | DRM_MODE_TYPE_BUILTIN)
#define DRM_MODE_TYPE_CRTC_C ((1<<2) | DRM_MODE_TYPE_BUILTIN)
#define DRM_MODE_TYPE_PREFERRED (1<<3)
#define DRM_MODE_TYPE_DEFAULT (1<<4)
#define DRM_MODE_TYPE_USERDEF (1<<5)
#define DRM_MODE_TYPE_DRIVER (1<<6)
/* Video mode flags */
/* bit compatible with the xorg definitions. */
@ -114,6 +119,14 @@ enum v4l2_colorspace {
V4L2_COLORSPACE_DCI_P3 = 12,
};
#define CRTC_INTERLACE_HALVE_V (1 << 0) /* halve V values for interlacing */
#define CRTC_STEREO_DOUBLE (1 << 1) /* adjust timings for stereo modes */
#define CRTC_NO_DBLSCAN (1 << 2) /* don't adjust doublescan */
#define CRTC_NO_VSCAN (1 << 3) /* don't adjust doublescan */
#define CRTC_STEREO_DOUBLE_ONLY (CRTC_STEREO_DOUBLE | CRTC_NO_DBLSCAN | CRTC_NO_VSCAN)
#define DRM_MODE_FLAG_3D_MAX DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF
struct drm_display_mode {
/* Proposed mode values */
int clock; /* in kHz */
@ -129,6 +142,23 @@ struct drm_display_mode {
int vscan;
unsigned int flags;
int picture_aspect_ratio;
int hskew;
unsigned int type;
/* Actual mode we give to hw */
int crtc_clock; /* in KHz */
int crtc_hdisplay;
int crtc_hblank_start;
int crtc_hblank_end;
int crtc_hsync_start;
int crtc_hsync_end;
int crtc_htotal;
int crtc_hskew;
int crtc_vdisplay;
int crtc_vblank_start;
int crtc_vblank_end;
int crtc_vsync_start;
int crtc_vsync_end;
int crtc_vtotal;
};
#endif