Linux Audio

Check our new training course

Linux BSP development engineering services

Need help to port Linux and bootloaders to your hardware?
Loading...
  1/*
  2 * Copyright 2017 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 "smumgr.h"
 25#include "vega12_inc.h"
 26#include "soc15_common.h"
 27#include "smu9_smumgr.h"
 28#include "vega12_smumgr.h"
 29#include "vega12_ppsmc.h"
 30#include "vega12/smu9_driver_if.h"
 31#include "ppatomctrl.h"
 32#include "pp_debug.h"
 33
 34
 35/*
 36 * Copy table from SMC into driver FB
 37 * @param   hwmgr    the address of the HW manager
 38 * @param   table_id    the driver's table ID to copy from
 39 */
 40static int vega12_copy_table_from_smc(struct pp_hwmgr *hwmgr,
 41				      uint8_t *table, int16_t table_id)
 42{
 43	struct vega12_smumgr *priv =
 44			(struct vega12_smumgr *)(hwmgr->smu_backend);
 45	struct amdgpu_device *adev = hwmgr->adev;
 46
 47	PP_ASSERT_WITH_CODE(table_id < TABLE_COUNT,
 48			"Invalid SMU Table ID!", return -EINVAL);
 49	PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].version != 0,
 50			"Invalid SMU Table version!", return -EINVAL);
 51	PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].size != 0,
 52			"Invalid SMU Table Length!", return -EINVAL);
 53	PP_ASSERT_WITH_CODE(smum_send_msg_to_smc_with_parameter(hwmgr,
 54			PPSMC_MSG_SetDriverDramAddrHigh,
 55			upper_32_bits(priv->smu_tables.entry[table_id].mc_addr),
 56			NULL) == 0,
 57			"[CopyTableFromSMC] Attempt to Set Dram Addr High Failed!", return -EINVAL);
 58	PP_ASSERT_WITH_CODE(smum_send_msg_to_smc_with_parameter(hwmgr,
 59			PPSMC_MSG_SetDriverDramAddrLow,
 60			lower_32_bits(priv->smu_tables.entry[table_id].mc_addr),
 61			NULL) == 0,
 62			"[CopyTableFromSMC] Attempt to Set Dram Addr Low Failed!",
 63			return -EINVAL);
 64	PP_ASSERT_WITH_CODE(smum_send_msg_to_smc_with_parameter(hwmgr,
 65			PPSMC_MSG_TransferTableSmu2Dram,
 66			table_id,
 67			NULL) == 0,
 68			"[CopyTableFromSMC] Attempt to Transfer Table From SMU Failed!",
 69			return -EINVAL);
 70
 71	amdgpu_asic_invalidate_hdp(adev, NULL);
 72
 73	memcpy(table, priv->smu_tables.entry[table_id].table,
 74			priv->smu_tables.entry[table_id].size);
 75
 76	return 0;
 77}
 78
 79/*
 80 * Copy table from Driver FB into SMC
 81 * @param   hwmgr    the address of the HW manager
 82 * @param   table_id    the table to copy from
 83 */
 84static int vega12_copy_table_to_smc(struct pp_hwmgr *hwmgr,
 85				    uint8_t *table, int16_t table_id)
 86{
 87	struct vega12_smumgr *priv =
 88			(struct vega12_smumgr *)(hwmgr->smu_backend);
 89	struct amdgpu_device *adev = hwmgr->adev;
 90
 91	PP_ASSERT_WITH_CODE(table_id < TABLE_COUNT,
 92			"Invalid SMU Table ID!", return -EINVAL);
 93	PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].version != 0,
 94			"Invalid SMU Table version!", return -EINVAL);
 95	PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].size != 0,
 96			"Invalid SMU Table Length!", return -EINVAL);
 97
 98	memcpy(priv->smu_tables.entry[table_id].table, table,
 99			priv->smu_tables.entry[table_id].size);
