drm/rockchip: dw_hdmi: Add delay to prevent HPD status misjudgments

Signed-off-by: Algea Cao <algea.cao@rock-chips.com>
Change-Id: Ibdd2395b4e33996c33bc7eb5134ba06d14f89466
This commit is contained in:
Algea Cao
2021-12-30 16:55:38 +08:00
committed by Tao Huang
parent 13dbe9c775
commit 0f6af0bdd7

View File

@@ -230,6 +230,9 @@ struct rockchip_hdmi {
struct next_hdr_sink_data next_hdr_data;
struct dw_hdmi_link_config link_cfg;
struct gpio_desc *enable_gpio;
struct delayed_work work;
struct workqueue_struct *workqueue;
};
#define to_rockchip_hdmi(x) container_of(x, struct rockchip_hdmi, x)
@@ -1204,6 +1207,18 @@ static int rockchip_hdmi_update_phy_table(struct rockchip_hdmi *hdmi,
return 0;
}
static void repo_hpd_event(struct work_struct *p_work)
{
struct rockchip_hdmi *hdmi = container_of(p_work, struct rockchip_hdmi, work.work);
bool change;
change = drm_helper_hpd_irq_event(hdmi->encoder.dev);
if (change) {
dev_dbg(hdmi->dev, "hpd stat changed:%d\n", hdmi->hpd_stat);
dw_hdmi_qp_cec_set_hpd(hdmi->hdmi_qp, hdmi->hpd_stat, change);
}
}
static irqreturn_t rockchip_hdmi_hardirq(int irq, void *dev_id)
{
struct rockchip_hdmi *hdmi = dev_id;
@@ -1231,6 +1246,7 @@ static irqreturn_t rockchip_hdmi_irq(int irq, void *dev_id)
{
struct rockchip_hdmi *hdmi = dev_id;
u32 intr_stat, val;
int msecs;
bool stat;
regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &intr_stat);
@@ -1256,13 +1272,14 @@ static irqreturn_t rockchip_hdmi_irq(int irq, void *dev_id)
regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
if (hdmi->hpd_stat != stat) {
bool change = false;
hdmi->hpd_stat = stat;
change = drm_helper_hpd_irq_event(hdmi->encoder.dev);
dw_hdmi_qp_cec_set_hpd(hdmi->hdmi_qp, stat, change);
if (stat) {
hdmi->hpd_stat = true;
msecs = 150;
} else {
hdmi->hpd_stat = false;
msecs = 20;
}
mod_delayed_work(hdmi->workqueue, &hdmi->work, msecs_to_jiffies(msecs));
if (!hdmi->id) {
val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_CLR,
@@ -1279,6 +1296,12 @@ static irqreturn_t rockchip_hdmi_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
static void init_hpd_work(struct rockchip_hdmi *hdmi)
{
hdmi->workqueue = create_workqueue("hpd_queue");
INIT_DELAYED_WORK(&hdmi->work, repo_hpd_event);
}
static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi)
{
int ret, val, phy_table_size;
@@ -2953,6 +2976,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
RK3588_HDMI1_GRANT_SEL);
regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON9, val);
}
init_hpd_work(hdmi);
}
ret = clk_prepare_enable(hdmi->phyref_clk);
@@ -3062,6 +3086,10 @@ static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
{
struct rockchip_hdmi *hdmi = dev_get_drvdata(dev);
cancel_delayed_work(&hdmi->work);
flush_workqueue(hdmi->workqueue);
destroy_workqueue(hdmi->workqueue);
if (hdmi->sub_dev.connector)
rockchip_drm_unregister_sub_dev(&hdmi->sub_dev);
@@ -3098,7 +3126,8 @@ static void dw_hdmi_rockchip_shutdown(struct platform_device *pdev)
if (!hdmi)
return;
cancel_delayed_work(&hdmi->work);
flush_workqueue(hdmi->workqueue);
dw_hdmi_suspend(hdmi->hdmi);
pm_runtime_put_sync(&pdev->dev);
}