All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] drm: Update edid-derived drm_display_info fields at edid property set
@ 2017-12-08  0:42 ` Keith Packard
  0 siblings, 0 replies; 10+ messages in thread
From: Keith Packard @ 2017-12-08  0:42 UTC (permalink / raw)
  To: linux-kernel, Dave Airlie, Daniel Vetter; +Cc: Keith Packard, dri-devel

There are a set of values in the drm_display_info structure for each
connector which hold information derived from EDID. These are computed
in drm_add_display_info. Before this patch, that was only called in
drm_add_edid_modes. This meant that they were only set when EDID was
present and never reset when EDID was not, as happened when the
display was disconnected.

One of these fields, non_desktop, is used from
drm_mode_connector_update_edid_property, the function responsible for
assigning the new edid value to the application-visible property.

Various drivers call these two functions (drm_add_edid_modes and
drm_mode_connector_update_edid_property) in different orders. This
means that even when EDID is present, the drm_display_info fields may
not have been computed at the time that
drm_mode_connector_update_edid_property used the non_desktop value to
set the non_desktop property.

I've added a public function (drm_reset_display_info) that resets the
drm_display_info field values to default values and then made the
drm_add_display_info function public. These two functions are now
called directly from drm_mode_connector_update_edid_property so that
the drm_display_info fields are always computed from the current EDID
information before being used in that function.

This means that the drm_display_info values are often computed twice,
once when the EDID property it set and a second time when EDID is used
to compute modes for the device. The alternative would be to uniformly
ensure that the values were computed once before being used, which
would require that all drivers reliably invoke the two paths in the
same order. The computation is inexpensive enough that it seems more
maintainable in the long term to simply compute them in both paths.

The API to drm_add_display_info has been changed so that it no longer
takes the set of edid-based quirks as a parameter. Rather, it now
computes those quirks itself and returns them for further use by
drm_add_edid_modes.

This patch also includes a number of 'const' additions caused by
drm_mode_connector_update_edid_property taking a 'const struct edid *'
parameter and wanting to pass that along to drm_add_display_info.

Signed-off-by: Keith Packard <keithp@keithp.com>
---
 drivers/gpu/drm/drm_connector.c | 13 ++++++++++
 drivers/gpu/drm/drm_edid.c      | 53 ++++++++++++++++++++++++++++++-----------
 include/drm/drm_edid.h          |  2 ++
 3 files changed, 54 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 25f4b2e9a44f..83c01f359d55 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -1207,6 +1207,19 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector,
 	if (edid)
 		size = EDID_LENGTH * (1 + edid->extensions);
 
+	/* Set the display info, using edid if available, otherwise
+	 * reseting the values to defaults. This duplicates the work
+	 * done in drm_add_edid_modes, but that function is not
+	 * consistently called before this one in all drivers and the
+	 * computation is cheap enough that it seems better to
+	 * duplicate it rather than attempt to ensure some arbitrary
+	 * ordering of calls.
+	 */
+	if (edid)
+		drm_add_display_info(connector, edid);
+	else
+		drm_reset_display_info(connector);
+
 	drm_object_property_set_value(&connector->base,
 				      dev->mode_config.non_desktop_property,
 				      connector->display_info.non_desktop);
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 524eace3d460..365901c1c33c 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -1731,7 +1731,7 @@ EXPORT_SYMBOL(drm_edid_duplicate);
  *
  * Returns true if @vendor is in @edid, false otherwise
  */
-static bool edid_vendor(struct edid *edid, const char *vendor)
+static bool edid_vendor(const struct edid *edid, const char *vendor)
 {
 	char edid_vendor[3];
 
@@ -1749,7 +1749,7 @@ static bool edid_vendor(struct edid *edid, const char *vendor)
  *
  * This tells subsequent routines what fixes they need to apply.
  */
-static u32 edid_get_quirks(struct edid *edid)
+static u32 edid_get_quirks(const struct edid *edid)
 {
 	const struct edid_quirk *quirk;
 	int i;
@@ -2813,7 +2813,7 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid,
 /*
  * Search EDID for CEA extension block.
  */
-static u8 *drm_find_edid_extension(struct edid *edid, int ext_id)
+static u8 *drm_find_edid_extension(const struct edid *edid, int ext_id)
 {
 	u8 *edid_ext = NULL;
 	int i;
@@ -2835,12 +2835,12 @@ static u8 *drm_find_edid_extension(struct edid *edid, int ext_id)
 	return edid_ext;
 }
 
-static u8 *drm_find_cea_extension(struct edid *edid)
+static u8 *drm_find_cea_extension(const struct edid *edid)
 {
 	return drm_find_edid_extension(edid, CEA_EXT);
 }
 
-static u8 *drm_find_displayid_extension(struct edid *edid)
+static u8 *drm_find_displayid_extension(const struct edid *edid)
 {
 	return drm_find_edid_extension(edid, DISPLAYID_EXT);
 }
@@ -4378,7 +4378,7 @@ drm_parse_hdmi_vsdb_video(struct drm_connector *connector, const u8 *db)
 }
 
 static void drm_parse_cea_ext(struct drm_connector *connector,
-			      struct edid *edid)
+			      const struct edid *edid)
 {
 	struct drm_display_info *info = &connector->display_info;
 	const u8 *edid_ext;
@@ -4412,11 +4412,34 @@ static void drm_parse_cea_ext(struct drm_connector *connector,
 	}
 }
 
-static void drm_add_display_info(struct drm_connector *connector,
-				 struct edid *edid, u32 quirks)
+/* A connector has no EDID information, so we've got no EDID to compute quirks from. Reset
+ * all of the values which would have been set from EDID
+ */
+void
+drm_reset_display_info(struct drm_connector *connector)
+{
+	struct drm_display_info *info = &connector->display_info;
+
+	info->width_mm = 0;
+	info->height_mm = 0;
+
+	info->bpc = 0;
+	info->color_formats = 0;
+	info->cea_rev = 0;
+	info->max_tmds_clock = 0;
+	info->dvi_dual = false;
+	info->has_hdmi_infoframe = false;
+
+	info->non_desktop = 0;
+}
+EXPORT_SYMBOL_GPL(drm_reset_display_info);
+
+u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edid)
 {
 	struct drm_display_info *info = &connector->display_info;
 
+	u32 quirks = edid_get_quirks(edid);
+
 	info->width_mm = edid->width_cm * 10;
 	info->height_mm = edid->height_cm * 10;
 
@@ -4430,11 +4453,13 @@ static void drm_add_display_info(struct drm_connector *connector,
 
 	info->non_desktop = !!(quirks & EDID_QUIRK_NON_DESKTOP);
 
+	DRM_DEBUG_KMS("non_desktop set to %d\n", info->non_desktop);
+
 	if (edid->revision < 3)
-		return;
+		return quirks;
 
 	if (!(edid->input & DRM_EDID_INPUT_DIGITAL))
-		return;
+		return quirks;
 
 	drm_parse_cea_ext(connector, edid);
 
@@ -4454,7 +4479,7 @@ static void drm_add_display_info(struct drm_connector *connector,
 
 	/* Only defined for 1.4 with digital displays */
 	if (edid->revision < 4)
-		return;
+		return quirks;
 
 	switch (edid->input & DRM_EDID_DIGITAL_DEPTH_MASK) {
 	case DRM_EDID_DIGITAL_DEPTH_6:
@@ -4489,7 +4514,9 @@ static void drm_add_display_info(struct drm_connector *connector,
 		info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
 	if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB422)
 		info->color_formats |= DRM_COLOR_FORMAT_YCRCB422;
+	return quirks;
 }
+EXPORT_SYMBOL_GPL(drm_add_display_info);
 
 static int validate_displayid(u8 *displayid, int length, int idx)
 {
@@ -4645,8 +4672,6 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
 		return 0;
 	}
 
-	quirks = edid_get_quirks(edid);
-
 	drm_edid_to_eld(connector, edid);
 
 	/*
@@ -4654,7 +4679,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
 	 * To avoid multiple parsing of same block, lets parse that map
 	 * from sink info, before parsing CEA modes.
 	 */
-	drm_add_display_info(connector, edid, quirks);
+	quirks = drm_add_display_info(connector, edid);
 
 	/*
 	 * EDID spec says modes should be preferred in this order:
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
index b25d12ef120a..8d89a9c3748d 100644
--- a/include/drm/drm_edid.h
+++ b/include/drm/drm_edid.h
@@ -465,6 +465,8 @@ struct edid *drm_get_edid(struct drm_connector *connector,
 struct edid *drm_get_edid_switcheroo(struct drm_connector *connector,
 				     struct i2c_adapter *adapter);
 struct edid *drm_edid_duplicate(const struct edid *edid);
+void drm_reset_display_info(struct drm_connector *connector);
+u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edid);
 int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid);
 
 u8 drm_match_cea_mode(const struct drm_display_mode *to_match);
-- 
2.15.0.rc0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH] drm: Update edid-derived drm_display_info fields at edid property set
@ 2017-12-08  0:42 ` Keith Packard
  0 siblings, 0 replies; 10+ messages in thread
From: Keith Packard @ 2017-12-08  0:42 UTC (permalink / raw)
  To: linux-kernel, Dave Airlie, Daniel Vetter; +Cc: Keith Packard, dri-devel

There are a set of values in the drm_display_info structure for each
connector which hold information derived from EDID. These are computed
in drm_add_display_info. Before this patch, that was only called in
drm_add_edid_modes. This meant that they were only set when EDID was
present and never reset when EDID was not, as happened when the
display was disconnected.

One of these fields, non_desktop, is used from
drm_mode_connector_update_edid_property, the function responsible for
assigning the new edid value to the application-visible property.

Various drivers call these two functions (drm_add_edid_modes and
drm_mode_connector_update_edid_property) in different orders. This
means that even when EDID is present, the drm_display_info fields may
not have been computed at the time that
drm_mode_connector_update_edid_property used the non_desktop value to
set the non_desktop property.

I've added a public function (drm_reset_display_info) that resets the
drm_display_info field values to default values and then made the
drm_add_display_info function public. These two functions are now
called directly from drm_mode_connector_update_edid_property so that
the drm_display_info fields are always computed from the current EDID
information before being used in that function.

This means that the drm_display_info values are often computed twice,
once when the EDID property it set and a second time when EDID is used
to compute modes for the device. The alternative would be to uniformly
ensure that the values were computed once before being used, which
would require that all drivers reliably invoke the two paths in the
same order. The computation is inexpensive enough that it seems more
maintainable in the long term to simply compute them in both paths.

The API to drm_add_display_info has been changed so that it no longer
takes the set of edid-based quirks as a parameter. Rather, it now
computes those quirks itself and returns them for further use by
drm_add_edid_modes.

This patch also includes a number of 'const' additions caused by
drm_mode_connector_update_edid_property taking a 'const struct edid *'
parameter and wanting to pass that along to drm_add_display_info.

