commit 3f9238ed77bf41b1bbdde75b9d16fdd670b79c8c parent 5771ad298c4c4432eff5a5a258183c2e03c2c15c Author: parazyd <parazyd@dyne.org> Date: Wed, 14 Feb 2018 15:13:25 +0100 Add and rebase sre's droid4 patches for linux 4.16-rc1. Diffstat:
27 files changed, 911 insertions(+), 2957 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 @@ -1,31 +0,0 @@ -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 @@ -0,0 +1,158 @@ +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 @@ -1,33 +0,0 @@ -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 @@ -0,0 +1,42 @@ +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 @@ -1,52 +0,0 @@ -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 @@ -0,0 +1,256 @@ +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 @@ -1,160 +0,0 @@ -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 @@ -0,0 +1,57 @@ +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 @@ -1,49 +0,0 @@ -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 @@ -0,0 +1,59 @@ +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 @@ -1,263 +0,0 @@ -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 @@ -0,0 +1,55 @@ +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 @@ -1,50 +0,0 @@ -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 @@ -0,0 +1,31 @@ +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 @@ -1,124 +0,0 @@ -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 @@ -0,0 +1,125 @@ +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 @@ -1,135 +0,0 @@ -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 @@ -0,0 +1,67 @@ +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 @@ -1,67 +0,0 @@ -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 @@ -1,247 +0,0 @@ -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 @@ -1,172 +0,0 @@ -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 @@ -1,39 +0,0 @@ -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 @@ -1,122 +0,0 @@ -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 @@ -1,89 +0,0 @@ -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 @@ -1,1222 +0,0 @@ -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 @@ -1,102 +0,0 @@ -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 @@ -0,0 +1,61 @@ +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