diff options
Diffstat (limited to 'drivers/gpu/drm/drm_edid.c')
-rw-r--r-- | drivers/gpu/drm/drm_edid.c | 314 |
1 files changed, 33 insertions, 281 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 0a1e4a5..830f750 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -458,15 +458,6 @@ static const struct drm_display_mode drm_dmt_modes[] = { DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, }; -/* - * These more or less come from the DMT spec. The 720x400 modes are - * inferred from historical 80x25 practice. The 640x480@67 and 832x624@75 - * modes are old-school Mac modes. The EDID spec says the 1152x864@75 mode - * should be 1152x870, again for the Mac, but instead we use the x864 DMT - * mode. - * - * The DMT modes have been fact-checked; the rest are mild guesses. - */ static const struct drm_display_mode edid_est_modes[] = { { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840, 968, 1056, 0, 600, 601, 605, 628, 0, @@ -569,7 +560,7 @@ static const struct minimode est3_modes[] = { { 1600, 1200, 75, 0 }, { 1600, 1200, 85, 0 }, { 1792, 1344, 60, 0 }, - { 1792, 1344, 75, 0 }, + { 1792, 1344, 85, 0 }, { 1856, 1392, 60, 0 }, { 1856, 1392, 75, 0 }, { 1920, 1200, 60, 1 }, @@ -1273,18 +1264,6 @@ struct edid *drm_get_edid(struct drm_connector *connector, } EXPORT_SYMBOL(drm_get_edid); -/** - * drm_edid_duplicate - duplicate an EDID and the extensions - * @edid: EDID to duplicate - * - * Return duplicate edid or NULL on allocation failure. - */ -struct edid *drm_edid_duplicate(const struct edid *edid) -{ - return kmemdup(edid, (edid->extensions + 1) * EDID_LENGTH, GFP_KERNEL); -} -EXPORT_SYMBOL(drm_edid_duplicate); - /*** EDID parsing ***/ /** @@ -1329,7 +1308,7 @@ static u32 edid_get_quirks(struct edid *edid) } #define MODE_SIZE(m) ((m)->hdisplay * (m)->vdisplay) -#define MODE_REFRESH_DIFF(c,t) (abs((c) - (t))) +#define MODE_REFRESH_DIFF(m,r) (abs((m)->vrefresh - target_refresh)) /** * edid_fixup_preferred - set preferred modes based on quirk list @@ -1344,7 +1323,6 @@ static void edid_fixup_preferred(struct drm_connector *connector, { struct drm_display_mode *t, *cur_mode, *preferred_mode; int target_refresh = 0; - int cur_vrefresh, preferred_vrefresh; if (list_empty(&connector->probed_modes)) return; @@ -1367,14 +1345,10 @@ static void edid_fixup_preferred(struct drm_connector *connector, if (MODE_SIZE(cur_mode) > MODE_SIZE(preferred_mode)) preferred_mode = cur_mode; - cur_vrefresh = cur_mode->vrefresh ? - cur_mode->vrefresh : drm_mode_vrefresh(cur_mode); - preferred_vrefresh = preferred_mode->vrefresh ? - preferred_mode->vrefresh : drm_mode_vrefresh(preferred_mode); /* At a given size, try to get closest to target refresh */ if ((MODE_SIZE(cur_mode) == MODE_SIZE(preferred_mode)) && - MODE_REFRESH_DIFF(cur_vrefresh, target_refresh) < - MODE_REFRESH_DIFF(preferred_vrefresh, target_refresh)) { + MODE_REFRESH_DIFF(cur_mode, target_refresh) < + MODE_REFRESH_DIFF(preferred_mode, target_refresh)) { preferred_mode = cur_mode; } } @@ -2094,7 +2068,7 @@ drm_est3_modes(struct drm_connector *connector, struct detailed_timing *timing) u8 *est = ((u8 *)timing) + 5; for (i = 0; i < 6; i++) { - for (j = 7; j >= 0; j--) { + for (j = 7; j > 0; j--) { m = (i * 8) + (7 - j); if (m >= ARRAY_SIZE(est3_modes)) break; @@ -2430,7 +2404,7 @@ u8 drm_match_cea_mode(const struct drm_display_mode *to_match) if ((KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock1) || KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock2)) && - drm_mode_equal_no_clocks_no_stereo(to_match, cea_mode)) + drm_mode_equal_no_clocks(to_match, cea_mode)) return mode + 1; } return 0; @@ -2479,7 +2453,7 @@ static u8 drm_match_hdmi_mode(const struct drm_display_mode *to_match) if ((KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock1) || KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock2)) && - drm_mode_equal_no_clocks_no_stereo(to_match, hdmi_mode)) + drm_mode_equal_no_clocks(to_match, hdmi_mode)) return mode + 1; } return 0; @@ -2533,9 +2507,6 @@ add_alternate_cea_modes(struct drm_connector *connector, struct edid *edid) if (!newmode) continue; - /* Carry over the stereo flags */ - newmode->flags |= mode->flags & DRM_MODE_FLAG_3D_MASK; - /* * The current mode could be either variant. Make * sure to pick the "other" clock for the new mode. @@ -2582,151 +2553,20 @@ do_cea_modes(struct drm_connector *connector, const u8 *db, u8 len) return modes; } -struct stereo_mandatory_mode { - int width, height, vrefresh; - unsigned int flags; -}; - -static const struct stereo_mandatory_mode stereo_mandatory_modes[] = { - { 1920, 1080, 24, DRM_MODE_FLAG_3D_TOP_AND_BOTTOM }, - { 1920, 1080, 24, DRM_MODE_FLAG_3D_FRAME_PACKING }, - { 1920, 1080, 50, - DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF }, - { 1920, 1080, 60, - DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF }, - { 1280, 720, 50, DRM_MODE_FLAG_3D_TOP_AND_BOTTOM }, - { 1280, 720, 50, DRM_MODE_FLAG_3D_FRAME_PACKING }, - { 1280, 720, 60, DRM_MODE_FLAG_3D_TOP_AND_BOTTOM }, - { 1280, 720, 60, DRM_MODE_FLAG_3D_FRAME_PACKING } -}; - -static bool -stereo_match_mandatory(const struct drm_display_mode *mode, - const struct stereo_mandatory_mode *stereo_mode) -{ - unsigned int interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE; - - return mode->hdisplay == stereo_mode->width && - mode->vdisplay == stereo_mode->height && - interlaced == (stereo_mode->flags & DRM_MODE_FLAG_INTERLACE) && - drm_mode_vrefresh(mode) == stereo_mode->vrefresh; -} - -static int add_hdmi_mandatory_stereo_modes(struct drm_connector *connector) -{ - struct drm_device *dev = connector->dev; - const struct drm_display_mode *mode; - struct list_head stereo_modes; - int modes = 0, i; - - INIT_LIST_HEAD(&stereo_modes); - - list_for_each_entry(mode, &connector->probed_modes, head) { - for (i = 0; i < ARRAY_SIZE(stereo_mandatory_modes); i++) { - const struct stereo_mandatory_mode *mandatory; - struct drm_display_mode *new_mode; - - if (!stereo_match_mandatory(mode, - &stereo_mandatory_modes[i])) - continue; - - mandatory = &stereo_mandatory_modes[i]; - new_mode = drm_mode_duplicate(dev, mode); - if (!new_mode) - continue; - - new_mode->flags |= mandatory->flags; - list_add_tail(&new_mode->head, &stereo_modes); - modes++; - } - } - - list_splice_tail(&stereo_modes, &connector->probed_modes); - - return modes; -} - -static int add_hdmi_mode(struct drm_connector *connector, u8 vic) -{ - struct drm_device *dev = connector->dev; - struct drm_display_mode *newmode; - - vic--; /* VICs start at 1 */ - if (vic >= ARRAY_SIZE(edid_4k_modes)) { - DRM_ERROR("Unknown HDMI VIC: %d\n", vic); - return 0; - } - - newmode = drm_mode_duplicate(dev, &edid_4k_modes[vic]); - if (!newmode) - return 0; - - drm_mode_probed_add(connector, newmode); - - return 1; -} - -static int add_3d_struct_modes(struct drm_connector *connector, u16 structure, - const u8 *video_db, u8 video_len, u8 video_index) -{ - struct drm_device *dev = connector->dev; - struct drm_display_mode *newmode; - int modes = 0; - u8 cea_mode; - - if (video_db == NULL || video_index >= video_len) - return 0; - - /* CEA modes are numbered 1..127 */ - cea_mode = (video_db[video_index] & 127) - 1; - if (cea_mode >= ARRAY_SIZE(edid_cea_modes)) - return 0; - - if (structure & (1 << 0)) { - newmode = drm_mode_duplicate(dev, &edid_cea_modes[cea_mode]); - if (newmode) { - newmode->flags |= DRM_MODE_FLAG_3D_FRAME_PACKING; - drm_mode_probed_add(connector, newmode); - modes++; - } - } - if (structure & (1 << 6)) { - newmode = drm_mode_duplicate(dev, &edid_cea_modes[cea_mode]); - if (newmode) { - newmode->flags |= DRM_MODE_FLAG_3D_TOP_AND_BOTTOM; - drm_mode_probed_add(connector, newmode); - modes++; - } - } - if (structure & (1 << 8)) { - newmode = drm_mode_duplicate(dev, &edid_cea_modes[cea_mode]); - if (newmode) { - newmode->flags |= DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF; - drm_mode_probed_add(connector, newmode); - modes++; - } - } - - return modes; -} - /* * do_hdmi_vsdb_modes - Parse the HDMI Vendor Specific data block * @connector: connector corresponding to the HDMI sink * @db: start of the CEA vendor specific block * @len: length of the CEA block payload, ie. one can access up to db[len] * - * Parses the HDMI VSDB looking for modes to add to @connector. This function - * also adds the stereo 3d modes when applicable. + * Parses the HDMI VSDB looking for modes to add to @connector. */ static int -do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len, - const u8 *video_db, u8 video_len) +do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len) { - int modes = 0, offset = 0, i, multi_present = 0; - u8 vic_len, hdmi_3d_len = 0; - u16 mask; - u16 structure_all; + struct drm_device *dev = connector->dev; + int modes = 0, offset = 0, i; + u8 vic_len; if (len < 8) goto out; @@ -2745,56 +2585,30 @@ do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len, /* the declared length is not long enough for the 2 first bytes * of additional video format capabilities */ - if (len < (8 + offset + 2)) + offset += 2; + if (len < (8 + offset)) goto out; - /* 3D_Present */ - offset++; - if (db[8 + offset] & (1 << 7)) { - modes += add_hdmi_mandatory_stereo_modes(connector); - - /* 3D_Multi_present */ - multi_present = (db[8 + offset] & 0x60) >> 5; - } - - offset++; vic_len = db[8 + offset] >> 5; - hdmi_3d_len = db[8 + offset] & 0x1f; for (i = 0; i < vic_len && len >= (9 + offset + i); i++) { + struct drm_display_mode *newmode; u8 vic; vic = db[9 + offset + i]; - modes += add_hdmi_mode(connector, vic); - } - offset += 1 + vic_len; - - if (!(multi_present == 1 || multi_present == 2)) - goto out; - - if ((multi_present == 1 && len < (9 + offset)) || - (multi_present == 2 && len < (11 + offset))) - goto out; - if ((multi_present == 1 && hdmi_3d_len < 2) || - (multi_present == 2 && hdmi_3d_len < 4)) - goto out; - - /* 3D_Structure_ALL */ - structure_all = (db[8 + offset] << 8) | db[9 + offset]; + vic--; /* VICs start at 1 */ + if (vic >= ARRAY_SIZE(edid_4k_modes)) { + DRM_ERROR("Unknown HDMI VIC: %d\n", vic); + continue; + } - /* check if 3D_MASK is present */ - if (multi_present == 2) - mask = (db[10 + offset] << 8) | db[11 + offset]; - else - mask = 0xffff; + newmode = drm_mode_duplicate(dev, &edid_4k_modes[vic]); + if (!newmode) + continue; - for (i = 0; i < 16; i++) { - if (mask & (1 << i)) - modes += add_3d_struct_modes(connector, - structure_all, - video_db, - video_len, i); + drm_mode_probed_add(connector, newmode); + modes++; } out: @@ -2854,8 +2668,8 @@ static int add_cea_modes(struct drm_connector *connector, struct edid *edid) { const u8 *cea = drm_find_cea_extension(edid); - const u8 *db, *hdmi = NULL, *video = NULL; - u8 dbl, hdmi_len, video_len = 0; + const u8 *db; + u8 dbl; int modes = 0; if (cea && cea_revision(cea) >= 3) { @@ -2868,26 +2682,13 @@ add_cea_modes(struct drm_connector *connector, struct edid *edid) db = &cea[i]; dbl = cea_db_payload_len(db); - if (cea_db_tag(db) == VIDEO_BLOCK) { - video = db + 1; - video_len = dbl; - modes += do_cea_modes(connector, video, dbl); - } - else if (cea_db_is_hdmi_vsdb(db)) { - hdmi = db; - hdmi_len = dbl; - } + if (cea_db_tag(db) == VIDEO_BLOCK) + modes += do_cea_modes(connector, db + 1, dbl); + else if (cea_db_is_hdmi_vsdb(db)) + modes += do_hdmi_vsdb_modes(connector, db, dbl); } } - /* - * We parse the HDMI VSDB after having added the cea modes as we will - * be patching their flags when the sink supports stereo 3D. - */ - if (hdmi) - modes += do_hdmi_vsdb_modes(connector, hdmi, hdmi_len, video, - video_len); - return modes; } @@ -3487,19 +3288,6 @@ int drm_add_modes_noedid(struct drm_connector *connector, } EXPORT_SYMBOL(drm_add_modes_noedid); -void drm_set_preferred_mode(struct drm_connector *connector, - int hpref, int vpref) -{ - struct drm_display_mode *mode; - - list_for_each_entry(mode, &connector->probed_modes, head) { - if (drm_mode_width(mode) == hpref && - drm_mode_height(mode) == vpref) - mode->type |= DRM_MODE_TYPE_PREFERRED; - } -} -EXPORT_SYMBOL(drm_set_preferred_mode); - /** * drm_hdmi_avi_infoframe_from_display_mode() - fill an HDMI AVI infoframe with * data from a DRM display mode @@ -3533,33 +3321,6 @@ drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame, } EXPORT_SYMBOL(drm_hdmi_avi_infoframe_from_display_mode); -static enum hdmi_3d_structure -s3d_structure_from_display_mode(const struct drm_display_mode *mode) -{ - u32 layout = mode->flags & DRM_MODE_FLAG_3D_MASK; - - switch (layout) { - case DRM_MODE_FLAG_3D_FRAME_PACKING: - return HDMI_3D_STRUCTURE_FRAME_PACKING; - case DRM_MODE_FLAG_3D_FIELD_ALTERNATIVE: - return HDMI_3D_STRUCTURE_FIELD_ALTERNATIVE; - case DRM_MODE_FLAG_3D_LINE_ALTERNATIVE: - return HDMI_3D_STRUCTURE_LINE_ALTERNATIVE; - case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_FULL: - return HDMI_3D_STRUCTURE_SIDE_BY_SIDE_FULL; - case DRM_MODE_FLAG_3D_L_DEPTH: - return HDMI_3D_STRUCTURE_L_DEPTH; - case DRM_MODE_FLAG_3D_L_DEPTH_GFX_GFX_DEPTH: - return HDMI_3D_STRUCTURE_L_DEPTH_GFX_GFX_DEPTH; - case DRM_MODE_FLAG_3D_TOP_AND_BOTTOM: - return HDMI_3D_STRUCTURE_TOP_AND_BOTTOM; - case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF: - return HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF; - default: - return HDMI_3D_STRUCTURE_INVALID; - } -} - /** * drm_hdmi_vendor_infoframe_from_display_mode() - fill an HDMI infoframe with * data from a DRM display mode @@ -3577,29 +3338,20 @@ drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame, const struct drm_display_mode *mode) { int err; - u32 s3d_flags; u8 vic; if (!frame || !mode) return -EINVAL; vic = drm_match_hdmi_mode(mode); - s3d_flags = mode->flags & DRM_MODE_FLAG_3D_MASK; - - if (!vic && !s3d_flags) - return -EINVAL; - - if (vic && s3d_flags) + if (!vic) return -EINVAL; err = hdmi_vendor_infoframe_init(frame); if (err < 0) return err; - if (vic) - frame->vic = vic; - else - frame->s3d_struct = s3d_structure_from_display_mode(mode); + frame->vic = vic; return 0; } |