diff mbox series

[v5,7/9] drm/bridge_connector: hook drm_atomic_helper_connector_hdmi_update_edid()

Message ID 20241201-drm-bridge-hdmi-connector-v5-7-b5316e82f61a@linaro.org
State New
Headers show
Series drm: add DRM HDMI Codec framework | expand

Commit Message

Dmitry Baryshkov Dec. 1, 2024, 12:44 a.m. UTC
Extend drm_bridge_connector code to read the EDID and use it to update
connector status if the bridge chain implements HDMI bridge. Performing
it from the generic location minimizes individual bridge's code and
enforces standard behaviour from all corresponding drivers.

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
 drivers/gpu/drm/display/drm_bridge_connector.c | 67 ++++++++++++++++++++------
 1 file changed, 53 insertions(+), 14 deletions(-)

Comments

Jani Nikula Dec. 3, 2024, 2:25 p.m. UTC | #1
On Sun, 01 Dec 2024, Dmitry Baryshkov <dmitry.baryshkov@linaro.org> wrote:
> Extend drm_bridge_connector code to read the EDID and use it to update
> connector status if the bridge chain implements HDMI bridge. Performing
> it from the generic location minimizes individual bridge's code and
> enforces standard behaviour from all corresponding drivers.
>
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> ---
>  drivers/gpu/drm/display/drm_bridge_connector.c | 67 ++++++++++++++++++++------
>  1 file changed, 53 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
> index 12ab9f14cc8a8672478ae2804c9a68d766d88ea5..71ae3b2c9049016d1cc0d39a787f6461633efd53 100644
> --- a/drivers/gpu/drm/display/drm_bridge_connector.c
> +++ b/drivers/gpu/drm/display/drm_bridge_connector.c
> @@ -17,6 +17,7 @@
>  #include <drm/drm_edid.h>
>  #include <drm/drm_managed.h>
>  #include <drm/drm_modeset_helper_vtables.h>
> +#include <drm/drm_print.h>
>  #include <drm/drm_probe_helper.h>
>  #include <drm/display/drm_hdmi_state_helper.h>
>  
> @@ -175,17 +176,55 @@ static void drm_bridge_connector_disable_hpd(struct drm_connector *connector)
>   * Bridge Connector Functions
>   */
>  
> +static const struct drm_edid *
> +drm_bridge_connector_read_edid(struct drm_connector *connector,
> +			       enum drm_connector_status status)
> +{
> +	struct drm_bridge_connector *bridge_connector =
> +		to_drm_bridge_connector(connector);
> +	const struct drm_edid *drm_edid;
> +	struct drm_bridge *bridge;
> +
> +	bridge = bridge_connector->bridge_edid;
> +	if (!bridge)
> +		return NULL;
> +
> +	if (status != connector_status_connected)
> +		return NULL;
> +
> +	drm_edid = drm_bridge_edid_read(bridge, connector);
> +	if (!drm_edid_valid(drm_edid)) {

What's the case this check is for?

My preference would be that bridge->funcs->edid_read() uses
drm_edid_read*() family of functions that do the checks and return the
EDID.

There are some cases that just allocate a blob and return it. Would be
nice if they could be converted, but in the mean time could use
drm_edid_valid() right there. Additional validity checks are redundant.

BR,
Jani.


> +		drm_edid_free(drm_edid);
> +		return NULL;
> +	}
> +
> +	return drm_edid;
> +}
> +
>  static enum drm_connector_status
>  drm_bridge_connector_detect(struct drm_connector *connector, bool force)
>  {
>  	struct drm_bridge_connector *bridge_connector =
>  		to_drm_bridge_connector(connector);
>  	struct drm_bridge *detect = bridge_connector->bridge_detect;
> +	struct drm_bridge *hdmi = bridge_connector->bridge_hdmi;
>  	enum drm_connector_status status;
>  
>  	if (detect) {
>  		status = detect->funcs->detect(detect);
>  
> +		if (hdmi) {
> +			const struct drm_edid *drm_edid;
> +			int ret;
> +
> +			drm_edid = drm_bridge_connector_read_edid(connector, status);
> +			ret = drm_atomic_helper_connector_hdmi_update_edid(connector, drm_edid);
> +			if (ret)
> +				drm_warn(connector->dev, "updating EDID failed with %d\n", ret);
> +
> +			drm_edid_free(drm_edid);
> +		}
> +
>  		drm_bridge_connector_hpd_notify(connector, status);
>  	} else {
>  		switch (connector->connector_type) {
> @@ -246,29 +285,29 @@ static const struct drm_connector_funcs drm_bridge_connector_funcs = {
>  static int drm_bridge_connector_get_modes_edid(struct drm_connector *connector,
>  					       struct drm_bridge *bridge)
>  {
> +	struct drm_bridge_connector *bridge_connector =
> +		to_drm_bridge_connector(connector);
> +	struct drm_bridge *hdmi = bridge_connector->bridge_hdmi;
>  	enum drm_connector_status status;
>  	const struct drm_edid *drm_edid;
> -	int n;
>  
>  	status = drm_bridge_connector_detect(connector, false);
>  	if (status != connector_status_connected)
> -		goto no_edid;
> +		return 0;
>  
> -	drm_edid = drm_bridge_edid_read(bridge, connector);
> -	if (!drm_edid_valid(drm_edid)) {
> +	/* In HDMI setup the EDID has been read and handled as a part of .detect() */
> +	if (!hdmi) {
> +		drm_edid = drm_bridge_connector_read_edid(connector, status);
> +		if (!drm_edid) {
> +			drm_edid_connector_update(connector, NULL);
> +			return 0;
> +		}
> +
> +		drm_edid_connector_update(connector, drm_edid);
>  		drm_edid_free(drm_edid);
> -		goto no_edid;
>  	}
>  
> -	drm_edid_connector_update(connector, drm_edid);
> -	n = drm_edid_connector_add_modes(connector);
> -
> -	drm_edid_free(drm_edid);
> -	return n;
> -
> -no_edid:
> -	drm_edid_connector_update(connector, NULL);
> -	return 0;
> +	return drm_edid_connector_add_modes(connector);
>  }
>  
>  static int drm_bridge_connector_get_modes(struct drm_connector *connector)
diff mbox series

Patch

diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index 12ab9f14cc8a8672478ae2804c9a68d766d88ea5..71ae3b2c9049016d1cc0d39a787f6461633efd53 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -17,6 +17,7 @@ 
 #include <drm/drm_edid.h>
 #include <drm/drm_managed.h>
 #include <drm/drm_modeset_helper_vtables.h>
+#include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
 #include <drm/display/drm_hdmi_state_helper.h>
 
@@ -175,17 +176,55 @@  static void drm_bridge_connector_disable_hpd(struct drm_connector *connector)
  * Bridge Connector Functions
  */
 
+static const struct drm_edid *
+drm_bridge_connector_read_edid(struct drm_connector *connector,
+			       enum drm_connector_status status)
+{
+	struct drm_bridge_connector *bridge_connector =
+		to_drm_bridge_connector(connector);
+	const struct drm_edid *drm_edid;
+	struct drm_bridge *bridge;
+
+	bridge = bridge_connector->bridge_edid;
+	if (!bridge)
+		return NULL;
+
+	if (status != connector_status_connected)
+		return NULL;
+
+	drm_edid = drm_bridge_edid_read(bridge, connector);
+	if (!drm_edid_valid(drm_edid)) {
+		drm_edid_free(drm_edid);
+		return NULL;
+	}
+
+	return drm_edid;
+}
+
 static enum drm_connector_status
 drm_bridge_connector_detect(struct drm_connector *connector, bool force)
 {
 	struct drm_bridge_connector *bridge_connector =
 		to_drm_bridge_connector(connector);
 	struct drm_bridge *detect = bridge_connector->bridge_detect;
+	struct drm_bridge *hdmi = bridge_connector->bridge_hdmi;
 	enum drm_connector_status status;
 
 	if (detect) {
 		status = detect->funcs->detect(detect);
 
+		if (hdmi) {
+			const struct drm_edid *drm_edid;
+			int ret;
+
+			drm_edid = drm_bridge_connector_read_edid(connector, status);
+			ret = drm_atomic_helper_connector_hdmi_update_edid(connector, drm_edid);
+			if (ret)
+				drm_warn(connector->dev, "updating EDID failed with %d\n", ret);
+
+			drm_edid_free(drm_edid);
+		}
+
 		drm_bridge_connector_hpd_notify(connector, status);
 	} else {
 		switch (connector->connector_type) {
@@ -246,29 +285,29 @@  static const struct drm_connector_funcs drm_bridge_connector_funcs = {
 static int drm_bridge_connector_get_modes_edid(struct drm_connector *connector,
 					       struct drm_bridge *bridge)
 {
+	struct drm_bridge_connector *bridge_connector =
+		to_drm_bridge_connector(connector);
+	struct drm_bridge *hdmi = bridge_connector->bridge_hdmi;
 	enum drm_connector_status status;
 	const struct drm_edid *drm_edid;
-	int n;
 
 	status = drm_bridge_connector_detect(connector, false);
 	if (status != connector_status_connected)
-		goto no_edid;
+		return 0;
 
-	drm_edid = drm_bridge_edid_read(bridge, connector);
-	if (!drm_edid_valid(drm_edid)) {
+	/* In HDMI setup the EDID has been read and handled as a part of .detect() */
+	if (!hdmi) {
+		drm_edid = drm_bridge_connector_read_edid(connector, status);
+		if (!drm_edid) {
+			drm_edid_connector_update(connector, NULL);
+			return 0;
+		}
+
+		drm_edid_connector_update(connector, drm_edid);
 		drm_edid_free(drm_edid);
-		goto no_edid;
 	}
 
-	drm_edid_connector_update(connector, drm_edid);
-	n = drm_edid_connector_add_modes(connector);
-
-	drm_edid_free(drm_edid);
-	return n;
-
-no_edid:
-	drm_edid_connector_update(connector, NULL);
-	return 0;
+	return drm_edid_connector_add_modes(connector);
 }
 
 static int drm_bridge_connector_get_modes(struct drm_connector *connector)