diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index edb540d34cb7..4dc70754e0ce 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -1125,7 +1125,47 @@ static int rockchip_drm_summary_show(struct seq_file *s, void *data) return 0; } +static int rockchip_drm_regs_dump(struct seq_file *s, void *data) +{ + struct drm_info_node *node = s->private; + struct drm_minor *minor = node->minor; + struct drm_device *drm_dev = minor->dev; + struct rockchip_drm_private *priv = drm_dev->dev_private; + struct drm_crtc *crtc; + + drm_for_each_crtc(crtc, drm_dev) { + int pipe = drm_crtc_index(crtc); + + if (priv->crtc_funcs[pipe] && + priv->crtc_funcs[pipe]->regs_dump) + priv->crtc_funcs[pipe]->regs_dump(crtc, s); + } + + return 0; +} + +static int rockchip_drm_active_regs_dump(struct seq_file *s, void *data) +{ + struct drm_info_node *node = s->private; + struct drm_minor *minor = node->minor; + struct drm_device *drm_dev = minor->dev; + struct rockchip_drm_private *priv = drm_dev->dev_private; + struct drm_crtc *crtc; + + drm_for_each_crtc(crtc, drm_dev) { + int pipe = drm_crtc_index(crtc); + + if (priv->crtc_funcs[pipe] && + priv->crtc_funcs[pipe]->active_regs_dump) + priv->crtc_funcs[pipe]->active_regs_dump(crtc, s); + } + + return 0; +} + static struct drm_info_list rockchip_debugfs_files[] = { + { "active_regs", rockchip_drm_active_regs_dump, 0, NULL }, + { "regs", rockchip_drm_regs_dump, 0, NULL }, { "summary", rockchip_drm_summary_show, 0, NULL }, { "mm_dump", rockchip_drm_mm_dump, 0, NULL }, }; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index 8f2716ca1e6c..b9a7ad673294 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -388,6 +388,7 @@ struct rockchip_crtc_funcs { int (*debugfs_init)(struct drm_minor *minor, struct drm_crtc *crtc); int (*debugfs_dump)(struct drm_crtc *crtc, struct seq_file *s); void (*regs_dump)(struct drm_crtc *crtc, struct seq_file *s); + void (*active_regs_dump)(struct drm_crtc *crtc, struct seq_file *s); enum drm_mode_status (*mode_valid)(struct drm_crtc *crtc, const struct drm_display_mode *mode, int output_type); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_logo.c b/drivers/gpu/drm/rockchip/rockchip_drm_logo.c index f1dd87f9fb0f..3a19a69a5b25 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_logo.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_logo.c @@ -1072,16 +1072,14 @@ void rockchip_drm_show_logo(struct drm_device *drm_dev) private->loader_protect = true; drm_modeset_unlock_all(drm_dev); - drm_for_each_crtc(crtc, drm_dev) { - struct drm_fb_helper *helper = private->fbdev_helper; - struct rockchip_crtc_state *s = NULL; + if (private->fbdev_helper && private->fbdev_helper->fb) { + drm_for_each_crtc(crtc, drm_dev) { + struct rockchip_crtc_state *s = NULL; - if (!helper) - break; - - s = to_rockchip_crtc_state(crtc->state); - if (is_support_hotplug(s->output_type)) - drm_framebuffer_get(helper->fb); + s = to_rockchip_crtc_state(crtc->state); + if (is_support_hotplug(s->output_type)) + drm_framebuffer_get(private->fbdev_helper->fb); + } } return; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h index 7d07d86be6ed..bb4978b2a441 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h @@ -123,10 +123,10 @@ enum vop2_win_dly_mode { }; 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, + VOP3_ESMART_8K_MODE, + VOP3_ESMART_4K_4K_MODE, + VOP3_ESMART_4K_2K_2K_MODE, + VOP3_ESMART_2K_2K_2K_2K_MODE, }; /* @@ -559,7 +559,7 @@ struct hdr_extend { }; enum _vop_hdrvivid_mode { - PQHDR2HDR_WITH_DYNAMIC, + PQHDR2HDR_WITH_DYNAMIC = 0, PQHDR2SDR_WITH_DYNAMIC, HLG2PQHDR_WITH_DYNAMIC, HLG2SDR_WITH_DYNAMIC, @@ -567,14 +567,16 @@ enum _vop_hdrvivid_mode { HLG2SDR_WITHOUT_DYNAMIC, HDR_BYPASS, HDR102SDR, - SDR2PQ, + SDR2HDR10, SDR2HLG, + SDR2HDR10_USERSPACE = 100, + SDR2HLG_USERSPACE = 101, }; enum vop_hdr_format { HDR_NONE = 0, HDR_HDR10 = 1, - HDR_HGGSTATIC = 2, + HDR_HLGSTATIC = 2, RESERVED3 = 3, /* reserved for more future static hdr format */ RESERVED4 = 4, /* reserved for more future static hdr format */ HDR_HDRVIVID = 5, @@ -720,6 +722,7 @@ struct vop2_cluster_regs { struct vop_reg enable; struct vop_reg afbc_enable; struct vop_reg lb_mode; + struct vop_reg scl_lb_mode; struct vop_reg src_color_ctrl; struct vop_reg dst_color_ctrl; @@ -1039,7 +1042,6 @@ 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; @@ -1211,6 +1213,7 @@ struct vop2_ctrl { struct vop_reg version; struct vop_reg standby; struct vop_reg dma_stop; + struct vop_reg dsp_vs_t_sel; struct vop_reg lut_dma_en; struct vop_reg axi_outstanding_max_num; struct vop_reg axi_max_outstanding_en; @@ -1307,6 +1310,8 @@ struct vop2_ctrl { struct vop_dump_regs { uint32_t offset; const char *name; + struct vop_reg state; + bool enable_state; }; /** diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 325f8210c036..216eb4807d4e 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -44,6 +44,8 @@ #include #include #include +#include +#include #include #include #include @@ -66,6 +68,8 @@ #define REG_SET_MASK(x, name, off, reg, mask, v, relaxed) \ _REG_SET(x, name, off, reg, reg.mask & mask, v, relaxed) +#define REG_GET(vop2, reg) ((vop2_readl(vop2, reg.offset) >> reg.shift) & reg.mask) + #define VOP_CLUSTER_SET(x, win, name, v) \ do { \ if (win->regs->cluster) \ @@ -87,6 +91,8 @@ #define VOP_CTRL_SET(x, name, v) \ REG_SET(x, name, 0, (x)->data->ctrl->name, v, false) +#define VOP_CTRL_GET(x, name) vop2_read_reg(x, 0, &(x)->data->ctrl->name) + #define VOP_INTR_GET(vop2, name) \ vop2_read_reg(vop2, 0, &vop2->data->ctrl->name) @@ -563,6 +569,8 @@ struct vop2_video_port { uint8_t id; bool layer_sel_update; bool xmirror_en; + bool need_reset_p2i_flag; + atomic_t post_buf_empty_flag; const struct vop2_video_port_regs *regs; struct completion dsp_hold_completion; @@ -736,10 +744,8 @@ struct vop2_video_port { */ struct drm_property *hdr_ext_data_prop; - bool hdr_ext_data_change; int hdrvivid_mode; - /** * @acm_lut_data_prop: acm lut data interaction with userspace */ @@ -822,6 +828,7 @@ struct vop2 { */ uint32_t registered_num_wins; uint8_t used_mixers; + uint8_t esmart_lb_mode; /** * @active_vp_mask: Bitmask of active video ports; */ @@ -867,6 +874,8 @@ struct vop2 { /* list_head of internal clk */ struct list_head clk_list_head; struct list_head pd_list_head; + struct work_struct post_buf_empty_work; + struct workqueue_struct *workqueue; struct vop2_layer layers[ROCKCHIP_MAX_LAYER]; /* must put at the end of the struct */ @@ -2414,7 +2423,7 @@ static int vop2_get_cluster_lb_mode(struct vop2_win *win, struct vop2_plane_stat #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)) + (fac * (dst - 1) >> 16 < (src - 1)) static uint16_t vop2_scale_factor(enum scale_mode mode, int32_t filter_mode, @@ -3238,7 +3247,7 @@ static void vop2_wb_commit(struct drm_crtc *crtc) fifo_throd = fb->pitches[0] >> 4; if (fifo_throd >= vop2->data->wb->fifo_depth) fifo_throd = vop2->data->wb->fifo_depth; - r2y = fb->format->is_yuv && (!is_yuv_output(vcstate->bus_format)); + r2y = !vcstate->yuv_overlay && fb->format->is_yuv; /* * the vp_id register config done immediately @@ -3610,25 +3619,15 @@ err: */ 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; + struct drm_plane *plane = NULL; - 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); - } + drm_for_each_plane(plane, vop2->drm_dev) { + struct vop2_win *win = to_vop2_win(plane); + + vp_id = VOP_CTRL_GET(vop2, win_vp_id[win->phys_id]); + win->vp_mask = BIT(vp_id); + win->old_vp_mask = win->vp_mask; } } @@ -3746,8 +3745,10 @@ 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)) + if (is_vop3(vop2)) { + VOP_CTRL_SET(vop2, dsp_vs_t_sel, 0); VOP_CTRL_SET(vop2, esmart_lb_mode, vop2->data->esmart_lb_mode); + } /* * This is unused and error init value for rk3528 vp1, if less of this config, @@ -3762,6 +3763,9 @@ static void vop2_initial(struct drm_crtc *crtc) * avoid display image shift when a window enabled. */ VOP_CTRL_SET(vop2, auto_gating_en, 0); + + VOP_CTRL_SET(vop2, aclk_pre_auto_gating_en, 0); + /* * Register OVERLAY_LAYER_SEL and OVERLAY_PORT_SEL should take effect immediately, * than windows configuration(CLUSTER/ESMART/SMART) can take effect according the @@ -4249,6 +4253,8 @@ static void vop2_crtc_atomic_disable(struct drm_crtc *crtc, VOP_MODULE_SET(vop2, vp, cubic_lut_en, 0); } + if (vp_data->feature & VOP_FEATURE_VIVID_HDR) + VOP_MODULE_SET(vop2, vp, hdr_lut_update_en, 0); vop2_disable_all_planes_for_crtc(crtc); /* @@ -4980,7 +4986,7 @@ static void vop2_win_atomic_update(struct vop2_win *win, struct drm_rect *src, s if (vop2->version != VOP_VERSION_RK3568) rk3588_vop2_win_cfg_axi(win); - if (is_vop3(vop2) && !vop2_cluster_window(win)) + if (!win->parent && !vop2_cluster_window(win) && is_vop3(vop2)) VOP_WIN_SET(vop2, win, scale_engine_num, win->scale_engine_num); if (vpstate->afbc_en) { @@ -5079,7 +5085,7 @@ static void vop2_win_atomic_update(struct vop2_win *win, struct drm_rect *src, s } VOP_WIN_SET(vop2, win, uv_vir, uv_stride); - VOP_WIN_SET(vop2, win, uv_mst, vpstate->uv_mst); + VOP_WIN_SET(vop2, win, uv_mst, uv_mst); } /* tile 4x4 m0 format, y and uv is packed together */ @@ -5108,6 +5114,7 @@ static void vop2_win_atomic_update(struct vop2_win *win, struct drm_rect *src, s if (vop2_cluster_window(win)) { lb_mode = vop2_get_cluster_lb_mode(win, vpstate); VOP_CLUSTER_SET(vop2, win, lb_mode, lb_mode); + VOP_CLUSTER_SET(vop2, win, scl_lb_mode, lb_mode == 1 ? 3 : 0); VOP_CLUSTER_SET(vop2, win, enable, 1); } spin_unlock(&vop2->reg_lock); @@ -5916,6 +5923,7 @@ 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; + const struct vop2_data *vop2_data = vop2->data; struct drm_crtc_state *cstate = crtc->state; const struct vop_dump_regs *regs = vop2->data->dump_regs; uint32_t buf[68]; @@ -5923,20 +5931,80 @@ static void vop2_crtc_regs_dump(struct drm_crtc *crtc, struct seq_file *s) unsigned int n, i, j; resource_size_t offset_addr; uint32_t base; + struct drm_crtc *first_active_crtc = NULL; if (!cstate->active) return; - n = vop2->data->dump_regs_size; + /* only need to dump once at first active crtc for vop2 */ + for (i = 0; i < vop2_data->nr_vps; i++) { + if (vop2->vps[i].rockchip_crtc.crtc.state->active) { + first_active_crtc = &vop2->vps[i].rockchip_crtc.crtc; + break; + } + } + if (first_active_crtc != crtc) + return; + n = vop2->data->dump_regs_size; for (i = 0; i < n; i++) { base = regs[i].offset; 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, - len << 2, 0); + DEBUG_PRINT("\n%s:\n", regs[i].name); + for (j = 0; j < len;) { + DEBUG_PRINT("%08x: %08x %08x %08x %08x\n", (u32)offset_addr + j * 4, + vop2_readl(vop2, base + (4 * j)), + vop2_readl(vop2, base + (4 * (j + 1))), + vop2_readl(vop2, base + (4 * (j + 2))), + vop2_readl(vop2, base + (4 * (j + 3)))); + j += 4; + } + } +} + +static void vop2_crtc_active_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; + const struct vop2_data *vop2_data = vop2->data; + struct drm_crtc_state *cstate = crtc->state; + const struct vop_dump_regs *regs = vop2->data->dump_regs; + uint32_t buf[68]; + uint32_t len = ARRAY_SIZE(buf); + unsigned int n, i, j; + resource_size_t offset_addr; + uint32_t base; + struct drm_crtc *first_active_crtc = NULL; + + if (!cstate->active) + return; + + /* only need to dump once at first active crtc for vop2 */ + for (i = 0; i < vop2_data->nr_vps; i++) { + if (vop2->vps[i].rockchip_crtc.crtc.state->active) { + first_active_crtc = &vop2->vps[i].rockchip_crtc.crtc; + break; + } + } + if (first_active_crtc != crtc) + return; + + n = vop2->data->dump_regs_size; + for (i = 0; i < n; i++) { + if (regs[i].state.mask && + REG_GET(vop2, regs[i].state) != regs[i].enable_state) + continue; + base = regs[i].offset; + offset_addr = vop2->res->start + base; + DEBUG_PRINT("\n%s:\n", regs[i].name); + for (j = 0; j < len;) { + DEBUG_PRINT("%08x: %08x %08x %08x %08x\n", (u32)offset_addr + j * 4, + vop2_readl(vop2, base + (4 * j)), + vop2_readl(vop2, base + (4 * (j + 1))), + vop2_readl(vop2, base + (4 * (j + 2))), + vop2_readl(vop2, base + (4 * (j + 3)))); + j += 4; + } } } @@ -6284,6 +6352,7 @@ static const struct rockchip_crtc_funcs private_crtc_funcs = { .debugfs_init = vop2_crtc_debugfs_init, .debugfs_dump = vop2_crtc_debugfs_dump, .regs_dump = vop2_crtc_regs_dump, + .active_regs_dump = vop2_crtc_active_regs_dump, .bandwidth = vop2_crtc_bandwidth, .crtc_close = vop2_crtc_close, .te_handler = vop2_crtc_te_handler, @@ -6375,6 +6444,8 @@ static void vop2_post_config(struct drm_crtc *crtc) to_rockchip_crtc_state(crtc->state); struct vop2_video_port *vp = to_vop2_video_port(crtc); struct vop2 *vop2 = vp->vop2; + const struct vop2_data *vop2_data = vop2->data; + const struct vop2_video_port_data *vp_data = &vop2_data->vp[vp->id]; struct drm_display_mode *mode = &crtc->state->adjusted_mode; u16 vtotal = mode->crtc_vtotal; u16 hdisplay = mode->crtc_hdisplay; @@ -6414,8 +6485,16 @@ static void vop2_post_config(struct drm_crtc *crtc) val = vact_st_f1 << 16 | vact_end_f1; VOP_MODULE_SET(vop2, vp, vpost_st_end_f1, val); } - VOP_MODULE_SET(vop2, vp, post_dsp_out_r2y, - is_yuv_output(vcstate->bus_format)); + + /* + * BCSH[R2Y] -> POST Linebuffer[post scale] -> the background R2Y will be deal by post_dsp_out_r2y + * + * POST Linebuffer[post scale] -> ACM[R2Y] -> the background R2Y will be deal by ACM[R2Y] + */ + if (vp_data->feature & VOP_FEATURE_POST_ACM) + VOP_MODULE_SET(vop2, vp, post_dsp_out_r2y, vcstate->yuv_overlay); + else + VOP_MODULE_SET(vop2, vp, post_dsp_out_r2y, is_yuv_output(vcstate->bus_format)); } /* @@ -7044,6 +7123,107 @@ static void vop2_post_color_swap(struct drm_crtc *crtc) VOP_MODULE_SET(vop2, vp, dsp_data_swap, data_swap); } +/* + * For vop3 video port0, if hdr_vivid is not enable, the pipe delay time as follow: + * win_dly + config_win_dly + layer_mix_dly + sdr2hdr_dly + * hdr_mix_dly = config_bg_dly + * + * if hdr_vivid is enable, the hdr layer's pipe delay time as follow: + * win_dly + config_win_dly +hdrvivid_dly + hdr_mix_dly = config_bg_dly + * + * If hdrvivid and sdr2hdr bot enable, the time arrivr hdr_mix should be the same: + * win_dly + config_win_dly0 + hdrvivid_dly = win_dly + config_win_dly1 + laer_mix_dly + + * sdr2hdr_dly + * + * For vop3 video port1, the pipe delay time as follow: + * win_dly + config_win_dly + layer_mix_dly = config_bg_dly + * + * Here, win_dly, layer_mix_dly, sdr2hdr_dly, hdr_mix_dly, hdrvivid_dly is the hardware + * delay cycles. Config_win_dly and config_bg_dly is the register value that we can config. + * Different hdr vivid mode have different hdrvivid_dly. For sdr2hdr_dly, only sde2hdr + * enable, it will delay, otherwise, the sdr2hdr_dly is 0. + * + * For default, the config_win_dly will be 0, it just user to make the pipe to arrive + * hdr_mix at the same time. + */ +static void vop3_setup_pipe_dly(struct vop2_video_port *vp, const struct vop2_zpos *vop2_zpos) +{ + struct vop2 *vop2 = vp->vop2; + struct drm_crtc *crtc = &vp->rockchip_crtc.crtc; + const struct vop2_zpos *zpos; + struct drm_plane *plane; + struct vop2_plane_state *vpstate; + struct vop2_win *win; + const struct vop2_data *vop2_data = vop2->data; + const struct vop2_video_port_data *vp_data = &vop2_data->vp[vp->id]; + struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode; + u16 hsync_len = adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start; + u16 hdisplay = adjusted_mode->crtc_hdisplay; + int bg_dly = 0x0; + int dly = 0x0; + int hdr_win_dly; + int sdr_win_dly; + int sdr2hdr_dly; + int pre_scan_dly; + int i; + + /** + * config bg dly, select the max delay num of hdrvivid and sdr2hdr module + * as the increase value of bg delay num. If hdrvivid and sdr2hdr is not + * work, the default bg_dly is 0x10. and the default win delay num is 0. + */ + if ((vp->hdr_en || vp->sdr2hdr_en) && + (vp->hdrvivid_mode >= 0 && vp->hdrvivid_mode <= SDR2HLG)) { + /* set sdr2hdr_dly to 0 if sdr2hdr is disable */ + sdr2hdr_dly = vp->sdr2hdr_en ? vp_data->sdr2hdr_dly : 0; + + /* set the max delay pipe's config_win_dly as 0 */ + if (vp_data->hdrvivid_dly[vp->hdrvivid_mode] >= + sdr2hdr_dly + vp_data->layer_mix_dly) { + bg_dly = vp_data->win_dly + vp_data->hdrvivid_dly[vp->hdrvivid_mode] + + vp_data->hdr_mix_dly; + hdr_win_dly = 0; + sdr_win_dly = vp_data->hdrvivid_dly[vp->hdrvivid_mode] - + vp_data->layer_mix_dly - sdr2hdr_dly; + } else { + bg_dly = vp_data->win_dly + vp_data->layer_mix_dly + sdr2hdr_dly + + vp_data->hdr_mix_dly; + hdr_win_dly = sdr2hdr_dly + vp_data->layer_mix_dly - + vp_data->hdrvivid_dly[vp->hdrvivid_mode]; + sdr_win_dly = 0; + } + } else { + bg_dly = vp_data->win_dly + vp_data->layer_mix_dly + vp_data->hdr_mix_dly; + sdr_win_dly = 0; + } + + pre_scan_dly = bg_dly + (hdisplay >> 1) - 1; + pre_scan_dly = (pre_scan_dly << 16) | hsync_len; + VOP_MODULE_SET(vop2, vp, bg_dly, bg_dly); + VOP_MODULE_SET(vop2, vp, pre_scan_htiming, pre_scan_dly); + + /** + * config win dly + */ + if (!vop2_zpos) + return; + + for (i = 0; i < vp->nr_layers; i++) { + zpos = &vop2_zpos[i]; + win = vop2_find_win_by_phys_id(vop2, zpos->win_phys_id); + plane = &win->base; + vpstate = to_vop2_plane_state(plane->state); + + if ((vp->hdr_en || vp->sdr2hdr_en) && + (vp->hdrvivid_mode >= 0 && vp->hdrvivid_mode <= SDR2HLG)) { + dly = vpstate->hdr_in ? hdr_win_dly : sdr_win_dly; + } + if (vop2_cluster_window(win)) + dly |= dly << 8; + + VOP_CTRL_SET(vop2, win_dly[win->phys_id], dly); + } +} + static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) { struct vop2_video_port *vp = to_vop2_video_port(crtc); @@ -7435,6 +7615,15 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state if (vp_data->feature & VOP_FEATURE_OVERSCAN) vop2_post_config(crtc); + /* + * For RK3528, the path of CVBS output is like: + * VOP BT656 ENCODER -> CVBS BT656 DECODER -> CVBS ENCODER -> CVBS VDAC + * The vop2 dclk should be four times crtc_clock for CVBS sampling clock needs. + */ + if (vop2->version == VOP_VERSION_RK3528 && vcstate->output_if & VOP_OUTPUT_IF_BT656) + clk_set_rate(vp->dclk, 4 * adjusted_mode->crtc_clock * 1000); + else + clk_set_rate(vp->dclk, adjusted_mode->crtc_clock * 1000); if (vcstate->dsc_enable) { if (vcstate->output_flags & ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE) { @@ -7454,6 +7643,9 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state */ if (vop2->version == VOP_VERSION_RK3588) VOP_MODULE_SET(vop2, vp, dsp_background, 0x80000000); + if (is_vop3(vop2)) + vop3_setup_pipe_dly(vp, NULL); + vop2_cfg_done(crtc); /* @@ -7498,53 +7690,9 @@ static int vop2_zpos_cmp(const void *a, const void *b) return pa->plane->base.id - pb->plane->base.id; } -static bool vop3_hdr_ext_data_equal(struct drm_crtc_state *old_state, - struct drm_crtc_state *new_state) -{ - struct rockchip_crtc_state *new_vcstate = to_rockchip_crtc_state(new_state); - struct rockchip_crtc_state *old_vcstate = to_rockchip_crtc_state(old_state); - struct drm_property_blob *new_blob = new_vcstate->hdr_ext_data; - struct drm_property_blob *old_blob = old_vcstate->hdr_ext_data; - - if (!old_blob || !new_blob) - return old_blob == new_blob; - - if (old_blob->length != new_blob->length) - return false; - - return !memcmp(old_blob->data, new_blob->data, old_blob->length); -} - static int vop2_crtc_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state) { - struct vop2_video_port *vp = to_vop2_video_port(crtc); - struct vop2_video_port *splice_vp; - struct vop2 *vop2 = vp->vop2; - const struct vop2_data *vop2_data = vop2->data; - const struct vop2_video_port_data *vp_data = &vop2_data->vp[vp->id]; - struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state); - struct rockchip_crtc_state *new_vcstate = to_rockchip_crtc_state(crtc_state); - struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode; - - if (vop2_has_feature(vop2, VOP_FEATURE_SPLICE)) { - if (adjusted_mode->hdisplay > VOP2_MAX_VP_OUTPUT_WIDTH) { - vcstate->splice_mode = true; - splice_vp = &vop2->vps[vp_data->splice_vp_id]; - splice_vp->splice_mode_right = true; - splice_vp->left_vp = vp; - } - } - - if ((vcstate->request_refresh_rate != new_vcstate->request_refresh_rate) || - crtc_state->active_changed || crtc_state->mode_changed) - vp->refresh_rate_change = true; - else - vp->refresh_rate_change = false; - - vp->hdr_ext_data_change = !vop3_hdr_ext_data_equal(crtc->state, crtc_state) | - crtc_state->active_changed; - return 0; } @@ -7559,8 +7707,10 @@ static void vop3_disable_dynamic_hdr(struct vop2_video_port *vp, uint8_t win_phy VOP_MODULE_SET(vop2, vp, hdr10_en, 0); VOP_MODULE_SET(vop2, vp, hdr_vivid_en, 0); VOP_MODULE_SET(vop2, vp, hdr_vivid_bypass_en, 0); + VOP_MODULE_SET(vop2, vp, hdr_lut_update_en, 0); VOP_MODULE_SET(vop2, vp, sdr2hdr_en, 0); VOP_MODULE_SET(vop2, vp, sdr2hdr_path_en, 0); + VOP_MODULE_SET(vop2, vp, sdr2hdr_auto_gating_en, 1); vp->hdr_en = false; vp->hdr_in = false; @@ -7601,13 +7751,19 @@ static void vop3_setup_hdrvivid(struct vop2_video_port *vp, uint8_t win_phys_id) hdr_mode = hdrvivid_data->hdr_mode; - if (hdr_mode > SDR2HLG) { + if (hdr_mode > SDR2HLG && hdr_mode != SDR2HDR10_USERSPACE && + hdr_mode != SDR2HLG_USERSPACE) { DRM_ERROR("Invalid HDR mode:%d, beyond the mode range\n", hdr_mode); return; } - if (hdr_mode <= HDR102SDR && vpstate->eotf != HDMI_EOTF_SMPTE_ST2084 && - vpstate->eotf != HDMI_EOTF_BT_2100_HLG) { + /* adjust userspace hdr mode value to kernel value */ + if (hdr_mode == SDR2HDR10_USERSPACE) + hdr_mode = SDR2HDR10; + if (hdr_mode == SDR2HLG_USERSPACE) + hdr_mode = SDR2HLG; + + if (hdr_mode <= HDR102SDR && vpstate->eotf != HDMI_EOTF_SMPTE_ST2084 && vpstate->eotf != HDMI_EOTF_BT_2100_HLG) { DRM_ERROR("Invalid HDR mode:%d, mismatch plane eotf:%d\n", hdr_mode, vpstate->eotf); return; @@ -7670,6 +7826,7 @@ static void vop3_setup_hdrvivid(struct vop2_video_port *vp, uint8_t win_phys_id) } VOP_MODULE_SET(vop2, vp, sdr2hdr_en, vp->sdr2hdr_en); VOP_MODULE_SET(vop2, vp, sdr2hdr_path_en, vp->sdr2hdr_en); + VOP_MODULE_SET(vop2, vp, sdr2hdr_auto_gating_en, vp->sdr2hdr_en ? 0 : 1); vop2_writel(vop2, RK3528_SDR_CFG_COE0, hdrvivid_data->sdr2hdr_coe0); vop2_writel(vop2, RK3528_SDR_CFG_COE1, hdrvivid_data->sdr2hdr_coe1); @@ -7738,15 +7895,18 @@ static void vop3_setup_dynamic_hdr(struct vop2_video_port *vp, uint8_t win_phys_ return; } - /* If hdr ext data is not change, do nothing here */ - if (!vp->hdr_ext_data_change) - return; - hdr_data = (struct hdr_extend *)vcstate->hdr_ext_data->data; hdr_format = hdr_data->hdr_type; switch (hdr_format) { + case HDR_NONE: + case HDR_HDR10: + case HDR_HLGSTATIC: case HDR_HDRVIVID: + /* + * hdr module support hdr10, hlg, vividhdr + * sdr2hdr module support hdrnone for sdr2hdr + */ vop3_setup_hdrvivid(vp, win_phys_id); break; default: @@ -8689,107 +8849,6 @@ static void vop2_crtc_update_vrr(struct drm_crtc *crtc) rockchip_connector_update_vfp_for_vrr(crtc, adjust_mode, new_vfp); } -/* - * For vop3 video port0, if hdr_vivid is not enable, the pipe delay time as follow: - * win_dly + config_win_dly + layer_mix_dly + sdr2hdr_dly + * hdr_mix_dly = config_bg_dly - * - * if hdr_vivid is enable, the hdr layer's pipe delay time as follow: - * win_dly + config_win_dly +hdrvivid_dly + hdr_mix_dly = config_bg_dly - * - * If hdrvivid and sdr2hdr bot enable, the time arrivr hdr_mix should be the same: - * win_dly + config_win_dly0 + hdrvivid_dly = win_dly + config_win_dly1 + laer_mix_dly + - * sdr2hdr_dly - * - * For vop3 video port1, the pipe delay time as follow: - * win_dly + config_win_dly + layer_mix_dly = config_bg_dly - * - * Here, win_dly, layer_mix_dly, sdr2hdr_dly, hdr_mix_dly, hdrvivid_dly is the hardware - * delay cycles. Config_win_dly and config_bg_dly is the register value that we can config. - * Different hdr vivid mode have different hdrvivid_dly. For sdr2hdr_dly, only sde2hdr - * enable, it will delay, otherwise, the sdr2hdr_dly is 0. - * - * For default, the config_win_dly will be 0, it just user to make the pipe to arrive - * hdr_mix at the same time. - */ -static void vop3_setup_pipe_dly(struct vop2_video_port *vp, const struct vop2_zpos *vop2_zpos) -{ - struct vop2 *vop2 = vp->vop2; - struct drm_crtc *crtc = &vp->rockchip_crtc.crtc; - const struct vop2_zpos *zpos; - struct drm_plane *plane; - struct vop2_plane_state *vpstate; - struct vop2_win *win; - const struct vop2_data *vop2_data = vop2->data; - const struct vop2_video_port_data *vp_data = &vop2_data->vp[vp->id]; - struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode; - u16 hsync_len = adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start; - u16 hdisplay = adjusted_mode->crtc_hdisplay; - int bg_dly = 0x0; - int dly = 0x0; - int hdr_win_dly; - int sdr_win_dly; - int sdr2hdr_dly; - int pre_scan_dly; - int i; - - /** - * config bg dly, select the max delay num of hdrvivid and sdr2hdr module - * as the increase value of bg delay num. If hdrvivid and sdr2hdr is not - * work, the default bg_dly is 0x10. and the default win delay num is 0. - */ - if ((vp->hdr_en || vp->sdr2hdr_en) && - (vp->hdrvivid_mode >= 0 && vp->hdrvivid_mode <= SDR2HLG)) { - /* set sdr2hdr_dly to 0 if sdr2hdr is disable */ - sdr2hdr_dly = vp->sdr2hdr_en ? vp_data->sdr2hdr_dly : 0; - - /* set the max delay pipe's config_win_dly as 0 */ - if (vp_data->hdrvivid_dly[vp->hdrvivid_mode] >= - sdr2hdr_dly + vp_data->layer_mix_dly) { - bg_dly = vp_data->win_dly + vp_data->hdrvivid_dly[vp->hdrvivid_mode] + - vp_data->hdr_mix_dly; - hdr_win_dly = 0; - sdr_win_dly = vp_data->hdrvivid_dly[vp->hdrvivid_mode] - - vp_data->layer_mix_dly - sdr2hdr_dly; - } else { - bg_dly = vp_data->win_dly + vp_data->layer_mix_dly + sdr2hdr_dly + - vp_data->hdr_mix_dly; - hdr_win_dly = sdr2hdr_dly + vp_data->layer_mix_dly - - vp_data->hdrvivid_dly[vp->hdrvivid_mode]; - sdr_win_dly = 0; - } - } else { - bg_dly = vp_data->win_dly + vp_data->layer_mix_dly + vp_data->hdr_mix_dly; - sdr_win_dly = 0; - } - - pre_scan_dly = bg_dly + (hdisplay >> 1) - 1; - pre_scan_dly = (pre_scan_dly << 16) | hsync_len; - VOP_MODULE_SET(vop2, vp, bg_dly, bg_dly); - VOP_MODULE_SET(vop2, vp, pre_scan_htiming, pre_scan_dly); - - /** - * config win dly - */ - if (!vop2_zpos) - return; - - for (i = 0; i < vp->nr_layers; i++) { - zpos = &vop2_zpos[i]; - win = vop2_find_win_by_phys_id(vop2, zpos->win_phys_id); - plane = &win->base; - vpstate = to_vop2_plane_state(plane->state); - - if ((vp->hdr_en || vp->sdr2hdr_en) && - (vp->hdrvivid_mode >= 0 && vp->hdrvivid_mode <= SDR2HLG)) { - dly = vpstate->hdr_in ? hdr_win_dly : sdr_win_dly; - } - if (vop2_cluster_window(win)) - dly |= dly << 8; - - VOP_CTRL_SET(vop2, win_dly[win->phys_id], dly); - } -} - static void vop2_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state) { struct vop2_video_port *vp = to_vop2_video_port(crtc); @@ -8919,7 +8978,8 @@ static void vop2_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_crtc_state } if (is_vop3(vop2)) { - vop3_setup_dynamic_hdr(vp, vop2_zpos[0].win_phys_id); + if (vp_data->feature & VOP_FEATURE_VIVID_HDR) + vop3_setup_dynamic_hdr(vp, vop2_zpos[0].win_phys_id); vop3_setup_alpha(vp, vop2_zpos); vop3_setup_pipe_dly(vp, vop2_zpos); } else { @@ -9143,7 +9203,7 @@ static void vop3_post_csc_config(struct drm_crtc *crtc, struct post_acm *acm, st if (is_yuv_output(vcstate->bus_format)) is_output_yuv = true; - vcstate->post_csc_mode = vop2_convert_csc_mode(vcstate->color_space, CSC_10BIT_DEPTH); + vcstate->post_csc_mode = vop2_convert_csc_mode(vcstate->color_space, CSC_13BIT_DEPTH); if (post_csc_en) { rockchip_calc_post_csc(csc, &csc_coef, vcstate->post_csc_mode, is_input_yuv, @@ -9165,23 +9225,6 @@ static void vop3_post_csc_config(struct drm_crtc *crtc, struct post_acm *acm, st range_type = csc_coef.range_type ? 0 : 1; range_type <<= is_input_yuv ? 0 : 1; VOP_MODULE_SET(vop2, vp, csc_mode, range_type); - - /* rgb input rgb output for csc need rg swap and bg swap */ - if (!is_input_yuv && !is_output_yuv) - VOP_MODULE_SET(vop2, vp, dsp_data_swap, DSP_RG_SWAP | DSP_BG_SWAP); - - /* rgb input yuv output for csc need rg swap */ - if (!is_input_yuv && is_output_yuv) - VOP_MODULE_SET(vop2, vp, dsp_data_swap, DSP_RG_SWAP); - - /* yuv input yuv output for csc need rg swap */ - if (is_input_yuv && is_output_yuv) - VOP_MODULE_SET(vop2, vp, dsp_data_swap, DSP_RG_SWAP); - } else { - if (vop2_output_uv_swap(vcstate->bus_format, vcstate->output_mode)) - VOP_MODULE_SET(vop2, vp, dsp_data_swap, DSP_RB_SWAP); - else - VOP_MODULE_SET(vop2, vp, dsp_data_swap, 0); } VOP_MODULE_SET(vop2, vp, acm_r2y_en, post_r2y_en ? 1 : 0); @@ -9989,6 +10032,16 @@ static irqreturn_t vop2_isr(int irq, void *data) ret = IRQ_HANDLED; } + if (vop2->version == VOP_VERSION_RK3528 && vp->id == 1) { + if (active_irqs & POST_BUF_EMPTY_INTR) + atomic_inc(&vp->post_buf_empty_flag); + + if (active_irqs & FS_FIELD_INTR && + (atomic_read(&vp->post_buf_empty_flag) > 0 || + vp->need_reset_p2i_flag == true)) + queue_work(vop2->workqueue, &vop2->post_buf_empty_work); + } + if (active_irqs & FS_FIELD_INTR) { rockchip_drm_dbg(vop2->dev, VOP_DEBUG_VSYNC, "vsync_vp%d\n", vp->id); vop2_wb_handler(vp); @@ -10083,6 +10136,39 @@ static int vop2_plane_create_feature_property(struct vop2 *vop2, struct vop2_win return 0; } +static bool vop3_ignore_plane(struct vop2 *vop2, struct vop2_win *win) +{ + if (!is_vop3(vop2)) + return false; + + if (vop2->esmart_lb_mode == VOP3_ESMART_8K_MODE && + win->phys_id != ROCKCHIP_VOP2_ESMART0) + return true; + else if (vop2->esmart_lb_mode == VOP3_ESMART_4K_4K_MODE && + (win->phys_id == ROCKCHIP_VOP2_ESMART1 || win->phys_id == ROCKCHIP_VOP2_ESMART3)) + return true; + else if (vop2->esmart_lb_mode == VOP3_ESMART_4K_2K_2K_MODE && + win->phys_id == ROCKCHIP_VOP2_ESMART1) + return true; + else + return false; +} + +static void vop3_init_esmart_scale_engine(struct vop2 *vop2) +{ + u8 scale_engine_num = 0; + struct drm_plane *plane = NULL; + + drm_for_each_plane(plane, vop2->drm_dev) { + struct vop2_win *win = to_vop2_win(plane); + + if (win->parent || vop2_cluster_window(win)) + continue; + + win->scale_engine_num = scale_engine_num++; + } +} + static int vop2_plane_init(struct vop2 *vop2, struct vop2_win *win, unsigned long possible_crtcs) { struct rockchip_drm_private *private = vop2->drm_dev->dev_private; @@ -10107,6 +10193,10 @@ static int vop2_plane_init(struct vop2 *vop2, struct vop2_win *win, unsigned lon return -EACCES; } + /* ignore some plane register according vop3 esmart lb mode */ + if (vop3_ignore_plane(vop2, win)) + return -EACCES; + ret = drm_universal_plane_init(vop2->drm_dev, &win->base, possible_crtcs, &vop2_plane_funcs, win->formats, win->nformats, win->format_modifiers, win->type, win->name); @@ -10182,15 +10272,27 @@ static int vop2_plane_init(struct vop2 *vop2, struct vop2_win *win, unsigned lon return 0; } -static struct drm_plane *vop2_cursor_plane_init(struct vop2_video_port *vp, - unsigned long possible_crtcs) +static struct drm_plane *vop2_cursor_plane_init(struct vop2_video_port *vp) { struct vop2 *vop2 = vp->vop2; struct drm_plane *cursor = NULL; struct vop2_win *win; + unsigned long possible_crtcs = 0; win = vop2_find_win_by_phys_id(vop2, vp->cursor_win_id); if (win) { + if (vop2->disable_win_move) { + const struct vop2_data *vop2_data = vop2->data; + struct drm_crtc *crtc = vop2_find_crtc_by_plane_mask(vop2, win->phys_id); + + if (crtc) + possible_crtcs = drm_crtc_mask(crtc); + else + possible_crtcs = (1 << vop2_data->nr_vps) - 1; + } + + if (win->possible_crtcs) + possible_crtcs = win->possible_crtcs; win->type = DRM_PLANE_TYPE_CURSOR; win->zpos = vop2->registered_num_wins - 1; if (!vop2_plane_init(vop2, win, possible_crtcs)) @@ -10415,7 +10517,7 @@ static int vop2_create_crtc(struct vop2 *vop2) const struct vop2_data *vop2_data = vop2->data; struct drm_device *drm_dev = vop2->drm_dev; struct device *dev = vop2->dev; - struct drm_plane *plane; + struct drm_plane *primary; struct drm_plane *cursor = NULL; struct drm_crtc *crtc; struct device_node *port; @@ -10464,6 +10566,9 @@ static int vop2_create_crtc(struct vop2 *vop2) vp->id = vp_data->id; vp->regs = vp_data->regs; vp->cursor_win_id = -1; + primary = NULL; + cursor = NULL; + if (vop2->disable_win_move) possible_crtcs = BIT(registered_num_crtcs); @@ -10524,6 +10629,7 @@ static int vop2_create_crtc(struct vop2 *vop2) win->type = DRM_PLANE_TYPE_PRIMARY; } } else { + j = 0; while (j < vop2->registered_num_wins) { be_used_for_primary_plane = false; win = &vop2->win[j]; @@ -10565,24 +10671,43 @@ static int vop2_create_crtc(struct vop2 *vop2) DRM_DEV_ERROR(vop2->dev, "failed to init primary plane\n"); break; } - plane = &win->base; + primary = &win->base; } /* some times we want a cursor window for some vp */ + if (vp->cursor_win_id < 0) { + bool be_used_for_cursor_plane = false; + + j = 0; + while (j < vop2->registered_num_wins) { + win = &vop2->win[j++]; + + if (win->parent || (win->feature & WIN_FEATURE_CLUSTER_SUB)) + continue; + + if (win->type != DRM_PLANE_TYPE_CURSOR) + continue; + + for (k = 0; k < vop2_data->nr_vps; k++) { + if (vop2->vps[k].cursor_win_id == win->phys_id) + be_used_for_cursor_plane = true; + } + if (be_used_for_cursor_plane) + continue; + vp->cursor_win_id = win->phys_id; + } + } + if (vp->cursor_win_id >= 0) { - if (win->possible_crtcs) - possible_crtcs = win->possible_crtcs; - cursor = vop2_cursor_plane_init(vp, possible_crtcs); + cursor = vop2_cursor_plane_init(vp); if (!cursor) DRM_WARN("failed to init cursor plane for vp%d\n", vp->id); else DRM_DEV_INFO(vop2->dev, "%s as cursor plane for vp%d\n", cursor->name, vp->id); - } else { - cursor = NULL; } - ret = drm_crtc_init_with_planes(drm_dev, crtc, plane, cursor, &vop2_crtc_funcs, + ret = drm_crtc_init_with_planes(drm_dev, crtc, primary, cursor, &vop2_crtc_funcs, "video_port%d", vp->id); if (ret) { DRM_DEV_ERROR(vop2->dev, "crtc init for video_port%d failed\n", i); @@ -10612,7 +10737,8 @@ static int vop2_create_crtc(struct vop2 *vop2) drm_object_attach_property(&crtc->base, drm_dev->mode_config.tv_bottom_margin_property, 100); } - vop2_crtc_create_plane_mask_property(vop2, crtc, plane_mask); + if (plane_mask) + vop2_crtc_create_plane_mask_property(vop2, crtc, plane_mask); vop2_crtc_create_feature_property(vop2, crtc); vop2_crtc_create_vrr_property(vop2, crtc); @@ -10693,6 +10819,9 @@ static int vop2_create_crtc(struct vop2 *vop2) DRM_WARN("failed to init overlay plane %s\n", win->name); } + if (is_vop3(vop2)) + vop3_init_esmart_scale_engine(vop2); + return registered_num_crtcs; } @@ -10812,7 +10941,6 @@ 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) @@ -10844,6 +10972,7 @@ static int vop2_win_init(struct vop2 *vop2) 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->possible_crtcs = win->possible_crtcs; area->vop2 = vop2; area->win_id = i; @@ -10888,6 +11017,42 @@ static int vop2_win_init(struct vop2 *vop2) } #include "rockchip_vop2_clk.c" +static void post_buf_empty_work_event(struct work_struct *work) +{ + struct vop2 *vop2 = container_of(work, struct vop2, post_buf_empty_work); + struct rockchip_drm_private *private = vop2->drm_dev->dev_private; + struct vop2_video_port *vp = &vop2->vps[1]; + + /* + * For RK3528, VP1 only supports NTSC and PAL mode(both interlace). If + * POST_BUF_EMPTY_INTR comes, it is needed to reset the p2i_en bit, in + * order to update the line parity flag, which ensures the correct order + * of odd and even lines. + */ + if (vop2->version == VOP_VERSION_RK3528) { + if (atomic_read(&vp->post_buf_empty_flag) > 0) { + atomic_set(&vp->post_buf_empty_flag, 0); + + mutex_lock(&private->ovl_lock); + vop2_wait_for_fs_by_done_bit_status(vp); + VOP_MODULE_SET(vop2, vp, p2i_en, 0); + vop2_cfg_done(&vp->rockchip_crtc.crtc); + vop2_wait_for_fs_by_done_bit_status(vp); + mutex_unlock(&private->ovl_lock); + + vp->need_reset_p2i_flag = true; + } else if (vp->need_reset_p2i_flag == true) { + mutex_lock(&private->ovl_lock); + vop2_wait_for_fs_by_done_bit_status(vp); + VOP_MODULE_SET(vop2, vp, p2i_en, 1); + vop2_cfg_done(&vp->rockchip_crtc.crtc); + vop2_wait_for_fs_by_done_bit_status(vp); + mutex_unlock(&private->ovl_lock); + + vp->need_reset_p2i_flag = false; + } + } +} static int vop2_bind(struct device *dev, struct device *master, void *data) { @@ -10933,6 +11098,22 @@ static int vop2_bind(struct device *dev, struct device *master, void *data) ret = vop2_pd_data_init(vop2); if (ret) return ret; + /* + * esmart lb mode default config at vop2_reg.c vop2_data.esmart_lb_mode, + * you can rewrite at dts vop node: + * + * VOP3_ESMART_8K_MODE = 0, + * VOP3_ESMART_4K_4K_MODE = 1, + * VOP3_ESMART_4K_2K_2K_MODE = 2, + * VOP3_ESMART_2K_2K_2K_2K_MODE = 3, + * + * &vop { + * esmart_lb_mode = /bits/ 8 <2>; + * }; + */ + ret = of_property_read_u8(dev->of_node, "esmart_lb_mode", &vop2->esmart_lb_mode); + if (ret < 0) + vop2->esmart_lb_mode = vop2->data->esmart_lb_mode; ret = vop2_win_init(vop2); if (ret) @@ -11045,6 +11226,12 @@ static int vop2_bind(struct device *dev, struct device *master, void *data) spin_lock_init(&vop2->irq_lock); mutex_init(&vop2->vop2_lock); + if (vop2->version == VOP_VERSION_RK3528) { + atomic_set(&vop2->vps[1].post_buf_empty_flag, 0); + vop2->workqueue = create_workqueue("post_buf_empty_wq"); + INIT_WORK(&vop2->post_buf_empty_work, post_buf_empty_work_event); + } + ret = devm_request_irq(dev, vop2->irq, vop2_isr, IRQF_SHARED, dev_name(dev), vop2); if (ret) return ret; diff --git a/drivers/gpu/drm/rockchip/rockchip_post_csc.c b/drivers/gpu/drm/rockchip/rockchip_post_csc.c index a1574a8feeff..7160be22a0cb 100644 --- a/drivers/gpu/drm/rockchip/rockchip_post_csc.c +++ b/drivers/gpu/drm/rockchip/rockchip_post_csc.c @@ -670,7 +670,7 @@ static const struct rk_csc_mode_coef g_mode_csc_coef[] = { &rk_csc_table_rgb_to_xv_yccsdy_cb_cr_full, &rk_dc_csc_table_rgb_to_xv_yccsdy_cb_cr_full, { - OPTM_CS_E_XV_YCC_601, OPTM_CS_E_RGB, true, true + OPTM_CS_E_RGB, OPTM_CS_E_XV_YCC_601, true, true } }, { @@ -782,7 +782,7 @@ static const struct rk_csc_mode_coef g_mode_csc_coef[] = { &rk_csc_table_rgb_limit_to_hdy_cb_cr, &rk_dc_csc_table_rgb_limit_to_hdy_cb_cr, { - OPTM_CS_E_RGB, OPTM_CS_E_XV_YCC_601, false, false + OPTM_CS_E_RGB, OPTM_CS_E_ITU_R_BT_709, false, false } }, { @@ -991,8 +991,8 @@ struct csc_mapping { enum vop_csc_format csc_format; enum color_space_type rgb_color_space; enum color_space_type yuv_color_space; - bool yuv_full_range; bool rgb_full_range; + bool yuv_full_range; }; static const struct csc_mapping csc_mapping_table[] = { @@ -1000,14 +1000,14 @@ static const struct csc_mapping csc_mapping_table[] = { CSC_BT601L, OPTM_CS_E_RGB, OPTM_CS_E_XV_YCC_601, - false, + true, false, }, { CSC_BT709L, OPTM_CS_E_RGB, OPTM_CS_E_XV_YCC_709, - false, + true, false, }, { @@ -1028,7 +1028,7 @@ static const struct csc_mapping csc_mapping_table[] = { CSC_BT709L_13BIT, OPTM_CS_E_RGB, OPTM_CS_E_XV_YCC_709, - false, + true, false, }, { @@ -1042,7 +1042,7 @@ static const struct csc_mapping csc_mapping_table[] = { CSC_BT2020L_13BIT, OPTM_CS_E_RGB_2020, OPTM_CS_E_XV_YCC_2020, - false, + true, false, }, { @@ -1054,6 +1054,30 @@ static const struct csc_mapping csc_mapping_table[] = { }, }; +static const struct rk_pq_csc_coef r2y_for_y2y = { + 306, 601, 117, + -151, -296, 446, + 630, -527, -102, +}; + +static const struct rk_pq_csc_coef y2r_for_y2y = { + 1024, -0, 1167, + 1024, -404, -594, + 1024, 2081, -1, +}; + +static const struct rk_pq_csc_coef rgb_input_swap_matrix = { + 0, 0, 1, + 1, 0, 0, + 0, 1, 0, +}; + +static const struct rk_pq_csc_coef yuv_output_swap_matrix = { + 0, 0, 1, + 1, 0, 0, + 0, 1, 0, +}; + static int csc_get_mode_index(int post_csc_mode, bool is_input_yuv, bool is_output_yuv) { const struct rk_csc_colorspace_info *colorspace_info; @@ -1244,35 +1268,17 @@ static struct rk_pq_csc_coef create_saturation_matrix(s32 saturation) return m; } -static const struct rk_pq_csc_coef r2y_for_y2y = { - 306, 601, 117, - -151, -296, 446, - 630, -527, -102, -}; - -static const struct rk_pq_csc_coef y2r_for_y2y = { - 1024, -0, 1167, - 1024, -404, -594, - 1024, 2081, -1, -}; - -static const struct rk_pq_csc_coef rgb_swap_matrix = { - 0, 0, 1, - 1, 0, 0, - 0, 1, 0, -}; - static int csc_calc_adjust_output_coef(bool is_input_yuv, bool is_output_yuv, struct post_csc *csc_input_cfg, const struct rk_csc_mode_coef *csc_mode_cfg, - struct post_csc_coef *csc_output) + struct rk_pq_csc_coef *out_matrix, + struct rk_pq_csc_ventor *out_dc) { struct rk_pq_csc_coef gain_matrix; struct rk_pq_csc_coef contrast_matrix; struct rk_pq_csc_coef hue_matrix; struct rk_pq_csc_coef saturation_matrix; struct rk_pq_csc_coef temp0, temp1; - struct rk_pq_csc_coef output; const struct rk_pq_csc_coef *r2y_matrix; const struct rk_pq_csc_coef *y2r_matrix; struct rk_pq_csc_ventor dc_in_ventor; @@ -1336,8 +1342,8 @@ static int csc_calc_adjust_output_coef(bool is_input_yuv, bool is_output_yuv, csc_matrix_element_left_shift(&temp1, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH); csc_matrix_multiply(&temp0, &temp1, &contrast_matrix); csc_matrix_element_left_shift(&temp0, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH); - csc_matrix_multiply(&output, &temp0, y2r_matrix); - csc_matrix_element_left_shift(&output, PQ_CSC_PARAM_FIX_BIT_WIDTH + + csc_matrix_multiply(out_matrix, &temp0, y2r_matrix); + csc_matrix_element_left_shift(out_matrix, PQ_CSC_PARAM_FIX_BIT_WIDTH + PQ_CALC_ENHANCE_BIT); dc_in_ventor.csc_offset0 = dc_in_offset; @@ -1359,8 +1365,8 @@ static int csc_calc_adjust_output_coef(bool is_input_yuv, bool is_output_yuv, csc_matrix_element_left_shift(&temp1, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH); csc_matrix_multiply(&temp0, &contrast_matrix, &temp1); csc_matrix_element_left_shift(&temp0, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH); - csc_matrix_multiply(&output, &gain_matrix, &temp0); - csc_matrix_element_left_shift(&output, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH + + csc_matrix_multiply(out_matrix, &gain_matrix, &temp0); + csc_matrix_element_left_shift(out_matrix, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH + PQ_CALC_ENHANCE_BIT); dc_in_ventor.csc_offset0 = dc_in_offset; @@ -1382,14 +1388,9 @@ static int csc_calc_adjust_output_coef(bool is_input_yuv, bool is_output_yuv, csc_matrix_element_left_shift(&temp1, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH); csc_matrix_multiply(&temp0, &saturation_matrix, &temp1); csc_matrix_element_left_shift(&temp0, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH); - csc_matrix_multiply(&temp1, &hue_matrix, &temp0); - csc_matrix_element_left_shift(&temp1, PQ_CSC_PARAM_FIX_BIT_WIDTH + + csc_matrix_multiply(out_matrix, &hue_matrix, &temp0); + csc_matrix_element_left_shift(out_matrix, PQ_CSC_PARAM_FIX_BIT_WIDTH + PQ_CALC_ENHANCE_BIT); - /* - * In rgb2yuv case, the rgb channel need swap, but vop post rgb swap - * function can't config the correct swap, do this work in csc. - */ - csc_matrix_multiply(&output, &temp1, &rgb_swap_matrix); dc_in_ventor.csc_offset0 = dc_in_offset; dc_in_ventor.csc_offset1 = dc_in_offset; @@ -1426,12 +1427,12 @@ static int csc_calc_adjust_output_coef(bool is_input_yuv, bool is_output_yuv, csc_matrix_element_left_shift(&temp0, PQ_CSC_PARAM_FIX_BIT_WIDTH); csc_matrix_multiply(&temp1, &temp0, &saturation_matrix); csc_matrix_element_left_shift(&temp1, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH); - csc_matrix_multiply(&output, &temp1, r2y_matrix); - csc_matrix_element_left_shift(&output, PQ_CSC_PARAM_FIX_BIT_WIDTH + + csc_matrix_multiply(out_matrix, &temp1, r2y_matrix); + csc_matrix_element_left_shift(out_matrix, PQ_CSC_PARAM_FIX_BIT_WIDTH + PQ_CALC_ENHANCE_BIT); if (color_info->in_full_range && color_info->out_full_range) - output.csc_coef00 += 1; + out_matrix->csc_coef00 += 1; dc_in_ventor.csc_offset0 = dc_in_offset; dc_in_ventor.csc_offset1 = dc_in_offset; @@ -1441,29 +1442,20 @@ static int csc_calc_adjust_output_coef(bool is_input_yuv, bool is_output_yuv, dc_out_ventor.csc_offset2 = brightness + dc_out_offset + b_offset; } - csc_output->csc_coef00 = output.csc_coef00; - csc_output->csc_coef01 = output.csc_coef01; - csc_output->csc_coef02 = output.csc_coef02; - csc_output->csc_coef10 = output.csc_coef10; - csc_output->csc_coef11 = output.csc_coef11; - csc_output->csc_coef12 = output.csc_coef12; - csc_output->csc_coef20 = output.csc_coef20; - csc_output->csc_coef21 = output.csc_coef21; - csc_output->csc_coef22 = output.csc_coef22; - - csc_matrix_ventor_multiply(&v, &output, &dc_in_ventor); - csc_output->csc_dc0 = v.csc_offset0 + dc_out_ventor.csc_offset0 * - PQ_CSC_SIMPLE_MAT_PARAM_FIX_NUM; - csc_output->csc_dc1 = v.csc_offset1 + dc_out_ventor.csc_offset1 * - PQ_CSC_SIMPLE_MAT_PARAM_FIX_NUM; - csc_output->csc_dc2 = v.csc_offset2 + dc_out_ventor.csc_offset2 * - PQ_CSC_SIMPLE_MAT_PARAM_FIX_NUM; + csc_matrix_ventor_multiply(&v, out_matrix, &dc_in_ventor); + out_dc->csc_offset0 = v.csc_offset0 + dc_out_ventor.csc_offset0 * + PQ_CSC_SIMPLE_MAT_PARAM_FIX_NUM; + out_dc->csc_offset1 = v.csc_offset1 + dc_out_ventor.csc_offset1 * + PQ_CSC_SIMPLE_MAT_PARAM_FIX_NUM; + out_dc->csc_offset2 = v.csc_offset2 + dc_out_ventor.csc_offset2 * + PQ_CSC_SIMPLE_MAT_PARAM_FIX_NUM; return 0; } static int csc_calc_default_output_coef(const struct rk_csc_mode_coef *csc_mode_cfg, - struct post_csc_coef *csc_output) + struct rk_pq_csc_coef *out_matrix, + struct rk_pq_csc_ventor *out_dc) { const struct rk_pq_csc_coef *csc_coef; const struct rk_pq_csc_dc_coef *csc_dc_coef; @@ -1474,15 +1466,15 @@ static int csc_calc_default_output_coef(const struct rk_csc_mode_coef *csc_mode_ csc_coef = csc_mode_cfg->pst_csc_coef; csc_dc_coef = csc_mode_cfg->pst_csc_dc_coef; - csc_output->csc_coef00 = csc_coef->csc_coef00; - csc_output->csc_coef01 = csc_coef->csc_coef01; - csc_output->csc_coef02 = csc_coef->csc_coef02; - csc_output->csc_coef10 = csc_coef->csc_coef10; - csc_output->csc_coef11 = csc_coef->csc_coef11; - csc_output->csc_coef12 = csc_coef->csc_coef12; - csc_output->csc_coef20 = csc_coef->csc_coef20; - csc_output->csc_coef21 = csc_coef->csc_coef21; - csc_output->csc_coef22 = csc_coef->csc_coef22; + out_matrix->csc_coef00 = csc_coef->csc_coef00; + out_matrix->csc_coef01 = csc_coef->csc_coef01; + out_matrix->csc_coef02 = csc_coef->csc_coef02; + out_matrix->csc_coef10 = csc_coef->csc_coef10; + out_matrix->csc_coef11 = csc_coef->csc_coef11; + out_matrix->csc_coef12 = csc_coef->csc_coef12; + out_matrix->csc_coef20 = csc_coef->csc_coef20; + out_matrix->csc_coef21 = csc_coef->csc_coef21; + out_matrix->csc_coef22 = csc_coef->csc_coef22; dc_in_ventor.csc_offset0 = csc_dc_coef->csc_in_dc0; dc_in_ventor.csc_offset1 = csc_dc_coef->csc_in_dc1; @@ -1492,11 +1484,11 @@ static int csc_calc_default_output_coef(const struct rk_csc_mode_coef *csc_mode_ dc_out_ventor.csc_offset2 = csc_dc_coef->csc_out_dc2; csc_matrix_ventor_multiply(&v, csc_coef, &dc_in_ventor); - csc_output->csc_dc0 = v.csc_offset0 + dc_out_ventor.csc_offset0 * + out_dc->csc_offset0 = v.csc_offset0 + dc_out_ventor.csc_offset0 * PQ_CSC_SIMPLE_MAT_PARAM_FIX_NUM; - csc_output->csc_dc1 = v.csc_offset1 + dc_out_ventor.csc_offset1 * + out_dc->csc_offset1 = v.csc_offset1 + dc_out_ventor.csc_offset1 * PQ_CSC_SIMPLE_MAT_PARAM_FIX_NUM; - csc_output->csc_dc2 = v.csc_offset2 + dc_out_ventor.csc_offset2 * + out_dc->csc_offset2 = v.csc_offset2 + dc_out_ventor.csc_offset2 * PQ_CSC_SIMPLE_MAT_PARAM_FIX_NUM; return 0; @@ -1513,10 +1505,46 @@ static inline s32 pq_csc_simple_round(s32 x, s32 n) return (((x) >= 0) ? value : -value); } +static void rockchip_swap_color_channel(bool is_input_yuv, bool is_output_yuv, + struct post_csc_coef *csc_simple_coef, + struct rk_pq_csc_coef *out_matrix, + struct rk_pq_csc_ventor *out_dc) +{ + struct rk_pq_csc_coef tmp_matrix; + struct rk_pq_csc_ventor tmp_v; + + if (!is_input_yuv) { + memcpy(&tmp_matrix, out_matrix, sizeof(struct rk_pq_csc_coef)); + csc_matrix_multiply(out_matrix, &tmp_matrix, &rgb_input_swap_matrix); + } + + if (is_output_yuv) { + memcpy(&tmp_matrix, out_matrix, sizeof(struct rk_pq_csc_coef)); + memcpy(&tmp_v, out_dc, sizeof(struct rk_pq_csc_ventor)); + csc_matrix_multiply(out_matrix, &yuv_output_swap_matrix, &tmp_matrix); + csc_matrix_ventor_multiply(out_dc, &yuv_output_swap_matrix, &tmp_v); + } + + csc_simple_coef->csc_coef00 = out_matrix->csc_coef00; + csc_simple_coef->csc_coef01 = out_matrix->csc_coef01; + csc_simple_coef->csc_coef02 = out_matrix->csc_coef02; + csc_simple_coef->csc_coef10 = out_matrix->csc_coef10; + csc_simple_coef->csc_coef11 = out_matrix->csc_coef11; + csc_simple_coef->csc_coef12 = out_matrix->csc_coef12; + csc_simple_coef->csc_coef20 = out_matrix->csc_coef20; + csc_simple_coef->csc_coef21 = out_matrix->csc_coef21; + csc_simple_coef->csc_coef22 = out_matrix->csc_coef22; + csc_simple_coef->csc_dc0 = out_dc->csc_offset0; + csc_simple_coef->csc_dc1 = out_dc->csc_offset1; + csc_simple_coef->csc_dc2 = out_dc->csc_offset2; +} + int rockchip_calc_post_csc(struct post_csc *csc_cfg, struct post_csc_coef *csc_simple_coef, int csc_mode, bool is_input_yuv, bool is_output_yuv) { int ret = 0; + struct rk_pq_csc_coef out_matrix; + struct rk_pq_csc_ventor out_dc; const struct rk_csc_mode_coef *csc_mode_cfg; int bit_num = PQ_CSC_SIMPLE_MAT_PARAM_FIX_BIT_WIDTH; @@ -1530,9 +1558,12 @@ int rockchip_calc_post_csc(struct post_csc *csc_cfg, struct post_csc_coef *csc_s if (csc_cfg) ret = csc_calc_adjust_output_coef(is_input_yuv, is_output_yuv, csc_cfg, - csc_mode_cfg, csc_simple_coef); + csc_mode_cfg, &out_matrix, &out_dc); else - ret = csc_calc_default_output_coef(csc_mode_cfg, csc_simple_coef); + ret = csc_calc_default_output_coef(csc_mode_cfg, &out_matrix, &out_dc); + + rockchip_swap_color_channel(is_input_yuv, is_output_yuv, csc_simple_coef, &out_matrix, + &out_dc); csc_simple_coef->csc_dc0 = pq_csc_simple_round(csc_simple_coef->csc_dc0, bit_num); csc_simple_coef->csc_dc1 = pq_csc_simple_round(csc_simple_coef->csc_dc1, bit_num); diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c index d03ebe695481..4e7c273730af 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c @@ -776,7 +776,9 @@ static const struct vop2_video_port_regs rk3528_vop_vp0_regs = { .overlay_mode = VOP_REG(RK3528_OVL_PORT0_CTRL, 0x1, 0), .dsp_background = VOP_REG(RK3568_VP0_DSP_BG, 0xffffffff, 0), .out_mode = VOP_REG(RK3568_VP0_DSP_CTRL, 0xf, 0), + .core_dclk_div = VOP_REG(RK3568_VP0_DSP_CTRL, 0x1, 4), .dclk_div2 = VOP_REG(RK3568_VP0_CLK_CTRL, 0x1, 4), + .dclk_div2_phase_lock = VOP_REG(RK3568_VP0_DUAL_CHANNEL_CTRL, 0x1, 4), .p2i_en = VOP_REG(RK3568_VP0_DSP_CTRL, 0x1, 5), .dsp_filed_pol = VOP_REG(RK3568_VP0_DSP_CTRL, 0x1, 6), .dsp_interlace = VOP_REG(RK3568_VP0_DSP_CTRL, 0x1, 7), @@ -818,6 +820,7 @@ static const struct vop2_video_port_regs rk3528_vop_vp0_regs = { .hdr10_en = VOP_REG(RK3568_OVL_CTRL, 0x1, 4), .sdr2hdr_path_en = VOP_REG(RK3568_OVL_CTRL, 0x1, 5), .sdr2hdr_en = VOP_REG(RK3568_SDR2HDR_CTRL, 0x1, 0), + .sdr2hdr_auto_gating_en = VOP_REG(RK3568_SDR2HDR_CTRL, 0x1, 1), .sdr2hdr_bypass_en = VOP_REG(RK3568_SDR2HDR_CTRL, 0x1, 2), .sdr2hdr_dstmode = VOP_REG(RK3568_SDR2HDR_CTRL, 0x1, 3), .hdr_vivid_en = VOP_REG(RK3528_HDRVIVID_CTRL, 0x1, 0), @@ -928,7 +931,7 @@ static const struct vop2_video_port_data rk3528_vop_video_ports[] = { .soc_id = { 0x3528, 0x3528 }, .lut_dma_rid = 14, .feature = VOP_FEATURE_ALPHA_SCALE | VOP_FEATURE_OVERSCAN | VOP_FEATURE_VIVID_HDR | - VOP_FEATURE_POST_ACM | VOP_FEATURE_POST_CSC, + VOP_FEATURE_POST_ACM | VOP_FEATURE_POST_CSC | VOP_FEATURE_OUTPUT_10BIT, .gamma_lut_len = 1024, .max_output = { 4096, 4096 }, .hdrvivid_dly = {17, 29, 32, 44, 15, 38, 1, 29, 0, 0}, @@ -1738,6 +1741,7 @@ static const struct vop2_cluster_regs rk3528_vop_cluster0 = { .afbc_enable = VOP_REG(RK3568_CLUSTER0_CTRL, 0x1, 1), .enable = VOP_REG(RK3568_CLUSTER0_CTRL, 1, 0), .lb_mode = VOP_REG(RK3568_CLUSTER0_CTRL, 0xf, 4), + .scl_lb_mode = VOP_REG(RK3568_CLUSTER0_CTRL, 0x3, 9), .src_color_ctrl = VOP_REG(RK3528_CLUSTER0_MIX_SRC_COLOR_CTRL, 0xffffffff, 0), .dst_color_ctrl = VOP_REG(RK3528_CLUSTER0_MIX_DST_COLOR_CTRL, 0xffffffff, 0), .src_alpha_ctrl = VOP_REG(RK3528_CLUSTER0_MIX_SRC_ALPHA_CTRL, 0xffffffff, 0), @@ -1810,6 +1814,9 @@ static const struct vop2_scl_regs rk3528_cluster0_win_scl = { .yrgb_ver_scl_mode = VOP_REG(RK3528_CLUSTER0_WIN0_CTRL1, 0x3, 14), .yrgb_hor_scl_mode = VOP_REG(RK3528_CLUSTER0_WIN0_CTRL1, 0x3, 22), + .yrgb_hscl_filter_mode = VOP_REG(RK3528_CLUSTER0_WIN0_CTRL1, 0x3, 12),/* supported from vop3 */ + .yrgb_vscl_filter_mode = VOP_REG(RK3528_CLUSTER0_WIN0_CTRL1, 0x3, 20),/* supported from vop3 */ + .vsd_yrgb_gt2 = VOP_REG(RK3568_CLUSTER0_WIN0_CTRL1, 0x1, 28), .vsd_yrgb_gt4 = VOP_REG(RK3568_CLUSTER0_WIN0_CTRL1, 0x1, 29), .vsd_cbcr_gt2 = VOP_REG(RK3568_CLUSTER0_WIN0_CTRL1, 0x1, 30), @@ -1963,6 +1970,9 @@ static const struct vop2_scl_regs rk3568_area1_scl = { .vsd_yrgb_gt4 = VOP_REG(RK3568_ESMART0_REGION1_CTRL, 0x1, 9), .vsd_cbcr_gt2 = VOP_REG(RK3568_ESMART0_REGION1_CTRL, 0x1, 10), .vsd_cbcr_gt4 = VOP_REG(RK3568_ESMART0_REGION1_CTRL, 0x1, 11), + .xavg_en = VOP_REG(RK3568_ESMART0_REGION1_CTRL, 0x1, 20),/* supported from vop3 */ + .xgt_en = VOP_REG(RK3568_ESMART0_REGION1_CTRL, 0x1, 21), + .xgt_mode = VOP_REG(RK3568_ESMART0_REGION1_CTRL, 0x3, 22), }; static const struct vop2_scl_regs rk3568_area2_scl = { @@ -1983,6 +1993,9 @@ static const struct vop2_scl_regs rk3568_area2_scl = { .vsd_yrgb_gt4 = VOP_REG(RK3568_ESMART0_REGION2_CTRL, 0x1, 9), .vsd_cbcr_gt2 = VOP_REG(RK3568_ESMART0_REGION2_CTRL, 0x1, 10), .vsd_cbcr_gt4 = VOP_REG(RK3568_ESMART0_REGION2_CTRL, 0x1, 11), + .xavg_en = VOP_REG(RK3568_ESMART0_REGION2_CTRL, 0x1, 20),/* supported from vop3 */ + .xgt_en = VOP_REG(RK3568_ESMART0_REGION2_CTRL, 0x1, 21), + .xgt_mode = VOP_REG(RK3568_ESMART0_REGION2_CTRL, 0x3, 22), }; static const struct vop2_scl_regs rk3568_area3_scl = { @@ -2003,6 +2016,9 @@ static const struct vop2_scl_regs rk3568_area3_scl = { .vsd_yrgb_gt4 = VOP_REG(RK3568_ESMART0_REGION3_CTRL, 0x1, 9), .vsd_cbcr_gt2 = VOP_REG(RK3568_ESMART0_REGION3_CTRL, 0x1, 10), .vsd_cbcr_gt4 = VOP_REG(RK3568_ESMART0_REGION3_CTRL, 0x1, 11), + .xavg_en = VOP_REG(RK3568_ESMART0_REGION2_CTRL, 0x1, 20),/* supported from vop3 */ + .xgt_en = VOP_REG(RK3568_ESMART0_REGION2_CTRL, 0x1, 21), + .xgt_mode = VOP_REG(RK3568_ESMART0_REGION2_CTRL, 0x3, 22), }; static const struct vop2_win_regs rk3568_area1_data = { @@ -2244,7 +2260,6 @@ static const struct vop2_win_data rk3528_vop_win_data[] = { .axi_id = 0, .axi_yrgb_id = 0x06, .axi_uv_id = 0x07, - .scale_engine_num = 0, .possible_crtcs = 0x1,/* vp0 only */ .max_upscale_factor = 8, .max_downscale_factor = 8, @@ -2274,7 +2289,6 @@ static const struct vop2_win_data rk3528_vop_win_data[] = { .axi_id = 0, .axi_yrgb_id = 0x08, .axi_uv_id = 0x09, - .scale_engine_num = 1, .possible_crtcs = 0x1,/* vp0 only */ .max_upscale_factor = 8, .max_downscale_factor = 8, @@ -2300,11 +2314,10 @@ static const struct vop2_win_data rk3528_vop_win_data[] = { .regs = &rk3568_esmart_win_data, .area = rk3568_area_data, .area_size = ARRAY_SIZE(rk3568_area_data), - .type = DRM_PLANE_TYPE_OVERLAY, + .type = DRM_PLANE_TYPE_CURSOR, .axi_id = 0, .axi_yrgb_id = 0x0a, .axi_uv_id = 0x0b, - .scale_engine_num = 2, .possible_crtcs = 0x3,/* vp0 or vp1 */ .max_upscale_factor = 8, .max_downscale_factor = 8, @@ -2334,7 +2347,6 @@ static const struct vop2_win_data rk3528_vop_win_data[] = { .axi_id = 0, .axi_yrgb_id = 0x0c, .axi_uv_id = 0x0d, - .scale_engine_num = 3, .possible_crtcs = 0x2,/* vp1 only */ .max_upscale_factor = 8, .max_downscale_factor = 8, @@ -3136,6 +3148,7 @@ static const struct vop2_ctrl rk3528_vop_ctrl = { .if_ctrl_cfg_done_imd = VOP_REG(RK3568_DSP_IF_POL, 0x1, 28), .version = VOP_REG(RK3568_VERSION_INFO, 0xffff, 16), .lut_dma_en = VOP_REG(RK3568_SYS_AXI_LUT_CTRL, 0x1, 0), + .dsp_vs_t_sel = VOP_REG(RK3568_SYS_AXI_LUT_CTRL, 0x1, 16), .rgb_en = VOP_REG(RK3568_DSP_IF_EN, 0x1, 0), .hdmi0_en = VOP_REG(RK3568_DSP_IF_EN, 0x1, 1), .bt656_en = VOP_REG(RK3568_DSP_IF_EN, 0x1, 7), @@ -3324,50 +3337,51 @@ static const struct vop2_ctrl rk3588_vop_ctrl = { }; static const struct vop_dump_regs rk3528_dump_regs[] = { - { RK3568_REG_CFG_DONE, "SYS" }, - { RK3528_OVL_SYS, "OVL_SYS" }, - { RK3528_OVL_PORT0_CTRL, "OVL_VP0" }, - { RK3528_OVL_PORT1_CTRL, "OVL_VP1" }, - { RK3568_VP0_DSP_CTRL, "VP0" }, - { RK3568_VP1_DSP_CTRL, "VP1" }, - { RK3568_CLUSTER0_WIN0_CTRL0, "Cluster0" }, - { RK3568_ESMART0_CTRL0, "Esmart0" }, - { RK3568_ESMART1_CTRL0, "Esmart1" }, - { RK3568_SMART0_CTRL0, "Esmart2" }, - { RK3568_SMART1_CTRL0, "Esmart3" }, + { RK3568_REG_CFG_DONE, "SYS", {0}, 0 }, + { RK3528_OVL_SYS, "OVL_SYS", {0}, 0 }, + { RK3528_OVL_PORT0_CTRL, "OVL_VP0", VOP_REG(RK3568_VP0_DSP_CTRL, 0x1, 31), 0 }, + { RK3528_OVL_PORT1_CTRL, "OVL_VP1", VOP_REG(RK3568_VP1_DSP_CTRL, 0x1, 31), 0 }, + { RK3568_VP0_DSP_CTRL, "VP0", VOP_REG(RK3568_VP0_DSP_CTRL, 0x1, 31), 0 }, + { RK3568_VP1_DSP_CTRL, "VP1", VOP_REG(RK3568_VP1_DSP_CTRL, 0x1, 31), 0 }, + { RK3568_CLUSTER0_WIN0_CTRL0, "Cluster0", VOP_REG(RK3568_CLUSTER0_WIN0_CTRL0, 0x1, 0), 1 }, + { RK3568_ESMART0_CTRL0, "Esmart0", VOP_REG(RK3568_ESMART0_REGION0_CTRL, 0x1, 0), 1 }, + { RK3568_ESMART1_CTRL0, "Esmart1", VOP_REG(RK3568_ESMART1_REGION0_CTRL, 0x1, 0), 1 }, + { RK3568_SMART0_CTRL0, "Esmart2", VOP_REG(RK3568_SMART0_CTRL0, 0x1, 0), 1 }, + { RK3568_SMART1_CTRL0, "Esmart3", VOP_REG(RK3568_SMART1_CTRL0, 0x1, 0), 1 }, + { RK3528_HDR_LUT_CTRL, "HDR", {0}, 0 }, }; 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" }, + { RK3568_REG_CFG_DONE, "SYS", {0}, 0 }, + { RK3568_OVL_CTRL, "OVL", {0}, 0 }, + { RK3568_VP0_DSP_CTRL, "VP0", VOP_REG(RK3568_VP0_DSP_CTRL, 0x1, 31), 0 }, + { RK3568_VP1_DSP_CTRL, "VP1", VOP_REG(RK3568_VP1_DSP_CTRL, 0x1, 31), 0 }, + { RK3568_VP2_DSP_CTRL, "VP2", VOP_REG(RK3568_VP2_DSP_CTRL, 0x1, 31), 0 }, + { RK3568_CLUSTER0_WIN0_CTRL0, "Cluster0", VOP_REG(RK3568_CLUSTER0_WIN0_CTRL0, 0x1, 0), 1 }, + { RK3568_CLUSTER1_WIN0_CTRL0, "Cluster1", VOP_REG(RK3568_CLUSTER1_WIN0_CTRL0, 0x1, 0), 1 }, + { RK3568_ESMART0_CTRL0, "Esmart0", VOP_REG(RK3568_ESMART0_REGION0_CTRL, 0x1, 0), 1 }, + { RK3568_ESMART1_CTRL0, "Esmart1", VOP_REG(RK3568_ESMART1_REGION0_CTRL, 0x1, 0), 1 }, + { RK3568_SMART0_CTRL0, "Smart0", VOP_REG(RK3568_SMART0_REGION0_CTRL, 0x1, 0), 1 }, + { RK3568_SMART1_CTRL0, "Smart1", VOP_REG(RK3568_SMART1_REGION0_CTRL, 0x1, 0), 1 }, + { RK3568_HDR_LUT_CTRL, "HDR", {0}, 0 }, }; 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" }, + { RK3568_REG_CFG_DONE, "SYS", {0}, 0 }, + { RK3568_OVL_CTRL, "OVL", {0}, 0 }, + { RK3568_VP0_DSP_CTRL, "VP0", VOP_REG(RK3568_VP0_DSP_CTRL, 0x1, 31), 0 }, + { RK3568_VP1_DSP_CTRL, "VP1", VOP_REG(RK3568_VP1_DSP_CTRL, 0x1, 31), 0 }, + { RK3568_VP2_DSP_CTRL, "VP2", VOP_REG(RK3568_VP2_DSP_CTRL, 0x1, 31), 0 }, + { RK3588_VP3_DSP_CTRL, "VP3", VOP_REG(RK3588_VP3_DSP_CTRL, 0x1, 31), 0 }, + { RK3568_CLUSTER0_WIN0_CTRL0, "Cluster0", VOP_REG(RK3568_CLUSTER0_WIN0_CTRL0, 0x1, 0), 1 }, + { RK3568_CLUSTER1_WIN0_CTRL0, "Cluster1", VOP_REG(RK3568_CLUSTER1_WIN0_CTRL0, 0x1, 0), 1 }, + { RK3588_CLUSTER2_WIN0_CTRL0, "Cluster2", VOP_REG(RK3588_CLUSTER2_WIN0_CTRL0, 0x1, 0), 1 }, + { RK3588_CLUSTER3_WIN0_CTRL0, "Cluster3", VOP_REG(RK3588_CLUSTER3_WIN0_CTRL0, 0x1, 0), 1 }, + { RK3568_ESMART0_CTRL0, "Esmart0", VOP_REG(RK3568_ESMART0_REGION0_CTRL, 0x1, 0), 1 }, + { RK3568_ESMART1_CTRL0, "Esmart1", VOP_REG(RK3568_ESMART1_REGION0_CTRL, 0x1, 0), 1 }, + { RK3568_SMART0_CTRL0, "Esmart2", VOP_REG(RK3568_SMART0_REGION0_CTRL, 0x1, 0), 1 }, + { RK3568_SMART1_CTRL0, "Esmart3", VOP_REG(RK3568_SMART1_REGION0_CTRL, 0x1, 0), 1 }, + { RK3568_HDR_LUT_CTRL, "HDR", {0}, 0 }, }; static const struct vop2_data rk3528_vop = { @@ -3375,10 +3389,10 @@ static const struct vop2_data rk3528_vop = { .nr_vps = 2, .nr_mixers = 4, .nr_layers = 4, - .nr_gammas = 1, - .esmart_lb_mode = VOP3_ESMART_FOUR_2K_MODE, - .max_input = { 4096, 2304 }, - .max_output = { 4096, 2304 }, + .nr_gammas = 2, + .esmart_lb_mode = VOP3_ESMART_4K_2K_2K_MODE, + .max_input = { 4096, 4096 }, + .max_output = { 4096, 4096 }, .ctrl = &rk3528_vop_ctrl, .axi_intr = rk3528_vop_axi_intr, .nr_axi_intr = ARRAY_SIZE(rk3528_vop_axi_intr),