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