| From 4f389283ad4ecc0bceb09cccb825df1822fca6e3 Mon Sep 17 00:00:00 2001 |
| From: John Stultz <john.stultz@linaro.org> |
| Date: Mon, 16 Jan 2017 16:52:47 -0800 |
| Subject: [PATCH 002/255] drm/bridge: adv7511: Use work_struct to defer hotplug |
| handing to out of irq context |
| |
| 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 <airlied@linux.ie> |
| Cc: Archit Taneja <architt@codeaurora.org> |
| Cc: Wolfram Sang <wsa+renesas@sang-engineering.com> |
| Cc: Lars-Peter Clausen <lars@metafoo.de> |
| Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com> |
| Cc: dri-devel@lists.freedesktop.org |
| Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> |
| Tested-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> |
| Signed-off-by: John Stultz <john.stultz@linaro.org> |
| Signed-off-by: Archit Taneja <architt@codeaurora.org> |
| Link: http://patchwork.freedesktop.org/patch/msgid/1484614372-15342-2-git-send-email-john.stultz@linaro.org |
| (cherry picked from commit 518cb7057a59b9441336d2e88a396d52b6ab0cce) |
| Signed-off-by: Simon Horman <horms+renesas@verge.net.au> |
| --- |
| drivers/gpu/drm/bridge/adv7511/adv7511.h | 2 ++ |
| drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 11 ++++++++++- |
| 2 files changed, 12 insertions(+), 1 deletion(-) |
| |
| --- a/drivers/gpu/drm/bridge/adv7511/adv7511.h |
| +++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h |
| @@ -318,6 +318,8 @@ struct adv7511 { |
| bool edid_read; |
| |
| wait_queue_head_t wq; |
| + struct work_struct hpd_work; |
| + |
| struct drm_bridge bridge; |
| struct drm_connector connector; |
| |
| --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c |
| +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c |
| @@ -402,6 +402,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; |
| @@ -419,7 +426,7 @@ static int adv7511_irq_process(struct ad |
| regmap_write(adv7511->regmap, ADV7511_REG_INT(1), irq1); |
| |
| if (process_hpd && irq0 & ADV7511_INT0_HPD && adv7511->bridge.encoder) |
| - drm_helper_hpd_irq_event(adv7511->connector.dev); |
| + schedule_work(&adv7511->hpd_work); |
| |
| if (irq0 & ADV7511_INT0_EDID_READY || irq1 & ADV7511_INT1_DDC_ERROR) { |
| adv7511->edid_read = true; |
| @@ -1070,6 +1077,8 @@ static int adv7511_probe(struct i2c_clie |
| goto err_i2c_unregister_edid; |
| } |
| |
| + INIT_WORK(&adv7511->hpd_work, adv7511_hpd_work); |
| + |
| if (i2c->irq) { |
| init_waitqueue_head(&adv7511->wq); |
| |