mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	drm/edid: Fix up clock for CEA/HDMI modes specified via detailed timings
EDID detailed timings have a resolution of 10kHz for the pixel clock, so they can't represent certain CEA/HDMI modes accurately. If we see a mode coming in via detailed timings which otherwise matches one of the CEA/HDMI modes except the clock is just a bit off, let's assume that the intention was for that mode to be one of the CEA/HDMI modes and go ahead and fix up the clock to match the CEA/HDMI spec exactly (well, as close as we can get with the 1 kHz resolution we use). This should help code that's looking for an exact clock match (eg. i915 audio N/CTS setup). Cc: Adam Jackson <ajax@redhat.com> Cc: Clint Taylor <clinton.a.taylor@intel.com> Cc: Libin Yang <libin.yang@intel.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
This commit is contained in:
		
							parent
							
								
									affa0e033b
								
							
						
					
					
						commit
						fa3a7340ea
					
				
					 1 changed files with 48 additions and 0 deletions
				
			
		| 
						 | 
				
			
			@ -2418,6 +2418,8 @@ add_cvt_modes(struct drm_connector *connector, struct edid *edid)
 | 
			
		|||
	return closure.modes;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void fixup_detailed_cea_mode_clock(struct drm_display_mode *mode);
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
do_detailed_mode(struct detailed_timing *timing, void *c)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -2434,6 +2436,13 @@ do_detailed_mode(struct detailed_timing *timing, void *c)
 | 
			
		|||
		if (closure->preferred)
 | 
			
		||||
			newmode->type |= DRM_MODE_TYPE_PREFERRED;
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * Detailed modes are limited to 10kHz pixel clock resolution,
 | 
			
		||||
		 * so fix up anything that looks like CEA/HDMI mode, but the clock
 | 
			
		||||
		 * is just slightly off.
 | 
			
		||||
		 */
 | 
			
		||||
		fixup_detailed_cea_mode_clock(newmode);
 | 
			
		||||
 | 
			
		||||
		drm_mode_probed_add(closure->connector, newmode);
 | 
			
		||||
		closure->modes++;
 | 
			
		||||
		closure->preferred = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -3103,6 +3112,45 @@ add_cea_modes(struct drm_connector *connector, struct edid *edid)
 | 
			
		|||
	return modes;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void fixup_detailed_cea_mode_clock(struct drm_display_mode *mode)
 | 
			
		||||
{
 | 
			
		||||
	const struct drm_display_mode *cea_mode;
 | 
			
		||||
	int clock1, clock2, clock;
 | 
			
		||||
	u8 mode_idx;
 | 
			
		||||
	const char *type;
 | 
			
		||||
 | 
			
		||||
	mode_idx = drm_match_cea_mode(mode) - 1;
 | 
			
		||||
	if (mode_idx < ARRAY_SIZE(edid_cea_modes)) {
 | 
			
		||||
		type = "CEA";
 | 
			
		||||
		cea_mode = &edid_cea_modes[mode_idx];
 | 
			
		||||
		clock1 = cea_mode->clock;
 | 
			
		||||
		clock2 = cea_mode_alternate_clock(cea_mode);
 | 
			
		||||
	} else {
 | 
			
		||||
		mode_idx = drm_match_hdmi_mode(mode) - 1;
 | 
			
		||||
		if (mode_idx < ARRAY_SIZE(edid_4k_modes)) {
 | 
			
		||||
			type = "HDMI";
 | 
			
		||||
			cea_mode = &edid_4k_modes[mode_idx];
 | 
			
		||||
			clock1 = cea_mode->clock;
 | 
			
		||||
			clock2 = hdmi_mode_alternate_clock(cea_mode);
 | 
			
		||||
		} else {
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* pick whichever is closest */
 | 
			
		||||
	if (abs(mode->clock - clock1) < abs(mode->clock - clock2))
 | 
			
		||||
		clock = clock1;
 | 
			
		||||
	else
 | 
			
		||||
		clock = clock2;
 | 
			
		||||
 | 
			
		||||
	if (mode->clock == clock)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	DRM_DEBUG("detailed mode matches %s VIC %d, adjusting clock %d -> %d\n",
 | 
			
		||||
		  type, mode_idx + 1, mode->clock, clock);
 | 
			
		||||
	mode->clock = clock;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
parse_hdmi_vsdb(struct drm_connector *connector, const u8 *db)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue