build/patch/kernel/archive/sunxi-6.2/patches.megous/drm-bridge-dw-hdmi-Allow-to-accept-HPD-status-from-other-driver.patch

154 lines
4.6 KiB
Diff

From 8c2f9f153942c6640a983565416b7be7ac74151b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Jirman?= <megi@xff.cz>
Date: Tue, 26 Oct 2021 01:27:34 +0200
Subject: [PATCH 213/391] drm: bridge: dw-hdmi: Allow to accept HPD status from
other drivers
This change allows other drivers to provide HPD status.
Signed-off-by: Ondrej Jirman <megi@xff.cz>
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 63 +++++++++++++++++++++--
1 file changed, 59 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index aa51c61a7..a503a8333 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -9,6 +9,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
+#include <linux/extcon.h>
#include <linux/hdmi.h>
#include <linux/i2c.h>
#include <linux/irq.h>
@@ -211,6 +212,8 @@ struct dw_hdmi {
hdmi_codec_plugged_cb plugged_cb;
struct device *codec_dev;
enum drm_connector_status last_connector_result;
+ struct extcon_dev *extcon;
+ struct notifier_block extcon_nb;
};
#define HDMI_IH_PHY_STAT0_RX_SENSE \
@@ -1703,6 +1706,12 @@ static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi, void *data)
enum drm_connector_status dw_hdmi_phy_read_hpd(struct dw_hdmi *hdmi,
void *data)
{
+ if (hdmi->extcon) {
+ return extcon_get_state(hdmi->extcon, EXTCON_DISP_HDMI) > 0
+ ? connector_status_connected
+ : connector_status_disconnected;
+ }
+
return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ?
connector_status_connected : connector_status_disconnected;
}
@@ -1713,7 +1722,7 @@ void dw_hdmi_phy_update_hpd(struct dw_hdmi *hdmi, void *data,
{
u8 old_mask = hdmi->phy_mask;
- if (force || disabled || !rxsense)
+ if (force || disabled || !rxsense || hdmi->extcon)
hdmi->phy_mask |= HDMI_PHY_RX_SENSE;
else
hdmi->phy_mask &= ~HDMI_PHY_RX_SENSE;
@@ -3143,7 +3152,7 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
status = connector_status_disconnected;
}
- if (status != connector_status_unknown) {
+ if (status != connector_status_unknown && !hdmi->extcon) {
dev_dbg(hdmi->dev, "EVENT=%s\n",
status == connector_status_connected ?
"plugin" : "plugout");
@@ -3346,6 +3355,25 @@ static int dw_hdmi_parse_dt(struct dw_hdmi *hdmi)
return 0;
}
+static int dw_hdmi_extcon_notifier(struct notifier_block *nb,
+ unsigned long event, void *ptr)
+{
+ struct dw_hdmi *hdmi = container_of(nb, struct dw_hdmi, extcon_nb);
+
+ enum drm_connector_status status = dw_hdmi_phy_read_hpd(hdmi, NULL);
+
+ dev_info(hdmi->dev, "EVENT=%s\n",
+ status == connector_status_connected ? "plugin" : "plugout");
+
+ if (hdmi->bridge.dev) {
+ //XXX: ???
+ drm_helper_hpd_irq_event(hdmi->bridge.dev);
+ drm_bridge_hpd_notify(&hdmi->bridge, status);
+ }
+
+ return NOTIFY_DONE;
+}
+
struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev,
const struct dw_hdmi_plat_data *plat_data)
{
@@ -3387,15 +3415,38 @@ struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev,
if (ret < 0)
return ERR_PTR(ret);
+ hdmi->extcon = extcon_get_edev_by_phandle(dev, 0);
+ if (IS_ERR(hdmi->extcon)) {
+ if (PTR_ERR(hdmi->extcon) == -ENODEV) {
+ hdmi->extcon = NULL;
+ } else {
+ if (PTR_ERR(hdmi->extcon) != -EPROBE_DEFER)
+ dev_err(dev, "Invalid or missing extcon\n");
+ return ERR_CAST(hdmi->extcon);
+ }
+ }
+
+ if (hdmi->extcon) {
+ /* don't register IRQ for native HPD */
+ hdmi->phy_mask = (u8)~(HDMI_PHY_RX_SENSE);
+
+ hdmi->extcon_nb.notifier_call = dw_hdmi_extcon_notifier;
+ ret = extcon_register_notifier_all(hdmi->extcon, &hdmi->extcon_nb);
+ if (ret < 0) {
+ dev_err(dev, "failed to register extcon notifier\n");
+ return ERR_PTR(ret);
+ }
+ }
+
ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
if (ddc_node) {
hdmi->ddc = of_get_i2c_adapter_by_node(ddc_node);
of_node_put(ddc_node);
if (!hdmi->ddc) {
dev_dbg(hdmi->dev, "failed to read ddc node\n");
- return ERR_PTR(-EPROBE_DEFER);
+ ret = -EPROBE_DEFER;
+ goto err_extcon;
}
-
} else {
dev_dbg(hdmi->dev, "no ddc property found\n");
}
@@ -3639,6 +3690,8 @@ struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev,
clk_disable_unprepare(hdmi->isfr_clk);
err_res:
i2c_put_adapter(hdmi->ddc);
+err_extcon:
+ extcon_unregister_notifier_all(hdmi->extcon, &hdmi->extcon_nb);
return ERR_PTR(ret);
}
@@ -3646,6 +3699,8 @@ EXPORT_SYMBOL_GPL(dw_hdmi_probe);
void dw_hdmi_remove(struct dw_hdmi *hdmi)
{
+ extcon_unregister_notifier_all(hdmi->extcon, &hdmi->extcon_nb);
+
drm_bridge_remove(&hdmi->bridge);
if (hdmi->audio && !IS_ERR(hdmi->audio))
--
2.35.3