vega10_smumgr.c 15.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
/*
 * Copyright 2016 Advanced Micro Devices, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 */

#include "smumgr.h"
#include "vega10_inc.h"
#include "pp_soc15.h"
#include "vega10_smumgr.h"
#include "vega10_ppsmc.h"
#include "smu9_driver_if.h"
#include "ppatomctrl.h"
#include "pp_debug.h"
32

33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53

#define AVFS_EN_MSB		1568
#define AVFS_EN_LSB		1568

#define VOLTAGE_SCALE	4

/* Microcode file is stored in this buffer */
#define BUFFER_SIZE                 80000
#define MAX_STRING_SIZE             15
#define BUFFER_SIZETWO              131072 /* 128 *1024 */

/* MP Apertures */
#define MP0_Public                  0x03800000
#define MP0_SRAM                    0x03900000
#define MP1_Public                  0x03b00000
#define MP1_SRAM                    0x03c00004

#define smnMP1_FIRMWARE_FLAGS                                                                           0x3010028
#define smnMP0_FW_INTF                                                                                  0x3010104
#define smnMP1_PUB_CTRL                                                                                 0x3010b14

54
static bool vega10_is_smc_ram_running(struct pp_hwmgr *hwmgr)
55 56 57 58 59 60
{
	uint32_t mp1_fw_flags, reg;

	reg = soc15_get_register_offset(NBIF_HWID, 0,
			mmPCIE_INDEX2_BASE_IDX, mmPCIE_INDEX2);

61
	cgs_write_register(hwmgr->device, reg,
62 63 64 65 66
			(MP1_Public | (smnMP1_FIRMWARE_FLAGS & 0xffffffff)));

	reg = soc15_get_register_offset(NBIF_HWID, 0,
			mmPCIE_DATA2_BASE_IDX, mmPCIE_DATA2);

67
	mp1_fw_flags = cgs_read_register(hwmgr->device, reg);
68 69 70 71 72 73 74

	if (mp1_fw_flags & MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED_MASK)
		return true;

	return false;
}

75 76 77 78 79 80
/*
 * Check if SMC has responded to previous message.
 *
 * @param    smumgr  the address of the powerplay hardware manager.
 * @return   TRUE    SMC has responded, FALSE otherwise.
 */
81
static uint32_t vega10_wait_for_response(struct pp_hwmgr *hwmgr)
82 83
{
	uint32_t reg;
84
	uint32_t ret;
85 86 87 88

	reg = soc15_get_register_offset(MP1_HWID, 0,
			mmMP1_SMN_C2PMSG_90_BASE_IDX, mmMP1_SMN_C2PMSG_90);

89
	ret = phm_wait_for_register_unequal(hwmgr, reg,
90 91
			0, MP1_C2PMSG_90__CONTENT_MASK);

92 93 94
	if (ret)
		pr_err("No response from smu\n");

95
	return cgs_read_register(hwmgr->device, reg);
96 97
}

98 99 100 101 102 103
/*
 * Send a message to the SMC, and do not wait for its response.
 * @param    smumgr  the address of the powerplay hardware manager.
 * @param    msg the message to send.
 * @return   Always return 0.
 */
104
static int vega10_send_msg_to_smc_without_waiting(struct pp_hwmgr *hwmgr,
105 106 107 108 109 110
		uint16_t msg)
{
	uint32_t reg;

	reg = soc15_get_register_offset(MP1_HWID, 0,
			mmMP1_SMN_C2PMSG_66_BASE_IDX, mmMP1_SMN_C2PMSG_66);
111
	cgs_write_register(hwmgr->device, reg, msg);
112 113 114 115

	return 0;
}

116 117
/*
 * Send a message to the SMC, and wait for its response.
118
 * @param    hwmgr  the address of the powerplay hardware manager.
119 120 121
 * @param    msg the message to send.
 * @return   Always return 0.
 */
122
static int vega10_send_msg_to_smc(struct pp_hwmgr *hwmgr, uint16_t msg)
123 124
{
	uint32_t reg;
125
	uint32_t ret;
126

127
	vega10_wait_for_response(hwmgr);
128 129 130

	reg = soc15_get_register_offset(MP1_HWID, 0,
			mmMP1_SMN_C2PMSG_90_BASE_IDX, mmMP1_SMN_C2PMSG_90);
131
	cgs_write_register(hwmgr->device, reg, 0);
132

133
	vega10_send_msg_to_smc_without_waiting(hwmgr, msg);
134

135 136 137
	ret = vega10_wait_for_response(hwmgr);
	if (ret != 1)
		pr_err("Failed to send message: 0x%x, ret value: 0x%x\n", msg, ret);
138 139 140 141

	return 0;
}

