Received: by 10.213.65.68 with SMTP id h4csp542727imn; Fri, 30 Mar 2018 10:21:44 -0700 (PDT) X-Google-Smtp-Source: AIpwx49NsU/AwwOFzvRgMqNxeh4B71Sv6fHGJexApKlPPjKbSi8Ero8dtZ7O4A5LpoP9SXL5Um3N X-Received: by 10.101.101.66 with SMTP id a2mr9124642pgw.223.1522430504464; Fri, 30 Mar 2018 10:21:44 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1522430504; cv=none; d=google.com; s=arc-20160816; b=0szU7gkshj0LAiKTYYpmKFItljgBmxAqjhC96BmsPvrZnZFytWVFOCFp2SwT8NIu70 hyxu/qyOrDWiGkvofnsT4lzIQ/sgMKxk13eu24PiFjnBjfpsshuBlkINHgAa/7gIYtzm 2aK8MHoYZI4av29Qw1GmyHT4q9lr0IoDEwR5mFi4q69hCs+XU6sFL7rTpePscrRRE/u0 MMBK6CrtmSzMAD1MHJCd+MttieWugbl0IBlJN7Oh+KWGRn5636Y395KS18AhtsIz8Q4c X3qc2/MIxz+LVxRDcwfdBoEAJiKIRf7XBosNJOla47RVwDczpAWYpeKUBqtpdTWN+M0t IGcg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:arc-authentication-results; bh=S0SRv8MLibdKBaJTVFcwk76N4LhQZxv0iORyCYosZVg=; b=qE/pMnS9edpptMpNILhO3zSMVoFJH5WXJH6R1Ae4GTczouztxa4QH/DLSIqclObjqI gH4PwWr5D5v2k1dhIdZEHWf8Ikzf/KEbXSvZWBvDGaZzNd5qif9FqLBMHija58bVrCbX o13xlyJhEwOMliOn8PVa6pAnaeIU700VHbNoRsV+v8cIZhRRP/zh14tYxUSZyDRjBpEG 9gRmM+ArL3JL+6qU4Ces+hWJqHXHJH5cIvK+mmodh1EWjkCPKeX4h16DaUrcpcHNKsQK FKPmco143NJNz87GVczuiPVBNF4gP/pHeSoVCusqLq/SxqZ0fYwuBxoOsvaAb+D8IR3g vh5g== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=collabora.co.uk Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id q10-v6si9501610plk.29.2018.03.30.10.21.30; Fri, 30 Mar 2018 10:21:44 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=collabora.co.uk Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752665AbeC3RT5 (ORCPT + 99 others); Fri, 30 Mar 2018 13:19:57 -0400 Received: from bhuna.collabora.co.uk ([46.235.227.227]:58738 "EHLO bhuna.collabora.co.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751868AbeC3RSf (ORCPT ); Fri, 30 Mar 2018 13:18:35 -0400 Received: from [127.0.0.1] (localhost [127.0.0.1]) (Authenticated sender: sre) with ESMTPSA id 68580276105 From: Sebastian Reichel To: Sebastian Reichel , Tomi Valkeinen , Tony Lindgren , Pavel Machek Cc: Laurent Pinchart , Rob Herring , Mark Rutland , dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, linux-omap@vger.kernel.org, linux-kernel@vger.kernel.org, kernel@collabora.com, Sebastian Reichel Subject: [PATCHv3 3/8] drm/omap: add support for manually updated displays Date: Fri, 30 Mar 2018 19:18:17 +0200 Message-Id: <20180330171822.25896-4-sebastian.reichel@collabora.co.uk> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180330171822.25896-1-sebastian.reichel@collabora.co.uk> References: <20180330171822.25896-1-sebastian.reichel@collabora.co.uk> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This adds the required infrastructure for manually updated displays, such as DSI command mode panels. While those panels often support partial updates we currently always do a full refresh. Display will be refreshed when something calls the dirty callback, such as libdrm's drmModeDirtyFB(). This is currently being implemented for the kernel console and for Xorg. Weston currently does not implement this and is known not to work on manually updated displays. Tested-by: Tony Lindgren Signed-off-by: Sebastian Reichel --- drivers/gpu/drm/omapdrm/omap_crtc.c | 107 +++++++++++++++++++++++++++++++++--- drivers/gpu/drm/omapdrm/omap_crtc.h | 1 + drivers/gpu/drm/omapdrm/omap_fb.c | 20 +++++++ 3 files changed, 120 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index b893985e4efb..1b91bff5bac6 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -51,6 +51,7 @@ struct omap_crtc { bool pending; wait_queue_head_t pending_wait; struct drm_pending_vblank_event *event; + struct delayed_work update_work; void (*framedone_handler)(void *); void *framedone_handler_data; @@ -146,6 +147,25 @@ static void omap_crtc_dss_disconnect(struct omap_drm_private *priv, static void omap_crtc_dss_start_update(struct omap_drm_private *priv, enum omap_channel channel) { + priv->dispc_ops->mgr_enable(priv->dispc, channel, true); +} + +static bool omap_crtc_is_manually_updated(struct drm_crtc *crtc) +{ + struct drm_connector *connector; + struct drm_connector_list_iter conn_iter; + bool result = false; + + drm_connector_list_iter_begin(crtc->dev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { + if (connector->state->crtc != crtc) + continue; + result = omap_connector_get_manually_updated(connector); + break; + } + drm_connector_list_iter_end(&conn_iter); + + return result; } /* Called only from the encoder enable/disable and suspend/resume handlers. */ @@ -157,12 +177,17 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable) enum omap_channel channel = omap_crtc->channel; struct omap_irq_wait *wait; u32 framedone_irq, vsync_irq; + bool is_manual = omap_crtc_is_manually_updated(crtc); + enum omap_display_type type = omap_crtc_output[channel]->output_type; int ret; if (WARN_ON(omap_crtc->enabled == enable)) return; - if (omap_crtc_output[channel]->output_type == OMAP_DISPLAY_TYPE_HDMI) { + if (is_manual) + omap_irq_enable_framedone(crtc, enable); + + if (is_manual || type == OMAP_DISPLAY_TYPE_HDMI) { priv->dispc_ops->mgr_enable(priv->dispc, channel, enable); omap_crtc->enabled = enable; return; @@ -214,7 +239,6 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable) } } - static int omap_crtc_dss_enable(struct omap_drm_private *priv, enum omap_channel channel) { @@ -378,6 +402,53 @@ void omap_crtc_framedone_irq(struct drm_crtc *crtc, uint32_t irqstatus) wake_up(&omap_crtc->pending_wait); } +void omap_crtc_flush(struct drm_crtc *crtc) +{ + struct omap_crtc *omap_crtc = to_omap_crtc(crtc); + + if (!omap_crtc_is_manually_updated(crtc)) + return; + + if (!delayed_work_pending(&omap_crtc->update_work)) + schedule_delayed_work(&omap_crtc->update_work, 0); +} + +static void omap_crtc_manual_display_update(struct work_struct *data) +{ + struct omap_crtc *omap_crtc = + container_of(data, struct omap_crtc, update_work.work); + struct omap_dss_device *dssdev = omap_crtc_output[omap_crtc->channel]; + struct drm_device *dev = omap_crtc->base.dev; + struct omap_dss_driver *dssdrv; + int ret, width, height; + + if (!dssdev || !dssdev->dst) { + dev_err_once(dev->dev, "missing dssdev!"); + return; + } + + dssdev = dssdev->dst; + dssdrv = dssdev->driver; + + if (!dssdrv || !dssdrv->update) { + dev_err_once(dev->dev, "incorrect dssdrv!"); + return; + } + + if (dssdrv->sync) + dssdrv->sync(dssdev); + + width = dssdev->panel.vm.hactive; + height = dssdev->panel.vm.vactive; + ret = dssdrv->update(dssdev, 0, 0, width, height); + if (ret < 0) { + spin_lock_irq(&dev->event_lock); + omap_crtc->pending = false; + spin_unlock_irq(&dev->event_lock); + wake_up(&omap_crtc->pending_wait); + } +} + static void omap_crtc_write_crtc_properties(struct drm_crtc *crtc) { struct omap_drm_private *priv = crtc->dev->dev_private; @@ -430,6 +501,10 @@ static void omap_crtc_atomic_enable(struct drm_crtc *crtc, DBG("%s", omap_crtc->name); + /* manual updated display will not trigger vsync irq */ + if (omap_crtc_is_manually_updated(crtc)) + return; + spin_lock_irq(&crtc->dev->event_lock); drm_crtc_vblank_on(crtc); ret = drm_crtc_vblank_get(crtc); @@ -443,6 +518,7 @@ static void omap_crtc_atomic_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) { struct omap_crtc *omap_crtc = to_omap_crtc(crtc); + struct drm_device *dev = crtc->dev; DBG("%s", omap_crtc->name); @@ -453,6 +529,11 @@ static void omap_crtc_atomic_disable(struct drm_crtc *crtc, } spin_unlock_irq(&crtc->dev->event_lock); + cancel_delayed_work(&omap_crtc->update_work); + + if (!omap_crtc_wait_pending(crtc)) + dev_warn(dev->dev, "manual display update did not finish!"); + drm_crtc_vblank_off(crtc); } @@ -603,13 +684,20 @@ static void omap_crtc_atomic_flush(struct drm_crtc *crtc, DBG("%s: GO", omap_crtc->name); - ret = drm_crtc_vblank_get(crtc); - WARN_ON(ret != 0); + if (!omap_crtc_is_manually_updated(crtc)) { + ret = drm_crtc_vblank_get(crtc); + WARN_ON(ret != 0); - spin_lock_irq(&crtc->dev->event_lock); - priv->dispc_ops->mgr_go(priv->dispc, omap_crtc->channel); - omap_crtc_arm_event(crtc); - spin_unlock_irq(&crtc->dev->event_lock); + spin_lock_irq(&crtc->dev->event_lock); + priv->dispc_ops->mgr_go(priv->dispc, omap_crtc->channel); + omap_crtc_arm_event(crtc); + spin_unlock_irq(&crtc->dev->event_lock); + } else { + spin_lock_irq(&crtc->dev->event_lock); + omap_crtc_flush(crtc); + omap_crtc_arm_event(crtc); + spin_unlock_irq(&crtc->dev->event_lock); + } } static int omap_crtc_atomic_set_property(struct drm_crtc *crtc, @@ -771,6 +859,9 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, omap_crtc->channel = channel; omap_crtc->name = channel_names[channel]; + INIT_DELAYED_WORK(&omap_crtc->update_work, + omap_crtc_manual_display_update); + ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL, &omap_crtc_funcs, NULL); if (ret < 0) { diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.h b/drivers/gpu/drm/omapdrm/omap_crtc.h index c748adc91665..300b6498d03e 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.h +++ b/drivers/gpu/drm/omapdrm/omap_crtc.h @@ -40,5 +40,6 @@ int omap_crtc_wait_pending(struct drm_crtc *crtc); void omap_crtc_error_irq(struct drm_crtc *crtc, u32 irqstatus); void omap_crtc_vblank_irq(struct drm_crtc *crtc); void omap_crtc_framedone_irq(struct drm_crtc *crtc, uint32_t irqstatus); +void omap_crtc_flush(struct drm_crtc *crtc); #endif /* __OMAPDRM_CRTC_H__ */ diff --git a/drivers/gpu/drm/omapdrm/omap_fb.c b/drivers/gpu/drm/omapdrm/omap_fb.c index 5fd22ca73913..b65212c9a423 100644 --- a/drivers/gpu/drm/omapdrm/omap_fb.c +++ b/drivers/gpu/drm/omapdrm/omap_fb.c @@ -95,8 +95,28 @@ static void omap_framebuffer_destroy(struct drm_framebuffer *fb) kfree(omap_fb); } +static int omap_framebuffer_dirty(struct drm_framebuffer *fb, + struct drm_file *file_priv, + unsigned flags, unsigned color, + struct drm_clip_rect *clips, + unsigned num_clips) +{ + struct drm_connector *connector = NULL; + + drm_modeset_lock_all(fb->dev); + + while ((connector = omap_framebuffer_get_next_connector(fb, connector))) + if (connector->encoder && connector->encoder->crtc) + omap_crtc_flush(connector->encoder->crtc); + + drm_modeset_unlock_all(fb->dev); + + return 0; +} + static const struct drm_framebuffer_funcs omap_framebuffer_funcs = { .create_handle = omap_framebuffer_create_handle, + .dirty = omap_framebuffer_dirty, .destroy = omap_framebuffer_destroy, }; -- 2.16.2