diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 387812d3cfc3..991f2df5f4e2 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -1655,6 +1655,11 @@ static void vop_initial(struct drm_crtc *crtc) } VOP_CTRL_SET(vop, afbdc_en, 0); vop_enable_debug_irq(crtc); + + if (vop->version == VOP_VERSION(2, 0xd)) { + VOP_GRF_SET(vop, grf_vopl_sel, 1); + VOP_CTRL_SET(vop, enable, 1); + } } static void vop_crtc_atomic_disable_for_psr(struct drm_crtc *crtc, @@ -2103,7 +2108,8 @@ static void vop_plane_atomic_update(struct drm_plane *plane, dsp_h = 4; actual_h = dsp_h * actual_h / drm_rect_height(dest); } - if ((adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) && vop->version == VOP_VERSION(2, 2)) + if ((vop->version == VOP_VERSION(2, 2) || vop->version == VOP_VERSION(2, 0xd)) && + (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)) dsp_h = dsp_h / 2; act_info = (actual_h - 1) << 16 | ((actual_w - 1) & 0xffff); @@ -2117,7 +2123,8 @@ static void vop_plane_atomic_update(struct drm_plane *plane, dsp_stx = dest->x1 + mode->crtc_htotal - mode->crtc_hsync_start; dsp_sty = dest->y1 + mode->crtc_vtotal - mode->crtc_vsync_start; - if ((adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) && vop->version == VOP_VERSION(2, 2)) + if ((vop->version == VOP_VERSION(2, 2) || vop->version == VOP_VERSION(2, 0xd)) && + (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)) dsp_sty = dest->y1 / 2 + mode->crtc_vtotal - mode->crtc_vsync_start; dsp_st = dsp_sty << 16 | (dsp_stx & 0xffff); @@ -3120,25 +3127,72 @@ static void vop_set_out_mode(struct vop *vop, u32 mode) 1000, 500 * 1000); if (ret) dev_err(vop->dev, "wait mode 0x%x timeout\n", mode); +} +static void vop_mcu_bypass_mode_setup(struct drm_crtc *crtc) +{ + struct vop *vop = to_vop(crtc); + + /* + * If mcu_hold_mode is 1, set 1 to mcu_frame_st will + * refresh one frame from ddr. So mcu_frame_st is needed + * to be initialized as 0. + */ + VOP_CTRL_SET(vop, mcu_frame_st, 0); + VOP_CTRL_SET(vop, mcu_clk_sel, 1); + VOP_CTRL_SET(vop, mcu_type, 1); + + VOP_CTRL_SET(vop, mcu_hold_mode, 1); + VOP_CTRL_SET(vop, mcu_pix_total, 53); + VOP_CTRL_SET(vop, mcu_cs_pst, 6); + VOP_CTRL_SET(vop, mcu_cs_pend, 48); + VOP_CTRL_SET(vop, mcu_rw_pst, 12); + VOP_CTRL_SET(vop, mcu_rw_pend, 30); +} + +static void vop_mcu_mode_setup(struct drm_crtc *crtc) +{ + struct vop *vop = to_vop(crtc); + + /* + * If mcu_hold_mode is 1, set 1 to mcu_frame_st will + * refresh one frame from ddr. So mcu_frame_st is needed + * to be initialized as 0. + */ + VOP_CTRL_SET(vop, mcu_frame_st, 0); + VOP_CTRL_SET(vop, mcu_clk_sel, 1); + VOP_CTRL_SET(vop, mcu_type, 1); + + VOP_CTRL_SET(vop, mcu_hold_mode, 1); + VOP_CTRL_SET(vop, mcu_pix_total, vop->mcu_timing.mcu_pix_total); + VOP_CTRL_SET(vop, mcu_cs_pst, vop->mcu_timing.mcu_cs_pst); + VOP_CTRL_SET(vop, mcu_cs_pend, vop->mcu_timing.mcu_cs_pend); + VOP_CTRL_SET(vop, mcu_rw_pst, vop->mcu_timing.mcu_rw_pst); + VOP_CTRL_SET(vop, mcu_rw_pend, vop->mcu_timing.mcu_rw_pend); } static void vop_crtc_send_mcu_cmd(struct drm_crtc *crtc, u32 type, u32 value) { - struct rockchip_crtc_state *state; + struct drm_display_mode *adjusted_mode; struct vop *vop = NULL; if (!crtc) return; vop = to_vop(crtc); - state = to_rockchip_crtc_state(crtc->state); + adjusted_mode = &crtc->state->adjusted_mode; + + if (vop->version == VOP_VERSION(2, 0xd)) { + /* + * 1.set mcu bypass mode timing. + * 2.set dclk rate to 150M. + */ + if ((type == MCU_SETBYPASS) && value) { + vop_mcu_bypass_mode_setup(crtc); + clk_set_rate(vop->dclk, 150000000); + } + } - /* - * set output mode to P888 when start send cmd. - */ - if ((type == MCU_SETBYPASS) && value) - vop_set_out_mode(vop, ROCKCHIP_OUT_MODE_P888); mutex_lock(&vop->vop_lock); if (vop && vop->is_enabled) { switch (type) { @@ -3160,11 +3214,16 @@ static void vop_crtc_send_mcu_cmd(struct drm_crtc *crtc, u32 type, u32 value) } mutex_unlock(&vop->vop_lock); - /* - * restore output mode at the end - */ - if ((type == MCU_SETBYPASS) && !value) - vop_set_out_mode(vop, state->output_mode); + if (vop->version == VOP_VERSION(2, 0xd)) { + /* + * 1.restore mcu data mode timing. + * 2.restore dclk rate to crtc_clock. + */ + if ((type == MCU_SETBYPASS) && !value) { + vop_mcu_mode_setup(crtc); + clk_set_rate(vop->dclk, adjusted_mode->crtc_clock * 1000); + } + } } static int vop_crtc_wait_vact_end(struct drm_crtc *crtc, unsigned int mstimeout) @@ -3364,6 +3423,8 @@ static void vop_update_csc(struct drm_crtc *crtc) */ if (!is_yuv_output(s->bus_format)) val = 0; + else if (vop->version == VOP_VERSION(2, 0xd)) + val = 0; else if (VOP_MAJOR(vop->version) == 3 && VOP_MINOR(vop->version) == 8 && s->hdr.pre_overlay) val = 0; @@ -3411,27 +3472,6 @@ static bool vop_crtc_mode_update(struct drm_crtc *crtc) return false; } -static void vop_mcu_mode(struct drm_crtc *crtc) -{ - struct vop *vop = to_vop(crtc); - - /* - * If mcu_hold_mode is 1, set 1 to mcu_frame_st will - * refresh one frame from ddr. So mcu_frame_st is needed - * to be initialized as 0. - */ - VOP_CTRL_SET(vop, mcu_frame_st, 0); - VOP_CTRL_SET(vop, mcu_clk_sel, 1); - VOP_CTRL_SET(vop, mcu_type, 1); - - VOP_CTRL_SET(vop, mcu_hold_mode, 1); - VOP_CTRL_SET(vop, mcu_pix_total, vop->mcu_timing.mcu_pix_total); - VOP_CTRL_SET(vop, mcu_cs_pst, vop->mcu_timing.mcu_cs_pst); - VOP_CTRL_SET(vop, mcu_cs_pend, vop->mcu_timing.mcu_cs_pend); - VOP_CTRL_SET(vop, mcu_rw_pst, vop->mcu_timing.mcu_rw_pst); - VOP_CTRL_SET(vop, mcu_rw_pend, vop->mcu_timing.mcu_rw_pend); -} - static void vop_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state) { @@ -3484,8 +3524,13 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc, if (vop->lut_active) vop_crtc_load_lut(crtc); - if (vop->mcu_timing.mcu_pix_total) - vop_mcu_mode(crtc); + if (vop->mcu_timing.mcu_pix_total) { + if (vop->version == VOP_VERSION(2, 0xd)) + vop_set_out_mode(vop, s->output_mode); + else + vop_set_out_mode(vop, ROCKCHIP_OUT_MODE_P888); + vop_mcu_mode_setup(crtc); + } dclk_inv = (s->bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE) ? 1 : 0; /* For improving signal quality, dclk need to be inverted by default on rv1106. */ diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h index d3a596bc2fad..abc4b08fb586 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h @@ -408,6 +408,7 @@ struct vop_ctrl { struct vop_reg mcu_rw_bypass_port; /* bt1120 */ + struct vop_reg bt1120_uv_swap; struct vop_reg bt1120_yc_swap; struct vop_reg bt1120_en; @@ -416,6 +417,13 @@ struct vop_ctrl { struct vop_reg reg_done_frm; struct vop_reg cfg_done; + + /* ebc vop */ + struct vop_reg enable; + struct vop_reg inf_out_en; + struct vop_reg mipi_1to4_en; + struct vop_reg hdmi_1to4_en; + struct vop_reg out_dresetn; }; struct vop_intr { @@ -1164,6 +1172,7 @@ struct vop_grf_ctrl { struct vop_reg grf_hdmi1_dsc_en; struct vop_reg grf_hdmi0_pin_pol; struct vop_reg grf_hdmi1_pin_pol; + struct vop_reg grf_vopl_sel; }; struct vop_data { diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c index 69377bb6f4e1..e7a4578ba5ea 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c @@ -112,6 +112,13 @@ static const uint32_t formats_win_lite[] = { DRM_FORMAT_BGR565, }; +static const uint32_t formats_win_ebc[] = { + DRM_FORMAT_XRGB8888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_RGB888, + DRM_FORMAT_RGB565, +}; + static const uint64_t format_modifiers[] = { DRM_FORMAT_MOD_LINEAR, DRM_FORMAT_MOD_INVALID, @@ -1984,6 +1991,128 @@ static const struct vop_data rv1106_vop = { .win_size = ARRAY_SIZE(rv1106_vop_win_data), }; +static const struct vop_ctrl rk3576_lit_ctrl_data = { + .cfg_done = VOP_REG(EBC_CONFIG_DONE, 0x1, 0), + + .enable = VOP_REG(EBC_VOP_SYS_CTRL, 0x1, 0), + .bcsh_r2y_en = VOP_REG(EBC_VOP_SYS_CTRL, 0x1, 1), + .bcsh_r2y_csc_mode = VOP_REG(EBC_VOP_SYS_CTRL, 0x1, 2), + .bt1120_yc_swap = VOP_REG(EBC_VOP_SYS_CTRL, 0x1, 6), + .bt1120_uv_swap = VOP_REG(EBC_VOP_SYS_CTRL, 0x1, 7), + .inf_out_en = VOP_REG(EBC_VOP_SYS_CTRL, 0x1, 8), + + .rgb_en = VOP_REG(EBC_VOP_DSP_CTRL0, 0x1, 0), + .bt1120_en = VOP_REG(EBC_VOP_DSP_CTRL0, 0x1, 1), + .bt656_en = VOP_REG(EBC_VOP_DSP_CTRL0, 0x1, 2), + .core_dclk_div = VOP_REG(EBC_VOP_DSP_CTRL0, 0x1, 3), + .dclk_pol = VOP_REG(EBC_VOP_DSP_CTRL0, 0x1, 4), + .rgb_pin_pol = VOP_REG(EBC_VOP_DSP_CTRL0, 0x7, 5), + .standby = VOP_REG(EBC_VOP_DSP_CTRL0, 0x1, 15), + .mipi_1to4_en = VOP_REG(EBC_VOP_DSP_CTRL0, 0x1, 24), + .mipi_pin_pol = VOP_REG(EBC_VOP_DSP_CTRL0, 0x3, 25), + .hdmi_1to4_en = VOP_REG(EBC_VOP_DSP_CTRL0, 0x1, 28), + .hdmi_pin_pol = VOP_REG(EBC_VOP_DSP_CTRL0, 0x3, 29), + .out_dresetn = VOP_REG(EBC_VOP_DSP_CTRL0, 0x1, 31), + + .dsp_interlace = VOP_REG(EBC_VOP_DSP_CTRL1, 0x1, 0), + .dsp_interlace_pol = VOP_REG(EBC_VOP_DSP_CTRL1, 0x1, 1), + .dither_up_en = VOP_REG(EBC_VOP_DSP_CTRL1, 0x1, 4), + .dither_down_en = VOP_REG(EBC_VOP_DSP_CTRL1, 0x1, 5), + .dither_down_mode = VOP_REG(EBC_VOP_DSP_CTRL1, 0x1, 6), + .dither_down_sel = VOP_REG(EBC_VOP_DSP_CTRL1, 0x1, 7), + .dsp_data_swap = VOP_REG(EBC_VOP_DSP_CTRL1, 0x1f, 9), + .dsp_bg_swap = VOP_REG(EBC_VOP_DSP_CTRL1, 0x1, 8), + .dsp_rb_swap = VOP_REG(EBC_VOP_DSP_CTRL1, 0x1, 9), + .dsp_rg_swap = VOP_REG(EBC_VOP_DSP_CTRL1, 0x1, 10), + .dsp_delta_swap = VOP_REG(EBC_VOP_DSP_CTRL1, 0x1, 11), + .dsp_dummy_swap = VOP_REG(EBC_VOP_DSP_CTRL1, 0x1, 12), + .dsp_black = VOP_REG(EBC_VOP_DSP_CTRL1, 0x1, 14), + .dsp_blank = VOP_REG(EBC_VOP_DSP_CTRL1, 0x1, 15), + .out_mode = VOP_REG(EBC_VOP_DSP_CTRL1, 0xf, 16), + + .mcu_pix_total = VOP_REG(EBC_VOP_MCU_CTRL, 0x3f, 0), + .mcu_cs_pst = VOP_REG(EBC_VOP_MCU_CTRL, 0xf, 6), + .mcu_cs_pend = VOP_REG(EBC_VOP_MCU_CTRL, 0x3f, 10), + .mcu_rw_pst = VOP_REG(EBC_VOP_MCU_CTRL, 0xf, 16), + .mcu_rw_pend = VOP_REG(EBC_VOP_MCU_CTRL, 0x3f, 20), + .mcu_hold_mode = VOP_REG(EBC_VOP_MCU_CTRL, 0x1, 27), + .mcu_frame_st = VOP_REG(EBC_VOP_MCU_CTRL, 0x1, 28), + .mcu_rs = VOP_REG(EBC_VOP_MCU_CTRL, 0x1, 29), + .mcu_bypass = VOP_REG(EBC_VOP_MCU_CTRL, 0x1, 30), + .mcu_type = VOP_REG(EBC_VOP_MCU_CTRL, 0x1, 31), + .mcu_rw_bypass_port = VOP_REG(EBC_MCU_RW_BYPASS_PORT, 0xffffffff, 0), + + .htotal_pw = VOP_REG(EBC_DSP_HTOTAL_HS_END, 0x0fff0fff, 0), + .hact_st_end = VOP_REG(EBC_DSP_HACT_ST_END, 0x0fff0fff, 0), + .vtotal_pw = VOP_REG(EBC_DSP_VTOTAL_VS_END, 0x0fff0fff, 0), + .vact_st_end = VOP_REG(EBC_DSP_VACT_ST_END, 0x0fff0fff, 0), + .vs_st_end_f1 = VOP_REG(EBC_DSP_VS_ST_END_F1, 0x0fff0fff, 0), + .vact_st_end_f1 = VOP_REG(EBC_DSP_VACT_ST_END_F1, 0x0fff0fff, 0), + + .dsp_background = VOP_REG(EBC_DSP_BG, 0xffffffff, 0), +}; + +static const int rk3576_vop_lit_intrs[] = { + FS_INTR, + DMA_FINISH_INTR, + LINE_FLAG_INTR, + LINE_FLAG1_INTR, + BUS_ERROR_INTR, + DSP_HOLD_VALID_INTR, +}; + +static const struct vop_intr rk3576_lit_intr = { + .intrs = rk3576_vop_lit_intrs, + .nintrs = ARRAY_SIZE(rk3576_vop_lit_intrs), + .line_flag_num[0] = VOP_REG(EBC_LINE_FLAG, 0xfff, 0), + .line_flag_num[1] = VOP_REG(EBC_LINE_FLAG, 0xfff, 16), + .status = VOP_REG_MASK(EBC_VOP_INT_STATUS, 0xffff, 0), + .enable = VOP_REG_MASK(EBC_VOP_INT_EN, 0xffff, 0), + .clear = VOP_REG_MASK(EBC_VOP_INT_CLR, 0xffff, 0), +}; + +static const struct vop_win_phy rk3576_lit_win2_data = { + .data_formats = formats_win_ebc, + .nformats = ARRAY_SIZE(formats_win_ebc), + + .dsp_info = VOP_REG(EBC_VOP_WIN_DSP_INFO, 0xffffffff, 0), + .dsp_st = VOP_REG(EBC_VOP_WIN_DSP_ST, 0xffffffff, 0), + + .yrgb_mst = VOP_REG(EBC_WIN_MST2, 0xffffffff, 0), + + .enable = VOP_REG(EBC_WIN2_CTRL, 0x1, 0), + + .interlace_read = VOP_REG(EBC_VOP_SYS_CTRL, 0x1, 3), + .format = VOP_REG(EBC_VOP_SYS_CTRL, 0x3, 4), + + .yrgb_vir = VOP_REG(EBC_VOP_WIN_VIR, 0x1fff, 0), +}; + +static const struct vop_win_data rk3576_lit_win_data[] = { + { .phy = NULL }, + { .phy = NULL }, + { .base = 0x00, .phy = &rk3576_lit_win2_data, + .type = DRM_PLANE_TYPE_PRIMARY }, +}; + +static const struct vop_grf_ctrl rk3576_lit_grf_ctrl = { + .grf_dclk_inv = VOP_REG(RK3576_IOC_GRF_MISC_CON8, 0x1, 9), + .grf_vopl_sel = VOP_REG(RK3576_IOC_GRF_MISC_CON8, 0x1, 11), +}; + +static const struct vop_data rk3576_vop_lit = { + .soc_id = 0x3576, + .vop_id = 0, + .version = VOP_VERSION(2, 0xd), + .max_input = {1920, 1920}, + .max_output = {1920, 1920}, + .ctrl = &rk3576_lit_ctrl_data, + .intr = &rk3576_lit_intr, + .grf_ctrl = &rk3576_lit_grf_ctrl, + .win = rk3576_lit_win_data, + .win_size = ARRAY_SIZE(rk3576_lit_win_data), +}; + static const struct of_device_id vop_driver_dt_match[] = { #if IS_ENABLED(CONFIG_CPU_RK3036) { .compatible = "rockchip,rk3036-vop", @@ -2040,6 +2169,10 @@ static const struct of_device_id vop_driver_dt_match[] = { #if IS_ENABLED(CONFIG_CPU_RK3328) { .compatible = "rockchip,rk3328-vop", .data = &rk3328_vop }, +#endif +#if IS_ENABLED(CONFIG_CPU_RK3576) + { .compatible = "rockchip,rk3576-vop-lit", + .data = &rk3576_vop_lit }, #endif {}, }; diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h index a33f6fcecb78..a917bb9608d0 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h @@ -1790,4 +1790,40 @@ #define RK3528_ACM_YHS_DEL_HS_SEG220 0x06d4 #define RK3528_ACM_YHS_DEL_HGAIN_SEG0 0x06d8 #define RK3528_ACM_YHS_DEL_HGAIN_SEG64 0x07d8 + +/* RK3576 EBC VOP register definition */ +#define EBC_CONFIG_DONE 0x0050 +#define EBC_WIN_MST2 0x0058 +#define EBC_WIN2_CTRL 0x006c + +#define EBC_VOP_SYS_CTRL 0x0100 +#define EBC_VOP_DSP_CTRL0 0x0104 +#define EBC_VOP_DSP_CTRL1 0x0108 +#define EBC_VOP_MCU_CTRL 0x010c +#define EBC_DSP_HTOTAL_HS_END 0x0110 +#define EBC_DSP_HACT_ST_END 0x0114 +#define EBC_DSP_VTOTAL_VS_END 0x0118 +#define EBC_DSP_VACT_ST_END 0x011c +#define EBC_DSP_VS_ST_END_F1 0x0120 +#define EBC_DSP_VACT_ST_END_F1 0x0124 +#define EBC_DSP_BG 0x0128 +#define EBC_BLANKING_VALUE 0x012c +#define EBC_FRC_LOWER01_0 0x0130 +#define EBC_FRC_LOWER01_1 0x0134 +#define EBC_FRC_LOWER10_0 0x0138 +#define EBC_FRC_LOWER10_1 0x013c +#define EBC_FRC_LOWER11_0 0x0140 +#define EBC_FRC_LOWER11_1 0x0144 +#define EBC_LINE_FLAG 0x0148 +#define EBC_VOP_SCAN_LINE_NUM 0x014c +#define EBC_VOP_WIN_VIR 0x0150 +#define EBC_VOP_INT_EN 0x0154 +#define EBC_VOP_WIN_DSP_INFO 0x0158 +#define EBC_VOP_WIN_DSP_ST 0x015c +#define EBC_MCU_RW_BYPASS_PORT 0x0160 +#define EBC_VOP_INT_CLR 0x0164 +#define EBC_VOP_INT_STATUS 0x0168 + +#define RK3576_IOC_GRF_MISC_CON8 0x6420 + #endif /* _ROCKCHIP_VOP_REG_H */