@@ -1522,21 +1522,101 @@ do_cea_modes (struct drm_connector *connector, u8 *db, u8 len)
return modes;
}
+static bool cea_hdmi_3d_present(u8 *hdmi)
+{
+ u8 len, skip = 0;
+
+ len = hdmi[0] & 0x1f;
+
+ if (len < 8)
+ return false;
+
+ /* no HDMI_Video_present */
+ if (!(hdmi[8] & (1<<5)))
+ return false;
+
+ /* Latency_fields_present */
+ if (hdmi[8] & (1 << 7))
+ skip += 2;
+
+ /* I_Latency_fields_present */
+ if (hdmi[8] & (1 << 6))
+ skip += 2;
+
+ /* the declared length is not long enough */
+ if (len < (9 + skip))
+ return false;
+
+ return (hdmi[9 + skip] & (1 << 7)) != 0;
+}
+
+static const struct {
+ int width, height, freq;
+ unsigned int select, value;
+ unsigned int formats;
+} s3d_mandatory_modes[] = {
+ { 1920, 1080, 24, DRM_MODE_FLAG_INTERLACE, 0,
+ DRM_MODE_FLAG_3D_TOP_BOTTOM | DRM_MODE_FLAG_3D_FRAME_PACKING },
+ { 1920, 1080, 50, DRM_MODE_FLAG_INTERLACE, DRM_MODE_FLAG_INTERLACE,
+ DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF },
+ { 1920, 1080, 60, DRM_MODE_FLAG_INTERLACE, DRM_MODE_FLAG_INTERLACE,
+ DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF },
+ { 1280, 720, 50, DRM_MODE_FLAG_INTERLACE, 0,
+ DRM_MODE_FLAG_3D_TOP_BOTTOM | DRM_MODE_FLAG_3D_FRAME_PACKING },
+ { 1280, 720, 60, DRM_MODE_FLAG_INTERLACE, 0,
+ DRM_MODE_FLAG_3D_TOP_BOTTOM | DRM_MODE_FLAG_3D_FRAME_PACKING }
+};
+
+static void cea_hdmi_patch_mandatory_3d_mode(struct drm_display_mode *mode)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(s3d_mandatory_modes); i++) {
+ if (mode->hdisplay == s3d_mandatory_modes[i].width &&
+ mode->vdisplay == s3d_mandatory_modes[i].height &&
+ (mode->flags & s3d_mandatory_modes[i].select) ==
+ s3d_mandatory_modes[i].value &&
+ drm_mode_vrefresh(mode) == s3d_mandatory_modes[i].freq) {
+ mode->flags |= s3d_mandatory_modes[i].formats;
+ }
+ }
+}
+
+static void cea_hdmi_patch_mandatory_3d_modes(struct drm_connector *connector)
+{
+ struct drm_display_mode *mode;
+
+ list_for_each_entry(mode, &connector->probed_modes, head)
+ cea_hdmi_patch_mandatory_3d_mode(mode);
+}
+
static int
add_cea_modes(struct drm_connector *connector, struct edid *edid)
{
u8 * cea = drm_find_cea_extension(edid);
- u8 * db, dbl;
+ u8 * db, *hdmi = NULL, dbl;
int modes = 0;
+ /* let's find the cea modes before looking at the hdmi vendor block
+ * as the 3d_present flag needs to know about the supported modes
+ * to infer the 3D modes */
if (cea && cea[1] >= 3) {
for (db = cea + 4; db < cea + cea[2]; db += dbl + 1) {
dbl = db[0] & 0x1f;
- if (((db[0] & 0xe0) >> 5) == VIDEO_BLOCK)
+ switch ((db[0] & 0xe0) >> 5) {
+ case VIDEO_BLOCK:
modes += do_cea_modes (connector, db+1, dbl);
+ break;
+ case VENDOR_BLOCK:
+ hdmi = db;
+ break;
+ }
}
}
+ if (hdmi && cea_hdmi_3d_present(hdmi))
+ cea_hdmi_patch_mandatory_3d_modes(connector);
+
return modes;
}
@@ -44,20 +44,27 @@
/* Video mode flags */
/* bit compatible with the xorg definitions. */
-#define DRM_MODE_FLAG_PHSYNC (1<<0)
-#define DRM_MODE_FLAG_NHSYNC (1<<1)
-#define DRM_MODE_FLAG_PVSYNC (1<<2)
-#define DRM_MODE_FLAG_NVSYNC (1<<3)
-#define DRM_MODE_FLAG_INTERLACE (1<<4)
-#define DRM_MODE_FLAG_DBLSCAN (1<<5)
-#define DRM_MODE_FLAG_CSYNC (1<<6)
-#define DRM_MODE_FLAG_PCSYNC (1<<7)
-#define DRM_MODE_FLAG_NCSYNC (1<<8)
-#define DRM_MODE_FLAG_HSKEW (1<<9) /* hskew provided */
-#define DRM_MODE_FLAG_BCAST (1<<10)
-#define DRM_MODE_FLAG_PIXMUX (1<<11)
-#define DRM_MODE_FLAG_DBLCLK (1<<12)
-#define DRM_MODE_FLAG_CLKDIV2 (1<<13)
+#define DRM_MODE_FLAG_PHSYNC (1<<0)
+#define DRM_MODE_FLAG_NHSYNC (1<<1)
+#define DRM_MODE_FLAG_PVSYNC (1<<2)
+#define DRM_MODE_FLAG_NVSYNC (1<<3)
+#define DRM_MODE_FLAG_INTERLACE (1<<4)
+#define DRM_MODE_FLAG_DBLSCAN (1<<5)
+#define DRM_MODE_FLAG_CSYNC (1<<6)
+#define DRM_MODE_FLAG_PCSYNC (1<<7)
+#define DRM_MODE_FLAG_NCSYNC (1<<8)
+#define DRM_MODE_FLAG_HSKEW (1<<9) /* hskew provided */
+#define DRM_MODE_FLAG_BCAST (1<<10)
+#define DRM_MODE_FLAG_PIXMUX (1<<11)
+#define DRM_MODE_FLAG_DBLCLK (1<<12)
+#define DRM_MODE_FLAG_CLKDIV2 (1<<13)
+#define DRM_MODE_FLAG_3D_TOP_BOTTOM (1<<14)
+#define DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF (1<<15)
+#define DRM_MODE_FLAG_3D_FRAME_PACKING (1<<16)
+
+#define DRM_MODE_FLAG_3D_MASK (DRM_MODE_FLAG_3D_TOP_BOTTOM | \
+ DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF | \
+ DRM_MODE_FLAG_3D_FRAME_PACKING)
/* DPMS flags */
/* bit compatible with the xorg definitions. */