mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	drm/edid: Parse and handle HDMI deep color modes.
Check the HDMI cea block for deep color mode bits. If available, assign the highest supported bpc for a hdmi display, corresponding to the given deep color modes. Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
		
							parent
							
								
									89b92339c1
								
							
						
					
					
						commit
						d0c94692e0
					
				
					 2 changed files with 113 additions and 2 deletions
				
			
		| 
						 | 
					@ -3422,17 +3422,117 @@ bool drm_rgb_quant_range_selectable(struct edid *edid)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(drm_rgb_quant_range_selectable);
 | 
					EXPORT_SYMBOL(drm_rgb_quant_range_selectable);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * drm_assign_hdmi_deep_color_info - detect whether monitor supports
 | 
				
			||||||
 | 
					 * hdmi deep color modes and update drm_display_info if so.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @edid: monitor EDID information
 | 
				
			||||||
 | 
					 * @info: Updated with maximum supported deep color bpc and color format
 | 
				
			||||||
 | 
					 *        if deep color supported.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Parse the CEA extension according to CEA-861-B.
 | 
				
			||||||
 | 
					 * Return true if HDMI deep color supported, false if not or unknown.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static bool drm_assign_hdmi_deep_color_info(struct edid *edid,
 | 
				
			||||||
 | 
					                                            struct drm_display_info *info,
 | 
				
			||||||
 | 
					                                            struct drm_connector *connector)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u8 *edid_ext, *hdmi;
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						int start_offset, end_offset;
 | 
				
			||||||
 | 
						unsigned int dc_bpc = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						edid_ext = drm_find_cea_extension(edid);
 | 
				
			||||||
 | 
						if (!edid_ext)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (cea_db_offsets(edid_ext, &start_offset, &end_offset))
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Because HDMI identifier is in Vendor Specific Block,
 | 
				
			||||||
 | 
						 * search it from all data blocks of CEA extension.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						for_each_cea_db(edid_ext, i, start_offset, end_offset) {
 | 
				
			||||||
 | 
							if (cea_db_is_hdmi_vsdb(&edid_ext[i])) {
 | 
				
			||||||
 | 
								/* HDMI supports at least 8 bpc */
 | 
				
			||||||
 | 
								info->bpc = 8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								hdmi = &edid_ext[i];
 | 
				
			||||||
 | 
								if (cea_db_payload_len(hdmi) < 6)
 | 
				
			||||||
 | 
									return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (hdmi[6] & DRM_EDID_HDMI_DC_30) {
 | 
				
			||||||
 | 
									dc_bpc = 10;
 | 
				
			||||||
 | 
									DRM_DEBUG("%s: HDMI sink does deep color 30.\n",
 | 
				
			||||||
 | 
											  drm_get_connector_name(connector));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (hdmi[6] & DRM_EDID_HDMI_DC_36) {
 | 
				
			||||||
 | 
									dc_bpc = 12;
 | 
				
			||||||
 | 
									DRM_DEBUG("%s: HDMI sink does deep color 36.\n",
 | 
				
			||||||
 | 
											  drm_get_connector_name(connector));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (hdmi[6] & DRM_EDID_HDMI_DC_48) {
 | 
				
			||||||
 | 
									dc_bpc = 16;
 | 
				
			||||||
 | 
									DRM_DEBUG("%s: HDMI sink does deep color 48.\n",
 | 
				
			||||||
 | 
											  drm_get_connector_name(connector));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (dc_bpc > 0) {
 | 
				
			||||||
 | 
									DRM_DEBUG("%s: Assigning HDMI sink color depth as %d bpc.\n",
 | 
				
			||||||
 | 
											  drm_get_connector_name(connector), dc_bpc);
 | 
				
			||||||
 | 
									info->bpc = dc_bpc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									/*
 | 
				
			||||||
 | 
									 * Deep color support mandates RGB444 support for all video
 | 
				
			||||||
 | 
									 * modes and forbids YCRCB422 support for all video modes per
 | 
				
			||||||
 | 
									 * HDMI 1.3 spec.
 | 
				
			||||||
 | 
									 */
 | 
				
			||||||
 | 
									info->color_formats = DRM_COLOR_FORMAT_RGB444;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									/* YCRCB444 is optional according to spec. */
 | 
				
			||||||
 | 
									if (hdmi[6] & DRM_EDID_HDMI_DC_Y444) {
 | 
				
			||||||
 | 
										info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
 | 
				
			||||||
 | 
										DRM_DEBUG("%s: HDMI sink does YCRCB444 in deep color.\n",
 | 
				
			||||||
 | 
												  drm_get_connector_name(connector));
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									/*
 | 
				
			||||||
 | 
									 * Spec says that if any deep color mode is supported at all,
 | 
				
			||||||
 | 
									 * then deep color 36 bit must be supported.
 | 
				
			||||||
 | 
									 */
 | 
				
			||||||
 | 
									if (!(hdmi[6] & DRM_EDID_HDMI_DC_36)) {
 | 
				
			||||||
 | 
										DRM_DEBUG("%s: HDMI sink should do DC_36, but does not!\n",
 | 
				
			||||||
 | 
												  drm_get_connector_name(connector));
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									return true;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else {
 | 
				
			||||||
 | 
									DRM_DEBUG("%s: No deep color support on this HDMI sink.\n",
 | 
				
			||||||
 | 
											  drm_get_connector_name(connector));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * drm_add_display_info - pull display info out if present
 | 
					 * drm_add_display_info - pull display info out if present
 | 
				
			||||||
 * @edid: EDID data
 | 
					 * @edid: EDID data
 | 
				
			||||||
 * @info: display info (attached to connector)
 | 
					 * @info: display info (attached to connector)
 | 
				
			||||||
 | 
					 * @connector: connector whose edid is used to build display info
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Grab any available display info and stuff it into the drm_display_info
 | 
					 * Grab any available display info and stuff it into the drm_display_info
 | 
				
			||||||
 * structure that's part of the connector.  Useful for tracking bpp and
 | 
					 * structure that's part of the connector.  Useful for tracking bpp and
 | 
				
			||||||
 * color spaces.
 | 
					 * color spaces.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void drm_add_display_info(struct edid *edid,
 | 
					static void drm_add_display_info(struct edid *edid,
 | 
				
			||||||
				 struct drm_display_info *info)
 | 
					                                 struct drm_display_info *info,
 | 
				
			||||||
 | 
					                                 struct drm_connector *connector)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	u8 *edid_ext;
 | 
						u8 *edid_ext;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3462,6 +3562,9 @@ static void drm_add_display_info(struct edid *edid,
 | 
				
			||||||
			info->color_formats |= DRM_COLOR_FORMAT_YCRCB422;
 | 
								info->color_formats |= DRM_COLOR_FORMAT_YCRCB422;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* HDMI deep color modes supported? Assign to info, if so */
 | 
				
			||||||
 | 
						drm_assign_hdmi_deep_color_info(edid, info, connector);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Only defined for 1.4 with digital displays */
 | 
						/* Only defined for 1.4 with digital displays */
 | 
				
			||||||
	if (edid->revision < 4)
 | 
						if (edid->revision < 4)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
| 
						 | 
					@ -3491,6 +3594,9 @@ static void drm_add_display_info(struct edid *edid,
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						DRM_DEBUG("%s: Assigning EDID-1.4 digital sink color depth as %d bpc.\n",
 | 
				
			||||||
 | 
								  drm_get_connector_name(connector), info->bpc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	info->color_formats |= DRM_COLOR_FORMAT_RGB444;
 | 
						info->color_formats |= DRM_COLOR_FORMAT_RGB444;
 | 
				
			||||||
	if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB444)
 | 
						if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB444)
 | 
				
			||||||
		info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
 | 
							info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
 | 
				
			||||||
| 
						 | 
					@ -3549,7 +3655,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
 | 
				
			||||||
	if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
 | 
						if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
 | 
				
			||||||
		edid_fixup_preferred(connector, quirks);
 | 
							edid_fixup_preferred(connector, quirks);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	drm_add_display_info(edid, &connector->display_info);
 | 
						drm_add_display_info(edid, &connector->display_info, connector);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (quirks & EDID_QUIRK_FORCE_8BPC)
 | 
						if (quirks & EDID_QUIRK_FORCE_8BPC)
 | 
				
			||||||
		connector->display_info.bpc = 8;
 | 
							connector->display_info.bpc = 8;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -202,6 +202,11 @@ struct detailed_timing {
 | 
				
			||||||
#define DRM_EDID_FEATURE_PM_SUSPEND       (1 << 6)
 | 
					#define DRM_EDID_FEATURE_PM_SUSPEND       (1 << 6)
 | 
				
			||||||
#define DRM_EDID_FEATURE_PM_STANDBY       (1 << 7)
 | 
					#define DRM_EDID_FEATURE_PM_STANDBY       (1 << 7)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DRM_EDID_HDMI_DC_48               (1 << 6)
 | 
				
			||||||
 | 
					#define DRM_EDID_HDMI_DC_36               (1 << 5)
 | 
				
			||||||
 | 
					#define DRM_EDID_HDMI_DC_30               (1 << 4)
 | 
				
			||||||
 | 
					#define DRM_EDID_HDMI_DC_Y444             (1 << 3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct edid {
 | 
					struct edid {
 | 
				
			||||||
	u8 header[8];
 | 
						u8 header[8];
 | 
				
			||||||
	/* Vendor & product info */
 | 
						/* Vendor & product info */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue