[v7 1/5] drm/edid: seek for available CEA and DisplayID block from specific EDID block index

Drew Davenport ddavenport at chromium.org
Tue Mar 15 17:22:25 UTC 2022


On Tue, Mar 15, 2022 at 03:21:05PM +0000, Lee, Shawn C wrote:
> On Tuesday, March 15, 2022 8:33 PM, Nikula, Jani <jani.nikula at intel.com> wrote:
> >On Mon, 14 Mar 2022, Drew Davenport <ddavenport at chromium.org> wrote:
> >> On Mon, Mar 14, 2022 at 10:40:47AM +0200, Jani Nikula wrote:
> >>> On Sun, 13 Mar 2022, Lee Shawn C <shawn.c.lee at intel.com> wrote:
> >>> > drm_find_cea_extension() always look for a top level CEA block. 
> >>> > Pass ext_index from caller then this function to search next 
> >>> > available CEA ext block from a specific EDID block pointer.
> >>> >
> >>> > v2: save proper extension block index if CTA data information
> >>> >     was found in DispalyID block.
> >>> > v3: using different parameters to store CEA and DisplayID block index.
> >>> >     configure DisplayID extansion block index before search available
> >>> >     DisplayID block.
> >>> >
> >>> > Cc: Jani Nikula <jani.nikula at linux.intel.com>
> >>> > Cc: Ville Syrjala <ville.syrjala at linux.intel.com>
> >>> > Cc: Ankit Nautiyal <ankit.k.nautiyal at intel.com>
> >>> > Cc: Drew Davenport <ddavenport at chromium.org>
> >>> > Cc: intel-gfx <intel-gfx at lists.freedesktop.org>
> >>> > Signed-off-by: Lee Shawn C <shawn.c.lee at intel.com>
> >>> > ---
> >>> >  drivers/gpu/drm/drm_displayid.c | 10 +++++--
> >>> >  drivers/gpu/drm/drm_edid.c      | 53 ++++++++++++++++++---------------
> >>> >  include/drm/drm_displayid.h     |  4 +--
> >>> >  3 files changed, 39 insertions(+), 28 deletions(-)
> >>> >
> >>> > diff --git a/drivers/gpu/drm/drm_displayid.c 
> >>> > b/drivers/gpu/drm/drm_displayid.c index 32da557b960f..31c3e6d7d549 
> >>> > 100644
> >>> > --- a/drivers/gpu/drm/drm_displayid.c
> >>> > +++ b/drivers/gpu/drm/drm_displayid.c
> >>> > @@ -59,11 +59,14 @@ static const u8 
> >>> > *drm_find_displayid_extension(const struct edid *edid,  }
> >>> >  
> >>> >  void displayid_iter_edid_begin(const struct edid *edid,
> >>> > -			       struct displayid_iter *iter)
> >>> > +			       struct displayid_iter *iter, int *ext_index)
> >>> 
> >>> Please don't do this. This just ruins the clean approach displayid 
> >>> iterator added.
> >>> 
> >>> Instead of making the displayid iterator ugly, and leaking its 
> >>> abstractions, I'll repeat what I said should be done in reply to the 
> >>> very first version of this patch series [1]:
> >>> 
> >>> "I think we're going to need abstracted EDID iteration similar to 
> >>> what I've done for DisplayID iteration. We can't have all places 
> >>> reimplementing the iteration like we have now."
> >>> 
> >>> This isn't a problem that should be solved by having all the callers 
> >>> hold a bunch of local variables and pass them around to all the 
> >>> functions. Nobody's going to be able to keep track of this anymore. 
> >>> And this series, as it is, makes it harder to fix this properly later on.
> >>
> >> I missed your original review comment, so apologies for repeating what 
> >> you said there already.
> >>
> >> I'd agree that passing a starting index to the displayid_iter_* 
> >> functions is probably not the right direction here. More thoughts below.
> >>
> >>> 
> >>> 
> >>> BR,
> >>> Jani.
> >>> 
> >>> 
> >>> [1] https://lore.kernel.org/r/87czjf8dik.fsf@intel.com
> >>> 
> >>> 
> >>> 
> >>> >  {
> >>> >  	memset(iter, 0, sizeof(*iter));
> >>> >  
> >>> >  	iter->edid = edid;
> >>> > +
> >>> > +	if (ext_index)
> >>> > +		iter->ext_index = *ext_index;
> >>> >  }
> >>> >  
> >>> >  static const struct displayid_block * @@ -126,7 +129,10 @@ 
> >>> > __displayid_iter_next(struct displayid_iter *iter)
> >>> >  	}
> >>> >  }
> >>> >  
> >>> > -void displayid_iter_end(struct displayid_iter *iter)
> >>> > +void displayid_iter_end(struct displayid_iter *iter, int 
> >>> > +*ext_index)
> >>> >  {
> >>> > +	if (ext_index)
> >>> > +		*ext_index = iter->ext_index;
> >>> > +
> >>> >  	memset(iter, 0, sizeof(*iter));
> >>> >  }
> >>> > diff --git a/drivers/gpu/drm/drm_edid.c 
> >>> > b/drivers/gpu/drm/drm_edid.c index 561f53831e29..78c415aa6889 
> >>> > 100644
> >>> > --- a/drivers/gpu/drm/drm_edid.c
> >>> > +++ b/drivers/gpu/drm/drm_edid.c
> >>> > @@ -3353,28 +3353,27 @@ const u8 *drm_find_edid_extension(const struct edid *edid,
> >>> >  	return edid_ext;
> >>> >  }
> >>> >  
> >>> > -static const u8 *drm_find_cea_extension(const struct edid *edid)
> >>> > +static const u8 *drm_find_cea_extension(const struct edid *edid,
> >>> > +					int *cea_ext_index, int *displayid_ext_index)
> >>
> >> As discussed above, passing both indices into this function may not be 
> >> the best approach here. But I think we need to keep track of some kind 
> >> of state in order to know which was the last CEA block that was 
> >> returned, and thus this function can return the next one after that, 
> >> whether it's in the CEA extension block or DisplayID block.
> >
> >Per DisplayID v1.3 Appendix B: DisplayID as an EDID Extension, it's recommended that DisplayID extensions are exposed after all of the CEA extensions.
> >
> >I think it should be fine to first iterate over all CEA extensions across the EDID, followed by iterating over all the DisplayID extensions. No need to keep track of the order between CEA and DisplayID, as the former should precede the latter.
> >
> 
> Refer to "DisplayID extensions are exposed after all of the CEA extensions". It looks to me patch v5 is able to support this. And did not touch DisplayID iterator.
> https://patchwork.freedesktop.org/series/100690/#rev5

Patch v5 does not iterate over all the DisplayID extensions, and it has
the previously mentioned problem about resulting in a possible infinite
loop when depending on ext_index to iterate over the CEA extensions.

> 
> >> What do you think of using the pointer returned from this function as 
> >> that state? The caller could pass in a u8* that was returned from a 
> >> previous call. This function would iterate through the extension 
> >> blocks and skip the CEA blocks it finds until it finds the passed in 
> >> pointer, and then return the next one after (or NULL).
> >>
> >> An alternative might be to create a linked list of ptrs to the edid 
> >> extension blocks, and allow a caller to iterate over them in whatever 
> >> way they need, but I'm not sure how useful that is elsewhere.
> >
> >I think the main problem here is trying to hack a for loop around
> >drm_find_cea_extension() and drm_find_edid_extension(), and duplicating that all over the place, without adding more structure or abstractions.
> >
> >Contrast with displayid_iter_edid_begin(), displayid_iter_for_each(), and displayid_iter_end() and their usage. They hide all the complexity of looping across DisplayID data blocks inside EDID extensions, and none of the users need to be aware of that complexity. All the state is hidden in struct displayid_iter, and the users don't need to look inside. No allocations, no linked lists.
> >
> >I think it's particularly bad to have the changes here break the abstractions in displayid_iter_*, especially because they should be usable for pure DisplayID 2.0 *without* an EDID block structure. They'll just need a displayid_iter_begin() for pure DisplayID and some internal changes.
> >
> >Looking at the usage, the iteration should probably be done at the CEA data block level, something like this:
> >
> >	struct cea_iter iter;
> >        const struct cea_block *block;
> >
> >	cea_iter_edid_begin(edid, &iter);
> >        cea_iter_for_each(block, &iter) {
> >		/* ... */        
> >        }
> >        cea_iter_end(&iter);
> >
> >This would replace cea_db_offsets() and for_each_cea_db(), and would iterate across the all CEA and DisplayID extensions in the entire EDID.
> >
> >This looks usable, and then you'd start figuring out how to implement that, instead of trying to retrofit all the existing usages to abstractions that don't cut it. You'll probably need an EDID extension iterator too, and then use that and __displayid_iter_next() within
> >cea_iter_for_each() i.e. you'd embed the edid_iter and displayid_iter within struct cea_iter. Exhaust the former first, and then the latter.
> >
> >
> >BR,
> >Jani.
> >
> 
> Hi Jani, Drew, thank you all for your comment! Agree that edid driver may need
> abstracted EDID iteration similar to what you did for DisplayID iteration.
> It will need a lot of code changes in drm driver.
> 
> But, we have a tight schedule and have to meet HDMI 2.1 compliance test requirement.
> Do you think this series can be a short term solution to pass HDMI CTS test?
> And we can have another long term plan to work on your opinion to modify
> the iterator and make edid driver more efficient and easier to maintain.
> 
> Best regards,
> Shawn
> 
> >
> >>
> >>> >  {
> >>> >  	const struct displayid_block *block;
> >>> >  	struct displayid_iter iter;
> >>> >  	const u8 *cea;
> >>> > -	int ext_index = 0;
> >>> >  
> >>> > -	/* Look for a top level CEA extension block */
> >>> > -	/* FIXME: make callers iterate through multiple CEA ext blocks? */
> >>> > -	cea = drm_find_edid_extension(edid, CEA_EXT, &ext_index);
> >>> > +	/* Look for a CEA extension block from ext_index */
> >>> > +	cea = drm_find_edid_extension(edid, CEA_EXT, cea_ext_index);
> >>> >  	if (cea)
> >>> >  		return cea;
> >>> >  
> >>> >  	/* CEA blocks can also be found embedded in a DisplayID block */
> >>> > -	displayid_iter_edid_begin(edid, &iter);
> >>> > +	displayid_iter_edid_begin(edid, &iter, displayid_ext_index);
> >>> >  	displayid_iter_for_each(block, &iter) {
> >>> >  		if (block->tag == DATA_BLOCK_CTA) {
> >>> >  			cea = (const u8 *)block;
> >>> >  			break;
> >>> >  		}
> >>> >  	}
> >>> > -	displayid_iter_end(&iter);
> >>> > +	displayid_iter_end(&iter, displayid_ext_index);
> >>> >  
> >>> >  	return cea;
> >>> >  }
> >>> > @@ -3643,10 +3642,10 @@ add_alternate_cea_modes(struct drm_connector *connector, struct edid *edid)
> >>> >  	struct drm_device *dev = connector->dev;
> >>> >  	struct drm_display_mode *mode, *tmp;
> >>> >  	LIST_HEAD(list);
> >>> > -	int modes = 0;
> >>> > +	int modes = 0, cea_ext_index = 0, displayid_ext_index = 0;
> >>> >  
> >>> >  	/* Don't add CEA modes if the CEA extension block is missing */
> >>> > -	if (!drm_find_cea_extension(edid))
> >>> > +	if (!drm_find_cea_extension(edid, &cea_ext_index, 
> >>> > +&displayid_ext_index))
> >>> >  		return 0;
> >>> >  
> >>> >  	/*
> >>> > @@ -4321,11 +4320,11 @@ static void 
> >>> > drm_parse_y420cmdb_bitmap(struct drm_connector *connector,  static 
> >>> > int  add_cea_modes(struct drm_connector *connector, struct edid 
> >>> > *edid)  {
> >>> > -	const u8 *cea = drm_find_cea_extension(edid);
> >>> > -	const u8 *db, *hdmi = NULL, *video = NULL;
> >>> > +	const u8 *cea, *db, *hdmi = NULL, *video = NULL;
> >>> >  	u8 dbl, hdmi_len, video_len = 0;
> >>> > -	int modes = 0;
> >>> > +	int modes = 0, cea_ext_index = 0, displayid_ext_index = 0;
> >>> >  
> >>> > +	cea = drm_find_cea_extension(edid, &cea_ext_index, 
> >>> > +&displayid_ext_index);
> >>> >  	if (cea && cea_revision(cea) >= 3) {
> >>> >  		int i, start, end;
> >>> >  
> >>> > @@ -4563,6 +4562,7 @@ static void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid)
> >>> >  	const u8 *cea;
> >>> >  	const u8 *db;
> >>> >  	int total_sad_count = 0;
> >>> > +	int cea_ext_index = 0, displayid_ext_index = 0;
> >>> >  	int mnl;
> >>> >  	int dbl;
> >>> >  
> >>> > @@ -4571,7 +4571,7 @@ static void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid)
> >>> >  	if (!edid)
> >>> >  		return;
> >>> >  
> >>> > -	cea = drm_find_cea_extension(edid);
> >>> > +	cea = drm_find_cea_extension(edid, &cea_ext_index, 
> >>> > +&displayid_ext_index);
> >>> >  	if (!cea) {
> >>> >  		DRM_DEBUG_KMS("ELD: no CEA Extension found\n");
> >>> >  		return;
> >>> > @@ -4657,9 +4657,10 @@ int drm_edid_to_sad(struct edid *edid, 
> >>> > struct cea_sad **sads)  {
> >>> >  	int count = 0;
> >>> >  	int i, start, end, dbl;
> >>> > +	int cea_ext_index = 0, displayid_ext_index = 0;
> >>> >  	const u8 *cea;
> >>> >  
> >>> > -	cea = drm_find_cea_extension(edid);
> >>> > +	cea = drm_find_cea_extension(edid, &cea_ext_index, 
> >>> > +&displayid_ext_index);
> >>> >  	if (!cea) {
> >>> >  		DRM_DEBUG_KMS("SAD: no CEA Extension found\n");
> >>> >  		return 0;
> >>> > @@ -4719,9 +4720,10 @@ int drm_edid_to_speaker_allocation(struct 
> >>> > edid *edid, u8 **sadb)  {
> >>> >  	int count = 0;
> >>> >  	int i, start, end, dbl;
> >>> > +	int cea_ext_index = 0, displayid_ext_index = 0;
> >>> >  	const u8 *cea;
> >>> >  
> >>> > -	cea = drm_find_cea_extension(edid);
> >>> > +	cea = drm_find_cea_extension(edid, &cea_ext_index, 
> >>> > +&displayid_ext_index);
> >>> >  	if (!cea) {
> >>> >  		DRM_DEBUG_KMS("SAD: no CEA Extension found\n");
> >>> >  		return 0;
> >>> > @@ -4815,8 +4817,9 @@ bool drm_detect_hdmi_monitor(struct edid *edid)
> >>> >  	const u8 *edid_ext;
> >>> >  	int i;
> >>> >  	int start_offset, end_offset;
> >>> > +	int cea_ext_index = 0, displayid_ext_index = 0;
> >>> >  
> >>> > -	edid_ext = drm_find_cea_extension(edid);
> >>> > +	edid_ext = drm_find_cea_extension(edid, &cea_ext_index, 
> >>> > +&displayid_ext_index);
> >>> >  	if (!edid_ext)
> >>> >  		return false;
> >>> >  
> >>> > @@ -4854,8 +4857,9 @@ bool drm_detect_monitor_audio(struct edid *edid)
> >>> >  	int i, j;
> >>> >  	bool has_audio = false;
> >>> >  	int start_offset, end_offset;
> >>> > +	int cea_ext_index = 0, displayid_ext_index = 0;
> >>> >  
> >>> > -	edid_ext = drm_find_cea_extension(edid);
> >>> > +	edid_ext = drm_find_cea_extension(edid, &cea_ext_index, 
> >>> > +&displayid_ext_index);
> >>> >  	if (!edid_ext)
> >>> >  		goto end;
> >>> >  
> >>> > @@ -5178,8 +5182,9 @@ static void drm_parse_cea_ext(struct drm_connector *connector,
> >>> >  	struct drm_display_info *info = &connector->display_info;
> >>> >  	const u8 *edid_ext;
> >>> >  	int i, start, end;
> >>> > +	int cea_ext_index = 0, displayid_ext_index = 0;
> >>> >  
> >>> > -	edid_ext = drm_find_cea_extension(edid);
> >>> > +	edid_ext = drm_find_cea_extension(edid, &cea_ext_index, 
> >>> > +&displayid_ext_index);
> >>> >  	if (!edid_ext)
> >>> >  		return;
> >>> >  
> >>> > @@ -5311,12 +5316,12 @@ static void drm_update_mso(struct drm_connector *connector, const struct edid *e
> >>> >  	const struct displayid_block *block;
> >>> >  	struct displayid_iter iter;
> >>> >  
> >>> > -	displayid_iter_edid_begin(edid, &iter);
> >>> > +	displayid_iter_edid_begin(edid, &iter, NULL);
> >>> >  	displayid_iter_for_each(block, &iter) {
> >>> >  		if (block->tag == DATA_BLOCK_2_VENDOR_SPECIFIC)
> >>> >  			drm_parse_vesa_mso_data(connector, block);
> >>> >  	}
> >>> > -	displayid_iter_end(&iter);
> >>> > +	displayid_iter_end(&iter, NULL);
> >>> >  }
> >>> >  
> >>> >  /* A connector has no EDID information, so we've got no EDID to 
> >>> > compute quirks from. Reset @@ -5516,13 +5521,13 @@ static int add_displayid_detailed_modes(struct drm_connector *connector,
> >>> >  	struct displayid_iter iter;
> >>> >  	int num_modes = 0;
> >>> >  
> >>> > -	displayid_iter_edid_begin(edid, &iter);
> >>> > +	displayid_iter_edid_begin(edid, &iter, NULL);
> >>> >  	displayid_iter_for_each(block, &iter) {
> >>> >  		if (block->tag == DATA_BLOCK_TYPE_1_DETAILED_TIMING ||
> >>> >  		    block->tag == DATA_BLOCK_2_TYPE_7_DETAILED_TIMING)
> >>> >  			num_modes += add_displayid_detailed_1_modes(connector, block);
> >>> >  	}
> >>> > -	displayid_iter_end(&iter);
> >>> > +	displayid_iter_end(&iter, NULL);
> >>> >  
> >>> >  	return num_modes;
> >>> >  }
> >>> > @@ -6164,12 +6169,12 @@ void drm_update_tile_info(struct 
> >>> > drm_connector *connector,
> >>> >  
> >>> >  	connector->has_tile = false;
> >>> >  
> >>> > -	displayid_iter_edid_begin(edid, &iter);
> >>> > +	displayid_iter_edid_begin(edid, &iter, NULL);
> >>> >  	displayid_iter_for_each(block, &iter) {
> >>> >  		if (block->tag == DATA_BLOCK_TILED_DISPLAY)
> >>> >  			drm_parse_tiled_block(connector, block);
> >>> >  	}
> >>> > -	displayid_iter_end(&iter);
> >>> > +	displayid_iter_end(&iter, NULL);
> >>> >  
> >>> >  	if (!connector->has_tile && connector->tile_group) {
> >>> >  		drm_mode_put_tile_group(connector->dev, connector->tile_group); 
> >>> > diff --git a/include/drm/drm_displayid.h 
> >>> > b/include/drm/drm_displayid.h index 7ffbd9f7bfc7..15442a161c11 
> >>> > 100644
> >>> > --- a/include/drm/drm_displayid.h
> >>> > +++ b/include/drm/drm_displayid.h
> >>> > @@ -150,11 +150,11 @@ struct displayid_iter {  };
> >>> >  
> >>> >  void displayid_iter_edid_begin(const struct edid *edid,
> >>> > -			       struct displayid_iter *iter);
> >>> > +			       struct displayid_iter *iter, int *ext_index);
> >>> >  const struct displayid_block *
> >>> >  __displayid_iter_next(struct displayid_iter *iter);  #define 
> >>> > displayid_iter_for_each(__block, __iter) \
> >>> >  	while (((__block) = __displayid_iter_next(__iter))) -void 
> >>> > displayid_iter_end(struct displayid_iter *iter);
> >>> > +void displayid_iter_end(struct displayid_iter *iter, int 
> >>> > +*ext_index);
> >>> >  
> >>> >  #endif
> >>> 
> >>> --
> >>> Jani Nikula, Intel Open Source Graphics Center
> >
> >--
> >Jani Nikula, Intel Open Source Graphics Center


More information about the dri-devel mailing list