0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026 #include "dc.h"
0027 #include "dc_dmub_srv.h"
0028 #include "../dmub/dmub_srv.h"
0029 #include "dm_helpers.h"
0030 #include "dc_hw_types.h"
0031 #include "core_types.h"
0032 #include "../basics/conversion.h"
0033
0034 #define CTX dc_dmub_srv->ctx
0035 #define DC_LOGGER CTX->logger
0036
0037 static void dc_dmub_srv_construct(struct dc_dmub_srv *dc_srv, struct dc *dc,
0038 struct dmub_srv *dmub)
0039 {
0040 dc_srv->dmub = dmub;
0041 dc_srv->ctx = dc->ctx;
0042 }
0043
0044 struct dc_dmub_srv *dc_dmub_srv_create(struct dc *dc, struct dmub_srv *dmub)
0045 {
0046 struct dc_dmub_srv *dc_srv =
0047 kzalloc(sizeof(struct dc_dmub_srv), GFP_KERNEL);
0048
0049 if (dc_srv == NULL) {
0050 BREAK_TO_DEBUGGER();
0051 return NULL;
0052 }
0053
0054 dc_dmub_srv_construct(dc_srv, dc, dmub);
0055
0056 return dc_srv;
0057 }
0058
0059 void dc_dmub_srv_destroy(struct dc_dmub_srv **dmub_srv)
0060 {
0061 if (*dmub_srv) {
0062 kfree(*dmub_srv);
0063 *dmub_srv = NULL;
0064 }
0065 }
0066
0067 void dc_dmub_srv_cmd_queue(struct dc_dmub_srv *dc_dmub_srv,
0068 union dmub_rb_cmd *cmd)
0069 {
0070 struct dmub_srv *dmub = dc_dmub_srv->dmub;
0071 struct dc_context *dc_ctx = dc_dmub_srv->ctx;
0072 enum dmub_status status;
0073
0074 status = dmub_srv_cmd_queue(dmub, cmd);
0075 if (status == DMUB_STATUS_OK)
0076 return;
0077
0078 if (status != DMUB_STATUS_QUEUE_FULL)
0079 goto error;
0080
0081
0082 dc_dmub_srv_cmd_execute(dc_dmub_srv);
0083 dc_dmub_srv_wait_idle(dc_dmub_srv);
0084
0085
0086 status = dmub_srv_cmd_queue(dmub, cmd);
0087 if (status == DMUB_STATUS_OK)
0088 return;
0089
0090 error:
0091 DC_ERROR("Error queuing DMUB command: status=%d\n", status);
0092 dc_dmub_srv_log_diagnostic_data(dc_dmub_srv);
0093 }
0094
0095 void dc_dmub_srv_cmd_execute(struct dc_dmub_srv *dc_dmub_srv)
0096 {
0097 struct dmub_srv *dmub = dc_dmub_srv->dmub;
0098 struct dc_context *dc_ctx = dc_dmub_srv->ctx;
0099 enum dmub_status status;
0100
0101 status = dmub_srv_cmd_execute(dmub);
0102 if (status != DMUB_STATUS_OK) {
0103 DC_ERROR("Error starting DMUB execution: status=%d\n", status);
0104 dc_dmub_srv_log_diagnostic_data(dc_dmub_srv);
0105 }
0106 }
0107
0108 void dc_dmub_srv_wait_idle(struct dc_dmub_srv *dc_dmub_srv)
0109 {
0110 struct dmub_srv *dmub = dc_dmub_srv->dmub;
0111 struct dc_context *dc_ctx = dc_dmub_srv->ctx;
0112 enum dmub_status status;
0113
0114 status = dmub_srv_wait_for_idle(dmub, 100000);
0115 if (status != DMUB_STATUS_OK) {
0116 DC_ERROR("Error waiting for DMUB idle: status=%d\n", status);
0117 dc_dmub_srv_log_diagnostic_data(dc_dmub_srv);
0118 }
0119 }
0120
0121 void dc_dmub_srv_clear_inbox0_ack(struct dc_dmub_srv *dmub_srv)
0122 {
0123 struct dmub_srv *dmub = dmub_srv->dmub;
0124 struct dc_context *dc_ctx = dmub_srv->ctx;
0125 enum dmub_status status = DMUB_STATUS_OK;
0126
0127 status = dmub_srv_clear_inbox0_ack(dmub);
0128 if (status != DMUB_STATUS_OK) {
0129 DC_ERROR("Error clearing INBOX0 ack: status=%d\n", status);
0130 dc_dmub_srv_log_diagnostic_data(dmub_srv);
0131 }
0132 }
0133
0134 void dc_dmub_srv_wait_for_inbox0_ack(struct dc_dmub_srv *dmub_srv)
0135 {
0136 struct dmub_srv *dmub = dmub_srv->dmub;
0137 struct dc_context *dc_ctx = dmub_srv->ctx;
0138 enum dmub_status status = DMUB_STATUS_OK;
0139
0140 status = dmub_srv_wait_for_inbox0_ack(dmub, 100000);
0141 if (status != DMUB_STATUS_OK) {
0142 DC_ERROR("Error waiting for INBOX0 HW Lock Ack\n");
0143 dc_dmub_srv_log_diagnostic_data(dmub_srv);
0144 }
0145 }
0146
0147 void dc_dmub_srv_send_inbox0_cmd(struct dc_dmub_srv *dmub_srv,
0148 union dmub_inbox0_data_register data)
0149 {
0150 struct dmub_srv *dmub = dmub_srv->dmub;
0151 struct dc_context *dc_ctx = dmub_srv->ctx;
0152 enum dmub_status status = DMUB_STATUS_OK;
0153
0154 status = dmub_srv_send_inbox0_cmd(dmub, data);
0155 if (status != DMUB_STATUS_OK) {
0156 DC_ERROR("Error sending INBOX0 cmd\n");
0157 dc_dmub_srv_log_diagnostic_data(dmub_srv);
0158 }
0159 }
0160
0161 bool dc_dmub_srv_cmd_with_reply_data(struct dc_dmub_srv *dc_dmub_srv, union dmub_rb_cmd *cmd)
0162 {
0163 struct dmub_srv *dmub;
0164 enum dmub_status status;
0165
0166 if (!dc_dmub_srv || !dc_dmub_srv->dmub)
0167 return false;
0168
0169 dmub = dc_dmub_srv->dmub;
0170
0171 status = dmub_srv_cmd_with_reply_data(dmub, cmd);
0172 if (status != DMUB_STATUS_OK) {
0173 DC_LOG_DEBUG("No reply for DMUB command: status=%d\n", status);
0174 return false;
0175 }
0176
0177 return true;
0178 }
0179
0180 void dc_dmub_srv_wait_phy_init(struct dc_dmub_srv *dc_dmub_srv)
0181 {
0182 struct dmub_srv *dmub = dc_dmub_srv->dmub;
0183 struct dc_context *dc_ctx = dc_dmub_srv->ctx;
0184 enum dmub_status status;
0185
0186 for (;;) {
0187
0188 status = dmub_srv_wait_for_phy_init(dmub, 1000000);
0189 if (status == DMUB_STATUS_OK)
0190
0191 break;
0192
0193 DC_ERROR("DMCUB PHY init failed: status=%d\n", status);
0194 ASSERT(0);
0195
0196 if (status != DMUB_STATUS_TIMEOUT)
0197
0198
0199
0200
0201 break;
0202
0203
0204 }
0205 }
0206
0207 bool dc_dmub_srv_notify_stream_mask(struct dc_dmub_srv *dc_dmub_srv,
0208 unsigned int stream_mask)
0209 {
0210 struct dmub_srv *dmub;
0211 const uint32_t timeout = 30;
0212
0213 if (!dc_dmub_srv || !dc_dmub_srv->dmub)
0214 return false;
0215
0216 dmub = dc_dmub_srv->dmub;
0217
0218 return dmub_srv_send_gpint_command(
0219 dmub, DMUB_GPINT__IDLE_OPT_NOTIFY_STREAM_MASK,
0220 stream_mask, timeout) == DMUB_STATUS_OK;
0221 }
0222
0223 bool dc_dmub_srv_is_restore_required(struct dc_dmub_srv *dc_dmub_srv)
0224 {
0225 struct dmub_srv *dmub;
0226 struct dc_context *dc_ctx;
0227 union dmub_fw_boot_status boot_status;
0228 enum dmub_status status;
0229
0230 if (!dc_dmub_srv || !dc_dmub_srv->dmub)
0231 return false;
0232
0233 dmub = dc_dmub_srv->dmub;
0234 dc_ctx = dc_dmub_srv->ctx;
0235
0236 status = dmub_srv_get_fw_boot_status(dmub, &boot_status);
0237 if (status != DMUB_STATUS_OK) {
0238 DC_ERROR("Error querying DMUB boot status: error=%d\n", status);
0239 return false;
0240 }
0241
0242 return boot_status.bits.restore_required;
0243 }
0244
0245 bool dc_dmub_srv_get_dmub_outbox0_msg(const struct dc *dc, struct dmcub_trace_buf_entry *entry)
0246 {
0247 struct dmub_srv *dmub = dc->ctx->dmub_srv->dmub;
0248 return dmub_srv_get_outbox0_msg(dmub, entry);
0249 }
0250
0251 void dc_dmub_trace_event_control(struct dc *dc, bool enable)
0252 {
0253 dm_helpers_dmub_outbox_interrupt_control(dc->ctx, enable);
0254 }
0255
0256 void dc_dmub_srv_drr_update_cmd(struct dc *dc, uint32_t tg_inst, uint32_t vtotal_min, uint32_t vtotal_max)
0257 {
0258 union dmub_rb_cmd cmd = { 0 };
0259
0260 cmd.drr_update.header.type = DMUB_CMD__FW_ASSISTED_MCLK_SWITCH;
0261 cmd.drr_update.header.sub_type = DMUB_CMD__FAMS_DRR_UPDATE;
0262 cmd.drr_update.dmub_optc_state_req.v_total_max = vtotal_max;
0263 cmd.drr_update.dmub_optc_state_req.v_total_min = vtotal_min;
0264 cmd.drr_update.dmub_optc_state_req.tg_inst = tg_inst;
0265
0266 cmd.drr_update.header.payload_bytes = sizeof(cmd.drr_update) - sizeof(cmd.drr_update.header);
0267
0268
0269 dc_dmub_srv_cmd_queue(dc->ctx->dmub_srv, &cmd);
0270 dc_dmub_srv_cmd_execute(dc->ctx->dmub_srv);
0271 dc_dmub_srv_wait_idle(dc->ctx->dmub_srv);
0272 }
0273
0274 void dc_dmub_srv_set_drr_manual_trigger_cmd(struct dc *dc, uint32_t tg_inst)
0275 {
0276 union dmub_rb_cmd cmd = { 0 };
0277
0278 cmd.drr_update.header.type = DMUB_CMD__FW_ASSISTED_MCLK_SWITCH;
0279 cmd.drr_update.header.sub_type = DMUB_CMD__FAMS_SET_MANUAL_TRIGGER;
0280 cmd.drr_update.dmub_optc_state_req.tg_inst = tg_inst;
0281
0282 cmd.drr_update.header.payload_bytes = sizeof(cmd.drr_update) - sizeof(cmd.drr_update.header);
0283
0284
0285 dc_dmub_srv_cmd_queue(dc->ctx->dmub_srv, &cmd);
0286 dc_dmub_srv_cmd_execute(dc->ctx->dmub_srv);
0287 dc_dmub_srv_wait_idle(dc->ctx->dmub_srv);
0288 }
0289
0290 static uint8_t dc_dmub_srv_get_pipes_for_stream(struct dc *dc, struct dc_stream_state *stream)
0291 {
0292 uint8_t pipes = 0;
0293 int i = 0;
0294
0295 for (i = 0; i < MAX_PIPES; i++) {
0296 struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i];
0297
0298 if (pipe->stream == stream && pipe->stream_res.tg)
0299 pipes = i;
0300 }
0301 return pipes;
0302 }
0303
0304 static int dc_dmub_srv_get_timing_generator_offset(struct dc *dc, struct dc_stream_state *stream)
0305 {
0306 int tg_inst = 0;
0307 int i = 0;
0308
0309 for (i = 0; i < MAX_PIPES; i++) {
0310 struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i];
0311
0312 if (pipe->stream == stream && pipe->stream_res.tg) {
0313 tg_inst = pipe->stream_res.tg->inst;
0314 break;
0315 }
0316 }
0317 return tg_inst;
0318 }
0319
0320 bool dc_dmub_srv_p_state_delegate(struct dc *dc, bool should_manage_pstate, struct dc_state *context)
0321 {
0322 union dmub_rb_cmd cmd = { 0 };
0323 struct dmub_cmd_fw_assisted_mclk_switch_config *config_data = &cmd.fw_assisted_mclk_switch.config_data;
0324 int i = 0;
0325 int ramp_up_num_steps = 1;
0326 uint8_t visual_confirm_enabled = dc->debug.visual_confirm == VISUAL_CONFIRM_FAMS;
0327
0328 if (dc == NULL)
0329 return false;
0330
0331
0332 cmd.fw_assisted_mclk_switch.header.type = DMUB_CMD__FW_ASSISTED_MCLK_SWITCH;
0333 cmd.fw_assisted_mclk_switch.header.sub_type = DMUB_CMD__FAMS_SETUP_FW_CTRL;
0334 cmd.fw_assisted_mclk_switch.config_data.fams_enabled = should_manage_pstate;
0335 cmd.fw_assisted_mclk_switch.config_data.visual_confirm_enabled = visual_confirm_enabled;
0336
0337 for (i = 0; context && i < context->stream_count; i++) {
0338 struct dc_stream_state *stream = context->streams[i];
0339 uint8_t min_refresh_in_hz = (stream->timing.min_refresh_in_uhz + 999999) / 1000000;
0340 int tg_inst = dc_dmub_srv_get_timing_generator_offset(dc, stream);
0341
0342 config_data->pipe_data[tg_inst].pix_clk_100hz = stream->timing.pix_clk_100hz;
0343 config_data->pipe_data[tg_inst].min_refresh_in_hz = min_refresh_in_hz;
0344 config_data->pipe_data[tg_inst].max_ramp_step = ramp_up_num_steps;
0345 config_data->pipe_data[tg_inst].pipes = dc_dmub_srv_get_pipes_for_stream(dc, stream);
0346 }
0347
0348 cmd.fw_assisted_mclk_switch.header.payload_bytes =
0349 sizeof(cmd.fw_assisted_mclk_switch) - sizeof(cmd.fw_assisted_mclk_switch.header);
0350
0351
0352 dc_dmub_srv_cmd_queue(dc->ctx->dmub_srv, &cmd);
0353 dc_dmub_srv_cmd_execute(dc->ctx->dmub_srv);
0354 dc_dmub_srv_wait_idle(dc->ctx->dmub_srv);
0355
0356 return true;
0357 }
0358
0359 void dc_dmub_srv_query_caps_cmd(struct dmub_srv *dmub)
0360 {
0361 union dmub_rb_cmd cmd = { 0 };
0362 enum dmub_status status;
0363
0364 if (!dmub) {
0365 return;
0366 }
0367
0368 memset(&cmd, 0, sizeof(cmd));
0369
0370
0371 cmd.query_feature_caps.header.type = DMUB_CMD__QUERY_FEATURE_CAPS;
0372 cmd.query_feature_caps.header.sub_type = 0;
0373 cmd.query_feature_caps.header.ret_status = 1;
0374 cmd.query_feature_caps.header.payload_bytes = sizeof(struct dmub_cmd_query_feature_caps_data);
0375
0376
0377 status = dmub_srv_cmd_with_reply_data(dmub, &cmd);
0378
0379 ASSERT(status == DMUB_STATUS_OK);
0380
0381
0382 if (status == DMUB_STATUS_OK &&
0383 cmd.query_feature_caps.header.ret_status == 0) {
0384 memcpy(&dmub->feature_caps,
0385 &cmd.query_feature_caps.query_feature_caps_data,
0386 sizeof(struct dmub_feature_caps));
0387 }
0388 }
0389
0390 #ifdef CONFIG_DRM_AMD_DC_DCN
0391
0392
0393
0394
0395
0396
0397
0398
0399
0400
0401
0402
0403
0404
0405
0406
0407
0408
0409
0410
0411
0412 static void populate_subvp_cmd_drr_info(struct dc *dc,
0413 struct pipe_ctx *subvp_pipe,
0414 struct pipe_ctx *vblank_pipe,
0415 struct dmub_cmd_fw_assisted_mclk_switch_pipe_data_v2 *pipe_data)
0416 {
0417 struct dc_crtc_timing *main_timing = &subvp_pipe->stream->timing;
0418 struct dc_crtc_timing *phantom_timing = &subvp_pipe->stream->mall_stream_config.paired_stream->timing;
0419 struct dc_crtc_timing *drr_timing = &vblank_pipe->stream->timing;
0420 uint16_t drr_frame_us = 0;
0421 uint16_t min_drr_supported_us = 0;
0422 uint16_t max_drr_supported_us = 0;
0423 uint16_t max_drr_vblank_us = 0;
0424 uint16_t max_drr_mallregion_us = 0;
0425 uint16_t mall_region_us = 0;
0426 uint16_t prefetch_us = 0;
0427 uint16_t subvp_active_us = 0;
0428 uint16_t drr_active_us = 0;
0429 uint16_t min_vtotal_supported = 0;
0430 uint16_t max_vtotal_supported = 0;
0431
0432 pipe_data->pipe_config.vblank_data.drr_info.drr_in_use = true;
0433 pipe_data->pipe_config.vblank_data.drr_info.use_ramping = false;
0434 pipe_data->pipe_config.vblank_data.drr_info.drr_window_size_ms = 4;
0435
0436 drr_frame_us = div64_u64(((uint64_t)drr_timing->v_total * drr_timing->h_total * 1000000),
0437 (((uint64_t)drr_timing->pix_clk_100hz * 100)));
0438
0439 mall_region_us = div64_u64(((uint64_t)phantom_timing->v_addressable * phantom_timing->h_total * 1000000),
0440 (((uint64_t)phantom_timing->pix_clk_100hz * 100)));
0441 min_drr_supported_us = drr_frame_us + mall_region_us + SUBVP_DRR_MARGIN_US;
0442 min_vtotal_supported = div64_u64(((uint64_t)drr_timing->pix_clk_100hz * 100 * min_drr_supported_us),
0443 (((uint64_t)drr_timing->h_total * 1000000)));
0444
0445 prefetch_us = div64_u64(((uint64_t)(phantom_timing->v_total - phantom_timing->v_front_porch) * phantom_timing->h_total * 1000000),
0446 (((uint64_t)phantom_timing->pix_clk_100hz * 100) + dc->caps.subvp_prefetch_end_to_mall_start_us));
0447 subvp_active_us = div64_u64(((uint64_t)main_timing->v_addressable * main_timing->h_total * 1000000),
0448 (((uint64_t)main_timing->pix_clk_100hz * 100)));
0449 drr_active_us = div64_u64(((uint64_t)drr_timing->v_addressable * drr_timing->h_total * 1000000),
0450 (((uint64_t)drr_timing->pix_clk_100hz * 100)));
0451 max_drr_vblank_us = div64_u64((subvp_active_us - prefetch_us - drr_active_us), 2) + drr_active_us;
0452 max_drr_mallregion_us = subvp_active_us - prefetch_us - mall_region_us;
0453 max_drr_supported_us = max_drr_vblank_us > max_drr_mallregion_us ? max_drr_vblank_us : max_drr_mallregion_us;
0454 max_vtotal_supported = div64_u64(((uint64_t)drr_timing->pix_clk_100hz * 100 * max_drr_supported_us),
0455 (((uint64_t)drr_timing->h_total * 1000000)));
0456
0457 pipe_data->pipe_config.vblank_data.drr_info.min_vtotal_supported = min_vtotal_supported;
0458 pipe_data->pipe_config.vblank_data.drr_info.max_vtotal_supported = max_vtotal_supported;
0459 }
0460
0461
0462
0463
0464
0465
0466
0467
0468
0469
0470
0471
0472
0473
0474
0475
0476
0477
0478
0479 static void populate_subvp_cmd_vblank_pipe_info(struct dc *dc,
0480 struct dc_state *context,
0481 union dmub_rb_cmd *cmd,
0482 struct pipe_ctx *vblank_pipe,
0483 uint8_t cmd_pipe_index)
0484 {
0485 uint32_t i;
0486 struct pipe_ctx *pipe = NULL;
0487 struct dmub_cmd_fw_assisted_mclk_switch_pipe_data_v2 *pipe_data =
0488 &cmd->fw_assisted_mclk_switch_v2.config_data.pipe_data[cmd_pipe_index];
0489
0490
0491 for (i = 0; i < dc->res_pool->pipe_count; i++) {
0492 pipe = &context->res_ctx.pipe_ctx[i];
0493
0494
0495
0496 if (!pipe->stream || !pipe->plane_state || pipe->top_pipe || pipe->prev_odm_pipe)
0497 continue;
0498
0499
0500 if (pipe->stream->mall_stream_config.type == SUBVP_MAIN)
0501 break;
0502 }
0503
0504 pipe_data->mode = VBLANK;
0505 pipe_data->pipe_config.vblank_data.pix_clk_100hz = vblank_pipe->stream->timing.pix_clk_100hz;
0506 pipe_data->pipe_config.vblank_data.vblank_start = vblank_pipe->stream->timing.v_total -
0507 vblank_pipe->stream->timing.v_front_porch;
0508 pipe_data->pipe_config.vblank_data.vtotal = vblank_pipe->stream->timing.v_total;
0509 pipe_data->pipe_config.vblank_data.htotal = vblank_pipe->stream->timing.h_total;
0510 pipe_data->pipe_config.vblank_data.vblank_pipe_index = vblank_pipe->pipe_idx;
0511 pipe_data->pipe_config.vblank_data.vstartup_start = vblank_pipe->pipe_dlg_param.vstartup_start;
0512 pipe_data->pipe_config.vblank_data.vblank_end =
0513 vblank_pipe->stream->timing.v_total - vblank_pipe->stream->timing.v_front_porch - vblank_pipe->stream->timing.v_addressable;
0514
0515 if (vblank_pipe->stream->ignore_msa_timing_param)
0516 populate_subvp_cmd_drr_info(dc, pipe, vblank_pipe, pipe_data);
0517 }
0518
0519
0520
0521
0522
0523
0524
0525
0526
0527
0528
0529
0530
0531
0532
0533
0534
0535
0536
0537 static void update_subvp_prefetch_end_to_mall_start(struct dc *dc,
0538 struct dc_state *context,
0539 union dmub_rb_cmd *cmd,
0540 struct pipe_ctx *subvp_pipes[])
0541 {
0542 uint32_t subvp0_prefetch_us = 0;
0543 uint32_t subvp1_prefetch_us = 0;
0544 uint32_t prefetch_delta_us = 0;
0545 struct dc_crtc_timing *phantom_timing0 = &subvp_pipes[0]->stream->mall_stream_config.paired_stream->timing;
0546 struct dc_crtc_timing *phantom_timing1 = &subvp_pipes[1]->stream->mall_stream_config.paired_stream->timing;
0547 struct dmub_cmd_fw_assisted_mclk_switch_pipe_data_v2 *pipe_data = NULL;
0548
0549 subvp0_prefetch_us = div64_u64(((uint64_t)(phantom_timing0->v_total - phantom_timing0->v_front_porch) *
0550 (uint64_t)phantom_timing0->h_total * 1000000),
0551 (((uint64_t)phantom_timing0->pix_clk_100hz * 100) + dc->caps.subvp_prefetch_end_to_mall_start_us));
0552 subvp1_prefetch_us = div64_u64(((uint64_t)(phantom_timing1->v_total - phantom_timing1->v_front_porch) *
0553 (uint64_t)phantom_timing1->h_total * 1000000),
0554 (((uint64_t)phantom_timing1->pix_clk_100hz * 100) + dc->caps.subvp_prefetch_end_to_mall_start_us));
0555
0556
0557
0558 if (subvp0_prefetch_us > subvp1_prefetch_us) {
0559 pipe_data = &cmd->fw_assisted_mclk_switch_v2.config_data.pipe_data[1];
0560 prefetch_delta_us = subvp0_prefetch_us - subvp1_prefetch_us;
0561 pipe_data->pipe_config.subvp_data.prefetch_to_mall_start_lines =
0562 div64_u64(((uint64_t)(dc->caps.subvp_prefetch_end_to_mall_start_us + prefetch_delta_us) *
0563 ((uint64_t)phantom_timing1->pix_clk_100hz * 100) + ((uint64_t)phantom_timing1->h_total * 1000000 - 1)),
0564 ((uint64_t)phantom_timing1->h_total * 1000000));
0565
0566 } else if (subvp1_prefetch_us > subvp0_prefetch_us) {
0567 pipe_data = &cmd->fw_assisted_mclk_switch_v2.config_data.pipe_data[0];
0568 prefetch_delta_us = subvp1_prefetch_us - subvp0_prefetch_us;
0569 pipe_data->pipe_config.subvp_data.prefetch_to_mall_start_lines =
0570 div64_u64(((uint64_t)(dc->caps.subvp_prefetch_end_to_mall_start_us + prefetch_delta_us) *
0571 ((uint64_t)phantom_timing0->pix_clk_100hz * 100) + ((uint64_t)phantom_timing0->h_total * 1000000 - 1)),
0572 ((uint64_t)phantom_timing0->h_total * 1000000));
0573 }
0574 }
0575
0576
0577
0578
0579
0580
0581
0582
0583
0584
0585
0586
0587
0588
0589
0590
0591
0592
0593
0594 static void populate_subvp_cmd_pipe_info(struct dc *dc,
0595 struct dc_state *context,
0596 union dmub_rb_cmd *cmd,
0597 struct pipe_ctx *subvp_pipe,
0598 uint8_t cmd_pipe_index)
0599 {
0600 uint32_t j;
0601 struct dmub_cmd_fw_assisted_mclk_switch_pipe_data_v2 *pipe_data =
0602 &cmd->fw_assisted_mclk_switch_v2.config_data.pipe_data[cmd_pipe_index];
0603 struct dc_crtc_timing *main_timing = &subvp_pipe->stream->timing;
0604 struct dc_crtc_timing *phantom_timing = &subvp_pipe->stream->mall_stream_config.paired_stream->timing;
0605 uint32_t out_num, out_den;
0606
0607 pipe_data->mode = SUBVP;
0608 pipe_data->pipe_config.subvp_data.pix_clk_100hz = subvp_pipe->stream->timing.pix_clk_100hz;
0609 pipe_data->pipe_config.subvp_data.htotal = subvp_pipe->stream->timing.h_total;
0610 pipe_data->pipe_config.subvp_data.vtotal = subvp_pipe->stream->timing.v_total;
0611 pipe_data->pipe_config.subvp_data.main_vblank_start =
0612 main_timing->v_total - main_timing->v_front_porch;
0613 pipe_data->pipe_config.subvp_data.main_vblank_end =
0614 main_timing->v_total - main_timing->v_front_porch - main_timing->v_addressable;
0615 pipe_data->pipe_config.subvp_data.mall_region_lines = phantom_timing->v_addressable;
0616 pipe_data->pipe_config.subvp_data.main_pipe_index = subvp_pipe->pipe_idx;
0617 pipe_data->pipe_config.subvp_data.is_drr = subvp_pipe->stream->ignore_msa_timing_param;
0618
0619
0620
0621
0622
0623 reduce_fraction(subvp_pipe->stream->src.height, subvp_pipe->stream->dst.height, &out_num, &out_den);
0624
0625
0626
0627
0628
0629 pipe_data->pipe_config.subvp_data.prefetch_lines =
0630 phantom_timing->v_total - phantom_timing->v_front_porch;
0631
0632
0633 pipe_data->pipe_config.subvp_data.prefetch_to_mall_start_lines =
0634 div64_u64(((uint64_t)dc->caps.subvp_prefetch_end_to_mall_start_us * ((uint64_t)phantom_timing->pix_clk_100hz * 100) +
0635 ((uint64_t)phantom_timing->h_total * 1000000 - 1)), ((uint64_t)phantom_timing->h_total * 1000000));
0636 pipe_data->pipe_config.subvp_data.processing_delay_lines =
0637 div64_u64(((uint64_t)(dc->caps.subvp_fw_processing_delay_us) * ((uint64_t)phantom_timing->pix_clk_100hz * 100) +
0638 ((uint64_t)phantom_timing->h_total * 1000000 - 1)), ((uint64_t)phantom_timing->h_total * 1000000));
0639
0640 for (j = 0; j < dc->res_pool->pipe_count; j++) {
0641 struct pipe_ctx *phantom_pipe = &context->res_ctx.pipe_ctx[j];
0642
0643 if (phantom_pipe->stream == subvp_pipe->stream->mall_stream_config.paired_stream) {
0644 pipe_data->pipe_config.subvp_data.phantom_pipe_index = phantom_pipe->pipe_idx;
0645 break;
0646 }
0647 }
0648 }
0649
0650
0651
0652
0653
0654
0655
0656
0657
0658
0659
0660
0661
0662
0663
0664
0665 void dc_dmub_setup_subvp_dmub_command(struct dc *dc,
0666 struct dc_state *context,
0667 bool enable)
0668 {
0669 uint8_t cmd_pipe_index = 0;
0670 uint32_t i, pipe_idx;
0671 uint8_t subvp_count = 0;
0672 union dmub_rb_cmd cmd;
0673 struct pipe_ctx *subvp_pipes[2];
0674 uint32_t wm_val_refclk = 0;
0675
0676 memset(&cmd, 0, sizeof(cmd));
0677
0678 cmd.fw_assisted_mclk_switch_v2.header.type = DMUB_CMD__FW_ASSISTED_MCLK_SWITCH;
0679 cmd.fw_assisted_mclk_switch_v2.header.sub_type = DMUB_CMD__HANDLE_SUBVP_CMD;
0680 cmd.fw_assisted_mclk_switch_v2.header.payload_bytes =
0681 sizeof(cmd.fw_assisted_mclk_switch_v2) - sizeof(cmd.fw_assisted_mclk_switch_v2.header);
0682
0683 for (i = 0; i < dc->res_pool->pipe_count; i++) {
0684 struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
0685
0686 if (!pipe->stream)
0687 continue;
0688
0689 if (pipe->plane_state && !pipe->top_pipe &&
0690 pipe->stream->mall_stream_config.type == SUBVP_MAIN)
0691 subvp_pipes[subvp_count++] = pipe;
0692 }
0693
0694 if (enable) {
0695
0696 for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) {
0697 struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
0698
0699 if (!pipe->stream)
0700 continue;
0701
0702 if (pipe->plane_state && pipe->stream->mall_stream_config.paired_stream &&
0703 pipe->stream->mall_stream_config.type == SUBVP_MAIN) {
0704 populate_subvp_cmd_pipe_info(dc, context, &cmd, pipe, cmd_pipe_index++);
0705 } else if (pipe->plane_state && pipe->stream->mall_stream_config.type == SUBVP_NONE) {
0706
0707
0708 populate_subvp_cmd_vblank_pipe_info(dc, context, &cmd, pipe, cmd_pipe_index++);
0709
0710 }
0711 pipe_idx++;
0712 }
0713 if (subvp_count == 2) {
0714 update_subvp_prefetch_end_to_mall_start(dc, context, &cmd, subvp_pipes);
0715 }
0716 cmd.fw_assisted_mclk_switch_v2.config_data.pstate_allow_width_us = dc->caps.subvp_pstate_allow_width_us;
0717 cmd.fw_assisted_mclk_switch_v2.config_data.vertical_int_margin_us = dc->caps.subvp_vertical_int_margin_us;
0718
0719
0720
0721 wm_val_refclk = context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns *
0722 dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000 / 1000;
0723
0724 cmd.fw_assisted_mclk_switch_v2.config_data.watermark_a_cache = wm_val_refclk < 0xFFFF ? wm_val_refclk : 0xFFFF;
0725 }
0726 dc_dmub_srv_cmd_queue(dc->ctx->dmub_srv, &cmd);
0727 dc_dmub_srv_cmd_execute(dc->ctx->dmub_srv);
0728 dc_dmub_srv_wait_idle(dc->ctx->dmub_srv);
0729 }
0730 #endif
0731
0732 bool dc_dmub_srv_get_diagnostic_data(struct dc_dmub_srv *dc_dmub_srv, struct dmub_diagnostic_data *diag_data)
0733 {
0734 if (!dc_dmub_srv || !dc_dmub_srv->dmub || !diag_data)
0735 return false;
0736 return dmub_srv_get_diagnostic_data(dc_dmub_srv->dmub, diag_data);
0737 }
0738
0739 void dc_dmub_srv_log_diagnostic_data(struct dc_dmub_srv *dc_dmub_srv)
0740 {
0741 struct dmub_diagnostic_data diag_data = {0};
0742
0743 if (!dc_dmub_srv || !dc_dmub_srv->dmub) {
0744 DC_LOG_ERROR("%s: invalid parameters.", __func__);
0745 return;
0746 }
0747
0748 if (!dc_dmub_srv_get_diagnostic_data(dc_dmub_srv, &diag_data)) {
0749 DC_LOG_ERROR("%s: dc_dmub_srv_get_diagnostic_data failed.", __func__);
0750 return;
0751 }
0752
0753 DC_LOG_DEBUG(
0754 "DMCUB STATE\n"
0755 " dmcub_version : %08x\n"
0756 " scratch [0] : %08x\n"
0757 " scratch [1] : %08x\n"
0758 " scratch [2] : %08x\n"
0759 " scratch [3] : %08x\n"
0760 " scratch [4] : %08x\n"
0761 " scratch [5] : %08x\n"
0762 " scratch [6] : %08x\n"
0763 " scratch [7] : %08x\n"
0764 " scratch [8] : %08x\n"
0765 " scratch [9] : %08x\n"
0766 " scratch [10] : %08x\n"
0767 " scratch [11] : %08x\n"
0768 " scratch [12] : %08x\n"
0769 " scratch [13] : %08x\n"
0770 " scratch [14] : %08x\n"
0771 " scratch [15] : %08x\n"
0772 " pc : %08x\n"
0773 " unk_fault_addr : %08x\n"
0774 " inst_fault_addr : %08x\n"
0775 " data_fault_addr : %08x\n"
0776 " inbox1_rptr : %08x\n"
0777 " inbox1_wptr : %08x\n"
0778 " inbox1_size : %08x\n"
0779 " inbox0_rptr : %08x\n"
0780 " inbox0_wptr : %08x\n"
0781 " inbox0_size : %08x\n"
0782 " is_enabled : %d\n"
0783 " is_soft_reset : %d\n"
0784 " is_secure_reset : %d\n"
0785 " is_traceport_en : %d\n"
0786 " is_cw0_en : %d\n"
0787 " is_cw6_en : %d\n",
0788 diag_data.dmcub_version,
0789 diag_data.scratch[0],
0790 diag_data.scratch[1],
0791 diag_data.scratch[2],
0792 diag_data.scratch[3],
0793 diag_data.scratch[4],
0794 diag_data.scratch[5],
0795 diag_data.scratch[6],
0796 diag_data.scratch[7],
0797 diag_data.scratch[8],
0798 diag_data.scratch[9],
0799 diag_data.scratch[10],
0800 diag_data.scratch[11],
0801 diag_data.scratch[12],
0802 diag_data.scratch[13],
0803 diag_data.scratch[14],
0804 diag_data.scratch[15],
0805 diag_data.pc,
0806 diag_data.undefined_address_fault_addr,
0807 diag_data.inst_fetch_fault_addr,
0808 diag_data.data_write_fault_addr,
0809 diag_data.inbox1_rptr,
0810 diag_data.inbox1_wptr,
0811 diag_data.inbox1_size,
0812 diag_data.inbox0_rptr,
0813 diag_data.inbox0_wptr,
0814 diag_data.inbox0_size,
0815 diag_data.is_dmcub_enabled,
0816 diag_data.is_dmcub_soft_reset,
0817 diag_data.is_dmcub_secure_reset,
0818 diag_data.is_traceport_en,
0819 diag_data.is_cw0_enabled,
0820 diag_data.is_cw6_enabled);
0821 }