Signed-off-by: Keith Packard <keithp@keithp.com>
---
 drivers/gpu/drm/drm_connector.c | 13 ++++++++++
 drivers/gpu/drm/drm_edid.c      | 53 ++++++++++++++++++++++++++++++-----------
 include/drm/drm_edid.h          |  2 ++
 3 files changed, 54 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 25f4b2e9a44f..83c01f359d55 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -1207,6 +1207,19 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector,
 	if (edid)
 		size = EDID_LENGTH * (1 + edid->extensions);
 
+	/* Set the display info, using edid if available, otherwise
+	 * reseting the values to defaults. This duplicates the work
+	 * done in drm_add_edid_modes, but that function is not
+	 * consistently called before this one in all drivers and the
+	 * computation is cheap enough that it seems better to
+	 * duplicate it rather than attempt to ensure some arbitrary
+	 * ordering of calls.
+	 */
+	if (edid)
+		drm_add_display_info(connector, edid);
+	else
+		drm_reset_display_info(connector);
+
 	drm_object_property_set_value(&connector->base,
 				      dev->mode_config.non_desktop_property,
 				      connector->display_info.non_desktop);
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 524eace3d460..365901c1c33c 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -1731,7 +1731,7 @@ EXPORT_SYMBOL(drm_edid_duplicate);
  *
  * Returns true if @vendor is in @edid, false otherwise
  */
-static bool edid_vendor(struct edid *edid, const char *vendor)
+static bool edid_vendor(const struct edid *edid, const char *vendor)
 {
 	char edid_vendor[3];
 
@@ -1749,7 +1749,7 @@ static bool edid_vendor(struct edid *edid, const char *vendor)
  *
  * This tells subsequent routines what fixes they need to apply.
  */
-static u32 edid_get_quirks(struct edid *edid)
+static u32 edid_get_quirks(const struct edid *edid)
 {
 	const struct edid_quirk *quirk;
 	int i;
@@ -2813,7 +2813,7 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid,
 /*
  * Search EDID for CEA extension block.
  */
-static u8 *drm_find_edid_extension(struct edid *edid, int ext_id)
+static u8 *drm_find_edid_extension(const struct edid *edid, int ext_id)
 {
 	u8 *edid_ext = NULL;
 	int i;
@@ -2835,12 +2835,12 @@ static u8 *drm_find_edid_extension(struct edid *edid, int ext_id)
 	return edid_ext;
 }
 
-static u8 *drm_find_cea_extension(struct edid *edid)
+static u8 *drm_find_cea_extension(const struct edid *edid)
 {
 	return drm_find_edid_extension(edid, CEA_EXT);
 }
 
-static u8 *drm_find_displayid_extension(struct edid *edid)
+static u8 *drm_find_displayid_extension(const struct edid *edid)
 {
 	return drm_find_edid_extension(edid, DISPLAYID_EXT);
 }
@@ -4378,7 +4378,7 @@ drm_parse_hdmi_vsdb_video(struct drm_connector *connector, const u8 *db)
 }
 
 static void drm_parse_cea_ext(struct drm_connector *connector,
-			      struct edid *edid)
+			      const struct edid *edid)
 {
 	struct drm_display_info *info = &connector->display_info;
 	const u8 *edid_ext;
@@ -4412,11 +4412,34 @@ static void drm_parse_cea_ext(struct drm_connector *connector,
 	}
 }
 
