diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index 88b149375f10..f50add350628 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -679,8 +679,9 @@ static void show_loader_logo(struct drm_device *drm_dev) struct device_node *np = drm_dev->dev->of_node; struct drm_mode_config *mode_config = &drm_dev->mode_config; struct device_node *root, *route; - struct rockchip_drm_mode_set *set, *tmp; + struct rockchip_drm_mode_set *set, *tmp, *unset; struct list_head mode_set_list; + struct list_head mode_unset_list; unsigned plane_mask = 0; int ret; @@ -696,6 +697,7 @@ static void show_loader_logo(struct drm_device *drm_dev) } INIT_LIST_HEAD(&mode_set_list); + INIT_LIST_HEAD(&mode_unset_list); drm_modeset_lock_all(drm_dev); state = drm_atomic_state_alloc(drm_dev); if (!state) { @@ -716,13 +718,41 @@ static void show_loader_logo(struct drm_device *drm_dev) if (setup_initial_state(drm_dev, state, set)) { drm_framebuffer_unreference(set->fb); - kfree(set); + INIT_LIST_HEAD(&set->head); + list_add_tail(&set->head, &mode_unset_list); continue; } INIT_LIST_HEAD(&set->head); list_add_tail(&set->head, &mode_set_list); } + /* + * the mode_unset_list store the unconnected route, if route's crtc + * isn't used, we should close it. + */ + list_for_each_entry_safe(unset, tmp, &mode_unset_list, head) { + struct rockchip_drm_mode_set *tmp_set; + int found_used_crtc = 0; + + list_for_each_entry_safe(set, tmp_set, &mode_set_list, head) { + if (set->crtc == unset->crtc) { + found_used_crtc = 1; + continue; + } + } + if (!found_used_crtc) { + struct drm_crtc *crtc = unset->crtc; + int pipe = drm_crtc_index(crtc); + struct rockchip_drm_private *priv = + drm_dev->dev_private; + + if (unset->hdisplay && unset->vdisplay) + priv->crtc_funcs[pipe]->crtc_close(crtc); + } + list_del(&unset->head); + kfree(unset); + } + if (list_empty(&mode_set_list)) { dev_warn(drm_dev->dev, "can't not find any loader display\n"); ret = -ENXIO; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index 7c090c97bf83..cd1500604f36 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -52,6 +52,7 @@ struct rockchip_crtc_funcs { enum drm_mode_status (*mode_valid)(struct drm_crtc *crtc, const struct drm_display_mode *mode, int output_type); + void (*crtc_close)(struct drm_crtc *crtc); }; struct drm_rockchip_subdrv { diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 898e85f8552f..f7edd04728c3 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -1344,6 +1344,7 @@ static void vop_crtc_disable(struct drm_crtc *crtc) mutex_lock(&vop->vop_lock); drm_crtc_vblank_off(crtc); + vop_disable_all_planes(vop); /* * Vop standby will take effect at end of current frame, @@ -1373,6 +1374,7 @@ static void vop_crtc_disable(struct drm_crtc *crtc) /* * vop standby complete, so iommu detach is safe. */ + VOP_CTRL_SET(vop, dma_stop, 1); rockchip_drm_dma_detach_device(vop->drm_dev, vop->dev); vop->is_iommu_enabled = false; } @@ -2290,6 +2292,16 @@ static size_t vop_crtc_bandwidth(struct drm_crtc *crtc, return bandwidth; } +static void vop_crtc_close(struct drm_crtc *crtc) +{ + struct vop *vop = NULL; + + if (!crtc) + return; + vop = to_vop(crtc); + vop_disable_all_planes(vop); +} + static const struct rockchip_crtc_funcs private_crtc_funcs = { .loader_protect = vop_crtc_loader_protect, .enable_vblank = vop_crtc_enable_vblank, @@ -2300,6 +2312,7 @@ static const struct rockchip_crtc_funcs private_crtc_funcs = { .regs_dump = vop_crtc_regs_dump, .mode_valid = vop_crtc_mode_valid, .bandwidth = vop_crtc_bandwidth, + .crtc_close = vop_crtc_close, }; static bool vop_crtc_mode_fixup(struct drm_crtc *crtc, @@ -2450,20 +2463,24 @@ static void vop_crtc_enable(struct drm_crtc *crtc) SYS_STATUS_LCDC1 : SYS_STATUS_LCDC0; uint32_t val; int act_end; + bool interlaced = !!(adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE); rockchip_set_system_status(sys_status); mutex_lock(&vop->vop_lock); + DRM_DEV_INFO(vop->dev, "Update mode to %dx%d%s%d, type: %d\n", + hdisplay, vdisplay, interlaced ? "i" : "p", + adjusted_mode->vrefresh, s->output_type); vop_initial(crtc); - + vop_disable_allwin(vop); VOP_CTRL_SET(vop, standby, 0); - vop_disable_all_planes(vop); + vop->mode_update = vop_crtc_mode_update(crtc); + if (vop->mode_update) + vop_disable_all_planes(vop); /* * restore the lut table. */ if (vop->lut_active) vop_crtc_load_lut(crtc); - vop->mode_update = vop_crtc_mode_update(crtc); - DRM_DEV_INFO(vop->dev, "Update mode to %d*%d\n", hdisplay, vdisplay); VOP_CTRL_SET(vop, dclk_pol, 1); val = (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) ? 0 : BIT(HSYNC_POSITIVE); @@ -3219,6 +3236,7 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc, ret); } else { vop->is_iommu_enabled = true; + VOP_CTRL_SET(vop, dma_stop, 0); } if (need_wait_vblank) { diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h index 61760b233e7d..e8b14e4036d1 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h @@ -102,6 +102,7 @@ struct vop_csc { struct vop_ctrl { struct vop_reg version; struct vop_reg standby; + struct vop_reg dma_stop; struct vop_reg axi_outstanding_max_num; struct vop_reg axi_max_outstanding_en; struct vop_reg htotal_pw; diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c index 21cc1cadddc5..ecfacd2022ac 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c @@ -174,6 +174,7 @@ static const struct vop_win_phy *rk3288_area_data[] = { static const struct vop_ctrl rk3288_ctrl_data = { .version = VOP_REG(RK3288_VERSION_INFO, 0xffff, 16), .standby = VOP_REG(RK3288_SYS_CTRL, 0x1, 22), + .dma_stop = VOP_REG(RK3288_SYS_CTRL, 0x1, 21), .axi_outstanding_max_num = VOP_REG(RK3288_SYS_CTRL1, 0x1f, 13), .axi_max_outstanding_en = VOP_REG(RK3288_SYS_CTRL1, 0x1, 12), .reg_done_frm = VOP_REG_VER(RK3288_SYS_CTRL1, 0x1, 24, 3, 7, -1), @@ -880,6 +881,7 @@ static const struct vop_hdr_table rk3328_hdr_table = { static const struct vop_ctrl rk3328_ctrl_data = { .standby = VOP_REG(RK3328_SYS_CTRL, 0x1, 22), + .dma_stop = VOP_REG(RK3328_SYS_CTRL, 0x1, 21), .axi_outstanding_max_num = VOP_REG(RK3328_SYS_CTRL1, 0x1f, 13), .axi_max_outstanding_en = VOP_REG(RK3328_SYS_CTRL1, 0x1, 12), .reg_done_frm = VOP_REG(RK3328_SYS_CTRL1, 0x1, 24),