| 1 | /* |
| 2 | * Copyright 2023 Advanced Micro Devices, Inc. |
| 3 | * |
| 4 | * Permission is hereby granted, free of charge, to any person obtaining a |
| 5 | * copy of this software and associated documentation files (the "Software"), |
| 6 | * to deal in the Software without restriction, including without limitation |
| 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| 8 | * and/or sell copies of the Software, and to permit persons to whom the |
| 9 | * Software is furnished to do so, subject to the following conditions: |
| 10 | * |
| 11 | * The above copyright notice and this permission notice shall be included in |
| 12 | * all copies or substantial portions of the Software. |
| 13 | * |
| 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| 17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
| 18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
| 19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
| 20 | * OTHER DEALINGS IN THE SOFTWARE. |
| 21 | * |
| 22 | * Authors: AMD |
| 23 | * |
| 24 | */ |
| 25 | |
| 26 | /* FILE POLICY AND INTENDED USAGE: |
| 27 | * This file owns timing validation against various link limitations. (ex. |
| 28 | * link bandwidth, receiver capability or our hardware capability) It also |
| 29 | * provides helper functions exposing bandwidth formulas used in validation. |
| 30 | */ |
| 31 | #include "link_validation.h" |
| 32 | #include "protocols/link_dp_capability.h" |
| 33 | #include "protocols/link_dp_dpia_bw.h" |
| 34 | #include "resource.h" |
| 35 | |
| 36 | #define DC_LOGGER_INIT(logger) |
| 37 | |
| 38 | static uint32_t get_tmds_output_pixel_clock_100hz(const struct dc_crtc_timing *timing) |
| 39 | { |
| 40 | |
| 41 | uint32_t pxl_clk = timing->pix_clk_100hz; |
| 42 | |
| 43 | if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) |
| 44 | pxl_clk /= 2; |
| 45 | else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) |
| 46 | pxl_clk = pxl_clk * 2 / 3; |
| 47 | |
| 48 | if (timing->display_color_depth == COLOR_DEPTH_101010) |
| 49 | pxl_clk = pxl_clk * 10 / 8; |
| 50 | else if (timing->display_color_depth == COLOR_DEPTH_121212) |
| 51 | pxl_clk = pxl_clk * 12 / 8; |
| 52 | |
| 53 | return pxl_clk; |
| 54 | } |
| 55 | |
| 56 | static bool dp_active_dongle_validate_timing( |
| 57 | const struct dc_crtc_timing *timing, |
| 58 | const struct dpcd_caps *dpcd_caps) |
| 59 | { |
| 60 | const struct dc_dongle_caps *dongle_caps = &dpcd_caps->dongle_caps; |
| 61 | |
| 62 | switch (dpcd_caps->dongle_type) { |
| 63 | case DISPLAY_DONGLE_DP_VGA_CONVERTER: |
| 64 | case DISPLAY_DONGLE_DP_DVI_CONVERTER: |
| 65 | case DISPLAY_DONGLE_DP_DVI_DONGLE: |
| 66 | if (timing->pixel_encoding == PIXEL_ENCODING_RGB) |
| 67 | return true; |
| 68 | else |
| 69 | return false; |
| 70 | default: |
| 71 | break; |
| 72 | } |
| 73 | |
| 74 | if (dpcd_caps->dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER && |
| 75 | dongle_caps->extendedCapValid == true) { |
| 76 | /* Check Pixel Encoding */ |
| 77 | switch (timing->pixel_encoding) { |
| 78 | case PIXEL_ENCODING_RGB: |
| 79 | case PIXEL_ENCODING_YCBCR444: |
| 80 | break; |
| 81 | case PIXEL_ENCODING_YCBCR422: |
| 82 | if (!dongle_caps->is_dp_hdmi_ycbcr422_pass_through) |
| 83 | return false; |
| 84 | break; |
| 85 | case PIXEL_ENCODING_YCBCR420: |
| 86 | if (!dongle_caps->is_dp_hdmi_ycbcr420_pass_through) |
| 87 | return false; |
| 88 | break; |
| 89 | case PIXEL_ENCODING_UNDEFINED: |
| 90 | /* These color depths are currently not supported */ |
| 91 | ASSERT(false); |
| 92 | break; |
| 93 | default: |
| 94 | /* Invalid Pixel Encoding*/ |
| 95 | return false; |
| 96 | } |
| 97 | |
| 98 | switch (timing->display_color_depth) { |
| 99 | case COLOR_DEPTH_666: |
| 100 | case COLOR_DEPTH_888: |
| 101 | /*888 and 666 should always be supported*/ |
| 102 | break; |
| 103 | case COLOR_DEPTH_101010: |
| 104 | if (dongle_caps->dp_hdmi_max_bpc < 10) |
| 105 | return false; |
| 106 | break; |
| 107 | case COLOR_DEPTH_121212: |
| 108 | if (dongle_caps->dp_hdmi_max_bpc < 12) |
| 109 | return false; |
| 110 | break; |
| 111 | case COLOR_DEPTH_UNDEFINED: |
| 112 | /* These color depths are currently not supported */ |
| 113 | ASSERT(false); |
| 114 | break; |
| 115 | case COLOR_DEPTH_141414: |
| 116 | case COLOR_DEPTH_161616: |
| 117 | default: |
| 118 | /* These color depths are currently not supported */ |
| 119 | return false; |
| 120 | } |
| 121 | |
| 122 | /* Check 3D format */ |
| 123 | switch (timing->timing_3d_format) { |
| 124 | case TIMING_3D_FORMAT_NONE: |
| 125 | case TIMING_3D_FORMAT_FRAME_ALTERNATE: |
| 126 | /*Only frame alternate 3D is supported on active dongle*/ |
| 127 | break; |
| 128 | default: |
| 129 | /*other 3D formats are not supported due to bad infoframe translation */ |
| 130 | return false; |
| 131 | } |
| 132 | |
| 133 | if (dongle_caps->dp_hdmi_frl_max_link_bw_in_kbps > 0) { // DP to HDMI FRL converter |
| 134 | struct dc_crtc_timing outputTiming = *timing; |
| 135 | |
| 136 | if (timing->flags.DSC && !timing->dsc_cfg.is_frl) |
| 137 | /* DP input has DSC, HDMI FRL output doesn't have DSC, remove DSC from output timing */ |
| 138 | outputTiming.flags.DSC = 0; |
| 139 | if (dc_bandwidth_in_kbps_from_timing(timing: &outputTiming, link_encoding: DC_LINK_ENCODING_HDMI_FRL) > |
| 140 | dongle_caps->dp_hdmi_frl_max_link_bw_in_kbps) |
| 141 | return false; |
| 142 | } else { // DP to HDMI TMDS converter |
| 143 | if (get_tmds_output_pixel_clock_100hz(timing) > (dongle_caps->dp_hdmi_max_pixel_clk_in_khz * 10)) |
| 144 | return false; |
| 145 | } |
| 146 | } |
| 147 | |
| 148 | if (dpcd_caps->channel_coding_cap.bits.DP_128b_132b_SUPPORTED == 0 && |
| 149 | dpcd_caps->dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_PASSTHROUGH_SUPPORT == 0 && |
| 150 | dongle_caps->dfp_cap_ext.supported) { |
| 151 | |
| 152 | if (dongle_caps->dfp_cap_ext.max_pixel_rate_in_mps < (timing->pix_clk_100hz / 10000)) |
| 153 | return false; |
| 154 | |
| 155 | if (dongle_caps->dfp_cap_ext.max_video_h_active_width < timing->h_addressable) |
| 156 | return false; |
| 157 | |
| 158 | if (dongle_caps->dfp_cap_ext.max_video_v_active_height < timing->v_addressable) |
| 159 | return false; |
| 160 | |
| 161 | if (timing->pixel_encoding == PIXEL_ENCODING_RGB) { |
| 162 | if (!dongle_caps->dfp_cap_ext.encoding_format_caps.support_rgb) |
| 163 | return false; |
| 164 | if (timing->display_color_depth == COLOR_DEPTH_666 && |
| 165 | !dongle_caps->dfp_cap_ext.rgb_color_depth_caps.support_6bpc) |
| 166 | return false; |
| 167 | else if (timing->display_color_depth == COLOR_DEPTH_888 && |
| 168 | !dongle_caps->dfp_cap_ext.rgb_color_depth_caps.support_8bpc) |
| 169 | return false; |
| 170 | else if (timing->display_color_depth == COLOR_DEPTH_101010 && |
| 171 | !dongle_caps->dfp_cap_ext.rgb_color_depth_caps.support_10bpc) |
| 172 | return false; |
| 173 | else if (timing->display_color_depth == COLOR_DEPTH_121212 && |
| 174 | !dongle_caps->dfp_cap_ext.rgb_color_depth_caps.support_12bpc) |
| 175 | return false; |
| 176 | else if (timing->display_color_depth == COLOR_DEPTH_161616 && |
| 177 | !dongle_caps->dfp_cap_ext.rgb_color_depth_caps.support_16bpc) |
| 178 | return false; |
| 179 | } else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR444) { |
| 180 | if (!dongle_caps->dfp_cap_ext.encoding_format_caps.support_rgb) |
| 181 | return false; |
| 182 | if (timing->display_color_depth == COLOR_DEPTH_888 && |
| 183 | !dongle_caps->dfp_cap_ext.ycbcr444_color_depth_caps.support_8bpc) |
| 184 | return false; |
| 185 | else if (timing->display_color_depth == COLOR_DEPTH_101010 && |
| 186 | !dongle_caps->dfp_cap_ext.ycbcr444_color_depth_caps.support_10bpc) |
| 187 | return false; |
| 188 | else if (timing->display_color_depth == COLOR_DEPTH_121212 && |
| 189 | !dongle_caps->dfp_cap_ext.ycbcr444_color_depth_caps.support_12bpc) |
| 190 | return false; |
| 191 | else if (timing->display_color_depth == COLOR_DEPTH_161616 && |
| 192 | !dongle_caps->dfp_cap_ext.ycbcr444_color_depth_caps.support_16bpc) |
| 193 | return false; |
| 194 | } else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) { |
| 195 | if (!dongle_caps->dfp_cap_ext.encoding_format_caps.support_rgb) |
| 196 | return false; |
| 197 | if (timing->display_color_depth == COLOR_DEPTH_888 && |
| 198 | !dongle_caps->dfp_cap_ext.ycbcr422_color_depth_caps.support_8bpc) |
| 199 | return false; |
| 200 | else if (timing->display_color_depth == COLOR_DEPTH_101010 && |
| 201 | !dongle_caps->dfp_cap_ext.ycbcr422_color_depth_caps.support_10bpc) |
| 202 | return false; |
| 203 | else if (timing->display_color_depth == COLOR_DEPTH_121212 && |
| 204 | !dongle_caps->dfp_cap_ext.ycbcr422_color_depth_caps.support_12bpc) |
| 205 | return false; |
| 206 | else if (timing->display_color_depth == COLOR_DEPTH_161616 && |
| 207 | !dongle_caps->dfp_cap_ext.ycbcr422_color_depth_caps.support_16bpc) |
| 208 | return false; |
| 209 | } else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) { |
| 210 | if (!dongle_caps->dfp_cap_ext.encoding_format_caps.support_rgb) |
| 211 | return false; |
| 212 | if (timing->display_color_depth == COLOR_DEPTH_888 && |
| 213 | !dongle_caps->dfp_cap_ext.ycbcr420_color_depth_caps.support_8bpc) |
| 214 | return false; |
| 215 | else if (timing->display_color_depth == COLOR_DEPTH_101010 && |
| 216 | !dongle_caps->dfp_cap_ext.ycbcr420_color_depth_caps.support_10bpc) |
| 217 | return false; |
| 218 | else if (timing->display_color_depth == COLOR_DEPTH_121212 && |
| 219 | !dongle_caps->dfp_cap_ext.ycbcr420_color_depth_caps.support_12bpc) |
| 220 | return false; |
| 221 | else if (timing->display_color_depth == COLOR_DEPTH_161616 && |
| 222 | !dongle_caps->dfp_cap_ext.ycbcr420_color_depth_caps.support_16bpc) |
| 223 | return false; |
| 224 | } |
| 225 | } |
| 226 | |
| 227 | return true; |
| 228 | } |
| 229 | |
| 230 | uint32_t dp_link_bandwidth_kbps( |
| 231 | const struct dc_link *link, |
| 232 | const struct dc_link_settings *link_settings) |
| 233 | { |
| 234 | uint32_t total_data_bw_efficiency_x10000 = 0; |
| 235 | uint32_t link_rate_per_lane_kbps = 0; |
| 236 | |
| 237 | switch (link_dp_get_encoding_format(link_settings)) { |
| 238 | case DP_8b_10b_ENCODING: |
| 239 | /* For 8b/10b encoding: |
| 240 | * link rate is defined in the unit of LINK_RATE_REF_FREQ_IN_KHZ per DP byte per lane. |
| 241 | * data bandwidth efficiency is 80% with additional 3% overhead if FEC is supported. |
| 242 | */ |
| 243 | link_rate_per_lane_kbps = link_settings->link_rate * LINK_RATE_REF_FREQ_IN_KHZ * BITS_PER_DP_BYTE; |
| 244 | total_data_bw_efficiency_x10000 = DATA_EFFICIENCY_8b_10b_x10000; |
| 245 | if (dp_should_enable_fec(link)) { |
| 246 | total_data_bw_efficiency_x10000 /= 100; |
| 247 | total_data_bw_efficiency_x10000 *= DATA_EFFICIENCY_8b_10b_FEC_EFFICIENCY_x100; |
| 248 | } |
| 249 | break; |
| 250 | case DP_128b_132b_ENCODING: |
| 251 | /* For 128b/132b encoding: |
| 252 | * link rate is defined in the unit of 10mbps per lane. |
| 253 | * total data bandwidth efficiency is always 96.71%. |
| 254 | */ |
| 255 | link_rate_per_lane_kbps = link_settings->link_rate * 10000; |
| 256 | total_data_bw_efficiency_x10000 = DATA_EFFICIENCY_128b_132b_x10000; |
| 257 | break; |
| 258 | default: |
| 259 | break; |
| 260 | } |
| 261 | |
| 262 | /* overall effective link bandwidth = link rate per lane * lane count * total data bandwidth efficiency */ |
| 263 | return link_rate_per_lane_kbps * link_settings->lane_count / 10000 * total_data_bw_efficiency_x10000; |
| 264 | } |
| 265 | |
| 266 | static uint32_t dp_get_timing_bandwidth_kbps( |
| 267 | const struct dc_crtc_timing *timing, |
| 268 | const struct dc_link *link) |
| 269 | { |
| 270 | return dc_bandwidth_in_kbps_from_timing(timing, |
| 271 | link_encoding: dc_link_get_highest_encoding_format(link)); |
| 272 | } |
| 273 | |
| 274 | static bool dp_validate_mode_timing( |
| 275 | struct dc_link *link, |
| 276 | const struct dc_crtc_timing *timing) |
| 277 | { |
| 278 | uint32_t req_bw; |
| 279 | uint32_t max_bw; |
| 280 | |
| 281 | const struct dc_link_settings *link_setting; |
| 282 | |
| 283 | /* According to spec, VSC SDP should be used if pixel format is YCbCr420 */ |
| 284 | if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420 && |
| 285 | !link->dpcd_caps.dprx_feature.bits.VSC_SDP_COLORIMETRY_SUPPORTED && |
| 286 | dal_graphics_object_id_get_connector_id(id: link->link_id) != CONNECTOR_ID_VIRTUAL) |
| 287 | return false; |
| 288 | |
| 289 | /*always DP fail safe mode*/ |
| 290 | if ((timing->pix_clk_100hz / 10) == (uint32_t) 25175 && |
| 291 | timing->h_addressable == (uint32_t) 640 && |
| 292 | timing->v_addressable == (uint32_t) 480) |
| 293 | return true; |
| 294 | |
| 295 | link_setting = dp_get_verified_link_cap(link); |
| 296 | |
| 297 | /* TODO: DYNAMIC_VALIDATION needs to be implemented */ |
| 298 | /*if (flags.DYNAMIC_VALIDATION == 1 && |
| 299 | link->verified_link_cap.lane_count != LANE_COUNT_UNKNOWN) |
| 300 | link_setting = &link->verified_link_cap; |
| 301 | */ |
| 302 | |
| 303 | req_bw = dc_bandwidth_in_kbps_from_timing(timing, link_encoding: dc_link_get_highest_encoding_format(link)); |
| 304 | max_bw = dp_link_bandwidth_kbps(link, link_settings: link_setting); |
| 305 | |
| 306 | bool is_max_uncompressed_pixel_rate_exceeded = link->dpcd_caps.max_uncompressed_pixel_rate_cap.bits.valid && |
| 307 | timing->pix_clk_100hz > link->dpcd_caps.max_uncompressed_pixel_rate_cap.bits.max_uncompressed_pixel_rate_cap * 10000; |
| 308 | |
| 309 | if (is_max_uncompressed_pixel_rate_exceeded && !timing->flags.DSC) { |
| 310 | return false; |
| 311 | } |
| 312 | |
| 313 | if (req_bw <= max_bw) { |
| 314 | /* remember the biggest mode here, during |
| 315 | * initial link training (to get |
| 316 | * verified_link_cap), LS sends event about |
| 317 | * cannot train at reported cap to upper |
| 318 | * layer and upper layer will re-enumerate modes. |
| 319 | * this is not necessary if the lower |
| 320 | * verified_link_cap is enough to drive |
| 321 | * all the modes */ |
| 322 | |
| 323 | /* TODO: DYNAMIC_VALIDATION needs to be implemented */ |
| 324 | /* if (flags.DYNAMIC_VALIDATION == 1) |
| 325 | dpsst->max_req_bw_for_verified_linkcap = dal_max( |
| 326 | dpsst->max_req_bw_for_verified_linkcap, req_bw); */ |
| 327 | return true; |
| 328 | } else |
| 329 | return false; |
| 330 | } |
| 331 | |
| 332 | enum dc_status link_validate_mode_timing( |
| 333 | const struct dc_stream_state *stream, |
| 334 | struct dc_link *link, |
| 335 | const struct dc_crtc_timing *timing) |
| 336 | { |
| 337 | uint32_t max_pix_clk = stream->link->dongle_max_pix_clk * 10; |
| 338 | struct dpcd_caps *dpcd_caps = &link->dpcd_caps; |
| 339 | |
| 340 | /* A hack to avoid failing any modes for EDID override feature on |
| 341 | * topology change such as lower quality cable for DP or different dongle |
| 342 | */ |
| 343 | if (link->remote_sinks[0] && link->remote_sinks[0]->sink_signal == SIGNAL_TYPE_VIRTUAL) |
| 344 | return DC_OK; |
| 345 | |
| 346 | /* Passive Dongle */ |
| 347 | if (max_pix_clk != 0 && get_tmds_output_pixel_clock_100hz(timing) > max_pix_clk) |
| 348 | return DC_EXCEED_DONGLE_CAP; |
| 349 | |
| 350 | /* Active Dongle*/ |
| 351 | if (!dp_active_dongle_validate_timing(timing, dpcd_caps)) |
| 352 | return DC_EXCEED_DONGLE_CAP; |
| 353 | |
| 354 | switch (stream->signal) { |
| 355 | case SIGNAL_TYPE_EDP: |
| 356 | case SIGNAL_TYPE_DISPLAY_PORT: |
| 357 | if (!dp_validate_mode_timing( |
| 358 | link, |
| 359 | timing)) |
| 360 | return DC_NO_DP_LINK_BANDWIDTH; |
| 361 | break; |
| 362 | |
| 363 | default: |
| 364 | break; |
| 365 | } |
| 366 | |
| 367 | return DC_OK; |
| 368 | } |
| 369 | |
| 370 | static const struct dc_tunnel_settings *get_dp_tunnel_settings(const struct dc_state *context, |
| 371 | const struct dc_stream_state *stream) |
| 372 | { |
| 373 | int i; |
| 374 | const struct dc_tunnel_settings *dp_tunnel_settings = NULL; |
| 375 | |
| 376 | for (i = 0; i < MAX_PIPES; i++) { |
| 377 | if (context->res_ctx.pipe_ctx[i].stream && (context->res_ctx.pipe_ctx[i].stream == stream)) { |
| 378 | dp_tunnel_settings = &context->res_ctx.pipe_ctx[i].link_config.dp_tunnel_settings; |
| 379 | break; |
| 380 | } |
| 381 | } |
| 382 | |
| 383 | return dp_tunnel_settings; |
| 384 | } |
| 385 | |
| 386 | /* |
| 387 | * Calculates the DP tunneling bandwidth required for the stream timing |
| 388 | * and aggregates the stream bandwidth for the respective DP tunneling link |
| 389 | * |
| 390 | * return: dc_status |
| 391 | */ |
| 392 | enum dc_status link_validate_dp_tunnel_bandwidth(const struct dc *dc, const struct dc_state *new_ctx) |
| 393 | { |
| 394 | struct dc_validation_dpia_set dpia_link_sets[MAX_DPIA_NUM] = { 0 }; |
| 395 | uint8_t link_count = 0; |
| 396 | enum dc_status result = DC_OK; |
| 397 | |
| 398 | // Iterate through streams in the new context |
| 399 | for (uint8_t i = 0; (i < MAX_PIPES && i < new_ctx->stream_count); i++) { |
| 400 | const struct dc_stream_state *stream = new_ctx->streams[i]; |
| 401 | const struct dc_link *link; |
| 402 | const struct dc_tunnel_settings *dp_tunnel_settings; |
| 403 | uint32_t timing_bw; |
| 404 | |
| 405 | if (stream == NULL) |
| 406 | continue; |
| 407 | |
| 408 | link = stream->link; |
| 409 | |
| 410 | if (!(link && (stream->signal == SIGNAL_TYPE_DISPLAY_PORT |
| 411 | || stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST))) |
| 412 | continue; |
| 413 | |
| 414 | if ((link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) && (link->hpd_status == false)) |
| 415 | continue; |
| 416 | |
| 417 | dp_tunnel_settings = get_dp_tunnel_settings(context: new_ctx, stream); |
| 418 | |
| 419 | if ((dp_tunnel_settings == NULL) || (dp_tunnel_settings->should_use_dp_bw_allocation == false)) |
| 420 | continue; |
| 421 | |
| 422 | timing_bw = dp_get_timing_bandwidth_kbps(timing: &stream->timing, link); |
| 423 | |
| 424 | // Find an existing entry for this 'link' in 'dpia_link_sets' |
| 425 | for (uint8_t j = 0; j < MAX_DPIA_NUM; j++) { |
| 426 | bool is_new_slot = false; |
| 427 | |
| 428 | if (dpia_link_sets[j].link == NULL) { |
| 429 | is_new_slot = true; |
| 430 | link_count++; |
| 431 | dpia_link_sets[j].required_bw = 0; |
| 432 | dpia_link_sets[j].link = link; |
| 433 | } |
| 434 | |
| 435 | if (is_new_slot || (dpia_link_sets[j].link == link)) { |
| 436 | dpia_link_sets[j].tunnel_settings = dp_tunnel_settings; |
| 437 | dpia_link_sets[j].required_bw += timing_bw; |
| 438 | break; |
| 439 | } |
| 440 | } |
| 441 | } |
| 442 | |
| 443 | if (link_count && link_dpia_validate_dp_tunnel_bandwidth(dpia_link_sets, count: link_count) == false) |
| 444 | result = DC_FAIL_DP_TUNNEL_BW_VALIDATE; |
| 445 | |
| 446 | return result; |
| 447 | } |
| 448 | |
| 449 | struct dp_audio_layout_config { |
| 450 | uint8_t layouts_per_sample_denom; |
| 451 | uint8_t symbols_per_layout; |
| 452 | uint8_t max_layouts_per_audio_sdp; |
| 453 | }; |
| 454 | |
| 455 | static void get_audio_layout_config( |
| 456 | uint32_t channel_count, |
| 457 | enum dp_link_encoding encoding, |
| 458 | struct dp_audio_layout_config *output) |
| 459 | { |
| 460 | memset(output, 0, sizeof(struct dp_audio_layout_config)); |
| 461 | |
| 462 | /* Assuming L-PCM audio. Current implementation uses max 1 layout per SDP, |
| 463 | * with each layout being the same size (8ch layout). |
| 464 | */ |
| 465 | if (encoding == DP_8b_10b_ENCODING) { |
| 466 | if (channel_count == 2) { |
| 467 | output->layouts_per_sample_denom = 4; |
| 468 | output->symbols_per_layout = 40; |
| 469 | output->max_layouts_per_audio_sdp = 1; |
| 470 | } else if (channel_count == 8 || channel_count == 6) { |
| 471 | output->layouts_per_sample_denom = 1; |
| 472 | output->symbols_per_layout = 40; |
| 473 | output->max_layouts_per_audio_sdp = 1; |
| 474 | } |
| 475 | } else if (encoding == DP_128b_132b_ENCODING) { |
| 476 | if (channel_count == 2) { |
| 477 | output->layouts_per_sample_denom = 4; |
| 478 | output->symbols_per_layout = 10; |
| 479 | output->max_layouts_per_audio_sdp = 1; |
| 480 | } else if (channel_count == 8 || channel_count == 6) { |
| 481 | output->layouts_per_sample_denom = 1; |
| 482 | output->symbols_per_layout = 10; |
| 483 | output->max_layouts_per_audio_sdp = 1; |
| 484 | } |
| 485 | } |
| 486 | } |
| 487 | |
| 488 | static uint32_t get_av_stream_map_lane_count( |
| 489 | enum dp_link_encoding encoding, |
| 490 | enum dc_lane_count lane_count, |
| 491 | bool is_mst) |
| 492 | { |
| 493 | uint32_t av_stream_map_lane_count = 0; |
| 494 | |
| 495 | if (encoding == DP_8b_10b_ENCODING) { |
| 496 | if (!is_mst) |
| 497 | av_stream_map_lane_count = lane_count; |
| 498 | else |
| 499 | av_stream_map_lane_count = 4; |
| 500 | } else if (encoding == DP_128b_132b_ENCODING) { |
| 501 | av_stream_map_lane_count = 4; |
| 502 | } |
| 503 | |
| 504 | ASSERT(av_stream_map_lane_count != 0); |
| 505 | |
| 506 | return av_stream_map_lane_count; |
| 507 | } |
| 508 | |
| 509 | static uint32_t get_audio_sdp_overhead( |
| 510 | enum dp_link_encoding encoding, |
| 511 | enum dc_lane_count lane_count, |
| 512 | bool is_mst) |
| 513 | { |
| 514 | uint32_t audio_sdp_overhead = 0; |
| 515 | |
| 516 | if (encoding == DP_8b_10b_ENCODING) { |
| 517 | if (is_mst) |
| 518 | audio_sdp_overhead = 16; /* 4 * 2 + 8 */ |
| 519 | else |
| 520 | audio_sdp_overhead = lane_count * 2 + 8; |
| 521 | } else if (encoding == DP_128b_132b_ENCODING) { |
| 522 | audio_sdp_overhead = 10; /* 4 x 2.5 */ |
| 523 | } |
| 524 | |
| 525 | ASSERT(audio_sdp_overhead != 0); |
| 526 | |
| 527 | return audio_sdp_overhead; |
| 528 | } |
| 529 | |
| 530 | /* Current calculation only applicable for 8b/10b MST and 128b/132b SST/MST. |
| 531 | */ |
| 532 | static uint32_t calculate_overhead_hblank_bw_in_symbols( |
| 533 | uint32_t max_slice_h) |
| 534 | { |
| 535 | uint32_t overhead_hblank_bw = 0; /* in stream symbols */ |
| 536 | |
| 537 | overhead_hblank_bw += max_slice_h * 4; /* EOC overhead */ |
| 538 | overhead_hblank_bw += 12; /* Main link overhead (VBID, BS/BE) */ |
| 539 | |
| 540 | return overhead_hblank_bw; |
| 541 | } |
| 542 | |
| 543 | uint32_t dp_required_hblank_size_bytes( |
| 544 | const struct dc_link *link, |
| 545 | struct dp_audio_bandwidth_params *audio_params) |
| 546 | { |
| 547 | /* Main logic from dce_audio is duplicated here, with the main |
| 548 | * difference being: |
| 549 | * - Pre-determined lane count of 4 |
| 550 | * - Assumed 16 dsc slices for worst case |
| 551 | * - Assumed SDP split disabled for worst case |
| 552 | * TODO: Unify logic from dce_audio to prevent duplicated logic. |
| 553 | */ |
| 554 | |
| 555 | const struct dc_crtc_timing *timing = audio_params->crtc_timing; |
| 556 | const uint32_t channel_count = audio_params->channel_count; |
| 557 | const uint32_t sample_rate_hz = audio_params->sample_rate_hz; |
| 558 | const enum dp_link_encoding link_encoding = audio_params->link_encoding; |
| 559 | |
| 560 | // 8b/10b MST and 128b/132b are always 4 logical lanes. |
| 561 | const uint32_t lane_count = 4; |
| 562 | const bool is_mst = (link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT); |
| 563 | // Maximum slice count is with ODM 4:1, 4 slices per DSC |
| 564 | const uint32_t max_slices_h = 16; |
| 565 | |
| 566 | const uint32_t av_stream_map_lane_count = get_av_stream_map_lane_count( |
| 567 | encoding: link_encoding, lane_count, is_mst); |
| 568 | const uint32_t audio_sdp_overhead = get_audio_sdp_overhead( |
| 569 | encoding: link_encoding, lane_count, is_mst); |
| 570 | struct dp_audio_layout_config layout_config; |
| 571 | |
| 572 | if (link_encoding == DP_8b_10b_ENCODING && link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT) |
| 573 | return 0; |
| 574 | |
| 575 | get_audio_layout_config( |
| 576 | channel_count, encoding: link_encoding, output: &layout_config); |
| 577 | |
| 578 | /* DP spec recommends between 1.05 to 1.1 safety margin to prevent sample under-run */ |
| 579 | struct fixed31_32 audio_sdp_margin = dc_fixpt_from_fraction(numerator: 110, denominator: 100); |
| 580 | struct fixed31_32 horizontal_line_freq_khz = dc_fixpt_from_fraction( |
| 581 | numerator: timing->pix_clk_100hz, denominator: (long long)timing->h_total * 10); |
| 582 | struct fixed31_32 samples_per_line; |
| 583 | struct fixed31_32 layouts_per_line; |
| 584 | struct fixed31_32 symbols_per_sdp_max_layout; |
| 585 | struct fixed31_32 remainder; |
| 586 | uint32_t num_sdp_with_max_layouts; |
| 587 | uint32_t required_symbols_per_hblank; |
| 588 | uint32_t required_bytes_per_hblank = 0; |
| 589 | |
| 590 | samples_per_line = dc_fixpt_from_fraction(numerator: sample_rate_hz, denominator: 1000); |
| 591 | samples_per_line = dc_fixpt_div(arg1: samples_per_line, arg2: horizontal_line_freq_khz); |
| 592 | layouts_per_line = dc_fixpt_div_int(arg1: samples_per_line, arg2: layout_config.layouts_per_sample_denom); |
| 593 | // HBlank expansion usage assumes SDP split disabled to allow for worst case. |
| 594 | layouts_per_line = dc_fixpt_from_int(arg: dc_fixpt_ceil(arg: layouts_per_line)); |
| 595 | |
| 596 | num_sdp_with_max_layouts = dc_fixpt_floor( |
| 597 | arg: dc_fixpt_div_int(arg1: layouts_per_line, arg2: layout_config.max_layouts_per_audio_sdp)); |
| 598 | symbols_per_sdp_max_layout = dc_fixpt_from_int( |
| 599 | arg: layout_config.max_layouts_per_audio_sdp * layout_config.symbols_per_layout); |
| 600 | symbols_per_sdp_max_layout = dc_fixpt_add_int(arg1: symbols_per_sdp_max_layout, arg2: audio_sdp_overhead); |
| 601 | symbols_per_sdp_max_layout = dc_fixpt_mul(arg1: symbols_per_sdp_max_layout, arg2: audio_sdp_margin); |
| 602 | required_symbols_per_hblank = num_sdp_with_max_layouts; |
| 603 | required_symbols_per_hblank *= ((dc_fixpt_ceil(arg: symbols_per_sdp_max_layout) + av_stream_map_lane_count) / |
| 604 | av_stream_map_lane_count) * av_stream_map_lane_count; |
| 605 | |
| 606 | if (num_sdp_with_max_layouts != dc_fixpt_ceil( |
| 607 | arg: dc_fixpt_div_int(arg1: layouts_per_line, arg2: layout_config.max_layouts_per_audio_sdp))) { |
| 608 | remainder = dc_fixpt_sub_int(arg1: layouts_per_line, |
| 609 | arg2: num_sdp_with_max_layouts * layout_config.max_layouts_per_audio_sdp); |
| 610 | remainder = dc_fixpt_mul_int(arg1: remainder, arg2: layout_config.symbols_per_layout); |
| 611 | remainder = dc_fixpt_add_int(arg1: remainder, arg2: audio_sdp_overhead); |
| 612 | remainder = dc_fixpt_mul(arg1: remainder, arg2: audio_sdp_margin); |
| 613 | required_symbols_per_hblank += ((dc_fixpt_ceil(arg: remainder) + av_stream_map_lane_count) / |
| 614 | av_stream_map_lane_count) * av_stream_map_lane_count; |
| 615 | } |
| 616 | |
| 617 | required_symbols_per_hblank += calculate_overhead_hblank_bw_in_symbols(max_slice_h: max_slices_h); |
| 618 | |
| 619 | if (link_encoding == DP_8b_10b_ENCODING) |
| 620 | required_bytes_per_hblank = required_symbols_per_hblank; // 8 bits per 8b/10b symbol |
| 621 | else if (link_encoding == DP_128b_132b_ENCODING) |
| 622 | required_bytes_per_hblank = required_symbols_per_hblank * 4; // 32 bits per 128b/132b symbol |
| 623 | |
| 624 | return required_bytes_per_hblank; |
| 625 | } |
| 626 | |
| 627 | |