aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_edid.c
diff options
context:
space:
mode:
authorDamien Lespiau <damien.lespiau@intel.com>2013-09-25 11:45:23 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2013-10-01 01:45:28 -0400
commitc858cfcae6dd3829e8708a48d009c2f676b79d4d (patch)
tree80d6ff61ebedd0e170c12089a944f68e55cab441 /drivers/gpu/drm/drm_edid.c
parent61d8e3282541139cf5bb31e4c42f952a6cc168f8 (diff)
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>
Diffstat (limited to 'drivers/gpu/drm/drm_edid.c')
-rw-r--r--drivers/gpu/drm/drm_edid.c110
1 files changed, 103 insertions, 7 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 1688ff500513..52e60879149b 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -2553,13 +2553,95 @@ do_cea_modes(struct drm_connector *connector, const u8 *db, u8 len)
2553 return modes; 2553 return modes;
2554} 2554}
2555 2555
2556struct stereo_mandatory_mode {
2557 int width, height, vrefresh;
2558 unsigned int flags;
2559};
2560
2561static const struct stereo_mandatory_mode stereo_mandatory_modes[] = {
2562 { 1920, 1080, 24,
2563 DRM_MODE_FLAG_3D_TOP_AND_BOTTOM | DRM_MODE_FLAG_3D_FRAME_PACKING },
2564 { 1920, 1080, 50,
2565 DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF },
2566 { 1920, 1080, 60,
2567 DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF },
2568 { 1280, 720, 50,
2569 DRM_MODE_FLAG_3D_TOP_AND_BOTTOM | DRM_MODE_FLAG_3D_FRAME_PACKING },
2570 { 1280, 720, 60,
2571 DRM_MODE_FLAG_3D_TOP_AND_BOTTOM | DRM_MODE_FLAG_3D_FRAME_PACKING }
2572};
2573
2574static bool
2575stereo_match_mandatory(const struct drm_display_mode *mode,
2576 const struct stereo_mandatory_mode *stereo_mode)
2577{
2578 unsigned int interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE;
2579
2580 return mode->hdisplay == stereo_mode->width &&
2581 mode->vdisplay == stereo_mode->height &&
2582 interlaced == (stereo_mode->flags & DRM_MODE_FLAG_INTERLACE) &&
2583 drm_mode_vrefresh(mode) == stereo_mode->vrefresh;
2584}
2585
2586static const struct stereo_mandatory_mode *
2587hdmi_find_stereo_mandatory_mode(const struct drm_display_mode *mode)
2588{
2589 int i;
2590
2591 for (i = 0; i < ARRAY_SIZE(stereo_mandatory_modes); i++)
2592 if (stereo_match_mandatory(mode, &stereo_mandatory_modes[i]))
2593 return &stereo_mandatory_modes[i];
2594
2595 return NULL;
2596}
2597
2598static int add_hdmi_mandatory_stereo_modes(struct drm_connector *connector)
2599{
2600 struct drm_device *dev = connector->dev;
2601 const struct drm_display_mode *mode;
2602 struct list_head stereo_modes;
2603 int modes = 0;
2604
2605 INIT_LIST_HEAD(&stereo_modes);
2606
2607 list_for_each_entry(mode, &connector->probed_modes, head) {
2608 const struct stereo_mandatory_mode *mandatory;
2609 u32 stereo_layouts, layout;
2610
2611 mandatory = hdmi_find_stereo_mandatory_mode(mode);
2612 if (!mandatory)
2613 continue;
2614
2615 stereo_layouts = mandatory->flags & DRM_MODE_FLAG_3D_MASK;
2616 do {
2617 struct drm_display_mode *new_mode;
2618
2619 layout = 1 << (ffs(stereo_layouts) - 1);
2620 stereo_layouts &= ~layout;
2621
2622 new_mode = drm_mode_duplicate(dev, mode);
2623 if (!new_mode)
2624 continue;
2625
2626 new_mode->flags |= layout;
2627 list_add_tail(&new_mode->head, &stereo_modes);
2628 modes++;
2629 } while (stereo_layouts);
2630 }
2631
2632 list_splice_tail(&stereo_modes, &connector->probed_modes);
2633
2634 return modes;
2635}
2636
2556/* 2637/*
2557 * do_hdmi_vsdb_modes - Parse the HDMI Vendor Specific data block 2638 * do_hdmi_vsdb_modes - Parse the HDMI Vendor Specific data block
2558 * @connector: connector corresponding to the HDMI sink 2639 * @connector: connector corresponding to the HDMI sink
2559 * @db: start of the CEA vendor specific block 2640 * @db: start of the CEA vendor specific block
2560 * @len: length of the CEA block payload, ie. one can access up to db[len] 2641 * @len: length of the CEA block payload, ie. one can access up to db[len]
2561 * 2642 *
2562 * Parses the HDMI VSDB looking for modes to add to @connector. 2643 * Parses the HDMI VSDB looking for modes to add to @connector. This function
2644 * also adds the stereo 3d modes when applicable.
2563 */ 2645 */
2564static int 2646static int
2565do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len) 2647do_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)
2585 2667
2586 /* the declared length is not long enough for the 2 first bytes 2668 /* the declared length is not long enough for the 2 first bytes
2587 * of additional video format capabilities */ 2669 * of additional video format capabilities */
2588 offset += 2; 2670 if (len < (8 + offset + 2))
2589 if (len < (8 + offset))
2590 goto out; 2671 goto out;
2591 2672
2673 /* 3D_Present */
2674 offset++;
2675 if (db[8 + offset] & (1 << 7))
2676 modes += add_hdmi_mandatory_stereo_modes(connector);
2677
2678 offset++;
2592 vic_len = db[8 + offset] >> 5; 2679 vic_len = db[8 + offset] >> 5;
2593 2680
2594 for (i = 0; i < vic_len && len >= (9 + offset + i); i++) { 2681 for (i = 0; i < vic_len && len >= (9 + offset + i); i++) {
@@ -2668,8 +2755,8 @@ static int
2668add_cea_modes(struct drm_connector *connector, struct edid *edid) 2755add_cea_modes(struct drm_connector *connector, struct edid *edid)
2669{ 2756{
2670 const u8 *cea = drm_find_cea_extension(edid); 2757 const u8 *cea = drm_find_cea_extension(edid);
2671 const u8 *db; 2758 const u8 *db, *hdmi = NULL;
2672 u8 dbl; 2759 u8 dbl, hdmi_len;
2673 int modes = 0; 2760 int modes = 0;
2674 2761
2675 if (cea && cea_revision(cea) >= 3) { 2762 if (cea && cea_revision(cea) >= 3) {
@@ -2684,11 +2771,20 @@ add_cea_modes(struct drm_connector *connector, struct edid *edid)
2684 2771
2685 if (cea_db_tag(db) == VIDEO_BLOCK) 2772 if (cea_db_tag(db) == VIDEO_BLOCK)
2686 modes += do_cea_modes(connector, db + 1, dbl); 2773 modes += do_cea_modes(connector, db + 1, dbl);
2687 else if (cea_db_is_hdmi_vsdb(db)) 2774 else if (cea_db_is_hdmi_vsdb(db)) {
2688 modes += do_hdmi_vsdb_modes(connector, db, dbl); 2775 hdmi = db;
2776 hdmi_len = dbl;
2777 }
2689 } 2778 }
2690 } 2779 }
2691 2780
2781 /*
2782 * We parse the HDMI VSDB after having added the cea modes as we will
2783 * be patching their flags when the sink supports stereo 3D.
2784 */
2785 if (hdmi)
2786 modes += do_hdmi_vsdb_modes(connector, hdmi, hdmi_len);
2787
2692 return modes; 2788 return modes;
2693} 2789}
2694 2790