From: Greg Kroah-Hartman Date: Fri, 8 Sep 2017 07:24:41 +0000 (+0200) Subject: 4.4-stable patches X-Git-Tag: v4.13.1~4 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=3c3e14453dfc88b14eec7a2aa0a7045fc6e9112d;p=thirdparty%2Fkernel%2Fstable-queue.git 4.4-stable patches added patches: drm-adv7511-really-enable-interrupts-for-edid-detection.patch drm-bridge-adv7511-fix-mutex-deadlock-when-interrupts-are-disabled.patch drm-bridge-adv7511-re-write-the-i2c-address-before-edid-probing.patch drm-bridge-adv7511-switch-to-using-drm_kms_helper_hotplug_event.patch drm-bridge-adv7511-use-work_struct-to-defer-hotplug-handing-to-out-of-irq-context.patch --- diff --git a/queue-4.4/drm-adv7511-really-enable-interrupts-for-edid-detection.patch b/queue-4.4/drm-adv7511-really-enable-interrupts-for-edid-detection.patch new file mode 100644 index 00000000000..176fd1f94e8 --- /dev/null +++ b/queue-4.4/drm-adv7511-really-enable-interrupts-for-edid-detection.patch @@ -0,0 +1,70 @@ +From d0be8584b01160eb6f49e77f8e9c1da286bb4ffb Mon Sep 17 00:00:00 2001 +From: Wolfram Sang +Date: Mon, 4 Jan 2016 03:33:45 +0100 +Subject: drm: adv7511: really enable interrupts for EDID detection + +From: Wolfram Sang + +commit d0be8584b01160eb6f49e77f8e9c1da286bb4ffb upstream. + +The interrupts for EDID_READY or DDC_ERROR were never enabled in this +driver, so reading EDID always timed out when chip was powered down and +interrupts were used. Fix this and also remove clearing the interrupt +flags, they are cleared in POWER_DOWN mode anyhow (unlike the interrupt +enable flags) according to docs and my tests. + +Signed-off-by: Wolfram Sang +Tested-by: Archit Taneja +Signed-off-by: Thong Ho +Signed-off-by: Nhan Nguyen +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/gpu/drm/i2c/adv7511.c | 25 +++++++++++++++++-------- + 1 file changed, 17 insertions(+), 8 deletions(-) + +--- a/drivers/gpu/drm/i2c/adv7511.c ++++ b/drivers/gpu/drm/i2c/adv7511.c +@@ -362,12 +362,19 @@ static void adv7511_power_on(struct adv7 + { + adv7511->current_edid_segment = -1; + +- regmap_write(adv7511->regmap, ADV7511_REG_INT(0), +- ADV7511_INT0_EDID_READY); +- regmap_write(adv7511->regmap, ADV7511_REG_INT(1), +- ADV7511_INT1_DDC_ERROR); + regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, + ADV7511_POWER_POWER_DOWN, 0); ++ if (adv7511->i2c_main->irq) { ++ /* ++ * Documentation says the INT_ENABLE registers are reset in ++ * POWER_DOWN mode. My 7511w preserved the bits, however. ++ * Still, let's be safe and stick to the documentation. ++ */ ++ regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(0), ++ ADV7511_INT0_EDID_READY); ++ regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(1), ++ ADV7511_INT1_DDC_ERROR); ++ } + + /* + * Per spec it is allowed to pulse the HDP signal to indicate that the +@@ -567,12 +574,14 @@ static int adv7511_get_modes(struct drm_ + + /* Reading the EDID only works if the device is powered */ + if (!adv7511->powered) { +- regmap_write(adv7511->regmap, ADV7511_REG_INT(0), +- ADV7511_INT0_EDID_READY); +- regmap_write(adv7511->regmap, ADV7511_REG_INT(1), +- ADV7511_INT1_DDC_ERROR); + regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, + ADV7511_POWER_POWER_DOWN, 0); ++ if (adv7511->i2c_main->irq) { ++ regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(0), ++ ADV7511_INT0_EDID_READY); ++ regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(1), ++ ADV7511_INT1_DDC_ERROR); ++ } + adv7511->current_edid_segment = -1; + } + diff --git a/queue-4.4/drm-bridge-adv7511-fix-mutex-deadlock-when-interrupts-are-disabled.patch b/queue-4.4/drm-bridge-adv7511-fix-mutex-deadlock-when-interrupts-are-disabled.patch new file mode 100644 index 00000000000..54ee141047f --- /dev/null +++ b/queue-4.4/drm-bridge-adv7511-fix-mutex-deadlock-when-interrupts-are-disabled.patch @@ -0,0 +1,75 @@ +From f0bfcc22d9822947b0ad3095e8363eab5261864c Mon Sep 17 00:00:00 2001 +From: Archit Taneja +Date: Wed, 15 Jun 2016 16:20:45 +0530 +Subject: drm/bridge: adv7511: Fix mutex deadlock when interrupts are disabled + +From: Archit Taneja + +commit f0bfcc22d9822947b0ad3095e8363eab5261864c upstream. + +When the adv7511 i2c client doesn't have an interrupt line, we observe a +deadlock on caused by trying to lock drm device's mode_config.mutex twice +in the same context. + +Here is the sequence that causes it: + +ioctl DRM_IOCTL_MODE_GETCONNECTOR from userspace + drm_mode_getconnector (acquires mode_config mutex) + connector->fill_modes() + drm_helper_probe_single_connector_modes + connector_funcs->get_modes + adv7511_encoder_get_modes + adv7511_get_edid_block + adv7511_irq_process + drm_helper_hpd_irq_event (acquires mode_config mutex again) + +In adv7511_irq_process, don't call drm_helper_hpd_irq_event when not +called from the interrupt handler. It doesn't serve any purpose there +anyway. + +Signed-off-by: Archit Taneja +Signed-off-by: Thong Ho +Signed-off-by: Nhan Nguyen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/i2c/adv7511.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/gpu/drm/i2c/adv7511.c ++++ b/drivers/gpu/drm/i2c/adv7511.c +@@ -429,7 +429,7 @@ static bool adv7511_hpd(struct adv7511 * + return false; + } + +-static int adv7511_irq_process(struct adv7511 *adv7511) ++static int adv7511_irq_process(struct adv7511 *adv7511, bool process_hpd) + { + unsigned int irq0, irq1; + int ret; +@@ -445,7 +445,7 @@ static int adv7511_irq_process(struct ad + regmap_write(adv7511->regmap, ADV7511_REG_INT(0), irq0); + regmap_write(adv7511->regmap, ADV7511_REG_INT(1), irq1); + +- if (irq0 & ADV7511_INT0_HDP && adv7511->encoder) ++ if (process_hpd && irq0 & ADV7511_INT0_HDP && adv7511->encoder) + drm_helper_hpd_irq_event(adv7511->encoder->dev); + + if (irq0 & ADV7511_INT0_EDID_READY || irq1 & ADV7511_INT1_DDC_ERROR) { +@@ -463,7 +463,7 @@ static irqreturn_t adv7511_irq_handler(i + struct adv7511 *adv7511 = devid; + int ret; + +- ret = adv7511_irq_process(adv7511); ++ ret = adv7511_irq_process(adv7511, true); + return ret < 0 ? IRQ_NONE : IRQ_HANDLED; + } + +@@ -480,7 +480,7 @@ static int adv7511_wait_for_edid(struct + adv7511->edid_read, msecs_to_jiffies(timeout)); + } else { + for (; timeout > 0; timeout -= 25) { +- ret = adv7511_irq_process(adv7511); ++ ret = adv7511_irq_process(adv7511, false); + if (ret < 0) + break; + diff --git a/queue-4.4/drm-bridge-adv7511-re-write-the-i2c-address-before-edid-probing.patch b/queue-4.4/drm-bridge-adv7511-re-write-the-i2c-address-before-edid-probing.patch new file mode 100644 index 00000000000..51ea6331737 --- /dev/null +++ b/queue-4.4/drm-bridge-adv7511-re-write-the-i2c-address-before-edid-probing.patch @@ -0,0 +1,73 @@ +From 3587c856675c45809010c2cee5b21096f6e8e938 Mon Sep 17 00:00:00 2001 +From: John Stultz +Date: Mon, 16 Jan 2017 16:52:52 -0800 +Subject: drm/bridge: adv7511: Re-write the i2c address before EDID probing + +From: John Stultz + +commit 3587c856675c45809010c2cee5b21096f6e8e938 upstream. + +I've found that by just turning the chip on and off via the +POWER_DOWN register, I end up getting i2c_transfer errors on +HiKey. + +Investigating further, it turns out that some of the register +state in hardware is getting lost, as the device registers are +reset when the chip is powered down. + +Thus this patch simply re-writes the i2c address to the +ADV7511_REG_EDID_I2C_ADDR register to ensure its properly set +before we try to read the EDID data. + +Cc: David Airlie +Cc: Archit Taneja +Cc: Wolfram Sang +Cc: Lars-Peter Clausen +Cc: Laurent Pinchart +Cc: dri-devel@lists.freedesktop.org +Reviewed-by: Laurent Pinchart +Tested-by: Laurent Pinchart +Signed-off-by: John Stultz +Signed-off-by: Archit Taneja +Link: http://patchwork.freedesktop.org/patch/msgid/1484614372-15342-7-git-send-email-john.stultz@linaro.org +Signed-off-by: Thong Ho +Signed-off-by: Nhan Nguyen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/i2c/adv7511.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +--- a/drivers/gpu/drm/i2c/adv7511.c ++++ b/drivers/gpu/drm/i2c/adv7511.c +@@ -51,6 +51,10 @@ struct adv7511 { + struct gpio_desc *gpio_pd; + }; + ++static const int edid_i2c_addr = 0x7e; ++static const int packet_i2c_addr = 0x70; ++static const int cec_i2c_addr = 0x78; ++ + static struct adv7511 *encoder_to_adv7511(struct drm_encoder *encoder) + { + return to_encoder_slave(encoder)->slave_priv; +@@ -606,6 +610,9 @@ static int adv7511_get_modes(struct drm_ + ADV7511_INT1_DDC_ERROR); + } + adv7511->current_edid_segment = -1; ++ /* Reset the EDID_I2C_ADDR register as it might be cleared */ ++ regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR, ++ edid_i2c_addr); + } + + edid = drm_do_get_edid(connector, adv7511_get_edid_block, adv7511); +@@ -881,10 +888,6 @@ static int adv7511_parse_dt(struct devic + return 0; + } + +-static const int edid_i2c_addr = 0x7e; +-static const int packet_i2c_addr = 0x70; +-static const int cec_i2c_addr = 0x78; +- + static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id) + { + struct adv7511_link_config link_config; diff --git a/queue-4.4/drm-bridge-adv7511-switch-to-using-drm_kms_helper_hotplug_event.patch b/queue-4.4/drm-bridge-adv7511-switch-to-using-drm_kms_helper_hotplug_event.patch new file mode 100644 index 00000000000..5d7e088ef54 --- /dev/null +++ b/queue-4.4/drm-bridge-adv7511-switch-to-using-drm_kms_helper_hotplug_event.patch @@ -0,0 +1,63 @@ +From 6d5104c5a6b56385426e15047050584794bb6254 Mon Sep 17 00:00:00 2001 +From: John Stultz +Date: Mon, 16 Jan 2017 16:52:48 -0800 +Subject: drm/bridge: adv7511: Switch to using drm_kms_helper_hotplug_event() + +From: John Stultz + +commit 6d5104c5a6b56385426e15047050584794bb6254 upstream. + +In chasing down a previous issue with EDID probing from calling +drm_helper_hpd_irq_event() from irq context, Laurent noticed +that the DRM documentation suggests that +drm_kms_helper_hotplug_event() should be used instead. + +Thus this patch replaces drm_helper_hpd_irq_event() with +drm_kms_helper_hotplug_event(), which requires we update the +connector.status entry and only call _hotplug_event() when the +status changes. + +Cc: David Airlie +Cc: Archit Taneja +Cc: Wolfram Sang +Cc: Lars-Peter Clausen +Cc: Laurent Pinchart +Cc: dri-devel@lists.freedesktop.org +Reviewed-by: Laurent Pinchart +Tested-by: Laurent Pinchart +Signed-off-by: John Stultz +Signed-off-by: Archit Taneja +Link: http://patchwork.freedesktop.org/patch/msgid/1484614372-15342-3-git-send-email-john.stultz@linaro.org +Signed-off-by: Thong Ho +Signed-off-by: Nhan Nguyen +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/gpu/drm/i2c/adv7511.c | 15 ++++++++++++++- + 1 file changed, 14 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/i2c/adv7511.c ++++ b/drivers/gpu/drm/i2c/adv7511.c +@@ -435,8 +435,21 @@ static bool adv7511_hpd(struct adv7511 * + static void adv7511_hpd_work(struct work_struct *work) + { + struct adv7511 *adv7511 = container_of(work, struct adv7511, hpd_work); ++ enum drm_connector_status status; ++ unsigned int val; ++ int ret; ++ ret = regmap_read(adv7511->regmap, ADV7511_REG_STATUS, &val); ++ if (ret < 0) ++ status = connector_status_disconnected; ++ else if (val & ADV7511_STATUS_HPD) ++ status = connector_status_connected; ++ else ++ status = connector_status_disconnected; + +- drm_helper_hpd_irq_event(adv7511->connector.dev); ++ if (adv7511->connector.status != status) { ++ adv7511->connector.status = status; ++ drm_kms_helper_hotplug_event(adv7511->connector.dev); ++ } + } + + static int adv7511_irq_process(struct adv7511 *adv7511, bool process_hpd) diff --git a/queue-4.4/drm-bridge-adv7511-use-work_struct-to-defer-hotplug-handing-to-out-of-irq-context.patch b/queue-4.4/drm-bridge-adv7511-use-work_struct-to-defer-hotplug-handing-to-out-of-irq-context.patch new file mode 100644 index 00000000000..1f769e12136 --- /dev/null +++ b/queue-4.4/drm-bridge-adv7511-use-work_struct-to-defer-hotplug-handing-to-out-of-irq-context.patch @@ -0,0 +1,87 @@ +From 518cb7057a59b9441336d2e88a396d52b6ab0cce Mon Sep 17 00:00:00 2001 +From: John Stultz +Date: Mon, 16 Jan 2017 16:52:47 -0800 +Subject: drm/bridge: adv7511: Use work_struct to defer hotplug handing to out of irq context + +From: John Stultz + +commit 518cb7057a59b9441336d2e88a396d52b6ab0cce upstream. + +I was recently seeing issues with EDID probing, where +the logic to wait for the EDID read bit to be set by the +IRQ wasn't happening and the code would time out and fail. + +Digging deeper, I found this was due to the fact that +IRQs were disabled as we were running in IRQ context from +the HPD signal. + +Thus this patch changes the logic to handle the HPD signal +via a work_struct so we can be out of irq context. + +With this patch, the EDID probing on hotplug does not time +out. + +Cc: David Airlie +Cc: Archit Taneja +Cc: Wolfram Sang +Cc: Lars-Peter Clausen +Cc: Laurent Pinchart +Cc: dri-devel@lists.freedesktop.org +Reviewed-by: Laurent Pinchart +Tested-by: Laurent Pinchart +Signed-off-by: John Stultz +Signed-off-by: Archit Taneja +Link: http://patchwork.freedesktop.org/patch/msgid/1484614372-15342-2-git-send-email-john.stultz@linaro.org +Signed-off-by: Thong Ho +Signed-off-by: Nhan Nguyen +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/gpu/drm/i2c/adv7511.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/i2c/adv7511.c ++++ b/drivers/gpu/drm/i2c/adv7511.c +@@ -36,7 +36,10 @@ struct adv7511 { + bool edid_read; + + wait_queue_head_t wq; ++ struct work_struct hpd_work; ++ + struct drm_encoder *encoder; ++ struct drm_connector connector; + + bool embedded_sync; + enum adv7511_sync_polarity vsync_polarity; +@@ -429,6 +432,13 @@ static bool adv7511_hpd(struct adv7511 * + return false; + } + ++static void adv7511_hpd_work(struct work_struct *work) ++{ ++ struct adv7511 *adv7511 = container_of(work, struct adv7511, hpd_work); ++ ++ drm_helper_hpd_irq_event(adv7511->connector.dev); ++} ++ + static int adv7511_irq_process(struct adv7511 *adv7511, bool process_hpd) + { + unsigned int irq0, irq1; +@@ -446,7 +456,7 @@ static int adv7511_irq_process(struct ad + regmap_write(adv7511->regmap, ADV7511_REG_INT(1), irq1); + + if (process_hpd && irq0 & ADV7511_INT0_HDP && adv7511->encoder) +- drm_helper_hpd_irq_event(adv7511->encoder->dev); ++ schedule_work(&adv7511->hpd_work); + + if (irq0 & ADV7511_INT0_EDID_READY || irq1 & ADV7511_INT1_DDC_ERROR) { + adv7511->edid_read = true; +@@ -922,6 +932,8 @@ static int adv7511_probe(struct i2c_clie + if (!adv7511->i2c_edid) + return -ENOMEM; + ++ INIT_WORK(&adv7511->hpd_work, adv7511_hpd_work); ++ + if (i2c->irq) { + init_waitqueue_head(&adv7511->wq); + diff --git a/queue-4.4/series b/queue-4.4/series index da8a8bdd291..386912a961f 100644 --- a/queue-4.4/series +++ b/queue-4.4/series @@ -18,3 +18,8 @@ workqueue-fix-flag-collision.patch cs5536-add-support-for-ide-controller-variant.patch scsi-sg-protect-against-races-between-mmap-and-sg_set_reserved_size.patch scsi-sg-recheck-mmap_io-request-length-with-lock-held.patch +drm-adv7511-really-enable-interrupts-for-edid-detection.patch +drm-bridge-adv7511-fix-mutex-deadlock-when-interrupts-are-disabled.patch +drm-bridge-adv7511-use-work_struct-to-defer-hotplug-handing-to-out-of-irq-context.patch +drm-bridge-adv7511-switch-to-using-drm_kms_helper_hotplug_event.patch +drm-bridge-adv7511-re-write-the-i2c-address-before-edid-probing.patch