Commit 5beed15e authored by Daniel Vetter's avatar Daniel Vetter

Merge tag 'topic/dp-hdmi-2.1-pcon-2020-12-23' of...

Merge tag 'topic/dp-hdmi-2.1-pcon-2020-12-23' of git://anongit.freedesktop.org/drm/drm-intel into drm-next

Add support for DP-HDMI2.1 PCON

From the series cover letter:

This patch series attempts to add support for a DP-HDMI2.1 Protocol
Convertor. The VESA spec for the HDMI2.1 PCON are proposed in Errata
E5 to DisplayPort_v2.0:
https://vesa.org/join-vesamemberships/member-downloads/?action=stamp&fileid=42299
The details are mentioned in:
VESA DP-to-HDMI PCON Specification Standalone Document
https://groups.vesa.org/wg/DP/document/15651

This series starts with adding support for FRL (Fixed Rate Link)
Training between the PCON and HDMI2.1 sink.
As per HDMI2.1 specification, a new data-channel or lane is added in
FRL mode, by repurposing the TMDS clock Channel. Through FRL, higher
bit-rate can be supported, ie. up to 12 Gbps/lane (48 Gbps over 4
lanes).

With these patches, the HDMI2.1 PCON can be configured to achieve FRL
training based on the maximum FRL rate supported by the panel, source
and the PCON.
The approach is to add the support for FRL training between PCON and
HDMI2.1 sink and gradually add other blocks for supporting higher
resolutions and other HDMI2.1 features, that can be supported by pcon
for the sources that do not natively support HDMI2.1.

This is done before the DP Link training between the source and PCON
is started. In case of FRL training is not achieved, the PCON will
work in the regular TMDS mode, without HDMI2.1 feature support.
Any interruption in FRL training between the PCON and HDMI2.1 sink is
notified through IRQ_HPD. On receiving the IRQ_HPD the concerned DPCD
registers are read and FRL training is re-attempted.

