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&fil... The details are mentioned in DP to HDMI2.1 PCON Enum/Config improvement slide decks: https://groups.vesa.org/wg/DP/document/folder/1316
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.
v2: Addressed review comments and re-organized patches as suggested in comments on RFC patches.
Ankit Nautiyal (9): drm/edid: Parse DSC1.2 cap fields from HFVSDB block drm/dp_helper: Add Helpers for FRL Link Training support for DP-HDMI2.1 PCON drm/dp_helper: Add support for Configuring DSC for HDMI2.1 Pcon drm/i915: Capture max frl rate for PCON in dfp cap structure drm/i915: Add support for starting FRL training for HDMI2.1 via PCON drm/i915: Check for FRL training before DP Link training drm/i915: Read DSC capabilities of the HDMI2.1 PCON encoder drm/i915: Add helper functions for calculating DSC parameters for HDMI2.1 drm/i915: Configure PCON for DSC1.1 to DSC1.2 encoding
Swati Sharma (4): drm/edid: Add additional HFVSDB fields for HDMI2.1 drm/edid: Parse MAX_FRL field from HFVSDB block drm/dp_helper: Add support for link failure detection drm/i915: Add support for enabling link status and recovery
drivers/gpu/drm/drm_dp_helper.c | 538 ++++++++++++++++++ drivers/gpu/drm/drm_edid.c | 103 ++++ drivers/gpu/drm/i915/display/intel_ddi.c | 3 + .../drm/i915/display/intel_display_types.h | 9 + drivers/gpu/drm/i915/display/intel_dp.c | 429 +++++++++++++- drivers/gpu/drm/i915/display/intel_dp.h | 4 + drivers/gpu/drm/i915/display/intel_hdmi.c | 181 ++++++ drivers/gpu/drm/i915/display/intel_hdmi.h | 7 + include/drm/drm_connector.h | 49 ++ include/drm/drm_dp_helper.h | 212 +++++++ include/drm/drm_edid.h | 30 + 11 files changed, 1560 insertions(+), 5 deletions(-)
From: Swati Sharma swati2.sharma@intel.com
The HDMI2.1 extends HFVSDB (HDMI Forum Vendor Specific Data block) to have fields related to newly defined methods of FRL (Fixed Rate Link) levels, number of lanes supported, DSC Color bit depth, VRR min/max, FVA (Fast Vactive), ALLM etc.
This patch adds the new HFVSDB fields that are required for HDMI2.1.
v2: Minor fixes + consistent naming for DPCD register masks (Uma Shankar)
Signed-off-by: Sharma, Swati2 swati2.sharma@intel.com Signed-off-by: Ankit Nautiyal ankit.k.nautiyal@intel.com --- include/drm/drm_edid.h | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+)
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index b27a0e2169c8..a6ca992e105d 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -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
-----Original Message----- From: Nautiyal, Ankit K ankit.k.nautiyal@intel.com Sent: Sunday, November 1, 2020 3:37 PM To: intel-gfx@lists.freedesktop.org Cc: dri-devel@lists.freedesktop.org; Shankar, Uma uma.shankar@intel.com; Kulkarni, Vandita vandita.kulkarni@intel.com; ville.syrjala@linux.intel.com; Sharma, Swati2 swati2.sharma@intel.com Subject: [PATCH v2 01/13] drm/edid: Add additional HFVSDB fields for HDMI2.1
From: Swati Sharma swati2.sharma@intel.com
The HDMI2.1 extends HFVSDB (HDMI Forum Vendor Specific Data block) to have fields related to newly defined methods of FRL (Fixed Rate Link) levels, number of lanes supported, DSC Color bit depth, VRR min/max, FVA (Fast Vactive), ALLM etc.
This patch adds the new HFVSDB fields that are required for HDMI2.1.
v2: Minor fixes + consistent naming for DPCD register masks (Uma Shankar)
Looks Good to me. Reviewed-by: Uma Shankar uma.shankar@intel.com
Signed-off-by: Sharma, Swati2 swati2.sharma@intel.com Signed-off-by: Ankit Nautiyal ankit.k.nautiyal@intel.com
include/drm/drm_edid.h | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+)
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index b27a0e2169c8..a6ca992e105d 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -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
-- 2.17.1
From: Swati Sharma swati2.sharma@intel.com
This patch parses MAX_FRL field to get the MAX rate in Gbps that the HDMI 2.1 panel can support in FRL mode. Source need this field to determine the optimal rate between the source and sink during FRL training.
v2: Fixed minor bugs, and removed extra wrapper function (Uma Shankar)
Signed-off-by: Sharma, Swati2 swati2.sharma@intel.com Signed-off-by: Ankit Nautiyal ankit.k.nautiyal@intel.com --- drivers/gpu/drm/drm_edid.c | 44 +++++++++++++++++++++++++++++++++++++ include/drm/drm_connector.h | 6 +++++ 2 files changed, 50 insertions(+)
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 631125b46e04..26797868ea5b 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -4849,6 +4849,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) { @@ -4902,6 +4937,15 @@ static void drm_parse_hdmi_forum_vsdb(struct drm_connector *connector, } }
+ if (hf_vsdb[7]) { + u8 max_frl_rate; + + 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); + } + drm_parse_ycbcr420_deep_color_info(connector, hf_vsdb); }
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 928136556174..f351bf10c076 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -207,6 +207,12 @@ 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; };
/**
-----Original Message----- From: Nautiyal, Ankit K ankit.k.nautiyal@intel.com Sent: Sunday, November 1, 2020 3:37 PM To: intel-gfx@lists.freedesktop.org Cc: dri-devel@lists.freedesktop.org; Shankar, Uma uma.shankar@intel.com; Kulkarni, Vandita vandita.kulkarni@intel.com; ville.syrjala@linux.intel.com; Sharma, Swati2 swati2.sharma@intel.com Subject: [PATCH v2 02/13] drm/edid: Parse MAX_FRL field from HFVSDB block
From: Swati Sharma swati2.sharma@intel.com
This patch parses MAX_FRL field to get the MAX rate in Gbps that the HDMI 2.1 panel can support in FRL mode. Source need this field to determine the optimal rate between the source and sink during FRL training.
v2: Fixed minor bugs, and removed extra wrapper function (Uma Shankar)
Reviewed-by: Uma Shankar uma.shankar@intel.com
Signed-off-by: Sharma, Swati2 swati2.sharma@intel.com Signed-off-by: Ankit Nautiyal ankit.k.nautiyal@intel.com
drivers/gpu/drm/drm_edid.c | 44 +++++++++++++++++++++++++++++++++++++ include/drm/drm_connector.h | 6 +++++ 2 files changed, 50 insertions(+)
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 631125b46e04..26797868ea5b 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -4849,6 +4849,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) { @@ -4902,6 +4937,15 @@ static void drm_parse_hdmi_forum_vsdb(struct drm_connector *connector, } }
- if (hf_vsdb[7]) {
u8 max_frl_rate;
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);
- }
- drm_parse_ycbcr420_deep_color_info(connector, hf_vsdb); }
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 928136556174..f351bf10c076 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -207,6 +207,12 @@ 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;
};
/**
2.17.1
This patch parses HFVSDB fields for DSC1.2 capabilities of an HDMI2.1 sink. These fields are required by a source to understand the DSC capability of the sink, to set appropriate PPS parameters, before transmitting compressed data stream.
v2: Addressed following issues as suggested by Uma Shankar: -Added a new struct for hdmi dsc cap -Fixed bugs in macros usage.
Signed-off-by: Ankit Nautiyal ankit.k.nautiyal@intel.com --- drivers/gpu/drm/drm_edid.c | 59 +++++++++++++++++++++++++++++++++++++ include/drm/drm_connector.h | 43 +++++++++++++++++++++++++++ 2 files changed, 102 insertions(+)
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 26797868ea5b..feaf2d7659a4 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -4939,11 +4939,70 @@ 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); diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index f351bf10c076..06d24e36268e 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.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 @@ -213,6 +253,9 @@ struct drm_hdmi_info {
/** @max_lanes: supported by sink */ u8 max_lanes; + + /** @dsc_cap: DSC capabilities of the sink */ + struct drm_hdmi_dsc_cap dsc_cap; };
/**
-----Original Message----- From: Nautiyal, Ankit K ankit.k.nautiyal@intel.com Sent: Sunday, November 1, 2020 3:37 PM To: intel-gfx@lists.freedesktop.org Cc: dri-devel@lists.freedesktop.org; Shankar, Uma uma.shankar@intel.com; Kulkarni, Vandita vandita.kulkarni@intel.com; ville.syrjala@linux.intel.com; Sharma, Swati2 swati2.sharma@intel.com Subject: [PATCH v2 03/13] drm/edid: Parse DSC1.2 cap fields from HFVSDB block
This patch parses HFVSDB fields for DSC1.2 capabilities of an HDMI2.1 sink. These fields are required by a source to understand the DSC capability of the sink, to set appropriate PPS parameters, before transmitting compressed data stream.
v2: Addressed following issues as suggested by Uma Shankar: -Added a new struct for hdmi dsc cap -Fixed bugs in macros usage.
Reviewed-by: Uma Shankar uma.shankar@intel.com
Signed-off-by: Ankit Nautiyal ankit.k.nautiyal@intel.com
drivers/gpu/drm/drm_edid.c | 59 +++++++++++++++++++++++++++++++++++++ include/drm/drm_connector.h | 43 +++++++++++++++++++++++++++ 2 files changed, 102 insertions(+)
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 26797868ea5b..feaf2d7659a4 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -4939,11 +4939,70 @@ 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); diff --git
a/include/drm/drm_connector.h b/include/drm/drm_connector.h index f351bf10c076..06d24e36268e 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.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
@@ -213,6 +253,9 @@ struct drm_hdmi_info {
/** @max_lanes: supported by sink */ u8 max_lanes;
- /** @dsc_cap: DSC capabilities of the sink */
- struct drm_hdmi_dsc_cap dsc_cap;
};
/**
2.17.1
This patch adds support for configuring a PCON device, connected as a DP branched device to enable FRL Link training with a HDMI2.1 + sink.
v2: Fixed typos and addressed other review comments from Uma Shankar. -changed the commit message for better clarity (Uma Shankar) -removed unnecessary argument supplied to a drm helper function. -fixed return value for max frl read from pcon.
Signed-off-by: Ankit Nautiyal ankit.k.nautiyal@intel.com --- drivers/gpu/drm/drm_dp_helper.c | 302 ++++++++++++++++++++++++++++++++ include/drm/drm_dp_helper.h | 81 +++++++++ 2 files changed, 383 insertions(+)
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 14ddf28ecac0..b67580294c4e 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -2591,3 +2591,305 @@ void drm_dp_vsc_sdp_log(const char *level, struct device *dev, #undef DP_SDP_LOG } EXPORT_SYMBOL(drm_dp_vsc_sdp_log); + +/** + * drm_dp_get_pcon_max_frl_bw() - maximum frl supported by PCON + * @dpcd: DisplayPort configuration data + * @port_cap: port capabilities + * + * Returns maximum frl bandwidth supported by PCON in GBPS, + * returns 0 if not supported. + **/ +int drm_dp_get_pcon_max_frl_bw(const u8 dpcd[DP_RECEIVER_CAP_SIZE], + const u8 port_cap[4]) +{ + int bw; + u8 buf; + + buf = port_cap[2]; + bw = buf & DP_PCON_MAX_FRL_BW; + + switch (bw) { + case DP_PCON_MAX_9GBPS: + return 9; + case DP_PCON_MAX_18GBPS: + return 18; + case DP_PCON_MAX_24GBPS: + return 24; + case DP_PCON_MAX_32GBPS: + return 32; + case DP_PCON_MAX_40GBPS: + return 40; + case DP_PCON_MAX_48GBPS: + return 48; + case DP_PCON_MAX_0GBPS: + default: + return 0; + } + + return 0; +} +EXPORT_SYMBOL(drm_dp_get_pcon_max_frl_bw); + +/** + * drm_dp_get_hdmi_sink_max_frl_bw() - maximum frl supported by HDMI Sink + * @aux: DisplayPort AUX channel + * + * Returns maximum frl bandwidth supported by HDMI in Gbps on success, + * returns 0, if not supported. + **/ +int drm_dp_get_hdmi_sink_max_frl_bw(struct drm_dp_aux *aux) +{ + u8 buf; + int bw, ret; + + ret = drm_dp_dpcd_readb(aux, DP_PCON_HDMI_SINK, &buf); + if (ret < 0) + return 0; + bw = buf & DP_HDMI_SINK_LINK_BW; + + switch (bw) { + case DP_HDMI_SINK_BW_9GBPS: + return 9; + case DP_HDMI_SINK_BW_18GBPS: + return 18; + case DP_HDMI_SINK_BW_24GBPS: + return 24; + case DP_HDMI_SINK_BW_32GBPS: + return 32; + case DP_HDMI_SINK_BW_40GBPS: + return 40; + case DP_HDMI_SINK_BW_48GBPS: + return 48; + case DP_HDMI_SINK_BW_0GBPS: + default: + return 0; + } + + return 0; +} +EXPORT_SYMBOL(drm_dp_get_hdmi_sink_max_frl_bw); + +/** + * drm_dp_pcon_frl_prepare() - Prepare PCON for FRL. + * @aux: DisplayPort AUX channel + * + * Returns 0 if success, else returns negative error code. + **/ +int drm_dp_pcon_frl_prepare(struct drm_dp_aux *aux, bool enable_frl_ready_hpd) +{ + int ret; + u8 buf = DP_PCON_ENABLE_SOURCE_CTL_MODE | + DP_PCON_ENABLE_LINK_FRL_MODE; + + if (enable_frl_ready_hpd) + buf |= DP_PCON_ENABLE_HPD_READY; + + ret = drm_dp_dpcd_writeb(aux, DP_PCON_HDMI_LINK_CONFIG_1, buf); + + return ret; +} +EXPORT_SYMBOL(drm_dp_pcon_frl_prepare); + +/** + * drm_dp_pcon_is_frl_ready() - Is PCON ready for FRL + * @aux: DisplayPort AUX channel + * + * Returns true if success, else returns false. + **/ +bool drm_dp_pcon_is_frl_ready(struct drm_dp_aux *aux) +{ + int ret; + u8 buf; + + ret = drm_dp_dpcd_readb(aux, DP_PCON_HDMI_TX_LINK_STATUS, &buf); + if (ret < 0) + return false; + + if (buf & DP_PCON_FRL_READY) + return true; + + return false; +} +EXPORT_SYMBOL(drm_dp_pcon_is_frl_ready); + +/** + * drm_dp_pcon_frl_configure_1() - Set HDMI LINK Configuration-Step1 + * @aux: DisplayPort AUX channel + * @max_frl_gbps: maximum frl bw to be configured between PCON and HDMI sink + * @concurrent_mode: true if concurrent mode or operation is required, + * false otherwise. + * + * Returns 0 if success, else returns negative error code. + **/ + +int drm_dp_pcon_frl_configure_1(struct drm_dp_aux *aux, int max_frl_gbps, + bool concurrent_mode) +{ + int ret; + u8 buf; + + ret = drm_dp_dpcd_readb(aux, DP_PCON_HDMI_LINK_CONFIG_1, &buf); + if (ret < 0) + return ret; + + if (concurrent_mode) + buf |= DP_PCON_ENABLE_CONCURRENT_LINK; + else + buf &= ~DP_PCON_ENABLE_CONCURRENT_LINK; + + switch (max_frl_gbps) { + case 9: + buf |= DP_PCON_ENABLE_MAX_BW_9GBPS; + break; + case 18: + buf |= DP_PCON_ENABLE_MAX_BW_18GBPS; + break; + case 24: + buf |= DP_PCON_ENABLE_MAX_BW_24GBPS; + break; + case 32: + buf |= DP_PCON_ENABLE_MAX_BW_32GBPS; + break; + case 40: + buf |= DP_PCON_ENABLE_MAX_BW_40GBPS; + break; + case 48: + buf |= DP_PCON_ENABLE_MAX_BW_48GBPS; + break; + case 0: + buf |= DP_PCON_ENABLE_MAX_BW_0GBPS; + break; + default: + return -EINVAL; + } + + ret = drm_dp_dpcd_writeb(aux, DP_PCON_HDMI_LINK_CONFIG_1, buf); + if (ret < 0) + return ret; + + return 0; +} +EXPORT_SYMBOL(drm_dp_pcon_frl_configure_1); + +/** + * drm_dp_pcon_frl_configure_2() - Set HDMI Link configuration Step-2 + * @aux: DisplayPort AUX channel + * @max_frl_mask : Max FRL BW to be tried by the PCON with HDMI Sink + * @extended_train_mode : true for Extended Mode, false for Normal Mode. + * In Normal mode, the PCON tries each frl bw from the max_frl_mask starting + * from min, and stops when link training is successful. In Extended mode, all + * frl bw selected in the mask are trained by the PCON. + * + * Returns 0 if success, else returns negative error code. + **/ +int drm_dp_pcon_frl_configure_2(struct drm_dp_aux *aux, int max_frl_mask, + bool extended_train_mode) +{ + int ret; + u8 buf = max_frl_mask; + + if (extended_train_mode) + buf |= DP_PCON_FRL_LINK_TRAIN_EXTENDED; + + ret = drm_dp_dpcd_writeb(aux, DP_PCON_HDMI_LINK_CONFIG_2, buf); + if (ret < 0) + return ret; + + return 0; +} +EXPORT_SYMBOL(drm_dp_pcon_frl_configure_2); + +/** + * drm_dp_pcon_reset_frl_config() - Re-Set HDMI Link configuration. + * @aux: DisplayPort AUX channel + * + * Returns 0 if success, else returns negative error code. + **/ +int drm_dp_pcon_reset_frl_config(struct drm_dp_aux *aux) +{ + int ret; + + ret = drm_dp_dpcd_writeb(aux, DP_PCON_HDMI_LINK_CONFIG_1, 0x0); + if (ret < 0) + return ret; + + return 0; +} +EXPORT_SYMBOL(drm_dp_pcon_reset_frl_config); + +/** + * drm_dp_pcon_frl_enable() - Enable HDMI link through FRL + * @aux: DisplayPort AUX channel + * + * Returns 0 if success, else returns negative error code. + **/ +int drm_dp_pcon_frl_enable(struct drm_dp_aux *aux) +{ + int ret; + u8 buf = 0; + + ret = drm_dp_dpcd_readb(aux, DP_PCON_HDMI_LINK_CONFIG_1, &buf); + if (ret < 0) + return ret; + if (!(buf & DP_PCON_ENABLE_SOURCE_CTL_MODE)) { + DRM_DEBUG_KMS("PCON in Autonomous mode, can't enable FRL\n"); + return -EINVAL; + } + buf |= DP_PCON_ENABLE_HDMI_LINK; + ret = drm_dp_dpcd_writeb(aux, DP_PCON_HDMI_LINK_CONFIG_1, buf); + if (ret < 0) + return ret; + + return 0; +} +EXPORT_SYMBOL(drm_dp_pcon_frl_enable); + +/** + * drm_dp_pcon_hdmi_link_active() - check if the PCON HDMI LINK status is active. + * @aux: DisplayPort AUX channel + * + * Returns true if link is active else returns false. + **/ +bool drm_dp_pcon_hdmi_link_active(struct drm_dp_aux *aux) +{ + u8 buf; + int ret; + + ret = drm_dp_dpcd_readb(aux, DP_PCON_HDMI_TX_LINK_STATUS, &buf); + if (ret < 0) + return false; + + return buf & DP_PCON_HDMI_TX_LINK_ACTIVE; +} +EXPORT_SYMBOL(drm_dp_pcon_hdmi_link_active); + +/** + * drm_dp_pcon_hdmi_link_mode() - get the PCON HDMI LINK MODE + * @aux: DisplayPort AUX channel + * @frl_trained_mask: pointer to store bitmask of the trained bw configuration. + * Valid only if the MODE returned is FRL. For Normal Link training mode + * only 1 of the bits will be set, but in case of Extended mode, more than + * one bits can be set. + * + * Returns the link mode : TMDS or FRL on success, else returns negative error + * code. + **/ +int drm_dp_pcon_hdmi_link_mode(struct drm_dp_aux *aux, u8 *frl_trained_mask) +{ + u8 buf; + int mode; + int ret; + + ret = drm_dp_dpcd_readb(aux, DP_PCON_HDMI_POST_FRL_STATUS, &buf); + if (ret < 0) + return ret; + + mode = buf & DP_PCON_HDMI_LINK_MODE; + + if (frl_trained_mask && DP_PCON_HDMI_MODE_FRL == mode) + *frl_trained_mask = (buf & DP_PCON_HDMI_FRL_TRAINED_BW) >> 1; + + return mode; +} +EXPORT_SYMBOL(drm_dp_pcon_hdmi_link_mode); diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index f55a9d1320ca..e2ed6bfaae89 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -411,6 +411,17 @@ struct drm_device; # define DP_DS_10BPC 1 # define DP_DS_12BPC 2 # define DP_DS_16BPC 3 +/* HDMI2.1 PCON FRL CONFIGURATION */ +# define DP_PCON_MAX_FRL_BW (7 << 2) +# define DP_PCON_MAX_0GBPS (0 << 2) +# define DP_PCON_MAX_9GBPS (1 << 2) +# define DP_PCON_MAX_18GBPS (2 << 2) +# define DP_PCON_MAX_24GBPS (3 << 2) +# define DP_PCON_MAX_32GBPS (4 << 2) +# define DP_PCON_MAX_40GBPS (5 << 2) +# define DP_PCON_MAX_48GBPS (6 << 2) +# define DP_PCON_SOURCE_CTL_MODE (1 << 5) + /* offset 3 for DVI */ # define DP_DS_DVI_DUAL_LINK (1 << 1) # define DP_DS_DVI_HIGH_COLOR_DEPTH (1 << 2) @@ -1053,6 +1064,61 @@ struct drm_device; #define DP_CEC_RX_MESSAGE_BUFFER 0x3010 #define DP_CEC_TX_MESSAGE_BUFFER 0x3020 #define DP_CEC_MESSAGE_BUFFER_LENGTH 0x10 +/* PROTOCOL CONVERSION HDMI SINK */ +#define DP_PCON_HDMI_SINK 0x3035 +# define DP_HDMI_SINK_LINK_BW (7 << 0) +# define DP_HDMI_SINK_BW_0GBPS 0 +# define DP_HDMI_SINK_BW_9GBPS 1 +# define DP_HDMI_SINK_BW_18GBPS 2 +# define DP_HDMI_SINK_BW_24GBPS 3 +# define DP_HDMI_SINK_BW_32GBPS 4 +# define DP_HDMI_SINK_BW_40GBPS 5 +# define DP_HDMI_SINK_BW_48GBPS 6 + +/* PCON CONFIGURE-1 FRL FOR HDMI SINK */ +#define DP_PCON_HDMI_LINK_CONFIG_1 0x305A +# define DP_PCON_ENABLE_MAX_FRL_BW (7 << 0) +# define DP_PCON_ENABLE_MAX_BW_0GBPS 0 +# define DP_PCON_ENABLE_MAX_BW_9GBPS 1 +# define DP_PCON_ENABLE_MAX_BW_18GBPS 2 +# define DP_PCON_ENABLE_MAX_BW_24GBPS 3 +# define DP_PCON_ENABLE_MAX_BW_32GBPS 4 +# define DP_PCON_ENABLE_MAX_BW_40GBPS 5 +# define DP_PCON_ENABLE_MAX_BW_48GBPS 6 +# define DP_PCON_ENABLE_SOURCE_CTL_MODE (1 << 3) +# define DP_PCON_ENABLE_CONCURRENT_LINK (1 << 4) +# define DP_PCON_ENABLE_LINK_FRL_MODE (1 << 5) +# define DP_PCON_ENABLE_HPD_READY (1 << 6) +# define DP_PCON_ENABLE_HDMI_LINK (1 << 7) + +/* PCON CONFIGURE-2 FRL FOR HDMI SINK */ +#define DP_PCON_HDMI_LINK_CONFIG_2 0x305B +# define DP_PCON_MAX_LINK_BW_MASK (0x3F << 0) +# define DP_PCON_FRL_BW_MASK_9GBPS (1 << 0) +# define DP_PCON_FRL_BW_MASK_18GBPS (1 << 1) +# define DP_PCON_FRL_BW_MASK_24GBPS (1 << 2) +# define DP_PCON_FRL_BW_MASK_32GBPS (1 << 3) +# define DP_PCON_FRL_BW_MASK_40GBPS (1 << 4) +# define DP_PCON_FRL_BW_MASK_48GBPS (1 << 5) +# define DP_PCON_FRL_LINK_TRAIN_EXTENDED (1 << 6) + +/* PCON HDMI LINK STATUS */ +#define DP_PCON_HDMI_TX_LINK_STATUS 0x303B +# define DP_PCON_HDMI_TX_LINK_ACTIVE (1 << 0) +# define DP_PCON_FRL_READY (1 << 1) + +/* PCON HDMI POST FRL STATUS */ +#define DP_PCON_HDMI_POST_FRL_STATUS 0x3036 +# define DP_PCON_HDMI_LINK_MODE (1 << 0) +# define DP_PCON_HDMI_MODE_TMDS 0 +# define DP_PCON_HDMI_MODE_FRL 1 +# define DP_PCON_HDMI_FRL_TRAINED_BW (0x3F << 1) +# define DP_PCON_FRL_TRAINED_BW_9GBPS (1 << 1) +# define DP_PCON_FRL_TRAINED_BW_18GBPS (1 << 2) +# define DP_PCON_FRL_TRAINED_BW_24GBPS (1 << 3) +# define DP_PCON_FRL_TRAINED_BW_32GBPS (1 << 4) +# define DP_PCON_FRL_TRAINED_BW_40GBPS (1 << 5) +# define DP_PCON_FRL_TRAINED_BW_48GBPS (1 << 6)
#define DP_PROTOCOL_CONVERTER_CONTROL_0 0x3050 /* DP 1.3 */ # define DP_HDMI_DVI_OUTPUT_CONFIG (1 << 0) /* DP 1.3 */ @@ -1967,4 +2033,19 @@ int drm_dp_get_phy_test_pattern(struct drm_dp_aux *aux, struct drm_dp_phy_test_params *data); int drm_dp_set_phy_test_pattern(struct drm_dp_aux *aux, struct drm_dp_phy_test_params *data, u8 dp_rev); +int drm_dp_get_pcon_max_frl_bw(const u8 dpcd[DP_RECEIVER_CAP_SIZE], + const u8 port_cap[4]); +int drm_dp_get_hdmi_sink_max_frl_bw(struct drm_dp_aux *aux); +int drm_dp_pcon_frl_prepare(struct drm_dp_aux *aux, bool enable_frl_ready_hpd); +bool drm_dp_pcon_is_frl_ready(struct drm_dp_aux *aux); +int drm_dp_pcon_frl_configure_1(struct drm_dp_aux *aux, int max_frl_gbps, + bool concurrent_mode); +int drm_dp_pcon_frl_configure_2(struct drm_dp_aux *aux, int max_frl_mask, + bool extended_train_mode); +int drm_dp_pcon_reset_frl_config(struct drm_dp_aux *aux); +int drm_dp_pcon_frl_enable(struct drm_dp_aux *aux); + +bool drm_dp_pcon_hdmi_link_active(struct drm_dp_aux *aux); +int drm_dp_pcon_hdmi_link_mode(struct drm_dp_aux *aux, u8 *frl_trained_mask); + #endif /* _DRM_DP_HELPER_H_ */
-----Original Message----- From: Nautiyal, Ankit K ankit.k.nautiyal@intel.com Sent: Sunday, November 1, 2020 3:37 PM To: intel-gfx@lists.freedesktop.org Cc: dri-devel@lists.freedesktop.org; Shankar, Uma uma.shankar@intel.com; Kulkarni, Vandita vandita.kulkarni@intel.com; ville.syrjala@linux.intel.com; Sharma, Swati2 swati2.sharma@intel.com Subject: [PATCH v2 04/13] drm/dp_helper: Add Helpers for FRL Link Training support for DP-HDMI2.1 PCON
This patch adds support for configuring a PCON device, connected as a DP branched device to enable FRL Link training with a HDMI2.1 + sink.
v2: Fixed typos and addressed other review comments from Uma Shankar. -changed the commit message for better clarity (Uma Shankar) -removed unnecessary argument supplied to a drm helper function. -fixed return value for max frl read from pcon.
Signed-off-by: Ankit Nautiyal ankit.k.nautiyal@intel.com
drivers/gpu/drm/drm_dp_helper.c | 302 ++++++++++++++++++++++++++++++++ include/drm/drm_dp_helper.h | 81 +++++++++ 2 files changed, 383 insertions(+)
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 14ddf28ecac0..b67580294c4e 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -2591,3 +2591,305 @@ void drm_dp_vsc_sdp_log(const char *level, struct device *dev, #undef DP_SDP_LOG } EXPORT_SYMBOL(drm_dp_vsc_sdp_log);
+/**
- drm_dp_get_pcon_max_frl_bw() - maximum frl supported by PCON
- @dpcd: DisplayPort configuration data
- @port_cap: port capabilities
- Returns maximum frl bandwidth supported by PCON in GBPS,
- returns 0 if not supported.
- **/
+int drm_dp_get_pcon_max_frl_bw(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
const u8 port_cap[4])
+{
- int bw;
- u8 buf;
- buf = port_cap[2];
- bw = buf & DP_PCON_MAX_FRL_BW;
- switch (bw) {
- case DP_PCON_MAX_9GBPS:
return 9;
- case DP_PCON_MAX_18GBPS:
return 18;
- case DP_PCON_MAX_24GBPS:
return 24;
- case DP_PCON_MAX_32GBPS:
return 32;
- case DP_PCON_MAX_40GBPS:
return 40;
- case DP_PCON_MAX_48GBPS:
return 48;
- case DP_PCON_MAX_0GBPS:
- default:
return 0;
- }
- return 0;
+} +EXPORT_SYMBOL(drm_dp_get_pcon_max_frl_bw);
+/**
- drm_dp_get_hdmi_sink_max_frl_bw() - maximum frl supported by HDMI
+Sink
- @aux: DisplayPort AUX channel
- Returns maximum frl bandwidth supported by HDMI in Gbps on success,
- returns 0, if not supported.
- **/
+int drm_dp_get_hdmi_sink_max_frl_bw(struct drm_dp_aux *aux) {
- u8 buf;
- int bw, ret;
- ret = drm_dp_dpcd_readb(aux, DP_PCON_HDMI_SINK, &buf);
- if (ret < 0)
return 0;
- bw = buf & DP_HDMI_SINK_LINK_BW;
- switch (bw) {
- case DP_HDMI_SINK_BW_9GBPS:
return 9;
- case DP_HDMI_SINK_BW_18GBPS:
return 18;
- case DP_HDMI_SINK_BW_24GBPS:
return 24;
- case DP_HDMI_SINK_BW_32GBPS:
return 32;
- case DP_HDMI_SINK_BW_40GBPS:
return 40;
- case DP_HDMI_SINK_BW_48GBPS:
return 48;
- case DP_HDMI_SINK_BW_0GBPS:
- default:
return 0;
- }
- return 0;
+} +EXPORT_SYMBOL(drm_dp_get_hdmi_sink_max_frl_bw);
+/**
- drm_dp_pcon_frl_prepare() - Prepare PCON for FRL.
- @aux: DisplayPort AUX channel
- Returns 0 if success, else returns negative error code.
- **/
+int drm_dp_pcon_frl_prepare(struct drm_dp_aux *aux, bool +enable_frl_ready_hpd) {
- int ret;
- u8 buf = DP_PCON_ENABLE_SOURCE_CTL_MODE |
DP_PCON_ENABLE_LINK_FRL_MODE;
- if (enable_frl_ready_hpd)
buf |= DP_PCON_ENABLE_HPD_READY;
- ret = drm_dp_dpcd_writeb(aux, DP_PCON_HDMI_LINK_CONFIG_1, buf);
- return ret;
+} +EXPORT_SYMBOL(drm_dp_pcon_frl_prepare);
+/**
- drm_dp_pcon_is_frl_ready() - Is PCON ready for FRL
- @aux: DisplayPort AUX channel
- Returns true if success, else returns false.
- **/
+bool drm_dp_pcon_is_frl_ready(struct drm_dp_aux *aux) {
- int ret;
- u8 buf;
- ret = drm_dp_dpcd_readb(aux, DP_PCON_HDMI_TX_LINK_STATUS, &buf);
- if (ret < 0)
return false;
- if (buf & DP_PCON_FRL_READY)
return true;
- return false;
+} +EXPORT_SYMBOL(drm_dp_pcon_is_frl_ready);
+/**
- drm_dp_pcon_frl_configure_1() - Set HDMI LINK Configuration-Step1
- @aux: DisplayPort AUX channel
- @max_frl_gbps: maximum frl bw to be configured between PCON and HDMI
+sink
- @concurrent_mode: true if concurrent mode or operation is required,
- false otherwise.
- Returns 0 if success, else returns negative error code.
- **/
+int drm_dp_pcon_frl_configure_1(struct drm_dp_aux *aux, int max_frl_gbps,
bool concurrent_mode)
+{
- int ret;
- u8 buf;
- ret = drm_dp_dpcd_readb(aux, DP_PCON_HDMI_LINK_CONFIG_1, &buf);
- if (ret < 0)
return ret;
- if (concurrent_mode)
buf |= DP_PCON_ENABLE_CONCURRENT_LINK;
- else
buf &= ~DP_PCON_ENABLE_CONCURRENT_LINK;
- switch (max_frl_gbps) {
- case 9:
buf |= DP_PCON_ENABLE_MAX_BW_9GBPS;
break;
- case 18:
buf |= DP_PCON_ENABLE_MAX_BW_18GBPS;
break;
- case 24:
buf |= DP_PCON_ENABLE_MAX_BW_24GBPS;
break;
- case 32:
buf |= DP_PCON_ENABLE_MAX_BW_32GBPS;
break;
- case 40:
buf |= DP_PCON_ENABLE_MAX_BW_40GBPS;
break;
- case 48:
buf |= DP_PCON_ENABLE_MAX_BW_48GBPS;
break;
- case 0:
buf |= DP_PCON_ENABLE_MAX_BW_0GBPS;
break;
- default:
return -EINVAL;
- }
- ret = drm_dp_dpcd_writeb(aux, DP_PCON_HDMI_LINK_CONFIG_1, buf);
- if (ret < 0)
return ret;
- return 0;
+} +EXPORT_SYMBOL(drm_dp_pcon_frl_configure_1);
+/**
- drm_dp_pcon_frl_configure_2() - Set HDMI Link configuration Step-2
- @aux: DisplayPort AUX channel
- @max_frl_mask : Max FRL BW to be tried by the PCON with HDMI Sink
- @extended_train_mode : true for Extended Mode, false for Normal Mode.
- In Normal mode, the PCON tries each frl bw from the max_frl_mask
+starting
- from min, and stops when link training is successful. In Extended
+mode, all
- frl bw selected in the mask are trained by the PCON.
- Returns 0 if success, else returns negative error code.
- **/
+int drm_dp_pcon_frl_configure_2(struct drm_dp_aux *aux, int max_frl_mask,
bool extended_train_mode)
+{
- int ret;
- u8 buf = max_frl_mask;
- if (extended_train_mode)
buf |= DP_PCON_FRL_LINK_TRAIN_EXTENDED;
- ret = drm_dp_dpcd_writeb(aux, DP_PCON_HDMI_LINK_CONFIG_2, buf);
- if (ret < 0)
return ret;
- return 0;
+} +EXPORT_SYMBOL(drm_dp_pcon_frl_configure_2);
+/**
- drm_dp_pcon_reset_frl_config() - Re-Set HDMI Link configuration.
- @aux: DisplayPort AUX channel
- Returns 0 if success, else returns negative error code.
- **/
+int drm_dp_pcon_reset_frl_config(struct drm_dp_aux *aux) {
- int ret;
- ret = drm_dp_dpcd_writeb(aux, DP_PCON_HDMI_LINK_CONFIG_1, 0x0);
- if (ret < 0)
return ret;
- return 0;
+} +EXPORT_SYMBOL(drm_dp_pcon_reset_frl_config);
+/**
- drm_dp_pcon_frl_enable() - Enable HDMI link through FRL
- @aux: DisplayPort AUX channel
- Returns 0 if success, else returns negative error code.
- **/
+int drm_dp_pcon_frl_enable(struct drm_dp_aux *aux) {
- int ret;
- u8 buf = 0;
- ret = drm_dp_dpcd_readb(aux, DP_PCON_HDMI_LINK_CONFIG_1, &buf);
- if (ret < 0)
return ret;
- if (!(buf & DP_PCON_ENABLE_SOURCE_CTL_MODE)) {
DRM_DEBUG_KMS("PCON in Autonomous mode, can't enable
FRL\n");
return -EINVAL;
- }
- buf |= DP_PCON_ENABLE_HDMI_LINK;
- ret = drm_dp_dpcd_writeb(aux, DP_PCON_HDMI_LINK_CONFIG_1, buf);
- if (ret < 0)
return ret;
- return 0;
+} +EXPORT_SYMBOL(drm_dp_pcon_frl_enable);
+/**
- drm_dp_pcon_hdmi_link_active() - check if the PCON HDMI LINK status is
active.
- @aux: DisplayPort AUX channel
- Returns true if link is active else returns false.
- **/
+bool drm_dp_pcon_hdmi_link_active(struct drm_dp_aux *aux) {
- u8 buf;
- int ret;
- ret = drm_dp_dpcd_readb(aux, DP_PCON_HDMI_TX_LINK_STATUS, &buf);
- if (ret < 0)
return false;
- return buf & DP_PCON_HDMI_TX_LINK_ACTIVE; }
+EXPORT_SYMBOL(drm_dp_pcon_hdmi_link_active);
+/**
- drm_dp_pcon_hdmi_link_mode() - get the PCON HDMI LINK MODE
- @aux: DisplayPort AUX channel
- @frl_trained_mask: pointer to store bitmask of the trained bw configuration.
- Valid only if the MODE returned is FRL. For Normal Link training
+mode
- only 1 of the bits will be set, but in case of Extended mode, more
+than
- one bits can be set.
- Returns the link mode : TMDS or FRL on success, else returns
+negative error
- code.
- **/
+int drm_dp_pcon_hdmi_link_mode(struct drm_dp_aux *aux, u8 +*frl_trained_mask) {
- u8 buf;
- int mode;
- int ret;
- ret = drm_dp_dpcd_readb(aux, DP_PCON_HDMI_POST_FRL_STATUS,
&buf);
- if (ret < 0)
return ret;
- mode = buf & DP_PCON_HDMI_LINK_MODE;
- if (frl_trained_mask && DP_PCON_HDMI_MODE_FRL == mode)
*frl_trained_mask = (buf & DP_PCON_HDMI_FRL_TRAINED_BW)
1;
- return mode;
+} +EXPORT_SYMBOL(drm_dp_pcon_hdmi_link_mode); diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index f55a9d1320ca..e2ed6bfaae89 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -411,6 +411,17 @@ struct drm_device; # define DP_DS_10BPC 1 # define DP_DS_12BPC 2 # define DP_DS_16BPC 3 +/* HDMI2.1 PCON FRL CONFIGURATION */ +# define DP_PCON_MAX_FRL_BW (7 << 2) +# define DP_PCON_MAX_0GBPS (0 << 2) +# define DP_PCON_MAX_9GBPS (1 << 2) +# define DP_PCON_MAX_18GBPS (2 << 2) +# define DP_PCON_MAX_24GBPS (3 << 2) +# define DP_PCON_MAX_32GBPS (4 << 2) +# define DP_PCON_MAX_40GBPS (5 << 2) +# define DP_PCON_MAX_48GBPS (6 << 2) +# define DP_PCON_SOURCE_CTL_MODE (1 << 5)
/* offset 3 for DVI */ # define DP_DS_DVI_DUAL_LINK (1 << 1) # define DP_DS_DVI_HIGH_COLOR_DEPTH (1 << 2) @@ -1053,6 +1064,61 @@ struct drm_device; #define DP_CEC_RX_MESSAGE_BUFFER 0x3010 #define DP_CEC_TX_MESSAGE_BUFFER 0x3020 #define DP_CEC_MESSAGE_BUFFER_LENGTH 0x10 +/* PROTOCOL CONVERSION HDMI SINK */ +#define DP_PCON_HDMI_SINK 0x3035 +# define DP_HDMI_SINK_LINK_BW (7 << 0) +# define DP_HDMI_SINK_BW_0GBPS 0 +# define DP_HDMI_SINK_BW_9GBPS 1 +# define DP_HDMI_SINK_BW_18GBPS 2 +# define DP_HDMI_SINK_BW_24GBPS 3 +# define DP_HDMI_SINK_BW_32GBPS 4 +# define DP_HDMI_SINK_BW_40GBPS 5 +# define DP_HDMI_SINK_BW_48GBPS 6
+/* PCON CONFIGURE-1 FRL FOR HDMI SINK */ +#define DP_PCON_HDMI_LINK_CONFIG_1 0x305A +# define DP_PCON_ENABLE_MAX_FRL_BW (7 << 0) +# define DP_PCON_ENABLE_MAX_BW_0GBPS 0 +# define DP_PCON_ENABLE_MAX_BW_9GBPS 1 +# define DP_PCON_ENABLE_MAX_BW_18GBPS 2 +# define DP_PCON_ENABLE_MAX_BW_24GBPS 3 +# define DP_PCON_ENABLE_MAX_BW_32GBPS 4 +# define DP_PCON_ENABLE_MAX_BW_40GBPS 5 +# define DP_PCON_ENABLE_MAX_BW_48GBPS 6 +# define DP_PCON_ENABLE_SOURCE_CTL_MODE (1 << 3) +# define DP_PCON_ENABLE_CONCURRENT_LINK (1 << 4) +# define DP_PCON_ENABLE_LINK_FRL_MODE (1 << 5) +# define DP_PCON_ENABLE_HPD_READY (1 << 6) +# define DP_PCON_ENABLE_HDMI_LINK (1 << 7)
+/* PCON CONFIGURE-2 FRL FOR HDMI SINK */ +#define DP_PCON_HDMI_LINK_CONFIG_2 0x305B +# define DP_PCON_MAX_LINK_BW_MASK (0x3F << 0) +# define DP_PCON_FRL_BW_MASK_9GBPS (1 << 0) +# define DP_PCON_FRL_BW_MASK_18GBPS (1 << 1) +# define DP_PCON_FRL_BW_MASK_24GBPS (1 << 2) +# define DP_PCON_FRL_BW_MASK_32GBPS (1 << 3) +# define DP_PCON_FRL_BW_MASK_40GBPS (1 << 4) +# define DP_PCON_FRL_BW_MASK_48GBPS (1 << 5) +# define DP_PCON_FRL_LINK_TRAIN_EXTENDED (1 << 6)
+/* PCON HDMI LINK STATUS */ +#define DP_PCON_HDMI_TX_LINK_STATUS 0x303B +# define DP_PCON_HDMI_TX_LINK_ACTIVE (1 << 0) +# define DP_PCON_FRL_READY (1 << 1)
+/* PCON HDMI POST FRL STATUS */ +#define DP_PCON_HDMI_POST_FRL_STATUS 0x3036 +# define DP_PCON_HDMI_LINK_MODE (1 << 0) +# define DP_PCON_HDMI_MODE_TMDS 0 +# define DP_PCON_HDMI_MODE_FRL 1 +# define DP_PCON_HDMI_FRL_TRAINED_BW (0x3F << 1)
Seems you have missed the comment here. Bit 4:7 are reserved, so adjust this accordingly. With this fixed: Reviewed-by: Uma Shankar uma.shankar@intel.com
+# define DP_PCON_FRL_TRAINED_BW_9GBPS (1 << 1) +# define DP_PCON_FRL_TRAINED_BW_18GBPS (1 << 2) +# define DP_PCON_FRL_TRAINED_BW_24GBPS (1 << 3) +# define DP_PCON_FRL_TRAINED_BW_32GBPS (1 << 4) +# define DP_PCON_FRL_TRAINED_BW_40GBPS (1 << 5) +# define DP_PCON_FRL_TRAINED_BW_48GBPS (1 << 6)
#define DP_PROTOCOL_CONVERTER_CONTROL_0 0x3050 /* DP 1.3 */ # define DP_HDMI_DVI_OUTPUT_CONFIG (1 << 0) /* DP 1.3 */ @@ -1967,4 +2033,19 @@ int drm_dp_get_phy_test_pattern(struct drm_dp_aux *aux, struct drm_dp_phy_test_params *data); int drm_dp_set_phy_test_pattern(struct drm_dp_aux *aux, struct drm_dp_phy_test_params *data, u8 dp_rev); +int drm_dp_get_pcon_max_frl_bw(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
const u8 port_cap[4]);
+int drm_dp_get_hdmi_sink_max_frl_bw(struct drm_dp_aux *aux); int +drm_dp_pcon_frl_prepare(struct drm_dp_aux *aux, bool +enable_frl_ready_hpd); bool drm_dp_pcon_is_frl_ready(struct drm_dp_aux +*aux); int drm_dp_pcon_frl_configure_1(struct drm_dp_aux *aux, int max_frl_gbps,
bool concurrent_mode);
+int drm_dp_pcon_frl_configure_2(struct drm_dp_aux *aux, int max_frl_mask,
bool extended_train_mode);
+int drm_dp_pcon_reset_frl_config(struct drm_dp_aux *aux); int +drm_dp_pcon_frl_enable(struct drm_dp_aux *aux);
+bool drm_dp_pcon_hdmi_link_active(struct drm_dp_aux *aux); int +drm_dp_pcon_hdmi_link_mode(struct drm_dp_aux *aux, u8 +*frl_trained_mask);
#endif /* _DRM_DP_HELPER_H_ */
2.17.1
From: Swati Sharma swati2.sharma@intel.com
There are specific DPCDs defined for detecting link failures between the PCON and HDMI sink and check the link status. In case of link failure, PCON will communicate the same using an IRQ_HPD to source. HDMI sink would have indicated the same to PCON using SCDC interrupt mechanism. While source can always read final HDMI sink's status using I2C over AUX, it is easier and faster to read the PCONs already read HDMI sink status registers.
This patch adds the DPCDs required for link failure detection and provide a helper function for printing error count/lane which might help in debugging the link failure issues.
v2: Addressed comments from Uma Shankar: -rephrased the commit message, as per the code. -fixed styling issues -added documentation for the helper function.
Signed-off-by: Swati Sharma swati2.sharma@intel.com Signed-off-by: Ankit Nautiyal ankit.k.nautiyal@intel.com --- drivers/gpu/drm/drm_dp_helper.c | 39 +++++++++++++++++++++++++++++++++ include/drm/drm_dp_helper.h | 17 ++++++++++++++ 2 files changed, 56 insertions(+)
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index b67580294c4e..05782091e7e1 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -2893,3 +2893,42 @@ int drm_dp_pcon_hdmi_link_mode(struct drm_dp_aux *aux, u8 *frl_trained_mask) return mode; } EXPORT_SYMBOL(drm_dp_pcon_hdmi_link_mode); + +/** + * drm_dp_pcon_hdmi_frl_link_error_count() - print the error count per lane + * during link failure between PCON and HDMI sink + * @aux: DisplayPort AUX channel + * @connector: DRM connector + * code. + **/ + +void drm_dp_pcon_hdmi_frl_link_error_count(struct drm_dp_aux *aux, + struct drm_connector *connector) +{ + u8 buf, error_count; + int i, num_error; + struct drm_hdmi_info *hdmi = &connector->display_info.hdmi; + + for (i = 0; i < hdmi->max_lanes; i++) { + if (drm_dp_dpcd_readb(aux, DP_PCON_HDMI_ERROR_STATUS_LN0 + i, &buf) < 0) + return; + + error_count = buf & DP_PCON_HDMI_ERROR_COUNT_MASK; + switch (error_count) { + case DP_PCON_HDMI_ERROR_COUNT_HUNDRED_PLUS: + num_error = 100; + break; + case DP_PCON_HDMI_ERROR_COUNT_TEN_PLUS: + num_error = 10; + break; + case DP_PCON_HDMI_ERROR_COUNT_THREE_PLUS: + num_error = 3; + break; + default: + num_error = 0; + } + + DRM_ERROR("More than %d errors since the last read for lane %d", num_error, i); + } +} +EXPORT_SYMBOL(drm_dp_pcon_hdmi_frl_link_error_count); diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index e2ed6bfaae89..bdbe9bbdb244 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -946,6 +946,11 @@ struct drm_device; # define DP_CEC_IRQ (1 << 2)
#define DP_LINK_SERVICE_IRQ_VECTOR_ESI0 0x2005 /* 1.2 */ +# define RX_CAP_CHANGED (1 << 0) +# define LINK_STATUS_CHANGED (1 << 1) +# define STREAM_STATUS_CHANGED (1 << 2) +# define HDMI_LINK_STATUS_CHANGED (1 << 3) +# define CONNECTED_OFF_ENTRY_REQUESTED (1 << 4)
#define DP_PSR_ERROR_STATUS 0x2006 /* XXX 1.2? */ # define DP_PSR_LINK_CRC_ERROR (1 << 0) @@ -1130,6 +1135,16 @@ struct drm_device; #define DP_PROTOCOL_CONVERTER_CONTROL_2 0x3052 /* DP 1.3 */ # define DP_CONVERSION_TO_YCBCR422_ENABLE (1 << 0) /* DP 1.3 */
+/* PCON Downstream HDMI ERROR Status per Lane */ +#define DP_PCON_HDMI_ERROR_STATUS_LN0 0x3037 +#define DP_PCON_HDMI_ERROR_STATUS_LN1 0x3038 +#define DP_PCON_HDMI_ERROR_STATUS_LN2 0x3039 +#define DP_PCON_HDMI_ERROR_STATUS_LN3 0x303A +# define DP_PCON_HDMI_ERROR_COUNT_MASK (0x7 << 0) +# define DP_PCON_HDMI_ERROR_COUNT_THREE_PLUS (1 << 0) +# define DP_PCON_HDMI_ERROR_COUNT_TEN_PLUS (1 << 1) +# define DP_PCON_HDMI_ERROR_COUNT_HUNDRED_PLUS (1 << 2) + /* HDCP 1.3 and HDCP 2.2 */ #define DP_AUX_HDCP_BKSV 0x68000 #define DP_AUX_HDCP_RI_PRIME 0x68005 @@ -2047,5 +2062,7 @@ int drm_dp_pcon_frl_enable(struct drm_dp_aux *aux);
bool drm_dp_pcon_hdmi_link_active(struct drm_dp_aux *aux); int drm_dp_pcon_hdmi_link_mode(struct drm_dp_aux *aux, u8 *frl_trained_mask); +void drm_dp_pcon_hdmi_frl_link_error_count(struct drm_dp_aux *aux, + struct drm_connector *connector);
#endif /* _DRM_DP_HELPER_H_ */
-----Original Message----- From: Nautiyal, Ankit K ankit.k.nautiyal@intel.com Sent: Sunday, November 1, 2020 3:37 PM To: intel-gfx@lists.freedesktop.org Cc: dri-devel@lists.freedesktop.org; Shankar, Uma uma.shankar@intel.com; Kulkarni, Vandita vandita.kulkarni@intel.com; ville.syrjala@linux.intel.com; Sharma, Swati2 swati2.sharma@intel.com Subject: [PATCH v2 05/13] drm/dp_helper: Add support for link failure detection
From: Swati Sharma swati2.sharma@intel.com
There are specific DPCDs defined for detecting link failures between the PCON and HDMI sink and check the link status. In case of link failure, PCON will communicate the same using an IRQ_HPD to source. HDMI sink would have indicated the same to PCON using SCDC interrupt mechanism. While source can always read final HDMI sink's status using I2C over AUX, it is easier and faster to read the PCONs already read HDMI sink status registers.
This patch adds the DPCDs required for link failure detection and provide a helper function for printing error count/lane which might help in debugging the link failure issues.
v2: Addressed comments from Uma Shankar: -rephrased the commit message, as per the code. -fixed styling issues -added documentation for the helper function.
Reviewed-by: Uma Shankar uma.shankar@intel.com
Signed-off-by: Swati Sharma swati2.sharma@intel.com Signed-off-by: Ankit Nautiyal ankit.k.nautiyal@intel.com
drivers/gpu/drm/drm_dp_helper.c | 39 +++++++++++++++++++++++++++++++++ include/drm/drm_dp_helper.h | 17 ++++++++++++++ 2 files changed, 56 insertions(+)
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index b67580294c4e..05782091e7e1 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -2893,3 +2893,42 @@ int drm_dp_pcon_hdmi_link_mode(struct drm_dp_aux *aux, u8 *frl_trained_mask) return mode; } EXPORT_SYMBOL(drm_dp_pcon_hdmi_link_mode);
+/**
- drm_dp_pcon_hdmi_frl_link_error_count() - print the error count per
+lane
- during link failure between PCON and HDMI sink
- @aux: DisplayPort AUX channel
- @connector: DRM connector
- code.
- **/
+void drm_dp_pcon_hdmi_frl_link_error_count(struct drm_dp_aux *aux,
struct drm_connector *connector) {
- u8 buf, error_count;
- int i, num_error;
- struct drm_hdmi_info *hdmi = &connector->display_info.hdmi;
- for (i = 0; i < hdmi->max_lanes; i++) {
if (drm_dp_dpcd_readb(aux,
DP_PCON_HDMI_ERROR_STATUS_LN0 + i, &buf) < 0)
return;
error_count = buf & DP_PCON_HDMI_ERROR_COUNT_MASK;
switch (error_count) {
case DP_PCON_HDMI_ERROR_COUNT_HUNDRED_PLUS:
num_error = 100;
break;
case DP_PCON_HDMI_ERROR_COUNT_TEN_PLUS:
num_error = 10;
break;
case DP_PCON_HDMI_ERROR_COUNT_THREE_PLUS:
num_error = 3;
break;
default:
num_error = 0;
}
DRM_ERROR("More than %d errors since the last read for lane
%d", num_error, i);
- }
+} +EXPORT_SYMBOL(drm_dp_pcon_hdmi_frl_link_error_count); diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index e2ed6bfaae89..bdbe9bbdb244 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -946,6 +946,11 @@ struct drm_device; # define DP_CEC_IRQ (1 << 2)
#define DP_LINK_SERVICE_IRQ_VECTOR_ESI0 0x2005 /* 1.2 */ +# define RX_CAP_CHANGED (1 << 0) +# define LINK_STATUS_CHANGED (1 << 1) +# define STREAM_STATUS_CHANGED (1 << 2) +# define HDMI_LINK_STATUS_CHANGED (1 << 3) +# define CONNECTED_OFF_ENTRY_REQUESTED (1 << 4)
#define DP_PSR_ERROR_STATUS 0x2006 /* XXX 1.2? */ # define DP_PSR_LINK_CRC_ERROR (1 << 0) @@ -1130,6 +1135,16 @@ struct drm_device; #define DP_PROTOCOL_CONVERTER_CONTROL_2 0x3052 /* DP 1.3 */ # define DP_CONVERSION_TO_YCBCR422_ENABLE (1 << 0) /* DP 1.3 */
+/* PCON Downstream HDMI ERROR Status per Lane */ +#define DP_PCON_HDMI_ERROR_STATUS_LN0 0x3037 +#define DP_PCON_HDMI_ERROR_STATUS_LN1 0x3038 +#define DP_PCON_HDMI_ERROR_STATUS_LN2 0x3039 +#define DP_PCON_HDMI_ERROR_STATUS_LN3 0x303A +# define DP_PCON_HDMI_ERROR_COUNT_MASK (0x7 << 0) +# define DP_PCON_HDMI_ERROR_COUNT_THREE_PLUS (1 << 0) +# define DP_PCON_HDMI_ERROR_COUNT_TEN_PLUS (1 << 1) +# define DP_PCON_HDMI_ERROR_COUNT_HUNDRED_PLUS (1 << 2)
/* HDCP 1.3 and HDCP 2.2 */ #define DP_AUX_HDCP_BKSV 0x68000 #define DP_AUX_HDCP_RI_PRIME 0x68005 @@ -2047,5 +2062,7 @@ int drm_dp_pcon_frl_enable(struct drm_dp_aux *aux);
bool drm_dp_pcon_hdmi_link_active(struct drm_dp_aux *aux); int drm_dp_pcon_hdmi_link_mode(struct drm_dp_aux *aux, u8 *frl_trained_mask); +void drm_dp_pcon_hdmi_frl_link_error_count(struct drm_dp_aux *aux,
struct drm_connector *connector);
#endif /* _DRM_DP_HELPER_H_ */
2.17.1
This patch adds registers for getting DSC encoder capability for a HDMI2.1 PCon. It also addes helper functions to configure DSC between the PCON and HDMI2.1 sink.
v2: Corrected offset for DSC encoder bpc and minor changes. Also added helper functions for getting pcon dsc encoder capabilities as suggested by Uma Shankar.
Signed-off-by: Ankit Nautiyal ankit.k.nautiyal@intel.com --- drivers/gpu/drm/drm_dp_helper.c | 197 ++++++++++++++++++++++++++++++++ include/drm/drm_dp_helper.h | 114 ++++++++++++++++++ 2 files changed, 311 insertions(+)
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 05782091e7e1..8162ee856b5d 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -2932,3 +2932,200 @@ void drm_dp_pcon_hdmi_frl_link_error_count(struct drm_dp_aux *aux, } } EXPORT_SYMBOL(drm_dp_pcon_hdmi_frl_link_error_count); + +/* + * drm_dp_pcon_enc_is_dsc_1_2 - Does PCON Encoder supports DSC 1.2 + * @pcon_dsc_dpcd: DSC capabilities of the PCON DSC Encoder + * + * Returns true is PCON encoder is DSC 1.2 else returns false. + */ +bool drm_dp_pcon_enc_is_dsc_1_2(const u8 pcon_dsc_dpcd[DP_PCON_DSC_ENCODER_CAP_SIZE]) +{ + u8 buf; + u8 major_v, minor_v; + + buf = pcon_dsc_dpcd[DP_PCON_DSC_VERSION - DP_PCON_DSC_ENCODER]; + major_v = (buf & DP_PCON_DSC_MAJOR_MASK) >> DP_PCON_DSC_MAJOR_SHIFT; + minor_v = (buf & DP_PCON_DSC_MINOR_MASK) >> DP_PCON_DSC_MINOR_SHIFT; + + if (major_v == 1 && minor_v == 2) + return true; + + return false; +} +EXPORT_SYMBOL(drm_dp_pcon_enc_is_dsc_1_2); + +/* + * drm_dp_pcon_dsc_max_slices - Get max slices supported by PCON DSC Encoder + * @pcon_dsc_dpcd: DSC capabilities of the PCON DSC Encoder + * + * Returns maximum no. of slices supported by the PCON DSC Encoder. + */ +int drm_dp_pcon_dsc_max_slices(const u8 pcon_dsc_dpcd[DP_PCON_DSC_ENCODER_CAP_SIZE]) +{ + u8 slice_cap1, slice_cap2; + + slice_cap1 = pcon_dsc_dpcd[DP_PCON_DSC_SLICE_CAP_1 - DP_PCON_DSC_ENCODER]; + slice_cap2 = pcon_dsc_dpcd[DP_PCON_DSC_SLICE_CAP_2 - DP_PCON_DSC_ENCODER]; + + if (slice_cap2 & DP_PCON_DSC_24_PER_DSC_ENC) + return 24; + if (slice_cap2 & DP_PCON_DSC_20_PER_DSC_ENC) + return 20; + if (slice_cap2 & DP_PCON_DSC_16_PER_DSC_ENC) + return 16; + if (slice_cap1 & DP_PCON_DSC_12_PER_DSC_ENC) + return 12; + if (slice_cap1 & DP_PCON_DSC_10_PER_DSC_ENC) + return 10; + if (slice_cap1 & DP_PCON_DSC_8_PER_DSC_ENC) + return 8; + if (slice_cap1 & DP_PCON_DSC_6_PER_DSC_ENC) + return 6; + if (slice_cap1 & DP_PCON_DSC_4_PER_DSC_ENC) + return 4; + if (slice_cap1 & DP_PCON_DSC_2_PER_DSC_ENC) + return 2; + if (slice_cap1 & DP_PCON_DSC_1_PER_DSC_ENC) + return 1; + + return 0; +} +EXPORT_SYMBOL(drm_dp_pcon_dsc_max_slices); + +/* + * drm_dp_pcon_dsc_max_slice_width() - Get max slice width for Pcon DSC encoder + * @pcon_dsc_dpcd: DSC capabilities of the PCON DSC Encoder + * + * Returns maximum width of the slices in pixel width i.e. no. of pixels x 320. + */ +int drm_dp_pcon_dsc_max_slice_width(const u8 pcon_dsc_dpcd[DP_PCON_DSC_ENCODER_CAP_SIZE]) +{ + u8 buf; + + buf = pcon_dsc_dpcd[DP_PCON_DSC_MAX_SLICE_WIDTH - DP_PCON_DSC_ENCODER]; + + return buf * DP_DSC_SLICE_WIDTH_MULTIPLIER; +} +EXPORT_SYMBOL(drm_dp_pcon_dsc_max_slice_width); + +/* + * drm_dp_pcon_dsc_bpp_incr() - Get bits per pixel increment for PCON DSC encoder + * @pcon_dsc_dpcd: DSC capabilities of the PCON DSC Encoder + * + * Returns the bpp precision supported by the PCON encoder. + */ +int drm_dp_pcon_dsc_bpp_incr(const u8 pcon_dsc_dpcd[DP_PCON_DSC_ENCODER_CAP_SIZE]) +{ + u8 buf; + + buf = pcon_dsc_dpcd[DP_PCON_DSC_BPP_INCR - DP_PCON_DSC_ENCODER]; + + switch (buf & DP_PCON_DSC_BPP_INCR_MASK) { + case DP_PCON_DSC_ONE_16TH_BPP: + return 16; + case DP_PCON_DSC_ONE_8TH_BPP: + return 8; + case DP_PCON_DSC_ONE_4TH_BPP: + return 4; + case DP_PCON_DSC_ONE_HALF_BPP: + return 2; + case DP_PCON_DSC_ONE_BPP: + return 1; + } + + return 0; +} +EXPORT_SYMBOL(drm_dp_pcon_dsc_bpp_incr); + +static +int drm_dp_pcon_configure_dsc_enc(struct drm_dp_aux *aux, u8 pps_buf_config) +{ + u8 buf = DP_PCON_ENABLE_DSC_ENCODER; + int ret; + + if (pps_buf_config <= DP_PCON_ENC_PPS_OVERRIDE_EN_BUFFER) { + buf &= ~DP_PCON_ENCODER_PPS_OVERRIDE_MASK; + buf |= pps_buf_config << 2; + } + + ret = drm_dp_dpcd_writeb(aux, DP_PROTOCOL_CONVERTER_CONTROL_2, buf); + if (ret < 0) + return ret; + + return 0; +} + +/** + * drm_dp_pcon_pps_default() - Let PCON fill the default pps parameters + * for DSC1.2 between PCON & HDMI2.1 sink + * @aux: DisplayPort AUX channel + * + * Returns 0 on success, else returns negative error code. + * */ +int drm_dp_pcon_pps_default(struct drm_dp_aux *aux) +{ + int ret; + + ret = drm_dp_pcon_configure_dsc_enc(aux, DP_PCON_ENC_PPS_OVERRIDE_DISABLED); + if (ret < 0) + return ret; + + return 0; +} +EXPORT_SYMBOL(drm_dp_pcon_pps_default); + +/** + * drm_dp_pcon_pps_override_buf() - Configure PPS encoder override buffer for + * HDMI sink + * @aux: DisplayPort AUX channel + * @pps_buf: 128 bytes to be written into PPS buffer for HDMI sink by PCON. + * + * Returns 0 on success, else returns negative error code. + * */ +int drm_dp_pcon_pps_override_buf(struct drm_dp_aux *aux, u8 pps_buf[128]) +{ + int ret; + + ret = drm_dp_dpcd_write(aux, DP_PCON_HDMI_PPS_OVERRIDE_BASE, &pps_buf, 128); + if (ret < 0) + return ret; + + ret = drm_dp_pcon_configure_dsc_enc(aux, DP_PCON_ENC_PPS_OVERRIDE_EN_BUFFER); + if (ret < 0) + return ret; + + return 0; +} +EXPORT_SYMBOL(drm_dp_pcon_pps_override_buf); + +/* + * drm_dp_pcon_pps_override_param() - Write PPS parameters to DSC encoder + * override registers + * @aux: DisplayPort AUX channel + * @pps_param: 3 Parameters (2 Bytes each) : Slice Width, Slice Height, + * bits_per_pixel. + * + * Returns 0 on success, else returns negative error code. + * */ +int drm_dp_pcon_pps_override_param(struct drm_dp_aux *aux, u8 pps_param[6]) +{ + int ret; + + ret = drm_dp_dpcd_write(aux, DP_PCON_HDMI_PPS_OVRD_SLICE_HEIGHT, &pps_param[0], 2); + if (ret < 0) + return ret; + ret = drm_dp_dpcd_write(aux, DP_PCON_HDMI_PPS_OVRD_SLICE_WIDTH, &pps_param[2], 2); + if (ret < 0) + return ret; + ret = drm_dp_dpcd_write(aux, DP_PCON_HDMI_PPS_OVRD_BPP, &pps_param[4], 2); + if (ret < 0) + return ret; + + ret = drm_dp_pcon_configure_dsc_enc(aux, DP_PCON_ENC_PPS_OVERRIDE_EN_BUFFER); + if (ret < 0) + return ret; + + return 0; +} +EXPORT_SYMBOL(drm_dp_pcon_pps_override_param); diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index bdbe9bbdb244..a1565498a798 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -441,6 +441,84 @@ struct drm_device; # define DP_FEC_CORR_BLK_ERROR_COUNT_CAP (1 << 2) # define DP_FEC_BIT_ERROR_COUNT_CAP (1 << 3)
+/* DP-HDMI2.1 PCON DSC ENCODER SUPPORT */ +#define DP_PCON_DSC_ENCODER_CAP_SIZE 0xC /* 0x9E - 0x92 */ +#define DP_PCON_DSC_ENCODER 0x092 +# define DP_PCON_DSC_ENCODER_SUPPORTED (1 << 0) +# define DP_PCON_DSC_PPS_ENC_OVERRIDE (1 << 1) + +/* DP-HDMI2.1 PCON DSC Version */ +#define DP_PCON_DSC_VERSION 0x093 +# define DP_PCON_DSC_MAJOR_MASK (0xF << 0) +# define DP_PCON_DSC_MINOR_MASK (0xF << 4) +# define DP_PCON_DSC_MAJOR_SHIFT 0 +# define DP_PCON_DSC_MINOR_SHIFT 4 + +/* DP-HDMI2.1 PCON DSC RC Buffer block size */ +#define DP_PCON_DSC_RC_BUF_BLK_INFO 0x094 +# define DP_PCON_DSC_RC_BUF_BLK_SIZE (0x3 << 0) +# define DP_PCON_DSC_RC_BUF_BLK_1KB 0 +# define DP_PCON_DSC_RC_BUF_BLK_4KB 1 +# define DP_PCON_DSC_RC_BUF_BLK_16KB 2 +# define DP_PCON_DSC_RC_BUF_BLK_64KB 3 + +/* DP-HDMI2.1 PCON DSC RC Buffer size */ +#define DP_PCON_DSC_RC_BUF_SIZE 0x095 + +/* DP-HDMI2.1 PCON DSC Slice capabilities-1 */ +#define DP_PCON_DSC_SLICE_CAP_1 0x096 +# define DP_PCON_DSC_1_PER_DSC_ENC (0x1 << 0) +# define DP_PCON_DSC_2_PER_DSC_ENC (0x1 << 1) +# define DP_PCON_DSC_4_PER_DSC_ENC (0x1 << 3) +# define DP_PCON_DSC_6_PER_DSC_ENC (0x1 << 4) +# define DP_PCON_DSC_8_PER_DSC_ENC (0x1 << 5) +# define DP_PCON_DSC_10_PER_DSC_ENC (0x1 << 6) +# define DP_PCON_DSC_12_PER_DSC_ENC (0x1 << 7) + +#define DP_PCON_DSC_BUF_BIT_DEPTH 0x097 +# define DP_PCON_DSC_BIT_DEPTH_MASK (0xF << 0) +# define DP_PCON_DSC_DEPTH_9_BITS 0 +# define DP_PCON_DSC_DEPTH_10_BITS 1 +# define DP_PCON_DSC_DEPTH_11_BITS 2 +# define DP_PCON_DSC_DEPTH_12_BITS 3 +# define DP_PCON_DSC_DEPTH_13_BITS 4 +# define DP_PCON_DSC_DEPTH_14_BITS 5 +# define DP_PCON_DSC_DEPTH_15_BITS 6 +# define DP_PCON_DSC_DEPTH_16_BITS 7 +# define DP_PCON_DSC_DEPTH_8_BITS 8 + +#define DP_PCON_DSC_BLOCK_PREDICTION 0x098 +# define DP_PCON_DSC_BLOCK_PRED_SUPPORT (0x1 << 0) + +#define DP_PCON_DSC_ENC_COLOR_FMT_CAP 0x099 +# define DP_PCON_DSC_ENC_RGB (0x1 << 0) +# define DP_PCON_DSC_ENC_YUV444 (0x1 << 1) +# define DP_PCON_DSC_ENC_YUV422_S (0x1 << 2) +# define DP_PCON_DSC_ENC_YUV422_N (0x1 << 3) +# define DP_PCON_DSC_ENC_YUV420_N (0x1 << 4) + +#define DP_PCON_DSC_ENC_COLOR_DEPTH_CAP 0x09A +# define DP_PCON_DSC_ENC_8BPC (0x1 << 1) +# define DP_PCON_DSC_ENC_10BPC (0x1 << 2) +# define DP_PCON_DSC_ENC_12BPC (0x1 << 3) + +#define DP_PCON_DSC_MAX_SLICE_WIDTH 0x09B + +/* DP-HDMI2.1 PCON DSC Slice capabilities-2 */ +#define DP_PCON_DSC_SLICE_CAP_2 0x09C +# define DP_PCON_DSC_16_PER_DSC_ENC (0x1 << 0) +# define DP_PCON_DSC_20_PER_DSC_ENC (0x1 << 1) +# define DP_PCON_DSC_24_PER_DSC_ENC (0x1 << 2) + +/* DP-HDMI2.1 PCON HDMI TX Encoder Bits/pixel increment */ +#define DP_PCON_DSC_BPP_INCR 0x09E +# define DP_PCON_DSC_BPP_INCR_MASK (0x7 << 0) +# define DP_PCON_DSC_ONE_16TH_BPP 0 +# define DP_PCON_DSC_ONE_8TH_BPP 1 +# define DP_PCON_DSC_ONE_4TH_BPP 2 +# define DP_PCON_DSC_ONE_HALF_BPP 3 +# define DP_PCON_DSC_ONE_BPP 4 + /* DP Extended DSC Capabilities */ #define DP_DSC_BRANCH_OVERALL_THROUGHPUT_0 0x0a0 /* DP 1.4a SCR */ #define DP_DSC_BRANCH_OVERALL_THROUGHPUT_1 0x0a1 @@ -1134,6 +1212,12 @@ struct drm_device; # define DP_HDMI_FORCE_SCRAMBLING (1 << 3) /* DP 1.4 */ #define DP_PROTOCOL_CONVERTER_CONTROL_2 0x3052 /* DP 1.3 */ # define DP_CONVERSION_TO_YCBCR422_ENABLE (1 << 0) /* DP 1.3 */ +# define DP_PCON_ENABLE_DSC_ENCODER (1 << 1) +# define DP_PCON_ENCODER_PPS_OVERRIDE_MASK (0x3 << 2) +# define DP_PCON_ENC_PPS_OVERRIDE_DISABLED 0 +# define DP_PCON_ENC_PPS_OVERRIDE_EN_PARAMS 1 +# define DP_PCON_ENC_PPS_OVERRIDE_EN_BUFFER 2 +
/* PCON Downstream HDMI ERROR Status per Lane */ #define DP_PCON_HDMI_ERROR_STATUS_LN0 0x3037 @@ -1145,6 +1229,29 @@ struct drm_device; # define DP_PCON_HDMI_ERROR_COUNT_TEN_PLUS (1 << 1) # define DP_PCON_HDMI_ERROR_COUNT_HUNDRED_PLUS (1 << 2)
+/* PCON HDMI CONFIG PPS Override Buffer + * Valid Offsets to be added to Base : 0-127 + */ +#define DP_PCON_HDMI_PPS_OVERRIDE_BASE 0x3100 + +/* PCON HDMI CONFIG PPS Override Parameter: Slice height + * Offset-0 8LSBs of the Slice height. + * Offset-1 8MSBs of the Slice height. + */ +#define DP_PCON_HDMI_PPS_OVRD_SLICE_HEIGHT 0x3180 + +/* PCON HDMI CONFIG PPS Override Parameter: Slice width + * Offset-0 8LSBs of the Slice width. + * Offset-1 8MSBs of the Slice width. + */ +#define DP_PCON_HDMI_PPS_OVRD_SLICE_WIDTH 0x3182 + +/* PCON HDMI CONFIG PPS Override Parameter: bits_per_pixel + * Offset-0 8LSBs of the bits_per_pixel. + * Offset-1 2MSBs of the bits_per_pixel. + */ +#define DP_PCON_HDMI_PPS_OVRD_BPP 0x3184 + /* HDCP 1.3 and HDCP 2.2 */ #define DP_AUX_HDCP_BKSV 0x68000 #define DP_AUX_HDCP_RI_PRIME 0x68005 @@ -2064,5 +2171,12 @@ bool drm_dp_pcon_hdmi_link_active(struct drm_dp_aux *aux); int drm_dp_pcon_hdmi_link_mode(struct drm_dp_aux *aux, u8 *frl_trained_mask); void drm_dp_pcon_hdmi_frl_link_error_count(struct drm_dp_aux *aux, struct drm_connector *connector); +bool drm_dp_pcon_enc_is_dsc_1_2(const u8 pcon_dsc_dpcd[DP_PCON_DSC_ENCODER_CAP_SIZE]); +int drm_dp_pcon_dsc_max_slices(const u8 pcon_dsc_dpcd[DP_PCON_DSC_ENCODER_CAP_SIZE]); +int drm_dp_pcon_dsc_max_slice_width(const u8 pcon_dsc_dpcd[DP_PCON_DSC_ENCODER_CAP_SIZE]); +int drm_dp_pcon_dsc_bpp_incr(const u8 pcon_dsc_dpcd[DP_PCON_DSC_ENCODER_CAP_SIZE]); +int drm_dp_pcon_pps_default(struct drm_dp_aux *aux); +int drm_dp_pcon_pps_override_buf(struct drm_dp_aux *aux, u8 pps_buf[128]); +int drm_dp_pcon_pps_override_param(struct drm_dp_aux *aux, u8 pps_param[6]);
#endif /* _DRM_DP_HELPER_H_ */
-----Original Message----- From: Nautiyal, Ankit K ankit.k.nautiyal@intel.com Sent: Sunday, November 1, 2020 3:37 PM To: intel-gfx@lists.freedesktop.org Cc: dri-devel@lists.freedesktop.org; Shankar, Uma uma.shankar@intel.com; Kulkarni, Vandita vandita.kulkarni@intel.com; ville.syrjala@linux.intel.com; Sharma, Swati2 swati2.sharma@intel.com Subject: [PATCH v2 06/13] drm/dp_helper: Add support for Configuring DSC for HDMI2.1 Pcon
This patch adds registers for getting DSC encoder capability for a HDMI2.1 PCon. It also addes helper functions to configure DSC between the PCON and HDMI2.1 sink.
v2: Corrected offset for DSC encoder bpc and minor changes. Also added helper functions for getting pcon dsc encoder capabilities as suggested by Uma Shankar.
Signed-off-by: Ankit Nautiyal ankit.k.nautiyal@intel.com
drivers/gpu/drm/drm_dp_helper.c | 197 ++++++++++++++++++++++++++++++++ include/drm/drm_dp_helper.h | 114 ++++++++++++++++++ 2 files changed, 311 insertions(+)
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 05782091e7e1..8162ee856b5d 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -2932,3 +2932,200 @@ void drm_dp_pcon_hdmi_frl_link_error_count(struct drm_dp_aux *aux, } } EXPORT_SYMBOL(drm_dp_pcon_hdmi_frl_link_error_count);
+/*
- drm_dp_pcon_enc_is_dsc_1_2 - Does PCON Encoder supports DSC 1.2
- @pcon_dsc_dpcd: DSC capabilities of the PCON DSC Encoder
- Returns true is PCON encoder is DSC 1.2 else returns false.
- */
+bool drm_dp_pcon_enc_is_dsc_1_2(const u8 +pcon_dsc_dpcd[DP_PCON_DSC_ENCODER_CAP_SIZE]) +{
- u8 buf;
- u8 major_v, minor_v;
- buf = pcon_dsc_dpcd[DP_PCON_DSC_VERSION -
DP_PCON_DSC_ENCODER];
- major_v = (buf & DP_PCON_DSC_MAJOR_MASK) >>
DP_PCON_DSC_MAJOR_SHIFT;
- minor_v = (buf & DP_PCON_DSC_MINOR_MASK) >>
DP_PCON_DSC_MINOR_SHIFT;
- if (major_v == 1 && minor_v == 2)
return true;
- return false;
+} +EXPORT_SYMBOL(drm_dp_pcon_enc_is_dsc_1_2);
+/*
- drm_dp_pcon_dsc_max_slices - Get max slices supported by PCON DSC
+Encoder
- @pcon_dsc_dpcd: DSC capabilities of the PCON DSC Encoder
- Returns maximum no. of slices supported by the PCON DSC Encoder.
- */
+int drm_dp_pcon_dsc_max_slices(const u8 +pcon_dsc_dpcd[DP_PCON_DSC_ENCODER_CAP_SIZE]) +{
- u8 slice_cap1, slice_cap2;
- slice_cap1 = pcon_dsc_dpcd[DP_PCON_DSC_SLICE_CAP_1 -
DP_PCON_DSC_ENCODER];
- slice_cap2 = pcon_dsc_dpcd[DP_PCON_DSC_SLICE_CAP_2 -
+DP_PCON_DSC_ENCODER];
- if (slice_cap2 & DP_PCON_DSC_24_PER_DSC_ENC)
return 24;
You can use else if to optimize this up.
- if (slice_cap2 & DP_PCON_DSC_20_PER_DSC_ENC)
return 20;
- if (slice_cap2 & DP_PCON_DSC_16_PER_DSC_ENC)
return 16;
- if (slice_cap1 & DP_PCON_DSC_12_PER_DSC_ENC)
return 12;
- if (slice_cap1 & DP_PCON_DSC_10_PER_DSC_ENC)
return 10;
- if (slice_cap1 & DP_PCON_DSC_8_PER_DSC_ENC)
return 8;
- if (slice_cap1 & DP_PCON_DSC_6_PER_DSC_ENC)
return 6;
- if (slice_cap1 & DP_PCON_DSC_4_PER_DSC_ENC)
return 4;
- if (slice_cap1 & DP_PCON_DSC_2_PER_DSC_ENC)
return 2;
- if (slice_cap1 & DP_PCON_DSC_1_PER_DSC_ENC)
return 1;
Add else return 0.
With this fixed: Reviewed-by: Uma Shankar uma.shankar@intel.com
- return 0;
+} +EXPORT_SYMBOL(drm_dp_pcon_dsc_max_slices);
+/*
- drm_dp_pcon_dsc_max_slice_width() - Get max slice width for Pcon DSC
+encoder
- @pcon_dsc_dpcd: DSC capabilities of the PCON DSC Encoder
- Returns maximum width of the slices in pixel width i.e. no. of pixels x 320.
- */
+int drm_dp_pcon_dsc_max_slice_width(const u8 +pcon_dsc_dpcd[DP_PCON_DSC_ENCODER_CAP_SIZE]) +{
- u8 buf;
- buf = pcon_dsc_dpcd[DP_PCON_DSC_MAX_SLICE_WIDTH -
+DP_PCON_DSC_ENCODER];
- return buf * DP_DSC_SLICE_WIDTH_MULTIPLIER; }
+EXPORT_SYMBOL(drm_dp_pcon_dsc_max_slice_width);
+/*
- drm_dp_pcon_dsc_bpp_incr() - Get bits per pixel increment for PCON
+DSC encoder
- @pcon_dsc_dpcd: DSC capabilities of the PCON DSC Encoder
- Returns the bpp precision supported by the PCON encoder.
- */
+int drm_dp_pcon_dsc_bpp_incr(const u8 +pcon_dsc_dpcd[DP_PCON_DSC_ENCODER_CAP_SIZE]) +{
- u8 buf;
- buf = pcon_dsc_dpcd[DP_PCON_DSC_BPP_INCR -
DP_PCON_DSC_ENCODER];
- switch (buf & DP_PCON_DSC_BPP_INCR_MASK) {
- case DP_PCON_DSC_ONE_16TH_BPP:
return 16;
- case DP_PCON_DSC_ONE_8TH_BPP:
return 8;
- case DP_PCON_DSC_ONE_4TH_BPP:
return 4;
- case DP_PCON_DSC_ONE_HALF_BPP:
return 2;
- case DP_PCON_DSC_ONE_BPP:
return 1;
- }
- return 0;
+} +EXPORT_SYMBOL(drm_dp_pcon_dsc_bpp_incr);
+static +int drm_dp_pcon_configure_dsc_enc(struct drm_dp_aux *aux, u8 +pps_buf_config) {
- u8 buf = DP_PCON_ENABLE_DSC_ENCODER;
- int ret;
- if (pps_buf_config <= DP_PCON_ENC_PPS_OVERRIDE_EN_BUFFER) {
buf &= ~DP_PCON_ENCODER_PPS_OVERRIDE_MASK;
buf |= pps_buf_config << 2;
- }
- ret = drm_dp_dpcd_writeb(aux,
DP_PROTOCOL_CONVERTER_CONTROL_2, buf);
- if (ret < 0)
return ret;
- return 0;
+}
+/**
- drm_dp_pcon_pps_default() - Let PCON fill the default pps parameters
- for DSC1.2 between PCON & HDMI2.1 sink
- @aux: DisplayPort AUX channel
- Returns 0 on success, else returns negative error code.
- */
+int drm_dp_pcon_pps_default(struct drm_dp_aux *aux) {
- int ret;
- ret = drm_dp_pcon_configure_dsc_enc(aux,
DP_PCON_ENC_PPS_OVERRIDE_DISABLED);
- if (ret < 0)
return ret;
- return 0;
+} +EXPORT_SYMBOL(drm_dp_pcon_pps_default);
+/**
- drm_dp_pcon_pps_override_buf() - Configure PPS encoder override
+buffer for
- HDMI sink
- @aux: DisplayPort AUX channel
- @pps_buf: 128 bytes to be written into PPS buffer for HDMI sink by PCON.
- Returns 0 on success, else returns negative error code.
- */
+int drm_dp_pcon_pps_override_buf(struct drm_dp_aux *aux, u8 +pps_buf[128]) {
- int ret;
- ret = drm_dp_dpcd_write(aux, DP_PCON_HDMI_PPS_OVERRIDE_BASE,
&pps_buf, 128);
- if (ret < 0)
return ret;
- ret = drm_dp_pcon_configure_dsc_enc(aux,
DP_PCON_ENC_PPS_OVERRIDE_EN_BUFFER);
- if (ret < 0)
return ret;
- return 0;
+} +EXPORT_SYMBOL(drm_dp_pcon_pps_override_buf);
+/*
- drm_dp_pcon_pps_override_param() - Write PPS parameters to DSC
+encoder
- override registers
- @aux: DisplayPort AUX channel
- @pps_param: 3 Parameters (2 Bytes each) : Slice Width, Slice Height,
- bits_per_pixel.
- Returns 0 on success, else returns negative error code.
- */
+int drm_dp_pcon_pps_override_param(struct drm_dp_aux *aux, u8 +pps_param[6]) {
- int ret;
- ret = drm_dp_dpcd_write(aux,
DP_PCON_HDMI_PPS_OVRD_SLICE_HEIGHT, &pps_param[0], 2);
- if (ret < 0)
return ret;
- ret = drm_dp_dpcd_write(aux,
DP_PCON_HDMI_PPS_OVRD_SLICE_WIDTH, &pps_param[2], 2);
- if (ret < 0)
return ret;
- ret = drm_dp_dpcd_write(aux, DP_PCON_HDMI_PPS_OVRD_BPP,
&pps_param[4], 2);
- if (ret < 0)
return ret;
- ret = drm_dp_pcon_configure_dsc_enc(aux,
DP_PCON_ENC_PPS_OVERRIDE_EN_BUFFER);
- if (ret < 0)
return ret;
- return 0;
+} +EXPORT_SYMBOL(drm_dp_pcon_pps_override_param); diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index bdbe9bbdb244..a1565498a798 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -441,6 +441,84 @@ struct drm_device; # define DP_FEC_CORR_BLK_ERROR_COUNT_CAP (1 << 2) # define DP_FEC_BIT_ERROR_COUNT_CAP (1 << 3)
+/* DP-HDMI2.1 PCON DSC ENCODER SUPPORT */ +#define DP_PCON_DSC_ENCODER_CAP_SIZE 0xC /* 0x9E - 0x92 */ +#define DP_PCON_DSC_ENCODER 0x092 +# define DP_PCON_DSC_ENCODER_SUPPORTED (1 << 0) +# define DP_PCON_DSC_PPS_ENC_OVERRIDE (1 << 1)
+/* DP-HDMI2.1 PCON DSC Version */ +#define DP_PCON_DSC_VERSION 0x093 +# define DP_PCON_DSC_MAJOR_MASK (0xF << 0) +# define DP_PCON_DSC_MINOR_MASK (0xF << 4) +# define DP_PCON_DSC_MAJOR_SHIFT 0 +# define DP_PCON_DSC_MINOR_SHIFT 4
+/* DP-HDMI2.1 PCON DSC RC Buffer block size */ +#define DP_PCON_DSC_RC_BUF_BLK_INFO 0x094 +# define DP_PCON_DSC_RC_BUF_BLK_SIZE (0x3 << 0) +# define DP_PCON_DSC_RC_BUF_BLK_1KB 0 +# define DP_PCON_DSC_RC_BUF_BLK_4KB 1 +# define DP_PCON_DSC_RC_BUF_BLK_16KB 2 +# define DP_PCON_DSC_RC_BUF_BLK_64KB 3
+/* DP-HDMI2.1 PCON DSC RC Buffer size */ +#define DP_PCON_DSC_RC_BUF_SIZE 0x095
+/* DP-HDMI2.1 PCON DSC Slice capabilities-1 */ +#define DP_PCON_DSC_SLICE_CAP_1 0x096 +# define DP_PCON_DSC_1_PER_DSC_ENC (0x1 << 0) +# define DP_PCON_DSC_2_PER_DSC_ENC (0x1 << 1) +# define DP_PCON_DSC_4_PER_DSC_ENC (0x1 << 3) +# define DP_PCON_DSC_6_PER_DSC_ENC (0x1 << 4) +# define DP_PCON_DSC_8_PER_DSC_ENC (0x1 << 5) +# define DP_PCON_DSC_10_PER_DSC_ENC (0x1 << 6) +# define DP_PCON_DSC_12_PER_DSC_ENC (0x1 << 7)
+#define DP_PCON_DSC_BUF_BIT_DEPTH 0x097 +# define DP_PCON_DSC_BIT_DEPTH_MASK (0xF << 0) +# define DP_PCON_DSC_DEPTH_9_BITS 0 +# define DP_PCON_DSC_DEPTH_10_BITS 1 +# define DP_PCON_DSC_DEPTH_11_BITS 2 +# define DP_PCON_DSC_DEPTH_12_BITS 3 +# define DP_PCON_DSC_DEPTH_13_BITS 4 +# define DP_PCON_DSC_DEPTH_14_BITS 5 +# define DP_PCON_DSC_DEPTH_15_BITS 6 +# define DP_PCON_DSC_DEPTH_16_BITS 7 +# define DP_PCON_DSC_DEPTH_8_BITS 8
+#define DP_PCON_DSC_BLOCK_PREDICTION 0x098 +# define DP_PCON_DSC_BLOCK_PRED_SUPPORT (0x1 << 0)
+#define DP_PCON_DSC_ENC_COLOR_FMT_CAP 0x099 +# define DP_PCON_DSC_ENC_RGB (0x1 << 0) +# define DP_PCON_DSC_ENC_YUV444 (0x1 << 1) +# define DP_PCON_DSC_ENC_YUV422_S (0x1 << 2) +# define DP_PCON_DSC_ENC_YUV422_N (0x1 << 3) +# define DP_PCON_DSC_ENC_YUV420_N (0x1 << 4)
+#define DP_PCON_DSC_ENC_COLOR_DEPTH_CAP 0x09A +# define DP_PCON_DSC_ENC_8BPC (0x1 << 1) +# define DP_PCON_DSC_ENC_10BPC (0x1 << 2) +# define DP_PCON_DSC_ENC_12BPC (0x1 << 3)
+#define DP_PCON_DSC_MAX_SLICE_WIDTH 0x09B
+/* DP-HDMI2.1 PCON DSC Slice capabilities-2 */ +#define DP_PCON_DSC_SLICE_CAP_2 0x09C +# define DP_PCON_DSC_16_PER_DSC_ENC (0x1 << 0) +# define DP_PCON_DSC_20_PER_DSC_ENC (0x1 << 1) +# define DP_PCON_DSC_24_PER_DSC_ENC (0x1 << 2)
+/* DP-HDMI2.1 PCON HDMI TX Encoder Bits/pixel increment */ +#define DP_PCON_DSC_BPP_INCR 0x09E +# define DP_PCON_DSC_BPP_INCR_MASK (0x7 << 0) +# define DP_PCON_DSC_ONE_16TH_BPP 0 +# define DP_PCON_DSC_ONE_8TH_BPP 1 +# define DP_PCON_DSC_ONE_4TH_BPP 2 +# define DP_PCON_DSC_ONE_HALF_BPP 3 +# define DP_PCON_DSC_ONE_BPP 4
/* DP Extended DSC Capabilities */ #define DP_DSC_BRANCH_OVERALL_THROUGHPUT_0 0x0a0 /* DP 1.4a SCR */ #define DP_DSC_BRANCH_OVERALL_THROUGHPUT_1 0x0a1 @@ -1134,6 +1212,12 @@ struct drm_device; # define DP_HDMI_FORCE_SCRAMBLING (1 << 3) /* DP 1.4 */ #define DP_PROTOCOL_CONVERTER_CONTROL_2 0x3052 /* DP 1.3 */ # define DP_CONVERSION_TO_YCBCR422_ENABLE (1 << 0) /* DP 1.3 */ +# define DP_PCON_ENABLE_DSC_ENCODER (1 << 1) +# define DP_PCON_ENCODER_PPS_OVERRIDE_MASK (0x3 << 2) +# define DP_PCON_ENC_PPS_OVERRIDE_DISABLED 0 +# define DP_PCON_ENC_PPS_OVERRIDE_EN_PARAMS 1 +# define DP_PCON_ENC_PPS_OVERRIDE_EN_BUFFER 2
/* PCON Downstream HDMI ERROR Status per Lane */ #define DP_PCON_HDMI_ERROR_STATUS_LN0 0x3037 @@ -1145,6 +1229,29 @@ struct drm_device; # define DP_PCON_HDMI_ERROR_COUNT_TEN_PLUS (1 << 1) # define DP_PCON_HDMI_ERROR_COUNT_HUNDRED_PLUS (1 << 2)
+/* PCON HDMI CONFIG PPS Override Buffer
- Valid Offsets to be added to Base : 0-127 */
+#define DP_PCON_HDMI_PPS_OVERRIDE_BASE 0x3100
+/* PCON HDMI CONFIG PPS Override Parameter: Slice height
- Offset-0 8LSBs of the Slice height.
- Offset-1 8MSBs of the Slice height.
- */
+#define DP_PCON_HDMI_PPS_OVRD_SLICE_HEIGHT 0x3180
+/* PCON HDMI CONFIG PPS Override Parameter: Slice width
- Offset-0 8LSBs of the Slice width.
- Offset-1 8MSBs of the Slice width.
- */
+#define DP_PCON_HDMI_PPS_OVRD_SLICE_WIDTH 0x3182
+/* PCON HDMI CONFIG PPS Override Parameter: bits_per_pixel
- Offset-0 8LSBs of the bits_per_pixel.
- Offset-1 2MSBs of the bits_per_pixel.
- */
+#define DP_PCON_HDMI_PPS_OVRD_BPP 0x3184
/* HDCP 1.3 and HDCP 2.2 */ #define DP_AUX_HDCP_BKSV 0x68000 #define DP_AUX_HDCP_RI_PRIME 0x68005 @@ -2064,5 +2171,12 @@ bool drm_dp_pcon_hdmi_link_active(struct drm_dp_aux *aux); int drm_dp_pcon_hdmi_link_mode(struct drm_dp_aux *aux, u8 *frl_trained_mask); void drm_dp_pcon_hdmi_frl_link_error_count(struct drm_dp_aux *aux, struct drm_connector *connector); +bool drm_dp_pcon_enc_is_dsc_1_2(const u8 +pcon_dsc_dpcd[DP_PCON_DSC_ENCODER_CAP_SIZE]); +int drm_dp_pcon_dsc_max_slices(const u8 +pcon_dsc_dpcd[DP_PCON_DSC_ENCODER_CAP_SIZE]); +int drm_dp_pcon_dsc_max_slice_width(const u8 +pcon_dsc_dpcd[DP_PCON_DSC_ENCODER_CAP_SIZE]); +int drm_dp_pcon_dsc_bpp_incr(const u8 +pcon_dsc_dpcd[DP_PCON_DSC_ENCODER_CAP_SIZE]); +int drm_dp_pcon_pps_default(struct drm_dp_aux *aux); int +drm_dp_pcon_pps_override_buf(struct drm_dp_aux *aux, u8 pps_buf[128]); +int drm_dp_pcon_pps_override_param(struct drm_dp_aux *aux, u8 +pps_param[6]);
#endif /* _DRM_DP_HELPER_H_ */
2.17.1
HDMI2.1 PCON advertises Max FRL bandwidth supported by the PCON and by the sink.
This patch captures these in dfp cap structure in intel_dp and uses these to prune connector modes that cannot be supported by the PCON and sink FRL bandwidth.
v2: Addressed review comments from Uma Shankar: -tweaked the comparison of target bw and pcon frl bw to avoid roundup errors. -minor modification of field names and comments.
Signed-off-by: Ankit Nautiyal ankit.k.nautiyal@intel.com --- .../drm/i915/display/intel_display_types.h | 1 + drivers/gpu/drm/i915/display/intel_dp.c | 38 ++++++++++++++++++- 2 files changed, 37 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index f6f0626649e0..282c6ee76384 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1397,6 +1397,7 @@ struct intel_dp { struct { int min_tmds_clock, max_tmds_clock; int max_dotclock; + int pcon_max_frl_bw, sink_max_frl_bw; u8 max_bpc; bool ycbcr_444_to_420; } dfp; diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 818daab252f3..caf7666f1892 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -684,6 +684,29 @@ intel_dp_mode_valid_downstream(struct intel_connector *connector, const struct drm_display_info *info = &connector->base.display_info; int tmds_clock;
+ /* + * If PCON and HDMI2.1 sink both support FRL MODE, check FRL + * bandwidth constraints. + */ + if (intel_dp->dfp.pcon_max_frl_bw) { + int target_bw; + int max_frl_bw; + int bpp = intel_dp_mode_min_output_bpp(&connector->base, mode); + + target_bw = bpp * target_clock; + + max_frl_bw = min(intel_dp->dfp.pcon_max_frl_bw, + intel_dp->dfp.sink_max_frl_bw); + + /* converting bw from Gbps to Kbps*/ + max_frl_bw = max_frl_bw * 1000000; + + if (target_bw > max_frl_bw) + return MODE_CLOCK_HIGH; + + return MODE_OK; + } + if (intel_dp->dfp.max_dotclock && target_clock > intel_dp->dfp.max_dotclock) return MODE_CLOCK_HIGH; @@ -6366,13 +6389,21 @@ intel_dp_update_dfp(struct intel_dp *intel_dp, intel_dp->downstream_ports, edid);
+ intel_dp->dfp.pcon_max_frl_bw = + drm_dp_get_pcon_max_frl_bw(intel_dp->dpcd, + intel_dp->downstream_ports); + + intel_dp->dfp.sink_max_frl_bw = drm_dp_get_hdmi_sink_max_frl_bw(&intel_dp->aux); + drm_dbg_kms(&i915->drm, - "[CONNECTOR:%d:%s] DFP max bpc %d, max dotclock %d, TMDS clock %d-%d\n", + "[CONNECTOR:%d:%s] DFP max bpc %d, max dotclock %d, TMDS clock %d-%d, PCON Max FRL BW %dGbps, Sink Max FRL BW %dGbps\n", connector->base.base.id, connector->base.name, intel_dp->dfp.max_bpc, intel_dp->dfp.max_dotclock, intel_dp->dfp.min_tmds_clock, - intel_dp->dfp.max_tmds_clock); + intel_dp->dfp.max_tmds_clock, + intel_dp->dfp.pcon_max_frl_bw, + intel_dp->dfp.sink_max_frl_bw); }
static void @@ -6464,6 +6495,9 @@ intel_dp_unset_edid(struct intel_dp *intel_dp) intel_dp->dfp.min_tmds_clock = 0; intel_dp->dfp.max_tmds_clock = 0;
+ intel_dp->dfp.pcon_max_frl_bw = 0; + intel_dp->dfp.sink_max_frl_bw = 0; + intel_dp->dfp.ycbcr_444_to_420 = false; connector->base.ycbcr_420_allowed = false; }
-----Original Message----- From: Nautiyal, Ankit K ankit.k.nautiyal@intel.com Sent: Sunday, November 1, 2020 3:37 PM To: intel-gfx@lists.freedesktop.org Cc: dri-devel@lists.freedesktop.org; Shankar, Uma uma.shankar@intel.com; Kulkarni, Vandita vandita.kulkarni@intel.com; ville.syrjala@linux.intel.com; Sharma, Swati2 swati2.sharma@intel.com Subject: [PATCH v2 07/13] drm/i915: Capture max frl rate for PCON in dfp cap structure
HDMI2.1 PCON advertises Max FRL bandwidth supported by the PCON and by the sink.
This patch captures these in dfp cap structure in intel_dp and uses these to prune connector modes that cannot be supported by the PCON and sink FRL bandwidth.
v2: Addressed review comments from Uma Shankar: -tweaked the comparison of target bw and pcon frl bw to avoid roundup errors. -minor modification of field names and comments.
Reviewed-by: Uma Shankar uma.shankar@intel.com
Signed-off-by: Ankit Nautiyal ankit.k.nautiyal@intel.com
.../drm/i915/display/intel_display_types.h | 1 + drivers/gpu/drm/i915/display/intel_dp.c | 38 ++++++++++++++++++- 2 files changed, 37 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index f6f0626649e0..282c6ee76384 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1397,6 +1397,7 @@ struct intel_dp { struct { int min_tmds_clock, max_tmds_clock; int max_dotclock;
u8 max_bpc; bool ycbcr_444_to_420; } dfp;int pcon_max_frl_bw, sink_max_frl_bw;
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 818daab252f3..caf7666f1892 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -684,6 +684,29 @@ intel_dp_mode_valid_downstream(struct intel_connector *connector, const struct drm_display_info *info = &connector->base.display_info; int tmds_clock;
- /*
* If PCON and HDMI2.1 sink both support FRL MODE, check FRL
* bandwidth constraints.
*/
- if (intel_dp->dfp.pcon_max_frl_bw) {
int target_bw;
int max_frl_bw;
int bpp = intel_dp_mode_min_output_bpp(&connector->base,
mode);
target_bw = bpp * target_clock;
max_frl_bw = min(intel_dp->dfp.pcon_max_frl_bw,
intel_dp->dfp.sink_max_frl_bw);
/* converting bw from Gbps to Kbps*/
max_frl_bw = max_frl_bw * 1000000;
if (target_bw > max_frl_bw)
return MODE_CLOCK_HIGH;
return MODE_OK;
- }
- if (intel_dp->dfp.max_dotclock && target_clock > intel_dp->dfp.max_dotclock) return MODE_CLOCK_HIGH;
@@ -6366,13 +6389,21 @@ intel_dp_update_dfp(struct intel_dp *intel_dp, intel_dp->downstream_ports, edid);
- intel_dp->dfp.pcon_max_frl_bw =
drm_dp_get_pcon_max_frl_bw(intel_dp->dpcd,
intel_dp->downstream_ports);
- intel_dp->dfp.sink_max_frl_bw =
+drm_dp_get_hdmi_sink_max_frl_bw(&intel_dp->aux);
- drm_dbg_kms(&i915->drm,
"[CONNECTOR:%d:%s] DFP max bpc %d, max dotclock %d,
TMDS clock %d-%d\n",
"[CONNECTOR:%d:%s] DFP max bpc %d, max dotclock %d,
TMDS clock +%d-%d, PCON Max FRL BW %dGbps, Sink Max FRL BW %dGbps\n", connector->base.base.id, connector->base.name, intel_dp->dfp.max_bpc, intel_dp->dfp.max_dotclock, intel_dp->dfp.min_tmds_clock,
intel_dp->dfp.max_tmds_clock);
intel_dp->dfp.max_tmds_clock,
intel_dp->dfp.pcon_max_frl_bw,
intel_dp->dfp.sink_max_frl_bw);
}
static void @@ -6464,6 +6495,9 @@ intel_dp_unset_edid(struct intel_dp *intel_dp) intel_dp->dfp.min_tmds_clock = 0; intel_dp->dfp.max_tmds_clock = 0;
- intel_dp->dfp.pcon_max_frl_bw = 0;
- intel_dp->dfp.sink_max_frl_bw = 0;
- intel_dp->dfp.ycbcr_444_to_420 = false; connector->base.ycbcr_420_allowed = false; }
-- 2.17.1
This patch adds functions to start FRL training for an HDMI2.1 sink, connected via a PCON as a DP branch device. This patch also adds a new structure for storing frl training related data, when FRL training is completed.
v2: As suggested by Uma Shankar: -renamed couple of variables for better clarity -tweaked the macros used for correct semantics for true/false -fixed other styling issues.
Signed-off-by: Ankit Nautiyal ankit.k.nautiyal@intel.com --- .../drm/i915/display/intel_display_types.h | 7 + drivers/gpu/drm/i915/display/intel_dp.c | 189 ++++++++++++++++++ drivers/gpu/drm/i915/display/intel_dp.h | 2 + 3 files changed, 198 insertions(+)
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 282c6ee76384..2c58d63928b8 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1286,6 +1286,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; @@ -1407,6 +1412,8 @@ struct intel_dp {
bool hobl_failed; bool hobl_active; + + struct intel_dp_pcon_frl frl; };
enum lspcon_vendor { diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index caf7666f1892..7feee2adf9b2 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -2871,6 +2871,9 @@ static void intel_dp_prepare(struct intel_encoder *encoder, intel_dp->DP |= DP_PIPE_SEL_CHV(crtc->pipe); else intel_dp->DP |= DP_PIPE_SEL(crtc->pipe); + + intel_dp->frl.is_trained = false; + intel_dp->frl.trained_rate_gbps = 0; } }
@@ -3769,6 +3772,8 @@ static void intel_disable_dp(struct intel_atomic_state *state, intel_edp_backlight_off(old_conn_state); intel_dp_set_power(intel_dp, DP_SET_POWER_D3); intel_edp_panel_off(intel_dp); + intel_dp->frl.is_trained = false; + intel_dp->frl.trained_rate_gbps = 0; }
static void g4x_disable_dp(struct intel_atomic_state *state, @@ -3864,6 +3869,190 @@ cpt_set_link_train(struct intel_dp *intel_dp, intel_de_posting_read(dev_priv, intel_dp->output_reg); }
+static int intel_dp_get_max_rate_gbps(struct intel_dp *intel_dp) +{ + int max_link_clock, max_lanes, max_rate_khz, max_rate_gbps; + + max_link_clock = intel_dp_max_link_rate(intel_dp); + max_lanes = intel_dp_max_lane_count(intel_dp); + max_rate_khz = intel_dp_max_data_rate(max_link_clock, max_lanes); + max_rate_gbps = 8 * DIV_ROUND_UP(max_rate_khz, 1000000); + + return max_rate_gbps; +} + +static int intel_dp_pcon_get_frl_mask(u8 frl_bw_mask) +{ + int bw_gbps[] = {9, 18, 24, 32, 40, 48}; + int i; + + for (i = ARRAY_SIZE(bw_gbps) - 1; i >= 0; i--) { + if (frl_bw_mask & (1 << i)) + return bw_gbps[i]; + } + return 0; +} + +static int intel_dp_pcon_set_frl_mask(int max_frl) +{ + + switch (max_frl) { + case 48: + return DP_PCON_FRL_BW_MASK_48GBPS; + case 40: + return DP_PCON_FRL_BW_MASK_40GBPS; + case 32: + return DP_PCON_FRL_BW_MASK_32GBPS; + case 24: + return DP_PCON_FRL_BW_MASK_24GBPS; + case 18: + return DP_PCON_FRL_BW_MASK_18GBPS; + case 9: + return DP_PCON_FRL_BW_MASK_9GBPS; + } + + return 0; +} + +static int intel_dp_hdmi_sink_max_frl(struct intel_dp *intel_dp) +{ + struct intel_connector *intel_connector = intel_dp->attached_connector; + struct drm_connector *connector = &intel_connector->base; + + return (connector->display_info.hdmi.max_frl_rate_per_lane * + connector->display_info.hdmi.max_lanes); +} + +static int intel_dp_pcon_start_frl_training(struct intel_dp *intel_dp) +{ +#define PCON_EXTENDED_TRAIN_MODE (1 > 0) +#define PCON_CONCURRENT_MODE (1 > 0) +#define PCON_SEQUENTIAL_MODE !PCON_CONCURRENT_MODE +#define PCON_NORMAL_TRAIN_MODE !PCON_EXTENDED_TRAIN_MODE +#define TIMEOUT_FRL_READY_MS 500 +#define TIMEOUT_HDMI_LINK_ACTIVE_MS 1000 + + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + int max_frl_bw, max_pcon_frl_bw, max_sink_frl_bw, max_rate_gbps, max_edid_frl_bw, ret; + u8 max_frl_bw_mask = 0, frl_trained_mask; + bool is_active; + + ret = drm_dp_pcon_reset_frl_config(&intel_dp->aux); + if (ret < 0) + return ret; + + max_rate_gbps = intel_dp_get_max_rate_gbps(intel_dp); + drm_dbg(&i915->drm, "Source max rate = %d Gbps\n", max_rate_gbps); + + max_pcon_frl_bw = intel_dp->dfp.pcon_max_frl_bw; + drm_dbg(&i915->drm, "PCON max rate = %d Gbps\n", max_pcon_frl_bw); + + /* Double Check from HDMI SINK EDID */ + max_edid_frl_bw = intel_dp_hdmi_sink_max_frl(intel_dp); + drm_dbg(&i915->drm, "Sink max rate from EDID = %d Gbps\n", max_edid_frl_bw); + + max_sink_frl_bw = intel_dp->dfp.sink_max_frl_bw; + drm_dbg(&i915->drm, "Sink max rate from PCON = %d Gbps\n", max_sink_frl_bw); + + /* + * TODO MAX SINK FRL from PCON is not enumerated. Using MAX FRL value + * directly from EDID. Need to confirm from Spec. + */ + max_frl_bw = min(max_rate_gbps, min(max_edid_frl_bw, max_pcon_frl_bw)); + + if (max_frl_bw <= 0) + return -EINVAL; + + ret = drm_dp_pcon_frl_prepare(&intel_dp->aux, false); + if (ret < 0) + return ret; + /* Wait for PCON to be FRL Ready */ + wait_for(is_active = drm_dp_pcon_is_frl_ready(&intel_dp->aux) == true, TIMEOUT_FRL_READY_MS); + + if (!is_active) + return -ETIMEDOUT; + + max_frl_bw_mask = intel_dp_pcon_set_frl_mask(max_frl_bw); + ret = drm_dp_pcon_frl_configure_1(&intel_dp->aux, max_frl_bw, PCON_SEQUENTIAL_MODE); + if (ret < 0) + return ret; + ret = drm_dp_pcon_frl_configure_2(&intel_dp->aux, max_frl_bw_mask, PCON_NORMAL_TRAIN_MODE); + if (ret < 0) + return ret; + ret = drm_dp_pcon_frl_enable(&intel_dp->aux); + if (ret < 0) + return ret; + /* + * Wait for FRL to be completed + * Check if the HDMI Link is up and active. + */ + wait_for(is_active = drm_dp_pcon_hdmi_link_active(&intel_dp->aux) == true, TIMEOUT_HDMI_LINK_ACTIVE_MS); + + if (!is_active) + return -ETIMEDOUT; + + /* Verify HDMI Link configuration shows FRL Mode */ + if (DP_PCON_HDMI_MODE_FRL != drm_dp_pcon_hdmi_link_mode(&intel_dp->aux, &frl_trained_mask)) { + drm_dbg(&i915->drm, "HDMI couldn't be trained in FRL Mode\n"); + return -EINVAL; + } + drm_dbg(&i915->drm, "MAX_FRL_MASK = %u, FRL_TRAINED_MASK = %u\n", max_frl_bw_mask, frl_trained_mask); + + /* + * Read HDMI_LINK_STATUS_TRAINED 0x2005 bit 5 + * TODO: Details not mentioned in spec. Need to check. + */ + + intel_dp->frl.trained_rate_gbps = intel_dp_pcon_get_frl_mask(frl_trained_mask); + intel_dp->frl.is_trained = true; + drm_dbg(&i915->drm, "FRL trained with : %d Gbps\n", intel_dp->frl.trained_rate_gbps); + + return 0; +} + +static bool intel_dp_is_frl_required(struct intel_dp *intel_dp) +{ + if (!intel_dp->frl.is_trained) + return true; + /* + * #TODO check if the mode really required FRL or can work + * with TMDS mode. + */ + + return false; +} + +static bool intel_dp_is_hdmi_2_1_sink(struct intel_dp *intel_dp) +{ + if (drm_dp_is_branch(intel_dp->dpcd) && + intel_dp_hdmi_sink_max_frl(intel_dp) > 0) + return true; + + return false; +} + +void intel_dp_check_frl_training(struct intel_dp *intel_dp) +{ + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + + if (!intel_dp_is_hdmi_2_1_sink(intel_dp) || + !intel_dp_is_frl_required(intel_dp)) + return; + + if (intel_dp_pcon_start_frl_training(intel_dp) < 0) { + int ret, mode; + + drm_dbg(&dev_priv->drm, "Couldnt set FRL mode, continuing with TMDS mode\n"); + ret = drm_dp_pcon_reset_frl_config(&intel_dp->aux); + mode = drm_dp_pcon_hdmi_link_mode(&intel_dp->aux, NULL); + + if (ret < 0 || mode != DP_PCON_HDMI_MODE_TMDS) + drm_dbg(&dev_priv->drm, "Issue with PCON, cannot set TMDS mode\n"); + } else { + drm_dbg(&dev_priv->drm, "FRL training Completed\n"); + } +} + static void g4x_set_link_train(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state, diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index 3f862b4fd34f..a667d3f578d6 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -143,4 +143,6 @@ 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); + #endif /* __INTEL_DP_H__ */
-----Original Message----- From: Nautiyal, Ankit K ankit.k.nautiyal@intel.com Sent: Sunday, November 1, 2020 3:37 PM To: intel-gfx@lists.freedesktop.org Cc: dri-devel@lists.freedesktop.org; Shankar, Uma uma.shankar@intel.com; Kulkarni, Vandita vandita.kulkarni@intel.com; ville.syrjala@linux.intel.com; Sharma, Swati2 swati2.sharma@intel.com Subject: [PATCH v2 08/13] drm/i915: Add support for starting FRL training for HDMI2.1 via PCON
This patch adds functions to start FRL training for an HDMI2.1 sink, connected via a PCON as a DP branch device. This patch also adds a new structure for storing frl training related data, when FRL training is completed.
v2: As suggested by Uma Shankar: -renamed couple of variables for better clarity -tweaked the macros used for correct semantics for true/false -fixed other styling issues.
Reviewed-by: Uma Shankar uma.shankar@intel.com
Signed-off-by: Ankit Nautiyal ankit.k.nautiyal@intel.com
.../drm/i915/display/intel_display_types.h | 7 + drivers/gpu/drm/i915/display/intel_dp.c | 189 ++++++++++++++++++ drivers/gpu/drm/i915/display/intel_dp.h | 2 + 3 files changed, 198 insertions(+)
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 282c6ee76384..2c58d63928b8 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1286,6 +1286,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; @@ -1407,6 +1412,8 @@ struct intel_dp {
bool hobl_failed; bool hobl_active;
- struct intel_dp_pcon_frl frl;
};
enum lspcon_vendor { diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index caf7666f1892..7feee2adf9b2 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -2871,6 +2871,9 @@ static void intel_dp_prepare(struct intel_encoder *encoder, intel_dp->DP |= DP_PIPE_SEL_CHV(crtc->pipe); else intel_dp->DP |= DP_PIPE_SEL(crtc->pipe);
intel_dp->frl.is_trained = false;
}intel_dp->frl.trained_rate_gbps = 0;
}
@@ -3769,6 +3772,8 @@ static void intel_disable_dp(struct intel_atomic_state *state, intel_edp_backlight_off(old_conn_state); intel_dp_set_power(intel_dp, DP_SET_POWER_D3); intel_edp_panel_off(intel_dp);
- intel_dp->frl.is_trained = false;
- intel_dp->frl.trained_rate_gbps = 0;
}
static void g4x_disable_dp(struct intel_atomic_state *state, @@ -3864,6 +3869,190 @@ cpt_set_link_train(struct intel_dp *intel_dp, intel_de_posting_read(dev_priv, intel_dp->output_reg); }
+static int intel_dp_get_max_rate_gbps(struct intel_dp *intel_dp) {
- int max_link_clock, max_lanes, max_rate_khz, max_rate_gbps;
- max_link_clock = intel_dp_max_link_rate(intel_dp);
- max_lanes = intel_dp_max_lane_count(intel_dp);
- max_rate_khz = intel_dp_max_data_rate(max_link_clock, max_lanes);
- max_rate_gbps = 8 * DIV_ROUND_UP(max_rate_khz, 1000000);
- return max_rate_gbps;
+}
+static int intel_dp_pcon_get_frl_mask(u8 frl_bw_mask) {
- int bw_gbps[] = {9, 18, 24, 32, 40, 48};
- int i;
- for (i = ARRAY_SIZE(bw_gbps) - 1; i >= 0; i--) {
if (frl_bw_mask & (1 << i))
return bw_gbps[i];
- }
- return 0;
+}
+static int intel_dp_pcon_set_frl_mask(int max_frl) {
- switch (max_frl) {
- case 48:
return DP_PCON_FRL_BW_MASK_48GBPS;
- case 40:
return DP_PCON_FRL_BW_MASK_40GBPS;
- case 32:
return DP_PCON_FRL_BW_MASK_32GBPS;
- case 24:
return DP_PCON_FRL_BW_MASK_24GBPS;
- case 18:
return DP_PCON_FRL_BW_MASK_18GBPS;
- case 9:
return DP_PCON_FRL_BW_MASK_9GBPS;
- }
- return 0;
+}
+static int intel_dp_hdmi_sink_max_frl(struct intel_dp *intel_dp) {
- struct intel_connector *intel_connector = intel_dp->attached_connector;
- struct drm_connector *connector = &intel_connector->base;
- return (connector->display_info.hdmi.max_frl_rate_per_lane *
connector->display_info.hdmi.max_lanes);
+}
+static int intel_dp_pcon_start_frl_training(struct intel_dp *intel_dp) +{ #define PCON_EXTENDED_TRAIN_MODE (1 > 0) #define PCON_CONCURRENT_MODE +(1 > 0) #define PCON_SEQUENTIAL_MODE !PCON_CONCURRENT_MODE #define +PCON_NORMAL_TRAIN_MODE !PCON_EXTENDED_TRAIN_MODE #define +TIMEOUT_FRL_READY_MS 500 #define TIMEOUT_HDMI_LINK_ACTIVE_MS 1000
- struct drm_i915_private *i915 = dp_to_i915(intel_dp);
- int max_frl_bw, max_pcon_frl_bw, max_sink_frl_bw, max_rate_gbps,
max_edid_frl_bw, ret;
- u8 max_frl_bw_mask = 0, frl_trained_mask;
- bool is_active;
- ret = drm_dp_pcon_reset_frl_config(&intel_dp->aux);
- if (ret < 0)
return ret;
- max_rate_gbps = intel_dp_get_max_rate_gbps(intel_dp);
- drm_dbg(&i915->drm, "Source max rate = %d Gbps\n", max_rate_gbps);
- max_pcon_frl_bw = intel_dp->dfp.pcon_max_frl_bw;
- drm_dbg(&i915->drm, "PCON max rate = %d Gbps\n", max_pcon_frl_bw);
- /* Double Check from HDMI SINK EDID */
- max_edid_frl_bw = intel_dp_hdmi_sink_max_frl(intel_dp);
- drm_dbg(&i915->drm, "Sink max rate from EDID = %d Gbps\n",
+max_edid_frl_bw);
- max_sink_frl_bw = intel_dp->dfp.sink_max_frl_bw;
- drm_dbg(&i915->drm, "Sink max rate from PCON = %d Gbps\n",
+max_sink_frl_bw);
- /*
* TODO MAX SINK FRL from PCON is not enumerated. Using MAX FRL
value
* directly from EDID. Need to confirm from Spec.
*/
- max_frl_bw = min(max_rate_gbps, min(max_edid_frl_bw,
+max_pcon_frl_bw));
- if (max_frl_bw <= 0)
return -EINVAL;
- ret = drm_dp_pcon_frl_prepare(&intel_dp->aux, false);
- if (ret < 0)
return ret;
- /* Wait for PCON to be FRL Ready */
- wait_for(is_active = drm_dp_pcon_is_frl_ready(&intel_dp->aux) == true,
+TIMEOUT_FRL_READY_MS);
- if (!is_active)
return -ETIMEDOUT;
- max_frl_bw_mask = intel_dp_pcon_set_frl_mask(max_frl_bw);
- ret = drm_dp_pcon_frl_configure_1(&intel_dp->aux, max_frl_bw,
PCON_SEQUENTIAL_MODE);
- if (ret < 0)
return ret;
- ret = drm_dp_pcon_frl_configure_2(&intel_dp->aux, max_frl_bw_mask,
PCON_NORMAL_TRAIN_MODE);
- if (ret < 0)
return ret;
- ret = drm_dp_pcon_frl_enable(&intel_dp->aux);
- if (ret < 0)
return ret;
- /*
* Wait for FRL to be completed
* Check if the HDMI Link is up and active.
*/
- wait_for(is_active = drm_dp_pcon_hdmi_link_active(&intel_dp->aux) ==
+true, TIMEOUT_HDMI_LINK_ACTIVE_MS);
- if (!is_active)
return -ETIMEDOUT;
- /* Verify HDMI Link configuration shows FRL Mode */
- if (DP_PCON_HDMI_MODE_FRL !=
drm_dp_pcon_hdmi_link_mode(&intel_dp->aux, &frl_trained_mask)) {
drm_dbg(&i915->drm, "HDMI couldn't be trained in FRL
Mode\n");
return -EINVAL;
- }
- drm_dbg(&i915->drm, "MAX_FRL_MASK = %u, FRL_TRAINED_MASK =
%u\n", +max_frl_bw_mask, frl_trained_mask);
- /*
* Read HDMI_LINK_STATUS_TRAINED 0x2005 bit 5
* TODO: Details not mentioned in spec. Need to check.
*/
- intel_dp->frl.trained_rate_gbps =
intel_dp_pcon_get_frl_mask(frl_trained_mask);
- intel_dp->frl.is_trained = true;
- drm_dbg(&i915->drm, "FRL trained with : %d Gbps\n",
+intel_dp->frl.trained_rate_gbps);
- return 0;
+}
+static bool intel_dp_is_frl_required(struct intel_dp *intel_dp) {
- if (!intel_dp->frl.is_trained)
return true;
- /*
* #TODO check if the mode really required FRL or can work
* with TMDS mode.
*/
- return false;
+}
+static bool intel_dp_is_hdmi_2_1_sink(struct intel_dp *intel_dp) {
- if (drm_dp_is_branch(intel_dp->dpcd) &&
intel_dp_hdmi_sink_max_frl(intel_dp) > 0)
return true;
- return false;
+}
+void intel_dp_check_frl_training(struct intel_dp *intel_dp) {
- struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
- if (!intel_dp_is_hdmi_2_1_sink(intel_dp) ||
!intel_dp_is_frl_required(intel_dp))
return;
- if (intel_dp_pcon_start_frl_training(intel_dp) < 0) {
int ret, mode;
drm_dbg(&dev_priv->drm, "Couldnt set FRL mode, continuing
with TMDS mode\n");
ret = drm_dp_pcon_reset_frl_config(&intel_dp->aux);
mode = drm_dp_pcon_hdmi_link_mode(&intel_dp->aux, NULL);
if (ret < 0 || mode != DP_PCON_HDMI_MODE_TMDS)
drm_dbg(&dev_priv->drm, "Issue with PCON, cannot set
TMDS mode\n");
- } else {
drm_dbg(&dev_priv->drm, "FRL training Completed\n");
- }
+}
static void g4x_set_link_train(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state, diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index 3f862b4fd34f..a667d3f578d6 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -143,4 +143,6 @@ 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);
#endif /* __INTEL_DP_H__ */
2.17.1
This patch calls functions to check FRL training requirements for an HDMI2.1 sink, when connected through PCON. The call is made before the DP link training. In case FRL is not required or failure during FRL training, the TMDS mode is selected for the pcon.
v2: moved check_frl_training() just after FEC READY, before starting DP link training. Signed-off-by: Ankit Nautiyal ankit.k.nautiyal@intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 2 ++ drivers/gpu/drm/i915/display/intel_dp.c | 2 ++ 2 files changed, 4 insertions(+)
diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 09811be08cfe..3e76fb1117df 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -3492,6 +3492,8 @@ 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); + /* * 7.i Follow DisplayPort specification training sequence (see notes for * failure handling) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 7feee2adf9b2..9047b620c0d0 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -4183,6 +4183,7 @@ static void intel_enable_dp(struct intel_atomic_state *state,
intel_dp_set_power(intel_dp, DP_SET_POWER_D0); intel_dp_configure_protocol_converter(intel_dp); + intel_dp_check_frl_training(intel_dp); intel_dp_start_link_train(intel_dp, pipe_config); intel_dp_stop_link_train(intel_dp, pipe_config);
@@ -6104,6 +6105,7 @@ int intel_dp_retrain_link(struct intel_encoder *encoder, !intel_dp_mst_is_master_trans(crtc_state)) continue;
+ intel_dp_check_frl_training(intel_dp); intel_dp_start_link_train(intel_dp, crtc_state); intel_dp_stop_link_train(intel_dp, crtc_state); break;
-----Original Message----- From: Nautiyal, Ankit K ankit.k.nautiyal@intel.com Sent: Sunday, November 1, 2020 3:37 PM To: intel-gfx@lists.freedesktop.org Cc: dri-devel@lists.freedesktop.org; Shankar, Uma uma.shankar@intel.com; Kulkarni, Vandita vandita.kulkarni@intel.com; ville.syrjala@linux.intel.com; Sharma, Swati2 swati2.sharma@intel.com Subject: [PATCH v2 09/13] drm/i915: Check for FRL training before DP Link training
This patch calls functions to check FRL training requirements for an HDMI2.1 sink, when connected through PCON. The call is made before the DP link training. In case FRL is not required or failure during FRL training, the TMDS mode is selected for the pcon.
v2: moved check_frl_training() just after FEC READY, before starting DP link training.
Reviewed-by: Uma Shankar uma.shankar@intel.com
Signed-off-by: Ankit Nautiyal ankit.k.nautiyal@intel.com
drivers/gpu/drm/i915/display/intel_ddi.c | 2 ++ drivers/gpu/drm/i915/display/intel_dp.c | 2 ++ 2 files changed, 4 insertions(+)
diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 09811be08cfe..3e76fb1117df 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -3492,6 +3492,8 @@ 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);
- /*
- 7.i Follow DisplayPort specification training sequence (see notes for
failure handling)
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 7feee2adf9b2..9047b620c0d0 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -4183,6 +4183,7 @@ static void intel_enable_dp(struct intel_atomic_state *state,
intel_dp_set_power(intel_dp, DP_SET_POWER_D0); intel_dp_configure_protocol_converter(intel_dp);
- intel_dp_check_frl_training(intel_dp); intel_dp_start_link_train(intel_dp, pipe_config); intel_dp_stop_link_train(intel_dp, pipe_config);
@@ -6104,6 +6105,7 @@ int intel_dp_retrain_link(struct intel_encoder *encoder, !intel_dp_mst_is_master_trans(crtc_state)) continue;
intel_dp_start_link_train(intel_dp, crtc_state); intel_dp_stop_link_train(intel_dp, crtc_state); break;intel_dp_check_frl_training(intel_dp);
-- 2.17.1
From: Swati Sharma swati2.sharma@intel.com
In this patch enables support for detecting link failures between PCON and HDMI sink in i915 driver. HDMI link loss indication to upstream DP source is indicated via IRQ_HPD. This is followed by reading of HDMI link configuration status (HDMI_TX_LINK_ACTIVE_STATUS). If the PCON → HDMI 2.1 link status is off; reinitiate frl link training to recover. Also, report HDMI FRL link error count range for each individual FRL active lane is indicated by DOWNSTREAM_HDMI_ERROR_STATUS_LN registers.
v2: Checked for dpcd read and write failures and added debug message. (Uma Shankar)
Signed-off-by: Swati Sharma swati2.sharma@intel.com Signed-off-by: Ankit Nautiyal ankit.k.nautiyal@intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 56 +++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 9047b620c0d0..6177169c4401 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -5932,6 +5932,31 @@ intel_dp_check_mst_status(struct intel_dp *intel_dp) return link_ok; }
+static void +intel_dp_handle_hdmi_link_status_change(struct intel_dp *intel_dp) +{ + bool is_active; + u8 buf = 0; + + is_active = drm_dp_pcon_hdmi_link_active(&intel_dp->aux); + if (intel_dp->frl.is_trained && !is_active) { + if (drm_dp_dpcd_readb(&intel_dp->aux, DP_PCON_HDMI_LINK_CONFIG_1, &buf) < 0) + return; + + buf &= ~DP_PCON_ENABLE_HDMI_LINK; + if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_PCON_HDMI_LINK_CONFIG_1, buf) < 0) + return; + + drm_dp_pcon_hdmi_frl_link_error_count(&intel_dp->aux, &intel_dp->attached_connector->base); + + intel_dp->frl.is_trained = false; + intel_dp->frl.trained_rate_gbps = 0; + + /* Restart FRL training or fall back to TMDS mode */ + intel_dp_check_frl_training(intel_dp); + } +} + static bool intel_dp_needs_link_retrain(struct intel_dp *intel_dp) { @@ -6297,7 +6322,7 @@ intel_dp_hotplug(struct intel_encoder *encoder, return state; }
-static void intel_dp_check_service_irq(struct intel_dp *intel_dp) +static void intel_dp_check_device_service_irq(struct intel_dp *intel_dp) { struct drm_i915_private *i915 = dp_to_i915(intel_dp); u8 val; @@ -6321,6 +6346,30 @@ static void intel_dp_check_service_irq(struct intel_dp *intel_dp) drm_dbg_kms(&i915->drm, "Sink specific irq unhandled\n"); }
+static void intel_dp_check_link_service_irq(struct intel_dp *intel_dp) +{ + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + u8 val; + + if (intel_dp->dpcd[DP_DPCD_REV] < 0x11) + return; + + if (drm_dp_dpcd_readb(&intel_dp->aux, + DP_LINK_SERVICE_IRQ_VECTOR_ESI0, &val) != 1 || !val) { + drm_dbg_kms(&i915->drm, "Error in reading link service irq vector\n"); + return; + } + + if (drm_dp_dpcd_writeb(&intel_dp->aux, + DP_LINK_SERVICE_IRQ_VECTOR_ESI0, val) != 1) { + drm_dbg_kms(&i915->drm, "Error in writing link service irq vector\n"); + return; + } + + if (val & HDMI_LINK_STATUS_CHANGED) + intel_dp_handle_hdmi_link_status_change(intel_dp); +} + /* * According to DP spec * 5.1.2: @@ -6360,7 +6409,8 @@ intel_dp_short_pulse(struct intel_dp *intel_dp) return false; }
- intel_dp_check_service_irq(intel_dp); + intel_dp_check_device_service_irq(intel_dp); + intel_dp_check_link_service_irq(intel_dp);
/* Handle CEC interrupts, if any */ drm_dp_cec_irq(&intel_dp->aux); @@ -6794,7 +6844,7 @@ intel_dp_detect(struct drm_connector *connector, to_intel_connector(connector)->detect_edid) status = connector_status_connected;
- intel_dp_check_service_irq(intel_dp); + intel_dp_check_device_service_irq(intel_dp);
out: if (status != connector_status_connected && !intel_dp->is_mst)
-----Original Message----- From: Nautiyal, Ankit K ankit.k.nautiyal@intel.com Sent: Sunday, November 1, 2020 3:37 PM To: intel-gfx@lists.freedesktop.org Cc: dri-devel@lists.freedesktop.org; Shankar, Uma uma.shankar@intel.com; Kulkarni, Vandita vandita.kulkarni@intel.com; ville.syrjala@linux.intel.com; Sharma, Swati2 swati2.sharma@intel.com Subject: [PATCH v2 10/13] drm/i915: Add support for enabling link status and recovery
From: Swati Sharma swati2.sharma@intel.com
In this patch enables support for detecting link failures between PCON and HDMI sink in i915 driver. HDMI link loss indication to upstream DP source is indicated via IRQ_HPD. This is followed by reading of HDMI link configuration status (HDMI_TX_LINK_ACTIVE_STATUS). If the PCON → HDMI 2.1 link status is off; reinitiate frl link training to recover. Also, report HDMI FRL link error count range for each individual FRL active lane is indicated by DOWNSTREAM_HDMI_ERROR_STATUS_LN registers.
v2: Checked for dpcd read and write failures and added debug message. (Uma Shankar)
Reviewed-by: Uma Shankar uma.shankar@intel.com
Signed-off-by: Swati Sharma swati2.sharma@intel.com Signed-off-by: Ankit Nautiyal ankit.k.nautiyal@intel.com
drivers/gpu/drm/i915/display/intel_dp.c | 56 +++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 9047b620c0d0..6177169c4401 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -5932,6 +5932,31 @@ intel_dp_check_mst_status(struct intel_dp *intel_dp) return link_ok; }
+static void +intel_dp_handle_hdmi_link_status_change(struct intel_dp *intel_dp) {
- bool is_active;
- u8 buf = 0;
- is_active = drm_dp_pcon_hdmi_link_active(&intel_dp->aux);
- if (intel_dp->frl.is_trained && !is_active) {
if (drm_dp_dpcd_readb(&intel_dp->aux,
DP_PCON_HDMI_LINK_CONFIG_1, &buf) < 0)
return;
buf &= ~DP_PCON_ENABLE_HDMI_LINK;
if (drm_dp_dpcd_writeb(&intel_dp->aux,
DP_PCON_HDMI_LINK_CONFIG_1, buf) < 0)
return;
drm_dp_pcon_hdmi_frl_link_error_count(&intel_dp->aux,
+&intel_dp->attached_connector->base);
intel_dp->frl.is_trained = false;
intel_dp->frl.trained_rate_gbps = 0;
/* Restart FRL training or fall back to TMDS mode */
intel_dp_check_frl_training(intel_dp);
- }
+}
static bool intel_dp_needs_link_retrain(struct intel_dp *intel_dp) { @@ -6297,7 +6322,7 @@ intel_dp_hotplug(struct intel_encoder *encoder, return state; }
-static void intel_dp_check_service_irq(struct intel_dp *intel_dp) +static void intel_dp_check_device_service_irq(struct intel_dp +*intel_dp) { struct drm_i915_private *i915 = dp_to_i915(intel_dp); u8 val; @@ -6321,6 +6346,30 @@ static void intel_dp_check_service_irq(struct intel_dp *intel_dp) drm_dbg_kms(&i915->drm, "Sink specific irq unhandled\n"); }
+static void intel_dp_check_link_service_irq(struct intel_dp *intel_dp) +{
- struct drm_i915_private *i915 = dp_to_i915(intel_dp);
- u8 val;
- if (intel_dp->dpcd[DP_DPCD_REV] < 0x11)
return;
- if (drm_dp_dpcd_readb(&intel_dp->aux,
DP_LINK_SERVICE_IRQ_VECTOR_ESI0, &val) != 1 ||
!val) {
drm_dbg_kms(&i915->drm, "Error in reading link service irq
vector\n");
return;
- }
- if (drm_dp_dpcd_writeb(&intel_dp->aux,
DP_LINK_SERVICE_IRQ_VECTOR_ESI0, val) != 1) {
drm_dbg_kms(&i915->drm, "Error in writing link service irq
vector\n");
return;
- }
- if (val & HDMI_LINK_STATUS_CHANGED)
intel_dp_handle_hdmi_link_status_change(intel_dp);
+}
/*
- According to DP spec
- 5.1.2:
@@ -6360,7 +6409,8 @@ intel_dp_short_pulse(struct intel_dp *intel_dp) return false; }
- intel_dp_check_service_irq(intel_dp);
intel_dp_check_device_service_irq(intel_dp);
intel_dp_check_link_service_irq(intel_dp);
/* Handle CEC interrupts, if any */ drm_dp_cec_irq(&intel_dp->aux);
@@ -6794,7 +6844,7 @@ intel_dp_detect(struct drm_connector *connector, to_intel_connector(connector)->detect_edid) status = connector_status_connected;
- intel_dp_check_service_irq(intel_dp);
- intel_dp_check_device_service_irq(intel_dp);
out: if (status != connector_status_connected && !intel_dp->is_mst) -- 2.17.1
This patch adds support to read and store the DSC capabilities of the HDMI2.1 PCon encoder. It also adds a new field to store these caps, The caps are read during dfp update and can later be used to get the PPS parameters for PCON-HDMI2.1 sink pair. Which inturn will be used to take a call to override the existing PPS-metadata, by either writing the entire new PPS metadata, or by writing only the PPS override parameters.
v2: Restructured the code to read all capability DPCDs at once and store in an array in intel_dp structure.
Signed-off-by: Ankit Nautiyal ankit.k.nautiyal@intel.com --- .../drm/i915/display/intel_display_types.h | 1 + drivers/gpu/drm/i915/display/intel_dp.c | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+)
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 2c58d63928b8..f43ded030c14 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1309,6 +1309,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; diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 6177169c4401..2e7ddb062efe 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -3869,6 +3869,24 @@ cpt_set_link_train(struct intel_dp *intel_dp, intel_de_posting_read(dev_priv, intel_dp->output_reg); }
+static void intel_dp_get_pcon_dsc_cap(struct intel_dp *intel_dp) +{ + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + + /* Clear the cached register set to avoid using stale values */ + + memset(intel_dp->pcon_dsc_dpcd, 0, sizeof(intel_dp->pcon_dsc_dpcd)); + + if (drm_dp_dpcd_read(&intel_dp->aux, DP_PCON_DSC_ENCODER, + intel_dp->pcon_dsc_dpcd, + sizeof(intel_dp->pcon_dsc_dpcd)) < 0) + drm_err(&i915->drm, "Failed to read DPCD register 0x%x\n", + DP_PCON_DSC_ENCODER); + + drm_dbg_kms(&i915->drm, "PCON ENCODER DSC DPCD: %*ph\n", + (int)sizeof(intel_dp->pcon_dsc_dpcd), intel_dp->pcon_dsc_dpcd); +} + static int intel_dp_get_max_rate_gbps(struct intel_dp *intel_dp) { int max_link_clock, max_lanes, max_rate_khz, max_rate_gbps; @@ -6645,6 +6663,8 @@ intel_dp_update_dfp(struct intel_dp *intel_dp, intel_dp->dfp.max_tmds_clock, intel_dp->dfp.pcon_max_frl_bw, intel_dp->dfp.sink_max_frl_bw); + + intel_dp_get_pcon_dsc_cap(intel_dp); }
static void
-----Original Message----- From: Nautiyal, Ankit K ankit.k.nautiyal@intel.com Sent: Sunday, November 1, 2020 3:37 PM To: intel-gfx@lists.freedesktop.org Cc: dri-devel@lists.freedesktop.org; Shankar, Uma uma.shankar@intel.com; Kulkarni, Vandita vandita.kulkarni@intel.com; ville.syrjala@linux.intel.com; Sharma, Swati2 swati2.sharma@intel.com Subject: [PATCH v2 11/13] drm/i915: Read DSC capabilities of the HDMI2.1 PCON encoder
This patch adds support to read and store the DSC capabilities of the HDMI2.1 PCon encoder. It also adds a new field to store these caps, The caps are read during dfp update and can later be used to get the PPS parameters for PCON-HDMI2.1 sink pair. Which inturn will be used to take a call to override the existing PPS-metadata, by either writing the entire new PPS metadata, or by writing only the PPS override parameters.
v2: Restructured the code to read all capability DPCDs at once and store in an array in intel_dp structure.
Signed-off-by: Ankit Nautiyal ankit.k.nautiyal@intel.com
.../drm/i915/display/intel_display_types.h | 1 + drivers/gpu/drm/i915/display/intel_dp.c | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+)
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 2c58d63928b8..f43ded030c14 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1309,6 +1309,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;
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 6177169c4401..2e7ddb062efe 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -3869,6 +3869,24 @@ cpt_set_link_train(struct intel_dp *intel_dp, intel_de_posting_read(dev_priv, intel_dp->output_reg); }
+static void intel_dp_get_pcon_dsc_cap(struct intel_dp *intel_dp) {
- struct drm_i915_private *i915 = dp_to_i915(intel_dp);
- /* Clear the cached register set to avoid using stale values */
Drop this extra line. With this fixed Reviewed-by: Uma Shankar uma.shankar@intel.com
- memset(intel_dp->pcon_dsc_dpcd, 0, sizeof(intel_dp->pcon_dsc_dpcd));
- if (drm_dp_dpcd_read(&intel_dp->aux, DP_PCON_DSC_ENCODER,
intel_dp->pcon_dsc_dpcd,
sizeof(intel_dp->pcon_dsc_dpcd)) < 0)
drm_err(&i915->drm, "Failed to read DPCD register 0x%x\n",
DP_PCON_DSC_ENCODER);
- drm_dbg_kms(&i915->drm, "PCON ENCODER DSC DPCD: %*ph\n",
(int)sizeof(intel_dp->pcon_dsc_dpcd), intel_dp-
pcon_dsc_dpcd); }
static int intel_dp_get_max_rate_gbps(struct intel_dp *intel_dp) { int max_link_clock, max_lanes, max_rate_khz, max_rate_gbps; @@ - 6645,6 +6663,8 @@ intel_dp_update_dfp(struct intel_dp *intel_dp, intel_dp->dfp.max_tmds_clock, intel_dp->dfp.pcon_max_frl_bw, intel_dp->dfp.sink_max_frl_bw);
- intel_dp_get_pcon_dsc_cap(intel_dp);
}
static void
2.17.1
The DP-HDMI2.1 PCON spec provides way for a source to set PPS parameters: slice height, slice width and bits_per_pixel, based on the HDMI2.1 sink capabilities. The DSC encoder of the PCON will respect these parameters, while preparing the 128 byte PPS.
This patch adds helper functions to calculate these PPS paremeters as per the HDMI2.1 specification.
Signed-off-by: Ankit Nautiyal ankit.k.nautiyal@intel.com --- drivers/gpu/drm/i915/display/intel_hdmi.c | 181 ++++++++++++++++++++++ drivers/gpu/drm/i915/display/intel_hdmi.h | 7 + 2 files changed, 188 insertions(+)
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index f90838bc74fb..6b9b9ea7f9b0 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -3438,3 +3438,184 @@ 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); } + +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; +} + +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 +#define HDMI_DSC_MAX_ENC_THROUGHPUT_0 340000 +#define HDMI_DSC_MAX_ENC_THROUGHPUT_1 400000 +#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 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_YCBCR420) + kslice_adjust = 5; + else + kslice_adjust = 10; + + 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); + + if (!max_throughput) + return 0; + + 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; +} + +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 { + min_dsc_bpp = 8; + max_dsc_bpp = 3 * 8; /* 3*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; + if (src_fractional_bpp) + return 0; + 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 = num_slices * slice_width * DIV_ROUND_UP(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; +} diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.h b/drivers/gpu/drm/i915/display/intel_hdmi.h index 15eb0ccde76e..fa1a9b030850 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.h +++ b/drivers/gpu/drm/i915/display/intel_hdmi.h @@ -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__ */
-----Original Message----- From: Nautiyal, Ankit K ankit.k.nautiyal@intel.com Sent: Sunday, November 1, 2020 3:37 PM To: intel-gfx@lists.freedesktop.org Cc: dri-devel@lists.freedesktop.org; Shankar, Uma uma.shankar@intel.com; Kulkarni, Vandita vandita.kulkarni@intel.com; ville.syrjala@linux.intel.com; Sharma, Swati2 swati2.sharma@intel.com Subject: [PATCH v2 12/13] drm/i915: Add helper functions for calculating DSC parameters for HDMI2.1
The DP-HDMI2.1 PCON spec provides way for a source to set PPS parameters: slice height, slice width and bits_per_pixel, based on the HDMI2.1 sink capabilities. The DSC encoder of the PCON will respect these parameters, while preparing the 128 byte PPS.
This patch adds helper functions to calculate these PPS paremeters as per the HDMI2.1 specification.
Signed-off-by: Ankit Nautiyal ankit.k.nautiyal@intel.com
drivers/gpu/drm/i915/display/intel_hdmi.c | 181 ++++++++++++++++++++++ drivers/gpu/drm/i915/display/intel_hdmi.h | 7 + 2 files changed, 188 insertions(+)
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index f90838bc74fb..6b9b9ea7f9b0 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -3438,3 +3438,184 @@ 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); }
+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;
+}
+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) {
It would be good to add a comment describing each of the function parameters, this will make following code easier.
+/* Pixel rates in KPixels/sec */ +#define HDMI_DSC_PEAK_PIXEL_RATE 2720000 +#define HDMI_DSC_MAX_ENC_THROUGHPUT_0 340000 +#define HDMI_DSC_MAX_ENC_THROUGHPUT_1 400000
It would be good to add a comment to describe what actually this represent.
+#define MAX_HDMI_SLICE_WIDTH 2720
How this limit is defined, may be mention of the spec details.
- 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 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_YCBCR420)
kslice_adjust = 5;
- else
kslice_adjust = 10;
May be add a note for 422 formats, or fail in that case, not sure if value of 1 holds good for 422 as well. If it's 1, then ignore the comment.
- 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;
A comment describing slight details will be good.
- /*
* 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);
- if (!max_throughput)
return 0;
hdmi_throughput is already checked for 0, so this is not needed.
- 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;
+}
+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)
Describe the parameters here as well.
+{
- 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 {
min_dsc_bpp = 8;
max_dsc_bpp = 3 * 8; /* 3*bpc */
- }
May be add a note for 422 formats, or fail in that case. I guess 8 and 24 will work for RGB and 422 will have different values. Please check and fix this.
- /*
* 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;
- if (src_fractional_bpp)
I think you missed a ! here
return 0;
- 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 = num_slices * slice_width * DIV_ROUND_UP(bpp,
8);
if (target_bytes <= hdmi_max_chunk_bytes) {
bpp_found = true;
break;
}
bpp_target_x16 -= bpp_decrement_x16;
Not sure on the overall calculation on this part, but if this works then I am good. Please confirm the same with actual bpp values computed and validate.
- }
- if (bpp_found)
return bpp_target_x16;
I think we should divide by 16 and return. Isn't it ?
- return 0;
+} diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.h b/drivers/gpu/drm/i915/display/intel_hdmi.h index 15eb0ccde76e..fa1a9b030850 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.h +++ b/drivers/gpu/drm/i915/display/intel_hdmi.h @@ -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__ */
2.17.1
Hi Uma,
Thanks for the comments and spotting the errors. I agree to most of the comments and will address them in the next version.
Please find my responses inline:
On 11/26/2020 1:58 AM, Shankar, Uma wrote:
-----Original Message----- From: Nautiyal, Ankit K ankit.k.nautiyal@intel.com Sent: Sunday, November 1, 2020 3:37 PM To: intel-gfx@lists.freedesktop.org Cc: dri-devel@lists.freedesktop.org; Shankar, Uma uma.shankar@intel.com; Kulkarni, Vandita vandita.kulkarni@intel.com; ville.syrjala@linux.intel.com; Sharma, Swati2 swati2.sharma@intel.com Subject: [PATCH v2 12/13] drm/i915: Add helper functions for calculating DSC parameters for HDMI2.1
The DP-HDMI2.1 PCON spec provides way for a source to set PPS parameters: slice height, slice width and bits_per_pixel, based on the HDMI2.1 sink capabilities. The DSC encoder of the PCON will respect these parameters, while preparing the 128 byte PPS.
This patch adds helper functions to calculate these PPS paremeters as per the HDMI2.1 specification.
Signed-off-by: Ankit Nautiyal ankit.k.nautiyal@intel.com
drivers/gpu/drm/i915/display/intel_hdmi.c | 181 ++++++++++++++++++++++ drivers/gpu/drm/i915/display/intel_hdmi.h | 7 + 2 files changed, 188 insertions(+)
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index f90838bc74fb..6b9b9ea7f9b0 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -3438,3 +3438,184 @@ 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); }
+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;
+}
+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) {
It would be good to add a comment describing each of the function parameters, this will make following code easier.
Alright, I will add documentation here.
+/* Pixel rates in KPixels/sec */ +#define HDMI_DSC_PEAK_PIXEL_RATE 2720000 +#define HDMI_DSC_MAX_ENC_THROUGHPUT_0 340000 +#define HDMI_DSC_MAX_ENC_THROUGHPUT_1 400000
It would be good to add a comment to describe what actually this represent.
Agreed will have a comment to describe these macros.
+#define MAX_HDMI_SLICE_WIDTH 2720
How this limit is defined, may be mention of the spec details.
Agreed, will provide details in next patch version.
- 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 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_YCBCR420)
kslice_adjust = 5;
- else
kslice_adjust = 10;
May be add a note for 422 formats, or fail in that case, not sure if value of 1 holds good for 422 as well. If it's 1, then ignore the comment.
You are right, for 422 format correct value is 0.5.
I will set the value of 1 for 444 formats and the else case for 422 and 420 will be then 0.5
- 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;
A comment describing slight details will be good.
Will add the comments in this part in next version.
- /*
* 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);
- if (!max_throughput)
return 0;
hdmi_throughput is already checked for 0, so this is not needed.
Agreed, this is redundant, will get rid of this condition.
- 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;
+}
+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)
Describe the parameters here as well.
Will add the documentation for the function in next version.
+{
- 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 {
min_dsc_bpp = 8;
max_dsc_bpp = 3 * 8; /* 3*bpc */
- }
May be add a note for 422 formats, or fail in that case. I guess 8 and 24 will work for RGB and 422 will have different values. Please check and fix this.
Alright, will have a separate condition for 444 format and 420 format.
The 422 format will be then in else case.
- /*
* 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;
- if (src_fractional_bpp)
I think you missed a ! here
Thanks for catching that. Will fix in the next version.
return 0;
- 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 = num_slices * slice_width * DIV_ROUND_UP(bpp,
8);
if (target_bytes <= hdmi_max_chunk_bytes) {
bpp_found = true;
break;
}
bpp_target_x16 -= bpp_decrement_x16;
Not sure on the overall calculation on this part, but if this works then I am good. Please confirm the same with actual bpp values computed and validate.
The value for bpp was seen to be around 10-12bpp for with TGL platform with for 8k resolutions with one of the DSC1.2 panel for 8k modes.
- }
- if (bpp_found)
return bpp_target_x16;
I think we should divide by 16 and return. Isn't it ?
The values expected to be written in PPS parameter register are x16 so I am directly returning this value.
Thanks & Regards,
Ankit
- return 0;
+} diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.h b/drivers/gpu/drm/i915/display/intel_hdmi.h index 15eb0ccde76e..fa1a9b030850 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.h +++ b/drivers/gpu/drm/i915/display/intel_hdmi.h @@ -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__ */
2.17.1
When a source supporting DSC1.1 is connected to DSC1.2 HDMI2.1 sink via DP HDMI2.1 PCON, the PCON can be configured to decode the DSC1.1 compressed stream and encode to DSC1.2. It then sends the DSC1.2 compressed stream to the HDMI2.1 sink.
This patch configures the PCON for DSC1.1 to DSC1.2 encoding, based on the PCON's DSC encoder capablities and HDMI2.1 sink's DSC decoder capabilities.
v2: Rebase
Signed-off-by: Ankit Nautiyal ankit.k.nautiyal@intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 1 + drivers/gpu/drm/i915/display/intel_dp.c | 128 ++++++++++++++++++++++- drivers/gpu/drm/i915/display/intel_dp.h | 2 + 3 files changed, 129 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 3e76fb1117df..dbf28d021d08 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -3493,6 +3493,7 @@ 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 diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 2e7ddb062efe..bc1f1afc35ad 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -788,6 +788,16 @@ intel_dp_mode_valid(struct drm_connector *connector, target_clock, mode->hdisplay); } + + /* + * TODO: If its a PCON with HDMI sink: + * Assumption : Source only supports DSC1.1 + * + * If HDMI supports DSC 1.2 but PCON does not support + * DSC1.1->DSC1.2 encoding Then return MODE_CLOCK_HIGH. + * Otherwise check if the mode can be applied according to + * DSC capablities of the PCON and HDMI Sink combine. + */ }
if ((mode_rate > max_rate && !(dsc_max_output_bpp && dsc_slice_count)) || @@ -3936,9 +3946,21 @@ static int intel_dp_hdmi_sink_max_frl(struct intel_dp *intel_dp) { struct intel_connector *intel_connector = intel_dp->attached_connector; struct drm_connector *connector = &intel_connector->base; + int max_frl_rate; + int max_lanes, rate_per_lane; + int max_dsc_lanes, dsc_rate_per_lane; + + max_lanes = connector->display_info.hdmi.max_lanes; + rate_per_lane = connector->display_info.hdmi.max_frl_rate_per_lane; + max_frl_rate = max_lanes * rate_per_lane; + + if (connector->display_info.hdmi.dsc_cap.v_1p2) { + max_dsc_lanes = connector->display_info.hdmi.dsc_cap.max_lanes; + dsc_rate_per_lane = connector->display_info.hdmi.dsc_cap.max_frl_rate_per_lane; + max_frl_rate = min(max_frl_rate, max_dsc_lanes * dsc_rate_per_lane); + }
- return (connector->display_info.hdmi.max_frl_rate_per_lane * - connector->display_info.hdmi.max_lanes); + return max_frl_rate; }
static int intel_dp_pcon_start_frl_training(struct intel_dp *intel_dp) @@ -4071,6 +4093,106 @@ void intel_dp_check_frl_training(struct intel_dp *intel_dp) } }
+static int +intel_dp_pcon_dsc_enc_slice_height(const struct intel_crtc_state *crtc_state) +{ + + int vactive = crtc_state->hw.adjusted_mode.vdisplay; + + return intel_hdmi_dsc_get_slice_height(vactive); +} + +static int +intel_dp_pcon_dsc_enc_slices(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state) +{ + struct intel_connector *intel_connector = intel_dp->attached_connector; + struct drm_connector *connector = &intel_connector->base; + int hdmi_throughput = connector->display_info.hdmi.dsc_cap.clk_per_slice; + int hdmi_max_slices = connector->display_info.hdmi.dsc_cap.max_slices; + int pcon_max_slices = drm_dp_pcon_dsc_max_slices(intel_dp->pcon_dsc_dpcd); + int pcon_max_slice_width = drm_dp_pcon_dsc_max_slice_width(intel_dp->pcon_dsc_dpcd); + + + return intel_hdmi_dsc_get_num_slices(crtc_state, pcon_max_slices, + pcon_max_slice_width, + hdmi_max_slices, hdmi_throughput); +} + +static int +intel_dp_pcon_dsc_enc_bpp(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state, + int num_slices, int slice_width) +{ + struct intel_connector *intel_connector = intel_dp->attached_connector; + struct drm_connector *connector = &intel_connector->base; + int output_format = crtc_state->output_format; + bool hdmi_all_bpp = connector->display_info.hdmi.dsc_cap.all_bpp; + int pcon_fractional_bpp = drm_dp_pcon_dsc_bpp_incr(intel_dp->pcon_dsc_dpcd); + int hdmi_max_chunk_bytes = + connector->display_info.hdmi.dsc_cap.total_chunk_kbytes * 1024; + + return intel_hdmi_dsc_get_bpp(pcon_fractional_bpp, slice_width, + num_slices, output_format, hdmi_all_bpp, + hdmi_max_chunk_bytes); +} + +void +intel_dp_pcon_dsc_configure(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state) +{ + u8 pps_param[6]; + u8 buf; + int version_major, version_minor; + int slice_height; + int slice_width; + int num_slices; + int bits_per_pixel; + int ret; + struct intel_connector *intel_connector = intel_dp->attached_connector; + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + struct drm_connector *connector = &intel_connector->base; + bool hdmi_is_dsc_1_2 = connector->display_info.hdmi.dsc_cap.v_1p2; + + + buf = intel_dp->pcon_dsc_dpcd[DP_PCON_DSC_VERSION - DP_PCON_DSC_ENCODER]; + version_major = (buf & DP_PCON_DSC_MAJOR_MASK) >> DP_PCON_DSC_MAJOR_SHIFT; + version_minor = (buf & DP_PCON_DSC_MINOR_MASK) >> DP_PCON_DSC_MINOR_SHIFT; + + + /* Only if PCON encoder and HDMI decoder both support DSC 1.2 */ + if ((version_major != 1 || version_minor != 2) || + (!hdmi_is_dsc_1_2)) + return; + + slice_height = intel_dp_pcon_dsc_enc_slice_height(crtc_state); + if (!slice_height) + return; + + num_slices = intel_dp_pcon_dsc_enc_slices(intel_dp, crtc_state); + if (!num_slices) + return; + + slice_width = DIV_ROUND_UP(crtc_state->hw.adjusted_mode.hdisplay, + num_slices); + + bits_per_pixel = intel_dp_pcon_dsc_enc_bpp(intel_dp, crtc_state, + num_slices, slice_width); + if (!bits_per_pixel) + return; + + pps_param[0] = slice_height >> 8; + pps_param[1] = slice_height & 0xFF; + pps_param[2] = slice_width >> 8; + pps_param[3] = slice_width & 0xFF; + pps_param[4] = bits_per_pixel >> 8; + pps_param[5] = bits_per_pixel & 0xFF; + + ret = drm_dp_pcon_pps_override_param(&intel_dp->aux, pps_param); + if (ret < 0) + drm_dbg_kms(&i915->drm, "Failed to set pcon DSC\n"); +} + static void g4x_set_link_train(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state, @@ -4202,6 +4324,7 @@ static void intel_enable_dp(struct intel_atomic_state *state, intel_dp_set_power(intel_dp, DP_SET_POWER_D0); intel_dp_configure_protocol_converter(intel_dp); intel_dp_check_frl_training(intel_dp); + intel_dp_pcon_dsc_configure(intel_dp, pipe_config); intel_dp_start_link_train(intel_dp, pipe_config); intel_dp_stop_link_train(intel_dp, pipe_config);
@@ -6149,6 +6272,7 @@ int intel_dp_retrain_link(struct intel_encoder *encoder, continue;
intel_dp_check_frl_training(intel_dp); + intel_dp_pcon_dsc_configure(intel_dp, crtc_state); intel_dp_start_link_train(intel_dp, crtc_state); intel_dp_stop_link_train(intel_dp, crtc_state); break; diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index a667d3f578d6..3515e057447e 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -144,5 +144,7 @@ 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__ */
-----Original Message----- From: Nautiyal, Ankit K ankit.k.nautiyal@intel.com Sent: Sunday, November 1, 2020 3:37 PM To: intel-gfx@lists.freedesktop.org Cc: dri-devel@lists.freedesktop.org; Shankar, Uma uma.shankar@intel.com; Kulkarni, Vandita vandita.kulkarni@intel.com; ville.syrjala@linux.intel.com; Sharma, Swati2 swati2.sharma@intel.com Subject: [PATCH v2 13/13] drm/i915: Configure PCON for DSC1.1 to DSC1.2 encoding
May be good to append i915/ with display as well.
When a source supporting DSC1.1 is connected to DSC1.2 HDMI2.1 sink via DP HDMI2.1 PCON, the PCON can be configured to decode the DSC1.1 compressed stream and encode to DSC1.2. It then sends the DSC1.2 compressed stream to the HDMI2.1 sink.
This patch configures the PCON for DSC1.1 to DSC1.2 encoding, based on the PCON's DSC encoder capablities and HDMI2.1 sink's DSC decoder capabilities.
v2: Rebase
Signed-off-by: Ankit Nautiyal ankit.k.nautiyal@intel.com
drivers/gpu/drm/i915/display/intel_ddi.c | 1 + drivers/gpu/drm/i915/display/intel_dp.c | 128 ++++++++++++++++++++++- drivers/gpu/drm/i915/display/intel_dp.h | 2 + 3 files changed, 129 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 3e76fb1117df..dbf28d021d08 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -3493,6 +3493,7 @@ 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);
These are called here unconditionally, I think we should invoke them only if we are driving a pcon and not a native DP.
/* * 7.i Follow DisplayPort specification training sequence (see notes for diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 2e7ddb062efe..bc1f1afc35ad 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -788,6 +788,16 @@ intel_dp_mode_valid(struct drm_connector *connector, target_clock, mode->hdisplay); }
/*
* TODO: If its a PCON with HDMI sink:
* Assumption : Source only supports DSC1.1
*
* If HDMI supports DSC 1.2 but PCON does not support
* DSC1.1->DSC1.2 encoding Then return MODE_CLOCK_HIGH.
* Otherwise check if the mode can be applied according to
* DSC capablities of the PCON and HDMI Sink combine.
*/
}
if ((mode_rate > max_rate && !(dsc_max_output_bpp &&
dsc_slice_count)) || @@ -3936,9 +3946,21 @@ static int intel_dp_hdmi_sink_max_frl(struct intel_dp *intel_dp) { struct intel_connector *intel_connector = intel_dp->attached_connector; struct drm_connector *connector = &intel_connector->base;
- int max_frl_rate;
- int max_lanes, rate_per_lane;
- int max_dsc_lanes, dsc_rate_per_lane;
- max_lanes = connector->display_info.hdmi.max_lanes;
- rate_per_lane = connector->display_info.hdmi.max_frl_rate_per_lane;
- max_frl_rate = max_lanes * rate_per_lane;
- if (connector->display_info.hdmi.dsc_cap.v_1p2) {
max_dsc_lanes = connector-
display_info.hdmi.dsc_cap.max_lanes;
dsc_rate_per_lane = connector-
display_info.hdmi.dsc_cap.max_frl_rate_per_lane;
max_frl_rate = min(max_frl_rate, max_dsc_lanes *
dsc_rate_per_lane);
- }
- return (connector->display_info.hdmi.max_frl_rate_per_lane *
connector->display_info.hdmi.max_lanes);
- return max_frl_rate;
}
static int intel_dp_pcon_start_frl_training(struct intel_dp *intel_dp) @@ - 4071,6 +4093,106 @@ void intel_dp_check_frl_training(struct intel_dp *intel_dp) } }
+static int +intel_dp_pcon_dsc_enc_slice_height(const struct intel_crtc_state +*crtc_state) {
- int vactive = crtc_state->hw.adjusted_mode.vdisplay;
- return intel_hdmi_dsc_get_slice_height(vactive);
+}
+static int +intel_dp_pcon_dsc_enc_slices(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state) {
- struct intel_connector *intel_connector = intel_dp->attached_connector;
- struct drm_connector *connector = &intel_connector->base;
- int hdmi_throughput = connector-
display_info.hdmi.dsc_cap.clk_per_slice;
- int hdmi_max_slices = connector->display_info.hdmi.dsc_cap.max_slices;
- int pcon_max_slices = drm_dp_pcon_dsc_max_slices(intel_dp-
pcon_dsc_dpcd);
- int pcon_max_slice_width =
+drm_dp_pcon_dsc_max_slice_width(intel_dp->pcon_dsc_dpcd);
- return intel_hdmi_dsc_get_num_slices(crtc_state, pcon_max_slices,
pcon_max_slice_width,
hdmi_max_slices, hdmi_throughput); }
+static int +intel_dp_pcon_dsc_enc_bpp(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state,
int num_slices, int slice_width)
+{
- struct intel_connector *intel_connector = intel_dp->attached_connector;
- struct drm_connector *connector = &intel_connector->base;
- int output_format = crtc_state->output_format;
- bool hdmi_all_bpp = connector->display_info.hdmi.dsc_cap.all_bpp;
- int pcon_fractional_bpp = drm_dp_pcon_dsc_bpp_incr(intel_dp-
pcon_dsc_dpcd);
- int hdmi_max_chunk_bytes =
connector->display_info.hdmi.dsc_cap.total_chunk_kbytes *
1024;
- return intel_hdmi_dsc_get_bpp(pcon_fractional_bpp, slice_width,
num_slices, output_format, hdmi_all_bpp,
hdmi_max_chunk_bytes);
+}
+void +intel_dp_pcon_dsc_configure(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state) {
- u8 pps_param[6];
- u8 buf;
- int version_major, version_minor;
- int slice_height;
- int slice_width;
- int num_slices;
- int bits_per_pixel;
- int ret;
- struct intel_connector *intel_connector = intel_dp->attached_connector;
- struct drm_i915_private *i915 = dp_to_i915(intel_dp);
- struct drm_connector *connector = &intel_connector->base;
- bool hdmi_is_dsc_1_2 = connector->display_info.hdmi.dsc_cap.v_1p2;
This may be NULL, please add a check before using it.
- buf = intel_dp->pcon_dsc_dpcd[DP_PCON_DSC_VERSION -
DP_PCON_DSC_ENCODER];
- version_major = (buf & DP_PCON_DSC_MAJOR_MASK) >>
DP_PCON_DSC_MAJOR_SHIFT;
- version_minor = (buf & DP_PCON_DSC_MINOR_MASK) >>
+DP_PCON_DSC_MINOR_SHIFT;
- /* Only if PCON encoder and HDMI decoder both support DSC 1.2 */
- if ((version_major != 1 || version_minor != 2) ||
(!hdmi_is_dsc_1_2))
return;
- slice_height = intel_dp_pcon_dsc_enc_slice_height(crtc_state);
- if (!slice_height)
return;
- num_slices = intel_dp_pcon_dsc_enc_slices(intel_dp, crtc_state);
- if (!num_slices)
return;
- slice_width = DIV_ROUND_UP(crtc_state->hw.adjusted_mode.hdisplay,
num_slices);
- bits_per_pixel = intel_dp_pcon_dsc_enc_bpp(intel_dp, crtc_state,
num_slices, slice_width);
- if (!bits_per_pixel)
return;
- pps_param[0] = slice_height >> 8;
- pps_param[1] = slice_height & 0xFF;
First we have LSB, so isn't the order be reversed ?
- pps_param[2] = slice_width >> 8;
- pps_param[3] = slice_width & 0xFF;
Same here.
- pps_param[4] = bits_per_pixel >> 8;
- pps_param[5] = bits_per_pixel & 0xFF;
Last 2:7 are reserved, so adjust the mask accordingly.
- ret = drm_dp_pcon_pps_override_param(&intel_dp->aux, pps_param);
- if (ret < 0)
drm_dbg_kms(&i915->drm, "Failed to set pcon DSC\n"); }
static void g4x_set_link_train(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state, @@ -4202,6 +4324,7 @@ static void intel_enable_dp(struct intel_atomic_state *state, intel_dp_set_power(intel_dp, DP_SET_POWER_D0); intel_dp_configure_protocol_converter(intel_dp); intel_dp_check_frl_training(intel_dp);
- intel_dp_pcon_dsc_configure(intel_dp, pipe_config); intel_dp_start_link_train(intel_dp, pipe_config); intel_dp_stop_link_train(intel_dp, pipe_config);
@@ -6149,6 +6272,7 @@ int intel_dp_retrain_link(struct intel_encoder *encoder, continue;
intel_dp_check_frl_training(intel_dp);
intel_dp_start_link_train(intel_dp, crtc_state); intel_dp_stop_link_train(intel_dp, crtc_state); break;intel_dp_pcon_dsc_configure(intel_dp, crtc_state);
diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index a667d3f578d6..3515e057447e 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -144,5 +144,7 @@ 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__ */
2.17.1
Thanks Uma for the comments.
Please find my responses inline:
On 11/26/2020 2:15 AM, Shankar, Uma wrote:
-----Original Message----- From: Nautiyal, Ankit K ankit.k.nautiyal@intel.com Sent: Sunday, November 1, 2020 3:37 PM To: intel-gfx@lists.freedesktop.org Cc: dri-devel@lists.freedesktop.org; Shankar, Uma uma.shankar@intel.com; Kulkarni, Vandita vandita.kulkarni@intel.com; ville.syrjala@linux.intel.com; Sharma, Swati2 swati2.sharma@intel.com Subject: [PATCH v2 13/13] drm/i915: Configure PCON for DSC1.1 to DSC1.2 encoding
May be good to append i915/ with display as well.
Alright, will change to drm/i915/display.
When a source supporting DSC1.1 is connected to DSC1.2 HDMI2.1 sink via DP HDMI2.1 PCON, the PCON can be configured to decode the DSC1.1 compressed stream and encode to DSC1.2. It then sends the DSC1.2 compressed stream to the HDMI2.1 sink.
This patch configures the PCON for DSC1.1 to DSC1.2 encoding, based on the PCON's DSC encoder capablities and HDMI2.1 sink's DSC decoder capabilities.
v2: Rebase
Signed-off-by: Ankit Nautiyal ankit.k.nautiyal@intel.com
drivers/gpu/drm/i915/display/intel_ddi.c | 1 + drivers/gpu/drm/i915/display/intel_dp.c | 128 ++++++++++++++++++++++- drivers/gpu/drm/i915/display/intel_dp.h | 2 + 3 files changed, 129 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 3e76fb1117df..dbf28d021d08 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -3493,6 +3493,7 @@ 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);
These are called here unconditionally, I think we should invoke them only if we are driving a pcon and not a native DP.
Right. I will add the condition to check if its a DP branched device and have hdmi2.1 as sink inside these functions.
So for native DP, these will just return. Will fix this in next patch set.
/* * 7.i Follow DisplayPort specification training sequence (see notes for diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 2e7ddb062efe..bc1f1afc35ad 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -788,6 +788,16 @@ intel_dp_mode_valid(struct drm_connector *connector, target_clock, mode->hdisplay); }
/*
* TODO: If its a PCON with HDMI sink:
* Assumption : Source only supports DSC1.1
*
* If HDMI supports DSC 1.2 but PCON does not support
* DSC1.1->DSC1.2 encoding Then return MODE_CLOCK_HIGH.
* Otherwise check if the mode can be applied according to
* DSC capablities of the PCON and HDMI Sink combine.
*/
}
if ((mode_rate > max_rate && !(dsc_max_output_bpp &&
dsc_slice_count)) || @@ -3936,9 +3946,21 @@ static int intel_dp_hdmi_sink_max_frl(struct intel_dp *intel_dp) { struct intel_connector *intel_connector = intel_dp->attached_connector; struct drm_connector *connector = &intel_connector->base;
- int max_frl_rate;
- int max_lanes, rate_per_lane;
- int max_dsc_lanes, dsc_rate_per_lane;
- max_lanes = connector->display_info.hdmi.max_lanes;
- rate_per_lane = connector->display_info.hdmi.max_frl_rate_per_lane;
- max_frl_rate = max_lanes * rate_per_lane;
- if (connector->display_info.hdmi.dsc_cap.v_1p2) {
max_dsc_lanes = connector-
display_info.hdmi.dsc_cap.max_lanes;
dsc_rate_per_lane = connector-
display_info.hdmi.dsc_cap.max_frl_rate_per_lane;
max_frl_rate = min(max_frl_rate, max_dsc_lanes *
dsc_rate_per_lane);
- }
- return (connector->display_info.hdmi.max_frl_rate_per_lane *
connector->display_info.hdmi.max_lanes);
return max_frl_rate; }
static int intel_dp_pcon_start_frl_training(struct intel_dp *intel_dp) @@ -
4071,6 +4093,106 @@ void intel_dp_check_frl_training(struct intel_dp *intel_dp) } }
+static int +intel_dp_pcon_dsc_enc_slice_height(const struct intel_crtc_state +*crtc_state) {
- int vactive = crtc_state->hw.adjusted_mode.vdisplay;
- return intel_hdmi_dsc_get_slice_height(vactive);
+}
+static int +intel_dp_pcon_dsc_enc_slices(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state) {
- struct intel_connector *intel_connector = intel_dp->attached_connector;
- struct drm_connector *connector = &intel_connector->base;
- int hdmi_throughput = connector-
display_info.hdmi.dsc_cap.clk_per_slice;
- int hdmi_max_slices = connector->display_info.hdmi.dsc_cap.max_slices;
- int pcon_max_slices = drm_dp_pcon_dsc_max_slices(intel_dp-
pcon_dsc_dpcd);
- int pcon_max_slice_width =
+drm_dp_pcon_dsc_max_slice_width(intel_dp->pcon_dsc_dpcd);
- return intel_hdmi_dsc_get_num_slices(crtc_state, pcon_max_slices,
pcon_max_slice_width,
hdmi_max_slices, hdmi_throughput); }
+static int +intel_dp_pcon_dsc_enc_bpp(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state,
int num_slices, int slice_width)
+{
- struct intel_connector *intel_connector = intel_dp->attached_connector;
- struct drm_connector *connector = &intel_connector->base;
- int output_format = crtc_state->output_format;
- bool hdmi_all_bpp = connector->display_info.hdmi.dsc_cap.all_bpp;
- int pcon_fractional_bpp = drm_dp_pcon_dsc_bpp_incr(intel_dp-
pcon_dsc_dpcd);
- int hdmi_max_chunk_bytes =
connector->display_info.hdmi.dsc_cap.total_chunk_kbytes *
1024;
- return intel_hdmi_dsc_get_bpp(pcon_fractional_bpp, slice_width,
num_slices, output_format, hdmi_all_bpp,
hdmi_max_chunk_bytes);
+}
+void +intel_dp_pcon_dsc_configure(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state) {
- u8 pps_param[6];
- u8 buf;
- int version_major, version_minor;
- int slice_height;
- int slice_width;
- int num_slices;
- int bits_per_pixel;
- int ret;
- struct intel_connector *intel_connector = intel_dp->attached_connector;
- struct drm_i915_private *i915 = dp_to_i915(intel_dp);
- struct drm_connector *connector = &intel_connector->base;
- bool hdmi_is_dsc_1_2 = connector->display_info.hdmi.dsc_cap.v_1p2;
This may be NULL, please add a check before using it.
Alright, will add a check for NULL here.
- buf = intel_dp->pcon_dsc_dpcd[DP_PCON_DSC_VERSION -
DP_PCON_DSC_ENCODER];
- version_major = (buf & DP_PCON_DSC_MAJOR_MASK) >>
DP_PCON_DSC_MAJOR_SHIFT;
- version_minor = (buf & DP_PCON_DSC_MINOR_MASK) >>
+DP_PCON_DSC_MINOR_SHIFT;
- /* Only if PCON encoder and HDMI decoder both support DSC 1.2 */
- if ((version_major != 1 || version_minor != 2) ||
(!hdmi_is_dsc_1_2))
return;
- slice_height = intel_dp_pcon_dsc_enc_slice_height(crtc_state);
- if (!slice_height)
return;
- num_slices = intel_dp_pcon_dsc_enc_slices(intel_dp, crtc_state);
- if (!num_slices)
return;
- slice_width = DIV_ROUND_UP(crtc_state->hw.adjusted_mode.hdisplay,
num_slices);
- bits_per_pixel = intel_dp_pcon_dsc_enc_bpp(intel_dp, crtc_state,
num_slices, slice_width);
- if (!bits_per_pixel)
return;
- pps_param[0] = slice_height >> 8;
- pps_param[1] = slice_height & 0xFF;
First we have LSB, so isn't the order be reversed ?
Thanks for pointing this out. I reversed the order by mistake.
Will fix this in next patch version.
- pps_param[2] = slice_width >> 8;
- pps_param[3] = slice_width & 0xFF;
Same here.
- pps_param[4] = bits_per_pixel >> 8;
- pps_param[5] = bits_per_pixel & 0xFF;
Last 2:7 are reserved, so adjust the mask accordingly.
Alright will use mask to use only [0:1] bits.
Thanks & Regards,
Ankit
- ret = drm_dp_pcon_pps_override_param(&intel_dp->aux, pps_param);
- if (ret < 0)
drm_dbg_kms(&i915->drm, "Failed to set pcon DSC\n"); }
- static void g4x_set_link_train(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state, @@ -4202,6 +4324,7
@@ static void intel_enable_dp(struct intel_atomic_state *state, intel_dp_set_power(intel_dp, DP_SET_POWER_D0); intel_dp_configure_protocol_converter(intel_dp); intel_dp_check_frl_training(intel_dp);
- intel_dp_pcon_dsc_configure(intel_dp, pipe_config); intel_dp_start_link_train(intel_dp, pipe_config); intel_dp_stop_link_train(intel_dp, pipe_config);
@@ -6149,6 +6272,7 @@ int intel_dp_retrain_link(struct intel_encoder *encoder, continue;
intel_dp_check_frl_training(intel_dp);
intel_dp_start_link_train(intel_dp, crtc_state); intel_dp_stop_link_train(intel_dp, crtc_state); break;intel_dp_pcon_dsc_configure(intel_dp, crtc_state);
diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index a667d3f578d6..3515e057447e 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -144,5 +144,7 @@ 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__ */
-- 2.17.1
dri-devel@lists.freedesktop.org