Message ID | 1443113495-32491-2-git-send-email-thierry.reding@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Thu, Sep 24, 2015 at 06:51:35PM +0200, Thierry Reding wrote: > From: Thierry Reding <treding@nvidia.com> > > Sinks compliant with the HDMI 2.0 specification may support SCDC, a > mechanism for the source and the sink to communicate. Sinks advertise > support for this feature in the HDMI Forum Vendor Specific Data Block > as defined in the HDMI 2.0 specification, section 10.4 "Status and > Control Data Channel". Implement a small helper that find the HF-VSDB > and parses it to check if the sink supports SCDC. > > Signed-off-by: Thierry Reding <treding@nvidia.com> > --- > drivers/gpu/drm/drm_edid.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++ > include/drm/drm_crtc.h | 1 + > include/linux/hdmi.h | 1 + > 3 files changed, 51 insertions(+) > > diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c > index d895556be4f0..af4da105d66e 100644 > --- a/drivers/gpu/drm/drm_edid.c > +++ b/drivers/gpu/drm/drm_edid.c > @@ -3059,6 +3059,21 @@ static bool cea_db_is_hdmi_vsdb(const u8 *db) > return hdmi_id == HDMI_IEEE_OUI; > } > > +static bool cea_db_is_hf_vsdb(const u8 *db) I would spell out the hdmi_forum here. Otherwise it's starting to look like random alphabet soup. > +{ > + unsigned int oui; > + > + if (cea_db_tag(db) != VENDOR_BLOCK) > + return false; > + > + if (cea_db_payload_len(db) < 7) > + return false; > + > + oui = db[3] << 16 | db[2] << 8 | db[1]; > + > + return oui == HDMI_FORUM_IEEE_OUI; > +} > + > #define for_each_cea_db(cea, i, start, end) \ > for ((i) = (start); (i) < (end) && (i) + cea_db_payload_len(&(cea)[(i)]) < (end); (i) += cea_db_payload_len(&(cea)[(i)]) + 1) > > @@ -3454,6 +3469,40 @@ bool drm_detect_hdmi_monitor(struct edid *edid) > EXPORT_SYMBOL(drm_detect_hdmi_monitor); > > /** > + * drm_detect_hdmi_scdc - detect whether an HDMI sink supports SCDC > + * @edid: sink EDID information > + * > + * Parse the CEA extension according to CEA-861-B to find an HF-VSDB as > + * defined in HDMI 2.0, section 10.3.2 "HDMI Forum Vendor Specific Data > + * Block" and checks if the SCDC_Present bit (bit 7 of byte 6) is set. > + * > + * Returns: > + * True if the sink supports SCDC, false otherwise. > + */ > +bool drm_detect_hdmi_scdc(struct edid *edid) > +{ > + unsigned int start, end, i; > + const u8 *cea; > + > + cea = drm_find_cea_extension(edid); > + if (!cea) > + return false; > + > + if (cea_db_offsets(cea, &start, &end)) > + return false; > + > + for_each_cea_db(cea, i, start, end) { > + if (cea_db_is_hf_vsdb(&cea[i])) { > + if (cea[i + 6] & 0x80) > + return true; > + } > + } > + > + return false; > +} > +EXPORT_SYMBOL(drm_detect_hdmi_scdc); > + > +/** > * drm_detect_monitor_audio - check monitor audio capability > * @edid: EDID block to scan > * > diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h > index 53a6f2455f35..5d0b88e4a80b 100644 > --- a/include/drm/drm_crtc.h > +++ b/include/drm/drm_crtc.h > @@ -1513,6 +1513,7 @@ extern enum hdmi_picture_aspect drm_get_cea_aspect_ratio(const u8 video_code); > extern bool drm_detect_hdmi_monitor(struct edid *edid); > extern bool drm_detect_monitor_audio(struct edid *edid); > extern bool drm_rgb_quant_range_selectable(struct edid *edid); > +extern bool drm_detect_hdmi_scdc(struct edid *edid); > extern int drm_mode_page_flip_ioctl(struct drm_device *dev, > void *data, struct drm_file *file_priv); > extern int drm_add_modes_noedid(struct drm_connector *connector, > diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h > index e9744202fa29..f860071e2d5a 100644 > --- a/include/linux/hdmi.h > +++ b/include/linux/hdmi.h > @@ -35,6 +35,7 @@ enum hdmi_infoframe_type { > }; > > #define HDMI_IEEE_OUI 0x000c03 > +#define HDMI_FORUM_IEEE_OUI 0xc45dd8 > #define HDMI_INFOFRAME_HEADER_SIZE 4 > #define HDMI_AVI_INFOFRAME_SIZE 13 > #define HDMI_SPD_INFOFRAME_SIZE 25 > -- > 2.5.0 > > _______________________________________________ > dri-devel mailing list > dri-devel@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/dri-devel
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index d895556be4f0..af4da105d66e 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3059,6 +3059,21 @@ static bool cea_db_is_hdmi_vsdb(const u8 *db) return hdmi_id == HDMI_IEEE_OUI; } +static bool cea_db_is_hf_vsdb(const u8 *db) +{ + unsigned int oui; + + if (cea_db_tag(db) != VENDOR_BLOCK) + return false; + + if (cea_db_payload_len(db) < 7) + return false; + + oui = db[3] << 16 | db[2] << 8 | db[1]; + + return oui == HDMI_FORUM_IEEE_OUI; +} + #define for_each_cea_db(cea, i, start, end) \ for ((i) = (start); (i) < (end) && (i) + cea_db_payload_len(&(cea)[(i)]) < (end); (i) += cea_db_payload_len(&(cea)[(i)]) + 1) @@ -3454,6 +3469,40 @@ bool drm_detect_hdmi_monitor(struct edid *edid) EXPORT_SYMBOL(drm_detect_hdmi_monitor); /** + * drm_detect_hdmi_scdc - detect whether an HDMI sink supports SCDC + * @edid: sink EDID information + * + * Parse the CEA extension according to CEA-861-B to find an HF-VSDB as + * defined in HDMI 2.0, section 10.3.2 "HDMI Forum Vendor Specific Data + * Block" and checks if the SCDC_Present bit (bit 7 of byte 6) is set. + * + * Returns: + * True if the sink supports SCDC, false otherwise. + */ +bool drm_detect_hdmi_scdc(struct edid *edid) +{ + unsigned int start, end, i; + const u8 *cea; + + cea = drm_find_cea_extension(edid); + if (!cea) + return false; + + if (cea_db_offsets(cea, &start, &end)) + return false; + + for_each_cea_db(cea, i, start, end) { + if (cea_db_is_hf_vsdb(&cea[i])) { + if (cea[i + 6] & 0x80) + return true; + } + } + + return false; +} +EXPORT_SYMBOL(drm_detect_hdmi_scdc); + +/** * drm_detect_monitor_audio - check monitor audio capability * @edid: EDID block to scan * diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 53a6f2455f35..5d0b88e4a80b 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -1513,6 +1513,7 @@ extern enum hdmi_picture_aspect drm_get_cea_aspect_ratio(const u8 video_code); extern bool drm_detect_hdmi_monitor(struct edid *edid); extern bool drm_detect_monitor_audio(struct edid *edid); extern bool drm_rgb_quant_range_selectable(struct edid *edid); +extern bool drm_detect_hdmi_scdc(struct edid *edid); extern int drm_mode_page_flip_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_add_modes_noedid(struct drm_connector *connector, diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h index e9744202fa29..f860071e2d5a 100644 --- a/include/linux/hdmi.h +++ b/include/linux/hdmi.h @@ -35,6 +35,7 @@ enum hdmi_infoframe_type { }; #define HDMI_IEEE_OUI 0x000c03 +#define HDMI_FORUM_IEEE_OUI 0xc45dd8 #define HDMI_INFOFRAME_HEADER_SIZE 4 #define HDMI_AVI_INFOFRAME_SIZE 13 #define HDMI_SPD_INFOFRAME_SIZE 25