Currently, we have tested the FRL training and are able to enable 4K
display with TGL Platform + Realtek PCON RTD2173 with HDMI2.1 supporting
panel.
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
From: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/87lfdpndkt.fsf@intel.com
parents 18589d74 522508b6
This diff is collapsed.
......@@ -4851,6 +4851,41 @@ static void drm_parse_vcdb(struct drm_connector *connector, const u8 *db)
info->rgb_quant_range_selectable = true;
}
static
void drm_get_max_frl_rate(int max_frl_rate, u8 *max_lanes, u8 *max_rate_per_lane)
{
switch (max_frl_rate) {
case 1:
*max_lanes = 3;
*max_rate_per_lane = 3;
break;
case 2:
*max_lanes = 3;
*max_rate_per_lane = 6;
break;
case 3:
*max_lanes = 4;
*max_rate_per_lane = 6;
break;
case 4:
*max_lanes = 4;
*max_rate_per_lane = 8;
break;
case 5:
*max_lanes = 4;
*max_rate_per_lane = 10;
break;
case 6:
*max_lanes = 4;
*max_rate_per_lane = 12;
break;
case 0:
default:
*max_lanes = 0;
*max_rate_per_lane = 0;
}
}
static void drm_parse_ycbcr420_deep_color_info(struct drm_connector *connector,
const u8 *db)
{
......@@ -4904,6 +4939,74 @@ static void drm_parse_hdmi_forum_vsdb(struct drm_connector *connector,
}
}
if (hf_vsdb[7]) {
u8 max_frl_rate;
u8 dsc_max_frl_rate;
u8 dsc_max_slices;
struct drm_hdmi_dsc_cap *hdmi_dsc = &hdmi->dsc_cap;
DRM_DEBUG_KMS("hdmi_21 sink detected. parsing edid\n");
max_frl_rate = (hf_vsdb[7] & DRM_EDID_MAX_FRL_RATE_MASK) >> 4;
drm_get_max_frl_rate(max_frl_rate, &hdmi->max_lanes,
&hdmi->max_frl_rate_per_lane);
hdmi_dsc->v_1p2 = hf_vsdb[11] & DRM_EDID_DSC_1P2;
if (hdmi_dsc->v_1p2) {
hdmi_dsc->native_420 = hf_vsdb[11] & DRM_EDID_DSC_NATIVE_420;
hdmi_dsc->all_bpp = hf_vsdb[11] & DRM_EDID_DSC_ALL_BPP;
if (hf_vsdb[11] & DRM_EDID_DSC_16BPC)
hdmi_dsc->bpc_supported = 16;
else if (hf_vsdb[11] & DRM_EDID_DSC_12BPC)
hdmi_dsc->bpc_supported = 12;
else if (hf_vsdb[11] & DRM_EDID_DSC_10BPC)
hdmi_dsc->bpc_supported = 10;
else
hdmi_dsc->bpc_supported = 0;
dsc_max_frl_rate = (hf_vsdb[12] & DRM_EDID_DSC_MAX_FRL_RATE_MASK) >> 4;
drm_get_max_frl_rate(dsc_max_frl_rate, &hdmi_dsc->max_lanes,
&hdmi_dsc->max_frl_rate_per_lane);
hdmi_dsc->total_chunk_kbytes = hf_vsdb[13] & DRM_EDID_DSC_TOTAL_CHUNK_KBYTES;
dsc_max_slices = hf_vsdb[12] & DRM_EDID_DSC_MAX_SLICES;
switch (dsc_max_slices) {
case 1:
hdmi_dsc->max_slices = 1;
hdmi_dsc->clk_per_slice = 340;
break;
case 2:
hdmi_dsc->max_slices = 2;
hdmi_dsc->clk_per_slice = 340;
break;
case 3:
hdmi_dsc->max_slices = 4;
hdmi_dsc->clk_per_slice = 340;
break;
case 4:
hdmi_dsc->max_slices = 8;
hdmi_dsc->clk_per_slice = 340;
break;
case 5:
hdmi_dsc->max_slices = 8;
hdmi_dsc->clk_per_slice = 400;
break;
case 6:
hdmi_dsc->max_slices = 12;
hdmi_dsc->clk_per_slice = 400;
break;
case 7:
hdmi_dsc->max_slices = 16;
hdmi_dsc->clk_per_slice = 400;
break;
case 0:
default:
hdmi_dsc->max_slices = 0;
hdmi_dsc->clk_per_slice = 0;
}
}
}
drm_parse_ycbcr420_deep_color_info(connector, hf_vsdb);
}
......
......@@ -3643,6 +3643,7 @@ static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state,
if (!is_mst)
intel_dp_set_power(intel_dp, DP_SET_POWER_D0);
intel_dp_configure_protocol_converter(intel_dp, crtc_state);
intel_dp_sink_set_decompression_state(intel_dp, crtc_state, true);
/*
* DDI FEC: "anticipates enabling FEC encoding sets the FEC_READY bit
......@@ -3651,6 +3652,9 @@ static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state,
*/
intel_dp_sink_set_fec_ready(intel_dp, crtc_state);
intel_dp_check_frl_training(intel_dp);
intel_dp_pcon_dsc_configure(intel_dp, crtc_state);
/*
* 7.i Follow DisplayPort specification training sequence (see notes for
* failure handling)
......@@ -3725,7 +3729,7 @@ static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state,
intel_ddi_init_dp_buf_reg(encoder, crtc_state);
if (!is_mst)
intel_dp_set_power(intel_dp, DP_SET_POWER_D0);
intel_dp_configure_protocol_converter(intel_dp);
intel_dp_configure_protocol_converter(intel_dp, crtc_state);
intel_dp_sink_set_decompression_state(intel_dp, crtc_state,
true);
intel_dp_sink_set_fec_ready(intel_dp, crtc_state);
......
......@@ -1321,6 +1321,11 @@ struct intel_dp_compliance {
u8 test_lane_count;
};
struct intel_dp_pcon_frl {
bool is_trained;
int trained_rate_gbps;
};
struct intel_dp {
i915_reg_t output_reg;
u32 DP;
......@@ -1339,6 +1344,7 @@ struct intel_dp {
u8 lttpr_common_caps[DP_LTTPR_COMMON_CAP_SIZE];
u8 lttpr_phy_caps[DP_MAX_LTTPR_COUNT][DP_LTTPR_PHY_CAP_SIZE];
u8 fec_capable;
u8 pcon_dsc_dpcd[DP_PCON_DSC_ENCODER_CAP_SIZE];
/* source rates */
int num_source_rates;
const int *source_rates;
......@@ -1432,8 +1438,10 @@ struct intel_dp {
struct {
int min_tmds_clock, max_tmds_clock;
int max_dotclock;
int pcon_max_frl_bw;
u8 max_bpc;
bool ycbcr_444_to_420;
bool rgb_to_ycbcr;
} dfp;
/* Display stream compression testing */
......@@ -1441,6 +1449,8 @@ struct intel_dp {
bool hobl_failed;
bool hobl_active;
struct intel_dp_pcon_frl frl;
};
enum lspcon_vendor {
......
This diff is collapsed.
......@@ -51,7 +51,8 @@ int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp,
int intel_dp_retrain_link(struct intel_encoder *encoder,
struct drm_modeset_acquire_ctx *ctx);
void intel_dp_set_power(struct intel_dp *intel_dp, u8 mode);
void intel_dp_configure_protocol_converter(struct intel_dp *intel_dp);
void intel_dp_configure_protocol_converter(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state);
void intel_dp_sink_set_decompression_state(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state,
bool enable);
......@@ -144,4 +145,8 @@ bool intel_dp_initial_fastset_check(struct intel_encoder *encoder,
void intel_dp_sync_state(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state);
void intel_dp_check_frl_training(struct intel_dp *intel_dp);
void intel_dp_pcon_dsc_configure(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state);
#endif /* __INTEL_DP_H__ */
......@@ -3438,3 +3438,236 @@ void intel_hdmi_init(struct drm_i915_private *dev_priv,
dig_port->aux_ch = intel_bios_port_aux_ch(dev_priv, port);
intel_hdmi_init_connector(dig_port, intel_connector);
}
/*
* intel_hdmi_dsc_get_slice_height - get the dsc slice_height
* @vactive: Vactive of a display mode
*
* @return: appropriate dsc slice height for a given mode.
*/
int intel_hdmi_dsc_get_slice_height(int vactive)
{
int slice_height;
/*
* Slice Height determination : HDMI2.1 Section 7.7.5.2
* Select smallest slice height >=96, that results in a valid PPS and
* requires minimum padding lines required for final slice.
*
* Assumption : Vactive is even.
*/
for (slice_height = 96; slice_height <= vactive; slice_height += 2)
if (vactive % slice_height == 0)
return slice_height;
return 0;
}
/*
* intel_hdmi_dsc_get_num_slices - get no. of dsc slices based on dsc encoder
* and dsc decoder capabilities
*
* @crtc_state: intel crtc_state
* @src_max_slices: maximum slices supported by the DSC encoder
* @src_max_slice_width: maximum slice width supported by DSC encoder
* @hdmi_max_slices: maximum slices supported by sink DSC decoder
* @hdmi_throughput: maximum clock per slice (MHz) supported by HDMI sink
*
* @return: num of dsc slices that can be supported by the dsc encoder
* and decoder.
*/
int
intel_hdmi_dsc_get_num_slices(const struct intel_crtc_state *crtc_state,
int src_max_slices, int src_max_slice_width,
int hdmi_max_slices, int hdmi_throughput)
{
/* Pixel rates in KPixels/sec */
#define HDMI_DSC_PEAK_PIXEL_RATE 2720000
/*
* Rates at which the source and sink are required to process pixels in each
* slice, can be two levels: either atleast 340000KHz or atleast 40000KHz.
*/
#define HDMI_DSC_MAX_ENC_THROUGHPUT_0 340000
#define HDMI_DSC_MAX_ENC_THROUGHPUT_1 400000
/* Spec limits the slice width to 2720 pixels */
#define MAX_HDMI_SLICE_WIDTH 2720
int kslice_adjust;
int adjusted_clk_khz;
int min_slices;
int target_slices;
int max_throughput; /* max clock freq. in khz per slice */
int max_slice_width;
int slice_width;
int pixel_clock = crtc_state->hw.adjusted_mode.crtc_clock;
if (!hdmi_throughput)
return 0;
/*
* Slice Width determination : HDMI2.1 Section 7.7.5.1
* kslice_adjust factor for 4:2:0, and 4:2:2 formats is 0.5, where as
* for 4:4:4 is 1.0. Multiplying these factors by 10 and later
* dividing adjusted clock value by 10.
*/
if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444 ||
crtc_state->output_format == INTEL_OUTPUT_FORMAT_RGB)
kslice_adjust = 10;
else
kslice_adjust = 5;
/*
* As per spec, the rate at which the source and the sink process
* the pixels per slice are at two levels: atleast 340Mhz or 400Mhz.
* This depends upon the pixel clock rate and output formats
* (kslice adjust).
* If pixel clock * kslice adjust >= 2720MHz slices can be processed
* at max 340MHz, otherwise they can be processed at max 400MHz.
*/
adjusted_clk_khz = DIV_ROUND_UP(kslice_adjust * pixel_clock, 10);
if (adjusted_clk_khz <= HDMI_DSC_PEAK_PIXEL_RATE)
max_throughput = HDMI_DSC_MAX_ENC_THROUGHPUT_0;
else
max_throughput = HDMI_DSC_MAX_ENC_THROUGHPUT_1;
/*
* Taking into account the sink's capability for maximum
* clock per slice (in MHz) as read from HF-VSDB.
*/
max_throughput = min(max_throughput, hdmi_throughput * 1000);
min_slices = DIV_ROUND_UP(adjusted_clk_khz, max_throughput);
max_slice_width = min(MAX_HDMI_SLICE_WIDTH, src_max_slice_width);
/*
* Keep on increasing the num of slices/line, starting from min_slices
* per line till we get such a number, for which the slice_width is
* just less than max_slice_width. The slices/line selected should be
* less than or equal to the max horizontal slices that the combination
* of PCON encoder and HDMI decoder can support.
*/
slice_width = max_slice_width;
do {
if (min_slices <= 1 && src_max_slices >= 1 && hdmi_max_slices >= 1)
target_slices = 1;
else if (min_slices <= 2 && src_max_slices >= 2 && hdmi_max_slices >= 2)
target_slices = 2;
else if (min_slices <= 4 && src_max_slices >= 4 && hdmi_max_slices >= 4)
target_slices = 4;
else if (min_slices <= 8 && src_max_slices >= 8 && hdmi_max_slices >= 8)
target_slices = 8;
else if (min_slices <= 12 && src_max_slices >= 12 && hdmi_max_slices >= 12)
target_slices = 12;
else if (min_slices <= 16 && src_max_slices >= 16 && hdmi_max_slices >= 16)
target_slices = 16;
else
return 0;
slice_width = DIV_ROUND_UP(crtc_state->hw.adjusted_mode.hdisplay, target_slices);
if (slice_width >= max_slice_width)
min_slices = target_slices + 1;
} while (slice_width >= max_slice_width);
return target_slices;
}
/*
* intel_hdmi_dsc_get_bpp - get the appropriate compressed bits_per_pixel based on
* source and sink capabilities.
*
* @src_fraction_bpp: fractional bpp supported by the source
* @slice_width: dsc slice width supported by the source and sink
* @num_slices: num of slices supported by the source and sink
* @output_format: video output format
* @hdmi_all_bpp: sink supports decoding of 1/16th bpp setting
* @hdmi_max_chunk_bytes: max bytes in a line of chunks supported by sink
*
* @return: compressed bits_per_pixel in step of 1/16 of bits_per_pixel
*/
int
intel_hdmi_dsc_get_bpp(int src_fractional_bpp, int slice_width, int num_slices,
int output_format, bool hdmi_all_bpp,
int hdmi_max_chunk_bytes)
{
int max_dsc_bpp, min_dsc_bpp;
int target_bytes;
bool bpp_found = false;
int bpp_decrement_x16;
int bpp_target;
int bpp_target_x16;
/*
* Get min bpp and max bpp as per Table 7.23, in HDMI2.1 spec
* Start with the max bpp and keep on decrementing with
* fractional bpp, if supported by PCON DSC encoder
*
* for each bpp we check if no of bytes can be supported by HDMI sink
*/
/* Assuming: bpc as 8*/
if (output_format == INTEL_OUTPUT_FORMAT_YCBCR420) {
min_dsc_bpp = 6;
max_dsc_bpp = 3 * 4; /* 3*bpc/2 */
} else if (output_format == INTEL_OUTPUT_FORMAT_YCBCR444 ||
output_format == INTEL_OUTPUT_FORMAT_RGB) {
min_dsc_bpp = 8;
max_dsc_bpp = 3 * 8; /* 3*bpc */
} else {
/* Assuming 4:2:2 encoding */
min_dsc_bpp = 7;
max_dsc_bpp = 2 * 8; /* 2*bpc */
}
/*
* Taking into account if all dsc_all_bpp supported by HDMI2.1 sink
* Section 7.7.34 : Source shall not enable compressed Video
* Transport with bpp_target settings above 12 bpp unless
* DSC_all_bpp is set to 1.
*/
if (!hdmi_all_bpp)
max_dsc_bpp = min(max_dsc_bpp, 12);
/*
* The Sink has a limit of compressed data in bytes for a scanline,
* as described in max_chunk_bytes field in HFVSDB block of edid.
* The no. of bytes depend on the target bits per pixel that the
* source configures. So we start with the max_bpp and calculate
* the target_chunk_bytes. We keep on decrementing the target_bpp,
* till we get the target_chunk_bytes just less than what the sink's
* max_chunk_bytes, or else till we reach the min_dsc_bpp.
*
* The decrement is according to the fractional support from PCON DSC
* encoder. For fractional BPP we use bpp_target as a multiple of 16.
*
* bpp_target_x16 = bpp_target * 16
* So we need to decrement by {1, 2, 4, 8, 16} for fractional bpps
* {1/16, 1/8, 1/4, 1/2, 1} respectively.
*/
bpp_target = max_dsc_bpp;
/* src does not support fractional bpp implies decrement by 16 for bppx16 */
if (!src_fractional_bpp)
src_fractional_bpp = 1;
bpp_decrement_x16 = DIV_ROUND_UP(16, src_fractional_bpp);
bpp_target_x16 = (bpp_target * 16) - bpp_decrement_x16;
while (bpp_target_x16 > (min_dsc_bpp * 16)) {
int bpp;
bpp = DIV_ROUND_UP(bpp_target_x16, 16);
target_bytes = DIV_ROUND_UP((num_slices * slice_width * bpp), 8);
if (target_bytes <= hdmi_max_chunk_bytes) {
bpp_found = true;
break;
}
bpp_target_x16 -= bpp_decrement_x16;
}
if (bpp_found)
return bpp_target_x16;
return 0;
}
......@@ -50,5 +50,12 @@ bool intel_hdmi_limited_color_range(const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state);
bool intel_hdmi_deep_color_possible(const struct intel_crtc_state *crtc_state, int bpc,
bool has_hdmi_sink, bool ycbcr420_output);
int intel_hdmi_dsc_get_bpp(int src_fractional_bpp, int slice_width,
int num_slices, int output_format, bool hdmi_all_bpp,
int hdmi_max_chunk_bytes);
int intel_hdmi_dsc_get_num_slices(const struct intel_crtc_state *crtc_state,
int src_max_slices, int src_max_slice_width,
int hdmi_max_slices, int hdmi_throughput);
int intel_hdmi_dsc_get_slice_height(int vactive);
#endif /* __INTEL_HDMI_H__ */
......@@ -175,6 +175,46 @@ struct drm_scdc {
struct drm_scrambling scrambling;
};
/**
* struct drm_hdmi_dsc_cap - DSC capabilities of HDMI sink
*
* Describes the DSC support provided by HDMI 2.1 sink.
* The information is fetched fom additional HFVSDB blocks defined
* for HDMI 2.1.
*/
struct drm_hdmi_dsc_cap {
/** @v_1p2: flag for dsc1.2 version support by sink */
bool v_1p2;
/** @native_420: Does sink support DSC with 4:2:0 compression */
bool native_420;
/**
* @all_bpp: Does sink support all bpp with 4:4:4: or 4:2:2
* compressed formats
*/
bool all_bpp;
/**
* @bpc_supported: compressed bpc supported by sink : 10, 12 or 16 bpc
*/
u8 bpc_supported;
/** @max_slices: maximum number of Horizontal slices supported by */
u8 max_slices;
/** @clk_per_slice : max pixel clock in MHz supported per slice */
int clk_per_slice;
/** @max_lanes : dsc max lanes supported for Fixed rate Link training */
u8 max_lanes;
/** @max_frl_rate_per_lane : maximum frl rate with DSC per lane */
u8 max_frl_rate_per_lane;
/** @total_chunk_kbytes: max size of chunks in KBs supported per line*/
u8 total_chunk_kbytes;
};
/**
* struct drm_hdmi_info - runtime information about the connected HDMI sink
......@@ -207,6 +247,15 @@ struct drm_hdmi_info {
/** @y420_dc_modes: bitmap of deep color support index */
u8 y420_dc_modes;
/** @max_frl_rate_per_lane: support fixed rate link */
u8 max_frl_rate_per_lane;
/** @max_lanes: supported by sink */
u8 max_lanes;
/** @dsc_cap: DSC capabilities of the sink */
struct drm_hdmi_dsc_cap dsc_cap;
};
/**
......
This diff is collapsed.
......@@ -229,6 +229,36 @@ struct detailed_timing {
DRM_EDID_YCBCR420_DC_36 | \
DRM_EDID_YCBCR420_DC_30)
/* HDMI 2.1 additional fields */
#define DRM_EDID_MAX_FRL_RATE_MASK 0xf0
#define DRM_EDID_FAPA_START_LOCATION (1 << 0)
#define DRM_EDID_ALLM (1 << 1)
#define DRM_EDID_FVA (1 << 2)
/* Deep Color specific */
#define DRM_EDID_DC_30BIT_420 (1 << 0)
#define DRM_EDID_DC_36BIT_420 (1 << 1)
#define DRM_EDID_DC_48BIT_420 (1 << 2)
/* VRR specific */
#define DRM_EDID_CNMVRR (1 << 3)
#define DRM_EDID_CINEMA_VRR (1 << 4)
#define DRM_EDID_MDELTA (1 << 5)
#define DRM_EDID_VRR_MAX_UPPER_MASK 0xc0
#define DRM_EDID_VRR_MAX_LOWER_MASK 0xff
#define DRM_EDID_VRR_MIN_MASK 0x3f
/* DSC specific */
#define DRM_EDID_DSC_10BPC (1 << 0)
#define DRM_EDID_DSC_12BPC (1 << 1)
#define DRM_EDID_DSC_16BPC (1 << 2)
#define DRM_EDID_DSC_ALL_BPP (1 << 3)
#define DRM_EDID_DSC_NATIVE_420 (1 << 6)
#define DRM_EDID_DSC_1P2 (1 << 7)
#define DRM_EDID_DSC_MAX_FRL_RATE_MASK 0xf0
#define DRM_EDID_DSC_MAX_SLICES 0xf
#define DRM_EDID_DSC_TOTAL_CHUNK_KBYTES 0x3f
/* ELD Header Block */
#define DRM_ELD_HEADER_BLOCK_SIZE 4
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment