Loading drivers/gpu/drm/drm_edid.c +171 −0 Original line number Diff line number Diff line Loading @@ -3076,6 +3076,21 @@ static bool cea_db_is_hdmi_vsdb(const u8 *db) return hdmi_id == HDMI_IEEE_OUI; } static bool cea_db_is_hdmi_hf_vsdb(const u8 *db) { int hdmi_id; if (cea_db_tag(db) != VENDOR_BLOCK) return false; if (cea_db_payload_len(db) < 7) return false; hdmi_id = db[1] | (db[2] << 8) | (db[3] << 16); return hdmi_id == HDMI_IEEE_OUI_HF; } #define for_each_cea_db(cea, i, start, end) \ for ((i) = (start); (i) < (end) && (i) + cea_db_payload_len(&(cea)[(i)]) < (end); (i) += cea_db_payload_len(&(cea)[(i)]) + 1) Loading Loading @@ -3198,6 +3213,37 @@ parse_hdmi_vsdb(struct drm_connector *connector, const u8 *db) connector->audio_latency[1]); } static void parse_hdmi_hf_vsdb(struct drm_connector *connector, const u8 *db) { u8 len = cea_db_payload_len(db); if (len < 7) return; if (db[4] != 1) return; /* invalid version */ connector->max_tmds_char = db[5] * 5; connector->scdc_present = db[6] & (1 << 7); connector->rr_capable = db[6] & (1 << 6); connector->flags_3d = db[6] & 0x7; connector->supports_scramble = connector->scdc_present && (db[6] & (1 << 3)); DRM_DEBUG_KMS("HDMI v2: max TMDS char %d, " "scdc %s, " "rr %s, " "3D flags 0x%x, " "scramble %s\n", connector->max_tmds_char, connector->scdc_present ? "available" : "not available", connector->rr_capable ? "capable" : "not capable", connector->flags_3d, connector->supports_scramble ? "supported" : "not supported"); } static void monitor_name(struct detailed_timing *t, void *data) { Loading Loading @@ -3277,6 +3323,9 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) /* HDMI Vendor-Specific Data Block */ if (cea_db_is_hdmi_vsdb(db)) parse_hdmi_vsdb(connector, db); /* HDMI Forum Vendor-Specific Data Block */ else if (cea_db_is_hdmi_hf_vsdb(db)) parse_hdmi_hf_vsdb(connector, db); break; default: break; Loading Loading @@ -3799,6 +3848,124 @@ static int validate_displayid(u8 *displayid, int length, int idx) return 0; } static struct drm_display_mode * drm_mode_displayid_detailed(struct drm_device *dev, struct displayid_detailed_timings_1 *timings) { struct drm_display_mode *mode; unsigned pixel_clock = (timings->pixel_clock[0] | (timings->pixel_clock[1] << 8) | (timings->pixel_clock[2] << 16)); unsigned hactive = (timings->hactive[0] | timings->hactive[1] << 8) + 1; unsigned hblank = (timings->hblank[0] | timings->hblank[1] << 8) + 1; unsigned hsync = (timings->hsync[0] | (timings->hsync[1] & 0x7f) << 8) + 1; unsigned hsync_width = (timings->hsw[0] | timings->hsw[1] << 8) + 1; unsigned vactive = (timings->vactive[0] | timings->vactive[1] << 8) + 1; unsigned vblank = (timings->vblank[0] | timings->vblank[1] << 8) + 1; unsigned vsync = (timings->vsync[0] | (timings->vsync[1] & 0x7f) << 8) + 1; unsigned vsync_width = (timings->vsw[0] | timings->vsw[1] << 8) + 1; bool hsync_positive = (timings->hsync[1] >> 7) & 0x1; bool vsync_positive = (timings->vsync[1] >> 7) & 0x1; mode = drm_mode_create(dev); if (!mode) return NULL; mode->clock = pixel_clock * 10; mode->hdisplay = hactive; mode->hsync_start = mode->hdisplay + hsync; mode->hsync_end = mode->hsync_start + hsync_width; mode->htotal = mode->hdisplay + hblank; mode->vdisplay = vactive; mode->vsync_start = mode->vdisplay + vsync; mode->vsync_end = mode->vsync_start + vsync_width; mode->vtotal = mode->vdisplay + vblank; mode->flags = 0; mode->flags |= hsync_positive ? DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC; mode->flags |= vsync_positive ? DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC; mode->type = DRM_MODE_TYPE_DRIVER; if (timings->flags & 0x80) mode->type |= DRM_MODE_TYPE_PREFERRED; mode->vrefresh = drm_mode_vrefresh(mode); drm_mode_set_name(mode); return mode; } static int add_displayid_detailed_1_modes(struct drm_connector *connector, struct displayid_block *block) { struct displayid_detailed_timing_block *det = (struct displayid_detailed_timing_block *)block; int i; int num_timings; struct drm_display_mode *newmode; int num_modes = 0; /* blocks must be multiple of 20 bytes length */ if (block->num_bytes % 20) return 0; num_timings = block->num_bytes / 20; for (i = 0; i < num_timings; i++) { struct displayid_detailed_timings_1 *timings = &det->timings[i]; newmode = drm_mode_displayid_detailed(connector->dev, timings); if (!newmode) continue; drm_mode_probed_add(connector, newmode); num_modes++; } return num_modes; } static int add_displayid_detailed_modes(struct drm_connector *connector, struct edid *edid) { u8 *displayid; int ret; int idx = 1; int length = EDID_LENGTH; struct displayid_block *block; int num_modes = 0; displayid = drm_find_displayid_extension(edid); if (!displayid) return 0; ret = validate_displayid(displayid, length, idx); if (ret) return 0; idx += sizeof(struct displayid_hdr); while (block = (struct displayid_block *)&displayid[idx], idx + sizeof(struct displayid_block) <= length && idx + sizeof(struct displayid_block) + block->num_bytes <= length && block->num_bytes > 0) { idx += block->num_bytes + sizeof(struct displayid_block); switch (block->tag) { case DATA_BLOCK_TYPE_1_DETAILED_TIMING: num_modes += add_displayid_detailed_1_modes(connector, block); break; } } return num_modes; } /** * drm_add_edid_modes - add modes from EDID data, if available * @connector: connector we're probing Loading Loading @@ -3844,6 +4011,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid) num_modes += add_established_modes(connector, edid); num_modes += add_cea_modes(connector, edid); num_modes += add_alternate_cea_modes(connector, edid); num_modes += add_displayid_detailed_modes(connector, edid); if (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF) num_modes += add_inferred_modes(connector, edid); Loading Loading @@ -4144,6 +4312,9 @@ static int drm_parse_display_id(struct drm_connector *connector, if (ret) return ret; break; case DATA_BLOCK_TYPE_1_DETAILED_TIMING: /* handled in mode gathering code. */ break; default: DRM_DEBUG_KMS("found DisplayID tag 0x%x, unhandled\n", block->tag); Loading drivers/video/hdmi.c +4 −0 Original line number Diff line number Diff line Loading @@ -533,6 +533,10 @@ hdmi_picture_aspect_get_name(enum hdmi_picture_aspect picture_aspect) return "4:3"; case HDMI_PICTURE_ASPECT_16_9: return "16:9"; case HDMI_PICTURE_ASPECT_64_27: return "64:27"; case HDMI_PICTURE_ASPECT_256_135: return "256:135"; case HDMI_PICTURE_ASPECT_RESERVED: return "Reserved"; } Loading include/drm/drm_crtc.h +12 −0 Original line number Diff line number Diff line Loading @@ -644,6 +644,11 @@ struct drm_encoder { * @audio_latency: audio latency info from ELD, if found * @null_edid_counter: track sinks that give us all zeros for the EDID * @bad_edid_counter: track sinks that give us an EDID with invalid checksum * @max_tmds_char: indicates the maximum TMDS Character Rate supported * @scdc_present: when set the sink supports SCDC functionality * @rr_capable: when set the sink is capable of initiating an SCDC read request * @supports_scramble: when set the sink supports less than 340Mcsc scrambling * @flags_3d: 3D view(s) supported by the sink, see drm_edid.h (DRM_EDID_3D_*) * @edid_corrupt: indicates whether the last read EDID was corrupt * @debugfs_entry: debugfs directory for this connector * @state: current atomic state for this connector Loading Loading @@ -717,6 +722,13 @@ struct drm_connector { int null_edid_counter; /* needed to workaround some HW bugs where we get all 0s */ unsigned bad_edid_counter; /* EDID bits HDMI 2.0 */ int max_tmds_char; /* in Mcsc */ bool scdc_present; bool rr_capable; bool supports_scramble; int flags_3d; /* Flag for raw EDID header corruption - used in Displayport * compliance testing - * Displayport Link CTS Core 1.2 rev1.1 4.2.2.6 */ Loading include/drm/drm_displayid.h +17 −0 Original line number Diff line number Diff line Loading @@ -73,4 +73,21 @@ struct displayid_tiled_block { u8 topology_id[8]; } __packed; struct displayid_detailed_timings_1 { u8 pixel_clock[3]; u8 flags; u8 hactive[2]; u8 hblank[2]; u8 hsync[2]; u8 hsw[2]; u8 vactive[2]; u8 vblank[2]; u8 vsync[2]; u8 vsw[2]; } __packed; struct displayid_detailed_timing_block { struct displayid_block base; struct displayid_detailed_timings_1 timings[0]; }; #endif include/drm/drm_edid.h +5 −0 Original line number Diff line number Diff line Loading @@ -266,6 +266,11 @@ struct detailed_timing { #define DRM_ELD_CEA_SAD(mnl, sad) (20 + (mnl) + 3 * (sad)) /* HDMI 2.0 */ #define DRM_EDID_3D_INDEPENDENT_VIEW (1 << 2) #define DRM_EDID_3D_DUAL_VIEW (1 << 1) #define DRM_EDID_3D_OSD_DISPARITY (1 << 0) struct edid { u8 header[8]; /* Vendor & product info */ Loading Loading
drivers/gpu/drm/drm_edid.c +171 −0 Original line number Diff line number Diff line Loading @@ -3076,6 +3076,21 @@ static bool cea_db_is_hdmi_vsdb(const u8 *db) return hdmi_id == HDMI_IEEE_OUI; } static bool cea_db_is_hdmi_hf_vsdb(const u8 *db) { int hdmi_id; if (cea_db_tag(db) != VENDOR_BLOCK) return false; if (cea_db_payload_len(db) < 7) return false; hdmi_id = db[1] | (db[2] << 8) | (db[3] << 16); return hdmi_id == HDMI_IEEE_OUI_HF; } #define for_each_cea_db(cea, i, start, end) \ for ((i) = (start); (i) < (end) && (i) + cea_db_payload_len(&(cea)[(i)]) < (end); (i) += cea_db_payload_len(&(cea)[(i)]) + 1) Loading Loading @@ -3198,6 +3213,37 @@ parse_hdmi_vsdb(struct drm_connector *connector, const u8 *db) connector->audio_latency[1]); } static void parse_hdmi_hf_vsdb(struct drm_connector *connector, const u8 *db) { u8 len = cea_db_payload_len(db); if (len < 7) return; if (db[4] != 1) return; /* invalid version */ connector->max_tmds_char = db[5] * 5; connector->scdc_present = db[6] & (1 << 7); connector->rr_capable = db[6] & (1 << 6); connector->flags_3d = db[6] & 0x7; connector->supports_scramble = connector->scdc_present && (db[6] & (1 << 3)); DRM_DEBUG_KMS("HDMI v2: max TMDS char %d, " "scdc %s, " "rr %s, " "3D flags 0x%x, " "scramble %s\n", connector->max_tmds_char, connector->scdc_present ? "available" : "not available", connector->rr_capable ? "capable" : "not capable", connector->flags_3d, connector->supports_scramble ? "supported" : "not supported"); } static void monitor_name(struct detailed_timing *t, void *data) { Loading Loading @@ -3277,6 +3323,9 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) /* HDMI Vendor-Specific Data Block */ if (cea_db_is_hdmi_vsdb(db)) parse_hdmi_vsdb(connector, db); /* HDMI Forum Vendor-Specific Data Block */ else if (cea_db_is_hdmi_hf_vsdb(db)) parse_hdmi_hf_vsdb(connector, db); break; default: break; Loading Loading @@ -3799,6 +3848,124 @@ static int validate_displayid(u8 *displayid, int length, int idx) return 0; } static struct drm_display_mode * drm_mode_displayid_detailed(struct drm_device *dev, struct displayid_detailed_timings_1 *timings) { struct drm_display_mode *mode; unsigned pixel_clock = (timings->pixel_clock[0] | (timings->pixel_clock[1] << 8) | (timings->pixel_clock[2] << 16)); unsigned hactive = (timings->hactive[0] | timings->hactive[1] << 8) + 1; unsigned hblank = (timings->hblank[0] | timings->hblank[1] << 8) + 1; unsigned hsync = (timings->hsync[0] | (timings->hsync[1] & 0x7f) << 8) + 1; unsigned hsync_width = (timings->hsw[0] | timings->hsw[1] << 8) + 1; unsigned vactive = (timings->vactive[0] | timings->vactive[1] << 8) + 1; unsigned vblank = (timings->vblank[0] | timings->vblank[1] << 8) + 1; unsigned vsync = (timings->vsync[0] | (timings->vsync[1] & 0x7f) << 8) + 1; unsigned vsync_width = (timings->vsw[0] | timings->vsw[1] << 8) + 1; bool hsync_positive = (timings->hsync[1] >> 7) & 0x1; bool vsync_positive = (timings->vsync[1] >> 7) & 0x1; mode = drm_mode_create(dev); if (!mode) return NULL; mode->clock = pixel_clock * 10; mode->hdisplay = hactive; mode->hsync_start = mode->hdisplay + hsync; mode->hsync_end = mode->hsync_start + hsync_width; mode->htotal = mode->hdisplay + hblank; mode->vdisplay = vactive; mode->vsync_start = mode->vdisplay + vsync; mode->vsync_end = mode->vsync_start + vsync_width; mode->vtotal = mode->vdisplay + vblank; mode->flags = 0; mode->flags |= hsync_positive ? DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC; mode->flags |= vsync_positive ? DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC; mode->type = DRM_MODE_TYPE_DRIVER; if (timings->flags & 0x80) mode->type |= DRM_MODE_TYPE_PREFERRED; mode->vrefresh = drm_mode_vrefresh(mode); drm_mode_set_name(mode); return mode; } static int add_displayid_detailed_1_modes(struct drm_connector *connector, struct displayid_block *block) { struct displayid_detailed_timing_block *det = (struct displayid_detailed_timing_block *)block; int i; int num_timings; struct drm_display_mode *newmode; int num_modes = 0; /* blocks must be multiple of 20 bytes length */ if (block->num_bytes % 20) return 0; num_timings = block->num_bytes / 20; for (i = 0; i < num_timings; i++) { struct displayid_detailed_timings_1 *timings = &det->timings[i]; newmode = drm_mode_displayid_detailed(connector->dev, timings); if (!newmode) continue; drm_mode_probed_add(connector, newmode); num_modes++; } return num_modes; } static int add_displayid_detailed_modes(struct drm_connector *connector, struct edid *edid) { u8 *displayid; int ret; int idx = 1; int length = EDID_LENGTH; struct displayid_block *block; int num_modes = 0; displayid = drm_find_displayid_extension(edid); if (!displayid) return 0; ret = validate_displayid(displayid, length, idx); if (ret) return 0; idx += sizeof(struct displayid_hdr); while (block = (struct displayid_block *)&displayid[idx], idx + sizeof(struct displayid_block) <= length && idx + sizeof(struct displayid_block) + block->num_bytes <= length && block->num_bytes > 0) { idx += block->num_bytes + sizeof(struct displayid_block); switch (block->tag) { case DATA_BLOCK_TYPE_1_DETAILED_TIMING: num_modes += add_displayid_detailed_1_modes(connector, block); break; } } return num_modes; } /** * drm_add_edid_modes - add modes from EDID data, if available * @connector: connector we're probing Loading Loading @@ -3844,6 +4011,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid) num_modes += add_established_modes(connector, edid); num_modes += add_cea_modes(connector, edid); num_modes += add_alternate_cea_modes(connector, edid); num_modes += add_displayid_detailed_modes(connector, edid); if (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF) num_modes += add_inferred_modes(connector, edid); Loading Loading @@ -4144,6 +4312,9 @@ static int drm_parse_display_id(struct drm_connector *connector, if (ret) return ret; break; case DATA_BLOCK_TYPE_1_DETAILED_TIMING: /* handled in mode gathering code. */ break; default: DRM_DEBUG_KMS("found DisplayID tag 0x%x, unhandled\n", block->tag); Loading
drivers/video/hdmi.c +4 −0 Original line number Diff line number Diff line Loading @@ -533,6 +533,10 @@ hdmi_picture_aspect_get_name(enum hdmi_picture_aspect picture_aspect) return "4:3"; case HDMI_PICTURE_ASPECT_16_9: return "16:9"; case HDMI_PICTURE_ASPECT_64_27: return "64:27"; case HDMI_PICTURE_ASPECT_256_135: return "256:135"; case HDMI_PICTURE_ASPECT_RESERVED: return "Reserved"; } Loading
include/drm/drm_crtc.h +12 −0 Original line number Diff line number Diff line Loading @@ -644,6 +644,11 @@ struct drm_encoder { * @audio_latency: audio latency info from ELD, if found * @null_edid_counter: track sinks that give us all zeros for the EDID * @bad_edid_counter: track sinks that give us an EDID with invalid checksum * @max_tmds_char: indicates the maximum TMDS Character Rate supported * @scdc_present: when set the sink supports SCDC functionality * @rr_capable: when set the sink is capable of initiating an SCDC read request * @supports_scramble: when set the sink supports less than 340Mcsc scrambling * @flags_3d: 3D view(s) supported by the sink, see drm_edid.h (DRM_EDID_3D_*) * @edid_corrupt: indicates whether the last read EDID was corrupt * @debugfs_entry: debugfs directory for this connector * @state: current atomic state for this connector Loading Loading @@ -717,6 +722,13 @@ struct drm_connector { int null_edid_counter; /* needed to workaround some HW bugs where we get all 0s */ unsigned bad_edid_counter; /* EDID bits HDMI 2.0 */ int max_tmds_char; /* in Mcsc */ bool scdc_present; bool rr_capable; bool supports_scramble; int flags_3d; /* Flag for raw EDID header corruption - used in Displayport * compliance testing - * Displayport Link CTS Core 1.2 rev1.1 4.2.2.6 */ Loading
include/drm/drm_displayid.h +17 −0 Original line number Diff line number Diff line Loading @@ -73,4 +73,21 @@ struct displayid_tiled_block { u8 topology_id[8]; } __packed; struct displayid_detailed_timings_1 { u8 pixel_clock[3]; u8 flags; u8 hactive[2]; u8 hblank[2]; u8 hsync[2]; u8 hsw[2]; u8 vactive[2]; u8 vblank[2]; u8 vsync[2]; u8 vsw[2]; } __packed; struct displayid_detailed_timing_block { struct displayid_block base; struct displayid_detailed_timings_1 timings[0]; }; #endif
include/drm/drm_edid.h +5 −0 Original line number Diff line number Diff line Loading @@ -266,6 +266,11 @@ struct detailed_timing { #define DRM_ELD_CEA_SAD(mnl, sad) (20 + (mnl) + 3 * (sad)) /* HDMI 2.0 */ #define DRM_EDID_3D_INDEPENDENT_VIEW (1 << 2) #define DRM_EDID_3D_DUAL_VIEW (1 << 1) #define DRM_EDID_3D_OSD_DISPARITY (1 << 0) struct edid { u8 header[8]; /* Vendor & product info */ Loading