1 // SPDX-License-Identifier: MIT 2 3 // Copyright 2026 Advanced Micro Devices, Inc. 4 5 #include "reg_helper.h" 6 #include "core_types.h" 7 #include "dcn42_pg_cntl.h" 8 #include "dccg.h" 9 10 #define TO_DCN_PG_CNTL(pg_cntl)\ 11 container_of(pg_cntl, struct dcn_pg_cntl, base) 12 13 #define REG(reg) \ 14 (pg_cntl_dcn->regs->reg) 15 16 #undef FN 17 #define FN(reg_name, field_name) \ 18 pg_cntl_dcn->pg_cntl_shift->field_name, pg_cntl_dcn->pg_cntl_mask->field_name 19 20 #define CTX \ 21 pg_cntl_dcn->base.ctx 22 #define DC_LOGGER \ 23 pg_cntl->ctx->logger 24 25 static bool pg_cntl42_dsc_pg_status(struct pg_cntl *pg_cntl, unsigned int dsc_inst) 26 { 27 struct dcn_pg_cntl *pg_cntl_dcn = TO_DCN_PG_CNTL(pg_cntl); 28 uint32_t pwr_status = 0; 29 30 if (pg_cntl->ctx->dc->debug.ignore_pg) 31 return true; 32 33 switch (dsc_inst) { 34 case 0: /* DSC0 */ 35 REG_GET(DOMAIN16_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, &pwr_status); 36 break; 37 case 1: /* DSC1 */ 38 REG_GET(DOMAIN17_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, &pwr_status); 39 break; 40 case 2: /* DSC2 */ 41 REG_GET(DOMAIN18_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, &pwr_status); 42 break; 43 case 3: /* DSC3 */ 44 REG_GET(DOMAIN19_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, &pwr_status); 45 break; 46 default: 47 BREAK_TO_DEBUGGER(); 48 break; 49 } 50 51 return pwr_status == 0; 52 } 53 54 void pg_cntl42_dsc_pg_control(struct pg_cntl *pg_cntl, unsigned int dsc_inst, bool power_on) 55 { 56 struct dcn_pg_cntl *pg_cntl_dcn = TO_DCN_PG_CNTL(pg_cntl); 57 uint32_t power_gate = power_on ? 0 : 1; 58 uint32_t pwr_status = power_on ? 0 : 2; 59 uint32_t org_ip_request_cntl = 0; 60 bool block_enabled; 61 62 /*need to enable dscclk regardless DSC_PG*/ 63 if (pg_cntl->ctx->dc->res_pool->dccg->funcs->enable_dsc && power_on) 64 pg_cntl->ctx->dc->res_pool->dccg->funcs->enable_dsc( 65 pg_cntl->ctx->dc->res_pool->dccg, dsc_inst); 66 67 if (pg_cntl->ctx->dc->debug.ignore_pg || 68 pg_cntl->ctx->dc->debug.disable_dsc_power_gate || 69 pg_cntl->ctx->dc->idle_optimizations_allowed) 70 return; 71 72 block_enabled = pg_cntl42_dsc_pg_status(pg_cntl, dsc_inst); 73 if (power_on) { 74 if (block_enabled) 75 return; 76 } else { 77 if (!block_enabled) 78 return; 79 } 80 81 REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); 82 if (org_ip_request_cntl == 0) 83 REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); 84 85 if (power_on) { 86 if (pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg) 87 pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg(pg_cntl->ctx->dc->res_pool->dccg, false); 88 } 89 switch (dsc_inst) { 90 case 0: /* DSC0 */ 91 REG_UPDATE(DOMAIN16_PG_CONFIG, 92 DOMAIN_POWER_GATE, power_gate); 93 94 REG_WAIT(DOMAIN16_PG_STATUS, 95 DOMAIN_PGFSM_PWR_STATUS, pwr_status, 96 1, 1000); 97 break; 98 case 1: /* DSC1 */ 99 REG_UPDATE(DOMAIN17_PG_CONFIG, 100 DOMAIN_POWER_GATE, power_gate); 101 102 REG_WAIT(DOMAIN17_PG_STATUS, 103 DOMAIN_PGFSM_PWR_STATUS, pwr_status, 104 1, 1000); 105 break; 106 case 2: /* DSC2 */ 107 REG_UPDATE(DOMAIN18_PG_CONFIG, 108 DOMAIN_POWER_GATE, power_gate); 109 110 REG_WAIT(DOMAIN18_PG_STATUS, 111 DOMAIN_PGFSM_PWR_STATUS, pwr_status, 112 1, 1000); 113 break; 114 case 3: /* DSC3 */ 115 REG_UPDATE(DOMAIN19_PG_CONFIG, 116 DOMAIN_POWER_GATE, power_gate); 117 118 REG_WAIT(DOMAIN19_PG_STATUS, 119 DOMAIN_PGFSM_PWR_STATUS, pwr_status, 120 1, 1000); 121 break; 122 default: 123 BREAK_TO_DEBUGGER(); 124 break; 125 } 126 127 if (power_on) { 128 if (pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg) 129 pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg(pg_cntl->ctx->dc->res_pool->dccg, true); 130 } 131 132 if (dsc_inst < MAX_PIPES) 133 pg_cntl->pg_pipe_res_enable[PG_DSC][dsc_inst] = power_on; 134 135 if (pg_cntl->ctx->dc->res_pool->dccg->funcs->disable_dsc && !power_on) { 136 /*this is to disable dscclk*/ 137 pg_cntl->ctx->dc->res_pool->dccg->funcs->disable_dsc( 138 pg_cntl->ctx->dc->res_pool->dccg, dsc_inst); 139 } 140 } 141 142 static bool pg_cntl42_hubp_dpp_pg_status(struct pg_cntl *pg_cntl, unsigned int hubp_dpp_inst) 143 { 144 struct dcn_pg_cntl *pg_cntl_dcn = TO_DCN_PG_CNTL(pg_cntl); 145 uint32_t pwr_status = 0; 146 147 switch (hubp_dpp_inst) { 148 case 0: 149 /* DPP0 & HUBP0 */ 150 REG_GET(DOMAIN0_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, &pwr_status); 151 break; 152 case 1: 153 /* DPP1 & HUBP1 */ 154 REG_GET(DOMAIN1_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, &pwr_status); 155 break; 156 case 2: 157 /* DPP2 & HUBP2 */ 158 REG_GET(DOMAIN2_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, &pwr_status); 159 break; 160 case 3: 161 /* DPP3 & HUBP3 */ 162 REG_GET(DOMAIN3_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, &pwr_status); 163 break; 164 default: 165 BREAK_TO_DEBUGGER(); 166 break; 167 } 168 169 return pwr_status == 0; 170 } 171 172 void pg_cntl42_hubp_dpp_pg_control(struct pg_cntl *pg_cntl, unsigned int hubp_dpp_inst, bool power_on) 173 { 174 struct dcn_pg_cntl *pg_cntl_dcn = TO_DCN_PG_CNTL(pg_cntl); 175 uint32_t power_gate = power_on ? 0 : 1; 176 uint32_t pwr_status = power_on ? 0 : 2; 177 uint32_t org_ip_request_cntl; 178 bool block_enabled; 179 bool skip_pg = pg_cntl->ctx->dc->debug.ignore_pg || 180 pg_cntl->ctx->dc->debug.disable_hubp_power_gate || 181 pg_cntl->ctx->dc->debug.disable_dpp_power_gate || 182 pg_cntl->ctx->dc->idle_optimizations_allowed; 183 184 if (skip_pg && !power_on) 185 return; 186 187 block_enabled = pg_cntl42_hubp_dpp_pg_status(pg_cntl, hubp_dpp_inst); 188 if (power_on) { 189 if (block_enabled) 190 return; 191 } else { 192 if (!block_enabled) 193 return; 194 } 195 196 REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); 197 if (org_ip_request_cntl == 0) 198 REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); 199 200 if (power_on) { 201 if (pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg) 202 pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg(pg_cntl->ctx->dc->res_pool->dccg, false); 203 } 204 205 switch (hubp_dpp_inst) { 206 case 0: 207 /* DPP0 & HUBP0 */ 208 REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN_POWER_GATE, power_gate); 209 REG_WAIT(DOMAIN0_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000); 210 break; 211 case 1: 212 /* DPP1 & HUBP1 */ 213 REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN_POWER_GATE, power_gate); 214 REG_WAIT(DOMAIN1_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000); 215 break; 216 case 2: 217 /* DPP2 & HUBP2 */ 218 REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN_POWER_GATE, power_gate); 219 REG_WAIT(DOMAIN2_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000); 220 break; 221 case 3: 222 /* DPP3 & HUBP3 */ 223 REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN_POWER_GATE, power_gate); 224 REG_WAIT(DOMAIN3_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000); 225 break; 226 default: 227 BREAK_TO_DEBUGGER(); 228 break; 229 } 230 231 if (power_on) { 232 if (pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg) 233 pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg(pg_cntl->ctx->dc->res_pool->dccg, true); 234 } 235 DC_LOG_DEBUG("HUBP DPP instance %d, power %s", hubp_dpp_inst, 236 power_on ? "ON" : "OFF"); 237 238 if (hubp_dpp_inst < MAX_PIPES) { 239 pg_cntl->pg_pipe_res_enable[PG_HUBP][hubp_dpp_inst] = power_on; 240 pg_cntl->pg_pipe_res_enable[PG_DPP][hubp_dpp_inst] = power_on; 241 } 242 } 243 244 static bool pg_cntl42_hpo_pg_status(struct pg_cntl *pg_cntl) 245 { 246 struct dcn_pg_cntl *pg_cntl_dcn = TO_DCN_PG_CNTL(pg_cntl); 247 uint32_t pwr_status = 0; 248 249 REG_GET(DOMAIN25_PG_STATUS, 250 DOMAIN_PGFSM_PWR_STATUS, &pwr_status); 251 252 return pwr_status == 0; 253 } 254 255 void pg_cntl42_hpo_pg_control(struct pg_cntl *pg_cntl, bool power_on) 256 { 257 struct dcn_pg_cntl *pg_cntl_dcn = TO_DCN_PG_CNTL(pg_cntl); 258 uint32_t power_gate = power_on ? 0 : 1; 259 uint32_t pwr_status = power_on ? 0 : 2; 260 uint32_t org_ip_request_cntl; 261 uint32_t power_forceon; 262 bool block_enabled; 263 264 if (pg_cntl->ctx->dc->debug.ignore_pg || 265 pg_cntl->ctx->dc->debug.disable_hpo_power_gate || 266 pg_cntl->ctx->dc->idle_optimizations_allowed) 267 return; 268 269 block_enabled = pg_cntl42_hpo_pg_status(pg_cntl); 270 if (power_on) { 271 if (block_enabled) 272 return; 273 } else { 274 if (!block_enabled) 275 return; 276 } 277 278 REG_GET(DOMAIN25_PG_CONFIG, DOMAIN_POWER_FORCEON, &power_forceon); 279 if (power_forceon) 280 return; 281 282 REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); 283 if (org_ip_request_cntl == 0) 284 REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); 285 if (power_on) { 286 if (pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg) 287 pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg(pg_cntl->ctx->dc->res_pool->dccg, false); 288 } 289 REG_UPDATE(DOMAIN25_PG_CONFIG, DOMAIN_POWER_GATE, power_gate); 290 REG_WAIT(DOMAIN25_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000); 291 292 if (power_on) { 293 if (pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg) 294 pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg(pg_cntl->ctx->dc->res_pool->dccg, true); 295 } 296 pg_cntl->pg_res_enable[PG_HPO] = power_on; 297 } 298 299 static bool pg_cntl42_io_clk_status(struct pg_cntl *pg_cntl) 300 { 301 struct dcn_pg_cntl *pg_cntl_dcn = TO_DCN_PG_CNTL(pg_cntl); 302 uint32_t pwr_status = 0; 303 304 REG_GET(DOMAIN22_PG_STATUS, 305 DOMAIN_PGFSM_PWR_STATUS, &pwr_status); 306 307 return pwr_status == 0; 308 } 309 310 void pg_cntl42_io_clk_pg_control(struct pg_cntl *pg_cntl, bool power_on) 311 { 312 struct dcn_pg_cntl *pg_cntl_dcn = TO_DCN_PG_CNTL(pg_cntl); 313 uint32_t power_gate = power_on ? 0 : 1; 314 uint32_t pwr_status = power_on ? 0 : 2; 315 uint32_t org_ip_request_cntl; 316 uint32_t power_forceon; 317 bool block_enabled; 318 319 if (pg_cntl->ctx->dc->debug.ignore_pg || 320 pg_cntl->ctx->dc->idle_optimizations_allowed || 321 pg_cntl->ctx->dc->debug.disable_io_clk_power_gate) 322 return; 323 324 block_enabled = pg_cntl42_io_clk_status(pg_cntl); 325 if (power_on) { 326 if (block_enabled) 327 return; 328 } else { 329 if (!block_enabled) 330 return; 331 } 332 333 REG_GET(DOMAIN22_PG_CONFIG, DOMAIN_POWER_FORCEON, &power_forceon); 334 if (power_forceon) 335 return; 336 337 if (!power_on) { 338 if (!pg_cntl->pg_res_enable[PG_DCCG] || !pg_cntl->pg_res_enable[PG_DCIO] || !pg_cntl->pg_res_enable[PG_DCOH]) 339 return; 340 } 341 REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); 342 if (org_ip_request_cntl == 0) 343 REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); 344 345 /* DCCG, DCOH, DCIO */ 346 REG_UPDATE(DOMAIN22_PG_CONFIG, DOMAIN_POWER_GATE, power_gate); 347 REG_WAIT(DOMAIN22_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000); 348 349 pg_cntl->pg_res_enable[PG_DCCG] = power_on; 350 pg_cntl->pg_res_enable[PG_DCOH] = power_on; 351 pg_cntl->pg_res_enable[PG_DCIO] = power_on; 352 } 353 354 static bool pg_cntl42_plane_otg_status(struct pg_cntl *pg_cntl) 355 { 356 struct dcn_pg_cntl *pg_cntl_dcn = TO_DCN_PG_CNTL(pg_cntl); 357 uint32_t pwr_status = 0; 358 359 REG_GET(DOMAIN24_PG_STATUS, 360 DOMAIN_PGFSM_PWR_STATUS, &pwr_status); 361 362 return pwr_status == 0; 363 } 364 365 void pg_cntl42_mpcc_pg_control(struct pg_cntl *pg_cntl, 366 unsigned int mpcc_inst, bool power_on) 367 { 368 if (pg_cntl->ctx->dc->idle_optimizations_allowed) 369 return; 370 371 if (mpcc_inst < MAX_PIPES) 372 pg_cntl->pg_pipe_res_enable[PG_MPCC][mpcc_inst] = power_on; 373 } 374 375 void pg_cntl42_opp_pg_control(struct pg_cntl *pg_cntl, 376 unsigned int opp_inst, bool power_on) 377 { 378 if (pg_cntl->ctx->dc->idle_optimizations_allowed) 379 return; 380 381 if (opp_inst < MAX_PIPES) 382 pg_cntl->pg_pipe_res_enable[PG_OPP][opp_inst] = power_on; 383 } 384 385 void pg_cntl42_optc_pg_control(struct pg_cntl *pg_cntl, 386 unsigned int optc_inst, bool power_on) 387 { 388 // Defer the ONO domain power up/down to plane_otg_pg_control 389 if (pg_cntl->ctx->dc->idle_optimizations_allowed) 390 return; 391 392 if (optc_inst < MAX_PIPES) 393 pg_cntl->pg_pipe_res_enable[PG_OPTC][optc_inst] = power_on; 394 } 395 static bool pg_cntl42_mem_status(struct pg_cntl *pg_cntl) 396 { 397 struct dcn_pg_cntl *pg_cntl_dcn = TO_DCN_PG_CNTL(pg_cntl); 398 uint32_t pwr_status = 0; 399 400 REG_GET(DOMAIN23_PG_STATUS, 401 DOMAIN_PGFSM_PWR_STATUS, &pwr_status); 402 403 return pwr_status == 0; 404 } 405 406 void pg_cntl42_mem_pg_control(struct pg_cntl *pg_cntl, bool power_on) 407 { 408 struct dcn_pg_cntl *pg_cntl_dcn = TO_DCN_PG_CNTL(pg_cntl); 409 uint32_t power_gate = power_on ? 0 : 1; 410 uint32_t pwr_status = power_on ? 0 : 2; 411 uint32_t org_ip_request_cntl; 412 uint32_t power_forceon; 413 bool block_enabled; 414 415 if (pg_cntl->ctx->dc->debug.ignore_pg || 416 pg_cntl->ctx->dc->idle_optimizations_allowed || 417 pg_cntl->ctx->dc->debug.disable_mem_power_gate) 418 return; 419 420 block_enabled = pg_cntl42_mem_status(pg_cntl); 421 if (power_on) { 422 if (block_enabled) 423 return; 424 } else { 425 if (!block_enabled) 426 return; 427 } 428 429 REG_GET(DOMAIN23_PG_CONFIG, DOMAIN_POWER_FORCEON, &power_forceon); 430 if (power_forceon) 431 return; 432 433 if (!power_on) { 434 if (!pg_cntl->pg_res_enable[PG_DCHUBBUB] || !pg_cntl->pg_res_enable[PG_DCHVM]) 435 return; 436 } 437 REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); 438 if (org_ip_request_cntl == 0) 439 REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); 440 441 /* DCHUBBUB, DCHUBBUBMEMn, DCHVM */ 442 REG_UPDATE(DOMAIN23_PG_CONFIG, DOMAIN_POWER_GATE, power_gate); 443 REG_WAIT(DOMAIN23_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000); 444 445 pg_cntl->pg_res_enable[PG_DCHUBBUB] = power_on; 446 pg_cntl->pg_res_enable[PG_DCHVM] = power_on; 447 } 448 static bool pg_cntl42_dio_pg_status(struct pg_cntl *pg_cntl) 449 { 450 struct dcn_pg_cntl *pg_cntl_dcn = TO_DCN_PG_CNTL(pg_cntl); 451 uint32_t pwr_status = 0; 452 453 REG_GET(DOMAIN26_PG_STATUS, 454 DOMAIN_PGFSM_PWR_STATUS, &pwr_status); 455 456 return pwr_status == 0; 457 } 458 459 void pg_cntl42_dio_pg_control(struct pg_cntl *pg_cntl, bool power_on) 460 { 461 struct dcn_pg_cntl *pg_cntl_dcn = TO_DCN_PG_CNTL(pg_cntl); 462 uint32_t power_gate = power_on ? 0 : 1; 463 uint32_t pwr_status = power_on ? 0 : 2; 464 uint32_t org_ip_request_cntl; 465 bool block_enabled; 466 467 if (pg_cntl->ctx->dc->debug.ignore_pg || 468 pg_cntl->ctx->dc->idle_optimizations_allowed || 469 pg_cntl->ctx->dc->debug.disable_dio_power_gate) 470 return; 471 472 block_enabled = pg_cntl42_dio_pg_status(pg_cntl); 473 if (power_on) { 474 if (block_enabled) 475 return; 476 } else { 477 if (!block_enabled) 478 return; 479 } 480 481 REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); 482 if (org_ip_request_cntl == 0) 483 REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); 484 if (power_on) { 485 if (pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg) 486 pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg(pg_cntl->ctx->dc->res_pool->dccg, false); 487 } 488 /* DIO */ 489 REG_UPDATE(DOMAIN26_PG_CONFIG, DOMAIN_POWER_GATE, power_gate); 490 REG_WAIT(DOMAIN26_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000); 491 492 if (power_on) { 493 if (pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg) 494 pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg(pg_cntl->ctx->dc->res_pool->dccg, true); 495 } 496 pg_cntl->pg_res_enable[PG_DIO] = power_on; 497 498 } 499 500 void pg_cntl42_plane_otg_pg_control(struct pg_cntl *pg_cntl, bool power_on) 501 { 502 struct dcn_pg_cntl *pg_cntl_dcn = TO_DCN_PG_CNTL(pg_cntl); 503 uint32_t power_gate = power_on ? 0 : 1; 504 uint32_t pwr_status = power_on ? 0 : 2; 505 uint32_t org_ip_request_cntl; 506 int i; 507 bool block_enabled; 508 bool all_mpcc_disabled = true, all_opp_disabled = true; 509 bool all_optc_disabled = true, all_stream_disabled = true; 510 511 if (pg_cntl->ctx->dc->debug.ignore_pg || 512 pg_cntl->ctx->dc->debug.disable_optc_power_gate || 513 pg_cntl->ctx->dc->idle_optimizations_allowed) 514 return; 515 516 block_enabled = pg_cntl42_plane_otg_status(pg_cntl); 517 if (power_on) { 518 if (block_enabled) 519 return; 520 } else { 521 if (!block_enabled) 522 return; 523 } 524 525 for (i = 0; i < pg_cntl->ctx->dc->res_pool->pipe_count; i++) { 526 struct pipe_ctx *pipe_ctx = &pg_cntl->ctx->dc->current_state->res_ctx.pipe_ctx[i]; 527 528 if (pipe_ctx) { 529 if (pipe_ctx->stream) 530 all_stream_disabled = false; 531 } 532 533 if (pg_cntl->pg_pipe_res_enable[PG_MPCC][i]) 534 all_mpcc_disabled = false; 535 536 if (pg_cntl->pg_pipe_res_enable[PG_OPP][i]) 537 all_opp_disabled = false; 538 539 if (pg_cntl->pg_pipe_res_enable[PG_OPTC][i]) 540 all_optc_disabled = false; 541 } 542 543 if (!power_on) { 544 if (!all_mpcc_disabled || !all_opp_disabled || !all_optc_disabled 545 || !all_stream_disabled) 546 return; 547 } 548 549 REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); 550 if (org_ip_request_cntl == 0) 551 REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); 552 553 /* MPC, OPP, OPTC, DWB */ 554 REG_UPDATE(DOMAIN24_PG_CONFIG, DOMAIN_POWER_GATE, power_gate); 555 REG_WAIT(DOMAIN24_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000); 556 557 for (i = 0; i < pg_cntl->ctx->dc->res_pool->pipe_count; i++) { 558 pg_cntl->pg_pipe_res_enable[PG_MPCC][i] = power_on; 559 pg_cntl->pg_pipe_res_enable[PG_OPP][i] = power_on; 560 pg_cntl->pg_pipe_res_enable[PG_OPTC][i] = power_on; 561 } 562 } 563 564 565 void pg_cntl42_init_pg_status(struct pg_cntl *pg_cntl) 566 { 567 int i = 0; 568 bool block_enabled; 569 570 pg_cntl->pg_res_enable[PG_HPO] = pg_cntl42_hpo_pg_status(pg_cntl); 571 572 block_enabled = pg_cntl42_io_clk_status(pg_cntl); 573 pg_cntl->pg_res_enable[PG_DCCG] = block_enabled; 574 pg_cntl->pg_res_enable[PG_DCIO] = block_enabled; 575 pg_cntl->pg_res_enable[PG_DCOH] = block_enabled; 576 577 block_enabled = pg_cntl42_dio_pg_status(pg_cntl); 578 pg_cntl->pg_res_enable[PG_DIO] = block_enabled; 579 580 block_enabled = pg_cntl42_mem_status(pg_cntl); 581 pg_cntl->pg_res_enable[PG_DCHUBBUB] = block_enabled; 582 pg_cntl->pg_res_enable[PG_DCHVM] = block_enabled; 583 584 for (i = 0; i < pg_cntl->ctx->dc->res_pool->pipe_count; i++) { 585 block_enabled = pg_cntl42_hubp_dpp_pg_status(pg_cntl, i); 586 pg_cntl->pg_pipe_res_enable[PG_HUBP][i] = block_enabled; 587 pg_cntl->pg_pipe_res_enable[PG_DPP][i] = block_enabled; 588 589 block_enabled = pg_cntl42_dsc_pg_status(pg_cntl, i); 590 pg_cntl->pg_pipe_res_enable[PG_DSC][i] = block_enabled; 591 } 592 593 block_enabled = pg_cntl42_plane_otg_status(pg_cntl); 594 for (i = 0; i < pg_cntl->ctx->dc->res_pool->pipe_count; i++) { 595 pg_cntl->pg_pipe_res_enable[PG_MPCC][i] = block_enabled; 596 pg_cntl->pg_pipe_res_enable[PG_OPP][i] = block_enabled; 597 pg_cntl->pg_pipe_res_enable[PG_OPTC][i] = block_enabled; 598 } 599 } 600 601 static const struct pg_cntl_funcs pg_cntl42_funcs = { 602 .init_pg_status = pg_cntl42_init_pg_status, 603 .dsc_pg_control = pg_cntl42_dsc_pg_control, 604 .hubp_dpp_pg_control = pg_cntl42_hubp_dpp_pg_control, 605 .hpo_pg_control = pg_cntl42_hpo_pg_control, 606 .io_clk_pg_control = pg_cntl42_io_clk_pg_control, 607 .plane_otg_pg_control = pg_cntl42_plane_otg_pg_control, 608 .mpcc_pg_control = pg_cntl42_mpcc_pg_control, 609 .opp_pg_control = pg_cntl42_opp_pg_control, 610 .optc_pg_control = pg_cntl42_optc_pg_control, 611 .mem_pg_control = pg_cntl42_mem_pg_control, 612 .dio_pg_control = pg_cntl42_dio_pg_control 613 }; 614 615 struct pg_cntl *pg_cntl42_create( 616 struct dc_context *ctx, 617 const struct pg_cntl_registers *regs, 618 const struct pg_cntl_shift *pg_cntl_shift, 619 const struct pg_cntl_mask *pg_cntl_mask) 620 { 621 struct dcn_pg_cntl *pg_cntl_dcn = kzalloc(sizeof(*pg_cntl_dcn), GFP_KERNEL); 622 struct pg_cntl *base; 623 624 if (pg_cntl_dcn == NULL) { 625 BREAK_TO_DEBUGGER(); 626 return NULL; 627 } 628 629 base = &pg_cntl_dcn->base; 630 base->ctx = ctx; 631 base->funcs = &pg_cntl42_funcs; 632 633 pg_cntl_dcn->regs = regs; 634 pg_cntl_dcn->pg_cntl_shift = pg_cntl_shift; 635 pg_cntl_dcn->pg_cntl_mask = pg_cntl_mask; 636 637 memset(base->pg_pipe_res_enable, 0, PG_HW_PIPE_RESOURCES_NUM_ELEMENT * MAX_PIPES * sizeof(bool)); 638 memset(base->pg_res_enable, 0, PG_HW_RESOURCES_NUM_ELEMENT * sizeof(bool)); 639 640 return &pg_cntl_dcn->base; 641 } 642 643 void dcn42_pg_cntl_destroy(struct pg_cntl **pg_cntl) 644 { 645 struct dcn_pg_cntl *pg_cntl_dcn = TO_DCN_PG_CNTL(*pg_cntl); 646 647 kfree(pg_cntl_dcn); 648 *pg_cntl = NULL; 649 } 650