1 // SPDX-License-Identifier: MIT 2 3 /* Copyright 2025 Advanced Micro Devices, Inc. */ 4 5 #include "../dmub_srv.h" 6 #include "dmub_reg.h" 7 #include "dmub_dcn60.h" 8 9 #include "dcn/dcn_6_0_0_offset.h" 10 #include "dcn/dcn_6_0_0_sh_mask.h" 11 #include "mmhub/mmhub_5_0_1_offset.h" 12 #include "mmhub/mmhub_5_0_1_sh_mask.h" 13 14 #define DCN_BASE__INST0_SEG2 0x000034C0 15 #define MMHUB_BASE__INST0_SEG1 0x0001A000 16 17 #define BASE_INNER(seg) DCN_BASE__INST0_SEG##seg 18 #define CTX dmub 19 #define REGS dmub->regs_dcn60 20 #define REG_OFFSET_EXP(reg_name) (BASE(reg##reg_name##_BASE_IDX) + reg##reg_name) 21 #define EXT_REG_READ(addr) dmub->funcs.reg_read(dmub->user_ctx, addr); 22 #define DAGB0_WRCLI_OSD_PENDING 0x1A083 23 24 #define MMHUB_BASE_INNER(seg) MMHUB_BASE__INST0_SEG##seg 25 #define MMHUB_BASE(seg) MMHUB_BASE_INNER(seg) 26 #define MMHUB_REG_OFFSET(reg_name) (MMHUB_BASE(reg##reg_name##_BASE_IDX) + reg##reg_name) 27 28 const struct dmub_srv_dcn60_regs dmub_srv_dcn60_regs = { 29 #define DMUB_SR(reg) .reg = REG_OFFSET_EXP(reg), 30 #define MMHUB_SR(reg) .reg = MMHUB_REG_OFFSET(reg), 31 .offset = { 32 DMUB_DCN60_REGS() 33 DMCUB_INTERNAL_REGS() 34 DCN60_EXTERNAL_MMHUB_REGS() 35 }, 36 #undef MMHUB_SR 37 #undef DMUB_SR 38 39 #define DMUB_SF(reg, field) .reg##__##field = FD_MASK(reg, field), 40 .mask = { 41 DMUB_DCN60_FIELDS() 42 DCN60_EXTERNAL_MMHUB_FIELDS() 43 }, 44 #undef DMUB_SF 45 46 #define DMUB_SF(reg, field) .reg##__##field = FD_SHIFT(reg, field), 47 .shift = { 48 DMUB_DCN60_FIELDS() 49 DCN60_EXTERNAL_MMHUB_FIELDS() 50 }, 51 #undef DMUB_SF 52 }; 53 54 static void dmub_dcn60_get_fb_base_offset(struct dmub_srv *dmub, 55 uint64_t *fb_base, 56 uint64_t *fb_offset) 57 { 58 uint32_t tmp_fb_base, tmp_fb_offset; 59 60 /* 61 * Favor override values from DM. 62 * This can handle multi device systems with shared memory space. 63 */ 64 if (dmub->soc_fb_info.fb_base || dmub->soc_fb_info.fb_offset) { 65 *fb_base = dmub->soc_fb_info.fb_base; 66 *fb_offset = dmub->soc_fb_info.fb_offset; 67 return; 68 } 69 70 /* 71 * For DCN only environments prefer DCN local registers first. 72 * These should be a copy of the MMHUB registers below for single device systems. 73 */ 74 REG_GET(DCN_VM_FB_LOCATION_BASE, FB_BASE, &tmp_fb_base); 75 REG_GET(DCN_VM_FB_OFFSET, FB_OFFSET, &tmp_fb_offset); 76 77 if (!dmub->no_ext_reg_access && tmp_fb_base == 0 && tmp_fb_offset == 0) { 78 /* 79 * Memory translation is handled by MMHUB for DMU. 80 * Use these as a fallback if DCN is not configured. 81 */ 82 REG_GET(MMMC_VM_FB_LOCATION_BASE, FB_BASE, &tmp_fb_base); 83 REG_GET(MMMC_VM_FB_OFFSET, FB_OFFSET, &tmp_fb_offset); 84 } 85 86 *fb_base = (uint64_t)tmp_fb_base << 24; 87 *fb_offset = (uint64_t)tmp_fb_offset << 24; 88 } 89 90 static inline void dmub_dcn60_translate_addr(const union dmub_addr *addr_in, 91 uint64_t fb_base, 92 uint64_t fb_offset, 93 union dmub_addr *addr_out) 94 { 95 addr_out->quad_part = addr_in->quad_part - fb_base + fb_offset; 96 } 97 98 void dmub_dcn60_reset(struct dmub_srv *dmub) 99 { 100 union dmub_gpint_data_register cmd; 101 const uint32_t timeout_us = 1 * 1000 * 1000; //1s 102 const uint32_t poll_delay_us = 1; //1us 103 uint32_t i = 0; 104 uint32_t enabled, in_reset, scratch, pwait_mode, outstanding_req;; 105 106 REG_GET(DMCUB_CNTL, 107 DMCUB_ENABLE, &enabled); 108 REG_GET(DMCUB_CNTL2, 109 DMCUB_SOFT_RESET, &in_reset); 110 111 if (enabled && in_reset == 0) { 112 cmd.bits.status = 1; 113 cmd.bits.command_code = DMUB_GPINT__STOP_FW; 114 cmd.bits.param = 0; 115 116 dmub->hw_funcs.set_gpint(dmub, cmd); 117 118 for (; i < timeout_us; i++) { 119 scratch = REG_READ(DMCUB_SCRATCH7); 120 if (scratch == DMUB_GPINT__STOP_FW_RESPONSE) 121 break; 122 123 udelay(poll_delay_us); 124 } 125 126 for (; i < timeout_us; i++) { 127 REG_GET(DMCUB_CNTL, DMCUB_PWAIT_MODE_STATUS, &pwait_mode); 128 if (pwait_mode & (1 << 0)) 129 break; 130 131 udelay(poll_delay_us); 132 } 133 134 if (!dmub->no_ext_reg_access) { 135 for (; i < timeout_us; i++) { 136 outstanding_req = EXT_REG_READ(DAGB0_WRCLI_OSD_PENDING); 137 if (!(outstanding_req & 0x10)) 138 break; 139 140 udelay(poll_delay_us); 141 } 142 } 143 } 144 145 if (enabled) { 146 REG_UPDATE(DMCUB_CNTL2, DMCUB_SOFT_RESET, 1); 147 udelay(1); 148 REG_UPDATE(DMCUB_CNTL, DMCUB_ENABLE, 0); 149 } 150 151 if (i >= timeout_us) { 152 /* timeout should never occur */ 153 BREAK_TO_DEBUGGER(); 154 } 155 156 REG_UPDATE(DMCUB_REGION3_CW2_TOP_ADDRESS, DMCUB_REGION3_CW2_ENABLE, 0); 157 REG_UPDATE(DMCUB_REGION3_CW3_TOP_ADDRESS, DMCUB_REGION3_CW3_ENABLE, 0); 158 REG_UPDATE(DMCUB_REGION3_CW4_TOP_ADDRESS, DMCUB_REGION3_CW4_ENABLE, 0); 159 REG_UPDATE(DMCUB_REGION3_CW5_TOP_ADDRESS, DMCUB_REGION3_CW5_ENABLE, 0); 160 REG_UPDATE(DMCUB_REGION3_CW6_TOP_ADDRESS, DMCUB_REGION3_CW6_ENABLE, 0); 161 REG_UPDATE(DMCUB_REGION3_CW7_TOP_ADDRESS, DMCUB_REGION3_CW7_ENABLE, 0); 162 163 REG_WRITE(DMCUB_INBOX1_RPTR, 0); 164 REG_WRITE(DMCUB_INBOX1_WPTR, 0); 165 REG_WRITE(DMCUB_OUTBOX1_RPTR, 0); 166 REG_WRITE(DMCUB_OUTBOX1_WPTR, 0); 167 REG_WRITE(DMCUB_OUTBOX0_RPTR, 0); 168 REG_WRITE(DMCUB_OUTBOX0_WPTR, 0); 169 REG_WRITE(DMCUB_SCRATCH0, 0); 170 171 /* Clear the GPINT command manually so we don't reset again. */ 172 cmd.all = 0; 173 dmub->hw_funcs.set_gpint(dmub, cmd); 174 } 175 176 void dmub_dcn60_reset_release(struct dmub_srv *dmub) 177 { 178 REG_UPDATE(MMHUBBUB_SOFT_RESET, DMUIF_SOFT_RESET, 0); 179 REG_WRITE(DMCUB_SCRATCH15, dmub->psp_version & 0x001100FF); 180 REG_UPDATE_2(DMCUB_CNTL, DMCUB_ENABLE, 1, DMCUB_TRACEPORT_EN, 1); 181 REG_UPDATE(DMCUB_CNTL2, DMCUB_SOFT_RESET, 0); 182 } 183 184 void dmub_dcn60_backdoor_load(struct dmub_srv *dmub, 185 const struct dmub_window *cw0, 186 const struct dmub_window *cw1) 187 { 188 union dmub_addr offset; 189 uint64_t fb_base, fb_offset; 190 191 dmub_dcn60_get_fb_base_offset(dmub, &fb_base, &fb_offset); 192 193 /* reset and disable DMCUB and MMHUBBUB DMUIF */ 194 REG_UPDATE(DMCUB_SEC_CNTL, DMCUB_SEC_RESET, 1); 195 REG_UPDATE(DMCUB_CNTL, DMCUB_ENABLE, 0); 196 197 dmub_dcn60_translate_addr(&cw0->offset, fb_base, fb_offset, &offset); 198 199 REG_WRITE(DMCUB_REGION3_CW0_OFFSET, offset.u.low_part); 200 REG_WRITE(DMCUB_REGION3_CW0_OFFSET_HIGH, offset.u.high_part); 201 REG_WRITE(DMCUB_REGION3_CW0_BASE_ADDRESS, cw0->region.base); 202 REG_SET_2(DMCUB_REGION3_CW0_TOP_ADDRESS, 0, 203 DMCUB_REGION3_CW0_TOP_ADDRESS, cw0->region.top, 204 DMCUB_REGION3_CW0_ENABLE, 1); 205 206 dmub_dcn60_translate_addr(&cw1->offset, fb_base, fb_offset, &offset); 207 208 REG_WRITE(DMCUB_REGION3_CW1_OFFSET, offset.u.low_part); 209 REG_WRITE(DMCUB_REGION3_CW1_OFFSET_HIGH, offset.u.high_part); 210 REG_WRITE(DMCUB_REGION3_CW1_BASE_ADDRESS, cw1->region.base); 211 REG_SET_2(DMCUB_REGION3_CW1_TOP_ADDRESS, 0, 212 DMCUB_REGION3_CW1_TOP_ADDRESS, cw1->region.top, 213 DMCUB_REGION3_CW1_ENABLE, 1); 214 215 /* release DMCUB reset only to prevent premature execution */ 216 REG_UPDATE_3(DMCUB_SEC_CNTL, DMCUB_SEC_RESET, 0, 217 DMCUB_MEM_SEC_LVL, 0x2, 218 DMCUB_MEM_UNIT_ID, 0x20); 219 } 220 221 void dmub_dcn60_backdoor_load_zfb_mode(struct dmub_srv *dmub, 222 const struct dmub_window *cw0, 223 const struct dmub_window *cw1) 224 { 225 union dmub_addr offset; 226 227 /* reset and disable DMCUB and MMHUBBUB DMUIF */ 228 REG_UPDATE(DMCUB_SEC_CNTL, DMCUB_SEC_RESET, 1); 229 REG_UPDATE(DMCUB_CNTL, DMCUB_ENABLE, 0); 230 231 offset = cw0->offset; 232 233 REG_WRITE(DMCUB_REGION3_CW0_OFFSET, offset.u.low_part); 234 REG_WRITE(DMCUB_REGION3_CW0_OFFSET_HIGH, offset.u.high_part); 235 REG_WRITE(DMCUB_REGION3_CW0_BASE_ADDRESS, cw0->region.base); 236 REG_SET_2(DMCUB_REGION3_CW0_TOP_ADDRESS, 0, 237 DMCUB_REGION3_CW0_TOP_ADDRESS, cw0->region.top, 238 DMCUB_REGION3_CW0_ENABLE, 1); 239 240 offset = cw1->offset; 241 242 REG_WRITE(DMCUB_REGION3_CW1_OFFSET, offset.u.low_part); 243 REG_WRITE(DMCUB_REGION3_CW1_OFFSET_HIGH, offset.u.high_part); 244 REG_WRITE(DMCUB_REGION3_CW1_BASE_ADDRESS, cw1->region.base); 245 REG_SET_2(DMCUB_REGION3_CW1_TOP_ADDRESS, 0, 246 DMCUB_REGION3_CW1_TOP_ADDRESS, cw1->region.top, 247 DMCUB_REGION3_CW1_ENABLE, 1); 248 249 /* release DMCUB reset only to prevent premature execution */ 250 REG_UPDATE_3(DMCUB_SEC_CNTL, DMCUB_SEC_RESET, 0, 251 DMCUB_MEM_SEC_LVL, 0x2, 252 DMCUB_MEM_UNIT_ID, 0x20); 253 } 254 255 void dmub_dcn60_setup_windows(struct dmub_srv *dmub, 256 const struct dmub_window *cw2, 257 const struct dmub_window *cw3, 258 const struct dmub_window *cw4, 259 const struct dmub_window *cw5, 260 const struct dmub_window *cw6, 261 const struct dmub_window *region6) 262 { 263 (void)cw2; 264 union dmub_addr offset; 265 266 offset = cw3->offset; 267 268 REG_WRITE(DMCUB_REGION3_CW3_OFFSET, offset.u.low_part); 269 REG_WRITE(DMCUB_REGION3_CW3_OFFSET_HIGH, offset.u.high_part); 270 REG_WRITE(DMCUB_REGION3_CW3_BASE_ADDRESS, cw3->region.base); 271 REG_SET_2(DMCUB_REGION3_CW3_TOP_ADDRESS, 0, 272 DMCUB_REGION3_CW3_TOP_ADDRESS, cw3->region.top, 273 DMCUB_REGION3_CW3_ENABLE, 1); 274 275 offset = cw4->offset; 276 277 REG_WRITE(DMCUB_REGION3_CW4_OFFSET, offset.u.low_part); 278 REG_WRITE(DMCUB_REGION3_CW4_OFFSET_HIGH, offset.u.high_part); 279 REG_WRITE(DMCUB_REGION3_CW4_BASE_ADDRESS, cw4->region.base); 280 REG_SET_2(DMCUB_REGION3_CW4_TOP_ADDRESS, 0, 281 DMCUB_REGION3_CW4_TOP_ADDRESS, cw4->region.top, 282 DMCUB_REGION3_CW4_ENABLE, 1); 283 284 offset = cw5->offset; 285 286 REG_WRITE(DMCUB_REGION3_CW5_OFFSET, offset.u.low_part); 287 REG_WRITE(DMCUB_REGION3_CW5_OFFSET_HIGH, offset.u.high_part); 288 REG_WRITE(DMCUB_REGION3_CW5_BASE_ADDRESS, cw5->region.base); 289 REG_SET_2(DMCUB_REGION3_CW5_TOP_ADDRESS, 0, 290 DMCUB_REGION3_CW5_TOP_ADDRESS, cw5->region.top, 291 DMCUB_REGION3_CW5_ENABLE, 1); 292 293 REG_WRITE(DMCUB_REGION5_OFFSET, offset.u.low_part); 294 REG_WRITE(DMCUB_REGION5_OFFSET_HIGH, offset.u.high_part); 295 REG_SET_2(DMCUB_REGION5_TOP_ADDRESS, 0, 296 DMCUB_REGION5_TOP_ADDRESS, 297 cw5->region.top - cw5->region.base - 1, 298 DMCUB_REGION5_ENABLE, 1); 299 300 offset = cw6->offset; 301 302 REG_WRITE(DMCUB_REGION3_CW6_OFFSET, offset.u.low_part); 303 REG_WRITE(DMCUB_REGION3_CW6_OFFSET_HIGH, offset.u.high_part); 304 REG_WRITE(DMCUB_REGION3_CW6_BASE_ADDRESS, cw6->region.base); 305 REG_SET_2(DMCUB_REGION3_CW6_TOP_ADDRESS, 0, 306 DMCUB_REGION3_CW6_TOP_ADDRESS, cw6->region.top, 307 DMCUB_REGION3_CW6_ENABLE, 1); 308 309 offset = region6->offset; 310 311 REG_WRITE(DMCUB_REGION6_OFFSET, offset.u.low_part); 312 REG_WRITE(DMCUB_REGION6_OFFSET_HIGH, offset.u.high_part); 313 REG_SET_2(DMCUB_REGION6_TOP_ADDRESS, 0, 314 DMCUB_REGION6_TOP_ADDRESS, 315 region6->region.top - region6->region.base - 1, 316 DMCUB_REGION6_ENABLE, 1); 317 } 318 319 void dmub_dcn60_setup_mailbox(struct dmub_srv *dmub, 320 const struct dmub_region *inbox1) 321 { 322 REG_WRITE(DMCUB_INBOX1_BASE_ADDRESS, inbox1->base); 323 REG_WRITE(DMCUB_INBOX1_SIZE, inbox1->top - inbox1->base); 324 } 325 326 uint32_t dmub_dcn60_get_inbox1_wptr(struct dmub_srv *dmub) 327 { 328 return REG_READ(DMCUB_INBOX1_WPTR); 329 } 330 331 uint32_t dmub_dcn60_get_inbox1_rptr(struct dmub_srv *dmub) 332 { 333 return REG_READ(DMCUB_INBOX1_RPTR); 334 } 335 336 void dmub_dcn60_set_inbox1_wptr(struct dmub_srv *dmub, uint32_t wptr_offset) 337 { 338 REG_WRITE(DMCUB_INBOX1_WPTR, wptr_offset); 339 } 340 341 void dmub_dcn60_setup_out_mailbox(struct dmub_srv *dmub, 342 const struct dmub_region *outbox1) 343 { 344 REG_WRITE(DMCUB_OUTBOX1_BASE_ADDRESS, outbox1->base); 345 REG_WRITE(DMCUB_OUTBOX1_SIZE, outbox1->top - outbox1->base); 346 } 347 348 uint32_t dmub_dcn60_get_outbox1_wptr(struct dmub_srv *dmub) 349 { 350 /** 351 * outbox1 wptr register is accessed without locks (dal & dc) 352 * and to be called only by dmub_srv_stat_get_notification() 353 */ 354 return REG_READ(DMCUB_OUTBOX1_WPTR); 355 } 356 357 void dmub_dcn60_set_outbox1_rptr(struct dmub_srv *dmub, uint32_t rptr_offset) 358 { 359 /** 360 * outbox1 rptr register is accessed without locks (dal & dc) 361 * and to be called only by dmub_srv_stat_get_notification() 362 */ 363 REG_WRITE(DMCUB_OUTBOX1_RPTR, rptr_offset); 364 } 365 366 bool dmub_dcn60_is_hw_init(struct dmub_srv *dmub) 367 { 368 union dmub_fw_boot_status status; 369 uint32_t is_hw_init; 370 371 status.all = REG_READ(DMCUB_SCRATCH0); 372 REG_GET(DMCUB_CNTL, DMCUB_ENABLE, &is_hw_init); 373 374 return is_hw_init != 0 && status.bits.dal_fw; 375 } 376 377 bool dmub_dcn60_is_supported(struct dmub_srv *dmub) 378 { 379 (void)dmub; 380 // TODO: CC_DC_PIPE_DIS::DC_DMCUB_ENABLE no longer exists 381 //REG_GET(CC_DC_PIPE_DIS, DC_DMCUB_ENABLE, &supported); 382 return 1; 383 } 384 385 void dmub_dcn60_set_gpint(struct dmub_srv *dmub, 386 union dmub_gpint_data_register reg) 387 { 388 REG_WRITE(DMCUB_GPINT_DATAIN1, reg.all); 389 } 390 391 bool dmub_dcn60_is_gpint_acked(struct dmub_srv *dmub, 392 union dmub_gpint_data_register reg) 393 { 394 union dmub_gpint_data_register test; 395 396 reg.bits.status = 0; 397 test.all = REG_READ(DMCUB_GPINT_DATAIN1); 398 399 return test.all == reg.all; 400 } 401 402 uint32_t dmub_dcn60_get_gpint_response(struct dmub_srv *dmub) 403 { 404 return REG_READ(DMCUB_SCRATCH7); 405 } 406 407 uint32_t dmub_dcn60_get_gpint_dataout(struct dmub_srv *dmub) 408 { 409 uint32_t dataout = REG_READ(DMCUB_GPINT_DATAOUT); 410 411 REG_UPDATE(DMCUB_INTERRUPT_ENABLE, DMCUB_GPINT_IH_INT_EN, 0); 412 413 REG_WRITE(DMCUB_GPINT_DATAOUT, 0); 414 REG_UPDATE(DMCUB_INTERRUPT_ACK, DMCUB_GPINT_IH_INT_ACK, 1); 415 REG_UPDATE(DMCUB_INTERRUPT_ACK, DMCUB_GPINT_IH_INT_ACK, 0); 416 417 REG_UPDATE(DMCUB_INTERRUPT_ENABLE, DMCUB_GPINT_IH_INT_EN, 1); 418 419 return dataout; 420 } 421 422 union dmub_fw_boot_status dmub_dcn60_get_fw_boot_status(struct dmub_srv *dmub) 423 { 424 union dmub_fw_boot_status status; 425 426 status.all = REG_READ(DMCUB_SCRATCH0); 427 return status; 428 } 429 430 void dmub_dcn60_enable_dmub_boot_options(struct dmub_srv *dmub, const struct dmub_srv_hw_params *params) 431 { 432 union dmub_fw_boot_options boot_options = {0}; 433 434 boot_options.bits.z10_disable = params->disable_z10; 435 436 boot_options.bits.skip_phy_access = params->disallow_phy_access; 437 438 REG_WRITE(DMCUB_SCRATCH14, boot_options.all); 439 } 440 441 void dmub_dcn60_skip_dmub_panel_power_sequence(struct dmub_srv *dmub, bool skip) 442 { 443 union dmub_fw_boot_options boot_options; 444 boot_options.all = REG_READ(DMCUB_SCRATCH14); 445 boot_options.bits.skip_phy_init_panel_sequence = skip; 446 REG_WRITE(DMCUB_SCRATCH14, boot_options.all); 447 } 448 449 void dmub_dcn60_setup_outbox0(struct dmub_srv *dmub, 450 const struct dmub_region *outbox0) 451 { 452 REG_WRITE(DMCUB_OUTBOX0_BASE_ADDRESS, outbox0->base); 453 454 REG_WRITE(DMCUB_OUTBOX0_SIZE, outbox0->top - outbox0->base); 455 } 456 457 uint32_t dmub_dcn60_get_outbox0_wptr(struct dmub_srv *dmub) 458 { 459 return REG_READ(DMCUB_OUTBOX0_WPTR); 460 } 461 462 void dmub_dcn60_set_outbox0_rptr(struct dmub_srv *dmub, uint32_t rptr_offset) 463 { 464 REG_WRITE(DMCUB_OUTBOX0_RPTR, rptr_offset); 465 } 466 467 uint32_t dmub_dcn60_get_current_time(struct dmub_srv *dmub) 468 { 469 return REG_READ(DMCUB_TIMER_CURRENT); 470 } 471 472 void dmub_dcn60_get_diagnostic_data(struct dmub_srv *dmub) 473 { 474 uint32_t is_dmub_enabled, is_soft_reset, is_sec_reset, is_pwait; 475 uint32_t is_traceport_enabled, is_cw0_enabled, is_cw6_enabled; 476 struct dmub_timeout_info timeout = {0}; 477 478 if (!dmub) 479 return; 480 481 /* timeout data filled externally, cache before resetting memory */ 482 timeout = dmub->debug.timeout_info; 483 memset(&dmub->debug, 0, sizeof(dmub->debug)); 484 dmub->debug.timeout_info = timeout; 485 486 dmub->debug.dmcub_version = dmub->fw_version; 487 488 dmub->debug.scratch[0] = REG_READ(DMCUB_SCRATCH0); 489 dmub->debug.scratch[1] = REG_READ(DMCUB_SCRATCH1); 490 dmub->debug.scratch[2] = REG_READ(DMCUB_SCRATCH2); 491 dmub->debug.scratch[3] = REG_READ(DMCUB_SCRATCH3); 492 dmub->debug.scratch[4] = REG_READ(DMCUB_SCRATCH4); 493 dmub->debug.scratch[5] = REG_READ(DMCUB_SCRATCH5); 494 dmub->debug.scratch[6] = REG_READ(DMCUB_SCRATCH6); 495 dmub->debug.scratch[7] = REG_READ(DMCUB_SCRATCH7); 496 dmub->debug.scratch[8] = REG_READ(DMCUB_SCRATCH8); 497 dmub->debug.scratch[9] = REG_READ(DMCUB_SCRATCH9); 498 dmub->debug.scratch[10] = REG_READ(DMCUB_SCRATCH10); 499 dmub->debug.scratch[11] = REG_READ(DMCUB_SCRATCH11); 500 dmub->debug.scratch[12] = REG_READ(DMCUB_SCRATCH12); 501 dmub->debug.scratch[13] = REG_READ(DMCUB_SCRATCH13); 502 dmub->debug.scratch[14] = REG_READ(DMCUB_SCRATCH14); 503 dmub->debug.scratch[15] = REG_READ(DMCUB_SCRATCH15); 504 dmub->debug.scratch[16] = REG_READ(DMCUB_SCRATCH16); 505 506 dmub->debug.undefined_address_fault_addr = REG_READ(DMCUB_UNDEFINED_ADDRESS_FAULT_ADDR); 507 dmub->debug.inst_fetch_fault_addr = REG_READ(DMCUB_INST_FETCH_FAULT_ADDR); 508 dmub->debug.data_write_fault_addr = REG_READ(DMCUB_DATA_WRITE_FAULT_ADDR); 509 510 dmub->debug.inbox1_rptr = REG_READ(DMCUB_INBOX1_RPTR); 511 dmub->debug.inbox1_wptr = REG_READ(DMCUB_INBOX1_WPTR); 512 dmub->debug.inbox1_size = REG_READ(DMCUB_INBOX1_SIZE); 513 514 dmub->debug.inbox0_rptr = REG_READ(DMCUB_INBOX0_RPTR); 515 dmub->debug.inbox0_wptr = REG_READ(DMCUB_INBOX0_WPTR); 516 dmub->debug.inbox0_size = REG_READ(DMCUB_INBOX0_SIZE); 517 518 dmub->debug.outbox1_rptr = REG_READ(DMCUB_OUTBOX1_RPTR); 519 dmub->debug.outbox1_wptr = REG_READ(DMCUB_OUTBOX1_WPTR); 520 dmub->debug.outbox1_size = REG_READ(DMCUB_OUTBOX1_SIZE); 521 522 REG_GET(DMCUB_CNTL, DMCUB_ENABLE, &is_dmub_enabled); 523 ASSERT(is_dmub_enabled <= 0xFF); 524 dmub->debug.is_dmcub_enabled = (uint8_t)is_dmub_enabled; 525 526 REG_GET(DMCUB_CNTL, DMCUB_PWAIT_MODE_STATUS, &is_pwait); 527 ASSERT(is_pwait <= 0xFF); 528 dmub->debug.is_pwait = (uint8_t)is_pwait; 529 530 REG_GET(DMCUB_CNTL2, DMCUB_SOFT_RESET, &is_soft_reset); 531 ASSERT(is_soft_reset <= 0xFF); 532 dmub->debug.is_dmcub_soft_reset = (uint8_t)is_soft_reset; 533 534 REG_GET(DMCUB_SEC_CNTL, DMCUB_SEC_RESET_STATUS, &is_sec_reset); 535 ASSERT(is_sec_reset <= 0xFF); 536 dmub->debug.is_dmcub_secure_reset = (uint8_t)is_sec_reset; 537 538 REG_GET(DMCUB_CNTL, DMCUB_TRACEPORT_EN, &is_traceport_enabled); 539 ASSERT(is_traceport_enabled <= 0xFF); 540 dmub->debug.is_traceport_en = (uint8_t)is_traceport_enabled; 541 542 REG_GET(DMCUB_REGION3_CW0_TOP_ADDRESS, DMCUB_REGION3_CW0_ENABLE, &is_cw0_enabled); 543 ASSERT(is_cw0_enabled <= 0xFF); 544 dmub->debug.is_cw0_enabled = (uint8_t)is_cw0_enabled; 545 546 REG_GET(DMCUB_REGION3_CW6_TOP_ADDRESS, DMCUB_REGION3_CW6_ENABLE, &is_cw6_enabled); 547 ASSERT(is_cw6_enabled <= 0xFF); 548 dmub->debug.is_cw6_enabled = (uint8_t)is_cw6_enabled; 549 550 dmub->debug.gpint_datain0 = REG_READ(DMCUB_GPINT_DATAIN0); 551 } 552 void dmub_dcn60_configure_dmub_in_system_memory(struct dmub_srv *dmub) 553 { 554 /* DMCUB_REGION3_TMR_AXI_SPACE values: 555 * 0b011 (0x3) - FB physical address 556 * 0b100 (0x4) - GPU virtual address 557 * 558 * Default value is 0x3 (FB Physical address for TMR). When programming 559 * DMUB to be in system memory, change to 0x4. The system memory allocated 560 * is accessible by both GPU and CPU, so we use GPU virtual address. 561 */ 562 REG_WRITE(DMCUB_REGION3_TMR_AXI_SPACE, 0x4); 563 } 564 565 void dmub_dcn60_send_inbox0_cmd(struct dmub_srv *dmub, union dmub_inbox0_data_register data) 566 { 567 REG_WRITE(DMCUB_INBOX0_WPTR, data.inbox0_cmd_common.all); 568 } 569 570 void dmub_dcn60_clear_inbox0_ack_register(struct dmub_srv *dmub) 571 { 572 REG_WRITE(DMCUB_SCRATCH17, 0); 573 } 574 575 uint32_t dmub_dcn60_read_inbox0_ack_register(struct dmub_srv *dmub) 576 { 577 return REG_READ(DMCUB_SCRATCH17); 578 } 579 580 void dmub_dcn60_send_reg_inbox0_cmd_msg(struct dmub_srv *dmub, 581 union dmub_rb_cmd *cmd) 582 { 583 uint32_t *dwords = (uint32_t *)cmd; 584 uint32_t payload_size_bytes = cmd->cmd_common.header.payload_bytes; 585 uint32_t msg_index; 586 static_assert(sizeof(*cmd) == 64, "DMUB command size mismatch"); 587 588 /* read remaining data based on payload size */ 589 for (msg_index = 0; msg_index < 15; msg_index++) { 590 if (payload_size_bytes <= msg_index * 4) { 591 break; 592 } 593 594 switch (msg_index) { 595 case 0: 596 REG_WRITE(DMCUB_REG_INBOX0_MSG0, dwords[msg_index + 1]); 597 break; 598 case 1: 599 REG_WRITE(DMCUB_REG_INBOX0_MSG1, dwords[msg_index + 1]); 600 break; 601 case 2: 602 REG_WRITE(DMCUB_REG_INBOX0_MSG2, dwords[msg_index + 1]); 603 break; 604 case 3: 605 REG_WRITE(DMCUB_REG_INBOX0_MSG3, dwords[msg_index + 1]); 606 break; 607 case 4: 608 REG_WRITE(DMCUB_REG_INBOX0_MSG4, dwords[msg_index + 1]); 609 break; 610 case 5: 611 REG_WRITE(DMCUB_REG_INBOX0_MSG5, dwords[msg_index + 1]); 612 break; 613 case 6: 614 REG_WRITE(DMCUB_REG_INBOX0_MSG6, dwords[msg_index + 1]); 615 break; 616 case 7: 617 REG_WRITE(DMCUB_REG_INBOX0_MSG7, dwords[msg_index + 1]); 618 break; 619 case 8: 620 REG_WRITE(DMCUB_REG_INBOX0_MSG8, dwords[msg_index + 1]); 621 break; 622 case 9: 623 REG_WRITE(DMCUB_REG_INBOX0_MSG9, dwords[msg_index + 1]); 624 break; 625 case 10: 626 REG_WRITE(DMCUB_REG_INBOX0_MSG10, dwords[msg_index + 1]); 627 break; 628 case 11: 629 REG_WRITE(DMCUB_REG_INBOX0_MSG11, dwords[msg_index + 1]); 630 break; 631 case 12: 632 REG_WRITE(DMCUB_REG_INBOX0_MSG12, dwords[msg_index + 1]); 633 break; 634 case 13: 635 REG_WRITE(DMCUB_REG_INBOX0_MSG13, dwords[msg_index + 1]); 636 break; 637 case 14: 638 REG_WRITE(DMCUB_REG_INBOX0_MSG14, dwords[msg_index + 1]); 639 break; 640 } 641 } 642 643 /* writing to INBOX RDY register will trigger DMUB REG INBOX0 RDY 644 * interrupt. 645 */ 646 REG_WRITE(DMCUB_REG_INBOX0_RDY, dwords[0]); 647 } 648 649 uint32_t dmub_dcn60_read_reg_inbox0_rsp_int_status(struct dmub_srv *dmub) 650 { 651 uint32_t status; 652 653 REG_GET(HOST_INTERRUPT_CSR, HOST_REG_INBOX0_RSP_INT_STAT, &status); 654 return status; 655 } 656 657 void dmub_dcn60_read_reg_inbox0_cmd_rsp(struct dmub_srv *dmub, 658 union dmub_rb_cmd *cmd) 659 { 660 uint32_t *dwords = (uint32_t *)cmd; 661 662 static_assert(sizeof(*cmd) == 64, "DMUB command size mismatch"); 663 664 dwords[0] = REG_READ(DMCUB_REG_INBOX0_RSP); 665 dwords[1] = REG_READ(DMCUB_REG_INBOX0_MSG0); 666 dwords[2] = REG_READ(DMCUB_REG_INBOX0_MSG1); 667 dwords[3] = REG_READ(DMCUB_REG_INBOX0_MSG2); 668 dwords[4] = REG_READ(DMCUB_REG_INBOX0_MSG3); 669 dwords[5] = REG_READ(DMCUB_REG_INBOX0_MSG4); 670 dwords[6] = REG_READ(DMCUB_REG_INBOX0_MSG5); 671 dwords[7] = REG_READ(DMCUB_REG_INBOX0_MSG6); 672 dwords[8] = REG_READ(DMCUB_REG_INBOX0_MSG7); 673 dwords[9] = REG_READ(DMCUB_REG_INBOX0_MSG8); 674 dwords[10] = REG_READ(DMCUB_REG_INBOX0_MSG9); 675 dwords[11] = REG_READ(DMCUB_REG_INBOX0_MSG10); 676 dwords[12] = REG_READ(DMCUB_REG_INBOX0_MSG11); 677 dwords[13] = REG_READ(DMCUB_REG_INBOX0_MSG12); 678 dwords[14] = REG_READ(DMCUB_REG_INBOX0_MSG13); 679 dwords[15] = REG_READ(DMCUB_REG_INBOX0_MSG14); 680 } 681 682 void dmub_dcn60_write_reg_inbox0_rsp_int_ack(struct dmub_srv *dmub) 683 { 684 REG_UPDATE(HOST_INTERRUPT_CSR, HOST_REG_INBOX0_RSP_INT_ACK, 1); 685 } 686 687 void dmub_dcn60_clear_reg_inbox0_rsp_int_ack(struct dmub_srv *dmub) 688 { 689 REG_UPDATE(HOST_INTERRUPT_CSR, HOST_REG_INBOX0_RSP_INT_ACK, 0); 690 } 691 692 void dmub_dcn60_enable_reg_inbox0_rsp_int(struct dmub_srv *dmub, bool enable) 693 { 694 REG_UPDATE(HOST_INTERRUPT_CSR, HOST_REG_INBOX0_RSP_INT_EN, enable ? 1:0); 695 } 696 697 void dmub_dcn60_write_reg_outbox0_rdy_int_ack(struct dmub_srv *dmub) 698 { 699 REG_UPDATE(HOST_INTERRUPT_CSR, HOST_REG_OUTBOX0_RDY_INT_ACK, 1); 700 REG_UPDATE(HOST_INTERRUPT_CSR, HOST_REG_OUTBOX0_RDY_INT_ACK, 0); 701 } 702 703 void dmub_dcn60_read_reg_outbox0_msg(struct dmub_srv *dmub, uint32_t *msg) 704 { 705 *msg = REG_READ(DMCUB_REG_OUTBOX0_MSG0); 706 } 707 708 void dmub_dcn60_write_reg_outbox0_rsp(struct dmub_srv *dmub, uint32_t *rsp) 709 { 710 REG_WRITE(DMCUB_REG_OUTBOX0_RSP, *rsp); 711 } 712 713 uint32_t dmub_dcn60_read_reg_outbox0_rsp_int_status(struct dmub_srv *dmub) 714 { 715 uint32_t status; 716 717 REG_GET(DMCUB_INTERRUPT_STATUS, DMCUB_REG_OUTBOX0_RSP_INT_STAT, &status); 718 return status; 719 } 720 721 void dmub_dcn60_enable_reg_outbox0_rdy_int(struct dmub_srv *dmub, bool enable) 722 { 723 REG_UPDATE(HOST_INTERRUPT_CSR, HOST_REG_OUTBOX0_RDY_INT_EN, enable ? 1:0); 724 } 725 726 uint32_t dmub_dcn60_read_reg_outbox0_rdy_int_status(struct dmub_srv *dmub) 727 { 728 uint32_t status; 729 730 REG_GET(HOST_INTERRUPT_CSR, HOST_REG_OUTBOX0_RDY_INT_STAT, &status); 731 return status; 732 } 733