mirror of
https://github.com/torvalds/linux.git
synced 2026-05-27 08:33:17 +02:00
drm/i915/dp: Replace intel_dp.dfp members with the new crtc_state sink_format
The decision to use DFP output format conversion capabilities should be during compute_config phase. This patch uses the members of intel_dp->dfp to only store the format conversion capabilities of the DP device and uses the crtc_state sink_format member, to program the protocol-converter for colorspace/format conversion. v2: Use sink_format to determine the color conversion config for the pcon (Ville). v3: Fix typo: missing 'break' in switch case (lkp kernel test robot). v4: Add helper to check if DP supports YCBCR420. v5: Simplify logic for computing output_format, based on the given sink_format. (Ville). Added scaler constraint for YCbCr420 output. v6: Split the patch for Scaler constraint for Ycbcr420. v7: Simplify the policy for selecting output_format: Always try for RGB first, followed by YCBCR444, and finally by YCBCR420. v8: Removed redundant comments, minor refactoring. (Ville) v9: Added member for ycbcr420 passthrough cap, fixed minor issues. (Ville) Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20230427125605.487769-3-ankit.k.nautiyal@intel.com
This commit is contained in:
parent
a04d27cdaf
commit
68910c2a90
|
|
@ -1775,6 +1775,7 @@ struct intel_dp {
|
|||
int pcon_max_frl_bw;
|
||||
u8 max_bpc;
|
||||
bool ycbcr_444_to_420;
|
||||
bool ycbcr420_passthrough;
|
||||
bool rgb_to_ycbcr;
|
||||
} dfp;
|
||||
|
||||
|
|
|
|||
|
|
@ -849,27 +849,88 @@ u8 intel_dp_dsc_get_slice_count(struct intel_dp *intel_dp,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool source_can_output(struct intel_dp *intel_dp,
|
||||
enum intel_output_format format)
|
||||
{
|
||||
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
|
||||
|
||||
switch (format) {
|
||||
case INTEL_OUTPUT_FORMAT_RGB:
|
||||
return true;
|
||||
|
||||
case INTEL_OUTPUT_FORMAT_YCBCR444:
|
||||
/*
|
||||
* No YCbCr output support on gmch platforms.
|
||||
* Also, ILK doesn't seem capable of DP YCbCr output.
|
||||
* The displayed image is severly corrupted. SNB+ is fine.
|
||||
*/
|
||||
return !HAS_GMCH(i915) && !IS_IRONLAKE(i915);
|
||||
|
||||
case INTEL_OUTPUT_FORMAT_YCBCR420:
|
||||
/* Platform < Gen 11 cannot output YCbCr420 format */
|
||||
return DISPLAY_VER(i915) >= 11;
|
||||
|
||||
default:
|
||||
MISSING_CASE(format);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
dfp_can_convert_from_rgb(struct intel_dp *intel_dp,
|
||||
enum intel_output_format sink_format)
|
||||
{
|
||||
if (!drm_dp_is_branch(intel_dp->dpcd))
|
||||
return false;
|
||||
|
||||
if (sink_format == INTEL_OUTPUT_FORMAT_YCBCR444)
|
||||
return intel_dp->dfp.rgb_to_ycbcr;
|
||||
|
||||
if (sink_format == INTEL_OUTPUT_FORMAT_YCBCR420)
|
||||
return intel_dp->dfp.rgb_to_ycbcr &&
|
||||
intel_dp->dfp.ycbcr_444_to_420;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
dfp_can_convert_from_ycbcr444(struct intel_dp *intel_dp,
|
||||
enum intel_output_format sink_format)
|
||||
{
|
||||
if (!drm_dp_is_branch(intel_dp->dpcd))
|
||||
return false;
|
||||
|
||||
if (sink_format == INTEL_OUTPUT_FORMAT_YCBCR420)
|
||||
return intel_dp->dfp.ycbcr_444_to_420;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static enum intel_output_format
|
||||
intel_dp_output_format(struct intel_connector *connector,
|
||||
enum intel_output_format sink_format)
|
||||
{
|
||||
struct intel_dp *intel_dp = intel_attached_dp(connector);
|
||||
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
|
||||
enum intel_output_format output_format;
|
||||
|
||||
if (intel_dp->force_dsc_output_format)
|
||||
return intel_dp->force_dsc_output_format;
|
||||
|
||||
if (!connector->base.ycbcr_420_allowed ||
|
||||
sink_format != INTEL_OUTPUT_FORMAT_YCBCR420)
|
||||
return INTEL_OUTPUT_FORMAT_RGB;
|
||||
if (sink_format == INTEL_OUTPUT_FORMAT_RGB ||
|
||||
dfp_can_convert_from_rgb(intel_dp, sink_format))
|
||||
output_format = INTEL_OUTPUT_FORMAT_RGB;
|
||||
|
||||
if (intel_dp->dfp.rgb_to_ycbcr &&
|
||||
intel_dp->dfp.ycbcr_444_to_420)
|
||||
return INTEL_OUTPUT_FORMAT_RGB;
|
||||
else if (sink_format == INTEL_OUTPUT_FORMAT_YCBCR444 ||
|
||||
dfp_can_convert_from_ycbcr444(intel_dp, sink_format))
|
||||
output_format = INTEL_OUTPUT_FORMAT_YCBCR444;
|
||||
|
||||
if (intel_dp->dfp.ycbcr_444_to_420)
|
||||
return INTEL_OUTPUT_FORMAT_YCBCR444;
|
||||
else
|
||||
return INTEL_OUTPUT_FORMAT_YCBCR420;
|
||||
output_format = INTEL_OUTPUT_FORMAT_YCBCR420;
|
||||
|
||||
drm_WARN_ON(&i915->drm, !source_can_output(intel_dp, output_format));
|
||||
|
||||
return output_format;
|
||||
}
|
||||
|
||||
int intel_dp_min_bpp(enum intel_output_format output_format)
|
||||
|
|
@ -2829,6 +2890,8 @@ void intel_dp_configure_protocol_converter(struct intel_dp *intel_dp,
|
|||
const struct intel_crtc_state *crtc_state)
|
||||
{
|
||||
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
|
||||
bool ycbcr444_to_420 = false;
|
||||
bool rgb_to_ycbcr = false;
|
||||
u8 tmp;
|
||||
|
||||
if (intel_dp->dpcd[DP_DPCD_REV] < 0x13)
|
||||
|
|
@ -2845,8 +2908,24 @@ void intel_dp_configure_protocol_converter(struct intel_dp *intel_dp,
|
|||
drm_dbg_kms(&i915->drm, "Failed to %s protocol converter HDMI mode\n",
|
||||
str_enable_disable(intel_dp->has_hdmi_sink));
|
||||
|
||||
tmp = crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444 &&
|
||||
intel_dp->dfp.ycbcr_444_to_420 ? DP_CONVERSION_TO_YCBCR420_ENABLE : 0;
|
||||
if (crtc_state->sink_format == INTEL_OUTPUT_FORMAT_YCBCR420) {
|
||||
switch (crtc_state->output_format) {
|
||||
case INTEL_OUTPUT_FORMAT_YCBCR420:
|
||||
break;
|
||||
case INTEL_OUTPUT_FORMAT_YCBCR444:
|
||||
ycbcr444_to_420 = true;
|
||||
break;
|
||||
case INTEL_OUTPUT_FORMAT_RGB:
|
||||
rgb_to_ycbcr = true;
|
||||
ycbcr444_to_420 = true;
|
||||
break;
|
||||
default:
|
||||
MISSING_CASE(crtc_state->output_format);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tmp = ycbcr444_to_420 ? DP_CONVERSION_TO_YCBCR420_ENABLE : 0;
|
||||
|
||||
if (drm_dp_dpcd_writeb(&intel_dp->aux,
|
||||
DP_PROTOCOL_CONVERTER_CONTROL_1, tmp) != 1)
|
||||
|
|
@ -2854,13 +2933,12 @@ void intel_dp_configure_protocol_converter(struct intel_dp *intel_dp,
|
|||
"Failed to %s protocol converter YCbCr 4:2:0 conversion mode\n",
|
||||
str_enable_disable(intel_dp->dfp.ycbcr_444_to_420));
|
||||
|
||||
tmp = intel_dp->dfp.rgb_to_ycbcr ?
|
||||
DP_CONVERSION_BT709_RGB_YCBCR_ENABLE : 0;
|
||||
tmp = rgb_to_ycbcr ? DP_CONVERSION_BT709_RGB_YCBCR_ENABLE : 0;
|
||||
|
||||
if (drm_dp_pcon_convert_rgb_to_ycbcr(&intel_dp->aux, tmp) < 0)
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"Failed to %s protocol converter RGB->YCbCr conversion mode\n",
|
||||
str_enable_disable(tmp));
|
||||
"Failed to %s protocol converter RGB->YCbCr conversion mode\n",
|
||||
str_enable_disable(tmp));
|
||||
}
|
||||
|
||||
bool intel_dp_get_colorimetry_status(struct intel_dp *intel_dp)
|
||||
|
|
@ -4650,57 +4728,44 @@ intel_dp_update_dfp(struct intel_dp *intel_dp,
|
|||
intel_dp_get_pcon_dsc_cap(intel_dp);
|
||||
}
|
||||
|
||||
static bool
|
||||
intel_dp_can_ycbcr420(struct intel_dp *intel_dp)
|
||||
{
|
||||
if (source_can_output(intel_dp, INTEL_OUTPUT_FORMAT_YCBCR420) &&
|
||||
(!drm_dp_is_branch(intel_dp->dpcd) || intel_dp->dfp.ycbcr420_passthrough))
|
||||
return true;
|
||||
|
||||
if (source_can_output(intel_dp, INTEL_OUTPUT_FORMAT_RGB) &&
|
||||
dfp_can_convert_from_rgb(intel_dp, INTEL_OUTPUT_FORMAT_YCBCR420))
|
||||
return true;
|
||||
|
||||
if (source_can_output(intel_dp, INTEL_OUTPUT_FORMAT_YCBCR444) &&
|
||||
dfp_can_convert_from_ycbcr444(intel_dp, INTEL_OUTPUT_FORMAT_YCBCR420))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
intel_dp_update_420(struct intel_dp *intel_dp)
|
||||
{
|
||||
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
|
||||
struct intel_connector *connector = intel_dp->attached_connector;
|
||||
bool is_branch, ycbcr_420_passthrough, ycbcr_444_to_420, rgb_to_ycbcr;
|
||||
|
||||
/* No YCbCr output support on gmch platforms */
|
||||
if (HAS_GMCH(i915))
|
||||
return;
|
||||
|
||||
/*
|
||||
* ILK doesn't seem capable of DP YCbCr output. The
|
||||
* displayed image is severly corrupted. SNB+ is fine.
|
||||
*/
|
||||
if (IS_IRONLAKE(i915))
|
||||
return;
|
||||
|
||||
is_branch = drm_dp_is_branch(intel_dp->dpcd);
|
||||
ycbcr_420_passthrough =
|
||||
intel_dp->dfp.ycbcr420_passthrough =
|
||||
drm_dp_downstream_420_passthrough(intel_dp->dpcd,
|
||||
intel_dp->downstream_ports);
|
||||
/* on-board LSPCON always assumed to support 4:4:4->4:2:0 conversion */
|
||||
ycbcr_444_to_420 =
|
||||
intel_dp->dfp.ycbcr_444_to_420 =
|
||||
dp_to_dig_port(intel_dp)->lspcon.active ||
|
||||
drm_dp_downstream_444_to_420_conversion(intel_dp->dpcd,
|
||||
intel_dp->downstream_ports);
|
||||
rgb_to_ycbcr = drm_dp_downstream_rgb_to_ycbcr_conversion(intel_dp->dpcd,
|
||||
intel_dp->downstream_ports,
|
||||
DP_DS_HDMI_BT709_RGB_YCBCR_CONV);
|
||||
intel_dp->dfp.rgb_to_ycbcr =
|
||||
drm_dp_downstream_rgb_to_ycbcr_conversion(intel_dp->dpcd,
|
||||
intel_dp->downstream_ports,
|
||||
DP_DS_HDMI_BT709_RGB_YCBCR_CONV);
|
||||
|
||||
if (DISPLAY_VER(i915) >= 11) {
|
||||
/* Let PCON convert from RGB->YCbCr if possible */
|
||||
if (is_branch && rgb_to_ycbcr && ycbcr_444_to_420) {
|
||||
intel_dp->dfp.rgb_to_ycbcr = true;
|
||||
intel_dp->dfp.ycbcr_444_to_420 = true;
|
||||
connector->base.ycbcr_420_allowed = true;
|
||||
} else {
|
||||
/* Prefer 4:2:0 passthrough over 4:4:4->4:2:0 conversion */
|
||||
intel_dp->dfp.ycbcr_444_to_420 =
|
||||
ycbcr_444_to_420 && !ycbcr_420_passthrough;
|
||||
|
||||
connector->base.ycbcr_420_allowed =
|
||||
!is_branch || ycbcr_444_to_420 || ycbcr_420_passthrough;
|
||||
}
|
||||
} else {
|
||||
/* 4:4:4->4:2:0 conversion is the only way */
|
||||
intel_dp->dfp.ycbcr_444_to_420 = ycbcr_444_to_420;
|
||||
|
||||
connector->base.ycbcr_420_allowed = ycbcr_444_to_420;
|
||||
}
|
||||
connector->base.ycbcr_420_allowed = intel_dp_can_ycbcr420(intel_dp);
|
||||
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"[CONNECTOR:%d:%s] RGB->YcbCr conversion? %s, YCbCr 4:2:0 allowed? %s, YCbCr 4:4:4->4:2:0 conversion? %s\n",
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user