100
101	amdgpu_asic_flush_hdp(adev, NULL);
102
103	PP_ASSERT_WITH_CODE(smum_send_msg_to_smc_with_parameter(hwmgr,
104			PPSMC_MSG_SetDriverDramAddrHigh,
105			upper_32_bits(priv->smu_tables.entry[table_id].mc_addr),
106			NULL) == 0,
107			"[CopyTableToSMC] Attempt to Set Dram Addr High Failed!",
108			return -EINVAL;);
109	PP_ASSERT_WITH_CODE(smum_send_msg_to_smc_with_parameter(hwmgr,
110			PPSMC_MSG_SetDriverDramAddrLow,
111			lower_32_bits(priv->smu_tables.entry[table_id].mc_addr),
112			NULL) == 0,
113			"[CopyTableToSMC] Attempt to Set Dram Addr Low Failed!",
114			return -EINVAL);
115	PP_ASSERT_WITH_CODE(smum_send_msg_to_smc_with_parameter(hwmgr,
116			PPSMC_MSG_TransferTableDram2Smu,
117			table_id,
118			NULL) == 0,
119			"[CopyTableToSMC] Attempt to Transfer Table To SMU Failed!",
120			return -EINVAL);
121
122	return 0;
123}
124
125int vega12_enable_smc_features(struct pp_hwmgr *hwmgr,
126		bool enable, uint64_t feature_mask)
127{
128	uint32_t smu_features_low, smu_features_high;
129
130	smu_features_low = (uint32_t)((feature_mask & SMU_FEATURES_LOW_MASK) >> SMU_FEATURES_LOW_SHIFT);
131	smu_features_high = (uint32_t)((feature_mask & SMU_FEATURES_HIGH_MASK) >> SMU_FEATURES_HIGH_SHIFT);
132
133	if (enable) {
134		PP_ASSERT_WITH_CODE(smum_send_msg_to_smc_with_parameter(hwmgr,
135				PPSMC_MSG_EnableSmuFeaturesLow, smu_features_low, NULL) == 0,
136				"[EnableDisableSMCFeatures] Attempt to enable SMU features Low failed!",
137				return -EINVAL);
138		PP_ASSERT_WITH_CODE(smum_send_msg_to_smc_with_parameter(hwmgr,
139				PPSMC_MSG_EnableSmuFeaturesHigh, smu_features_high, NULL) == 0,
140				"[EnableDisableSMCFeatures] Attempt to enable SMU features High failed!",
141				return -EINVAL);
142	} else {
143		PP_ASSERT_WITH_CODE(smum_send_msg_to_smc_with_parameter(hwmgr,
144				PPSMC_MSG_DisableSmuFeaturesLow, smu_features_low, NULL) == 0,
145				"[EnableDisableSMCFeatures] Attempt to disable SMU features Low failed!",
146				return -EINVAL);
147		PP_ASSERT_WITH_CODE(smum_send_msg_to_smc_with_parameter(hwmgr,
148				PPSMC_MSG_DisableSmuFeaturesHigh, smu_features_high, NULL) == 0,
149				"[EnableDisableSMCFeatures] Attempt to disable SMU features High failed!",
150				return -EINVAL);
151	}
152
153	return 0;
154}
155
156int vega12_get_enabled_smc_features(struct pp_hwmgr *hwmgr,
157		uint64_t *features_enabled)
158{
159	uint32_t smc_features_low, smc_features_high;
160
161	if (features_enabled == NULL)
162		return -EINVAL;
163
164	PP_ASSERT_WITH_CODE(smum_send_msg_to_smc(hwmgr,
165			PPSMC_MSG_GetEnabledSmuFeaturesLow,
166			&smc_features_low) == 0,
167			"[GetEnabledSMCFeatures] Attempt to get SMU features Low failed!",
168			return -EINVAL);
169
170	PP_ASSERT_WITH_CODE(smum_send_msg_to_smc(hwmgr,
171			PPSMC_MSG_GetEnabledSmuFeaturesHigh,
172			&smc_features_high) == 0,
173			"[GetEnabledSMCFeatures] Attempt to get SMU features High failed!",
174			return -EINVAL);
175
176	*features_enabled = ((((uint64_t)smc_features_low << SMU_FEATURES_LOW_SHIFT) & SMU_FEATURES_LOW_MASK) |
177			(((uint64_t)smc_features_high << SMU_FEATURES_HIGH_SHIFT) & SMU_FEATURES_HIGH_MASK));
178
179	return 0;
180}
181
182static bool vega12_is_dpm_running(struct pp_hwmgr *hwmgr)
183{
184	uint64_t features_enabled = 0;
185
186	vega12_get_enabled_smc_features(hwmgr, &features_enabled);
187
188	if (features_enabled & SMC_DPM_FEATURES)
189		return true;
190	else
191		return false;
192}
193
194static int vega12_set_tools_address(struct pp_hwmgr *hwmgr)
195{
196	struct vega12_smumgr *priv =
197			(struct vega12_smumgr *)(hwmgr->smu_backend);
198
199	if (priv->smu_tables.entry[TABLE_PMSTATUSLOG].mc_addr) {
200		if (!smum_send_msg_to_smc_with_parameter(hwmgr,
201				PPSMC_MSG_SetToolsDramAddrHigh,
202				upper_32_bits(priv->smu_tables.entry[TABLE_PMSTATUSLOG].mc_addr),
203				NULL))
204			smum_send_msg_to_smc_with_parameter(hwmgr,
205					PPSMC_MSG_SetToolsDramAddrLow,
206					lower_32_bits(priv->smu_tables.entry[TABLE_PMSTATUSLOG].mc_addr),
207					NULL);
208	}
209	return 0;
210}
211
212static int vega12_smu_init(struct pp_hwmgr *hwmgr)
213{
214	struct vega12_smumgr *priv;
215	unsigned long tools_size;
216	struct cgs_firmware_info info = {0};
217	int ret;
218
219	ret = cgs_get_firmware_info(hwmgr->device, CGS_UCODE_ID_SMU,
220				&info);
221	if (ret || !info.kptr)
222		return -EINVAL;
223
224	priv = kzalloc(sizeof(struct vega12_smumgr), GFP_KERNEL);
225	if (!priv)
226		return -ENOMEM;
227
228	hwmgr->smu_backend = priv;
229
230	/* allocate space for pptable */
231	ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev,
232			sizeof(PPTable_t),
233			PAGE_SIZE,
234			AMDGPU_GEM_DOMAIN_VRAM,
235			&priv->smu_tables.entry[TABLE_PPTABLE].handle,
236			&priv->smu_tables.entry[TABLE_PPTABLE].mc_addr,
237			&priv->smu_tables.entry[TABLE_PPTABLE].table);
238	if (ret)
239		goto free_backend;
240
241	priv->smu_tables.entry[TABLE_PPTABLE].version = 0x01;
242	priv->smu_tables.entry[TABLE_PPTABLE].size = sizeof(PPTable_t);
243
244	/* allocate space for watermarks table */
245	ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev,
246				      sizeof(Watermarks_t),
247				      PAGE_SIZE,
248				      AMDGPU_GEM_DOMAIN_VRAM,
249				      &priv->smu_tables.entry[TABLE_WATERMARKS].handle,
250				      &priv->smu_tables.entry[TABLE_WATERMARKS].mc_addr,
251				      &priv->smu_tables.entry[TABLE_WATERMARKS].table);
252
253	if (ret)
254		goto err0;
255
256	priv->smu_tables.entry[TABLE_WATERMARKS].version = 0x01;
257	priv->smu_tables.entry[TABLE_WATERMARKS].size = sizeof(Watermarks_t);
258
259	tools_size = 0x19000;
260	if (tools_size) {
261		ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev,
262					      tools_size,
263					      PAGE_SIZE,
264					      AMDGPU_GEM_DOMAIN_VRAM,
265					      &priv->smu_tables.entry[TABLE_PMSTATUSLOG].handle,
266					      &priv->smu_tables.entry[TABLE_PMSTATUSLOG].mc_addr,
267					      &priv->smu_tables.entry[TABLE_PMSTATUSLOG].table);
268		if (ret)
269			goto err1;
270
271		priv->smu_tables.entry[TABLE_PMSTATUSLOG].version = 0x01;
272		priv->smu_tables.entry[TABLE_PMSTATUSLOG].size = tools_size;
273	}
274
275	/* allocate space for AVFS Fuse table */
276	ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev,
277				      sizeof(AvfsFuseOverride_t),
278				      PAGE_SIZE,
279				      AMDGPU_GEM_DOMAIN_VRAM,
280				      &priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].handle,
281				      &priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].mc_addr,
282				      &priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].table);
283
284	if (ret)
285		goto err2;
286
287	priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].version = 0x01;
288	priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].size = sizeof(AvfsFuseOverride_t);
289
290	/* allocate space for OverDrive table */
291	ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev,
292				      sizeof(OverDriveTable_t),
293				      PAGE_SIZE,
294				      AMDGPU_GEM_DOMAIN_VRAM,
295				      &priv->smu_tables.entry[TABLE_OVERDRIVE].handle,
296				      &priv->smu_tables.entry[TABLE_OVERDRIVE].mc_addr,
297				      &priv->smu_tables.entry[TABLE_OVERDRIVE].table);
298	if (ret)
299		goto err3;
300
301	priv->smu_tables.entry[TABLE_OVERDRIVE].version = 0x01;
302	priv->smu_tables.entry[TABLE_OVERDRIVE].size = sizeof(OverDriveTable_t);
303
304	/* allocate space for SMU_METRICS table */
305	ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev,
306				      sizeof(SmuMetrics_t),
307				      PAGE_SIZE,
308				      AMDGPU_GEM_DOMAIN_VRAM,
309				      &priv->smu_tables.entry[TABLE_SMU_METRICS].handle,
310				      &priv->smu_tables.entry[TABLE_SMU_METRICS].mc_addr,
311				      &priv->smu_tables.entry[TABLE_SMU_METRICS].table);
312	if (ret)
313		goto err4;
314
315	priv->smu_tables.entry[TABLE_SMU_METRICS].version = 0x01;
316	priv->smu_tables.entry[TABLE_SMU_METRICS].size = sizeof(SmuMetrics_t);
317
318	return 0;
319
320err4:
321	amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_OVERDRIVE].handle,
322				&priv->smu_tables.entry[TABLE_OVERDRIVE].mc_addr,
323				&priv->smu_tables.entry[TABLE_OVERDRIVE].table);
324err3:
325	amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].handle,
326				&priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].mc_addr,
327				&priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].table);
328err2:
329	if (priv->smu_tables.entry[TABLE_PMSTATUSLOG].table)
330		amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_PMSTATUSLOG].handle,
331				&priv->smu_tables.entry[TABLE_PMSTATUSLOG].mc_addr,
332				&priv->smu_tables.entry[TABLE_PMSTATUSLOG].table);
333err1:
334	amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_WATERMARKS].handle,
335				&priv->smu_tables.entry[TABLE_WATERMARKS].mc_addr,
336				&priv->smu_tables.entry[TABLE_WATERMARKS].table);
337err0:
338	amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_PPTABLE].handle,
339			&priv->smu_tables.entry[TABLE_PPTABLE].mc_addr,
340			&priv->smu_tables.entry[TABLE_PPTABLE].table);
341free_backend:
342	kfree(hwmgr->smu_backend);
343
344	return -EINVAL;
345}
346
347static int vega12_smu_fini(struct pp_hwmgr *hwmgr)
348{
349	struct vega12_smumgr *priv =
350			(struct vega12_smumgr *)(hwmgr->smu_backend);
351
352	if (priv) {
353		amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_PPTABLE].handle,
354				      &priv->smu_tables.entry[TABLE_PPTABLE].mc_addr,
355				      &priv->smu_tables.entry[TABLE_PPTABLE].table);
356		amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_WATERMARKS].handle,
357				      &priv->smu_tables.entry[TABLE_WATERMARKS].mc_addr,
358				      &priv->smu_tables.entry[TABLE_WATERMARKS].table);
359		if (priv->smu_tables.entry[TABLE_PMSTATUSLOG].table)
360			amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_PMSTATUSLOG].handle,
361					      &priv->smu_tables.entry[TABLE_PMSTATUSLOG].mc_addr,
362					      &priv->smu_tables.entry[TABLE_PMSTATUSLOG].table);
363		amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].handle,
364				      &priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].mc_addr,
365				      &priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].table);
366		amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_OVERDRIVE].handle,
367				      &priv->smu_tables.entry[TABLE_OVERDRIVE].mc_addr,
368				      &priv->smu_tables.entry[TABLE_OVERDRIVE].table);
369		amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_SMU_METRICS].handle,
370				      &priv->smu_tables.entry[TABLE_SMU_METRICS].mc_addr,
371				      &priv->smu_tables.entry[TABLE_SMU_METRICS].table);
372		kfree(hwmgr->smu_backend);
373		hwmgr->smu_backend = NULL;
374	}
375	return 0;
376}
377
378static int vega12_start_smu(struct pp_hwmgr *hwmgr)
379{
380	PP_ASSERT_WITH_CODE(smu9_is_smc_ram_running(hwmgr),
381			"SMC is not running!",
382			return -EINVAL);
383
384	vega12_set_tools_address(hwmgr);
385
386	return 0;
387}
388
389static int vega12_smc_table_manager(struct pp_hwmgr *hwmgr, uint8_t *table,
390				    uint16_t table_id, bool rw)
391{
392	int ret;
393
394	if (rw)
395		ret = vega12_copy_table_from_smc(hwmgr, table, table_id);
396	else
397		ret = vega12_copy_table_to_smc(hwmgr, table, table_id);
398
399	return ret;
400}
401
402const struct pp_smumgr_func vega12_smu_funcs = {
403	.name = "vega12_smu",
404	.smu_init = &vega12_smu_init,
405	.smu_fini = &vega12_smu_fini,
406	.start_smu = &vega12_start_smu,
407	.request_smu_load_specific_fw = NULL,
408	.send_msg_to_smc = &smu9_send_msg_to_smc,
409	.send_msg_to_smc_with_parameter = &smu9_send_msg_to_smc_with_parameter,
410	.download_pptable_settings = NULL,
411	.upload_pptable_settings = NULL,
412	.is_dpm_running = vega12_is_dpm_running,
413	.get_argument = smu9_get_argument,
414	.smc_table_manager = vega12_smc_table_manager,
415};
1