summaryrefslogtreecommitdiffstats
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:29:18 -0500
commit170178fe99dd212bf25e70c89bc4b6e195564ffc (patch)
tree25e17394ad4e2c287bb6d44a71bea48d6454dda5
parent69adff9d9d257eb10329b2a5b9bf9c295a3b4bef (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> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20171213084427.31199-1-keithp@keithp.com
-rw-r--r--drivers/gpu/drm/drm_connector.c13
-rw-r--r--drivers/gpu/drm/drm_edid.c53
-rw-r--r--include/drm/drm_edid.h2
3 files changed, 54 insertions, 14 deletions
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 624edeb5c50d..0bc35545e86a 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -1229,6 +1229,19 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector,
1229 if (edid) 1229 if (edid)
1230 size = EDID_LENGTH * (1 + edid->extensions); 1230 size = EDID_LENGTH * (1 + edid->extensions);
1231 1231
1232 /* Set the display info, using edid if available, otherwise
1233 * reseting the values to defaults. This duplicates the work
1234 * done in drm_add_edid_modes, but that function is not
1235 * consistently called before this one in all drivers and the
1236 * computation is cheap enough that it seems better to
1237 * duplicate it rather than attempt to ensure some arbitrary
1238 * ordering of calls.
1239 */
1240 if (edid)
1241 drm_add_display_info(connector, edid);
1242 else
1243 drm_reset_display_info(connector);
1244
1232 drm_object_property_set_value(&connector->base, 1245 drm_object_property_set_value(&connector->base,
1233 dev->mode_config.non_desktop_property, 1246 dev->mode_config.non_desktop_property,
1234 connector->display_info.non_desktop); 1247 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);
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}
@@ -4378,7 +4378,7 @@ drm_parse_hdmi_vsdb_video(struct drm_connector *connector, const u8 *db)
4378} 4378}
4379 4379
4380static void drm_parse_cea_ext(struct drm_connector *connector, 4380static void drm_parse_cea_ext(struct drm_connector *connector,
4381 struct edid *edid) 4381 const struct edid *edid)
4382{ 4382{
4383 struct drm_display_info *info = &connector->display_info; 4383 struct drm_display_info *info = &connector->display_info;
4384 const u8 *edid_ext; 4384 const u8 *edid_ext;
@@ -4412,11 +4412,34 @@ static void drm_parse_cea_ext(struct drm_connector *connector,
4412 } 4412 }
4413} 4413}
4414 4414
4415static void drm_add_display_info(struct drm_connector *connector, 4415/* A connector has no EDID information, so we've got no EDID to compute quirks from. Reset
4416 struct edid *edid, u32 quirks) 4416 * all of the values which would have been set from EDID
4417 */
4418void
4419drm_reset_display_info(struct drm_connector *connector)
4420{
4421 struct drm_display_info *info = &connector->display_info;
4422
4423 info->width_mm = 0;
4424 info->height_mm = 0;
4425
4426 info->bpc = 0;
4427 info->color_formats = 0;
4428 info->cea_rev = 0;
4429 info->max_tmds_clock = 0;
4430 info->dvi_dual = false;
4431 info->has_hdmi_infoframe = false;
4432
4433 info->non_desktop = 0;
4434}
4435EXPORT_SYMBOL_GPL(drm_reset_display_info);
4436
4437u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edid)
4417{ 4438{
4418 struct drm_display_info *info = &connector->display_info; 4439 struct drm_display_info *info = &connector->display_info;
4419 4440
4441 u32 quirks = edid_get_quirks(edid);
4442
4420 info->width_mm = edid->width_cm * 10; 4443 info->width_mm = edid->width_cm * 10;
4421 info->height_mm = edid->height_cm * 10; 4444 info->height_mm = edid->height_cm * 10;
4422 4445
@@ -4430,11 +4453,13 @@ static void drm_add_display_info(struct drm_connector *connector,
4430 4453
4431 info->non_desktop = !!(quirks & EDID_QUIRK_NON_DESKTOP); 4454 info->non_desktop = !!(quirks & EDID_QUIRK_NON_DESKTOP);
4432 4455
4456 DRM_DEBUG_KMS("non_desktop set to %d\n", info->non_desktop);
4457
4433 if (edid->revision < 3) 4458 if (edid->revision < 3)
4434 return; 4459 return quirks;
4435 4460
4436 if (!(edid->input & DRM_EDID_INPUT_DIGITAL)) 4461 if (!(edid->input & DRM_EDID_INPUT_DIGITAL))
4437 return; 4462 return quirks;
4438 4463
4439 drm_parse_cea_ext(connector, edid); 4464 drm_parse_cea_ext(connector, edid);
4440 4465
@@ -4454,7 +4479,7 @@ static void drm_add_display_info(struct drm_connector *connector,
4454 4479
4455 /* Only defined for 1.4 with digital displays */ 4480 /* Only defined for 1.4 with digital displays */
4456 if (edid->revision < 4) 4481 if (edid->revision < 4)
4457 return; 4482 return quirks;
4458 4483
4459 switch (edid->input & DRM_EDID_DIGITAL_DEPTH_MASK) { 4484 switch (edid->input & DRM_EDID_DIGITAL_DEPTH_MASK) {
4460 case DRM_EDID_DIGITAL_DEPTH_6: 4485 case DRM_EDID_DIGITAL_DEPTH_6:
@@ -4489,7 +4514,9 @@ static void drm_add_display_info(struct drm_connector *connector,
4489 info->color_formats |= DRM_COLOR_FORMAT_YCRCB444; 4514 info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
4490 if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB422) 4515 if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB422)
4491 info->color_formats |= DRM_COLOR_FORMAT_YCRCB422; 4516 info->color_formats |= DRM_COLOR_FORMAT_YCRCB422;
4517 return quirks;
4492} 4518}
4519EXPORT_SYMBOL_GPL(drm_add_display_info);
4493 4520
4494static int validate_displayid(u8 *displayid, int length, int idx) 4521static int validate_displayid(u8 *displayid, int length, int idx)
4495{ 4522{
@@ -4645,8 +4672,6 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
4645 return 0; 4672 return 0;
4646 } 4673 }
4647 4674
4648 quirks = edid_get_quirks(edid);
4649
4650 drm_edid_to_eld(connector, edid); 4675 drm_edid_to_eld(connector, edid);
4651 4676
4652 /* 4677 /*
@@ -4654,7 +4679,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
4654 * To avoid multiple parsing of same block, lets parse that map 4679 * To avoid multiple parsing of same block, lets parse that map
4655 * from sink info, before parsing CEA modes. 4680 * from sink info, before parsing CEA modes.
4656 */ 4681 */
4657 drm_add_display_info(connector, edid, quirks); 4682 quirks = drm_add_display_info(connector, edid);
4658 4683
4659 /* 4684 /*
4660 * EDID spec says modes should be preferred in this order: 4685 * 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,
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);