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