drm: bridge: dw-hdmi: optimize edid reading process

1.change SDA high level holding time to 3us.
2.when plug in,add timer to avoid unstable state.

Change-Id: Idc6faec710137ac9f8e589d75cbc1b85f7a45faf
Signed-off-by: Algea Cao <algea.cao@rock-chips.com>
This commit is contained in:
Algea Cao
2019-08-08 10:29:33 +08:00
committed by Tao Huang
parent 9a72f564de
commit feaeccc19d
2 changed files with 53 additions and 12 deletions

View File

@@ -227,6 +227,10 @@ struct dw_hdmi {
void __iomem *regs;
bool sink_is_hdmi;
bool sink_has_audio;
bool hpd_state;
struct delayed_work work;
struct workqueue_struct *workqueue;
struct mutex mutex; /* for state below and previous_mode */
enum drm_connector_force force; /* mutex-protected force state */
@@ -288,6 +292,49 @@ static void hdmi_mask_writeb(struct dw_hdmi *hdmi, u8 data, unsigned int reg,
hdmi_modb(hdmi, data << shift, mask, reg);
}
static void repo_hpd_event(struct work_struct *p_work)
{
struct dw_hdmi *hdmi = container_of(p_work, struct dw_hdmi, work.work);
if (hdmi->bridge.dev)
drm_helper_hpd_irq_event(hdmi->bridge.dev);
#ifdef CONFIG_SWITCH
if (hdmi->hpd_state)
switch_set_state(&hdmi->switchdev, 1);
else
switch_set_state(&hdmi->switchdev, 0);
#endif
}
static bool check_hdmi_irq(struct dw_hdmi *hdmi, int intr_stat,
int phy_int_pol)
{
int msecs;
/* To determine whether interrupt type is HPD */
if (!(intr_stat & HDMI_IH_PHY_STAT0_HPD))
return false;
if (phy_int_pol & HDMI_PHY_HPD) {
dev_dbg(hdmi->dev, "dw hdmi plug in\n");
msecs = 150;
hdmi->hpd_state = true;
} else {
dev_dbg(hdmi->dev, "dw hdmi plug out\n");
msecs = 20;
hdmi->hpd_state = false;
}
mod_delayed_work(hdmi->workqueue, &hdmi->work, msecs_to_jiffies(msecs));
return true;
}
static void init_hpd_work(struct dw_hdmi *hdmi)
{
hdmi->workqueue = create_workqueue("hpd_queue");
INIT_DELAYED_WORK(&hdmi->work, repo_hpd_event);
}
static void dw_hdmi_i2c_init(struct dw_hdmi *hdmi)
{
/* Software reset */
@@ -308,6 +355,9 @@ static void dw_hdmi_i2c_init(struct dw_hdmi *hdmi)
/* Mute DONE and ERROR interrupts */
hdmi_writeb(hdmi, HDMI_IH_I2CM_STAT0_ERROR | HDMI_IH_I2CM_STAT0_DONE,
HDMI_IH_MUTE_I2CM_STAT0);
/* set SDA high level holding time */
hdmi_writeb(hdmi, 0x48, HDMI_I2CM_SDA_HOLD);
}
static int dw_hdmi_i2c_read(struct dw_hdmi *hdmi,
@@ -2513,18 +2563,7 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
CEC_PHYS_ADDR_INVALID);
}
if (intr_stat & HDMI_IH_PHY_STAT0_HPD) {
dev_dbg(hdmi->dev, "EVENT=%s\n",
phy_int_pol & HDMI_PHY_HPD ? "plugin" : "plugout");
if (hdmi->bridge.dev)
drm_helper_hpd_irq_event(hdmi->bridge.dev);
#ifdef CONFIG_SWITCH
if (phy_int_pol & HDMI_PHY_HPD)
switch_set_state(&hdmi->switchdev, 1);
else
switch_set_state(&hdmi->switchdev, 0);
#endif
}
check_hdmi_irq(hdmi, intr_stat, phy_int_pol);
hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0);
hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE),
@@ -2957,6 +2996,7 @@ __dw_hdmi_probe(struct platform_device *pdev,
prod_id1 & HDMI_PRODUCT_ID1_HDCP ? "with" : "without",
hdmi->phy.name);
init_hpd_work(hdmi);
initialize_hdmi_ih_mutes(hdmi);
irq = platform_get_irq(pdev, 0);

View File

@@ -544,6 +544,7 @@
#define HDMI_I2CM_FS_SCL_HCNT_0_ADDR 0x7E10
#define HDMI_I2CM_FS_SCL_LCNT_1_ADDR 0x7E11
#define HDMI_I2CM_FS_SCL_LCNT_0_ADDR 0x7E12
#define HDMI_I2CM_SDA_HOLD 0x7E13
enum {
/* PRODUCT_ID0 field values */