mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	drm/edid: Unify detailed block parsing between base and extension blocks
Also fix an embarassing bug in standard timing subblock parsing that would result in an infinite loop. Signed-off-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
This commit is contained in:
		
							parent
							
								
									9632b41f00
								
							
						
					
					
						commit
						9cf00977da
					
				
					 1 changed files with 61 additions and 102 deletions
				
			
		| 
						 | 
				
			
			@ -838,8 +838,57 @@ static int add_standard_modes(struct drm_connector *connector, struct edid *edid
 | 
			
		|||
	return modes;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int add_detailed_modes(struct drm_connector *connector,
 | 
			
		||||
			      struct detailed_timing *timing,
 | 
			
		||||
			      struct edid *edid, u32 quirks, int preferred)
 | 
			
		||||
{
 | 
			
		||||
	int i, modes = 0;
 | 
			
		||||
	struct detailed_non_pixel *data = &timing->data.other_data;
 | 
			
		||||
	int timing_level = standard_timing_level(edid);
 | 
			
		||||
	struct drm_display_mode *newmode;
 | 
			
		||||
	struct drm_device *dev = connector->dev;
 | 
			
		||||
 | 
			
		||||
	if (timing->pixel_clock) {
 | 
			
		||||
		newmode = drm_mode_detailed(dev, edid, timing, quirks);
 | 
			
		||||
		if (!newmode)
 | 
			
		||||
			return 0;
 | 
			
		||||
 | 
			
		||||
		if (preferred)
 | 
			
		||||
			newmode->type |= DRM_MODE_TYPE_PREFERRED;
 | 
			
		||||
 | 
			
		||||
		drm_mode_probed_add(connector, newmode);
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* other timing types */
 | 
			
		||||
	switch (data->type) {
 | 
			
		||||
	case EDID_DETAIL_MONITOR_RANGE:
 | 
			
		||||
		/* Get monitor range data */
 | 
			
		||||
		break;
 | 
			
		||||
	case EDID_DETAIL_STD_MODES:
 | 
			
		||||
		/* Six modes per detailed section */
 | 
			
		||||
		for (i = 0; i < 6; i++) {
 | 
			
		||||
			struct std_timing *std;
 | 
			
		||||
			struct drm_display_mode *newmode;
 | 
			
		||||
 | 
			
		||||
			std = &data->data.timings[i];
 | 
			
		||||
			newmode = drm_mode_std(dev, std, edid->revision,
 | 
			
		||||
					       timing_level);
 | 
			
		||||
			if (newmode) {
 | 
			
		||||
				drm_mode_probed_add(connector, newmode);
 | 
			
		||||
				modes++;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return modes;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * add_detailed_modes - get detailed mode info from EDID data
 | 
			
		||||
 * add_detailed_info - get detailed mode info from EDID data
 | 
			
		||||
 * @connector: attached connector
 | 
			
		||||
 * @edid: EDID block to scan
 | 
			
		||||
 * @quirks: quirks to apply
 | 
			
		||||
| 
						 | 
				
			
			@ -850,67 +899,24 @@ static int add_standard_modes(struct drm_connector *connector, struct edid *edid
 | 
			
		|||
static int add_detailed_info(struct drm_connector *connector,
 | 
			
		||||
			     struct edid *edid, u32 quirks)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_device *dev = connector->dev;
 | 
			
		||||
	int i, j, modes = 0;
 | 
			
		||||
	int timing_level;
 | 
			
		||||
 | 
			
		||||
	timing_level = standard_timing_level(edid);
 | 
			
		||||
	int i, modes = 0;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < EDID_DETAILED_TIMINGS; i++) {
 | 
			
		||||
		struct detailed_timing *timing = &edid->detailed_timings[i];
 | 
			
		||||
		struct detailed_non_pixel *data = &timing->data.other_data;
 | 
			
		||||
		struct drm_display_mode *newmode;
 | 
			
		||||
		int preferred = (i == 0) && (edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING);
 | 
			
		||||
 | 
			
		||||
		/* X server check is version 1.1 or higher */
 | 
			
		||||
		if (edid->version == 1 && edid->revision >= 1 &&
 | 
			
		||||
		    !timing->pixel_clock) {
 | 
			
		||||
			/* Other timing or info */
 | 
			
		||||
			switch (data->type) {
 | 
			
		||||
			case EDID_DETAIL_MONITOR_SERIAL:
 | 
			
		||||
				break;
 | 
			
		||||
			case EDID_DETAIL_MONITOR_STRING:
 | 
			
		||||
				break;
 | 
			
		||||
			case EDID_DETAIL_MONITOR_RANGE:
 | 
			
		||||
				/* Get monitor range data */
 | 
			
		||||
				break;
 | 
			
		||||
			case EDID_DETAIL_MONITOR_NAME:
 | 
			
		||||
				break;
 | 
			
		||||
			case EDID_DETAIL_MONITOR_CPDATA:
 | 
			
		||||
				break;
 | 
			
		||||
			case EDID_DETAIL_STD_MODES:
 | 
			
		||||
				for (j = 0; j < 6; i++) {
 | 
			
		||||
					struct std_timing *std;
 | 
			
		||||
					struct drm_display_mode *newmode;
 | 
			
		||||
		/* In 1.0, only timings are allowed */
 | 
			
		||||
		if (!timing->pixel_clock && edid->version == 1 &&
 | 
			
		||||
			edid->revision == 0)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
					std = &data->data.timings[j];
 | 
			
		||||
					newmode = drm_mode_std(dev, std,
 | 
			
		||||
							       edid->revision,
 | 
			
		||||
							       timing_level);
 | 
			
		||||
					if (newmode) {
 | 
			
		||||
						drm_mode_probed_add(connector, newmode);
 | 
			
		||||
						modes++;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				break;
 | 
			
		||||
			default:
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			newmode = drm_mode_detailed(dev, edid, timing, quirks);
 | 
			
		||||
			if (!newmode)
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
			/* First detailed mode is preferred */
 | 
			
		||||
			if (i == 0 && (edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING))
 | 
			
		||||
				newmode->type |= DRM_MODE_TYPE_PREFERRED;
 | 
			
		||||
			drm_mode_probed_add(connector, newmode);
 | 
			
		||||
 | 
			
		||||
			modes++;
 | 
			
		||||
		}
 | 
			
		||||
		modes += add_detailed_modes(connector, timing, edid, quirks,
 | 
			
		||||
					    preferred);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return modes;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * add_detailed_mode_eedid - get detailed mode info from addtional timing
 | 
			
		||||
 * 			EDID block
 | 
			
		||||
| 
						 | 
				
			
			@ -924,12 +930,9 @@ static int add_detailed_info(struct drm_connector *connector,
 | 
			
		|||
static int add_detailed_info_eedid(struct drm_connector *connector,
 | 
			
		||||
			     struct edid *edid, u32 quirks)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_device *dev = connector->dev;
 | 
			
		||||
	int i, j, modes = 0;
 | 
			
		||||
	int i, modes = 0;
 | 
			
		||||
	char *edid_ext = NULL;
 | 
			
		||||
	struct detailed_timing *timing;
 | 
			
		||||
	struct detailed_non_pixel *data;
 | 
			
		||||
	struct drm_display_mode *newmode;
 | 
			
		||||
	int edid_ext_num;
 | 
			
		||||
	int start_offset, end_offset;
 | 
			
		||||
	int timing_level;
 | 
			
		||||
| 
						 | 
				
			
			@ -980,51 +983,7 @@ static int add_detailed_info_eedid(struct drm_connector *connector,
 | 
			
		|||
	for (i = start_offset; i < end_offset;
 | 
			
		||||
			i += sizeof(struct detailed_timing)) {
 | 
			
		||||
		timing = (struct detailed_timing *)(edid_ext + i);
 | 
			
		||||
		data = &timing->data.other_data;
 | 
			
		||||
		/* Detailed mode timing */
 | 
			
		||||
		if (timing->pixel_clock) {
 | 
			
		||||
			newmode = drm_mode_detailed(dev, edid, timing, quirks);
 | 
			
		||||
			if (!newmode)
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
			drm_mode_probed_add(connector, newmode);
 | 
			
		||||
 | 
			
		||||
			modes++;
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* Other timing or info */
 | 
			
		||||
		switch (data->type) {
 | 
			
		||||
		case EDID_DETAIL_MONITOR_SERIAL:
 | 
			
		||||
			break;
 | 
			
		||||
		case EDID_DETAIL_MONITOR_STRING:
 | 
			
		||||
			break;
 | 
			
		||||
		case EDID_DETAIL_MONITOR_RANGE:
 | 
			
		||||
			/* Get monitor range data */
 | 
			
		||||
			break;
 | 
			
		||||
		case EDID_DETAIL_MONITOR_NAME:
 | 
			
		||||
			break;
 | 
			
		||||
		case EDID_DETAIL_MONITOR_CPDATA:
 | 
			
		||||
			break;
 | 
			
		||||
		case EDID_DETAIL_STD_MODES:
 | 
			
		||||
			/* Five modes per detailed section */
 | 
			
		||||
			for (j = 0; j < 5; i++) {
 | 
			
		||||
				struct std_timing *std;
 | 
			
		||||
				struct drm_display_mode *newmode;
 | 
			
		||||
 | 
			
		||||
				std = &data->data.timings[j];
 | 
			
		||||
				newmode = drm_mode_std(dev, std,
 | 
			
		||||
						       edid->revision,
 | 
			
		||||
						       timing_level);
 | 
			
		||||
				if (newmode) {
 | 
			
		||||
					drm_mode_probed_add(connector, newmode);
 | 
			
		||||
					modes++;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		modes += add_detailed_modes(connector, timing, edid, quirks, 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return modes;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue