mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-19 18:24:14 +08:00
drm/edid: Expose mandatory stereo modes for HDMI sinks
For now, let's just look at the 3D_present flag of the CEA HDMI vendor block to detect if the sink supports a small list of then mandatory 3D formats. See the HDMI 1.4a 3D extraction for detail: http://www.hdmi.org/manufacturer/specification.aspx v2: Rename freq to vrefresh, make the mandatory structure a bit more compact, fix some white space issues and add a couple of const (Ville Syrjälä) Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Damien Lespiau <damien.lespiau@intel.com> Acked-by: Dave Airlie <airlied@gmail.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
This commit is contained in:
parent
61d8e32825
commit
c858cfcae6
@ -2553,13 +2553,95 @@ 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 | 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 | DRM_MODE_FLAG_3D_FRAME_PACKING },
|
||||
{ 1280, 720, 60,
|
||||
DRM_MODE_FLAG_3D_TOP_AND_BOTTOM | 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 const struct stereo_mandatory_mode *
|
||||
hdmi_find_stereo_mandatory_mode(const struct drm_display_mode *mode)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(stereo_mandatory_modes); i++)
|
||||
if (stereo_match_mandatory(mode, &stereo_mandatory_modes[i]))
|
||||
return &stereo_mandatory_modes[i];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
INIT_LIST_HEAD(&stereo_modes);
|
||||
|
||||
list_for_each_entry(mode, &connector->probed_modes, head) {
|
||||
const struct stereo_mandatory_mode *mandatory;
|
||||
u32 stereo_layouts, layout;
|
||||
|
||||
mandatory = hdmi_find_stereo_mandatory_mode(mode);
|
||||
if (!mandatory)
|
||||
continue;
|
||||
|
||||
stereo_layouts = mandatory->flags & DRM_MODE_FLAG_3D_MASK;
|
||||
do {
|
||||
struct drm_display_mode *new_mode;
|
||||
|
||||
layout = 1 << (ffs(stereo_layouts) - 1);
|
||||
stereo_layouts &= ~layout;
|
||||
|
||||
new_mode = drm_mode_duplicate(dev, mode);
|
||||
if (!new_mode)
|
||||
continue;
|
||||
|
||||
new_mode->flags |= layout;
|
||||
list_add_tail(&new_mode->head, &stereo_modes);
|
||||
modes++;
|
||||
} while (stereo_layouts);
|
||||
}
|
||||
|
||||
list_splice_tail(&stereo_modes, &connector->probed_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.
|
||||
* Parses the HDMI VSDB looking for modes to add to @connector. This function
|
||||
* also adds the stereo 3d modes when applicable.
|
||||
*/
|
||||
static int
|
||||
do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len)
|
||||
@ -2585,10 +2667,15 @@ 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 */
|
||||
offset += 2;
|
||||
if (len < (8 + offset))
|
||||
if (len < (8 + offset + 2))
|
||||
goto out;
|
||||
|
||||
/* 3D_Present */
|
||||
offset++;
|
||||
if (db[8 + offset] & (1 << 7))
|
||||
modes += add_hdmi_mandatory_stereo_modes(connector);
|
||||
|
||||
offset++;
|
||||
vic_len = db[8 + offset] >> 5;
|
||||
|
||||
for (i = 0; i < vic_len && len >= (9 + offset + i); i++) {
|
||||
@ -2668,8 +2755,8 @@ static int
|
||||
add_cea_modes(struct drm_connector *connector, struct edid *edid)
|
||||
{
|
||||
const u8 *cea = drm_find_cea_extension(edid);
|
||||
const u8 *db;
|
||||
u8 dbl;
|
||||
const u8 *db, *hdmi = NULL;
|
||||
u8 dbl, hdmi_len;
|
||||
int modes = 0;
|
||||
|
||||
if (cea && cea_revision(cea) >= 3) {
|
||||
@ -2684,11 +2771,20 @@ add_cea_modes(struct drm_connector *connector, struct edid *edid)
|
||||
|
||||
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);
|
||||
else if (cea_db_is_hdmi_vsdb(db)) {
|
||||
hdmi = db;
|
||||
hdmi_len = 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);
|
||||
|
||||
return modes;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user