From 95b6a39dab6d229f7e6e52077d727eceb0c14d3a Mon Sep 17 00:00:00 2001 From: Andy Yan Date: Thu, 9 Sep 2021 15:45:52 +0800 Subject: [PATCH] drm/rockchip: vop2: Add support for rk3588 RK3588 VOP: 4 Video Ports. 4 Cluster Windows. 4 Esmart Windows. Can drive HDMI/eDP/DP/MIPI/BT1120/BT656 interface. Support drive HDMI/DP 8k output in splice mode. Signed-off-by: Andy Yan Change-Id: I37df329fcab729cd7fa1de47c4d5faf232bb265f --- drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 6 + drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 66 +- drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 996 ++++++++++++++++--- drivers/gpu/drm/rockchip/rockchip_vop2_clk.c | 324 ++++++ drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 993 +++++++++++++++++- drivers/gpu/drm/rockchip/rockchip_vop_reg.h | 141 +++ 6 files changed, 2356 insertions(+), 170 deletions(-) create mode 100644 drivers/gpu/drm/rockchip/rockchip_vop2_clk.c diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index 80b59b6df8c3..bb1aa545222f 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -105,6 +105,10 @@ struct rockchip_crtc_state { int output_bpc; int output_flags; bool enable_afbc; + /** + * @splice_mode: enabled when display a hdisplay > 4096 on rk3588 + */ + bool splice_mode; struct drm_tv_connector_state *tv_state; int left_margin; @@ -135,6 +139,8 @@ struct rockchip_crtc_state { u32 background; u32 line_flag; u8 mode_update; + u8 dsc_enable; + unsigned long dsc_clk; struct rockchip_hdr_state hdr; }; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h index 0f83af3e0079..52a0e691a0a6 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h @@ -18,6 +18,9 @@ #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 ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE BIT(0) #define ROCKCHIP_OUTPUT_DUAL_CHANNEL_ODD_EVEN_MODE BIT(1) #define ROCKCHIP_OUTPUT_DATA_SWAP BIT(2) @@ -31,15 +34,20 @@ #define VOP_FEATURE_ALPHA_SCALE BIT(2) #define VOP_FEATURE_ALPHA_HDR10 BIT(3) #define VOP_FEATURE_ALPHA_DOLBY_HDR BIT(4) +/* a feature to splice two windows and two vps to support resolution > 4096 */ +#define VOP_FEATURE_SPLICE BIT(5) #define VOP_FEATURE_OUTPUT_10BIT VOP_FEATURE_OUTPUT_RGB10 + #define WIN_FEATURE_HDR2SDR BIT(0) #define WIN_FEATURE_SDR2HDR BIT(1) #define WIN_FEATURE_PRE_OVERLAY BIT(2) #define WIN_FEATURE_AFBDC BIT(3) #define WIN_FEATURE_CLUSTER_MAIN BIT(4) #define WIN_FEATURE_CLUSTER_SUB BIT(5) +/* Left win in splice mode */ +#define WIN_FEATURE_SPLICE_LEFT BIT(6) /* a mirror win can only get fb address * from source win: * Cluster1---->Cluster0 @@ -640,6 +648,18 @@ struct vop2_video_port_regs { struct vop_reg cubic_lut_en; struct vop_reg cubic_lut_update_en; struct vop_reg cubic_lut_mst; + + /* cru */ + struct vop_reg dclk_core_div; + struct vop_reg dclk_out_div; + struct vop_reg dclk_src_sel; + + struct vop_reg splice_en; +}; + +struct vop2_dsc_regs { + struct vop_reg rst_deassert; + struct vop_reg port_mux; }; struct vop2_wb_regs { @@ -658,9 +678,26 @@ struct vop2_wb_regs { struct vop_reg axi_uv_id; }; +/* + * connector interface(RGB/HDMI/eDP/DP/MIPI) data + */ +struct vop2_connector_if_data { + u32 id; + const char *clk_src_name; + const char *clk_parent_name; + const char *pixclk_name; + const char *dclk_name; + u32 post_proc_div_shift; + u32 if_div_shift; + u32 if_div_yuv420_shift; + u32 bus_div_shift; + u32 pixel_clk_div_shift; +}; + struct vop2_win_data { const char *name; uint8_t phys_id; + uint8_t splice_win_id; uint32_t base; enum drm_plane_type type; @@ -692,6 +729,11 @@ struct vop2_win_data { const uint8_t dly[VOP2_DLY_MODE_MAX]; }; +struct vop2_dsc_data { + char id; + const struct vop2_dsc_regs *regs; +}; + struct vop2_wb_data { uint32_t nformats; const uint32_t *formats; @@ -701,10 +743,12 @@ struct vop2_wb_data { struct vop2_video_port_data { char id; + uint8_t splice_vp_id; uint32_t feature; uint64_t soc_id[VOP2_SOC_VARIANT]; uint16_t gamma_lut_len; uint16_t cubic_lut_len; + unsigned long dclk_max; struct vop_rect max_output; const u8 pre_scan_max_dly[4]; const struct vop_intr *intr; @@ -812,8 +856,9 @@ struct vop2_ctrl { struct vop_reg dp_dclk_pol; struct vop_reg dp_pin_pol; - struct vop_reg win_vp_id[8]; - struct vop_reg win_dly[8]; + /* This will be reference by win_phy_id */ + struct vop_reg win_vp_id[16]; + struct vop_reg win_dly[16]; /* connector mux */ struct vop_reg rgb_mux; @@ -832,6 +877,19 @@ struct vop2_ctrl { struct vop_reg lvds_dual_mode; struct vop_reg lvds_dual_channel_swap; + struct vop_reg hdmi0_dclk_div; + struct vop_reg hdmi0_pixclk_div; + struct vop_reg edp0_dclk_div; + struct vop_reg edp0_pixclk_div; + + struct vop_reg hdmi1_dclk_div; + struct vop_reg hdmi1_pixclk_div; + struct vop_reg edp1_dclk_div; + struct vop_reg edp1_pixclk_div; + + struct vop_reg mipi0_pixclk_div; + struct vop_reg mipi1_pixclk_div; + struct vop_reg cluster0_src_color_ctrl; struct vop_reg cluster0_dst_color_ctrl; struct vop_reg cluster0_src_alpha_ctrl; @@ -859,15 +917,19 @@ struct vop2_ctrl { struct vop2_data { uint32_t version; uint32_t feature; + uint8_t nr_dscs; uint8_t nr_vps; uint8_t nr_mixers; uint8_t nr_layers; uint8_t nr_axi_intr; uint8_t nr_gammas; + uint8_t nr_conns; const struct vop_intr *axi_intr; const struct vop2_ctrl *ctrl; + const struct vop2_dsc_data *dsc; const struct vop2_win_data *win; const struct vop2_video_port_data *vp; + const struct vop2_connector_if_data *conn; const struct vop2_wb_data *wb; const struct vop2_layer_data *layer; const struct vop_csc_table *csc_table; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 651207827a77..3f5265466841 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -137,6 +138,8 @@ #define VOP2_WB_JOB_MAX 2 #define VOP2_SYS_AXI_BUS_NUM 2 +#define VOP2_MAX_VP_OUTPUT_WIDTH 4096 + #define VOP2_COLOR_KEY_NONE (0 << 31) #define VOP2_COLOR_KEY_MASK (1 << 31) @@ -281,6 +284,12 @@ struct vop2_win { * a main window and a sub window. */ bool two_win_mode; + /** + * @splice_mode: splice the right part of a plane + * in splice mode on rk3588. + * + */ + bool splice_mode; /** * @phys_id: physical id for cluster0/1, esmart0/1, smart0/1 @@ -288,6 +297,13 @@ struct vop2_win { * configuration such as OVL_LAYER_SEL/OVL_PORT_SEL. */ uint8_t phys_id; + + /** + * @splice_win_id: physical id of a win which used to splice for + * resolution > 4096 + */ + uint8_t splice_win_id; + /** * @win_id: graphic window id, a cluster maybe split into two * graphics windows. @@ -389,6 +405,11 @@ struct vop2_wb { }; +struct vop2_dsc { + uint8_t id; + const struct vop2_dsc_regs *regs; +}; + enum vop2_wb_format { VOP2_WB_ARGB8888, VOP2_WB_BGR888, @@ -460,6 +481,21 @@ struct vop2_video_port { */ int hdr_en; + /** + * ----------------- + * | | | + * | Left | Right | + * | | | + * | VP0 | VP1 | + * ----------------- + * @splice_mode_right: As right part of the screen in splice mode. + */ + bool splice_mode_right; + /** + * @left_vp: VP as left part of the screen in splice mode. + */ + struct vop2_video_port *left_vp; + /** * @win_mask: Bitmask of wins attached to the video port; */ @@ -542,6 +578,7 @@ struct vop2 { u32 version; struct device *dev; struct drm_device *drm_dev; + struct vop2_dsc dscs[ROCKCHIP_MAX_CRTC]; struct vop2_video_port vps[ROCKCHIP_MAX_CRTC]; struct vop2_wb wb; struct dentry *debugfs; @@ -593,11 +630,26 @@ struct vop2 { struct clk *hclk; struct clk *aclk; + /* list_head of internal clk */ + struct list_head clk_list_head; + struct vop2_layer layers[ROCKCHIP_MAX_LAYER]; /* must put at the end of the struct */ struct vop2_win win[]; }; +struct vop2_clk { + struct vop2 *vop2; + struct list_head list; + unsigned long rate; + struct clk_hw hw; + struct clk_divider div; + int div_val; + u8 parent_index; +}; + +#define to_vop2_clk(_hw) container_of(_hw, struct vop2_clk, hw) + /* * bus-format types. */ @@ -799,6 +851,20 @@ static struct vop2_win *vop2_find_win_by_phys_id(struct vop2 *vop2, uint8_t phys return NULL; } +static const struct vop2_connector_if_data *vop2_find_connector_if_data(struct vop2 *vop2, int id) +{ + const struct vop2_connector_if_data *if_data; + int i; + + for (i = 0; i < vop2->data->nr_conns; i++) { + if_data = &vop2->data->conn[i]; + if (if_data->id == id) + return if_data; + } + + return NULL; +} + static void vop2_load_hdr2sdr_table(struct vop2_video_port *vp) { struct vop2 *vop2 = vp->vop2; @@ -1044,7 +1110,7 @@ static int32_t vop2_pending_done_bits(struct vop2_video_port *vp) return done_bits; } -static inline void vop2_cfg_done(struct drm_crtc *crtc) +static inline void rk3568_vop2_cfg_done(struct drm_crtc *crtc) { struct vop2_video_port *vp = to_vop2_video_port(crtc); struct vop2 *vop2 = vp->vop2; @@ -1091,6 +1157,20 @@ static inline void vop2_cfg_done(struct drm_crtc *crtc) } } +static inline void rk3588_vop2_cfg_done(struct drm_crtc *crtc) +{ + struct vop2_video_port *vp = to_vop2_video_port(crtc); + struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state); + const struct vop2_video_port_data *vp_data = &vp->vop2->data->vp[vp->id]; + struct vop2 *vop2 = vp->vop2; + uint32_t val; + + val = RK3568_VOP2_GLB_CFG_DONE_EN | BIT(vp->id) | (BIT(vp->id) << 16); + if (vcstate->splice_mode) + val |= BIT(vp_data->splice_vp_id) | (BIT(vp_data->splice_vp_id) << 16); + vop2_writel(vop2, 0, val); +} + static inline void vop2_wb_cfg_done(struct vop2_video_port *vp) { struct vop2 *vop2 = vp->vop2; @@ -1108,6 +1188,17 @@ static inline void vop2_wb_cfg_done(struct vop2_video_port *vp) } +static inline void vop2_cfg_done(struct drm_crtc *crtc) +{ + struct vop2_video_port *vp = to_vop2_video_port(crtc); + struct vop2 *vop2 = vp->vop2; + + if (vop2->version == VOP_VERSION_RK3568) + return rk3568_vop2_cfg_done(crtc); + else if (vop2->version == VOP_VERSION_RK3588) + return rk3588_vop2_cfg_done(crtc); +} + static void vop2_win_multi_area_disable(struct vop2_win *parent) { struct vop2 *vop2 = parent->vop2; @@ -1125,6 +1216,7 @@ static void vop2_win_disable(struct vop2_win *win) { struct vop2 *vop2 = win->vop2; + win->splice_mode = false; VOP_WIN_SET(vop2, win, enable, 0); if (win->feature & WIN_FEATURE_CLUSTER_MAIN) { struct vop2_win *sub_win; @@ -1450,6 +1542,11 @@ static inline bool vop2_cluster_window(struct vop2_win *win) return (win->feature & (WIN_FEATURE_CLUSTER_MAIN | WIN_FEATURE_CLUSTER_SUB)); } +static inline bool vop2_has_feature(struct vop2 *vop2, uint64_t feature) +{ + return (vop2->data->feature & feature); +} + static int vop2_afbc_half_block_enable(struct vop2_plane_state *vpstate) { if (vpstate->rotate_270_en || vpstate->rotate_90_en) @@ -1458,7 +1555,11 @@ static int vop2_afbc_half_block_enable(struct vop2_plane_state *vpstate) return 1; } -static uint32_t vop2_afbc_transform_offset(struct vop2_plane_state *vpstate) +/* + * @xoffset: the src x offset of the right win in splice mode, other wise it + * must be zero. + */ +static uint32_t vop2_afbc_transform_offset(struct vop2_plane_state *vpstate, int xoffset) { struct drm_rect *src = &vpstate->src; struct drm_framebuffer *fb = vpstate->base.fb; @@ -1478,6 +1579,7 @@ static uint32_t vop2_afbc_transform_offset(struct vop2_plane_state *vpstate) uint8_t top_crop_line_num = 0; uint8_t bottom_crop_line_num = 0; + act_xoffset += xoffset; /* 16 pixel align */ if (height & 0xf) align16_crop = 16 - (height & 0xf); @@ -2632,13 +2734,30 @@ static void vop2_layer_map_initial(struct vop2 *vop2, uint32_t current_vp_id) } +static void rk3588_vop2_regsbak(struct vop2 *vop2) +{ + uint32_t *base = vop2->regs; + int i = 0; + + vop2_writel(vop2, RK3568_SYS_PD_CTRL, 0); + + /* + * No need to backup DSC/GAMMA_LUT/BPP_LUT/MMU + */ + for (i = 0; i < (RK3588_DSC_8K_PPS0_3 >> 2); i++) + vop2->regsbak[i] = base[i]; +} + static void vop2_initial(struct drm_crtc *crtc) { struct vop2_video_port *vp = to_vop2_video_port(crtc); struct vop2 *vop2 = vp->vop2; + const struct vop2_data *vop2_data = vop2->data; uint32_t current_vp_id = vp->id; struct vop2_wb *wb = &vop2->wb; + struct vop2_dsc *dsc; int ret; + int i; if (vop2->enable_count == 0) { @@ -2657,7 +2776,19 @@ static void vop2_initial(struct drm_crtc *crtc) if (vop2_soc_is_rk3566()) VOP_CTRL_SET(vop2, otp_en, 1); - memcpy(vop2->regsbak, vop2->regs, vop2->len); + /* dsc must deassert rst before its register can accessed */ + for (i = 0; i < vop2_data->nr_dscs; i++) { + dsc = &vop2->dscs[i]; + VOP_MODULE_SET(vop2, dsc, rst_deassert, 1); + } + + /* + * rk3588 don't support access mmio by memcpy + */ + if (vop2->version == VOP_VERSION_RK3588) + rk3588_vop2_regsbak(vop2); + else + memcpy(vop2->regsbak, vop2->regs, vop2->len); VOP_MODULE_SET(vop2, wb, axi_yrgb_id, 0xd); VOP_MODULE_SET(vop2, wb, axi_uv_id, 0xe); @@ -2727,6 +2858,7 @@ static void vop2_crtc_atomic_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) { struct vop2_video_port *vp = to_vop2_video_port(crtc); + struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state); struct vop2 *vop2 = vp->vop2; int ret; @@ -2759,6 +2891,9 @@ static void vop2_crtc_atomic_disable(struct drm_crtc *crtc, vop2_dsp_hold_valid_irq_disable(crtc); vop2_disable(crtc); + + vcstate->splice_mode = false; + vp->splice_mode_right = false; vop2_unlock(vop2); vop2->active_vp_mask &= ~BIT(vp->id); @@ -2773,13 +2908,75 @@ static void vop2_crtc_atomic_disable(struct drm_crtc *crtc, } } +static int vop2_cluter_splice_scale_check(struct vop2_win *win, struct drm_plane_state *pstate, + u16 hdisplay) +{ + struct drm_rect src = drm_plane_state_src(pstate); + struct drm_rect dst = drm_plane_state_dest(pstate); + u16 half_hdisplay = hdisplay >> 1; + + /* scale up is ok */ + if ((drm_rect_width(&src) >> 16) <= drm_rect_width(&dst)) + return 0; + + /* + * Cluster scale down limitation in splice mode: + * If scale down, must display at horizontal center + */ + if ((dst.x1 < half_hdisplay) && (dst.x2 > half_hdisplay)) { + if ((dst.x2 + dst.x1) != hdisplay) { + DRM_ERROR("%s dst(%d %d)must scale down at center in splice mode\n", + win->name, dst.x1, dst.x2); + return -EINVAL; + } + + if (drm_rect_calc_hscale(&src, &dst, 1, FRAC_16_16(6, 5)) < 0) { + DRM_ERROR("%s %d --> %d scale down factor should < 1.2 in splice mode\n", + win->name, drm_rect_width(&src) >> 16, drm_rect_width(&dst)); + return -EINVAL; + } + } + + return 0; +} + +static int vop2_plane_splice_check(struct drm_plane *plane, struct drm_plane_state *pstate, + struct drm_display_mode *mode) +{ + struct vop2_win *win = to_vop2_win(plane); + int ret = 0; + + if (!(win->feature & WIN_FEATURE_SPLICE_LEFT)) { + DRM_ERROR("%s can't be left win in splice mode\n", win->name); + return -EINVAL; + } + + if (win->feature & WIN_FEATURE_CLUSTER_SUB) { + DRM_ERROR("%s can't use two win mode in splice mode\n", win->name); + return -EINVAL; + } + + if ((pstate->rotation & DRM_MODE_ROTATE_270) || (pstate->rotation & DRM_MODE_ROTATE_90)) { + DRM_ERROR("%s can't rotate 270/90 in splice mode\n", win->name); + return -EINVAL; + } + + /* check for cluster splice scale down */ + if (win->feature & WIN_FEATURE_CLUSTER_MAIN) + ret = vop2_cluter_splice_scale_check(win, pstate, mode->hdisplay); + + return ret; +} + static int vop2_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *state) { struct vop2_plane_state *vpstate = to_vop2_plane_state(state); struct vop2_win *win = to_vop2_win(plane); struct drm_framebuffer *fb = state->fb; + struct drm_display_mode *mode; struct drm_crtc *crtc = state->crtc; struct drm_crtc_state *cstate; + struct rockchip_crtc_state *vcstate; struct vop2_video_port *vp; const struct vop2_data *vop2_data; struct drm_rect *dest = &vpstate->dest; @@ -2805,6 +3002,18 @@ static int vop2_plane_atomic_check(struct drm_plane *plane, struct drm_plane_sta if (WARN_ON(!cstate)) return -EINVAL; + mode = &cstate->mode; + vcstate = to_rockchip_crtc_state(cstate); + + if (vop2_has_feature(win->vop2, VOP_FEATURE_SPLICE)) { + if (mode->hdisplay > VOP2_MAX_VP_OUTPUT_WIDTH) { + vcstate->splice_mode = true; + ret = vop2_plane_splice_check(plane, state, mode); + if (ret < 0) + return ret; + } + } + vpstate->xmirror_en = (state->rotation & DRM_MODE_REFLECT_X) ? 1 : 0; vpstate->ymirror_en = (state->rotation & DRM_MODE_REFLECT_Y) ? 1 : 0; vpstate->rotate_270_en = (state->rotation & DRM_MODE_ROTATE_270) ? 1 : 0; @@ -2815,7 +3024,6 @@ static int vop2_plane_atomic_check(struct drm_plane *plane, struct drm_plane_sta return -EINVAL; } - ret = drm_atomic_helper_check_plane_state(state, cstate, min_scale, max_scale, true, true); @@ -2874,13 +3082,20 @@ static int vop2_plane_atomic_check(struct drm_plane *plane, struct drm_plane_sta * This is special feature at rk356x, the cluster layer only can support * afbc format and can't support linear format; */ - if (VOP_MAJOR(vop2_data->version) == 0x40 && VOP_MINOR(vop2_data->version) == 0x15) { + if (vp->vop2->version == VOP_VERSION_RK3568) { if (vop2_cluster_window(win) && !vpstate->afbc_en) { DRM_ERROR("Unsupported linear format at %s\n", win->name); return -EINVAL; } } + if (vp->vop2->version > VOP_VERSION_RK3568) { + if (vop2_cluster_window(win) && !vpstate->afbc_en && fb->format->is_yuv) { + DRM_ERROR("Unsupported linear yuv format at %s\n", win->name); + return -EINVAL; + } + } + /* * Src.x1 can be odd when do clip, but yuv plane start point * need align with 2 pixel. @@ -2929,7 +3144,9 @@ static int vop2_plane_atomic_check(struct drm_plane *plane, struct drm_plane_sta static void vop2_plane_atomic_disable(struct drm_plane *plane, struct drm_plane_state *old_state) { struct vop2_win *win = to_vop2_win(plane); + struct vop2_win *splice_win; struct vop2 *vop2 = win->vop2; + struct rockchip_crtc_state *vcstate; #if defined(CONFIG_ROCKCHIP_DRM_DEBUG) struct vop2_plane_state *vpstate = to_vop2_plane_state(plane->state); #endif @@ -2941,7 +3158,12 @@ static void vop2_plane_atomic_disable(struct drm_plane *plane, struct drm_plane_ spin_lock(&vop2->reg_lock); + vcstate = to_rockchip_crtc_state(old_state->crtc->state); vop2_win_disable(win); + if (vcstate->splice_mode) { + splice_win = vop2_find_win_by_phys_id(vop2, win->splice_win_id); + vop2_win_disable(splice_win); + } #if defined(CONFIG_ROCKCHIP_DRM_DEBUG) kfree(vpstate->planlist); @@ -3005,16 +3227,52 @@ static void vop2_plane_setup_color_key(struct drm_plane *plane) VOP_WIN_SET(vop2, win, color_key, color_key); } -static void vop2_plane_atomic_update(struct drm_plane *plane, struct drm_plane_state *old_state) +static void vop2_calc_drm_rect_for_splice(struct vop2_plane_state *vpstate, + struct drm_rect *left_src, struct drm_rect *left_dst, + struct drm_rect *right_src, struct drm_rect *right_dst) +{ + struct drm_crtc *crtc = vpstate->base.crtc; + struct drm_display_mode *mode = &crtc->state->adjusted_mode; + struct drm_rect *dst = &vpstate->dest; + struct drm_rect *src = &vpstate->src; + u16 half_hdisplay = mode->crtc_hdisplay >> 1; + int hscale = drm_rect_calc_hscale(src, dst, 0, INT_MAX); + int left_src_w, left_dst_w; + + left_dst_w = min_t(u16, half_hdisplay, dst->x2) - dst->x1; + if (left_dst_w < 0) + left_dst_w = 0; + + left_src_w = (left_dst_w * hscale) >> 16; + left_src->x1 = src->x1; + left_src->x2 = src->x1 + (left_src_w << 16); + left_dst->x1 = dst->x1; + left_dst->x2 = dst->x1 + left_dst_w; + right_src->x1 = left_src->x2; + right_src->x2 = src->x2; + right_dst->x1 = left_dst->x2; + right_dst->x2 = dst->x2; + + left_src->y1 = src->y1; + left_src->y2 = src->y2; + left_dst->y1 = dst->y1; + left_dst->y2 = dst->y2; + right_src->y1 = src->y1; + right_src->y2 = src->y2; + right_dst->y1 = dst->y1; + right_dst->y2 = dst->y2; +} + +static void vop2_win_atomic_update(struct vop2_win *win, struct drm_rect *src, struct drm_rect *dst, + struct drm_plane_state *pstate) { - struct drm_plane_state *pstate = plane->state; struct drm_crtc *crtc = pstate->crtc; - struct vop2_win *win = to_vop2_win(plane); struct vop2_video_port *vp = to_vop2_video_port(crtc); struct vop2_plane_state *vpstate = to_vop2_plane_state(pstate); struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode; struct vop2 *vop2 = win->vop2; struct drm_framebuffer *fb = pstate->fb; + struct drm_rect *left_src = &vpstate->src; uint32_t bpp = rockchip_drm_get_bpp(fb->format); uint32_t actual_w, actual_h, dsp_w, dsp_h; uint32_t dsp_stx, dsp_sty; @@ -3023,17 +3281,216 @@ static void vop2_plane_atomic_update(struct drm_plane *plane, struct drm_plane_s uint32_t afbc_format; uint32_t rb_swap; uint32_t uv_swap; - struct drm_rect *src = &vpstate->src; - struct drm_rect *dest = &vpstate->dest; - uint32_t afbc_tile_num; uint32_t afbc_half_block_en; + uint32_t afbc_tile_num; uint32_t lb_mode; uint32_t stride; uint32_t transform_offset; + /* offset of the right window in splice mode */ + uint32_t splice_pixel_offset = 0; + uint32_t splice_yrgb_offset = 0; + uint32_t splice_uv_offset = 0; + uint32_t afbc_xoffset; + uint32_t hsub; + dma_addr_t yrgb_mst; + dma_addr_t uv_mst; + struct drm_format_name_buf format_name; bool dither_up; + actual_w = drm_rect_width(src) >> 16; + actual_h = drm_rect_height(src) >> 16; + + if (!actual_w || !actual_h) { + vop2_win_disable(win); + return; + } + + /* + * This win is for the right part of the plane, + * we need calculate the fb offset for it. + */ + if (win->splice_mode) { + splice_pixel_offset = (src->x1 - left_src->x1) >> 16; + splice_yrgb_offset = splice_pixel_offset * fb->format->cpp[0]; + + if (fb->format->is_yuv && fb->format->num_planes > 1) { + hsub = fb->format->hsub; + splice_uv_offset = splice_pixel_offset * fb->format->cpp[1] / hsub; + } + } + + dsp_w = drm_rect_width(dst); + if (dst->x1 + dsp_w > adjusted_mode->hdisplay) { + DRM_ERROR("vp%d %s dest->x1[%d] + dsp_w[%d] exceed mode hdisplay[%d]\n", + vp->id, win->name, dst->x1, dsp_w, adjusted_mode->hdisplay); + dsp_w = adjusted_mode->hdisplay - dst->x1; + if (dsp_w < 4) + dsp_w = 4; + actual_w = dsp_w * actual_w / drm_rect_width(dst); + } + dsp_h = drm_rect_height(dst); + if (dst->y1 + dsp_h > adjusted_mode->vdisplay) { + DRM_ERROR("vp%d %s dest->y1[%d] + dsp_h[%d] exceed mode vdisplay[%d]\n", + vp->id, win->name, dst->y1, dsp_h, adjusted_mode->vdisplay); + dsp_h = adjusted_mode->vdisplay - dst->y1; + if (dsp_h < 4) + dsp_h = 4; + actual_h = dsp_h * actual_h / drm_rect_height(dst); + } + + /* + * This is workaround solution for IC design: + * esmart can't support scale down when actual_w % 16 == 1. + */ + if (!(win->feature & WIN_FEATURE_AFBDC)) { + if (actual_w > dsp_w && (actual_w & 0xf) == 1) { + DRM_WARN("vp%d %s act_w[%d] MODE 16 == 1\n", vp->id, win->name, actual_w); + actual_w -= 1; + } + } + + if (vpstate->afbc_en && actual_w % 4) { + DRM_ERROR("vp%d %s actual_w[%d] should align as 4 pixel when enable afbc\n", + vp->id, win->name, actual_w); + actual_w = ALIGN_DOWN(actual_w, 4); + } + + act_info = (actual_h - 1) << 16 | ((actual_w - 1) & 0xffff); + dsp_info = (dsp_h - 1) << 16 | ((dsp_w - 1) & 0xffff); + stride = DIV_ROUND_UP(fb->pitches[0], 4); + dsp_stx = dst->x1; + dsp_sty = dst->y1; + dsp_st = dsp_sty << 16 | (dsp_stx & 0xffff); + + format = vop2_convert_format(fb->format->format); + + vop2_setup_csc_mode(vp, vpstate); + + afbc_half_block_en = vop2_afbc_half_block_enable(vpstate); + + spin_lock(&vop2->reg_lock); + DRM_DEV_DEBUG(vop2->dev, "vp%d update %s[%dx%d->%dx%d@%dx%d] fmt[%.4s_%s] addr[%pad]\n", + 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); + + if (vpstate->afbc_en) { + /* the afbc superblock is 16 x 16 */ + afbc_format = vop2_convert_afbc_format(fb->format->format); + /* Enable color transform for YTR */ + if (fb->modifier & AFBC_FORMAT_MOD_YTR) + afbc_format |= (1 << 4); + afbc_tile_num = ALIGN(actual_w, 16) >> 4; + + /* The right win should have a src offset in splice mode */ + afbc_xoffset = (src->x1 >> 16) + splice_pixel_offset; + /* AFBC pic_vir_width is count by pixel, this is different + * with WIN_VIR_STRIDE. + */ + stride = (fb->pitches[0] << 3) / bpp; + if ((stride & 0x3f) && + (vpstate->xmirror_en || vpstate->rotate_90_en || vpstate->rotate_270_en)) + DRM_ERROR("vp%d %s stride[%d] must align as 64 pixel when enable xmirror/rotate_90/rotate_270[0x%x]\n", + vp->id, win->name, stride, pstate->rotation); + + rb_swap = vop2_afbc_rb_swap(fb->format->format); + uv_swap = vop2_afbc_uv_swap(fb->format->format); + vpstate->afbc_half_block_en = afbc_half_block_en; + + transform_offset = vop2_afbc_transform_offset(vpstate, splice_pixel_offset); + VOP_CLUSTER_SET(vop2, win, afbc_enable, 1); + VOP_AFBC_SET(vop2, win, format, afbc_format); + VOP_AFBC_SET(vop2, win, rb_swap, rb_swap); + VOP_AFBC_SET(vop2, win, uv_swap, uv_swap); + VOP_AFBC_SET(vop2, win, auto_gating_en, 0); + VOP_AFBC_SET(vop2, win, block_split_en, 0); + VOP_AFBC_SET(vop2, win, hdr_ptr, vpstate->yrgb_mst); + VOP_AFBC_SET(vop2, win, pic_size, act_info); + VOP_AFBC_SET(vop2, win, transform_offset, transform_offset); + VOP_AFBC_SET(vop2, win, pic_offset, (afbc_xoffset | src->y1)); + VOP_AFBC_SET(vop2, win, dsp_offset, (dst->x1 | (dst->y1 << 16))); + VOP_AFBC_SET(vop2, win, pic_vir_width, stride); + VOP_AFBC_SET(vop2, win, tile_num, afbc_tile_num); + VOP_AFBC_SET(vop2, win, xmirror, vpstate->xmirror_en); + VOP_AFBC_SET(vop2, win, ymirror, vpstate->ymirror_en); + VOP_AFBC_SET(vop2, win, rotate_270, vpstate->rotate_270_en); + VOP_AFBC_SET(vop2, win, rotate_90, vpstate->rotate_90_en); + } else { + VOP_CLUSTER_SET(vop2, win, afbc_enable, 0); + VOP_WIN_SET(vop2, win, ymirror, vpstate->ymirror_en); + VOP_WIN_SET(vop2, win, xmirror, vpstate->xmirror_en); + } + + if (vpstate->rotate_90_en || vpstate->rotate_270_en) { + act_info = swahw32(act_info); + actual_w = drm_rect_height(src) >> 16; + actual_h = drm_rect_width(src) >> 16; + } + + yrgb_mst = vpstate->yrgb_mst + splice_yrgb_offset; + uv_mst = vpstate->uv_mst + splice_uv_offset; + /* rk3588 should set half_blocK_en to 1 in line and tile mode */ + 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); + 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); + } + + vop2_setup_scale(vop2, win, actual_w, actual_h, dsp_w, dsp_h, fb->format->format); + 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); + VOP_WIN_SET(vop2, win, dsp_st, dsp_st); + + VOP_WIN_SET(vop2, win, y2r_en, vpstate->y2r_en); + VOP_WIN_SET(vop2, win, r2y_en, vpstate->r2y_en); + VOP_WIN_SET(vop2, win, csc_mode, vpstate->csc_mode); + + dither_up = vop2_win_dither_up(fb->format->format); + VOP_WIN_SET(vop2, win, dither_up, dither_up); + + VOP_WIN_SET(vop2, win, enable, 1); + 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, enable, 1); + } + spin_unlock(&vop2->reg_lock); +} + +static void vop2_plane_atomic_update(struct drm_plane *plane, struct drm_plane_state *old_state) +{ + struct drm_plane_state *pstate = plane->state; + struct drm_crtc *crtc = pstate->crtc; + struct vop2_win *win = to_vop2_win(plane); + struct vop2_win *splice_win; + struct vop2_video_port *vp = to_vop2_video_port(crtc); + struct vop2_plane_state *vpstate = to_vop2_plane_state(pstate); + struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state); + struct drm_framebuffer *fb = pstate->fb; + struct drm_format_name_buf format_name; + struct vop2 *vop2 = win->vop2; + struct drm_rect wsrc; + struct drm_rect wdst; + /* right part in splice mode */ + struct drm_rect right_wsrc; + struct drm_rect right_wdst; + #if defined(CONFIG_ROCKCHIP_DRM_DEBUG) + struct drm_rect *psrc = &vpstate->src; bool AFBC_flag = false; struct vop_dump_list *planlist; unsigned long num_pages; @@ -3081,151 +3538,25 @@ static void vop2_plane_atomic_update(struct drm_plane *plane, struct drm_plane_s vp->skip_vsync = false; } - actual_w = drm_rect_width(src) >> 16; - actual_h = drm_rect_height(src) >> 16; - dsp_w = drm_rect_width(dest); - if (dest->x1 + dsp_w > adjusted_mode->hdisplay) { - DRM_ERROR("vp%d %s dest->x1[%d] + dsp_w[%d] exceed mode hdisplay[%d]\n", - vp->id, win->name, dest->x1, dsp_w, adjusted_mode->hdisplay); - dsp_w = adjusted_mode->hdisplay - dest->x1; - if (dsp_w < 4) - dsp_w = 4; - actual_w = dsp_w * actual_w / drm_rect_width(dest); - } - dsp_h = drm_rect_height(dest); - if (dest->y1 + dsp_h > adjusted_mode->vdisplay) { - DRM_ERROR("vp%d %s dest->y1[%d] + dsp_h[%d] exceed mode vdisplay[%d]\n", - vp->id, win->name, dest->y1, dsp_h, adjusted_mode->vdisplay); - dsp_h = adjusted_mode->vdisplay - dest->y1; - if (dsp_h < 4) - dsp_h = 4; - actual_h = dsp_h * actual_h / drm_rect_height(dest); - } + if (vcstate->splice_mode) { + DRM_DEV_DEBUG(vop2->dev, "vp%d update %s[%dx%d->%dx%d@%dx%d] fmt[%.4s_%s] addr[%pad]\n", + vp->id, win->name, drm_rect_width(&vpstate->src) >> 16, + drm_rect_height(&vpstate->src) >> 16, + 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); - /* - * This is workaround solution for IC design: - * esmart can't support scale down when actual_w % 16 == 1. - */ - if (!(win->feature & WIN_FEATURE_AFBDC)) { - if (actual_w > dsp_w && (actual_w & 0xf) == 1) { - DRM_WARN("vp%d %s act_w[%d] MODE 16 == 1\n", vp->id, win->name, actual_w); - actual_w -= 1; - } - } - - if (vpstate->afbc_en && actual_w % 4) { - DRM_ERROR("vp%d %s actual_w[%d] should align as 4 pixel when enable afbc\n", - vp->id, win->name, actual_w); - actual_w = ALIGN_DOWN(actual_w, 4); - } - - act_info = (actual_h - 1) << 16 | ((actual_w - 1) & 0xffff); - dsp_info = (dsp_h - 1) << 16 | ((dsp_w - 1) & 0xffff); - stride = DIV_ROUND_UP(fb->pitches[0], 4); - dsp_stx = dest->x1; - dsp_sty = dest->y1; - dsp_st = dsp_sty << 16 | (dsp_stx & 0xffff); - - format = vop2_convert_format(fb->format->format); - - vop2_setup_csc_mode(vp, vpstate); - - afbc_half_block_en = vop2_afbc_half_block_enable(vpstate); - - spin_lock(&vop2->reg_lock); - DRM_DEV_DEBUG(vop2->dev, "vp%d update %s[%dx%d->%dx%d@%dx%d] fmt[%.4s_%s] addr[%pad]\n", - 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); - - if (vpstate->afbc_en) { - /* the afbc superblock is 16 x 16 */ - afbc_format = vop2_convert_afbc_format(fb->format->format); - /* Enable color transform for YTR */ - if (fb->modifier & AFBC_FORMAT_MOD_YTR) - afbc_format |= (1 << 4); - afbc_tile_num = ALIGN(actual_w, 16) >> 4; - /* AFBC pic_vir_width is count by pixel, this is different - * with WIN_VIR_STRIDE. - */ - stride = (fb->pitches[0] << 3) / bpp; - if ((stride & 0x3f) && - (vpstate->xmirror_en || vpstate->rotate_90_en || vpstate->rotate_270_en)) - DRM_ERROR("vp%d %s stride[%d] must align as 64 pixel when enable xmirror/rotate_90/rotate_270[0x%x]\n", - vp->id, win->name, stride, pstate->rotation); - - rb_swap = vop2_afbc_rb_swap(fb->format->format); - uv_swap = vop2_afbc_uv_swap(fb->format->format); - vpstate->afbc_half_block_en = afbc_half_block_en; - transform_offset = vop2_afbc_transform_offset(vpstate); - VOP_CLUSTER_SET(vop2, win, afbc_enable, 1); - VOP_AFBC_SET(vop2, win, format, afbc_format); - VOP_AFBC_SET(vop2, win, rb_swap, rb_swap); - VOP_AFBC_SET(vop2, win, uv_swap, uv_swap); - VOP_AFBC_SET(vop2, win, auto_gating_en, 0); - VOP_AFBC_SET(vop2, win, block_split_en, 0); - VOP_AFBC_SET(vop2, win, hdr_ptr, vpstate->yrgb_mst); - VOP_AFBC_SET(vop2, win, pic_size, act_info); - VOP_AFBC_SET(vop2, win, transform_offset, transform_offset); - VOP_AFBC_SET(vop2, win, pic_offset, ((src->x1 >> 16) | src->y1)); - VOP_AFBC_SET(vop2, win, dsp_offset, (dest->x1 | (dest->y1 << 16))); - VOP_AFBC_SET(vop2, win, pic_vir_width, stride); - VOP_AFBC_SET(vop2, win, tile_num, afbc_tile_num); - VOP_AFBC_SET(vop2, win, xmirror, vpstate->xmirror_en); - VOP_AFBC_SET(vop2, win, ymirror, vpstate->ymirror_en); - VOP_AFBC_SET(vop2, win, rotate_270, vpstate->rotate_270_en); - VOP_AFBC_SET(vop2, win, rotate_90, vpstate->rotate_90_en); + vop2_calc_drm_rect_for_splice(vpstate, &wsrc, &wdst, &right_wsrc, &right_wdst); + splice_win = vop2_find_win_by_phys_id(vop2, win->splice_win_id); + splice_win->splice_mode = true; + vop2_win_atomic_update(splice_win, &right_wsrc, &right_wdst, pstate); } else { - VOP_AFBC_SET(vop2, win, enable, 0); - VOP_WIN_SET(vop2, win, ymirror, vpstate->ymirror_en); - VOP_WIN_SET(vop2, win, xmirror, vpstate->xmirror_en); + memcpy(&wsrc, &vpstate->src, sizeof(struct drm_rect)); + memcpy(&wdst, &vpstate->dest, sizeof(struct drm_rect)); } - if (vpstate->rotate_90_en || vpstate->rotate_270_en) { - act_info = swahw32(act_info); - actual_w = drm_rect_height(src) >> 16; - actual_h = drm_rect_width(src) >> 16; - } - - /* rk3588 should set half_blocK_en to 1 in line and tile mode */ - 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, vpstate->yrgb_mst); - - rb_swap = vop2_win_rb_swap(fb->format->format); - uv_swap = vop2_win_uv_swap(fb->format->format); - 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, vpstate->uv_mst); - } - - vop2_setup_scale(vop2, win, actual_w, actual_h, dsp_w, dsp_h, fb->format->format); - vop2_plane_setup_color_key(plane); - VOP_WIN_SET(vop2, win, act_info, act_info); - VOP_WIN_SET(vop2, win, dsp_info, dsp_info); - VOP_WIN_SET(vop2, win, dsp_st, dsp_st); - - VOP_WIN_SET(vop2, win, y2r_en, vpstate->y2r_en); - VOP_WIN_SET(vop2, win, r2y_en, vpstate->r2y_en); - VOP_WIN_SET(vop2, win, csc_mode, vpstate->csc_mode); - - dither_up = vop2_win_dither_up(fb->format->format); - VOP_WIN_SET(vop2, win, dither_up, dither_up); - - VOP_WIN_SET(vop2, win, enable, 1); - 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, enable, 1); - } - spin_unlock(&vop2->reg_lock); + vop2_win_atomic_update(win, &wsrc, &wdst, pstate); vop2->is_iommu_needed = true; #if defined(CONFIG_ROCKCHIP_DRM_DEBUG) @@ -3242,7 +3573,7 @@ static void vop2_plane_atomic_update(struct drm_plane *plane, struct drm_plane_s planlist->dump_info.pages = pages; planlist->dump_info.offset = vpstate->offset; planlist->dump_info.pitches = fb->pitches[0]; - planlist->dump_info.height = actual_h; + planlist->dump_info.height = drm_rect_height(psrc) >> 16; planlist->dump_info.format = fb->format; list_add_tail(&planlist->entry, &vp->rockchip_crtc.vop_dump_list_head); vpstate->planlist = planlist; @@ -4262,9 +4593,175 @@ static bool vop2_crtc_mode_update(struct drm_crtc *crtc) return false; } +static struct vop2_clk *vop2_clk_get(struct vop2 *vop2, const char *name) +{ + struct vop2_clk *clk, *n; + + if (!name) + return NULL; + + list_for_each_entry_safe(clk, n, &vop2->clk_list_head, list) { + if (!strcmp(clk_hw_get_name(&clk->hw), name)) + return clk; + } + + return NULL; +} + +static int vop2_cru_set_rate(struct vop2_clk *if_pixclk, struct vop2_clk *if_dclk) +{ + int ret = 0; + + if (if_pixclk) { + ret = clk_set_rate(if_pixclk->hw.clk, if_pixclk->rate); + if (ret < 0) { + DRM_DEV_ERROR(if_pixclk->vop2->dev, "set %s to %ld failed: %d\n", + clk_hw_get_name(&if_pixclk->hw), if_pixclk->rate, ret); + return ret; + } + } + + if (if_dclk) { + ret = clk_set_rate(if_dclk->hw.clk, if_dclk->rate); + if (ret < 0) + DRM_DEV_ERROR(if_dclk->vop2->dev, "set %s to %ld failed %d\n", + clk_hw_get_name(&if_dclk->hw), if_dclk->rate, ret); + } + + return ret; +} + +static int vop2_cacl_if_clk(struct drm_crtc *crtc, const struct vop2_connector_if_data *if_data, + struct vop2_clk *if_pixclk, struct vop2_clk *if_dclk) +{ + struct vop2_video_port *vp = to_vop2_video_port(crtc); + struct vop2 *vop2 = vp->vop2; + struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode; + struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state); + unsigned long long v_pixclk = adjusted_mode->crtc_clock * 1000; /* video timing pixclk */ + unsigned long dclk_core_rate, dclk_out_rate; + /*conn_dclk = conn_pixclk or conn_dclk = conn_pixclk / 2 */ + unsigned long hdmi_edp_pixclk, hdmi_edp_dclk, mipi_pixclk; + char dclk_core_div_shift = 2; + char K = 1; + char clk_name[32]; + struct vop2_clk *dclk_core; + int ret; + + dclk_core_div_shift = if_data->post_proc_div_shift; + dclk_core_rate = v_pixclk >> dclk_core_div_shift; + + if (!if_dclk && (vcstate->output_type == DRM_MODE_CONNECTOR_HDMIA || + vcstate->output_type == DRM_MODE_CONNECTOR_eDP)) + return -EINVAL; + + if (vcstate->output_type == DRM_MODE_CONNECTOR_HDMIA) { + if (vcstate->output_mode == ROCKCHIP_OUT_MODE_YUV420) + K = 2; + if (vcstate->dsc_enable) { + hdmi_edp_pixclk = vcstate->dsc_clk << 1; + hdmi_edp_dclk = vcstate->dsc_clk; + } else { + hdmi_edp_pixclk = (dclk_core_rate << 1) / K; + hdmi_edp_dclk = dclk_core_rate / K; + } + + if_pixclk->rate = hdmi_edp_pixclk; + if_dclk->rate = hdmi_edp_dclk; + } else if (vcstate->output_type == DRM_MODE_CONNECTOR_eDP) { + hdmi_edp_pixclk = v_pixclk / K; + hdmi_edp_dclk = v_pixclk / K; + + if_pixclk->rate = hdmi_edp_pixclk; + if_dclk->rate = hdmi_edp_dclk; + } else if (vcstate->output_type == DRM_MODE_CONNECTOR_DisplayPort) { + if (vcstate->output_mode == ROCKCHIP_OUT_MODE_YUV420) + dclk_out_rate = v_pixclk >> 3; + else + dclk_out_rate = v_pixclk >> 2; + if_pixclk->rate = dclk_out_rate; + } else if (vcstate->output_type == DRM_MODE_CONNECTOR_DSI) { + if (vcstate->output_flags & ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE) + K = 2; + if (vcstate->dsc_enable) + mipi_pixclk = vcstate->dsc_clk >> 1; + else + mipi_pixclk = dclk_core_rate / K; + + if_pixclk->rate = mipi_pixclk; + } else if (vcstate->output_type == DRM_MODE_CONNECTOR_DPI) { + if_pixclk->rate = v_pixclk; + } + + /* + * RGB/eDP/HDMI: if_pixclk >= dclk_core + * DP: dp_pixclk = dclk_out <= dclk_core + * DSI: mipi_pixclk <= dclk_out <= dclk_core + * + */ + snprintf(clk_name, sizeof(clk_name), "dclk_core%d", vp->id); + dclk_core = vop2_clk_get(vop2, clk_name); + if (dclk_core_rate > if_pixclk->rate) { + clk_set_rate(dclk_core->hw.clk, dclk_core_rate); + ret = vop2_cru_set_rate(if_pixclk, if_dclk); + + } else { + ret = vop2_cru_set_rate(if_pixclk, if_dclk); + clk_set_rate(dclk_core->hw.clk, dclk_core_rate); + } + + return ret; +} + +static int vop2_calc_cru_cfg(struct drm_crtc *crtc, int conn_id, + struct vop2_clk **if_pixclk, struct vop2_clk **if_dclk) +{ + struct vop2_video_port *vp = to_vop2_video_port(crtc); + struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state); + struct vop2 *vop2 = vp->vop2; + const struct vop2_connector_if_data *if_data; + struct vop2_clk *if_clk_src, *if_clk_parent; + int output_type; + char clk_name[32]; + int ret; + + if (vop2->version < VOP_VERSION_RK3588) + return 0; + + output_type = vcstate->output_type; + + if_data = vop2_find_connector_if_data(vop2, conn_id); + if_clk_src = vop2_clk_get(vop2, if_data->clk_src_name); + snprintf(clk_name, sizeof(clk_name), "%s%d", if_data->clk_parent_name, vp->id); + if_clk_parent = vop2_clk_get(vop2, clk_name); + *if_pixclk = vop2_clk_get(vop2, if_data->pixclk_name); + *if_dclk = vop2_clk_get(vop2, if_data->dclk_name); + if (!(*if_pixclk) || !if_clk_parent) { + DRM_DEV_ERROR(vop2->dev, "failed to get connector interface clk\n"); + return -ENODEV; + } + + ret = clk_set_parent(if_clk_src->hw.clk, if_clk_parent->hw.clk); + if (ret < 0) { + DRM_DEV_ERROR(vop2->dev, "failed to set parent(%s) for %s: %d\n", + __clk_get_name(if_clk_parent->hw.clk), + __clk_get_name(if_clk_src->hw.clk), ret); + return ret; + } + + /* HDMI and eDP use independent if_pixclk and if_dclk, and others if_pixclk = if_dclk */ + if (output_type == DRM_MODE_CONNECTOR_HDMIA || output_type == DRM_MODE_CONNECTOR_eDP) + ret = vop2_cacl_if_clk(crtc, if_data, *if_pixclk, *if_dclk); + else + ret = vop2_cacl_if_clk(crtc, if_data, *if_pixclk, NULL); + + return ret; +} + 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); + 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]; @@ -4287,6 +4784,12 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state bool dclk_inv, yc_swap = false; int act_end; uint32_t val; + char clk_name[32]; + struct vop2_clk *if_pixclk = NULL; + struct vop2_clk *if_dclk = NULL; + struct vop2_clk *dclk, *dclk_out, *dclk_core; + int splice_en = 0; + int ret; vop2->active_vp_mask |= BIT(vp->id); vop2_set_system_status(vop2); @@ -4295,6 +4798,13 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state DRM_DEV_INFO(vop2->dev, "Update mode to %dx%d%s%d, type: %d for vp%d\n", hdisplay, vdisplay, interlaced ? "i" : "p", drm_mode_vrefresh(adjusted_mode), vcstate->output_type, vp->id); + if (vcstate->splice_mode) { + splice_vp = &vop2->vps[vp_data->splice_vp_id]; + splice_vp->splice_mode_right = true; + splice_vp->left_vp = vp; + splice_en = 1; + } + vop2_initial(crtc); vcstate->vdisplay = vdisplay; vcstate->mode_update = vop2_crtc_mode_update(crtc); @@ -4311,12 +4821,20 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state val |= (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) ? 0 : BIT(VSYNC_POSITIVE); if (vcstate->output_if & VOP_OUTPUT_IF_RGB) { + ret = vop2_calc_cru_cfg(crtc, VOP_OUTPUT_IF_RGB, &if_pixclk, &if_dclk); + if (ret < 0) + goto out; + VOP_CTRL_SET(vop2, rgb_en, 1); VOP_CTRL_SET(vop2, rgb_mux, vp_data->id); VOP_GRF_SET(vop2, grf_dclk_inv, dclk_inv); } if (vcstate->output_if & VOP_OUTPUT_IF_BT1120) { + ret = vop2_calc_cru_cfg(crtc, VOP_OUTPUT_IF_RGB, &if_pixclk, &if_dclk); + if (ret < 0) + goto out; + VOP_CTRL_SET(vop2, rgb_en, 1); VOP_CTRL_SET(vop2, bt1120_en, 1); VOP_CTRL_SET(vop2, rgb_mux, vp_data->id); @@ -4326,6 +4844,10 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state } if (vcstate->output_if & VOP_OUTPUT_IF_BT656) { + ret = vop2_calc_cru_cfg(crtc, VOP_OUTPUT_IF_RGB, &if_pixclk, &if_dclk); + if (ret < 0) + goto out; + VOP_CTRL_SET(vop2, bt656_en, 1); VOP_CTRL_SET(vop2, rgb_mux, vp_data->id); VOP_GRF_SET(vop2, grf_bt656_clk_inv, !dclk_inv); @@ -4357,6 +4879,11 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state } if (vcstate->output_if & VOP_OUTPUT_IF_MIPI0) { + ret = vop2_calc_cru_cfg(crtc, VOP_OUTPUT_IF_MIPI0, &if_pixclk, &if_dclk); + if (ret < 0) + goto out; + if (if_pixclk) + VOP_CTRL_SET(vop2, mipi0_pixclk_div, if_pixclk->div_val); VOP_CTRL_SET(vop2, mipi0_en, 1); VOP_CTRL_SET(vop2, mipi0_mux, vp_data->id); VOP_CTRL_SET(vop2, mipi_pin_pol, val); @@ -4364,6 +4891,12 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state } if (vcstate->output_if & VOP_OUTPUT_IF_MIPI1) { + ret = vop2_calc_cru_cfg(crtc, VOP_OUTPUT_IF_MIPI1, &if_pixclk, &if_dclk); + if (ret < 0) + goto out; + if (if_pixclk) + VOP_CTRL_SET(vop2, mipi1_pixclk_div, if_pixclk->div_val); + VOP_CTRL_SET(vop2, mipi1_en, 1); VOP_CTRL_SET(vop2, mipi1_mux, vp_data->id); VOP_CTRL_SET(vop2, mipi_pin_pol, val); @@ -4377,6 +4910,14 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state } if (vcstate->output_if & VOP_OUTPUT_IF_eDP0) { + ret = vop2_calc_cru_cfg(crtc, VOP_OUTPUT_IF_eDP0, &if_pixclk, &if_dclk); + if (ret < 0) + goto out; + if (if_pixclk && if_dclk) { + VOP_CTRL_SET(vop2, edp0_pixclk_div, if_pixclk->div_val); + VOP_CTRL_SET(vop2, edp0_dclk_div, if_dclk->div_val); + } + VOP_CTRL_SET(vop2, edp0_en, 1); VOP_CTRL_SET(vop2, edp0_mux, vp_data->id); VOP_CTRL_SET(vop2, edp_pin_pol, val); @@ -4384,6 +4925,14 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state } if (vcstate->output_if & VOP_OUTPUT_IF_eDP1) { + ret = vop2_calc_cru_cfg(crtc, VOP_OUTPUT_IF_eDP1, &if_pixclk, &if_dclk); + if (ret < 0) + goto out; + if (if_pixclk && if_dclk) { + VOP_CTRL_SET(vop2, edp1_pixclk_div, if_pixclk->div_val); + VOP_CTRL_SET(vop2, edp1_dclk_div, if_dclk->div_val); + } + VOP_CTRL_SET(vop2, edp1_en, 1); VOP_CTRL_SET(vop2, edp1_mux, vp_data->id); VOP_CTRL_SET(vop2, edp_pin_pol, val); @@ -4391,6 +4940,9 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state } if (vcstate->output_if & VOP_OUTPUT_IF_DP0) { + ret = vop2_calc_cru_cfg(crtc, VOP_OUTPUT_IF_DP0, &if_pixclk, &if_dclk); + if (ret < 0) + goto out; VOP_CTRL_SET(vop2, dp0_en, 1); VOP_CTRL_SET(vop2, dp0_mux, vp_data->id); VOP_CTRL_SET(vop2, dp_dclk_pol, 0); @@ -4398,6 +4950,10 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state } if (vcstate->output_if & VOP_OUTPUT_IF_DP1) { + ret = vop2_calc_cru_cfg(crtc, VOP_OUTPUT_IF_DP0, &if_pixclk, &if_dclk); + if (ret < 0) + goto out; + VOP_CTRL_SET(vop2, dp1_en, 1); VOP_CTRL_SET(vop2, dp1_mux, vp_data->id); VOP_CTRL_SET(vop2, dp_dclk_pol, 0); @@ -4405,6 +4961,15 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state } if (vcstate->output_if & VOP_OUTPUT_IF_HDMI0) { + ret = vop2_calc_cru_cfg(crtc, VOP_OUTPUT_IF_HDMI0, &if_pixclk, &if_dclk); + if (ret < 0) + goto out; + if (if_pixclk && if_dclk) { + VOP_CTRL_SET(vop2, hdmi0_pixclk_div, if_pixclk->div_val); + VOP_CTRL_SET(vop2, hdmi0_dclk_div, if_dclk->div_val); + } + + VOP_CTRL_SET(vop2, hdmi0_en, 1); VOP_CTRL_SET(vop2, hdmi0_en, 1); VOP_CTRL_SET(vop2, hdmi0_mux, vp_data->id); VOP_CTRL_SET(vop2, hdmi_pin_pol, val); @@ -4412,6 +4977,15 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state } if (vcstate->output_if & VOP_OUTPUT_IF_HDMI1) { + ret = vop2_calc_cru_cfg(crtc, VOP_OUTPUT_IF_HDMI1, &if_pixclk, &if_dclk); + if (ret < 0) + goto out; + + if (if_pixclk && if_dclk) { + VOP_CTRL_SET(vop2, hdmi1_pixclk_div, if_pixclk->div_val); + VOP_CTRL_SET(vop2, hdmi1_dclk_div, if_dclk->div_val); + } + VOP_CTRL_SET(vop2, hdmi1_en, 1); VOP_CTRL_SET(vop2, hdmi1_mux, vp_data->id); VOP_CTRL_SET(vop2, hdmi_pin_pol, val); @@ -4433,6 +5007,8 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state vop2_dither_setup(crtc); + VOP_MODULE_SET(vop2, vp, splice_en, splice_en); + VOP_MODULE_SET(vop2, vp, htotal_pw, (htotal << 16) | hsync_len); val = hact_st << 16; val |= hact_end; @@ -4478,7 +5054,26 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state VOP_MODULE_SET(vop2, vp, dclk_div2_phase_lock, 0); } - clk_set_rate(vp->dclk, adjusted_mode->crtc_clock * 1000); + snprintf(clk_name, sizeof(clk_name), "dclk_out%d", vp->id); + dclk_out = vop2_clk_get(vop2, clk_name); + snprintf(clk_name, sizeof(clk_name), "dclk_core%d", vp->id); + dclk_core = vop2_clk_get(vop2, clk_name); + if (dclk_out && dclk_core) { + DRM_DEV_INFO(vop2->dev, "%s div: %d %s div: %d\n", + __clk_get_name(dclk_out->hw.clk), dclk_out->div_val, + __clk_get_name(dclk_core->hw.clk), dclk_core->div_val); + VOP_MODULE_SET(vop2, vp, dclk_src_sel, 0); + VOP_MODULE_SET(vop2, vp, dclk_out_div, dclk_out->div_val); + VOP_MODULE_SET(vop2, vp, dclk_core_div, dclk_core->div_val); + } + + snprintf(clk_name, sizeof(clk_name), "dclk%d", vp->id); + dclk = vop2_clk_get(vop2, clk_name); + if (dclk) + clk_set_rate(vp->dclk, dclk->rate); + else + clk_set_rate(vp->dclk, adjusted_mode->crtc_clock * 1000); + vop2_post_config(crtc); @@ -4502,7 +5097,7 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state VOP_MODULE_SET(vop2, vp, standby, 0); drm_crtc_vblank_on(crtc); - +out: vop2_unlock(vop2); } @@ -4553,6 +5148,12 @@ static void vop2_setup_hdr10(struct vop2_video_port *vp, uint8_t win_phys_id) if (!hdr_table) return; + /* + * right vp share the same crtc state in splice mode + */ + if (vp->splice_mode_right) + vcstate = to_rockchip_crtc_state(vp->left_vp->rockchip_crtc.crtc.state); + /* * HDR video plane input */ @@ -5022,6 +5623,7 @@ static void vop2_setup_dly_for_vp(struct vop2_video_port *vp) const struct vop2_data *vop2_data = vop2->data; const struct vop2_video_port_data *vp_data = &vop2_data->vp[vp->id]; struct drm_crtc *crtc = &vp->rockchip_crtc.crtc; + struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state); 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; @@ -5042,9 +5644,19 @@ static void vop2_setup_dly_for_vp(struct vop2_video_port *vp) if (!vp->hdr_in) bg_dly -= vp->bg_ovl_dly; + /* + * right vp share the same crtc state in splice mode + */ + if (vp->splice_mode_right) + vcstate = to_rockchip_crtc_state(vp->left_vp->rockchip_crtc.crtc.state); + + if (vcstate->splice_mode) + pre_scan_dly = bg_dly + (hdisplay >> 2) - 1; + else + pre_scan_dly = bg_dly + (hdisplay >> 1) - 1; - 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); } @@ -5084,9 +5696,12 @@ static void vop2_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_crtc_state { struct vop2_video_port *vp = to_vop2_video_port(crtc); struct vop2 *vop2 = vp->vop2; + 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]; struct drm_plane *plane; struct vop2_plane_state *vpstate; struct vop2_zpos *vop2_zpos; + struct vop2_zpos *vop2_zpos_splice; struct vop2_cluster cluster; uint8_t nr_layers = 0; struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state); @@ -5095,6 +5710,12 @@ static void vop2_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_crtc_state vop2_zpos = kmalloc_array(vop2->data->win_size, sizeof(*vop2_zpos), GFP_KERNEL); if (!vop2_zpos) return; + if (vcstate->splice_mode) { + vop2_zpos_splice = kmalloc_array(vop2->data->win_size, sizeof(*vop2_zpos), + GFP_KERNEL); + if (!vop2_zpos_splice) + goto out; + } /* Process cluster sub windows overlay. */ drm_atomic_crtc_for_each_plane(plane, crtc) { @@ -5118,6 +5739,7 @@ static void vop2_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_crtc_state drm_atomic_crtc_for_each_plane(plane, crtc) { struct vop2_win *win = to_vop2_win(plane); + struct vop2_win *splice_win; struct vop2_video_port *old_vp; uint8_t old_vp_id; @@ -5137,9 +5759,24 @@ static void vop2_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_crtc_state vop2_zpos[nr_layers].win_phys_id = win->phys_id; vop2_zpos[nr_layers].zpos = vpstate->zpos; vop2_zpos[nr_layers].plane = plane; - nr_layers++; + DRM_DEV_DEBUG(vop2->dev, "%s active zpos:%d for vp%d from vp%d\n", win->name, vpstate->zpos, vp->id, old_vp->id); + if (vcstate->splice_mode) { + splice_win = vop2_find_win_by_phys_id(vop2, win->splice_win_id); + old_vp_id = ffs(splice_win->vp_mask); + old_vp_id = (old_vp_id == 0) ? 0 : old_vp_id - 1; + old_vp = &vop2->vps[old_vp_id]; + old_vp->win_mask &= ~BIT(splice_win->phys_id); + splice_vp->win_mask |= BIT(splice_win->phys_id); + splice_win->vp_mask = BIT(splice_vp->id); + vop2_zpos_splice[nr_layers].win_phys_id = splice_win->phys_id; + vop2_zpos_splice[nr_layers].zpos = vpstate->zpos; + vop2_zpos_splice[nr_layers].plane = &splice_win->base; + DRM_DEV_DEBUG(vop2->dev, "%s active zpos:%d for vp%d from vp%d\n", + splice_win->name, vpstate->zpos, splice_vp->id, old_vp->id); + } + nr_layers++; } DRM_DEV_DEBUG(vop2->dev, "vp%d: %d windows, active layers %d\n", @@ -5154,11 +5791,26 @@ static void vop2_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_crtc_state vop2_setup_alpha(vp, vop2_zpos); vop2_setup_dly_for_vp(vp); vop2_setup_dly_for_window(vp, vop2_zpos); + if (vcstate->splice_mode) { + splice_vp->nr_layers = nr_layers; + + sort(vop2_zpos_splice, nr_layers, sizeof(vop2_zpos_splice[0]), + vop2_zpos_cmp, NULL); + + vop2_setup_layer_mixer_for_vp(splice_vp, vop2_zpos_splice); + vop2_setup_hdr10(splice_vp, vop2_zpos_splice[0].win_phys_id); + vop2_setup_alpha(splice_vp, vop2_zpos_splice); + vop2_setup_dly_for_vp(splice_vp); + vop2_setup_dly_for_window(splice_vp, vop2_zpos_splice); + + } + } /* The pre alpha overlay of Cluster still need process in one win mode. */ drm_atomic_crtc_for_each_plane(plane, crtc) { struct vop2_win *win = to_vop2_win(plane); + struct vop2_win *splice_win; if (!(win->feature & WIN_FEATURE_CLUSTER_MAIN)) continue; @@ -5167,8 +5819,16 @@ static void vop2_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_crtc_state cluster.main = win; cluster.sub = NULL; vop2_setup_cluster_alpha(vop2, &cluster); + if (vcstate->splice_mode) { + splice_win = vop2_find_win_by_phys_id(vop2, win->splice_win_id); + cluster.main = splice_win; + vop2_setup_cluster_alpha(vop2, &cluster); + } } + if (vcstate->splice_mode) + kfree(vop2_zpos_splice); +out: kfree(vop2_zpos); } @@ -6383,6 +7043,21 @@ static void vop2_destroy_crtc(struct drm_crtc *crtc) drm_flip_work_cleanup(&vp->fb_unref_work); } +static void vop2_dsc_data_init(struct vop2 *vop2) +{ + const struct vop2_data *vop2_data = vop2->data; + const struct vop2_dsc_data *dsc_data; + struct vop2_dsc *dsc; + int i; + + for (i = 0; i < vop2_data->nr_dscs; i++) { + dsc = &vop2->dscs[i]; + dsc_data = &vop2_data->dsc[i]; + dsc->id = dsc_data->id; + dsc->regs = dsc_data->regs; + } +} + static int vop2_win_init(struct vop2 *vop2) { const struct vop2_data *vop2_data = vop2->data; @@ -6416,6 +7091,7 @@ static int vop2_win_init(struct vop2 *vop2) win->dly = win_data->dly; win->feature = win_data->feature; win->phys_id = win_data->phys_id; + win->splice_win_id = win_data->splice_win_id; win->layer_sel_id = win_data->layer_sel_id; win->win_id = i; win->plane_id = plane_id++; @@ -6489,6 +7165,8 @@ static int vop2_win_init(struct vop2 *vop2) return 0; } +#include "rockchip_vop2_clk.c" + static int vop2_bind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); @@ -6605,12 +7283,16 @@ static int vop2_bind(struct device *dev, struct device *master, void *data) if (ret) return ret; + vop2_dsc_data_init(vop2); + registered_num_crtcs = vop2_create_crtc(vop2); if (registered_num_crtcs <= 0) return -ENODEV; + ret = vop2_gamma_init(vop2); if (ret) return ret; + vop2_clk_init(vop2); vop2_cubic_lut_init(vop2); vop2_wb_connector_init(vop2, registered_num_crtcs); pm_runtime_enable(&pdev->dev); diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_clk.c b/drivers/gpu/drm/rockchip/rockchip_vop2_clk.c new file mode 100644 index 000000000000..e055f115e4ba --- /dev/null +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_clk.c @@ -0,0 +1,324 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 Rockchip Electronics Co. Ltd. + * Author: Elaine Zhang + */ +#include +#include +#include + +static int cru_debug; + +#define cru_dbg(format, ...) do { \ + if (cru_debug) \ + pr_info("%s: " format, __func__, ## __VA_ARGS__); \ + } while (0) + +#define PNAME(x) static const char *const x[] + +enum vop_clk_branch_type { + branch_mux, + branch_divider, + branch_factor, + branch_virtual, +}; + +#define VIR(cname) \ + { \ + .branch_type = branch_virtual, \ + .name = cname, \ + } + + +#define MUX(cname, pnames, f) \ + { \ + .branch_type = branch_mux, \ + .name = cname, \ + .parent_names = pnames, \ + .num_parents = ARRAY_SIZE(pnames), \ + .flags = f, \ + } + +#define FACTOR(cname, pname, f) \ + { \ + .branch_type = branch_factor, \ + .name = cname, \ + .parent_names = (const char *[]){ pname }, \ + .num_parents = 1, \ + .flags = f, \ + } + +#define DIV(cname, pname, f, w) \ + { \ + .branch_type = branch_divider, \ + .name = cname, \ + .parent_names = (const char *[]){ pname }, \ + .num_parents = 1, \ + .flags = f, \ + .div_width = w, \ + } + +struct vop2_clk_branch { + enum vop_clk_branch_type branch_type; + const char *name; + const char *const *parent_names; + u8 num_parents; + unsigned long flags; + u8 div_shift; + u8 div_width; + u8 div_flags; +}; + +PNAME(mux_port0_dclk_src_p) = { "dclk0", "dclk1" }; +PNAME(mux_port2_dclk_src_p) = { "dclk2", "dclk1" }; +PNAME(mux_dp_pixclk_p) = { "dclk_out0", "dclk_out1", "dclk_out2" }; +PNAME(mux_hdmi_edp_clk_src_p) = { "dclk0", "dclk1", "dclk2" }; +PNAME(mux_mipi_clk_src_p) = { "dclk_out2", "dclk_out3" }; +PNAME(mux_dsc_8k_clk_src_p) = { "dclk0", "dclk1", "dclk2", "dclk3" }; +PNAME(mux_dsc_4k_clk_src_p) = { "dclk0", "dclk1", "dclk2", "dclk3" }; + +/* + * We only use this clk driver calculate the div + * of dclk_core/dclk_out/if_pixclk/if_dclk and + * the rate of the dclk from the soc. + * + * We don't touch the cru in the vop here, as + * these registers has special read andy write + * limits. + */ +static struct vop2_clk_branch rk3588_vop_clk_branches[] = { + VIR("dclk0"), + VIR("dclk1"), + VIR("dclk2"), + VIR("dclk3"), + + MUX("port0_dclk_src", mux_port0_dclk_src_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT), + DIV("dclk_core0", "port0_dclk_src", CLK_SET_RATE_PARENT, 2), + DIV("dclk_out0", "port0_dclk_src", CLK_SET_RATE_PARENT, 2), + + FACTOR("port1_dclk_src", "dclk1", CLK_SET_RATE_PARENT), + DIV("dclk_core1", "port1_dclk_src", CLK_SET_RATE_PARENT, 2), + DIV("dclk_out1", "port1_dclk_src", CLK_SET_RATE_PARENT, 2), + + MUX("port2_dclk_src", mux_port2_dclk_src_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT), + DIV("dclk_core2", "port2_dclk_src", CLK_SET_RATE_PARENT, 2), + DIV("dclk_out2", "port2_dclk_src", CLK_SET_RATE_PARENT, 2), + + FACTOR("port3_dclk_src", "dclk3", CLK_SET_RATE_PARENT), + DIV("dclk_core3", "port3_dclk_src", CLK_SET_RATE_PARENT, 2), + DIV("dclk_out3", "port3_dclk_src", CLK_SET_RATE_PARENT, 2), + + MUX("dp0_pixclk", mux_dp_pixclk_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT), + MUX("dp1_pixclk", mux_dp_pixclk_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT), + + MUX("hdmi_edp0_clk_src", mux_hdmi_edp_clk_src_p, + CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT), + DIV("hdmi_edp0_dclk", "hdmi_edp0_clk_src", 0, 2), + DIV("hdmi_edp0_pixclk", "hdmi_edp0_clk_src", CLK_SET_RATE_PARENT, 1), + + MUX("hdmi_edp1_clk_src", mux_hdmi_edp_clk_src_p, + CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT), + DIV("hdmi_edp1_dclk", "hdmi_edp1_clk_src", 0, 2), + DIV("hdmi_edp1_pixclk", "hdmi_edp1_clk_src", CLK_SET_RATE_PARENT, 2), + + MUX("mipi0_clk_src", mux_mipi_clk_src_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT), + DIV("mipi0_pixclk", "mipi0_clk_src", CLK_SET_RATE_PARENT, 2), + + MUX("mipi1_clk_src", mux_mipi_clk_src_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT), + DIV("mipi1_pixclk", "mipi1_clk_src", CLK_SET_RATE_PARENT, 2), + + FACTOR("rgb_pixclk", "port3_dclk_src", CLK_SET_RATE_PARENT), + + MUX("dsc_8k_clk_src", mux_dsc_8k_clk_src_p, CLK_SET_RATE_NO_REPARENT), + DIV("dsc_8k_pixclk", "dsc_8k_clk_src", 0, 2), + DIV("dsc_8k_cds_clk", "dsc_8k_pixclk", 0, 2), + DIV("dsc_8k_slice_clk", "dsc_8k_pixclk", 0, 2), + + MUX("dsc_4k_clk_src", mux_dsc_4k_clk_src_p, CLK_SET_RATE_NO_REPARENT), + DIV("dsc_4k_pixclk", "dsc_4k_clk_src", 0, 2), + DIV("dsc_4k_cds_clk", "dsc_4k_pixclk", 0, 2), + DIV("dsc_4k_slice_clk", "dsc_4k_pixclk", 0, 2), +}; + +static unsigned long clk_virtual_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct vop2_clk *vop2_clk = to_vop2_clk(hw); + + return (unsigned long)vop2_clk->rate; +} + +static long clk_virtual_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct vop2_clk *vop2_clk = to_vop2_clk(hw); + + vop2_clk->rate = rate; + + return rate; +} + +static int clk_virtual_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + return 0; +} + +const struct clk_ops clk_virtual_ops = { + .round_rate = clk_virtual_round_rate, + .set_rate = clk_virtual_set_rate, + .recalc_rate = clk_virtual_recalc_rate, +}; + +static u8 vop2_mux_get_parent(struct clk_hw *hw) +{ + struct vop2_clk *vop2_clk = to_vop2_clk(hw); + + cru_dbg("%s index: %d\n", clk_hw_get_name(hw), vop2_clk->parent_index); + return vop2_clk->parent_index; +} + +static int vop2_mux_set_parent(struct clk_hw *hw, u8 index) +{ + struct vop2_clk *vop2_clk = to_vop2_clk(hw); + + vop2_clk->parent_index = index; + + cru_dbg("%s index: %d\n", clk_hw_get_name(hw), index); + return 0; +} + +static int vop2_clk_mux_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + cru_dbg("%s %ld(min: %ld max: %ld)\n", + clk_hw_get_name(hw), req->rate, req->min_rate, req->max_rate); + return __clk_mux_determine_rate(hw, req); +} + +static const struct clk_ops vop2_mux_clk_ops = { + .get_parent = vop2_mux_get_parent, + .set_parent = vop2_mux_set_parent, + .determine_rate = vop2_clk_mux_determine_rate, +}; + +#define div_mask(width) ((1 << (width)) - 1) + +static int vop2_div_get_val(unsigned long rate, unsigned long parent_rate) +{ + unsigned int div, value; + + div = DIV_ROUND_UP_ULL((u64)parent_rate, rate); + + value = ilog2(div); + + return value; +} + +static unsigned long vop2_clk_div_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct vop2_clk *vop2_clk = to_vop2_clk(hw); + unsigned long rate; + unsigned int div; + + div = 1 << vop2_clk->div_val; + rate = parent_rate / div; + + cru_dbg("%s rate: %ld(prate: %ld)\n", clk_hw_get_name(hw), rate, parent_rate); + + return rate; +} + +static long vop2_clk_div_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) { + if (*prate < rate) + *prate = rate; + } + + cru_dbg("%s rate: %ld(prate: %ld)\n", clk_hw_get_name(hw), rate, *prate); + + return rate; +} + +static int vop2_clk_div_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) +{ + struct vop2_clk *vop2_clk = to_vop2_clk(hw); + int div_val; + + div_val = vop2_div_get_val(rate, parent_rate); + vop2_clk->div_val = div_val; + + cru_dbg("%s prate: %ld rate: %ld div_val: %d\n", + clk_hw_get_name(hw), parent_rate, rate, div_val); + + return 0; +} + +static const struct clk_ops vop2_div_clk_ops = { + .recalc_rate = vop2_clk_div_recalc_rate, + .round_rate = vop2_clk_div_round_rate, + .set_rate = vop2_clk_div_set_rate, +}; + +static struct clk *vop2_clk_register(struct vop2 *vop2, struct vop2_clk_branch *branch) +{ + struct clk_init_data init = {}; + struct vop2_clk *vop2_clk; + struct clk *clk; + + vop2_clk = devm_kzalloc(vop2->dev, sizeof(*vop2_clk), GFP_KERNEL); + if (!vop2_clk) + return ERR_PTR(-ENOMEM); + + vop2_clk->vop2 = vop2; + vop2_clk->hw.init = &init; + vop2_clk->div.shift = branch->div_shift; + vop2_clk->div.width = branch->div_width; + + init.name = branch->name; + init.flags = branch->flags; + init.num_parents = branch->num_parents; + init.parent_names = branch->parent_names; + if (branch->branch_type == branch_divider) { + init.ops = &vop2_div_clk_ops; + } else if (branch->branch_type == branch_virtual) { + init.ops = &clk_virtual_ops; + init.num_parents = 0; + init.parent_names = NULL; + } else { + init.ops = &vop2_mux_clk_ops; + } + + clk = devm_clk_register(vop2->dev, &vop2_clk->hw); + if (!IS_ERR(clk)) + list_add_tail(&vop2_clk->list, &vop2->clk_list_head); + else + DRM_DEV_ERROR(vop2->dev, "Register %s failed\n", branch->name); + + return clk; +} + +int vop2_clk_init(struct vop2 *vop2) +{ + struct vop2_clk_branch *branch = rk3588_vop_clk_branches; + unsigned int nr_clk = ARRAY_SIZE(rk3588_vop_clk_branches); + unsigned int idx; + struct vop2_clk *clk, *n; + + INIT_LIST_HEAD(&vop2->clk_list_head); + + if (vop2->version < VOP_VERSION_RK3588) + return 0; + + list_for_each_entry_safe(clk, n, &vop2->clk_list_head, list) { + list_del(&clk->list); + } + + for (idx = 0; idx < nr_clk; idx++, branch++) + vop2_clk_register(vop2, branch); + + return 0; +} diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c index 6df97d1c1e59..411532a9d4fe 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c @@ -14,6 +14,7 @@ #include #include "rockchip_drm_vop.h" #include "rockchip_vop_reg.h" +#include "rockchip_drm_drv.h" #define _VOP_REG(off, _mask, _shift, _write_mask) \ { \ @@ -439,6 +440,37 @@ static const struct vop_intr rk3568_vp2_intr = { .clear = VOP_REG_MASK(RK3568_VP2_INT_CLR, 0xffff, 0), }; +static const struct vop_intr rk3588_vp3_intr = { + .intrs = rk3568_vop_intrs, + .nintrs = ARRAY_SIZE(rk3568_vop_intrs), + .line_flag_num[0] = VOP_REG(RK3588_VP3_LINE_FLAG, 0x1fff, 0), + .line_flag_num[1] = VOP_REG(RK3588_VP3_LINE_FLAG, 0x1fff, 16), + .status = VOP_REG(RK3588_VP3_INT_STATUS, 0xffff, 0), + .enable = VOP_REG_MASK(RK3588_VP3_INT_EN, 0xffff, 0), + .clear = VOP_REG_MASK(RK3588_VP3_INT_CLR, 0xffff, 0), +}; + +static const struct vop2_dsc_regs rk3588_vop_dsc0_regs = { + .rst_deassert = VOP_REG(RK3588_DSC0_RST, 0x1, 0), + .port_mux = VOP_REG(RK3588_DSC0_SYS_CTRL, 0x3, 0), +}; + +static const struct vop2_dsc_regs rk3588_vop_dsc1_regs = { + .rst_deassert = VOP_REG(RK3588_DSC1_RST, 0x1, 0), + .port_mux = VOP_REG(RK3588_DSC1_SYS_CTRL, 0x3, 0), +}; + +static const struct vop2_dsc_data rk3588_vop_dsc_data[] = { + { + .id = 0, + .regs = &rk3588_vop_dsc0_regs, + }, + { + .id = 1, + .regs = &rk3588_vop_dsc1_regs, + }, +}; + static const struct vop2_wb_regs rk3568_vop_wb_regs = { .enable = VOP_REG(RK3568_WB_CTRL, 0x1, 0), .format = VOP_REG(RK3568_WB_CTRL, 0x7, 1), @@ -677,6 +709,435 @@ static const struct vop2_video_port_data rk3568_vop_video_ports[] = { }, }; +static const struct vop2_video_port_regs rk3588_vop_vp0_regs = { + .cfg_done = VOP_REG(RK3568_REG_CFG_DONE, 0x1, 0), + .overlay_mode = VOP_REG(RK3568_OVL_CTRL, 0x1, 0), + .dsp_background = VOP_REG(RK3568_VP0_DSP_BG, 0xffffffff, 0), + .port_mux = VOP_REG(RK3568_OVL_PORT_SEL, 0xf, 0), + .out_mode = VOP_REG(RK3568_VP0_DSP_CTRL, 0xf, 0), + .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), + .dsp_data_swap = VOP_REG(RK3568_VP0_DSP_CTRL, 0x1f, 8), + .post_dsp_out_r2y = VOP_REG(RK3568_VP0_DSP_CTRL, 0x1, 15), + .pre_dither_down_en = VOP_REG(RK3568_VP0_DSP_CTRL, 0x1, 16), + .dither_down_en = VOP_REG(RK3568_VP0_DSP_CTRL, 0x1, 17), + .dither_down_sel = VOP_REG(RK3568_VP0_DSP_CTRL, 0x3, 18), + .dither_down_mode = VOP_REG(RK3568_VP0_DSP_CTRL, 0x1, 20), + .dsp_lut_en = VOP_REG(RK3568_VP0_DSP_CTRL, 0x1, 28), + .standby = VOP_REG(RK3568_VP0_DSP_CTRL, 0x1, 31), + .dclk_src_sel = VOP_REG(RK3568_LUT_PORT_SEL, 0x1, 30), + .splice_en = VOP_REG(RK3568_LUT_PORT_SEL, 0x1, 16), + .dclk_core_div = VOP_REG(RK3568_VP0_CLK_CTRL, 0x3, 0), + .dclk_out_div = VOP_REG(RK3568_VP0_CLK_CTRL, 0x3, 2), + .pre_scan_htiming = VOP_REG(RK3568_VP0_PRE_SCAN_HTIMING, 0x1fff1fff, 0), + .bg_dly = VOP_REG(RK3568_VP0_BG_MIX_CTRL, 0xff, 24), + .hpost_st_end = VOP_REG(RK3568_VP0_POST_DSP_HACT_INFO, 0x1fff1fff, 0), + .vpost_st_end = VOP_REG(RK3568_VP0_POST_DSP_VACT_INFO, 0x1fff1fff, 0), + .post_scl_factor = VOP_REG(RK3568_VP0_POST_SCL_FACTOR_YRGB, 0xffffffff, 0), + .post_scl_ctrl = VOP_REG(RK3568_VP0_POST_SCL_CTRL, 0x3, 0), + .htotal_pw = VOP_REG(RK3568_VP0_DSP_HTOTAL_HS_END, 0x1fff1fff, 0), + .hact_st_end = VOP_REG(RK3568_VP0_DSP_HACT_ST_END, 0x1fff1fff, 0), + .vtotal_pw = VOP_REG(RK3568_VP0_DSP_VTOTAL_VS_END, 0x1fff1fff, 0), + .vact_st_end = VOP_REG(RK3568_VP0_DSP_VACT_ST_END, 0x1fff1fff, 0), + .vact_st_end_f1 = VOP_REG(RK3568_VP0_DSP_VACT_ST_END_F1, 0x1fff1fff, 0), + .vs_st_end_f1 = VOP_REG(RK3568_VP0_DSP_VS_ST_END_F1, 0x1fff1fff, 0), + .vpost_st_end_f1 = VOP_REG(RK3568_VP0_POST_DSP_VACT_INFO_F1, 0x1fff1fff, 0), + .mipi_dual_en = VOP_REG(RK3568_VP0_MIPI_CTRL, 0x1, 20), + .mipi_dual_channel_swap = VOP_REG(RK3568_VP0_MIPI_CTRL, 0x1, 21), + .hdr10_en = VOP_REG(RK3568_OVL_CTRL, 0x1, 4), + .hdr_lut_update_en = VOP_REG(RK3568_HDR_LUT_CTRL, 0x1, 0), + .hdr_lut_mode = VOP_REG(RK3568_HDR_LUT_CTRL, 0x1, 1), + .hdr_lut_mst = VOP_REG(RK3568_HDR_LUT_MST, 0xffffffff, 0), + .sdr2hdr_eotf_en = VOP_REG(RK3568_SDR2HDR_CTRL, 0x1, 0), + .sdr2hdr_r2r_en = VOP_REG(RK3568_SDR2HDR_CTRL, 0x1, 1), + .sdr2hdr_r2r_mode = VOP_REG(RK3568_SDR2HDR_CTRL, 0x1, 2), + .sdr2hdr_oetf_en = VOP_REG(RK3568_SDR2HDR_CTRL, 0x1, 3), + .sdr2hdr_bypass_en = VOP_REG(RK3568_SDR2HDR_CTRL, 0x1, 8), + .sdr2hdr_auto_gating_en = VOP_REG(RK3568_SDR2HDR_CTRL, 0x1, 9), + .sdr2hdr_path_en = VOP_REG(RK3568_OVL_CTRL, 0x1, 5), + .hdr2sdr_en = VOP_REG(RK3568_HDR2SDR_CTRL, 0x1, 0), + .hdr2sdr_bypass_en = VOP_REG(RK3568_HDR2SDR_CTRL, 0x1, 8), + .hdr2sdr_auto_gating_en = VOP_REG(RK3568_HDR2SDR_CTRL, 0x1, 9), + .hdr2sdr_src_min = VOP_REG(RK3568_HDR2SDR_SRC_RANGE, 0x3fff, 0), + .hdr2sdr_src_max = VOP_REG(RK3568_HDR2SDR_SRC_RANGE, 0x3fff, 16), + .hdr2sdr_normfaceetf = VOP_REG(RK3568_HDR2SDR_NORMFACEETF, 0x7ff, 0), + .hdr2sdr_dst_min = VOP_REG(RK3568_HDR2SDR_DST_RANGE, 0xffff, 0), + .hdr2sdr_dst_max = VOP_REG(RK3568_HDR2SDR_DST_RANGE, 0xffff, 16), + .hdr2sdr_normfacgamma = VOP_REG(RK3568_HDR2SDR_NORMFACCGAMMA, 0xffff, 0), + .hdr2sdr_eetf_oetf_y0_offset = RK3568_HDR_EETF_OETF_Y0, + .hdr2sdr_sat_y0_offset = RK3568_HDR_SAT_Y0, + .sdr2hdr_eotf_oetf_y0_offset = RK3568_HDR_EOTF_OETF_Y0, + .sdr2hdr_oetf_dx_pow1_offset = RK3568_HDR_OETF_DX_POW1, + .sdr2hdr_oetf_xn1_offset = RK3568_HDR_OETF_XN1, + .hdr_src_color_ctrl = VOP_REG(RK3568_HDR0_SRC_COLOR_CTRL, 0xffffffff, 0), + .hdr_dst_color_ctrl = VOP_REG(RK3568_HDR0_DST_COLOR_CTRL, 0xffffffff, 0), + .hdr_src_alpha_ctrl = VOP_REG(RK3568_HDR0_SRC_ALPHA_CTRL, 0xffffffff, 0), + .hdr_dst_alpha_ctrl = VOP_REG(RK3568_HDR0_DST_ALPHA_CTRL, 0xffffffff, 0), + + .bcsh_brightness = VOP_REG(RK3568_VP0_BCSH_BCS, 0xff, 0), + .bcsh_contrast = VOP_REG(RK3568_VP0_BCSH_BCS, 0x1ff, 8), + .bcsh_sat_con = VOP_REG(RK3568_VP0_BCSH_BCS, 0x3ff, 20), + .bcsh_out_mode = VOP_REG(RK3568_VP0_BCSH_BCS, 0x3, 30), + .bcsh_sin_hue = VOP_REG(RK3568_VP0_BCSH_H, 0x1ff, 0), + .bcsh_cos_hue = VOP_REG(RK3568_VP0_BCSH_H, 0x1ff, 16), + .bcsh_r2y_csc_mode = VOP_REG(RK3568_VP0_BCSH_CTRL, 0x3, 6), + .bcsh_r2y_en = VOP_REG(RK3568_VP0_BCSH_CTRL, 0x1, 4), + .bcsh_y2r_csc_mode = VOP_REG(RK3568_VP0_BCSH_CTRL, 0x3, 2), + .bcsh_y2r_en = VOP_REG(RK3568_VP0_BCSH_CTRL, 0x1, 0), + .bcsh_en = VOP_REG(RK3568_VP0_BCSH_COLOR_BAR, 0x1, 31), +}; + +/* + * VP1 can splice with VP0 to output hdisplay > 4096, + * VP1 has a another HDR10 controller, but share the + * same eotf curve with VP1. + */ +static const struct vop2_video_port_regs rk3588_vop_vp1_regs = { + .cfg_done = VOP_REG(RK3568_REG_CFG_DONE, 0x1, 1), + .overlay_mode = VOP_REG(RK3568_OVL_CTRL, 0x1, 1), + .dsp_background = VOP_REG(RK3568_VP1_DSP_BG, 0xffffffff, 0), + .port_mux = VOP_REG(RK3568_OVL_PORT_SEL, 0xf, 4), + .out_mode = VOP_REG(RK3568_VP1_DSP_CTRL, 0xf, 0), + .p2i_en = VOP_REG(RK3568_VP1_DSP_CTRL, 0x1, 5), + .dsp_filed_pol = VOP_REG(RK3568_VP1_DSP_CTRL, 0x1, 6), + .dsp_interlace = VOP_REG(RK3568_VP1_DSP_CTRL, 0x1, 7), + .dsp_data_swap = VOP_REG(RK3568_VP1_DSP_CTRL, 0x1f, 8), + .post_dsp_out_r2y = VOP_REG(RK3568_VP1_DSP_CTRL, 0x1, 15), + .pre_dither_down_en = VOP_REG(RK3568_VP1_DSP_CTRL, 0x1, 16), + .dither_down_en = VOP_REG(RK3568_VP1_DSP_CTRL, 0x1, 17), + .dither_down_sel = VOP_REG(RK3568_VP1_DSP_CTRL, 0x3, 18), + .dither_down_mode = VOP_REG(RK3568_VP1_DSP_CTRL, 0x1, 20), + .dsp_lut_en = VOP_REG(RK3568_VP1_DSP_CTRL, 0x1, 28), + .standby = VOP_REG(RK3568_VP1_DSP_CTRL, 0x1, 31), + .dclk_core_div = VOP_REG(RK3568_VP1_CLK_CTRL, 0x3, 0), + .dclk_out_div = VOP_REG(RK3568_VP1_CLK_CTRL, 0x3, 2), + .pre_scan_htiming = VOP_REG(RK3568_VP1_PRE_SCAN_HTIMING, 0x1fff1fff, 0), + .bg_dly = VOP_REG(RK3568_VP1_BG_MIX_CTRL, 0xff, 24), + .hpost_st_end = VOP_REG(RK3568_VP1_POST_DSP_HACT_INFO, 0x1fff1fff, 0), + .vpost_st_end = VOP_REG(RK3568_VP1_POST_DSP_VACT_INFO, 0x1fff1fff, 0), + .post_scl_factor = VOP_REG(RK3568_VP1_POST_SCL_FACTOR_YRGB, 0xffffffff, 0), + .post_scl_ctrl = VOP_REG(RK3568_VP1_POST_SCL_CTRL, 0x3, 0), + .htotal_pw = VOP_REG(RK3568_VP1_DSP_HTOTAL_HS_END, 0x1fff1fff, 0), + .hact_st_end = VOP_REG(RK3568_VP1_DSP_HACT_ST_END, 0x1fff1fff, 0), + .vtotal_pw = VOP_REG(RK3568_VP1_DSP_VTOTAL_VS_END, 0x1fff1fff, 0), + .vact_st_end = VOP_REG(RK3568_VP1_DSP_VACT_ST_END, 0x1fff1fff, 0), + .vact_st_end_f1 = VOP_REG(RK3568_VP1_DSP_VACT_ST_END_F1, 0x1fff1fff, 0), + .vs_st_end_f1 = VOP_REG(RK3568_VP1_DSP_VS_ST_END_F1, 0x1fff1fff, 0), + .vpost_st_end_f1 = VOP_REG(RK3568_VP1_POST_DSP_VACT_INFO_F1, 0x1fff1fff, 0), + .mipi_dual_en = VOP_REG(RK3568_VP1_MIPI_CTRL, 0x1, 20), + .mipi_dual_channel_swap = VOP_REG(RK3568_VP1_MIPI_CTRL, 0x1, 21), + .hdr10_en = VOP_REG(RK3568_OVL_CTRL, 0x1, 24), + .hdr_lut_update_en = VOP_REG(RK3568_HDR_LUT_CTRL, 0x1, 0), + .hdr_lut_mode = VOP_REG(RK3568_HDR_LUT_CTRL, 0x1, 1), + .hdr_lut_mst = VOP_REG(RK3568_HDR_LUT_MST, 0xffffffff, 0), + .sdr2hdr_eotf_en = VOP_REG(RK3568_SDR2HDR_CTRL1, 0x1, 0), + .sdr2hdr_r2r_en = VOP_REG(RK3568_SDR2HDR_CTRL1, 0x1, 1), + .sdr2hdr_r2r_mode = VOP_REG(RK3568_SDR2HDR_CTRL1, 0x1, 2), + .sdr2hdr_oetf_en = VOP_REG(RK3568_SDR2HDR_CTRL1, 0x1, 3), + .sdr2hdr_bypass_en = VOP_REG(RK3568_SDR2HDR_CTRL1, 0x1, 8), + .sdr2hdr_auto_gating_en = VOP_REG(RK3568_SDR2HDR_CTRL1, 0x1, 9), + .sdr2hdr_path_en = VOP_REG(RK3568_OVL_CTRL, 0x1, 25), + .hdr2sdr_en = VOP_REG(RK3568_HDR2SDR_CTRL1, 0x1, 0), + .hdr2sdr_bypass_en = VOP_REG(RK3568_HDR2SDR_CTRL1, 0x1, 8), + .hdr2sdr_auto_gating_en = VOP_REG(RK3568_HDR2SDR_CTRL1, 0x1, 9), + .hdr2sdr_src_min = VOP_REG(RK3568_HDR2SDR_SRC_RANGE, 0x3fff, 0), + .hdr2sdr_src_max = VOP_REG(RK3568_HDR2SDR_SRC_RANGE, 0x3fff, 16), + .hdr2sdr_normfaceetf = VOP_REG(RK3568_HDR2SDR_NORMFACEETF, 0x7ff, 0), + .hdr2sdr_dst_min = VOP_REG(RK3568_HDR2SDR_DST_RANGE, 0xffff, 0), + .hdr2sdr_dst_max = VOP_REG(RK3568_HDR2SDR_DST_RANGE, 0xffff, 16), + .hdr2sdr_normfacgamma = VOP_REG(RK3568_HDR2SDR_NORMFACCGAMMA, 0xffff, 0), + .hdr2sdr_eetf_oetf_y0_offset = RK3568_HDR_EETF_OETF_Y0, + .hdr2sdr_sat_y0_offset = RK3568_HDR_SAT_Y0, + .sdr2hdr_eotf_oetf_y0_offset = RK3568_HDR_EOTF_OETF_Y0, + .sdr2hdr_oetf_dx_pow1_offset = RK3568_HDR_OETF_DX_POW1, + .sdr2hdr_oetf_xn1_offset = RK3568_HDR_OETF_XN1, + .hdr_src_color_ctrl = VOP_REG(RK3568_HDR1_SRC_COLOR_CTRL, 0xffffffff, 0), + .hdr_dst_color_ctrl = VOP_REG(RK3568_HDR1_DST_COLOR_CTRL, 0xffffffff, 0), + .hdr_src_alpha_ctrl = VOP_REG(RK3568_HDR1_SRC_ALPHA_CTRL, 0xffffffff, 0), + .hdr_dst_alpha_ctrl = VOP_REG(RK3568_HDR1_DST_ALPHA_CTRL, 0xffffffff, 0), + + .bcsh_brightness = VOP_REG(RK3568_VP1_BCSH_BCS, 0xff, 0), + .bcsh_contrast = VOP_REG(RK3568_VP1_BCSH_BCS, 0x1ff, 8), + .bcsh_sat_con = VOP_REG(RK3568_VP1_BCSH_BCS, 0x3ff, 20), + .bcsh_out_mode = VOP_REG(RK3568_VP1_BCSH_BCS, 0x3, 30), + .bcsh_sin_hue = VOP_REG(RK3568_VP1_BCSH_H, 0x1ff, 0), + .bcsh_cos_hue = VOP_REG(RK3568_VP1_BCSH_H, 0x1ff, 16), + .bcsh_r2y_csc_mode = VOP_REG(RK3568_VP1_BCSH_CTRL, 0x3, 6), + .bcsh_r2y_en = VOP_REG(RK3568_VP1_BCSH_CTRL, 0x1, 4), + .bcsh_y2r_csc_mode = VOP_REG(RK3568_VP1_BCSH_CTRL, 0x3, 2), + .bcsh_y2r_en = VOP_REG(RK3568_VP1_BCSH_CTRL, 0x1, 0), + .bcsh_en = VOP_REG(RK3568_VP1_BCSH_COLOR_BAR, 0x1, 31), +}; + +static const struct vop2_video_port_regs rk3588_vop_vp2_regs = { + .cfg_done = VOP_REG(RK3568_REG_CFG_DONE, 0x1, 2), + .overlay_mode = VOP_REG(RK3568_OVL_CTRL, 0x1, 2), + .dsp_background = VOP_REG(RK3568_VP2_DSP_BG, 0xffffffff, 0), + .port_mux = VOP_REG(RK3568_OVL_PORT_SEL, 0xf, 8), + .out_mode = VOP_REG(RK3568_VP2_DSP_CTRL, 0xf, 0), + .p2i_en = VOP_REG(RK3568_VP2_DSP_CTRL, 0x1, 5), + .dsp_filed_pol = VOP_REG(RK3568_VP2_DSP_CTRL, 0x1, 6), + .dsp_interlace = VOP_REG(RK3568_VP2_DSP_CTRL, 0x1, 7), + .dsp_data_swap = VOP_REG(RK3568_VP2_DSP_CTRL, 0x1f, 8), + .post_dsp_out_r2y = VOP_REG(RK3568_VP2_DSP_CTRL, 0x1, 15), + .pre_dither_down_en = VOP_REG(RK3568_VP2_DSP_CTRL, 0x1, 16), + .dither_down_en = VOP_REG(RK3568_VP2_DSP_CTRL, 0x1, 17), + .dither_down_sel = VOP_REG(RK3568_VP2_DSP_CTRL, 0x3, 18), + .dither_down_mode = VOP_REG(RK3568_VP2_DSP_CTRL, 0x1, 20), + .dsp_lut_en = VOP_REG(RK3568_VP2_DSP_CTRL, 0x1, 28), + .standby = VOP_REG(RK3568_VP2_DSP_CTRL, 0x1, 31), + .dclk_src_sel = VOP_REG(RK3568_LUT_PORT_SEL, 0x1, 31), + .dclk_core_div = VOP_REG(RK3568_VP2_CLK_CTRL, 0x3, 0), + .dclk_out_div = VOP_REG(RK3568_VP2_CLK_CTRL, 0x3, 2), + .pre_scan_htiming = VOP_REG(RK3568_VP2_PRE_SCAN_HTIMING, 0x1fff1fff, 0), + .bg_dly = VOP_REG(RK3568_VP2_BG_MIX_CTRL, 0xff, 24), + .hpost_st_end = VOP_REG(RK3568_VP2_POST_DSP_HACT_INFO, 0x1fff1fff, 0), + .vpost_st_end = VOP_REG(RK3568_VP2_POST_DSP_VACT_INFO, 0x1fff1fff, 0), + .post_scl_factor = VOP_REG(RK3568_VP2_POST_SCL_FACTOR_YRGB, 0xffffffff, 0), + .post_scl_ctrl = VOP_REG(RK3568_VP2_POST_SCL_CTRL, 0x3, 0), + .htotal_pw = VOP_REG(RK3568_VP2_DSP_HTOTAL_HS_END, 0x1fff1fff, 0), + .hact_st_end = VOP_REG(RK3568_VP2_DSP_HACT_ST_END, 0x1fff1fff, 0), + .vtotal_pw = VOP_REG(RK3568_VP2_DSP_VTOTAL_VS_END, 0x1fff1fff, 0), + .vact_st_end = VOP_REG(RK3568_VP2_DSP_VACT_ST_END, 0x1fff1fff, 0), + .vact_st_end_f1 = VOP_REG(RK3568_VP2_DSP_VACT_ST_END_F1, 0x1fff1fff, 0), + .vs_st_end_f1 = VOP_REG(RK3568_VP2_DSP_VS_ST_END_F1, 0x1fff1fff, 0), + .vpost_st_end_f1 = VOP_REG(RK3568_VP2_POST_DSP_VACT_INFO_F1, 0x1fff1fff, 0), + .mipi_dual_en = VOP_REG(RK3568_VP2_MIPI_CTRL, 0x1, 20), + .mipi_dual_channel_swap = VOP_REG(RK3568_VP2_MIPI_CTRL, 0x1, 21), + .bcsh_brightness = VOP_REG(RK3568_VP2_BCSH_BCS, 0xff, 0), + .bcsh_contrast = VOP_REG(RK3568_VP2_BCSH_BCS, 0x1ff, 8), + .bcsh_sat_con = VOP_REG(RK3568_VP2_BCSH_BCS, 0x3ff, 20), + .bcsh_out_mode = VOP_REG(RK3568_VP2_BCSH_BCS, 0x3, 30), + .bcsh_sin_hue = VOP_REG(RK3568_VP2_BCSH_H, 0x1ff, 0), + .bcsh_cos_hue = VOP_REG(RK3568_VP2_BCSH_H, 0x1ff, 16), + .bcsh_r2y_csc_mode = VOP_REG(RK3568_VP2_BCSH_CTRL, 0x3, 6), + .bcsh_r2y_en = VOP_REG(RK3568_VP2_BCSH_CTRL, 0x1, 4), + .bcsh_y2r_csc_mode = VOP_REG(RK3568_VP2_BCSH_CTRL, 0x3, 2), + .bcsh_y2r_en = VOP_REG(RK3568_VP2_BCSH_CTRL, 0x1, 0), + .bcsh_en = VOP_REG(RK3568_VP2_BCSH_COLOR_BAR, 0x1, 31), +}; + +static const struct vop2_video_port_regs rk3588_vop_vp3_regs = { + .cfg_done = VOP_REG(RK3568_REG_CFG_DONE, 0x1, 3), + .overlay_mode = VOP_REG(RK3568_OVL_CTRL, 0x1, 3), + .port_mux = VOP_REG(RK3568_OVL_PORT_SEL, 0xf, 12), + .dsp_background = VOP_REG(RK3588_VP3_DSP_BG, 0xffffffff, 0), + .out_mode = VOP_REG(RK3588_VP3_DSP_CTRL, 0xf, 0), + .p2i_en = VOP_REG(RK3588_VP3_DSP_CTRL, 0x1, 5), + .dsp_filed_pol = VOP_REG(RK3588_VP3_DSP_CTRL, 0x1, 6), + .dsp_interlace = VOP_REG(RK3588_VP3_DSP_CTRL, 0x1, 7), + .dsp_data_swap = VOP_REG(RK3588_VP3_DSP_CTRL, 0x1f, 8), + .post_dsp_out_r2y = VOP_REG(RK3588_VP3_DSP_CTRL, 0x1, 15), + .pre_dither_down_en = VOP_REG(RK3588_VP3_DSP_CTRL, 0x1, 16), + .dither_down_en = VOP_REG(RK3588_VP3_DSP_CTRL, 0x1, 17), + .dither_down_sel = VOP_REG(RK3588_VP3_DSP_CTRL, 0x3, 18), + .dither_down_mode = VOP_REG(RK3588_VP3_DSP_CTRL, 0x1, 20), + .dsp_lut_en = VOP_REG(RK3588_VP3_DSP_CTRL, 0x1, 28), + .standby = VOP_REG(RK3588_VP3_DSP_CTRL, 0x1, 31), + .dclk_src_sel = VOP_REG(RK3568_LUT_PORT_SEL, 0x1, 30), + .dclk_core_div = VOP_REG(RK3568_VP3_CLK_CTRL, 0x3, 0), + .dclk_out_div = VOP_REG(RK3568_VP3_CLK_CTRL, 0x3, 2), + .pre_scan_htiming = VOP_REG(RK3588_VP3_PRE_SCAN_HTIMING, 0x1fff1fff, 0), + .bg_dly = VOP_REG(RK3588_VP3_BG_MIX_CTRL, 0xff, 24), + .hpost_st_end = VOP_REG(RK3588_VP3_POST_DSP_HACT_INFO, 0x1fff1fff, 0), + .vpost_st_end = VOP_REG(RK3588_VP3_POST_DSP_VACT_INFO, 0x1fff1fff, 0), + .post_scl_factor = VOP_REG(RK3588_VP3_POST_SCL_FACTOR_YRGB, 0xffffffff, 0), + .post_scl_ctrl = VOP_REG(RK3588_VP3_POST_SCL_CTRL, 0x3, 0), + .htotal_pw = VOP_REG(RK3588_VP3_DSP_HTOTAL_HS_END, 0x1fff1fff, 0), + .hact_st_end = VOP_REG(RK3588_VP3_DSP_HACT_ST_END, 0x1fff1fff, 0), + .vtotal_pw = VOP_REG(RK3588_VP3_DSP_VTOTAL_VS_END, 0x1fff1fff, 0), + .vact_st_end = VOP_REG(RK3588_VP3_DSP_VACT_ST_END, 0x1fff1fff, 0), + .vact_st_end_f1 = VOP_REG(RK3588_VP3_DSP_VACT_ST_END_F1, 0x1fff1fff, 0), + .vs_st_end_f1 = VOP_REG(RK3588_VP3_DSP_VS_ST_END_F1, 0x1fff1fff, 0), + .vpost_st_end_f1 = VOP_REG(RK3588_VP3_POST_DSP_VACT_INFO_F1, 0x1fff1fff, 0), + .mipi_dual_en = VOP_REG(RK3588_VP3_MIPI_CTRL, 0x1, 20), + .mipi_dual_channel_swap = VOP_REG(RK3588_VP3_MIPI_CTRL, 0x1, 21), + .bcsh_brightness = VOP_REG(RK3588_VP3_BCSH_BCS, 0xff, 0), + .bcsh_contrast = VOP_REG(RK3588_VP3_BCSH_BCS, 0x1ff, 8), + .bcsh_sat_con = VOP_REG(RK3588_VP3_BCSH_BCS, 0x3ff, 20), + .bcsh_out_mode = VOP_REG(RK3588_VP3_BCSH_BCS, 0x3, 30), + .bcsh_sin_hue = VOP_REG(RK3588_VP3_BCSH_H, 0x1ff, 0), + .bcsh_cos_hue = VOP_REG(RK3588_VP3_BCSH_H, 0x1ff, 16), + .bcsh_r2y_csc_mode = VOP_REG(RK3588_VP3_BCSH_CTRL, 0x3, 6), + .bcsh_r2y_en = VOP_REG(RK3588_VP3_BCSH_CTRL, 0x1, 4), + .bcsh_y2r_csc_mode = VOP_REG(RK3588_VP3_BCSH_CTRL, 0x3, 2), + .bcsh_y2r_en = VOP_REG(RK3588_VP3_BCSH_CTRL, 0x1, 0), + .bcsh_en = VOP_REG(RK3588_VP3_BCSH_COLOR_BAR, 0x1, 31), +}; + +static const struct vop2_video_port_data rk3588_vop_video_ports[] = { + { + .id = 0, + .splice_vp_id = 1, + .soc_id = { 0x3588, 0x3588 }, + .feature = VOP_FEATURE_OUTPUT_10BIT, + .gamma_lut_len = 1024, + .cubic_lut_len = 729, /* 9x9x9 */ + .dclk_max = 600000000, + .max_output = { 7680, 4320 }, + /* hdr2sdr sdr2hdr hdr2hdr sdr2sdr */ + .pre_scan_max_dly = { 76, 65, 53, 54 }, + .intr = &rk3568_vp0_intr, + .hdr_table = &rk3568_vop_hdr_table, + .regs = &rk3588_vop_vp0_regs, + }, + { + .id = 1, + .soc_id = { 0x3588, 0x3588 }, + .gamma_lut_len = 1024, + .dclk_max = 600000000, + .max_output = { 4096, 2304 }, + .pre_scan_max_dly = { 76, 65, 53, 54 }, + .intr = &rk3568_vp1_intr, + /* vp1 share the same hdr curve with vp0 */ + .hdr_table = &rk3568_vop_hdr_table, + .regs = &rk3588_vop_vp1_regs, + }, + { + .id = 2, + .soc_id = { 0x3588, 0x3588 }, + .gamma_lut_len = 1024, + .dclk_max = 600000000, + .max_output = { 4096, 2304 }, + .pre_scan_max_dly = { 52, 52, 52, 52 }, + .intr = &rk3568_vp2_intr, + .regs = &rk3588_vop_vp2_regs, + }, + { + .id = 3, + .soc_id = { 0x3588, 0x3588 }, + .gamma_lut_len = 1024, + .dclk_max = 200000000, + .max_output = { 2048, 1536 }, + .pre_scan_max_dly = { 52, 52, 52, 52 }, + .intr = &rk3588_vp3_intr, + .regs = &rk3588_vop_vp3_regs, + }, + +}; + +/* + * HDMI/eDP infterface pixclk and dclk are independent of each other. + * MIPI and DP interface pixclk and dclk are the same in itself. + */ +static const struct vop2_connector_if_data rk3588_conn_if_data[] = { + { + .id = VOP_OUTPUT_IF_HDMI0, + .clk_src_name = "hdmi_edp0_clk_src", + .clk_parent_name = "dclk", + .pixclk_name = "hdmi_edp0_pixclk", + .dclk_name = "hdmi_edp0_dclk", + .post_proc_div_shift = 2, + .if_div_shift = 4, + .if_div_yuv420_shift = 1, + .bus_div_shift = 2, + .pixel_clk_div_shift = 2, + }, + + { + .id = VOP_OUTPUT_IF_HDMI1, + .clk_src_name = "hdmi_edp1_clk_src", + .clk_parent_name = "dclk", + .pixclk_name = "hdmi_edp1_pixclk", + .dclk_name = "hdmi_edp1_dclk", + .post_proc_div_shift = 2, + .if_div_shift = 4, + .if_div_yuv420_shift = 1, + .bus_div_shift = 2, + .pixel_clk_div_shift = 2, + }, + + { + .id = VOP_OUTPUT_IF_eDP0, + .clk_src_name = "hdmi_edp0_clk_src", + .clk_parent_name = "dclk", + .pixclk_name = "hdmi_edp0_pixclk", + .dclk_name = "hdmi_edp0_dclk", + .post_proc_div_shift = 2, + .if_div_shift = 4, + .if_div_yuv420_shift = 1, + .bus_div_shift = 1, + .pixel_clk_div_shift = 1, + }, + + { + .id = VOP_OUTPUT_IF_eDP1, + .clk_src_name = "hdmi_edp1_clk_src", + .clk_parent_name = "dclk", + .pixclk_name = "hdmi_edp1_pixclk", + .dclk_name = "hdmi_edp1_dclk", + .post_proc_div_shift = 2, + .if_div_shift = 4, + .if_div_yuv420_shift = 1, + .bus_div_shift = 1, + .pixel_clk_div_shift = 1, + }, + + { + .id = VOP_OUTPUT_IF_DP0, + .clk_src_name = "dp0_pixclk", + .clk_parent_name = "dclk_out", + .pixclk_name = "dp0_pixclk", + .post_proc_div_shift = 2, + .if_div_shift = 1, + .if_div_yuv420_shift = 2, + .bus_div_shift = 1, + .pixel_clk_div_shift = 1, + + }, + + { + .id = VOP_OUTPUT_IF_DP1, + .clk_src_name = "dp1_pixclk", + .clk_parent_name = "dclk_out", + .pixclk_name = "dp1_pixclk", + .post_proc_div_shift = 2, + .if_div_shift = 1, + .if_div_yuv420_shift = 2, + .bus_div_shift = 1, + .pixel_clk_div_shift = 1, + + }, + + { + .id = VOP_OUTPUT_IF_MIPI0, + .clk_src_name = "mipi0_clk_src", + .clk_parent_name = "dclk_out", + .pixclk_name = "mipi0_pixclk", + .post_proc_div_shift = 2, + .if_div_shift = 1, + .if_div_yuv420_shift = 1, + .bus_div_shift = 1, + .pixel_clk_div_shift = 1, + }, + + { + .id = VOP_OUTPUT_IF_MIPI1, + .clk_src_name = "mipi1_clk_src", + .clk_parent_name = "dclk_out", + .pixclk_name = "mipi1_pixclk", + .post_proc_div_shift = 2, + .if_div_shift = 1, + .if_div_yuv420_shift = 1, + .bus_div_shift = 1, + .pixel_clk_div_shift = 1, + }, + + { + .id = VOP_OUTPUT_IF_RGB, + .clk_src_name = "port3_dclk_src", + .clk_parent_name = "dclk", + .pixclk_name = "rgb_pixclk", + .post_proc_div_shift = 2, + .if_div_shift = 0, + .if_div_yuv420_shift = 0, + .bus_div_shift = 0, + .pixel_clk_div_shift = 0, + }, +}; + + const struct vop2_layer_regs rk3568_vop_layer0_regs = { .layer_sel = VOP_REG(RK3568_OVL_LAYER_SEL, 0x7, 0) }; @@ -701,6 +1162,14 @@ const struct vop2_layer_regs rk3568_vop_layer5_regs = { .layer_sel = VOP_REG(RK3568_OVL_LAYER_SEL, 0x7, 20) }; +const struct vop2_layer_regs rk3568_vop_layer6_regs = { + .layer_sel = VOP_REG(RK3568_OVL_LAYER_SEL, 0x7, 24) +}; + +const struct vop2_layer_regs rk3568_vop_layer7_regs = { + .layer_sel = VOP_REG(RK3568_OVL_LAYER_SEL, 0x7, 28) +}; + static const struct vop2_layer_data rk3568_vop_layers[] = { { .id = 0, @@ -731,6 +1200,17 @@ static const struct vop2_layer_data rk3568_vop_layers[] = { .id = 5, .regs = &rk3568_vop_layer5_regs, }, + + { + .id = 6, + .regs = &rk3568_vop_layer6_regs, + }, + + { + .id = 7, + .regs = &rk3568_vop_layer7_regs, + }, + }; static const struct vop2_cluster_regs rk3568_vop_cluster0 = { @@ -745,6 +1225,18 @@ static const struct vop2_cluster_regs rk3568_vop_cluster1 = { .lb_mode = VOP_REG(RK3568_CLUSTER1_CTRL, 0xf, 4), }; +static const struct vop2_cluster_regs rk3588_vop_cluster2 = { + .afbc_enable = VOP_REG(RK3588_CLUSTER2_CTRL, 0x1, 1), + .enable = VOP_REG(RK3588_CLUSTER2_CTRL, 1, 0), + .lb_mode = VOP_REG(RK3588_CLUSTER2_CTRL, 0xf, 4), +}; + +static const struct vop2_cluster_regs rk3588_vop_cluster3 = { + .afbc_enable = VOP_REG(RK3588_CLUSTER3_CTRL, 0x1, 1), + .enable = VOP_REG(RK3588_CLUSTER3_CTRL, 1, 0), + .lb_mode = VOP_REG(RK3588_CLUSTER3_CTRL, 0xf, 4), +}; + static const struct vop_afbc rk3568_cluster0_afbc = { .format = VOP_REG(RK3568_CLUSTER0_WIN0_AFBCD_CTRL, 0x1f, 2), .rb_swap = VOP_REG(RK3568_CLUSTER0_WIN0_AFBCD_CTRL, 0x1, 9), @@ -805,6 +1297,65 @@ static const struct vop2_scl_regs rk3568_cluster1_win_scl = { .vsd_yrgb_gt4 = VOP_REG(RK3568_CLUSTER1_WIN0_CTRL1, 0x1, 29), }; +static const struct vop_afbc rk3588_cluster2_afbc = { + .format = VOP_REG(RK3588_CLUSTER2_WIN0_AFBCD_CTRL, 0x1f, 2), + .rb_swap = VOP_REG(RK3588_CLUSTER2_WIN0_AFBCD_CTRL, 0x1, 9), + .uv_swap = VOP_REG(RK3588_CLUSTER2_WIN0_AFBCD_CTRL, 0x1, 10), + .auto_gating_en = VOP_REG(RK3588_CLUSTER2_WIN0_AFBCD_OUTPUT_CTRL, 0x1, 4), + .half_block_en = VOP_REG(RK3588_CLUSTER2_WIN0_AFBCD_CTRL, 0x1, 7), + .block_split_en = VOP_REG(RK3588_CLUSTER2_WIN0_AFBCD_CTRL, 0x1, 8), + .hdr_ptr = VOP_REG(RK3588_CLUSTER2_WIN0_AFBCD_HDR_PTR, 0xffffffff, 0), + .pic_size = VOP_REG(RK3588_CLUSTER2_WIN0_AFBCD_PIC_SIZE, 0xffffffff, 0), + .pic_vir_width = VOP_REG(RK3588_CLUSTER2_WIN0_AFBCD_VIR_WIDTH, 0xffff, 0), + .tile_num = VOP_REG(RK3588_CLUSTER2_WIN0_AFBCD_VIR_WIDTH, 0xffff, 16), + .pic_offset = VOP_REG(RK3588_CLUSTER2_WIN0_AFBCD_PIC_OFFSET, 0xffffffff, 0), + .dsp_offset = VOP_REG(RK3588_CLUSTER2_WIN0_AFBCD_DSP_OFFSET, 0xffffffff, 0), + .transform_offset = VOP_REG(RK3588_CLUSTER2_WIN0_AFBCD_TRANSFORM_OFFSET, 0xffffffff, 0), + .rotate_90 = VOP_REG(RK3588_CLUSTER2_WIN0_AFBCD_ROTATE_MODE, 0x1, 0), + .rotate_270 = VOP_REG(RK3588_CLUSTER2_WIN0_AFBCD_ROTATE_MODE, 0x1, 1), + .xmirror = VOP_REG(RK3588_CLUSTER2_WIN0_AFBCD_ROTATE_MODE, 0x1, 2), + .ymirror = VOP_REG(RK3588_CLUSTER2_WIN0_AFBCD_ROTATE_MODE, 0x1, 3), +}; + +static const struct vop2_scl_regs rk3588_cluster2_win_scl = { + .scale_yrgb_x = VOP_REG(RK3588_CLUSTER2_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0), + .scale_yrgb_y = VOP_REG(RK3588_CLUSTER2_WIN0_SCL_FACTOR_YRGB, 0xffff, 16), + .yrgb_ver_scl_mode = VOP_REG(RK3588_CLUSTER2_WIN0_CTRL1, 0x3, 14), + .yrgb_hor_scl_mode = VOP_REG(RK3588_CLUSTER2_WIN0_CTRL1, 0x3, 12), + .bic_coe_sel = VOP_REG(RK3588_CLUSTER2_WIN0_CTRL1, 0x3, 2), + .vsd_yrgb_gt2 = VOP_REG(RK3588_CLUSTER2_WIN0_CTRL1, 0x1, 28), + .vsd_yrgb_gt4 = VOP_REG(RK3588_CLUSTER2_WIN0_CTRL1, 0x1, 29), +}; + +static const struct vop_afbc rk3588_cluster3_afbc = { + .format = VOP_REG(RK3588_CLUSTER3_WIN0_AFBCD_CTRL, 0x1f, 2), + .rb_swap = VOP_REG(RK3588_CLUSTER3_WIN0_AFBCD_CTRL, 0x1, 9), + .uv_swap = VOP_REG(RK3588_CLUSTER3_WIN0_AFBCD_CTRL, 0x1, 10), + .auto_gating_en = VOP_REG(RK3588_CLUSTER3_WIN0_AFBCD_OUTPUT_CTRL, 0x1, 4), + .half_block_en = VOP_REG(RK3588_CLUSTER3_WIN0_AFBCD_CTRL, 0x1, 7), + .block_split_en = VOP_REG(RK3588_CLUSTER3_WIN0_AFBCD_CTRL, 0x1, 8), + .hdr_ptr = VOP_REG(RK3588_CLUSTER3_WIN0_AFBCD_HDR_PTR, 0xffffffff, 0), + .pic_size = VOP_REG(RK3588_CLUSTER3_WIN0_AFBCD_PIC_SIZE, 0xffffffff, 0), + .pic_vir_width = VOP_REG(RK3588_CLUSTER3_WIN0_AFBCD_VIR_WIDTH, 0xffff, 0), + .tile_num = VOP_REG(RK3588_CLUSTER3_WIN0_AFBCD_VIR_WIDTH, 0xffff, 16), + .pic_offset = VOP_REG(RK3588_CLUSTER3_WIN0_AFBCD_PIC_OFFSET, 0xffffffff, 0), + .dsp_offset = VOP_REG(RK3588_CLUSTER3_WIN0_AFBCD_DSP_OFFSET, 0xffffffff, 0), + .transform_offset = VOP_REG(RK3588_CLUSTER3_WIN0_AFBCD_TRANSFORM_OFFSET, 0xffffffff, 0), + .rotate_90 = VOP_REG(RK3588_CLUSTER3_WIN0_AFBCD_ROTATE_MODE, 0x1, 0), + .rotate_270 = VOP_REG(RK3588_CLUSTER3_WIN0_AFBCD_ROTATE_MODE, 0x1, 1), + .xmirror = VOP_REG(RK3588_CLUSTER3_WIN0_AFBCD_ROTATE_MODE, 0x1, 2), + .ymirror = VOP_REG(RK3588_CLUSTER3_WIN0_AFBCD_ROTATE_MODE, 0x1, 3), +}; + +static const struct vop2_scl_regs rk3588_cluster3_win_scl = { + .scale_yrgb_x = VOP_REG(RK3588_CLUSTER3_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0), + .scale_yrgb_y = VOP_REG(RK3588_CLUSTER3_WIN0_SCL_FACTOR_YRGB, 0xffff, 16), + .yrgb_ver_scl_mode = VOP_REG(RK3588_CLUSTER3_WIN0_CTRL1, 0x3, 14), + .yrgb_hor_scl_mode = VOP_REG(RK3588_CLUSTER3_WIN0_CTRL1, 0x3, 12), + .bic_coe_sel = VOP_REG(RK3588_CLUSTER3_WIN0_CTRL1, 0x3, 2), + .vsd_yrgb_gt2 = VOP_REG(RK3588_CLUSTER3_WIN0_CTRL1, 0x1, 28), + .vsd_yrgb_gt4 = VOP_REG(RK3588_CLUSTER3_WIN0_CTRL1, 0x1, 29), +}; static const struct vop2_scl_regs rk3568_esmart_win_scl = { .scale_yrgb_x = VOP_REG(RK3568_ESMART0_REGION0_SCL_FACTOR_YRGB, 0xffff, 0x0), @@ -946,7 +1497,7 @@ static const struct vop2_win_regs rk3568_cluster0_win_data = { .rb_swap = VOP_REG(RK3568_CLUSTER0_WIN0_CTRL0, 0x1, 14), .dither_up = VOP_REG(RK3568_CLUSTER0_WIN0_CTRL0, 0x1, 18), .act_info = VOP_REG(RK3568_CLUSTER0_WIN0_ACT_INFO, 0x1fff1fff, 0), - .dsp_info = VOP_REG(RK3568_CLUSTER0_WIN0_DSP_INFO, 0x0fff0fff, 0), + .dsp_info = VOP_REG(RK3568_CLUSTER0_WIN0_DSP_INFO, 0x1fff1fff, 0), .dsp_st = VOP_REG(RK3568_CLUSTER0_WIN0_DSP_ST, 0x1fff1fff, 0), .yrgb_mst = VOP_REG(RK3568_CLUSTER0_WIN0_YRGB_MST, 0xffffffff, 0), .uv_mst = VOP_REG(RK3568_CLUSTER0_WIN0_CBR_MST, 0xffffffff, 0), @@ -966,7 +1517,7 @@ static const struct vop2_win_regs rk3568_cluster1_win_data = { .rb_swap = VOP_REG(RK3568_CLUSTER1_WIN0_CTRL0, 0x1, 14), .dither_up = VOP_REG(RK3568_CLUSTER1_WIN0_CTRL0, 0x1, 18), .act_info = VOP_REG(RK3568_CLUSTER1_WIN0_ACT_INFO, 0x1fff1fff, 0), - .dsp_info = VOP_REG(RK3568_CLUSTER1_WIN0_DSP_INFO, 0x0fff0fff, 0), + .dsp_info = VOP_REG(RK3568_CLUSTER1_WIN0_DSP_INFO, 0x1fff1fff, 0), .dsp_st = VOP_REG(RK3568_CLUSTER1_WIN0_DSP_ST, 0x1fff1fff, 0), .yrgb_mst = VOP_REG(RK3568_CLUSTER1_WIN0_YRGB_MST, 0xffffffff, 0), .uv_mst = VOP_REG(RK3568_CLUSTER1_WIN0_CBR_MST, 0xffffffff, 0), @@ -977,6 +1528,44 @@ static const struct vop2_win_regs rk3568_cluster1_win_data = { .csc_mode = VOP_REG(RK3568_CLUSTER1_WIN0_CTRL0, 0x3, 10), }; +static const struct vop2_win_regs rk3588_cluster2_win_data = { + .scl = &rk3588_cluster2_win_scl, + .afbc = &rk3588_cluster2_afbc, + .cluster = &rk3588_vop_cluster2, + .enable = VOP_REG(RK3588_CLUSTER2_WIN0_CTRL0, 0x1, 0), + .format = VOP_REG(RK3588_CLUSTER2_WIN0_CTRL0, 0x1f, 1), + .rb_swap = VOP_REG(RK3588_CLUSTER2_WIN0_CTRL0, 0x1, 14), + .act_info = VOP_REG(RK3588_CLUSTER2_WIN0_ACT_INFO, 0x1fff1fff, 0), + .dsp_info = VOP_REG(RK3588_CLUSTER2_WIN0_DSP_INFO, 0x1fff1fff, 0), + .dsp_st = VOP_REG(RK3588_CLUSTER2_WIN0_DSP_ST, 0x1fff1fff, 0), + .yrgb_mst = VOP_REG(RK3588_CLUSTER2_WIN0_YRGB_MST, 0xffffffff, 0), + .uv_mst = VOP_REG(RK3588_CLUSTER2_WIN0_CBR_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3588_CLUSTER2_WIN0_VIR, 0xffff, 0), + .uv_vir = VOP_REG(RK3588_CLUSTER2_WIN0_VIR, 0xffff, 16), + .y2r_en = VOP_REG(RK3588_CLUSTER2_WIN0_CTRL0, 0x1, 8), + .r2y_en = VOP_REG(RK3588_CLUSTER2_WIN0_CTRL0, 0x1, 9), + .csc_mode = VOP_REG(RK3588_CLUSTER2_WIN0_CTRL0, 0x3, 10), +}; + +static const struct vop2_win_regs rk3588_cluster3_win_data = { + .scl = &rk3588_cluster3_win_scl, + .afbc = &rk3588_cluster3_afbc, + .cluster = &rk3588_vop_cluster3, + .enable = VOP_REG(RK3588_CLUSTER3_WIN0_CTRL0, 0x1, 0), + .format = VOP_REG(RK3588_CLUSTER3_WIN0_CTRL0, 0x1f, 1), + .rb_swap = VOP_REG(RK3588_CLUSTER3_WIN0_CTRL0, 0x1, 14), + .act_info = VOP_REG(RK3588_CLUSTER3_WIN0_ACT_INFO, 0x1fff1fff, 0), + .dsp_info = VOP_REG(RK3588_CLUSTER3_WIN0_DSP_INFO, 0x1fff1fff, 0), + .dsp_st = VOP_REG(RK3588_CLUSTER3_WIN0_DSP_ST, 0x1fff1fff, 0), + .yrgb_mst = VOP_REG(RK3588_CLUSTER3_WIN0_YRGB_MST, 0xffffffff, 0), + .uv_mst = VOP_REG(RK3588_CLUSTER3_WIN0_CBR_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3588_CLUSTER3_WIN0_VIR, 0xffff, 0), + .uv_vir = VOP_REG(RK3588_CLUSTER3_WIN0_VIR, 0xffff, 16), + .y2r_en = VOP_REG(RK3588_CLUSTER3_WIN0_CTRL0, 0x1, 8), + .r2y_en = VOP_REG(RK3588_CLUSTER3_WIN0_CTRL0, 0x1, 9), + .csc_mode = VOP_REG(RK3588_CLUSTER3_WIN0_CTRL0, 0x3, 10), +}; + static const struct vop2_win_regs rk3568_esmart_win_data = { .scl = &rk3568_esmart_win_scl, .enable = VOP_REG(RK3568_ESMART0_REGION0_CTRL, 0x1, 0), @@ -985,7 +1574,7 @@ static const struct vop2_win_regs rk3568_esmart_win_data = { .rb_swap = VOP_REG(RK3568_ESMART0_REGION0_CTRL, 0x1, 14), .uv_swap = VOP_REG(RK3568_ESMART0_REGION0_CTRL, 0x1, 16), .act_info = VOP_REG(RK3568_ESMART0_REGION0_ACT_INFO, 0x1fff1fff, 0), - .dsp_info = VOP_REG(RK3568_ESMART0_REGION0_DSP_INFO, 0x0fff0fff, 0), + .dsp_info = VOP_REG(RK3568_ESMART0_REGION0_DSP_INFO, 0x1fff1fff, 0), .dsp_st = VOP_REG(RK3568_ESMART0_REGION0_DSP_ST, 0x1fff1fff, 0), .yrgb_mst = VOP_REG(RK3568_ESMART0_REGION0_YRGB_MST, 0xffffffff, 0), .uv_mst = VOP_REG(RK3568_ESMART0_REGION0_CBR_MST, 0xffffffff, 0), @@ -1194,6 +1783,287 @@ static const struct vop2_win_data rk3568_vop_win_data[] = { }, }; +/* + * rk3588 vop with 4 cluster, 4 esmart win. + * Every cluster can work as 4K win or split into two win. + * All win in cluster support AFBCD. + * + * Every esmart win and smart win support 4 Multi-region. + * + * Scale filter mode: + * + * * Cluster: bicubic for horizontal scale up, others use bilinear + * * ESmart: + * * nearest-neighbor/bilinear/bicubic for scale up + * * nearest-neighbor/bilinear/average for scale down + * + * + * @TODO describe the wind like cpu-map dt nodes; + */ +static const struct vop2_win_data rk3588_vop_win_data[] = { + { + .name = "Cluster0-win0", + .phys_id = ROCKCHIP_VOP2_CLUSTER0, + .splice_win_id = ROCKCHIP_VOP2_CLUSTER1, + .base = 0x00, + .formats = formats_win_full_10bit, + .nformats = ARRAY_SIZE(formats_win_full_10bit), + .format_modifiers = format_modifiers_afbc, + .layer_sel_id = 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, + .hsd_filter_mode = VOP2_SCALE_DOWN_BIL, + .vsu_filter_mode = VOP2_SCALE_UP_BIL, + .vsd_filter_mode = VOP2_SCALE_DOWN_BIL, + .regs = &rk3568_cluster0_win_data, + .max_upscale_factor = 4, + .max_downscale_factor = 4, + .dly = { 4, 26, 29 }, + .type = DRM_PLANE_TYPE_OVERLAY, + .feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER_MAIN | WIN_FEATURE_SPLICE_LEFT, + }, + + { + .name = "Cluster0-win1", + .phys_id = ROCKCHIP_VOP2_CLUSTER0, + .base = 0x80, + .layer_sel_id = -1, + .formats = formats_win_full_10bit, + .nformats = ARRAY_SIZE(formats_win_full_10bit), + .format_modifiers = format_modifiers_afbc, + .supported_rotations = DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y, + .hsu_filter_mode = VOP2_SCALE_UP_BIC, + .hsd_filter_mode = VOP2_SCALE_DOWN_BIL, + .vsu_filter_mode = VOP2_SCALE_UP_BIL, + .vsd_filter_mode = VOP2_SCALE_DOWN_BIL, + .regs = &rk3568_cluster0_win_data, + .max_upscale_factor = 4, + .max_downscale_factor = 4, + .type = DRM_PLANE_TYPE_OVERLAY, + .feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER_SUB, + }, + + { + .name = "Cluster1-win0", + .phys_id = ROCKCHIP_VOP2_CLUSTER1, + .base = 0x00, + .formats = formats_win_full_10bit, + .nformats = ARRAY_SIZE(formats_win_full_10bit), + .format_modifiers = format_modifiers_afbc, + .layer_sel_id = 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, + .hsd_filter_mode = VOP2_SCALE_DOWN_BIL, + .vsu_filter_mode = VOP2_SCALE_UP_BIL, + .vsd_filter_mode = VOP2_SCALE_DOWN_BIL, + .regs = &rk3568_cluster1_win_data, + .type = DRM_PLANE_TYPE_OVERLAY, + .max_upscale_factor = 4, + .max_downscale_factor = 4, + .dly = { 4, 26, 29 }, + .feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER_MAIN, + }, + + { + .name = "Cluster1-win1", + .phys_id = ROCKCHIP_VOP2_CLUSTER1, + .layer_sel_id = -1, + .formats = formats_win_full_10bit, + .nformats = ARRAY_SIZE(formats_win_full_10bit), + .format_modifiers = format_modifiers_afbc, + .base = 0x80, + .supported_rotations = DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y, + .hsu_filter_mode = VOP2_SCALE_UP_BIC, + .hsd_filter_mode = VOP2_SCALE_DOWN_BIL, + .vsu_filter_mode = VOP2_SCALE_UP_BIL, + .vsd_filter_mode = VOP2_SCALE_DOWN_BIL, + .regs = &rk3568_cluster1_win_data, + .type = DRM_PLANE_TYPE_OVERLAY, + .max_upscale_factor = 4, + .max_downscale_factor = 4, + .feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER_SUB, + }, + + { + .name = "Cluster2-win0", + .phys_id = ROCKCHIP_VOP2_CLUSTER2, + .splice_win_id = ROCKCHIP_VOP2_CLUSTER3, + .base = 0x00, + .formats = formats_win_full_10bit, + .nformats = ARRAY_SIZE(formats_win_full_10bit), + .format_modifiers = format_modifiers_afbc, + .layer_sel_id = 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, + .hsd_filter_mode = VOP2_SCALE_DOWN_BIL, + .vsu_filter_mode = VOP2_SCALE_UP_BIL, + .vsd_filter_mode = VOP2_SCALE_DOWN_BIL, + .regs = &rk3588_cluster2_win_data, + .type = DRM_PLANE_TYPE_OVERLAY, + .max_upscale_factor = 4, + .max_downscale_factor = 4, + .dly = { 4, 26, 29 }, + .feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER_MAIN | WIN_FEATURE_SPLICE_LEFT, + }, + + { + .name = "Cluster2-win1", + .phys_id = ROCKCHIP_VOP2_CLUSTER2, + .layer_sel_id = -1, + .formats = formats_win_full_10bit, + .nformats = ARRAY_SIZE(formats_win_full_10bit), + .format_modifiers = format_modifiers_afbc, + .base = 0x80, + .supported_rotations = DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y, + .hsu_filter_mode = VOP2_SCALE_UP_BIC, + .hsd_filter_mode = VOP2_SCALE_DOWN_BIL, + .vsu_filter_mode = VOP2_SCALE_UP_BIL, + .vsd_filter_mode = VOP2_SCALE_DOWN_BIL, + .regs = &rk3588_cluster2_win_data, + .type = DRM_PLANE_TYPE_OVERLAY, + .max_upscale_factor = 4, + .max_downscale_factor = 4, + .feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER_SUB, + }, + + { + .name = "Cluster3-win0", + .phys_id = ROCKCHIP_VOP2_CLUSTER3, + .base = 0x00, + .formats = formats_win_full_10bit, + .nformats = ARRAY_SIZE(formats_win_full_10bit), + .format_modifiers = format_modifiers_afbc, + .layer_sel_id = 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, + .hsd_filter_mode = VOP2_SCALE_DOWN_BIL, + .vsu_filter_mode = VOP2_SCALE_UP_BIL, + .vsd_filter_mode = VOP2_SCALE_DOWN_BIL, + .regs = &rk3588_cluster3_win_data, + .type = DRM_PLANE_TYPE_OVERLAY, + .max_upscale_factor = 4, + .max_downscale_factor = 4, + .dly = { 4, 26, 29 }, + .feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER_MAIN, + }, + + { + .name = "Cluster3-win1", + .phys_id = ROCKCHIP_VOP2_CLUSTER3, + .layer_sel_id = -1, + .formats = formats_win_full_10bit, + .nformats = ARRAY_SIZE(formats_win_full_10bit), + .format_modifiers = format_modifiers_afbc, + .base = 0x80, + .supported_rotations = DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y, + .hsu_filter_mode = VOP2_SCALE_UP_BIC, + .hsd_filter_mode = VOP2_SCALE_DOWN_BIL, + .vsu_filter_mode = VOP2_SCALE_UP_BIL, + .vsd_filter_mode = VOP2_SCALE_DOWN_BIL, + .regs = &rk3588_cluster3_win_data, + .type = DRM_PLANE_TYPE_OVERLAY, + .max_upscale_factor = 4, + .max_downscale_factor = 4, + .feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER_SUB, + }, + + { + .name = "Esmart0-win0", + .phys_id = ROCKCHIP_VOP2_ESMART0, + .splice_win_id = ROCKCHIP_VOP2_ESMART1, + .formats = formats_win_full_10bit, + .nformats = ARRAY_SIZE(formats_win_full_10bit), + .format_modifiers = format_modifiers, + .base = 0x0, + .layer_sel_id = 2, + .supported_rotations = DRM_MODE_REFLECT_Y, + .hsu_filter_mode = VOP2_SCALE_UP_BIC, + .hsd_filter_mode = VOP2_SCALE_DOWN_BIL, + .vsu_filter_mode = VOP2_SCALE_UP_BIL, + .vsd_filter_mode = VOP2_SCALE_DOWN_BIL, + .regs = &rk3568_esmart_win_data, + .area = rk3568_area_data, + .area_size = ARRAY_SIZE(rk3568_area_data), + .type = DRM_PLANE_TYPE_PRIMARY, + .max_upscale_factor = 8, + .max_downscale_factor = 8, + .dly = { 23, 45, 48 }, + .feature = WIN_FEATURE_SPLICE_LEFT, + }, + + { + .name = "Esmart2-win0", + .phys_id = ROCKCHIP_VOP2_ESMART2, + .splice_win_id = ROCKCHIP_VOP2_ESMART3, + .base = 0x400, + .formats = formats_win_full_10bit, + .nformats = ARRAY_SIZE(formats_win_full_10bit), + .format_modifiers = format_modifiers, + .layer_sel_id = 6, + .supported_rotations = DRM_MODE_REFLECT_Y, + .hsu_filter_mode = VOP2_SCALE_UP_BIC, + .hsd_filter_mode = VOP2_SCALE_DOWN_BIL, + .vsu_filter_mode = VOP2_SCALE_UP_BIL, + .vsd_filter_mode = VOP2_SCALE_DOWN_BIL, + .regs = &rk3568_esmart_win_data, + .area = rk3568_area_data, + .area_size = ARRAY_SIZE(rk3568_area_data), + .type = DRM_PLANE_TYPE_PRIMARY, + .max_upscale_factor = 8, + .max_downscale_factor = 8, + .dly = { 23, 45, 48 }, + .feature = WIN_FEATURE_SPLICE_LEFT, + }, + + { + .name = "Esmart1-win0", + .phys_id = ROCKCHIP_VOP2_ESMART1, + .formats = formats_win_full_10bit, + .nformats = ARRAY_SIZE(formats_win_full_10bit), + .format_modifiers = format_modifiers, + .base = 0x200, + .layer_sel_id = 3, + .supported_rotations = DRM_MODE_REFLECT_Y, + .hsu_filter_mode = VOP2_SCALE_UP_BIC, + .hsd_filter_mode = VOP2_SCALE_DOWN_BIL, + .vsu_filter_mode = VOP2_SCALE_UP_BIL, + .vsd_filter_mode = VOP2_SCALE_DOWN_BIL, + .regs = &rk3568_esmart_win_data, + .area = rk3568_area_data, + .area_size = ARRAY_SIZE(rk3568_area_data), + .type = DRM_PLANE_TYPE_PRIMARY, + .max_upscale_factor = 8, + .max_downscale_factor = 8, + .dly = { 23, 45, 48 }, + }, + + { + .name = "Esmart3-win0", + .phys_id = ROCKCHIP_VOP2_ESMART3, + .formats = formats_win_full_10bit, + .nformats = ARRAY_SIZE(formats_win_full_10bit), + .format_modifiers = format_modifiers, + .base = 0x600, + .layer_sel_id = 7, + .supported_rotations = DRM_MODE_REFLECT_Y, + .hsu_filter_mode = VOP2_SCALE_UP_BIC, + .hsd_filter_mode = VOP2_SCALE_DOWN_BIL, + .vsu_filter_mode = VOP2_SCALE_UP_BIL, + .vsd_filter_mode = VOP2_SCALE_DOWN_BIL, + .regs = &rk3568_esmart_win_data, + .area = rk3568_area_data, + .area_size = ARRAY_SIZE(rk3568_area_data), + .type = DRM_PLANE_TYPE_PRIMARY, + .max_upscale_factor = 8, + .max_downscale_factor = 8, + .dly = { 23, 45, 48 }, + }, +}; + static const struct vop_grf_ctrl rk3568_grf_ctrl = { .grf_bt656_clk_inv = VOP_REG(RK3568_GRF_VO_CON1, 0x1, 1), .grf_bt1120_clk_inv = VOP_REG(RK3568_GRF_VO_CON1, 0x1, 2), @@ -1254,19 +2124,96 @@ static const struct vop2_ctrl rk3568_vop_ctrl = { .win_vp_id[ROCKCHIP_VOP2_ESMART1] = VOP_REG(RK3568_OVL_PORT_SEL, 0x3, 26), .win_vp_id[ROCKCHIP_VOP2_SMART0] = VOP_REG(RK3568_OVL_PORT_SEL, 0x3, 28), .win_vp_id[ROCKCHIP_VOP2_SMART1] = VOP_REG(RK3568_OVL_PORT_SEL, 0x3, 30), - .win_dly[0] = VOP_REG(RK3568_CLUSTER_DLY_NUM, 0xffff, 0), - .win_dly[1] = VOP_REG(RK3568_CLUSTER_DLY_NUM, 0xffff, 16), - .win_dly[2] = VOP_REG(RK3568_SMART_DLY_NUM, 0xff, 0), - .win_dly[3] = VOP_REG(RK3568_SMART_DLY_NUM, 0xff, 8), - .win_dly[4] = VOP_REG(RK3568_SMART_DLY_NUM, 0xff, 16), - .win_dly[5] = VOP_REG(RK3568_SMART_DLY_NUM, 0xff, 24), + .win_dly[ROCKCHIP_VOP2_CLUSTER0] = VOP_REG(RK3568_CLUSTER_DLY_NUM, 0xffff, 0), + .win_dly[ROCKCHIP_VOP2_CLUSTER1] = VOP_REG(RK3568_CLUSTER_DLY_NUM, 0xffff, 16), + .win_dly[ROCKCHIP_VOP2_CLUSTER2] = VOP_REG(RK3568_CLUSTER_DLY_NUM1, 0xffff, 0), + .win_dly[ROCKCHIP_VOP2_CLUSTER3] = VOP_REG(RK3568_CLUSTER_DLY_NUM1, 0xffff, 16), + .win_dly[ROCKCHIP_VOP2_ESMART0] = VOP_REG(RK3568_SMART_DLY_NUM, 0xff, 0), + .win_dly[ROCKCHIP_VOP2_ESMART1] = VOP_REG(RK3568_SMART_DLY_NUM, 0xff, 8), + .win_dly[ROCKCHIP_VOP2_ESMART2] = VOP_REG(RK3568_SMART_DLY_NUM, 0xff, 16), + .win_dly[ROCKCHIP_VOP2_ESMART3] = VOP_REG(RK3568_SMART_DLY_NUM, 0xff, 24), .otp_en = VOP_REG(RK3568_OTP_WIN_EN, 0x1, 0), }; +static const struct vop2_ctrl rk3588_vop_ctrl = { + .cfg_done_en = VOP_REG(RK3568_REG_CFG_DONE, 0x1, 15), + .wb_cfg_done = VOP_REG_MASK(RK3568_REG_CFG_DONE, 0x1, 14), + .auto_gating_en = VOP_REG(RK3568_SYS_AUTO_GATING_CTRL, 0x1, 31), + .ovl_cfg_done_port = VOP_REG(RK3568_OVL_CTRL, 0x3, 30), + .ovl_port_mux_cfg_done_imd = VOP_REG(RK3568_OVL_CTRL, 0x1, 28), + .ovl_port_mux_cfg = VOP_REG(RK3568_OVL_PORT_SEL, 0xffff, 0), + .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), + .cluster0_src_color_ctrl = VOP_REG(RK3568_CLUSTER0_MIX_SRC_COLOR_CTRL, 0xffffffff, 0), + .cluster0_dst_color_ctrl = VOP_REG(RK3568_CLUSTER0_MIX_DST_COLOR_CTRL, 0xffffffff, 0), + .cluster0_src_alpha_ctrl = VOP_REG(RK3568_CLUSTER0_MIX_SRC_ALPHA_CTRL, 0xffffffff, 0), + .cluster0_dst_alpha_ctrl = VOP_REG(RK3568_CLUSTER0_MIX_DST_ALPHA_CTRL, 0xffffffff, 0), + .src_color_ctrl = VOP_REG(RK3568_MIX0_SRC_COLOR_CTRL, 0xffffffff, 0), + .dst_color_ctrl = VOP_REG(RK3568_MIX0_DST_COLOR_CTRL, 0xffffffff, 0), + .src_alpha_ctrl = VOP_REG(RK3568_MIX0_SRC_ALPHA_CTRL, 0xffffffff, 0), + .dst_alpha_ctrl = VOP_REG(RK3568_MIX0_DST_ALPHA_CTRL, 0xffffffff, 0), + .dp0_en = VOP_REG(RK3568_DSP_IF_EN, 0x1, 0), + .dp1_en = VOP_REG(RK3568_DSP_IF_EN, 0x1, 1), + .edp0_en = VOP_REG(RK3568_DSP_IF_EN, 0x1, 2), + .hdmi0_en = VOP_REG(RK3568_DSP_IF_EN, 0x1, 3), + .edp1_en = VOP_REG(RK3568_DSP_IF_EN, 0x1, 4), + .hdmi1_en = VOP_REG(RK3568_DSP_IF_EN, 0x1, 5), + .mipi0_en = VOP_REG(RK3568_DSP_IF_EN, 0x1, 6), + .mipi1_en = VOP_REG(RK3568_DSP_IF_EN, 0x1, 7), + .rgb_en = VOP_REG(RK3568_DSP_IF_EN, 0x1, 8), + .bt1120_en = VOP_REG(RK3568_DSP_IF_EN, 0x1, 9), + .bt656_en = VOP_REG(RK3568_DSP_IF_EN, 0x1, 10), + .dp0_mux = VOP_REG(RK3568_DSP_IF_EN, 0x3, 12), + .dp1_mux = VOP_REG(RK3568_DSP_IF_EN, 0x3, 14), + .hdmi0_mux = VOP_REG(RK3568_DSP_IF_EN, 0x3, 16), + .edp0_mux = VOP_REG(RK3568_DSP_IF_EN, 0x3, 16), + .hdmi1_mux = VOP_REG(RK3568_DSP_IF_EN, 0x3, 18), + .edp1_mux = VOP_REG(RK3568_DSP_IF_EN, 0x3, 18), + .mipi0_mux = VOP_REG(RK3568_DSP_IF_EN, 0x3, 20), + .mipi1_mux = VOP_REG(RK3568_DSP_IF_EN, 0x3, 21), + .bt656_yc_swap = VOP_REG(RK3568_DSP_IF_CTRL, 0x1, 1), + .bt1120_yc_swap = VOP_REG(RK3568_DSP_IF_CTRL, 0x1, 5), + .hdmi0_dclk_div = VOP_REG(RK3568_DSP_IF_CTRL, 0x3, 16), + .hdmi0_pixclk_div = VOP_REG(RK3568_DSP_IF_CTRL, 0x3, 18), + .hdmi1_dclk_div = VOP_REG(RK3568_DSP_IF_CTRL, 0x3, 20), + .hdmi1_pixclk_div = VOP_REG(RK3568_DSP_IF_CTRL, 0x3, 22), + .edp0_dclk_div = VOP_REG(RK3568_DSP_IF_CTRL, 0x3, 16), + .edp0_pixclk_div = VOP_REG(RK3568_DSP_IF_CTRL, 0x3, 18), + .edp1_dclk_div = VOP_REG(RK3568_DSP_IF_CTRL, 0x3, 20), + .edp1_pixclk_div = VOP_REG(RK3568_DSP_IF_CTRL, 0x3, 22), + + .mipi0_pixclk_div = VOP_REG(RK3568_DSP_IF_CTRL, 0x3, 24), + .mipi1_pixclk_div = VOP_REG(RK3568_DSP_IF_CTRL, 0x3, 26), + .hdmi_pin_pol = VOP_REG(RK3568_DSP_IF_POL, 0x7, 4), + .hdmi_dclk_pol = VOP_REG(RK3568_DSP_IF_POL, 0x1, 7), + .edp_pin_pol = VOP_REG(RK3568_DSP_IF_POL, 0x3, 12), + .edp_dclk_pol = VOP_REG(RK3568_DSP_IF_POL, 0x1, 15), + .mipi_pin_pol = VOP_REG(RK3568_DSP_IF_POL, 0x7, 16), + .mipi_dclk_pol = VOP_REG(RK3568_DSP_IF_POL, 0x1, 19), + .win_vp_id[ROCKCHIP_VOP2_CLUSTER0] = VOP_REG(RK3568_OVL_PORT_SEL, 0x3, 16), + .win_vp_id[ROCKCHIP_VOP2_CLUSTER1] = VOP_REG(RK3568_OVL_PORT_SEL, 0x3, 18), + .win_vp_id[ROCKCHIP_VOP2_CLUSTER2] = VOP_REG(RK3568_OVL_PORT_SEL, 0x3, 20), + .win_vp_id[ROCKCHIP_VOP2_CLUSTER3] = VOP_REG(RK3568_OVL_PORT_SEL, 0x3, 22), + .win_vp_id[ROCKCHIP_VOP2_ESMART0] = VOP_REG(RK3568_OVL_PORT_SEL, 0x3, 24), + .win_vp_id[ROCKCHIP_VOP2_ESMART1] = VOP_REG(RK3568_OVL_PORT_SEL, 0x3, 26), + .win_vp_id[ROCKCHIP_VOP2_ESMART2] = VOP_REG(RK3568_OVL_PORT_SEL, 0x3, 28), + .win_vp_id[ROCKCHIP_VOP2_ESMART3] = VOP_REG(RK3568_OVL_PORT_SEL, 0x3, 30), + .win_dly[0] = VOP_REG(RK3568_CLUSTER_DLY_NUM, 0xffff, 0), + .win_dly[1] = VOP_REG(RK3568_CLUSTER_DLY_NUM, 0xffff, 16), + .win_dly[2] = VOP_REG(RK3568_CLUSTER_DLY_NUM1, 0xffff, 0), + .win_dly[3] = VOP_REG(RK3568_CLUSTER_DLY_NUM1, 0xffff, 16), + .win_dly[4] = VOP_REG(RK3568_SMART_DLY_NUM, 0xff, 0), + .win_dly[5] = VOP_REG(RK3568_SMART_DLY_NUM, 0xff, 8), + .win_dly[6] = VOP_REG(RK3568_SMART_DLY_NUM, 0xff, 16), + .win_dly[7] = VOP_REG(RK3568_SMART_DLY_NUM, 0xff, 24), +}; + static const struct vop2_data rk3568_vop = { - .version = VOP_VERSION(0x40, 0x15), + .version = VOP_VERSION_RK3568, .nr_vps = 3, .nr_mixers = 5, + .nr_layers = 6, .nr_gammas = 1, .max_input = { 4096, 2304 }, .max_output = { 4096, 2304 }, @@ -1277,14 +2224,38 @@ static const struct vop2_data rk3568_vop = { .vp = rk3568_vop_video_ports, .wb = &rk3568_vop_wb_data, .layer = rk3568_vop_layers, - .nr_layers = ARRAY_SIZE(rk3568_vop_layers), .win = rk3568_vop_win_data, .win_size = ARRAY_SIZE(rk3568_vop_win_data), }; +static const struct vop2_data rk3588_vop = { + .version = VOP_VERSION_RK3588, + .feature = VOP_FEATURE_SPLICE, + .nr_dscs = 2, + .nr_vps = 4, + .nr_mixers = 7, + .nr_layers = 8, + .max_input = { 8192, 4320 }, + .max_output = { 4096, 2304 }, + .ctrl = &rk3588_vop_ctrl, + .axi_intr = rk3568_vop_axi_intr, + .nr_axi_intr = ARRAY_SIZE(rk3568_vop_axi_intr), + .dsc = rk3588_vop_dsc_data, + .vp = rk3588_vop_video_ports, + .conn = rk3588_conn_if_data, + .nr_conns = ARRAY_SIZE(rk3588_conn_if_data), + .wb = &rk3568_vop_wb_data, + .layer = rk3568_vop_layers, + .win = rk3588_vop_win_data, + .win_size = ARRAY_SIZE(rk3588_vop_win_data), +}; + static const struct of_device_id vop2_dt_match[] = { { .compatible = "rockchip,rk3568-vop", .data = &rk3568_vop }, + { .compatible = "rockchip,rk3588-vop", + .data = &rk3588_vop }, + {}, }; MODULE_DEVICE_TABLE(of, vop2_dt_match); diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h index db75e014a00b..f73857a52d97 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h @@ -1050,6 +1050,7 @@ #define RK3568_DSP_IF_EN 0x028 #define RK3568_DSP_IF_CTRL 0x02c #define RK3568_DSP_IF_POL 0x030 +#define RK3568_SYS_PD_CTRL 0x034 #define RK3568_WB_CTRL 0x40 #define RK3568_WB_XSCAL_FACTOR 0x44 #define RK3568_WB_YRGB_MST 0x48 @@ -1060,6 +1061,7 @@ #define RK3568_VP0_LINE_FLAG 0x70 #define RK3568_VP1_LINE_FLAG 0x74 #define RK3568_VP2_LINE_FLAG 0x78 +#define RK3588_VP3_LINE_FLAG 0x7C #define RK3568_SYS0_INT_EN 0x80 #define RK3568_SYS0_INT_CLR 0x84 #define RK3568_SYS0_INT_STATUS 0x88 @@ -1078,11 +1080,32 @@ #define RK3568_VP2_INT_CLR 0xC4 #define RK3568_VP2_INT_STATUS 0xC8 #define RK3568_VP2_INT_RAW_STATUS 0xCC +#define RK3588_VP3_INT_EN 0xD0 +#define RK3588_VP3_INT_CLR 0xD4 +#define RK3588_VP3_INT_STATUS 0xD8 + +#define RK3588_DSC0_SYS_CTRL 0x200 +#define RK3588_DSC0_RST 0x204 +#define RK3588_DSC0_CFG_DONE 0x208 +#define RK3588_DSC0_INIT_DLY 0x20C +#define RK3588_DSC0_HTOTAL_HS_END 0x210 +#define RK3588_DSC0_HACT_ST_END 0x214 +#define RK3588_DSC0_VTOTAL_VS_END 0x218 +#define RK3588_DSC0_VACT_ST_END 0x21C +#define RK3588_DSC1_SYS_CTRL 0x230 +#define RK3588_DSC1_RST 0x234 +#define RK3588_DSC1_CFG_DONE 0x238 +#define RK3588_DSC1_INIT_DLY 0x23C +#define RK3588_DSC1_HTOTAL_HS_END 0x240 +#define RK3588_DSC1_HACT_ST_END 0x244 +#define RK3588_DSC1_VTOTAL_VS_END 0x248 +#define RK3588_DSC1_VACT_ST_END 0x24C /* Video Port registers definition */ #define RK3568_VP0_DSP_CTRL 0xC00 #define RK3568_VP0_MIPI_CTRL 0xC04 #define RK3568_VP0_COLOR_BAR_CTRL 0xC08 +#define RK3568_VP0_CLK_CTRL 0xC0C #define RK3568_VP0_3D_LUT_CTRL 0xC10 #define RK3568_VP0_3D_LUT_MST 0xC20 #define RK3568_VP0_DSP_BG 0xC2C @@ -1106,6 +1129,7 @@ #define RK3568_VP1_DSP_CTRL 0xD00 #define RK3568_VP1_MIPI_CTRL 0xD04 #define RK3568_VP1_COLOR_BAR_CTRL 0xD08 +#define RK3568_VP1_CLK_CTRL 0xD0C #define RK3568_VP1_DSP_BG 0xD2C #define RK3568_VP1_PRE_SCAN_HTIMING 0xD30 #define RK3568_VP1_POST_DSP_HACT_INFO 0xD34 @@ -1129,6 +1153,7 @@ #define RK3568_VP2_DSP_CTRL 0xE00 #define RK3568_VP2_MIPI_CTRL 0xE04 #define RK3568_VP2_COLOR_BAR_CTRL 0xE08 +#define RK3568_VP2_CLK_CTRL 0xE0C #define RK3568_VP2_DSP_BG 0xE2C #define RK3568_VP2_PRE_SCAN_HTIMING 0xE30 #define RK3568_VP2_POST_DSP_HACT_INFO 0xE34 @@ -1149,6 +1174,30 @@ #define RK3568_VP2_BCSH_H 0xE68 #define RK3568_VP2_BCSH_COLOR_BAR 0xE6C +#define RK3588_VP3_DSP_CTRL 0xF00 +#define RK3588_VP3_MIPI_CTRL 0xF04 +#define RK3588_VP3_COLOR_BAR_CTRL 0xF08 +#define RK3568_VP3_CLK_CTRL 0xF0C +#define RK3588_VP3_DSP_BG 0xF2C +#define RK3588_VP3_PRE_SCAN_HTIMING 0xF30 +#define RK3588_VP3_POST_DSP_HACT_INFO 0xF34 +#define RK3588_VP3_POST_DSP_VACT_INFO 0xF38 +#define RK3588_VP3_POST_SCL_FACTOR_YRGB 0xF3C +#define RK3588_VP3_POST_SCL_CTRL 0xF40 +#define RK3588_VP3_DSP_HACT_INFO 0xF34 +#define RK3588_VP3_DSP_VACT_INFO 0xF38 +#define RK3588_VP3_POST_DSP_VACT_INFO_F1 0xF44 +#define RK3588_VP3_DSP_HTOTAL_HS_END 0xF48 +#define RK3588_VP3_DSP_HACT_ST_END 0xF4C +#define RK3588_VP3_DSP_VTOTAL_VS_END 0xF50 +#define RK3588_VP3_DSP_VACT_ST_END 0xF54 +#define RK3588_VP3_DSP_VS_ST_END_F1 0xF58 +#define RK3588_VP3_DSP_VACT_ST_END_F1 0xF5C +#define RK3588_VP3_BCSH_CTRL 0xF60 +#define RK3588_VP3_BCSH_BCS 0xF64 +#define RK3588_VP3_BCSH_H 0xF68 +#define RK3588_VP3_BCSH_COLOR_BAR 0xF6C + /* Overlay registers definition */ #define RK3568_OVL_CTRL 0x600 #define RK3568_OVL_LAYER_SEL 0x604 @@ -1165,10 +1214,16 @@ #define RK3568_HDR0_DST_COLOR_CTRL 0x6C4 #define RK3568_HDR0_SRC_ALPHA_CTRL 0x6C8 #define RK3568_HDR0_DST_ALPHA_CTRL 0x6CC +#define RK3568_HDR1_SRC_COLOR_CTRL 0x6D0 +#define RK3568_HDR1_DST_COLOR_CTRL 0x6D4 +#define RK3568_HDR1_SRC_ALPHA_CTRL 0x6D8 +#define RK3568_HDR1_DST_ALPHA_CTRL 0x6DC #define RK3568_VP0_BG_MIX_CTRL 0x6E0 #define RK3568_VP1_BG_MIX_CTRL 0x6E4 #define RK3568_VP2_BG_MIX_CTRL 0x6E8 +#define RK3588_VP3_BG_MIX_CTRL 0x6EC #define RK3568_CLUSTER_DLY_NUM 0x6F0 +#define RK3568_CLUSTER_DLY_NUM1 0x6F4 #define RK3568_SMART_DLY_NUM 0x6F8 /* Cluster0 register definition */ @@ -1250,6 +1305,84 @@ #define RK3568_CLUSTER1_CTRL 0x1300 +#define RK3588_CLUSTER2_WIN0_CTRL0 0x1400 +#define RK3588_CLUSTER2_WIN0_CTRL1 0x1404 +#define RK3588_CLUSTER2_WIN0_YRGB_MST 0x1410 +#define RK3588_CLUSTER2_WIN0_CBR_MST 0x1414 +#define RK3588_CLUSTER2_WIN0_VIR 0x1418 +#define RK3588_CLUSTER2_WIN0_ACT_INFO 0x1420 +#define RK3588_CLUSTER2_WIN0_DSP_INFO 0x1424 +#define RK3588_CLUSTER2_WIN0_DSP_ST 0x1428 +#define RK3588_CLUSTER2_WIN0_SCL_FACTOR_YRGB 0x1430 +#define RK3588_CLUSTER2_WIN0_AFBCD_TRANSFORM_OFFSET 0x143C +#define RK3588_CLUSTER2_WIN0_AFBCD_OUTPUT_CTRL 0x1450 +#define RK3588_CLUSTER2_WIN0_AFBCD_ROTATE_MODE 0x1454 +#define RK3588_CLUSTER2_WIN0_AFBCD_HDR_PTR 0x1458 +#define RK3588_CLUSTER2_WIN0_AFBCD_VIR_WIDTH 0x145C +#define RK3588_CLUSTER2_WIN0_AFBCD_PIC_SIZE 0x1460 +#define RK3588_CLUSTER2_WIN0_AFBCD_PIC_OFFSET 0x1464 +#define RK3588_CLUSTER2_WIN0_AFBCD_DSP_OFFSET 0x1468 +#define RK3588_CLUSTER2_WIN0_AFBCD_CTRL 0x146C + +#define RK3588_CLUSTER2_WIN1_CTRL0 0x1480 +#define RK3588_CLUSTER2_WIN1_CTRL1 0x1484 +#define RK3588_CLUSTER2_WIN1_YRGB_MST 0x1490 +#define RK3588_CLUSTER2_WIN1_CBR_MST 0x1494 +#define RK3588_CLUSTER2_WIN1_VIR 0x1498 +#define RK3588_CLUSTER2_WIN1_ACT_INFO 0x14A0 +#define RK3588_CLUSTER2_WIN1_DSP_INFO 0x14A4 +#define RK3588_CLUSTER2_WIN1_DSP_ST 0x14A8 +#define RK3588_CLUSTER2_WIN1_SCL_FACTOR_YRGB 0x14B0 +#define RK3588_CLUSTER2_WIN1_AFBCD_OUTPUT_CTRL 0x14D0 +#define RK3588_CLUSTER2_WIN1_AFBCD_ROTATE_MODE 0x14D4 +#define RK3588_CLUSTER2_WIN1_AFBCD_HDR_PTR 0x14D8 +#define RK3588_CLUSTER2_WIN1_AFBCD_VIR_WIDTH 0x14DC +#define RK3588_CLUSTER2_WIN1_AFBCD_PIC_SIZE 0x14E0 +#define RK3588_CLUSTER2_WIN1_AFBCD_PIC_OFFSET 0x14E4 +#define RK3588_CLUSTER2_WIN1_AFBCD_DSP_OFFSET 0x14E8 +#define RK3588_CLUSTER2_WIN1_AFBCD_CTRL 0x14EC + +#define RK3588_CLUSTER2_CTRL 0x1500 + +#define RK3588_CLUSTER3_WIN0_CTRL0 0x1600 +#define RK3588_CLUSTER3_WIN0_CTRL1 0x1604 +#define RK3588_CLUSTER3_WIN0_YRGB_MST 0x1610 +#define RK3588_CLUSTER3_WIN0_CBR_MST 0x1614 +#define RK3588_CLUSTER3_WIN0_VIR 0x1618 +#define RK3588_CLUSTER3_WIN0_ACT_INFO 0x1620 +#define RK3588_CLUSTER3_WIN0_DSP_INFO 0x1624 +#define RK3588_CLUSTER3_WIN0_DSP_ST 0x1628 +#define RK3588_CLUSTER3_WIN0_SCL_FACTOR_YRGB 0x1630 +#define RK3588_CLUSTER3_WIN0_AFBCD_TRANSFORM_OFFSET 0x163C +#define RK3588_CLUSTER3_WIN0_AFBCD_OUTPUT_CTRL 0x1650 +#define RK3588_CLUSTER3_WIN0_AFBCD_ROTATE_MODE 0x1654 +#define RK3588_CLUSTER3_WIN0_AFBCD_HDR_PTR 0x1658 +#define RK3588_CLUSTER3_WIN0_AFBCD_VIR_WIDTH 0x165C +#define RK3588_CLUSTER3_WIN0_AFBCD_PIC_SIZE 0x1660 +#define RK3588_CLUSTER3_WIN0_AFBCD_PIC_OFFSET 0x1664 +#define RK3588_CLUSTER3_WIN0_AFBCD_DSP_OFFSET 0x1668 +#define RK3588_CLUSTER3_WIN0_AFBCD_CTRL 0x166C + +#define RK3588_CLUSTER3_WIN1_CTRL0 0x1680 +#define RK3588_CLUSTER3_WIN1_CTRL1 0x1684 +#define RK3588_CLUSTER3_WIN1_YRGB_MST 0x1690 +#define RK3588_CLUSTER3_WIN1_CBR_MST 0x1694 +#define RK3588_CLUSTER3_WIN1_VIR 0x1698 +#define RK3588_CLUSTER3_WIN1_ACT_INFO 0x16A0 +#define RK3588_CLUSTER3_WIN1_DSP_INFO 0x16A4 +#define RK3588_CLUSTER3_WIN1_DSP_ST 0x16A8 +#define RK3588_CLUSTER3_WIN1_SCL_FACTOR_YRGB 0x16B0 +#define RK3588_CLUSTER3_WIN1_AFBCD_OUTPUT_CTRL 0x16D0 +#define RK3588_CLUSTER3_WIN1_AFBCD_ROTATE_MODE 0x16D4 +#define RK3588_CLUSTER3_WIN1_AFBCD_HDR_PTR 0x16D8 +#define RK3588_CLUSTER3_WIN1_AFBCD_VIR_WIDTH 0x16DC +#define RK3588_CLUSTER3_WIN1_AFBCD_PIC_SIZE 0x16E0 +#define RK3588_CLUSTER3_WIN1_AFBCD_PIC_OFFSET 0x16E4 +#define RK3588_CLUSTER3_WIN1_AFBCD_DSP_OFFSET 0x16E8 +#define RK3588_CLUSTER3_WIN1_AFBCD_CTRL 0x16EC + +#define RK3588_CLUSTER3_CTRL 0x1700 + /* Esmart register definition */ #define RK3568_ESMART0_CTRL0 0x1800 #define RK3568_ESMART0_CTRL1 0x1804 @@ -1444,6 +1577,9 @@ #define RK3568_HDR_LUT_CTRL 0x2000 #define RK3568_HDR_LUT_MST 0x2004 #define RK3568_SDR2HDR_CTRL 0x2010 +/* for HDR10 controller1 */ +#define RK3568_SDR2HDR_CTRL1 0x2018 +#define RK3568_HDR2SDR_CTRL1 0x201C #define RK3568_HDR2SDR_CTRL 0x2020 #define RK3568_HDR2SDR_SRC_RANGE 0x2024 #define RK3568_HDR2SDR_NORMFACEETF 0x2028 @@ -1454,4 +1590,9 @@ #define RK3568_HDR_EOTF_OETF_Y0 0x20F0 #define RK3568_HDR_OETF_DX_POW1 0x2200 #define RK3568_HDR_OETF_XN1 0x2300 + +/* DSC register definition */ + +#define RK3588_DSC_8K_PPS0_3 0x4000 + #endif /* _ROCKCHIP_VOP_REG_H */