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 }
34 
35 static int smu7_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable)
36 {
37 	return smum_send_msg_to_smc(hwmgr, enable ?
38 			PPSMC_MSG_VCEDPM_Enable :
39 			PPSMC_MSG_VCEDPM_Disable);
40 }
41 
42 static int smu7_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate)
43 {
44 	if (!bgate)
45 		smum_update_smc_table(hwmgr, SMU_UVD_TABLE);
46 	return smu7_enable_disable_uvd_dpm(hwmgr, !bgate);
47 }
48 
49 static int smu7_update_vce_dpm(struct pp_hwmgr *hwmgr, bool bgate)
50 {
51 	if (!bgate)
52 		smum_update_smc_table(hwmgr, SMU_VCE_TABLE);
53 	return smu7_enable_disable_vce_dpm(hwmgr, !bgate);
54 }
55 
56 int smu7_powerdown_uvd(struct pp_hwmgr *hwmgr)
57 {
58 	if (phm_cf_want_uvd_power_gating(hwmgr))
59 		return smum_send_msg_to_smc(hwmgr,
60 				PPSMC_MSG_UVDPowerOFF);
61 	return 0;
62 }
63 
64 static int smu7_powerup_uvd(struct pp_hwmgr *hwmgr)
65 {
66 	if (phm_cf_want_uvd_power_gating(hwmgr)) {
67 		if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
68 				  PHM_PlatformCaps_UVDDynamicPowerGating)) {
69 			return smum_send_msg_to_smc_with_parameter(hwmgr,
70 					PPSMC_MSG_UVDPowerON, 1);
71 		} else {
72 			return smum_send_msg_to_smc_with_parameter(hwmgr,
73 					PPSMC_MSG_UVDPowerON, 0);
74 		}
75 	}
76 
77 	return 0;
78 }
79 
80 static int smu7_powerdown_vce(struct pp_hwmgr *hwmgr)
81 {
82 	if (phm_cf_want_vce_power_gating(hwmgr))
83 		return smum_send_msg_to_smc(hwmgr,
84 				PPSMC_MSG_VCEPowerOFF);
85 	return 0;
86 }
87 
88 static int smu7_powerup_vce(struct pp_hwmgr *hwmgr)
89 {
90 	if (phm_cf_want_vce_power_gating(hwmgr))
91 		return smum_send_msg_to_smc(hwmgr,
92 				PPSMC_MSG_VCEPowerON);
93 	return 0;
94 }
95 
96 int smu7_disable_clock_power_gating(struct pp_hwmgr *hwmgr)
97 {
98 	struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
99 
100 	data->uvd_power_gated = false;
101 	data->vce_power_gated = false;
102 
103 	smu7_powerup_uvd(hwmgr);
104 	smu7_powerup_vce(hwmgr);
105 
106 	return 0;
107 }
108 
109 void smu7_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate)
110 {
111 	struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
112 
113 	data->uvd_power_gated = bgate;
114 
115 	if (bgate) {
116 		amdgpu_device_ip_set_powergating_state(hwmgr->adev,
117 						AMD_IP_BLOCK_TYPE_UVD,
118 						AMD_PG_STATE_GATE);
119 		amdgpu_device_ip_set_clockgating_state(hwmgr->adev,
120 				AMD_IP_BLOCK_TYPE_UVD,
121 				AMD_CG_STATE_GATE);
122 		smu7_update_uvd_dpm(hwmgr, true);
123 		smu7_powerdown_uvd(hwmgr);
124 	} else {
125 		smu7_powerup_uvd(hwmgr);
126 		amdgpu_device_ip_set_clockgating_state(hwmgr->adev,
127 				AMD_IP_BLOCK_TYPE_UVD,
128 				AMD_CG_STATE_UNGATE);
129 		amdgpu_device_ip_set_powergating_state(hwmgr->adev,
130 						AMD_IP_BLOCK_TYPE_UVD,
131 						AMD_PG_STATE_UNGATE);
132 		smu7_update_uvd_dpm(hwmgr, false);
133 	}
134 
135 }
136 
137 void smu7_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate)
138 {
139 	struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
140 
141 	data->vce_power_gated = bgate;
142 
143 	if (bgate) {
144 		amdgpu_device_ip_set_powergating_state(hwmgr->adev,
145 						AMD_IP_BLOCK_TYPE_VCE,
146 						AMD_PG_STATE_GATE);
147 		amdgpu_device_ip_set_clockgating_state(hwmgr->adev,
148 				AMD_IP_BLOCK_TYPE_VCE,
149 				AMD_CG_STATE_GATE);
150 		smu7_update_vce_dpm(hwmgr, true);
151 		smu7_powerdown_vce(hwmgr);
152 	} else {
153 		smu7_powerup_vce(hwmgr);
154 		amdgpu_device_ip_set_clockgating_state(hwmgr->adev,
155 				AMD_IP_BLOCK_TYPE_VCE,
156 				AMD_CG_STATE_UNGATE);
157 		amdgpu_device_ip_set_powergating_state(hwmgr->adev,
158 						AMD_IP_BLOCK_TYPE_VCE,
159 						AMD_PG_STATE_UNGATE);
160 		smu7_update_vce_dpm(hwmgr, false);
161 	}
162 }
163 
164 int smu7_update_clock_gatings(struct pp_hwmgr *hwmgr,
165 					const uint32_t *msg_id)
166 {
167 	PPSMC_Msg msg;
168 	uint32_t value;
169 
170 	if (!(hwmgr->feature_mask & PP_ENABLE_GFX_CG_THRU_SMU))
171 		return 0;
172 
173 	switch ((*msg_id & PP_GROUP_MASK) >> PP_GROUP_SHIFT) {
174 	case PP_GROUP_GFX:
175 		switch ((*msg_id & PP_BLOCK_MASK) >> PP_BLOCK_SHIFT) {
176 		case PP_BLOCK_GFX_CG:
177 			if (PP_STATE_SUPPORT_CG & *msg_id) {
178 				msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG) ?
179 						PPSMC_MSG_EnableClockGatingFeature :
180 						PPSMC_MSG_DisableClockGatingFeature;
181 				value = CG_GFX_CGCG_MASK;
182 
183 				if (smum_send_msg_to_smc_with_parameter(
184 						hwmgr, msg, value))
185 					return -EINVAL;
186 			}
187 			if (PP_STATE_SUPPORT_LS & *msg_id) {
188 				msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS
189 					? PPSMC_MSG_EnableClockGatingFeature
190 					: PPSMC_MSG_DisableClockGatingFeature;
191 				value = CG_GFX_CGLS_MASK;
192 
193 				if (smum_send_msg_to_smc_with_parameter(
194 						hwmgr, msg, value))
195 					return -EINVAL;
196 			}
197 			break;
198 
199 		case PP_BLOCK_GFX_3D:
200 			if (PP_STATE_SUPPORT_CG & *msg_id) {
201 				msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG) ?
202 						PPSMC_MSG_EnableClockGatingFeature :
203 						PPSMC_MSG_DisableClockGatingFeature;
204 				value = CG_GFX_3DCG_MASK;
205 
206 				if (smum_send_msg_to_smc_with_parameter(
207 						hwmgr, msg, value))
208 					return -EINVAL;
209 			}
210 
211 			if  (PP_STATE_SUPPORT_LS & *msg_id) {
212 				msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
213 						PPSMC_MSG_EnableClockGatingFeature :
214 						PPSMC_MSG_DisableClockGatingFeature;
215 				value = CG_GFX_3DLS_MASK;
216 
217 				if (smum_send_msg_to_smc_with_parameter(
218 						hwmgr, msg, value))
219 					return -EINVAL;
220 			}
221 			break;
222 
223 		case PP_BLOCK_GFX_RLC:
224 			if (PP_STATE_SUPPORT_LS & *msg_id) {
225 				msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
226 						PPSMC_MSG_EnableClockGatingFeature :
227 						PPSMC_MSG_DisableClockGatingFeature;
228 				value = CG_GFX_RLC_LS_MASK;
229 
230 				if (smum_send_msg_to_smc_with_parameter(
231 						hwmgr, msg, value))
232 					return -EINVAL;
233 			}
234 			break;
235 
236 		case PP_BLOCK_GFX_CP:
237 			if (PP_STATE_SUPPORT_LS & *msg_id) {
238 				msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
239 						PPSMC_MSG_EnableClockGatingFeature :
240 						PPSMC_MSG_DisableClockGatingFeature;
241 				value = CG_GFX_CP_LS_MASK;
242 
243 				if (smum_send_msg_to_smc_with_parameter(
244 						hwmgr, msg, value))
245 					return -EINVAL;
246 			}
247 			break;
248 
249 		case PP_BLOCK_GFX_MG:
250 			if (PP_STATE_SUPPORT_CG & *msg_id) {
251 				msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG)	?
252 						PPSMC_MSG_EnableClockGatingFeature :
253 						PPSMC_MSG_DisableClockGatingFeature;
254 				value = (CG_CPF_MGCG_MASK | CG_RLC_MGCG_MASK |
255 						CG_GFX_OTHERS_MGCG_MASK);
256 
257 				if (smum_send_msg_to_smc_with_parameter(
258 						hwmgr, msg, value))
259 					return -EINVAL;
260 			}
261 			break;
262 
263 		default:
264 			return -EINVAL;
265 		}
266 		break;
267 
268 	case PP_GROUP_SYS:
269 		switch ((*msg_id & PP_BLOCK_MASK) >> PP_BLOCK_SHIFT) {
270 		case PP_BLOCK_SYS_BIF:
271 			if (PP_STATE_SUPPORT_CG & *msg_id) {
272 				msg = (*msg_id & PP_STATE_MASK) & PP_STATE_CG ?
273 						PPSMC_MSG_EnableClockGatingFeature :
274 						PPSMC_MSG_DisableClockGatingFeature;
275 				value = CG_SYS_BIF_MGCG_MASK;
276 
277 				if (smum_send_msg_to_smc_with_parameter(
278 						hwmgr, msg, value))
279 					return -EINVAL;
280 			}
281 			if  (PP_STATE_SUPPORT_LS & *msg_id) {
282 				msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
283 						PPSMC_MSG_EnableClockGatingFeature :
284 						PPSMC_MSG_DisableClockGatingFeature;
285 				value = CG_SYS_BIF_MGLS_MASK;
286 
287 				if (smum_send_msg_to_smc_with_parameter(
288 						hwmgr, msg, value))
289 					return -EINVAL;
290 			}
291 			break;
292 
293 		case PP_BLOCK_SYS_MC:
294 			if (PP_STATE_SUPPORT_CG & *msg_id) {
295 				msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG)	?
296 						PPSMC_MSG_EnableClockGatingFeature :
297 						PPSMC_MSG_DisableClockGatingFeature;
298 				value = CG_SYS_MC_MGCG_MASK;
299 
300 				if (smum_send_msg_to_smc_with_parameter(
301 						hwmgr, msg, value))
302 					return -EINVAL;
303 			}
304 
305 			if (PP_STATE_SUPPORT_LS & *msg_id) {
306 				msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
307 						PPSMC_MSG_EnableClockGatingFeature :
308 						PPSMC_MSG_DisableClockGatingFeature;
309 				value = CG_SYS_MC_MGLS_MASK;
310 
311 				if (smum_send_msg_to_smc_with_parameter(
312 						hwmgr, msg, value))
313 					return -EINVAL;
314 			}
315 			break;
316 
317 		case PP_BLOCK_SYS_DRM:
318 			if (PP_STATE_SUPPORT_CG & *msg_id) {
319 				msg = (*msg_id & PP_STATE_MASK) & PP_STATE_CG ?
320 						PPSMC_MSG_EnableClockGatingFeature :
321 						PPSMC_MSG_DisableClockGatingFeature;
322 				value = CG_SYS_DRM_MGCG_MASK;
323 
324 				if (smum_send_msg_to_smc_with_parameter(
325 						hwmgr, msg, value))
326 					return -EINVAL;
327 			}
328 			if (PP_STATE_SUPPORT_LS & *msg_id) {
329 				msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
330 						PPSMC_MSG_EnableClockGatingFeature :
331 						PPSMC_MSG_DisableClockGatingFeature;
332 				value = CG_SYS_DRM_MGLS_MASK;
333 
334 				if (smum_send_msg_to_smc_with_parameter(
335 						hwmgr, msg, value))
336 					return -EINVAL;
337 			}
338 			break;
339 
340 		case PP_BLOCK_SYS_HDP:
341 			if (PP_STATE_SUPPORT_CG & *msg_id) {
342 				msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG) ?
343 						PPSMC_MSG_EnableClockGatingFeature :
344 						PPSMC_MSG_DisableClockGatingFeature;
345 				value = CG_SYS_HDP_MGCG_MASK;
346 
347 				if (smum_send_msg_to_smc_with_parameter(
348 						hwmgr, msg, value))
349 					return -EINVAL;
350 			}
351 
352 			if (PP_STATE_SUPPORT_LS & *msg_id) {
353 				msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
354 						PPSMC_MSG_EnableClockGatingFeature :
355 						PPSMC_MSG_DisableClockGatingFeature;
356 				value = CG_SYS_HDP_MGLS_MASK;
357 
358 				if (smum_send_msg_to_smc_with_parameter(
359 						hwmgr, msg, value))
360 					return -EINVAL;
361 			}
362 			break;
363 
364 		case PP_BLOCK_SYS_SDMA:
365 			if (PP_STATE_SUPPORT_CG & *msg_id) {
366 				msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG)	?
367 						PPSMC_MSG_EnableClockGatingFeature :
368 						PPSMC_MSG_DisableClockGatingFeature;
369 				value = CG_SYS_SDMA_MGCG_MASK;
370 
371 				if (smum_send_msg_to_smc_with_parameter(
372 						hwmgr, msg, value))
373 					return -EINVAL;
374 			}
375 
376 			if (PP_STATE_SUPPORT_LS & *msg_id) {
377 				msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
378 						PPSMC_MSG_EnableClockGatingFeature :
379 						PPSMC_MSG_DisableClockGatingFeature;
380 				value = CG_SYS_SDMA_MGLS_MASK;
381 
382 				if (smum_send_msg_to_smc_with_parameter(
383 						hwmgr, msg, value))
384 					return -EINVAL;
385 			}
386 			break;
387 
388 		case PP_BLOCK_SYS_ROM:
389 			if (PP_STATE_SUPPORT_CG & *msg_id) {
390 				msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG) ?
391 						PPSMC_MSG_EnableClockGatingFeature :
392 						PPSMC_MSG_DisableClockGatingFeature;
393 				value = CG_SYS_ROM_MASK;
394 
395 				if (smum_send_msg_to_smc_with_parameter(
396 						hwmgr, msg, value))
397 					return -EINVAL;
398 			}
399 			break;
400 
401 		default:
402 			return -EINVAL;
403 
404 		}
405 		break;
406 
407 	default:
408 		return -EINVAL;
409 
410 	}
411 
412 	return 0;
413 }
414 
415 /* This function is for Polaris11 only for now,
416  * Powerplay will only control the static per CU Power Gating.
417  * Dynamic per CU Power Gating will be done in gfx.
418  */
419 int smu7_powergate_gfx(struct pp_hwmgr *hwmgr, bool enable)
420 {
421 	struct amdgpu_device *adev = hwmgr->adev;
422 
423 	if (enable)
424 		return smum_send_msg_to_smc_with_parameter(hwmgr,
425 					PPSMC_MSG_GFX_CU_PG_ENABLE,
426 					adev->gfx.cu_info.number);
427 	else
428 		return smum_send_msg_to_smc(hwmgr,
429 				PPSMC_MSG_GFX_CU_PG_DISABLE);
430 }
431