From 708010d987e463a807bb2fb28dde01d9c58d0637 Mon Sep 17 00:00:00 2001 From: Damon Ding Date: Wed, 22 Jan 2025 09:57:36 +0800 Subject: [PATCH] drm/rockchip: vop2: add support to assign plane_mask for RK3528/RK3562/RK3576 RK3528/RK3562/RK3576 use the VOP3 architecture, which supports flexible switching of planes between different VP. User can switch planes between different CRTCs based on the &drm_plane.possible_crtcs in userspace, and the plane-mask does not need to be assigned by default in DTS. However, for some Linux systems, there may still be scenarios where it is necessary to specify the primary and cursor planes specifically used on a VP. Therefore, the valid plane-mask assignment will change the &drm_plane.possible_crtcs and establish a fixed binding relationship between planes and CRTCs, which means that the flexible switching of planes is not available in the case. Change-Id: I156f71ceb238c5945a92f48c0024f398711ea811 Signed-off-by: Damon Ding --- drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 115 +++++++++++++++++-- drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 17 +++ 2 files changed, 122 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 76cc7eef3429..743607816aad 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -15282,29 +15282,103 @@ static void post_buf_empty_work_event(struct work_struct *work) } } +static void vop2_plane_mask_to_possible_vp_mask(struct vop2 *vop2) +{ + const struct vop2_data *vop2_data = vop2->data; + struct vop2_video_port *vp; + struct vop2_win *win; + uint32_t plane_mask; + uint32_t nr_planes; + uint32_t phys_id; + int i, j, k; + + for (i = 0; i < vop2->registered_num_wins; i++) { + win = &vop2->win[i]; + win->possible_vp_mask = 0; + } + + for (i = 0; i < vop2_data->nr_vps; i++) { + vp = &vop2->vps[i]; + plane_mask = vp->plane_mask; + nr_planes = hweight32(plane_mask); + + for (j = 0; j < nr_planes; j++) { + phys_id = ffs(plane_mask) - 1; + + for (k = 0; k < vop2->registered_num_wins; k++) { + win = &vop2->win[k]; + if (win->phys_id == phys_id) + win->possible_vp_mask |= BIT(i); + } + + plane_mask &= ~BIT(phys_id); + } + } +} + +/* + * The function checks whether the 'rockchip,plane-mask' property assigned + * in DTS is valid. + */ static bool vop2_plane_mask_check(struct vop2 *vop2) { const struct vop2_data *vop2_data = vop2->data; + struct vop2_video_port *vp; + struct vop2_win *win; char *full_plane, *current_plane; - u32 plane_mask = 0; - int i; + u32 full_plane_mask = 0, plane_mask = 0; + u32 phys_id; + u32 nr_planes; + int i, j; /* - * For RK3568 and RK3588, all windows need to be assigned to - * one of all vps, and two of vps can not share the same window. + * If plane_mask is assigned in DTS, then every plane need to be assigned to + * one of all the VPs, and no single plane can be assigned to more than one + * VP. */ - if (vop2->version != VOP_VERSION_RK3568 && vop2->version != VOP_VERSION_RK3588) - return true; - for (i = 0; i < vop2_data->nr_vps; i++) { - if (plane_mask & vop2->vps[i].plane_mask) { + vp = &vop2->vps[i]; + plane_mask = vp->plane_mask; + nr_planes = hweight32(plane_mask); + + /* + * Every plane assigned to the specific VP should follow the constraints + * of default &vop2_win.possible_vp_mask. + */ + for (j = 0; j < nr_planes; j++) { + phys_id = ffs(plane_mask) - 1; + win = vop2_find_win_by_phys_id(vop2, phys_id); + if (!win) { + DRM_WARN("Invalid plane id %d in VP%d assigned plane mask\n", + phys_id, i); + return false; + } + + if (!(win->possible_vp_mask & BIT(i))) { + DRM_WARN("%s can not attach to VP%d\n", + vop2_plane_phys_id_to_string(phys_id), i); + return false; + } + + plane_mask &= ~BIT(phys_id); + } + + if (full_plane_mask & vop2->vps[i].plane_mask) { DRM_WARN("the same window can't be assigned to two vp\n"); return false; } - plane_mask |= vop2->vps[i].plane_mask; + full_plane_mask |= vop2->vps[i].plane_mask; } - if (plane_mask != vop2_data->plane_mask_base) { + /* + * For VOP3, the DTS assignment of plane_mask is not mandatory. If no plane_mask + * assignment, the planes can be switched between different CRTCs according to + * the &drm_plane.possible_crtcs. + */ + if (is_vop3(vop2) && !full_plane_mask) + return true; + + if (full_plane_mask != vop2_data->plane_mask_base) { full_plane = vop2_plane_mask_to_string(vop2_data->plane_mask_base); current_plane = vop2_plane_mask_to_string(plane_mask); DRM_WARN("all windows should be assigned, full plane mask: %s[0x%x], current plane mask: %s[0x%x]\n", @@ -15314,6 +15388,12 @@ static bool vop2_plane_mask_check(struct vop2 *vop2) return false; } + /* + * If plane_mask assigned in DTS is valid, then convert it to &vop2_win.possible_vp_mask + * and replace the default one with it. + */ + vop2_plane_mask_to_possible_vp_mask(vop2); + return true; } @@ -15354,6 +15434,21 @@ static void vop2_plane_mask_assign(struct vop2 *vop2, struct device_node *vop_ou int vp_id; int i = 0; + /* + * For VOP3, users can switch planes between different CRTCs base on the + * &drm_plane.possible_crtcs that exported to the userspace. Therefore, + * there is no need to set the &vop2_video_port.plane_mask and + * &vop2_video_port.primary_plane_phy_id by default, which are used to + * fix the binding relationship between the plane and the CRTC for VOP2. + */ + if (is_vop3(vop2)) { + for (i = 0; i < vop2->data->nr_vps; i++) { + vop2->vps[i].plane_mask = 0; + vop2->vps[i].primary_plane_phy_id = ROCKCHIP_VOP2_PHY_ID_INVALID; + } + return; + } + for_each_child_of_node(vop_out_node, child) { if (vop2_get_vp_of_status(child)) active_vp_num++; diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c index 9eafe51e72cc..6199e71596a8 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c @@ -5046,11 +5046,25 @@ static const struct vop_dump_regs rk3588_dump_regs[] = { { RK3568_HDR_LUT_CTRL, "HDR", {0}, 0 }, }; +#define RK3528_PLANE_MASK_BASE \ + (BIT(ROCKCHIP_VOP2_CLUSTER0) | \ + BIT(ROCKCHIP_VOP2_ESMART0) | BIT(ROCKCHIP_VOP2_ESMART1) | \ + BIT(ROCKCHIP_VOP2_ESMART2) | BIT(ROCKCHIP_VOP2_ESMART3)) + +#define RK3562_PLANE_MASK_BASE \ + (BIT(ROCKCHIP_VOP2_ESMART0) | BIT(ROCKCHIP_VOP2_ESMART1) | \ + BIT(ROCKCHIP_VOP2_ESMART2) | BIT(ROCKCHIP_VOP2_ESMART3)) + #define RK3568_PLANE_MASK_BASE \ (BIT(ROCKCHIP_VOP2_CLUSTER0) | BIT(ROCKCHIP_VOP2_CLUSTER1) | \ BIT(ROCKCHIP_VOP2_ESMART0) | BIT(ROCKCHIP_VOP2_ESMART1) | \ BIT(ROCKCHIP_VOP2_SMART0) | BIT(ROCKCHIP_VOP2_SMART1)) +#define RK3576_PLANE_MASK_BASE \ + (BIT(ROCKCHIP_VOP2_CLUSTER0) | BIT(ROCKCHIP_VOP2_CLUSTER1) | \ + BIT(ROCKCHIP_VOP2_ESMART0) | BIT(ROCKCHIP_VOP2_ESMART1) | \ + BIT(ROCKCHIP_VOP2_ESMART2) | BIT(ROCKCHIP_VOP2_ESMART3)) + #define RK3588_PLANE_MASK_BASE \ (BIT(ROCKCHIP_VOP2_CLUSTER0) | BIT(ROCKCHIP_VOP2_CLUSTER1) | \ BIT(ROCKCHIP_VOP2_CLUSTER2) | BIT(ROCKCHIP_VOP2_CLUSTER3) | \ @@ -5244,6 +5258,7 @@ static const struct vop2_data rk3528_vop = { .win_size = ARRAY_SIZE(rk3528_vop_win_data), .dump_regs = rk3528_dump_regs, .dump_regs_size = ARRAY_SIZE(rk3528_dump_regs), + .plane_mask_base = RK3528_PLANE_MASK_BASE, }; static const struct vop2_data rk3562_vop = { @@ -5265,6 +5280,7 @@ static const struct vop2_data rk3562_vop = { .win_size = ARRAY_SIZE(rk3562_vop_win_data), .dump_regs = rk3562_dump_regs, .dump_regs_size = ARRAY_SIZE(rk3562_dump_regs), + .plane_mask_base = RK3562_PLANE_MASK_BASE, }; static const struct vop2_data rk3568_vop = { @@ -5313,6 +5329,7 @@ static const struct vop2_data rk3576_vop = { .nr_pds = ARRAY_SIZE(rk3576_vop_pd_data), .dump_regs = rk3576_dump_regs, .dump_regs_size = ARRAY_SIZE(rk3576_dump_regs), + .plane_mask_base = RK3576_PLANE_MASK_BASE, .crc_sources = rk3576_crc_sources, .crc_sources_num = ARRAY_SIZE(rk3576_crc_sources), };