summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/drm_edid.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/drm_edid.c')
-rw-r--r--drivers/gpu/drm/drm_edid.c314
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;
}