From 77545064949be4694957586866dfe30ec6c4e680 Mon Sep 17 00:00:00 2001 From: Andy Yan Date: Mon, 15 Nov 2021 20:16:49 +0800 Subject: [PATCH] drm/rockchip: vop2: Don't turn off a parent pd if this module is not enabled Signed-off-by: Andy Yan Change-Id: I610af0ac0e0a31becee62be5a5e5bc9b2a61381f --- drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 2 +- drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 52 +++++++++++++------- 2 files changed, 34 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h index 5ec0a429af38..b094f0e3dc21 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h @@ -113,9 +113,9 @@ enum vop2_win_dly_mode { #define VOP2_PD_CLUSTER1 BIT(1) #define VOP2_PD_CLUSTER2 BIT(2) #define VOP2_PD_CLUSTER3 BIT(3) -#define VOP2_PD_ESMART0 BIT(4) #define VOP2_PD_DSC_8K BIT(5) #define VOP2_PD_DSC_4K BIT(6) +#define VOP2_PD_ESMART0 BIT(7) /* * vop2 submem power gate, diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index bb1613ab9d9d..92f3321faf34 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -214,6 +214,10 @@ struct vop2_power_domain { spinlock_t lock; unsigned int ref_count; bool on; + /* + * If the module powered by this power domain was enabled. + */ + bool module_on; const struct vop2_power_domain_data *data; struct list_head list; struct delayed_work power_off_work; @@ -1310,7 +1314,7 @@ static void vop2_wait_power_domain_off(struct vop2_power_domain *pd) ret = readx_poll_timeout_atomic(vop2_power_domain_status, pd, val, val, 0, 50 * 1000); if (ret) - DRM_DEV_ERROR(vop2->dev, "wait pd off timeout\n"); + DRM_DEV_ERROR(vop2->dev, "wait pd%d off timeout\n", ffs(pd->data->id) - 1); } static void vop2_wait_power_domain_on(struct vop2_power_domain *pd) @@ -1321,7 +1325,7 @@ static void vop2_wait_power_domain_on(struct vop2_power_domain *pd) ret = readx_poll_timeout_atomic(vop2_power_domain_status, pd, val, !val, 0, 50 * 1000); if (ret) - DRM_DEV_ERROR(vop2->dev, "wait pd on timeout\n"); + DRM_DEV_ERROR(vop2->dev, "wait pd%d on timeout\n", ffs(pd->data->id) - 1); } /* @@ -1332,11 +1336,11 @@ static void vop2_power_domain_on(struct vop2_power_domain *pd) struct vop2 *vop2 = pd->vop2; if (!pd->on) { + dev_dbg(vop2->dev, "pd%d on\n", ffs(pd->data->id) - 1); vop2_wait_power_domain_off(pd); VOP_MODULE_SET(vop2, pd->data, pd, 0); vop2_wait_power_domain_on(pd); pd->on = true; - dev_dbg(vop2->dev, "pd%d on\n", pd->data->id); } } @@ -1347,7 +1351,7 @@ static void vop2_power_domain_off(struct vop2_power_domain *pd) { struct vop2 *vop2 = pd->vop2; - dev_dbg(vop2->dev, "pd%d off\n", pd->data->id); + dev_dbg(vop2->dev, "pd%d off\n", ffs(pd->data->id) - 1); pd->on = false; VOP_MODULE_SET(vop2, pd->data, pd, 1); } @@ -1370,7 +1374,24 @@ static void vop2_power_domain_get(struct vop2_power_domain *pd) static void vop2_power_domain_put(struct vop2_power_domain *pd) { spin_lock(&pd->lock); - if (--pd->ref_count == 0) { + + /* + * For a nested power domain(PD_Cluster0 is the parent of PD_CLuster1/2/3) + * the parent powe domain must be enabled before child power domain + * is on. + * + * So we may met this condition: Cluster0 is not enabled, but PD_Cluster0 + * must enabled as one of the child PD_CLUSTER1/2/3 is enabled. + * when all child PD is disabled, we want disable the parent + * PD(PD_CLUSTER0), but as module CLUSTER0 is not enabled, + * the turn down configuration will never take effect. + * so we will see a "wait pd0 off timeout" log when we + * turn on PD_CLUSTER0 next time. + * + * So don't try to turn off a power domain when the module is not + * enabled. + */ + if (--pd->ref_count == 0 && pd->module_on) { if (pd->vop2->data->delayed_pd) schedule_delayed_work(&pd->power_off_work, msecs_to_jiffies(2500)); else @@ -1401,8 +1422,10 @@ static void vop2_power_domain_off_work(struct work_struct *work) static void vop2_win_enable(struct vop2_win *win) { if (!win->enabled) { - if (win->pd) + if (win->pd) { vop2_power_domain_get(win->pd); + win->pd->module_on = true; + } win->enabled = true; } } @@ -1450,8 +1473,10 @@ static void vop2_win_disable(struct vop2_win *win) */ if (!win->parent && (win->feature & WIN_FEATURE_MULTI_AREA)) vop2_win_multi_area_disable(win); - if (win->pd) + if (win->pd) { vop2_power_domain_put(win->pd); + win->pd->module_on = false; + } win->enabled = false; } } @@ -2982,15 +3007,6 @@ static void rk3588_vop2_regsbak(struct vop2 *vop2) vop2->regsbak[i] = base[i]; } -static void vop2_power_domain_init(struct vop2 *vop2) -{ - struct vop2_power_domain *pd, *n; - - list_for_each_entry_safe(pd, n, &vop2->pd_list_head, list) { - vop2_power_domain_on(pd); - } -} - static void vop2_initial(struct drm_crtc *crtc) { struct vop2_video_port *vp = to_vop2_video_port(crtc); @@ -3019,8 +3035,6 @@ static void vop2_initial(struct drm_crtc *crtc) if (vop2_soc_is_rk3566()) VOP_CTRL_SET(vop2, otp_en, 1); - vop2_power_domain_init(vop2); - /* dsc must deassert rst before its register can accessed */ for (i = 0; i < vop2_data->nr_dscs; i++) { dsc = &vop2->dscs[i]; @@ -3059,7 +3073,6 @@ static void vop2_initial(struct drm_crtc *crtc) vop2_layer_map_initial(vop2, current_vp_id); vop2_axi_irqs_enable(vop2); - vop2->is_enabled = true; } @@ -7796,6 +7809,7 @@ static int vop2_pd_data_init(struct vop2 *vop2) return -ENOMEM; pd->vop2 = vop2; pd->data = pd_data; + pd->module_on = false; spin_lock_init(&pd->lock); list_add_tail(&pd->list, &vop2->pd_list_head); INIT_DELAYED_WORK(&pd->power_off_work, vop2_power_domain_off_work);