1 /*
2  * Copyright 2016 Advanced Micro Devices, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  */
23 
24 #include "smu7_hwmgr.h"
25 #include "smu7_clockpowergating.h"
26 #include "smu7_common.h"
27 
28 static int smu7_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable)
29 {
30 	return smum_send_msg_to_smc(hwmgr, enable ?
31 			PPSMC_MSG_UVDDPM_Enable :
32 			PPSMC_MSG_UVDDPM_Disable,
33 			NULL);
34 }
35 
36 static int smu7_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable)
37 {
38 	return smum_send_msg_to_smc(hwmgr, enable ?
39 			PPSMC_MSG_VCEDPM_Enable :
40 			PPSMC_MSG_VCEDPM_Disable,
41 			NULL);
42 }
43 
44 static int smu7_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate)
45 {
46 	if (!bgate)
47 		smum_update_smc_table(hwmgr, SMU_UVD_TABLE);
48 	return smu7_enable_disable_uvd_dpm(hwmgr, !bgate);
49 }
50 
51 static int smu7_update_vce_dpm(struct pp_hwmgr *hwmgr, bool bgate)
52 {
53 	if (!bgate)
54 		smum_update_smc_table(hwmgr, SMU_VCE_TABLE);
55 	return smu7_enable_disable_vce_dpm(hwmgr, !bgate);
56 }
57 
58 int smu7_powerdown_uvd(struct pp_hwmgr *hwmgr)
59 {
60 	if (phm_cf_want_uvd_power_gating(hwmgr))
61 		return smum_send_msg_to_smc(hwmgr,
62 				PPSMC_MSG_UVDPowerOFF,
63 				NULL);
64 	return 0;
65 }
66 
67 static int smu7_powerup_uvd(struct pp_hwmgr *hwmgr)
68 {
69 	if (phm_cf_want_uvd_power_gating(hwmgr)) {
70 		if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
71 				  PHM_PlatformCaps_UVDDynamicPowerGating)) {
72 			return smum_send_msg_to_smc_with_parameter(hwmgr,
73 					PPSMC_MSG_UVDPowerON, 1, NULL);
74 		} else {
75 			return smum_send_msg_to_smc_with_parameter(hwmgr,
76 					PPSMC_MSG_UVDPowerON, 0, NULL);
77 		}
78 	}
79 
80 	return 0;
81 }
82 
83 static int smu7_powerdown_vce(struct pp_hwmgr *hwmgr)
84 {
85 	if (phm_cf_want_vce_power_gating(hwmgr))
86 		return smum_send_msg_to_smc(hwmgr,
87 				PPSMC_MSG_VCEPowerOFF,
88 				NULL);
89 	return 0;
90 }
91 
92 static int smu7_powerup_vce(struct pp_hwmgr *hwmgr)
93 {
94 	if (phm_cf_want_vce_power_gating(hwmgr))
95 		return smum_send_msg_to_smc(hwmgr,
96 				PPSMC_MSG_VCEPowerON,
97 				NULL);
98 	return 0;
99 }
100 
101 int smu7_disable_clock_power_gating(struct pp_hwmgr *hwmgr)
102 {
103 	struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
104 
105 	data->uvd_power_gated = false;
106 	data->vce_power_gated = false;
107 
108 	smu7_powerup_uvd(hwmgr);
109 	smu7_powerup_vce(hwmgr);
110 
111 	return 0;
112 }
113 
114 void smu7_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate)
115 {
116 	struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
117 
118 	data->uvd_power_gated = bgate;
119 
120 	if (bgate) {
121 		amdgpu_device_ip_set_powergating_state(hwmgr->adev,
122 						AMD_IP_BLOCK_TYPE_UVD,
123 						AMD_PG_STATE_GATE);
124 		amdgpu_device_ip_set_clockgating_state(hwmgr->adev,
125 				AMD_IP_BLOCK_TYPE_UVD,
126 				AMD_CG_STATE_GATE);
127 		smu7_update_uvd_dpm(hwmgr, true);
128 		smu7_powerdown_uvd(hwmgr);
129 	} else {
130 		smu7_powerup_uvd(hwmgr);
131 		amdgpu_device_ip_set_clockgating_state(hwmgr->adev,
132 				AMD_IP_BLOCK_TYPE_UVD,
133 				AMD_CG_STATE_UNGATE);
134 		amdgpu_device_ip_set_powergating_state(hwmgr->adev,
135 						AMD_IP_BLOCK_TYPE_UVD,
136 						AMD_PG_STATE_UNGATE);
137 		smu7_update_uvd_dpm(hwmgr, false);
138 	}
139 
140 }
141 
142 void smu7_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate)
143 {
144 	struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
145 
146 	data->vce_power_gated = bgate;
147 
148 	if (bgate) {
149 		amdgpu_device_ip_set_powergating_state(hwmgr->adev,
150 						AMD_IP_BLOCK_TYPE_VCE,
151 						AMD_PG_STATE_GATE);
152 		amdgpu_device_ip_set_clockgating_state(hwmgr->adev,
153 				AMD_IP_BLOCK_TYPE_VCE,
154 				AMD_CG_STATE_GATE);
155 		smu7_update_vce_dpm(hwmgr, true);
156 		smu7_powerdown_vce(hwmgr);
157 	} else {
158 		smu7_powerup_vce(hwmgr);
159 		amdgpu_device_ip_set_clockgating_state(hwmgr->adev,
160 				AMD_IP_BLOCK_TYPE_VCE,
161 				AMD_CG_STATE_UNGATE);
162 		amdgpu_device_ip_set_powergating_state(hwmgr->adev,
163 						AMD_IP_BLOCK_TYPE_VCE,
164 						AMD_PG_STATE_UNGATE);
165 		smu7_update_vce_dpm(hwmgr, false);
166 	}
167 }
168 
169 int smu7_update_clock_gatings(struct pp_hwmgr *hwmgr,
170 					const uint32_t *msg_id)
171 {
172 	PPSMC_Msg msg;
173 	uint32_t value;
174 
175 	if (!(hwmgr->feature_mask & PP_ENABLE_GFX_CG_THRU_SMU))
176 		return 0;
177 
178 	switch ((*msg_id & PP_GROUP_MASK) >> PP_GROUP_SHIFT) {
179 	case PP_GROUP_GFX:
180 		switch ((*msg_id & PP_BLOCK_MASK) >> PP_BLOCK_SHIFT) {
181 		case PP_BLOCK_GFX_CG:
182 			if (PP_STATE_SUPPORT_CG & *msg_id) {
183 				msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG) ?
184 						PPSMC_MSG_EnableClockGatingFeature :
185 						PPSMC_MSG_DisableClockGatingFeature;
186 				value = CG_GFX_CGCG_MASK;
187 
188 				if (smum_send_msg_to_smc_with_parameter(
189 						hwmgr, msg, value, NULL))
190 					return -EINVAL;
191 			}
192 			if (PP_STATE_SUPPORT_LS & *msg_id) {
193 				msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS
194 					? PPSMC_MSG_EnableClockGatingFeature
195 					: PPSMC_MSG_DisableClockGatingFeature;
196 				value = CG_GFX_CGLS_MASK;
197 
198 				if (smum_send_msg_to_smc_with_parameter(
199 						hwmgr, msg, value, NULL))
200 					return -EINVAL;
201 			}
202 			break;
203 
204 		case PP_BLOCK_GFX_3D:
205 			if (PP_STATE_SUPPORT_CG & *msg_id) {
206 				msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG) ?
207 						PPSMC_MSG_EnableClockGatingFeature :
208 						PPSMC_MSG_DisableClockGatingFeature;
209 				value = CG_GFX_3DCG_MASK;
210 
211 				if (smum_send_msg_to_smc_with_parameter(
212 						hwmgr, msg, value, NULL))
213 					return -EINVAL;
214 			}
215 
216 			if  (PP_STATE_SUPPORT_LS & *msg_id) {
217 				msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
218 						PPSMC_MSG_EnableClockGatingFeature :
219 						PPSMC_MSG_DisableClockGatingFeature;
220 				value = CG_GFX_3DLS_MASK;
221 
222 				if (smum_send_msg_to_smc_with_parameter(
223 						hwmgr, msg, value, NULL))
224 					return -EINVAL;
225 			}
226 			break;
227 
228 		case PP_BLOCK_GFX_RLC:
229 			if (PP_STATE_SUPPORT_LS & *msg_id) {
230 				msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
231 						PPSMC_MSG_EnableClockGatingFeature :
232 						PPSMC_MSG_DisableClockGatingFeature;
233 				value = CG_GFX_RLC_LS_MASK;
234 
235 				if (smum_send_msg_to_smc_with_parameter(
236 						hwmgr, msg, value, NULL))
237 					return -EINVAL;
238 			}
239 			break;
240 
241 		case PP_BLOCK_GFX_CP:
242 			if (PP_STATE_SUPPORT_LS & *msg_id) {
243 				msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
244 						PPSMC_MSG_EnableClockGatingFeature :
245 						PPSMC_MSG_DisableClockGatingFeature;
246 				value = CG_GFX_CP_LS_MASK;
247 
248 				if (smum_send_msg_to_smc_with_parameter(
249 						hwmgr, msg, value, NULL))
250 					return -EINVAL;
251 			}
252 			break;
253 
254 		case PP_BLOCK_GFX_MG:
255 			if (PP_STATE_SUPPORT_CG & *msg_id) {
256 				msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG)	?
257 						PPSMC_MSG_EnableClockGatingFeature :
258 						PPSMC_MSG_DisableClockGatingFeature;
259 				value = (CG_CPF_MGCG_MASK | CG_RLC_MGCG_MASK |
260 						CG_GFX_OTHERS_MGCG_MASK);
261 
262 				if (smum_send_msg_to_smc_with_parameter(
263 						hwmgr, msg, value, NULL))
264 					return -EINVAL;
265 			}
266 			break;
267 
268 		default:
269 			return -EINVAL;
270 		}
271 		break;
272 
273 	case PP_GROUP_SYS:
274 		switch ((*msg_id & PP_BLOCK_MASK) >> PP_BLOCK_SHIFT) {
275 		case PP_BLOCK_SYS_BIF:
276 			if (PP_STATE_SUPPORT_CG & *msg_id) {
277 				msg = (*msg_id & PP_STATE_MASK) & PP_STATE_CG ?
278 						PPSMC_MSG_EnableClockGatingFeature :
279 						PPSMC_MSG_DisableClockGatingFeature;
280 				value = CG_SYS_BIF_MGCG_MASK;
281 
282 				if (smum_send_msg_to_smc_with_parameter(
283 						hwmgr, msg, value, NULL))
284 					return -EINVAL;
285 			}
286 			if  (PP_STATE_SUPPORT_LS & *msg_id) {
287 				msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
288 						PPSMC_MSG_EnableClockGatingFeature :
289 						PPSMC_MSG_DisableClockGatingFeature;
290 				value = CG_SYS_BIF_MGLS_MASK;
291 
292 				if (smum_send_msg_to_smc_with_parameter(
293 						hwmgr, msg, value, NULL))
294 					return -EINVAL;
295 			}
296 			break;
297 
298 		case PP_BLOCK_SYS_MC:
299 			if (PP_STATE_SUPPORT_CG & *msg_id) {
300 				msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG)	?
301 						PPSMC_MSG_EnableClockGatingFeature :
302 						PPSMC_MSG_DisableClockGatingFeature;
303 				value = CG_SYS_MC_MGCG_MASK;
304 
305 				if (smum_send_msg_to_smc_with_parameter(
306 						hwmgr, msg, value, NULL))
307 					return -EINVAL;
308 			}
309 
310 			if (PP_STATE_SUPPORT_LS & *msg_id) {
311 				msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
312 						PPSMC_MSG_EnableClockGatingFeature :
313 						PPSMC_MSG_DisableClockGatingFeature;
314 				value = CG_SYS_MC_MGLS_MASK;
315 
316 				if (smum_send_msg_to_smc_with_parameter(
317 						hwmgr, msg, value, NULL))
318 					return -EINVAL;
319 			}
320 			break;
321 
322 		case PP_BLOCK_SYS_DRM:
323 			if (PP_STATE_SUPPORT_CG & *msg_id) {
324 				msg = (*msg_id & PP_STATE_MASK) & PP_STATE_CG ?
325 						PPSMC_MSG_EnableClockGatingFeature :
326 						PPSMC_MSG_DisableClockGatingFeature;
327 				value = CG_SYS_DRM_MGCG_MASK;
328 
329 				if (smum_send_msg_to_smc_with_parameter(
330 						hwmgr, msg, value, NULL))
331 					return -EINVAL;
332 			}
333 			if (PP_STATE_SUPPORT_LS & *msg_id) {
334 				msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
335 						PPSMC_MSG_EnableClockGatingFeature :
336 						PPSMC_MSG_DisableClockGatingFeature;
337 				value = CG_SYS_DRM_MGLS_MASK;
338 
339 				if (smum_send_msg_to_smc_with_parameter(
340 						hwmgr, msg, value, NULL))
341 					return -EINVAL;
342 			}
343 			break;
344 
345 		case PP_BLOCK_SYS_HDP:
346 			if (PP_STATE_SUPPORT_CG & *msg_id) {
347 				msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG) ?
348 						PPSMC_MSG_EnableClockGatingFeature :
349 						PPSMC_MSG_DisableClockGatingFeature;
350 				value = CG_SYS_HDP_MGCG_MASK;
351 
352 				if (smum_send_msg_to_smc_with_parameter(
353 						hwmgr, msg, value, NULL))
354 					return -EINVAL;
355 			}
356 
357 			if (PP_STATE_SUPPORT_LS & *msg_id) {
358 				msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
359 						PPSMC_MSG_EnableClockGatingFeature :
360 						PPSMC_MSG_DisableClockGatingFeature;
361 				value = CG_SYS_HDP_MGLS_MASK;
362 
363 				if (smum_send_msg_to_smc_with_parameter(
364 						hwmgr, msg, value, NULL))
365 					return -EINVAL;
366 			}
367 			break;
368 
369 		case PP_BLOCK_SYS_SDMA:
370 			if (PP_STATE_SUPPORT_CG & *msg_id) {
371 				msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG)	?
372 						PPSMC_MSG_EnableClockGatingFeature :
373 						PPSMC_MSG_DisableClockGatingFeature;
374 				value = CG_SYS_SDMA_MGCG_MASK;
375 
376 				if (smum_send_msg_to_smc_with_parameter(
377 						hwmgr, msg, value, NULL))
378 					return -EINVAL;
379 			}
380 
381 			if (PP_STATE_SUPPORT_LS & *msg_id) {
382 				msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
383 						PPSMC_MSG_EnableClockGatingFeature :
384 						PPSMC_MSG_DisableClockGatingFeature;
385 				value = CG_SYS_SDMA_MGLS_MASK;
386 
387 				if (smum_send_msg_to_smc_with_parameter(
388 						hwmgr, msg, value, NULL))
389 					return -EINVAL;
390 			}
391 			break;
392 
393 		case PP_BLOCK_SYS_ROM:
394 			if (PP_STATE_SUPPORT_CG & *msg_id) {
395 				msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG) ?
396 						PPSMC_MSG_EnableClockGatingFeature :
397 						PPSMC_MSG_DisableClockGatingFeature;
398 				value = CG_SYS_ROM_MASK;
399 
400 				if (smum_send_msg_to_smc_with_parameter(
401 						hwmgr, msg, value, NULL))
402 					return -EINVAL;
403 			}
404 			break;
405 
406 		default:
407 			return -EINVAL;
408 
409 		}
410 		break;
411 
412 	default:
413 		return -EINVAL;
414 
415 	}
416 
417 	return 0;
418 }
419 
420 /* This function is for Polaris11 only for now,
421  * Powerplay will only control the static per CU Power Gating.
422  * Dynamic per CU Power Gating will be done in gfx.
423  */
424 int smu7_powergate_gfx(struct pp_hwmgr *hwmgr, bool enable)
425 {
426 	struct amdgpu_device *adev = hwmgr->adev;
427 
428 	if (enable)
429 		return smum_send_msg_to_smc_with_parameter(hwmgr,
430 					PPSMC_MSG_GFX_CU_PG_ENABLE,
431 					adev->gfx.cu_info.number,
432 					NULL);
433 	else
434 		return smum_send_msg_to_smc(hwmgr,
435 				PPSMC_MSG_GFX_CU_PG_DISABLE,
436 				NULL);
437 }
438