tRemove pwclient and add patches to tree - arm-sdk - os build toolkit for various embedded devices (HTM) git clone https://git.parazyd.org/arm-sdk (DIR) Log (DIR) Files (DIR) Refs (DIR) Submodules (DIR) README (DIR) LICENSE --- (DIR) commit 4505896abaf1a7b30fa723383575aba5c59e84f3 (DIR) parent 6718f5d50438c71c0c484247929ca705ebce61b7 (HTM) Author: David Derby <dderby@users.noreply.github.com> Date: Fri, 20 Apr 2018 10:14:56 -0500 Remove pwclient and add patches to tree Diffstat: M boards/nokia-n9.sh | 20 +------------------- M boards/nokia-n950.sh | 20 +------------------- A extra/patches/linux-n9-patches/000… | 175 +++++++++++++++++++++++++++++++ A extra/patches/linux-n9-patches/000… | 59 +++++++++++++++++++++++++++++++ A extra/patches/linux-n9-patches/000… | 273 +++++++++++++++++++++++++++++++ A extra/patches/linux-n9-patches/000… | 74 +++++++++++++++++++++++++++++++ A extra/patches/linux-n9-patches/000… | 76 +++++++++++++++++++++++++++++++ A extra/patches/linux-n9-patches/000… | 71 +++++++++++++++++++++++++++++++ A extra/patches/linux-n9-patches/000… | 48 +++++++++++++++++++++++++++++++ A extra/patches/linux-n9-patches/000… | 141 +++++++++++++++++++++++++++++++ A extra/patches/linux-n950-patches/0… | 175 +++++++++++++++++++++++++++++++ A extra/patches/linux-n950-patches/0… | 59 +++++++++++++++++++++++++++++++ A extra/patches/linux-n950-patches/0… | 273 +++++++++++++++++++++++++++++++ A extra/patches/linux-n950-patches/0… | 74 +++++++++++++++++++++++++++++++ A extra/patches/linux-n950-patches/0… | 76 +++++++++++++++++++++++++++++++ A extra/patches/linux-n950-patches/0… | 71 +++++++++++++++++++++++++++++++ A extra/patches/linux-n950-patches/0… | 48 +++++++++++++++++++++++++++++++ A extra/patches/linux-n950-patches/0… | 141 +++++++++++++++++++++++++++++++ D extra/pwclient/.pwclientrc | 6 ------ D extra/pwclient/pwclient | 704 ------------------------------- 20 files changed, 1836 insertions(+), 748 deletions(-) --- (DIR) diff --git a/boards/nokia-n9.sh b/boards/nokia-n9.sh t@@ -39,20 +39,6 @@ custmodules=() gitkernel="https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git" gitbranch="linux-4.16.y" -# patch series from linux-omap patchwork -# [PATCHv2 0/8] omapdrm: DSI command mode panel support -patchids=( - 10207753 # [PATCHv2,1/8] drm/omap: add framedone interrupt support - 10207763 # [PATCHv2,2/8] drm/omap: add manual update detection helper - 10207759 # [PATCHv2,3/8] drm/omap: add support for manually updated displays - 10207749 # [PATCHv2,4/8] dt-bindings: panel: common: document orientation property - 10207733 # [PATCHv2,5/8] drm/omap: add support for orientation hints from display drivers - 10207747 # [PATCHv2,6/8] drm/omap: panel-dsi-cm: add orientation support - 10207755 # [PATCHv2,7/8] ARM: dts: omap4-droid4: Add LCD panel orientation property - 10207743 # [PATCHv2,8/8] drm/omap: plane: update fifo size on ovl setup -) -pwclient=$R/extra/pwclient/pwclient - postbuild() { fn postbuild t@@ -77,11 +63,7 @@ build_kernel_${arch}() { git checkout -- . copy-kernel-config - notice "applying patches from patchwork" - cp $R/extra/pwclient/.pwclientrc ~ - $pwclient git-am -p linux-omap $patchids - - notice "applying addtional patches" + notice "applying patches" _patchdir="$R/extra/patches/linux-n9-patches" _patchset="$(find ${_patchdir} -name '*.patch' | sort)" for i in "${=_patchset}"; do (DIR) diff --git a/boards/nokia-n950.sh b/boards/nokia-n950.sh t@@ -39,20 +39,6 @@ custmodules=() gitkernel="https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git" gitbranch="linux-4.16.y" -# patch series from linux-omap patchwork -# [PATCHv2 0/8] omapdrm: DSI command mode panel support -patchids=( - 10207753 # [PATCHv2,1/8] drm/omap: add framedone interrupt support - 10207763 # [PATCHv2,2/8] drm/omap: add manual update detection helper - 10207759 # [PATCHv2,3/8] drm/omap: add support for manually updated displays - 10207749 # [PATCHv2,4/8] dt-bindings: panel: common: document orientation property - 10207733 # [PATCHv2,5/8] drm/omap: add support for orientation hints from display drivers - 10207747 # [PATCHv2,6/8] drm/omap: panel-dsi-cm: add orientation support - 10207755 # [PATCHv2,7/8] ARM: dts: omap4-droid4: Add LCD panel orientation property - 10207743 # [PATCHv2,8/8] drm/omap: plane: update fifo size on ovl setup -) -pwclient=$R/extra/pwclient/pwclient - postbuild() { fn postbuild t@@ -77,11 +63,7 @@ build_kernel_${arch}() { git checkout -- . copy-kernel-config - notice "applying patches from patchwork" - cp $R/extra/pwclient/.pwclientrc ~ - $pwclient git-am -p linux-omap $patchids - - notice "applying addtional patches" + notice "applying patches" _patchdir="$R/extra/patches/linux-n950-patches" _patchset="$(find ${_patchdir} -name '*.patch' | sort)" for i in "${=_patchset}"; do (DIR) diff --git a/extra/patches/linux-n9-patches/0001-PATCHv2-1-8-drm-omap-add-framedone-interrupt-support.patch b/extra/patches/linux-n9-patches/0001-PATCHv2-1-8-drm-omap-add-framedone-interrupt-support.patch t@@ -0,0 +1,175 @@ +From patchwork Thu Feb 8 18:30:28 2018 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [PATCHv2,1/8] drm/omap: add framedone interrupt support +From: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +X-Patchwork-Id: 10207753 +Message-Id: <20180208183035.8461-2-sebastian.reichel@collabora.co.uk> +To: Sebastian Reichel <sre@kernel.org>, + Tomi Valkeinen <tomi.valkeinen@ti.com>, Tony Lindgren <tony@atomide.com> +Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>, + Hans de Goede <hdegoede@redhat.com>, Rob Herring <robh+dt@kernel.org>, + Mark Rutland <mark.rutland@arm.com>, + dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, + linux-omap@vger.kernel.org, linux-kernel@vger.kernel.org, + kernel@collabora.com, Sebastian Reichel <sebastian.reichel@collabora.co.uk> +Date: Thu, 8 Feb 2018 19:30:28 +0100 + +This prepares framedone interrupt handling for +manual display update support. + +Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +Tested-by: Tony Lindgren <tony@atomide.com> +--- + drivers/gpu/drm/omapdrm/omap_crtc.c | 48 +++++++++++++++++++++++++++++++++++++ + drivers/gpu/drm/omapdrm/omap_crtc.h | 1 + + drivers/gpu/drm/omapdrm/omap_irq.c | 24 +++++++++++++++++++ + drivers/gpu/drm/omapdrm/omap_irq.h | 1 + + 4 files changed, 74 insertions(+) + +diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c +index 1b8154e58d18..2278e3433008 100644 +--- a/drivers/gpu/drm/omapdrm/omap_crtc.c ++++ b/drivers/gpu/drm/omapdrm/omap_crtc.c +@@ -51,6 +51,9 @@ struct omap_crtc { + bool pending; + wait_queue_head_t pending_wait; + struct drm_pending_vblank_event *event; ++ ++ void (*framedone_handler)(void *); ++ void *framedone_handler_data; + }; + + /* ----------------------------------------------------------------------------- +@@ -247,6 +250,17 @@ static int omap_crtc_dss_register_framedone( + enum omap_channel channel, + void (*handler)(void *), void *data) + { ++ struct omap_crtc *omap_crtc = omap_crtcs[channel]; ++ struct drm_device *dev = omap_crtc->base.dev; ++ ++ if (omap_crtc->framedone_handler) ++ return -EBUSY; ++ ++ dev_dbg(dev->dev, "register framedone %s", omap_crtc->name); ++ ++ omap_crtc->framedone_handler = handler; ++ omap_crtc->framedone_handler_data = data; ++ + return 0; + } + +@@ -254,6 +268,16 @@ static void omap_crtc_dss_unregister_framedone( + enum omap_channel channel, + void (*handler)(void *), void *data) + { ++ struct omap_crtc *omap_crtc = omap_crtcs[channel]; ++ struct drm_device *dev = omap_crtc->base.dev; ++ ++ dev_dbg(dev->dev, "unregister framedone %s", omap_crtc->name); ++ ++ WARN_ON(omap_crtc->framedone_handler != handler); ++ WARN_ON(omap_crtc->framedone_handler_data != data); ++ ++ omap_crtc->framedone_handler = NULL; ++ omap_crtc->framedone_handler_data = NULL; + } + + static const struct dss_mgr_ops mgr_ops = { +@@ -321,6 +345,30 @@ void omap_crtc_vblank_irq(struct drm_crtc *crtc) + DBG("%s: apply done", omap_crtc->name); + } + ++void omap_crtc_framedone_irq(struct drm_crtc *crtc, uint32_t irqstatus) ++{ ++ struct omap_crtc *omap_crtc = to_omap_crtc(crtc); ++ ++ if (!omap_crtc->framedone_handler) { ++ dev_warn(omap_crtc->base.dev->dev, "no framedone handler?"); ++ return; ++ } ++ ++ omap_crtc->framedone_handler(omap_crtc->framedone_handler_data); ++ ++ spin_lock(&crtc->dev->event_lock); ++ /* Send the vblank event if one has been requested. */ ++ if (omap_crtc->event) { ++ drm_crtc_send_vblank_event(crtc, omap_crtc->event); ++ omap_crtc->event = NULL; ++ } ++ omap_crtc->pending = false; ++ spin_unlock(&crtc->dev->event_lock); ++ ++ /* Wake up omap_atomic_complete. */ ++ 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; +diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.h b/drivers/gpu/drm/omapdrm/omap_crtc.h +index ad7b007c6174..bd316bc0b6f4 100644 +--- a/drivers/gpu/drm/omapdrm/omap_crtc.h ++++ b/drivers/gpu/drm/omapdrm/omap_crtc.h +@@ -39,5 +39,6 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, + int omap_crtc_wait_pending(struct drm_crtc *crtc); + void omap_crtc_error_irq(struct drm_crtc *crtc, uint32_t irqstatus); + void omap_crtc_vblank_irq(struct drm_crtc *crtc); ++void omap_crtc_framedone_irq(struct drm_crtc *crtc, uint32_t irqstatus); + + #endif /* __OMAPDRM_CRTC_H__ */ +diff --git a/drivers/gpu/drm/omapdrm/omap_irq.c b/drivers/gpu/drm/omapdrm/omap_irq.c +index 53ba424823b2..354df3583229 100644 +--- a/drivers/gpu/drm/omapdrm/omap_irq.c ++++ b/drivers/gpu/drm/omapdrm/omap_irq.c +@@ -85,6 +85,27 @@ int omap_irq_wait(struct drm_device *dev, struct omap_irq_wait *wait, + return ret == 0 ? -1 : 0; + } + ++int omap_irq_enable_framedone(struct drm_crtc *crtc, bool enable) ++{ ++ struct drm_device *dev = crtc->dev; ++ struct omap_drm_private *priv = dev->dev_private; ++ unsigned long flags; ++ enum omap_channel channel = omap_crtc_channel(crtc); ++ int framedone_irq = priv->dispc_ops->mgr_get_framedone_irq(channel); ++ ++ DBG("dev=%p, crtc=%u, enable=%d", dev, channel, enable); ++ ++ spin_lock_irqsave(&priv->wait_lock, flags); ++ if (enable) ++ priv->irq_mask |= framedone_irq; ++ else ++ priv->irq_mask &= ~framedone_irq; ++ omap_irq_update(dev); ++ spin_unlock_irqrestore(&priv->wait_lock, flags); ++ ++ return 0; ++} ++ + /** + * enable_vblank - enable vblank interrupt events + * @dev: DRM device +@@ -215,6 +236,9 @@ static irqreturn_t omap_irq_handler(int irq, void *arg) + + if (irqstatus & priv->dispc_ops->mgr_get_sync_lost_irq(channel)) + omap_crtc_error_irq(crtc, irqstatus); ++ ++ if (irqstatus & priv->dispc_ops->mgr_get_framedone_irq(channel)) ++ omap_crtc_framedone_irq(crtc, irqstatus); + } + + omap_irq_ocp_error_handler(dev, irqstatus); +diff --git a/drivers/gpu/drm/omapdrm/omap_irq.h b/drivers/gpu/drm/omapdrm/omap_irq.h +index 606c09932bc0..69f4ff80a0e4 100644 +--- a/drivers/gpu/drm/omapdrm/omap_irq.h ++++ b/drivers/gpu/drm/omapdrm/omap_irq.h +@@ -27,6 +27,7 @@ struct drm_device; + struct omap_irq_wait; + + int omap_irq_enable_vblank(struct drm_crtc *crtc); ++int omap_irq_enable_framedone(struct drm_crtc *crtc, bool enable); + void omap_irq_disable_vblank(struct drm_crtc *crtc); + void omap_drm_irq_uninstall(struct drm_device *dev); + int omap_drm_irq_install(struct drm_device *dev); (DIR) diff --git a/extra/patches/linux-n9-patches/0001-PATCHv2-2-8-drm-omap-add-manual-update-detection-helper.patch b/extra/patches/linux-n9-patches/0001-PATCHv2-2-8-drm-omap-add-manual-update-detection-helper.patch t@@ -0,0 +1,59 @@ +From patchwork Thu Feb 8 18:30:29 2018 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [PATCHv2,2/8] drm/omap: add manual update detection helper +From: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +X-Patchwork-Id: 10207763 +Message-Id: <20180208183035.8461-3-sebastian.reichel@collabora.co.uk> +To: Sebastian Reichel <sre@kernel.org>, + Tomi Valkeinen <tomi.valkeinen@ti.com>, Tony Lindgren <tony@atomide.com> +Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>, + Hans de Goede <hdegoede@redhat.com>, Rob Herring <robh+dt@kernel.org>, + Mark Rutland <mark.rutland@arm.com>, + dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, + linux-omap@vger.kernel.org, linux-kernel@vger.kernel.org, + kernel@collabora.com, Sebastian Reichel <sebastian.reichel@collabora.co.uk> +Date: Thu, 8 Feb 2018 19:30:29 +0100 + +In preparation for manually updated display support, such as DSI +command mode panels, this adds a simple helper to see if a connector +is manually updated. + +Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +Tested-by: Tony Lindgren <tony@atomide.com> +--- + drivers/gpu/drm/omapdrm/omap_connector.c | 8 ++++++++ + drivers/gpu/drm/omapdrm/omap_connector.h | 1 + + 2 files changed, 9 insertions(+) + +diff --git a/drivers/gpu/drm/omapdrm/omap_connector.c b/drivers/gpu/drm/omapdrm/omap_connector.c +index a0d7b1d905e8..a33b51484b2d 100644 +--- a/drivers/gpu/drm/omapdrm/omap_connector.c ++++ b/drivers/gpu/drm/omapdrm/omap_connector.c +@@ -57,6 +57,14 @@ bool omap_connector_get_hdmi_mode(struct drm_connector *connector) + return omap_connector->hdmi_mode; + } + ++bool omap_connector_get_manually_updated(struct drm_connector *connector) ++{ ++ struct omap_connector *omap_connector = to_omap_connector(connector); ++ ++ return !!(omap_connector->dssdev->caps & ++ OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE); ++} ++ + static enum drm_connector_status omap_connector_detect( + struct drm_connector *connector, bool force) + { +diff --git a/drivers/gpu/drm/omapdrm/omap_connector.h b/drivers/gpu/drm/omapdrm/omap_connector.h +index 98bbc779b302..652136d167f5 100644 +--- a/drivers/gpu/drm/omapdrm/omap_connector.h ++++ b/drivers/gpu/drm/omapdrm/omap_connector.h +@@ -33,5 +33,6 @@ struct drm_connector *omap_connector_init(struct drm_device *dev, + struct drm_encoder *omap_connector_attached_encoder( + struct drm_connector *connector); + bool omap_connector_get_hdmi_mode(struct drm_connector *connector); ++bool omap_connector_get_manually_updated(struct drm_connector *connector); + + #endif /* __OMAPDRM_CONNECTOR_H__ */ (DIR) diff --git a/extra/patches/linux-n9-patches/0001-PATCHv2-3-8-drm-omap-add-support-for-manually-updated-displays.patch b/extra/patches/linux-n9-patches/0001-PATCHv2-3-8-drm-omap-add-support-for-manually-updated-displays.patch t@@ -0,0 +1,273 @@ +From patchwork Thu Feb 8 18:30:30 2018 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [PATCHv2,3/8] drm/omap: add support for manually updated displays +From: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +X-Patchwork-Id: 10207759 +Message-Id: <20180208183035.8461-4-sebastian.reichel@collabora.co.uk> +To: Sebastian Reichel <sre@kernel.org>, + Tomi Valkeinen <tomi.valkeinen@ti.com>, Tony Lindgren <tony@atomide.com> +Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>, + Hans de Goede <hdegoede@redhat.com>, Rob Herring <robh+dt@kernel.org>, + Mark Rutland <mark.rutland@arm.com>, + dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, + linux-omap@vger.kernel.org, linux-kernel@vger.kernel.org, + kernel@collabora.com, Sebastian Reichel <sebastian.reichel@collabora.co.uk> +Date: Thu, 8 Feb 2018 19:30:30 +0100 + +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. + +Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +Tested-by: Tony Lindgren <tony@atomide.com> +--- + drivers/gpu/drm/omapdrm/omap_crtc.c | 110 +++++++++++++++++++++++++++++++++--- + drivers/gpu/drm/omapdrm/omap_crtc.h | 1 + + drivers/gpu/drm/omapdrm/omap_fb.c | 20 +++++++ + 3 files changed, 123 insertions(+), 8 deletions(-) + +diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c +index 2278e3433008..c2defb514b9f 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; +@@ -142,6 +143,28 @@ static void omap_crtc_dss_disconnect(enum omap_channel channel, + + static void omap_crtc_dss_start_update(enum omap_channel channel) + { ++ struct omap_crtc *omap_crtc = omap_crtcs[channel]; ++ struct omap_drm_private *priv = omap_crtc->base.dev->dev_private; ++ ++ priv->dispc_ops->mgr_enable(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. */ +@@ -153,12 +176,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(channel, enable); + omap_crtc->enabled = enable; + return; +@@ -209,7 +237,6 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable) + } + } + +- + static int omap_crtc_dss_enable(enum omap_channel channel) + { + struct omap_crtc *omap_crtc = omap_crtcs[channel]; +@@ -369,6 +396,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; +@@ -421,6 +495,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); +@@ -434,6 +512,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); + +@@ -444,6 +523,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); + } + +@@ -593,13 +677,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(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(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, +@@ -761,6 +852,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 bd316bc0b6f4..b61c94b34f04 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, uint32_t 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 b2539a90e1a4..57b1767bef09 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, + }; + (DIR) diff --git a/extra/patches/linux-n9-patches/0001-PATCHv2-4-8-dt-bindings-panel-common-document-orientation-property.patch b/extra/patches/linux-n9-patches/0001-PATCHv2-4-8-dt-bindings-panel-common-document-orientation-property.patch t@@ -0,0 +1,74 @@ +From patchwork Thu Feb 8 18:30:31 2018 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [PATCHv2, + 4/8] dt-bindings: panel: common: document orientation property +From: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +X-Patchwork-Id: 10207749 +Message-Id: <20180208183035.8461-5-sebastian.reichel@collabora.co.uk> +To: Sebastian Reichel <sre@kernel.org>, + Tomi Valkeinen <tomi.valkeinen@ti.com>, Tony Lindgren <tony@atomide.com> +Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>, + Hans de Goede <hdegoede@redhat.com>, Rob Herring <robh+dt@kernel.org>, + Mark Rutland <mark.rutland@arm.com>, + dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, + linux-omap@vger.kernel.org, linux-kernel@vger.kernel.org, + kernel@collabora.com, Sebastian Reichel <sebastian.reichel@collabora.co.uk> +Date: Thu, 8 Feb 2018 19:30:31 +0100 + +Introduce new "orientation" property for describing in which +orientation a panel has been mounted to the device. This can +be used by the operating system to automatically rotate the +display correctly. + +Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +--- + .../devicetree/bindings/display/panel/panel-common.txt | 12 ++++++++++++ + include/dt-bindings/display/common.h | 14 ++++++++++++++ + 2 files changed, 26 insertions(+) + create mode 100644 include/dt-bindings/display/common.h + +diff --git a/Documentation/devicetree/bindings/display/panel/panel-common.txt b/Documentation/devicetree/bindings/display/panel/panel-common.txt +index 557fa765adcb..c646b8908458 100644 +--- a/Documentation/devicetree/bindings/display/panel/panel-common.txt ++++ b/Documentation/devicetree/bindings/display/panel/panel-common.txt +@@ -18,6 +18,18 @@ Descriptive Properties + physical area where images are displayed. These properties are expressed in + millimeters and rounded to the closest unit. + ++- orientation: The orientation property specifies the panel orientation ++ in relation to the device's casing. The following values are possible: ++ ++ * 0 = The top side of the panel matches the top side of the device's ++ casing. ++ * 1 = The top side of the panel matches the bottom side of the device's ++ casing. In other words the panel is mounted upside-down. ++ * 2 = The left side of the panel matches the top side of the device's ++ casing. ++ * 3 = The right side of the panel matches the top side of the device's ++ casing. ++ + - label: The label property specifies a symbolic name for the panel as a + string suitable for use by humans. It typically contains a name inscribed on + the system (e.g. as an affixed label) or specified in the system's +diff --git a/include/dt-bindings/display/common.h b/include/dt-bindings/display/common.h +new file mode 100644 +index 000000000000..a864775445a0 +--- /dev/null ++++ b/include/dt-bindings/display/common.h +@@ -0,0 +1,14 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * This header provides common constants for displays ++ */ ++ ++#ifndef _DT_BINDINGS_DISPLAY_COMMON_H ++#define _DT_BINDINGS_DISPLAY_COMMON_H ++ ++#define PANEL_ORIENTATION_NORMAL 0 ++#define PANEL_ORIENTATION_BOTTOM_UP 1 ++#define PANEL_ORIENTATION_LEFT_UP 2 ++#define PANEL_ORIENTATION_RIGHT_UP 3 ++ ++#endif (DIR) diff --git a/extra/patches/linux-n9-patches/0001-PATCHv2-5-8-drm-omap-add-support-for-orientation-hints-from-display-drivers.patch b/extra/patches/linux-n9-patches/0001-PATCHv2-5-8-drm-omap-add-support-for-orientation-hints-from-display-drivers.patch t@@ -0,0 +1,76 @@ +From patchwork Thu Feb 8 18:30:32 2018 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [PATCHv2, + 5/8] drm/omap: add support for orientation hints from display drivers +From: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +X-Patchwork-Id: 10207733 +Message-Id: <20180208183035.8461-6-sebastian.reichel@collabora.co.uk> +To: Sebastian Reichel <sre@kernel.org>, + Tomi Valkeinen <tomi.valkeinen@ti.com>, Tony Lindgren <tony@atomide.com> +Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>, + Hans de Goede <hdegoede@redhat.com>, Rob Herring <robh+dt@kernel.org>, + Mark Rutland <mark.rutland@arm.com>, + dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, + linux-omap@vger.kernel.org, linux-kernel@vger.kernel.org, + kernel@collabora.com, Sebastian Reichel <sebastian.reichel@collabora.co.uk> +Date: Thu, 8 Feb 2018 19:30:32 +0100 + +This adds support for setting DRM panel orientation property +based on information from the display driver. + +Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +--- + drivers/gpu/drm/omapdrm/dss/omapdss.h | 2 ++ + drivers/gpu/drm/omapdrm/omap_connector.c | 10 +++++++++- + 2 files changed, 11 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h +index f8f83e826a56..72ebd82409d3 100644 +--- a/drivers/gpu/drm/omapdrm/dss/omapdss.h ++++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h +@@ -565,6 +565,8 @@ struct omap_dss_driver { + struct videomode *vm); + void (*get_size)(struct omap_dss_device *dssdev, + unsigned int *width, unsigned int *height); ++ void (*get_orientation)(struct omap_dss_device *dssdev, ++ int *orientation); + + int (*set_wss)(struct omap_dss_device *dssdev, u32 wss); + u32 (*get_wss)(struct omap_dss_device *dssdev); +diff --git a/drivers/gpu/drm/omapdrm/omap_connector.c b/drivers/gpu/drm/omapdrm/omap_connector.c +index a33b51484b2d..2f296d29b74b 100644 +--- a/drivers/gpu/drm/omapdrm/omap_connector.c ++++ b/drivers/gpu/drm/omapdrm/omap_connector.c +@@ -249,6 +249,7 @@ struct drm_connector *omap_connector_init(struct drm_device *dev, + struct drm_connector *connector = NULL; + struct omap_connector *omap_connector; + bool hpd_supported = false; ++ int ret; + + DBG("%s", dssdev->name); + +@@ -267,7 +268,7 @@ struct drm_connector *omap_connector_init(struct drm_device *dev, + drm_connector_helper_add(connector, &omap_connector_helper_funcs); + + if (dssdev->driver->register_hpd_cb) { +- int ret = dssdev->driver->register_hpd_cb(dssdev, ++ ret = dssdev->driver->register_hpd_cb(dssdev, + omap_connector_hpd_cb, + omap_connector); + if (!ret) +@@ -288,6 +289,13 @@ struct drm_connector *omap_connector_init(struct drm_device *dev, + connector->interlace_allowed = 1; + connector->doublescan_allowed = 0; + ++ if (dssdev->driver->get_orientation) ++ dssdev->driver->get_orientation(dssdev, &connector->display_info.panel_orientation); ++ ++ ret = drm_connector_init_panel_orientation_property(connector, 0, 0); ++ if (ret) ++ DBG("%s: Failed to init orientation property (%d)", dssdev->name, ret); ++ + return connector; + + fail: (DIR) diff --git a/extra/patches/linux-n9-patches/0001-PATCHv2-6-8-drm-omap-panel-dsi-cm-add-orientation-support.patch b/extra/patches/linux-n9-patches/0001-PATCHv2-6-8-drm-omap-panel-dsi-cm-add-orientation-support.patch t@@ -0,0 +1,71 @@ +From patchwork Thu Feb 8 18:30:33 2018 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [PATCHv2,6/8] drm/omap: panel-dsi-cm: add orientation support +From: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +X-Patchwork-Id: 10207747 +Message-Id: <20180208183035.8461-7-sebastian.reichel@collabora.co.uk> +To: Sebastian Reichel <sre@kernel.org>, + Tomi Valkeinen <tomi.valkeinen@ti.com>, Tony Lindgren <tony@atomide.com> +Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>, + Hans de Goede <hdegoede@redhat.com>, Rob Herring <robh+dt@kernel.org>, + Mark Rutland <mark.rutland@arm.com>, + dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, + linux-omap@vger.kernel.org, linux-kernel@vger.kernel.org, + kernel@collabora.com, Sebastian Reichel <sebastian.reichel@collabora.co.uk> +Date: Thu, 8 Feb 2018 19:30:33 +0100 + +Add support to inform the DRM subsystem about the orientation +the display has been mounted to the casing. + +Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +--- + drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c +index 15399a1a666b..7a63d6775a27 100644 +--- a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c ++++ b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c +@@ -68,6 +68,7 @@ struct panel_drv_data { + + int width_mm; + int height_mm; ++ int orientation; + + struct omap_dsi_pin_config pin_config; + +@@ -1198,6 +1199,14 @@ static void dsicm_get_size(struct omap_dss_device *dssdev, + *height = ddata->height_mm; + } + ++static void dsicm_get_orientation(struct omap_dss_device *dssdev, ++ int *orientation) ++{ ++ struct panel_drv_data *ddata = to_panel_data(dssdev); ++ ++ *orientation = ddata->orientation; ++} ++ + static struct omap_dss_driver dsicm_ops = { + .connect = dsicm_connect, + .disconnect = dsicm_disconnect, +@@ -1211,6 +1220,7 @@ static struct omap_dss_driver dsicm_ops = { + .get_timings = dsicm_get_timings, + .check_timings = dsicm_check_timings, + .get_size = dsicm_get_size, ++ .get_orientation = dsicm_get_orientation, + + .enable_te = dsicm_enable_te, + .get_te = dsicm_get_te, +@@ -1259,6 +1269,9 @@ static int dsicm_probe_of(struct platform_device *pdev) + ddata->height_mm = 0; + of_property_read_u32(node, "height-mm", &ddata->height_mm); + ++ ddata->orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN; ++ of_property_read_u32(node, "orientation", &ddata->orientation); ++ + in = omapdss_of_find_source_for_first_ep(node); + if (IS_ERR(in)) { + dev_err(&pdev->dev, "failed to find video source\n"); (DIR) diff --git a/extra/patches/linux-n9-patches/0001-PATCHv2-7-8-ARM-dts-omap4-droid4-Add-LCD-panel-orientation-property.patch b/extra/patches/linux-n9-patches/0001-PATCHv2-7-8-ARM-dts-omap4-droid4-Add-LCD-panel-orientation-property.patch t@@ -0,0 +1,48 @@ +From patchwork Thu Feb 8 18:30:34 2018 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [PATCHv2, + 7/8] ARM: dts: omap4-droid4: Add LCD panel orientation property +From: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +X-Patchwork-Id: 10207755 +Message-Id: <20180208183035.8461-8-sebastian.reichel@collabora.co.uk> +To: Sebastian Reichel <sre@kernel.org>, + Tomi Valkeinen <tomi.valkeinen@ti.com>, Tony Lindgren <tony@atomide.com> +Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>, + Hans de Goede <hdegoede@redhat.com>, Rob Herring <robh+dt@kernel.org>, + Mark Rutland <mark.rutland@arm.com>, + dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, + linux-omap@vger.kernel.org, linux-kernel@vger.kernel.org, + kernel@collabora.com, Sebastian Reichel <sebastian.reichel@collabora.co.uk> +Date: Thu, 8 Feb 2018 19:30:34 +0100 + +This adds a LCD panel orientation hint to the Droid 4. If the +display is rotated this way the keyboard can be used properly. + +Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +--- + arch/arm/boot/dts/omap4-droid4-xt894.dts | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/arch/arm/boot/dts/omap4-droid4-xt894.dts b/arch/arm/boot/dts/omap4-droid4-xt894.dts +index b21084da490b..e11a24397163 100644 +--- a/arch/arm/boot/dts/omap4-droid4-xt894.dts ++++ b/arch/arm/boot/dts/omap4-droid4-xt894.dts +@@ -6,6 +6,7 @@ + /dts-v1/; + + #include <dt-bindings/input/input.h> ++#include <dt-bindings/display/common.h> + #include "omap443x.dtsi" + #include "motorola-cpcap-mapphone.dtsi" + +@@ -181,6 +182,8 @@ + height-mm = <89>; + backlight = <&lcd_backlight>; + ++ orientation = <PANEL_ORIENTATION_RIGHT_UP>; ++ + panel-timing { + clock-frequency = <0>; /* Calculated by dsi */ + (DIR) diff --git a/extra/patches/linux-n9-patches/0001-PATCHv2-8-8-drm-omap-plane-update-fifo-size-on-ovl-setup.patch b/extra/patches/linux-n9-patches/0001-PATCHv2-8-8-drm-omap-plane-update-fifo-size-on-ovl-setup.patch t@@ -0,0 +1,141 @@ +From patchwork Thu Feb 8 18:30:35 2018 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [PATCHv2,8/8] drm/omap: plane: update fifo size on ovl setup +From: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +X-Patchwork-Id: 10207743 +Message-Id: <20180208183035.8461-9-sebastian.reichel@collabora.co.uk> +To: Sebastian Reichel <sre@kernel.org>, + Tomi Valkeinen <tomi.valkeinen@ti.com>, Tony Lindgren <tony@atomide.com> +Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>, + Hans de Goede <hdegoede@redhat.com>, Rob Herring <robh+dt@kernel.org>, + Mark Rutland <mark.rutland@arm.com>, + dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, + linux-omap@vger.kernel.org, linux-kernel@vger.kernel.org, + kernel@collabora.com, Sebastian Reichel <sebastian.reichel@collabora.co.uk> +Date: Thu, 8 Feb 2018 19:30:35 +0100 + +This is a workaround for a hardware bug occuring on OMAP3 +with manually updated panels. Details about the HW bug are +unknown to me, but without this fix the panel refresh does +not work at all on Nokia N950. This is not the case for the +OMAP4 based Droid 4, which works perfectly fine with default +settings. + +Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +--- + drivers/gpu/drm/omapdrm/dss/dispc.c | 36 +++++++++++++++++++++++++++++++++++- + 1 file changed, 35 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c +index 4e8f68efd169..0904c3201914 100644 +--- a/drivers/gpu/drm/omapdrm/dss/dispc.c ++++ b/drivers/gpu/drm/omapdrm/dss/dispc.c +@@ -157,6 +157,8 @@ struct dispc_features { + bool has_gamma_table:1; + + bool has_gamma_i734_bug:1; ++ ++ bool has_fifo_stallmode_bug:1; + }; + + #define DISPC_MAX_NR_FIFOS 5 +@@ -1489,6 +1491,18 @@ void dispc_ovl_compute_fifo_thresholds(enum omap_plane_id plane, + } + } + ++static void dispc_ovl_set_manual_fifo_threshold(enum omap_plane_id plane) ++{ ++ u32 fifo_low, fifo_high; ++ bool use_fifo_merge = false; ++ bool use_manual_update = true; ++ ++ dispc_ovl_compute_fifo_thresholds(plane, &fifo_low, &fifo_high, ++ use_fifo_merge, use_manual_update); ++ ++ dispc_ovl_set_fifo_threshold(plane, fifo_low, fifo_high); ++} ++ + static void dispc_ovl_set_mflag(enum omap_plane_id plane, bool enable) + { + int bit; +@@ -2651,8 +2665,21 @@ static int dispc_ovl_setup(enum omap_plane_id plane, + oi->out_width, oi->out_height, oi->fourcc, oi->rotation, + oi->zorder, oi->pre_mult_alpha, oi->global_alpha, + oi->rotation_type, replication, vm, mem_to_mem); ++ if (r) ++ return r; + +- return r; ++ /* ++ * OMAP3 chips have non-working FIFO thresholds for manually updated ++ * displays. The issue is not fully understood, but this workaround ++ * fixes the issue. OMAP4 is known to work with default thresholds. ++ */ ++ if (mgr_fld_read(channel, DISPC_MGR_FLD_STALLMODE) && ++ dispc.feat->has_fifo_stallmode_bug) { ++ DSSDBG("Enable OMAP3 FIFO stallmode bug workaround!\n"); ++ dispc_ovl_set_manual_fifo_threshold(plane); ++ } ++ ++ return 0; + } + + int dispc_wb_setup(const struct omap_dss_writeback_info *wi, +@@ -4067,6 +4094,7 @@ static const struct dispc_features omap24xx_dispc_feats = { + .no_framedone_tv = true, + .set_max_preload = false, + .last_pixel_inc_missing = true, ++ .has_fifo_stallmode_bug = true, + }; + + static const struct dispc_features omap34xx_rev1_0_dispc_feats = { +@@ -4101,6 +4129,7 @@ static const struct dispc_features omap34xx_rev1_0_dispc_feats = { + .no_framedone_tv = true, + .set_max_preload = false, + .last_pixel_inc_missing = true, ++ .has_fifo_stallmode_bug = true, + }; + + static const struct dispc_features omap34xx_rev3_0_dispc_feats = { +@@ -4135,6 +4164,7 @@ static const struct dispc_features omap34xx_rev3_0_dispc_feats = { + .no_framedone_tv = true, + .set_max_preload = false, + .last_pixel_inc_missing = true, ++ .has_fifo_stallmode_bug = true, + }; + + static const struct dispc_features omap36xx_dispc_feats = { +@@ -4169,6 +4199,7 @@ static const struct dispc_features omap36xx_dispc_feats = { + .no_framedone_tv = true, + .set_max_preload = false, + .last_pixel_inc_missing = true, ++ .has_fifo_stallmode_bug = true, + }; + + static const struct dispc_features am43xx_dispc_feats = { +@@ -4203,6 +4234,7 @@ static const struct dispc_features am43xx_dispc_feats = { + .no_framedone_tv = true, + .set_max_preload = false, + .last_pixel_inc_missing = true, ++ .has_fifo_stallmode_bug = false, + }; + + static const struct dispc_features omap44xx_dispc_feats = { +@@ -4242,6 +4274,7 @@ static const struct dispc_features omap44xx_dispc_feats = { + .reverse_ilace_field_order = true, + .has_gamma_table = true, + .has_gamma_i734_bug = true, ++ .has_fifo_stallmode_bug = false, + }; + + static const struct dispc_features omap54xx_dispc_feats = { +@@ -4282,6 +4315,7 @@ static const struct dispc_features omap54xx_dispc_feats = { + .reverse_ilace_field_order = true, + .has_gamma_table = true, + .has_gamma_i734_bug = true, ++ .has_fifo_stallmode_bug = false, + }; + + static irqreturn_t dispc_irq_handler(int irq, void *arg) (DIR) diff --git a/extra/patches/linux-n950-patches/0001-PATCHv2-1-8-drm-omap-add-framedone-interrupt-support.patch b/extra/patches/linux-n950-patches/0001-PATCHv2-1-8-drm-omap-add-framedone-interrupt-support.patch t@@ -0,0 +1,175 @@ +From patchwork Thu Feb 8 18:30:28 2018 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [PATCHv2,1/8] drm/omap: add framedone interrupt support +From: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +X-Patchwork-Id: 10207753 +Message-Id: <20180208183035.8461-2-sebastian.reichel@collabora.co.uk> +To: Sebastian Reichel <sre@kernel.org>, + Tomi Valkeinen <tomi.valkeinen@ti.com>, Tony Lindgren <tony@atomide.com> +Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>, + Hans de Goede <hdegoede@redhat.com>, Rob Herring <robh+dt@kernel.org>, + Mark Rutland <mark.rutland@arm.com>, + dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, + linux-omap@vger.kernel.org, linux-kernel@vger.kernel.org, + kernel@collabora.com, Sebastian Reichel <sebastian.reichel@collabora.co.uk> +Date: Thu, 8 Feb 2018 19:30:28 +0100 + +This prepares framedone interrupt handling for +manual display update support. + +Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +Tested-by: Tony Lindgren <tony@atomide.com> +--- + drivers/gpu/drm/omapdrm/omap_crtc.c | 48 +++++++++++++++++++++++++++++++++++++ + drivers/gpu/drm/omapdrm/omap_crtc.h | 1 + + drivers/gpu/drm/omapdrm/omap_irq.c | 24 +++++++++++++++++++ + drivers/gpu/drm/omapdrm/omap_irq.h | 1 + + 4 files changed, 74 insertions(+) + +diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c +index 1b8154e58d18..2278e3433008 100644 +--- a/drivers/gpu/drm/omapdrm/omap_crtc.c ++++ b/drivers/gpu/drm/omapdrm/omap_crtc.c +@@ -51,6 +51,9 @@ struct omap_crtc { + bool pending; + wait_queue_head_t pending_wait; + struct drm_pending_vblank_event *event; ++ ++ void (*framedone_handler)(void *); ++ void *framedone_handler_data; + }; + + /* ----------------------------------------------------------------------------- +@@ -247,6 +250,17 @@ static int omap_crtc_dss_register_framedone( + enum omap_channel channel, + void (*handler)(void *), void *data) + { ++ struct omap_crtc *omap_crtc = omap_crtcs[channel]; ++ struct drm_device *dev = omap_crtc->base.dev; ++ ++ if (omap_crtc->framedone_handler) ++ return -EBUSY; ++ ++ dev_dbg(dev->dev, "register framedone %s", omap_crtc->name); ++ ++ omap_crtc->framedone_handler = handler; ++ omap_crtc->framedone_handler_data = data; ++ + return 0; + } + +@@ -254,6 +268,16 @@ static void omap_crtc_dss_unregister_framedone( + enum omap_channel channel, + void (*handler)(void *), void *data) + { ++ struct omap_crtc *omap_crtc = omap_crtcs[channel]; ++ struct drm_device *dev = omap_crtc->base.dev; ++ ++ dev_dbg(dev->dev, "unregister framedone %s", omap_crtc->name); ++ ++ WARN_ON(omap_crtc->framedone_handler != handler); ++ WARN_ON(omap_crtc->framedone_handler_data != data); ++ ++ omap_crtc->framedone_handler = NULL; ++ omap_crtc->framedone_handler_data = NULL; + } + + static const struct dss_mgr_ops mgr_ops = { +@@ -321,6 +345,30 @@ void omap_crtc_vblank_irq(struct drm_crtc *crtc) + DBG("%s: apply done", omap_crtc->name); + } + ++void omap_crtc_framedone_irq(struct drm_crtc *crtc, uint32_t irqstatus) ++{ ++ struct omap_crtc *omap_crtc = to_omap_crtc(crtc); ++ ++ if (!omap_crtc->framedone_handler) { ++ dev_warn(omap_crtc->base.dev->dev, "no framedone handler?"); ++ return; ++ } ++ ++ omap_crtc->framedone_handler(omap_crtc->framedone_handler_data); ++ ++ spin_lock(&crtc->dev->event_lock); ++ /* Send the vblank event if one has been requested. */ ++ if (omap_crtc->event) { ++ drm_crtc_send_vblank_event(crtc, omap_crtc->event); ++ omap_crtc->event = NULL; ++ } ++ omap_crtc->pending = false; ++ spin_unlock(&crtc->dev->event_lock); ++ ++ /* Wake up omap_atomic_complete. */ ++ 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; +diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.h b/drivers/gpu/drm/omapdrm/omap_crtc.h +index ad7b007c6174..bd316bc0b6f4 100644 +--- a/drivers/gpu/drm/omapdrm/omap_crtc.h ++++ b/drivers/gpu/drm/omapdrm/omap_crtc.h +@@ -39,5 +39,6 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, + int omap_crtc_wait_pending(struct drm_crtc *crtc); + void omap_crtc_error_irq(struct drm_crtc *crtc, uint32_t irqstatus); + void omap_crtc_vblank_irq(struct drm_crtc *crtc); ++void omap_crtc_framedone_irq(struct drm_crtc *crtc, uint32_t irqstatus); + + #endif /* __OMAPDRM_CRTC_H__ */ +diff --git a/drivers/gpu/drm/omapdrm/omap_irq.c b/drivers/gpu/drm/omapdrm/omap_irq.c +index 53ba424823b2..354df3583229 100644 +--- a/drivers/gpu/drm/omapdrm/omap_irq.c ++++ b/drivers/gpu/drm/omapdrm/omap_irq.c +@@ -85,6 +85,27 @@ int omap_irq_wait(struct drm_device *dev, struct omap_irq_wait *wait, + return ret == 0 ? -1 : 0; + } + ++int omap_irq_enable_framedone(struct drm_crtc *crtc, bool enable) ++{ ++ struct drm_device *dev = crtc->dev; ++ struct omap_drm_private *priv = dev->dev_private; ++ unsigned long flags; ++ enum omap_channel channel = omap_crtc_channel(crtc); ++ int framedone_irq = priv->dispc_ops->mgr_get_framedone_irq(channel); ++ ++ DBG("dev=%p, crtc=%u, enable=%d", dev, channel, enable); ++ ++ spin_lock_irqsave(&priv->wait_lock, flags); ++ if (enable) ++ priv->irq_mask |= framedone_irq; ++ else ++ priv->irq_mask &= ~framedone_irq; ++ omap_irq_update(dev); ++ spin_unlock_irqrestore(&priv->wait_lock, flags); ++ ++ return 0; ++} ++ + /** + * enable_vblank - enable vblank interrupt events + * @dev: DRM device +@@ -215,6 +236,9 @@ static irqreturn_t omap_irq_handler(int irq, void *arg) + + if (irqstatus & priv->dispc_ops->mgr_get_sync_lost_irq(channel)) + omap_crtc_error_irq(crtc, irqstatus); ++ ++ if (irqstatus & priv->dispc_ops->mgr_get_framedone_irq(channel)) ++ omap_crtc_framedone_irq(crtc, irqstatus); + } + + omap_irq_ocp_error_handler(dev, irqstatus); +diff --git a/drivers/gpu/drm/omapdrm/omap_irq.h b/drivers/gpu/drm/omapdrm/omap_irq.h +index 606c09932bc0..69f4ff80a0e4 100644 +--- a/drivers/gpu/drm/omapdrm/omap_irq.h ++++ b/drivers/gpu/drm/omapdrm/omap_irq.h +@@ -27,6 +27,7 @@ struct drm_device; + struct omap_irq_wait; + + int omap_irq_enable_vblank(struct drm_crtc *crtc); ++int omap_irq_enable_framedone(struct drm_crtc *crtc, bool enable); + void omap_irq_disable_vblank(struct drm_crtc *crtc); + void omap_drm_irq_uninstall(struct drm_device *dev); + int omap_drm_irq_install(struct drm_device *dev); (DIR) diff --git a/extra/patches/linux-n950-patches/0001-PATCHv2-2-8-drm-omap-add-manual-update-detection-helper.patch b/extra/patches/linux-n950-patches/0001-PATCHv2-2-8-drm-omap-add-manual-update-detection-helper.patch t@@ -0,0 +1,59 @@ +From patchwork Thu Feb 8 18:30:29 2018 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [PATCHv2,2/8] drm/omap: add manual update detection helper +From: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +X-Patchwork-Id: 10207763 +Message-Id: <20180208183035.8461-3-sebastian.reichel@collabora.co.uk> +To: Sebastian Reichel <sre@kernel.org>, + Tomi Valkeinen <tomi.valkeinen@ti.com>, Tony Lindgren <tony@atomide.com> +Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>, + Hans de Goede <hdegoede@redhat.com>, Rob Herring <robh+dt@kernel.org>, + Mark Rutland <mark.rutland@arm.com>, + dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, + linux-omap@vger.kernel.org, linux-kernel@vger.kernel.org, + kernel@collabora.com, Sebastian Reichel <sebastian.reichel@collabora.co.uk> +Date: Thu, 8 Feb 2018 19:30:29 +0100 + +In preparation for manually updated display support, such as DSI +command mode panels, this adds a simple helper to see if a connector +is manually updated. + +Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +Tested-by: Tony Lindgren <tony@atomide.com> +--- + drivers/gpu/drm/omapdrm/omap_connector.c | 8 ++++++++ + drivers/gpu/drm/omapdrm/omap_connector.h | 1 + + 2 files changed, 9 insertions(+) + +diff --git a/drivers/gpu/drm/omapdrm/omap_connector.c b/drivers/gpu/drm/omapdrm/omap_connector.c +index a0d7b1d905e8..a33b51484b2d 100644 +--- a/drivers/gpu/drm/omapdrm/omap_connector.c ++++ b/drivers/gpu/drm/omapdrm/omap_connector.c +@@ -57,6 +57,14 @@ bool omap_connector_get_hdmi_mode(struct drm_connector *connector) + return omap_connector->hdmi_mode; + } + ++bool omap_connector_get_manually_updated(struct drm_connector *connector) ++{ ++ struct omap_connector *omap_connector = to_omap_connector(connector); ++ ++ return !!(omap_connector->dssdev->caps & ++ OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE); ++} ++ + static enum drm_connector_status omap_connector_detect( + struct drm_connector *connector, bool force) + { +diff --git a/drivers/gpu/drm/omapdrm/omap_connector.h b/drivers/gpu/drm/omapdrm/omap_connector.h +index 98bbc779b302..652136d167f5 100644 +--- a/drivers/gpu/drm/omapdrm/omap_connector.h ++++ b/drivers/gpu/drm/omapdrm/omap_connector.h +@@ -33,5 +33,6 @@ struct drm_connector *omap_connector_init(struct drm_device *dev, + struct drm_encoder *omap_connector_attached_encoder( + struct drm_connector *connector); + bool omap_connector_get_hdmi_mode(struct drm_connector *connector); ++bool omap_connector_get_manually_updated(struct drm_connector *connector); + + #endif /* __OMAPDRM_CONNECTOR_H__ */ (DIR) diff --git a/extra/patches/linux-n950-patches/0001-PATCHv2-3-8-drm-omap-add-support-for-manually-updated-displays.patch b/extra/patches/linux-n950-patches/0001-PATCHv2-3-8-drm-omap-add-support-for-manually-updated-displays.patch t@@ -0,0 +1,273 @@ +From patchwork Thu Feb 8 18:30:30 2018 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [PATCHv2,3/8] drm/omap: add support for manually updated displays +From: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +X-Patchwork-Id: 10207759 +Message-Id: <20180208183035.8461-4-sebastian.reichel@collabora.co.uk> +To: Sebastian Reichel <sre@kernel.org>, + Tomi Valkeinen <tomi.valkeinen@ti.com>, Tony Lindgren <tony@atomide.com> +Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>, + Hans de Goede <hdegoede@redhat.com>, Rob Herring <robh+dt@kernel.org>, + Mark Rutland <mark.rutland@arm.com>, + dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, + linux-omap@vger.kernel.org, linux-kernel@vger.kernel.org, + kernel@collabora.com, Sebastian Reichel <sebastian.reichel@collabora.co.uk> +Date: Thu, 8 Feb 2018 19:30:30 +0100 + +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. + +Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +Tested-by: Tony Lindgren <tony@atomide.com> +--- + drivers/gpu/drm/omapdrm/omap_crtc.c | 110 +++++++++++++++++++++++++++++++++--- + drivers/gpu/drm/omapdrm/omap_crtc.h | 1 + + drivers/gpu/drm/omapdrm/omap_fb.c | 20 +++++++ + 3 files changed, 123 insertions(+), 8 deletions(-) + +diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c +index 2278e3433008..c2defb514b9f 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; +@@ -142,6 +143,28 @@ static void omap_crtc_dss_disconnect(enum omap_channel channel, + + static void omap_crtc_dss_start_update(enum omap_channel channel) + { ++ struct omap_crtc *omap_crtc = omap_crtcs[channel]; ++ struct omap_drm_private *priv = omap_crtc->base.dev->dev_private; ++ ++ priv->dispc_ops->mgr_enable(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. */ +@@ -153,12 +176,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(channel, enable); + omap_crtc->enabled = enable; + return; +@@ -209,7 +237,6 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable) + } + } + +- + static int omap_crtc_dss_enable(enum omap_channel channel) + { + struct omap_crtc *omap_crtc = omap_crtcs[channel]; +@@ -369,6 +396,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; +@@ -421,6 +495,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); +@@ -434,6 +512,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); + +@@ -444,6 +523,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); + } + +@@ -593,13 +677,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(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(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, +@@ -761,6 +852,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 bd316bc0b6f4..b61c94b34f04 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, uint32_t 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 b2539a90e1a4..57b1767bef09 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, + }; + (DIR) diff --git a/extra/patches/linux-n950-patches/0001-PATCHv2-4-8-dt-bindings-panel-common-document-orientation-property.patch b/extra/patches/linux-n950-patches/0001-PATCHv2-4-8-dt-bindings-panel-common-document-orientation-property.patch t@@ -0,0 +1,74 @@ +From patchwork Thu Feb 8 18:30:31 2018 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [PATCHv2, + 4/8] dt-bindings: panel: common: document orientation property +From: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +X-Patchwork-Id: 10207749 +Message-Id: <20180208183035.8461-5-sebastian.reichel@collabora.co.uk> +To: Sebastian Reichel <sre@kernel.org>, + Tomi Valkeinen <tomi.valkeinen@ti.com>, Tony Lindgren <tony@atomide.com> +Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>, + Hans de Goede <hdegoede@redhat.com>, Rob Herring <robh+dt@kernel.org>, + Mark Rutland <mark.rutland@arm.com>, + dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, + linux-omap@vger.kernel.org, linux-kernel@vger.kernel.org, + kernel@collabora.com, Sebastian Reichel <sebastian.reichel@collabora.co.uk> +Date: Thu, 8 Feb 2018 19:30:31 +0100 + +Introduce new "orientation" property for describing in which +orientation a panel has been mounted to the device. This can +be used by the operating system to automatically rotate the +display correctly. + +Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +--- + .../devicetree/bindings/display/panel/panel-common.txt | 12 ++++++++++++ + include/dt-bindings/display/common.h | 14 ++++++++++++++ + 2 files changed, 26 insertions(+) + create mode 100644 include/dt-bindings/display/common.h + +diff --git a/Documentation/devicetree/bindings/display/panel/panel-common.txt b/Documentation/devicetree/bindings/display/panel/panel-common.txt +index 557fa765adcb..c646b8908458 100644 +--- a/Documentation/devicetree/bindings/display/panel/panel-common.txt ++++ b/Documentation/devicetree/bindings/display/panel/panel-common.txt +@@ -18,6 +18,18 @@ Descriptive Properties + physical area where images are displayed. These properties are expressed in + millimeters and rounded to the closest unit. + ++- orientation: The orientation property specifies the panel orientation ++ in relation to the device's casing. The following values are possible: ++ ++ * 0 = The top side of the panel matches the top side of the device's ++ casing. ++ * 1 = The top side of the panel matches the bottom side of the device's ++ casing. In other words the panel is mounted upside-down. ++ * 2 = The left side of the panel matches the top side of the device's ++ casing. ++ * 3 = The right side of the panel matches the top side of the device's ++ casing. ++ + - label: The label property specifies a symbolic name for the panel as a + string suitable for use by humans. It typically contains a name inscribed on + the system (e.g. as an affixed label) or specified in the system's +diff --git a/include/dt-bindings/display/common.h b/include/dt-bindings/display/common.h +new file mode 100644 +index 000000000000..a864775445a0 +--- /dev/null ++++ b/include/dt-bindings/display/common.h +@@ -0,0 +1,14 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * This header provides common constants for displays ++ */ ++ ++#ifndef _DT_BINDINGS_DISPLAY_COMMON_H ++#define _DT_BINDINGS_DISPLAY_COMMON_H ++ ++#define PANEL_ORIENTATION_NORMAL 0 ++#define PANEL_ORIENTATION_BOTTOM_UP 1 ++#define PANEL_ORIENTATION_LEFT_UP 2 ++#define PANEL_ORIENTATION_RIGHT_UP 3 ++ ++#endif (DIR) diff --git a/extra/patches/linux-n950-patches/0001-PATCHv2-5-8-drm-omap-add-support-for-orientation-hints-from-display-drivers.patch b/extra/patches/linux-n950-patches/0001-PATCHv2-5-8-drm-omap-add-support-for-orientation-hints-from-display-drivers.patch t@@ -0,0 +1,76 @@ +From patchwork Thu Feb 8 18:30:32 2018 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [PATCHv2, + 5/8] drm/omap: add support for orientation hints from display drivers +From: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +X-Patchwork-Id: 10207733 +Message-Id: <20180208183035.8461-6-sebastian.reichel@collabora.co.uk> +To: Sebastian Reichel <sre@kernel.org>, + Tomi Valkeinen <tomi.valkeinen@ti.com>, Tony Lindgren <tony@atomide.com> +Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>, + Hans de Goede <hdegoede@redhat.com>, Rob Herring <robh+dt@kernel.org>, + Mark Rutland <mark.rutland@arm.com>, + dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, + linux-omap@vger.kernel.org, linux-kernel@vger.kernel.org, + kernel@collabora.com, Sebastian Reichel <sebastian.reichel@collabora.co.uk> +Date: Thu, 8 Feb 2018 19:30:32 +0100 + +This adds support for setting DRM panel orientation property +based on information from the display driver. + +Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +--- + drivers/gpu/drm/omapdrm/dss/omapdss.h | 2 ++ + drivers/gpu/drm/omapdrm/omap_connector.c | 10 +++++++++- + 2 files changed, 11 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h +index f8f83e826a56..72ebd82409d3 100644 +--- a/drivers/gpu/drm/omapdrm/dss/omapdss.h ++++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h +@@ -565,6 +565,8 @@ struct omap_dss_driver { + struct videomode *vm); + void (*get_size)(struct omap_dss_device *dssdev, + unsigned int *width, unsigned int *height); ++ void (*get_orientation)(struct omap_dss_device *dssdev, ++ int *orientation); + + int (*set_wss)(struct omap_dss_device *dssdev, u32 wss); + u32 (*get_wss)(struct omap_dss_device *dssdev); +diff --git a/drivers/gpu/drm/omapdrm/omap_connector.c b/drivers/gpu/drm/omapdrm/omap_connector.c +index a33b51484b2d..2f296d29b74b 100644 +--- a/drivers/gpu/drm/omapdrm/omap_connector.c ++++ b/drivers/gpu/drm/omapdrm/omap_connector.c +@@ -249,6 +249,7 @@ struct drm_connector *omap_connector_init(struct drm_device *dev, + struct drm_connector *connector = NULL; + struct omap_connector *omap_connector; + bool hpd_supported = false; ++ int ret; + + DBG("%s", dssdev->name); + +@@ -267,7 +268,7 @@ struct drm_connector *omap_connector_init(struct drm_device *dev, + drm_connector_helper_add(connector, &omap_connector_helper_funcs); + + if (dssdev->driver->register_hpd_cb) { +- int ret = dssdev->driver->register_hpd_cb(dssdev, ++ ret = dssdev->driver->register_hpd_cb(dssdev, + omap_connector_hpd_cb, + omap_connector); + if (!ret) +@@ -288,6 +289,13 @@ struct drm_connector *omap_connector_init(struct drm_device *dev, + connector->interlace_allowed = 1; + connector->doublescan_allowed = 0; + ++ if (dssdev->driver->get_orientation) ++ dssdev->driver->get_orientation(dssdev, &connector->display_info.panel_orientation); ++ ++ ret = drm_connector_init_panel_orientation_property(connector, 0, 0); ++ if (ret) ++ DBG("%s: Failed to init orientation property (%d)", dssdev->name, ret); ++ + return connector; + + fail: (DIR) diff --git a/extra/patches/linux-n950-patches/0001-PATCHv2-6-8-drm-omap-panel-dsi-cm-add-orientation-support.patch b/extra/patches/linux-n950-patches/0001-PATCHv2-6-8-drm-omap-panel-dsi-cm-add-orientation-support.patch t@@ -0,0 +1,71 @@ +From patchwork Thu Feb 8 18:30:33 2018 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [PATCHv2,6/8] drm/omap: panel-dsi-cm: add orientation support +From: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +X-Patchwork-Id: 10207747 +Message-Id: <20180208183035.8461-7-sebastian.reichel@collabora.co.uk> +To: Sebastian Reichel <sre@kernel.org>, + Tomi Valkeinen <tomi.valkeinen@ti.com>, Tony Lindgren <tony@atomide.com> +Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>, + Hans de Goede <hdegoede@redhat.com>, Rob Herring <robh+dt@kernel.org>, + Mark Rutland <mark.rutland@arm.com>, + dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, + linux-omap@vger.kernel.org, linux-kernel@vger.kernel.org, + kernel@collabora.com, Sebastian Reichel <sebastian.reichel@collabora.co.uk> +Date: Thu, 8 Feb 2018 19:30:33 +0100 + +Add support to inform the DRM subsystem about the orientation +the display has been mounted to the casing. + +Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +--- + drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c +index 15399a1a666b..7a63d6775a27 100644 +--- a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c ++++ b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c +@@ -68,6 +68,7 @@ struct panel_drv_data { + + int width_mm; + int height_mm; ++ int orientation; + + struct omap_dsi_pin_config pin_config; + +@@ -1198,6 +1199,14 @@ static void dsicm_get_size(struct omap_dss_device *dssdev, + *height = ddata->height_mm; + } + ++static void dsicm_get_orientation(struct omap_dss_device *dssdev, ++ int *orientation) ++{ ++ struct panel_drv_data *ddata = to_panel_data(dssdev); ++ ++ *orientation = ddata->orientation; ++} ++ + static struct omap_dss_driver dsicm_ops = { + .connect = dsicm_connect, + .disconnect = dsicm_disconnect, +@@ -1211,6 +1220,7 @@ static struct omap_dss_driver dsicm_ops = { + .get_timings = dsicm_get_timings, + .check_timings = dsicm_check_timings, + .get_size = dsicm_get_size, ++ .get_orientation = dsicm_get_orientation, + + .enable_te = dsicm_enable_te, + .get_te = dsicm_get_te, +@@ -1259,6 +1269,9 @@ static int dsicm_probe_of(struct platform_device *pdev) + ddata->height_mm = 0; + of_property_read_u32(node, "height-mm", &ddata->height_mm); + ++ ddata->orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN; ++ of_property_read_u32(node, "orientation", &ddata->orientation); ++ + in = omapdss_of_find_source_for_first_ep(node); + if (IS_ERR(in)) { + dev_err(&pdev->dev, "failed to find video source\n"); (DIR) diff --git a/extra/patches/linux-n950-patches/0001-PATCHv2-7-8-ARM-dts-omap4-droid4-Add-LCD-panel-orientation-property.patch b/extra/patches/linux-n950-patches/0001-PATCHv2-7-8-ARM-dts-omap4-droid4-Add-LCD-panel-orientation-property.patch t@@ -0,0 +1,48 @@ +From patchwork Thu Feb 8 18:30:34 2018 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [PATCHv2, + 7/8] ARM: dts: omap4-droid4: Add LCD panel orientation property +From: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +X-Patchwork-Id: 10207755 +Message-Id: <20180208183035.8461-8-sebastian.reichel@collabora.co.uk> +To: Sebastian Reichel <sre@kernel.org>, + Tomi Valkeinen <tomi.valkeinen@ti.com>, Tony Lindgren <tony@atomide.com> +Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>, + Hans de Goede <hdegoede@redhat.com>, Rob Herring <robh+dt@kernel.org>, + Mark Rutland <mark.rutland@arm.com>, + dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, + linux-omap@vger.kernel.org, linux-kernel@vger.kernel.org, + kernel@collabora.com, Sebastian Reichel <sebastian.reichel@collabora.co.uk> +Date: Thu, 8 Feb 2018 19:30:34 +0100 + +This adds a LCD panel orientation hint to the Droid 4. If the +display is rotated this way the keyboard can be used properly. + +Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +--- + arch/arm/boot/dts/omap4-droid4-xt894.dts | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/arch/arm/boot/dts/omap4-droid4-xt894.dts b/arch/arm/boot/dts/omap4-droid4-xt894.dts +index b21084da490b..e11a24397163 100644 +--- a/arch/arm/boot/dts/omap4-droid4-xt894.dts ++++ b/arch/arm/boot/dts/omap4-droid4-xt894.dts +@@ -6,6 +6,7 @@ + /dts-v1/; + + #include <dt-bindings/input/input.h> ++#include <dt-bindings/display/common.h> + #include "omap443x.dtsi" + #include "motorola-cpcap-mapphone.dtsi" + +@@ -181,6 +182,8 @@ + height-mm = <89>; + backlight = <&lcd_backlight>; + ++ orientation = <PANEL_ORIENTATION_RIGHT_UP>; ++ + panel-timing { + clock-frequency = <0>; /* Calculated by dsi */ + (DIR) diff --git a/extra/patches/linux-n950-patches/0001-PATCHv2-8-8-drm-omap-plane-update-fifo-size-on-ovl-setup.patch b/extra/patches/linux-n950-patches/0001-PATCHv2-8-8-drm-omap-plane-update-fifo-size-on-ovl-setup.patch t@@ -0,0 +1,141 @@ +From patchwork Thu Feb 8 18:30:35 2018 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [PATCHv2,8/8] drm/omap: plane: update fifo size on ovl setup +From: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +X-Patchwork-Id: 10207743 +Message-Id: <20180208183035.8461-9-sebastian.reichel@collabora.co.uk> +To: Sebastian Reichel <sre@kernel.org>, + Tomi Valkeinen <tomi.valkeinen@ti.com>, Tony Lindgren <tony@atomide.com> +Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>, + Hans de Goede <hdegoede@redhat.com>, Rob Herring <robh+dt@kernel.org>, + Mark Rutland <mark.rutland@arm.com>, + dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, + linux-omap@vger.kernel.org, linux-kernel@vger.kernel.org, + kernel@collabora.com, Sebastian Reichel <sebastian.reichel@collabora.co.uk> +Date: Thu, 8 Feb 2018 19:30:35 +0100 + +This is a workaround for a hardware bug occuring on OMAP3 +with manually updated panels. Details about the HW bug are +unknown to me, but without this fix the panel refresh does +not work at all on Nokia N950. This is not the case for the +OMAP4 based Droid 4, which works perfectly fine with default +settings. + +Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +--- + drivers/gpu/drm/omapdrm/dss/dispc.c | 36 +++++++++++++++++++++++++++++++++++- + 1 file changed, 35 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c +index 4e8f68efd169..0904c3201914 100644 +--- a/drivers/gpu/drm/omapdrm/dss/dispc.c ++++ b/drivers/gpu/drm/omapdrm/dss/dispc.c +@@ -157,6 +157,8 @@ struct dispc_features { + bool has_gamma_table:1; + + bool has_gamma_i734_bug:1; ++ ++ bool has_fifo_stallmode_bug:1; + }; + + #define DISPC_MAX_NR_FIFOS 5 +@@ -1489,6 +1491,18 @@ void dispc_ovl_compute_fifo_thresholds(enum omap_plane_id plane, + } + } + ++static void dispc_ovl_set_manual_fifo_threshold(enum omap_plane_id plane) ++{ ++ u32 fifo_low, fifo_high; ++ bool use_fifo_merge = false; ++ bool use_manual_update = true; ++ ++ dispc_ovl_compute_fifo_thresholds(plane, &fifo_low, &fifo_high, ++ use_fifo_merge, use_manual_update); ++ ++ dispc_ovl_set_fifo_threshold(plane, fifo_low, fifo_high); ++} ++ + static void dispc_ovl_set_mflag(enum omap_plane_id plane, bool enable) + { + int bit; +@@ -2651,8 +2665,21 @@ static int dispc_ovl_setup(enum omap_plane_id plane, + oi->out_width, oi->out_height, oi->fourcc, oi->rotation, + oi->zorder, oi->pre_mult_alpha, oi->global_alpha, + oi->rotation_type, replication, vm, mem_to_mem); ++ if (r) ++ return r; + +- return r; ++ /* ++ * OMAP3 chips have non-working FIFO thresholds for manually updated ++ * displays. The issue is not fully understood, but this workaround ++ * fixes the issue. OMAP4 is known to work with default thresholds. ++ */ ++ if (mgr_fld_read(channel, DISPC_MGR_FLD_STALLMODE) && ++ dispc.feat->has_fifo_stallmode_bug) { ++ DSSDBG("Enable OMAP3 FIFO stallmode bug workaround!\n"); ++ dispc_ovl_set_manual_fifo_threshold(plane); ++ } ++ ++ return 0; + } + + int dispc_wb_setup(const struct omap_dss_writeback_info *wi, +@@ -4067,6 +4094,7 @@ static const struct dispc_features omap24xx_dispc_feats = { + .no_framedone_tv = true, + .set_max_preload = false, + .last_pixel_inc_missing = true, ++ .has_fifo_stallmode_bug = true, + }; + + static const struct dispc_features omap34xx_rev1_0_dispc_feats = { +@@ -4101,6 +4129,7 @@ static const struct dispc_features omap34xx_rev1_0_dispc_feats = { + .no_framedone_tv = true, + .set_max_preload = false, + .last_pixel_inc_missing = true, ++ .has_fifo_stallmode_bug = true, + }; + + static const struct dispc_features omap34xx_rev3_0_dispc_feats = { +@@ -4135,6 +4164,7 @@ static const struct dispc_features omap34xx_rev3_0_dispc_feats = { + .no_framedone_tv = true, + .set_max_preload = false, + .last_pixel_inc_missing = true, ++ .has_fifo_stallmode_bug = true, + }; + + static const struct dispc_features omap36xx_dispc_feats = { +@@ -4169,6 +4199,7 @@ static const struct dispc_features omap36xx_dispc_feats = { + .no_framedone_tv = true, + .set_max_preload = false, + .last_pixel_inc_missing = true, ++ .has_fifo_stallmode_bug = true, + }; + + static const struct dispc_features am43xx_dispc_feats = { +@@ -4203,6 +4234,7 @@ static const struct dispc_features am43xx_dispc_feats = { + .no_framedone_tv = true, + .set_max_preload = false, + .last_pixel_inc_missing = true, ++ .has_fifo_stallmode_bug = false, + }; + + static const struct dispc_features omap44xx_dispc_feats = { +@@ -4242,6 +4274,7 @@ static const struct dispc_features omap44xx_dispc_feats = { + .reverse_ilace_field_order = true, + .has_gamma_table = true, + .has_gamma_i734_bug = true, ++ .has_fifo_stallmode_bug = false, + }; + + static const struct dispc_features omap54xx_dispc_feats = { +@@ -4282,6 +4315,7 @@ static const struct dispc_features omap54xx_dispc_feats = { + .reverse_ilace_field_order = true, + .has_gamma_table = true, + .has_gamma_i734_bug = true, ++ .has_fifo_stallmode_bug = false, + }; + + static irqreturn_t dispc_irq_handler(int irq, void *arg) (DIR) diff --git a/extra/pwclient/.pwclientrc b/extra/pwclient/.pwclientrc t@@ -1,6 +0,0 @@ -[options] -default=linux-omap - -[linux-omap] -url= https://patchwork.kernel.org/xmlrpc/ - (DIR) diff --git a/extra/pwclient/pwclient b/extra/pwclient/pwclient t@@ -1,704 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# -# Patchwork command line client -# Copyright (C) 2008 Nate Case <ncase@xes-inc.com> -# -# This file is part of the Patchwork package. -# -# Patchwork is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# Patchwork 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. -# -# You should have received a copy of the GNU General Public License -# along with Patchwork; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -from __future__ import print_function - -import os -import sys -try: - import xmlrpclib -except ImportError: - # Python 3 has merged/renamed things. - import xmlrpc.client as xmlrpclib -import argparse -import string -import tempfile -import subprocess -import base64 -try: - import ConfigParser -except ImportError: - # Python 3 has renamed things. - import configparser as ConfigParser -import shutil -import re - -# Add a shim for Python 2's unicode() helper. -try: - unicode -except NameError: - # Python 3 does everything by unicode now. - unicode = str - -# Default Patchwork remote XML-RPC server URL -# This script will check the PW_XMLRPC_URL environment variable -# for the URL to access. If that is unspecified, it will fallback to -# the hardcoded default value specified here. -DEFAULT_URL = "http://patchwork/xmlrpc/" -CONFIG_FILE = os.path.expanduser('~/.pwclientrc') - -class Filter(object): - """Filter for selecting patches.""" - def __init__(self): - # These fields refer to specific objects, so they are special - # because we have to resolve them to IDs before passing the - # filter to the server - self.state = "" - self.project = "" - - # The dictionary that gets passed to via XML-RPC - self.d = {} - - def add(self, field, value): - if field == 'state': - self.state = value - elif field == 'project': - self.project = value - else: - # OK to add directly - self.d[field] = value - - def resolve_ids(self, rpc): - """Resolve State, Project, and Person IDs based on filter strings.""" - if self.state != "": - id = state_id_by_name(rpc, self.state) - if id == 0: - sys.stderr.write("Note: No State found matching %s*, " \ - "ignoring filter\n" % self.state) - else: - self.d['state_id'] = id - - if self.project != None: - id = project_id_by_name(rpc, self.project) - if id == 0: - sys.stderr.write("Note: No Project found matching %s, " \ - "ignoring filter\n" % self.project) - else: - self.d['project_id'] = id - - def __str__(self): - """Return human-readable description of the filter.""" - return str(self.d) - -class BasicHTTPAuthTransport(xmlrpclib.SafeTransport): - - def __init__(self, username = None, password = None, use_https = False): - self.username = username - self.password = password - self.use_https = use_https - xmlrpclib.SafeTransport.__init__(self) - - def authenticated(self): - return self.username != None and self.password != None - - def send_host(self, connection, host): - xmlrpclib.Transport.send_host(self, connection, host) - if not self.authenticated(): - return - credentials = '%s:%s' % (self.username, self.password) - auth = 'Basic ' + base64.encodestring(credentials).strip() - connection.putheader('Authorization', auth) - - def make_connection(self, host): - if self.use_https: - fn = xmlrpclib.SafeTransport.make_connection - else: - fn = xmlrpclib.Transport.make_connection - return fn(self, host) - -def project_id_by_name(rpc, linkname): - """Given a project short name, look up the Project ID.""" - if len(linkname) == 0: - return 0 - projects = rpc.project_list(linkname, 0) - for project in projects: - if project['linkname'] == linkname: - return project['id'] - return 0 - -def state_id_by_name(rpc, name): - """Given a partial state name, look up the state ID.""" - if len(name) == 0: - return 0 - states = rpc.state_list(name, 0) - for state in states: - if state['name'].lower().startswith(name.lower()): - return state['id'] - return 0 - -def person_ids_by_name(rpc, name): - """Given a partial name or email address, return a list of the - person IDs that match.""" - if len(name) == 0: - return [] - people = rpc.person_list(name, 0) - return [x['id'] for x in people] - -def list_patches(patches, format_str=None): - """Dump a list of patches to stdout.""" - if format_str: - format_field_re = re.compile("%{([a-z0-9_]+)}") - - def patch_field(matchobj): - fieldname = matchobj.group(1) - - if fieldname == "_msgid_": - # naive way to strip < and > from message-id - val = string.strip(str(patch["msgid"]), "<>") - else: - val = str(patch[fieldname]) - - return val - - for patch in patches: - print(format_field_re.sub(patch_field, format_str)) - else: - print("%-7s %-12s %s" % ("ID", "State", "Name")) - print("%-7s %-12s %s" % ("--", "-----", "----")) - for patch in patches: - print("%-7d %-12s %s" % (patch['id'], patch['state'], patch['name'])) - -def action_list(rpc, filter, submitter_str, delegate_str, format_str=None): - filter.resolve_ids(rpc) - - if submitter_str != None: - ids = person_ids_by_name(rpc, submitter_str) - if len(ids) == 0: - sys.stderr.write("Note: Nobody found matching *%s*\n" % \ - submitter_str) - else: - for id in ids: - person = rpc.person_get(id) - print('Patches submitted by %s <%s>:' % - (unicode(person['name']).encode('utf-8'), - unicode(person['email']).encode('utf-8'))) - f = filter - f.add("submitter_id", id) - patches = rpc.patch_list(f.d) - list_patches(patches, format_str) - return - - if delegate_str != None: - ids = person_ids_by_name(rpc, delegate_str) - if len(ids) == 0: - sys.stderr.write("Note: Nobody found matching *%s*\n" % \ - delegate_str) - else: - for id in ids: - person = rpc.person_get(id) - print('Patches delegated to %s <%s>:' % - (person['name'], person['email'])) - f = filter - f.add("delegate_id", id) - patches = rpc.patch_list(f.d) - list_patches(patches, format_str) - return - - patches = rpc.patch_list(filter.d) - list_patches(patches, format_str) - -def action_projects(rpc): - projects = rpc.project_list("", 0) - print("%-5s %-24s %s" % ("ID", "Name", "Description")) - print("%-5s %-24s %s" % ("--", "----", "-----------")) - for project in projects: - print("%-5d %-24s %s" % (project['id'], \ - project['linkname'], \ - project['name'])) - -def action_states(rpc): - states = rpc.state_list("", 0) - print("%-5s %s" % ("ID", "Name")) - print("%-5s %s" % ("--", "----")) - for state in states: - print("%-5d %s" % (state['id'], state['name'])) - -def action_info(rpc, patch_id): - patch = rpc.patch_get(patch_id) - s = "Information for patch id %d" % (patch_id) - print(s) - print('-' * len(s)) - for key, value in sorted(patch.items()): - print("- %- 14s: %s" % (key, unicode(value).encode("utf-8"))) - -def action_get(rpc, patch_id): - patch = rpc.patch_get(patch_id) - s = rpc.patch_get_mbox(patch_id) - - if patch == {} or len(s) == 0: - sys.stderr.write("Unable to get patch %d\n" % patch_id) - sys.exit(1) - - base_fname = fname = os.path.basename(patch['filename']) - i = 0 - while os.path.exists(fname): - fname = "%s.%d" % (base_fname, i) - i += 1 - - try: - f = open(fname, "w") - except: - sys.stderr.write("Unable to open %s for writing\n" % fname) - sys.exit(1) - - try: - f.write(unicode(s).encode("utf-8")) - f.close() - print('Saved patch to %s' % fname) - except: - sys.stderr.write("Failed to write to %s\n" % fname) - sys.exit(1) - -def action_apply(rpc, patch_id, apply_cmd=None): - patch = rpc.patch_get(patch_id) - if patch == {}: - sys.stderr.write("Error getting information on patch ID %d\n" % \ - patch_id) - sys.exit(1) - - if apply_cmd is None: - print('Applying patch #%d to current directory' % patch_id) - apply_cmd = ['patch', '-p1'] - else: - print('Applying patch #%d using %s' % - (patch_id, repr(' '.join(apply_cmd)))) - - print('Description: %s' % patch['name']) - s = rpc.patch_get_mbox(patch_id) - if len(s) > 0: - proc = subprocess.Popen(apply_cmd, stdin = subprocess.PIPE) - proc.communicate(unicode(s).encode('utf-8')) - return proc.returncode - else: - sys.stderr.write("Error: No patch content found\n") - sys.exit(1) - -def action_update_patch(rpc, patch_id, state = None, archived = None, commit = None): - patch = rpc.patch_get(patch_id) - if patch == {}: - sys.stderr.write("Error getting information on patch ID %d\n" % \ - patch_id) - sys.exit(1) - - params = {} - - if state: - state_id = state_id_by_name(rpc, state) - if state_id == 0: - sys.stderr.write("Error: No State found matching %s*\n" % state) - sys.exit(1) - params['state'] = state_id - - if commit: - params['commit_ref'] = commit - - if archived: - params['archived'] = archived == 'yes' - - success = False - try: - success = rpc.patch_set(patch_id, params) - except xmlrpclib.Fault as f: - sys.stderr.write("Error updating patch: %s\n" % f.faultString) - - if not success: - sys.stderr.write("Patch not updated\n") - -def patch_id_from_hash(rpc, project, hash): - try: - patch = rpc.patch_get_by_project_hash(project, hash) - except xmlrpclib.Fault: - # the server may not have the newer patch_get_by_project_hash function, - # so fall back to hash-only. - patch = rpc.patch_get_by_hash(hash) - - if patch == {}: - sys.stderr.write("No patch has the hash provided\n") - sys.exit(1) - - patch_id = patch['id'] - # be super paranoid - try: - patch_id = int(patch_id) - except: - sys.stderr.write("Invalid patch ID obtained from server\n") - sys.exit(1) - return patch_id - -auth_actions = ['update'] - -def main(): - hash_parser = argparse.ArgumentParser(add_help=False) - hash_parser.add_argument( - '-h', metavar='HASH', dest='hash', action='store', - help='''Lookup by patch hash''' - ) - hash_parser.add_argument( - 'id', metavar='ID', nargs='*', action='store', type=int, - help='Patch ID', - ) - hash_parser.add_argument( - '-p', metavar='PROJECT', - help='''Lookup patch in project''' - ) - - filter_parser = argparse.ArgumentParser(add_help=False) - filter_parser.add_argument( - '-s', metavar='STATE', - help='''Filter by patch state (e.g., 'New', 'Accepted', etc.)''' - ) - filter_parser.add_argument( - '-a', choices=['yes','no'], - help='''Filter by patch archived state''' - ) - filter_parser.add_argument( - '-p', metavar='PROJECT', - help='''Filter by project name (see 'projects' for list)''' - ) - filter_parser.add_argument( - '-w', metavar='WHO', - help='''Filter by submitter (name, e-mail substring search)''' - ) - filter_parser.add_argument( - '-d', metavar='WHO', - help='''Filter by delegate (name, e-mail substring search)''' - ) - filter_parser.add_argument( - '-n', metavar='MAX#', - type=int, - help='''Restrict number of results''' - ) - filter_parser.add_argument( - '-m', metavar='MESSAGEID', - help='''Filter by Message-Id''' - ) - filter_parser.add_argument( - '-f', metavar='FORMAT', - help='''Print output in the given format. You can use tags matching ''' - '''fields, e.g. %%{id}, %%{state}, or %%{msgid}.''' - ) - filter_parser.add_argument( - 'patch_name', metavar='STR', nargs='?', - help='substring to search for patches by name', - ) - - action_parser = argparse.ArgumentParser( - prog='pwclient', - epilog='Use \'pwclient <command> --help\' for more info', - ) - - subparsers = action_parser.add_subparsers( - title='Commands', - ) - apply_parser = subparsers.add_parser( - 'apply', parents=[hash_parser], conflict_handler='resolve', - help='''Apply a patch (in the current dir, using -p1)''' - ) - apply_parser.set_defaults(subcmd='apply') - git_am_parser = subparsers.add_parser( - 'git-am', parents=[hash_parser], conflict_handler='resolve', - help='''Apply a patch to current git branch using "git am".''' - ) - git_am_parser.set_defaults(subcmd='git_am') - git_am_parser.add_argument( - '-s', '--signoff', - action='store_true', - help='''pass --signoff to git-am''' - ) - get_parser = subparsers.add_parser( - 'get', parents=[hash_parser], conflict_handler='resolve', - help='''Download a patch and save it locally''' - ) - get_parser.set_defaults(subcmd='get') - info_parser = subparsers.add_parser( - 'info', parents=[hash_parser], conflict_handler='resolve', - help='''Display patchwork info about a given patch ID''' - ) - info_parser.set_defaults(subcmd='info') - projects_parser = subparsers.add_parser( - 'projects', - help='''List all projects''' - ) - projects_parser.set_defaults(subcmd='projects') - states_parser = subparsers.add_parser( - 'states', - help='''Show list of potential patch states''' - ) - states_parser.set_defaults(subcmd='states') - view_parser = subparsers.add_parser( - 'view', parents=[hash_parser], conflict_handler='resolve', - help='''View a patch''' - ) - view_parser.set_defaults(subcmd='view') - update_parser = subparsers.add_parser( - 'update', parents=[hash_parser], conflict_handler='resolve', - help='''Update patch''', - epilog='''Using a COMMIT-REF allows for only one ID to be specified''', - ) - update_parser.add_argument( - '-c', metavar='COMMIT-REF', - help='''commit reference hash''' - ) - update_parser.add_argument( - '-s', metavar='STATE', - help='''Set patch state (e.g., 'Accepted', 'Superseded' etc.)''' - ) - update_parser.add_argument( - '-a', choices=['yes', 'no'], - help='''Set patch archived state''' - ) - update_parser.set_defaults(subcmd='update') - list_parser = subparsers.add_parser("list", - #aliases=['search'], - parents=[filter_parser], - help='''List patches, using the optional filters specified - below and an optional substring to search for patches - by name''' - ) - list_parser.set_defaults(subcmd='list') - search_parser = subparsers.add_parser("search", - parents=[filter_parser], - help='''Alias for "list"''' - ) - # Poor man's argparse aliases: - # We register the "search" parser but effectively use "list" for the - # help-text. - search_parser.set_defaults(subcmd='list') - if len(sys.argv) < 2: - action_parser.print_help() - sys.exit(0) - - args = action_parser.parse_args() - args = dict(vars(args)) - action = args.get('subcmd') - - if args.get('hash') and len(args.get('id')): - # mimic mutual exclusive group - locals()[action + '_parser'].error( - "[-h HASH] and [ID [ID ...]] are mutually exlusive") - - # set defaults - filt = Filter() - commit_str = None - url = DEFAULT_URL - - archived_str = args.get('a') - state_str = args.get('s') - project_str = args.get('p') - submitter_str = args.get('w') - delegate_str = args.get('d') - format_str = args.get('f') - hash_str = args.get('hash') - patch_ids = args.get('id') - msgid_str = args.get('m') - if args.get('c'): - # update multiple IDs with a single commit-hash does not make sense - if action == 'update' and patch_ids and len(patch_ids) > 1: - update_parser.error("Declining update with COMMIT-REF on multiple IDs") - commit_str = args.get('c') - - if state_str is None and archived_str is None and action == 'update': - update_parser.error('Must specify one or more update options (-a or -s)') - - if args.get('n') != None: - try: - filt.add("max_count", args.get('n')) - except: - action_parser.error("Invalid maximum count '%s'" % args.get('n')) - - do_signoff = args.get('signoff') - - # grab settings from config files - config = ConfigParser.ConfigParser() - config.read([CONFIG_FILE]) - - if not config.has_section('options') and os.path.exists(CONFIG_FILE): - sys.stderr.write('~/.pwclientrc is in the old format. Migrating it...') - - old_project = config.get('base','project') - - new_config = ConfigParser.ConfigParser() - new_config.add_section('options') - - new_config.set('options','default',old_project) - new_config.add_section(old_project) - - new_config.set(old_project,'url',config.get('base','url')) - if config.has_option('auth', 'username'): - new_config.set(old_project,'username',config.get('auth','username')) - if config.has_option('auth', 'password'): - new_config.set(old_project,'password',config.get('auth','password')) - - old_config_file = CONFIG_FILE + '.orig' - shutil.copy2(CONFIG_FILE,old_config_file) - - with open(CONFIG_FILE, 'wb') as fd: - new_config.write(fd) - - sys.stderr.write(' Done.\n') - sys.stderr.write('Your old ~/.pwclientrc was saved to %s\n' % old_config_file) - sys.stderr.write('and was converted to the new format. You may want to\n') - sys.stderr.write('inspect it before continuing.\n') - sys.exit(1) - - if not project_str: - try: - project_str = config.get('options', 'default') - except: - action_parser.error("No default project configured in ~/.pwclientrc") - - if not config.has_section(project_str): - sys.stderr.write('No section for project %s in ~/.pwclientrc\n' % project_str) - sys.exit(1) - if not config.has_option(project_str, 'url'): - sys.stderr.write('No URL for project %s in ~/.pwclientrc\n' % project_str) - sys.exit(1) - if not do_signoff and config.has_option('options', 'signoff'): - do_signoff = config.getboolean('options', 'signoff') - if not do_signoff and config.has_option(project_str, 'signoff'): - do_signoff = config.getboolean(project_str, 'signoff') - - url = config.get(project_str, 'url') - - transport = None - if action in auth_actions: - if config.has_option(project_str, 'username') and \ - config.has_option(project_str, 'password'): - - use_https = url.startswith('https') - - transport = BasicHTTPAuthTransport( \ - config.get(project_str, 'username'), - config.get(project_str, 'password'), - use_https) - - else: - sys.stderr.write(("The %s action requires authentication, " - "but no username or password\nis configured\n") % action) - sys.exit(1) - - if project_str: - filt.add("project", project_str) - - if state_str: - filt.add("state", state_str) - - if archived_str: - filt.add("archived", archived_str == 'yes') - - if msgid_str: - filt.add("msgid", msgid_str) - - try: - rpc = xmlrpclib.Server(url, transport = transport) - except: - sys.stderr.write("Unable to connect to %s\n" % url) - sys.exit(1) - - # It should be safe to assume hash_str is not zero, but who knows.. - if hash_str != None: - patch_ids = [patch_id_from_hash(rpc, project_str, hash_str)] - - # helper for non_empty() to print correct helptext - h = locals()[action + '_parser'] - - # Require either hash_str or IDs for - def non_empty(h, patch_ids): - """Error out if no patch IDs were specified""" - if patch_ids == None or len(patch_ids) < 1: - sys.stderr.write("Error: Missing Argument! " + - "Either [-h HASH] or [ID [ID ...]] are required\n") - if h: - h.print_help() - sys.exit(1) - return patch_ids - - if action == 'list' or action == 'search': - if args.get('patch_name') != None: - filt.add("name__icontains", args.get('patch_name')) - action_list(rpc, filt, submitter_str, delegate_str, format_str) - - elif action.startswith('project'): - action_projects(rpc) - - elif action.startswith('state'): - action_states(rpc) - - elif action == 'view': - pager = os.environ.get('PAGER') - if pager: - pager = subprocess.Popen( - pager.split(), stdin=subprocess.PIPE - ) - if pager: - i = list() - for patch_id in non_empty(h, patch_ids): - s = rpc.patch_get_mbox(patch_id) - if len(s) > 0: - i.append(unicode(s).encode("utf-8")) - if len(i) > 0: - pager.communicate(input="\n".join(i)) - pager.stdin.close() - else: - for patch_id in non_empty(h, patch_ids): - s = rpc.patch_get_mbox(patch_id) - if len(s) > 0: - print(unicode(s).encode("utf-8")) - - elif action == 'info': - for patch_id in non_empty(h, patch_ids): - action_info(rpc, patch_id) - - elif action == 'get': - for patch_id in non_empty(h, patch_ids): - action_get(rpc, patch_id) - - elif action == 'apply': - for patch_id in non_empty(h, patch_ids): - ret = action_apply(rpc, patch_id) - if ret: - sys.stderr.write("Apply failed with exit status %d\n" % ret) - sys.exit(1) - - elif action == 'git_am': - cmd = ['git', 'am'] - if do_signoff: - cmd.append('-s') - for patch_id in non_empty(h, patch_ids): - ret = action_apply(rpc, patch_id, cmd) - if ret: - sys.stderr.write("'git am' failed with exit status %d\n" % ret) - sys.exit(1) - - elif action == 'update': - for patch_id in non_empty(h, patch_ids): - action_update_patch(rpc, patch_id, state = state_str, - archived = archived_str, commit = commit_str - ) - - else: - sys.stderr.write("Unknown action '%s'\n" % action) - action_parser.print_help() - sys.exit(1) - -if __name__ == "__main__": - main()