drm/amd/display: Add DP-HDMI FRL PCON Support in DC
authorFangzhi Zuo <Jerry.Zuo@amd.com>
Thu, 25 Nov 2021 21:06:10 +0000 (16:06 -0500)
committerAlex Deucher <alexander.deucher@amd.com>
Wed, 1 Dec 2021 21:04:56 +0000 (16:04 -0500)
Change since v1: add brief description
1. Add hdmi frl pcon support to existing asic family.
2. Determine pcon frl capability based on pcon dpcd.
3. pcon frl is taken into consideration into mode validation.

v2: squash in warning fix (Alex)

Signed-off-by: Fangzhi Zuo <Jerry.Zuo@amd.com>
Reviewed-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Acked-by: Harry Wentland <harry.wentland@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/core/dc_link.c
drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
drivers/gpu/drm/amd/display/dc/dc.h
drivers/gpu/drm/amd/display/dc/dc_dp_types.h
drivers/gpu/drm/amd/display/dc/dc_hw_types.h
drivers/gpu/drm/amd/display/dc/dc_link.h
drivers/gpu/drm/amd/display/dc/dc_types.h
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c
drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c
drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c

index 3d08f8eba402e67614a240f09fd58fe70cece860..dad7a4fdc427ec2d6c78177e86c9a7ffaac692d1 100644 (file)
@@ -2750,8 +2750,23 @@ static bool dp_active_dongle_validate_timing(
                return false;
        }
 
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+       if (dongle_caps->dp_hdmi_frl_max_link_bw_in_kbps > 0) { // DP to HDMI FRL converter
+               struct dc_crtc_timing outputTiming = *timing;
+
+               if (timing->flags.DSC && !timing->dsc_cfg.is_frl)
+                       /* DP input has DSC, HDMI FRL output doesn't have DSC, remove DSC from output timing */
+                       outputTiming.flags.DSC = 0;
+               if (dc_bandwidth_in_kbps_from_timing(&outputTiming) > dongle_caps->dp_hdmi_frl_max_link_bw_in_kbps)
+                       return false;
+       } else { // DP to HDMI TMDS converter
+               if (get_timing_pixel_clock_100hz(timing) > (dongle_caps->dp_hdmi_max_pixel_clk_in_khz * 10))
+                       return false;
+       }
+#else
        if (get_timing_pixel_clock_100hz(timing) > (dongle_caps->dp_hdmi_max_pixel_clk_in_khz * 10))
                return false;
+#endif
 
 #if defined(CONFIG_DRM_AMD_DC_DCN)
        }
