1 // SPDX-License-Identifier: MIT 2 // 3 // Copyright 2024 Advanced Micro Devices, Inc. 4 5 #include "dc.h" 6 #include "dc_dmub_srv.h" 7 #include "dc_dp_types.h" 8 #include "dmub/dmub_srv.h" 9 #include "core_types.h" 10 #include "dmub_replay.h" 11 12 #define DC_TRACE_LEVEL_MESSAGE(...) /* do nothing */ 13 14 #define MAX_PIPES 6 15 16 #define GPINT_RETRY_NUM 20 17 18 static const uint8_t DP_SINK_DEVICE_STR_ID_1[] = {7, 1, 8, 7, 3}; 19 static const uint8_t DP_SINK_DEVICE_STR_ID_2[] = {7, 1, 8, 7, 5}; 20 21 /* 22 * Get Replay state from firmware. 23 */ 24 static void dmub_replay_get_state(struct dmub_replay *dmub, enum replay_state *state, uint8_t panel_inst) 25 { 26 uint32_t retry_count = 0; 27 28 do { 29 // Send gpint command and wait for ack 30 if (!dc_wake_and_execute_gpint(dmub->ctx, DMUB_GPINT__GET_REPLAY_STATE, panel_inst, 31 (uint32_t *)state, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)) { 32 // Return invalid state when GPINT times out 33 *state = REPLAY_STATE_INVALID; 34 } 35 } while (++retry_count <= 1000 && *state == REPLAY_STATE_INVALID); 36 37 // Assert if max retry hit 38 if (retry_count >= 1000 && *state == REPLAY_STATE_INVALID) { 39 ASSERT(0); 40 /* To-do: Add retry fail log */ 41 } 42 } 43 44 /* 45 * Enable/Disable Replay. 46 */ 47 static void dmub_replay_enable(struct dmub_replay *dmub, bool enable, bool wait, uint8_t panel_inst, 48 struct dc_link *link) 49 { 50 union dmub_rb_cmd cmd; 51 struct dc_context *dc = dmub->ctx; 52 uint32_t retry_count; 53 enum replay_state state = REPLAY_STATE_0; 54 struct pipe_ctx *pipe_ctx = NULL; 55 struct resource_context *res_ctx = &link->ctx->dc->current_state->res_ctx; 56 uint8_t i; 57 58 memset(&cmd, 0, sizeof(cmd)); 59 cmd.replay_enable.header.type = DMUB_CMD__REPLAY; 60 cmd.replay_enable.data.panel_inst = panel_inst; 61 62 cmd.replay_enable.header.sub_type = DMUB_CMD__REPLAY_ENABLE; 63 if (enable) { 64 cmd.replay_enable.data.enable = REPLAY_ENABLE; 65 // hpo stream/link encoder assignments are not static, need to update everytime we try to enable replay 66 if (link->cur_link_settings.link_rate >= LINK_RATE_UHBR10) { 67 for (i = 0; i < MAX_PIPES; i++) { 68 if (res_ctx && 69 res_ctx->pipe_ctx[i].stream && 70 res_ctx->pipe_ctx[i].stream->link && 71 res_ctx->pipe_ctx[i].stream->link == link && 72 res_ctx->pipe_ctx[i].stream->link->connector_signal == SIGNAL_TYPE_EDP) { 73 pipe_ctx = &res_ctx->pipe_ctx[i]; 74 //TODO: refactor for multi edp support 75 break; 76 } 77 } 78 79 if (!pipe_ctx) 80 return; 81 82 cmd.replay_enable.data.hpo_stream_enc_inst = pipe_ctx->stream_res.hpo_dp_stream_enc->inst; 83 cmd.replay_enable.data.hpo_link_enc_inst = pipe_ctx->link_res.hpo_dp_link_enc->inst; 84 } 85 } else 86 cmd.replay_enable.data.enable = REPLAY_DISABLE; 87 88 cmd.replay_enable.header.payload_bytes = sizeof(struct dmub_rb_cmd_replay_enable_data); 89 90 dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); 91 92 /* Below loops 1000 x 500us = 500 ms. 93 * Exit REPLAY may need to wait 1-2 frames to power up. Timeout after at 94 * least a few frames. Should never hit the max retry assert below. 95 */ 96 if (wait) { 97 for (retry_count = 0; retry_count <= 1000; retry_count++) { 98 dmub_replay_get_state(dmub, &state, panel_inst); 99 100 if (enable) { 101 if (state != REPLAY_STATE_0) 102 break; 103 } else { 104 if (state == REPLAY_STATE_0) 105 break; 106 } 107 108 /* must *not* be fsleep - this can be called from high irq levels */ 109 udelay(500); 110 } 111 112 /* assert if max retry hit */ 113 if (retry_count >= 1000) 114 ASSERT(0); 115 } 116 } 117 118 /* 119 * Set REPLAY power optimization flags. 120 */ 121 static void dmub_replay_set_power_opt(struct dmub_replay *dmub, unsigned int power_opt, uint8_t panel_inst) 122 { 123 union dmub_rb_cmd cmd; 124 struct dc_context *dc = dmub->ctx; 125 126 memset(&cmd, 0, sizeof(cmd)); 127 cmd.replay_set_power_opt.header.type = DMUB_CMD__REPLAY; 128 cmd.replay_set_power_opt.header.sub_type = DMUB_CMD__SET_REPLAY_POWER_OPT; 129 cmd.replay_set_power_opt.header.payload_bytes = sizeof(struct dmub_cmd_replay_set_power_opt_data); 130 cmd.replay_set_power_opt.replay_set_power_opt_data.power_opt = power_opt; 131 cmd.replay_set_power_opt.replay_set_power_opt_data.panel_inst = panel_inst; 132 133 dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); 134 } 135 136 /* 137 * Setup Replay by programming phy registers and sending replay hw context values to firmware. 138 */ 139 static bool dmub_replay_copy_settings(struct dmub_replay *dmub, 140 struct dc_link *link, 141 struct replay_context *replay_context, 142 uint8_t panel_inst) 143 { 144 union dmub_rb_cmd cmd; 145 struct dc_context *dc = dmub->ctx; 146 struct dmub_cmd_replay_copy_settings_data *copy_settings_data 147 = &cmd.replay_copy_settings.replay_copy_settings_data; 148 struct pipe_ctx *pipe_ctx = NULL; 149 struct resource_context *res_ctx = &link->ctx->dc->current_state->res_ctx; 150 int i = 0; 151 152 for (i = 0; i < MAX_PIPES; i++) { 153 if (res_ctx && 154 res_ctx->pipe_ctx[i].stream && 155 res_ctx->pipe_ctx[i].stream->link && 156 res_ctx->pipe_ctx[i].stream->link == link && 157 res_ctx->pipe_ctx[i].stream->link->connector_signal == SIGNAL_TYPE_EDP) { 158 pipe_ctx = &res_ctx->pipe_ctx[i]; 159 //TODO: refactor for multi edp support 160 break; 161 } 162 } 163 164 if (!pipe_ctx) 165 return false; 166 167 memset(&cmd, 0, sizeof(cmd)); 168 cmd.replay_copy_settings.header.type = DMUB_CMD__REPLAY; 169 cmd.replay_copy_settings.header.sub_type = DMUB_CMD__REPLAY_COPY_SETTINGS; 170 cmd.replay_copy_settings.header.payload_bytes = sizeof(struct dmub_cmd_replay_copy_settings_data); 171 172 // HW insts 173 copy_settings_data->aux_inst = replay_context->aux_inst; 174 copy_settings_data->digbe_inst = replay_context->digbe_inst; 175 copy_settings_data->digfe_inst = replay_context->digfe_inst; 176 177 if (link->cur_link_settings.link_rate >= LINK_RATE_UHBR10) { 178 if (pipe_ctx->stream_res.hpo_dp_stream_enc) 179 copy_settings_data->hpo_stream_enc_inst = pipe_ctx->stream_res.hpo_dp_stream_enc->inst; 180 else 181 copy_settings_data->hpo_stream_enc_inst = 0; 182 if (pipe_ctx->link_res.hpo_dp_link_enc) 183 copy_settings_data->hpo_link_enc_inst = pipe_ctx->link_res.hpo_dp_link_enc->inst; 184 else 185 copy_settings_data->hpo_link_enc_inst = 0; 186 } 187 188 if (pipe_ctx->plane_res.dpp) 189 copy_settings_data->dpp_inst = pipe_ctx->plane_res.dpp->inst; 190 else 191 copy_settings_data->dpp_inst = 0; 192 if (pipe_ctx->stream_res.tg) 193 copy_settings_data->otg_inst = pipe_ctx->stream_res.tg->inst; 194 else 195 copy_settings_data->otg_inst = 0; 196 197 copy_settings_data->dpphy_inst = link->link_enc->transmitter; 198 199 // Misc 200 copy_settings_data->line_time_in_ns = replay_context->line_time_in_ns; 201 copy_settings_data->panel_inst = panel_inst; 202 copy_settings_data->debug.u32All = link->replay_settings.config.debug_flags; 203 copy_settings_data->pixel_deviation_per_line = link->dpcd_caps.pr_info.pixel_deviation_per_line; 204 copy_settings_data->max_deviation_line = link->dpcd_caps.pr_info.max_deviation_line; 205 copy_settings_data->smu_optimizations_en = link->replay_settings.replay_smu_opt_enable; 206 copy_settings_data->replay_timing_sync_supported = link->replay_settings.config.replay_timing_sync_supported; 207 208 copy_settings_data->debug.bitfields.enable_ips_visual_confirm = dc->dc->debug.enable_ips_visual_confirm; 209 210 copy_settings_data->flags.u32All = 0; 211 copy_settings_data->flags.bitfields.fec_enable_status = (link->fec_state == dc_link_fec_enabled); 212 copy_settings_data->flags.bitfields.dsc_enable_status = (pipe_ctx->stream->timing.flags.DSC == 1); 213 // WA for PSRSU+DSC on specific TCON, if DSC is enabled, force PSRSU as ffu mode(full frame update) 214 if (((link->dpcd_caps.fec_cap.bits.FEC_CAPABLE && 215 !link->dc->debug.disable_fec) && 216 (link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_SUPPORT && 217 !link->panel_config.dsc.disable_dsc_edp && 218 link->dc->caps.edp_dsc_support)) && 219 link->dpcd_caps.sink_dev_id == DP_DEVICE_ID_38EC11 && 220 (!memcmp(link->dpcd_caps.sink_dev_id_str, DP_SINK_DEVICE_STR_ID_1, 221 sizeof(DP_SINK_DEVICE_STR_ID_1)) || 222 !memcmp(link->dpcd_caps.sink_dev_id_str, DP_SINK_DEVICE_STR_ID_2, 223 sizeof(DP_SINK_DEVICE_STR_ID_2)))) 224 copy_settings_data->flags.bitfields.force_wakeup_by_tps3 = 1; 225 else 226 copy_settings_data->flags.bitfields.force_wakeup_by_tps3 = 0; 227 228 dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); 229 230 return true; 231 } 232 233 /* 234 * Set coasting vtotal. 235 */ 236 static void dmub_replay_set_coasting_vtotal(struct dmub_replay *dmub, 237 uint32_t coasting_vtotal, 238 uint8_t panel_inst) 239 { 240 union dmub_rb_cmd cmd; 241 struct dc_context *dc = dmub->ctx; 242 struct dmub_rb_cmd_replay_set_coasting_vtotal *pCmd = NULL; 243 244 pCmd = &(cmd.replay_set_coasting_vtotal); 245 246 memset(&cmd, 0, sizeof(cmd)); 247 pCmd->header.type = DMUB_CMD__REPLAY; 248 pCmd->header.sub_type = DMUB_CMD__REPLAY_SET_COASTING_VTOTAL; 249 pCmd->header.payload_bytes = sizeof(struct dmub_cmd_replay_set_coasting_vtotal_data); 250 pCmd->replay_set_coasting_vtotal_data.panel_inst = panel_inst; 251 pCmd->replay_set_coasting_vtotal_data.coasting_vtotal = (coasting_vtotal & 0xFFFF); 252 pCmd->replay_set_coasting_vtotal_data.coasting_vtotal_high = (coasting_vtotal & 0xFFFF0000) >> 16; 253 254 dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); 255 } 256 257 /* 258 * Get Replay residency from firmware. 259 */ 260 static void dmub_replay_residency(struct dmub_replay *dmub, uint8_t panel_inst, 261 uint32_t *residency, const bool is_start, enum pr_residency_mode mode) 262 { 263 uint16_t param = (uint16_t)(panel_inst << 8); 264 uint32_t i = 0; 265 266 switch (mode) { 267 case PR_RESIDENCY_MODE_PHY: 268 param |= REPLAY_RESIDENCY_FIELD_MODE_PHY; 269 break; 270 case PR_RESIDENCY_MODE_ALPM: 271 param |= REPLAY_RESIDENCY_FIELD_MODE_ALPM; 272 break; 273 case PR_RESIDENCY_MODE_IPS2: 274 param |= REPLAY_RESIDENCY_REVISION_1; 275 param |= REPLAY_RESIDENCY_FIELD_MODE2_IPS; 276 break; 277 case PR_RESIDENCY_MODE_FRAME_CNT: 278 param |= REPLAY_RESIDENCY_REVISION_1; 279 param |= REPLAY_RESIDENCY_FIELD_MODE2_FRAME_CNT; 280 break; 281 case PR_RESIDENCY_MODE_ENABLEMENT_PERIOD: 282 param |= REPLAY_RESIDENCY_REVISION_1; 283 param |= REPLAY_RESIDENCY_FIELD_MODE2_EN_PERIOD; 284 break; 285 default: 286 break; 287 } 288 289 if (is_start) 290 param |= REPLAY_RESIDENCY_ENABLE; 291 292 for (i = 0; i < GPINT_RETRY_NUM; i++) { 293 // Send gpint command and wait for ack 294 if (dc_wake_and_execute_gpint(dmub->ctx, DMUB_GPINT__REPLAY_RESIDENCY, param, 295 residency, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)) 296 return; 297 298 udelay(100); 299 } 300 301 // it means gpint retry many times 302 *residency = 0; 303 } 304 305 /* 306 * Set REPLAY power optimization flags and coasting vtotal. 307 */ 308 static void dmub_replay_set_power_opt_and_coasting_vtotal(struct dmub_replay *dmub, 309 unsigned int power_opt, uint8_t panel_inst, uint32_t coasting_vtotal) 310 { 311 union dmub_rb_cmd cmd; 312 struct dc_context *dc = dmub->ctx; 313 struct dmub_rb_cmd_replay_set_power_opt_and_coasting_vtotal *pCmd = NULL; 314 315 pCmd = &(cmd.replay_set_power_opt_and_coasting_vtotal); 316 317 memset(&cmd, 0, sizeof(cmd)); 318 pCmd->header.type = DMUB_CMD__REPLAY; 319 pCmd->header.sub_type = DMUB_CMD__REPLAY_SET_POWER_OPT_AND_COASTING_VTOTAL; 320 pCmd->header.payload_bytes = 321 sizeof(struct dmub_rb_cmd_replay_set_power_opt_and_coasting_vtotal) - 322 sizeof(struct dmub_cmd_header); 323 pCmd->replay_set_power_opt_data.power_opt = power_opt; 324 pCmd->replay_set_power_opt_data.panel_inst = panel_inst; 325 pCmd->replay_set_coasting_vtotal_data.coasting_vtotal = (coasting_vtotal & 0xFFFF); 326 pCmd->replay_set_coasting_vtotal_data.coasting_vtotal_high = (coasting_vtotal & 0xFFFF0000) >> 16; 327 328 dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); 329 } 330 331 /* 332 * send Replay general cmd to DMUB. 333 */ 334 static void dmub_replay_send_cmd(struct dmub_replay *dmub, 335 enum replay_FW_Message_type msg, union dmub_replay_cmd_set *cmd_element) 336 { 337 union dmub_rb_cmd cmd; 338 struct dc_context *ctx = NULL; 339 340 if (dmub == NULL || cmd_element == NULL) 341 return; 342 343 ctx = dmub->ctx; 344 if (ctx != NULL) { 345 346 if (msg != Replay_Msg_Not_Support) { 347 memset(&cmd, 0, sizeof(cmd)); 348 //Header 349 cmd.replay_set_timing_sync.header.type = DMUB_CMD__REPLAY; 350 } else 351 return; 352 } else 353 return; 354 355 switch (msg) { 356 case Replay_Set_Timing_Sync_Supported: 357 //Header 358 cmd.replay_set_timing_sync.header.sub_type = 359 DMUB_CMD__REPLAY_SET_TIMING_SYNC_SUPPORTED; 360 cmd.replay_set_timing_sync.header.payload_bytes = 361 sizeof(struct dmub_rb_cmd_replay_set_timing_sync) - 362 sizeof(struct dmub_cmd_header); 363 //Cmd Body 364 cmd.replay_set_timing_sync.replay_set_timing_sync_data.panel_inst = 365 cmd_element->sync_data.panel_inst; 366 cmd.replay_set_timing_sync.replay_set_timing_sync_data.timing_sync_supported = 367 cmd_element->sync_data.timing_sync_supported; 368 break; 369 case Replay_Set_Residency_Frameupdate_Timer: 370 //Header 371 cmd.replay_set_frameupdate_timer.header.sub_type = 372 DMUB_CMD__REPLAY_SET_RESIDENCY_FRAMEUPDATE_TIMER; 373 cmd.replay_set_frameupdate_timer.header.payload_bytes = 374 sizeof(struct dmub_rb_cmd_replay_set_frameupdate_timer) - 375 sizeof(struct dmub_cmd_header); 376 //Cmd Body 377 cmd.replay_set_frameupdate_timer.data.panel_inst = 378 cmd_element->panel_inst; 379 cmd.replay_set_frameupdate_timer.data.enable = 380 cmd_element->timer_data.enable; 381 cmd.replay_set_frameupdate_timer.data.frameupdate_count = 382 cmd_element->timer_data.frameupdate_count; 383 break; 384 case Replay_Set_Pseudo_VTotal: 385 //Header 386 cmd.replay_set_pseudo_vtotal.header.sub_type = 387 DMUB_CMD__REPLAY_SET_PSEUDO_VTOTAL; 388 cmd.replay_set_pseudo_vtotal.header.payload_bytes = 389 sizeof(struct dmub_rb_cmd_replay_set_pseudo_vtotal) - 390 sizeof(struct dmub_cmd_header); 391 //Cmd Body 392 cmd.replay_set_pseudo_vtotal.data.panel_inst = 393 cmd_element->pseudo_vtotal_data.panel_inst; 394 cmd.replay_set_pseudo_vtotal.data.vtotal = 395 cmd_element->pseudo_vtotal_data.vtotal; 396 break; 397 case Replay_Disabled_Adaptive_Sync_SDP: 398 //Header 399 cmd.replay_disabled_adaptive_sync_sdp.header.sub_type = 400 DMUB_CMD__REPLAY_DISABLED_ADAPTIVE_SYNC_SDP; 401 cmd.replay_disabled_adaptive_sync_sdp.header.payload_bytes = 402 sizeof(struct dmub_rb_cmd_replay_disabled_adaptive_sync_sdp) - 403 sizeof(struct dmub_cmd_header); 404 //Cmd Body 405 cmd.replay_disabled_adaptive_sync_sdp.data.panel_inst = 406 cmd_element->disabled_adaptive_sync_sdp_data.panel_inst; 407 cmd.replay_disabled_adaptive_sync_sdp.data.force_disabled = 408 cmd_element->disabled_adaptive_sync_sdp_data.force_disabled; 409 break; 410 case Replay_Set_General_Cmd: 411 //Header 412 cmd.replay_set_general_cmd.header.sub_type = 413 DMUB_CMD__REPLAY_SET_GENERAL_CMD; 414 cmd.replay_set_general_cmd.header.payload_bytes = 415 sizeof(struct dmub_rb_cmd_replay_set_general_cmd) - 416 sizeof(struct dmub_cmd_header); 417 //Cmd Body 418 cmd.replay_set_general_cmd.data.panel_inst = 419 cmd_element->set_general_cmd_data.panel_inst; 420 cmd.replay_set_general_cmd.data.subtype = 421 cmd_element->set_general_cmd_data.subtype; 422 cmd.replay_set_general_cmd.data.param1 = 423 cmd_element->set_general_cmd_data.param1; 424 cmd.replay_set_general_cmd.data.param2 = 425 cmd_element->set_general_cmd_data.param2; 426 break; 427 case Replay_Msg_Not_Support: 428 default: 429 return; 430 break; 431 } 432 433 dc_wake_and_execute_dmub_cmd(ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); 434 } 435 436 static const struct dmub_replay_funcs replay_funcs = { 437 .replay_copy_settings = dmub_replay_copy_settings, 438 .replay_enable = dmub_replay_enable, 439 .replay_get_state = dmub_replay_get_state, 440 .replay_set_power_opt = dmub_replay_set_power_opt, 441 .replay_set_coasting_vtotal = dmub_replay_set_coasting_vtotal, 442 .replay_residency = dmub_replay_residency, 443 .replay_set_power_opt_and_coasting_vtotal = dmub_replay_set_power_opt_and_coasting_vtotal, 444 .replay_send_cmd = dmub_replay_send_cmd, 445 }; 446 447 /* 448 * Construct Replay object. 449 */ 450 static void dmub_replay_construct(struct dmub_replay *replay, struct dc_context *ctx) 451 { 452 replay->ctx = ctx; 453 replay->funcs = &replay_funcs; 454 } 455 456 /* 457 * Allocate and initialize Replay object. 458 */ 459 struct dmub_replay *dmub_replay_create(struct dc_context *ctx) 460 { 461 struct dmub_replay *replay = kzalloc(sizeof(struct dmub_replay), GFP_KERNEL); 462 463 if (replay == NULL) { 464 BREAK_TO_DEBUGGER(); 465 return NULL; 466 } 467 468 dmub_replay_construct(replay, ctx); 469 470 return replay; 471 } 472 473 /* 474 * Deallocate Replay object. 475 */ 476 void dmub_replay_destroy(struct dmub_replay **dmub) 477 { 478 kfree(*dmub); 479 *dmub = NULL; 480 } 481