142
/*
143
 * Send a message to the SMC with parameter
144
 * @param    hwmgr:  the address of the powerplay hardware manager.
145 146
 * @param    msg: the message to send.
 * @param    parameter: the parameter to send
147
 * @return   Always return 0.
148
 */
149
static int vega10_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr,
150 151 152
		uint16_t msg, uint32_t parameter)
{
	uint32_t reg;
153
	uint32_t ret;
154

155
	vega10_wait_for_response(hwmgr);
156 157 158

	reg = soc15_get_register_offset(MP1_HWID, 0,
			mmMP1_SMN_C2PMSG_90_BASE_IDX, mmMP1_SMN_C2PMSG_90);
159
	cgs_write_register(hwmgr->device, reg, 0);
160 161 162

	reg = soc15_get_register_offset(MP1_HWID, 0,
			mmMP1_SMN_C2PMSG_82_BASE_IDX, mmMP1_SMN_C2PMSG_82);
163
	cgs_write_register(hwmgr->device, reg, parameter);
164

165
	vega10_send_msg_to_smc_without_waiting(hwmgr, msg);
166

167 168
	ret = vega10_wait_for_response(hwmgr);
	if (ret != 1)
169
		pr_err("Failed message: 0x%x, input parameter: 0x%x, error code: 0x%x\n", msg, parameter, ret);
170 171 172 173

	return 0;
}

174
static int vega10_get_argument(struct pp_hwmgr *hwmgr)
175 176 177 178 179 180
{
	uint32_t reg;

	reg = soc15_get_register_offset(MP1_HWID, 0,
			mmMP1_SMN_C2PMSG_82_BASE_IDX, mmMP1_SMN_C2PMSG_82);

181
	return cgs_read_register(hwmgr->device, reg);
182 183
}

184
static int vega10_copy_table_from_smc(struct pp_hwmgr *hwmgr,
185 186 187
		uint8_t *table, int16_t table_id)
{
	struct vega10_smumgr *priv =
188
			(struct vega10_smumgr *)(hwmgr->smu_backend);
189 190

	PP_ASSERT_WITH_CODE(table_id < MAX_SMU_TABLE,
191
			"Invalid SMU Table ID!", return -EINVAL);
192
	PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].version != 0,
193
			"Invalid SMU Table version!", return -EINVAL);
194
	PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].size != 0,
195
			"Invalid SMU Table Length!", return -EINVAL);
196
	vega10_send_msg_to_smc_with_parameter(hwmgr,
197
			PPSMC_MSG_SetDriverDramAddrHigh,
198
			upper_32_bits(priv->smu_tables.entry[table_id].mc_addr));
199
	vega10_send_msg_to_smc_with_parameter(hwmgr,
200
			PPSMC_MSG_SetDriverDramAddrLow,
201
			lower_32_bits(priv->smu_tables.entry[table_id].mc_addr));
202
	vega10_send_msg_to_smc_with_parameter(hwmgr,
203
			PPSMC_MSG_TransferTableSmu2Dram,
204
			priv->smu_tables.entry[table_id].table_id);
205 206 207 208 209 210 211

	memcpy(table, priv->smu_tables.entry[table_id].table,
			priv->smu_tables.entry[table_id].size);

	return 0;
}

212
static int vega10_copy_table_to_smc(struct pp_hwmgr *hwmgr,
213 214 215
		uint8_t *table, int16_t table_id)
{
	struct vega10_smumgr *priv =
216
			(struct vega10_smumgr *)(hwmgr->smu_backend);
217 218

	PP_ASSERT_WITH_CODE(table_id < MAX_SMU_TABLE,
219
			"Invalid SMU Table ID!", return -EINVAL);
220
	PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].version != 0,
221
			"Invalid SMU Table version!", return -EINVAL);
222
	PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].size != 0,
223
			"Invalid SMU Table Length!", return -EINVAL);
224 225 226 227

	memcpy(priv->smu_tables.entry[table_id].table, table,
			priv->smu_tables.entry[table_id].size);

228
	vega10_send_msg_to_smc_with_parameter(hwmgr,
229
			PPSMC_MSG_SetDriverDramAddrHigh,
230
			upper_32_bits(priv->smu_tables.entry[table_id].mc_addr));
231
	vega10_send_msg_to_smc_with_parameter(hwmgr,
232
			PPSMC_MSG_SetDriverDramAddrLow,
233
			lower_32_bits(priv->smu_tables.entry[table_id].mc_addr));
234
	vega10_send_msg_to_smc_with_parameter(hwmgr,
235
			PPSMC_MSG_TransferTableDram2Smu,
236
			priv->smu_tables.entry[table_id].table_id);
237 238 239 240

	return 0;
}

241
int vega10_enable_smc_features(struct pp_hwmgr *hwmgr,
242 243 244 245 246
		bool enable, uint32_t feature_mask)
{
	int msg = enable ? PPSMC_MSG_EnableSmuFeatures :
			PPSMC_MSG_DisableSmuFeatures;

247
	return vega10_send_msg_to_smc_with_parameter(hwmgr,
248 249 250
			msg, feature_mask);
}

251
static int vega10_get_smc_features(struct pp_hwmgr *hwmgr,
252 253
		uint32_t *features_enabled)
{
254 255 256
	if (features_enabled == NULL)
		return -EINVAL;

257
	vega10_send_msg_to_smc(hwmgr, PPSMC_MSG_GetEnabledSmuFeatures);
258 259
	*features_enabled = vega10_get_argument(hwmgr);

260
	return 0;
261 262
}

263 264 265 266 267 268 269 270 271 272 273 274
static bool vega10_is_dpm_running(struct pp_hwmgr *hwmgr)
{
	uint32_t features_enabled = 0;

	vega10_get_smc_features(hwmgr, &features_enabled);

	if (features_enabled & SMC_DPM_FEATURES)
		return true;
	else
		return false;
}

275
static int vega10_set_tools_address(struct pp_hwmgr *hwmgr)
276 277
{
	struct vega10_smumgr *priv =
278
			(struct vega10_smumgr *)(hwmgr->smu_backend);
279

280
	if (priv->smu_tables.entry[TOOLSTABLE].mc_addr) {
281
		vega10_send_msg_to_smc_with_parameter(hwmgr,
282
				PPSMC_MSG_SetToolsDramAddrHigh,
283
				upper_32_bits(priv->smu_tables.entry[TOOLSTABLE].mc_addr));
284 285
		vega10_send_msg_to_smc_with_parameter(hwmgr,
				PPSMC_MSG_SetToolsDramAddrLow,
286
				lower_32_bits(priv->smu_tables.entry[TOOLSTABLE].mc_addr));
287 288 289 290
	}
	return 0;
}

291
static int vega10_verify_smc_interface(struct pp_hwmgr *hwmgr)
292 293
{
	uint32_t smc_driver_if_version;
294
	struct amdgpu_device *adev = hwmgr->adev;
295 296
	uint32_t dev_id;
	uint32_t rev_id;
297

298
	PP_ASSERT_WITH_CODE(!vega10_send_msg_to_smc(hwmgr,
299 300
			PPSMC_MSG_GetDriverIfVersion),
			"Attempt to get SMC IF Version Number Failed!",
301
			return -EINVAL);
302
	smc_driver_if_version = vega10_get_argument(hwmgr);
303

304 305
	dev_id = adev->pdev->device;
	rev_id = adev->pdev->revision;
306 307 308 309 310 311

	if (!((dev_id == 0x687f) &&
		((rev_id == 0xc0) ||
		(rev_id == 0xc1) ||
		(rev_id == 0xc3)))) {
		if (smc_driver_if_version != SMU9_DRIVER_IF_VERSION) {
312 313
			pr_err("Your firmware(0x%x) doesn't match SMU9_DRIVER_IF_VERSION(0x%x). Please update your firmware!\n",
			       smc_driver_if_version, SMU9_DRIVER_IF_VERSION);
314 315
			return -EINVAL;
		}
316
	}
317 318 319 320

	return 0;
}

321
static int vega10_smu_init(struct pp_hwmgr *hwmgr)
322 323
{
	struct vega10_smumgr *priv;
324
	unsigned long tools_size;
325 326 327
	int ret;
	struct cgs_firmware_info info = {0};

328
	ret = cgs_get_firmware_info(hwmgr->device,
329
				    CGS_UCODE_ID_SMU,
330 331 332 333 334 335 336 337 338
				    &info);
	if (ret || !info.kptr)
		return -EINVAL;

	priv = kzalloc(sizeof(struct vega10_smumgr), GFP_KERNEL);

	if (!priv)
		return -ENOMEM;

339
	hwmgr->smu_backend = priv;
340 341

	/* allocate space for pptable */
342
	ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev,
343 344
			sizeof(PPTable_t),
			PAGE_SIZE,
345
			AMDGPU_GEM_DOMAIN_VRAM,
346 347 348
			&priv->smu_tables.entry[PPTABLE].handle,
			&priv->smu_tables.entry[PPTABLE].mc_addr,
			&priv->smu_tables.entry[PPTABLE].table);
349
	if (ret)
350
		goto free_backend;
351 352 353 354 355 356

	priv->smu_tables.entry[PPTABLE].version = 0x01;
	priv->smu_tables.entry[PPTABLE].size = sizeof(PPTable_t);
	priv->smu_tables.entry[PPTABLE].table_id = TABLE_PPTABLE;

	/* allocate space for watermarks table */
357
	ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev,
358 359
			sizeof(Watermarks_t),
			PAGE_SIZE,
360
			AMDGPU_GEM_DOMAIN_VRAM,
361 362 363
			&priv->smu_tables.entry[WMTABLE].handle,
			&priv->smu_tables.entry[WMTABLE].mc_addr,
			&priv->smu_tables.entry[WMTABLE].table);
364 365 366

	if (ret)
		goto err0;
367 368 369 370 371 372

	priv->smu_tables.entry[WMTABLE].version = 0x01;
	priv->smu_tables.entry[WMTABLE].size = sizeof(Watermarks_t);
	priv->smu_tables.entry[WMTABLE].table_id = TABLE_WATERMARKS;

	/* allocate space for AVFS table */
373
	ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev,
374 375
			sizeof(AvfsTable_t),
			PAGE_SIZE,
376
			AMDGPU_GEM_DOMAIN_VRAM,
377 378 379
			&priv->smu_tables.entry[AVFSTABLE].handle,
			&priv->smu_tables.entry[AVFSTABLE].mc_addr,
			&priv->smu_tables.entry[AVFSTABLE].table);
380 381 382

	if (ret)
		goto err1;
383 384 385 386 387

	priv->smu_tables.entry[AVFSTABLE].version = 0x01;
	priv->smu_tables.entry[AVFSTABLE].size = sizeof(AvfsTable_t);
	priv->smu_tables.entry[AVFSTABLE].table_id = TABLE_AVFS;

388
	tools_size = 0x19000;
389
	if (tools_size) {
390
		ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev,
391 392
				tools_size,
				PAGE_SIZE,
393
				AMDGPU_GEM_DOMAIN_VRAM,
394 395 396
				&priv->smu_tables.entry[TOOLSTABLE].handle,
				&priv->smu_tables.entry[TOOLSTABLE].mc_addr,
				&priv->smu_tables.entry[TOOLSTABLE].table);
397 398 399 400 401
		if (ret)
			goto err2;
		priv->smu_tables.entry[TOOLSTABLE].version = 0x01;
		priv->smu_tables.entry[TOOLSTABLE].size = tools_size;
		priv->smu_tables.entry[TOOLSTABLE].table_id = TABLE_PMSTATUSLOG;
402 403
	}

404
	/* allocate space for AVFS Fuse table */
405
	ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev,
406 407
			sizeof(AvfsFuseOverride_t),
			PAGE_SIZE,
408
			AMDGPU_GEM_DOMAIN_VRAM,
409 410 411
			&priv->smu_tables.entry[AVFSFUSETABLE].handle,
			&priv->smu_tables.entry[AVFSFUSETABLE].mc_addr,
			&priv->smu_tables.entry[AVFSFUSETABLE].table);
412 413
	if (ret)
		goto err3;
414 415 416 417

	priv->smu_tables.entry[AVFSFUSETABLE].version = 0x01;
	priv->smu_tables.entry[AVFSFUSETABLE].size = sizeof(AvfsFuseOverride_t);
	priv->smu_tables.entry[AVFSFUSETABLE].table_id = TABLE_AVFS_FUSE_OVERRIDE;
418

419

420
	return 0;
421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438

err3:
	if (priv->smu_tables.entry[TOOLSTABLE].table)
		amdgpu_bo_free_kernel(&priv->smu_tables.entry[TOOLSTABLE].handle,
				&priv->smu_tables.entry[TOOLSTABLE].mc_addr,
				&priv->smu_tables.entry[TOOLSTABLE].table);
