1 /* 2 * Copyright 2019 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 #include "dm_services.h" 27 #include "dc.h" 28 #include "dc_dmub_srv.h" 29 #include "../dmub/dmub_srv.h" 30 #include "dm_helpers.h" 31 #include "dc_hw_types.h" 32 #include "core_types.h" 33 #include "../basics/conversion.h" 34 #include "cursor_reg_cache.h" 35 #include "resource.h" 36 #include "clk_mgr.h" 37 #include "dc_state_priv.h" 38 #include "dc_plane_priv.h" 39 40 #define CTX dc_dmub_srv->ctx 41 #define DC_LOGGER CTX->logger 42 #define GPINT_RETRY_NUM 20 43 44 #define MAX_WAIT_US 100000 45 46 static void dc_dmub_srv_construct(struct dc_dmub_srv *dc_srv, struct dc *dc, 47 struct dmub_srv *dmub) 48 { 49 dc_srv->dmub = dmub; 50 dc_srv->ctx = dc->ctx; 51 } 52 53 static void dc_dmub_srv_handle_failure(struct dc_dmub_srv *dc_dmub_srv) 54 { 55 dc_dmub_srv_log_diagnostic_data(dc_dmub_srv); 56 if (dc_dmub_srv->ctx->dc->debug.enable_dmu_recovery) 57 dm_helpers_dmu_timeout(dc_dmub_srv->ctx); 58 } 59 60 struct dc_dmub_srv *dc_dmub_srv_create(struct dc *dc, struct dmub_srv *dmub) 61 { 62 struct dc_dmub_srv *dc_srv = 63 kzalloc_obj(struct dc_dmub_srv); 64 65 if (dc_srv == NULL) { 66 BREAK_TO_DEBUGGER(); 67 return NULL; 68 } 69 70 dc_dmub_srv_construct(dc_srv, dc, dmub); 71 72 return dc_srv; 73 } 74 75 void dc_dmub_srv_destroy(struct dc_dmub_srv **dmub_srv) 76 { 77 if (*dmub_srv) { 78 kfree(*dmub_srv); 79 *dmub_srv = NULL; 80 } 81 } 82 83 bool dc_dmub_srv_wait_for_pending(struct dc_dmub_srv *dc_dmub_srv) 84 { 85 struct dmub_srv *dmub; 86 struct dc_context *dc_ctx; 87 enum dmub_status status; 88 89 if (!dc_dmub_srv || !dc_dmub_srv->dmub) 90 return false; 91 92 dc_ctx = dc_dmub_srv->ctx; 93 dmub = dc_dmub_srv->dmub; 94 95 do { 96 status = dmub_srv_wait_for_pending(dmub, MAX_WAIT_US); 97 } while (dc_dmub_srv->ctx->dc->debug.disable_timeout && status != DMUB_STATUS_OK); 98 99 if (status != DMUB_STATUS_OK) { 100 DC_ERROR("Error waiting for DMUB idle: status=%d\n", status); 101 dc_dmub_srv_handle_failure(dc_dmub_srv); 102 } 103 104 return status == DMUB_STATUS_OK; 105 } 106 107 void dc_dmub_srv_clear_inbox0_ack(struct dc_dmub_srv *dc_dmub_srv) 108 { 109 struct dmub_srv *dmub = dc_dmub_srv->dmub; 110 struct dc_context *dc_ctx = dc_dmub_srv->ctx; 111 enum dmub_status status = DMUB_STATUS_OK; 112 113 status = dmub_srv_clear_inbox0_ack(dmub); 114 if (status != DMUB_STATUS_OK) { 115 DC_ERROR("Error clearing INBOX0 ack: status=%d\n", status); 116 dc_dmub_srv_handle_failure(dc_dmub_srv); 117 } 118 } 119 120 void dc_dmub_srv_wait_for_inbox0_ack(struct dc_dmub_srv *dc_dmub_srv) 121 { 122 struct dmub_srv *dmub = dc_dmub_srv->dmub; 123 struct dc_context *dc_ctx = dc_dmub_srv->ctx; 124 enum dmub_status status = DMUB_STATUS_OK; 125 126 status = dmub_srv_wait_for_inbox0_ack(dmub, MAX_WAIT_US); 127 if (status != DMUB_STATUS_OK) { 128 DC_ERROR("Error waiting for INBOX0 HW Lock Ack\n"); 129 dc_dmub_srv_handle_failure(dc_dmub_srv); 130 } 131 } 132 133 void dc_dmub_srv_send_inbox0_cmd(struct dc_dmub_srv *dc_dmub_srv, 134 union dmub_inbox0_data_register data) 135 { 136 struct dmub_srv *dmub = dc_dmub_srv->dmub; 137 struct dc_context *dc_ctx = dc_dmub_srv->ctx; 138 enum dmub_status status = DMUB_STATUS_OK; 139 140 status = dmub_srv_send_inbox0_cmd(dmub, data); 141 if (status != DMUB_STATUS_OK) { 142 DC_ERROR("Error sending INBOX0 cmd\n"); 143 dc_dmub_srv_handle_failure(dc_dmub_srv); 144 } 145 } 146 147 static bool dc_dmub_srv_reg_cmd_list_queue_execute(struct dc_dmub_srv *dc_dmub_srv, 148 unsigned int count, 149 union dmub_rb_cmd *cmd_list) 150 { 151 struct dc_context *dc_ctx; 152 struct dmub_srv *dmub; 153 enum dmub_status status = DMUB_STATUS_OK; 154 unsigned int i; 155 156 if (!dc_dmub_srv || !dc_dmub_srv->dmub) 157 return false; 158 159 dc_ctx = dc_dmub_srv->ctx; 160 dmub = dc_dmub_srv->dmub; 161 162 for (i = 0 ; i < count; i++) { 163 /* confirm no messages pending */ 164 do { 165 status = dmub_srv_wait_for_idle(dmub, MAX_WAIT_US); 166 } while (dc_dmub_srv->ctx->dc->debug.disable_timeout && status != DMUB_STATUS_OK); 167 168 /* queue command */ 169 if (status == DMUB_STATUS_OK) 170 status = dmub_srv_reg_cmd_execute(dmub, &cmd_list[i]); 171 172 /* check for errors */ 173 if (status != DMUB_STATUS_OK) { 174 break; 175 } 176 } 177 178 if (status != DMUB_STATUS_OK) { 179 if (status != DMUB_STATUS_POWER_STATE_D3) { 180 DC_ERROR("Error starting DMUB execution: status=%d\n", status); 181 dc_dmub_srv_handle_failure(dc_dmub_srv); 182 } 183 return false; 184 } 185 186 return true; 187 } 188 189 static bool dc_dmub_srv_fb_cmd_list_queue_execute(struct dc_dmub_srv *dc_dmub_srv, 190 unsigned int count, 191 union dmub_rb_cmd *cmd_list) 192 { 193 struct dc_context *dc_ctx; 194 struct dmub_srv *dmub; 195 enum dmub_status status; 196 unsigned int i; 197 198 if (!dc_dmub_srv || !dc_dmub_srv->dmub) 199 return false; 200 201 dc_ctx = dc_dmub_srv->ctx; 202 dmub = dc_dmub_srv->dmub; 203 204 for (i = 0 ; i < count; i++) { 205 // Queue command 206 if (!cmd_list[i].cmd_common.header.multi_cmd_pending || 207 dmub_rb_num_free(&dmub->inbox1.rb) >= count - i) { 208 status = dmub_srv_fb_cmd_queue(dmub, &cmd_list[i]); 209 } else { 210 status = DMUB_STATUS_QUEUE_FULL; 211 } 212 213 if (status == DMUB_STATUS_QUEUE_FULL) { 214 /* Execute and wait for queue to become empty again. */ 215 status = dmub_srv_fb_cmd_execute(dmub); 216 if (status == DMUB_STATUS_POWER_STATE_D3) 217 return false; 218 219 do { 220 status = dmub_srv_wait_for_inbox_free(dmub, MAX_WAIT_US, count - i); 221 } while (dc_dmub_srv->ctx->dc->debug.disable_timeout && status != DMUB_STATUS_OK); 222 223 /* Requeue the command. */ 224 status = dmub_srv_fb_cmd_queue(dmub, &cmd_list[i]); 225 } 226 227 if (status != DMUB_STATUS_OK) { 228 if (status != DMUB_STATUS_POWER_STATE_D3) { 229 DC_ERROR("Error queueing DMUB command: status=%d\n", status); 230 dc_dmub_srv_handle_failure(dc_dmub_srv); 231 } 232 return false; 233 } 234 } 235 236 status = dmub_srv_fb_cmd_execute(dmub); 237 if (status != DMUB_STATUS_OK) { 238 if (status != DMUB_STATUS_POWER_STATE_D3) { 239 DC_ERROR("Error starting DMUB execution: status=%d\n", status); 240 dc_dmub_srv_handle_failure(dc_dmub_srv); 241 } 242 return false; 243 } 244 245 return true; 246 } 247 248 bool dc_dmub_srv_cmd_list_queue_execute(struct dc_dmub_srv *dc_dmub_srv, 249 unsigned int count, 250 union dmub_rb_cmd *cmd_list) 251 { 252 bool res = false; 253 254 if (dc_dmub_srv && dc_dmub_srv->dmub) { 255 if (dc_dmub_srv->dmub->inbox_type == DMUB_CMD_INTERFACE_REG) { 256 res = dc_dmub_srv_reg_cmd_list_queue_execute(dc_dmub_srv, count, cmd_list); 257 } else { 258 res = dc_dmub_srv_fb_cmd_list_queue_execute(dc_dmub_srv, count, cmd_list); 259 } 260 261 if (res) 262 res = dmub_srv_update_inbox_status(dc_dmub_srv->dmub) == DMUB_STATUS_OK; 263 } 264 265 return res; 266 } 267 268 bool dc_dmub_srv_wait_for_idle(struct dc_dmub_srv *dc_dmub_srv, 269 enum dm_dmub_wait_type wait_type, 270 union dmub_rb_cmd *cmd_list) 271 { 272 struct dmub_srv *dmub; 273 enum dmub_status status; 274 275 if (!dc_dmub_srv || !dc_dmub_srv->dmub) 276 return false; 277 278 dmub = dc_dmub_srv->dmub; 279 280 // Wait for DMUB to process command 281 if (wait_type != DM_DMUB_WAIT_TYPE_NO_WAIT) { 282 do { 283 status = dmub_srv_wait_for_idle(dmub, MAX_WAIT_US); 284 } while (dc_dmub_srv->ctx->dc->debug.disable_timeout && status != DMUB_STATUS_OK); 285 286 if (status != DMUB_STATUS_OK) { 287 DC_LOG_DEBUG("No reply for DMUB command: status=%d\n", status); 288 if (!dmub->debug.timeout_info.timeout_occured) { 289 dmub->debug.timeout_info.timeout_occured = true; 290 if (cmd_list) 291 dmub->debug.timeout_info.timeout_cmd = *cmd_list; 292 dmub->debug.timeout_info.timestamp = dm_get_timestamp(dc_dmub_srv->ctx); 293 } 294 dc_dmub_srv_handle_failure(dc_dmub_srv); 295 return false; 296 } 297 298 // Copy data back from ring buffer into command 299 if (wait_type == DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY && cmd_list) { 300 dmub_srv_cmd_get_response(dc_dmub_srv->dmub, cmd_list); 301 } 302 } 303 304 return true; 305 } 306 307 bool dc_dmub_srv_cmd_run(struct dc_dmub_srv *dc_dmub_srv, union dmub_rb_cmd *cmd, enum dm_dmub_wait_type wait_type) 308 { 309 return dc_dmub_srv_cmd_run_list(dc_dmub_srv, 1, cmd, wait_type); 310 } 311 312 bool dc_dmub_srv_cmd_run_list(struct dc_dmub_srv *dc_dmub_srv, unsigned int count, union dmub_rb_cmd *cmd_list, enum dm_dmub_wait_type wait_type) 313 { 314 if (!dc_dmub_srv_cmd_list_queue_execute(dc_dmub_srv, count, cmd_list)) 315 return false; 316 317 return dc_dmub_srv_wait_for_idle(dc_dmub_srv, wait_type, cmd_list); 318 } 319 320 bool dc_dmub_srv_optimized_init_done(struct dc_dmub_srv *dc_dmub_srv) 321 { 322 struct dmub_srv *dmub; 323 struct dc_context *dc_ctx; 324 union dmub_fw_boot_status boot_status; 325 enum dmub_status status; 326 327 if (!dc_dmub_srv || !dc_dmub_srv->dmub) 328 return false; 329 330 dmub = dc_dmub_srv->dmub; 331 dc_ctx = dc_dmub_srv->ctx; 332 333 status = dmub_srv_get_fw_boot_status(dmub, &boot_status); 334 if (status != DMUB_STATUS_OK) { 335 DC_ERROR("Error querying DMUB boot status: error=%d\n", status); 336 return false; 337 } 338 339 return (bool)boot_status.bits.optimized_init_done; 340 } 341 342 bool dc_dmub_srv_notify_stream_mask(struct dc_dmub_srv *dc_dmub_srv, 343 unsigned int stream_mask) 344 { 345 if (!dc_dmub_srv || !dc_dmub_srv->dmub) 346 return false; 347 348 return dc_wake_and_execute_gpint(dc_dmub_srv->ctx, DMUB_GPINT__IDLE_OPT_NOTIFY_STREAM_MASK, 349 (uint16_t)stream_mask, NULL, DM_DMUB_WAIT_TYPE_WAIT); 350 } 351 352 bool dc_dmub_srv_is_restore_required(struct dc_dmub_srv *dc_dmub_srv) 353 { 354 struct dmub_srv *dmub; 355 struct dc_context *dc_ctx; 356 union dmub_fw_boot_status boot_status; 357 enum dmub_status status; 358 359 if (!dc_dmub_srv || !dc_dmub_srv->dmub) 360 return false; 361 362 dmub = dc_dmub_srv->dmub; 363 dc_ctx = dc_dmub_srv->ctx; 364 365 status = dmub_srv_get_fw_boot_status(dmub, &boot_status); 366 if (status != DMUB_STATUS_OK) { 367 DC_ERROR("Error querying DMUB boot status: error=%d\n", status); 368 return false; 369 } 370 371 return (bool)boot_status.bits.restore_required; 372 } 373 374 bool dc_dmub_srv_get_dmub_outbox0_msg(const struct dc *dc, struct dmcub_trace_buf_entry *entry) 375 { 376 struct dmub_srv *dmub = dc->ctx->dmub_srv->dmub; 377 return dmub_srv_get_outbox0_msg(dmub, entry); 378 } 379 380 void dc_dmub_trace_event_control(struct dc *dc, bool enable) 381 { 382 dm_helpers_dmub_outbox_interrupt_control(dc->ctx, enable); 383 } 384 385 void dc_dmub_srv_drr_update_cmd(struct dc *dc, uint32_t tg_inst, uint32_t vtotal_min, uint32_t vtotal_max) 386 { 387 union dmub_rb_cmd cmd = { 0 }; 388 389 cmd.drr_update.header.type = DMUB_CMD__FW_ASSISTED_MCLK_SWITCH; 390 cmd.drr_update.header.sub_type = DMUB_CMD__FAMS_DRR_UPDATE; 391 cmd.drr_update.dmub_optc_state_req.v_total_max = vtotal_max; 392 cmd.drr_update.dmub_optc_state_req.v_total_min = vtotal_min; 393 cmd.drr_update.dmub_optc_state_req.tg_inst = tg_inst; 394 395 cmd.drr_update.header.payload_bytes = sizeof(cmd.drr_update) - sizeof(cmd.drr_update.header); 396 397 // Send the command to the DMCUB. 398 dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); 399 } 400 401 void dc_dmub_srv_set_drr_manual_trigger_cmd(struct dc *dc, uint32_t tg_inst) 402 { 403 union dmub_rb_cmd cmd = { 0 }; 404 405 cmd.drr_update.header.type = DMUB_CMD__FW_ASSISTED_MCLK_SWITCH; 406 cmd.drr_update.header.sub_type = DMUB_CMD__FAMS_SET_MANUAL_TRIGGER; 407 cmd.drr_update.dmub_optc_state_req.tg_inst = tg_inst; 408 409 cmd.drr_update.header.payload_bytes = sizeof(cmd.drr_update) - sizeof(cmd.drr_update.header); 410 411 // Send the command to the DMCUB. 412 dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); 413 } 414 415 static uint8_t dc_dmub_srv_get_pipes_for_stream(struct dc *dc, struct dc_stream_state *stream) 416 { 417 uint8_t pipes = 0; 418 uint8_t i = 0; 419 420 for (i = 0; i < MAX_PIPES; i++) { 421 struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i]; 422 423 if (pipe->stream == stream && pipe->stream_res.tg) 424 pipes = i; 425 } 426 return pipes; 427 } 428 429 static void dc_dmub_srv_populate_fams_pipe_info(struct dc *dc, struct dc_state *context, 430 struct pipe_ctx *head_pipe, 431 struct dmub_cmd_fw_assisted_mclk_switch_pipe_data *fams_pipe_data) 432 { 433 unsigned int j; 434 int pipe_idx = 0; 435 436 fams_pipe_data->pipe_index[pipe_idx++] = (uint8_t)head_pipe->plane_res.hubp->inst; 437 for (j = 0; j < dc->res_pool->pipe_count; j++) { 438 struct pipe_ctx *split_pipe = &context->res_ctx.pipe_ctx[j]; 439 440 if (split_pipe->stream == head_pipe->stream && (split_pipe->top_pipe || split_pipe->prev_odm_pipe)) { 441 fams_pipe_data->pipe_index[pipe_idx++] = (uint8_t)split_pipe->plane_res.hubp->inst; 442 } 443 } 444 fams_pipe_data->pipe_count = (uint8_t)pipe_idx; 445 } 446 447 bool dc_dmub_srv_p_state_delegate(struct dc *dc, bool should_manage_pstate, struct dc_state *context) 448 { 449 union dmub_rb_cmd cmd = { 0 }; 450 struct dmub_cmd_fw_assisted_mclk_switch_config *config_data = &cmd.fw_assisted_mclk_switch.config_data; 451 unsigned int i = 0; 452 int k = 0; 453 int ramp_up_num_steps = 1; // TODO: Ramp is currently disabled. Reenable it. 454 uint8_t visual_confirm_enabled; 455 struct dc_stream_status *stream_status = NULL; 456 457 if (dc == NULL) 458 return false; 459 460 visual_confirm_enabled = (uint8_t)(dc->debug.visual_confirm == VISUAL_CONFIRM_FAMS); 461 462 // Format command. 463 cmd.fw_assisted_mclk_switch.header.type = DMUB_CMD__FW_ASSISTED_MCLK_SWITCH; 464 cmd.fw_assisted_mclk_switch.header.sub_type = DMUB_CMD__FAMS_SETUP_FW_CTRL; 465 cmd.fw_assisted_mclk_switch.config_data.fams_enabled = should_manage_pstate; 466 cmd.fw_assisted_mclk_switch.config_data.visual_confirm_enabled = visual_confirm_enabled; 467 468 if (should_manage_pstate) { 469 for (i = 0; i < dc->res_pool->pipe_count; i++) { 470 struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; 471 472 if (!pipe->stream) 473 continue; 474 475 /* If FAMS is being used to support P-State and there is a stream 476 * that does not use FAMS, we are in an FPO + VActive scenario. 477 * Assign vactive stretch margin in this case. 478 */ 479 stream_status = dc_state_get_stream_status(context, pipe->stream); 480 if (stream_status && !stream_status->fpo_in_use) { 481 cmd.fw_assisted_mclk_switch.config_data.vactive_stretch_margin_us = 482 (uint16_t)dc->debug.fpo_vactive_margin_us; 483 break; 484 } 485 } 486 } 487 488 for (i = 0, k = 0; context && i < dc->res_pool->pipe_count; i++) { 489 struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; 490 491 if (!resource_is_pipe_type(pipe, OTG_MASTER) || !pipe->stream) 492 continue; 493 494 stream_status = dc_state_get_stream_status(context, pipe->stream); 495 if (stream_status && stream_status->fpo_in_use) { 496 uint8_t min_refresh_in_hz; 497 498 min_refresh_in_hz = (uint8_t)((pipe->stream->timing.min_refresh_in_uhz + 999999) / 1000000); 499 500 config_data->pipe_data[k].pix_clk_100hz = pipe->stream->timing.pix_clk_100hz; 501 config_data->pipe_data[k].min_refresh_in_hz = min_refresh_in_hz; 502 config_data->pipe_data[k].max_ramp_step = (uint8_t)ramp_up_num_steps; 503 config_data->pipe_data[k].pipes = dc_dmub_srv_get_pipes_for_stream(dc, pipe->stream); 504 dc_dmub_srv_populate_fams_pipe_info(dc, context, pipe, &config_data->pipe_data[k]); 505 k++; 506 } 507 } 508 cmd.fw_assisted_mclk_switch.header.payload_bytes = 509 sizeof(cmd.fw_assisted_mclk_switch) - sizeof(cmd.fw_assisted_mclk_switch.header); 510 511 // Send the command to the DMCUB. 512 dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); 513 514 return true; 515 } 516 517 void dc_dmub_srv_query_caps_cmd(struct dc_dmub_srv *dc_dmub_srv) 518 { 519 union dmub_rb_cmd cmd = { 0 }; 520 521 if (dc_dmub_srv->ctx->dc->debug.dmcub_emulation) 522 return; 523 524 memset(&cmd, 0, sizeof(cmd)); 525 526 /* Prepare fw command */ 527 cmd.query_feature_caps.header.type = DMUB_CMD__QUERY_FEATURE_CAPS; 528 cmd.query_feature_caps.header.sub_type = 0; 529 cmd.query_feature_caps.header.ret_status = 1; 530 cmd.query_feature_caps.header.payload_bytes = sizeof(struct dmub_cmd_query_feature_caps_data); 531 532 /* If command was processed, copy feature caps to dmub srv */ 533 if (dc_wake_and_execute_dmub_cmd(dc_dmub_srv->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY) && 534 cmd.query_feature_caps.header.ret_status == 0) { 535 memcpy(&dc_dmub_srv->dmub->feature_caps, 536 &cmd.query_feature_caps.query_feature_caps_data, 537 sizeof(struct dmub_feature_caps)); 538 } 539 } 540 541 void dc_dmub_srv_get_visual_confirm_color_cmd(struct dc *dc, struct pipe_ctx *pipe_ctx) 542 { 543 union dmub_rb_cmd cmd = { 0 }; 544 unsigned int panel_inst = 0; 545 546 if (!dc_get_edp_link_panel_inst(dc, pipe_ctx->stream->link, &panel_inst) && 547 dc->debug.visual_confirm == VISUAL_CONFIRM_DISABLE) 548 return; 549 550 memset(&cmd, 0, sizeof(cmd)); 551 552 // Prepare fw command 553 cmd.visual_confirm_color.header.type = DMUB_CMD__GET_VISUAL_CONFIRM_COLOR; 554 cmd.visual_confirm_color.header.sub_type = 0; 555 cmd.visual_confirm_color.header.ret_status = 1; 556 cmd.visual_confirm_color.header.payload_bytes = sizeof(struct dmub_cmd_visual_confirm_color_data); 557 cmd.visual_confirm_color.visual_confirm_color_data.visual_confirm_color.panel_inst = (uint16_t)panel_inst; 558 559 // If command was processed, copy feature caps to dmub srv 560 if (dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY) && 561 cmd.visual_confirm_color.header.ret_status == 0) { 562 memcpy(&dc->ctx->dmub_srv->dmub->visual_confirm_color, 563 &cmd.visual_confirm_color.visual_confirm_color_data, 564 sizeof(struct dmub_visual_confirm_color)); 565 } 566 } 567 568 /** 569 * populate_subvp_cmd_drr_info - Helper to populate DRR pipe info for the DMCUB subvp command 570 * 571 * @dc: [in] pointer to dc object 572 * @subvp_pipe: [in] pipe_ctx for the SubVP pipe 573 * @vblank_pipe: [in] pipe_ctx for the DRR pipe 574 * @pipe_data: [in] Pipe data which stores the VBLANK/DRR info 575 * @context: [in] DC state for access to phantom stream 576 * 577 * Populate the DMCUB SubVP command with DRR pipe info. All the information 578 * required for calculating the SubVP + DRR microschedule is populated here. 579 * 580 * High level algorithm: 581 * 1. Get timing for SubVP pipe, phantom pipe, and DRR pipe 582 * 2. Calculate the min and max vtotal which supports SubVP + DRR microschedule 583 * 3. Populate the drr_info with the min and max supported vtotal values 584 */ 585 static void populate_subvp_cmd_drr_info(struct dc *dc, 586 struct dc_state *context, 587 struct pipe_ctx *subvp_pipe, 588 struct pipe_ctx *vblank_pipe, 589 struct dmub_cmd_fw_assisted_mclk_switch_pipe_data_v2 *pipe_data) 590 { 591 struct dc_stream_state *phantom_stream = dc_state_get_paired_subvp_stream(context, subvp_pipe->stream); 592 struct dc_crtc_timing *main_timing = &subvp_pipe->stream->timing; 593 struct dc_crtc_timing *phantom_timing; 594 struct dc_crtc_timing *drr_timing = &vblank_pipe->stream->timing; 595 uint64_t drr_frame_us = 0; 596 uint64_t min_drr_supported_us = 0; 597 uint64_t max_drr_supported_us = 0; 598 uint64_t max_drr_vblank_us = 0; 599 uint64_t max_drr_mallregion_us = 0; 600 uint64_t mall_region_us = 0; 601 uint64_t prefetch_us = 0; 602 uint64_t subvp_active_us = 0; 603 uint64_t drr_active_us = 0; 604 uint64_t min_vtotal_supported = 0; 605 uint64_t max_vtotal_supported = 0; 606 607 if (!phantom_stream) 608 return; 609 610 phantom_timing = &phantom_stream->timing; 611 612 pipe_data->pipe_config.vblank_data.drr_info.drr_in_use = true; 613 pipe_data->pipe_config.vblank_data.drr_info.use_ramping = false; // for now don't use ramping 614 pipe_data->pipe_config.vblank_data.drr_info.drr_window_size_ms = 4; // hardcode 4ms DRR window for now 615 616 drr_frame_us = div64_u64(((uint64_t)drr_timing->v_total * drr_timing->h_total * 1000000), 617 (((uint64_t)drr_timing->pix_clk_100hz * 100))); 618 // P-State allow width and FW delays already included phantom_timing->v_addressable 619 mall_region_us = div64_u64(((uint64_t)phantom_timing->v_addressable * phantom_timing->h_total * 1000000), 620 (((uint64_t)phantom_timing->pix_clk_100hz * 100))); 621 min_drr_supported_us = drr_frame_us + mall_region_us + SUBVP_DRR_MARGIN_US; 622 min_vtotal_supported = div64_u64(((uint64_t)drr_timing->pix_clk_100hz * 100 * min_drr_supported_us), 623 (((uint64_t)drr_timing->h_total * 1000000))); 624 625 prefetch_us = div64_u64(((uint64_t)(phantom_timing->v_total - phantom_timing->v_front_porch) * phantom_timing->h_total * 1000000), 626 (((uint64_t)phantom_timing->pix_clk_100hz * 100) + dc->caps.subvp_prefetch_end_to_mall_start_us)); 627 subvp_active_us = div64_u64(((uint64_t)main_timing->v_addressable * main_timing->h_total * 1000000), 628 (((uint64_t)main_timing->pix_clk_100hz * 100))); 629 drr_active_us = div64_u64(((uint64_t)drr_timing->v_addressable * drr_timing->h_total * 1000000), 630 (((uint64_t)drr_timing->pix_clk_100hz * 100))); 631 max_drr_vblank_us = div64_u64((subvp_active_us - prefetch_us - 632 dc->caps.subvp_fw_processing_delay_us - drr_active_us), 2) + drr_active_us; 633 max_drr_mallregion_us = subvp_active_us - prefetch_us - mall_region_us - dc->caps.subvp_fw_processing_delay_us; 634 max_drr_supported_us = max_drr_vblank_us > max_drr_mallregion_us ? max_drr_vblank_us : max_drr_mallregion_us; 635 max_vtotal_supported = div64_u64(((uint64_t)drr_timing->pix_clk_100hz * 100 * max_drr_supported_us), 636 (((uint64_t)drr_timing->h_total * 1000000))); 637 638 /* When calculating the max vtotal supported for SubVP + DRR cases, add 639 * margin due to possible rounding errors (being off by 1 line in the 640 * FW calculation can incorrectly push the P-State switch to wait 1 frame 641 * longer). 642 */ 643 max_vtotal_supported = max_vtotal_supported - dc->caps.subvp_drr_max_vblank_margin_us; 644 645 pipe_data->pipe_config.vblank_data.drr_info.min_vtotal_supported = (uint16_t)min_vtotal_supported; 646 pipe_data->pipe_config.vblank_data.drr_info.max_vtotal_supported = (uint16_t)max_vtotal_supported; 647 pipe_data->pipe_config.vblank_data.drr_info.drr_vblank_start_margin = 648 (uint16_t)dc->caps.subvp_drr_vblank_start_margin_us; 649 } 650 651 /** 652 * populate_subvp_cmd_vblank_pipe_info - Helper to populate VBLANK pipe info for the DMUB subvp command 653 * 654 * @dc: [in] current dc state 655 * @context: [in] new dc state 656 * @cmd: [in] DMUB cmd to be populated with SubVP info 657 * @vblank_pipe: [in] pipe_ctx for the VBLANK pipe 658 * @cmd_pipe_index: [in] index for the pipe array in DMCUB SubVP cmd 659 * 660 * Populate the DMCUB SubVP command with VBLANK pipe info. All the information 661 * required to calculate the microschedule for SubVP + VBLANK case is stored in 662 * the pipe_data (subvp_data and vblank_data). Also check if the VBLANK pipe 663 * is a DRR display -- if it is make a call to populate drr_info. 664 */ 665 static void populate_subvp_cmd_vblank_pipe_info(struct dc *dc, 666 struct dc_state *context, 667 union dmub_rb_cmd *cmd, 668 struct pipe_ctx *vblank_pipe, 669 uint8_t cmd_pipe_index) 670 { 671 uint32_t i; 672 struct pipe_ctx *pipe = NULL; 673 struct dmub_cmd_fw_assisted_mclk_switch_pipe_data_v2 *pipe_data = 674 &cmd->fw_assisted_mclk_switch_v2.config_data.pipe_data[cmd_pipe_index]; 675 676 // Find the SubVP pipe 677 for (i = 0; i < dc->res_pool->pipe_count; i++) { 678 pipe = &context->res_ctx.pipe_ctx[i]; 679 680 // We check for master pipe, but it shouldn't matter since we only need 681 // the pipe for timing info (stream should be same for any pipe splits) 682 if (!resource_is_pipe_type(pipe, OTG_MASTER) || 683 !resource_is_pipe_type(pipe, DPP_PIPE)) 684 continue; 685 686 // Find the SubVP pipe 687 if (dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_MAIN) 688 break; 689 } 690 691 pipe_data->mode = VBLANK; 692 pipe_data->pipe_config.vblank_data.pix_clk_100hz = vblank_pipe->stream->timing.pix_clk_100hz; 693 pipe_data->pipe_config.vblank_data.vblank_start = (uint16_t)(vblank_pipe->stream->timing.v_total - 694 vblank_pipe->stream->timing.v_front_porch); 695 pipe_data->pipe_config.vblank_data.vtotal = (uint16_t)vblank_pipe->stream->timing.v_total; 696 pipe_data->pipe_config.vblank_data.htotal = (uint16_t)vblank_pipe->stream->timing.h_total; 697 pipe_data->pipe_config.vblank_data.vblank_pipe_index = vblank_pipe->pipe_idx; 698 pipe_data->pipe_config.vblank_data.vstartup_start = (uint16_t)vblank_pipe->pipe_dlg_param.vstartup_start; 699 pipe_data->pipe_config.vblank_data.vblank_end = 700 (uint16_t)(vblank_pipe->stream->timing.v_total - 701 vblank_pipe->stream->timing.v_front_porch - vblank_pipe->stream->timing.v_addressable); 702 703 if (vblank_pipe->stream->ignore_msa_timing_param && 704 (vblank_pipe->stream->allow_freesync || vblank_pipe->stream->vrr_active_variable || vblank_pipe->stream->vrr_active_fixed)) 705 populate_subvp_cmd_drr_info(dc, context, pipe, vblank_pipe, pipe_data); 706 } 707 708 /** 709 * update_subvp_prefetch_end_to_mall_start - Helper for SubVP + SubVP case 710 * 711 * @dc: [in] current dc state 712 * @context: [in] new dc state 713 * @cmd: [in] DMUB cmd to be populated with SubVP info 714 * @subvp_pipes: [in] Array of SubVP pipes (should always be length 2) 715 * 716 * For SubVP + SubVP, we use a single vertical interrupt to start the 717 * microschedule for both SubVP pipes. In order for this to work correctly, the 718 * MALL REGION of both SubVP pipes must start at the same time. This function 719 * lengthens the prefetch end to mall start delay of the SubVP pipe that has 720 * the shorter prefetch so that both MALL REGION's will start at the same time. 721 */ 722 static void update_subvp_prefetch_end_to_mall_start(struct dc *dc, 723 struct dc_state *context, 724 union dmub_rb_cmd *cmd, 725 struct pipe_ctx *subvp_pipes[]) 726 { 727 uint32_t subvp0_prefetch_us = 0; 728 uint32_t subvp1_prefetch_us = 0; 729 uint32_t prefetch_delta_us = 0; 730 struct dc_stream_state *phantom_stream0 = NULL; 731 struct dc_stream_state *phantom_stream1 = NULL; 732 struct dc_crtc_timing *phantom_timing0 = NULL; 733 struct dc_crtc_timing *phantom_timing1 = NULL; 734 struct dmub_cmd_fw_assisted_mclk_switch_pipe_data_v2 *pipe_data = NULL; 735 736 phantom_stream0 = dc_state_get_paired_subvp_stream(context, subvp_pipes[0]->stream); 737 if (!phantom_stream0) 738 return; 739 740 phantom_stream1 = dc_state_get_paired_subvp_stream(context, subvp_pipes[1]->stream); 741 if (!phantom_stream1) 742 return; 743 744 phantom_timing0 = &phantom_stream0->timing; 745 phantom_timing1 = &phantom_stream1->timing; 746 747 subvp0_prefetch_us = (uint32_t)div64_u64(((uint64_t)(phantom_timing0->v_total - phantom_timing0->v_front_porch) * 748 (uint64_t)phantom_timing0->h_total * 1000000), 749 (((uint64_t)phantom_timing0->pix_clk_100hz * 100) + dc->caps.subvp_prefetch_end_to_mall_start_us)); 750 subvp1_prefetch_us = (uint32_t)div64_u64(((uint64_t)(phantom_timing1->v_total - phantom_timing1->v_front_porch) * 751 (uint64_t)phantom_timing1->h_total * 1000000), 752 (((uint64_t)phantom_timing1->pix_clk_100hz * 100) + dc->caps.subvp_prefetch_end_to_mall_start_us)); 753 754 // Whichever SubVP PIPE has the smaller prefetch (including the prefetch end to mall start time) 755 // should increase it's prefetch time to match the other 756 if (subvp0_prefetch_us > subvp1_prefetch_us) { 757 pipe_data = &cmd->fw_assisted_mclk_switch_v2.config_data.pipe_data[1]; 758 prefetch_delta_us = subvp0_prefetch_us - subvp1_prefetch_us; 759 pipe_data->pipe_config.subvp_data.prefetch_to_mall_start_lines = 760 (uint16_t)div64_u64(((uint64_t)(dc->caps.subvp_prefetch_end_to_mall_start_us + prefetch_delta_us) * 761 ((uint64_t)phantom_timing1->pix_clk_100hz * 100) + ((uint64_t)phantom_timing1->h_total * 1000000 - 1)), 762 ((uint64_t)phantom_timing1->h_total * 1000000)); 763 764 } else if (subvp1_prefetch_us > subvp0_prefetch_us) { 765 pipe_data = &cmd->fw_assisted_mclk_switch_v2.config_data.pipe_data[0]; 766 prefetch_delta_us = subvp1_prefetch_us - subvp0_prefetch_us; 767 pipe_data->pipe_config.subvp_data.prefetch_to_mall_start_lines = 768 (uint16_t)div64_u64(((uint64_t)(dc->caps.subvp_prefetch_end_to_mall_start_us + prefetch_delta_us) * 769 ((uint64_t)phantom_timing0->pix_clk_100hz * 100) + ((uint64_t)phantom_timing0->h_total * 1000000 - 1)), 770 ((uint64_t)phantom_timing0->h_total * 1000000)); 771 } 772 } 773 774 /** 775 * populate_subvp_cmd_pipe_info - Helper to populate the SubVP pipe info for the DMUB subvp command 776 * 777 * @dc: [in] current dc state 778 * @context: [in] new dc state 779 * @cmd: [in] DMUB cmd to be populated with SubVP info 780 * @subvp_pipe: [in] pipe_ctx for the SubVP pipe 781 * @cmd_pipe_index: [in] index for the pipe array in DMCUB SubVP cmd 782 * 783 * Populate the DMCUB SubVP command with SubVP pipe info. All the information 784 * required to calculate the microschedule for the SubVP pipe is stored in the 785 * pipe_data of the DMCUB SubVP command. 786 */ 787 static void populate_subvp_cmd_pipe_info(struct dc *dc, 788 struct dc_state *context, 789 union dmub_rb_cmd *cmd, 790 struct pipe_ctx *subvp_pipe, 791 uint8_t cmd_pipe_index) 792 { 793 uint32_t j; 794 struct dmub_cmd_fw_assisted_mclk_switch_pipe_data_v2 *pipe_data = 795 &cmd->fw_assisted_mclk_switch_v2.config_data.pipe_data[cmd_pipe_index]; 796 struct dc_stream_state *phantom_stream = dc_state_get_paired_subvp_stream(context, subvp_pipe->stream); 797 struct dc_crtc_timing *main_timing = &subvp_pipe->stream->timing; 798 struct dc_crtc_timing *phantom_timing; 799 uint32_t out_num_stream, out_den_stream, out_num_plane, out_den_plane, out_num, out_den; 800 801 if (!phantom_stream) 802 return; 803 804 phantom_timing = &phantom_stream->timing; 805 806 pipe_data->mode = SUBVP; 807 pipe_data->pipe_config.subvp_data.pix_clk_100hz = subvp_pipe->stream->timing.pix_clk_100hz; 808 pipe_data->pipe_config.subvp_data.htotal = (uint16_t)subvp_pipe->stream->timing.h_total; 809 pipe_data->pipe_config.subvp_data.vtotal = (uint16_t)subvp_pipe->stream->timing.v_total; 810 pipe_data->pipe_config.subvp_data.main_vblank_start = 811 (uint16_t)(main_timing->v_total - main_timing->v_front_porch); 812 pipe_data->pipe_config.subvp_data.main_vblank_end = 813 (uint16_t)(main_timing->v_total - main_timing->v_front_porch - main_timing->v_addressable); 814 pipe_data->pipe_config.subvp_data.mall_region_lines = (uint16_t)phantom_timing->v_addressable; 815 pipe_data->pipe_config.subvp_data.main_pipe_index = (uint8_t)subvp_pipe->stream_res.tg->inst; 816 pipe_data->pipe_config.subvp_data.is_drr = subvp_pipe->stream->ignore_msa_timing_param && 817 (subvp_pipe->stream->allow_freesync || subvp_pipe->stream->vrr_active_variable || subvp_pipe->stream->vrr_active_fixed); 818 819 /* Calculate the scaling factor from the src and dst height. 820 * e.g. If 3840x2160 being downscaled to 1920x1080, the scaling factor is 1/2. 821 * Reduce the fraction 1080/2160 = 1/2 for the "scaling factor" 822 * 823 * Make sure to combine stream and plane scaling together. 824 */ 825 reduce_fraction(subvp_pipe->stream->src.height, subvp_pipe->stream->dst.height, 826 &out_num_stream, &out_den_stream); 827 reduce_fraction(subvp_pipe->plane_state->src_rect.height, subvp_pipe->plane_state->dst_rect.height, 828 &out_num_plane, &out_den_plane); 829 reduce_fraction(out_num_stream * out_num_plane, out_den_stream * out_den_plane, &out_num, &out_den); 830 pipe_data->pipe_config.subvp_data.scale_factor_numerator = (uint8_t)out_num; 831 pipe_data->pipe_config.subvp_data.scale_factor_denominator = (uint8_t)out_den; 832 833 // Prefetch lines is equal to VACTIVE + BP + VSYNC 834 pipe_data->pipe_config.subvp_data.prefetch_lines = 835 (uint16_t)(phantom_timing->v_total - phantom_timing->v_front_porch); 836 837 // Round up 838 pipe_data->pipe_config.subvp_data.prefetch_to_mall_start_lines = 839 (uint16_t)div64_u64(((uint64_t)dc->caps.subvp_prefetch_end_to_mall_start_us * ((uint64_t)phantom_timing->pix_clk_100hz * 100) + 840 ((uint64_t)phantom_timing->h_total * 1000000 - 1)), ((uint64_t)phantom_timing->h_total * 1000000)); 841 pipe_data->pipe_config.subvp_data.processing_delay_lines = 842 (uint16_t)div64_u64(((uint64_t)(dc->caps.subvp_fw_processing_delay_us) * ((uint64_t)phantom_timing->pix_clk_100hz * 100) + 843 ((uint64_t)phantom_timing->h_total * 1000000 - 1)), ((uint64_t)phantom_timing->h_total * 1000000)); 844 845 if (subvp_pipe->bottom_pipe) { 846 pipe_data->pipe_config.subvp_data.main_split_pipe_index = (uint8_t)subvp_pipe->bottom_pipe->pipe_idx; 847 } else if (subvp_pipe->next_odm_pipe) { 848 pipe_data->pipe_config.subvp_data.main_split_pipe_index = (uint8_t)subvp_pipe->next_odm_pipe->pipe_idx; 849 } else { 850 pipe_data->pipe_config.subvp_data.main_split_pipe_index = 0xF; 851 } 852 853 // Find phantom pipe index based on phantom stream 854 for (j = 0; j < dc->res_pool->pipe_count; j++) { 855 struct pipe_ctx *phantom_pipe = &context->res_ctx.pipe_ctx[j]; 856 857 if (resource_is_pipe_type(phantom_pipe, OTG_MASTER) && 858 phantom_pipe->stream == dc_state_get_paired_subvp_stream(context, subvp_pipe->stream)) { 859 pipe_data->pipe_config.subvp_data.phantom_pipe_index = (uint8_t)phantom_pipe->stream_res.tg->inst; 860 if (phantom_pipe->bottom_pipe) { 861 pipe_data->pipe_config.subvp_data.phantom_split_pipe_index = (uint8_t)phantom_pipe->bottom_pipe->plane_res.hubp->inst; 862 } else if (phantom_pipe->next_odm_pipe) { 863 pipe_data->pipe_config.subvp_data.phantom_split_pipe_index = (uint8_t)phantom_pipe->next_odm_pipe->plane_res.hubp->inst; 864 } else { 865 pipe_data->pipe_config.subvp_data.phantom_split_pipe_index = 0xF; 866 } 867 break; 868 } 869 } 870 } 871 872 /** 873 * dc_dmub_setup_subvp_dmub_command - Populate the DMCUB SubVP command 874 * 875 * @dc: [in] current dc state 876 * @context: [in] new dc state 877 * @enable: [in] if true enables the pipes population 878 * 879 * This function loops through each pipe and populates the DMUB SubVP CMD info 880 * based on the pipe (e.g. SubVP, VBLANK). 881 */ 882 void dc_dmub_setup_subvp_dmub_command(struct dc *dc, 883 struct dc_state *context, 884 bool enable) 885 { 886 uint8_t cmd_pipe_index = 0; 887 uint32_t i; 888 uint8_t subvp_count = 0; 889 union dmub_rb_cmd cmd; 890 struct pipe_ctx *subvp_pipes[2]; 891 uint32_t wm_val_refclk = 0; 892 enum mall_stream_type pipe_mall_type; 893 894 memset(&cmd, 0, sizeof(cmd)); 895 // FW command for SUBVP 896 cmd.fw_assisted_mclk_switch_v2.header.type = DMUB_CMD__FW_ASSISTED_MCLK_SWITCH; 897 cmd.fw_assisted_mclk_switch_v2.header.sub_type = DMUB_CMD__HANDLE_SUBVP_CMD; 898 cmd.fw_assisted_mclk_switch_v2.header.payload_bytes = 899 sizeof(cmd.fw_assisted_mclk_switch_v2) - sizeof(cmd.fw_assisted_mclk_switch_v2.header); 900 901 for (i = 0; i < dc->res_pool->pipe_count; i++) { 902 struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; 903 904 /* For SubVP pipe count, only count the top most (ODM / MPC) pipe 905 */ 906 if (resource_is_pipe_type(pipe, OTG_MASTER) && 907 resource_is_pipe_type(pipe, DPP_PIPE) && 908 dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_MAIN) 909 subvp_pipes[subvp_count++] = pipe; 910 } 911 912 if (enable) { 913 // For each pipe that is a "main" SUBVP pipe, fill in pipe data for DMUB SUBVP cmd 914 for (i = 0; i < dc->res_pool->pipe_count; i++) { 915 struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; 916 pipe_mall_type = dc_state_get_pipe_subvp_type(context, pipe); 917 918 if (!pipe->stream) 919 continue; 920 921 /* When populating subvp cmd info, only pass in the top most (ODM / MPC) pipe. 922 * Any ODM or MPC splits being used in SubVP will be handled internally in 923 * populate_subvp_cmd_pipe_info 924 */ 925 if (resource_is_pipe_type(pipe, OTG_MASTER) && 926 resource_is_pipe_type(pipe, DPP_PIPE) && 927 pipe_mall_type == SUBVP_MAIN) { 928 populate_subvp_cmd_pipe_info(dc, context, &cmd, pipe, cmd_pipe_index++); 929 } else if (resource_is_pipe_type(pipe, OTG_MASTER) && 930 resource_is_pipe_type(pipe, DPP_PIPE) && 931 pipe_mall_type == SUBVP_NONE) { 932 // Don't need to check for ActiveDRAMClockChangeMargin < 0, not valid in cases where 933 // we run through DML without calculating "natural" P-state support 934 populate_subvp_cmd_vblank_pipe_info(dc, context, &cmd, pipe, cmd_pipe_index++); 935 936 } 937 } 938 if (subvp_count == 2) { 939 update_subvp_prefetch_end_to_mall_start(dc, context, &cmd, subvp_pipes); 940 } 941 cmd.fw_assisted_mclk_switch_v2.config_data.pstate_allow_width_us = (uint8_t)dc->caps.subvp_pstate_allow_width_us; 942 cmd.fw_assisted_mclk_switch_v2.config_data.vertical_int_margin_us = (uint8_t)dc->caps.subvp_vertical_int_margin_us; 943 944 // Store the original watermark value for this SubVP config so we can lower it when the 945 // MCLK switch starts 946 wm_val_refclk = context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns * 947 (dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000) / 1000; 948 949 cmd.fw_assisted_mclk_switch_v2.config_data.watermark_a_cache = (uint16_t)(wm_val_refclk < 0xFFFF ? wm_val_refclk : 0xFFFF); 950 } 951 952 dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); 953 } 954 955 bool dc_dmub_srv_get_diagnostic_data(struct dc_dmub_srv *dc_dmub_srv) 956 { 957 if (!dc_dmub_srv || !dc_dmub_srv->dmub) 958 return false; 959 return dmub_srv_get_diagnostic_data(dc_dmub_srv->dmub); 960 } 961 962 void dc_dmub_srv_log_diagnostic_data(struct dc_dmub_srv *dc_dmub_srv) 963 { 964 uint32_t i; 965 966 if (!dc_dmub_srv) 967 return; 968 969 if (!dc_dmub_srv->dmub) { 970 DC_LOG_ERROR("%s: invalid parameters.", __func__); 971 return; 972 } 973 974 DC_LOG_ERROR("%s: DMCUB error - collecting diagnostic data\n", __func__); 975 976 if (!dc_dmub_srv_get_diagnostic_data(dc_dmub_srv)) { 977 DC_LOG_ERROR("%s: dc_dmub_srv_get_diagnostic_data failed.", __func__); 978 return; 979 } 980 981 DC_LOG_DEBUG("DMCUB STATE:"); 982 DC_LOG_DEBUG(" dmcub_version : %08x", dc_dmub_srv->dmub->debug.dmcub_version); 983 DC_LOG_DEBUG(" scratch [0] : %08x", dc_dmub_srv->dmub->debug.scratch[0]); 984 DC_LOG_DEBUG(" scratch [1] : %08x", dc_dmub_srv->dmub->debug.scratch[1]); 985 DC_LOG_DEBUG(" scratch [2] : %08x", dc_dmub_srv->dmub->debug.scratch[2]); 986 DC_LOG_DEBUG(" scratch [3] : %08x", dc_dmub_srv->dmub->debug.scratch[3]); 987 DC_LOG_DEBUG(" scratch [4] : %08x", dc_dmub_srv->dmub->debug.scratch[4]); 988 DC_LOG_DEBUG(" scratch [5] : %08x", dc_dmub_srv->dmub->debug.scratch[5]); 989 DC_LOG_DEBUG(" scratch [6] : %08x", dc_dmub_srv->dmub->debug.scratch[6]); 990 DC_LOG_DEBUG(" scratch [7] : %08x", dc_dmub_srv->dmub->debug.scratch[7]); 991 DC_LOG_DEBUG(" scratch [8] : %08x", dc_dmub_srv->dmub->debug.scratch[8]); 992 DC_LOG_DEBUG(" scratch [9] : %08x", dc_dmub_srv->dmub->debug.scratch[9]); 993 DC_LOG_DEBUG(" scratch [10] : %08x", dc_dmub_srv->dmub->debug.scratch[10]); 994 DC_LOG_DEBUG(" scratch [11] : %08x", dc_dmub_srv->dmub->debug.scratch[11]); 995 DC_LOG_DEBUG(" scratch [12] : %08x", dc_dmub_srv->dmub->debug.scratch[12]); 996 DC_LOG_DEBUG(" scratch [13] : %08x", dc_dmub_srv->dmub->debug.scratch[13]); 997 DC_LOG_DEBUG(" scratch [14] : %08x", dc_dmub_srv->dmub->debug.scratch[14]); 998 DC_LOG_DEBUG(" scratch [15] : %08x", dc_dmub_srv->dmub->debug.scratch[15]); 999 for (i = 0; i < DMUB_PC_SNAPSHOT_COUNT; i++) 1000 DC_LOG_DEBUG(" pc[%d] : %08x", i, dc_dmub_srv->dmub->debug.pc[i]); 1001 DC_LOG_DEBUG(" unk_fault_addr : %08x", dc_dmub_srv->dmub->debug.undefined_address_fault_addr); 1002 DC_LOG_DEBUG(" inst_fault_addr : %08x", dc_dmub_srv->dmub->debug.inst_fetch_fault_addr); 1003 DC_LOG_DEBUG(" data_fault_addr : %08x", dc_dmub_srv->dmub->debug.data_write_fault_addr); 1004 DC_LOG_DEBUG(" inbox1_rptr : %08x", dc_dmub_srv->dmub->debug.inbox1_rptr); 1005 DC_LOG_DEBUG(" inbox1_wptr : %08x", dc_dmub_srv->dmub->debug.inbox1_wptr); 1006 DC_LOG_DEBUG(" inbox1_size : %08x", dc_dmub_srv->dmub->debug.inbox1_size); 1007 DC_LOG_DEBUG(" inbox0_rptr : %08x", dc_dmub_srv->dmub->debug.inbox0_rptr); 1008 DC_LOG_DEBUG(" inbox0_wptr : %08x", dc_dmub_srv->dmub->debug.inbox0_wptr); 1009 DC_LOG_DEBUG(" inbox0_size : %08x", dc_dmub_srv->dmub->debug.inbox0_size); 1010 DC_LOG_DEBUG(" outbox1_rptr : %08x", dc_dmub_srv->dmub->debug.outbox1_rptr); 1011 DC_LOG_DEBUG(" outbox1_wptr : %08x", dc_dmub_srv->dmub->debug.outbox1_wptr); 1012 DC_LOG_DEBUG(" outbox1_size : %08x", dc_dmub_srv->dmub->debug.outbox1_size); 1013 DC_LOG_DEBUG(" is_enabled : %d", dc_dmub_srv->dmub->debug.is_dmcub_enabled); 1014 DC_LOG_DEBUG(" is_soft_reset : %d", dc_dmub_srv->dmub->debug.is_dmcub_soft_reset); 1015 DC_LOG_DEBUG(" is_secure_reset : %d", dc_dmub_srv->dmub->debug.is_dmcub_secure_reset); 1016 DC_LOG_DEBUG(" is_traceport_en : %d", dc_dmub_srv->dmub->debug.is_traceport_en); 1017 DC_LOG_DEBUG(" is_cw0_en : %d", dc_dmub_srv->dmub->debug.is_cw0_enabled); 1018 DC_LOG_DEBUG(" is_cw6_en : %d", dc_dmub_srv->dmub->debug.is_cw6_enabled); 1019 DC_LOG_DEBUG(" is_pwait : %d", dc_dmub_srv->dmub->debug.is_pwait); 1020 } 1021 1022 static bool dc_dmub_should_update_cursor_data(struct pipe_ctx *pipe_ctx) 1023 { 1024 if (pipe_ctx->plane_state != NULL) { 1025 if (pipe_ctx->plane_state->address.type == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE || 1026 resource_can_pipe_disable_cursor(pipe_ctx)) 1027 return false; 1028 } 1029 1030 if ((pipe_ctx->stream->link->psr_settings.psr_version == DC_PSR_VERSION_SU_1 || 1031 pipe_ctx->stream->link->psr_settings.psr_version == DC_PSR_VERSION_1) && 1032 pipe_ctx->stream->ctx->dce_version >= DCN_VERSION_3_1) 1033 return true; 1034 1035 if (pipe_ctx->stream->link->replay_settings.config.replay_supported) 1036 return true; 1037 1038 return false; 1039 } 1040 1041 static void dc_build_cursor_update_payload0( 1042 struct pipe_ctx *pipe_ctx, uint8_t p_idx, 1043 struct dmub_cmd_update_cursor_payload0 *payload) 1044 { 1045 struct dc *dc = pipe_ctx->stream->ctx->dc; 1046 struct hubp *hubp = pipe_ctx->plane_res.hubp; 1047 unsigned int panel_inst = 0; 1048 1049 if (dc->config.frame_update_cmd_version2 == true) { 1050 /* Don't need panel_inst for command version2 */ 1051 payload->cmd_version = DMUB_CMD_CURSOR_UPDATE_VERSION_2; 1052 } else { 1053 if (!dc_get_edp_link_panel_inst(hubp->ctx->dc, 1054 pipe_ctx->stream->link, &panel_inst)) 1055 return; 1056 payload->cmd_version = DMUB_CMD_CURSOR_UPDATE_VERSION_1; 1057 } 1058 1059 /* Payload: Cursor Rect is built from position & attribute 1060 * x & y are obtained from postion 1061 */ 1062 payload->cursor_rect.x = hubp->cur_rect.x; 1063 payload->cursor_rect.y = hubp->cur_rect.y; 1064 /* w & h are obtained from attribute */ 1065 payload->cursor_rect.width = hubp->cur_rect.w; 1066 payload->cursor_rect.height = hubp->cur_rect.h; 1067 1068 payload->enable = (uint8_t)hubp->pos.cur_ctl.bits.cur_enable; 1069 payload->pipe_idx = p_idx; 1070 payload->panel_inst = (uint8_t)panel_inst; 1071 payload->otg_inst = (uint8_t)pipe_ctx->stream_res.tg->inst; 1072 } 1073 1074 static void dc_build_cursor_position_update_payload0( 1075 struct dmub_cmd_update_cursor_payload0 *pl, const uint8_t p_idx, 1076 const struct hubp *hubp, const struct dpp *dpp) 1077 { 1078 /* Hubp */ 1079 pl->position_cfg.pHubp.cur_ctl.raw = hubp->pos.cur_ctl.raw; 1080 pl->position_cfg.pHubp.position.raw = hubp->pos.position.raw; 1081 pl->position_cfg.pHubp.hot_spot.raw = hubp->pos.hot_spot.raw; 1082 pl->position_cfg.pHubp.dst_offset.raw = hubp->pos.dst_offset.raw; 1083 1084 /* dpp */ 1085 pl->position_cfg.pDpp.cur0_ctl.raw = dpp->pos.cur0_ctl.raw; 1086 pl->position_cfg.pipe_idx = p_idx; 1087 } 1088 1089 static void dc_build_cursor_attribute_update_payload1( 1090 struct dmub_cursor_attributes_cfg *pl_A, const uint8_t p_idx, 1091 const struct hubp *hubp, const struct dpp *dpp) 1092 { 1093 (void)p_idx; 1094 /* Hubp */ 1095 pl_A->aHubp.SURFACE_ADDR_HIGH = hubp->att.SURFACE_ADDR_HIGH; 1096 pl_A->aHubp.SURFACE_ADDR = hubp->att.SURFACE_ADDR; 1097 pl_A->aHubp.cur_ctl.raw = hubp->att.cur_ctl.raw; 1098 pl_A->aHubp.size.raw = hubp->att.size.raw; 1099 pl_A->aHubp.settings.raw = hubp->att.settings.raw; 1100 1101 /* dpp */ 1102 pl_A->aDpp.cur0_ctl.raw = dpp->att.cur0_ctl.raw; 1103 } 1104 1105 /** 1106 * dc_send_update_cursor_info_to_dmu - Populate the DMCUB Cursor update info command 1107 * 1108 * @pCtx: [in] pipe context 1109 * @pipe_idx: [in] pipe index 1110 * 1111 * This function would store the cursor related information and pass it into 1112 * dmub 1113 */ 1114 void dc_send_update_cursor_info_to_dmu( 1115 struct pipe_ctx *pCtx, uint8_t pipe_idx) 1116 { 1117 union dmub_rb_cmd cmd[2]; 1118 union dmub_cmd_update_cursor_info_data *update_cursor_info_0 = 1119 &cmd[0].update_cursor_info.update_cursor_info_data; 1120 1121 memset(cmd, 0, sizeof(cmd)); 1122 1123 if (!dc_dmub_should_update_cursor_data(pCtx)) 1124 return; 1125 /* 1126 * Since we use multi_cmd_pending for dmub command, the 2nd command is 1127 * only assigned to store cursor attributes info. 1128 * 1st command can view as 2 parts, 1st is for PSR/Replay data, the other 1129 * is to store cursor position info. 1130 * 1131 * Command heaer type must be the same type if using multi_cmd_pending. 1132 * Besides, while process 2nd command in DMU, the sub type is useless. 1133 * So it's meanless to pass the sub type header with different type. 1134 */ 1135 1136 { 1137 /* Build Payload#0 Header */ 1138 cmd[0].update_cursor_info.header.type = DMUB_CMD__UPDATE_CURSOR_INFO; 1139 cmd[0].update_cursor_info.header.payload_bytes = 1140 sizeof(cmd[0].update_cursor_info.update_cursor_info_data); 1141 cmd[0].update_cursor_info.header.multi_cmd_pending = 1; //To combine multi dmu cmd, 1st cmd 1142 1143 /* Prepare Payload */ 1144 dc_build_cursor_update_payload0(pCtx, pipe_idx, &update_cursor_info_0->payload0); 1145 1146 dc_build_cursor_position_update_payload0(&update_cursor_info_0->payload0, pipe_idx, 1147 pCtx->plane_res.hubp, pCtx->plane_res.dpp); 1148 } 1149 { 1150 /* Build Payload#1 Header */ 1151 cmd[1].update_cursor_info.header.type = DMUB_CMD__UPDATE_CURSOR_INFO; 1152 cmd[1].update_cursor_info.header.payload_bytes = sizeof(struct cursor_attributes_cfg); 1153 cmd[1].update_cursor_info.header.multi_cmd_pending = 0; //Indicate it's the last command. 1154 1155 dc_build_cursor_attribute_update_payload1( 1156 &cmd[1].update_cursor_info.update_cursor_info_data.payload1.attribute_cfg, 1157 pipe_idx, pCtx->plane_res.hubp, pCtx->plane_res.dpp); 1158 1159 /* Combine 2nd cmds update_curosr_info to DMU */ 1160 dc_wake_and_execute_dmub_cmd_list(pCtx->stream->ctx, 2, cmd, DM_DMUB_WAIT_TYPE_WAIT); 1161 } 1162 } 1163 1164 bool dc_dmub_check_min_version(struct dmub_srv *srv) 1165 { 1166 if (!srv->hw_funcs.is_psrsu_supported) 1167 return true; 1168 return srv->hw_funcs.is_psrsu_supported(srv); 1169 } 1170 1171 void dc_dmub_srv_enable_dpia_trace(const struct dc *dc) 1172 { 1173 struct dc_dmub_srv *dc_dmub_srv = dc->ctx->dmub_srv; 1174 1175 if (!dc_dmub_srv) 1176 return; 1177 1178 if (!dc_dmub_srv->dmub) { 1179 DC_LOG_ERROR("%s: invalid parameters.", __func__); 1180 return; 1181 } 1182 1183 if (!dc_wake_and_execute_gpint(dc->ctx, DMUB_GPINT__SET_TRACE_BUFFER_MASK_WORD1, 1184 0x0010, NULL, DM_DMUB_WAIT_TYPE_WAIT)) { 1185 DC_LOG_ERROR("timeout updating trace buffer mask word\n"); 1186 return; 1187 } 1188 1189 if (!dc_wake_and_execute_gpint(dc->ctx, DMUB_GPINT__UPDATE_TRACE_BUFFER_MASK, 1190 0x0000, NULL, DM_DMUB_WAIT_TYPE_WAIT)) { 1191 DC_LOG_ERROR("timeout updating trace buffer mask word\n"); 1192 return; 1193 } 1194 1195 DC_LOG_DEBUG("Enabled DPIA trace\n"); 1196 } 1197 1198 void dc_dmub_srv_subvp_save_surf_addr(const struct dc_dmub_srv *dc_dmub_srv, const struct dc_plane_address *addr, uint8_t subvp_index) 1199 { 1200 dmub_srv_subvp_save_surf_addr(dc_dmub_srv->dmub, addr, subvp_index); 1201 } 1202 1203 void dc_dmub_srv_cursor_offload_init(struct dc *dc) 1204 { 1205 struct dmub_rb_cmd_cursor_offload_init *init; 1206 struct dc_dmub_srv *dc_dmub_srv = dc->ctx->dmub_srv; 1207 union dmub_rb_cmd cmd; 1208 1209 if (!dc->config.enable_cursor_offload) 1210 return; 1211 1212 if (!dc_dmub_srv->dmub->meta_info.feature_bits.bits.cursor_offload_v1_support) 1213 return; 1214 1215 if (!dc_dmub_srv->dmub->cursor_offload_fb.gpu_addr || !dc_dmub_srv->dmub->cursor_offload_fb.cpu_addr) 1216 return; 1217 1218 if (!dc_dmub_srv->dmub->cursor_offload_v1) 1219 return; 1220 1221 if (!dc_dmub_srv->dmub->shared_state) 1222 return; 1223 1224 memset(&cmd, 0, sizeof(cmd)); 1225 1226 init = &cmd.cursor_offload_init; 1227 init->header.type = DMUB_CMD__CURSOR_OFFLOAD; 1228 init->header.sub_type = DMUB_CMD__CURSOR_OFFLOAD_INIT; 1229 init->header.payload_bytes = sizeof(init->init_data); 1230 init->init_data.state_addr.quad_part = dc_dmub_srv->dmub->cursor_offload_fb.gpu_addr; 1231 init->init_data.state_size = dc_dmub_srv->dmub->cursor_offload_fb.size; 1232 1233 dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); 1234 1235 dc_dmub_srv->cursor_offload_enabled = true; 1236 } 1237 1238 void dc_dmub_srv_control_cursor_offload(struct dc *dc, struct dc_state *context, 1239 const struct dc_stream_state *stream, bool enable) 1240 { 1241 struct pipe_ctx const *pipe_ctx; 1242 struct dmub_rb_cmd_cursor_offload_stream_cntl *cntl; 1243 union dmub_rb_cmd cmd; 1244 1245 if (!dc_dmub_srv_is_cursor_offload_enabled(dc)) 1246 return; 1247 1248 if (!stream) 1249 return; 1250 1251 pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream); 1252 if (!pipe_ctx || !pipe_ctx->stream_res.tg || pipe_ctx->stream != stream) 1253 return; 1254 1255 memset(&cmd, 0, sizeof(cmd)); 1256 1257 cntl = &cmd.cursor_offload_stream_ctnl; 1258 cntl->header.type = DMUB_CMD__CURSOR_OFFLOAD; 1259 cntl->header.sub_type = 1260 enable ? DMUB_CMD__CURSOR_OFFLOAD_STREAM_ENABLE : DMUB_CMD__CURSOR_OFFLOAD_STREAM_DISABLE; 1261 cntl->header.payload_bytes = sizeof(cntl->data); 1262 1263 cntl->data.otg_inst = pipe_ctx->stream_res.tg->inst; 1264 cntl->data.line_time_in_ns = 1u + (uint32_t)(div64_u64(stream->timing.h_total * 1000000ull, 1265 stream->timing.pix_clk_100hz / 10)); 1266 1267 cntl->data.v_total_max = stream->adjust.v_total_max > stream->timing.v_total ? 1268 stream->adjust.v_total_max : 1269 stream->timing.v_total; 1270 1271 dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, 1272 enable ? DM_DMUB_WAIT_TYPE_NO_WAIT : DM_DMUB_WAIT_TYPE_WAIT); 1273 } 1274 1275 void dc_dmub_srv_program_cursor_now(struct dc *dc, const struct pipe_ctx *pipe) 1276 { 1277 struct dmub_rb_cmd_cursor_offload_stream_cntl *cntl; 1278 union dmub_rb_cmd cmd; 1279 1280 if (!dc_dmub_srv_is_cursor_offload_enabled(dc)) 1281 return; 1282 1283 if (!pipe || !pipe->stream || !pipe->stream_res.tg) 1284 return; 1285 1286 memset(&cmd, 0, sizeof(cmd)); 1287 1288 cntl = &cmd.cursor_offload_stream_ctnl; 1289 cntl->header.type = DMUB_CMD__CURSOR_OFFLOAD; 1290 cntl->header.sub_type = DMUB_CMD__CURSOR_OFFLOAD_STREAM_PROGRAM; 1291 cntl->header.payload_bytes = sizeof(cntl->data); 1292 cntl->data.otg_inst = pipe->stream_res.tg->inst; 1293 1294 dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_NO_WAIT); 1295 } 1296 1297 bool dc_dmub_srv_is_hw_pwr_up(struct dc_dmub_srv *dc_dmub_srv, bool wait) 1298 { 1299 struct dc_context *dc_ctx; 1300 enum dmub_status status; 1301 1302 if (!dc_dmub_srv || !dc_dmub_srv->dmub) 1303 return true; 1304 1305 if (dc_dmub_srv->ctx->dc->debug.dmcub_emulation) 1306 return true; 1307 1308 dc_ctx = dc_dmub_srv->ctx; 1309 1310 if (wait) { 1311 if (dc_dmub_srv->ctx->dc->debug.disable_timeout) { 1312 do { 1313 status = dmub_srv_wait_for_hw_pwr_up(dc_dmub_srv->dmub, 500000); 1314 } while (status != DMUB_STATUS_OK); 1315 } else { 1316 status = dmub_srv_wait_for_hw_pwr_up(dc_dmub_srv->dmub, 500000); 1317 if (status != DMUB_STATUS_OK) { 1318 DC_ERROR("Error querying DMUB hw power up status: error=%d\n", status); 1319 return false; 1320 } 1321 } 1322 } else 1323 return dmub_srv_is_hw_pwr_up(dc_dmub_srv->dmub); 1324 1325 return true; 1326 } 1327 1328 static int count_active_streams(const struct dc *dc) 1329 { 1330 int i, count = 0; 1331 1332 for (i = 0; i < dc->current_state->stream_count; ++i) { 1333 struct dc_stream_state *stream = dc->current_state->streams[i]; 1334 1335 if (stream && (!stream->dpms_off || dc->config.disable_ips_in_dpms_off)) 1336 count += 1; 1337 } 1338 1339 return count; 1340 } 1341 1342 static void dc_dmub_srv_notify_idle(const struct dc *dc, bool allow_idle) 1343 { 1344 volatile const struct dmub_shared_state_ips_fw *ips_fw; 1345 struct dc_dmub_srv *dc_dmub_srv; 1346 union dmub_rb_cmd cmd = {0}; 1347 1348 if (dc->debug.dmcub_emulation) 1349 return; 1350 1351 if (!dc->ctx->dmub_srv || !dc->ctx->dmub_srv->dmub) 1352 return; 1353 1354 dc_dmub_srv = dc->ctx->dmub_srv; 1355 ips_fw = &dc_dmub_srv->dmub->shared_state[DMUB_SHARED_SHARE_FEATURE__IPS_FW].data.ips_fw; 1356 1357 memset(&cmd, 0, sizeof(cmd)); 1358 cmd.idle_opt_notify_idle.header.type = DMUB_CMD__IDLE_OPT; 1359 cmd.idle_opt_notify_idle.header.sub_type = DMUB_CMD__IDLE_OPT_DCN_NOTIFY_IDLE; 1360 cmd.idle_opt_notify_idle.header.payload_bytes = 1361 sizeof(cmd.idle_opt_notify_idle) - 1362 sizeof(cmd.idle_opt_notify_idle.header); 1363 1364 cmd.idle_opt_notify_idle.cntl_data.driver_idle = allow_idle; 1365 1366 if (dc->work_arounds.skip_psr_ips_crtc_disable) 1367 cmd.idle_opt_notify_idle.cntl_data.skip_otg_disable = true; 1368 1369 if (allow_idle) { 1370 volatile struct dmub_shared_state_ips_driver *ips_driver = 1371 &dc_dmub_srv->dmub->shared_state[DMUB_SHARED_SHARE_FEATURE__IPS_DRIVER].data.ips_driver; 1372 union dmub_shared_state_ips_driver_signals new_signals; 1373 1374 DC_LOG_IPS( 1375 "%s wait idle (ips1_commit=%u ips2_commit=%u)", 1376 __func__, 1377 ips_fw->signals.bits.ips1_commit, 1378 ips_fw->signals.bits.ips2_commit); 1379 1380 dc_dmub_srv_wait_for_idle(dc->ctx->dmub_srv, DM_DMUB_WAIT_TYPE_WAIT, NULL); 1381 1382 memset(&new_signals, 0, sizeof(new_signals)); 1383 1384 new_signals.bits.allow_idle = 1; /* always set */ 1385 1386 if (dc->config.disable_ips == DMUB_IPS_ENABLE || 1387 dc->config.disable_ips == DMUB_IPS_DISABLE_DYNAMIC) { 1388 new_signals.bits.allow_pg = 1; 1389 new_signals.bits.allow_ips1 = 1; 1390 new_signals.bits.allow_ips2 = 1; 1391 new_signals.bits.allow_z10 = 1; 1392 // New in IPSv2.0 1393 new_signals.bits.allow_ips1z8 = 1; 1394 } else if (dc->config.disable_ips == DMUB_IPS_DISABLE_IPS1) { 1395 new_signals.bits.allow_ips1 = 1; 1396 } else if (dc->config.disable_ips == DMUB_IPS_DISABLE_IPS2) { 1397 // IPSv1.0 only 1398 new_signals.bits.allow_pg = 1; 1399 new_signals.bits.allow_ips1 = 1; 1400 } else if (dc->config.disable_ips == DMUB_IPS_DISABLE_IPS2_Z10) { 1401 // IPSv1.0 only 1402 new_signals.bits.allow_pg = 1; 1403 new_signals.bits.allow_ips1 = 1; 1404 new_signals.bits.allow_ips2 = 1; 1405 } else if (dc->config.disable_ips == DMUB_IPS_RCG_IN_ACTIVE_IPS2_IN_OFF) { 1406 /* TODO: Move this logic out to hwseq */ 1407 if (count_active_streams(dc) == 0) { 1408 /* IPS2 - Display off */ 1409 new_signals.bits.allow_pg = 1; 1410 new_signals.bits.allow_ips1 = 1; 1411 new_signals.bits.allow_ips2 = 1; 1412 new_signals.bits.allow_z10 = 1; 1413 // New in IPSv2.0 1414 new_signals.bits.allow_ips1z8 = 1; 1415 } else { 1416 /* RCG only */ 1417 new_signals.bits.allow_pg = 0; 1418 new_signals.bits.allow_ips1 = 1; 1419 new_signals.bits.allow_ips2 = 0; 1420 new_signals.bits.allow_z10 = 0; 1421 } 1422 } else if (dc->config.disable_ips == DMUB_IPS_DISABLE_Z8_RETENTION) { 1423 new_signals.bits.allow_pg = 1; 1424 new_signals.bits.allow_ips1 = 1; 1425 new_signals.bits.allow_ips2 = 1; 1426 new_signals.bits.allow_z10 = 1; 1427 } 1428 // Setting RCG allow bits (IPSv2.0) 1429 if (dc->config.disable_ips_rcg == DMUB_IPS_RCG_ENABLE) { 1430 new_signals.bits.allow_ips0_rcg = 1; 1431 new_signals.bits.allow_ips1_rcg = 1; 1432 } else if (dc->config.disable_ips_rcg == DMUB_IPS0_RCG_DISABLE) { 1433 new_signals.bits.allow_ips1_rcg = 1; 1434 } else if (dc->config.disable_ips_rcg == DMUB_IPS1_RCG_DISABLE) { 1435 new_signals.bits.allow_ips0_rcg = 1; 1436 } 1437 // IPS dynamic allow bits (IPSv2 change, vpb use case) 1438 if (dc->config.disable_ips_in_vpb == DMUB_IPS_VPB_ENABLE_IPS1_AND_RCG) { 1439 new_signals.bits.allow_dynamic_ips1 = 1; 1440 } else if (dc->config.disable_ips_in_vpb == DMUB_IPS_VPB_ENABLE_ALL) { 1441 new_signals.bits.allow_dynamic_ips1 = 1; 1442 new_signals.bits.allow_dynamic_ips1_z8 = 1; 1443 } 1444 ips_driver->signals = new_signals; 1445 dc_dmub_srv->driver_signals = ips_driver->signals; 1446 } 1447 1448 DC_LOG_IPS( 1449 "%s send allow_idle=%d (ips1_commit=%u ips2_commit=%u)", 1450 __func__, 1451 allow_idle, 1452 ips_fw->signals.bits.ips1_commit, 1453 ips_fw->signals.bits.ips2_commit); 1454 1455 /* NOTE: This does not use the "wake" interface since this is part of the wake path. */ 1456 /* We also do not perform a wait since DMCUB could enter idle after the notification. */ 1457 dm_execute_dmub_cmd(dc->ctx, &cmd, allow_idle ? DM_DMUB_WAIT_TYPE_NO_WAIT : DM_DMUB_WAIT_TYPE_WAIT); 1458 1459 /* Register access should stop at this point. */ 1460 if (allow_idle) 1461 dc_dmub_srv->needs_idle_wake = true; 1462 } 1463 1464 static void dc_dmub_srv_exit_low_power_state(const struct dc *dc) 1465 { 1466 struct dc_dmub_srv *dc_dmub_srv; 1467 uint32_t rcg_exit_count = 0, ips1_exit_count = 0, ips2_exit_count = 0, ips1z8_exit_count = 0; 1468 1469 if (dc->debug.dmcub_emulation) 1470 return; 1471 1472 if (!dc->ctx->dmub_srv || !dc->ctx->dmub_srv->dmub) 1473 return; 1474 1475 dc_dmub_srv = dc->ctx->dmub_srv; 1476 1477 if (dc->clk_mgr->funcs->exit_low_power_state) { 1478 volatile const struct dmub_shared_state_ips_fw *ips_fw = 1479 &dc_dmub_srv->dmub->shared_state[DMUB_SHARED_SHARE_FEATURE__IPS_FW].data.ips_fw; 1480 volatile struct dmub_shared_state_ips_driver *ips_driver = 1481 &dc_dmub_srv->dmub->shared_state[DMUB_SHARED_SHARE_FEATURE__IPS_DRIVER].data.ips_driver; 1482 union dmub_shared_state_ips_driver_signals prev_driver_signals = ips_driver->signals; 1483 1484 rcg_exit_count = ips_fw->rcg_exit_count; 1485 ips1_exit_count = ips_fw->ips1_exit_count; 1486 ips2_exit_count = ips_fw->ips2_exit_count; 1487 ips1z8_exit_count = ips_fw->ips1_z8ret_exit_count; 1488 1489 ips_driver->signals.all = 0; 1490 dc_dmub_srv->driver_signals = ips_driver->signals; 1491 1492 DC_LOG_IPS( 1493 "%s (allow ips1=%u ips2=%u) (commit ips1=%u ips2=%u ips1z8=%u) (count rcg=%u ips1=%u ips2=%u ips1_z8=%u)", 1494 __func__, 1495 ips_driver->signals.bits.allow_ips1, 1496 ips_driver->signals.bits.allow_ips2, 1497 ips_fw->signals.bits.ips1_commit, 1498 ips_fw->signals.bits.ips2_commit, 1499 ips_fw->signals.bits.ips1z8_commit, 1500 ips_fw->rcg_entry_count, 1501 ips_fw->ips1_entry_count, 1502 ips_fw->ips2_entry_count, 1503 ips_fw->ips1_z8ret_entry_count); 1504 1505 /* Note: register access has technically not resumed for DCN here, but we 1506 * need to be message PMFW through our standard register interface. 1507 */ 1508 dc_dmub_srv->needs_idle_wake = false; 1509 1510 if (!dc->caps.ips_v2_support && ((prev_driver_signals.bits.allow_ips2 || prev_driver_signals.all == 0) && 1511 (!dc->debug.optimize_ips_handshake || 1512 ips_fw->signals.bits.ips2_commit || !ips_fw->signals.bits.in_idle))) { 1513 DC_LOG_IPS( 1514 "wait IPS2 eval (ips1_commit=%u ips2_commit=%u )", 1515 ips_fw->signals.bits.ips1_commit, 1516 ips_fw->signals.bits.ips2_commit); 1517 1518 if (!dc->debug.optimize_ips_handshake || !ips_fw->signals.bits.ips2_commit) 1519 udelay(dc->debug.ips2_eval_delay_us); 1520 1521 DC_LOG_IPS( 1522 "exit IPS2 #1 (ips1_commit=%u ips2_commit=%u)", 1523 ips_fw->signals.bits.ips1_commit, 1524 ips_fw->signals.bits.ips2_commit); 1525 1526 // Tell PMFW to exit low power state 1527 dc->clk_mgr->funcs->exit_low_power_state(dc->clk_mgr); 1528 1529 if (ips_fw->signals.bits.ips2_commit) { 1530 1531 DC_LOG_IPS( 1532 "wait IPS2 entry delay (ips1_commit=%u ips2_commit=%u)", 1533 ips_fw->signals.bits.ips1_commit, 1534 ips_fw->signals.bits.ips2_commit); 1535 1536 // Wait for IPS2 entry upper bound 1537 udelay(dc->debug.ips2_entry_delay_us); 1538 1539 DC_LOG_IPS( 1540 "exit IPS2 #2 (ips1_commit=%u ips2_commit=%u)", 1541 ips_fw->signals.bits.ips1_commit, 1542 ips_fw->signals.bits.ips2_commit); 1543 1544 dc->clk_mgr->funcs->exit_low_power_state(dc->clk_mgr); 1545 1546 DC_LOG_IPS( 1547 "wait IPS2 commit clear (ips1_commit=%u ips2_commit=%u)", 1548 ips_fw->signals.bits.ips1_commit, 1549 ips_fw->signals.bits.ips2_commit); 1550 1551 while (ips_fw->signals.bits.ips2_commit) 1552 udelay(1); 1553 1554 DC_LOG_IPS( 1555 "wait hw_pwr_up (ips1_commit=%u ips2_commit=%u)", 1556 ips_fw->signals.bits.ips1_commit, 1557 ips_fw->signals.bits.ips2_commit); 1558 1559 if (!dc_dmub_srv_is_hw_pwr_up(dc->ctx->dmub_srv, true)) 1560 ASSERT(0); 1561 1562 DC_LOG_IPS( 1563 "resync inbox1 (ips1_commit=%u ips2_commit=%u)", 1564 ips_fw->signals.bits.ips1_commit, 1565 ips_fw->signals.bits.ips2_commit); 1566 1567 dmub_srv_sync_inboxes(dc->ctx->dmub_srv->dmub); 1568 } 1569 } 1570 1571 dc_dmub_srv_notify_idle(dc, false); 1572 if (prev_driver_signals.bits.allow_ips1 || prev_driver_signals.all == 0) { 1573 DC_LOG_IPS( 1574 "wait for IPS1 commit clear (ips1_commit=%u ips2_commit=%u ips1z8=%u)", 1575 ips_fw->signals.bits.ips1_commit, 1576 ips_fw->signals.bits.ips2_commit, 1577 ips_fw->signals.bits.ips1z8_commit); 1578 1579 while (ips_fw->signals.bits.ips1_commit) 1580 udelay(1); 1581 1582 DC_LOG_IPS( 1583 "wait for IPS1 commit clear done (ips1_commit=%u ips2_commit=%u ips1z8=%u)", 1584 ips_fw->signals.bits.ips1_commit, 1585 ips_fw->signals.bits.ips2_commit, 1586 ips_fw->signals.bits.ips1z8_commit); 1587 } 1588 } 1589 1590 if (!dc_dmub_srv_is_hw_pwr_up(dc->ctx->dmub_srv, true)) 1591 ASSERT(0); 1592 1593 DC_LOG_IPS("%s exit (count rcg=%u ips1=%u ips2=%u ips1z8=%u)", 1594 __func__, 1595 rcg_exit_count, 1596 ips1_exit_count, 1597 ips2_exit_count, 1598 ips1z8_exit_count); 1599 } 1600 1601 void dc_dmub_srv_set_power_state(struct dc_dmub_srv *dc_dmub_srv, enum dc_acpi_cm_power_state power_state) 1602 { 1603 struct dmub_srv *dmub; 1604 1605 if (!dc_dmub_srv) 1606 return; 1607 1608 dmub = dc_dmub_srv->dmub; 1609 1610 if (power_state == DC_ACPI_CM_POWER_STATE_D0) 1611 dmub_srv_set_power_state(dmub, DMUB_POWER_STATE_D0); 1612 else 1613 dmub_srv_set_power_state(dmub, DMUB_POWER_STATE_D3); 1614 } 1615 1616 void dc_dmub_srv_notify_fw_dc_power_state(struct dc_dmub_srv *dc_dmub_srv, 1617 enum dc_acpi_cm_power_state power_state) 1618 { 1619 union dmub_rb_cmd cmd; 1620 1621 if (!dc_dmub_srv) 1622 return; 1623 1624 memset(&cmd, 0, sizeof(cmd)); 1625 1626 cmd.idle_opt_set_dc_power_state.header.type = DMUB_CMD__IDLE_OPT; 1627 cmd.idle_opt_set_dc_power_state.header.sub_type = DMUB_CMD__IDLE_OPT_SET_DC_POWER_STATE; 1628 cmd.idle_opt_set_dc_power_state.header.payload_bytes = 1629 sizeof(cmd.idle_opt_set_dc_power_state) - sizeof(cmd.idle_opt_set_dc_power_state.header); 1630 1631 if (power_state == DC_ACPI_CM_POWER_STATE_D0) { 1632 cmd.idle_opt_set_dc_power_state.data.power_state = DMUB_IDLE_OPT_DC_POWER_STATE_D0; 1633 } else if (power_state == DC_ACPI_CM_POWER_STATE_D3) { 1634 cmd.idle_opt_set_dc_power_state.data.power_state = DMUB_IDLE_OPT_DC_POWER_STATE_D3; 1635 } else { 1636 cmd.idle_opt_set_dc_power_state.data.power_state = DMUB_IDLE_OPT_DC_POWER_STATE_UNKNOWN; 1637 } 1638 1639 dc_wake_and_execute_dmub_cmd(dc_dmub_srv->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); 1640 } 1641 1642 bool dc_dmub_srv_should_detect(struct dc_dmub_srv *dc_dmub_srv) 1643 { 1644 volatile const struct dmub_shared_state_ips_fw *ips_fw; 1645 bool reallow_idle = false, should_detect = false; 1646 1647 if (!dc_dmub_srv || !dc_dmub_srv->dmub) 1648 return false; 1649 1650 if (dc_dmub_srv->dmub->shared_state && 1651 dc_dmub_srv->dmub->meta_info.feature_bits.bits.shared_state_link_detection) { 1652 ips_fw = &dc_dmub_srv->dmub->shared_state[DMUB_SHARED_SHARE_FEATURE__IPS_FW].data.ips_fw; 1653 return (bool)ips_fw->signals.bits.detection_required; 1654 } 1655 1656 /* Detection may require reading scratch 0 - exit out of idle prior to the read. */ 1657 if (dc_dmub_srv->idle_allowed) { 1658 dc_dmub_srv_apply_idle_power_optimizations(dc_dmub_srv->ctx->dc, false); 1659 reallow_idle = true; 1660 } 1661 1662 should_detect = dmub_srv_should_detect(dc_dmub_srv->dmub); 1663 1664 /* Re-enter idle if we're not about to immediately redetect links. */ 1665 if (!should_detect && reallow_idle && dc_dmub_srv->idle_exit_counter == 0 && 1666 !dc_dmub_srv->ctx->dc->debug.disable_dmub_reallow_idle) 1667 dc_dmub_srv_apply_idle_power_optimizations(dc_dmub_srv->ctx->dc, true); 1668 1669 return should_detect; 1670 } 1671 1672 void dc_dmub_srv_apply_idle_power_optimizations(const struct dc *dc, bool allow_idle) 1673 { 1674 struct dc_dmub_srv *dc_dmub_srv = dc->ctx->dmub_srv; 1675 1676 if (!dc_dmub_srv || !dc_dmub_srv->dmub) 1677 return; 1678 1679 allow_idle &= (!dc->debug.ips_disallow_entry); 1680 1681 if (dc_dmub_srv->idle_allowed == allow_idle) 1682 return; 1683 1684 DC_LOG_IPS("%s state change: old=%d new=%d", __func__, dc_dmub_srv->idle_allowed, allow_idle); 1685 1686 /* 1687 * Entering a low power state requires a driver notification. 1688 * Powering up the hardware requires notifying PMFW and DMCUB. 1689 * Clearing the driver idle allow requires a DMCUB command. 1690 * DMCUB commands requires the DMCUB to be powered up and restored. 1691 */ 1692 1693 if (!allow_idle) { 1694 dc_dmub_srv->idle_exit_counter += 1; 1695 1696 dc_dmub_srv_exit_low_power_state(dc); 1697 /* 1698 * Idle is considered fully exited only after the sequence above 1699 * fully completes. If we have a race of two threads exiting 1700 * at the same time then it's safe to perform the sequence 1701 * twice as long as we're not re-entering. 1702 * 1703 * Infinite command submission is avoided by using the 1704 * dm_execute_dmub_cmd submission instead of the "wake" helpers. 1705 */ 1706 dc_dmub_srv->idle_allowed = false; 1707 1708 dc_dmub_srv->idle_exit_counter -= 1; 1709 if (dc_dmub_srv->idle_exit_counter < 0) { 1710 ASSERT(0); 1711 dc_dmub_srv->idle_exit_counter = 0; 1712 } 1713 } else { 1714 /* Consider idle as notified prior to the actual submission to 1715 * prevent multiple entries. */ 1716 dc_dmub_srv->idle_allowed = true; 1717 1718 dc_dmub_srv_notify_idle(dc, allow_idle); 1719 } 1720 } 1721 1722 bool dc_wake_and_execute_dmub_cmd(const struct dc_context *ctx, union dmub_rb_cmd *cmd, 1723 enum dm_dmub_wait_type wait_type) 1724 { 1725 return dc_wake_and_execute_dmub_cmd_list(ctx, 1, cmd, wait_type); 1726 } 1727 1728 bool dc_wake_and_execute_dmub_cmd_list(const struct dc_context *ctx, unsigned int count, 1729 union dmub_rb_cmd *cmd, enum dm_dmub_wait_type wait_type) 1730 { 1731 struct dc_dmub_srv *dc_dmub_srv = ctx->dmub_srv; 1732 bool result = false, reallow_idle = false; 1733 1734 if (!dc_dmub_srv || !dc_dmub_srv->dmub) 1735 return false; 1736 1737 if (count == 0) 1738 return true; 1739 1740 if (dc_dmub_srv->idle_allowed) { 1741 dc_dmub_srv_apply_idle_power_optimizations(ctx->dc, false); 1742 reallow_idle = true; 1743 } 1744 1745 /* 1746 * These may have different implementations in DM, so ensure 1747 * that we guide it to the expected helper. 1748 */ 1749 if (count > 1) 1750 result = dm_execute_dmub_cmd_list(ctx, count, cmd, wait_type); 1751 else 1752 result = dm_execute_dmub_cmd(ctx, cmd, wait_type); 1753 1754 if (result && reallow_idle && dc_dmub_srv->idle_exit_counter == 0 && 1755 !ctx->dc->debug.disable_dmub_reallow_idle) 1756 dc_dmub_srv_apply_idle_power_optimizations(ctx->dc, true); 1757 1758 return result; 1759 } 1760 1761 static bool dc_dmub_execute_gpint(const struct dc_context *ctx, enum dmub_gpint_command command_code, 1762 uint16_t param, uint32_t *response, enum dm_dmub_wait_type wait_type) 1763 { 1764 struct dc_dmub_srv *dc_dmub_srv = ctx->dmub_srv; 1765 const uint32_t wait_us = wait_type == DM_DMUB_WAIT_TYPE_NO_WAIT ? 0 : 30; 1766 enum dmub_status status; 1767 1768 if (response) 1769 *response = 0; 1770 1771 if (!dc_dmub_srv || !dc_dmub_srv->dmub) 1772 return false; 1773 1774 status = dmub_srv_send_gpint_command(dc_dmub_srv->dmub, command_code, param, wait_us); 1775 if (status != DMUB_STATUS_OK) { 1776 if (status == DMUB_STATUS_TIMEOUT && wait_type == DM_DMUB_WAIT_TYPE_NO_WAIT) 1777 return true; 1778 1779 return false; 1780 } 1781 1782 if (response && wait_type == DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY) 1783 dmub_srv_get_gpint_response(dc_dmub_srv->dmub, response); 1784 1785 return true; 1786 } 1787 1788 bool dc_wake_and_execute_gpint(const struct dc_context *ctx, enum dmub_gpint_command command_code, 1789 uint16_t param, uint32_t *response, enum dm_dmub_wait_type wait_type) 1790 { 1791 struct dc_dmub_srv *dc_dmub_srv = ctx->dmub_srv; 1792 bool result = false, reallow_idle = false; 1793 1794 if (!dc_dmub_srv || !dc_dmub_srv->dmub) 1795 return false; 1796 1797 if (dc_dmub_srv->idle_allowed) { 1798 dc_dmub_srv_apply_idle_power_optimizations(ctx->dc, false); 1799 reallow_idle = true; 1800 } 1801 1802 result = dc_dmub_execute_gpint(ctx, command_code, param, response, wait_type); 1803 1804 if (result && reallow_idle && dc_dmub_srv->idle_exit_counter == 0 && 1805 !ctx->dc->debug.disable_dmub_reallow_idle) 1806 dc_dmub_srv_apply_idle_power_optimizations(ctx->dc, true); 1807 1808 return result; 1809 } 1810 1811 static void dc_dmub_srv_rb_based_fams2_update_config(struct dc *dc, 1812 struct dc_state *context, 1813 bool enable) 1814 { 1815 uint32_t num_cmds = 1; 1816 uint32_t i; 1817 union dmub_rb_cmd cmd[2 * MAX_STREAMS + 1]; 1818 struct dmub_rb_cmd_fams2 *global_cmd = &cmd[0].fams2_config; 1819 1820 memset(cmd, 0, sizeof(union dmub_rb_cmd) * (2 * MAX_STREAMS + 1)); 1821 /* fill in generic command header */ 1822 global_cmd->header.type = DMUB_CMD__FW_ASSISTED_MCLK_SWITCH; 1823 global_cmd->header.sub_type = DMUB_CMD__FAMS2_CONFIG; 1824 global_cmd->header.payload_bytes = 1825 sizeof(struct dmub_rb_cmd_fams2) - sizeof(struct dmub_cmd_header); 1826 1827 if (enable) { 1828 /* send global configuration parameters */ 1829 memcpy(&global_cmd->config.global, &context->bw_ctx.bw.dcn.fams2_global_config, sizeof(struct dmub_cmd_fams2_global_config)); 1830 1831 /* copy static feature configuration overrides */ 1832 global_cmd->config.global.features.bits.enable_stall_recovery = dc->debug.fams2_config.bits.enable_stall_recovery; 1833 global_cmd->config.global.features.bits.enable_debug = dc->debug.fams2_config.bits.enable_debug; 1834 global_cmd->config.global.features.bits.enable_offload_flip = dc->debug.fams2_config.bits.enable_offload_flip; 1835 1836 /* construct per-stream configs */ 1837 for (i = 0; i < context->bw_ctx.bw.dcn.fams2_global_config.num_streams; i++) { 1838 struct dmub_rb_cmd_fams2 *stream_base_cmd = &cmd[i+1].fams2_config; 1839 struct dmub_rb_cmd_fams2 *stream_sub_state_cmd = &cmd[i+1+context->bw_ctx.bw.dcn.fams2_global_config.num_streams].fams2_config; 1840 1841 /* configure command header */ 1842 stream_base_cmd->header.type = DMUB_CMD__FW_ASSISTED_MCLK_SWITCH; 1843 stream_base_cmd->header.sub_type = DMUB_CMD__FAMS2_CONFIG; 1844 stream_base_cmd->header.payload_bytes = 1845 sizeof(struct dmub_rb_cmd_fams2) - sizeof(struct dmub_cmd_header); 1846 stream_base_cmd->header.multi_cmd_pending = 1; 1847 stream_sub_state_cmd->header.type = DMUB_CMD__FW_ASSISTED_MCLK_SWITCH; 1848 stream_sub_state_cmd->header.sub_type = DMUB_CMD__FAMS2_CONFIG; 1849 stream_sub_state_cmd->header.payload_bytes = 1850 sizeof(struct dmub_rb_cmd_fams2) - sizeof(struct dmub_cmd_header); 1851 stream_sub_state_cmd->header.multi_cmd_pending = 1; 1852 /* copy stream static base state */ 1853 memcpy(&stream_base_cmd->config, 1854 &context->bw_ctx.bw.dcn.fams2_stream_base_params[i], 1855 sizeof(union dmub_cmd_fams2_config)); 1856 /* copy stream static sub state */ 1857 memcpy(&stream_sub_state_cmd->config, 1858 &context->bw_ctx.bw.dcn.fams2_stream_sub_params[i], 1859 sizeof(union dmub_cmd_fams2_config)); 1860 } 1861 } 1862 1863 /* apply feature configuration based on current driver state */ 1864 global_cmd->config.global.features.bits.enable_visual_confirm = dc->debug.visual_confirm == VISUAL_CONFIRM_FAMS2; 1865 global_cmd->config.global.features.bits.enable = enable && context->bw_ctx.bw.dcn.fams2_global_config.features.bits.enable; 1866 global_cmd->config.global.features.bits.enable_ppt_check = dc->debug.fams2_config.bits.enable_ppt_check; 1867 1868 if (enable) { 1869 /* set multi pending for global, and unset for last stream cmd */ 1870 global_cmd->header.multi_cmd_pending = 1; 1871 cmd[2 * context->bw_ctx.bw.dcn.fams2_global_config.num_streams].fams2_config.header.multi_cmd_pending = 0; 1872 num_cmds += 2 * context->bw_ctx.bw.dcn.fams2_global_config.num_streams; 1873 } 1874 1875 dm_execute_dmub_cmd_list(dc->ctx, num_cmds, cmd, DM_DMUB_WAIT_TYPE_WAIT); 1876 } 1877 1878 static void dc_dmub_srv_ib_based_fams2_update_config(struct dc *dc, 1879 struct dc_state *context, 1880 bool enable) 1881 { 1882 struct dmub_fams2_config_v2 *config = (struct dmub_fams2_config_v2 *)dc->ctx->dmub_srv->dmub->ib_mem_gart.cpu_addr; 1883 union dmub_rb_cmd cmd; 1884 uint32_t i; 1885 1886 memset(config, 0, sizeof(*config)); 1887 memset(&cmd, 0, sizeof(cmd)); 1888 1889 cmd.ib_fams2_config.header.type = DMUB_CMD__FW_ASSISTED_MCLK_SWITCH; 1890 cmd.ib_fams2_config.header.sub_type = DMUB_CMD__FAMS2_IB_CONFIG; 1891 1892 cmd.ib_fams2_config.ib_data.src.quad_part = dc->ctx->dmub_srv->dmub->ib_mem_gart.gpu_addr; 1893 cmd.ib_fams2_config.ib_data.size = sizeof(*config); 1894 1895 if (enable) { 1896 /* send global configuration parameters */ 1897 memcpy(&config->global, &context->bw_ctx.bw.dcn.fams2_global_config, 1898 sizeof(struct dmub_cmd_fams2_global_config)); 1899 1900 /* copy static feature configuration overrides */ 1901 config->global.features.bits.enable_stall_recovery = dc->debug.fams2_config.bits.enable_stall_recovery; 1902 config->global.features.bits.enable_offload_flip = dc->debug.fams2_config.bits.enable_offload_flip; 1903 config->global.features.bits.enable_debug = dc->debug.fams2_config.bits.enable_debug; 1904 1905 /* construct per-stream configs */ 1906 for (i = 0; i < context->bw_ctx.bw.dcn.fams2_global_config.num_streams; i++) { 1907 /* copy stream static base state */ 1908 memcpy(&config->stream_v1[i].base, 1909 &context->bw_ctx.bw.dcn.fams2_stream_base_params[i], 1910 sizeof(config->stream_v1[i].base)); 1911 1912 /* copy stream static sub-state */ 1913 memcpy(&config->stream_v1[i].sub_state, 1914 &context->bw_ctx.bw.dcn.fams2_stream_sub_params_v2[i], 1915 sizeof(config->stream_v1[i].sub_state)); 1916 } 1917 } 1918 1919 config->global.features.bits.enable_visual_confirm = dc->debug.visual_confirm == VISUAL_CONFIRM_FAMS2; 1920 config->global.features.bits.enable = enable && context->bw_ctx.bw.dcn.fams2_global_config.features.bits.enable; 1921 config->global.features.bits.enable_ppt_check = dc->debug.fams2_config.bits.enable_ppt_check; 1922 1923 dm_execute_dmub_cmd_list(dc->ctx, 1, &cmd, DM_DMUB_WAIT_TYPE_WAIT); 1924 } 1925 1926 void dc_dmub_srv_fams2_update_config(struct dc *dc, 1927 struct dc_state *context, 1928 bool enable) 1929 { 1930 if (dc->debug.fams_version.major == 2) 1931 dc_dmub_srv_rb_based_fams2_update_config(dc, context, enable); 1932 if (dc->debug.fams_version.major == 3) 1933 dc_dmub_srv_ib_based_fams2_update_config(dc, context, enable); 1934 } 1935 1936 void dc_dmub_srv_fams2_drr_update(struct dc *dc, 1937 uint32_t tg_inst, 1938 uint32_t vtotal_min, 1939 uint32_t vtotal_max, 1940 uint32_t vtotal_mid, 1941 uint32_t vtotal_mid_frame_num, 1942 bool program_manual_trigger) 1943 { 1944 union dmub_rb_cmd cmd = { 0 }; 1945 1946 cmd.fams2_drr_update.header.type = DMUB_CMD__FW_ASSISTED_MCLK_SWITCH; 1947 cmd.fams2_drr_update.header.sub_type = DMUB_CMD__FAMS2_DRR_UPDATE; 1948 cmd.fams2_drr_update.dmub_optc_state_req.tg_inst = (uint8_t)tg_inst; 1949 cmd.fams2_drr_update.dmub_optc_state_req.v_total_max = vtotal_max; 1950 cmd.fams2_drr_update.dmub_optc_state_req.v_total_min = vtotal_min; 1951 cmd.fams2_drr_update.dmub_optc_state_req.v_total_mid = vtotal_mid; 1952 cmd.fams2_drr_update.dmub_optc_state_req.v_total_mid_frame_num = vtotal_mid_frame_num; 1953 cmd.fams2_drr_update.dmub_optc_state_req.program_manual_trigger = program_manual_trigger; 1954 1955 cmd.fams2_drr_update.header.payload_bytes = 1956 sizeof(cmd.fams2_drr_update) - sizeof(cmd.fams2_drr_update.header); 1957 1958 dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); 1959 } 1960 1961 void dc_dmub_srv_fams2_passthrough_flip( 1962 struct dc *dc, 1963 struct dc_state *state, 1964 struct dc_stream_state *stream, 1965 struct dc_surface_update *srf_updates, 1966 int surface_count) 1967 { 1968 int plane_index; 1969 union dmub_rb_cmd cmds[MAX_PLANES]; 1970 struct dc_plane_address *address; 1971 struct dc_plane_state *plane_state; 1972 int num_cmds = 0; 1973 struct dc_stream_status *stream_status = dc_stream_get_status(stream); 1974 1975 if (surface_count <= 0 || stream_status == NULL) 1976 return; 1977 1978 memset(cmds, 0, sizeof(union dmub_rb_cmd) * MAX_PLANES); 1979 1980 /* build command for each surface update */ 1981 for (plane_index = 0; plane_index < surface_count; plane_index++) { 1982 plane_state = srf_updates[plane_index].surface; 1983 address = &plane_state->address; 1984 1985 /* skip if there is no address update for plane */ 1986 if (!srf_updates[plane_index].flip_addr) 1987 continue; 1988 1989 /* build command header */ 1990 cmds[num_cmds].fams2_flip.header.type = DMUB_CMD__FW_ASSISTED_MCLK_SWITCH; 1991 cmds[num_cmds].fams2_flip.header.sub_type = DMUB_CMD__FAMS2_FLIP; 1992 cmds[num_cmds].fams2_flip.header.payload_bytes = 1993 sizeof(struct dmub_rb_cmd_fams2_flip) - sizeof(struct dmub_cmd_header); 1994 1995 /* for chaining multiple commands, all but last command should set to 1 */ 1996 cmds[num_cmds].fams2_flip.header.multi_cmd_pending = 1; 1997 1998 /* set topology info */ 1999 cmds[num_cmds].fams2_flip.flip_info.pipe_mask = (uint8_t)dc_plane_get_pipe_mask(state, plane_state); 2000 if (stream_status) { 2001 cmds[num_cmds].fams2_flip.flip_info.otg_inst = (uint8_t)stream_status->primary_otg_inst; 2002 } 2003 cmds[num_cmds].fams2_flip.flip_info.config.bits.is_immediate = plane_state->flip_immediate; 2004 2005 /* build address info for command */ 2006 switch (address->type) { 2007 case PLN_ADDR_TYPE_GRAPHICS: 2008 if (address->grph.addr.quad_part == 0) { 2009 BREAK_TO_DEBUGGER(); 2010 break; 2011 } 2012 2013 cmds[num_cmds].fams2_flip.flip_info.addr_info.meta_addr_lo = 2014 address->grph.meta_addr.low_part; 2015 cmds[num_cmds].fams2_flip.flip_info.addr_info.meta_addr_hi = 2016 (uint16_t)address->grph.meta_addr.high_part; 2017 cmds[num_cmds].fams2_flip.flip_info.addr_info.surf_addr_lo = 2018 address->grph.addr.low_part; 2019 cmds[num_cmds].fams2_flip.flip_info.addr_info.surf_addr_hi = 2020 (uint16_t)address->grph.addr.high_part; 2021 break; 2022 case PLN_ADDR_TYPE_VIDEO_PROGRESSIVE: 2023 if (address->video_progressive.luma_addr.quad_part == 0 || 2024 address->video_progressive.chroma_addr.quad_part == 0) { 2025 BREAK_TO_DEBUGGER(); 2026 break; 2027 } 2028 2029 cmds[num_cmds].fams2_flip.flip_info.addr_info.meta_addr_lo = 2030 address->video_progressive.luma_meta_addr.low_part; 2031 cmds[num_cmds].fams2_flip.flip_info.addr_info.meta_addr_hi = 2032 (uint16_t)address->video_progressive.luma_meta_addr.high_part; 2033 cmds[num_cmds].fams2_flip.flip_info.addr_info.meta_addr_c_lo = 2034 address->video_progressive.chroma_meta_addr.low_part; 2035 cmds[num_cmds].fams2_flip.flip_info.addr_info.meta_addr_c_hi = 2036 (uint16_t)address->video_progressive.chroma_meta_addr.high_part; 2037 cmds[num_cmds].fams2_flip.flip_info.addr_info.surf_addr_lo = 2038 address->video_progressive.luma_addr.low_part; 2039 cmds[num_cmds].fams2_flip.flip_info.addr_info.surf_addr_hi = 2040 (uint16_t)address->video_progressive.luma_addr.high_part; 2041 cmds[num_cmds].fams2_flip.flip_info.addr_info.surf_addr_c_lo = 2042 address->video_progressive.chroma_addr.low_part; 2043 cmds[num_cmds].fams2_flip.flip_info.addr_info.surf_addr_c_hi = 2044 (uint16_t)address->video_progressive.chroma_addr.high_part; 2045 break; 2046 default: 2047 // Should never be hit 2048 BREAK_TO_DEBUGGER(); 2049 break; 2050 } 2051 2052 num_cmds++; 2053 } 2054 2055 if (num_cmds > 0) { 2056 cmds[num_cmds - 1].fams2_flip.header.multi_cmd_pending = 0; 2057 dm_execute_dmub_cmd_list(dc->ctx, num_cmds, cmds, DM_DMUB_WAIT_TYPE_WAIT); 2058 } 2059 } 2060 2061 2062 bool dc_dmub_srv_ips_residency_cntl(const struct dc_context *ctx, uint8_t panel_inst, bool start_measurement) 2063 { 2064 union dmub_rb_cmd cmd; 2065 2066 memset(&cmd, 0, sizeof(cmd)); 2067 2068 cmd.ips_residency_cntl.header.type = DMUB_CMD__IPS; 2069 cmd.ips_residency_cntl.header.sub_type = DMUB_CMD__IPS_RESIDENCY_CNTL; 2070 cmd.ips_residency_cntl.header.payload_bytes = sizeof(struct dmub_cmd_ips_residency_cntl_data); 2071 2072 // only panel_inst=0 is supported at the moment 2073 cmd.ips_residency_cntl.cntl_data.panel_inst = panel_inst; 2074 cmd.ips_residency_cntl.cntl_data.start_measurement = start_measurement; 2075 2076 if (!dc_wake_and_execute_dmub_cmd(ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)) 2077 return false; 2078 2079 return true; 2080 } 2081 2082 bool dc_dmub_srv_ips_query_residency_info(const struct dc_context *ctx, uint8_t panel_inst, struct dmub_ips_residency_info *driver_info, 2083 enum ips_residency_mode ips_mode) 2084 { 2085 union dmub_rb_cmd cmd; 2086 uint32_t bytes = sizeof(struct dmub_ips_residency_info); 2087 2088 dmub_flush_buffer_mem(&ctx->dmub_srv->dmub->scratch_mem_fb); 2089 memset(&cmd, 0, sizeof(cmd)); 2090 2091 cmd.ips_query_residency_info.header.type = DMUB_CMD__IPS; 2092 cmd.ips_query_residency_info.header.sub_type = DMUB_CMD__IPS_QUERY_RESIDENCY_INFO; 2093 cmd.ips_query_residency_info.header.payload_bytes = sizeof(struct dmub_cmd_ips_query_residency_info_data); 2094 2095 cmd.ips_query_residency_info.info_data.dest.quad_part = ctx->dmub_srv->dmub->scratch_mem_fb.gpu_addr; 2096 cmd.ips_query_residency_info.info_data.size = bytes; 2097 cmd.ips_query_residency_info.info_data.panel_inst = panel_inst; 2098 cmd.ips_query_residency_info.info_data.ips_mode = (uint32_t)ips_mode; 2099 2100 if (!dc_wake_and_execute_dmub_cmd(ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY) || 2101 cmd.ips_query_residency_info.header.ret_status == 0) 2102 return false; 2103 2104 // copy the result to the output since ret_status != 0 means the command returned data 2105 memcpy(driver_info, ctx->dmub_srv->dmub->scratch_mem_fb.cpu_addr, bytes); 2106 2107 return true; 2108 } 2109 2110 bool dmub_lsdma_init(struct dc_dmub_srv *dc_dmub_srv) 2111 { 2112 struct dc_context *dc_ctx = dc_dmub_srv->ctx; 2113 union dmub_rb_cmd cmd; 2114 enum dm_dmub_wait_type wait_type; 2115 struct dmub_cmd_lsdma_data *lsdma_data = &cmd.lsdma.lsdma_data; 2116 bool result; 2117 2118 if (!dc_dmub_srv->dmub->feature_caps.lsdma_support_in_dmu) 2119 return false; 2120 2121 memset(&cmd, 0, sizeof(cmd)); 2122 2123 cmd.cmd_common.header.type = DMUB_CMD__LSDMA; 2124 cmd.cmd_common.header.sub_type = DMUB_CMD__LSDMA_INIT_CONFIG; 2125 wait_type = DM_DMUB_WAIT_TYPE_NO_WAIT; 2126 2127 lsdma_data->u.init_data.gpu_addr_base.quad_part = dc_ctx->dmub_srv->dmub->lsdma_rb_fb.gpu_addr; 2128 lsdma_data->u.init_data.ring_size = dc_ctx->dmub_srv->dmub->lsdma_rb_fb.size; 2129 2130 result = dc_wake_and_execute_dmub_cmd(dc_ctx, &cmd, wait_type); 2131 2132 if (!result) 2133 DC_ERROR("LSDMA Init failed in DMUB"); 2134 2135 return result; 2136 } 2137 2138 bool dmub_lsdma_send_linear_copy_command( 2139 struct dc_dmub_srv *dc_dmub_srv, 2140 uint64_t src_addr, 2141 uint64_t dst_addr, 2142 uint32_t count 2143 ) 2144 { 2145 struct dc_context *dc_ctx = dc_dmub_srv->ctx; 2146 union dmub_rb_cmd cmd; 2147 enum dm_dmub_wait_type wait_type; 2148 struct dmub_cmd_lsdma_data *lsdma_data = &cmd.lsdma.lsdma_data; 2149 bool result; 2150 2151 memset(&cmd, 0, sizeof(cmd)); 2152 2153 cmd.cmd_common.header.type = DMUB_CMD__LSDMA; 2154 cmd.cmd_common.header.sub_type = DMUB_CMD__LSDMA_LINEAR_COPY; 2155 wait_type = DM_DMUB_WAIT_TYPE_NO_WAIT; 2156 2157 lsdma_data->u.linear_copy_data.count = count - 1; // LSDMA controller expects bytes to copy -1 2158 lsdma_data->u.linear_copy_data.src_lo = src_addr & 0xFFFFFFFF; 2159 lsdma_data->u.linear_copy_data.src_hi = (src_addr >> 32) & 0xFFFFFFFF; 2160 lsdma_data->u.linear_copy_data.dst_lo = dst_addr & 0xFFFFFFFF; 2161 lsdma_data->u.linear_copy_data.dst_hi = (dst_addr >> 32) & 0xFFFFFFFF; 2162 2163 result = dc_wake_and_execute_dmub_cmd(dc_ctx, &cmd, wait_type); 2164 2165 if (!result) 2166 DC_ERROR("LSDMA Linear Copy failed in DMUB"); 2167 2168 return result; 2169 } 2170 2171 bool dmub_lsdma_send_linear_sub_window_copy_command( 2172 struct dc_dmub_srv *dc_dmub_srv, 2173 struct lsdma_linear_sub_window_copy_params copy_data 2174 ) 2175 { 2176 struct dc_context *dc_ctx = dc_dmub_srv->ctx; 2177 union dmub_rb_cmd cmd; 2178 enum dm_dmub_wait_type wait_type; 2179 struct dmub_cmd_lsdma_data *lsdma_data = &cmd.lsdma.lsdma_data; 2180 bool result; 2181 2182 memset(&cmd, 0, sizeof(cmd)); 2183 2184 cmd.cmd_common.header.type = DMUB_CMD__LSDMA; 2185 cmd.cmd_common.header.sub_type = DMUB_CMD__LSDMA_LINEAR_SUB_WINDOW_COPY; 2186 wait_type = DM_DMUB_WAIT_TYPE_NO_WAIT; 2187 2188 lsdma_data->u.linear_sub_window_copy_data.tmz = copy_data.tmz; 2189 lsdma_data->u.linear_sub_window_copy_data.element_size = copy_data.element_size; 2190 lsdma_data->u.linear_sub_window_copy_data.src_lo = copy_data.src_lo; 2191 lsdma_data->u.linear_sub_window_copy_data.src_hi = copy_data.src_hi; 2192 lsdma_data->u.linear_sub_window_copy_data.src_x = copy_data.src_x; 2193 lsdma_data->u.linear_sub_window_copy_data.src_y = copy_data.src_y; 2194 lsdma_data->u.linear_sub_window_copy_data.src_pitch = copy_data.src_pitch; 2195 lsdma_data->u.linear_sub_window_copy_data.src_slice_pitch = copy_data.src_slice_pitch; 2196 lsdma_data->u.linear_sub_window_copy_data.dst_lo = copy_data.dst_lo; 2197 lsdma_data->u.linear_sub_window_copy_data.dst_hi = copy_data.dst_hi; 2198 lsdma_data->u.linear_sub_window_copy_data.dst_x = copy_data.dst_x; 2199 lsdma_data->u.linear_sub_window_copy_data.dst_y = copy_data.dst_y; 2200 lsdma_data->u.linear_sub_window_copy_data.dst_pitch = copy_data.dst_pitch; 2201 lsdma_data->u.linear_sub_window_copy_data.dst_slice_pitch = copy_data.dst_slice_pitch; 2202 lsdma_data->u.linear_sub_window_copy_data.rect_x = copy_data.rect_x; 2203 lsdma_data->u.linear_sub_window_copy_data.rect_y = copy_data.rect_y; 2204 lsdma_data->u.linear_sub_window_copy_data.src_cache_policy = copy_data.src_cache_policy; 2205 lsdma_data->u.linear_sub_window_copy_data.dst_cache_policy = copy_data.dst_cache_policy; 2206 2207 result = dc_wake_and_execute_dmub_cmd(dc_ctx, &cmd, wait_type); 2208 2209 if (!result) 2210 DC_ERROR("LSDMA Linear Sub Window Copy failed in DMUB"); 2211 2212 return result; 2213 } 2214 2215 bool dmub_lsdma_send_tiled_to_tiled_copy_command( 2216 struct dc_dmub_srv *dc_dmub_srv, 2217 struct lsdma_send_tiled_to_tiled_copy_command_params params 2218 ) 2219 { 2220 struct dc_context *dc_ctx = dc_dmub_srv->ctx; 2221 union dmub_rb_cmd cmd; 2222 enum dm_dmub_wait_type wait_type; 2223 struct dmub_cmd_lsdma_data *lsdma_data = &cmd.lsdma.lsdma_data; 2224 bool result; 2225 2226 memset(&cmd, 0, sizeof(cmd)); 2227 2228 cmd.cmd_common.header.type = DMUB_CMD__LSDMA; 2229 cmd.cmd_common.header.sub_type = DMUB_CMD__LSDMA_TILED_TO_TILED_COPY; 2230 wait_type = DM_DMUB_WAIT_TYPE_NO_WAIT; 2231 2232 lsdma_data->u.tiled_copy_data.src_addr_lo = params.src_addr & 0xFFFFFFFF; 2233 lsdma_data->u.tiled_copy_data.src_addr_hi = (params.src_addr >> 32) & 0xFFFFFFFF; 2234 lsdma_data->u.tiled_copy_data.dst_addr_lo = params.dst_addr & 0xFFFFFFFF; 2235 lsdma_data->u.tiled_copy_data.dst_addr_hi = (params.dst_addr >> 32) & 0xFFFFFFFF; 2236 lsdma_data->u.tiled_copy_data.src_x = params.src_x; 2237 lsdma_data->u.tiled_copy_data.src_y = params.src_y; 2238 lsdma_data->u.tiled_copy_data.dst_x = params.dst_x; 2239 lsdma_data->u.tiled_copy_data.dst_y = params.dst_y; 2240 lsdma_data->u.tiled_copy_data.src_width = params.src_width; 2241 lsdma_data->u.tiled_copy_data.dst_width = params.dst_width; 2242 lsdma_data->u.tiled_copy_data.src_swizzle_mode = params.swizzle_mode; 2243 lsdma_data->u.tiled_copy_data.dst_swizzle_mode = params.swizzle_mode; 2244 lsdma_data->u.tiled_copy_data.src_element_size = params.element_size; 2245 lsdma_data->u.tiled_copy_data.dst_element_size = params.element_size; 2246 lsdma_data->u.tiled_copy_data.rect_x = params.rect_x; 2247 lsdma_data->u.tiled_copy_data.rect_y = params.rect_y; 2248 lsdma_data->u.tiled_copy_data.dcc = params.dcc; 2249 lsdma_data->u.tiled_copy_data.tmz = params.tmz; 2250 lsdma_data->u.tiled_copy_data.read_compress = params.read_compress; 2251 lsdma_data->u.tiled_copy_data.write_compress = params.write_compress; 2252 lsdma_data->u.tiled_copy_data.src_height = params.src_height; 2253 lsdma_data->u.tiled_copy_data.dst_height = params.dst_height; 2254 lsdma_data->u.tiled_copy_data.data_format = params.data_format; 2255 lsdma_data->u.tiled_copy_data.max_com = params.max_com; 2256 lsdma_data->u.tiled_copy_data.max_uncom = params.max_uncom; 2257 lsdma_data->u.tiled_copy_data.cache_policy_src = params.src_cache_policy; 2258 lsdma_data->u.tiled_copy_data.cache_policy_dst = params.dst_cache_policy; 2259 2260 result = dc_wake_and_execute_dmub_cmd(dc_ctx, &cmd, wait_type); 2261 2262 if (!result) 2263 DC_ERROR("LSDMA Tiled to Tiled Copy failed in DMUB"); 2264 2265 return result; 2266 } 2267 2268 bool dmub_lsdma_send_pio_copy_command( 2269 struct dc_dmub_srv *dc_dmub_srv, 2270 uint64_t src_addr, 2271 uint64_t dst_addr, 2272 uint32_t byte_count, 2273 uint32_t overlap_disable 2274 ) 2275 { 2276 struct dc_context *dc_ctx = dc_dmub_srv->ctx; 2277 union dmub_rb_cmd cmd; 2278 enum dm_dmub_wait_type wait_type; 2279 struct dmub_cmd_lsdma_data *lsdma_data = &cmd.lsdma.lsdma_data; 2280 bool result; 2281 2282 memset(&cmd, 0, sizeof(cmd)); 2283 2284 cmd.cmd_common.header.type = DMUB_CMD__LSDMA; 2285 cmd.cmd_common.header.sub_type = DMUB_CMD__LSDMA_PIO_COPY; 2286 wait_type = DM_DMUB_WAIT_TYPE_NO_WAIT; 2287 2288 lsdma_data->u.pio_copy_data.packet.fields.byte_count = byte_count; 2289 lsdma_data->u.pio_copy_data.packet.fields.overlap_disable = overlap_disable; 2290 lsdma_data->u.pio_copy_data.src_lo = src_addr & 0xFFFFFFFF; 2291 lsdma_data->u.pio_copy_data.src_hi = (src_addr >> 32) & 0xFFFFFFFF; 2292 lsdma_data->u.pio_copy_data.dst_lo = dst_addr & 0xFFFFFFFF; 2293 lsdma_data->u.pio_copy_data.dst_hi = (dst_addr >> 32) & 0xFFFFFFFF; 2294 2295 result = dc_wake_and_execute_dmub_cmd(dc_ctx, &cmd, wait_type); 2296 2297 if (!result) 2298 DC_ERROR("LSDMA PIO Copy failed in DMUB"); 2299 2300 return result; 2301 } 2302 2303 bool dmub_lsdma_send_pio_constfill_command( 2304 struct dc_dmub_srv *dc_dmub_srv, 2305 uint64_t dst_addr, 2306 uint32_t byte_count, 2307 uint32_t data 2308 ) 2309 { 2310 struct dc_context *dc_ctx = dc_dmub_srv->ctx; 2311 union dmub_rb_cmd cmd; 2312 enum dm_dmub_wait_type wait_type; 2313 struct dmub_cmd_lsdma_data *lsdma_data = &cmd.lsdma.lsdma_data; 2314 bool result; 2315 2316 memset(&cmd, 0, sizeof(cmd)); 2317 2318 cmd.cmd_common.header.type = DMUB_CMD__LSDMA; 2319 cmd.cmd_common.header.sub_type = DMUB_CMD__LSDMA_PIO_CONSTFILL; 2320 wait_type = DM_DMUB_WAIT_TYPE_NO_WAIT; 2321 2322 lsdma_data->u.pio_constfill_data.packet.fields.constant_fill = 1; 2323 lsdma_data->u.pio_constfill_data.packet.fields.byte_count = byte_count; 2324 lsdma_data->u.pio_constfill_data.dst_lo = dst_addr & 0xFFFFFFFF; 2325 lsdma_data->u.pio_constfill_data.dst_hi = (dst_addr >> 32) & 0xFFFFFFFF; 2326 lsdma_data->u.pio_constfill_data.data = data; 2327 2328 result = dc_wake_and_execute_dmub_cmd(dc_ctx, &cmd, wait_type); 2329 2330 if (!result) 2331 DC_ERROR("LSDMA PIO Constfill failed in DMUB"); 2332 2333 return result; 2334 } 2335 2336 bool dmub_lsdma_send_poll_reg_write_command(struct dc_dmub_srv *dc_dmub_srv, uint32_t reg_addr, uint32_t reg_data) 2337 { 2338 struct dc_context *dc_ctx = dc_dmub_srv->ctx; 2339 union dmub_rb_cmd cmd; 2340 enum dm_dmub_wait_type wait_type; 2341 struct dmub_cmd_lsdma_data *lsdma_data = &cmd.lsdma.lsdma_data; 2342 bool result; 2343 2344 memset(&cmd, 0, sizeof(cmd)); 2345 2346 cmd.cmd_common.header.type = DMUB_CMD__LSDMA; 2347 cmd.cmd_common.header.sub_type = DMUB_CMD__LSDMA_POLL_REG_WRITE; 2348 wait_type = DM_DMUB_WAIT_TYPE_NO_WAIT; 2349 2350 lsdma_data->u.reg_write_data.reg_addr = reg_addr; 2351 lsdma_data->u.reg_write_data.reg_data = reg_data; 2352 2353 result = dc_wake_and_execute_dmub_cmd(dc_ctx, &cmd, wait_type); 2354 2355 if (!result) 2356 DC_ERROR("LSDMA Poll Reg failed in DMUB"); 2357 2358 return result; 2359 } 2360 2361 bool dc_dmub_srv_is_cursor_offload_enabled(const struct dc *dc) 2362 { 2363 return dc->ctx->dmub_srv && dc->ctx->dmub_srv->cursor_offload_enabled; 2364 } 2365 2366 void dc_dmub_srv_boot_time_crc_init(const struct dc *dc, uint64_t gpu_addr, uint32_t size) 2367 { 2368 struct dc_dmub_srv *dc_dmub_srv; 2369 struct dc_context *dc_ctx; 2370 union dmub_rb_cmd cmd = {0}; 2371 bool result = false; 2372 2373 if (!dc || !dc->ctx || !dc->ctx->dmub_srv || size == 0) 2374 return; 2375 2376 dc_dmub_srv = dc->ctx->dmub_srv; 2377 dc_ctx = dc_dmub_srv->ctx; 2378 2379 memset(&cmd, 0, sizeof(cmd)); 2380 cmd.boot_time_crc_init.header.type = DMUB_CMD__BOOT_TIME_CRC; 2381 cmd.boot_time_crc_init.header.sub_type = DMUB_CMD__BOOT_TIME_CRC_INIT_MEM; 2382 cmd.boot_time_crc_init.header.payload_bytes = 2383 sizeof(struct dmub_rb_cmd_boot_time_crc_init); 2384 cmd.boot_time_crc_init.data.buffer_addr.quad_part = gpu_addr; 2385 cmd.boot_time_crc_init.data.buffer_size = size; 2386 2387 result = dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_NO_WAIT); 2388 2389 if (!result) 2390 DC_ERROR("Boot time crc init failed in DMUB"); 2391 } 2392 2393 void dc_dmub_srv_release_hw(const struct dc *dc) 2394 { 2395 struct dc_dmub_srv *dc_dmub_srv = dc->ctx->dmub_srv; 2396 union dmub_rb_cmd cmd = {0}; 2397 2398 if (!dc_dmub_srv || !dc_dmub_srv->dmub) 2399 return; 2400 2401 memset(&cmd, 0, sizeof(cmd)); 2402 cmd.idle_opt_notify_idle.header.type = DMUB_CMD__IDLE_OPT; 2403 cmd.idle_opt_notify_idle.header.sub_type = DMUB_CMD__IDLE_OPT_RELEASE_HW; 2404 cmd.idle_opt_notify_idle.header.payload_bytes = 2405 sizeof(cmd.idle_opt_notify_idle) - 2406 sizeof(cmd.idle_opt_notify_idle.header); 2407 2408 dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); 2409 } 2410 2411 void dc_dmub_srv_log_preos_dmcub_info(struct dc_dmub_srv *dc_dmub_srv) 2412 { 2413 struct dmub_srv *dmub; 2414 2415 if (!dc_dmub_srv || !dc_dmub_srv->dmub) 2416 return; 2417 2418 dmub = dc_dmub_srv->dmub; 2419 2420 if (dmub_srv_get_preos_info(dmub)) { 2421 DC_LOG_DEBUG("%s: PreOS DMCUB Info", __func__); 2422 DC_LOG_DEBUG("fw_version : 0x%08x", dmub->preos_info.fw_version); 2423 DC_LOG_DEBUG("boot_options : 0x%08x", dmub->preos_info.boot_options); 2424 DC_LOG_DEBUG("boot_status : 0x%08x", dmub->preos_info.boot_status); 2425 DC_LOG_DEBUG("trace_buffer_phy_addr : 0x%016llx", dmub->preos_info.trace_buffer_phy_addr); 2426 DC_LOG_DEBUG("trace_buffer_size_bytes : 0x%08x", dmub->preos_info.trace_buffer_size); 2427 DC_LOG_DEBUG("fb_base : 0x%016llx", dmub->preos_info.fb_base); 2428 DC_LOG_DEBUG("fb_offset : 0x%016llx", dmub->preos_info.fb_offset); 2429 } 2430 } 2431