aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2017-12-13 03:44:26 -0500
committerDaniel Vetter <daniel.vetter@ffwll.ch>2017-12-13 08:51:37 -0500
commit4b4df570b41dbb421f52605357d5d56c872df6d9 (patch)
treee4184907bbfd935742d09f184098089fcef4166d
parentbabc8110057cb9ca542c3c1666cbda4e8ccf9250 (diff)
drm: Update edid-derived drm_display_info fields at edid property set [v2]
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> Link: https://patchwork.freedesktop.org/patch/msgid/20171213084427.31199-1-keithp@keithp.com (danvet: cherry picked from commit 12a889bf4bca ("drm: rework delayed connector cleanup in connector_iter") from drm-misc-next since functional conflict with changes in -next and we need to make sure both have the right version and nothing gets lost.) Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
-rw-r--r--drivers/gpu/drm/drm_connector.c13
-rw-r--r--drivers/gpu/drm/drm_edid.c52
-rw-r--r--include/drm/drm_edid.h2
3 files changed, 53 insertions, 14 deletions
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 482014137953..c4dfcbc861a1 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -1231,6 +1231,19 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector,
1231 if (edid) 1231 if (edid)
1232 size = EDID_LENGTH * (1 + edid->extensions); 1232 size = EDID_LENGTH * (1 + edid->extensions);
1233 1233
1234 /* Set the display info, using edid if available, otherwise
1235 * reseting the values to defaults. This duplicates the work
1236 * done in drm_add_edid_modes, but that function is not
1237 * consistently called before this one in all drivers and the
1238 * computation is cheap enough that it seems better to
1239 * duplicate it rather than attempt to ensure some arbitrary
1240 * ordering of calls.
1241 */
1242 if (edid)
1243 drm_add_display_info(connector, edid);
1244 else
1245 drm_reset_display_info(connector);
1246
1234 drm_object_property_set_value(&connector->base, 1247 drm_object_property_set_value(&connector->base,
1235 dev->mode_config.non_desktop_property, 1248 dev->mode_config.non_desktop_property,
1236 connector->display_info.non_desktop); 1249 connector->display_info.non_desktop);
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 5dfe14763871..cb487148359a 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -1731,7 +1731,7 @@ EXPORT_SYMBOL(drm_edid_duplicate);
1731 * 1731 *
1732 * Returns true if @vendor is in @edid, false otherwise 1732 * Returns true if @vendor is in @edid, false otherwise
1733 */ 1733 */
1734static bool edid_vendor(struct edid *edid, const char *vendor) 1734static bool edid_vendor(const struct edid *edid, const char *vendor)
1735{ 1735{
1736 char edid_vendor[3]; 1736 char edid_vendor[3];
1737 1737
@@ -1749,7 +1749,7 @@ static bool edid_vendor(struct edid *edid, const char *vendor)
1749 * 1749 *
1750 * This tells subsequent routines what fixes they need to apply. 1750 * This tells subsequent routines what fixes they need to apply.
1751 */ 1751 */
1752static u32 edid_get_quirks(struct edid *edid) 1752static u32 edid_get_quirks(const struct edid *edid)
1753{ 1753{
1754 const struct edid_quirk *quirk; 1754 const struct edid_quirk *quirk;
1755 int i; 1755 int i;
@@ -2813,7 +2813,7 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid,
2813/* 2813/*
2814 * Search EDID for CEA extension block. 2814 * Search EDID for CEA extension block.
2815 */ 2815 */
2816static u8 *drm_find_edid_extension(struct edid *edid, int ext_id) 2816static u8 *drm_find_edid_extension(const struct edid *edid, int ext_id)
2817{ 2817{
2818 u8 *edid_ext = NULL; 2818 u8 *edid_ext = NULL;
2819 int i; 2819 int i;
@@ -2835,12 +2835,12 @@ static u8 *drm_find_edid_extension(struct edid *edid, int ext_id)
2835 return edid_ext; 2835 return edid_ext;
2836} 2836}
2837 2837
2838static u8 *drm_find_cea_extension(struct edid *edid) 2838static u8 *drm_find_cea_extension(const struct edid *edid)
2839{ 2839{
2840 return drm_find_edid_extension(edid, CEA_EXT); 2840 return drm_find_edid_extension(edid, CEA_EXT);
2841} 2841}
2842 2842
2843static u8 *drm_find_displayid_extension(struct edid *edid) 2843static u8 *drm_find_displayid_extension(const struct edid *edid)
2844{ 2844{
2845 return drm_find_edid_extension(edid, DISPLAYID_EXT); 2845 return drm_find_edid_extension(edid, DISPLAYID_EXT);
2846} 2846}
@@ -4363,7 +4363,7 @@ drm_parse_hdmi_vsdb_video(struct drm_connector *connector, const u8 *db)
4363} 4363}
4364 4364
4365static void drm_parse_cea_ext(struct drm_connector *connector, 4365static void drm_parse_cea_ext(struct drm_connector *connector,
4366 struct edid *edid) 4366 const struct edid *edid)
4367{ 4367{
4368 struct drm_display_info *info = &connector->display_info; 4368 struct drm_display_info *info = &connector->display_info;
4369 const u8 *edid_ext; 4369 const u8 *edid_ext;
@@ -4397,11 +4397,33 @@ static void drm_parse_cea_ext(struct drm_connector *connector,
4397 } 4397 }
4398} 4398}
4399 4399
4400static void drm_add_display_info(struct drm_connector *connector, 4400/* A connector has no EDID information, so we've got no EDID to compute quirks from. Reset
4401 struct edid *edid, u32 quirks) 4401 * all of the values which would have been set from EDID
4402 */
4403void
4404drm_reset_display_info(struct drm_connector *connector)
4402{ 4405{
4403 struct drm_display_info *info = &connector->display_info; 4406 struct drm_display_info *info = &connector->display_info;
4404 4407
4408 info->width_mm = 0;
4409 info->height_mm = 0;
4410
4411 info->bpc = 0;
4412 info->color_formats = 0;
4413 info->cea_rev = 0;
4414 info->max_tmds_clock = 0;
4415 info->dvi_dual = false;
4416
4417 info->non_desktop = 0;
4418}
4419EXPORT_SYMBOL_GPL(drm_reset_display_info);
4420
4421u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edid)
4422{
4423 struct drm_display_info *info = &connector->display_info;
4424
4425 u32 quirks = edid_get_quirks(edid);
4426
4405 info->width_mm = edid->width_cm * 10; 4427 info->width_mm = edid->width_cm * 10;
4406 info->height_mm = edid->height_cm * 10; 4428 info->height_mm = edid->height_cm * 10;
4407 4429
@@ -4414,11 +4436,13 @@ static void drm_add_display_info(struct drm_connector *connector,
4414 4436
4415 info->non_desktop = !!(quirks & EDID_QUIRK_NON_DESKTOP); 4437 info->non_desktop = !!(quirks & EDID_QUIRK_NON_DESKTOP);
4416 4438
4439 DRM_DEBUG_KMS("non_desktop set to %d\n", info->non_desktop);
4440
4417 if (edid->revision < 3) 4441 if (edid->revision < 3)
4418 return; 4442 return quirks;
4419 4443
4420 if (!(edid->input & DRM_EDID_INPUT_DIGITAL)) 4444 if (!(edid->input & DRM_EDID_INPUT_DIGITAL))
4421 return; 4445 return quirks;
4422 4446
4423 drm_parse_cea_ext(connector, edid); 4447 drm_parse_cea_ext(connector, edid);
4424 4448
@@ -4438,7 +4462,7 @@ static void drm_add_display_info(struct drm_connector *connector,
4438 4462
4439 /* Only defined for 1.4 with digital displays */ 4463 /* Only defined for 1.4 with digital displays */
4440 if (edid->revision < 4) 4464 if (edid->revision < 4)
4441 return; 4465 return quirks;
4442 4466
4443 switch (edid->input & DRM_EDID_DIGITAL_DEPTH_MASK) { 4467 switch (edid->input & DRM_EDID_DIGITAL_DEPTH_MASK) {
4444 case DRM_EDID_DIGITAL_DEPTH_6: 4468 case DRM_EDID_DIGITAL_DEPTH_6:
@@ -4473,7 +4497,9 @@ static void drm_add_display_info(struct drm_connector *connector,
4473 info->color_formats |= DRM_COLOR_FORMAT_YCRCB444; 4497 info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
4474 if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB422) 4498 if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB422)
4475 info->color_formats |= DRM_COLOR_FORMAT_YCRCB422; 4499 info->color_formats |= DRM_COLOR_FORMAT_YCRCB422;
4500 return quirks;
4476} 4501}
4502EXPORT_SYMBOL_GPL(drm_add_display_info);
4477 4503
4478static int validate_displayid(u8 *displayid, int length, int idx) 4504static int validate_displayid(u8 *displayid, int length, int idx)
4479{ 4505{
@@ -4627,14 +4653,12 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
4627 return 0; 4653 return 0;
4628 } 4654 }
4629 4655
4630 quirks = edid_get_quirks(edid);
4631
4632 /* 4656 /*
4633 * CEA-861-F adds ycbcr capability map block, for HDMI 2.0 sinks. 4657 * CEA-861-F adds ycbcr capability map block, for HDMI 2.0 sinks.
4634 * To avoid multiple parsing of same block, lets parse that map 4658 * To avoid multiple parsing of same block, lets parse that map
4635 * from sink info, before parsing CEA modes. 4659 * from sink info, before parsing CEA modes.
4636 */ 4660 */
4637 drm_add_display_info(connector, edid, quirks); 4661 quirks = drm_add_display_info(connector, edid);
4638 4662
4639 /* 4663 /*
4640 * EDID spec says modes should be preferred in this order: 4664 * 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 2ec41d032e56..efe6d5a8e834 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,
465struct edid *drm_get_edid_switcheroo(struct drm_connector *connector, 465struct edid *drm_get_edid_switcheroo(struct drm_connector *connector,
466 struct i2c_adapter *adapter); 466 struct i2c_adapter *adapter);
467struct edid *drm_edid_duplicate(const struct edid *edid); 467struct edid *drm_edid_duplicate(const struct edid *edid);
468void drm_reset_display_info(struct drm_connector *connector);
469u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edid);
468int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid); 470int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid);
469 471
470u8 drm_match_cea_mode(const struct drm_display_mode *to_match); 472u8 drm_match_cea_mode(const struct drm_display_mode *to_match);