diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h index cb5a67eac61b..bedf2a99a793 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h @@ -10,16 +10,24 @@ #include #include +#include "rockchip_drm_drv.h" + /* * major: IP major version, used for IP structure * minor: big feature change under same structure + * build: RTL current SVN number */ #define VOP_VERSION(major, minor) ((major) << 8 | (minor)) #define VOP_MAJOR(version) ((version) >> 8) #define VOP_MINOR(version) ((version) & 0xff) -#define VOP_VERSION_RK3568 VOP_VERSION(0x40, 0x15) -#define VOP_VERSION_RK3588 VOP_VERSION(0x40, 0x17) +#define VOP2_VERSION(major, minor, build) ((major) << 24 | (minor) << 16 | (build)) +#define VOP2_MAJOR(version) (((version) >> 24) & 0xff) +#define VOP2_MINOR(version) (((version) >> 16) & 0xff) +#define VOP2_BUILD(version) ((version) & 0xffff) + +#define VOP_VERSION_RK3568 VOP2_VERSION(0x40, 0x15, 0x8023) +#define VOP_VERSION_RK3588 VOP2_VERSION(0x40, 0x17, 0x6786) #define ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE BIT(0) #define ROCKCHIP_OUTPUT_DUAL_CHANNEL_ODD_EVEN_MODE BIT(1) @@ -60,6 +68,7 @@ */ #define WIN_FEATURE_MIRROR BIT(6) #define WIN_FEATURE_MULTI_AREA BIT(7) +#define WIN_FEATURE_Y2R_13BIT_DEPTH BIT(8) #define VOP2_SOC_VARIANT 4 @@ -109,6 +118,13 @@ enum vop2_win_dly_mode { VOP2_DLY_MODE_MAX, }; +enum vop3_esmart_lb_mode { + VOP3_ESMART_ONE_8K_MODE, + VOP3_ESMART_TWO_4K_MODE, + VOP3_ESMART_ONE_4K_AND_TWO_2K_MODE, + VOP3_ESMART_FOUR_2K_MODE, +}; + /* * vop2 dsc id */ @@ -147,11 +163,18 @@ enum vop2_win_dly_mode { #define DSP_RG_SWAP 0x4 #define DSP_DELTA_SWAP 0x8 +#define V4L2_COLORSPACE_BT709F 0xfe +#define V4L2_COLORSPACE_BT2020F 0xff + enum vop_csc_format { CSC_BT601L, CSC_BT709L, CSC_BT601F, CSC_BT2020, + CSC_BT709L_13BIT, + CSC_BT709F_13BIT, + CSC_BT2020L_13BIT, + CSC_BT2020F_13BIT, }; enum vop_csc_mode { @@ -159,6 +182,11 @@ enum vop_csc_mode { CSC_YUV, }; +enum vop_csc_bit_depth { + CSC_10BIT_DEPTH, + CSC_13BIT_DEPTH, +}; + enum vop_data_format { VOP_FMT_ARGB8888 = 0, VOP_FMT_RGB888, @@ -585,6 +613,11 @@ struct vop2_scl_regs { struct vop_reg vsd_yrgb_gt2; struct vop_reg vsd_yrgb_gt4; struct vop_reg bic_coe_sel; + struct vop_reg xavg_en; /* supported from vop3 */ + struct vop_reg xgt_en; + struct vop_reg xgt_mode; + struct vop_reg vsd_avg2; + struct vop_reg vsd_avg4; }; struct vop2_win_regs { @@ -595,7 +628,9 @@ struct vop2_win_regs { struct vop_reg gate; struct vop_reg enable; struct vop_reg format; + struct vop_reg tile_mode; struct vop_reg csc_mode; + struct vop_reg csc_13bit_en; struct vop_reg xmirror; struct vop_reg ymirror; struct vop_reg rb_swap; @@ -623,6 +658,7 @@ struct vop2_win_regs { struct vop_reg axi_id; struct vop_reg axi_yrgb_id; struct vop_reg axi_uv_id; + struct vop_reg scale_engine_num; }; struct vop2_video_port_regs { @@ -697,6 +733,7 @@ struct vop2_video_port_regs { struct vop_reg hdr_src_alpha_ctrl; struct vop_reg hdr_dst_alpha_ctrl; struct vop_reg bg_mix_ctrl; + struct vop_reg layer_sel; /* BCSH */ struct vop_reg bcsh_brightness; @@ -728,6 +765,20 @@ struct vop2_video_port_regs { struct vop_reg edpi_wms_fs; struct vop_reg gamma_update_en; struct vop_reg lut_dma_rid; + + /* MCU output */ + struct vop_reg mcu_pix_total; + struct vop_reg mcu_cs_pst; + struct vop_reg mcu_cs_pend; + struct vop_reg mcu_rw_pst; + struct vop_reg mcu_rw_pend; + struct vop_reg mcu_clk_sel; + struct vop_reg mcu_hold_mode; + struct vop_reg mcu_frame_st; + struct vop_reg mcu_rs; + struct vop_reg mcu_bypass; + struct vop_reg mcu_type; + struct vop_reg mcu_rw_bypass_port; }; struct vop2_power_domain_regs { @@ -830,6 +881,8 @@ struct vop2_win_data { uint8_t axi_id; uint8_t axi_yrgb_id; uint8_t axi_uv_id; + uint8_t scale_engine_num; + uint8_t possible_crtcs; uint32_t base; enum drm_plane_type type; @@ -850,10 +903,12 @@ struct vop2_win_data { const u8 hsd_filter_mode; const u8 vsu_filter_mode; const u8 vsd_filter_mode; + const u8 hsd_pre_filter_mode; + const u8 vsd_pre_filter_mode; /** * @layer_sel_id: defined by register OVERLAY_LAYER_SEL of VOP2 */ - int layer_sel_id; + const uint8_t layer_sel_id[ROCKCHIP_MAX_CRTC]; uint64_t feature; unsigned int max_upscale_factor; @@ -887,6 +942,18 @@ struct vop2_wb_data { uint32_t fifo_depth; }; +struct vop3_ovl_mix_regs { + struct vop_reg src_color_ctrl; + struct vop_reg dst_color_ctrl; + struct vop_reg src_alpha_ctrl; + struct vop_reg dst_alpha_ctrl; +}; + +struct vop3_ovl_regs { + const struct vop3_ovl_mix_regs *layer_mix_regs; + const struct vop3_ovl_mix_regs *hdr_mix_regs; +}; + struct vop2_video_port_data { char id; uint8_t splice_vp_id; @@ -901,6 +968,7 @@ struct vop2_video_port_data { const struct vop_intr *intr; const struct vop_hdr_table *hdr_table; const struct vop2_video_port_regs *regs; + const struct vop3_ovl_regs *ovl_regs; }; struct vop2_layer_regs { @@ -972,6 +1040,7 @@ struct vop2_ctrl { struct vop_reg cfg_done_en; struct vop_reg wb_cfg_done; struct vop_reg auto_gating_en; + struct vop_reg aclk_pre_auto_gating_en; struct vop_reg ovl_cfg_done_port; struct vop_reg ovl_port_mux_cfg_done_imd; struct vop_reg ovl_port_mux_cfg; @@ -996,6 +1065,8 @@ struct vop2_ctrl { struct vop_reg lvds1_en; struct vop_reg bt656_en; struct vop_reg bt1120_en; + struct vop_reg bt656_dclk_pol; + struct vop_reg bt1120_dclk_pol; struct vop_reg dclk_pol; struct vop_reg pin_pol; struct vop_reg rgb_dclk_pol; @@ -1065,10 +1136,16 @@ struct vop2_ctrl { struct vop_reg pd_off_imd; struct vop_reg otp_en; + struct vop_reg esmart_lb_mode; struct vop_reg reg_done_frm; struct vop_reg cfg_done; }; +struct vop_dump_regs { + uint32_t offset; + const char *name; +}; + /** * VOP2 data structe * @@ -1089,6 +1166,7 @@ struct vop2_data { uint8_t nr_conns; uint8_t nr_pds; uint8_t nr_mem_pgs; + uint8_t esmart_lb_mode; bool delayed_pd; const struct vop_intr *axi_intr; const struct vop2_ctrl *ctrl; @@ -1108,6 +1186,8 @@ struct vop2_data { const struct vop_grf_ctrl *grf; const struct vop_grf_ctrl *vo0_grf; const struct vop_grf_ctrl *vo1_grf; + const struct vop_dump_regs *dump_regs; + uint32_t dump_regs_size; struct vop_rect max_input; struct vop_rect max_output; @@ -1279,6 +1359,12 @@ enum vop2_scale_down_mode { VOP2_SCALE_DOWN_AVG, }; +enum vop3_pre_scale_down_mode { + VOP3_PRE_SCALE_UNSPPORT, + VOP3_PRE_SCALE_DOWN_GT, + VOP3_PRE_SCALE_DOWN_AVG, +}; + enum dither_down_mode { RGB888_TO_RGB565 = 0x0, RGB888_TO_RGB666 = 0x1 diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index fcfce8bf55f9..7ea5a356e16e 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -191,6 +192,40 @@ enum vop2_afbc_format { VOP2_AFBC_FMT_INVALID = -1, }; +enum vop2_tiled_format { + VOP2_TILED_8X8_FMT_YUV420SP = 0xc, + VOP2_TILED_8X8_FMT_YUV422SP, + VOP2_TILED_8X8_FMT_YUV444SP, + VOP2_TILED_8X8_FMT_YUV400SP, + VOP2_TILED_8X8_FMT_YUV420SP_10 = 0x1c, + VOP2_TILED_8X8_FMT_YUV422SP_10, + VOP2_TILED_8X8_FMT_YUV444SP_10, + VOP2_TILED_8X8_FMT_YUV400SP_10, + VOP2_TILED_FMT_INVALID = -1, +}; + +enum vop3_tiled_format { + VOP3_TILED_4X4_FMT_YUV420SP = 0xc, + VOP3_TILED_4X4_FMT_YUV422SP, + VOP3_TILED_4X4_FMT_YUV444SP, + VOP3_TILED_4X4_FMT_YUV400SP, + VOP3_TILED_4X4_FMT_YUV420SP_10 = 0x1c, + VOP3_TILED_4X4_FMT_YUV422SP_10, + VOP3_TILED_4X4_FMT_YUV444SP_10, + VOP3_TILED_4X4_FMT_YUV400SP_10, + + VOP3_TILED_8X8_FMT_YUV420SP = 0x2c, + VOP3_TILED_8X8_FMT_YUV422SP, + VOP3_TILED_8X8_FMT_YUV444SP, + VOP3_TILED_8X8_FMT_YUV400SP, + VOP3_TILED_8X8_FMT_YUV420SP_10 = 0x3c, + VOP3_TILED_8X8_FMT_YUV422SP_10, + VOP3_TILED_8X8_FMT_YUV444SP_10, + VOP3_TILED_8X8_FMT_YUV400SP_10, + + VOP3_TILED_FMT_INVALID = -1, +}; + enum vop2_hdr_lut_mode { VOP2_HDR_LUT_MODE_AXI, VOP2_HDR_LUT_MODE_AHB, @@ -270,6 +305,22 @@ union vop2_alpha_ctrl { } bits; }; +union vop2_bg_alpha_ctrl { + uint32_t val; + struct { + /* [0:1] */ + uint32_t alpha_en:1; + uint32_t alpha_mode:1; + /* [2:3] */ + uint32_t alpha_pre_mul:1; + uint32_t alpha_sat_mode:1; + /* [4:7] */ + uint32_t reserved:4; + /* [8:15] */ + uint32_t glb_alpha:8; + } bits; +}; + struct vop2_alpha { union vop2_alpha_ctrl src_color_ctrl; union vop2_alpha_ctrl dst_color_ctrl; @@ -305,6 +356,7 @@ struct vop2_plane_state { uint8_t rotate_90_en; uint8_t rotate_270_en; uint8_t afbc_half_block_en; + uint8_t tiled_en; int eotf; int color_space; int global_alpha; @@ -380,7 +432,7 @@ struct vop2_win { * @layer_id: id of the layer which the window attached to */ uint8_t layer_id; - int layer_sel_id; + const uint8_t *layer_sel_id; /** * @vp_mask: Bitmask of video_port0/1/2 this win attached to, * one win can only attach to one vp at the one time. @@ -396,7 +448,8 @@ struct vop2_win { uint8_t axi_id; uint8_t axi_yrgb_id; uint8_t axi_uv_id; - + uint8_t scale_engine_num; + uint8_t possible_crtcs; enum drm_plane_type type; unsigned int max_upscale_factor; unsigned int max_downscale_factor; @@ -409,6 +462,8 @@ struct vop2_win { uint8_t hsd_filter_mode; uint8_t vsu_filter_mode; uint8_t vsd_filter_mode; + uint8_t hsd_pre_filter_mode; + uint8_t vsd_pre_filter_mode; const struct vop2_win_regs *regs; const uint64_t *format_modifiers; @@ -750,6 +805,7 @@ struct vop2 { uint16_t port_mux_cfg; uint32_t *regsbak; + struct resource *res; void __iomem *regs; struct regmap *grf; struct regmap *sys_grf; @@ -761,6 +817,7 @@ struct vop2 { uint32_t len; void __iomem *lut_regs; + void __iomem *acm_regs; /* one time only one process allowed to config the register */ spinlock_t reg_lock; /* lock vop2 irq reg */ @@ -949,6 +1006,14 @@ static inline bool vop2_plane_active(struct drm_plane_state *pstate) return true; } +static inline bool is_vop3(struct vop2 *vop2) +{ + if (vop2->version == VOP_VERSION_RK3568 || vop2->version == VOP_VERSION_RK3588) + return false; + else + return true; +} + static bool vop2_soc_is_rk3566(void) { return soc_is_rk3566(); @@ -1478,7 +1543,7 @@ static inline void vop2_cfg_done(struct drm_crtc *crtc) if (vop2->version == VOP_VERSION_RK3568) return rk3568_vop2_cfg_done(crtc); - else if (vop2->version == VOP_VERSION_RK3588) + else return rk3588_vop2_cfg_done(crtc); } @@ -1822,6 +1887,64 @@ static enum vop2_afbc_format vop2_convert_afbc_format(uint32_t format) return VOP2_AFBC_FMT_INVALID; } +static enum vop2_tiled_format vop2_convert_tiled_format(uint32_t format) +{ + switch (format) { + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV21: + return VOP2_TILED_8X8_FMT_YUV420SP; + case DRM_FORMAT_NV16: + case DRM_FORMAT_NV61: + return VOP2_TILED_8X8_FMT_YUV422SP; + case DRM_FORMAT_NV24: + case DRM_FORMAT_NV42: + return VOP2_TILED_8X8_FMT_YUV444SP; + case DRM_FORMAT_NV15: + return VOP2_TILED_8X8_FMT_YUV420SP_10; + case DRM_FORMAT_NV20: + return VOP2_TILED_8X8_FMT_YUV422SP_10; + case DRM_FORMAT_NV30: + return VOP2_TILED_8X8_FMT_YUV444SP_10; + default: + DRM_WARN_ONCE("unsupported tiled format[%08x]\n", format); + return VOP2_TILED_FMT_INVALID; + } + + return VOP2_TILED_FMT_INVALID; +} + +static enum vop3_tiled_format vop3_convert_tiled_format(uint32_t format, uint32_t tile_mode) +{ + switch (format) { + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV21: + return tile_mode == ROCKCHIP_TILED_BLOCK_SIZE_8x8 ? + VOP3_TILED_8X8_FMT_YUV420SP : VOP3_TILED_4X4_FMT_YUV420SP; + case DRM_FORMAT_NV16: + case DRM_FORMAT_NV61: + return tile_mode == ROCKCHIP_TILED_BLOCK_SIZE_8x8 ? + VOP3_TILED_8X8_FMT_YUV422SP : VOP3_TILED_4X4_FMT_YUV422SP; + case DRM_FORMAT_NV24: + case DRM_FORMAT_NV42: + return tile_mode == ROCKCHIP_TILED_BLOCK_SIZE_8x8 ? + VOP3_TILED_8X8_FMT_YUV444SP : VOP3_TILED_4X4_FMT_YUV444SP; + case DRM_FORMAT_NV15: + return tile_mode == ROCKCHIP_TILED_BLOCK_SIZE_8x8 ? + VOP3_TILED_8X8_FMT_YUV420SP_10 : VOP3_TILED_4X4_FMT_YUV420SP_10; + case DRM_FORMAT_NV20: + return tile_mode == ROCKCHIP_TILED_BLOCK_SIZE_8x8 ? + VOP3_TILED_8X8_FMT_YUV422SP_10 : VOP3_TILED_4X4_FMT_YUV422SP_10; + case DRM_FORMAT_NV30: + return tile_mode == ROCKCHIP_TILED_BLOCK_SIZE_8x8 ? + VOP3_TILED_8X8_FMT_YUV444SP_10 : VOP3_TILED_4X4_FMT_YUV444SP_10; + default: + DRM_WARN_ONCE("unsupported tiled format[%08x]\n", format); + return VOP3_TILED_FMT_INVALID; + } + + return VOP3_TILED_FMT_INVALID; +} + static enum vop2_wb_format vop2_convert_wb_format(uint32_t format) { switch (format) { @@ -1993,12 +2116,31 @@ static inline bool rockchip_afbc(struct drm_plane *plane, u64 modifier) if (modifier == DRM_FORMAT_MOD_LINEAR) return false; + if (!drm_is_afbc(modifier)) + return false; + for (i = 0 ; i < plane->modifier_count; i++) if (plane->modifiers[i] == modifier) break; return (i < plane->modifier_count) ? true : false; +} +static inline bool rockchip_tiled(struct drm_plane *plane, u64 modifier) +{ + int i; + + if (modifier == DRM_FORMAT_MOD_LINEAR) + return false; + + if (!IS_ROCKCHIP_TILED_MOD(modifier)) + return false; + + for (i = 0 ; i < plane->modifier_count; i++) + if (plane->modifiers[i] == modifier) + break; + + return (i < plane->modifier_count) ? true : false; } static bool rockchip_vop2_mod_supported(struct drm_plane *plane, u32 format, u64 modifier) @@ -2009,13 +2151,15 @@ static bool rockchip_vop2_mod_supported(struct drm_plane *plane, u32 format, u64 if (modifier == DRM_FORMAT_MOD_LINEAR) return true; - if (!rockchip_afbc(plane, modifier)) { + if (!rockchip_afbc(plane, modifier) && !rockchip_tiled(plane, modifier)) { DRM_ERROR("Unsupported format modifier 0x%llx\n", modifier); return false; } - return vop2_convert_afbc_format(format) >= 0; + return vop2_convert_afbc_format(format) >= 0 || + vop2_convert_tiled_format(format) >= 0 || + vop3_convert_tiled_format(format, 0) >= 0; } static inline bool vop2_multi_area_sub_window(struct vop2_win *win) @@ -2169,6 +2313,25 @@ static uint32_t vop2_afbc_transform_offset(struct vop2_plane_state *vpstate, int return (transform_xoffset & 0xf) | ((transform_yoffset & 0xf) << 16); } +static uint32_t vop2_tile_transform_offset(struct vop2_plane_state *vpstate, uint8_t tiled_en) +{ + struct drm_rect *src = &vpstate->src; + uint32_t act_xoffset = src->x1 >> 16; + uint32_t act_yoffset = src->y1 >> 16; + uint8_t transform_xoffset = 0; + uint8_t transform_yoffset = 0; + uint32_t tile_size = 1; + + if (tiled_en == 0) + return 0; + + tile_size = tiled_en == ROCKCHIP_TILED_BLOCK_SIZE_8x8 ? 8 : 4; + transform_xoffset = act_xoffset & (tile_size - 1); + transform_yoffset = act_yoffset & (tile_size - 1); + + return (transform_xoffset & 0xf) | ((transform_yoffset & 0xf) << 16); +} + /* * A Cluster window has 2048 x 16 line buffer, which can * works at 2048 x 16(Full) or 4096 x 8 (Half) mode. @@ -2195,8 +2358,8 @@ static int vop2_get_cluster_lb_mode(struct vop2_win *win, struct vop2_plane_stat * bic_su_factor: * = (src - 1) / (dst - 1) << 16; * - * gt2 enable: dst get one line from two line of the src - * gt4 enable: dst get one line from four line of the src. + * ygt2 enable: dst get one line from two line of the src + * ygt4 enable: dst get one line from four line of the src. * */ #define VOP2_BILI_SCL_DN(src, dst) (((src - 1) << 12) / (dst - 1)) @@ -2206,6 +2369,8 @@ static int vop2_get_cluster_lb_mode(struct vop2_win *win, struct vop2_plane_stat (fac * (dst - 1) >> 12 < (src - 1)) #define VOP2_COMMON_SCL_FAC_CHECK(src, dst, fac) \ (fac * (dst - 1) >> 16 < (src - 1)) +#define VOP3_COMMON_HOR_SCL_FAC_CHECK(src, dst, fac) \ + (fac * (dst - 1) >> 16 <= (src - 1)) static uint16_t vop2_scale_factor(enum scale_mode mode, int32_t filter_mode, @@ -2246,12 +2411,60 @@ static uint16_t vop2_scale_factor(enum scale_mode mode, return fac; } -static void vop2_setup_scale(struct vop2 *vop2, const struct vop2_win *win, +static bool vop3_scale_up_fac_check(uint32_t src, uint32_t dst, uint32_t fac, bool is_hor) +{ + if (is_hor) + return VOP3_COMMON_HOR_SCL_FAC_CHECK(src, dst, fac); + return VOP2_COMMON_SCL_FAC_CHECK(src, dst, fac); +} + +static uint16_t vop3_scale_factor(enum scale_mode mode, + uint32_t src, uint32_t dst, bool is_hor) +{ + uint32_t fac = 0; + int i = 0; + + if (mode == SCALE_NONE) + return 0; + + /* + * A workaround to avoid zero div. + */ + if ((dst == 1) || (src == 1)) { + dst = dst + 1; + src = src + 1; + } + + if (mode == SCALE_DOWN) { + fac = VOP2_BILI_SCL_DN(src, dst); + for (i = 0; i < 100; i++) { + if (VOP2_BILI_SCL_FAC_CHECK(src, dst, fac)) + break; + fac -= 1; + DRM_DEBUG("down fac cali: src:%d, dst:%d, fac:0x%x\n", src, dst, fac); + } + } else { + fac = VOP2_COMMON_SCL(src, dst); + for (i = 0; i < 100; i++) { + if (vop3_scale_up_fac_check(src, dst, fac, is_hor)) + break; + fac -= 1; + DRM_DEBUG("up fac cali: src:%d, dst:%d, fac:0x%x\n", src, dst, fac); + } + } + + return fac; +} + +static void vop2_setup_scale(struct vop2 *vop2, struct vop2_win *win, uint32_t src_w, uint32_t src_h, uint32_t dst_w, - uint32_t dst_h, uint32_t pixel_format) + uint32_t dst_h, struct drm_plane_state *pstate) { const struct vop2_data *vop2_data = vop2->data; const struct vop2_win_data *win_data = &vop2_data->win[win->win_id]; + struct vop2_plane_state *vpstate = to_vop2_plane_state(pstate); + struct drm_framebuffer *fb = pstate->fb; + uint32_t pixel_format = fb->format->format; const struct drm_format_info *info = drm_format_info(pixel_format); uint8_t hsub = info->hsub; uint8_t vsub = info->vsub; @@ -2260,19 +2473,27 @@ static void vop2_setup_scale(struct vop2 *vop2, const struct vop2_win *win, uint16_t yrgb_hor_scl_mode, yrgb_ver_scl_mode; uint16_t cbcr_hor_scl_mode, cbcr_ver_scl_mode; uint16_t hscl_filter_mode, vscl_filter_mode; - uint8_t gt2 = 0; - uint8_t gt4 = 0; + uint8_t xgt2 = 0, xgt4 = 0; + uint8_t ygt2 = 0, ygt4 = 0; uint32_t val; - if (src_h >= (4 * dst_h)) - gt4 = 1; - else if (src_h >= (2 * dst_h)) - gt2 = 1; + if (is_vop3(vop2)) { + if (src_w >= (4 * dst_w)) { + xgt4 = 1; + src_w >>= 2; + } else if (src_w >= (2 * dst_w)) { + xgt2 = 1; + src_w >>= 1; + } + } - if (gt4) + if (src_h >= (4 * dst_h)) { + ygt4 = 1; src_h >>= 2; - else if (gt2) + } else if (src_h >= (2 * dst_h)) { + ygt2 = 1; src_h >>= 1; + } yrgb_hor_scl_mode = scl_get_scl_mode(src_w, dst_w); yrgb_ver_scl_mode = scl_get_scl_mode(src_h, dst_h); @@ -2291,22 +2512,50 @@ static void vop2_setup_scale(struct vop2 *vop2, const struct vop2_win *win, * RK3568 VOP Esmart/Smart dsp_w should be even pixel * at scale down mode */ - if (!(win->feature & WIN_FEATURE_AFBDC)) { + if (!(win->feature & WIN_FEATURE_AFBDC) && !is_vop3(vop2)) { if ((yrgb_hor_scl_mode == SCALE_DOWN) && (dst_w & 0x1)) { dev_dbg(vop2->dev, "%s dst_w[%d] should align as 2 pixel\n", win->name, dst_w); dst_w += 1; } } - val = vop2_scale_factor(yrgb_hor_scl_mode, hscl_filter_mode, - src_w, dst_w); - VOP_SCL_SET(vop2, win, scale_yrgb_x, val); - val = vop2_scale_factor(yrgb_ver_scl_mode, vscl_filter_mode, - src_h, dst_h); - VOP_SCL_SET(vop2, win, scale_yrgb_y, val); + if (is_vop3(vop2)) { + bool xgt_en = false, xavg_en = false; - VOP_SCL_SET(vop2, win, vsd_yrgb_gt4, gt4); - VOP_SCL_SET(vop2, win, vsd_yrgb_gt2, gt2); + val = vop3_scale_factor(yrgb_hor_scl_mode, src_w, dst_w, true); + VOP_SCL_SET(vop2, win, scale_yrgb_x, val); + val = vop3_scale_factor(yrgb_ver_scl_mode, src_h, dst_h, false); + VOP_SCL_SET(vop2, win, scale_yrgb_y, val); + + if (win_data->hsd_pre_filter_mode == VOP3_PRE_SCALE_DOWN_AVG) + xavg_en = xgt2 || xgt4; + else + xgt_en = xgt2 || xgt4; + + VOP_SCL_SET(vop2, win, xgt_en, xgt_en); + VOP_SCL_SET(vop2, win, xavg_en, xavg_en); + VOP_SCL_SET(vop2, win, xgt_mode, xgt2 ? 0 : 1); + } else { + val = vop2_scale_factor(yrgb_hor_scl_mode, hscl_filter_mode, src_w, dst_w); + VOP_SCL_SET(vop2, win, scale_yrgb_x, val); + val = vop2_scale_factor(yrgb_ver_scl_mode, vscl_filter_mode, src_h, dst_h); + VOP_SCL_SET(vop2, win, scale_yrgb_y, val); + } + + /* vop2 and linear mode only can support gt */ + if (!is_vop3(vop2) || + (!vpstate->afbc_en && !vpstate->tiled_en) || + win_data->vsd_pre_filter_mode == VOP3_PRE_SCALE_DOWN_GT) { + VOP_SCL_SET(vop2, win, vsd_yrgb_gt4, ygt4); + VOP_SCL_SET(vop2, win, vsd_yrgb_gt2, ygt2); + VOP_SCL_SET(vop2, win, vsd_avg4, 0); + VOP_SCL_SET(vop2, win, vsd_avg2, 0); + } else { + VOP_SCL_SET(vop2, win, vsd_yrgb_gt4, 0); + VOP_SCL_SET(vop2, win, vsd_yrgb_gt2, 0); + VOP_SCL_SET(vop2, win, vsd_avg4, ygt4); + VOP_SCL_SET(vop2, win, vsd_avg2, ygt2); + } VOP_SCL_SET(vop2, win, yrgb_hor_scl_mode, yrgb_hor_scl_mode); VOP_SCL_SET(vop2, win, yrgb_ver_scl_mode, yrgb_ver_scl_mode); @@ -2315,38 +2564,44 @@ static void vop2_setup_scale(struct vop2 *vop2, const struct vop2_win *win, VOP_SCL_SET(vop2, win, yrgb_vscl_filter_mode, vscl_filter_mode); if (info->is_yuv) { - gt4 = gt2 = 0; + ygt4 = ygt2 = 0; - if (cbcr_src_h >= (4 * dst_h)) - gt4 = 1; - else if (cbcr_src_h >= (2 * dst_h)) - gt2 = 1; + if (!is_vop3(vop2) || + (!vpstate->afbc_en && !vpstate->tiled_en) || + win_data->vsd_pre_filter_mode == VOP3_PRE_SCALE_DOWN_GT) { + if (cbcr_src_h >= (4 * dst_h)) + ygt4 = 1; + else if (cbcr_src_h >= (2 * dst_h)) + ygt2 = 1; - if (gt4) - cbcr_src_h >>= 2; - else if (gt2) - cbcr_src_h >>= 1; + if (ygt4) + cbcr_src_h >>= 2; + else if (ygt2) + cbcr_src_h >>= 1; + } + VOP_SCL_SET(vop2, win, vsd_cbcr_gt4, ygt4); + VOP_SCL_SET(vop2, win, vsd_cbcr_gt2, ygt2); - cbcr_hor_scl_mode = scl_get_scl_mode(cbcr_src_w, dst_w); - cbcr_ver_scl_mode = scl_get_scl_mode(cbcr_src_h, dst_h); + if (!is_vop3(vop2)) { + cbcr_hor_scl_mode = scl_get_scl_mode(cbcr_src_w, dst_w); + cbcr_ver_scl_mode = scl_get_scl_mode(cbcr_src_h, dst_h); - val = vop2_scale_factor(cbcr_hor_scl_mode, hscl_filter_mode, - cbcr_src_w, dst_w); - VOP_SCL_SET(vop2, win, scale_cbcr_x, val); - val = vop2_scale_factor(cbcr_ver_scl_mode, vscl_filter_mode, - cbcr_src_h, dst_h); - VOP_SCL_SET(vop2, win, scale_cbcr_y, val); + val = vop2_scale_factor(cbcr_hor_scl_mode, hscl_filter_mode, + cbcr_src_w, dst_w); + VOP_SCL_SET(vop2, win, scale_cbcr_x, val); + val = vop2_scale_factor(cbcr_ver_scl_mode, vscl_filter_mode, + cbcr_src_h, dst_h); + VOP_SCL_SET(vop2, win, scale_cbcr_y, val); - VOP_SCL_SET(vop2, win, vsd_cbcr_gt4, gt4); - VOP_SCL_SET(vop2, win, vsd_cbcr_gt2, gt2); - VOP_SCL_SET(vop2, win, cbcr_hor_scl_mode, cbcr_hor_scl_mode); - VOP_SCL_SET(vop2, win, cbcr_ver_scl_mode, cbcr_ver_scl_mode); - VOP_SCL_SET(vop2, win, cbcr_hscl_filter_mode, hscl_filter_mode); - VOP_SCL_SET(vop2, win, cbcr_vscl_filter_mode, vscl_filter_mode); + VOP_SCL_SET(vop2, win, cbcr_hor_scl_mode, cbcr_hor_scl_mode); + VOP_SCL_SET(vop2, win, cbcr_ver_scl_mode, cbcr_ver_scl_mode); + VOP_SCL_SET(vop2, win, cbcr_hscl_filter_mode, hscl_filter_mode); + VOP_SCL_SET(vop2, win, cbcr_vscl_filter_mode, vscl_filter_mode); + } } } -static int vop2_convert_csc_mode(int csc_mode) +static int vop2_convert_csc_mode(int csc_mode, int bit_depth) { switch (csc_mode) { case V4L2_COLORSPACE_SMPTE170M: @@ -2356,11 +2611,31 @@ static int vop2_convert_csc_mode(int csc_mode) case V4L2_COLORSPACE_REC709: case V4L2_COLORSPACE_SMPTE240M: case V4L2_COLORSPACE_DEFAULT: - return CSC_BT709L; + if (bit_depth == CSC_13BIT_DEPTH) + return CSC_BT709L_13BIT; + else + return CSC_BT709L; case V4L2_COLORSPACE_JPEG: return CSC_BT601F; case V4L2_COLORSPACE_BT2020: - return CSC_BT2020; + if (bit_depth == CSC_13BIT_DEPTH) + return CSC_BT2020L_13BIT; + else + return CSC_BT2020; + case V4L2_COLORSPACE_BT709F: + if (bit_depth == CSC_10BIT_DEPTH) { + DRM_WARN("Unsupported bt709f at 10bit csc depth, use bt601f instead\n"); + return CSC_BT601F; + } else { + return CSC_BT709F_13BIT; + } + case V4L2_COLORSPACE_BT2020F: + if (bit_depth == CSC_10BIT_DEPTH) { + DRM_WARN("Unsupported bt2020f at 10bit csc depth, use bt601f instead\n"); + return CSC_BT601F; + } else { + return CSC_BT2020F_13BIT; + } default: return CSC_BT709L; } @@ -2449,6 +2724,11 @@ static void vop2_setup_csc_mode(struct vop2_video_port *vp, int is_output_yuv = vcstate->yuv_overlay; int input_csc = vpstate->color_space; int output_csc = vcstate->color_space; + struct vop2_win *win = to_vop2_win(pstate->plane); + int csc_y2r_bit_depth = CSC_10BIT_DEPTH; + + if (win->feature & WIN_FEATURE_Y2R_13BIT_DEPTH) + csc_y2r_bit_depth = CSC_13BIT_DEPTH; vpstate->y2r_en = 0; vpstate->r2y_en = 0; @@ -2463,7 +2743,7 @@ static void vop2_setup_csc_mode(struct vop2_video_port *vp, */ if (!is_input_yuv) { vpstate->r2y_en = 1; - vpstate->csc_mode = vop2_convert_csc_mode(output_csc); + vpstate->csc_mode = vop2_convert_csc_mode(output_csc, CSC_10BIT_DEPTH); } return; } else if (!vpstate->hdr_in && vp->sdr2hdr_en) { @@ -2474,17 +2754,17 @@ static void vop2_setup_csc_mode(struct vop2_video_port *vp, */ if (is_input_yuv) { vpstate->y2r_en = 1; - vpstate->csc_mode = vop2_convert_csc_mode(input_csc); + vpstate->csc_mode = vop2_convert_csc_mode(input_csc, csc_y2r_bit_depth); } return; } if (is_input_yuv && !is_output_yuv) { vpstate->y2r_en = 1; - vpstate->csc_mode = vop2_convert_csc_mode(input_csc); + vpstate->csc_mode = vop2_convert_csc_mode(input_csc, csc_y2r_bit_depth); } else if (!is_input_yuv && is_output_yuv) { vpstate->r2y_en = 1; - vpstate->csc_mode = vop2_convert_csc_mode(output_csc); + vpstate->csc_mode = vop2_convert_csc_mode(output_csc, CSC_10BIT_DEPTH); } } @@ -2876,8 +3156,8 @@ static void vop2_wb_commit(struct drm_crtc *crtc) if (conn_state->writeback_job && conn_state->writeback_job->fb) { struct drm_framebuffer *fb = conn_state->writeback_job->fb; - DRM_DEV_DEBUG(vop2->dev, "Enable wb %ux%u fmt: %u pitches: %d\n", - fb->width, fb->height, wb_state->format, fb->pitches[0]); + DRM_DEV_DEBUG(vop2->dev, "Enable wb %ux%u fmt: %u pitches: %d addr: %pad\n", + fb->width, fb->height, wb_state->format, fb->pitches[0], &wb_state->yrgb_addr); drm_writeback_queue_job(wb_conn, conn_state); conn_state->writeback_job = NULL; @@ -2988,7 +3268,7 @@ static void vop2_crtc_load_lut(struct drm_crtc *crtc) if (vop2->version == VOP_VERSION_RK3568) { rk3568_crtc_load_lut(crtc); - } else if (vop2->version == VOP_VERSION_RK3588) { + } else { struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state); const struct vop2_video_port_data *vp_data = &vop2->data->vp[vp->id]; struct vop2_video_port *splice_vp = &vop2->vps[vp_data->splice_vp_id]; @@ -3014,7 +3294,8 @@ static void vop2_crtc_load_lut(struct drm_crtc *crtc) * so we add vop2_wait_for_fs_by_done_bit_status() to make sure the first config done take * effect and then to do next frame config. */ - vop2_wait_for_fs_by_done_bit_status(vp); + if (VOP_MODULE_GET(vop2, vp, standby) == 0) + vop2_wait_for_fs_by_done_bit_status(vp); } static void rockchip_vop2_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, @@ -3261,6 +3542,30 @@ err: +----------+ +-------------+ | eDP | * +-----------+ */ +static void vop3_layer_map_initial(struct vop2 *vop2, uint32_t current_vp_id) +{ + struct vop2_video_port *vp; + struct vop2_win *win; + unsigned long win_mask; + uint16_t vp_id; + int phys_id; + int i; + + for (i = 0; i < vop2->data->nr_vps; i++) { + vp_id = i; + vp = &vop2->vps[vp_id]; + vp->win_mask = vp->plane_mask; + win_mask = vp->win_mask; + for_each_set_bit(phys_id, &win_mask, ROCKCHIP_MAX_LAYER) { + win = vop2_find_win_by_phys_id(vop2, phys_id); + VOP_CTRL_SET(vop2, win_vp_id[phys_id], vp_id); + win->vp_mask = BIT(vp_id); + win->old_vp_mask = win->vp_mask; + DRM_DEV_DEBUG(vop2->dev, "%s attach to vp%d\n", win->name, vp_id); + } + } +} + static void vop2_layer_map_initial(struct vop2 *vop2, uint32_t current_vp_id) { struct vop2_layer *layer; @@ -3275,6 +3580,11 @@ static void vop2_layer_map_initial(struct vop2 *vop2, uint32_t current_vp_id) int phys_id; int i, j; + if (is_vop3(vop2)) { + vop3_layer_map_initial(vop2, current_vp_id); + return; + } + for (i = 0; i < vop2->data->nr_vps; i++) { vp_id = i; j = 0; @@ -3286,7 +3596,7 @@ static void vop2_layer_map_initial(struct vop2 *vop2, uint32_t current_vp_id) layer = &vop2->layers[used_layers + j]; win = vop2_find_win_by_phys_id(vop2, phys_id); VOP_CTRL_SET(vop2, win_vp_id[phys_id], vp_id); - VOP_MODULE_SET(vop2, layer, layer_sel, win->layer_sel_id); + VOP_MODULE_SET(vop2, layer, layer_sel, win->layer_sel_id[vp_id]); win->vp_mask = BIT(i); win->old_vp_mask = win->vp_mask; layer->win_phys_id = win->phys_id; @@ -3343,7 +3653,6 @@ static void vop2_initial(struct drm_crtc *crtc) int ret; if (vop2->enable_count == 0) { - ret = pm_runtime_get_sync(vop2->dev); if (ret < 0) { DRM_DEV_ERROR(vop2->dev, "failed to get pm runtime: %d\n", ret); @@ -3371,6 +3680,9 @@ static void vop2_initial(struct drm_crtc *crtc) VOP_MODULE_SET(vop2, wb, axi_uv_id, 0xe); vop2_wb_cfg_done(vp); + if (is_vop3(vop2)) + VOP_CTRL_SET(vop2, esmart_lb_mode, vop2->data->esmart_lb_mode); + VOP_CTRL_SET(vop2, cfg_done_en, 1); /* * Disable auto gating, this is a workaround to @@ -3389,6 +3701,9 @@ static void vop2_initial(struct drm_crtc *crtc) */ VOP_CTRL_SET(vop2, if_ctrl_cfg_done_imd, 1); + VOP_CTRL_SET(vop2, axi_outstanding_max_num, 30); + VOP_CTRL_SET(vop2, axi_max_outstanding_en, 1); + vop2_layer_map_initial(vop2, current_vp_id); vop2_axi_irqs_enable(vop2); vop2->is_enabled = true; @@ -3855,6 +4170,12 @@ static void vop2_crtc_atomic_disable(struct drm_crtc *crtc, vop2_crtc_disable_dsc(vop2, vcstate->dsc_id); } } + + if (vp->cubic_lut) { + VOP_MODULE_SET(vop2, vp, cubic_lut_update_en, 0); + VOP_MODULE_SET(vop2, vp, cubic_lut_en, 0); + } + vop2_disable_all_planes_for_crtc(crtc); /* @@ -4080,6 +4401,7 @@ static int vop2_plane_atomic_check(struct drm_plane *plane, struct drm_plane_sta struct rockchip_gem_object *rk_obj, *rk_uv_obj; int min_scale = win->regs->scl ? FRAC_16_16(1, 8) : DRM_PLANE_HELPER_NO_SCALING; int max_scale = win->regs->scl ? FRAC_16_16(8, 1) : DRM_PLANE_HELPER_NO_SCALING; + uint32_t tile_size = 1; int max_input_w; int max_input_h; unsigned long offset; @@ -4183,6 +4505,16 @@ static int vop2_plane_atomic_check(struct drm_plane *plane, struct drm_plane_sta else vpstate->afbc_en = false; + vpstate->tiled_en = rockchip_tiled(plane, fb->modifier) ? + fb->modifier & ROCKCHIP_TILED_BLOCK_SIZE_MASK : 0; + if (vpstate->tiled_en && vpstate->afbc_en) { + DRM_ERROR("%s afbc and tiled format can't be enabled at same time(modifier: 0x%llx)\n", + win->name, fb->modifier); + return -EINVAL; + } + if (vpstate->tiled_en) + tile_size = vpstate->tiled_en == ROCKCHIP_TILED_BLOCK_SIZE_8x8 ? 8 : 4; + /* * This is special feature at rk356x, the cluster layer only can support * afbc format and can't support linear format; @@ -4195,7 +4527,7 @@ static int vop2_plane_atomic_check(struct drm_plane *plane, struct drm_plane_sta } if (vp->vop2->version > VOP_VERSION_RK3568) { - if (vop2_cluster_window(win) && !vpstate->afbc_en && fb->format->is_yuv) { + if (vop2_cluster_window(win) && !vpstate->afbc_en && fb->format->is_yuv && !is_vop3(vop2)) { DRM_ERROR("Unsupported linear yuv format at %s\n", win->name); return -EINVAL; } @@ -4223,7 +4555,10 @@ static int vop2_plane_atomic_check(struct drm_plane *plane, struct drm_plane_sta return -EINVAL; } - offset = (src->x1 >> 16) * fb->format->cpp[0]; + if (fb->format->char_per_block[0] == 0) + offset = ALIGN_DOWN(src->x1 >> 16, tile_size) * fb->format->cpp[0] * tile_size; + else + offset = drm_format_info_min_pitch(fb->format, 0, ALIGN_DOWN(src->x1 >> 16, tile_size)) * tile_size; vpstate->offset = offset + fb->offsets[0]; /* @@ -4234,7 +4569,7 @@ static int vop2_plane_atomic_check(struct drm_plane *plane, struct drm_plane_sta else if (vpstate->ymirror_en) offset += ((src->y2 >> 16) - 1) * fb->pitches[0]; else - offset += (src->y1 >> 16) * fb->pitches[0]; + offset += ALIGN_DOWN(src->y1 >> 16, tile_size) * fb->pitches[0]; obj = fb->obj[0]; rk_obj = to_rockchip_obj(obj); @@ -4244,8 +4579,14 @@ static int vop2_plane_atomic_check(struct drm_plane *plane, struct drm_plane_sta int hsub = fb->format->hsub; int vsub = fb->format->vsub; - offset = (src->x1 >> 16) * fb->format->cpp[1] / hsub; - offset += (src->y1 >> 16) * fb->pitches[1] / vsub; + if (fb->format->char_per_block[0] == 0) + offset = ALIGN_DOWN(src->x1 >> 16, tile_size) * fb->format->cpp[1] / hsub * tile_size; + else + offset = drm_format_info_min_pitch(fb->format, 1, ALIGN_DOWN(src->x1 >> 16, tile_size)) * tile_size / hsub; + + if (vpstate->tiled_en) + offset /= vsub; + offset += ALIGN_DOWN(src->y1 >> 16, tile_size) * fb->pitches[1] / vsub; uv_obj = fb->obj[1]; rk_uv_obj = to_rockchip_obj(uv_obj); @@ -4254,6 +4595,9 @@ static int vop2_plane_atomic_check(struct drm_plane *plane, struct drm_plane_sta offset += fb->pitches[1] * ((state->src_h >> 16) - 2) / vsub; dma_addr = rk_uv_obj->dma_addr + offset + fb->offsets[1]; vpstate->uv_mst = dma_addr; + /* tile 4x4 m0 format, y and uv is packed together */ + if (vpstate->tiled_en == ROCKCHIP_TILED_BLOCK_SIZE_4x4_MODE0) + vpstate->yrgb_mst += offset; } return 0; @@ -4418,6 +4762,20 @@ static void rk3588_vop2_win_cfg_axi(struct vop2_win *win) VOP_WIN_SET(vop2, win, axi_uv_id, win->axi_uv_id); } +static const char *modifier_to_string(uint64_t modifier) +{ + switch (modifier) { + case DRM_FORMAT_MOD_ROCKCHIP_TILED(ROCKCHIP_TILED_BLOCK_SIZE_8x8): + return "[TILE_8x8]"; + case DRM_FORMAT_MOD_ROCKCHIP_TILED(ROCKCHIP_TILED_BLOCK_SIZE_4x4_MODE0): + return "[TILE_4x4_M0]"; + case DRM_FORMAT_MOD_ROCKCHIP_TILED(ROCKCHIP_TILED_BLOCK_SIZE_4x4_MODE1): + return "[TILE_4x4_M1]"; + default: + return drm_is_afbc(modifier) ? "[AFBC]" : ""; + } +} + static void vop2_win_atomic_update(struct vop2_win *win, struct drm_rect *src, struct drm_rect *dst, struct drm_plane_state *pstate) { @@ -4439,7 +4797,7 @@ static void vop2_win_atomic_update(struct vop2_win *win, struct drm_rect *src, s uint32_t afbc_half_block_en; uint32_t afbc_tile_num; uint32_t lb_mode; - uint32_t stride; + uint32_t stride, uv_stride = 0; uint32_t transform_offset; /* offset of the right window in splice mode */ uint32_t splice_pixel_offset = 0; @@ -4452,6 +4810,7 @@ static void vop2_win_atomic_update(struct vop2_win *win, struct drm_rect *src, s struct drm_format_name_buf format_name; bool dither_up; + bool tile_4x4_m0 = vpstate->tiled_en == ROCKCHIP_TILED_BLOCK_SIZE_4x4_MODE0 ? true : false; actual_w = drm_rect_width(src) >> 16; actual_h = drm_rect_height(src) >> 16; @@ -4522,7 +4881,14 @@ static void vop2_win_atomic_update(struct vop2_win *win, struct drm_rect *src, s dsp_sty = dst->y1; dsp_st = dsp_sty << 16 | (dsp_stx & 0xffff); - format = vop2_convert_format(fb->format->format); + if (vpstate->tiled_en) { + if (is_vop3(vop2)) + format = vop3_convert_tiled_format(fb->format->format, vpstate->tiled_en); + else + format = vop2_convert_tiled_format(fb->format->format); + } else { + format = vop2_convert_format(fb->format->format); + } vop2_setup_csc_mode(vp, vpstate); @@ -4534,11 +4900,14 @@ static void vop2_win_atomic_update(struct vop2_win *win, struct drm_rect *src, s vp->id, win->name, actual_w, actual_h, dsp_w, dsp_h, dsp_stx, dsp_sty, drm_get_format_name(fb->format->format, &format_name), - vpstate->afbc_en ? "_AFBC" : "", &vpstate->yrgb_mst); + modifier_to_string(fb->modifier), &vpstate->yrgb_mst); if (vop2->version != VOP_VERSION_RK3568) rk3588_vop2_win_cfg_axi(win); + if (is_vop3(vop2) && !vop2_cluster_window(win)) + VOP_WIN_SET(vop2, win, scale_engine_num, win->scale_engine_num); + if (vpstate->afbc_en) { /* the afbc superblock is 16 x 16 */ afbc_format = vop2_convert_afbc_format(fb->format->format); @@ -4590,7 +4959,8 @@ static void vop2_win_atomic_update(struct vop2_win *win, struct drm_rect *src, s VOP_AFBC_SET(vop2, win, rotate_90, vpstate->rotate_90_en); } else { VOP_CLUSTER_SET(vop2, win, afbc_enable, 0); - VOP_AFBC_SET(vop2, win, transform_offset, 0); + transform_offset = vop2_tile_transform_offset(vpstate, vpstate->tiled_en); + VOP_AFBC_SET(vop2, win, transform_offset, transform_offset); VOP_WIN_SET(vop2, win, ymirror, vpstate->ymirror_en); VOP_WIN_SET(vop2, win, xmirror, vpstate->xmirror_en); } @@ -4607,21 +4977,43 @@ static void vop2_win_atomic_update(struct vop2_win *win, struct drm_rect *src, s VOP_AFBC_SET(vop2, win, half_block_en, afbc_half_block_en); VOP_WIN_SET(vop2, win, format, format); - /* win->yrgb_vir only take effect at non-afbc mode */ - VOP_WIN_SET(vop2, win, yrgb_vir, stride); VOP_WIN_SET(vop2, win, yrgb_mst, yrgb_mst); rb_swap = vop2_win_rb_swap(fb->format->format); uv_swap = vop2_win_uv_swap(fb->format->format); + if (vpstate->tiled_en) { + uv_swap = 1; + if (vpstate->tiled_en == ROCKCHIP_TILED_BLOCK_SIZE_8x8) + stride <<= 3; + else + stride <<= 2; + } VOP_WIN_SET(vop2, win, rb_swap, rb_swap); VOP_WIN_SET(vop2, win, uv_swap, uv_swap); if (fb->format->is_yuv) { - VOP_WIN_SET(vop2, win, uv_vir, DIV_ROUND_UP(fb->pitches[1], 4)); - VOP_WIN_SET(vop2, win, uv_mst, uv_mst); + uv_stride = DIV_ROUND_UP(fb->pitches[1], 4); + if (vpstate->tiled_en) { + int vsub = fb->format->vsub; + + if (vpstate->tiled_en == ROCKCHIP_TILED_BLOCK_SIZE_8x8) + uv_stride = uv_stride * 8 / vsub; + else + uv_stride = uv_stride * 4 / vsub; + VOP_WIN_SET(vop2, win, tile_mode, tile_4x4_m0); + } + + VOP_WIN_SET(vop2, win, uv_vir, uv_stride); + VOP_WIN_SET(vop2, win, uv_mst, vpstate->uv_mst); } - vop2_setup_scale(vop2, win, actual_w, actual_h, dsp_w, dsp_h, fb->format->format); + /* tile 4x4 m0 format, y and uv is packed together */ + if (tile_4x4_m0) + VOP_WIN_SET(vop2, win, yrgb_vir, stride + uv_stride); + else + VOP_WIN_SET(vop2, win, yrgb_vir, stride); + + vop2_setup_scale(vop2, win, actual_w, actual_h, dsp_w, dsp_h, pstate); vop2_plane_setup_color_key(&win->base); VOP_WIN_SET(vop2, win, act_info, act_info); VOP_WIN_SET(vop2, win, dsp_info, dsp_info); @@ -4631,6 +5023,9 @@ static void vop2_win_atomic_update(struct vop2_win *win, struct drm_rect *src, s VOP_WIN_SET(vop2, win, r2y_en, vpstate->r2y_en); VOP_WIN_SET(vop2, win, csc_mode, vpstate->csc_mode); + if (win->feature & WIN_FEATURE_Y2R_13BIT_DEPTH && !vop2_cluster_window(win)) + VOP_WIN_SET(vop2, win, csc_13bit_en, !!(vpstate->csc_mode & CSC_BT709L_13BIT)); + dither_up = vop2_win_dither_up(fb->format->format); VOP_WIN_SET(vop2, win, dither_up, dither_up); @@ -4707,7 +5102,8 @@ static void vop2_plane_atomic_update(struct drm_plane *plane, struct drm_plane_s */ if (win->old_vp_mask != win->vp_mask) { win->old_vp_mask = win->vp_mask; - vp->skip_vsync = false; + if (!is_vop3(vop2)) + vp->skip_vsync = false; } if (vcstate->splice_mode) { @@ -4717,7 +5113,7 @@ static void vop2_plane_atomic_update(struct drm_plane *plane, struct drm_plane_s drm_rect_width(&vpstate->dest), drm_rect_height(&vpstate->dest), vpstate->dest.x1, vpstate->dest.y1, drm_get_format_name(fb->format->format, &format_name), - vpstate->afbc_en ? "_AFBC" : "", &vpstate->yrgb_mst); + modifier_to_string(fb->modifier), &vpstate->yrgb_mst); vop2_calc_drm_rect_for_splice(vpstate, &wsrc, &wdst, &right_wsrc, &right_wdst); splice_win = win->splice_win; @@ -5139,6 +5535,39 @@ static void vop2_crtc_line_flag_irq_disable(struct vop2_video_port *vp) spin_unlock_irqrestore(&vop2->irq_lock, flags); } +static void vop3_crtc_send_mcu_cmd(struct drm_crtc *crtc, u32 type, u32 value) +{ + struct vop2_video_port *vp; + struct vop2 *vop2; + + if (!crtc) + return; + + vp = to_vop2_video_port(crtc); + vop2 = vp->vop2; + + mutex_lock(&vop2->vop2_lock); + if (vop2 && vop2->is_enabled) { + switch (type) { + case MCU_WRCMD: + VOP_MODULE_SET(vop2, vp, mcu_rs, 0); + VOP_MODULE_SET(vop2, vp, mcu_rw_bypass_port, value); + VOP_MODULE_SET(vop2, vp, mcu_rs, 1); + break; + case MCU_WRDATA: + VOP_MODULE_SET(vop2, vp, mcu_rs, 1); + VOP_MODULE_SET(vop2, vp, mcu_rw_bypass_port, value); + break; + case MCU_SETBYPASS: + VOP_MODULE_SET(vop2, vp, mcu_bypass, value ? 1 : 0); + break; + default: + break; + } + } + mutex_unlock(&vop2->vop2_lock); +} + static int vop2_crtc_wait_vact_end(struct drm_crtc *crtc, unsigned int mstimeout) { struct vop2_video_port *vp = to_vop2_video_port(crtc); @@ -5328,7 +5757,7 @@ static int vop2_plane_info_dump(struct seq_file *s, struct drm_plane *plane) drm_get_format_name(fb->format->format, &format_name); DEBUG_PRINT("\tformat: %s%s%s[%d] color_space[%d] glb_alpha[0x%x]\n", format_name.str, - rockchip_afbc(plane, fb->modifier) ? "[AFBC]" : "", + modifier_to_string(fb->modifier), vpstate->eotf ? " HDR" : " SDR", vpstate->eotf, vpstate->color_space, vpstate->global_alpha); DEBUG_PRINT("\trotate: xmirror: %d ymirror: %d rotate_90: %d rotate_270: %d\n", @@ -5413,38 +5842,22 @@ static void vop2_crtc_regs_dump(struct drm_crtc *crtc, struct seq_file *s) struct vop2_video_port *vp = to_vop2_video_port(crtc); struct vop2 *vop2 = vp->vop2; struct drm_crtc_state *cstate = crtc->state; - const struct reg { - uint32_t offset; - const char *name; - } regs[] = { - { RK3568_REG_CFG_DONE, "SYS" }, - { RK3568_OVL_CTRL, "OVL" }, - { RK3568_VP0_DSP_CTRL, "VP0" }, - { RK3568_VP1_DSP_CTRL, "VP1" }, - { RK3568_VP2_DSP_CTRL, "VP2" }, - { RK3568_CLUSTER0_WIN0_CTRL0, "Cluster0" }, - { RK3568_CLUSTER1_WIN0_CTRL0, "Cluster1" }, - { RK3588_CLUSTER2_WIN0_CTRL0, "Cluster2" }, - { RK3588_CLUSTER3_WIN0_CTRL0, "Cluster3" }, - { RK3568_ESMART0_CTRL0, "Esmart0" }, - { RK3568_ESMART1_CTRL0, "Esmart1" }, - { RK3568_SMART0_CTRL0, "Smart0" }, - { RK3568_SMART1_CTRL0, "Smart1" }, - { RK3568_HDR_LUT_CTRL, "HDR" }, - }; + const struct vop_dump_regs *regs = vop2->data->dump_regs; uint32_t buf[68]; - unsigned int len = ARRAY_SIZE(buf); + uint32_t len = ARRAY_SIZE(buf); unsigned int n, i, j; + resource_size_t offset_addr; uint32_t base; if (!cstate->active) return; - n = ARRAY_SIZE(regs); + n = vop2->data->dump_regs_size; for (i = 0; i < n; i++) { base = regs[i].offset; - pr_info("%s:\n", regs[i].name); + offset_addr = vop2->res->start + base; + pr_info("%s[%pa]:\n", regs[i].name, &offset_addr); for (j = 0; j < len; j++) buf[j] = vop2_readl(vop2, base + (4 * j)); print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 4, buf, @@ -5799,6 +6212,7 @@ static const struct rockchip_crtc_funcs private_crtc_funcs = { .bandwidth = vop2_crtc_bandwidth, .crtc_close = vop2_crtc_close, .te_handler = vop2_crtc_te_handler, + .crtc_send_mcu_cmd = vop3_crtc_send_mcu_cmd, .wait_vact_end = vop2_crtc_wait_vact_end, .crtc_standby = vop2_crtc_standby, }; @@ -6224,7 +6638,7 @@ static int vop2_calc_cru_cfg(struct drm_crtc *crtc, int conn_id, char clk_name[32]; int ret; - if (vop2->version < VOP_VERSION_RK3588) + if (vop2->version != VOP_VERSION_RK3588) return 0; if_data = vop2_find_connector_if_data(vop2, conn_id); @@ -6667,6 +7081,7 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state } VOP_CTRL_SET(vop2, rgb_mux, vp_data->id); VOP_GRF_SET(vop2, sys_grf, grf_bt1120_clk_inv, !dclk_inv); + VOP_CTRL_SET(vop2, bt1120_dclk_pol, !dclk_inv); yc_swap = vop2_output_yc_swap(vcstate->bus_format); VOP_CTRL_SET(vop2, bt1120_yc_swap, yc_swap); } @@ -6679,6 +7094,7 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state VOP_CTRL_SET(vop2, bt656_en, 1); VOP_CTRL_SET(vop2, rgb_mux, vp_data->id); VOP_GRF_SET(vop2, sys_grf, grf_bt656_clk_inv, !dclk_inv); + VOP_CTRL_SET(vop2, bt656_dclk_pol, !dclk_inv); yc_swap = vop2_output_yc_swap(vcstate->bus_format); VOP_CTRL_SET(vop2, bt656_yc_swap, yc_swap); } @@ -7482,6 +7898,146 @@ static void vop2_setup_alpha(struct vop2_video_port *vp, } } +static void vop3_setup_alpha(struct vop2_video_port *vp, + const struct vop2_zpos *vop2_zpos) +{ + struct vop2 *vop2 = vp->vop2; + const struct vop2_video_port_data *vp_data = &vop2->data->vp[vp->id]; + const struct vop3_ovl_regs *ovl_regs = vop2->data->vp[vp->id].ovl_regs; + uint32_t src_color_ctrl_offset = ovl_regs->layer_mix_regs->src_color_ctrl.offset; + uint32_t dst_color_ctrl_offset = ovl_regs->layer_mix_regs->dst_color_ctrl.offset; + uint32_t src_alpha_ctrl_offset = ovl_regs->layer_mix_regs->src_alpha_ctrl.offset; + uint32_t dst_alpha_ctrl_offset = ovl_regs->layer_mix_regs->dst_alpha_ctrl.offset; + unsigned long win_mask = vp->win_mask; + const struct vop2_zpos *zpos; + struct vop2_plane_state *vpstate; + struct vop2_alpha_config alpha_config; + union vop2_bg_alpha_ctrl bg_alpha_ctrl; + struct vop2_alpha alpha; + struct vop2_win *win; + struct drm_plane_state *pstate; + struct drm_framebuffer *fb; + int pixel_alpha_en; + int premulti_en = 1; + int phys_id; + uint32_t offset; + int i; + bool bottom_layer_alpha_en = false; + u32 dst_global_alpha = 0xff; + + for_each_set_bit(phys_id, &win_mask, ROCKCHIP_MAX_LAYER) { + win = vop2_find_win_by_phys_id(vop2, phys_id); + pstate = win->base.state; + vpstate = to_vop2_plane_state(pstate); + + if (!vop2_plane_active(pstate)) + continue; + + if (vpstate->zpos == 0 && vpstate->global_alpha != 0xff && + !vop2_cluster_window(win)) { + /* + * If bottom layer have global alpha effect [except cluster layer, + * because cluster have deal with bottom layer global alpha value + * at cluster mix], bottom layer mix need deal with global alpha. + */ + bottom_layer_alpha_en = true; + dst_global_alpha = vpstate->global_alpha; + if (pstate->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI) + premulti_en = 1; + else + premulti_en = 0; + + break; + } + } + + alpha_config.dst_pixel_alpha_en = true; /* alpha value need transfer to next mix */ + for (i = 1; i < vp->nr_layers; i++) { + zpos = &vop2_zpos[i]; + win = vop2_find_win_by_phys_id(vop2, zpos->win_phys_id); + pstate = win->base.state; + vpstate = to_vop2_plane_state(pstate); + fb = pstate->fb; + if (pstate->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI) + premulti_en = 1; + else + premulti_en = 0; + pixel_alpha_en = is_alpha_support(fb->format->format); + + alpha_config.src_premulti_en = premulti_en; + if (bottom_layer_alpha_en && i == 1) {/* Cd = Cs + (1 - As) * Cd * Agd */ + alpha_config.dst_premulti_en = false; + alpha_config.src_pixel_alpha_en = pixel_alpha_en; + alpha_config.src_glb_alpha_value = vpstate->global_alpha; + alpha_config.dst_glb_alpha_value = dst_global_alpha; + } else if (vop2_cluster_window(win)) {/* Mix output data only have pixel alpha */ + alpha_config.dst_premulti_en = true; + alpha_config.src_pixel_alpha_en = true; + alpha_config.src_glb_alpha_value = 0xff; + alpha_config.dst_glb_alpha_value = 0xff; + } else {/* Cd = Cs + (1 - As) * Cd */ + alpha_config.dst_premulti_en = true; + alpha_config.src_pixel_alpha_en = pixel_alpha_en; + alpha_config.src_glb_alpha_value = vpstate->global_alpha; + alpha_config.dst_glb_alpha_value = 0xff; + } + vop2_parse_alpha(&alpha_config, &alpha); + + offset = (i - 1) * 0x10; + vop2_writel(vop2, src_color_ctrl_offset + offset, alpha.src_color_ctrl.val); + vop2_writel(vop2, dst_color_ctrl_offset + offset, alpha.dst_color_ctrl.val); + vop2_writel(vop2, src_alpha_ctrl_offset + offset, alpha.src_alpha_ctrl.val); + vop2_writel(vop2, dst_alpha_ctrl_offset + offset, alpha.dst_alpha_ctrl.val); + } + + /* Transfer pixel alpha value to next mix */ + alpha_config.src_premulti_en = true; + alpha_config.dst_premulti_en = true; + alpha_config.src_pixel_alpha_en = false; + alpha_config.src_glb_alpha_value = 0xff; + alpha_config.dst_glb_alpha_value = 0xff; + vop2_parse_alpha(&alpha_config, &alpha); + + for (; i < vop2->data->nr_layers; i++) { + offset = (i - 1) * 0x10; + + vop2_writel(vop2, src_color_ctrl_offset + offset, alpha.src_color_ctrl.val); + vop2_writel(vop2, dst_color_ctrl_offset + offset, alpha.dst_color_ctrl.val); + vop2_writel(vop2, src_alpha_ctrl_offset + offset, alpha.src_alpha_ctrl.val); + vop2_writel(vop2, dst_alpha_ctrl_offset + offset, alpha.dst_alpha_ctrl.val); + } + + if (vp_data->feature & VOP_FEATURE_HDR10) { + src_color_ctrl_offset = ovl_regs->hdr_mix_regs->src_color_ctrl.offset; + dst_color_ctrl_offset = ovl_regs->hdr_mix_regs->dst_color_ctrl.offset; + src_alpha_ctrl_offset = ovl_regs->hdr_mix_regs->src_alpha_ctrl.offset; + dst_alpha_ctrl_offset = ovl_regs->hdr_mix_regs->dst_alpha_ctrl.offset; + + if (bottom_layer_alpha_en || vp->hdr_en) { + /* Transfer pixel alpha to hdr mix */ + alpha_config.src_premulti_en = premulti_en; + alpha_config.dst_premulti_en = true; + alpha_config.src_pixel_alpha_en = true; + alpha_config.src_glb_alpha_value = 0xff; + alpha_config.dst_glb_alpha_value = 0xff; + vop2_parse_alpha(&alpha_config, &alpha); + + vop2_writel(vop2, src_color_ctrl_offset, alpha.src_color_ctrl.val); + vop2_writel(vop2, dst_color_ctrl_offset, alpha.dst_color_ctrl.val); + vop2_writel(vop2, src_alpha_ctrl_offset, alpha.src_alpha_ctrl.val); + vop2_writel(vop2, dst_alpha_ctrl_offset, alpha.dst_alpha_ctrl.val); + } else { + vop2_writel(vop2, src_color_ctrl_offset, 0); + vop2_writel(vop2, dst_color_ctrl_offset, 0); + vop2_writel(vop2, src_alpha_ctrl_offset, 0); + vop2_writel(vop2, dst_alpha_ctrl_offset, 0); + } + } + + bg_alpha_ctrl.bits.alpha_en = 0; + VOP_MODULE_SET(vop2, vp, bg_mix_ctrl, bg_alpha_ctrl.val); +} + static u32 vop2_layer_cfg_update(struct vop2_layer *layer, u32 old_layer_cfg, u8 win_layer_id) { const struct vop_reg *reg = &layer->regs->layer_sel; @@ -7600,12 +8156,12 @@ static void vop2_setup_layer_mixer_for_vp(struct vop2_video_port *vp, layer_id = win->layer_id; win_phys_id = layer->win_phys_id; VOP_CTRL_SET(vop2, win_vp_id[win->phys_id], port_id); - new_layer_cfg = vop2_layer_cfg_update(layer, new_layer_cfg, win->layer_sel_id); + new_layer_cfg = vop2_layer_cfg_update(layer, new_layer_cfg, win->layer_sel_id[vp->id]); win->layer_id = layer->id; layer->win_phys_id = win->phys_id; layer = &vop2->layers[layer_id]; win = vop2_find_win_by_phys_id(vop2, win_phys_id); - new_layer_cfg = vop2_layer_cfg_update(layer, new_layer_cfg, win->layer_sel_id); + new_layer_cfg = vop2_layer_cfg_update(layer, new_layer_cfg, win->layer_sel_id[vp->id]); win->layer_id = layer_id; layer->win_phys_id = win_phys_id; } @@ -7623,6 +8179,34 @@ static void vop2_setup_layer_mixer_for_vp(struct vop2_video_port *vp, VOP_CTRL_SET(vop2, ovl_port_mux_cfg_done_imd, 0); } +static void vop3_setup_layer_sel_for_vp(struct vop2_video_port *vp, + const struct vop2_zpos *vop2_zpos) +{ + struct vop2 *vop2 = vp->vop2; + const struct vop2_zpos *zpos; + struct vop2_win *win; + u32 layer_sel = 0; + u8 port_id = vp->id; + u8 layer_sel_id; + u8 layer_sel_none = 0xff; + int i; + + for (i = 0; i < vop2->data->nr_layers; i++) { + layer_sel_id = layer_sel_none; + if (i < vp->nr_layers) { + zpos = &vop2_zpos[i]; + win = vop2_find_win_by_phys_id(vop2, zpos->win_phys_id); + if (win->old_vp_mask != win->vp_mask && VOP_WIN_GET(vop2, win, enable)) + DRM_ERROR("must wait %s disabled and change vp_mask[0x%x->0x%x]\n", + win->name, win->old_vp_mask, win->vp_mask); + VOP_CTRL_SET(vop2, win_vp_id[win->phys_id], port_id); + layer_sel_id = win->layer_sel_id[vp->id]; + } + layer_sel |= layer_sel_id << i * 4; + } + VOP_MODULE_SET(vop2, vp, layer_sel, layer_sel); +} + /* * HDR window is fixed(not move in the overlay path with port_mux change) * and is the most slow window. And the bg is the fast. So other windows @@ -7675,7 +8259,7 @@ static void vop2_setup_dly_for_vp(struct vop2_video_port *vp) else pre_scan_dly = bg_dly + (hdisplay >> 1) - 1; - if (vop2->version == VOP_VERSION_RK3588 && hsync_len < 8) + if (vop2->version >= VOP_VERSION_RK3588 && hsync_len < 8) hsync_len = 8; pre_scan_dly = (pre_scan_dly << 16) | hsync_len; @@ -7936,14 +8520,21 @@ static void vop2_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_crtc_state sort(vop2_zpos, nr_layers, sizeof(vop2_zpos[0]), vop2_zpos_cmp, NULL); if (!vp->hdr10_at_splice_mode) { - vop2_setup_port_mux(vp); - vop2_setup_layer_mixer_for_vp(vp, vop2_zpos); + if (is_vop3(vop2)) { + vop3_setup_layer_sel_for_vp(vp, vop2_zpos); + } else { + vop2_setup_port_mux(vp); + vop2_setup_layer_mixer_for_vp(vp, vop2_zpos); + } } vop2_setup_hdr10(vp, vop2_zpos[0].win_phys_id); - vop2_setup_alpha(vp, vop2_zpos); + if (is_vop3(vop2)) + vop3_setup_alpha(vp, vop2_zpos); + else + vop2_setup_alpha(vp, vop2_zpos); vop2_setup_dly_for_vp(vp); vop2_setup_dly_for_window(vp, vop2_zpos); - if (vcstate->splice_mode) { + if (vcstate->splice_mode) {/* Fixme for VOP3 8K */ splice_vp->nr_layers = splice_nr_layers; sort(vop2_zpos_splice, splice_nr_layers, sizeof(vop2_zpos_splice[0]), @@ -7963,7 +8554,8 @@ static void vop2_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_crtc_state } } else { - vop2_calc_bg_ovl_and_port_mux(vp); + if (!is_vop3(vop2)) + vop2_calc_bg_ovl_and_port_mux(vp); vop2_setup_dly_for_vp(vp); if (vcstate->splice_mode) vop2_setup_dly_for_vp(splice_vp); @@ -8073,7 +8665,7 @@ static void vop2_tv_config_update(struct drm_crtc *crtc, vcstate->post_y2r_en = 1; } - vcstate->post_csc_mode = vop2_convert_csc_mode(vcstate->color_space); + vcstate->post_csc_mode = vop2_convert_csc_mode(vcstate->color_space, CSC_10BIT_DEPTH); if (vp_data->feature & VOP_FEATURE_OUTPUT_10BIT) brightness = interpolate(0, -128, 100, 127, @@ -8983,6 +9575,8 @@ static int vop2_gamma_init(struct vop2 *vop2) continue; vp_data = &vop2_data->vp[vp->id]; lut_len = vp_data->gamma_lut_len; + if (!lut_len) + continue; vp->gamma_lut_len = vp_data->gamma_lut_len; vp->lut_dma_rid = vp_data->lut_dma_rid; vp->lut = devm_kmalloc_array(dev, lut_len, sizeof(*vp->lut), @@ -9272,6 +9866,8 @@ static int vop2_create_crtc(struct vop2 *vop2) } else { /* give lowest zpos for primary plane */ win->zpos = registered_num_crtcs; + if (win->possible_crtcs) + possible_crtcs = win->possible_crtcs; if (vop2_plane_init(vop2, win, possible_crtcs)) { DRM_DEV_ERROR(vop2->dev, "failed to init primary plane\n"); break; @@ -9281,6 +9877,8 @@ static int vop2_create_crtc(struct vop2 *vop2) /* some times we want a cursor window for some vp */ if (vp->cursor_win_id >= 0) { + if (win->possible_crtcs) + possible_crtcs = win->possible_crtcs; cursor = vop2_cursor_plane_init(vp, possible_crtcs); if (!cursor) DRM_WARN("failed to init cursor plane for vp%d\n", vp->id); @@ -9380,6 +9978,8 @@ static int vop2_create_crtc(struct vop2 *vop2) else possible_crtcs = (1 << vop2_data->nr_vps) - 1; } + if (win->possible_crtcs) + possible_crtcs = win->possible_crtcs; ret = vop2_plane_init(vop2, win, possible_crtcs); if (ret) @@ -9488,6 +10088,8 @@ static int vop2_win_init(struct vop2 *vop2) win->hsd_filter_mode = win_data->hsd_filter_mode; win->vsu_filter_mode = win_data->vsu_filter_mode; win->vsd_filter_mode = win_data->vsd_filter_mode; + win->hsd_pre_filter_mode = win_data->hsd_pre_filter_mode; + win->vsd_pre_filter_mode = win_data->vsd_pre_filter_mode; win->dly = win_data->dly; win->feature = win_data->feature; win->phys_id = win_data->phys_id; @@ -9501,6 +10103,8 @@ static int vop2_win_init(struct vop2 *vop2) win->axi_id = win_data->axi_id; win->axi_yrgb_id = win_data->axi_yrgb_id; win->axi_uv_id = win_data->axi_uv_id; + win->scale_engine_num = win_data->scale_engine_num; + win->possible_crtcs = win_data->possible_crtcs; if (win_data->pd_id) win->pd = vop2_find_pd_by_id(vop2, win_data->pd_id); @@ -9529,13 +10133,14 @@ static int vop2_win_init(struct vop2 *vop2) area->hsd_filter_mode = win_data->hsd_filter_mode; area->vsu_filter_mode = win_data->vsu_filter_mode; area->vsd_filter_mode = win_data->vsd_filter_mode; + area->hsd_pre_filter_mode = win_data->hsd_pre_filter_mode; + area->vsd_pre_filter_mode = win_data->vsd_pre_filter_mode; area->vop2 = vop2; area->win_id = i; area->phys_id = win->phys_id; area->area_id = j + 1; area->plane_id = plane_id++; - area->layer_sel_id = -1; snprintf(name, min(sizeof(name), strlen(win->name)), "%s", win->name); snprintf(name, sizeof(name), "%s%d", name, area->area_id); area->name = devm_kstrdup(vop2->dev, name, GFP_KERNEL); @@ -9545,11 +10150,13 @@ static int vop2_win_init(struct vop2 *vop2) vop2->registered_num_wins = num_wins; - for (i = 0; i < vop2_data->nr_layers; i++) { - layer = &vop2->layers[i]; - layer_data = &vop2_data->layer[i]; - layer->id = layer_data->id; - layer->regs = layer_data->regs; + if (!is_vop3(vop2)) { + for (i = 0; i < vop2_data->nr_layers; i++) { + layer = &vop2->layers[i]; + layer_data = &vop2_data->layer[i]; + layer->id = layer_data->id; + layer->regs = layer_data->regs; + } } plane_name_list = devm_kzalloc(vop2->dev, @@ -9627,6 +10234,7 @@ static int vop2_bind(struct device *dev, struct device *master, void *data) DRM_DEV_ERROR(vop2->dev, "failed to get vop2 register byname\n"); return -EINVAL; } + vop2->res = res; vop2->regs = devm_ioremap_resource(dev, res); if (IS_ERR(vop2->regs)) return PTR_ERR(vop2->regs); @@ -9643,6 +10251,13 @@ static int vop2_bind(struct device *dev, struct device *master, void *data) return PTR_ERR(vop2->lut_regs); } + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "acm_regs"); + if (res) { + vop2->acm_regs = devm_ioremap_resource(dev, res); + if (IS_ERR(vop2->acm_regs)) + return PTR_ERR(vop2->acm_regs); + } + vop2->sys_grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf"); vop2->grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,vop-grf"); vop2->vo1_grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,vo1-grf"); diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c index 050ea4f65c3d..836752b03bc1 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c @@ -1896,7 +1896,7 @@ static const struct vop2_win_data rk3568_vop_win_data[] = { .formats = formats_for_smart, .nformats = ARRAY_SIZE(formats_for_smart), .format_modifiers = format_modifiers, - .layer_sel_id = 3, + .layer_sel_id = { 3, 3, 3, 0xff }, .supported_rotations = DRM_MODE_REFLECT_Y, .hsu_filter_mode = VOP2_SCALE_UP_BIC, .hsd_filter_mode = VOP2_SCALE_DOWN_BIL, @@ -1919,7 +1919,7 @@ static const struct vop2_win_data rk3568_vop_win_data[] = { .nformats = ARRAY_SIZE(formats_for_smart), .format_modifiers = format_modifiers, .base = 0x600, - .layer_sel_id = 7, + .layer_sel_id = { 7, 7, 7, 0xff }, .supported_rotations = DRM_MODE_REFLECT_Y, .hsu_filter_mode = VOP2_SCALE_UP_BIC, .hsd_filter_mode = VOP2_SCALE_DOWN_BIL, @@ -1942,7 +1942,7 @@ static const struct vop2_win_data rk3568_vop_win_data[] = { .nformats = ARRAY_SIZE(formats_for_rk356x_esmart), .format_modifiers = format_modifiers, .base = 0x200, - .layer_sel_id = 6, + .layer_sel_id = { 6, 6, 6, 0xff }, .supported_rotations = DRM_MODE_REFLECT_Y, .hsu_filter_mode = VOP2_SCALE_UP_BIC, .hsd_filter_mode = VOP2_SCALE_DOWN_BIL, @@ -1965,7 +1965,7 @@ static const struct vop2_win_data rk3568_vop_win_data[] = { .nformats = ARRAY_SIZE(formats_for_rk356x_esmart), .format_modifiers = format_modifiers, .base = 0x0, - .layer_sel_id = 2, + .layer_sel_id = { 2, 2, 2, 0xff }, .supported_rotations = DRM_MODE_REFLECT_Y, .hsu_filter_mode = VOP2_SCALE_UP_BIC, .hsd_filter_mode = VOP2_SCALE_DOWN_BIL, @@ -1988,7 +1988,7 @@ static const struct vop2_win_data rk3568_vop_win_data[] = { .formats = formats_for_cluster, .nformats = ARRAY_SIZE(formats_for_cluster), .format_modifiers = format_modifiers_afbc_no_linear_mode, - .layer_sel_id = 0, + .layer_sel_id = { 0, 0, 0, 0xff }, .supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 | DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y, .hsu_filter_mode = VOP2_SCALE_UP_BIC, @@ -2007,7 +2007,7 @@ static const struct vop2_win_data rk3568_vop_win_data[] = { .name = "Cluster0-win1", .phys_id = ROCKCHIP_VOP2_CLUSTER0, .base = 0x80, - .layer_sel_id = -1, + .layer_sel_id = { 0xff, 0xff, 0xff, 0xff }, .formats = formats_for_cluster, .nformats = ARRAY_SIZE(formats_for_cluster), .format_modifiers = format_modifiers_afbc_no_linear_mode, @@ -2030,7 +2030,7 @@ static const struct vop2_win_data rk3568_vop_win_data[] = { .formats = formats_for_cluster, .nformats = ARRAY_SIZE(formats_for_cluster), .format_modifiers = format_modifiers_afbc_no_linear_mode, - .layer_sel_id = 1, + .layer_sel_id = { 1, 1, 1, 0xff }, .supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 | DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y, .hsu_filter_mode = VOP2_SCALE_UP_BIC, @@ -2048,7 +2048,7 @@ static const struct vop2_win_data rk3568_vop_win_data[] = { { .name = "Cluster1-win1", .phys_id = ROCKCHIP_VOP2_CLUSTER1, - .layer_sel_id = -1, + .layer_sel_id = { 0xff, 0xff, 0xff, 0xff }, .formats = formats_for_cluster, .nformats = ARRAY_SIZE(formats_for_cluster), .format_modifiers = format_modifiers_afbc_no_linear_mode, @@ -2304,7 +2304,7 @@ static const struct vop2_win_data rk3588_vop_win_data[] = { .formats = formats_for_cluster, .nformats = ARRAY_SIZE(formats_for_cluster), .format_modifiers = format_modifiers_afbc, - .layer_sel_id = 0, + .layer_sel_id = { 0, 0, 0, 0 }, .supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 | DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y, .hsu_filter_mode = VOP2_SCALE_UP_BIC, @@ -2327,7 +2327,7 @@ static const struct vop2_win_data rk3588_vop_win_data[] = { .name = "Cluster0-win1", .phys_id = ROCKCHIP_VOP2_CLUSTER0, .base = 0x80, - .layer_sel_id = -1, + .layer_sel_id = { 0xff, 0xff, 0xff, 0xff }, .formats = formats_for_cluster, .nformats = ARRAY_SIZE(formats_for_cluster), .format_modifiers = format_modifiers_afbc, @@ -2353,7 +2353,7 @@ static const struct vop2_win_data rk3588_vop_win_data[] = { .formats = formats_for_cluster, .nformats = ARRAY_SIZE(formats_for_cluster), .format_modifiers = format_modifiers_afbc, - .layer_sel_id = 1, + .layer_sel_id = { 1, 1, 1, 1 }, .supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 | DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y, .hsu_filter_mode = VOP2_SCALE_UP_BIC, @@ -2375,7 +2375,7 @@ static const struct vop2_win_data rk3588_vop_win_data[] = { { .name = "Cluster1-win1", .phys_id = ROCKCHIP_VOP2_CLUSTER1, - .layer_sel_id = -1, + .layer_sel_id = { 0xff, 0xff, 0xff, 0xff }, .formats = formats_for_cluster, .nformats = ARRAY_SIZE(formats_for_cluster), .format_modifiers = format_modifiers_afbc, @@ -2404,7 +2404,7 @@ static const struct vop2_win_data rk3588_vop_win_data[] = { .formats = formats_for_cluster, .nformats = ARRAY_SIZE(formats_for_cluster), .format_modifiers = format_modifiers_afbc, - .layer_sel_id = 4, + .layer_sel_id = { 4, 4, 4, 4 }, .supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 | DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y, .hsu_filter_mode = VOP2_SCALE_UP_BIC, @@ -2425,7 +2425,7 @@ static const struct vop2_win_data rk3588_vop_win_data[] = { { .name = "Cluster2-win1", .phys_id = ROCKCHIP_VOP2_CLUSTER2, - .layer_sel_id = -1, + .layer_sel_id = { 0xff, 0xff, 0xff, 0xff }, .formats = formats_for_cluster, .nformats = ARRAY_SIZE(formats_for_cluster), .format_modifiers = format_modifiers_afbc, @@ -2453,7 +2453,7 @@ static const struct vop2_win_data rk3588_vop_win_data[] = { .formats = formats_for_cluster, .nformats = ARRAY_SIZE(formats_for_cluster), .format_modifiers = format_modifiers_afbc, - .layer_sel_id = 5, + .layer_sel_id = { 5, 5, 5, 5 }, .supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 | DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y, .hsu_filter_mode = VOP2_SCALE_UP_BIC, @@ -2474,7 +2474,7 @@ static const struct vop2_win_data rk3588_vop_win_data[] = { { .name = "Cluster3-win1", .phys_id = ROCKCHIP_VOP2_CLUSTER3, - .layer_sel_id = -1, + .layer_sel_id = { 0xff, 0xff, 0xff, 0xff }, .formats = formats_for_cluster, .nformats = ARRAY_SIZE(formats_for_cluster), .format_modifiers = format_modifiers_afbc, @@ -2502,7 +2502,7 @@ static const struct vop2_win_data rk3588_vop_win_data[] = { .nformats = ARRAY_SIZE(formats_for_esmart), .format_modifiers = format_modifiers, .base = 0x0, - .layer_sel_id = 2, + .layer_sel_id = { 2, 2, 2, 2 }, .supported_rotations = DRM_MODE_REFLECT_Y, .hsu_filter_mode = VOP2_SCALE_UP_BIC, .hsd_filter_mode = VOP2_SCALE_DOWN_BIL, @@ -2530,7 +2530,7 @@ static const struct vop2_win_data rk3588_vop_win_data[] = { .formats = formats_for_esmart, .nformats = ARRAY_SIZE(formats_for_esmart), .format_modifiers = format_modifiers, - .layer_sel_id = 6, + .layer_sel_id = { 6, 6, 6, 6 }, .supported_rotations = DRM_MODE_REFLECT_Y, .hsu_filter_mode = VOP2_SCALE_UP_BIC, .hsd_filter_mode = VOP2_SCALE_DOWN_BIL, @@ -2557,7 +2557,7 @@ static const struct vop2_win_data rk3588_vop_win_data[] = { .nformats = ARRAY_SIZE(formats_for_esmart), .format_modifiers = format_modifiers, .base = 0x200, - .layer_sel_id = 3, + .layer_sel_id = { 3, 3, 3, 3 }, .supported_rotations = DRM_MODE_REFLECT_Y, .hsu_filter_mode = VOP2_SCALE_UP_BIC, .hsd_filter_mode = VOP2_SCALE_DOWN_BIL, @@ -2584,7 +2584,7 @@ static const struct vop2_win_data rk3588_vop_win_data[] = { .nformats = ARRAY_SIZE(formats_for_esmart), .format_modifiers = format_modifiers, .base = 0x600, - .layer_sel_id = 7, + .layer_sel_id = { 7, 7, 7, 7 }, .supported_rotations = DRM_MODE_REFLECT_Y, .hsu_filter_mode = VOP2_SCALE_UP_BIC, .hsd_filter_mode = VOP2_SCALE_DOWN_BIL, @@ -2769,6 +2769,40 @@ static const struct vop2_ctrl rk3588_vop_ctrl = { .win_dly[ROCKCHIP_VOP2_ESMART3] = VOP_REG(RK3568_SMART_DLY_NUM, 0xff, 24), }; + +static const struct vop_dump_regs rk3568_dump_regs[] = { + { RK3568_REG_CFG_DONE, "SYS" }, + { RK3568_OVL_CTRL, "OVL" }, + { RK3568_VP0_DSP_CTRL, "VP0" }, + { RK3568_VP1_DSP_CTRL, "VP1" }, + { RK3568_VP2_DSP_CTRL, "VP2" }, + { RK3568_CLUSTER0_WIN0_CTRL0, "Cluster0" }, + { RK3568_CLUSTER1_WIN0_CTRL0, "Cluster1" }, + { RK3568_ESMART0_CTRL0, "Esmart0" }, + { RK3568_ESMART1_CTRL0, "Esmart1" }, + { RK3568_SMART0_CTRL0, "Smart0" }, + { RK3568_SMART1_CTRL0, "Smart1" }, + { RK3568_HDR_LUT_CTRL, "HDR" }, +}; + +static const struct vop_dump_regs rk3588_dump_regs[] = { + { RK3568_REG_CFG_DONE, "SYS" }, + { RK3568_OVL_CTRL, "OVL" }, + { RK3568_VP0_DSP_CTRL, "VP0" }, + { RK3568_VP1_DSP_CTRL, "VP1" }, + { RK3568_VP2_DSP_CTRL, "VP2" }, + { RK3588_VP3_DSP_CTRL, "VP3" }, + { RK3568_CLUSTER0_WIN0_CTRL0, "Cluster0" }, + { RK3568_CLUSTER1_WIN0_CTRL0, "Cluster1" }, + { RK3588_CLUSTER2_WIN0_CTRL0, "Cluster2" }, + { RK3588_CLUSTER3_WIN0_CTRL0, "Cluster3" }, + { RK3568_ESMART0_CTRL0, "Esmart0" }, + { RK3568_ESMART1_CTRL0, "Esmart1" }, + { RK3568_SMART0_CTRL0, "Esmart2" }, + { RK3568_SMART1_CTRL0, "Esmart3" }, + { RK3568_HDR_LUT_CTRL, "HDR" }, +}; + static const struct vop2_data rk3568_vop = { .version = VOP_VERSION_RK3568, .nr_vps = 3, @@ -2786,6 +2820,8 @@ static const struct vop2_data rk3568_vop = { .layer = rk3568_vop_layers, .win = rk3568_vop_win_data, .win_size = ARRAY_SIZE(rk3568_vop_win_data), + .dump_regs = rk3568_dump_regs, + .dump_regs_size = ARRAY_SIZE(rk3568_dump_regs), }; static const struct vop2_data rk3588_vop = { @@ -2821,6 +2857,8 @@ static const struct vop2_data rk3588_vop = { .nr_pds = ARRAY_SIZE(rk3588_vop_pd_data), .mem_pg = rk3588_vop_mem_pg_data, .nr_mem_pgs = ARRAY_SIZE(rk3588_vop_mem_pg_data), + .dump_regs = rk3588_dump_regs, + .dump_regs_size = ARRAY_SIZE(rk3588_dump_regs), }; static const struct of_device_id vop2_dt_match[] = {