aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2015-06-06 16:41:09 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2015-09-15 11:19:48 -0400
commit0fc6f44d9683c61678da4b0eebc89e8fa624de39 (patch)
treebf0e5d5e975a34c36e352d48609e0a1df7e871c8
parentf84a97d4804a09240372dc7b195f9d6162152228 (diff)
drm/i2c: tda998x: re-implement "Fix EDID read timeout on HDMI connect"
Commit 6833d26ef823 ("drm: tda998x: Fix EDID read timeout on HDMI connect") used a weak scheme to try and delay reading EDID on a HDMI connect event. It is weak because delaying the notification of a hotplug event does not stop userspace from trying to read the EDID within the 100ms delay. The solution provided here solves this issue: * When a HDMI connection event is detected, mark a blocking flag for EDID reads, and start a timer for the delay. * If an EDID read is attempted, and the blocking flag is set, wait for the blocking flag to clear. * When the timer expires, clear the blocking flag and wake any thread waiting for the EDID read. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--drivers/gpu/drm/i2c/tda998x_drv.c80
1 files changed, 68 insertions, 12 deletions
diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c
index ad3ce3479edf..a53696fd8938 100644
--- a/drivers/gpu/drm/i2c/tda998x_drv.c
+++ b/drivers/gpu/drm/i2c/tda998x_drv.c
@@ -34,7 +34,6 @@ struct tda998x_priv {
34 struct i2c_client *cec; 34 struct i2c_client *cec;
35 struct i2c_client *hdmi; 35 struct i2c_client *hdmi;
36 struct mutex mutex; 36 struct mutex mutex;
37 struct delayed_work dwork;
38 uint16_t rev; 37 uint16_t rev;
39 uint8_t current_page; 38 uint8_t current_page;
40 int dpms; 39 int dpms;
@@ -47,6 +46,11 @@ struct tda998x_priv {
47 wait_queue_head_t wq_edid; 46 wait_queue_head_t wq_edid;
48 volatile int wq_edid_wait; 47 volatile int wq_edid_wait;
49 struct drm_encoder *encoder; 48 struct drm_encoder *encoder;
49
50 struct work_struct detect_work;
51 struct timer_list edid_delay_timer;
52 wait_queue_head_t edid_delay_waitq;
53 bool edid_delay_active;
50}; 54};
51 55
52#define to_tda998x_priv(x) ((struct tda998x_priv *)to_encoder_slave(x)->slave_priv) 56#define to_tda998x_priv(x) ((struct tda998x_priv *)to_encoder_slave(x)->slave_priv)
@@ -551,15 +555,50 @@ tda998x_reset(struct tda998x_priv *priv)
551 reg_write(priv, REG_MUX_VP_VIP_OUT, 0x24); 555 reg_write(priv, REG_MUX_VP_VIP_OUT, 0x24);
552} 556}
553 557
554/* handle HDMI connect/disconnect */ 558/*
555static void tda998x_hpd(struct work_struct *work) 559 * The TDA998x has a problem when trying to read the EDID close to a
560 * HPD assertion: it needs a delay of 100ms to avoid timing out while
561 * trying to read EDID data.
562 *
563 * However, tda998x_encoder_get_modes() may be called at any moment
564 * after tda998x_encoder_detect() indicates that we are connected, so
565 * we need to delay probing modes in tda998x_encoder_get_modes() after
566 * we have seen a HPD inactive->active transition. This code implements
567 * that delay.
568 */
569static void tda998x_edid_delay_done(unsigned long data)
570{
571 struct tda998x_priv *priv = (struct tda998x_priv *)data;
572
573 priv->edid_delay_active = false;
574 wake_up(&priv->edid_delay_waitq);
575 schedule_work(&priv->detect_work);
576}
577
578static void tda998x_edid_delay_start(struct tda998x_priv *priv)
579{
580 priv->edid_delay_active = true;
581 mod_timer(&priv->edid_delay_timer, jiffies + HZ/10);
582}
583
584static int tda998x_edid_delay_wait(struct tda998x_priv *priv)
585{
586 return wait_event_killable(priv->edid_delay_waitq, !priv->edid_delay_active);
587}
588
589/*
590 * We need to run the KMS hotplug event helper outside of our threaded
591 * interrupt routine as this can call back into our get_modes method,
592 * which will want to make use of interrupts.
593 */
594static void tda998x_detect_work(struct work_struct *work)
556{ 595{
557 struct delayed_work *dwork = to_delayed_work(work);
558 struct tda998x_priv *priv = 596 struct tda998x_priv *priv =
559 container_of(dwork, struct tda998x_priv, dwork); 597 container_of(work, struct tda998x_priv, detect_work);
598 struct drm_device *dev = priv->encoder->dev;
560 599
561 if (priv->encoder->dev) 600 if (dev)
562 drm_kms_helper_hotplug_event(priv->encoder->dev); 601 drm_kms_helper_hotplug_event(dev);
563} 602}
564 603
565/* 604/*
@@ -585,7 +624,11 @@ static irqreturn_t tda998x_irq_thread(int irq, void *data)
585 wake_up(&priv->wq_edid); 624 wake_up(&priv->wq_edid);
586 handled = true; 625 handled = true;
587 } else if (cec != 0) { /* HPD change */ 626 } else if (cec != 0) { /* HPD change */
588 schedule_delayed_work(&priv->dwork, HZ/10); 627 if (lvl & CEC_RXSHPDLEV_HPD)
628 tda998x_edid_delay_start(priv);
629 else
630 schedule_work(&priv->detect_work);
631
589 handled = true; 632 handled = true;
590 } 633 }
591 return IRQ_RETVAL(handled); 634 return IRQ_RETVAL(handled);
@@ -1103,6 +1146,14 @@ tda998x_encoder_get_modes(struct tda998x_priv *priv,
1103 struct edid *edid; 1146 struct edid *edid;
1104 int n; 1147 int n;
1105 1148
1149 /*
1150 * If we get killed while waiting for the HPD timeout, return
1151 * no modes found: we are not in a restartable path, so we
1152 * can't handle signals gracefully.
1153 */
1154 if (tda998x_edid_delay_wait(priv))
1155 return 0;
1156
1106 if (priv->rev == TDA19988) 1157 if (priv->rev == TDA19988)
1107 reg_clear(priv, REG_TX4, TX4_PD_RAM); 1158 reg_clear(priv, REG_TX4, TX4_PD_RAM);
1108 1159
@@ -1149,10 +1200,12 @@ static void tda998x_destroy(struct tda998x_priv *priv)
1149 /* disable all IRQs and free the IRQ handler */ 1200 /* disable all IRQs and free the IRQ handler */
1150 cec_write(priv, REG_CEC_RXSHPDINTENA, 0); 1201 cec_write(priv, REG_CEC_RXSHPDINTENA, 0);
1151 reg_clear(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD); 1202 reg_clear(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD);
1152 if (priv->hdmi->irq) { 1203
1204 if (priv->hdmi->irq)
1153 free_irq(priv->hdmi->irq, priv); 1205 free_irq(priv->hdmi->irq, priv);
1154 cancel_delayed_work_sync(&priv->dwork); 1206
1155 } 1207 del_timer_sync(&priv->edid_delay_timer);
1208 cancel_work_sync(&priv->detect_work);
1156 1209
1157 i2c_unregister_device(priv->cec); 1210 i2c_unregister_device(priv->cec);
1158} 1211}
@@ -1253,6 +1306,10 @@ static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv)
1253 priv->dpms = DRM_MODE_DPMS_OFF; 1306 priv->dpms = DRM_MODE_DPMS_OFF;
1254 1307
1255 mutex_init(&priv->mutex); /* protect the page access */ 1308 mutex_init(&priv->mutex); /* protect the page access */
1309 init_waitqueue_head(&priv->edid_delay_waitq);
1310 setup_timer(&priv->edid_delay_timer, tda998x_edid_delay_done,
1311 (unsigned long)priv);
1312 INIT_WORK(&priv->detect_work, tda998x_detect_work);
1256 1313
1257 /* wake up the device: */ 1314 /* wake up the device: */
1258 cec_write(priv, REG_CEC_ENAMODS, 1315 cec_write(priv, REG_CEC_ENAMODS,
@@ -1311,7 +1368,6 @@ static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv)
1311 1368
1312 /* init read EDID waitqueue and HDP work */ 1369 /* init read EDID waitqueue and HDP work */
1313 init_waitqueue_head(&priv->wq_edid); 1370 init_waitqueue_head(&priv->wq_edid);
1314 INIT_DELAYED_WORK(&priv->dwork, tda998x_hpd);
1315 1371
1316 /* clear pending interrupts */ 1372 /* clear pending interrupts */
1317 reg_read(priv, REG_INT_FLAGS_0); 1373 reg_read(priv, REG_INT_FLAGS_0);