err2:
	amdgpu_bo_free_kernel(&priv->smu_tables.entry[AVFSTABLE].handle,
				&priv->smu_tables.entry[AVFSTABLE].mc_addr,
				&priv->smu_tables.entry[AVFSTABLE].table);
err1:
	amdgpu_bo_free_kernel(&priv->smu_tables.entry[WMTABLE].handle,
				&priv->smu_tables.entry[WMTABLE].mc_addr,
				&priv->smu_tables.entry[WMTABLE].table);
err0:
	amdgpu_bo_free_kernel(&priv->smu_tables.entry[PPTABLE].handle,
			&priv->smu_tables.entry[PPTABLE].mc_addr,
			&priv->smu_tables.entry[PPTABLE].table);
439 440 441
free_backend:
	kfree(hwmgr->smu_backend);

442
	return -EINVAL;
443 444
}

445
static int vega10_smu_fini(struct pp_hwmgr *hwmgr)
446 447
{
	struct vega10_smumgr *priv =
448
			(struct vega10_smumgr *)(hwmgr->smu_backend);
449 450

	if (priv) {
451 452 453 454 455 456 457 458 459
		amdgpu_bo_free_kernel(&priv->smu_tables.entry[PPTABLE].handle,
				&priv->smu_tables.entry[PPTABLE].mc_addr,
				&priv->smu_tables.entry[PPTABLE].table);
		amdgpu_bo_free_kernel(&priv->smu_tables.entry[WMTABLE].handle,
					&priv->smu_tables.entry[WMTABLE].mc_addr,
					&priv->smu_tables.entry[WMTABLE].table);
		amdgpu_bo_free_kernel(&priv->smu_tables.entry[AVFSTABLE].handle,
					&priv->smu_tables.entry[AVFSTABLE].mc_addr,
					&priv->smu_tables.entry[AVFSTABLE].table);
460
		if (priv->smu_tables.entry[TOOLSTABLE].table)
461 462 463 464 465 466
			amdgpu_bo_free_kernel(&priv->smu_tables.entry[TOOLSTABLE].handle,
					&priv->smu_tables.entry[TOOLSTABLE].mc_addr,
					&priv->smu_tables.entry[TOOLSTABLE].table);
		amdgpu_bo_free_kernel(&priv->smu_tables.entry[AVFSFUSETABLE].handle,
					&priv->smu_tables.entry[AVFSFUSETABLE].mc_addr,
					&priv->smu_tables.entry[AVFSFUSETABLE].table);
467 468
		kfree(hwmgr->smu_backend);
		hwmgr->smu_backend = NULL;
469 470 471 472
	}
	return 0;
}

473
static int vega10_start_smu(struct pp_hwmgr *hwmgr)
474
{
475 476 477
	if (!vega10_is_smc_ram_running(hwmgr))
		return -EINVAL;

478
	PP_ASSERT_WITH_CODE(!vega10_verify_smc_interface(hwmgr),
479
			"Failed to verify SMC interface!",
480
			return -EINVAL);
481

482
	vega10_set_tools_address(hwmgr);
483

484 485 486
	return 0;
}

487 488 489 490 491 492 493 494 495 496 497 498
static int vega10_smc_table_manager(struct pp_hwmgr *hwmgr, uint8_t *table, uint16_t table_id, bool rw)
{
	int ret;

	if (rw)
		ret = vega10_copy_table_from_smc(hwmgr, table, table_id);
	else
		ret = vega10_copy_table_to_smc(hwmgr, table, table_id);

	return ret;
}

499 500 501 502 503 504 505 506 507
const struct pp_smumgr_func vega10_smu_funcs = {
	.smu_init = &vega10_smu_init,
	.smu_fini = &vega10_smu_fini,
	.start_smu = &vega10_start_smu,
	.request_smu_load_specific_fw = NULL,
	.send_msg_to_smc = &vega10_send_msg_to_smc,
	.send_msg_to_smc_with_parameter = &vega10_send_msg_to_smc_with_parameter,
	.download_pptable_settings = NULL,
	.upload_pptable_settings = NULL,
508
	.is_dpm_running = vega10_is_dpm_running,
509 510
	.get_argument = vega10_get_argument,
	.smc_table_manager = vega10_smc_table_manager,
511
};