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), };