diff options
author | Dave Airlie <airlied@redhat.com> | 2017-12-04 05:38:52 +1000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2017-12-04 05:42:49 +1000 |
commit | 2c1c55cb75a9c72f9726fabb8c3607947711a8df (patch) | |
tree | fa835b954149545970eaa256107876d9a24bbf28 /drivers/gpu/drm/drm_edid.c | |
parent | ae64f9bd1d3621b5e60d7363bc20afb46aede215 (diff) | |
parent | 2f51be0945b9e0b9baafe47289c802be6d4c7980 (diff) | |
download | lwn-2c1c55cb75a9c72f9726fabb8c3607947711a8df.tar.gz lwn-2c1c55cb75a9c72f9726fabb8c3607947711a8df.zip |
Merge tag 'drm-misc-next-2017-11-30' of git://anongit.freedesktop.org/drm/drm-misc into drm-next
Cross-subsystem Changes:
- device tree doc for the Mitsubishi AA070MC01 and Tianma TM070RVHG71
panels (Lukasz Majewski) and for a 2nd endpoint on stm32 (Philippe Cornu)
Core Changes:
The most important changes are:
- Add drm_driver .last_close and .output_poll_changed helpers to reduce
fbdev emulation footprint in drivers (Noralf)
- Fix plane clipping in core and for vmwgfx (Ville)
Then we have a bunch of of improvement for print and debug such as the
addition of a framebuffer debugfs file. ELD connector, HDMI and
improvements. And a bunch of misc improvements, clean ups and style
changes and doc updates
[airlied: drop eld bits from amdgpu_dm]
Driver Changes:
- sii8620: filter unsupported modes and add DVI mode support (Maciej Purski)
- rockchip: analogix_dp: Remove unnecessary init code (Jeffy Chen)
- virtio, cirrus: add fb create_handle support to enable screenshots(Lepton Wu)
- virtio: replace reference/unreference with get/put (Aastha Gupta)
- vc4, gma500: Convert timers to use timer_setup() (Kees Cook)
- vc4: Reject HDMI modes with too high of clocks (Eric)
- vc4: Add support for more pixel formats (Dave Stevenson)
- stm: dsi: Rename driver name to "stm32-display-dsi" (Philippe Cornu)
- stm: ltdc: add a 2nd endpoint (Philippe Cornu)
- via: use monotonic time for VIA_WAIT_IRQ (Arnd Bergmann)
* tag 'drm-misc-next-2017-11-30' of git://anongit.freedesktop.org/drm/drm-misc: (96 commits)
drm/bridge: tc358767: add copyright lines
MAINTAINERS: change maintainer for Rockchip drm drivers
drm/vblank: Fix vblank timestamp debugs
drm/via: use monotonic time for VIA_WAIT_IRQ
dma-buf: Fix ifnullfree.cocci warnings
drm/printer: Add drm_vprintf()
drm/edid: Allow HDMI infoframe without VIC or S3D
video/hdmi: Allow "empty" HDMI infoframes
dma-buf/fence: Fix lock inversion within dma-fence-array
drm/sti: Handle return value of platform_get_irq_byname
drm/vc4: Add support for NV21 and NV61.
drm/vc4: Use .pixel_order instead of custom .flip_cbcr
drm/vc4: Add support for DRM_FORMAT_RGB888 and DRM_FORMAT_BGR888
drm: Move drm_plane_helper_check_state() into drm_atomic_helper.c
drm: Check crtc_state->enable rather than crtc->enabled in drm_plane_helper_check_state()
drm/vmwgfx: Try to fix plane clipping
drm/vmwgfx: Use drm_plane_helper_check_state()
drm/vmwgfx: Remove bogus crtc coords vs fb size check
gpu: gma500: remove unneeded DRIVER_LICENSE #define
drm: don't link DP aux i2c adapter to the hardware device node
...
Diffstat (limited to 'drivers/gpu/drm/drm_edid.c')
-rw-r--r-- | drivers/gpu/drm/drm_edid.c | 104 |
1 files changed, 70 insertions, 34 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 5dfe14763871..524eace3d460 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3398,6 +3398,7 @@ static int do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len, const u8 *video_db, u8 video_len) { + struct drm_display_info *info = &connector->display_info; int modes = 0, offset = 0, i, multi_present = 0, multi_len; u8 vic_len, hdmi_3d_len = 0; u16 mask; @@ -3525,6 +3526,8 @@ do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len, } out: + if (modes > 0) + info->has_hdmi_infoframe = true; return modes; } @@ -3761,8 +3764,8 @@ drm_parse_hdmi_vsdb_audio(struct drm_connector *connector, const u8 *db) { u8 len = cea_db_payload_len(db); - if (len >= 6) - connector->eld[5] |= (db[6] >> 7) << 1; /* Supports_AI */ + if (len >= 6 && (db[6] & (1 << 7))) + connector->eld[DRM_ELD_SAD_COUNT_CONN_TYPE] |= DRM_ELD_SUPPORTS_AI; if (len >= 8) { connector->latency_present[0] = db[8] >> 7; connector->latency_present[1] = (db[8] >> 6) & 1; @@ -3834,16 +3837,27 @@ void drm_edid_get_monitor_name(struct edid *edid, char *name, int bufsize) } EXPORT_SYMBOL(drm_edid_get_monitor_name); -/** +static void clear_eld(struct drm_connector *connector) +{ + memset(connector->eld, 0, sizeof(connector->eld)); + + connector->latency_present[0] = false; + connector->latency_present[1] = false; + connector->video_latency[0] = 0; + connector->audio_latency[0] = 0; + connector->video_latency[1] = 0; + connector->audio_latency[1] = 0; +} + +/* * drm_edid_to_eld - build ELD from EDID * @connector: connector corresponding to the HDMI/DP sink * @edid: EDID to parse * * Fill the ELD (EDID-Like Data) buffer for passing to the audio driver. The - * Conn_Type, HDCP and Port_ID ELD fields are left for the graphics driver to - * fill in. + * HDCP and Port_ID ELD fields are left for the graphics driver to fill in. */ -void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) +static void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) { uint8_t *eld = connector->eld; u8 *cea; @@ -3852,14 +3866,7 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) int mnl; int dbl; - memset(eld, 0, sizeof(connector->eld)); - - connector->latency_present[0] = false; - connector->latency_present[1] = false; - connector->video_latency[0] = 0; - connector->audio_latency[0] = 0; - connector->video_latency[1] = 0; - connector->audio_latency[1] = 0; + clear_eld(connector); if (!edid) return; @@ -3870,17 +3877,18 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) return; } - mnl = get_monitor_name(edid, eld + 20); + mnl = get_monitor_name(edid, &eld[DRM_ELD_MONITOR_NAME_STRING]); + DRM_DEBUG_KMS("ELD monitor %s\n", &eld[DRM_ELD_MONITOR_NAME_STRING]); - eld[4] = (cea[1] << 5) | mnl; - DRM_DEBUG_KMS("ELD monitor %s\n", eld + 20); + eld[DRM_ELD_CEA_EDID_VER_MNL] = cea[1] << DRM_ELD_CEA_EDID_VER_SHIFT; + eld[DRM_ELD_CEA_EDID_VER_MNL] |= mnl; - eld[0] = 2 << 3; /* ELD version: 2 */ + eld[DRM_ELD_VER] = DRM_ELD_VER_CEA861D; - eld[16] = edid->mfg_id[0]; - eld[17] = edid->mfg_id[1]; - eld[18] = edid->prod_code[0]; - eld[19] = edid->prod_code[1]; + eld[DRM_ELD_MANUFACTURER_NAME0] = edid->mfg_id[0]; + eld[DRM_ELD_MANUFACTURER_NAME1] = edid->mfg_id[1]; + eld[DRM_ELD_PRODUCT_CODE0] = edid->prod_code[0]; + eld[DRM_ELD_PRODUCT_CODE1] = edid->prod_code[1]; if (cea_revision(cea) >= 3) { int i, start, end; @@ -3901,14 +3909,14 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) /* Audio Data Block, contains SADs */ sad_count = min(dbl / 3, 15 - total_sad_count); if (sad_count >= 1) - memcpy(eld + 20 + mnl + total_sad_count * 3, + memcpy(&eld[DRM_ELD_CEA_SAD(mnl, total_sad_count)], &db[1], sad_count * 3); total_sad_count += sad_count; break; case SPEAKER_BLOCK: /* Speaker Allocation Data Block */ if (dbl >= 1) - eld[7] = db[1]; + eld[DRM_ELD_SPEAKER] = db[1]; break; case VENDOR_BLOCK: /* HDMI Vendor-Specific Data Block */ @@ -3920,7 +3928,13 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) } } } - eld[5] |= total_sad_count << 4; + eld[DRM_ELD_SAD_COUNT_CONN_TYPE] |= total_sad_count << DRM_ELD_SAD_COUNT_SHIFT; + + if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort || + connector->connector_type == DRM_MODE_CONNECTOR_eDP) + eld[DRM_ELD_SAD_COUNT_CONN_TYPE] |= DRM_ELD_CONN_TYPE_DP; + else + eld[DRM_ELD_SAD_COUNT_CONN_TYPE] |= DRM_ELD_CONN_TYPE_HDMI; eld[DRM_ELD_BASELINE_ELD_LEN] = DIV_ROUND_UP(drm_eld_calc_baseline_block_size(eld), 4); @@ -3928,7 +3942,6 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) DRM_DEBUG_KMS("ELD size %d, SAD count %d\n", drm_eld_size(eld), total_sad_count); } -EXPORT_SYMBOL(drm_edid_to_eld); /** * drm_edid_to_sad - extracts SADs from EDID @@ -4238,6 +4251,8 @@ static void drm_parse_hdmi_forum_vsdb(struct drm_connector *connector, struct drm_display_info *display = &connector->display_info; struct drm_hdmi_info *hdmi = &display->hdmi; + display->has_hdmi_infoframe = true; + if (hf_vsdb[6] & 0x80) { hdmi->scdc.supported = true; if (hf_vsdb[6] & 0x40) @@ -4411,6 +4426,7 @@ static void drm_add_display_info(struct drm_connector *connector, info->cea_rev = 0; info->max_tmds_clock = 0; info->dvi_dual = false; + info->has_hdmi_infoframe = false; info->non_desktop = !!(quirks & EDID_QUIRK_NON_DESKTOP); @@ -4608,8 +4624,8 @@ static int add_displayid_detailed_modes(struct drm_connector *connector, * @edid: EDID data * * Add the specified modes to the connector's mode list. Also fills out the - * &drm_display_info structure in @connector with any information which can be - * derived from the edid. + * &drm_display_info structure and ELD in @connector with any information which + * can be derived from the edid. * * Return: The number of modes added or 0 if we couldn't find any. */ @@ -4619,9 +4635,11 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid) u32 quirks; if (edid == NULL) { + clear_eld(connector); return 0; } if (!drm_edid_is_valid(edid)) { + clear_eld(connector); dev_warn(connector->dev->dev, "%s: EDID invalid.\n", connector->name); return 0; @@ -4629,6 +4647,8 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid) quirks = edid_get_quirks(edid); + drm_edid_to_eld(connector, edid); + /* * CEA-861-F adds ycbcr capability map block, for HDMI 2.0 sinks. * To avoid multiple parsing of same block, lets parse that map @@ -4904,6 +4924,7 @@ s3d_structure_from_display_mode(const struct drm_display_mode *mode) * drm_hdmi_vendor_infoframe_from_display_mode() - fill an HDMI infoframe with * data from a DRM display mode * @frame: HDMI vendor infoframe + * @connector: the connector * @mode: DRM display mode * * Note that there's is a need to send HDMI vendor infoframes only when using a @@ -4914,8 +4935,15 @@ s3d_structure_from_display_mode(const struct drm_display_mode *mode) */ int drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame, + struct drm_connector *connector, const struct drm_display_mode *mode) { + /* + * FIXME: sil-sii8620 doesn't have a connector around when + * we need one, so we have to be prepared for a NULL connector. + */ + bool has_hdmi_infoframe = connector ? + connector->display_info.has_hdmi_infoframe : false; int err; u32 s3d_flags; u8 vic; @@ -4923,11 +4951,21 @@ drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame, if (!frame || !mode) return -EINVAL; + if (!has_hdmi_infoframe) + return -EINVAL; + vic = drm_match_hdmi_mode(mode); s3d_flags = mode->flags & DRM_MODE_FLAG_3D_MASK; - if (!vic && !s3d_flags) - return -EINVAL; + /* + * Even if it's not absolutely necessary to send the infoframe + * (ie.vic==0 and s3d_struct==0) we will still send it if we + * know that the sink can handle it. This is based on a + * suggestion in HDMI 2.0 Appendix F. Apparently some sinks + * have trouble realizing that they shuld switch from 3D to 2D + * mode if the source simply stops sending the infoframe when + * it wants to switch from 3D to 2D. + */ if (vic && s3d_flags) return -EINVAL; @@ -4936,10 +4974,8 @@ drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame, if (err < 0) return err; - if (vic) - frame->vic = vic; - else - frame->s3d_struct = s3d_structure_from_display_mode(mode); + frame->vic = vic; + frame->s3d_struct = s3d_structure_from_display_mode(mode); return 0; } |