Blob Blame History Raw
From: Kenneth Feng <kenneth.feng@amd.com>
Date: Tue, 20 Mar 2018 14:02:07 +0800
Subject: drm/amd/powerplay: Return per DPM level clock
Git-commit: 7436854ebd4166a7c4b023031f62f24f1174d2d2
Patch-mainline: v4.17-rc1
References: FATE#326289 FATE#326079 FATE#326049 FATE#322398 FATE#326166

Add change to return per DPM level clock in DAL interface

Signed-off-by: Kenneth Feng <kenneth.feng@amd.com>
Reviewed-by: Evan Quan <evan.quan@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Acked-by: Petr Tesarik <ptesarik@suse.com>
---
 drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c |  372 +++++++++++++++------
 drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.h |    2 
 2 files changed, 277 insertions(+), 97 deletions(-)

--- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c
@@ -483,6 +483,56 @@ static void vega12_init_dpm_state(struct
 	dpm_state->hard_max_level = 0xff;
 }
 
+static int vega12_get_number_dpm_level(struct pp_hwmgr *hwmgr,
+		PPCLK_e clkID, uint32_t *num_dpm_level)
+{
+	int result;
+	/*
+	 * SMU expects the Clock ID to be in the top 16 bits.
+	 * Lower 16 bits specify the level however 0xFF is a
+	 * special argument the returns the total number of levels
+	 */
+	PP_ASSERT_WITH_CODE(smum_send_msg_to_smc_with_parameter(hwmgr,
+		PPSMC_MSG_GetDpmFreqByIndex, (clkID << 16 | 0xFF)) == 0,
+		"[GetNumberDpmLevel] Failed to get DPM levels from SMU for CLKID!",
+		return -EINVAL);
+
+	result = vega12_read_arg_from_smc(hwmgr, num_dpm_level);
+
+	PP_ASSERT_WITH_CODE(*num_dpm_level < MAX_REGULAR_DPM_NUMBER,
+		"[GetNumberDPMLevel] Number of DPM levels is greater than limit",
+		return -EINVAL);
+
+	PP_ASSERT_WITH_CODE(*num_dpm_level != 0,
+		"[GetNumberDPMLevel] Number of CLK Levels is zero!",
+		return -EINVAL);
+
+	return result;
+}
+
+static int vega12_get_dpm_frequency_by_index(struct pp_hwmgr *hwmgr,
+		PPCLK_e clkID, uint32_t index, uint32_t *clock)
+{
+	int result;
+
+	/*
+	 *SMU expects the Clock ID to be in the top 16 bits.
+	 *Lower 16 bits specify the level
+	 */
+	PP_ASSERT_WITH_CODE(smum_send_msg_to_smc_with_parameter(hwmgr,
+		PPSMC_MSG_GetDpmFreqByIndex, (clkID << 16 | index)) == 0,
+		"[GetDpmFrequencyByIndex] Failed to get dpm frequency from SMU!",
+		return -EINVAL);
+
+	result = vega12_read_arg_from_smc(hwmgr, clock);
+
+	PP_ASSERT_WITH_CODE(*clock != 0,
+		"[GetDPMFrequencyByIndex] Failed to get dpm frequency by index.!",
+		return -EINVAL);
+
+	return result;
+}
+
 /*
  * This function is to initialize all DPM state tables
  * for SMU based on the dependency table.
@@ -493,43 +543,214 @@ static void vega12_init_dpm_state(struct
  */
 static int vega12_setup_default_dpm_tables(struct pp_hwmgr *hwmgr)
 {
+	uint32_t num_levels, i, clock;
+
 	struct vega12_hwmgr *data =
 			(struct vega12_hwmgr *)(hwmgr->backend);
+
 	struct vega12_single_dpm_table *dpm_table;
 
 	memset(&data->dpm_table, 0, sizeof(data->dpm_table));
 
-	/* Initialize Sclk DPM table based on allow Sclk values */
+	/* Initialize Sclk DPM and SOC DPM table based on allow Sclk values */
 	dpm_table = &(data->dpm_table.soc_table);
+
+	PP_ASSERT_WITH_CODE(vega12_get_number_dpm_level(hwmgr, PPCLK_SOCCLK,
+		&num_levels) == 0,
+		"[SetupDefaultDPMTables] Failed to get DPM levels from SMU for SOCCLK!",
+		return -EINVAL);
+
+	dpm_table->count = num_levels;
+
+	for (i = 0; i < num_levels; i++) {
+		PP_ASSERT_WITH_CODE(vega12_get_dpm_frequency_by_index(hwmgr,
+			PPCLK_SOCCLK, i, &clock) == 0,
+			"[SetupDefaultDPMTables] Failed to get DPM levels from SMU for SOCCLK!",
+			return -EINVAL);
+
+		dpm_table->dpm_levels[i].value = clock;
+	}
+
 	vega12_init_dpm_state(&(dpm_table->dpm_state));
 
 	dpm_table = &(data->dpm_table.gfx_table);
-	vega12_init_dpm_state(&(dpm_table->dpm_state));
 
-	/* Initialize Mclk DPM table based on allow Mclk values */
+	PP_ASSERT_WITH_CODE(vega12_get_number_dpm_level(hwmgr, PPCLK_GFXCLK,
+		&num_levels) == 0,
+		"[SetupDefaultDPMTables] Failed to get DPM levels from SMU for GFXCLK!",
+		return -EINVAL);
+
+	dpm_table->count = num_levels;
+	for (i = 0; i < num_levels; i++) {
+		PP_ASSERT_WITH_CODE(vega12_get_dpm_frequency_by_index(hwmgr,
+			PPCLK_GFXCLK, i, &clock) == 0,
+			"[SetupDefaultDPMTables] Failed to get DPM levels from SMU for GFXCLK!",
+			return -EINVAL);
+
+		dpm_table->dpm_levels[i].value = clock;
+	}
+
+	vega12_init_dpm_state(&(dpm_table->dpm_state));
+    /* Initialize Mclk DPM table based on allow Mclk values */
 	dpm_table = &(data->dpm_table.mem_table);
+
+	PP_ASSERT_WITH_CODE(vega12_get_number_dpm_level(hwmgr, PPCLK_UCLK,
+		&num_levels) == 0,
+		"[SetupDefaultDPMTables] Failed to get DPM levels from SMU for UCLK!",
+		return -EINVAL);
+
+	dpm_table->count = num_levels;
+
+	for (i = 0; i < num_levels; i++) {
+		PP_ASSERT_WITH_CODE(vega12_get_dpm_frequency_by_index(hwmgr,
+			PPCLK_UCLK, i, &clock) == 0,
+			"[SetupDefaultDPMTables] Failed to get DPM levels from SMU for UCLK!",
+			return -EINVAL);
+
+		dpm_table->dpm_levels[i].value = clock;
+	}
+
 	vega12_init_dpm_state(&(dpm_table->dpm_state));
 
 	dpm_table = &(data->dpm_table.eclk_table);
+
+	PP_ASSERT_WITH_CODE(vega12_get_number_dpm_level(hwmgr, PPCLK_ECLK,
+		&num_levels) == 0,
+		"[SetupDefaultDPMTables] Failed to get DPM levels from SMU for ECLK!",
+		return -EINVAL);
+
+	dpm_table->count = num_levels;
+
+	for (i = 0; i < num_levels; i++) {
+		PP_ASSERT_WITH_CODE(vega12_get_dpm_frequency_by_index(hwmgr,
+		PPCLK_ECLK, i, &clock) == 0,
+		"[SetupDefaultDPMTables] Failed to get DPM levels from SMU for ECLK!",
+		return -EINVAL);
+
+		dpm_table->dpm_levels[i].value = clock;
+	}
+
 	vega12_init_dpm_state(&(dpm_table->dpm_state));
 
 	dpm_table = &(data->dpm_table.vclk_table);
+
+	PP_ASSERT_WITH_CODE(vega12_get_number_dpm_level(hwmgr, PPCLK_VCLK,
+		&num_levels) == 0,
+		"[SetupDefaultDPMTables] Failed to get DPM levels from SMU for VCLK!",
+		return -EINVAL);
+
+	dpm_table->count = num_levels;
+
+	for (i = 0; i < num_levels; i++) {
+		PP_ASSERT_WITH_CODE(vega12_get_dpm_frequency_by_index(hwmgr,
+			PPCLK_VCLK, i, &clock) == 0,
+			"[SetupDefaultDPMTables] Failed to get DPM levels from SMU for VCLK!",
+			return -EINVAL);
+
+		dpm_table->dpm_levels[i].value = clock;
+	}
+
 	vega12_init_dpm_state(&(dpm_table->dpm_state));
 
 	dpm_table = &(data->dpm_table.dclk_table);
+
+	PP_ASSERT_WITH_CODE(vega12_get_number_dpm_level(hwmgr, PPCLK_DCLK,
+		&num_levels) == 0,
+		"[SetupDefaultDPMTables] Failed to get DPM levels from SMU for DCLK!",
+		return -EINVAL);
+
+	dpm_table->count = num_levels;
+
+	for (i = 0; i < num_levels; i++) {
+		PP_ASSERT_WITH_CODE(vega12_get_dpm_frequency_by_index(hwmgr,
+			PPCLK_DCLK, i, &clock) == 0,
+		"[SetupDefaultDPMTables] Failed to get DPM levels from SMU for DCLK!",
+		return -EINVAL);
+
+		dpm_table->dpm_levels[i].value = clock;
+	}
+
 	vega12_init_dpm_state(&(dpm_table->dpm_state));
 
 	/* Assume there is no headless Vega12 for now */
 	dpm_table = &(data->dpm_table.dcef_table);
+
+	PP_ASSERT_WITH_CODE(vega12_get_number_dpm_level(hwmgr,
+		PPCLK_DCEFCLK, &num_levels) == 0,
+		"[SetupDefaultDPMTables] Failed to get DPM levels from SMU for DCEFCLK!",
+		return -EINVAL);
+
+	dpm_table->count = num_levels;
+
+	for (i = 0; i < num_levels; i++) {
+		PP_ASSERT_WITH_CODE(vega12_get_dpm_frequency_by_index(hwmgr,
+			PPCLK_DCEFCLK, i, &clock) == 0,
+			"[SetupDefaultDPMTables] Failed to get DPM levels from SMU for DCEFCLK!",
+			return -EINVAL);
+
+		dpm_table->dpm_levels[i].value = clock;
+	}
+
 	vega12_init_dpm_state(&(dpm_table->dpm_state));
 
 	dpm_table = &(data->dpm_table.pixel_table);
+
+	PP_ASSERT_WITH_CODE(vega12_get_number_dpm_level(hwmgr,
+		PPCLK_PIXCLK, &num_levels) == 0,
+		"[SetupDefaultDPMTables] Failed to get DPM levels from SMU for PIXCLK!",
+		return -EINVAL);
+
+	dpm_table->count = num_levels;
+
+	for (i = 0; i < num_levels; i++) {
+		PP_ASSERT_WITH_CODE(vega12_get_dpm_frequency_by_index(hwmgr,
+			PPCLK_PIXCLK, i, &clock) == 0,
+			"[SetupDefaultDPMTables] Failed to get DPM levels from SMU for PIXCLK!",
+			return -EINVAL);
+
+		dpm_table->dpm_levels[i].value = clock;
+	}
+
 	vega12_init_dpm_state(&(dpm_table->dpm_state));
 
 	dpm_table = &(data->dpm_table.display_table);
+
+	PP_ASSERT_WITH_CODE(vega12_get_number_dpm_level(hwmgr,
+		PPCLK_DISPCLK, &num_levels) == 0,
+		"[SetupDefaultDPMTables] Failed to get DPM levels from SMU for DISPCLK!",
+		return -EINVAL);
+
+	dpm_table->count = num_levels;
+
+	for (i = 0; i < num_levels; i++) {
+		PP_ASSERT_WITH_CODE(vega12_get_dpm_frequency_by_index(hwmgr,
+			PPCLK_DISPCLK, i, &clock) == 0,
+			"[SetupDefaultDPMTables] Failed to get DPM levels from SMU for DISPCLK!",
+			return -EINVAL);
+
+		dpm_table->dpm_levels[i].value = clock;
+	}
+
 	vega12_init_dpm_state(&(dpm_table->dpm_state));
 
 	dpm_table = &(data->dpm_table.phy_table);
+
+	PP_ASSERT_WITH_CODE(vega12_get_number_dpm_level(hwmgr,
+		PPCLK_PHYCLK, &num_levels) == 0,
+		"[SetupDefaultDPMTables] Failed to get DPM levels from SMU for PHYCLK!",
+		return -EINVAL);
+
+	dpm_table->count = num_levels;
+
+	for (i = 0; i < num_levels; i++) {
+		PP_ASSERT_WITH_CODE(vega12_get_dpm_frequency_by_index(hwmgr,
+			PPCLK_PHYCLK, i, &clock) == 0,
+			"[SetupDefaultDPMTables] Failed to get DPM levels from SMU for PHYCLK!",
+			return -EINVAL);
+
+		dpm_table->dpm_levels[i].value = clock;
+	}
+
 	vega12_init_dpm_state(&(dpm_table->dpm_state));
 
 	/* save a copy of the default DPM table */
@@ -586,11 +807,6 @@ static int vega12_init_smc_table(struct
 	struct phm_ppt_v3_information *pptable_information =
 		(struct phm_ppt_v3_information *)hwmgr->pptable;
 
-	result = vega12_setup_default_dpm_tables(hwmgr);
-	PP_ASSERT_WITH_CODE(!result,
-			"Failed to setup default DPM tables!",
-			return result);
-
 	result = pp_atomfwctrl_get_vbios_bootup_values(hwmgr, &boot_up_values);
 	if (!result) {
 		data->vbios_boot_state.vddc     = boot_up_values.usVddc;
@@ -731,6 +947,10 @@ static int vega12_enable_dpm_tasks(struc
 			"Failed to power control set level!",
 			return result);
 
+	result = vega12_setup_default_dpm_tables(hwmgr);
+	PP_ASSERT_WITH_CODE(!result,
+			"Failed to setup default DPM tables!",
+			return result);
 	return result;
 }
 
@@ -1633,33 +1853,25 @@ static int vega12_get_sclks(struct pp_hw
 		struct pp_clock_levels_with_latency *clocks)
 {
 	struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend);
+	uint32_t ucount;
 	int i;
-	uint32_t min, max, increments;
+	struct vega12_single_dpm_table *dpm_table;
 
 	if (!data->smu_features[GNLD_DPM_GFXCLK].enabled)
 		return -1;
 
-	PP_ASSERT_WITH_CODE(
-		vega12_get_clock_ranges(hwmgr, &min, PPCLK_GFXCLK, false) == 0,
-		"[GetSclks]: fail to get min PPCLK_GFXCLK\n",
-		return -1);
-	PP_ASSERT_WITH_CODE(
-		vega12_get_clock_ranges(hwmgr, &max, PPCLK_GFXCLK, true) == 0,
-		"[GetSclks]: fail to get max PPCLK_GFXCLK\n",
-		return -1);
+	dpm_table = &(data->dpm_table.gfx_table);
+	ucount = (dpm_table->count > VG12_PSUEDO_NUM_GFXCLK_DPM_LEVELS) ?
+		VG12_PSUEDO_NUM_GFXCLK_DPM_LEVELS : dpm_table->count;
 
-	clocks->data[0].clocks_in_khz = min * 100;
-	increments = (max - min) / (VG12_PSUEDO_NUM_GFXCLK_DPM_LEVELS - 1);
+	for (i = 0; i < ucount; i++) {
+		clocks->data[i].clocks_in_khz =
+			dpm_table->dpm_levels[i].value * 100;
 
-	for (i = 1; i < (VG12_PSUEDO_NUM_GFXCLK_DPM_LEVELS - 1); i++) {
-		if ((min + (increments * i)) != 0) {
-			clocks->data[i].clocks_in_khz =
-				(min + increments * i) * 100;
-			clocks->data[i].latency_in_us = 0;
-		}
+		clocks->data[i].latency_in_us = 0;
 	}
-	clocks->data[i].clocks_in_khz = max * 100;
-	clocks->num_levels = i + 1;
+
+	clocks->num_levels = ucount;
 
 	return 0;
 }
@@ -1674,44 +1886,26 @@ static int vega12_get_memclocks(struct p
 		struct pp_clock_levels_with_latency *clocks)
 {
 	struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend);
-	uint32_t min, max, increments;
+	uint32_t ucount;
 	int i;
-
+	struct vega12_single_dpm_table *dpm_table;
 	if (!data->smu_features[GNLD_DPM_UCLK].enabled)
 		return -1;
 
-	PP_ASSERT_WITH_CODE(
-		vega12_get_clock_ranges(hwmgr, &min, PPCLK_UCLK, false) == 0,
-		"[GetMclks]: fail to get min PPCLK_UCLK\n",
-		return -1);
-	PP_ASSERT_WITH_CODE(
-		vega12_get_clock_ranges(hwmgr, &max, PPCLK_UCLK, true) == 0,
-		"[GetMclks]: fail to get max PPCLK_UCLK\n",
-		return -1);
+	dpm_table = &(data->dpm_table.mem_table);
+	ucount = (dpm_table->count > VG12_PSUEDO_NUM_UCLK_DPM_LEVELS) ?
+		VG12_PSUEDO_NUM_UCLK_DPM_LEVELS : dpm_table->count;
 
-	clocks->data[0].clocks_in_khz = min * 100;
-	clocks->data[0].latency_in_us =
-		data->mclk_latency_table.entries[0].latency =
-		vega12_get_mem_latency(hwmgr, min);
-
-	increments = (max - min) / (VG12_PSUEDO_NUM_UCLK_DPM_LEVELS - 1);
-
-	for (i = 1; i < (VG12_PSUEDO_NUM_UCLK_DPM_LEVELS - 1); i++) {
-		if ((min + (increments * i)) != 0) {
-			clocks->data[i].clocks_in_khz =
-				(min + (increments * i)) * 100;
-			clocks->data[i].latency_in_us =
-				data->mclk_latency_table.entries[i].latency =
-				vega12_get_mem_latency(hwmgr, min + increments * i);
-		}
-	}
+	for (i = 0; i < ucount; i++) {
+		clocks->data[i].clocks_in_khz =
+			dpm_table->dpm_levels[i].value * 100;
 
-	clocks->data[i].clocks_in_khz = max * 100;
-	clocks->data[i].latency_in_us =
-		data->mclk_latency_table.entries[i].latency =
-		vega12_get_mem_latency(hwmgr, max);
+		clocks->data[i].latency_in_us =
+			data->mclk_latency_table.entries[i].latency =
+			vega12_get_mem_latency(hwmgr, dpm_table->dpm_levels[i].value);
+	}
 
-	clocks->num_levels = data->mclk_latency_table.count = i + 1;
+	clocks->num_levels = data->mclk_latency_table.count = ucount;
 
 	return 0;
 }
@@ -1720,33 +1914,26 @@ static int vega12_get_dcefclocks(struct
 		struct pp_clock_levels_with_latency *clocks)
 {
 	struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend);
+	uint32_t ucount;
 	int i;
-	uint32_t min, max, increments;
+	struct vega12_single_dpm_table *dpm_table;
 
 	if (!data->smu_features[GNLD_DPM_DCEFCLK].enabled)
 		return -1;
 
-	PP_ASSERT_WITH_CODE(
-		vega12_get_clock_ranges(hwmgr, &min, PPCLK_DCEFCLK, false) == 0,
-		"[GetDcfclocks]: fail to get min PPCLK_DCEFCLK\n",
-		return -1);
-	PP_ASSERT_WITH_CODE(
-		vega12_get_clock_ranges(hwmgr, &max, PPCLK_DCEFCLK, true) == 0,
-		"[GetDcfclocks]: fail to get max PPCLK_DCEFCLK\n",
-		return -1);
 
-	clocks->data[0].clocks_in_khz = min * 100;
-	increments = (max - min) / (VG12_PSUEDO_NUM_DCEFCLK_DPM_LEVELS - 1);
+	dpm_table = &(data->dpm_table.dcef_table);
+	ucount = (dpm_table->count > VG12_PSUEDO_NUM_DCEFCLK_DPM_LEVELS) ?
+		VG12_PSUEDO_NUM_DCEFCLK_DPM_LEVELS : dpm_table->count;
 
-	for (i = 1; i < (VG12_PSUEDO_NUM_DCEFCLK_DPM_LEVELS - 1); i++) {
-		if ((min + (increments * i)) != 0) {
-			clocks->data[i].clocks_in_khz =
-				(min + increments * i) * 100;
-			clocks->data[i].latency_in_us = 0;
-		}
+	for (i = 0; i < ucount; i++) {
+		clocks->data[i].clocks_in_khz =
+			dpm_table->dpm_levels[i].value * 100;
+
+		clocks->data[i].latency_in_us = 0;
 	}
-	clocks->data[i].clocks_in_khz = max * 100;
-	clocks->num_levels = i + 1;
+
+	clocks->num_levels = ucount;
 
 	return 0;
 }
@@ -1755,34 +1942,26 @@ static int vega12_get_socclocks(struct p
 		struct pp_clock_levels_with_latency *clocks)
 {
 	struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend);
+	uint32_t ucount;
 	int i;
-	uint32_t min, max, increments;
+	struct vega12_single_dpm_table *dpm_table;
 
 	if (!data->smu_features[GNLD_DPM_SOCCLK].enabled)
 		return -1;
 
-	PP_ASSERT_WITH_CODE(
-		vega12_get_clock_ranges(hwmgr, &min, PPCLK_SOCCLK, false) == 0,
-		"[GetSocclks]: fail to get min PPCLK_SOCCLK\n",
-		return -1);
-	PP_ASSERT_WITH_CODE(
-		vega12_get_clock_ranges(hwmgr, &max, PPCLK_SOCCLK, true) == 0,
-		"[GetSocclks]: fail to get max PPCLK_SOCCLK\n",
-		return -1);
 
-	clocks->data[0].clocks_in_khz = min * 100;
-	increments = (max - min) / (VG12_PSUEDO_NUM_SOCCLK_DPM_LEVELS - 1);
+	dpm_table = &(data->dpm_table.soc_table);
+	ucount = (dpm_table->count > VG12_PSUEDO_NUM_SOCCLK_DPM_LEVELS) ?
+		VG12_PSUEDO_NUM_SOCCLK_DPM_LEVELS : dpm_table->count;
+
+	for (i = 0; i < ucount; i++) {
+		clocks->data[i].clocks_in_khz =
+			dpm_table->dpm_levels[i].value * 100;
 
-	for (i = 1; i < (VG12_PSUEDO_NUM_SOCCLK_DPM_LEVELS - 1); i++) {
-		if ((min + (increments * i)) != 0) {
-			clocks->data[i].clocks_in_khz =
-				(min + increments * i) * 100;
-			clocks->data[i].latency_in_us = 0;
-		}
+		clocks->data[i].latency_in_us = 0;
 	}
 
-	clocks->data[i].clocks_in_khz = max * 100;
-	clocks->num_levels = i + 1;
+	clocks->num_levels = ucount;
 
 	return 0;
 
@@ -2374,6 +2553,7 @@ static int vega12_register_thermal_inter
 	return 0;
 }
 
+
 static const struct pp_hwmgr_func vega12_hwmgr_funcs = {
 	.backend_init = vega12_hwmgr_backend_init,
 	.backend_fini = vega12_hwmgr_backend_fini,
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.h
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.h
@@ -124,7 +124,7 @@ struct vega12_dpm_level {
 };
 
 #define VEGA12_MAX_DEEPSLEEP_DIVIDER_ID 5
-#define MAX_REGULAR_DPM_NUMBER 8
+#define MAX_REGULAR_DPM_NUMBER 16
 #define MAX_PCIE_CONF 2
 #define VEGA12_MINIMUM_ENGINE_CLOCK 2500