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 = (uint8_t)pipe_ctx->plane_res.dpp->inst; 155 else 156 copy_settings_data->dpp_inst = 0; 157 158 if (pipe_ctx->stream_res.tg) 159 copy_settings_data->otg_inst = (uint8_t)pipe_ctx->stream_res.tg->inst; 160 else 161 copy_settings_data->otg_inst = 0; 162 163 copy_settings_data->dpphy_inst = link->link_enc->transmitter; 164 165 // Misc 166 copy_settings_data->line_time_in_ns = (uint16_t)replay_context->line_time_in_ns; 167 copy_settings_data->panel_inst = (uint16_t)panel_inst; 168 copy_settings_data->debug.u32All = link->replay_settings.config.debug_flags; 169 copy_settings_data->pixel_deviation_per_line = link->dpcd_caps.pr_info.pixel_deviation_per_line; 170 copy_settings_data->max_deviation_line = (uint16_t)link->dpcd_caps.pr_info.max_deviation_line; 171 copy_settings_data->smu_optimizations_en = link->replay_settings.replay_smu_opt_enable; 172 copy_settings_data->replay_timing_sync_supported = link->replay_settings.config.replay_timing_sync_supported; 173 copy_settings_data->replay_support_fast_resync_in_ultra_sleep_mode = link->replay_settings.config.replay_support_fast_resync_in_ultra_sleep_mode; 174 175 copy_settings_data->debug.bitfields.enable_ips_visual_confirm = dc->dc->debug.enable_ips_visual_confirm; 176 177 copy_settings_data->flags.u32All = 0; 178 copy_settings_data->flags.bitfields.fec_enable_status = (link->fec_state == dc_link_fec_enabled); 179 copy_settings_data->flags.bitfields.dsc_enable_status = (pipe_ctx->stream->timing.flags.DSC == 1); 180 // WA for PSRSU+DSC on specific TCON, if DSC is enabled, force PSRSU as ffu mode(full frame update) 181 if (((link->dpcd_caps.fec_cap.bits.FEC_CAPABLE && 182 !link->dc->debug.disable_fec) && 183 (link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_SUPPORT && 184 !link->panel_config.dsc.disable_dsc_edp && 185 link->dc->caps.edp_dsc_support)) && 186 link->dpcd_caps.sink_dev_id == DP_DEVICE_ID_38EC11 && 187 (!memcmp(link->dpcd_caps.sink_dev_id_str, DP_SINK_DEVICE_STR_ID_1, 188 sizeof(DP_SINK_DEVICE_STR_ID_1)) || 189 !memcmp(link->dpcd_caps.sink_dev_id_str, DP_SINK_DEVICE_STR_ID_2, 190 sizeof(DP_SINK_DEVICE_STR_ID_2)))) 191 copy_settings_data->flags.bitfields.force_wakeup_by_tps3 = 1; 192 else 193 copy_settings_data->flags.bitfields.force_wakeup_by_tps3 = 0; 194 195 copy_settings_data->flags.bitfields.alpm_mode = (enum dmub_alpm_mode)link->replay_settings.config.alpm_mode; 196 if (link->replay_settings.config.alpm_mode == DC_ALPM_AUXLESS) { 197 copy_settings_data->auxless_alpm_data.lfps_setup_ns = (uint16_t)dc->dc->debug.auxless_alpm_lfps_setup_ns; 198 copy_settings_data->auxless_alpm_data.lfps_period_ns = (uint16_t)dc->dc->debug.auxless_alpm_lfps_period_ns; 199 copy_settings_data->auxless_alpm_data.lfps_silence_ns = (uint16_t)dc->dc->debug.auxless_alpm_lfps_silence_ns; 200 copy_settings_data->auxless_alpm_data.lfps_t1_t2_override_us = 201 (uint16_t)dc->dc->debug.auxless_alpm_lfps_t1t2_us; 202 copy_settings_data->auxless_alpm_data.lfps_t1_t2_offset_us = 203 (uint16_t)dc->dc->debug.auxless_alpm_lfps_t1t2_offset_us; 204 copy_settings_data->auxless_alpm_data.lttpr_count = link->dc->link_srv->dp_get_lttpr_count(link); 205 } 206 207 dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); 208 209 return true; 210 } 211 212 /* 213 * Set coasting vtotal. 214 */ 215 static void dmub_replay_set_coasting_vtotal(struct dmub_replay *dmub, 216 uint32_t coasting_vtotal, 217 uint8_t panel_inst, 218 uint16_t frame_skip_number) 219 { 220 (void)panel_inst; 221 union dmub_rb_cmd cmd; 222 struct dc_context *dc = dmub->ctx; 223 struct dmub_rb_cmd_replay_set_coasting_vtotal *pCmd = NULL; 224 225 pCmd = &(cmd.replay_set_coasting_vtotal); 226 227 memset(&cmd, 0, sizeof(cmd)); 228 pCmd->header.type = DMUB_CMD__REPLAY; 229 pCmd->header.sub_type = DMUB_CMD__REPLAY_SET_COASTING_VTOTAL; 230 pCmd->header.payload_bytes = sizeof(struct dmub_cmd_replay_set_coasting_vtotal_data); 231 pCmd->replay_set_coasting_vtotal_data.coasting_vtotal = (coasting_vtotal & 0xFFFF); 232 pCmd->replay_set_coasting_vtotal_data.coasting_vtotal_high = (coasting_vtotal & 0xFFFF0000) >> 16; 233 pCmd->replay_set_coasting_vtotal_data.frame_skip_number = frame_skip_number; 234 235 dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); 236 } 237 238 /* 239 * Get Replay residency from firmware. 240 */ 241 static void dmub_replay_residency(struct dmub_replay *dmub, uint8_t panel_inst, 242 uint32_t *residency, const bool is_start, enum pr_residency_mode mode) 243 { 244 uint16_t param = (uint16_t)(panel_inst << 8); 245 uint32_t i = 0; 246 247 switch (mode) { 248 case PR_RESIDENCY_MODE_PHY: 249 param |= REPLAY_RESIDENCY_FIELD_MODE_PHY; 250 break; 251 case PR_RESIDENCY_MODE_ALPM: 252 param |= REPLAY_RESIDENCY_FIELD_MODE_ALPM; 253 break; 254 case PR_RESIDENCY_MODE_IPS2: 255 param |= REPLAY_RESIDENCY_REVISION_1; 256 param |= REPLAY_RESIDENCY_FIELD_MODE2_IPS; 257 break; 258 case PR_RESIDENCY_MODE_FRAME_CNT: 259 param |= REPLAY_RESIDENCY_REVISION_1; 260 param |= REPLAY_RESIDENCY_FIELD_MODE2_FRAME_CNT; 261 break; 262 case PR_RESIDENCY_MODE_ENABLEMENT_PERIOD: 263 param |= REPLAY_RESIDENCY_REVISION_1; 264 param |= REPLAY_RESIDENCY_FIELD_MODE2_EN_PERIOD; 265 break; 266 default: 267 break; 268 } 269 270 if (is_start) 271 param |= REPLAY_RESIDENCY_ENABLE; 272 273 for (i = 0; i < GPINT_RETRY_NUM; i++) { 274 // Send gpint command and wait for ack 275 if (dc_wake_and_execute_gpint(dmub->ctx, DMUB_GPINT__REPLAY_RESIDENCY, param, 276 residency, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)) 277 return; 278 279 udelay(100); 280 } 281 282 // it means gpint retry many times 283 *residency = 0; 284 } 285 286 /* 287 * Set REPLAY power optimization flags and coasting vtotal. 288 */ 289 static void dmub_replay_set_power_opt_and_coasting_vtotal(struct dmub_replay *dmub, 290 unsigned int power_opt, uint8_t panel_inst, uint32_t coasting_vtotal, uint16_t frame_skip_number) 291 { 292 union dmub_rb_cmd cmd; 293 struct dc_context *dc = dmub->ctx; 294 struct dmub_rb_cmd_replay_set_power_opt_and_coasting_vtotal *pCmd = NULL; 295 296 pCmd = &(cmd.replay_set_power_opt_and_coasting_vtotal); 297 298 memset(&cmd, 0, sizeof(cmd)); 299 pCmd->header.type = DMUB_CMD__REPLAY; 300 pCmd->header.sub_type = DMUB_CMD__REPLAY_SET_POWER_OPT_AND_COASTING_VTOTAL; 301 pCmd->header.payload_bytes = 302 sizeof(struct dmub_rb_cmd_replay_set_power_opt_and_coasting_vtotal) - 303 sizeof(struct dmub_cmd_header); 304 pCmd->replay_set_power_opt_data.power_opt = power_opt; 305 pCmd->replay_set_power_opt_data.panel_inst = panel_inst; 306 pCmd->replay_set_coasting_vtotal_data.coasting_vtotal = (coasting_vtotal & 0xFFFF); 307 pCmd->replay_set_coasting_vtotal_data.coasting_vtotal_high = (coasting_vtotal & 0xFFFF0000) >> 16; 308 pCmd->replay_set_coasting_vtotal_data.frame_skip_number = frame_skip_number; 309 310 dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); 311 } 312 313 /* 314 * send Replay general cmd to DMUB. 315 */ 316 static void dmub_replay_send_cmd(struct dmub_replay *dmub, 317 enum replay_FW_Message_type msg, union dmub_replay_cmd_set *cmd_element) 318 { 319 union dmub_rb_cmd cmd; 320 struct dc_context *ctx = NULL; 321 322 if (dmub == NULL || cmd_element == NULL) 323 return; 324 325 ctx = dmub->ctx; 326 if (ctx != NULL) { 327 328 if (msg != Replay_Msg_Not_Support) { 329 memset(&cmd, 0, sizeof(cmd)); 330 //Header 331 cmd.replay_set_timing_sync.header.type = DMUB_CMD__REPLAY; 332 } else 333 return; 334 } else 335 return; 336 337 switch (msg) { 338 case Replay_Set_Timing_Sync_Supported: 339 //Header 340 cmd.replay_set_timing_sync.header.sub_type = 341 DMUB_CMD__REPLAY_SET_TIMING_SYNC_SUPPORTED; 342 cmd.replay_set_timing_sync.header.payload_bytes = 343 sizeof(struct dmub_rb_cmd_replay_set_timing_sync) - 344 sizeof(struct dmub_cmd_header); 345 //Cmd Body 346 cmd.replay_set_timing_sync.replay_set_timing_sync_data.panel_inst = 347 cmd_element->sync_data.panel_inst; 348 cmd.replay_set_timing_sync.replay_set_timing_sync_data.timing_sync_supported = 349 cmd_element->sync_data.timing_sync_supported; 350 break; 351 case Replay_Set_Residency_Frameupdate_Timer: 352 //Header 353 cmd.replay_set_frameupdate_timer.header.sub_type = 354 DMUB_CMD__REPLAY_SET_RESIDENCY_FRAMEUPDATE_TIMER; 355 cmd.replay_set_frameupdate_timer.header.payload_bytes = 356 sizeof(struct dmub_rb_cmd_replay_set_frameupdate_timer) - 357 sizeof(struct dmub_cmd_header); 358 //Cmd Body 359 cmd.replay_set_frameupdate_timer.data.panel_inst = 360 cmd_element->panel_inst; 361 cmd.replay_set_frameupdate_timer.data.enable = 362 cmd_element->timer_data.enable; 363 cmd.replay_set_frameupdate_timer.data.frameupdate_count = 364 cmd_element->timer_data.frameupdate_count; 365 break; 366 case Replay_Set_Pseudo_VTotal: 367 //Header 368 cmd.replay_set_pseudo_vtotal.header.sub_type = 369 DMUB_CMD__REPLAY_SET_PSEUDO_VTOTAL; 370 cmd.replay_set_pseudo_vtotal.header.payload_bytes = 371 sizeof(struct dmub_rb_cmd_replay_set_pseudo_vtotal) - 372 sizeof(struct dmub_cmd_header); 373 //Cmd Body 374 cmd.replay_set_pseudo_vtotal.data.panel_inst = 375 cmd_element->pseudo_vtotal_data.panel_inst; 376 cmd.replay_set_pseudo_vtotal.data.vtotal = 377 cmd_element->pseudo_vtotal_data.vtotal; 378 break; 379 case Replay_Disabled_Adaptive_Sync_SDP: 380 //Header 381 cmd.replay_disabled_adaptive_sync_sdp.header.sub_type = 382 DMUB_CMD__REPLAY_DISABLED_ADAPTIVE_SYNC_SDP; 383 cmd.replay_disabled_adaptive_sync_sdp.header.payload_bytes = 384 sizeof(struct dmub_rb_cmd_replay_disabled_adaptive_sync_sdp) - 385 sizeof(struct dmub_cmd_header); 386 //Cmd Body 387 cmd.replay_disabled_adaptive_sync_sdp.data.panel_inst = 388 cmd_element->disabled_adaptive_sync_sdp_data.panel_inst; 389 cmd.replay_disabled_adaptive_sync_sdp.data.force_disabled = 390 cmd_element->disabled_adaptive_sync_sdp_data.force_disabled; 391 break; 392 case Replay_Set_General_Cmd: 393 //Header 394 cmd.replay_set_general_cmd.header.sub_type = 395 DMUB_CMD__REPLAY_SET_GENERAL_CMD; 396 cmd.replay_set_general_cmd.header.payload_bytes = 397 sizeof(struct dmub_rb_cmd_replay_set_general_cmd) - 398 sizeof(struct dmub_cmd_header); 399 //Cmd Body 400 cmd.replay_set_general_cmd.data.panel_inst = 401 cmd_element->set_general_cmd_data.panel_inst; 402 cmd.replay_set_general_cmd.data.subtype = 403 cmd_element->set_general_cmd_data.subtype; 404 cmd.replay_set_general_cmd.data.param1 = 405 cmd_element->set_general_cmd_data.param1; 406 cmd.replay_set_general_cmd.data.param2 = 407 cmd_element->set_general_cmd_data.param2; 408 break; 409 case Replay_Msg_Not_Support: 410 default: 411 return; 412 break; 413 } 414 415 dc_wake_and_execute_dmub_cmd(ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); 416 } 417 418 static const struct dmub_replay_funcs replay_funcs = { 419 .replay_copy_settings = dmub_replay_copy_settings, 420 .replay_enable = dmub_replay_enable, 421 .replay_get_state = dmub_replay_get_state, 422 .replay_set_power_opt = dmub_replay_set_power_opt, 423 .replay_set_coasting_vtotal = dmub_replay_set_coasting_vtotal, 424 .replay_residency = dmub_replay_residency, 425 .replay_set_power_opt_and_coasting_vtotal = dmub_replay_set_power_opt_and_coasting_vtotal, 426 .replay_send_cmd = dmub_replay_send_cmd, 427 }; 428 429 /* 430 * Construct Replay object. 431 */ 432 static void dmub_replay_construct(struct dmub_replay *replay, struct dc_context *ctx) 433 { 434 replay->ctx = ctx; 435 replay->funcs = &replay_funcs; 436 } 437 438 /* 439 * Allocate and initialize Replay object. 440 */ 441 struct dmub_replay *dmub_replay_create(struct dc_context *ctx) 442 { 443 struct dmub_replay *replay = kzalloc_obj(struct dmub_replay); 444 445 if (replay == NULL) { 446 BREAK_TO_DEBUGGER(); 447 return NULL; 448 } 449 450 dmub_replay_construct(replay, ctx); 451 452 return replay; 453 } 454 455 /* 456 * Deallocate Replay object. 457 */ 458 void dmub_replay_destroy(struct dmub_replay **dmub) 459 { 460 kfree(*dmub); 461 *dmub = NULL; 462 } 463