index 84f3545c3032996dbdffa18064902a2502b4b0d4..61aa68014bc34ac3731cd5e2e3123405a9a2f036 100644 (file)
@@ -4313,6 +4313,56 @@ static int translate_dpcd_max_bpc(enum dpcd_downstream_port_max_bpc bpc)
        return -1;
 }
 
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+uint32_t dc_link_bw_kbps_from_raw_frl_link_rate_data(uint8_t bw)
+{
+       switch (bw) {
+       case 0b001:
+               return 9000000;
+       case 0b010:
+               return 18000000;
+       case 0b011:
+               return 24000000;
+       case 0b100:
+               return 32000000;
+       case 0b101:
+               return 40000000;
+       case 0b110:
+               return 48000000;
+       }
+
+       return 0;
+}
+
+/**
+ * Return PCON's post FRL link training supported BW if its non-zero, otherwise return max_supported_frl_bw.
+ */
+static uint32_t intersect_frl_link_bw_support(
+       const uint32_t max_supported_frl_bw_in_kbps,
+       const union hdmi_encoded_link_bw hdmi_encoded_link_bw)
+{
+       uint32_t supported_bw_in_kbps = max_supported_frl_bw_in_kbps;
+
+       // HDMI_ENCODED_LINK_BW bits are only valid if HDMI Link Configuration bit is 1 (FRL mode)
+       if (hdmi_encoded_link_bw.bits.FRL_MODE) {
+               if (hdmi_encoded_link_bw.bits.BW_48Gbps)
+                       supported_bw_in_kbps = 48000000;
+               else if (hdmi_encoded_link_bw.bits.BW_40Gbps)
+                       supported_bw_in_kbps = 40000000;
+               else if (hdmi_encoded_link_bw.bits.BW_32Gbps)
+                       supported_bw_in_kbps = 32000000;
+               else if (hdmi_encoded_link_bw.bits.BW_24Gbps)
+                       supported_bw_in_kbps = 24000000;
+               else if (hdmi_encoded_link_bw.bits.BW_18Gbps)
+                       supported_bw_in_kbps = 18000000;
+               else if (hdmi_encoded_link_bw.bits.BW_9Gbps)
+                       supported_bw_in_kbps = 9000000;
+       }
+
+       return supported_bw_in_kbps;
+}
+#endif
+
 static void read_dp_device_vendor_id(struct dc_link *link)
 {
        struct dp_device_vendor_id dp_id;
@@ -4424,6 +4474,27 @@ static void get_active_converter_info(
                                                translate_dpcd_max_bpc(
                                                        hdmi_color_caps.bits.MAX_BITS_PER_COLOR_COMPONENT);
 
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+                                       if (link->dc->caps.hdmi_frl_pcon_support) {
+                                               union hdmi_encoded_link_bw hdmi_encoded_link_bw;
+
+                                               link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps =
+                                                               dc_link_bw_kbps_from_raw_frl_link_rate_data(
+                                                                               hdmi_color_caps.bits.MAX_ENCODED_LINK_BW_SUPPORT);
+
+                                               // Intersect reported max link bw support with the supported link rate post FRL link training
+                                               if (core_link_read_dpcd(link, DP_PCON_HDMI_POST_FRL_STATUS,
+                                                               &hdmi_encoded_link_bw.raw, sizeof(hdmi_encoded_link_bw)) == DC_OK) {
+                                                       link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps = intersect_frl_link_bw_support(
+                                                                       link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps,
+                                                                       hdmi_encoded_link_bw);
+                                               }
+
+                                               if (link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps > 0)
+                                                       link->dpcd_caps.dongle_caps.extendedCapValid = true;
+                                       }
+#endif
+
                                        if (link->dpcd_caps.dongle_caps.dp_hdmi_max_pixel_clk_in_khz != 0)
                                                link->dpcd_caps.dongle_caps.extendedCapValid = true;
                                }
index c14e7db3f69d14aa954dd657606f409203de1e48..2d001de42117dccad898129d5c0945bd075d10e3 100644 (file)
@@ -187,6 +187,7 @@ struct dc_caps {
        struct dc_color_caps color;
 #if defined(CONFIG_DRM_AMD_DC_DCN)
        bool dp_hpo;
+       bool hdmi_frl_pcon_support;
 #endif
        bool edp_dsc_support;
        bool vbios_lttpr_aware;
@@ -1294,6 +1295,11 @@ struct dc_sink_dsc_caps {
        // 'true' if these are virtual DPCD's DSC caps (immediately upstream of sink in MST topology),
        // 'false' if they are sink's DSC caps
        bool is_virtual_dpcd_dsc;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+       // 'true' if MST topology supports DSC passthrough for sink
+       // 'false' if MST topology does not support DSC passthrough
+       bool is_dsc_passthrough_supported;
+#endif
        struct dsc_dec_dpcd_caps dsc_dec_caps;
 };
 
index e68e9a86a4d9d0ccf8cb123aabde63039cc18806..99d26fb315662a6f6bdc373e8c562a2fb4297700 100644 (file)
@@ -378,7 +378,14 @@ enum dpcd_downstream_port_detailed_type {
 union dwnstream_port_caps_byte2 {
        struct {
                uint8_t MAX_BITS_PER_COLOR_COMPONENT:2;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+               uint8_t MAX_ENCODED_LINK_BW_SUPPORT:3;
+               uint8_t SOURCE_CONTROL_MODE_SUPPORT:1;
+               uint8_t CONCURRENT_LINK_BRING_UP_SEQ_SUPPORT:1;
+               uint8_t RESERVED:1;
+#else
                uint8_t RESERVED:6;
+#endif
        } bits;
        uint8_t raw;
 };
@@ -416,6 +423,30 @@ union dwnstream_port_caps_byte3_hdmi {
        uint8_t raw;
 };
 
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+union hdmi_sink_encoded_link_bw_support {
+       struct {
+               uint8_t HDMI_SINK_ENCODED_LINK_BW_SUPPORT:3;
+               uint8_t RESERVED:5;
+       } bits;
+       uint8_t raw;
+};
+
+union hdmi_encoded_link_bw {
+       struct {
+               uint8_t FRL_MODE:1; // Bit 0
+               uint8_t BW_9Gbps:1;
+               uint8_t BW_18Gbps:1;
+               uint8_t BW_24Gbps:1;
+               uint8_t BW_32Gbps:1;
+               uint8_t BW_40Gbps:1;
+               uint8_t BW_48Gbps:1;
+               uint8_t RESERVED:1; // Bit 7
+       } bits;
+       uint8_t raw;
+};
+#endif
+
 /*4-byte structure for detailed capabilities of a down-stream port
 (DP-to-TMDS converter).*/
 union dwnstream_portxcaps {
index 52355fe6994c1448b0d9591e3efa9d2462b9c70d..eac34f591a3fd8a9f7704f256a2df4e83144a7b9 100644 (file)
@@ -741,6 +741,9 @@ struct dc_dsc_config {
        uint32_t version_minor; /* DSC minor version. Full version is formed as 1.version_minor. */
        bool ycbcr422_simple; /* Tell DSC engine to convert YCbCr 4:2:2 to 'YCbCr 4:2:2 simple'. */
        int32_t rc_buffer_size; /* DSC RC buffer block size in bytes */
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+       bool is_frl; /* indicate if DSC is applied based on HDMI FRL sink's capability */
+#endif
        bool is_dp; /* indicate if DSC is applied based on DP's capability */
 };
 struct dc_crtc_timing {
index d449e72a4e2a92c675d4034b8a059749d0206953..d5887d976ef6d3ebcb2245001389bbfa7365e0f9 100644 (file)
@@ -443,6 +443,7 @@ bool dc_link_is_fec_supported(const struct dc_link *link);
 bool dc_link_should_enable_fec(const struct dc_link *link);
 
 #if defined(CONFIG_DRM_AMD_DC_DCN)
+uint32_t dc_link_bw_kbps_from_raw_frl_link_rate_data(uint8_t bw);
 enum dp_link_encoding dc_link_dp_mst_decide_link_encoding_format(const struct dc_link *link);
 #endif
 #endif /* DC_LINK_H_ */
index 388457ffc0a88166d5cadd1fac836c5d32c0b0cc..cb26ff8a54c59c504e8cc71b375fdc46435b39b9 100644 (file)
@@ -430,6 +430,7 @@ struct dc_dongle_caps {
        uint32_t dp_hdmi_max_bpc;
        uint32_t dp_hdmi_max_pixel_clk_in_khz;
 #if defined(CONFIG_DRM_AMD_DC_DCN)
+       uint32_t dp_hdmi_frl_max_link_bw_in_kbps;
        struct dc_dongle_dfp_cap_ext dfp_cap_ext;
 #endif
 };
index 3883f918b3bb2b907496e1e34d4d9414391ad082..40b122a708ef2bf3c918d58c81fe3e578914a08a 100644 (file)
@@ -3796,6 +3796,8 @@ static bool dcn20_resource_construct(
        dc->caps.color.mpc.ogam_rom_caps.hlg = 0;
        dc->caps.color.mpc.ocsc = 1;
 
+       dc->caps.hdmi_frl_pcon_support = true;
+
        if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV) {
                dc->debug = debug_defaults_drv;
        } else if (dc->ctx->dce_environment == DCE_ENV_FPGA_MAXIMUS) {
index d452a0d1777eadf0df22cd41d895dd448d1da8ef..da6031cef244c0f88e92e1a47623ca21a5feecc7 100644 (file)
@@ -2028,6 +2028,8 @@ static bool dcn21_resource_construct(
        dc->caps.color.mpc.ogam_rom_caps.hlg = 0;
        dc->caps.color.mpc.ocsc = 1;
 
+       dc->caps.hdmi_frl_pcon_support = true;
+
        if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV)
                dc->debug = debug_defaults_drv;
        else if (dc->ctx->dce_environment == DCE_ENV_FPGA_MAXIMUS) {
index 79a66e0c4303922889563e2ab3613087e8525673..77331a45a74907eacb57c7779ff1056b98cd9ff2 100644 (file)
@@ -2639,6 +2639,8 @@ static bool dcn30_resource_construct(
        dc->caps.color.mpc.ogam_rom_caps.hlg = 0;
        dc->caps.color.mpc.ocsc = 1;
 
+       dc->caps.hdmi_frl_pcon_support = true;
+
        /* read VBIOS LTTPR caps */
        {
                if (ctx->dc_bios->funcs->get_lttpr_caps) {
index 88e04068794005132026c673dc1f3564762b2b67..b3070c2e45c9b6e3755da442da80dd4dbccefef0 100644 (file)
@@ -2199,6 +2199,7 @@ static bool dcn31_resource_construct(
        dc->caps.post_blend_color_processing = true;
        dc->caps.force_dp_tps4_for_cp2520 = true;
        dc->caps.dp_hpo = true;
+       dc->caps.hdmi_frl_pcon_support = true;
        dc->caps.edp_dsc_support = true;
        dc->caps.extended_aux_timeout_support = true;
        dc->caps.dmcub_support = true;