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