diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-03-24 16:19:43 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-03-24 16:19:43 -0700 |
| commit | b14ffae378aa1db993e62b01392e70d1e585fb23 (patch) | |
| tree | 0ac179d24e8a62ec4c2732ed18d90d83da4b82d7 /drivers/gpu/drm/i915/display/intel_hdmi.c | |
| parent | 52deda9551a01879b3562e7b41748e85c591f14c (diff) | |
| parent | c6e90a1c660874736bd09c1fec6312b4b4c2ff7b (diff) | |
Merge tag 'drm-next-2022-03-24' of git://anongit.freedesktop.org/drm/drm
Pull drm updates from Dave Airlie:
"Lots of work all over, Intel improving DG2 support, amdkfd CRIU
support, msm new hw support, and faster fbdev support.
dma-buf:
- rename dma-buf-map to iosys-map
core:
- move buddy allocator to core
- add pci/platform init macros
- improve EDID parser deep color handling
- EDID timing type 7 support
- add GPD Win Max quirk
- add yes/no helpers to string_helpers
- flatten syncobj chains
- add nomodeset support to lots of drivers
- improve fb-helper clipping support
- add default property value interface
fbdev:
- improve fbdev ops speed
ttm:
- add a backpointer from ttm bo->ttm resource
dp:
- move displayport headers
- add a dp helper module
bridge:
- anx7625 atomic support, HDCP support
panel:
- split out panel-lvds and lvds bindings
- find panels in OF subnodes
privacy:
- add chromeos privacy screen support
fb:
- hot unplug fw fb on forced removal
simpledrm:
- request region instead of marking ioresource busy
- add panel oreintation property
udmabuf:
- fix oops with 0 pages
amdgpu:
- power management code cleanup
- Enable freesync video mode by default
- RAS code cleanup
- Improve VRAM access for debug using SDMA
- SR-IOV rework special register access and fixes
- profiling power state request ioctl
- expose IP discovery via sysfs
- Cyan skillfish updates
- GC 10.3.7, SDMA 5.2.7, DCN 3.1.6 updates
- expose benchmark tests via debugfs
- add module param to disable XGMI for testing
- GPU reset debugfs register dumping support
amdkfd:
- CRIU support
- SDMA queue fixes
radeon:
- UVD suspend fix
- iMac backlight fix
i915:
- minimal parallel submission for execlists
- DG2-G12 subplatform added
- DG2 programming workarounds
- DG2 accelerated migration support
- flat CCS and CCS engine support for XeHP
- initial small BAR support
- drop fake LMEM support
- ADL-N PCH support
- bigjoiner updates
- introduce VMA resources and async unbinding
- register definitions cleanups
- multi-FBC refactoring
- DG1 OPROM over SPI support
- ADL-N platform enabling
- opregion mailbox #5 support
- DP MST ESI improvements
- drm device based logging
- async flip optimisation for DG2
- CPU arch abstraction fixes
- improve GuC ADS init to work on aarch64
- tweak TTM LRU priority hint
- GuC 69.0.3 support
- remove short term execbuf pins
nouveau:
- higher DP/eDP bitrates
- backlight fixes
msm:
- dpu + dp support for sc8180x
- dp support for sm8350
- dpu + dsi support for qcm2290
- 10nm dsi phy tuning support
- bridge support for dp encoder
- gpu support for additional 7c3 SKUs
ingenic:
- HDMI support for JZ4780
- aux channel EDID support
ast:
- AST2600 support
- add wide screen support
- create DP/DVI connectors
omapdrm:
- fix implicit dma_buf fencing
vc4:
- add CSC + full range support
- better display firmware handoff
panfrost:
- add initial dual-core GPU support
stm:
- new revision support
- fb handover support
mediatek:
- transfer display binding document to yaml format.
- add mt8195 display device binding.
- allow commands to be sent during video mode.
- add wait_for_event for crtc disable by cmdq.
tegra:
- YUV format support
rcar-du:
- LVDS support for M3-W+ (R8A77961)
exynos:
- BGR pixel format for FIMD device"
* tag 'drm-next-2022-03-24' of git://anongit.freedesktop.org/drm/drm: (1529 commits)
drm/i915/display: Do not re-enable PSR after it was marked as not reliable
drm/i915/display: Fix HPD short pulse handling for eDP
drm/amdgpu: Use drm_mode_copy()
drm/radeon: Use drm_mode_copy()
drm/amdgpu: Use ternary operator in `vcn_v1_0_start()`
drm/amdgpu: Remove pointless on stack mode copies
drm/amd/pm: fix indenting in __smu_cmn_reg_print_error()
drm/amdgpu/dc: fix typos in comments
drm/amdgpu: fix typos in comments
drm/amd/pm: fix typos in comments
drm/amdgpu: Add stolen reserved memory for MI25 SRIOV.
drm/amdgpu: Merge get_reserved_allocation to get_vbios_allocations.
drm/amdkfd: evict svm bo worker handle error
drm/amdgpu/vcn: fix vcn ring test failure in igt reload test
drm/amdgpu: only allow secure submission on rings which support that
drm/amdgpu: fixed the warnings reported by kernel test robot
drm/amd/display: 3.2.177
drm/amd/display: [FW Promotion] Release 0.0.108.0
drm/amd/display: Add save/restore PANEL_PWRSEQ_REF_DIV2
drm/amd/display: Wait for hubp read line for Pollock
...
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_hdmi.c')
| -rw-r--r-- | drivers/gpu/drm/i915/display/intel_hdmi.c | 145 |
1 files changed, 87 insertions, 58 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index 3b5b9e7b05b7..1aa5bdc7b0dc 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -730,7 +730,7 @@ intel_hdmi_compute_avi_infoframe(struct intel_encoder *encoder, else frame->colorspace = HDMI_COLORSPACE_RGB; - drm_hdmi_avi_infoframe_colorspace(frame, conn_state); + drm_hdmi_avi_infoframe_colorimetry(frame, conn_state); /* nonsense combination */ drm_WARN_ON(encoder->base.dev, crtc_state->limited_color_range && @@ -1869,7 +1869,7 @@ hdmi_port_clock_valid(struct intel_hdmi *hdmi, return MODE_OK; } -static int intel_hdmi_tmds_clock(int clock, int bpc, bool ycbcr420_output) +int intel_hdmi_tmds_clock(int clock, int bpc, bool ycbcr420_output) { /* YCBCR420 TMDS rate requirement is half the pixel clock */ if (ycbcr420_output) @@ -1912,7 +1912,7 @@ static bool intel_hdmi_sink_bpc_possible(struct drm_connector *connector, if (ycbcr420_output) return hdmi->y420_dc_modes & DRM_EDID_YCBCR420_DC_36; else - return info->edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_36; + return info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_36; case 10: if (!has_hdmi_sink) return false; @@ -1920,7 +1920,7 @@ static bool intel_hdmi_sink_bpc_possible(struct drm_connector *connector, if (ycbcr420_output) return hdmi->y420_dc_modes & DRM_EDID_YCBCR420_DC_30; else - return info->edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30; + return info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_30; case 8: return true; default: @@ -1935,25 +1935,30 @@ intel_hdmi_mode_clock_valid(struct drm_connector *connector, int clock, { struct drm_i915_private *i915 = to_i915(connector->dev); struct intel_hdmi *hdmi = intel_attached_hdmi(to_intel_connector(connector)); - enum drm_mode_status status; + enum drm_mode_status status = MODE_OK; + int bpc; + + /* + * Try all color depths since valid port clock range + * can have holes. Any mode that can be used with at + * least one color depth is accepted. + */ + for (bpc = 12; bpc >= 8; bpc -= 2) { + int tmds_clock = intel_hdmi_tmds_clock(clock, bpc, ycbcr420_output); - /* check if we can do 8bpc */ - status = hdmi_port_clock_valid(hdmi, intel_hdmi_tmds_clock(clock, 8, ycbcr420_output), - true, has_hdmi_sink); + if (!intel_hdmi_source_bpc_possible(i915, bpc)) + continue; + + if (!intel_hdmi_sink_bpc_possible(connector, bpc, has_hdmi_sink, ycbcr420_output)) + continue; - /* if we can't do 8bpc we may still be able to do 12bpc */ - if (status != MODE_OK && - intel_hdmi_source_bpc_possible(i915, 12) && - intel_hdmi_sink_bpc_possible(connector, 12, has_hdmi_sink, ycbcr420_output)) - status = hdmi_port_clock_valid(hdmi, intel_hdmi_tmds_clock(clock, 12, ycbcr420_output), - true, has_hdmi_sink); + status = hdmi_port_clock_valid(hdmi, tmds_clock, true, has_hdmi_sink); + if (status == MODE_OK) + return MODE_OK; + } - /* if we can't do 8,12bpc we may still be able to do 10bpc */ - if (status != MODE_OK && - intel_hdmi_source_bpc_possible(i915, 10) && - intel_hdmi_sink_bpc_possible(connector, 10, has_hdmi_sink, ycbcr420_output)) - status = hdmi_port_clock_valid(hdmi, intel_hdmi_tmds_clock(clock, 10, ycbcr420_output), - true, has_hdmi_sink); + /* can never happen */ + drm_WARN_ON(&i915->drm, status == MODE_OK); return status; } @@ -2002,17 +2007,14 @@ intel_hdmi_mode_valid(struct drm_connector *connector, return intel_mode_valid_max_plane_size(dev_priv, mode, false); } -bool intel_hdmi_deep_color_possible(const struct intel_crtc_state *crtc_state, - int bpc, bool has_hdmi_sink, bool ycbcr420_output) +bool intel_hdmi_bpc_possible(const struct intel_crtc_state *crtc_state, + int bpc, bool has_hdmi_sink, bool ycbcr420_output) { struct drm_atomic_state *state = crtc_state->uapi.state; struct drm_connector_state *connector_state; struct drm_connector *connector; int i; - if (crtc_state->pipe_bpp < bpc * 3) - return false; - for_each_new_connector_in_state(state, connector, connector_state, i) { if (connector_state->crtc != crtc_state->uapi.crtc) continue; @@ -2024,8 +2026,7 @@ bool intel_hdmi_deep_color_possible(const struct intel_crtc_state *crtc_state, return true; } -static bool hdmi_deep_color_possible(const struct intel_crtc_state *crtc_state, - int bpc) +static bool hdmi_bpc_possible(const struct intel_crtc_state *crtc_state, int bpc) { struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); @@ -2039,7 +2040,7 @@ static bool hdmi_deep_color_possible(const struct intel_crtc_state *crtc_state, * HDMI deep color affects the clocks, so it's only possible * when not cloning with other encoder types. */ - if (crtc_state->output_types != BIT(INTEL_OUTPUT_HDMI)) + if (bpc > 8 && crtc_state->output_types != BIT(INTEL_OUTPUT_HDMI)) return false; /* Display Wa_1405510057:icl,ehl */ @@ -2049,35 +2050,50 @@ static bool hdmi_deep_color_possible(const struct intel_crtc_state *crtc_state, adjusted_mode->crtc_hblank_start) % 8 == 2) return false; - return intel_hdmi_deep_color_possible(crtc_state, bpc, - crtc_state->has_hdmi_sink, - intel_hdmi_is_ycbcr420(crtc_state)); + return intel_hdmi_bpc_possible(crtc_state, bpc, crtc_state->has_hdmi_sink, + intel_hdmi_is_ycbcr420(crtc_state)); } static int intel_hdmi_compute_bpc(struct intel_encoder *encoder, struct intel_crtc_state *crtc_state, - int clock) + int clock, bool respect_downstream_limits) { struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); bool ycbcr420_output = intel_hdmi_is_ycbcr420(crtc_state); int bpc; - for (bpc = 12; bpc >= 10; bpc -= 2) { - if (hdmi_deep_color_possible(crtc_state, bpc) && - hdmi_port_clock_valid(intel_hdmi, - intel_hdmi_tmds_clock(clock, bpc, ycbcr420_output), - true, crtc_state->has_hdmi_sink) == MODE_OK) + /* + * pipe_bpp could already be below 8bpc due to FDI + * bandwidth constraints. HDMI minimum is 8bpc however. + */ + bpc = max(crtc_state->pipe_bpp / 3, 8); + + /* + * We will never exceed downstream TMDS clock limits while + * attempting deep color. If the user insists on forcing an + * out of spec mode they will have to be satisfied with 8bpc. + */ + if (!respect_downstream_limits) + bpc = 8; + + for (; bpc >= 8; bpc -= 2) { + int tmds_clock = intel_hdmi_tmds_clock(clock, bpc, ycbcr420_output); + + if (hdmi_bpc_possible(crtc_state, bpc) && + hdmi_port_clock_valid(intel_hdmi, tmds_clock, + respect_downstream_limits, + crtc_state->has_hdmi_sink) == MODE_OK) return bpc; } - return 8; + return -EINVAL; } static int intel_hdmi_compute_clock(struct intel_encoder *encoder, - struct intel_crtc_state *crtc_state) + struct intel_crtc_state *crtc_state, + bool respect_downstream_limits) { struct drm_i915_private *i915 = to_i915(encoder->base.dev); - struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; int bpc, clock = adjusted_mode->crtc_clock; @@ -2085,31 +2101,25 @@ static int intel_hdmi_compute_clock(struct intel_encoder *encoder, if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) clock *= 2; - bpc = intel_hdmi_compute_bpc(encoder, crtc_state, clock); + bpc = intel_hdmi_compute_bpc(encoder, crtc_state, clock, + respect_downstream_limits); + if (bpc < 0) + return bpc; - crtc_state->port_clock = intel_hdmi_tmds_clock(clock, bpc, - intel_hdmi_is_ycbcr420(crtc_state)); + crtc_state->port_clock = + intel_hdmi_tmds_clock(clock, bpc, intel_hdmi_is_ycbcr420(crtc_state)); /* * pipe_bpp could already be below 8bpc due to * FDI bandwidth constraints. We shouldn't bump it - * back up to 8bpc in that case. + * back up to the HDMI minimum 8bpc in that case. */ - if (crtc_state->pipe_bpp > bpc * 3) - crtc_state->pipe_bpp = bpc * 3; + crtc_state->pipe_bpp = min(crtc_state->pipe_bpp, bpc * 3); drm_dbg_kms(&i915->drm, "picking %d bpc for HDMI output (pipe bpp: %d)\n", bpc, crtc_state->pipe_bpp); - if (hdmi_port_clock_valid(intel_hdmi, crtc_state->port_clock, - false, crtc_state->has_hdmi_sink) != MODE_OK) { - drm_dbg_kms(&i915->drm, - "unsupported HDMI clock (%d kHz), rejecting mode\n", - crtc_state->port_clock); - return -EINVAL; - } - return 0; } @@ -2170,7 +2180,8 @@ intel_hdmi_output_format(struct intel_connector *connector, static int intel_hdmi_compute_output_format(struct intel_encoder *encoder, struct intel_crtc_state *crtc_state, - const struct drm_connector_state *conn_state) + const struct drm_connector_state *conn_state, + bool respect_downstream_limits) { struct intel_connector *connector = to_intel_connector(conn_state->connector); const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; @@ -2187,7 +2198,7 @@ static int intel_hdmi_compute_output_format(struct intel_encoder *encoder, crtc_state->output_format = INTEL_OUTPUT_FORMAT_RGB; } - ret = intel_hdmi_compute_clock(encoder, crtc_state); + ret = intel_hdmi_compute_clock(encoder, crtc_state, respect_downstream_limits); if (ret) { if (intel_hdmi_is_ycbcr420(crtc_state) || !connector->base.ycbcr_420_allowed || @@ -2195,7 +2206,7 @@ static int intel_hdmi_compute_output_format(struct intel_encoder *encoder, return ret; crtc_state->output_format = intel_hdmi_output_format(connector, true); - ret = intel_hdmi_compute_clock(encoder, crtc_state); + ret = intel_hdmi_compute_clock(encoder, crtc_state, respect_downstream_limits); } return ret; @@ -2231,9 +2242,19 @@ int intel_hdmi_compute_config(struct intel_encoder *encoder, pipe_config->has_audio = intel_hdmi_has_audio(encoder, pipe_config, conn_state); - ret = intel_hdmi_compute_output_format(encoder, pipe_config, conn_state); + /* + * Try to respect downstream TMDS clock limits first, if + * that fails assume the user might know something we don't. + */ + ret = intel_hdmi_compute_output_format(encoder, pipe_config, conn_state, true); if (ret) + ret = intel_hdmi_compute_output_format(encoder, pipe_config, conn_state, false); + if (ret) { + drm_dbg_kms(&dev_priv->drm, + "unsupported HDMI clock (%d kHz), rejecting mode\n", + pipe_config->hw.adjusted_mode.crtc_clock); return ret; + } if (intel_hdmi_is_ycbcr420(pipe_config)) { ret = intel_panel_fitting(pipe_config, conn_state); @@ -2359,6 +2380,14 @@ intel_hdmi_dp_dual_mode_detect(struct drm_connector *connector, bool has_edid) "DP dual mode adaptor (%s) detected (max TMDS clock: %d kHz)\n", drm_dp_get_dual_mode_type_name(type), hdmi->dp_dual_mode.max_tmds_clock); + + /* Older VBTs are often buggy and can't be trusted :( Play it safe. */ + if ((DISPLAY_VER(dev_priv) >= 8 || IS_HASWELL(dev_priv)) && + !intel_bios_is_port_dp_dual_mode(dev_priv, port)) { + drm_dbg_kms(&dev_priv->drm, + "Ignoring DP dual mode adaptor max TMDS clock for native HDMI port\n"); + hdmi->dp_dual_mode.max_tmds_clock = 0; + } } static bool |