From patchwork Thu Jun 2 12:57:38 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yakir Yang X-Patchwork-Id: 9149953 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 236A260221 for ; Thu, 2 Jun 2016 12:58:07 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 13ACD26907 for ; Thu, 2 Jun 2016 12:58:07 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 088CD2824A; Thu, 2 Jun 2016 12:58:07 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.5 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, URIBL_BLACK autolearn=unavailable version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 3A80426907 for ; Thu, 2 Jun 2016 12:58:06 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1b8SCL-0007nf-TE; Thu, 02 Jun 2016 12:58:05 +0000 Received: from lucky1.263xmail.com ([211.157.147.132]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1b8SCJ-0007Z4-EJ for linux-rockchip@lists.infradead.org; Thu, 02 Jun 2016 12:58:05 +0000 Received: from ykk?rock-chips.com (unknown [192.168.167.84]) by lucky1.263xmail.com (Postfix) with SMTP id 391DE631E4; Thu, 2 Jun 2016 20:57:39 +0800 (CST) X-263anti-spam: KSV:0; X-MAIL-GRAY: 1 X-MAIL-DELIVERY: 0 X-KSVirus-check: 0 X-ABS-CHECKED: 4 X-ADDR-CHECKED: 0 Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.263.net (Postfix) with ESMTP id DAE332395A; Thu, 2 Jun 2016 20:57:32 +0800 (CST) X-RL-SENDER: ykk@rock-chips.com X-FST-TO: yzq@rock-chips.com X-SENDER-IP: 58.22.7.114 X-LOGIN-NAME: ykk@rock-chips.com X-UNIQUE-TAG: <272508efe6d73b7d1e1483f615f2a952> X-ATTACHMENT-NUM: 0 X-SENDER: ykk@rock-chips.com X-DNS-TYPE: 0 Received: from localhost.localdomain (unknown [58.22.7.114]) by smtp.263.net (Postfix) whith ESMTP id 17094OKMU3M; Thu, 02 Jun 2016 20:57:33 +0800 (CST) From: Yakir Yang To: Mark Yao , Heiko Stuebner , tfiga@chromium.org Subject: [RFC PATCH v2 3/3] drm/rockchip: analogix_dp: add PSR support Date: Thu, 2 Jun 2016 20:57:38 +0800 Message-Id: <1464872258-18468-1-git-send-email-ykk@rock-chips.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1464872228-18292-1-git-send-email-ykk@rock-chips.com> References: <1464872228-18292-1-git-send-email-ykk@rock-chips.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20160602_055804_168138_A529AB0B X-CRM114-Status: GOOD ( 17.43 ) X-BeenThere: linux-rockchip@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: Upstream kernel work for Rockchip platforms List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: David Airlie , daniel.vetter@ffwll.ch, dianders@chromium.org, dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-rockchip@lists.infradead.org, Yakir Yang , Thierry Reding MIME-Version: 1.0 Sender: "Linux-rockchip" Errors-To: linux-rockchip-bounces+patchwork-linux-rockchip=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP 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 --- Changes in v2: - Remove vblank notify out (Daniel) - Create a psr_active() callback in vop data struct. 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 + * + * 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 + +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);