From b55ca3bdaf0bbfd14ad6619a991fbd324ae1ad4b Mon Sep 17 00:00:00 2001
From: Likun Gao <Likun.Gao@amd.com>
Date: Tue, 8 Jan 2019 14:18:02 +0800
Subject: [PATCH] drm/amd/powerplay: add function to store overdrive
 information for smu11

Add vega20_setup_od8_information function to store overdrive information
from powerplay_table to smu_table which will used when setting od8.

Signed-off-by: Likun Gao <Likun.Gao@amd.com>
Reviewed-by: Kevin Wang <kevin1.wang@amd.com>
Reviewed-by: Evan Quan <evan.quan@amd.com>
Acked-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/amd/powerplay/amdgpu_smu.c    | 15 ++++
 .../gpu/drm/amd/powerplay/inc/amdgpu_smu.h    |  4 +
 drivers/gpu/drm/amd/powerplay/vega20_ppt.c    | 86 ++++++++++++++++++-
 3 files changed, 104 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/powerplay/amdgpu_smu.c b/drivers/gpu/drm/amd/powerplay/amdgpu_smu.c
index e6915ef55b6ae..dded495374c9b 100644
--- a/drivers/gpu/drm/amd/powerplay/amdgpu_smu.c
+++ b/drivers/gpu/drm/amd/powerplay/amdgpu_smu.c
@@ -689,6 +689,21 @@ static int smu_hw_fini(void *handle)
 		table_context->max_sustainable_clocks = NULL;
 	}
 
+	if (table_context->od_feature_capabilities) {
+		kfree(table_context->od_feature_capabilities);
+		table_context->od_feature_capabilities = NULL;
+	}
+
+	if (table_context->od_settings_max) {
+		kfree(table_context->od_settings_max);
+		table_context->od_settings_max = NULL;
+	}
+
+	if (table_context->od_settings_min) {
+		kfree(table_context->od_settings_min);
+		table_context->od_settings_min = NULL;
+	}
+
 	ret = smu_fini_fb_allocations(smu);
 	if (ret)
 		return ret;
diff --git a/drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h
index 97d44a6681697..f2e2baace5172 100644
--- a/drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h
+++ b/drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h
@@ -192,6 +192,10 @@ struct smu_table_context
 	struct smu_table		memory_pool;
 	uint16_t                        software_shutdown_temp;
 	uint8_t                         thermal_controller_type;
+
+	uint8_t				*od_feature_capabilities;
+	uint32_t			*od_settings_max;
+	uint32_t			*od_settings_min;
 };
 
 struct smu_dpm_context {
diff --git a/drivers/gpu/drm/amd/powerplay/vega20_ppt.c b/drivers/gpu/drm/amd/powerplay/vega20_ppt.c
index ed0fbe755bfb7..df34953767e2d 100644
--- a/drivers/gpu/drm/amd/powerplay/vega20_ppt.c
+++ b/drivers/gpu/drm/amd/powerplay/vega20_ppt.c
@@ -146,10 +146,92 @@ static int vega20_allocate_dpm_context(struct smu_context *smu)
 	return 0;
 }
 
+static int vega20_setup_od8_information(struct smu_context *smu)
+{
+	ATOM_Vega20_POWERPLAYTABLE *powerplay_table = NULL;
+	struct smu_table_context *table_context = &smu->smu_table;
+
+	uint32_t od_feature_count, od_feature_array_size,
+		 od_setting_count, od_setting_array_size;
+
+	if (!table_context->power_play_table)
+		return -EINVAL;
+
+	powerplay_table = table_context->power_play_table;
+
+	if (powerplay_table->OverDrive8Table.ucODTableRevision == 1) {
+		/* Setup correct ODFeatureCount, and store ODFeatureArray from
+		 * powerplay table to od_feature_capabilities */
+		od_feature_count =
+			(le32_to_cpu(powerplay_table->OverDrive8Table.ODFeatureCount) >
+			 ATOM_VEGA20_ODFEATURE_COUNT) ?
+			ATOM_VEGA20_ODFEATURE_COUNT :
+			le32_to_cpu(powerplay_table->OverDrive8Table.ODFeatureCount);
+
+		od_feature_array_size = sizeof(uint8_t) * od_feature_count;
+
+		if (table_context->od_feature_capabilities)
+			return -EINVAL;
+
+		table_context->od_feature_capabilities = kzalloc(od_feature_array_size, GFP_KERNEL);
+		if (!table_context->od_feature_capabilities)
+			return -ENOMEM;
+
+		memcpy(table_context->od_feature_capabilities,
+		       &powerplay_table->OverDrive8Table.ODFeatureCapabilities,
+		       od_feature_array_size);
+
+		/* Setup correct ODSettingCount, and store ODSettingArray from
+		 * powerplay table to od_settings_max and od_setting_min */
+		od_setting_count =
+			(le32_to_cpu(powerplay_table->OverDrive8Table.ODSettingCount) >
+			 ATOM_VEGA20_ODSETTING_COUNT) ?
+			ATOM_VEGA20_ODSETTING_COUNT :
+			le32_to_cpu(powerplay_table->OverDrive8Table.ODSettingCount);
+
+		od_setting_array_size = sizeof(uint32_t) * od_setting_count;
+
+		if (table_context->od_settings_max)
+			return -EINVAL;
+
+		table_context->od_settings_max = kzalloc(od_setting_array_size, GFP_KERNEL);
+
+		if (!table_context->od_settings_max) {
+			kfree(table_context->od_feature_capabilities);
+			table_context->od_feature_capabilities = NULL;
+			return -ENOMEM;
+		}
+
+		memcpy(table_context->od_settings_max,
+		       &powerplay_table->OverDrive8Table.ODSettingsMax,
+		       od_setting_array_size);
+
+		if (table_context->od_settings_min)
+			return -EINVAL;
+
+		table_context->od_settings_min = kzalloc(od_setting_array_size, GFP_KERNEL);
+
+		if (!table_context->od_settings_min) {
+			kfree(table_context->od_feature_capabilities);
+			table_context->od_feature_capabilities = NULL;
+			kfree(table_context->od_settings_max);
+			table_context->od_settings_max = NULL;
+			return -ENOMEM;
+		}
+
+		memcpy(table_context->od_settings_min,
+		       &powerplay_table->OverDrive8Table.ODSettingsMin,
+		       od_setting_array_size);
+	}
+
+	return 0;
+}
+
 static int vega20_store_powerplay_table(struct smu_context *smu)
 {
 	ATOM_Vega20_POWERPLAYTABLE *powerplay_table = NULL;
 	struct smu_table_context *table_context = &smu->smu_table;
+	int ret;
 
 	if (!table_context->power_play_table)
 		return -EINVAL;
@@ -162,7 +244,9 @@ static int vega20_store_powerplay_table(struct smu_context *smu)
 	table_context->software_shutdown_temp = powerplay_table->usSoftwareShutdownTemp;
 	table_context->thermal_controller_type = powerplay_table->ucThermalControllerType;
 
-	return 0;
+	ret = vega20_setup_od8_information(smu);
+
+	return ret;
 }
 
 static int vega20_append_powerplay_table(struct smu_context *smu)
-- 
2.30.2