Hi Daniel, Thanks for your fast respond. On 06/02/2016 09:18 PM, Daniel Vetter wrote: > On Thu, Jun 02, 2016 at 08:57:38PM +0800, Yakir Yang wrote: >> Let VOP vblank status decide whether panle should enter into or >> exit from PSR status. Before eDP start to change PSR status, it >> need to wait for VOP vact_end event. In order to listen vact_end >> event, I create a new file about PSR notify between eDP and VOP. >> >> Signed-off-by: Yakir Yang <ykk at rock-chips.com> >> --- >> Changes in v2: >> - Remove vblank notify out (Daniel) >> - Create a psr_active() callback in vop data struct. > Still contains a notifier. Still doesn't contain a proper fb->dirty > callback. Please don't just act on review without understanding the deeper > implications, since I didn't ask you to remove the vblank logic (you > probably still need that), I suggested to implement it differently > (withotu notifiers). > -Daniel Yes, I misunderstand what you comment before, I thought only the vblank notify is bad, so i create a callback entry in vop. But the vact_end event is still an evil too, specific to a given crtc. Hmmm, after i abandon the notify, i need to found a good way for eDP to get the vact_end or vblank event. That would be a question, have no idea now..... As for why i ignore the the fb->dirty callback in this case, please see my previous reply to you. Thanks, - Yakir >> drivers/gpu/drm/rockchip/Makefile | 2 +- >> drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 64 ++++++++++++++++++++++++- >> drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 7 +++ >> drivers/gpu/drm/rockchip/rockchip_drm_notify.c | 54 +++++++++++++++++++++ >> drivers/gpu/drm/rockchip/rockchip_drm_notify.h | 23 +++++++++ >> drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 41 ++++++++++++++++ >> 6 files changed, 189 insertions(+), 2 deletions(-) >> create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_notify.c >> create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_notify.h >> >> diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile >> index 05d0713..49fee8c 100644 >> --- a/drivers/gpu/drm/rockchip/Makefile >> +++ b/drivers/gpu/drm/rockchip/Makefile >> @@ -3,7 +3,7 @@ >> # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. >> >> rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \ >> - rockchip_drm_gem.o rockchip_drm_vop.o >> + rockchip_drm_gem.o rockchip_drm_vop.o rockchip_drm_notify.o >> rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o >> >> obj-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o >> diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c >> index 4b64964..25fb687 100644 >> --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c >> +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c >> @@ -33,6 +33,7 @@ >> >> #include "rockchip_drm_drv.h" >> #include "rockchip_drm_vop.h" >> +#include "rockchip_drm_notify.h" >> >> #define to_dp(nm) container_of(nm, struct rockchip_dp_device, nm) >> >> @@ -54,6 +55,10 @@ struct rockchip_dp_device { >> struct regmap *grf; >> struct reset_control *rst; >> >> + struct workqueue_struct *dp_workq; >> + struct work_struct psr_work; >> + unsigned int psr_state; >> + >> const struct rockchip_dp_chip_data *data; >> >> struct analogix_dp_plat_data plat_data; >> @@ -97,6 +102,42 @@ static int rockchip_dp_powerdown(struct analogix_dp_plat_data *plat_data) >> return 0; >> } >> >> +static int rockchip_dp_psr_active(enum psr_action action, void *priv) >> +{ >> + struct rockchip_dp_device *dp = (struct rockchip_dp_device *)priv; >> + >> + switch (action) { >> + case PSR_INACTIVE: >> + dp->psr_state = 0; >> + break; >> + case PSR_ACTIVE: >> + dp->psr_state = EDP_VSC_PSR_STATE_ACTIVE; >> + break; >> + default: >> + return 0; >> + } >> + >> + queue_work(dp->dp_workq, &dp->psr_work); >> + return 0; >> +} >> + >> +static void dp_psr_work(struct work_struct *psr_work) >> +{ >> + struct rockchip_dp_device *dp = to_dp(psr_work); >> + int psr_state = dp->psr_state; >> + int ret; >> + >> + if (psr_state == EDP_VSC_PSR_STATE_ACTIVE) { >> + ret = rockchip_psr_ready_wait(); >> + if (ret == 0) >> + analogix_dp_actice_psr(dp->dev); >> + } else { >> + ret = rockchip_psr_ready_wait(); >> + if (ret == 0) >> + analogix_dp_inactice_psr(dp->dev); >> + } >> +} >> + >> static enum drm_mode_status >> rockchip_dp_mode_valid(struct analogix_dp_plat_data *plat_data, >> struct drm_connector *connector, >> @@ -128,9 +169,18 @@ static void rockchip_dp_drm_encoder_mode_set(struct drm_encoder *encoder, >> struct drm_display_mode *mode, >> struct drm_display_mode *adjusted) >> { >> - /* do nothing */ >> + struct rockchip_dp_device *dp = to_dp(encoder); >> + struct drm_crtc *crtc = encoder->crtc; >> + struct rockchip_crtc_state *s; >> + >> + if (crtc) { >> + s = to_rockchip_crtc_state(crtc->state); >> + s->psr_active = rockchip_dp_psr_active; >> + s->psr_priv = dp; >> + } >> } >> >> + >> static void rockchip_dp_drm_encoder_enable(struct drm_encoder *encoder) >> { >> struct rockchip_dp_device *dp = to_dp(encoder); >> @@ -198,6 +248,9 @@ rockchip_dp_drm_encoder_atomic_check(struct drm_encoder *encoder, >> break; >> } >> >> + s->psr_active = rockchip_dp_psr_active; >> + s->psr_priv = dp; >> + >> return 0; >> } >> >> @@ -320,6 +373,15 @@ static int rockchip_dp_bind(struct device *dev, struct device *master, >> dp->plat_data.power_off = rockchip_dp_powerdown; >> dp->plat_data.mode_valid = rockchip_dp_mode_valid; >> >> + dp->dp_workq = create_singlethread_workqueue("dp"); >> + if (!dp->dp_workq) { >> + dev_err(dp->dev, "failed to create workqueue\n"); >> + return PTR_ERR(dp->dp_workq); >> + } >> + >> + dp->psr_state = 0; >> + INIT_WORK(&dp->psr_work, dp_psr_work); >> + >> return analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data); >> } >> >> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h >> index 56f43a3..f1ccc10 100644 >> --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h >> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h >> @@ -31,6 +31,11 @@ >> struct drm_device; >> struct drm_connector; >> >> +enum psr_action { >> + PSR_ACTIVE = 0, >> + PSR_INACTIVE, >> +}; >> + >> /* >> * Rockchip drm private crtc funcs. >> * @enable_vblank: enable crtc vblank irq. >> @@ -54,6 +59,8 @@ struct rockchip_crtc_state { >> struct drm_crtc_state base; >> int output_type; >> int output_mode; >> + int (*psr_active)(enum psr_action action, void *priv); >> + void *psr_priv; >> }; >> #define to_rockchip_crtc_state(s) \ >> container_of(s, struct rockchip_crtc_state, base) >> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_notify.c b/drivers/gpu/drm/rockchip/rockchip_drm_notify.c >> new file mode 100644 >> index 0000000..908e991 >> --- /dev/null >> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_notify.c >> @@ -0,0 +1,54 @@ >> +/* >> + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd >> + * Author: Yakir Yang <ykk at rock-chips.com> >> + * >> + * This software is licensed under the terms of the GNU General Public >> + * License version 2, as published by the Free Software Foundation, and >> + * may be copied, distributed, and modified under those terms. >> + * >> + * This program is distributed in the hope that it will be useful, >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> + * GNU General Public License for more details. >> + */ >> + >> +#include "rockchip_drm_notify.h" >> + >> +static RAW_NOTIFIER_HEAD(psr_ready_chain); >> +static DEFINE_MUTEX(psr_ready_lock); >> + >> +int rockchip_drm_psr_ready_register_notifier(struct notifier_block *nb) >> +{ >> + int ret = 0; >> + >> + if (!nb) >> + return -EINVAL; >> + >> + ret = raw_notifier_chain_register(&psr_ready_chain, nb); >> + return ret; >> +} >> +EXPORT_SYMBOL_GPL(rockchip_drm_psr_ready_register_notifier); >> + >> +int rockchip_drm_psr_ready_unregister_notifier(struct notifier_block *nb) >> +{ >> + int ret = 0; >> + >> + if (!nb) >> + return -EINVAL; >> + >> + ret = raw_notifier_chain_unregister(&psr_ready_chain, nb); >> + return ret; >> +} >> +EXPORT_SYMBOL_GPL(rockchip_drm_psr_ready_unregister_notifier); >> + >> +int rockchip_psr_ready_wait(void) >> +{ >> + int ret; >> + >> + ret = raw_notifier_call_chain(&psr_ready_chain, 0, 0); >> + if (ret == NOTIFY_BAD) >> + return -ETIMEDOUT; >> + >> + return 0; >> +} >> +EXPORT_SYMBOL_GPL(rockchip_psr_ready_wait); >> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_notify.h b/drivers/gpu/drm/rockchip/rockchip_drm_notify.h >> new file mode 100644 >> index 0000000..1b190e5 >> --- /dev/null >> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_notify.h >> @@ -0,0 +1,23 @@ >> +/* >> + * Copyright (C) 2014 Google, Inc. >> + * >> + * This software is licensed under the terms of the GNU General Public >> + * License version 2, as published by the Free Software Foundation, and >> + * may be copied, distributed, and modified under those terms. >> + * >> + * This program is distributed in the hope that it will be useful, >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> + * GNU General Public License for more details. >> + */ >> + >> +#ifndef __ROCKCHIP_DRM_NOTIFY_H >> +#define __ROCKCHIP_DRM_NOTIFY_H >> + >> +#include <linux/notifier.h> >> + >> +int rockchip_psr_ready_wait(void); >> +int rockchip_drm_psr_ready_register_notifier(struct notifier_block *nb); >> +int rockchip_drm_psr_ready_unregister_notifier(struct notifier_block *nb); >> + >> +#endif /* __ROCKCHIP_DRM_NOTIFY_H */ >> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c >> index b2a36db..b5a015b 100644 >> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c >> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c >> @@ -35,6 +35,7 @@ >> #include "rockchip_drm_gem.h" >> #include "rockchip_drm_fb.h" >> #include "rockchip_drm_vop.h" >> +#include "rockchip_drm_notify.h" >> >> #define __REG_SET_RELAXED(x, off, mask, shift, v, write_mask) \ >> vop_mask_write(x, off, mask, shift, v, write_mask, true) >> @@ -117,6 +118,10 @@ struct vop { >> struct completion wait_update_complete; >> struct drm_pending_vblank_event *event; >> >> + /* eDP PSR callback */ >> + int (*psr_active)(enum psr_action action, void *priv); >> + void *psr_priv; >> + struct notifier_block psr_prepare_nb; >> struct completion line_flag_completion; >> >> const struct vop_data *data; >> @@ -906,6 +911,9 @@ static int vop_crtc_enable_vblank(struct drm_crtc *crtc) >> >> spin_unlock_irqrestore(&vop->irq_lock, flags); >> >> + if (vop->psr_active) >> + vop->psr_active(PSR_INACTIVE, vop->psr_priv); >> + >> return 0; >> } >> >> @@ -922,6 +930,9 @@ static void vop_crtc_disable_vblank(struct drm_crtc *crtc) >> VOP_INTR_SET_TYPE(vop, enable, FS_INTR, 0); >> >> spin_unlock_irqrestore(&vop->irq_lock, flags); >> + >> + if (vop->psr_active) >> + vop->psr_active(PSR_ACTIVE, vop->psr_priv); >> } >> >> static void vop_crtc_wait_for_update(struct drm_crtc *crtc) >> @@ -1066,6 +1077,9 @@ static void vop_crtc_enable(struct drm_crtc *crtc) >> clk_set_rate(vop->dclk, adjusted_mode->clock * 1000); >> >> VOP_CTRL_SET(vop, standby, 0); >> + >> + vop->psr_active = s->psr_active; >> + vop->psr_priv = s->psr_priv; >> } >> >> static void vop_crtc_atomic_flush(struct drm_crtc *crtc, >> @@ -1178,6 +1192,30 @@ static void vop_handle_vblank(struct vop *vop) >> complete(&vop->wait_update_complete); >> } >> >> +static int psr_prepare_notify(struct notifier_block *psr_prepare_nb, >> + unsigned long action, void *data) >> +{ >> + struct vop *vop = container_of(psr_prepare_nb, struct vop, >> + psr_prepare_nb); >> + struct drm_display_mode *mode = &vop->crtc.mode; >> + int vact_end = mode->vtotal - mode->vsync_start + mode->vdisplay; >> + unsigned long jiffies_left; >> + >> + reinit_completion(&vop->line_flag_completion); >> + vop_line_flag_irq_enable(vop, vact_end); >> + >> + jiffies_left = wait_for_completion_timeout(&vop->line_flag_completion, >> + msecs_to_jiffies(200)); >> + vop_line_flag_irq_disable(vop); >> + >> + if (jiffies_left == 0) { >> + dev_err(vop->dev, "Timeout waiting for IRQ\n"); >> + return NOTIFY_BAD; >> + } >> + >> + return NOTIFY_STOP; >> +} >> + >> static irqreturn_t vop_isr(int irq, void *data) >> { >> struct vop *vop = data; >> @@ -1312,6 +1350,9 @@ static int vop_create_crtc(struct vop *vop) >> goto err_cleanup_crtc; >> } >> >> + vop->psr_prepare_nb.notifier_call = psr_prepare_notify; >> + rockchip_drm_psr_ready_register_notifier(&vop->psr_prepare_nb); >> + >> init_completion(&vop->dsp_hold_completion); >> init_completion(&vop->wait_update_complete); >> init_completion(&vop->line_flag_completion); >> -- >> 1.9.1 >> >> >> _______________________________________________ >> dri-devel mailing list >> dri-devel at lists.freedesktop.org >> https://lists.freedesktop.org/mailman/listinfo/dri-devel