forked from mirrors/linux
		
	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
	
	 Ville Syrjälä
						Ville Syrjälä