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@xxxxxxxxxxxxxx> > --- > 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 > > 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@xxxxxxxxxxxxxx> > + * > + * 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@xxxxxxxxxxxxxxxxxxxxx > https://lists.freedesktop.org/mailman/listinfo/dri-devel -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel