diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index ea8e70e3976c..b917b9905bf1 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -200,6 +200,7 @@ struct dw_hdmi { const struct dw_hdmi_plat_data *plat_data; int vic; + int irq; u8 edid[HDMI_EDID_LEN]; @@ -2554,6 +2555,7 @@ __dw_hdmi_probe(struct platform_device *pdev, goto err_iahb; } + hdmi->irq = irq; ret = devm_request_threaded_irq(dev, irq, dw_hdmi_hardirq, dw_hdmi_irq, IRQF_SHARED, dev_name(dev), hdmi); @@ -2748,6 +2750,49 @@ void dw_hdmi_unbind(struct dw_hdmi *hdmi) } EXPORT_SYMBOL_GPL(dw_hdmi_unbind); +static void dw_hdmi_reg_initial(struct dw_hdmi *hdmi) +{ + if (hdmi_readb(hdmi, HDMI_IH_MUTE)) { + initialize_hdmi_ih_mutes(hdmi); + hdmi_writeb(hdmi, HDMI_PHY_I2CM_INT_ADDR_DONE_POL, + HDMI_PHY_I2CM_INT_ADDR); + + hdmi_writeb(hdmi, HDMI_PHY_I2CM_CTLINT_ADDR_NAC_POL | + HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL, + HDMI_PHY_I2CM_CTLINT_ADDR); + + hdmi_writeb(hdmi, HDMI_PHY_HPD | HDMI_PHY_RX_SENSE, + HDMI_PHY_POL0); + hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0); + hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD | + HDMI_IH_PHY_STAT0_RX_SENSE), + HDMI_IH_MUTE_PHY_STAT0); + } +} + +void dw_hdmi_suspend(struct device *dev) +{ + struct dw_hdmi *hdmi = dev_get_drvdata(dev); + + mutex_lock(&hdmi->mutex); + if (hdmi->irq) + disable_irq(hdmi->irq); + mutex_unlock(&hdmi->mutex); +} +EXPORT_SYMBOL_GPL(dw_hdmi_suspend); + +void dw_hdmi_resume(struct device *dev) +{ + struct dw_hdmi *hdmi = dev_get_drvdata(dev); + + mutex_lock(&hdmi->mutex); + dw_hdmi_reg_initial(hdmi); + if (hdmi->irq) + enable_irq(hdmi->irq); + mutex_unlock(&hdmi->mutex); +} +EXPORT_SYMBOL_GPL(dw_hdmi_resume); + MODULE_AUTHOR("Sascha Hauer "); MODULE_AUTHOR("Andy Yan "); MODULE_AUTHOR("Yakir Yang "); diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index 97228087224f..26ec8492ca0f 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -592,11 +592,31 @@ static int dw_hdmi_rockchip_remove(struct platform_device *pdev) return 0; } +static int dw_hdmi_rockchip_suspend(struct device *dev) +{ + dw_hdmi_suspend(dev); + + return 0; +} + +static int dw_hdmi_rockchip_resume(struct device *dev) +{ + dw_hdmi_resume(dev); + + return 0; +} + +static const struct dev_pm_ops dw_hdmi_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(dw_hdmi_rockchip_suspend, + dw_hdmi_rockchip_resume) +}; + struct platform_driver dw_hdmi_rockchip_pltfm_driver = { .probe = dw_hdmi_rockchip_probe, .remove = dw_hdmi_rockchip_remove, .driver = { .name = "dwhdmi-rockchip", .of_match_table = dw_hdmi_rockchip_dt_ids, + .pm = &dw_hdmi_pm_ops, }, }; diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h index 2855650778e8..96fe67b62d04 100644 --- a/include/drm/bridge/dw_hdmi.h +++ b/include/drm/bridge/dw_hdmi.h @@ -159,6 +159,8 @@ void dw_hdmi_unbind(struct dw_hdmi *hdmi); struct dw_hdmi *dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder, const struct dw_hdmi_plat_data *plat_data); +void dw_hdmi_suspend(struct device *dev); +void dw_hdmi_resume(struct device *dev); void dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense);