Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/amdgpu: fix dp link rate selection (v2)

Need to properly handle the max link rate in the dpcd.
This prevents some cases where 5.4 Ghz is selected when
it shouldn't be.

v2: simplify logic, add array bounds check

Reviewed-by: Tom St Denis <tom.stdenis@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

+35 -59
+35 -59
drivers/gpu/drm/amd/amdgpu/atombios_dp.c
··· 243 243 244 244 /* convert bits per color to bits per pixel */ 245 245 /* get bpc from the EDID */ 246 - static int amdgpu_atombios_dp_convert_bpc_to_bpp(int bpc) 246 + static unsigned amdgpu_atombios_dp_convert_bpc_to_bpp(int bpc) 247 247 { 248 248 if (bpc == 0) 249 249 return 24; ··· 251 251 return bpc * 3; 252 252 } 253 253 254 - /* get the max pix clock supported by the link rate and lane num */ 255 - static int amdgpu_atombios_dp_get_max_dp_pix_clock(int link_rate, 256 - int lane_num, 257 - int bpp) 258 - { 259 - return (link_rate * lane_num * 8) / bpp; 260 - } 261 - 262 254 /***** amdgpu specific DP functions *****/ 263 255 264 - /* First get the min lane# when low rate is used according to pixel clock 265 - * (prefer low rate), second check max lane# supported by DP panel, 266 - * if the max lane# < low rate lane# then use max lane# instead. 267 - */ 268 - static int amdgpu_atombios_dp_get_dp_lane_number(struct drm_connector *connector, 256 + static int amdgpu_atombios_dp_get_dp_link_config(struct drm_connector *connector, 269 257 const u8 dpcd[DP_DPCD_SIZE], 270 - int pix_clock) 258 + unsigned pix_clock, 259 + unsigned *dp_lanes, unsigned *dp_rate) 271 260 { 272 - int bpp = amdgpu_atombios_dp_convert_bpc_to_bpp(amdgpu_connector_get_monitor_bpc(connector)); 273 - int max_link_rate = drm_dp_max_link_rate(dpcd); 274 - int max_lane_num = drm_dp_max_lane_count(dpcd); 275 - int lane_num; 276 - int max_dp_pix_clock; 261 + unsigned bpp = 262 + amdgpu_atombios_dp_convert_bpc_to_bpp(amdgpu_connector_get_monitor_bpc(connector)); 263 + static const unsigned link_rates[3] = { 162000, 270000, 540000 }; 264 + unsigned max_link_rate = drm_dp_max_link_rate(dpcd); 265 + unsigned max_lane_num = drm_dp_max_lane_count(dpcd); 266 + unsigned lane_num, i, max_pix_clock; 277 267 278 - for (lane_num = 1; lane_num < max_lane_num; lane_num <<= 1) { 279 - max_dp_pix_clock = amdgpu_atombios_dp_get_max_dp_pix_clock(max_link_rate, lane_num, bpp); 280 - if (pix_clock <= max_dp_pix_clock) 281 - break; 268 + for (lane_num = 1; lane_num <= max_lane_num; lane_num <<= 1) { 269 + for (i = 0; i < ARRAY_SIZE(link_rates) && link_rates[i] <= max_link_rate; i++) { 270 + max_pix_clock = (lane_num * link_rates[i] * 8) / bpp; 271 + if (max_pix_clock >= pix_clock) { 272 + *dp_lanes = lane_num; 273 + *dp_rate = link_rates[i]; 274 + return 0; 275 + } 276 + } 282 277 } 283 278 284 - return lane_num; 285 - } 286 - 287 - static int amdgpu_atombios_dp_get_dp_link_clock(struct drm_connector *connector, 288 - const u8 dpcd[DP_DPCD_SIZE], 289 - int pix_clock) 290 - { 291 - int bpp = amdgpu_atombios_dp_convert_bpc_to_bpp(amdgpu_connector_get_monitor_bpc(connector)); 292 - int lane_num, max_pix_clock; 293 - 294 - if (amdgpu_connector_encoder_get_dp_bridge_encoder_id(connector) == 295 - ENCODER_OBJECT_ID_NUTMEG) 296 - return 270000; 297 - 298 - lane_num = amdgpu_atombios_dp_get_dp_lane_number(connector, dpcd, pix_clock); 299 - max_pix_clock = amdgpu_atombios_dp_get_max_dp_pix_clock(162000, lane_num, bpp); 300 - if (pix_clock <= max_pix_clock) 301 - return 162000; 302 - max_pix_clock = amdgpu_atombios_dp_get_max_dp_pix_clock(270000, lane_num, bpp); 303 - if (pix_clock <= max_pix_clock) 304 - return 270000; 305 - if (amdgpu_connector_is_dp12_capable(connector)) { 306 - max_pix_clock = amdgpu_atombios_dp_get_max_dp_pix_clock(540000, lane_num, bpp); 307 - if (pix_clock <= max_pix_clock) 308 - return 540000; 309 - } 310 - 311 - return drm_dp_max_link_rate(dpcd); 279 + return -EINVAL; 312 280 } 313 281 314 282 static u8 amdgpu_atombios_dp_encoder_service(struct amdgpu_device *adev, ··· 390 422 { 391 423 struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); 392 424 struct amdgpu_connector_atom_dig *dig_connector; 425 + int ret; 393 426 394 427 if (!amdgpu_connector->con_priv) 395 428 return; ··· 398 429 399 430 if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) || 400 431 (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) { 401 - dig_connector->dp_clock = 402 - amdgpu_atombios_dp_get_dp_link_clock(connector, dig_connector->dpcd, mode->clock); 403 - dig_connector->dp_lane_count = 404 - amdgpu_atombios_dp_get_dp_lane_number(connector, dig_connector->dpcd, mode->clock); 432 + ret = amdgpu_atombios_dp_get_dp_link_config(connector, dig_connector->dpcd, 433 + mode->clock, 434 + &dig_connector->dp_lane_count, 435 + &dig_connector->dp_clock); 436 + if (ret) { 437 + dig_connector->dp_clock = 0; 438 + dig_connector->dp_lane_count = 0; 439 + } 405 440 } 406 441 } 407 442 ··· 414 441 { 415 442 struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); 416 443 struct amdgpu_connector_atom_dig *dig_connector; 417 - int dp_clock; 444 + unsigned dp_lanes, dp_clock; 445 + int ret; 418 446 419 447 if (!amdgpu_connector->con_priv) 420 448 return MODE_CLOCK_HIGH; 421 449 dig_connector = amdgpu_connector->con_priv; 422 450 423 - dp_clock = 424 - amdgpu_atombios_dp_get_dp_link_clock(connector, dig_connector->dpcd, mode->clock); 451 + ret = amdgpu_atombios_dp_get_dp_link_config(connector, dig_connector->dpcd, 452 + mode->clock, &dp_lanes, &dp_clock); 453 + if (ret) 454 + return MODE_CLOCK_HIGH; 425 455 426 456 if ((dp_clock == 540000) && 427 457 (!amdgpu_connector_is_dp12_capable(connector)))