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