diff options
author | Damien Lespiau <damien.lespiau@intel.com> | 2013-09-25 11:45:23 -0400 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2013-10-01 01:45:28 -0400 |
commit | c858cfcae6dd3829e8708a48d009c2f676b79d4d (patch) | |
tree | 80d6ff61ebedd0e170c12089a944f68e55cab441 /drivers/gpu/drm/drm_edid.c | |
parent | 61d8e3282541139cf5bb31e4c42f952a6cc168f8 (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.c | 110 |
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 | ||
2556 | struct stereo_mandatory_mode { | ||
2557 | int width, height, vrefresh; | ||
2558 | unsigned int flags; | ||
2559 | }; | ||
2560 | |||
2561 | static 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 | |||
2574 | static bool | ||
2575 | stereo_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 | |||
2586 | static const struct stereo_mandatory_mode * | ||
2587 | hdmi_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 | |||
2598 | static 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 | */ |
2564 | static int | 2646 | static int |
2565 | do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len) | 2647 | 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) | |||
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 | |||
2668 | add_cea_modes(struct drm_connector *connector, struct edid *edid) | 2755 | add_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 | ||