drm/rockchip: vop2: Add support for hdmi

Signed-off-by: Algea Cao <algea.cao@rock-chips.com>
Change-Id: I6043fad382c48670c765bce67a3f291a0fc66bd5
This commit is contained in:
Algea Cao 2020-12-29 11:33:39 +08:00 committed by Jianhong Chen
parent 1d22de7f19
commit 10ee9f5b51
1 changed files with 89 additions and 2 deletions

View File

@ -62,6 +62,8 @@
#define IF_CRTL_MIPI_DCLK_POL_SHIT 19 #define IF_CRTL_MIPI_DCLK_POL_SHIT 19
#define IF_CRTL_EDP_DCLK_POL_SHIT 15 #define IF_CRTL_EDP_DCLK_POL_SHIT 15
#define IF_CRTL_HDMI_DCLK_POL_SHIT 7 #define IF_CRTL_HDMI_DCLK_POL_SHIT 7
#define IF_CRTL_HDMI_PIN_POL_MASK 0x7
#define IF_CRTL_HDMI_PIN_POL_SHIT 4
#define IF_CRTL_RGB_LVDS_DCLK_POL_SHIT 3 #define IF_CRTL_RGB_LVDS_DCLK_POL_SHIT 3
#define RK3568_VP0_LINE_FLAG 0x70 #define RK3568_VP0_LINE_FLAG 0x70
#define RK3568_VP1_LINE_FLAG 0x74 #define RK3568_VP1_LINE_FLAG 0x74
@ -86,14 +88,20 @@
#define RK3568_VP0_DSP_CTRL 0xC00 #define RK3568_VP0_DSP_CTRL 0xC00
#define OUT_MODE_MASK 0xf #define OUT_MODE_MASK 0xf
#define OUT_MODE_SHIFT 0 #define OUT_MODE_SHIFT 0
#define DCLK_DIV2_EN_SHIFT 4 #define DATA_SWAP_MASK 0x1f
#define DATA_SWAP_SHIFT 8
#define DSP_RB_SWAP 2
#define CORE_DCLK_DIV_EN_SHIFT 4
#define P2I_EN_SHIFT 5 #define P2I_EN_SHIFT 5
#define INTERLACE_EN_SHIFT 7 #define INTERLACE_EN_SHIFT 7
#define POST_DSP_OUT_R2Y_SHIFT 15
#define PRE_DITHER_DOWN_EN_SHIFT 16 #define PRE_DITHER_DOWN_EN_SHIFT 16
#define DITHER_DOWN_EN_SHIFT 17 #define DITHER_DOWN_EN_SHIFT 17
#define STANDBY_EN_SHIFT 31 #define STANDBY_EN_SHIFT 31
#define RK3568_VP0_MIPI_CTRL 0xC04 #define RK3568_VP0_MIPI_CTRL 0xC04
#define DCLK_DIV2_SHIFT 4
#define DCLK_DIV2_MASK 0x3
#define MIPI_DUAL_EN_SHIFT 20 #define MIPI_DUAL_EN_SHIFT 20
#define MIPI_DUAL_SWAP_EN_SHIFT 21 #define MIPI_DUAL_SWAP_EN_SHIFT 21
@ -253,10 +261,14 @@
/* Esmart register definition */ /* Esmart register definition */
#define RK3568_ESMART0_CTRL0 0x1800 #define RK3568_ESMART0_CTRL0 0x1800
#define RGB2YUV_EN_SHIFT 1
#define CSC_MODE_SHIFT 2
#define CSC_MODE_MASK 0x3
#define RK3568_ESMART0_CTRL1 0x1804 #define RK3568_ESMART0_CTRL1 0x1804
#define YMIRROR_EN_SHIFT 31 #define YMIRROR_EN_SHIFT 31
#define RK3568_ESMART0_REGION0_CTRL 0x1810 #define RK3568_ESMART0_REGION0_CTRL 0x1810
#define REGION0_RB_SWAP_SHIFT 14
#define WIN_EN_SHIFT 0 #define WIN_EN_SHIFT 0
#define WIN_FORMAT_MASK 0x1f #define WIN_FORMAT_MASK 0x1f
#define WIN_FORMAT_SHIFT 1 #define WIN_FORMAT_SHIFT 1
@ -451,6 +463,20 @@
#define VOP2_LAYER_MAX 8 #define VOP2_LAYER_MAX 8
#define VOP2_MAX_VP 4 #define VOP2_MAX_VP 4
enum vop2_csc_format {
CSC_BT601L,
CSC_BT709L,
CSC_BT601F,
CSC_BT2020,
};
enum vop2_pol {
HSYNC_POSITIVE = 0,
VSYNC_POSITIVE = 1,
DEN_NEGATIVE = 2,
DCLK_INVERT = 3
};
#define _VOP_REG(off, _mask, _shift, _write_mask) \ #define _VOP_REG(off, _mask, _shift, _write_mask) \
{ \ { \
.offset = off, \ .offset = off, \
@ -596,6 +622,26 @@ static bool is_yuv_output(uint32_t bus_format)
} }
} }
static int vop2_convert_csc_mode(int csc_mode)
{
switch (csc_mode) {
case V4L2_COLORSPACE_SMPTE170M:
case V4L2_COLORSPACE_470_SYSTEM_M:
case V4L2_COLORSPACE_470_SYSTEM_BG:
return CSC_BT601L;
case V4L2_COLORSPACE_REC709:
case V4L2_COLORSPACE_SMPTE240M:
case V4L2_COLORSPACE_DEFAULT:
return CSC_BT709L;
case V4L2_COLORSPACE_JPEG:
return CSC_BT601F;
case V4L2_COLORSPACE_BT2020:
return CSC_BT2020;
default:
return CSC_BT709L;
}
}
static __maybe_unused bool is_uv_swap(uint32_t bus_format, uint32_t output_mode) static __maybe_unused bool is_uv_swap(uint32_t bus_format, uint32_t output_mode)
{ {
/* /*
@ -817,6 +863,8 @@ static int rockchip_vop2_init(struct display_state *state)
vop2_initial(vop2, state); vop2_initial(vop2, state);
dclk_inv = (mode->flags & DRM_MODE_FLAG_PPIXDATA) ? 0 : 1; dclk_inv = (mode->flags & DRM_MODE_FLAG_PPIXDATA) ? 0 : 1;
val = (mode->flags & DRM_MODE_FLAG_NHSYNC) ? 0 : BIT(HSYNC_POSITIVE);
val |= (mode->flags & DRM_MODE_FLAG_NVSYNC) ? 0 : BIT(VSYNC_POSITIVE);
if (conn_state->output_if & VOP_OUTPUT_IF_RGB) { if (conn_state->output_if & VOP_OUTPUT_IF_RGB) {
vop2_mask_write(vop2, RK3568_DSP_IF_EN, EN_MASK, RGB_EN_SHIFT, vop2_mask_write(vop2, RK3568_DSP_IF_EN, EN_MASK, RGB_EN_SHIFT,
@ -913,7 +961,22 @@ static int rockchip_vop2_init(struct display_state *state)
1, false); 1, false);
vop2_mask_write(vop2, RK3568_DSP_IF_EN, IF_MUX_MASK, vop2_mask_write(vop2, RK3568_DSP_IF_EN, IF_MUX_MASK,
HDMI0_MUX_SHIFT, cstate->crtc_id, false); HDMI0_MUX_SHIFT, cstate->crtc_id, false);
vop2_mask_write(vop2, RK3568_DSP_IF_POL, EN_MASK,
IF_CRTL_HDMI_DCLK_POL_SHIT, 1, false);
vop2_mask_write(vop2, RK3568_DSP_IF_POL,
IF_CRTL_HDMI_PIN_POL_MASK,
IF_CRTL_HDMI_PIN_POL_SHIT, val, false);
} }
if (is_uv_swap(conn_state->bus_format, conn_state->output_mode))
vop2_mask_write(vop2, RK3568_VP0_DSP_CTRL + vp_offset,
DATA_SWAP_MASK, DATA_SWAP_SHIFT, DSP_RB_SWAP,
false);
else
vop2_mask_write(vop2, RK3568_VP0_DSP_CTRL + vp_offset,
DATA_SWAP_MASK, DATA_SWAP_SHIFT, 0,
false);
vop2_mask_write(vop2, RK3568_VP0_DSP_CTRL + vp_offset, OUT_MODE_MASK, vop2_mask_write(vop2, RK3568_VP0_DSP_CTRL + vp_offset, OUT_MODE_MASK,
OUT_MODE_SHIFT, conn_state->output_mode, false); OUT_MODE_SHIFT, conn_state->output_mode, false);
@ -991,7 +1054,23 @@ static int rockchip_vop2_init(struct display_state *state)
(vtotal << 16) | vsync_len); (vtotal << 16) | vsync_len);
val = ! !(mode->flags & DRM_MODE_FLAG_DBLCLK); val = ! !(mode->flags & DRM_MODE_FLAG_DBLCLK);
vop2_mask_write(vop2, RK3568_VP0_DSP_CTRL + vp_offset, EN_MASK, vop2_mask_write(vop2, RK3568_VP0_DSP_CTRL + vp_offset, EN_MASK,
DCLK_DIV2_EN_SHIFT, val, false); CORE_DCLK_DIV_EN_SHIFT, val, false);
if (conn_state->output_mode == ROCKCHIP_OUT_MODE_YUV420)
vop2_mask_write(vop2, RK3568_VP0_MIPI_CTRL + vp_offset, DCLK_DIV2_MASK,
DCLK_DIV2_SHIFT, 0x3, false);
else
vop2_mask_write(vop2, RK3568_VP0_MIPI_CTRL + vp_offset, DCLK_DIV2_MASK,
DCLK_DIV2_SHIFT, 0, false);
if (yuv_overlay)
val = 0x20010200;
else
val = 0;
vop2_writel(vop2, RK3568_VP0_DSP_BG + vp_offset, val);
vop2_mask_write(vop2, RK3568_VP0_DSP_CTRL + vp_offset, EN_MASK,
POST_DSP_OUT_R2Y_SHIFT, yuv_overlay, false);
vop2_post_config(state, vop2); vop2_post_config(state, vop2);
vop2_setup_win_for_vp(state); vop2_setup_win_for_vp(state);
@ -1073,6 +1152,7 @@ static int rockchip_vop2_set_plane(struct display_state *state)
int crtc_h = cstate->crtc_h; int crtc_h = cstate->crtc_h;
int xvir = cstate->xvir; int xvir = cstate->xvir;
int y_mirror = 0; int y_mirror = 0;
int csc_mode;
uint32_t win_offset = cstate->crtc_id * 0x200; uint32_t win_offset = cstate->crtc_id * 0x200;
uint32_t cfg_done = CFG_DONE_EN | BIT(cstate->crtc_id); uint32_t cfg_done = CFG_DONE_EN | BIT(cstate->crtc_id);
@ -1118,6 +1198,13 @@ static int rockchip_vop2_set_plane(struct display_state *state)
vop2_mask_write(vop2, RK3568_ESMART0_REGION0_CTRL + win_offset, EN_MASK, vop2_mask_write(vop2, RK3568_ESMART0_REGION0_CTRL + win_offset, EN_MASK,
WIN_EN_SHIFT, 1, false); WIN_EN_SHIFT, 1, false);
csc_mode = vop2_convert_csc_mode(conn_state->color_space);
vop2_mask_write(vop2, RK3568_ESMART0_CTRL0 + win_offset, EN_MASK,
RGB2YUV_EN_SHIFT,
is_yuv_output(conn_state->bus_format), false);
vop2_mask_write(vop2, RK3568_ESMART0_CTRL0 + win_offset, CSC_MODE_MASK,
CSC_MODE_SHIFT, csc_mode, false);
vop2_writel(vop2, RK3568_REG_CFG_DONE, cfg_done); vop2_writel(vop2, RK3568_REG_CFG_DONE, cfg_done);
return 0; return 0;
} }