arm-sdk

os build toolkit for various embedded devices
git clone https://git.parazyd.org/arm-sdk
Log | Files | Refs | Submodules | README | LICENSE

commit 6b61bec7be1f2d7efee082c008b7cd5f1ac42432
parent 7efcb3d202487652337722ac2fa40256933be3ef
Author: parazyd <parazyd@dyne.org>
Date:   Thu, 15 Feb 2018 20:40:01 +0100

Revert "Add and rebase sre's droid4 patches for linux 4.16-rc1."

This reverts commit 3f9238ed77bf41b1bbdde75b9d16fdd670b79c8c.

Diffstat:
Aextra/patches/linux-droid4-patches/0001-drm-omap-remove-unused-function-defines.patch | 31+++++++++++++++++++++++++++++++
Dextra/patches/linux-droid4-patches/0001_drm-omap-add-framedone-interrupt-support.patch | 158-------------------------------------------------------------------------------
Aextra/patches/linux-droid4-patches/0002-drm-omap-drop-incorrect-comment.patch | 33+++++++++++++++++++++++++++++++++
Dextra/patches/linux-droid4-patches/0002_drm-omap-add-manual-update-detection-helper.patch | 42------------------------------------------
Aextra/patches/linux-droid4-patches/0003-drm-omap-plane-update-fifo-size-on-ovl-setup.patch | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Dextra/patches/linux-droid4-patches/0003_drm-omap-add-support-for-manually-updated-displays.patch | 256-------------------------------------------------------------------------------
Aextra/patches/linux-droid4-patches/0004-drm-omap-add-framedone-interrupt-support.patch | 160+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dextra/patches/linux-droid4-patches/0004_dt-bindings-panel-common-document-orientation-property.patch | 57---------------------------------------------------------
Aextra/patches/linux-droid4-patches/0005-drm-omap-add-manual-update-detection-helper.patch | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Dextra/patches/linux-droid4-patches/0005_drm-omap-add-support-for-orientation-hints-from-display-drivers.patch | 59-----------------------------------------------------------
Aextra/patches/linux-droid4-patches/0006-drm-omap-add-support-for-manually-updated-displays.patch | 263+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dextra/patches/linux-droid4-patches/0006_drm-omap-panel-dsi-cm-add-orientation-support.patch | 55-------------------------------------------------------
Aextra/patches/linux-droid4-patches/0007-drm-omap-add-support-for-physical-size-hints-from-di.patch | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Dextra/patches/linux-droid4-patches/0007_arm-dts-omap4-droid4-add-lcd-panel-orientation-property.patch | 31-------------------------------
Aextra/patches/linux-droid4-patches/0008-drm-omap-panel-dsi-cm-fix-driver.patch | 124+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dextra/patches/linux-droid4-patches/0008_drm-omap-plane-update-fifo-size-on-ovl-setup.patch | 125-------------------------------------------------------------------------------
Aextra/patches/linux-droid4-patches/0009-drm-omap-panel-dsi-cm-add-regulator-support.patch | 135+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dextra/patches/linux-droid4-patches/0009_arm-dts-omap4-droid4-update-touchscreen.patch | 67-------------------------------------------------------------------
Aextra/patches/linux-droid4-patches/0010-drm-omap-panel-dsi-cm-add-physical-size-support.patch | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aextra/patches/linux-droid4-patches/0011-drm-omap-panel-dsi-cm-add-external-backlight-support.patch | 247+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aextra/patches/linux-droid4-patches/0012-drm-omap-panel-dsi-cm-switch-to-gpiod.patch | 172+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aextra/patches/linux-droid4-patches/0013-ARM-dts-omap4-droid4-improve-LCD-description.patch | 39+++++++++++++++++++++++++++++++++++++++
Aextra/patches/linux-droid4-patches/0014-ARM-dts-n950-add-display-support.patch | 122+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aextra/patches/linux-droid4-patches/0015-dt-bindings-backlight-add-ti-lmu-backlight-binding.patch | 89+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aextra/patches/linux-droid4-patches/0016-backlight-add-TI-LMU-backlight-driver.patch | 1222+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aextra/patches/linux-droid4-patches/0017-droid4-hdmi-on-4.14-rc4.patch | 102+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dextra/patches/linux-droid4-patches/README | 61-------------------------------------------------------------
27 files changed, 2957 insertions(+), 911 deletions(-)

