mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 03:40:35 +09:00
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:
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user