xref: /linux/drivers/gpu/drm/amd/display/dc/pg/dcn42/dcn42_pg_cntl.c (revision 0fc8f6200d2313278fbf4539bbab74677c685531)
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