diff --git a/extra/patches/linux-droid4-patches/0001-drm-omap-remove-unused-function-defines.patch b/extra/patches/linux-droid4-patches/0001-drm-omap-remove-unused-function-defines.patch @@ -0,0 +1,31 @@ +From a7129365bbffa136d3987e9ae8480337882f753a Mon Sep 17 00:00:00 2001 +From: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +Date: Mon, 24 Jul 2017 19:32:58 +0200 +Subject: [PATCH 01/17] drm/omap: remove unused function defines + +Remove driver (un)register API defines. They do not even exist +anymore. + +Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +Acked-by: Pavel Machek <pavel@ucw.cz> +--- + drivers/gpu/drm/omapdrm/dss/omapdss.h | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h +index 47a3316..3d25359 100644 +--- a/drivers/gpu/drm/omapdrm/dss/omapdss.h ++++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h +@@ -584,9 +584,6 @@ struct omap_dss_driver { + + bool omapdss_is_initialized(void); + +-int omap_dss_register_driver(struct omap_dss_driver *); +-void omap_dss_unregister_driver(struct omap_dss_driver *); +- + int omapdss_register_display(struct omap_dss_device *dssdev); + void omapdss_unregister_display(struct omap_dss_device *dssdev); + +-- +2.1.4 + diff --git a/extra/patches/linux-droid4-patches/0001_drm-omap-add-framedone-interrupt-support.patch b/extra/patches/linux-droid4-patches/0001_drm-omap-add-framedone-interrupt-support.patch @@ -1,158 +0,0 @@ -This prepares framedone interrupt handling for -manual display update support. - -Signed-off-by: Sebastian Reichel <sebastian.reichel@xxxxxxxxxxxxxxx> ---- - 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); --- -2.15.1 diff --git a/extra/patches/linux-droid4-patches/0002-drm-omap-drop-incorrect-comment.patch b/extra/patches/linux-droid4-patches/0002-drm-omap-drop-incorrect-comment.patch @@ -0,0 +1,33 @@ +From faf0e2475147bd8e755dbce7f9f1a0fb8e731e4f Mon Sep 17 00:00:00 2001 +From: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +Date: Mon, 24 Jul 2017 19:32:59 +0200 +Subject: [PATCH 02/17] drm/omap: drop incorrect comment + +The wrappers have been removed in commit 5a35876e2830 +(drm: omapdrm: Remove manual update display support) +and will not be reintroduced, since the normal sys +functions properly call the dirty callback. + +Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +Acked-by: Pavel Machek <pavel@ucw.cz> +--- + drivers/gpu/drm/omapdrm/omap_fbdev.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c +index 9273118..e037818 100644 +--- a/drivers/gpu/drm/omapdrm/omap_fbdev.c ++++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c +@@ -84,9 +84,6 @@ static struct fb_ops omap_fb_ops = { + .owner = THIS_MODULE, + DRM_FB_HELPER_DEFAULT_OPS, + +- /* Note: to properly handle manual update displays, we wrap the +- * basic fbdev ops which write to the framebuffer +- */ + .fb_read = drm_fb_helper_sys_read, + .fb_write = drm_fb_helper_sys_write, + .fb_fillrect = drm_fb_helper_sys_fillrect, +-- +2.1.4 + diff --git a/extra/patches/linux-droid4-patches/0002_drm-omap-add-manual-update-detection-helper.patch b/extra/patches/linux-droid4-patches/0002_drm-omap-add-manual-update-detection-helper.patch @@ -1,42 +0,0 @@ -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@xxxxxxxxxxxxxxx> ---- - 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__ */ --- -2.15.1 diff --git a/extra/patches/linux-droid4-patches/0003-drm-omap-plane-update-fifo-size-on-ovl-setup.patch b/extra/patches/linux-droid4-patches/0003-drm-omap-plane-update-fifo-size-on-ovl-setup.patch @@ -0,0 +1,52 @@ +From 8bb3dd3ffe60be576bd6a843ebb65979e49e3e25 Mon Sep 17 00:00:00 2001 +From: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +Date: Mon, 24 Jul 2017 19:33:00 +0200 +Subject: [PATCH 03/17] drm/omap: plane: update fifo size on ovl setup + +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. + +Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +--- + drivers/gpu/drm/omapdrm/dss/dispc.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c +index 0f4fdb2..d5d2d3c 100644 +--- a/drivers/gpu/drm/omapdrm/dss/dispc.c ++++ b/drivers/gpu/drm/omapdrm/dss/dispc.c +@@ -1491,6 +1491,18 @@ void dispc_ovl_compute_fifo_thresholds(enum omap_plane_id plane, + } + } + ++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; +@@ -2654,6 +2666,10 @@ static int dispc_ovl_setup(enum omap_plane_id plane, + oi->zorder, oi->pre_mult_alpha, oi->global_alpha, + oi->rotation_type, replication, vm, mem_to_mem); + ++ /* manual mode needs other fifo thresholds */ ++ if (mgr_fld_read(channel, DISPC_MGR_FLD_STALLMODE)) ++ dispc_ovl_set_manual_fifo_threshold(plane); ++ + return r; + } + +-- +2.1.4 + diff --git a/extra/patches/linux-droid4-patches/0003_drm-omap-add-support-for-manually-updated-displays.patch b/extra/patches/linux-droid4-patches/0003_drm-omap-add-support-for-manually-updated-displays.patch @@ -1,256 +0,0 @@ -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@xxxxxxxxxxxxxxx> ---- - 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, - }; - --- -2.15.1 diff --git a/extra/patches/linux-droid4-patches/0004-drm-omap-add-framedone-interrupt-support.patch b/extra/patches/linux-droid4-patches/0004-drm-omap-add-framedone-interrupt-support.patch @@ -0,0 +1,160 @@ +From 8af6ec6efc7607cc5af52af895ac7f8e63820f80 Mon Sep 17 00:00:00 2001 +From: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +Date: Mon, 24 Jul 2017 19:33:01 +0200 +Subject: [PATCH 04/17] drm/omap: add framedone interrupt support + +This prepares framedone interrupt handling for +manual display update support. + +Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +--- + drivers/gpu/drm/omapdrm/omap_crtc.c | 48 +++++++++++++++++++++++++++++++++++++ + drivers/gpu/drm/omapdrm/omap_drv.h | 2 ++ + drivers/gpu/drm/omapdrm/omap_irq.c | 24 +++++++++++++++++++ + 3 files changed, 74 insertions(+) + +diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c +index cc85c16..dee9b6e 100644 +--- a/drivers/gpu/drm/omapdrm/omap_crtc.c ++++ b/drivers/gpu/drm/omapdrm/omap_crtc.c +@@ -52,6 +52,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; + }; + + /* ----------------------------------------------------------------------------- +@@ -248,6 +251,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; + } + +@@ -255,6 +269,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 = { +@@ -322,6 +346,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_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h +index 4bd1e90..22f3d94 100644 +--- a/drivers/gpu/drm/omapdrm/omap_drv.h ++++ b/drivers/gpu/drm/omapdrm/omap_drv.h +@@ -97,6 +97,7 @@ void omap_gem_describe_objects(struct list_head *list, struct seq_file *m); + int omap_gem_resume(struct device *dev); + #endif + ++int omap_irq_enable_framedone(struct drm_crtc *crtc, bool enable); + int omap_irq_enable_vblank(struct drm_crtc *crtc); + void omap_irq_disable_vblank(struct drm_crtc *crtc); + void omap_drm_irq_uninstall(struct drm_device *dev); +@@ -124,6 +125,7 @@ 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); + + struct drm_plane *omap_plane_init(struct drm_device *dev, + int idx, enum drm_plane_type type, +diff --git a/drivers/gpu/drm/omapdrm/omap_irq.c b/drivers/gpu/drm/omapdrm/omap_irq.c +index 013b0bb..301c0e7 100644 +--- a/drivers/gpu/drm/omapdrm/omap_irq.c ++++ b/drivers/gpu/drm/omapdrm/omap_irq.c +@@ -87,6 +87,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 +@@ -217,6 +238,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); +-- +2.1.4 + diff --git a/extra/patches/linux-droid4-patches/0004_dt-bindings-panel-common-document-orientation-property.patch b/extra/patches/linux-droid4-patches/0004_dt-bindings-panel-common-document-orientation-property.patch @@ -1,57 +0,0 @@ -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@xxxxxxxxxxxxxxx> ---- - .../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 --- -2.15.1 diff --git a/extra/patches/linux-droid4-patches/0005-drm-omap-add-manual-update-detection-helper.patch b/extra/patches/linux-droid4-patches/0005-drm-omap-add-manual-update-detection-helper.patch @@ -0,0 +1,49 @@ +From 6dae0575adf3b15c51832bfa8c0320e8526e9b8e Mon Sep 17 00:00:00 2001 +From: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +Date: Mon, 24 Jul 2017 19:33:02 +0200 +Subject: [PATCH 05/17] drm/omap: add manual update detection helper + +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> +--- + drivers/gpu/drm/omapdrm/omap_connector.c | 8 ++++++++ + drivers/gpu/drm/omapdrm/omap_drv.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 aa5ba9a..4f4c7ef 100644 +--- a/drivers/gpu/drm/omapdrm/omap_connector.c ++++ b/drivers/gpu/drm/omapdrm/omap_connector.c +@@ -59,6 +59,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_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h +index 22f3d94..f6c48f2 100644 +--- a/drivers/gpu/drm/omapdrm/omap_drv.h ++++ b/drivers/gpu/drm/omapdrm/omap_drv.h +@@ -142,6 +142,7 @@ 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); + + struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev, + struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd); +-- +2.1.4 + diff --git a/extra/patches/linux-droid4-patches/0005_drm-omap-add-support-for-orientation-hints-from-display-drivers.patch b/extra/patches/linux-droid4-patches/0005_drm-omap-add-support-for-orientation-hints-from-display-drivers.patch @@ -1,59 +0,0 @@ -This adds support for setting DRM panel orientation property -based on information from the display driver. - -Signed-off-by: Sebastian Reichel <sebastian.reichel@xxxxxxxxxxxxxxx> ---- - 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: --- -2.15.1 diff --git a/extra/patches/linux-droid4-patches/0006-drm-omap-add-support-for-manually-updated-displays.patch b/extra/patches/linux-droid4-patches/0006-drm-omap-add-support-for-manually-updated-displays.patch @@ -0,0 +1,263 @@ +From 2a51a11e2f2705bbf7642e2e08ae6b2f1372d79c Mon Sep 17 00:00:00 2001 +From: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +Date: Mon, 24 Jul 2017 19:33:03 +0200 +Subject: [PATCH 06/17] drm/omap: add support for manually updated displays + +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> +--- + drivers/gpu/drm/omapdrm/omap_crtc.c | 110 +++++++++++++++++++++++++++++++++--- + drivers/gpu/drm/omapdrm/omap_drv.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 dee9b6e..8255241 100644 +--- a/drivers/gpu/drm/omapdrm/omap_crtc.c ++++ b/drivers/gpu/drm/omapdrm/omap_crtc.c +@@ -52,6 +52,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; +@@ -143,6 +144,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. */ +@@ -154,12 +177,17 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable) + enum omap_channel channel = omap_crtc->channel; + struct omap_irq_wait *wait; + u32 framedone_irq, vsync_irq; ++ bool is_manual = omap_crtc_is_manually_updated(crtc); ++ enum omap_display_type type = omap_crtc_output[channel]->output_type; + int ret; + + if (WARN_ON(omap_crtc->enabled == enable)) + return; + +- if (omap_crtc_output[channel]->output_type == OMAP_DISPLAY_TYPE_HDMI) { ++ if (is_manual) ++ omap_irq_enable_framedone(crtc, enable); ++ ++ if (is_manual || type == OMAP_DISPLAY_TYPE_HDMI) { + priv->dispc_ops->mgr_enable(channel, enable); + omap_crtc->enabled = enable; + return; +@@ -210,7 +238,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]; +@@ -370,6 +397,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; +@@ -422,6 +496,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); +@@ -435,6 +513,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); + +@@ -445,6 +524,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); + } + +@@ -559,13 +643,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, +@@ -726,6 +817,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_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h +index f6c48f2..3cb9f9a 100644 +--- a/drivers/gpu/drm/omapdrm/omap_drv.h ++++ b/drivers/gpu/drm/omapdrm/omap_drv.h +@@ -126,6 +126,7 @@ 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); + + struct drm_plane *omap_plane_init(struct drm_device *dev, + int idx, enum drm_plane_type type, +diff --git a/drivers/gpu/drm/omapdrm/omap_fb.c b/drivers/gpu/drm/omapdrm/omap_fb.c +index b1a762b..9492be6 100644 +--- a/drivers/gpu/drm/omapdrm/omap_fb.c ++++ b/drivers/gpu/drm/omapdrm/omap_fb.c +@@ -97,8 +97,28 @@ static void omap_framebuffer_destroy(struct drm_framebuffer *fb) + kfree(omap_fb); + } + ++static int omap_framebuffer_dirty(struct drm_framebuffer *fb, ++ struct drm_file *file_priv, ++ unsigned flags, unsigned color, ++ struct drm_clip_rect *clips, ++ unsigned num_clips) ++{ ++ struct drm_connector *connector = NULL; ++ ++ drm_modeset_lock_all(fb->dev); ++ ++ while ((connector = omap_framebuffer_get_next_connector(fb, connector))) ++ if (connector->encoder && connector->encoder->crtc) ++ omap_crtc_flush(connector->encoder->crtc); ++ ++ drm_modeset_unlock_all(fb->dev); ++ ++ return 0; ++} ++ + static const struct drm_framebuffer_funcs omap_framebuffer_funcs = { + .create_handle = omap_framebuffer_create_handle, ++ .dirty = omap_framebuffer_dirty, + .destroy = omap_framebuffer_destroy, + }; + +-- +2.1.4 + diff --git a/extra/patches/linux-droid4-patches/0006_drm-omap-panel-dsi-cm-add-orientation-support.patch b/extra/patches/linux-droid4-patches/0006_drm-omap-panel-dsi-cm-add-orientation-support.patch @@ -1,55 +0,0 @@ -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@xxxxxxxxxxxxxxx> ---- - 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"); --- -2.15.1 diff --git a/extra/patches/linux-droid4-patches/0007-drm-omap-add-support-for-physical-size-hints-from-di.patch b/extra/patches/linux-droid4-patches/0007-drm-omap-add-support-for-physical-size-hints-from-di.patch @@ -0,0 +1,50 @@ +From 1e66c0a2f776d6054c2324daf55fc3e3df126c33 Mon Sep 17 00:00:00 2001 +From: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +Date: Mon, 24 Jul 2017 19:33:04 +0200 +Subject: [PATCH 07/17] drm/omap: add support for physical size hints from + display drivers + +While physical size information is automatically parsed for EDID +based displays, we need to provide it manually for displays providing +one fixed mode. + +Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +Acked-by: Pavel Machek <pavel@ucw.cz> +--- + drivers/gpu/drm/omapdrm/dss/omapdss.h | 2 ++ + drivers/gpu/drm/omapdrm/omap_connector.c | 6 ++++++ + 2 files changed, 8 insertions(+) + +diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h +index 3d25359..5be6ff8 100644 +--- a/drivers/gpu/drm/omapdrm/dss/omapdss.h ++++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h +@@ -562,6 +562,8 @@ struct omap_dss_driver { + struct videomode *vm); + void (*get_timings)(struct omap_dss_device *dssdev, + struct videomode *vm); ++ void (*get_size)(struct omap_dss_device *dssdev, ++ unsigned int *width, unsigned int *height); + + 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 4f4c7ef..8874f55 100644 +--- a/drivers/gpu/drm/omapdrm/omap_connector.c ++++ b/drivers/gpu/drm/omapdrm/omap_connector.c +@@ -157,6 +157,12 @@ static int omap_connector_get_modes(struct drm_connector *connector) + drm_mode_set_name(mode); + drm_mode_probed_add(connector, mode); + ++ if (dssdrv->get_size) { ++ dssdrv->get_size(dssdev, ++ &connector->display_info.width_mm, ++ &connector->display_info.height_mm); ++ } ++ + n = 1; + } + +-- +2.1.4 + diff --git a/extra/patches/linux-droid4-patches/0007_arm-dts-omap4-droid4-add-lcd-panel-orientation-property.patch b/extra/patches/linux-droid4-patches/0007_arm-dts-omap4-droid4-add-lcd-panel-orientation-property.patch @@ -1,31 +0,0 @@ -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@xxxxxxxxxxxxxxx> ---- - 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 */ - --- -2.15.1 diff --git a/extra/patches/linux-droid4-patches/0008-drm-omap-panel-dsi-cm-fix-driver.patch b/extra/patches/linux-droid4-patches/0008-drm-omap-panel-dsi-cm-fix-driver.patch @@ -0,0 +1,124 @@ +From 328a31aeb9e4cb56f312be7722010ede59ef96be Mon Sep 17 00:00:00 2001 +From: Tony Lindgren <tony@atomide.com> +Date: Mon, 24 Jul 2017 19:33:05 +0200 +Subject: [PATCH 08/17] drm/omap: panel-dsi-cm: fix driver + +This adds support for get_timings() and check_timings() +to get the driver working and properly initializes the +timing information from DT. + +Signed-off-by: Tony Lindgren <tony@atomide.com> +Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +--- + drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c | 56 ++++++++++++++++++++++--- + 1 file changed, 51 insertions(+), 5 deletions(-) + +diff --git a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c +index 92c556a..905b717 100644 +--- a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c ++++ b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c +@@ -25,6 +25,7 @@ + #include <linux/of_gpio.h> + + #include <video/mipi_display.h> ++#include <video/of_display_timing.h> + + #include "../dss/omapdss.h" + +@@ -1099,6 +1100,36 @@ static void dsicm_ulps_work(struct work_struct *work) + mutex_unlock(&ddata->lock); + } + ++static void dsicm_get_timings(struct omap_dss_device *dssdev, ++ struct videomode *vm) ++{ ++ struct panel_drv_data *ddata = to_panel_data(dssdev); ++ ++ *vm = ddata->vm; ++} ++ ++static int dsicm_check_timings(struct omap_dss_device *dssdev, ++ struct videomode *vm) ++{ ++ struct panel_drv_data *ddata = to_panel_data(dssdev); ++ int ret = 0; ++ ++ if (vm->hactive != ddata->vm.hactive) ++ ret = -EINVAL; ++ ++ if (vm->vactive != ddata->vm.vactive) ++ ret = -EINVAL; ++ ++ if (ret) { ++ dev_warn(dssdev->dev, "wrong resolution: %d x %d", ++ vm->hactive, vm->vactive); ++ dev_warn(dssdev->dev, "panel resolution: %d x %d", ++ ddata->vm.hactive, ddata->vm.vactive); ++ } ++ ++ return ret; ++} ++ + static struct omap_dss_driver dsicm_ops = { + .connect = dsicm_connect, + .disconnect = dsicm_disconnect, +@@ -1109,6 +1140,9 @@ static struct omap_dss_driver dsicm_ops = { + .update = dsicm_update, + .sync = dsicm_sync, + ++ .get_timings = dsicm_get_timings, ++ .check_timings = dsicm_check_timings, ++ + .enable_te = dsicm_enable_te, + .get_te = dsicm_get_te, + +@@ -1120,7 +1154,8 @@ static int dsicm_probe_of(struct platform_device *pdev) + struct device_node *node = pdev->dev.of_node; + struct panel_drv_data *ddata = platform_get_drvdata(pdev); + struct omap_dss_device *in; +- int gpio; ++ struct display_timing timing; ++ int gpio, err; + + gpio = of_get_named_gpio(node, "reset-gpios", 0); + if (!gpio_is_valid(gpio)) { +@@ -1137,6 +1172,17 @@ static int dsicm_probe_of(struct platform_device *pdev) + return gpio; + } + ++ err = of_get_display_timing(node, "panel-timing", &timing); ++ if (!err) { ++ videomode_from_timing(&timing, &ddata->vm); ++ if (!ddata->vm.pixelclock) ++ ddata->vm.pixelclock = ++ ddata->vm.hactive * ddata->vm.vactive * 60; ++ } else { ++ dev_warn(&pdev->dev, ++ "failed to get video timing, using defaults\n"); ++ } ++ + in = omapdss_of_find_source_for_first_ep(node); + if (IS_ERR(in)) { + dev_err(&pdev->dev, "failed to find video source\n"); +@@ -1171,14 +1217,14 @@ static int dsicm_probe(struct platform_device *pdev) + if (!pdev->dev.of_node) + return -ENODEV; + +- r = dsicm_probe_of(pdev); +- if (r) +- return r; +- + ddata->vm.hactive = 864; + ddata->vm.vactive = 480; + ddata->vm.pixelclock = 864 * 480 * 60; + ++ r = dsicm_probe_of(pdev); ++ if (r) ++ return r; ++ + dssdev = &ddata->dssdev; + dssdev->dev = dev; + dssdev->driver = &dsicm_ops; +-- +2.1.4 + diff --git a/extra/patches/linux-droid4-patches/0008_drm-omap-plane-update-fifo-size-on-ovl-setup.patch b/extra/patches/linux-droid4-patches/0008_drm-omap-plane-update-fifo-size-on-ovl-setup.patch @@ -1,125 +0,0 @@ -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@xxxxxxxxxxxxxxx> ---- - 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) --- -2.15.1 diff --git a/extra/patches/linux-droid4-patches/0009-drm-omap-panel-dsi-cm-add-regulator-support.patch b/extra/patches/linux-droid4-patches/0009-drm-omap-panel-dsi-cm-add-regulator-support.patch @@ -0,0 +1,135 @@ +From 594f7f466237d32323f63c04e92f7ce7be2f2a4f Mon Sep 17 00:00:00 2001 +From: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +Date: Mon, 24 Jul 2017 19:33:06 +0200 +Subject: [PATCH 09/17] drm/omap: panel-dsi-cm: add regulator support + +Add support for regulators used by panels found inside +of the Nokia N950, N9 and Motorola Droid 4. + +Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +--- + drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c | 57 +++++++++++++++++++++++-- + 1 file changed, 53 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c +index 905b717..b98ea9e 100644 +--- a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c ++++ b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c +@@ -23,6 +23,7 @@ + #include <linux/workqueue.h> + #include <linux/of_device.h> + #include <linux/of_gpio.h> ++#include <linux/regulator/consumer.h> + + #include <video/mipi_display.h> + #include <video/of_display_timing.h> +@@ -60,6 +61,9 @@ struct panel_drv_data { + int reset_gpio; + int ext_te_gpio; + ++ struct regulator *vpnl; ++ struct regulator *vddi; ++ + bool use_dsi_backlight; + + struct omap_dsi_pin_config pin_config; +@@ -590,25 +594,43 @@ static int dsicm_power_on(struct panel_drv_data *ddata) + .lp_clk_max = 10000000, + }; + ++ if (ddata->vpnl) { ++ r = regulator_enable(ddata->vpnl); ++ if (r) { ++ dev_err(&ddata->pdev->dev, ++ "failed to enable VPNL: %d\n", r); ++ return r; ++ } ++ } ++ ++ if (ddata->vddi) { ++ r = regulator_enable(ddata->vddi); ++ if (r) { ++ dev_err(&ddata->pdev->dev, ++ "failed to enable VDDI: %d\n", r); ++ goto err_vpnl; ++ } ++ } ++ + if (ddata->pin_config.num_pins > 0) { + r = in->ops.dsi->configure_pins(in, &ddata->pin_config); + if (r) { + dev_err(&ddata->pdev->dev, + "failed to configure DSI pins\n"); +- goto err0; ++ goto err_vddi; + } + } + + r = in->ops.dsi->set_config(in, &dsi_config); + if (r) { + dev_err(&ddata->pdev->dev, "failed to configure DSI\n"); +- goto err0; ++ goto err_vddi; + } + + r = in->ops.dsi->enable(in); + if (r) { + dev_err(&ddata->pdev->dev, "failed to enable DSI\n"); +- goto err0; ++ goto err_vddi; + } + + dsicm_hw_reset(ddata); +@@ -666,7 +688,13 @@ static int dsicm_power_on(struct panel_drv_data *ddata) + dsicm_hw_reset(ddata); + + in->ops.dsi->disable(in, true, false); +-err0: ++err_vddi: ++ if (ddata->vddi) ++ regulator_disable(ddata->vddi); ++err_vpnl: ++ if (ddata->vpnl) ++ regulator_disable(ddata->vpnl); ++ + return r; + } + +@@ -689,6 +717,11 @@ static void dsicm_power_off(struct panel_drv_data *ddata) + + in->ops.dsi->disable(in, true, false); + ++ if (ddata->vddi) ++ regulator_disable(ddata->vddi); ++ if (ddata->vpnl) ++ regulator_disable(ddata->vpnl); ++ + ddata->enabled = 0; + } + +@@ -1189,6 +1222,22 @@ static int dsicm_probe_of(struct platform_device *pdev) + return PTR_ERR(in); + } + ++ ddata->vpnl = devm_regulator_get_optional(&pdev->dev, "vpnl"); ++ if (IS_ERR(ddata->vpnl)) { ++ err = PTR_ERR(ddata->vpnl); ++ if (err == -EPROBE_DEFER) ++ return err; ++ ddata->vpnl = NULL; ++ } ++ ++ ddata->vddi = devm_regulator_get_optional(&pdev->dev, "vddi"); ++ if (IS_ERR(ddata->vddi)) { ++ err = PTR_ERR(ddata->vddi); ++ if (err == -EPROBE_DEFER) ++ return err; ++ ddata->vddi = NULL; ++ } ++ + ddata->in = in; + + /* TODO: ulps, backlight */ +-- +2.1.4 + diff --git a/extra/patches/linux-droid4-patches/0009_arm-dts-omap4-droid4-update-touchscreen.patch b/extra/patches/linux-droid4-patches/0009_arm-dts-omap4-droid4-update-touchscreen.patch @@ -1,67 +0,0 @@ -From: Sebastian Reichel <sebastian.reichel@xxxxxxxxxxxxxxx> - -Update the Droid 4 devicetree to properly describe the reset -GPIO. Also rename the node to touchscreen instead of tsp, -which seems to be commonly used for touchscreens. - -Signed-off-by: Sebastian Reichel <sebastian.reichel@xxxxxxxxxxxxxxx> ---- - arch/arm/boot/dts/omap4-droid4-xt894.dts | 22 ++++++---------------- - 1 file changed, 6 insertions(+), 16 deletions(-) - -diff --git a/arch/arm/boot/dts/omap4-droid4-xt894.dts b/arch/arm/boot/dts/omap4-droid4-xt894.dts -index 81c701929c70..40df997fc453 100644 ---- a/arch/arm/boot/dts/omap4-droid4-xt894.dts -+++ b/arch/arm/boot/dts/omap4-droid4-xt894.dts -@@ -145,13 +145,6 @@ - }; - - &gpio6 { -- touchscreen_reset { -- gpio-hog; -- gpios = <13 0>; -- output-high; -- line-name = "touchscreen-reset"; -- }; -- - pwm8: dmtimer-pwm-8 { - pinctrl-names = "default"; - pinctrl-0 = <&vibrator_direction_pin>; -@@ -385,22 +378,18 @@ - }; - }; - --/* -- * REVISIT: Add gpio173 reset pin handling to the driver, see gpio-hog above. -- * If the GPIO reset is used, we probably need to have /lib/firmware/maxtouch.fw -- * available. See "mxt-app" and "droid4-touchscreen-firmware" tools for more -- * information. -- */ - &i2c2 { -- tsp@4a { -+ touchscreen@4a { - compatible = "atmel,maxtouch"; - reg = <0x4a>; - pinctrl-names = "default"; - pinctrl-0 = <&touchscreen_pins>; - -+ reset-gpios = <&gpio6 13 GPIO_ACTIVE_HIGH>; /* gpio173 */ -+ - /* gpio_183 with sys_nirq2 pad as wakeup */ -- interrupts-extended = <&gpio6 23 IRQ_TYPE_EDGE_FALLING -- &omap4_pmx_core 0x160>; -+ interrupts-extended = <&gpio6 23 IRQ_TYPE_EDGE_FALLING>, -+ <&omap4_pmx_core 0x160>; - interrupt-names = "irq", "wakeup"; - wakeup-source; - }; -@@ -484,6 +473,7 @@ - - touchscreen_pins: pinmux_touchscreen_pins { - pinctrl-single,pins = < -+ OMAP4_IOPAD(0x180, PIN_OUTPUT | MUX_MODE3) - OMAP4_IOPAD(0x1a0, PIN_INPUT_PULLUP | MUX_MODE3) - >; - }; --- -2.15.1 diff --git a/extra/patches/linux-droid4-patches/0010-drm-omap-panel-dsi-cm-add-physical-size-support.patch b/extra/patches/linux-droid4-patches/0010-drm-omap-panel-dsi-cm-add-physical-size-support.patch @@ -0,0 +1,67 @@ +From 7561ba59ec083593412b8794dd3221fdca2ab49e Mon Sep 17 00:00:00 2001 +From: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +Date: Mon, 24 Jul 2017 19:33:07 +0200 +Subject: [PATCH 10/17] drm/omap: panel-dsi-cm: add physical size support + +Add support to load physical size information from DT using +the properties defined by the common panel binding. + +Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +--- + drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c +index b98ea9e..8459139 100644 +--- a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c ++++ b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c +@@ -66,6 +66,9 @@ struct panel_drv_data { + + bool use_dsi_backlight; + ++ int width_mm; ++ int height_mm; ++ + struct omap_dsi_pin_config pin_config; + + /* runtime variables */ +@@ -1163,6 +1166,15 @@ static int dsicm_check_timings(struct omap_dss_device *dssdev, + return ret; + } + ++static void dsicm_get_size(struct omap_dss_device *dssdev, ++ unsigned int *width, unsigned int *height) ++{ ++ struct panel_drv_data *ddata = to_panel_data(dssdev); ++ ++ *width = ddata->width_mm; ++ *height = ddata->height_mm; ++} ++ + static struct omap_dss_driver dsicm_ops = { + .connect = dsicm_connect, + .disconnect = dsicm_disconnect, +@@ -1175,6 +1187,7 @@ static struct omap_dss_driver dsicm_ops = { + + .get_timings = dsicm_get_timings, + .check_timings = dsicm_check_timings, ++ .get_size = dsicm_get_size, + + .enable_te = dsicm_enable_te, + .get_te = dsicm_get_te, +@@ -1216,6 +1229,12 @@ static int dsicm_probe_of(struct platform_device *pdev) + "failed to get video timing, using defaults\n"); + } + ++ ddata->width_mm = 0; ++ of_property_read_u32(node, "width-mm", &ddata->width_mm); ++ ++ ddata->height_mm = 0; ++ of_property_read_u32(node, "height-mm", &ddata->height_mm); ++ + in = omapdss_of_find_source_for_first_ep(node); + if (IS_ERR(in)) { + dev_err(&pdev->dev, "failed to find video source\n"); +-- +2.1.4 + diff --git a/extra/patches/linux-droid4-patches/0011-drm-omap-panel-dsi-cm-add-external-backlight-support.patch b/extra/patches/linux-droid4-patches/0011-drm-omap-panel-dsi-cm-add-external-backlight-support.patch @@ -0,0 +1,247 @@ +From ed924fc352d6e2caa0d3fc1be1f1c65a35c9343b Mon Sep 17 00:00:00 2001 +From: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +Date: Mon, 24 Jul 2017 19:33:08 +0200 +Subject: [PATCH 11/17] drm/omap: panel-dsi-cm: add external backlight support + +Droid 4 has a command mode DSI panel, which does not have/use +DSI based backlight support. This adds proper support for this +using a backlight phandle property, which follows the common +panel binding. + +If no backlight phandle is found, it is assumed, that the +native backlight should be used instead. This is used by +the Nokia N950. + +Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +--- + drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c | 91 ++++++++++++++++--------- + 1 file changed, 60 insertions(+), 31 deletions(-) + +diff --git a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c +index 8459139..d139bb7 100644 +--- a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c ++++ b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c +@@ -51,6 +51,7 @@ struct panel_drv_data { + struct mutex lock; + + struct backlight_device *bldev; ++ struct backlight_device *extbldev; + + unsigned long hw_guard_end; /* next value of jiffies when we can + * issue the next sleep in/out command +@@ -100,6 +101,30 @@ static int dsicm_panel_reset(struct panel_drv_data *ddata); + + static void dsicm_ulps_work(struct work_struct *work); + ++static void dsicm_bl_power(struct panel_drv_data *ddata, bool enable) ++{ ++ struct backlight_device *backlight; ++ ++ if (ddata->bldev) ++ backlight = ddata->bldev; ++ else if (ddata->extbldev) ++ backlight = ddata->extbldev; ++ else ++ return; ++ ++ if (enable) { ++ backlight->props.fb_blank = FB_BLANK_UNBLANK; ++ backlight->props.state = ~(BL_CORE_FBBLANK | BL_CORE_SUSPENDED); ++ backlight->props.power = FB_BLANK_UNBLANK; ++ } else { ++ backlight->props.fb_blank = FB_BLANK_NORMAL; ++ backlight->props.power = FB_BLANK_POWERDOWN; ++ backlight->props.state |= BL_CORE_FBBLANK | BL_CORE_SUSPENDED; ++ } ++ ++ backlight_update_status(backlight); ++} ++ + static void hw_guard_start(struct panel_drv_data *ddata, int guard_msec) + { + ddata->hw_guard_wait = msecs_to_jiffies(guard_msec); +@@ -343,7 +368,7 @@ static int dsicm_bl_update_status(struct backlight_device *dev) + { + struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev); + struct omap_dss_device *in = ddata->in; +- int r; ++ int r = 0; + int level; + + if (dev->props.fb_blank == FB_BLANK_UNBLANK && +@@ -364,8 +389,6 @@ static int dsicm_bl_update_status(struct backlight_device *dev) + r = dsicm_dcs_write_1(ddata, DCS_BRIGHTNESS, level); + + in->ops.dsi->bus_unlock(in); +- } else { +- r = 0; + } + + mutex_unlock(&ddata->lock); +@@ -819,6 +842,8 @@ static int dsicm_enable(struct omap_dss_device *dssdev) + + mutex_unlock(&ddata->lock); + ++ dsicm_bl_power(ddata, true); ++ + return 0; + err: + dev_dbg(&ddata->pdev->dev, "enable failed\n"); +@@ -834,6 +859,8 @@ static void dsicm_disable(struct omap_dss_device *dssdev) + + dev_dbg(&ddata->pdev->dev, "disable\n"); + ++ dsicm_bl_power(ddata, false); ++ + mutex_lock(&ddata->lock); + + dsicm_cancel_ulps_work(ddata); +@@ -1198,6 +1225,7 @@ static struct omap_dss_driver dsicm_ops = { + static int dsicm_probe_of(struct platform_device *pdev) + { + struct device_node *node = pdev->dev.of_node; ++ struct device_node *backlight; + struct panel_drv_data *ddata = platform_get_drvdata(pdev); + struct omap_dss_device *in; + struct display_timing timing; +@@ -1259,14 +1287,25 @@ static int dsicm_probe_of(struct platform_device *pdev) + + ddata->in = in; + +- /* TODO: ulps, backlight */ ++ backlight = of_parse_phandle(node, "backlight", 0); ++ if (backlight) { ++ ddata->extbldev = of_find_backlight_by_node(backlight); ++ of_node_put(backlight); ++ ++ if (!ddata->extbldev) ++ return -EPROBE_DEFER; ++ } else { ++ /* assume native backlight support */ ++ ddata->use_dsi_backlight = true; ++ } ++ ++ /* TODO: ulps */ + + return 0; + } + + static int dsicm_probe(struct platform_device *pdev) + { +- struct backlight_properties props; + struct panel_drv_data *ddata; + struct backlight_device *bldev = NULL; + struct device *dev = &pdev->dev; +@@ -1319,7 +1358,7 @@ static int dsicm_probe(struct platform_device *pdev) + GPIOF_OUT_INIT_LOW, "taal rst"); + if (r) { + dev_err(dev, "failed to request reset gpio\n"); +- return r; ++ goto err_reg; + } + } + +@@ -1328,7 +1367,7 @@ static int dsicm_probe(struct platform_device *pdev) + GPIOF_IN, "taal irq"); + if (r) { + dev_err(dev, "GPIO request failed\n"); +- return r; ++ goto err_reg; + } + + r = devm_request_irq(dev, gpio_to_irq(ddata->ext_te_gpio), +@@ -1338,7 +1377,7 @@ static int dsicm_probe(struct platform_device *pdev) + + if (r) { + dev_err(dev, "IRQ request failed\n"); +- return r; ++ goto err_reg; + } + + INIT_DEFERRABLE_WORK(&ddata->te_timeout_work, +@@ -1348,48 +1387,43 @@ static int dsicm_probe(struct platform_device *pdev) + } + + ddata->workqueue = create_singlethread_workqueue("dsicm_wq"); +- if (ddata->workqueue == NULL) { +- dev_err(dev, "can't create workqueue\n"); +- return -ENOMEM; ++ if (!ddata->workqueue) { ++ r = -ENOMEM; ++ goto err_reg; + } + INIT_DELAYED_WORK(&ddata->ulps_work, dsicm_ulps_work); + + dsicm_hw_reset(ddata); + + if (ddata->use_dsi_backlight) { +- memset(&props, 0, sizeof(props)); ++ struct backlight_properties props = { 0 }; + props.max_brightness = 255; +- + props.type = BACKLIGHT_RAW; +- bldev = backlight_device_register(dev_name(dev), +- dev, ddata, &dsicm_bl_ops, &props); ++ ++ bldev = devm_backlight_device_register(dev, dev_name(dev), ++ dev, ddata, &dsicm_bl_ops, &props); + if (IS_ERR(bldev)) { + r = PTR_ERR(bldev); + goto err_bl; + } + + ddata->bldev = bldev; +- +- bldev->props.fb_blank = FB_BLANK_UNBLANK; +- bldev->props.power = FB_BLANK_UNBLANK; +- bldev->props.brightness = 255; +- +- dsicm_bl_update_status(bldev); + } + + r = sysfs_create_group(&dev->kobj, &dsicm_attr_group); + if (r) { + dev_err(dev, "failed to create sysfs files\n"); +- goto err_sysfs_create; ++ goto err_bl; + } + + return 0; + +-err_sysfs_create: +- backlight_device_unregister(bldev); + err_bl: + destroy_workqueue(ddata->workqueue); + err_reg: ++ if (ddata->extbldev) ++ put_device(&ddata->extbldev->dev); ++ + return r; + } + +@@ -1397,7 +1431,6 @@ static int __exit dsicm_remove(struct platform_device *pdev) + { + struct panel_drv_data *ddata = platform_get_drvdata(pdev); + struct omap_dss_device *dssdev = &ddata->dssdev; +- struct backlight_device *bldev; + + dev_dbg(&pdev->dev, "remove\n"); + +@@ -1408,12 +1441,8 @@ static int __exit dsicm_remove(struct platform_device *pdev) + + sysfs_remove_group(&pdev->dev.kobj, &dsicm_attr_group); + +- bldev = ddata->bldev; +- if (bldev != NULL) { +- bldev->props.power = FB_BLANK_POWERDOWN; +- dsicm_bl_update_status(bldev); +- backlight_device_unregister(bldev); +- } ++ if (ddata->extbldev) ++ put_device(&ddata->extbldev->dev); + + omap_dss_put_device(ddata->in); + +-- +2.1.4 + diff --git a/extra/patches/linux-droid4-patches/0012-drm-omap-panel-dsi-cm-switch-to-gpiod.patch b/extra/patches/linux-droid4-patches/0012-drm-omap-panel-dsi-cm-switch-to-gpiod.patch @@ -0,0 +1,172 @@ +From d4b696beecee6b132c024e847dc54efee05f3ccc Mon Sep 17 00:00:00 2001 +From: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +Date: Mon, 24 Jul 2017 19:33:09 +0200 +Subject: [PATCH 12/17] drm/omap: panel-dsi-cm: switch to gpiod + +Use the new descriptor based GPIO API instead of +the legacy one, which results in cleaner code +with less lines of code. + +Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +--- + drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c | 74 +++++++++---------------- + 1 file changed, 27 insertions(+), 47 deletions(-) + +diff --git a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c +index d139bb7..996991d 100644 +--- a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c ++++ b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c +@@ -22,7 +22,6 @@ + #include <linux/slab.h> + #include <linux/workqueue.h> + #include <linux/of_device.h> +-#include <linux/of_gpio.h> + #include <linux/regulator/consumer.h> + + #include <video/mipi_display.h> +@@ -59,8 +58,8 @@ struct panel_drv_data { + unsigned long hw_guard_wait; /* max guard time in jiffies */ + + /* panel HW configuration from DT or platform data */ +- int reset_gpio; +- int ext_te_gpio; ++ struct gpio_desc *reset_gpio; ++ struct gpio_desc *ext_te_gpio; + + struct regulator *vpnl; + struct regulator *vddi; +@@ -288,8 +287,8 @@ static int dsicm_enter_ulps(struct panel_drv_data *ddata) + if (r) + goto err; + +- if (gpio_is_valid(ddata->ext_te_gpio)) +- disable_irq(gpio_to_irq(ddata->ext_te_gpio)); ++ if (ddata->ext_te_gpio) ++ disable_irq(gpiod_to_irq(ddata->ext_te_gpio)); + + in->ops.dsi->disable(in, false, true); + +@@ -330,8 +329,8 @@ static int dsicm_exit_ulps(struct panel_drv_data *ddata) + goto err2; + } + +- if (gpio_is_valid(ddata->ext_te_gpio)) +- enable_irq(gpio_to_irq(ddata->ext_te_gpio)); ++ if (ddata->ext_te_gpio) ++ enable_irq(gpiod_to_irq(ddata->ext_te_gpio)); + + dsicm_queue_ulps_work(ddata); + +@@ -344,8 +343,8 @@ static int dsicm_exit_ulps(struct panel_drv_data *ddata) + + r = dsicm_panel_reset(ddata); + if (!r) { +- if (gpio_is_valid(ddata->ext_te_gpio)) +- enable_irq(gpio_to_irq(ddata->ext_te_gpio)); ++ if (ddata->ext_te_gpio) ++ enable_irq(gpiod_to_irq(ddata->ext_te_gpio)); + ddata->ulps_enabled = false; + } + err1: +@@ -591,16 +590,13 @@ static const struct attribute_group dsicm_attr_group = { + + static void dsicm_hw_reset(struct panel_drv_data *ddata) + { +- if (!gpio_is_valid(ddata->reset_gpio)) +- return; +- +- gpio_set_value(ddata->reset_gpio, 1); ++ gpiod_set_value(ddata->reset_gpio, 1); + udelay(10); + /* reset the panel */ +- gpio_set_value(ddata->reset_gpio, 0); ++ gpiod_set_value(ddata->reset_gpio, 0); + /* assert reset */ + udelay(10); +- gpio_set_value(ddata->reset_gpio, 1); ++ gpiod_set_value(ddata->reset_gpio, 1); + /* wait after releasing reset */ + usleep_range(5000, 10000); + } +@@ -954,7 +950,7 @@ static int dsicm_update(struct omap_dss_device *dssdev, + if (r) + goto err; + +- if (ddata->te_enabled && gpio_is_valid(ddata->ext_te_gpio)) { ++ if (ddata->te_enabled && ddata->ext_te_gpio) { + schedule_delayed_work(&ddata->te_timeout_work, + msecs_to_jiffies(250)); + atomic_set(&ddata->do_update, 1); +@@ -1001,7 +997,7 @@ static int _dsicm_enable_te(struct panel_drv_data *ddata, bool enable) + else + r = dsicm_dcs_write_0(ddata, MIPI_DCS_SET_TEAR_OFF); + +- if (!gpio_is_valid(ddata->ext_te_gpio)) ++ if (!ddata->ext_te_gpio) + in->ops.dsi->enable_te(in, enable); + + /* possible panel bug */ +@@ -1229,21 +1225,21 @@ static int dsicm_probe_of(struct platform_device *pdev) + struct panel_drv_data *ddata = platform_get_drvdata(pdev); + struct omap_dss_device *in; + struct display_timing timing; +- int gpio, err; ++ int err; + +- gpio = of_get_named_gpio(node, "reset-gpios", 0); +- if (!gpio_is_valid(gpio)) { +- dev_err(&pdev->dev, "failed to parse reset gpio\n"); +- return gpio; ++ ddata->reset_gpio = devm_gpiod_get(&pdev->dev, "reset", GPIOD_OUT_LOW); ++ if (IS_ERR(ddata->reset_gpio)) { ++ err = PTR_ERR(ddata->reset_gpio); ++ dev_err(&pdev->dev, "reset gpio request failed: %d", err); ++ return err; + } +- ddata->reset_gpio = gpio; + +- gpio = of_get_named_gpio(node, "te-gpios", 0); +- if (gpio_is_valid(gpio) || gpio == -ENOENT) { +- ddata->ext_te_gpio = gpio; +- } else { +- dev_err(&pdev->dev, "failed to parse TE gpio\n"); +- return gpio; ++ ddata->ext_te_gpio = devm_gpiod_get_optional(&pdev->dev, "te", ++ GPIOD_IN); ++ if (IS_ERR(ddata->ext_te_gpio)) { ++ err = PTR_ERR(ddata->ext_te_gpio); ++ dev_err(&pdev->dev, "TE gpio request failed: %d", err); ++ return err; + } + + err = of_get_display_timing(node, "panel-timing", &timing); +@@ -1353,24 +1349,8 @@ static int dsicm_probe(struct platform_device *pdev) + + atomic_set(&ddata->do_update, 0); + +- if (gpio_is_valid(ddata->reset_gpio)) { +- r = devm_gpio_request_one(dev, ddata->reset_gpio, +- GPIOF_OUT_INIT_LOW, "taal rst"); +- if (r) { +- dev_err(dev, "failed to request reset gpio\n"); +- goto err_reg; +- } +- } +- +- if (gpio_is_valid(ddata->ext_te_gpio)) { +- r = devm_gpio_request_one(dev, ddata->ext_te_gpio, +- GPIOF_IN, "taal irq"); +- if (r) { +- dev_err(dev, "GPIO request failed\n"); +- goto err_reg; +- } +- +- r = devm_request_irq(dev, gpio_to_irq(ddata->ext_te_gpio), ++ if (ddata->ext_te_gpio) { ++ r = devm_request_irq(dev, gpiod_to_irq(ddata->ext_te_gpio), + dsicm_te_isr, + IRQF_TRIGGER_RISING, + "taal vsync", ddata); +-- +2.1.4 + diff --git a/extra/patches/linux-droid4-patches/0013-ARM-dts-omap4-droid4-improve-LCD-description.patch b/extra/patches/linux-droid4-patches/0013-ARM-dts-omap4-droid4-improve-LCD-description.patch @@ -0,0 +1,39 @@ +From caebc72b95edde23e564f221f09d11148c8526fd Mon Sep 17 00:00:00 2001 +From: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +Date: Mon, 24 Jul 2017 19:33:10 +0200 +Subject: [PATCH 13/17] ARM: dts: omap4-droid4: improve LCD description + +This improves LCD support for the Droid 4. + +Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +--- + arch/arm/boot/dts/omap4-droid4-xt894.dts | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/omap4-droid4-xt894.dts b/arch/arm/boot/dts/omap4-droid4-xt894.dts +index 8b93d37..4620b20 100644 +--- a/arch/arm/boot/dts/omap4-droid4-xt894.dts ++++ b/arch/arm/boot/dts/omap4-droid4-xt894.dts +@@ -176,6 +176,10 @@ + vddi-supply = <&lcd_regulator>; + reset-gpios = <&gpio4 5 GPIO_ACTIVE_HIGH>; /* gpio101 */ + ++ width-mm = <50>; ++ height-mm = <89>; ++ backlight = <&lcd_backlight>; ++ + panel-timing { + clock-frequency = <0>; /* Calculated by dsi */ + +@@ -345,7 +349,7 @@ + + enable-gpios = <&gpio6 12 GPIO_ACTIVE_HIGH>; + +- backlight { ++ lcd_backlight: backlight { + compatible = "ti,lm3532-backlight"; + + lcd { +-- +2.1.4 + diff --git a/extra/patches/linux-droid4-patches/0014-ARM-dts-n950-add-display-support.patch b/extra/patches/linux-droid4-patches/0014-ARM-dts-n950-add-display-support.patch @@ -0,0 +1,122 @@ +From e2e3c533158df1e24c6172a2d5f83d7a4b96db16 Mon Sep 17 00:00:00 2001 +From: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +Date: Mon, 24 Jul 2017 19:33:11 +0200 +Subject: [PATCH 14/17] ARM: dts: n950: add display support + +Add basic panel support for the Nokia N950. It must be tweaked a +little bit later, since the panel was built into the device +upside-down. Also the first 5 and the last 5 pixels are covered +by plastic. + +Signed-off-By: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +Acked-by: Pavel Machek <pavel@ucw.cz> +--- + arch/arm/boot/dts/omap3-n950.dts | 88 ++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 88 insertions(+) + +diff --git a/arch/arm/boot/dts/omap3-n950.dts b/arch/arm/boot/dts/omap3-n950.dts +index 646601a..ef70aae 100644 +--- a/arch/arm/boot/dts/omap3-n950.dts ++++ b/arch/arm/boot/dts/omap3-n950.dts +@@ -51,6 +51,26 @@ + }; + }; + ++&omap3_pmx_core { ++ dsi_pins: pinmux_dsi_pins { ++ pinctrl-single,pins = < ++ OMAP3_CORE1_IOPAD(0x20dc, PIN_OUTPUT | MUX_MODE1) /* dsi_dx0 - data0+ */ ++ OMAP3_CORE1_IOPAD(0x20de, PIN_OUTPUT | MUX_MODE1) /* dsi_dy0 - data0- */ ++ OMAP3_CORE1_IOPAD(0x20e0, PIN_OUTPUT | MUX_MODE1) /* dsi_dx1 - clk+ */ ++ OMAP3_CORE1_IOPAD(0x20e2, PIN_OUTPUT | MUX_MODE1) /* dsi_dy1 - clk- */ ++ OMAP3_CORE1_IOPAD(0x20e4, PIN_OUTPUT | MUX_MODE1) /* dsi_dx2 - data1+ */ ++ OMAP3_CORE1_IOPAD(0x20e6, PIN_OUTPUT | MUX_MODE1) /* dsi_dy2 - data1- */ ++ >; ++ }; ++ ++ display_pins: pinmux_display_pins { ++ pinctrl-single,pins = < ++ OMAP3_CORE1_IOPAD(0x20ca, PIN_INPUT | MUX_MODE4) /* gpio 62 - display te */ ++ OMAP3_CORE1_IOPAD(0x20fe, PIN_OUTPUT | MUX_MODE4) /* gpio 87 - display reset */ ++ >; ++ }; ++}; ++ + &i2c2 { + smia_1: camera@10 { + compatible = "nokia,smia"; +@@ -185,3 +205,71 @@ + st,max-limit-y = <32>; + st,max-limit-z = <32>; + }; ++ ++&dss { ++ status = "ok"; ++ ++ vdda_video-supply = <&vdac>; ++}; ++ ++&dsi { ++ status = "ok"; ++ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&dsi_pins>; ++ ++ vdd-supply = <&vpll2>; ++ ++ port { ++ dsi_out_ep: endpoint { ++ remote-endpoint = <&lcd0_in>; ++ lanes = <2 3 0 1 4 5>; ++ }; ++ }; ++ ++ lcd0: display { ++ compatible = "nokia,himalaya", "panel-dsi-cm"; ++ label = "lcd0"; ++ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&display_pins>; ++ ++ vpnl-supply = <&vmmc2>; ++ vddi-supply = <&vio>; ++ ++ reset-gpios = <&gpio3 23 GPIO_ACTIVE_HIGH>; /* 87 */ ++ te-gpios = <&gpio2 30 GPIO_ACTIVE_HIGH>; /* 62 */ ++ ++ width-mm = <49>; /* 48.960 mm */ ++ height-mm = <88>; /* 88.128 mm */ ++ ++ /* TODO: ++ * - panel is upside-down ++ * - top + bottom 5px are not visible ++ */ ++ panel-timing { ++ clock-frequency = <0>; /* Calculated by dsi */ ++ ++ hback-porch = <2>; ++ hactive = <480>; ++ hfront-porch = <0>; ++ hsync-len = <2>; ++ ++ vback-porch = <1>; ++ vactive = <864>; ++ vfront-porch = <0>; ++ vsync-len = <1>; ++ ++ hsync-active = <0>; ++ vsync-active = <0>; ++ de-active = <1>; ++ pixelclk-active = <1>; ++ }; ++ ++ port { ++ lcd0_in: endpoint { ++ remote-endpoint = <&dsi_out_ep>; ++ }; ++ }; ++ }; ++}; +-- +2.1.4 + diff --git a/extra/patches/linux-droid4-patches/0015-dt-bindings-backlight-add-ti-lmu-backlight-binding.patch b/extra/patches/linux-droid4-patches/0015-dt-bindings-backlight-add-ti-lmu-backlight-binding.patch @@ -0,0 +1,89 @@ +From ce34e7400299f5130f4f78bf3e894905373bc3c3 Mon Sep 17 00:00:00 2001 +From: Milo Kim <Milo.Kim@ti.com> +Date: Mon, 17 Jul 2017 15:39:55 +0200 +Subject: [PATCH 15/17] dt-bindings: backlight: add ti-lmu-backlight binding + +Add DT binding for ti-lmu devices. + +Signed-off-by: Milo Kim <milo.kim@ti.com> +Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +--- + .../bindings/leds/backlight/ti-lmu-backlight.txt | 66 ++++++++++++++++++++++ + 1 file changed, 66 insertions(+) + create mode 100644 Documentation/devicetree/bindings/leds/backlight/ti-lmu-backlight.txt + +diff --git a/Documentation/devicetree/bindings/leds/backlight/ti-lmu-backlight.txt b/Documentation/devicetree/bindings/leds/backlight/ti-lmu-backlight.txt +new file mode 100644 +index 0000000..5fb1458 +--- /dev/null ++++ b/Documentation/devicetree/bindings/leds/backlight/ti-lmu-backlight.txt +@@ -0,0 +1,66 @@ ++TI LMU backlight device tree bindings ++ ++Required property: ++ - compatible: Should be one of: ++ "ti,lm3532-backlight" ++ "ti,lm3631-backlight" ++ "ti,lm3632-backlight" ++ "ti,lm3633-backlight" ++ "ti,lm3695-backlight" ++ "ti,lm3697-backlight" ++ ++Optional properties: ++ There are two backlight control mode. One is I2C, the other is PWM mode. ++ Following properties are only specified in PWM mode. ++ Please note that LMU backlight device can have only one PWM channel. ++ ++ - pwms: OF device-tree PWM specification. ++ - pwm-names: a list of names for the PWM devices specified in the "pwms" ++ property. ++ ++ For the PWM user nodes, please refer to [1]. ++ ++Child nodes: ++ LMU backlight is represented as sub-nodes of the TI LMU device [2]. ++ So, LMU backlight should have more than one backlight child node. ++ Each node exactly matches with backlight control bank configuration. ++ Maximum numbers of child nodes depend on the device. ++ ++ 1 = LM3631, LM3632, LM3695 ++ 2 = LM3633, LM3697 ++ 3 = LM3532 ++ ++ Required property of a child node: ++ - led-sources: List of enabled channels from 0 to 2. ++ Please refer to LED binding [3]. ++ For output channels, please refer to the datasheets [4]. ++ ++ Optional properties of a child node: ++ - label: Backlight channel identification. ++ Please refer to LED binding [3]. ++ - default-brightness-level: Backlight initial brightness value. ++ Type is <u32>. It is set as soon as backlight ++ device is created. ++ 0 ~ 2047 = LM3631, LM3632, LM3633, LM3695 and ++ LM3697 ++ 0 ~ 255 = LM3532 ++ - ramp-up-msec, ramp-down-msec: Light dimming effect properties. ++ Type is <u32>. Unit is millisecond. ++ 0 ~ 65 msec = LM3532 ++ 0 ~ 4000 msec = LM3631 ++ 0 ~ 16000 msec = LM3633 and LM3697 ++ - pwm-period: PWM period. Only valid in PWM brightness mode. ++ Type is <u32>. If this property is missing, then control ++ mode is set to I2C by default. ++ ++Examples: Please refer to ti-lmu dt-bindings. [2]. ++ ++[1] ../pwm/pwm.txt ++[2] ../mfd/ti-lmu.txt ++[3] ../leds/common.txt ++[4] LM3532: http://www.ti.com/product/LM3532/datasheet ++ LM3631: http://www.ti.com/product/LM3631/datasheet ++ LM3632: http://www.ti.com/product/LM3632A/datasheet ++ LM3633: http://www.ti.com/product/LM3633/datasheet ++ LM3695: Datasheet is not opened yet, but only two strings are used. ++ LM3697: http://www.ti.com/product/LM3697/datasheet +-- +2.1.4 + diff --git a/extra/patches/linux-droid4-patches/0016-backlight-add-TI-LMU-backlight-driver.patch b/extra/patches/linux-droid4-patches/0016-backlight-add-TI-LMU-backlight-driver.patch @@ -0,0 +1,1222 @@ +From 102ad25228f75277c9f023a121c073c906034d13 Mon Sep 17 00:00:00 2001 +From: Milo Kim <Milo.Kim@ti.com> +Date: Mon, 17 Jul 2017 15:39:56 +0200 +Subject: [PATCH 16/17] backlight: add TI LMU backlight driver + +This is consolidated driver which supports the following +backlight devices: LM3532, LM3631, LM3632, LM3633, LM3695 +and LM3697. + +Structure +--------- + It consists of two parts - core and data. + + Core part supports features below. + - Backlight subsystem control + - Channel configuration from DT properties + - Light dimming effect control: ramp up and down. + - LMU fault monitor notifier handling + - PWM brightness control + + Data part describes device specific data. + - Register value configuration for each LMU device + : initialization, channel configuration, control mode, enable and + brightness. + - PWM action configuration + - Light dimming effect table + - Option for LMU fault monitor support + +Signed-off-by: Milo Kim <milo.kim@ti.com> +Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk> +--- + drivers/video/backlight/Kconfig | 7 + + drivers/video/backlight/Makefile | 3 + + drivers/video/backlight/ti-lmu-backlight-core.c | 729 ++++++++++++++++++++++++ + drivers/video/backlight/ti-lmu-backlight-data.c | 304 ++++++++++ + drivers/video/backlight/ti-lmu-backlight-data.h | 95 +++ + 5 files changed, 1138 insertions(+) + create mode 100644 drivers/video/backlight/ti-lmu-backlight-core.c + create mode 100644 drivers/video/backlight/ti-lmu-backlight-data.c + create mode 100644 drivers/video/backlight/ti-lmu-backlight-data.h + +diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig +index 4e1d2ad..c3cc833 100644 +--- a/drivers/video/backlight/Kconfig ++++ b/drivers/video/backlight/Kconfig +@@ -427,6 +427,13 @@ config BACKLIGHT_SKY81452 + To compile this driver as a module, choose M here: the module will + be called sky81452-backlight + ++config BACKLIGHT_TI_LMU ++ tristate "Backlight driver for TI LMU" ++ depends on BACKLIGHT_CLASS_DEVICE && MFD_TI_LMU ++ help ++ Say Y to enable the backlight driver for TI LMU devices. ++ This supports LM3532, LM3631, LM3632, LM3633, LM3695 and LM3697. ++ + config BACKLIGHT_TPS65217 + tristate "TPS65217 Backlight" + depends on BACKLIGHT_CLASS_DEVICE && MFD_TPS65217 +diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile +index 8905129..c532e43 100644 +--- a/drivers/video/backlight/Makefile ++++ b/drivers/video/backlight/Makefile +@@ -52,6 +52,9 @@ obj-$(CONFIG_BACKLIGHT_PM8941_WLED) += pm8941-wled.o + obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.o + obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o + obj-$(CONFIG_BACKLIGHT_SKY81452) += sky81452-backlight.o ++ti-lmu-backlight-objs := ti-lmu-backlight-core.o \ ++ ti-lmu-backlight-data.o ++obj-$(CONFIG_BACKLIGHT_TI_LMU) += ti-lmu-backlight.o + obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o + obj-$(CONFIG_BACKLIGHT_TPS65217) += tps65217_bl.o + obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o +diff --git a/drivers/video/backlight/ti-lmu-backlight-core.c b/drivers/video/backlight/ti-lmu-backlight-core.c +new file mode 100644 +index 0000000..fca9508 +--- /dev/null ++++ b/drivers/video/backlight/ti-lmu-backlight-core.c +@@ -0,0 +1,729 @@ ++/* ++ * TI LMU (Lighting Management Unit) Backlight Driver ++ * ++ * Copyright 2015 Texas Instruments ++ * ++ * Author: Milo Kim <milo.kim@ti.com> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/backlight.h> ++#include <linux/bitops.h> ++#include <linux/device.h> ++#include <linux/delay.h> ++#include <linux/err.h> ++#include <linux/kernel.h> ++#include <linux/mfd/ti-lmu.h> ++#include <linux/mfd/ti-lmu-register.h> ++#include <linux/module.h> ++#include <linux/notifier.h> ++#include <linux/of.h> ++#include <linux/of_device.h> ++#include <linux/platform_device.h> ++#include <linux/pwm.h> ++#include <linux/slab.h> ++ ++#include "ti-lmu-backlight-data.h" ++ ++enum ti_lmu_bl_ctrl_mode { ++ BL_REGISTER_BASED, ++ BL_PWM_BASED, ++}; ++ ++enum ti_lmu_bl_ramp_mode { ++ BL_RAMP_UP, ++ BL_RAMP_DOWN, ++}; ++ ++struct ti_lmu_bl; ++ ++/** ++ * struct ti_lmu_bl_chip ++ * ++ * @dev: Parent device pointer ++ * @lmu: LMU structure. ++ * Used for register R/W access and notification. ++ * @cfg: Device configuration data ++ * @lmu_bl: Multiple backlight channels ++ * @num_backlights: Number of backlight channels ++ * @nb: Notifier block for handling LMU fault monitor event ++ * ++ * One backlight chip can have multiple backlight channels, 'ti_lmu_bl'. ++ */ ++struct ti_lmu_bl_chip { ++ struct device *dev; ++ struct ti_lmu *lmu; ++ const struct ti_lmu_bl_cfg *cfg; ++ struct ti_lmu_bl *lmu_bl; ++ int num_backlights; ++ struct notifier_block nb; ++}; ++ ++/** ++ * struct ti_lmu_bl ++ * ++ * @chip: Pointer to parent backlight device ++ * @bl_dev: Backlight subsystem device structure ++ * @bank_id: Backlight bank ID ++ * @name: Backlight channel name ++ * @mode: Backlight control mode ++ * @led_sources: Backlight output channel configuration. ++ * Bit mask is set on parsing DT. ++ * @default_brightness: [Optional] Initial brightness value ++ * @ramp_up_msec: [Optional] Ramp up time ++ * @ramp_down_msec: [Optional] Ramp down time ++ * @pwm_period: [Optional] PWM period ++ * @pwm: [Optional] PWM subsystem structure ++ * ++ * Each backlight device has its own channel configuration. ++ * For chip control, parent chip data structure is used. ++ */ ++struct ti_lmu_bl { ++ struct ti_lmu_bl_chip *chip; ++ struct backlight_device *bl_dev; ++ ++ int bank_id; ++ const char *name; ++ enum ti_lmu_bl_ctrl_mode mode; ++ unsigned long led_sources; ++ ++ unsigned int default_brightness; ++ ++ /* Used for lighting effect */ ++ unsigned int ramp_up_msec; ++ unsigned int ramp_down_msec; ++ ++ /* Only valid in PWM mode */ ++ unsigned int pwm_period; ++ struct pwm_device *pwm; ++}; ++ ++#define NUM_DUAL_CHANNEL 2 ++#define LMU_BACKLIGHT_DUAL_CHANNEL_USED (BIT(0) | BIT(1)) ++#define LMU_BACKLIGHT_11BIT_LSB_MASK (BIT(0) | BIT(1) | BIT(2)) ++#define LMU_BACKLIGHT_11BIT_MSB_SHIFT 3 ++#define DEFAULT_PWM_NAME "lmu-backlight" ++ ++static int ti_lmu_backlight_enable(struct ti_lmu_bl *lmu_bl, bool enable) ++{ ++ struct ti_lmu_bl_chip *chip = lmu_bl->chip; ++ struct regmap *regmap = chip->lmu->regmap; ++ unsigned long enable_time = chip->cfg->reginfo->enable_usec; ++ u8 *reg = chip->cfg->reginfo->enable; ++ u8 mask = BIT(lmu_bl->bank_id); ++ u8 val = (enable == true) ? mask : 0; ++ int ret; ++ ++ if (!reg) ++ return -EINVAL; ++ ++ ret = regmap_update_bits(regmap, *reg, mask, val); ++ if (ret) ++ return ret; ++ ++ if (enable_time > 0) ++ usleep_range(enable_time, enable_time + 100); ++ ++ return 0; ++} ++ ++static int ti_lmu_backlight_pwm_ctrl(struct ti_lmu_bl *lmu_bl, int brightness, ++ int max_brightness) ++{ ++ struct pwm_state state = { }; ++ int ret; ++ ++ if (!lmu_bl->pwm) { ++ lmu_bl->pwm = devm_pwm_get(lmu_bl->chip->dev, DEFAULT_PWM_NAME); ++ if (IS_ERR(lmu_bl->pwm)) { ++ ret = PTR_ERR(lmu_bl->pwm); ++ lmu_bl->pwm = NULL; ++ dev_err(lmu_bl->chip->dev, ++ "Can not get PWM device, err: %d\n", ret); ++ return ret; ++ } ++ } ++ ++ pwm_init_state(lmu_bl->pwm, &state); ++ state.period = lmu_bl->pwm_period; ++ state.duty_cycle = brightness * state.period / max_brightness; ++ ++ if (state.duty_cycle) ++ state.enabled = true; ++ else ++ state.enabled = false; ++ ++ ret = pwm_apply_state(lmu_bl->pwm, &state); ++ if (ret) ++ dev_err(lmu_bl->chip->dev, "Failed to configure PWM: %d", ret); ++ ++ return ret; ++} ++ ++static int ti_lmu_backlight_update_brightness_register(struct ti_lmu_bl *lmu_bl, ++ int brightness) ++{ ++ const struct ti_lmu_bl_cfg *cfg = lmu_bl->chip->cfg; ++ const struct ti_lmu_bl_reg *reginfo = cfg->reginfo; ++ struct regmap *regmap = lmu_bl->chip->lmu->regmap; ++ u8 reg, val; ++ int ret; ++ ++ /* ++ * Brightness register update ++ * ++ * 11 bit dimming: update LSB bits and write MSB byte. ++ * MSB brightness should be shifted. ++ * 8 bit dimming: write MSB byte. ++ */ ++ if (cfg->max_brightness == MAX_BRIGHTNESS_11BIT) { ++ reg = reginfo->brightness_lsb[lmu_bl->bank_id]; ++ ret = regmap_update_bits(regmap, reg, ++ LMU_BACKLIGHT_11BIT_LSB_MASK, ++ brightness); ++ if (ret) ++ return ret; ++ ++ val = brightness >> LMU_BACKLIGHT_11BIT_MSB_SHIFT; ++ } else { ++ val = brightness; ++ } ++ ++ reg = reginfo->brightness_msb[lmu_bl->bank_id]; ++ return regmap_write(regmap, reg, val); ++} ++ ++static int ti_lmu_backlight_update_status(struct backlight_device *bl_dev) ++{ ++ struct ti_lmu_bl *lmu_bl = bl_get_data(bl_dev); ++ const struct ti_lmu_bl_cfg *cfg = lmu_bl->chip->cfg; ++ int brightness = bl_dev->props.brightness; ++ bool enable = brightness > 0; ++ int ret; ++ ++ if (bl_dev->props.state & BL_CORE_SUSPENDED) ++ brightness = 0; ++ ++ ret = ti_lmu_backlight_enable(lmu_bl, enable); ++ if (ret) ++ return ret; ++ ++ if (lmu_bl->mode == BL_PWM_BASED) { ++ ti_lmu_backlight_pwm_ctrl(lmu_bl, brightness, ++ bl_dev->props.max_brightness); ++ ++ switch (cfg->pwm_action) { ++ case UPDATE_PWM_ONLY: ++ /* No register update is required */ ++ return 0; ++ case UPDATE_MAX_BRT: ++ /* ++ * PWM can start from any non-zero code and dim down ++ * to zero. So, brightness register should be updated ++ * even in PWM mode. ++ */ ++ if (brightness > 0) ++ brightness = MAX_BRIGHTNESS_11BIT; ++ else ++ brightness = 0; ++ break; ++ default: ++ break; ++ } ++ } ++ ++ return ti_lmu_backlight_update_brightness_register(lmu_bl, brightness); ++} ++ ++static const struct backlight_ops lmu_backlight_ops = { ++ .options = BL_CORE_SUSPENDRESUME, ++ .update_status = ti_lmu_backlight_update_status, ++}; ++ ++static int ti_lmu_backlight_of_get_ctrl_bank(struct device_node *np, ++ struct ti_lmu_bl *lmu_bl) ++{ ++ const char *name; ++ u32 *sources; ++ int num_channels = lmu_bl->chip->cfg->num_channels; ++ int ret, num_sources; ++ ++ sources = devm_kzalloc(lmu_bl->chip->dev, num_channels, GFP_KERNEL); ++ if (!sources) ++ return -ENOMEM; ++ ++ if (!of_property_read_string(np, "label", &name)) ++ lmu_bl->name = name; ++ else ++ lmu_bl->name = np->name; ++ ++ ret = of_property_count_u32_elems(np, "led-sources"); ++ if (ret < 0 || ret > num_channels) ++ return -EINVAL; ++ ++ num_sources = ret; ++ ret = of_property_read_u32_array(np, "led-sources", sources, ++ num_sources); ++ if (ret) ++ return ret; ++ ++ lmu_bl->led_sources = 0; ++ while (num_sources--) ++ set_bit(sources[num_sources], &lmu_bl->led_sources); ++ ++ return 0; ++} ++ ++static void ti_lmu_backlight_of_get_light_properties(struct device_node *np, ++ struct ti_lmu_bl *lmu_bl) ++{ ++ of_property_read_u32(np, "default-brightness-level", ++ &lmu_bl->default_brightness); ++ ++ of_property_read_u32(np, "ramp-up-msec", &lmu_bl->ramp_up_msec); ++ of_property_read_u32(np, "ramp-down-msec", &lmu_bl->ramp_down_msec); ++} ++ ++static void ti_lmu_backlight_of_get_brightness_mode(struct device_node *np, ++ struct ti_lmu_bl *lmu_bl) ++{ ++ of_property_read_u32(np, "pwm-period", &lmu_bl->pwm_period); ++ ++ if (lmu_bl->pwm_period > 0) ++ lmu_bl->mode = BL_PWM_BASED; ++ else ++ lmu_bl->mode = BL_REGISTER_BASED; ++} ++ ++static int ti_lmu_backlight_of_create(struct ti_lmu_bl_chip *chip, ++ struct device_node *np) ++{ ++ struct device_node *child; ++ struct ti_lmu_bl *lmu_bl, *each; ++ int ret, num_backlights; ++ int i = 0; ++ ++ num_backlights = of_get_child_count(np); ++ if (num_backlights == 0) { ++ dev_err(chip->dev, "No backlight strings\n"); ++ return -ENODEV; ++ } ++ ++ /* One chip can have mulitple backlight strings */ ++ lmu_bl = devm_kzalloc(chip->dev, sizeof(*lmu_bl) * num_backlights, ++ GFP_KERNEL); ++ if (!lmu_bl) ++ return -ENOMEM; ++ ++ /* Child is mapped to LMU backlight control bank */ ++ for_each_child_of_node(np, child) { ++ each = lmu_bl + i; ++ each->bank_id = i; ++ each->chip = chip; ++ ++ ret = ti_lmu_backlight_of_get_ctrl_bank(child, each); ++ if (ret) { ++ of_node_put(np); ++ return ret; ++ } ++ ++ ti_lmu_backlight_of_get_light_properties(child, each); ++ ti_lmu_backlight_of_get_brightness_mode(child, each); ++ ++ i++; ++ } ++ ++ chip->lmu_bl = lmu_bl; ++ chip->num_backlights = num_backlights; ++ ++ return 0; ++} ++ ++static int ti_lmu_backlight_check_channel(struct ti_lmu_bl *lmu_bl) ++{ ++ const struct ti_lmu_bl_cfg *cfg = lmu_bl->chip->cfg; ++ const struct ti_lmu_bl_reg *reginfo = lmu_bl->chip->cfg->reginfo; ++ ++ if (!reginfo->brightness_msb) ++ return -EINVAL; ++ ++ if (cfg->max_brightness > MAX_BRIGHTNESS_8BIT) { ++ if (!reginfo->brightness_lsb) ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int ti_lmu_backlight_create_channel(struct ti_lmu_bl *lmu_bl) ++{ ++ struct regmap *regmap = lmu_bl->chip->lmu->regmap; ++ const struct lmu_bl_reg_data *regdata = ++ lmu_bl->chip->cfg->reginfo->channel; ++ int num_channels = lmu_bl->chip->cfg->num_channels; ++ int i, ret; ++ u8 shift; ++ ++ /* ++ * How to create backlight output channels: ++ * Check 'led_sources' bit and update registers. ++ * ++ * 1) Dual channel configuration ++ * The 1st register data is used for single channel. ++ * The 2nd register data is used for dual channel. ++ * ++ * 2) Multiple channel configuration ++ * Each register data is mapped to bank ID. ++ * Bit shift operation is defined in channel registers. ++ * ++ * Channel register data consists of address, mask, value. ++ */ ++ ++ if (num_channels == NUM_DUAL_CHANNEL) { ++ if (lmu_bl->led_sources == LMU_BACKLIGHT_DUAL_CHANNEL_USED) ++ regdata++; ++ ++ return regmap_update_bits(regmap, regdata->reg, regdata->mask, ++ regdata->val); ++ } ++ ++ for (i = 0; regdata && i < num_channels; i++) { ++ /* ++ * Note that the result of regdata->val is shift bit. ++ * The bank_id should be shifted for the channel configuration. ++ */ ++ if (test_bit(i, &lmu_bl->led_sources)) { ++ shift = regdata->val; ++ ret = regmap_update_bits(regmap, regdata->reg, ++ regdata->mask, ++ lmu_bl->bank_id << shift); ++ if (ret) ++ return ret; ++ } ++ ++ regdata++; ++ } ++ ++ return 0; ++} ++ ++static int ti_lmu_backlight_update_ctrl_mode(struct ti_lmu_bl *lmu_bl) ++{ ++ struct regmap *regmap = lmu_bl->chip->lmu->regmap; ++ const struct lmu_bl_reg_data *regdata = ++ lmu_bl->chip->cfg->reginfo->mode + lmu_bl->bank_id; ++ u8 val = regdata->val; ++ ++ if (!regdata) ++ return 0; ++ ++ /* ++ * Update PWM configuration register. ++ * If the mode is register based, then clear the bit. ++ */ ++ if (lmu_bl->mode != BL_PWM_BASED) ++ val = 0; ++ ++ return regmap_update_bits(regmap, regdata->reg, regdata->mask, val); ++} ++ ++static int ti_lmu_backlight_convert_ramp_to_index(struct ti_lmu_bl *lmu_bl, ++ enum ti_lmu_bl_ramp_mode mode) ++{ ++ const int *ramp_table = lmu_bl->chip->cfg->ramp_table; ++ const int size = lmu_bl->chip->cfg->size_ramp; ++ unsigned int msec; ++ int i; ++ ++ if (!ramp_table) ++ return -EINVAL; ++ ++ switch (mode) { ++ case BL_RAMP_UP: ++ msec = lmu_bl->ramp_up_msec; ++ break; ++ case BL_RAMP_DOWN: ++ msec = lmu_bl->ramp_down_msec; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ if (msec <= ramp_table[0]) ++ return 0; ++ ++ if (msec > ramp_table[size - 1]) ++ return size - 1; ++ ++ for (i = 1; i < size; i++) { ++ if (msec == ramp_table[i]) ++ return i; ++ ++ /* Find an approximate index by looking up the table */ ++ if (msec > ramp_table[i - 1] && msec < ramp_table[i]) { ++ if (msec - ramp_table[i - 1] < ramp_table[i] - msec) ++ return i - 1; ++ else ++ return i; ++ } ++ } ++ ++ return -EINVAL; ++} ++ ++static int ti_lmu_backlight_set_ramp(struct ti_lmu_bl *lmu_bl) ++{ ++ struct regmap *regmap = lmu_bl->chip->lmu->regmap; ++ const struct ti_lmu_bl_reg *reginfo = lmu_bl->chip->cfg->reginfo; ++ int offset = reginfo->ramp_reg_offset; ++ int i, ret, index; ++ struct lmu_bl_reg_data regdata; ++ ++ for (i = BL_RAMP_UP; i <= BL_RAMP_DOWN; i++) { ++ index = ti_lmu_backlight_convert_ramp_to_index(lmu_bl, i); ++ if (index > 0) { ++ if (!reginfo->ramp) ++ break; ++ ++ regdata = reginfo->ramp[i]; ++ if (lmu_bl->bank_id != 0) ++ regdata.val += offset; ++ ++ /* regdata.val is shift bit */ ++ ret = regmap_update_bits(regmap, regdata.reg, ++ regdata.mask, ++ index << regdata.val); ++ if (ret) ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++static int ti_lmu_backlight_configure(struct ti_lmu_bl *lmu_bl) ++{ ++ int ret; ++ ++ ret = ti_lmu_backlight_check_channel(lmu_bl); ++ if (ret) ++ return ret; ++ ++ ret = ti_lmu_backlight_create_channel(lmu_bl); ++ if (ret) ++ return ret; ++ ++ ret = ti_lmu_backlight_update_ctrl_mode(lmu_bl); ++ if (ret) ++ return ret; ++ ++ return ti_lmu_backlight_set_ramp(lmu_bl); ++} ++ ++static int ti_lmu_backlight_init(struct ti_lmu_bl_chip *chip) ++{ ++ struct regmap *regmap = chip->lmu->regmap; ++ const struct lmu_bl_reg_data *regdata = ++ chip->cfg->reginfo->init; ++ int num_init = chip->cfg->reginfo->num_init; ++ int i, ret; ++ ++ for (i = 0; regdata && i < num_init; i++) { ++ ret = regmap_update_bits(regmap, regdata->reg, regdata->mask, ++ regdata->val); ++ if (ret) ++ return ret; ++ ++ regdata++; ++ } ++ ++ return 0; ++} ++ ++static int ti_lmu_backlight_reload(struct ti_lmu_bl_chip *chip) ++{ ++ struct ti_lmu_bl *each; ++ int i, ret; ++ ++ ret = ti_lmu_backlight_init(chip); ++ if (ret) ++ return ret; ++ ++ for (i = 0; i < chip->num_backlights; i++) { ++ each = chip->lmu_bl + i; ++ ret = ti_lmu_backlight_configure(each); ++ if (ret) ++ return ret; ++ ++ ret = backlight_update_status(each->bl_dev); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int ti_lmu_backlight_add_device(struct device *dev, ++ struct ti_lmu_bl *lmu_bl) ++{ ++ struct backlight_device *bl_dev; ++ struct backlight_properties props; ++ ++ memset(&props, 0, sizeof(struct backlight_properties)); ++ props.type = BACKLIGHT_PLATFORM; ++ props.brightness = lmu_bl->default_brightness; ++ props.max_brightness = lmu_bl->chip->cfg->max_brightness; ++ ++ bl_dev = devm_backlight_device_register(dev, lmu_bl->name, ++ lmu_bl->chip->dev, lmu_bl, ++ &lmu_backlight_ops, &props); ++ if (IS_ERR(bl_dev)) ++ return PTR_ERR(bl_dev); ++ ++ lmu_bl->bl_dev = bl_dev; ++ ++ return 0; ++} ++ ++static struct ti_lmu_bl_chip * ++ti_lmu_backlight_register(struct device *dev, struct ti_lmu *lmu, ++ const struct ti_lmu_bl_cfg *cfg) ++{ ++ struct ti_lmu_bl_chip *chip; ++ struct ti_lmu_bl *each; ++ int i, ret; ++ ++ if (!cfg) { ++ dev_err(dev, "Operation is not configured\n"); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); ++ if (!chip) ++ return ERR_PTR(-ENOMEM); ++ ++ chip->dev = dev; ++ chip->lmu = lmu; ++ chip->cfg = cfg; ++ ++ ret = ti_lmu_backlight_of_create(chip, dev->of_node); ++ if (ret) ++ return ERR_PTR(ret); ++ ++ ret = ti_lmu_backlight_init(chip); ++ if (ret) { ++ dev_err(dev, "Backlight init err: %d\n", ret); ++ return ERR_PTR(ret); ++ } ++ ++ for (i = 0; i < chip->num_backlights; i++) { ++ each = chip->lmu_bl + i; ++ ++ ret = ti_lmu_backlight_configure(each); ++ if (ret) { ++ dev_err(dev, "Backlight config err: %d\n", ret); ++ return ERR_PTR(ret); ++ } ++ ++ ret = ti_lmu_backlight_add_device(dev, each); ++ if (ret) { ++ dev_err(dev, "Backlight device err: %d\n", ret); ++ return ERR_PTR(ret); ++ } ++ ++ ret = backlight_update_status(each->bl_dev); ++ if (ret) { ++ dev_err(dev, "Backlight update err: %d\n", ret); ++ return ERR_PTR(ret); ++ } ++ } ++ ++ return chip; ++} ++ ++static void ti_lmu_backlight_unregister(struct ti_lmu_bl_chip *chip) ++{ ++ struct ti_lmu_bl *each; ++ int i; ++ ++ /* Turn off the brightness */ ++ for (i = 0; i < chip->num_backlights; i++) { ++ each = chip->lmu_bl + i; ++ each->bl_dev->props.brightness = 0; ++ backlight_update_status(each->bl_dev); ++ } ++} ++ ++static int ti_lmu_backlight_monitor_notifier(struct notifier_block *nb, ++ unsigned long action, void *unused) ++{ ++ struct ti_lmu_bl_chip *chip = container_of(nb, struct ti_lmu_bl_chip, ++ nb); ++ ++ if (action == LMU_EVENT_MONITOR_DONE) { ++ if (ti_lmu_backlight_reload(chip)) ++ return NOTIFY_STOP; ++ } ++ ++ return NOTIFY_OK; ++} ++ ++static int ti_lmu_backlight_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct ti_lmu *lmu = dev_get_drvdata(dev->parent); ++ struct ti_lmu_bl_chip *chip; ++ int ret; ++ ++ chip = ti_lmu_backlight_register(dev, lmu, &lmu_bl_cfg[pdev->id]); ++ if (IS_ERR(chip)) ++ return PTR_ERR(chip); ++ ++ /* ++ * Notifier callback is required because backlight device needs ++ * reconfiguration after fault detection procedure is done by ++ * ti-lmu-fault-monitor driver. ++ */ ++ if (chip->cfg->fault_monitor_used) { ++ chip->nb.notifier_call = ti_lmu_backlight_monitor_notifier; ++ ret = blocking_notifier_chain_register(&chip->lmu->notifier, ++ &chip->nb); ++ if (ret) ++ return ret; ++ } ++ ++ platform_set_drvdata(pdev, chip); ++ ++ return 0; ++} ++ ++static int ti_lmu_backlight_remove(struct platform_device *pdev) ++{ ++ struct ti_lmu_bl_chip *chip = platform_get_drvdata(pdev); ++ ++ if (chip->cfg->fault_monitor_used) ++ blocking_notifier_chain_unregister(&chip->lmu->notifier, ++ &chip->nb); ++ ++ ti_lmu_backlight_unregister(chip); ++ ++ return 0; ++} ++ ++static struct platform_driver ti_lmu_backlight_driver = { ++ .probe = ti_lmu_backlight_probe, ++ .remove = ti_lmu_backlight_remove, ++ .driver = { ++ .name = "ti-lmu-backlight", ++ }, ++}; ++ ++module_platform_driver(ti_lmu_backlight_driver) ++ ++MODULE_DESCRIPTION("TI LMU Backlight Driver"); ++MODULE_AUTHOR("Milo Kim"); ++MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("platform:ti-lmu-backlight"); +diff --git a/drivers/video/backlight/ti-lmu-backlight-data.c b/drivers/video/backlight/ti-lmu-backlight-data.c +new file mode 100644 +index 0000000..583136c +--- /dev/null ++++ b/drivers/video/backlight/ti-lmu-backlight-data.c +@@ -0,0 +1,304 @@ ++/* ++ * TI LMU (Lighting Management Unit) Backlight Device Data ++ * ++ * Copyright 2015 Texas Instruments ++ * ++ * Author: Milo Kim <milo.kim@ti.com> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include "ti-lmu-backlight-data.h" ++ ++/* LM3532 */ ++static const struct lmu_bl_reg_data lm3532_init_data[] = { ++ { LM3532_REG_ZONE_CFG_A, LM3532_ZONE_MASK, LM3532_ZONE_0 }, ++ { LM3532_REG_ZONE_CFG_B, LM3532_ZONE_MASK, LM3532_ZONE_1 }, ++ { LM3532_REG_ZONE_CFG_C, LM3532_ZONE_MASK, LM3532_ZONE_2 }, ++}; ++ ++static const struct lmu_bl_reg_data lm3532_channel_data[] = { ++ { LM3532_REG_OUTPUT_CFG, LM3532_ILED1_CFG_MASK, ++ LM3532_ILED1_CFG_SHIFT }, ++ { LM3532_REG_OUTPUT_CFG, LM3532_ILED2_CFG_MASK, ++ LM3532_ILED2_CFG_SHIFT }, ++ { LM3532_REG_OUTPUT_CFG, LM3532_ILED3_CFG_MASK, ++ LM3532_ILED3_CFG_SHIFT }, ++}; ++ ++static const struct lmu_bl_reg_data lm3532_mode_data[] = { ++ { LM3532_REG_PWM_A_CFG, LM3532_PWM_A_MASK, LM3532_PWM_ZONE_0 }, ++ { LM3532_REG_PWM_B_CFG, LM3532_PWM_B_MASK, LM3532_PWM_ZONE_1 }, ++ { LM3532_REG_PWM_C_CFG, LM3532_PWM_C_MASK, LM3532_PWM_ZONE_2 }, ++}; ++ ++static const struct lmu_bl_reg_data lm3532_ramp_data[] = { ++ { LM3532_REG_RAMPUP, LM3532_RAMPUP_MASK, LM3532_RAMPUP_SHIFT }, ++ { LM3532_REG_RAMPDN, LM3532_RAMPDN_MASK, LM3532_RAMPDN_SHIFT }, ++}; ++ ++static u8 lm3532_enable_reg = LM3532_REG_ENABLE; ++ ++static u8 lm3532_brightness_regs[] = { ++ LM3532_REG_BRT_A, ++ LM3532_REG_BRT_B, ++ LM3532_REG_BRT_C, ++}; ++ ++static const struct ti_lmu_bl_reg lm3532_reg_info = { ++ .init = lm3532_init_data, ++ .num_init = ARRAY_SIZE(lm3532_init_data), ++ .channel = lm3532_channel_data, ++ .mode = lm3532_mode_data, ++ .ramp = lm3532_ramp_data, ++ .enable = &lm3532_enable_reg, ++ .brightness_msb = lm3532_brightness_regs, ++}; ++ ++/* LM3631 */ ++static const struct lmu_bl_reg_data lm3631_init_data[] = { ++ { LM3631_REG_BRT_MODE, LM3631_MODE_MASK, LM3631_DEFAULT_MODE }, ++ { LM3631_REG_BL_CFG, LM3631_MAP_MASK, LM3631_EXPONENTIAL_MAP }, ++}; ++ ++static const struct lmu_bl_reg_data lm3631_channel_data[] = { ++ { LM3631_REG_BL_CFG, LM3631_BL_CHANNEL_MASK, LM3631_BL_SINGLE_CHANNEL }, ++ { LM3631_REG_BL_CFG, LM3631_BL_CHANNEL_MASK, LM3631_BL_DUAL_CHANNEL }, ++}; ++ ++static const struct lmu_bl_reg_data lm3631_ramp_data[] = { ++ { LM3631_REG_SLOPE, LM3631_SLOPE_MASK, LM3631_SLOPE_SHIFT }, ++}; ++ ++static u8 lm3631_enable_reg = LM3631_REG_DEVCTRL; ++static u8 lm3631_brightness_msb_reg = LM3631_REG_BRT_MSB; ++static u8 lm3631_brightness_lsb_reg = LM3631_REG_BRT_LSB; ++ ++static const struct ti_lmu_bl_reg lm3631_reg_info = { ++ .init = lm3631_init_data, ++ .num_init = ARRAY_SIZE(lm3631_init_data), ++ .channel = lm3631_channel_data, ++ .ramp = lm3631_ramp_data, ++ .enable = &lm3631_enable_reg, ++ .brightness_msb = &lm3631_brightness_msb_reg, ++ .brightness_lsb = &lm3631_brightness_lsb_reg, ++}; ++ ++/* LM3632 */ ++static const struct lmu_bl_reg_data lm3632_init_data[] = { ++ { LM3632_REG_CONFIG1, LM3632_OVP_MASK, LM3632_OVP_25V }, ++ { LM3632_REG_CONFIG2, LM3632_SWFREQ_MASK, LM3632_SWFREQ_1MHZ }, ++}; ++ ++static const struct lmu_bl_reg_data lm3632_channel_data[] = { ++ { LM3632_REG_ENABLE, LM3632_BL_CHANNEL_MASK, LM3632_BL_SINGLE_CHANNEL }, ++ { LM3632_REG_ENABLE, LM3632_BL_CHANNEL_MASK, LM3632_BL_DUAL_CHANNEL }, ++}; ++ ++static const struct lmu_bl_reg_data lm3632_mode_data[] = { ++ { LM3632_REG_IO_CTRL, LM3632_PWM_MASK, LM3632_PWM_MODE }, ++}; ++ ++static u8 lm3632_enable_reg = LM3632_REG_ENABLE; ++static u8 lm3632_brightness_msb_reg = LM3632_REG_BRT_MSB; ++static u8 lm3632_brightness_lsb_reg = LM3632_REG_BRT_LSB; ++ ++static const struct ti_lmu_bl_reg lm3632_reg_info = { ++ .init = lm3632_init_data, ++ .num_init = ARRAY_SIZE(lm3632_init_data), ++ .channel = lm3632_channel_data, ++ .mode = lm3632_mode_data, ++ .enable = &lm3632_enable_reg, ++ .brightness_msb = &lm3632_brightness_msb_reg, ++ .brightness_lsb = &lm3632_brightness_lsb_reg, ++}; ++ ++/* LM3633 */ ++static const struct lmu_bl_reg_data lm3633_init_data[] = { ++ { LM3633_REG_BOOST_CFG, LM3633_OVP_MASK, LM3633_OVP_40V }, ++ { LM3633_REG_BL_RAMP_CONF, LM3633_BL_RAMP_MASK, LM3633_BL_RAMP_EACH }, ++}; ++ ++static const struct lmu_bl_reg_data lm3633_channel_data[] = { ++ { LM3633_REG_HVLED_OUTPUT_CFG, LM3633_HVLED1_CFG_MASK, ++ LM3633_HVLED1_CFG_SHIFT }, ++ { LM3633_REG_HVLED_OUTPUT_CFG, LM3633_HVLED2_CFG_MASK, ++ LM3633_HVLED2_CFG_SHIFT }, ++ { LM3633_REG_HVLED_OUTPUT_CFG, LM3633_HVLED3_CFG_MASK, ++ LM3633_HVLED3_CFG_SHIFT }, ++}; ++ ++static const struct lmu_bl_reg_data lm3633_mode_data[] = { ++ { LM3633_REG_PWM_CFG, LM3633_PWM_A_MASK, LM3633_PWM_A_MASK }, ++ { LM3633_REG_PWM_CFG, LM3633_PWM_B_MASK, LM3633_PWM_B_MASK }, ++}; ++ ++static const struct lmu_bl_reg_data lm3633_ramp_data[] = { ++ { LM3633_REG_BL0_RAMP, LM3633_BL_RAMPUP_MASK, LM3633_BL_RAMPUP_SHIFT }, ++ { LM3633_REG_BL0_RAMP, LM3633_BL_RAMPDN_MASK, LM3633_BL_RAMPDN_SHIFT }, ++}; ++ ++static u8 lm3633_enable_reg = LM3633_REG_ENABLE; ++ ++static u8 lm3633_brightness_msb_regs[] = { ++ LM3633_REG_BRT_HVLED_A_MSB, ++ LM3633_REG_BRT_HVLED_B_MSB, ++}; ++ ++static u8 lm3633_brightness_lsb_regs[] = { ++ LM3633_REG_BRT_HVLED_A_LSB, ++ LM3633_REG_BRT_HVLED_B_LSB, ++}; ++ ++static const struct ti_lmu_bl_reg lm3633_reg_info = { ++ .init = lm3633_init_data, ++ .num_init = ARRAY_SIZE(lm3633_init_data), ++ .channel = lm3633_channel_data, ++ .mode = lm3633_mode_data, ++ .ramp = lm3633_ramp_data, ++ .ramp_reg_offset = 1, /* For LM3633_REG_BL1_RAMPUP/DN */ ++ .enable = &lm3633_enable_reg, ++ .brightness_msb = lm3633_brightness_msb_regs, ++ .brightness_lsb = lm3633_brightness_lsb_regs, ++}; ++ ++/* LM3695 */ ++static const struct lmu_bl_reg_data lm3695_init_data[] = { ++ { LM3695_REG_GP, LM3695_BRT_RW_MASK, LM3695_BRT_RW_MASK }, ++}; ++ ++static const struct lmu_bl_reg_data lm3695_channel_data[] = { ++ { LM3695_REG_GP, LM3695_BL_CHANNEL_MASK, LM3695_BL_SINGLE_CHANNEL }, ++ { LM3695_REG_GP, LM3695_BL_CHANNEL_MASK, LM3695_BL_DUAL_CHANNEL }, ++}; ++ ++static u8 lm3695_enable_reg = LM3695_REG_GP; ++static u8 lm3695_brightness_msb_reg = LM3695_REG_BRT_MSB; ++static u8 lm3695_brightness_lsb_reg = LM3695_REG_BRT_LSB; ++ ++static const struct ti_lmu_bl_reg lm3695_reg_info = { ++ .init = lm3695_init_data, ++ .num_init = ARRAY_SIZE(lm3695_init_data), ++ .channel = lm3695_channel_data, ++ .enable = &lm3695_enable_reg, ++ .enable_usec = 600, ++ .brightness_msb = &lm3695_brightness_msb_reg, ++ .brightness_lsb = &lm3695_brightness_lsb_reg, ++}; ++ ++/* LM3697 */ ++static const struct lmu_bl_reg_data lm3697_init_data[] = { ++ { LM3697_REG_RAMP_CONF, LM3697_RAMP_MASK, LM3697_RAMP_EACH }, ++}; ++ ++static const struct lmu_bl_reg_data lm3697_channel_data[] = { ++ { LM3697_REG_HVLED_OUTPUT_CFG, LM3697_HVLED1_CFG_MASK, ++ LM3697_HVLED1_CFG_SHIFT }, ++ { LM3697_REG_HVLED_OUTPUT_CFG, LM3697_HVLED2_CFG_MASK, ++ LM3697_HVLED2_CFG_SHIFT }, ++ { LM3697_REG_HVLED_OUTPUT_CFG, LM3697_HVLED3_CFG_MASK, ++ LM3697_HVLED3_CFG_SHIFT }, ++}; ++ ++static const struct lmu_bl_reg_data lm3697_mode_data[] = { ++ { LM3697_REG_PWM_CFG, LM3697_PWM_A_MASK, LM3697_PWM_A_MASK }, ++ { LM3697_REG_PWM_CFG, LM3697_PWM_B_MASK, LM3697_PWM_B_MASK }, ++}; ++ ++static const struct lmu_bl_reg_data lm3697_ramp_data[] = { ++ { LM3697_REG_BL0_RAMP, LM3697_RAMPUP_MASK, LM3697_RAMPUP_SHIFT }, ++ { LM3697_REG_BL0_RAMP, LM3697_RAMPDN_MASK, LM3697_RAMPDN_SHIFT }, ++}; ++ ++static u8 lm3697_enable_reg = LM3697_REG_ENABLE; ++ ++static u8 lm3697_brightness_msb_regs[] = { ++ LM3697_REG_BRT_A_MSB, ++ LM3697_REG_BRT_B_MSB, ++}; ++ ++static u8 lm3697_brightness_lsb_regs[] = { ++ LM3697_REG_BRT_A_LSB, ++ LM3697_REG_BRT_B_LSB, ++}; ++ ++static const struct ti_lmu_bl_reg lm3697_reg_info = { ++ .init = lm3697_init_data, ++ .num_init = ARRAY_SIZE(lm3697_init_data), ++ .channel = lm3697_channel_data, ++ .mode = lm3697_mode_data, ++ .ramp = lm3697_ramp_data, ++ .ramp_reg_offset = 1, /* For LM3697_REG_BL1_RAMPUP/DN */ ++ .enable = &lm3697_enable_reg, ++ .brightness_msb = lm3697_brightness_msb_regs, ++ .brightness_lsb = lm3697_brightness_lsb_regs, ++}; ++ ++static int lm3532_ramp_table[] = { 0, 1, 2, 4, 8, 16, 32, 65 }; ++ ++static int lm3631_ramp_table[] = { ++ 0, 1, 2, 5, 10, 20, 50, 100, ++ 250, 500, 750, 1000, 1500, 2000, 3000, 4000, ++}; ++ ++static int common_ramp_table[] = { ++ 2, 250, 500, 1000, 2000, 4000, 8000, 16000, ++}; ++ ++#define LM3532_MAX_CHANNELS 3 ++#define LM3631_MAX_CHANNELS 2 ++#define LM3632_MAX_CHANNELS 2 ++#define LM3633_MAX_CHANNELS 3 ++#define LM3695_MAX_CHANNELS 2 ++#define LM3697_MAX_CHANNELS 3 ++ ++const struct ti_lmu_bl_cfg lmu_bl_cfg[LMU_MAX_ID] = { ++ { ++ .reginfo = &lm3532_reg_info, ++ .num_channels = LM3532_MAX_CHANNELS, ++ .max_brightness = MAX_BRIGHTNESS_8BIT, ++ .pwm_action = UPDATE_PWM_AND_BRT_REGISTER, ++ .ramp_table = lm3532_ramp_table, ++ .size_ramp = ARRAY_SIZE(lm3532_ramp_table), ++ }, ++ { ++ .reginfo = &lm3631_reg_info, ++ .num_channels = LM3631_MAX_CHANNELS, ++ .max_brightness = MAX_BRIGHTNESS_11BIT, ++ .pwm_action = UPDATE_PWM_ONLY, ++ .ramp_table = lm3631_ramp_table, ++ .size_ramp = ARRAY_SIZE(lm3631_ramp_table), ++ }, ++ { ++ .reginfo = &lm3632_reg_info, ++ .num_channels = LM3632_MAX_CHANNELS, ++ .max_brightness = MAX_BRIGHTNESS_11BIT, ++ .pwm_action = UPDATE_PWM_ONLY, ++ }, ++ { ++ .reginfo = &lm3633_reg_info, ++ .num_channels = LM3633_MAX_CHANNELS, ++ .max_brightness = MAX_BRIGHTNESS_11BIT, ++ .pwm_action = UPDATE_MAX_BRT, ++ .ramp_table = common_ramp_table, ++ .size_ramp = ARRAY_SIZE(common_ramp_table), ++ .fault_monitor_used = true, ++ }, ++ { ++ .reginfo = &lm3695_reg_info, ++ .num_channels = LM3695_MAX_CHANNELS, ++ .max_brightness = MAX_BRIGHTNESS_11BIT, ++ .pwm_action = UPDATE_PWM_AND_BRT_REGISTER, ++ }, ++ { ++ .reginfo = &lm3697_reg_info, ++ .num_channels = LM3697_MAX_CHANNELS, ++ .max_brightness = MAX_BRIGHTNESS_11BIT, ++ .pwm_action = UPDATE_PWM_AND_BRT_REGISTER, ++ .ramp_table = common_ramp_table, ++ .size_ramp = ARRAY_SIZE(common_ramp_table), ++ .fault_monitor_used = true, ++ }, ++}; +diff --git a/drivers/video/backlight/ti-lmu-backlight-data.h b/drivers/video/backlight/ti-lmu-backlight-data.h +new file mode 100644 +index 0000000..c64e8e6 +--- /dev/null ++++ b/drivers/video/backlight/ti-lmu-backlight-data.h +@@ -0,0 +1,95 @@ ++/* ++ * TI LMU (Lighting Management Unit) Backlight Device Data Definitions ++ * ++ * Copyright 2015 Texas Instruments ++ * ++ * Author: Milo Kim <milo.kim@ti.com> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __TI_LMU_BACKLIGHT_H__ ++#define __TI_LMU_BACKLIGHT_H__ ++ ++#include <linux/mfd/ti-lmu.h> ++#include <linux/mfd/ti-lmu-register.h> ++ ++#define MAX_BRIGHTNESS_8BIT 255 ++#define MAX_BRIGHTNESS_11BIT 2047 ++ ++enum ti_lmu_bl_pwm_action { ++ /* Update PWM duty, no brightness register update is required */ ++ UPDATE_PWM_ONLY, ++ /* Update not only duty but also brightness register */ ++ UPDATE_PWM_AND_BRT_REGISTER, ++ /* Update max value in brightness registers */ ++ UPDATE_MAX_BRT, ++}; ++ ++struct lmu_bl_reg_data { ++ u8 reg; ++ u8 mask; ++ u8 val; ++}; ++ ++/** ++ * struct ti_lmu_bl_reg ++ * ++ * @init: Device initialization registers ++ * @num_init: Numbers of initialization registers ++ * @channel: Backlight channel configuration registers ++ * @mode: Brightness control mode registers ++ * @ramp: Ramp registers for lighting effect ++ * @ramp_reg_offset: Ramp register offset. ++ * Only used for multiple ramp registers. ++ * @enable: Enable control register address ++ * @enable_usec: Delay time for updating enable register. ++ * Unit is microsecond. ++ * @brightness_msb: Brightness MSB(Upper 8 bits) registers. ++ * Concatenated with LSB in 11 bit dimming mode. ++ * In 8 bit dimming, only MSB is used. ++ * @brightness_lsb: Brightness LSB(Lower 3 bits) registers. ++ * Only valid in 11 bit dimming mode. ++ */ ++struct ti_lmu_bl_reg { ++ const struct lmu_bl_reg_data *init; ++ int num_init; ++ const struct lmu_bl_reg_data *channel; ++ const struct lmu_bl_reg_data *mode; ++ const struct lmu_bl_reg_data *ramp; ++ int ramp_reg_offset; ++ u8 *enable; ++ unsigned long enable_usec; ++ u8 *brightness_msb; ++ u8 *brightness_lsb; ++}; ++ ++/** ++ * struct ti_lmu_bl_cfg ++ * ++ * @reginfo: Device register configuration ++ * @num_channels: Number of backlight channels ++ * @max_brightness: Max brightness value of backlight device ++ * @pwm_action: How to control brightness registers in PWM mode ++ * @ramp_table: [Optional] Ramp time table for lighting effect. ++ * It's used for searching approximate register index. ++ * @size_ramp: [Optional] Size of ramp table ++ * @fault_monitor_used: [Optional] Set true if the device needs to handle ++ * LMU fault monitor event. ++ * ++ * This structure is used for device specific data configuration. ++ */ ++struct ti_lmu_bl_cfg { ++ const struct ti_lmu_bl_reg *reginfo; ++ int num_channels; ++ int max_brightness; ++ enum ti_lmu_bl_pwm_action pwm_action; ++ int *ramp_table; ++ int size_ramp; ++ bool fault_monitor_used; ++}; ++ ++extern const struct ti_lmu_bl_cfg lmu_bl_cfg[LMU_MAX_ID]; ++#endif +-- +2.1.4 + diff --git a/extra/patches/linux-droid4-patches/0017-droid4-hdmi-on-4.14-rc4.patch b/extra/patches/linux-droid4-patches/0017-droid4-hdmi-on-4.14-rc4.patch @@ -0,0 +1,102 @@ +From 4f23bc7bf13c779f3640a3bf68ce688a98d434b8 Mon Sep 17 00:00:00 2001 +From: Tony Lindgren <tony@atomide.com> +Date: Wed, 25 Oct 2017 15:07:32 -0700 +Subject: [PATCH 17/17] droid4 hdmi on 4.14-rc4+ + +* Merlijn Wajer <merlijn@wizzup.org> [171025 14:54]: +> Hi, +> +> I have been trying to get HDMI to work on the Motorola Droid4, as I saw +> that it should be supported. When I enable DRM_OMAP, OMAP4_DSS_HDMI and +> DRM_OMAP_CONNECTOR_HDMI, I don't get any output on HDMI (Full config +> here [1], for Linux 4.14-rc4). I see this in dmesg (repeatedly) [2]: +> +> [ 21.360321] of_get_named_gpiod_flags: parsed 'hpd-gpios' property of +> node '/connector[0]' - status (0) +> [ 21.370147] connector-hdmi connector: failed to find video source +> +> My hunch is that perhaps something is missing in the device tree, but +> after looking for time in the omapdrm code I cannot figure it out. Am I +> perhaps missing some configuration options? +> +> I also do not seem to have any /dev/dri entries, although I did expect +> to see them. + +Hmm I've been using it a lot over past six months with lapdock with +typically updating to Linux next about once a week or every few weeks. +I'm just using pending LCD and backlight patches, and omap2plus_defconfig +with following patch. Maybe see if you're missing something from that +patch? + +Also Tomi pointed out earlier that n900 needed the analog tv module +loaded for LCD output.. I wonder if you need also the pending LCD +patches applied? + +Cheers, + +Tony + +> [1] http://sprunge.us/GIhC +> [2] http://sprunge.us/bXWf + +8< ------------------------- +--- + arch/arm/configs/omap2plus_defconfig | 38 ++++++++++++++++++++---------------- + 1 file changed, 21 insertions(+), 17 deletions(-) + +diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig +index 7b97200..59d8c14 100644 +--- a/arch/arm/configs/omap2plus_defconfig ++++ b/arch/arm/configs/omap2plus_defconfig +@@ -318,27 +318,31 @@ CONFIG_V4L_PLATFORM_DRIVERS=y + CONFIG_VIDEO_OMAP3=m + # CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set + CONFIG_VIDEO_TVP5150=m ++CONFIG_DRM=m ++CONFIG_DRM_OMAP=m ++CONFIG_DRM_OMAP_NUM_CRTCS=2 ++CONFIG_OMAP5_DSS_HDMI=y ++CONFIG_OMAP2_DSS_SDI=y ++CONFIG_OMAP2_DSS_DSI=y ++CONFIG_DRM_OMAP_ENCODER_OPA362=m ++CONFIG_DRM_OMAP_ENCODER_TFP410=m ++CONFIG_DRM_OMAP_ENCODER_TPD12S015=m ++CONFIG_DRM_OMAP_CONNECTOR_DVI=m ++CONFIG_DRM_OMAP_CONNECTOR_HDMI=m ++CONFIG_DRM_OMAP_CONNECTOR_ANALOG_TV=m ++CONFIG_DRM_OMAP_PANEL_DPI=m ++CONFIG_DRM_OMAP_PANEL_DSI_CM=m ++CONFIG_DRM_OMAP_PANEL_SONY_ACX565AKM=m ++CONFIG_DRM_OMAP_PANEL_LGPHILIPS_LB035Q02=m ++CONFIG_DRM_OMAP_PANEL_SHARP_LS037V7DW01=m ++CONFIG_DRM_OMAP_PANEL_TPO_TD028TTEC1=m ++CONFIG_DRM_OMAP_PANEL_TPO_TD043MTEA1=m ++CONFIG_DRM_OMAP_PANEL_NEC_NL8048HL11=m ++CONFIG_DRM_TILCDC=m + CONFIG_FB=y + CONFIG_FIRMWARE_EDID=y + CONFIG_FB_MODE_HELPERS=y + CONFIG_FB_TILEBLITTING=y +-CONFIG_FB_OMAP2=m +-CONFIG_FB_OMAP5_DSS_HDMI=y +-CONFIG_FB_OMAP2_DSS_SDI=y +-CONFIG_FB_OMAP2_DSS_DSI=y +-CONFIG_FB_OMAP2_ENCODER_TFP410=m +-CONFIG_FB_OMAP2_ENCODER_TPD12S015=m +-CONFIG_FB_OMAP2_CONNECTOR_DVI=m +-CONFIG_FB_OMAP2_CONNECTOR_HDMI=m +-CONFIG_FB_OMAP2_CONNECTOR_ANALOG_TV=m +-CONFIG_FB_OMAP2_PANEL_DPI=m +-CONFIG_FB_OMAP2_PANEL_DSI_CM=m +-CONFIG_FB_OMAP2_PANEL_SONY_ACX565AKM=m +-CONFIG_FB_OMAP2_PANEL_LGPHILIPS_LB035Q02=m +-CONFIG_FB_OMAP2_PANEL_SHARP_LS037V7DW01=m +-CONFIG_FB_OMAP2_PANEL_TPO_TD028TTEC1=m +-CONFIG_FB_OMAP2_PANEL_TPO_TD043MTEA1=m +-CONFIG_FB_OMAP2_PANEL_NEC_NL8048HL11=m + CONFIG_BACKLIGHT_LCD_SUPPORT=y + CONFIG_LCD_CLASS_DEVICE=y + CONFIG_LCD_PLATFORM=y +-- +2.1.4 + diff --git a/extra/patches/linux-droid4-patches/README b/extra/patches/linux-droid4-patches/README @@ -1,61 +0,0 @@ -https://www.spinics.net/lists/linux-omap/msg141500.html - -Hi, - -These are the remaining patches from my previous patchset to get -Droid 4 (omap4) display working. The patches have been rebased to -current master branch from Torvalds (581e400ff935). Since N950 -(omap3) is broken even with the workaround I moved it to the end, -so that it can be skipped. - -Working on Droid 4: - * Framebuffer Console, updated at 1Hz due to blinking cursor - * kmstest (static image) - * Display blanking - * Xorg with omap and modesetting driver - * No updates send when nothing needs to be sent - * Orientation DRM property is attached to the DSI panel - -Known issues: - * N950 (omap3) is broken. I have updated the omap3 fifo workaround, - but it's not enough to fix omap3. - * N950 (and N9) has first and last few lines covered by plastic, so - we should expose a smaller screen - -Changes since PATCHv1: - * Drop patches, that were queued by Tomi - * Rebase to current master - * Rework the omap3 workaround patch to only affect omap3 - * Add orientation DRM property support - --- Sebastian - - -Sebastian Reichel (8): - drm/omap: add framedone interrupt support - drm/omap: add manual update detection helper - drm/omap: add support for manually updated displays - dt-bindings: panel: common: document orientation property - drm/omap: add support for orientation hints from display drivers - drm/omap: panel-dsi-cm: add orientation support - ARM: dts: omap4-droid4: Add LCD panel orientation property - drm/omap: plane: update fifo size on ovl setup - - .../bindings/display/panel/panel-common.txt | 12 ++ - arch/arm/boot/dts/omap4-droid4-xt894.dts | 3 + - drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c | 13 ++ - drivers/gpu/drm/omapdrm/dss/dispc.c | 36 ++++- - drivers/gpu/drm/omapdrm/dss/omapdss.h | 2 + - drivers/gpu/drm/omapdrm/omap_connector.c | 18 ++- - drivers/gpu/drm/omapdrm/omap_connector.h | 1 + - drivers/gpu/drm/omapdrm/omap_crtc.c | 158 +++++++++++++++++++-- - drivers/gpu/drm/omapdrm/omap_crtc.h | 2 + - drivers/gpu/drm/omapdrm/omap_fb.c | 20 +++ - drivers/gpu/drm/omapdrm/omap_irq.c | 24 ++++ - drivers/gpu/drm/omapdrm/omap_irq.h | 1 + - include/dt-bindings/display/common.h | 14 ++ - 13 files changed, 294 insertions(+), 10 deletions(-) - create mode 100644 include/dt-bindings/display/common.h - --- -2.15.1