drm/rockchip: vop2: add support hardware cursor layer

The hardware cursor is always on the top of ther layers, and bypass
other layer mix.

Signed-off-by: Sandy Huang <hjc@rock-chips.com>
Change-Id: I5da0598b178f7eda85ea8556867d8f2a14ee1075
This commit is contained in:
Sandy Huang
2025-08-23 11:24:27 +08:00
parent bfbc56cd9b
commit d0d57884b7
3 changed files with 92 additions and 2 deletions

View File

@@ -80,6 +80,7 @@
#define VOP_FEATURE_POST_CSC BIT(9)
#define VOP_FEATURE_POST_FRC_V2 BIT(10)
#define VOP_FEATURE_POST_SHARP BIT(11)
#define VOP_FEATURE_HW_CURSOR BIT(12)
#define VOP_FEATURE_OUTPUT_10BIT VOP_FEATURE_OUTPUT_RGB10
@@ -103,6 +104,7 @@
#define WIN_FEATURE_MULTI_AREA BIT(7)
#define WIN_FEATURE_Y2R_13BIT_DEPTH BIT(8)
#define WIN_FEATURE_DCI BIT(9)
#define WIN_FEATURE_HW_CURSOR BIT(10)
#define VOP2_SOC_VARIANT 4
@@ -1329,6 +1331,7 @@ struct vop3_ovl_regs {
const struct vop3_ovl_mix_regs *layer_mix_regs;
const struct vop3_ovl_mix_regs *hdr_mix_regs;
const struct vop3_ovl_mix_regs *extra_mix_regs;
const struct vop3_ovl_mix_regs *cursor_mix_regs;
};
struct vop2_video_port_data {
@@ -1349,6 +1352,7 @@ struct vop2_video_port_data {
const u8 hdr_mix_dly;
const u8 win_dly;
const u8 pixel_rate;
const u8 cursor_dly;
const struct vop_intr *intr;
const struct vop_urgency *urgency;
const struct vop_hdr_table *hdr_table;

View File

@@ -2814,6 +2814,11 @@ static inline bool vop2_cluster_sub_window(struct vop2_win *win)
return (win->feature & WIN_FEATURE_CLUSTER_SUB);
}
static inline bool vop2_cursor_window(struct vop2_win *win)
{
return (win->feature & WIN_FEATURE_HW_CURSOR);
}
static inline bool vop2_has_feature(struct vop2 *vop2, uint64_t feature)
{
return (vop2->data->feature & feature);
@@ -10301,6 +10306,10 @@ static void vop3_setup_pipe_dly(struct vop2_video_port *vp, const struct vop2_zp
if (vop2_cluster_window(win))
dly |= dly << 8;
/* cursor bypass other layer mix, so need to add extra cursor dly */
if (vop2_cursor_window(win))
dly += vp_data->cursor_dly;
win->dly_num = dly;
}
}
@@ -11999,6 +12008,60 @@ static void rk3576_extra_alpha(struct vop2_video_port *vp, const struct vop2_zpo
}
}
static void rk3572_cursor_alpha(struct vop2_video_port *vp,
const struct vop2_zpos *vop2_zpos)
{
struct vop2 *vop2 = vp->vop2;
const struct vop3_ovl_regs *ovl_regs = vop2->data->vp[vp->id].ovl_regs;
uint32_t src_color_ctrl_offset = ovl_regs->cursor_mix_regs->src_color_ctrl.offset;
uint32_t dst_color_ctrl_offset = ovl_regs->cursor_mix_regs->dst_color_ctrl.offset;
uint32_t src_alpha_ctrl_offset = ovl_regs->cursor_mix_regs->src_alpha_ctrl.offset;
uint32_t dst_alpha_ctrl_offset = ovl_regs->cursor_mix_regs->dst_alpha_ctrl.offset;
const struct vop2_zpos *zpos;
struct vop2_plane_state *vpstate;
struct vop2_alpha_config alpha_config;
struct vop2_alpha alpha;
struct vop2_win *win;
struct drm_plane_state *pstate;
struct drm_framebuffer *fb;
int premulti_en = 1;
int pixel_alpha_en = 1;
zpos = &vop2_zpos[vp->nr_layers - 1];/* top layer */
win = vop2_find_win_by_phys_id(vop2, zpos->win_phys_id);
if (win && vop2_cursor_window(win)) {
pstate = win->base.state;
vpstate = to_vop2_plane_state(pstate);
fb = pstate->fb;
if (pstate->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI ||
pstate->pixel_blend_mode == DRM_MODE_BLEND_PIXEL_NONE)
premulti_en = 1;
else
premulti_en = 0;
pixel_alpha_en = is_alpha_support(fb->format->format);
alpha_config.src_premulti_en = premulti_en;
alpha_config.dst_premulti_en = true;
alpha_config.src_pixel_alpha_en = pixel_alpha_en;
alpha_config.dst_pixel_alpha_en = true;
alpha_config.src_glb_alpha_value = vpstate->global_alpha;
alpha_config.dst_glb_alpha_value = 0xff;
} else {
alpha_config.src_premulti_en = true;
alpha_config.dst_premulti_en = true;
alpha_config.src_pixel_alpha_en = false;
alpha_config.dst_pixel_alpha_en = true;
alpha_config.src_glb_alpha_value = 0xff;
alpha_config.dst_glb_alpha_value = 0xff;
}
vop2_parse_alpha(&alpha_config, &alpha);
vop2_writel(vop2, src_color_ctrl_offset, alpha.src_color_ctrl.val);
vop2_writel(vop2, dst_color_ctrl_offset, alpha.dst_color_ctrl.val);
vop2_writel(vop2, src_alpha_ctrl_offset, alpha.src_alpha_ctrl.val);
vop2_writel(vop2, dst_alpha_ctrl_offset, alpha.dst_alpha_ctrl.val);
}
static void vop3_setup_alpha(struct vop2_video_port *vp,
const struct vop2_zpos *vop2_zpos)
{
@@ -12025,6 +12088,8 @@ static void vop3_setup_alpha(struct vop2_video_port *vp,
bool bottom_layer_pixel_alpha_en = false;
bool bottom_layer_global_alpha_en = false;
u32 bottom_layer_global_alpha = 0xff;
uint8_t cursor_mix = 0;
uint8_t nr_layers;
zpos = &vop2_zpos[0];
win = vop2_find_win_by_phys_id(vop2, zpos->win_phys_id);
@@ -12046,9 +12111,21 @@ static void vop3_setup_alpha(struct vop2_video_port *vp,
bottom_layer_premulti_en = 0;
}
bottom_win = win;
if (vp_data->feature & VOP_FEATURE_HW_CURSOR) {
zpos = &vop2_zpos[vp->nr_layers - 1];/* top layer */
win = vop2_find_win_by_phys_id(vop2, zpos->win_phys_id);
if (vop2_cursor_window(win))
cursor_mix = 1;
}
alpha_config.dst_pixel_alpha_en = true; /* alpha value need transfer to next mix */
for (i = 1; i < vp->nr_layers; i++) {
/*
* The cursor layer always stays on top of all other layers. No matter
* how many layers there are or whether all layer-mix paths are in use,
* the cursor mix is applied last.
*/
nr_layers = vp->nr_layers - cursor_mix;
for (i = 1; i < nr_layers; i++) {
zpos = &vop2_zpos[i];
win = vop2_find_win_by_phys_id(vop2, zpos->win_phys_id);
pstate = win->base.state;
@@ -12155,7 +12232,8 @@ static void vop3_setup_alpha(struct vop2_video_port *vp,
alpha_config.dst_glb_alpha_value = 0xff;
vop2_parse_alpha(&alpha_config, &alpha);
for (; i < vop2->data->nr_layers; i++) {
nr_layers = vop2->data->nr_layers - cursor_mix;
for (; i < nr_layers; i++) {
offset = (i - 1) * 0x10;
vop2_writel(vop2, src_color_ctrl_offset + offset, alpha.src_color_ctrl.val);
@@ -12164,6 +12242,10 @@ static void vop3_setup_alpha(struct vop2_video_port *vp,
vop2_writel(vop2, dst_alpha_ctrl_offset + offset, alpha.dst_alpha_ctrl.val);
}
if (vp_data->feature & VOP_FEATURE_HW_CURSOR)
rk3572_cursor_alpha(vp, vop2_zpos);
if (vp_data->feature & (VOP_FEATURE_HDR10 | VOP_FEATURE_VIVID_HDR)) {
src_color_ctrl_offset = ovl_regs->hdr_mix_regs->src_color_ctrl.offset;
dst_color_ctrl_offset = ovl_regs->hdr_mix_regs->dst_color_ctrl.offset;
@@ -15308,6 +15390,8 @@ static int vop2_crtc_create_plane_mask_property(struct vop2 *vop2,
{ ROCKCHIP_VOP2_CLUSTER3, "Cluster3" },
{ ROCKCHIP_VOP2_ESMART2, "Esmart2" },
{ ROCKCHIP_VOP2_ESMART3, "Esmart3" },
{ ROCKCHIP_VOP2_CURSOR0, "Cursor0" },
{ ROCKCHIP_VOP2_CURSOR1, "Cursor1" },
};
prop = drm_property_create_bitmask(vop2->drm_dev,

View File

@@ -25,6 +25,8 @@
#define ROCKCHIP_VOP2_CLUSTER3 7
#define ROCKCHIP_VOP2_ESMART2 8
#define ROCKCHIP_VOP2_ESMART3 9
#define ROCKCHIP_VOP2_CURSOR0 10
#define ROCKCHIP_VOP2_CURSOR1 11
#define ROCKCHIP_VOP2_PHY_ID_INVALID -1