-static void drm_add_display_info(struct drm_connector *connector,
-				 struct edid *edid, u32 quirks)
+/* A connector has no EDID information, so we've got no EDID to compute quirks from. Reset
+ * all of the values which would have been set from EDID
+ */
+void
+drm_reset_display_info(struct drm_connector *connector)
+{
+	struct drm_display_info *info = &connector->display_info;
+
+	info->width_mm = 0;
+	info->height_mm = 0;
+
+	info->bpc = 0;
+	info->color_formats = 0;
+	info->cea_rev = 0;
+	info->max_tmds_clock = 0;
+	info->dvi_dual = false;
+	info->has_hdmi_infoframe = false;
+
+	info->non_desktop = 0;
+}
+EXPORT_SYMBOL_GPL(drm_reset_display_info);
+
+u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edid)
 {
 	struct drm_display_info *info = &connector->display_info;
 
+	u32 quirks = edid_get_quirks(edid);
+
 	info->width_mm = edid->width_cm * 10;
 	info->height_mm = edid->height_cm * 10;
 
@@ -4430,11 +4453,13 @@ static void drm_add_display_info(struct drm_connector *connector,
 
 	info->non_desktop = !!(quirks & EDID_QUIRK_NON_DESKTOP);
 
+	DRM_DEBUG_KMS("non_desktop set to %d\n", info->non_desktop);
+
 	if (edid->revision < 3)
-		return;
+		return quirks;
 
 	if (!(edid->input & DRM_EDID_INPUT_DIGITAL))
-		return;
+		return quirks;
 
 	drm_parse_cea_ext(connector, edid);
 
@@ -4454,7 +4479,7 @@ static void drm_add_display_info(struct drm_connector *connector,
 
 	/* Only defined for 1.4 with digital displays */
 	if (edid->revision < 4)
-		return;
+		return quirks;
 
 	switch (edid->input & DRM_EDID_DIGITAL_DEPTH_MASK) {
 	case DRM_EDID_DIGITAL_DEPTH_6:
@@ -4489,7 +4514,9 @@ static void drm_add_display_info(struct drm_connector *connector,
 		info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
 	if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB422)
 		info->color_formats |= DRM_COLOR_FORMAT_YCRCB422;
+	return quirks;
 }
+EXPORT_SYMBOL_GPL(drm_add_display_info);
 
 static int validate_displayid(u8 *displayid, int length, int idx)
 {
@@ -4645,8 +4672,6 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
 		return 0;
 	}
 
-	quirks = edid_get_quirks(edid);
-
 	drm_edid_to_eld(connector, edid);
 
 	/*
@@ -4654,7 +4679,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
 	 * To avoid multiple parsing of same block, lets parse that map
 	 * from sink info, before parsing CEA modes.
 	 */
-	drm_add_display_info(connector, edid, quirks);
+	quirks = drm_add_display_info(connector, edid);
 
 	/*
 	 * EDID spec says modes should be preferred in this order:
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
index b25d12ef120a..8d89a9c3748d 100644
--- a/include/drm/drm_edid.h
+++ b/include/drm/drm_edid.h
@@ -465,6 +465,8 @@ struct edid *drm_get_edid(struct drm_connector *connector,
 struct edid *drm_get_edid_switcheroo(struct drm_connector *connector,
 				     struct i2c_adapter *adapter);
 struct edid *drm_edid_duplicate(const struct edid *edid);
+void drm_reset_display_info(struct drm_connector *connector);
+u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edid);
 int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid);
 
 u8 drm_match_cea_mode(const struct drm_display_mode *to_match);
-- 
2.15.0.rc0

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH] drm: Update edid-derived drm_display_info fields at edid property set
  2017-12-08  0:42 ` Keith Packard
@ 2017-12-11 10:19   ` Daniel Vetter
  -1 siblings, 0 replies; 10+ messages in thread
From: Daniel Vetter @ 2017-12-11 10:19 UTC (permalink / raw)
  To: Keith Packard; +Cc: linux-kernel, Dave Airlie, Daniel Vetter, dri-devel

On Thu, Dec 07, 2017 at 04:42:57PM -0800, Keith Packard wrote:
> There are a set of values in the drm_display_info structure for each
> connector which hold information derived from EDID. These are computed
> in drm_add_display_info. Before this patch, that was only called in
> drm_add_edid_modes. This meant that they were only set when EDID was
> present and never reset when EDID was not, as happened when the
> display was disconnected.
> 
> One of these fields, non_desktop, is used from
> drm_mode_connector_update_edid_property, the function responsible for
> assigning the new edid value to the application-visible property.
> 
> Various drivers call these two functions (drm_add_edid_modes and
> drm_mode_connector_update_edid_property) in different orders. This
> means that even when EDID is present, the drm_display_info fields may
> not have been computed at the time that
> drm_mode_connector_update_edid_property used the non_desktop value to
> set the non_desktop property.
> 
> I've added a public function (drm_reset_display_info) that resets the
> drm_display_info field values to default values and then made the
> drm_add_display_info function public. These two functions are now
> called directly from drm_mode_connector_update_edid_property so that
> the drm_display_info fields are always computed from the current EDID
> information before being used in that function.
> 
> This means that the drm_display_info values are often computed twice,
> once when the EDID property it set and a second time when EDID is used
> to compute modes for the device. The alternative would be to uniformly
> ensure that the values were computed once before being used, which
> would require that all drivers reliably invoke the two paths in the
> same order. The computation is inexpensive enough that it seems more
> maintainable in the long term to simply compute them in both paths.
> 
> The API to drm_add_display_info has been changed so that it no longer
> takes the set of edid-based quirks as a parameter. Rather, it now
> computes those quirks itself and returns them for further use by
> drm_add_edid_modes.
> 
> This patch also includes a number of 'const' additions caused by
> drm_mode_connector_update_edid_property taking a 'const struct edid *'
> parameter and wanting to pass that along to drm_add_display_info.
> 
> Signed-off-by: Keith Packard <keithp@keithp.com>

Yeah looks like a good way to reset the desktop-mode in all cases.

> ---
>  drivers/gpu/drm/drm_connector.c | 13 ++++++++++
>  drivers/gpu/drm/drm_edid.c      | 53 ++++++++++++++++++++++++++++++-----------
>  include/drm/drm_edid.h          |  2 ++
>  3 files changed, 54 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
> index 25f4b2e9a44f..83c01f359d55 100644
> --- a/drivers/gpu/drm/drm_connector.c
> +++ b/drivers/gpu/drm/drm_connector.c
> @@ -1207,6 +1207,19 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector,
>  	if (edid)
>  		size = EDID_LENGTH * (1 + edid->extensions);
>  
> +	/* Set the display info, using edid if available, otherwise
> +	 * reseting the values to defaults. This duplicates the work
> +	 * done in drm_add_edid_modes, but that function is not
> +	 * consistently called before this one in all drivers and the
> +	 * computation is cheap enough that it seems better to
> +	 * duplicate it rather than attempt to ensure some arbitrary
> +	 * ordering of calls.
> +	 */

Looks like the most reasonable fix for -rc. For the future, maybe capture
a FIXME/TODO in this comment that we should look into merging
drm_add_edid_modes() and drm_mode_connector_update_edid_property(). I
really can't think of a good reason for that split.

> +	if (edid)
> +		drm_add_display_info(connector, edid);
> +	else
> +		drm_reset_display_info(connector);
> +
>  	drm_object_property_set_value(&connector->base,
>  				      dev->mode_config.non_desktop_property,
>  				      connector->display_info.non_desktop);
> diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
> index 524eace3d460..365901c1c33c 100644
> --- a/drivers/gpu/drm/drm_edid.c
> +++ b/drivers/gpu/drm/drm_edid.c
> @@ -1731,7 +1731,7 @@ EXPORT_SYMBOL(drm_edid_duplicate);
>   *
>   * Returns true if @vendor is in @edid, false otherwise
>   */
> -static bool edid_vendor(struct edid *edid, const char *vendor)
> +static bool edid_vendor(const struct edid *edid, const char *vendor)
>  {
>  	char edid_vendor[3];
>  
> @@ -1749,7 +1749,7 @@ static bool edid_vendor(struct edid *edid, const char *vendor)
>   *
>   * This tells subsequent routines what fixes they need to apply.
>   */
> -static u32 edid_get_quirks(struct edid *edid)
> +static u32 edid_get_quirks(const struct edid *edid)
>  {
>  	const struct edid_quirk *quirk;
>  	int i;
> @@ -2813,7 +2813,7 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid,
>  /*
>   * Search EDID for CEA extension block.
>   */
> -static u8 *drm_find_edid_extension(struct edid *edid, int ext_id)
> +static u8 *drm_find_edid_extension(const struct edid *edid, int ext_id)
>  {
>  	u8 *edid_ext = NULL;
>  	int i;
> @@ -2835,12 +2835,12 @@ static u8 *drm_find_edid_extension(struct edid *edid, int ext_id)
>  	return edid_ext;
>  }
>  
> -static u8 *drm_find_cea_extension(struct edid *edid)
> +static u8 *drm_find_cea_extension(const struct edid *edid)
>  {
>  	return drm_find_edid_extension(edid, CEA_EXT);
>  }
>  
> -static u8 *drm_find_displayid_extension(struct edid *edid)
> +static u8 *drm_find_displayid_extension(const struct edid *edid)
>  {
>  	return drm_find_edid_extension(edid, DISPLAYID_EXT);
>  }
> @@ -4378,7 +4378,7 @@ drm_parse_hdmi_vsdb_video(struct drm_connector *connector, const u8 *db)
>  }
>  
>  static void drm_parse_cea_ext(struct drm_connector *connector,
> -			      struct edid *edid)
> +			      const struct edid *edid)
>  {
>  	struct drm_display_info *info = &connector->display_info;
>  	const u8 *edid_ext;
> @@ -4412,11 +4412,34 @@ static void drm_parse_cea_ext(struct drm_connector *connector,
>  	}
>  }
>  
> -static void drm_add_display_info(struct drm_connector *connector,
> -				 struct edid *edid, u32 quirks)
> +/* A connector has no EDID information, so we've got no EDID to compute quirks from. Reset
> + * all of the values which would have been set from EDID
> + */
> +void
> +drm_reset_display_info(struct drm_connector *connector)
> +{
> +	struct drm_display_info *info = &connector->display_info;
> +
> +	info->width_mm = 0;
> +	info->height_mm = 0;
> +
> +	info->bpc = 0;
> +	info->color_formats = 0;
> +	info->cea_rev = 0;
> +	info->max_tmds_clock = 0;
> +	info->dvi_dual = false;
> +	info->has_hdmi_infoframe = false;
> +
> +	info->non_desktop = 0;
> +}
> +EXPORT_SYMBOL_GPL(drm_reset_display_info);

Do we really need these 2 EXPORT_SYMBOL here?

>From a quick look the users are only internal to drm.ko, so not needed.
And that would gives us a clearer driver api (plus I won't nag you about
lack of kerneldoc for said driver api).

If that's correct pls also move the decls to drm_crtc_internal.h. There's
already another function exported like that from drm_edid.c.

With the nits addressed:

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

Please also cc: intel-gfx for v2 so our CI can double-check I didn't miss
anything.

Dave's out, but there's some other drm-misc fixes, I'll probably forward a
-fixes pull to Linus directly.

Thanks, Daniel

> +
> +u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edid)
>  {
>  	struct drm_display_info *info = &connector->display_info;
>  
> +	u32 quirks = edid_get_quirks(edid);
> +
>  	info->width_mm = edid->width_cm * 10;
>  	info->height_mm = edid->height_cm * 10;
>  
> @@ -4430,11 +4453,13 @@ static void drm_add_display_info(struct drm_connector *connector,
>  
>  	info->non_desktop = !!(quirks & EDID_QUIRK_NON_DESKTOP);
>  
> +	DRM_DEBUG_KMS("non_desktop set to %d\n", info->non_desktop);
> +
>  	if (edid->revision < 3)
> -		return;
> +		return quirks;
>  
>  	if (!(edid->input & DRM_EDID_INPUT_DIGITAL))
> -		return;
> +		return quirks;
>  
>  	drm_parse_cea_ext(connector, edid);
>  
> @@ -4454,7 +4479,7 @@ static void drm_add_display_info(struct drm_connector *connector,
>  
>  	/* Only defined for 1.4 with digital displays */
>  	if (edid->revision < 4)
> -		return;
> +		return quirks;
>  
>  	switch (edid->input & DRM_EDID_DIGITAL_DEPTH_MASK) {
>  	case DRM_EDID_DIGITAL_DEPTH_6:
> @@ -4489,7 +4514,9 @@ static void drm_add_display_info(struct drm_connector *connector,
>  		info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
>  	if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB422)
>  		info->color_formats |= DRM_COLOR_FORMAT_YCRCB422;
> +	return quirks;
>  }
> +EXPORT_SYMBOL_GPL(drm_add_display_info);
>  
>  static int validate_displayid(u8 *displayid, int length, int idx)
>  {
> @@ -4645,8 +4672,6 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
>  		return 0;
>  	}
>  
> -	quirks = edid_get_quirks(edid);
> -
>  	drm_edid_to_eld(connector, edid);
>  
>  	/*
> @@ -4654,7 +4679,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
>  	 * To avoid multiple parsing of same block, lets parse that map
>  	 * from sink info, before parsing CEA modes.
>  	 */
> -	drm_add_display_info(connector, edid, quirks);
> +	quirks = drm_add_display_info(connector, edid);
>  
>  	/*
>  	 * EDID spec says modes should be preferred in this order:
> diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
> index b25d12ef120a..8d89a9c3748d 100644
> --- a/include/drm/drm_edid.h
> +++ b/include/drm/drm_edid.h
> @@ -465,6 +465,8 @@ struct edid *drm_get_edid(struct drm_connector *connector,
>  struct edid *drm_get_edid_switcheroo(struct drm_connector *connector,
>  				     struct i2c_adapter *adapter);
>  struct edid *drm_edid_duplicate(const struct edid *edid);
> +void drm_reset_display_info(struct drm_connector *connector);
> +u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edid);
>  int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid);
>  
>  u8 drm_match_cea_mode(const struct drm_display_mode *to_match);
> -- 
> 2.15.0.rc0
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] drm: Update edid-derived drm_display_info fields at edid property set
@ 2017-12-11 10:19   ` Daniel Vetter
  0 siblings, 0 replies; 10+ messages in thread
From: Daniel Vetter @ 2017-12-11 10:19 UTC (permalink / raw)
  To: Keith Packard; +Cc: Dave Airlie, dri-devel, linux-kernel

On Thu, Dec 07, 2017 at 04:42:57PM -0800, Keith Packard wrote:
> There are a set of values in the drm_display_info structure for each
> connector which hold information derived from EDID. These are computed
> in drm_add_display_info. Before this patch, that was only called in
> drm_add_edid_modes. This meant that they were only set when EDID was
> present and never reset when EDID was not, as happened when the
> display was disconnected.
> 
> One of these fields, non_desktop, is used from
> drm_mode_connector_update_edid_property, the function responsible for
> assigning the new edid value to the application-visible property.
> 
> Various drivers call these two functions (drm_add_edid_modes and
> drm_mode_connector_update_edid_property) in different orders. This
> means that even when EDID is present, the drm_display_info fields may
> not have been computed at the time that
> drm_mode_connector_update_edid_property used the non_desktop value to
> set the non_desktop property.
> 
> I've added a public function (drm_reset_display_info) that resets the
> drm_display_info field values to default values and then made the
> drm_add_display_info function public. These two functions are now
> called directly from drm_mode_connector_update_edid_property so that
> the drm_display_info fields are always computed from the current EDID
> information before being used in that function.
> 
> This means that the drm_display_info values are often computed twice,
> once when the EDID property it set and a second time when EDID is used
> to compute modes for the device. The alternative would be to uniformly
> ensure that the values were computed once before being used, which
> would require that all drivers reliably invoke the two paths in the
> same order. The computation is inexpensive enough that it seems more
> maintainable in the long term to simply compute them in both paths.
> 
> The API to drm_add_display_info has been changed so that it no longer
> takes the set of edid-based quirks as a parameter. Rather, it now
> computes those quirks itself and returns them for further use by
> drm_add_edid_modes.
> 
> This patch also includes a number of 'const' additions caused by
> drm_mode_connector_update_edid_property taking a 'const struct edid *'
> parameter and wanting to pass that along to drm_add_display_info.
> 
> Signed-off-by: Keith Packard <keithp@keithp.com>

Yeah looks like a good way to reset the desktop-mode in all cases.

> ---
>  drivers/gpu/drm/drm_connector.c | 13 ++++++++++
>  drivers/gpu/drm/drm_edid.c      | 53 ++++++++++++++++++++++++++++++-----------
>  include/drm/drm_edid.h          |  2 ++
>  3 files changed, 54 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
> index 25f4b2e9a44f..83c01f359d55 100644
> --- a/drivers/gpu/drm/drm_connector.c
> +++ b/drivers/gpu/drm/drm_connector.c
> @@ -1207,6 +1207,19 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector,
>  	if (edid)
>  		size = EDID_LENGTH * (1 + edid->extensions);
>  
> +	/* Set the display info, using edid if available, otherwise
> +	 * reseting the values to defaults. This duplicates the work
> +	 * done in drm_add_edid_modes, but that function is not
> +	 * consistently called before this one in all drivers and the
> +	 * computation is cheap enough that it seems better to
> +	 * duplicate it rather than attempt to ensure some arbitrary
> +	 * ordering of calls.
> +	 */

Looks like the most reasonable fix for -rc. For the future, maybe capture
a FIXME/TODO in this comment that we should look into merging
drm_add_edid_modes() and drm_mode_connector_update_edid_property(). I
really can't think of a good reason for that split.

> +	if (edid)
> +		drm_add_display_info(connector, edid);
> +	else
> +		drm_reset_display_info(connector);
> +
>  	drm_object_property_set_value(&connector->base,
>  				      dev->mode_config.non_desktop_property,
>  				      connector->display_info.non_desktop);
> diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
> index 524eace3d460..365901c1c33c 100644
> --- a/drivers/gpu/drm/drm_edid.c
> +++ b/drivers/gpu/drm/drm_edid.c
> @@ -1731,7 +1731,7 @@ EXPORT_SYMBOL(drm_edid_duplicate);
>   *
>   * Returns true if @vendor is in @edid, false otherwise
>   */
> -static bool edid_vendor(struct edid *edid, const char *vendor)
> +static bool edid_vendor(const struct edid *edid, const char *vendor)
>  {
>  	char edid_vendor[3];
>  
> @@ -1749,7 +1749,7 @@ static bool edid_vendor(struct edid *edid, const char *vendor)
>   *
>   * This tells subsequent routines what fixes they need to apply.
>   */
> -static u32 edid_get_quirks(struct edid *edid)
> +static u32 edid_get_quirks(const struct edid *edid)
>  {
>  	const struct edid_quirk *quirk;
>  	int i;
> @@ -2813,7 +2813,7 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid,
>  /*
>   * Search EDID for CEA extension block.
>   */
> -static u8 *drm_find_edid_extension(struct edid *edid, int ext_id)
> +static u8 *drm_find_edid_extension(const struct edid *edid, int ext_id)
>  {
>  	u8 *edid_ext = NULL;
>  	int i;
> @@ -2835,12 +2835,12 @@ static u8 *drm_find_edid_extension(struct edid *edid, int ext_id)
>  	return edid_ext;
>  }
>  
> -static u8 *drm_find_cea_extension(struct edid *edid)
> +static u8 *drm_find_cea_extension(const struct edid *edid)
>  {
>  	return drm_find_edid_extension(edid, CEA_EXT);
>  }
>  
> -static u8 *drm_find_displayid_extension(struct edid *edid)
> +static u8 *drm_find_displayid_extension(const struct edid *edid)
>  {
>  	return drm_find_edid_extension(edid, DISPLAYID_EXT);
>  }
> @@ -4378,7 +4378,7 @@ drm_parse_hdmi_vsdb_video(struct drm_connector *connector, const u8 *db)
>  }
>  
>  static void drm_parse_cea_ext(struct drm_connector *connector,
> -			      struct edid *edid)
> +			      const struct edid *edid)
>  {
>  	struct drm_display_info *info = &connector->display_info;
>  	const u8 *edid_ext;
> @@ -4412,11 +4412,34 @@ static void drm_parse_cea_ext(struct drm_connector *connector,
>  	}
>  }
>  
> -static void drm_add_display_info(struct drm_connector *connector,
> -				 struct edid *edid, u32 quirks)
> +/* A connector has no EDID information, so we've got no EDID to compute quirks from. Reset
> + * all of the values which would have been set from EDID
> + */
> +void
> +drm_reset_display_info(struct drm_connector *connector)
> +{
> +	struct drm_display_info *info = &connector->display_info;
> +
> +	info->width_mm = 0;
> +	info->height_mm = 0;
> +
> +	info->bpc = 0;
> +	info->color_formats = 0;
> +	info->cea_rev = 0;
> +	info->max_tmds_clock = 0;
> +	info->dvi_dual = false;
> +	info->has_hdmi_infoframe = false;
> +
> +	info->non_desktop = 0;
> +}
> +EXPORT_SYMBOL_GPL(drm_reset_display_info);

Do we really need these 2 EXPORT_SYMBOL here?

From a quick look the users are only internal to drm.ko, so not needed.
And that would gives us a clearer driver api (plus I won't nag you about
lack of kerneldoc for said driver api).

If that's correct pls also move the decls to drm_crtc_internal.h. There's
already another function exported like that from drm_edid.c.

With the nits addressed:

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

Please also cc: intel-gfx for v2 so our CI can double-check I didn't miss
anything.

Dave's out, but there's some other drm-misc fixes, I'll probably forward a
-fixes pull to Linus directly.

Thanks, Daniel

> +
> +u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edid)
>  {
>  	struct drm_display_info *info = &connector->display_info;
>  
> +	u32 quirks = edid_get_quirks(edid);
> +
>  	info->width_mm = edid->width_cm * 10;
>  	info->height_mm = edid->height_cm * 10;
>  
> @@ -4430,11 +4453,13 @@ static void drm_add_display_info(struct drm_connector *connector,
>  
>  	info->non_desktop = !!(quirks & EDID_QUIRK_NON_DESKTOP);
>  
> +	DRM_DEBUG_KMS("non_desktop set to %d\n", info->non_desktop);
> +
>  	if (edid->revision < 3)
> -		return;
> +		return quirks;
>  
>  	if (!(edid->input & DRM_EDID_INPUT_DIGITAL))
> -		return;
> +		return quirks;
>  
>  	drm_parse_cea_ext(connector, edid);
>  
> @@ -4454,7 +4479,7 @@ static void drm_add_display_info(struct drm_connector *connector,
>  
>  	/* Only defined for 1.4 with digital displays */
>  	if (edid->revision < 4)
> -		return;
> +		return quirks;
>  
>  	switch (edid->input & DRM_EDID_DIGITAL_DEPTH_MASK) {
>  	case DRM_EDID_DIGITAL_DEPTH_6:
> @@ -4489,7 +4514,9 @@ static void drm_add_display_info(struct drm_connector *connector,
>  		info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
>  	if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB422)
>  		info->color_formats |= DRM_COLOR_FORMAT_YCRCB422;
> +	return quirks;
>  }
> +EXPORT_SYMBOL_GPL(drm_add_display_info);
>  
>  static int validate_displayid(u8 *displayid, int length, int idx)
>  {
> @@ -4645,8 +4672,6 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
>  		return 0;
>  	}
>  
> -	quirks = edid_get_quirks(edid);
> -
>  	drm_edid_to_eld(connector, edid);
>  
>  	/*
> @@ -4654,7 +4679,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
>  	 * To avoid multiple parsing of same block, lets parse that map
>  	 * from sink info, before parsing CEA modes.
>  	 */
> -	drm_add_display_info(connector, edid, quirks);
> +	quirks = drm_add_display_info(connector, edid);
>  
>  	/*
>  	 * EDID spec says modes should be preferred in this order:
> diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
> index b25d12ef120a..8d89a9c3748d 100644
> --- a/include/drm/drm_edid.h
> +++ b/include/drm/drm_edid.h
> @@ -465,6 +465,8 @@ struct edid *drm_get_edid(struct drm_connector *connector,
>  struct edid *drm_get_edid_switcheroo(struct drm_connector *connector,
>  				     struct i2c_adapter *adapter);
>  struct edid *drm_edid_duplicate(const struct edid *edid);
> +void drm_reset_display_info(struct drm_connector *connector);
> +u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edid);
>  int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid);
>  
>  u8 drm_match_cea_mode(const struct drm_display_mode *to_match);
> -- 
> 2.15.0.rc0
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH] drm: Update edid-derived drm_display_info fields at edid property set [v2]
  2017-12-11 10:19   ` Daniel Vetter
@ 2017-12-13  8:44     ` Keith Packard
  -1 siblings, 0 replies; 10+ messages in thread
From: Keith Packard @ 2017-12-13  8:44 UTC (permalink / raw)
  To: linux-kernel, Dave Airlie, Daniel Vetter
  Cc: Keith Packard, dri-devel, intel-gfx

There are a set of values in the drm_display_info structure for each
connector which hold information derived from EDID. These are computed
in drm_add_display_info. Before this patch, that was only called in
drm_add_edid_modes. This meant that they were only set when EDID was
present and never reset when EDID was not, as happened when the
display was disconnected.

One of these fields, non_desktop, is used from
drm_mode_connector_update_edid_property, the function responsible for
assigning the new edid value to the application-visible property.

Various drivers call these two functions (drm_add_edid_modes and
drm_mode_connector_update_edid_property) in different orders. This
means that even when EDID is present, the drm_display_info fields may
not have been computed at the time that
drm_mode_connector_update_edid_property used the non_desktop value to
set the non_desktop property.

I've added a public function (drm_reset_display_info) that resets the
drm_display_info field values to default values and then made the
drm_add_display_info function public. These two functions are now
called directly from drm_mode_connector_update_edid_property so that
the drm_display_info fields are always computed from the current EDID
information before being used in that function.

This means that the drm_display_info values are often computed twice,
once when the EDID property it set and a second time when EDID is used
to compute modes for the device. The alternative would be to uniformly
ensure that the values were computed once before being used, which
would require that all drivers reliably invoke the two paths in the
same order. The computation is inexpensive enough that it seems more
maintainable in the long term to simply compute them in both paths.

The API to drm_add_display_info has been changed so that it no longer
takes the set of edid-based quirks as a parameter. Rather, it now
computes those quirks itself and returns them for further use by
drm_add_edid_modes.

This patch also includes a number of 'const' additions caused by
drm_mode_connector_update_edid_property taking a 'const struct edid *'
parameter and wanting to pass that along to drm_add_display_info.

v2: after review by Daniel Vetter <daniel.vetter@ffwll.ch>

	Removed EXPORT_SYMBOL_GPL for drm_reset_display_info and
	drm_add_display_info.

	Added FIXME in drm_mode_connector_update_edid_property about
	potentially merging that with drm_add_edid_modes to avoid
	the need for two driver calls.

Signed-off-by: Keith Packard <keithp@keithp.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_connector.c | 13 ++++++++++
 drivers/gpu/drm/drm_edid.c      | 53 ++++++++++++++++++++++++++++++-----------
 include/drm/drm_edid.h          |  2 ++
 3 files changed, 54 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 25f4b2e9a44f..83c01f359d55 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -1207,6 +1207,19 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector,
 	if (edid)
 		size = EDID_LENGTH * (1 + edid->extensions);
 
+	/* Set the display info, using edid if available, otherwise
+	 * reseting the values to defaults. This duplicates the work
+	 * done in drm_add_edid_modes, but that function is not
+	 * consistently called before this one in all drivers and the
+	 * computation is cheap enough that it seems better to
+	 * duplicate it rather than attempt to ensure some arbitrary
+	 * ordering of calls.
+	 */
+	if (edid)
+		drm_add_display_info(connector, edid);
+	else
+		drm_reset_display_info(connector);
+
 	drm_object_property_set_value(&connector->base,
 				      dev->mode_config.non_desktop_property,
 				      connector->display_info.non_desktop);
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 524eace3d460..365901c1c33c 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -1731,7 +1731,7 @@ EXPORT_SYMBOL(drm_edid_duplicate);
  *
  * Returns true if @vendor is in @edid, false otherwise
  */
-static bool edid_vendor(struct edid *edid, const char *vendor)
+static bool edid_vendor(const struct edid *edid, const char *vendor)
 {
 	char edid_vendor[3];
 
@@ -1749,7 +1749,7 @@ static bool edid_vendor(struct edid *edid, const char *vendor)
  *
  * This tells subsequent routines what fixes they need to apply.
  */
-static u32 edid_get_quirks(struct edid *edid)
+static u32 edid_get_quirks(const struct edid *edid)
 {
 	const struct edid_quirk *quirk;
 	int i;
@@ -2813,7 +2813,7 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid,
 /*
  * Search EDID for CEA extension block.
  */
-static u8 *drm_find_edid_extension(struct edid *edid, int ext_id)
+static u8 *drm_find_edid_extension(const struct edid *edid, int ext_id)
 {
 	u8 *edid_ext = NULL;
 	int i;
@@ -2835,12 +2835,12 @@ static u8 *drm_find_edid_extension(struct edid *edid, int ext_id)
 	return edid_ext;
 }
 
-static u8 *drm_find_cea_extension(struct edid *edid)
+static u8 *drm_find_cea_extension(const struct edid *edid)
 {
 	return drm_find_edid_extension(edid, CEA_EXT);
 }
 
-static u8 *drm_find_displayid_extension(struct edid *edid)
+static u8 *drm_find_displayid_extension(const struct edid *edid)
 {
 	return drm_find_edid_extension(edid, DISPLAYID_EXT);
 }
@@ -4378,7 +4378,7 @@ drm_parse_hdmi_vsdb_video(struct drm_connector *connector, const u8 *db)
 }
 
 static void drm_parse_cea_ext(struct drm_connector *connector,
-			      struct edid *edid)
+			      const struct edid *edid)
 {
 	struct drm_display_info *info = &connector->display_info;
 	const u8 *edid_ext;
@@ -4412,11 +4412,34 @@ static void drm_parse_cea_ext(struct drm_connector *connector,
 	}
 }
 
-static void drm_add_display_info(struct drm_connector *connector,
-				 struct edid *edid, u32 quirks)
+/* A connector has no EDID information, so we've got no EDID to compute quirks from. Reset
+ * all of the values which would have been set from EDID
+ */
+void
+drm_reset_display_info(struct drm_connector *connector)
+{
+	struct drm_display_info *info = &connector->display_info;
+
+	info->width_mm = 0;
+	info->height_mm = 0;
+
+	info->bpc = 0;
+	info->color_formats = 0;
+	info->cea_rev = 0;
+	info->max_tmds_clock = 0;
+	info->dvi_dual = false;
+	info->has_hdmi_infoframe = false;
+
+	info->non_desktop = 0;
+}
+EXPORT_SYMBOL_GPL(drm_reset_display_info);
+
+u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edid)
 {
 	struct drm_display_info *info = &connector->display_info;
 
+	u32 quirks = edid_get_quirks(edid);
+
 	info->width_mm = edid->width_cm * 10;
 	info->height_mm = edid->height_cm * 10;
 
@@ -4430,11 +4453,13 @@ static void drm_add_display_info(struct drm_connector *connector,
 
 	info->non_desktop = !!(quirks & EDID_QUIRK_NON_DESKTOP);
 
+	DRM_DEBUG_KMS("non_desktop set to %d\n", info->non_desktop);
+
 	if (edid->revision < 3)
-		return;
+		return quirks;
 
 	if (!(edid->input & DRM_EDID_INPUT_DIGITAL))
-		return;
+		return quirks;
 
 	drm_parse_cea_ext(connector, edid);
 
@@ -4454,7 +4479,7 @@ static void drm_add_display_info(struct drm_connector *connector,
 
 	/* Only defined for 1.4 with digital displays */
 	if (edid->revision < 4)
-		return;
+		return quirks;
 
 	switch (edid->input & DRM_EDID_DIGITAL_DEPTH_MASK) {
 	case DRM_EDID_DIGITAL_DEPTH_6:
@@ -4489,7 +4514,9 @@ static void drm_add_display_info(struct drm_connector *connector,
 		info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
 	if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB422)
 		info->color_formats |= DRM_COLOR_FORMAT_YCRCB422;
+	return quirks;
 }
+EXPORT_SYMBOL_GPL(drm_add_display_info);
 
 static int validate_displayid(u8 *displayid, int length, int idx)
 {
@@ -4645,8 +4672,6 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
 		return 0;
 	}
 
-	quirks = edid_get_quirks(edid);
-
 	drm_edid_to_eld(connector, edid);
 
 	/*
@@ -4654,7 +4679,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
 	 * To avoid multiple parsing of same block, lets parse that map
 	 * from sink info, before parsing CEA modes.
 	 */
-	drm_add_display_info(connector, edid, quirks);
+	quirks = drm_add_display_info(connector, edid);
 
 	/*
 	 * EDID spec says modes should be preferred in this order:
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
index b25d12ef120a..8d89a9c3748d 100644
--- a/include/drm/drm_edid.h
+++ b/include/drm/drm_edid.h
@@ -465,6 +465,8 @@ struct edid *drm_get_edid(struct drm_connector *connector,
 struct edid *drm_get_edid_switcheroo(struct drm_connector *connector,
 				     struct i2c_adapter *adapter);
 struct edid *drm_edid_duplicate(const struct edid *edid);
+void drm_reset_display_info(struct drm_connector *connector);
+u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edid);
 int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid);
 
 u8 drm_match_cea_mode(const struct drm_display_mode *to_match);
-- 
2.15.0.rc0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH] drm: Update edid-derived drm_display_info fields at edid property set [v2]
@ 2017-12-13  8:44     ` Keith Packard
  0 siblings, 0 replies; 10+ messages in thread
From: Keith Packard @ 2017-12-13  8:44 UTC (permalink / raw)
  To: linux-kernel, Dave Airlie, Daniel Vetter
  Cc: Keith Packard, intel-gfx, dri-devel

There are a set of values in the drm_display_info structure for each
connector which hold information derived from EDID. These are computed
in drm_add_display_info. Before this patch, that was only called in
drm_add_edid_modes. This meant that they were only set when EDID was
present and never reset when EDID was not, as happened when the
display was disconnected.

One of these fields, non_desktop, is used from
drm_mode_connector_update_edid_property, the function responsible for
assigning the new edid value to the application-visible property.

Various drivers call these two functions (drm_add_edid_modes and
drm_mode_connector_update_edid_property) in different orders. This
means that even when EDID is present, the drm_display_info fields may
not have been computed at the time that
drm_mode_connector_update_edid_property used the non_desktop value to
set the non_desktop property.

I've added a public function (drm_reset_display_info) that resets the
drm_display_info field values to default values and then made the
drm_add_display_info function public. These two functions are now
called directly from drm_mode_connector_update_edid_property so that
the drm_display_info fields are always computed from the current EDID
information before being used in that function.

This means that the drm_display_info values are often computed twice,
once when the EDID property it set and a second time when EDID is used
to compute modes for the device. The alternative would be to uniformly
ensure that the values were computed once before being used, which
would require that all drivers reliably invoke the two paths in the
same order. The computation is inexpensive enough that it seems more
maintainable in the long term to simply compute them in both paths.

The API to drm_add_display_info has been changed so that it no longer
takes the set of edid-based quirks as a parameter. Rather, it now
computes those quirks itself and returns them for further use by
drm_add_edid_modes.

This patch also includes a number of 'const' additions caused by
drm_mode_connector_update_edid_property taking a 'const struct edid *'
parameter and wanting to pass that along to drm_add_display_info.

v2: after review by Daniel Vetter <daniel.vetter@ffwll.ch>

	Removed EXPORT_SYMBOL_GPL for drm_reset_display_info and
	drm_add_display_info.

	Added FIXME in drm_mode_connector_update_edid_property about
	potentially merging that with drm_add_edid_modes to avoid
	the need for two driver calls.

Signed-off-by: Keith Packard <keithp@keithp.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_connector.c | 13 ++++++++++
 drivers/gpu/drm/drm_edid.c      | 53 ++++++++++++++++++++++++++++++-----------
 include/drm/drm_edid.h          |  2 ++
 3 files changed, 54 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 25f4b2e9a44f..83c01f359d55 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -1207,6 +1207,19 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector,
 	if (edid)
 		size = EDID_LENGTH * (1 + edid->extensions);
 
+	/* Set the display info, using edid if available, otherwise
+	 * reseting the values to defaults. This duplicates the work
+	 * done in drm_add_edid_modes, but that function is not
+	 * consistently called before this one in all drivers and the
+	 * computation is cheap enough that it seems better to
+	 * duplicate it rather than attempt to ensure some arbitrary
+	 * ordering of calls.
+	 */
+	if (edid)
+		drm_add_display_info(connector, edid);
+	else
+		drm_reset_display_info(connector);
+
 	drm_object_property_set_value(&connector->base,
 				      dev->mode_config.non_desktop_property,
 				      connector->display_info.non_desktop);
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 524eace3d460..365901c1c33c 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -1731,7 +1731,7 @@ EXPORT_SYMBOL(drm_edid_duplicate);
  *
  * Returns true if @vendor is in @edid, false otherwise
  */
-static bool edid_vendor(struct edid *edid, const char *vendor)
+static bool edid_vendor(const struct edid *edid, const char *vendor)
 {
 	char edid_vendor[3];
 
@@ -1749,7 +1749,7 @@ static bool edid_vendor(struct edid *edid, const char *vendor)
  *
  * This tells subsequent routines what fixes they need to apply.
  */
-static u32 edid_get_quirks(struct edid *edid)
+static u32 edid_get_quirks(const struct edid *edid)
 {
 	const struct edid_quirk *quirk;
 	int i;
@@ -2813,7 +2813,7 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid,
 /*
  * Search EDID for CEA extension block.
  */
-static u8 *drm_find_edid_extension(struct edid *edid, int ext_id)
+static u8 *drm_find_edid_extension(const struct edid *edid, int ext_id)
 {
 	u8 *edid_ext = NULL;
 	int i;
@@ -2835,12 +2835,12 @@ static u8 *drm_find_edid_extension(struct edid *edid, int ext_id)
 	return edid_ext;
 }
 
-static u8 *drm_find_cea_extension(struct edid *edid)
+static u8 *drm_find_cea_extension(const struct edid *edid)
 {
 	return drm_find_edid_extension(edid, CEA_EXT);
 }
 
-static u8 *drm_find_displayid_extension(struct edid *edid)
+static u8 *drm_find_displayid_extension(const struct edid *edid)
 {
 	return drm_find_edid_extension(edid, DISPLAYID_EXT);
 }
@@ -4378,7 +4378,7 @@ drm_parse_hdmi_vsdb_video(struct drm_connector *connector, const u8 *db)
 }
 
 static void drm_parse_cea_ext(struct drm_connector *connector,
-			      struct edid *edid)
+			      const struct edid *edid)
 {
 	struct drm_display_info *info = &connector->display_info;
 	const u8 *edid_ext;
@@ -4412,11 +4412,34 @@ static void drm_parse_cea_ext(struct drm_connector *connector,
 	}
 }
 
-static void drm_add_display_info(struct drm_connector *connector,
-				 struct edid *edid, u32 quirks)
+/* A connector has no EDID information, so we've got no EDID to compute quirks from. Reset
+ * all of the values which would have been set from EDID
+ */
+void
+drm_reset_display_info(struct drm_connector *connector)
+{
+	struct drm_display_info *info = &connector->display_info;
+
+	info->width_mm = 0;
+	info->height_mm = 0;
+
+	info->bpc = 0;
+	info->color_formats = 0;
+	info->cea_rev = 0;
+	info->max_tmds_clock = 0;
+	info->dvi_dual = false;
+	info->has_hdmi_infoframe = false;
+
+	info->non_desktop = 0;
+}
+EXPORT_SYMBOL_GPL(drm_reset_display_info);
+
+u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edid)
 {
 	struct drm_display_info *info = &connector->display_info;
 
+	u32 quirks = edid_get_quirks(edid);
+
 	info->width_mm = edid->width_cm * 10;
 	info->height_mm = edid->height_cm * 10;
 
@@ -4430,11 +4453,13 @@ static void drm_add_display_info(struct drm_connector *connector,
 
 	info->non_desktop = !!(quirks & EDID_QUIRK_NON_DESKTOP);
 
+	DRM_DEBUG_KMS("non_desktop set to %d\n", info->non_desktop);
+
 	if (edid->revision < 3)
-		return;
+		return quirks;
 
 	if (!(edid->input & DRM_EDID_INPUT_DIGITAL))
-		return;
+		return quirks;
 
 	drm_parse_cea_ext(connector, edid);
 
@@ -4454,7 +4479,7 @@ static void drm_add_display_info(struct drm_connector *connector,
 
 	/* Only defined for 1.4 with digital displays */
 	if (edid->revision < 4)
-		return;
+		return quirks;
 
 	switch (edid->input & DRM_EDID_DIGITAL_DEPTH_MASK) {
 	case DRM_EDID_DIGITAL_DEPTH_6:
@@ -4489,7 +4514,9 @@ static void drm_add_display_info(struct drm_connector *connector,
 		info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
 	if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB422)
 		info->color_formats |= DRM_COLOR_FORMAT_YCRCB422;
+	return quirks;
 }
+EXPORT_SYMBOL_GPL(drm_add_display_info);
 
 static int validate_displayid(u8 *displayid, int length, int idx)
 {
@@ -4645,8 +4672,6 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
 		return 0;
 	}
 
-	quirks = edid_get_quirks(edid);
-
 	drm_edid_to_eld(connector, edid);
 
 	/*
@@ -4654,7 +4679,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
 	 * To avoid multiple parsing of same block, lets parse that map
 	 * from sink info, before parsing CEA modes.
 	 */
-	drm_add_display_info(connector, edid, quirks);
+	quirks = drm_add_display_info(connector, edid);
 
 	/*
 	 * EDID spec says modes should be preferred in this order:
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
index b25d12ef120a..8d89a9c3748d 100644
--- a/include/drm/drm_edid.h
+++ b/include/drm/drm_edid.h
@@ -465,6 +465,8 @@ struct edid *drm_get_edid(struct drm_connector *connector,
 struct edid *drm_get_edid_switcheroo(struct drm_connector *connector,
 				     struct i2c_adapter *adapter);
 struct edid *drm_edid_duplicate(const struct edid *edid);
+void drm_reset_display_info(struct drm_connector *connector);
+u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edid);
 int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid);
 
 u8 drm_match_cea_mode(const struct drm_display_mode *to_match);
-- 
2.15.0.rc0

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* ✓ Fi.CI.BAT: success for drm: Update edid-derived drm_display_info fields at edid property set [v2]
  2017-12-08  0:42 ` Keith Packard
  (?)
  (?)
@ 2017-12-13  9:04 ` Patchwork
  -1 siblings, 0 replies; 10+ messages in thread
From: Patchwork @ 2017-12-13  9:04 UTC (permalink / raw)
  To: Keith Packard; +Cc: intel-gfx

== Series Details ==

Series: drm: Update edid-derived drm_display_info fields at edid property set [v2]
URL   : https://patchwork.freedesktop.org/series/35271/
State : success

== Summary ==

Series 35271v1 drm: Update edid-derived drm_display_info fields at edid property set [v2]
https://patchwork.freedesktop.org/api/1.0/series/35271/revisions/1/mbox/

Test gem_mmap_gtt:
        Subgroup basic-small-bo-tiledx:
                pass       -> FAIL       (fi-gdg-551) fdo#102575
Test kms_pipe_crc_basic:
        Subgroup suspend-read-crc-pipe-a:
                pass       -> DMESG-WARN (fi-kbl-r) fdo#104172 +1

fdo#102575 https://bugs.freedesktop.org/show_bug.cgi?id=102575
fdo#104172 https://bugs.freedesktop.org/show_bug.cgi?id=104172

fi-bdw-5557u     total:288  pass:267  dwarn:0   dfail:0   fail:0   skip:21  time:437s
fi-bdw-gvtdvm    total:288  pass:264  dwarn:0   dfail:0   fail:0   skip:24  time:441s
fi-blb-e6850     total:288  pass:223  dwarn:1   dfail:0   fail:0   skip:64  time:385s
fi-bsw-n3050     total:288  pass:242  dwarn:0   dfail:0   fail:0   skip:46  time:508s
fi-bwr-2160      total:288  pass:183  dwarn:0   dfail:0   fail:0   skip:105 time:277s
fi-bxt-dsi       total:288  pass:258  dwarn:0   dfail:0   fail:0   skip:30  time:504s
fi-bxt-j4205     total:288  pass:259  dwarn:0   dfail:0   fail:0   skip:29  time:505s
fi-byt-j1900     total:288  pass:253  dwarn:0   dfail:0   fail:0   skip:35  time:489s
fi-byt-n2820     total:288  pass:249  dwarn:0   dfail:0   fail:0   skip:39  time:473s
fi-elk-e7500     total:224  pass:163  dwarn:15  dfail:0   fail:0   skip:45 
fi-gdg-551       total:288  pass:178  dwarn:1   dfail:0   fail:1   skip:108 time:269s
fi-glk-1         total:288  pass:260  dwarn:0   dfail:0   fail:0   skip:28  time:541s
fi-hsw-4770      total:288  pass:261  dwarn:0   dfail:0   fail:0   skip:27  time:353s
fi-hsw-4770r     total:288  pass:224  dwarn:0   dfail:0   fail:0   skip:64  time:260s
fi-ilk-650       total:288  pass:228  dwarn:0   dfail:0   fail:0   skip:60  time:390s
fi-ivb-3520m     total:288  pass:259  dwarn:0   dfail:0   fail:0   skip:29  time:468s
fi-ivb-3770      total:288  pass:259  dwarn:0   dfail:0   fail:0   skip:29  time:444s
fi-kbl-7500u     total:288  pass:263  dwarn:1   dfail:0   fail:0   skip:24  time:487s
fi-kbl-7560u     total:288  pass:269  dwarn:0   dfail:0   fail:0   skip:19  time:527s
fi-kbl-7567u     total:288  pass:268  dwarn:0   dfail:0   fail:0   skip:20  time:474s
fi-kbl-r         total:288  pass:260  dwarn:1   dfail:0   fail:0   skip:27  time:526s
fi-pnv-d510      total:288  pass:222  dwarn:1   dfail:0   fail:0   skip:65  time:590s
fi-skl-6260u     total:288  pass:268  dwarn:0   dfail:0   fail:0   skip:20  time:448s
fi-skl-6600u     total:288  pass:261  dwarn:0   dfail:0   fail:0   skip:27  time:543s
fi-skl-6700hq    total:288  pass:262  dwarn:0   dfail:0   fail:0   skip:26  time:562s
fi-skl-6700k     total:288  pass:264  dwarn:0   dfail:0   fail:0   skip:24  time:517s
fi-skl-6770hq    total:288  pass:268  dwarn:0   dfail:0   fail:0   skip:20  time:495s
fi-skl-gvtdvm    total:288  pass:265  dwarn:0   dfail:0   fail:0   skip:23  time:440s
fi-snb-2520m     total:288  pass:249  dwarn:0   dfail:0   fail:0   skip:39  time:541s
fi-snb-2600      total:288  pass:248  dwarn:0   dfail:0   fail:0   skip:40  time:415s
Blacklisted hosts:
fi-cfl-s2        total:288  pass:262  dwarn:0   dfail:0   fail:0   skip:26  time:599s
fi-cnl-y         total:288  pass:262  dwarn:0   dfail:0   fail:0   skip:26  time:612s
fi-glk-dsi       total:288  pass:258  dwarn:0   dfail:0   fail:0   skip:30  time:492s

8874c0f95698c533c0daf69c6c41834d837fef87 drm-tip: 2017y-12m-12d-21h-34m-33s UTC integration manifest
7fe02ab8e97e drm: Update edid-derived drm_display_info fields at edid property set [v2]

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_7479/issues.html
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 10+ messages in thread

* ✓ Fi.CI.IGT: success for drm: Update edid-derived drm_display_info fields at edid property set [v2]
  2017-12-08  0:42 ` Keith Packard
                   ` (2 preceding siblings ...)
  (?)
@ 2017-12-13  9:51 ` Patchwork
  -1 siblings, 0 replies; 10+ messages in thread
From: Patchwork @ 2017-12-13  9:51 UTC (permalink / raw)
  To: Keith Packard; +Cc: intel-gfx

== Series Details ==

Series: drm: Update edid-derived drm_display_info fields at edid property set [v2]
URL   : https://patchwork.freedesktop.org/series/35271/
State : success

== Summary ==

Test gem_pwrite:
        Subgroup huge-gtt-backwards:
                incomplete -> PASS       (shard-hsw) fdo#104218
Test kms_frontbuffer_tracking:
        Subgroup fbc-1p-primscrn-spr-indfb-fullscreen:
                pass       -> FAIL       (shard-hsw) fdo#101623
Test kms_flip:
        Subgroup plain-flip-fb-recreate-interruptible:
                pass       -> FAIL       (shard-hsw) fdo#100368

fdo#104218 https://bugs.freedesktop.org/show_bug.cgi?id=104218
fdo#101623 https://bugs.freedesktop.org/show_bug.cgi?id=101623
fdo#100368 https://bugs.freedesktop.org/show_bug.cgi?id=100368

shard-hsw        total:2712 pass:1535 dwarn:1   dfail:0   fail:12  skip:1164 time:9449s
shard-snb        total:2681 pass:1291 dwarn:1   dfail:0   fail:11  skip:1377 time:7760s
Blacklisted hosts:
shard-apl        total:2712 pass:1687 dwarn:2   dfail:0   fail:21  skip:1001 time:13870s
shard-kbl        total:2712 pass:1811 dwarn:1   dfail:0   fail:24  skip:876 time:11054s

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_7479/shards.html
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] drm: Update edid-derived drm_display_info fields at edid property set [v2]
  2017-12-13  8:44     ` Keith Packard
@ 2017-12-13 13:58       ` Daniel Vetter
  -1 siblings, 0 replies; 10+ messages in thread
From: Daniel Vetter @ 2017-12-13 13:58 UTC (permalink / raw)
  To: Keith Packard
  Cc: linux-kernel, Dave Airlie, Daniel Vetter, dri-devel, intel-gfx

On Wed, Dec 13, 2017 at 12:44:26AM -0800, Keith Packard wrote:
> There are a set of values in the drm_display_info structure for each
> connector which hold information derived from EDID. These are computed
> in drm_add_display_info. Before this patch, that was only called in
> drm_add_edid_modes. This meant that they were only set when EDID was
> present and never reset when EDID was not, as happened when the
> display was disconnected.
> 
> One of these fields, non_desktop, is used from
> drm_mode_connector_update_edid_property, the function responsible for
> assigning the new edid value to the application-visible property.
> 
> Various drivers call these two functions (drm_add_edid_modes and
> drm_mode_connector_update_edid_property) in different orders. This
> means that even when EDID is present, the drm_display_info fields may
> not have been computed at the time that
> drm_mode_connector_update_edid_property used the non_desktop value to
> set the non_desktop property.
> 
> I've added a public function (drm_reset_display_info) that resets the
> drm_display_info field values to default values and then made the
> drm_add_display_info function public. These two functions are now
> called directly from drm_mode_connector_update_edid_property so that
> the drm_display_info fields are always computed from the current EDID
> information before being used in that function.
> 
> This means that the drm_display_info values are often computed twice,
> once when the EDID property it set and a second time when EDID is used
> to compute modes for the device. The alternative would be to uniformly
> ensure that the values were computed once before being used, which
> would require that all drivers reliably invoke the two paths in the
> same order. The computation is inexpensive enough that it seems more
> maintainable in the long term to simply compute them in both paths.
> 
> The API to drm_add_display_info has been changed so that it no longer
> takes the set of edid-based quirks as a parameter. Rather, it now
> computes those quirks itself and returns them for further use by
> drm_add_edid_modes.
> 
> This patch also includes a number of 'const' additions caused by
> drm_mode_connector_update_edid_property taking a 'const struct edid *'
> parameter and wanting to pass that along to drm_add_display_info.
> 
> v2: after review by Daniel Vetter <daniel.vetter@ffwll.ch>
> 
> 	Removed EXPORT_SYMBOL_GPL for drm_reset_display_info and
> 	drm_add_display_info.
> 
> 	Added FIXME in drm_mode_connector_update_edid_property about
> 	potentially merging that with drm_add_edid_modes to avoid
> 	the need for two driver calls.
> 
> Signed-off-by: Keith Packard <keithp@keithp.com>
> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

Ok there's a functional conflict when I tried to apply this to -fixes,
due to some rework already in drm-misc-next. Hence I applied your original
patch here to drm-misc-next, and then cherry-picked it over to
drm-misc-fixes and fixed it up. That way we'll not loose the bits needed
in -next.

Please double-check I didn't wreck stuff before I send the pull request
out.

Thanks, Daniel
> ---
>  drivers/gpu/drm/drm_connector.c | 13 ++++++++++
>  drivers/gpu/drm/drm_edid.c      | 53 ++++++++++++++++++++++++++++++-----------
>  include/drm/drm_edid.h          |  2 ++
>  3 files changed, 54 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
> index 25f4b2e9a44f..83c01f359d55 100644
> --- a/drivers/gpu/drm/drm_connector.c
> +++ b/drivers/gpu/drm/drm_connector.c
> @@ -1207,6 +1207,19 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector,
>  	if (edid)
>  		size = EDID_LENGTH * (1 + edid->extensions);
>  
> +	/* Set the display info, using edid if available, otherwise
> +	 * reseting the values to defaults. This duplicates the work
> +	 * done in drm_add_edid_modes, but that function is not
> +	 * consistently called before this one in all drivers and the
> +	 * computation is cheap enough that it seems better to
> +	 * duplicate it rather than attempt to ensure some arbitrary
> +	 * ordering of calls.
> +	 */
> +	if (edid)
> +		drm_add_display_info(connector, edid);
> +	else
> +		drm_reset_display_info(connector);
> +
>  	drm_object_property_set_value(&connector->base,
>  				      dev->mode_config.non_desktop_property,
>  				      connector->display_info.non_desktop);
> diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
> index 524eace3d460..365901c1c33c 100644
> --- a/drivers/gpu/drm/drm_edid.c
> +++ b/drivers/gpu/drm/drm_edid.c
> @@ -1731,7 +1731,7 @@ EXPORT_SYMBOL(drm_edid_duplicate);
>   *
>   * Returns true if @vendor is in @edid, false otherwise
>   */
> -static bool edid_vendor(struct edid *edid, const char *vendor)
> +static bool edid_vendor(const struct edid *edid, const char *vendor)
>  {
>  	char edid_vendor[3];
>  
> @@ -1749,7 +1749,7 @@ static bool edid_vendor(struct edid *edid, const char *vendor)
>   *
>   * This tells subsequent routines what fixes they need to apply.
>   */
> -static u32 edid_get_quirks(struct edid *edid)
> +static u32 edid_get_quirks(const struct edid *edid)
>  {
>  	const struct edid_quirk *quirk;
>  	int i;
> @@ -2813,7 +2813,7 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid,
>  /*
>   * Search EDID for CEA extension block.
>   */
> -static u8 *drm_find_edid_extension(struct edid *edid, int ext_id)
> +static u8 *drm_find_edid_extension(const struct edid *edid, int ext_id)
>  {
>  	u8 *edid_ext = NULL;
>  	int i;
> @@ -2835,12 +2835,12 @@ static u8 *drm_find_edid_extension(struct edid *edid, int ext_id)
>  	return edid_ext;
>  }
>  
> -static u8 *drm_find_cea_extension(struct edid *edid)
> +static u8 *drm_find_cea_extension(const struct edid *edid)
>  {
>  	return drm_find_edid_extension(edid, CEA_EXT);
>  }
>  
> -static u8 *drm_find_displayid_extension(struct edid *edid)
> +static u8 *drm_find_displayid_extension(const struct edid *edid)
>  {
>  	return drm_find_edid_extension(edid, DISPLAYID_EXT);
>  }
> @@ -4378,7 +4378,7 @@ drm_parse_hdmi_vsdb_video(struct drm_connector *connector, const u8 *db)
>  }
>  
>  static void drm_parse_cea_ext(struct drm_connector *connector,
> -			      struct edid *edid)
> +			      const struct edid *edid)
>  {
>  	struct drm_display_info *info = &connector->display_info;
>  	const u8 *edid_ext;
> @@ -4412,11 +4412,34 @@ static void drm_parse_cea_ext(struct drm_connector *connector,
>  	}
>  }
>  
> -static void drm_add_display_info(struct drm_connector *connector,
> -				 struct edid *edid, u32 quirks)
> +/* A connector has no EDID information, so we've got no EDID to compute quirks from. Reset
> + * all of the values which would have been set from EDID
> + */
> +void
> +drm_reset_display_info(struct drm_connector *connector)
> +{
> +	struct drm_display_info *info = &connector->display_info;
> +
> +	info->width_mm = 0;
> +	info->height_mm = 0;
> +
> +	info->bpc = 0;
> +	info->color_formats = 0;
> +	info->cea_rev = 0;
> +	info->max_tmds_clock = 0;
> +	info->dvi_dual = false;
> +	info->has_hdmi_infoframe = false;
> +
> +	info->non_desktop = 0;
> +}
> +EXPORT_SYMBOL_GPL(drm_reset_display_info);
> +
> +u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edid)
>  {
>  	struct drm_display_info *info = &connector->display_info;
>  
> +	u32 quirks = edid_get_quirks(edid);
> +
>  	info->width_mm = edid->width_cm * 10;
>  	info->height_mm = edid->height_cm * 10;
>  
> @@ -4430,11 +4453,13 @@ static void drm_add_display_info(struct drm_connector *connector,
>  
>  	info->non_desktop = !!(quirks & EDID_QUIRK_NON_DESKTOP);
>  
> +	DRM_DEBUG_KMS("non_desktop set to %d\n", info->non_desktop);
> +
>  	if (edid->revision < 3)
> -		return;
> +		return quirks;
>  
>  	if (!(edid->input & DRM_EDID_INPUT_DIGITAL))
> -		return;
> +		return quirks;
>  
>  	drm_parse_cea_ext(connector, edid);
>  
> @@ -4454,7 +4479,7 @@ static void drm_add_display_info(struct drm_connector *connector,
>  
>  	/* Only defined for 1.4 with digital displays */
>  	if (edid->revision < 4)
> -		return;
> +		return quirks;
>  
>  	switch (edid->input & DRM_EDID_DIGITAL_DEPTH_MASK) {
>  	case DRM_EDID_DIGITAL_DEPTH_6:
> @@ -4489,7 +4514,9 @@ static void drm_add_display_info(struct drm_connector *connector,
>  		info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
>  	if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB422)
>  		info->color_formats |= DRM_COLOR_FORMAT_YCRCB422;
> +	return quirks;
>  }
> +EXPORT_SYMBOL_GPL(drm_add_display_info);
>  
>  static int validate_displayid(u8 *displayid, int length, int idx)
>  {
> @@ -4645,8 +4672,6 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
>  		return 0;
>  	}
>  
> -	quirks = edid_get_quirks(edid);
> -
>  	drm_edid_to_eld(connector, edid);
>  
>  	/*
> @@ -4654,7 +4679,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
>  	 * To avoid multiple parsing of same block, lets parse that map
>  	 * from sink info, before parsing CEA modes.
>  	 */
> -	drm_add_display_info(connector, edid, quirks);
> +	quirks = drm_add_display_info(connector, edid);
>  
>  	/*
>  	 * EDID spec says modes should be preferred in this order:
> diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
> index b25d12ef120a..8d89a9c3748d 100644
> --- a/include/drm/drm_edid.h
> +++ b/include/drm/drm_edid.h
> @@ -465,6 +465,8 @@ struct edid *drm_get_edid(struct drm_connector *connector,
>  struct edid *drm_get_edid_switcheroo(struct drm_connector *connector,
>  				     struct i2c_adapter *adapter);
>  struct edid *drm_edid_duplicate(const struct edid *edid);
> +void drm_reset_display_info(struct drm_connector *connector);
> +u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edid);
>  int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid);
>  
>  u8 drm_match_cea_mode(const struct drm_display_mode *to_match);
> -- 
> 2.15.0.rc0
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] drm: Update edid-derived drm_display_info fields at edid property set [v2]
@ 2017-12-13 13:58       ` Daniel Vetter
  0 siblings, 0 replies; 10+ messages in thread
From: Daniel Vetter @ 2017-12-13 13:58 UTC (permalink / raw)
  To: Keith Packard; +Cc: Dave Airlie, dri-devel, intel-gfx, linux-kernel

On Wed, Dec 13, 2017 at 12:44:26AM -0800, Keith Packard wrote:
> There are a set of values in the drm_display_info structure for each
> connector which hold information derived from EDID. These are computed
> in drm_add_display_info. Before this patch, that was only called in
> drm_add_edid_modes. This meant that they were only set when EDID was
> present and never reset when EDID was not, as happened when the
> display was disconnected.
> 
> One of these fields, non_desktop, is used from
> drm_mode_connector_update_edid_property, the function responsible for
> assigning the new edid value to the application-visible property.
> 
> Various drivers call these two functions (drm_add_edid_modes and
> drm_mode_connector_update_edid_property) in different orders. This
> means that even when EDID is present, the drm_display_info fields may
> not have been computed at the time that
> drm_mode_connector_update_edid_property used the non_desktop value to
> set the non_desktop property.
> 
> I've added a public function (drm_reset_display_info) that resets the
> drm_display_info field values to default values and then made the
> drm_add_display_info function public. These two functions are now
> called directly from drm_mode_connector_update_edid_property so that
> the drm_display_info fields are always computed from the current EDID
> information before being used in that function.
> 
> This means that the drm_display_info values are often computed twice,
> once when the EDID property it set and a second time when EDID is used
> to compute modes for the device. The alternative would be to uniformly
> ensure that the values were computed once before being used, which
> would require that all drivers reliably invoke the two paths in the
> same order. The computation is inexpensive enough that it seems more
> maintainable in the long term to simply compute them in both paths.
> 
> The API to drm_add_display_info has been changed so that it no longer
> takes the set of edid-based quirks as a parameter. Rather, it now
> computes those quirks itself and returns them for further use by
> drm_add_edid_modes.
> 
> This patch also includes a number of 'const' additions caused by
> drm_mode_connector_update_edid_property taking a 'const struct edid *'
> parameter and wanting to pass that along to drm_add_display_info.
> 
> v2: after review by Daniel Vetter <daniel.vetter@ffwll.ch>
> 
> 	Removed EXPORT_SYMBOL_GPL for drm_reset_display_info and
> 	drm_add_display_info.
> 
> 	Added FIXME in drm_mode_connector_update_edid_property about
> 	potentially merging that with drm_add_edid_modes to avoid
> 	the need for two driver calls.
> 
> Signed-off-by: Keith Packard <keithp@keithp.com>
> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

Ok there's a functional conflict when I tried to apply this to -fixes,
due to some rework already in drm-misc-next. Hence I applied your original
patch here to drm-misc-next, and then cherry-picked it over to
drm-misc-fixes and fixed it up. That way we'll not loose the bits needed
in -next.

Please double-check I didn't wreck stuff before I send the pull request
out.

Thanks, Daniel
> ---
>  drivers/gpu/drm/drm_connector.c | 13 ++++++++++
>  drivers/gpu/drm/drm_edid.c      | 53 ++++++++++++++++++++++++++++++-----------
>  include/drm/drm_edid.h          |  2 ++
>  3 files changed, 54 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
> index 25f4b2e9a44f..83c01f359d55 100644
> --- a/drivers/gpu/drm/drm_connector.c
> +++ b/drivers/gpu/drm/drm_connector.c
> @@ -1207,6 +1207,19 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector,
>  	if (edid)
>  		size = EDID_LENGTH * (1 + edid->extensions);
>  
> +	/* Set the display info, using edid if available, otherwise
> +	 * reseting the values to defaults. This duplicates the work
> +	 * done in drm_add_edid_modes, but that function is not
> +	 * consistently called before this one in all drivers and the
> +	 * computation is cheap enough that it seems better to
> +	 * duplicate it rather than attempt to ensure some arbitrary
> +	 * ordering of calls.
> +	 */
> +	if (edid)
> +		drm_add_display_info(connector, edid);
> +	else
> +		drm_reset_display_info(connector);
> +
>  	drm_object_property_set_value(&connector->base,
>  				      dev->mode_config.non_desktop_property,
>  				      connector->display_info.non_desktop);
> diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
> index 524eace3d460..365901c1c33c 100644
> --- a/drivers/gpu/drm/drm_edid.c
> +++ b/drivers/gpu/drm/drm_edid.c
> @@ -1731,7 +1731,7 @@ EXPORT_SYMBOL(drm_edid_duplicate);
>   *
>   * Returns true if @vendor is in @edid, false otherwise
>   */
> -static bool edid_vendor(struct edid *edid, const char *vendor)
> +static bool edid_vendor(const struct edid *edid, const char *vendor)
>  {
>  	char edid_vendor[3];
>  
> @@ -1749,7 +1749,7 @@ static bool edid_vendor(struct edid *edid, const char *vendor)
>   *
>   * This tells subsequent routines what fixes they need to apply.
>   */
> -static u32 edid_get_quirks(struct edid *edid)
> +static u32 edid_get_quirks(const struct edid *edid)
>  {
>  	const struct edid_quirk *quirk;
>  	int i;
> @@ -2813,7 +2813,7 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid,
>  /*
>   * Search EDID for CEA extension block.
>   */
> -static u8 *drm_find_edid_extension(struct edid *edid, int ext_id)
> +static u8 *drm_find_edid_extension(const struct edid *edid, int ext_id)
>  {
>  	u8 *edid_ext = NULL;
>  	int i;
> @@ -2835,12 +2835,12 @@ static u8 *drm_find_edid_extension(struct edid *edid, int ext_id)
>  	return edid_ext;
>  }
>  
> -static u8 *drm_find_cea_extension(struct edid *edid)
> +static u8 *drm_find_cea_extension(const struct edid *edid)
>  {
>  	return drm_find_edid_extension(edid, CEA_EXT);
>  }
>  
> -static u8 *drm_find_displayid_extension(struct edid *edid)
> +static u8 *drm_find_displayid_extension(const struct edid *edid)
>  {
>  	return drm_find_edid_extension(edid, DISPLAYID_EXT);
>  }
> @@ -4378,7 +4378,7 @@ drm_parse_hdmi_vsdb_video(struct drm_connector *connector, const u8 *db)
>  }
>  
>  static void drm_parse_cea_ext(struct drm_connector *connector,
> -			      struct edid *edid)
> +			      const struct edid *edid)
>  {
>  	struct drm_display_info *info = &connector->display_info;
>  	const u8 *edid_ext;
> @@ -4412,11 +4412,34 @@ static void drm_parse_cea_ext(struct drm_connector *connector,
>  	}
>  }
>  
> -static void drm_add_display_info(struct drm_connector *connector,
> -				 struct edid *edid, u32 quirks)
> +/* A connector has no EDID information, so we've got no EDID to compute quirks from. Reset
> + * all of the values which would have been set from EDID
> + */
> +void
> +drm_reset_display_info(struct drm_connector *connector)
> +{
> +	struct drm_display_info *info = &connector->display_info;
> +
> +	info->width_mm = 0;
> +	info->height_mm = 0;
> +
> +	info->bpc = 0;
> +	info->color_formats = 0;
> +	info->cea_rev = 0;
> +	info->max_tmds_clock = 0;
> +	info->dvi_dual = false;
> +	info->has_hdmi_infoframe = false;
> +
> +	info->non_desktop = 0;
> +}
> +EXPORT_SYMBOL_GPL(drm_reset_display_info);
> +
> +u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edid)
>  {
>  	struct drm_display_info *info = &connector->display_info;
>  
> +	u32 quirks = edid_get_quirks(edid);
> +
>  	info->width_mm = edid->width_cm * 10;
>  	info->height_mm = edid->height_cm * 10;
>  
> @@ -4430,11 +4453,13 @@ static void drm_add_display_info(struct drm_connector *connector,
>  
>  	info->non_desktop = !!(quirks & EDID_QUIRK_NON_DESKTOP);
>  
> +	DRM_DEBUG_KMS("non_desktop set to %d\n", info->non_desktop);
> +
>  	if (edid->revision < 3)
> -		return;
> +		return quirks;
>  
>  	if (!(edid->input & DRM_EDID_INPUT_DIGITAL))
> -		return;
> +		return quirks;
>  
>  	drm_parse_cea_ext(connector, edid);
>  
> @@ -4454,7 +4479,7 @@ static void drm_add_display_info(struct drm_connector *connector,
>  
>  	/* Only defined for 1.4 with digital displays */
>  	if (edid->revision < 4)
> -		return;
> +		return quirks;
>  
>  	switch (edid->input & DRM_EDID_DIGITAL_DEPTH_MASK) {
>  	case DRM_EDID_DIGITAL_DEPTH_6:
> @@ -4489,7 +4514,9 @@ static void drm_add_display_info(struct drm_connector *connector,
>  		info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
>  	if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB422)
>  		info->color_formats |= DRM_COLOR_FORMAT_YCRCB422;
> +	return quirks;
>  }
> +EXPORT_SYMBOL_GPL(drm_add_display_info);
>  
>  static int validate_displayid(u8 *displayid, int length, int idx)
>  {
> @@ -4645,8 +4672,6 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
>  		return 0;
>  	}
>  
> -	quirks = edid_get_quirks(edid);
> -
>  	drm_edid_to_eld(connector, edid);
>  
>  	/*
> @@ -4654,7 +4679,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
>  	 * To avoid multiple parsing of same block, lets parse that map
>  	 * from sink info, before parsing CEA modes.
>  	 */
> -	drm_add_display_info(connector, edid, quirks);
> +	quirks = drm_add_display_info(connector, edid);
>  
>  	/*
>  	 * EDID spec says modes should be preferred in this order:
> diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
> index b25d12ef120a..8d89a9c3748d 100644
> --- a/include/drm/drm_edid.h
> +++ b/include/drm/drm_edid.h
> @@ -465,6 +465,8 @@ struct edid *drm_get_edid(struct drm_connector *connector,
>  struct edid *drm_get_edid_switcheroo(struct drm_connector *connector,
>  				     struct i2c_adapter *adapter);
>  struct edid *drm_edid_duplicate(const struct edid *edid);
> +void drm_reset_display_info(struct drm_connector *connector);
> +u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edid);
>  int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid);
>  
>  u8 drm_match_cea_mode(const struct drm_display_mode *to_match);
> -- 
> 2.15.0.rc0
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2017-12-13 13:58 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-12-08  0:42 [PATCH] drm: Update edid-derived drm_display_info fields at edid property set Keith Packard
2017-12-08  0:42 ` Keith Packard
2017-12-11 10:19 ` Daniel Vetter
2017-12-11 10:19   ` Daniel Vetter
2017-12-13  8:44   ` [PATCH] drm: Update edid-derived drm_display_info fields at edid property set [v2] Keith Packard
2017-12-13  8:44     ` Keith Packard
2017-12-13 13:58     ` Daniel Vetter
2017-12-13 13:58       ` Daniel Vetter
2017-12-13  9:04 ` ✓ Fi.CI.BAT: success for " Patchwork
2017-12-13  9:51 ` ✓ Fi.CI.IGT: " Patchwork

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.