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