diff options
| -rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h | 4 | ||||
| -rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | 10 | ||||
| -rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/amd/powerplay/Makefile | 5 | ||||
| -rw-r--r-- | drivers/gpu/drm/amd/powerplay/amd_powerplay.c | 112 | ||||
| -rw-r--r-- | drivers/gpu/drm/amd/powerplay/hwmgr/Makefile | 3 | ||||
| -rw-r--r-- | drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c | 18 | ||||
| -rw-r--r-- | drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c | 214 | ||||
| -rw-r--r-- | drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.c | 246 | ||||
| -rw-r--r-- | drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.h | 40 | ||||
| -rw-r--r-- | drivers/gpu/drm/amd/powerplay/inc/amd_powerplay.h | 96 | ||||
| -rw-r--r-- | drivers/gpu/drm/amd/powerplay/inc/hwmgr.h | 5 | ||||
| -rw-r--r-- | drivers/gpu/drm/amd/powerplay/inc/pp_instance.h | 2 | 
13 files changed, 475 insertions, 282 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h index 8c96a4caa715..3eba4137508b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h @@ -383,8 +383,8 @@ struct amdgpu_dpm_funcs {  #define amdgpu_dpm_set_mclk_od(adev, value) \  	((adev)->powerplay.pp_funcs->set_mclk_od((adev)->powerplay.pp_handle, value)) -#define amdgpu_dpm_dispatch_task(adev, event_id, input, output)		\ -	(adev)->powerplay.pp_funcs->dispatch_tasks((adev)->powerplay.pp_handle, (event_id), (input), (output)) +#define amdgpu_dpm_dispatch_task(adev, task_id, input, output)		\ +	((adev)->powerplay.pp_funcs->dispatch_tasks)((adev)->powerplay.pp_handle, (task_id), (input), (output))  #define amgdpu_dpm_check_state_equal(adev, cps, rps, equal) (adev)->pm.funcs->check_state_equal((adev), (cps),(rps),(equal)) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c index 7df503aedb69..10c5d78081ed 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c @@ -119,7 +119,7 @@ static ssize_t amdgpu_set_dpm_state(struct device *dev,  	}  	if (adev->pp_enabled) { -		amdgpu_dpm_dispatch_task(adev, AMD_PP_EVENT_ENABLE_USER_STATE, &state, NULL); +		amdgpu_dpm_dispatch_task(adev, AMD_PP_TASK_ENABLE_USER_STATE, &state, NULL);  	} else {  		mutex_lock(&adev->pm.mutex);  		adev->pm.dpm.user_state = state; @@ -330,7 +330,7 @@ static ssize_t amdgpu_set_pp_force_state(struct device *dev,  		if (state != POWER_STATE_TYPE_INTERNAL_BOOT &&  		    state != POWER_STATE_TYPE_DEFAULT) {  			amdgpu_dpm_dispatch_task(adev, -					AMD_PP_EVENT_ENABLE_USER_STATE, &state, NULL); +					AMD_PP_TASK_ENABLE_USER_STATE, &state, NULL);  			adev->pp_force_state_enabled = true;  		}  	} @@ -559,7 +559,7 @@ static ssize_t amdgpu_set_pp_sclk_od(struct device *dev,  	if (adev->pp_enabled) {  		amdgpu_dpm_set_sclk_od(adev, (uint32_t)value); -		amdgpu_dpm_dispatch_task(adev, AMD_PP_EVENT_READJUST_POWER_STATE, NULL, NULL); +		amdgpu_dpm_dispatch_task(adev, AMD_PP_TASK_READJUST_POWER_STATE, NULL, NULL);  	} else if (adev->pm.funcs->set_sclk_od) {  		adev->pm.funcs->set_sclk_od(adev, (uint32_t)value);  		adev->pm.dpm.current_ps = adev->pm.dpm.boot_ps; @@ -605,7 +605,7 @@ static ssize_t amdgpu_set_pp_mclk_od(struct device *dev,  	if (adev->pp_enabled) {  		amdgpu_dpm_set_mclk_od(adev, (uint32_t)value); -		amdgpu_dpm_dispatch_task(adev, AMD_PP_EVENT_READJUST_POWER_STATE, NULL, NULL); +		amdgpu_dpm_dispatch_task(adev, AMD_PP_TASK_READJUST_POWER_STATE, NULL, NULL);  	} else if (adev->pm.funcs->set_mclk_od) {  		adev->pm.funcs->set_mclk_od(adev, (uint32_t)value);  		adev->pm.dpm.current_ps = adev->pm.dpm.boot_ps; @@ -1496,7 +1496,7 @@ void amdgpu_pm_compute_clocks(struct amdgpu_device *adev)  	}  	if (adev->pp_enabled) { -		amdgpu_dpm_dispatch_task(adev, AMD_PP_EVENT_DISPLAY_CONFIG_CHANGE, NULL, NULL); +		amdgpu_dpm_dispatch_task(adev, AMD_PP_TASK_DISPLAY_CONFIG_CHANGE, NULL, NULL);  	} else {  		mutex_lock(&adev->pm.mutex);  		adev->pm.dpm.new_active_crtcs = 0; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c index b7e1c026c0c8..b0c4db8098ed 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c @@ -128,7 +128,7 @@ static int amdgpu_pp_late_init(void *handle)  	if (adev->pp_enabled && adev->pm.dpm_enabled) {  		amdgpu_pm_sysfs_init(adev); -		amdgpu_dpm_dispatch_task(adev, AMD_PP_EVENT_COMPLETE_INIT, NULL, NULL); +		amdgpu_dpm_dispatch_task(adev, AMD_PP_TASK_COMPLETE_INIT, NULL, NULL);  	}  	return ret; diff --git a/drivers/gpu/drm/amd/powerplay/Makefile b/drivers/gpu/drm/amd/powerplay/Makefile index 4e132b936e3d..68b417ac94dd 100644 --- a/drivers/gpu/drm/amd/powerplay/Makefile +++ b/drivers/gpu/drm/amd/powerplay/Makefile @@ -4,12 +4,11 @@ subdir-ccflags-y += \  		-I$(FULL_AMD_PATH)/include/asic_reg  \  		-I$(FULL_AMD_PATH)/include  \  		-I$(FULL_AMD_PATH)/powerplay/smumgr\ -		-I$(FULL_AMD_PATH)/powerplay/hwmgr \ -		-I$(FULL_AMD_PATH)/powerplay/eventmgr +		-I$(FULL_AMD_PATH)/powerplay/hwmgr  AMD_PP_PATH = ../powerplay -PP_LIBS = smumgr hwmgr eventmgr +PP_LIBS = smumgr hwmgr  AMD_POWERPLAY = $(addsuffix /Makefile,$(addprefix $(FULL_AMD_PATH)/powerplay/,$(PP_LIBS))) diff --git a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c index f73e80c4bf33..94bed3c08161 100644 --- a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c +++ b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c @@ -29,7 +29,6 @@  #include "amd_powerplay.h"  #include "pp_instance.h"  #include "power_state.h" -#include "eventmanager.h"  static inline int pp_check(struct pp_instance *handle) @@ -43,8 +42,7 @@ static inline int pp_check(struct pp_instance *handle)  	if (handle->pm_en == 0)  		return PP_DPM_DISABLED; -	if (handle->hwmgr == NULL || handle->hwmgr->hwmgr_func == NULL -		|| handle->eventmgr == NULL) +	if (handle->hwmgr == NULL || handle->hwmgr->hwmgr_func == NULL)  		return PP_DPM_DISABLED;  	return 0; @@ -69,14 +67,6 @@ static int pp_early_init(void *handle)  		return PP_DPM_DISABLED;  	} -	ret = eventmgr_early_init(pp_handle); -	if (ret) { -		kfree(pp_handle->hwmgr); -		pp_handle->hwmgr = NULL; -		pp_handle->pm_en = 0; -		return PP_DPM_DISABLED; -	} -  	return 0;  } @@ -122,7 +112,6 @@ static int pp_sw_fini(void *handle)  static int pp_hw_init(void *handle)  {  	struct pp_smumgr *smumgr; -	struct pp_eventmgr *eventmgr;  	int ret = 0;  	struct pp_instance *pp_handle = (struct pp_instance *)handle; @@ -146,38 +135,23 @@ static int pp_hw_init(void *handle)  	ret = hwmgr_hw_init(pp_handle);  	if (ret)  		goto err; - -	eventmgr = pp_handle->eventmgr; -	if (eventmgr->pp_eventmgr_init == NULL || -		eventmgr->pp_eventmgr_init(eventmgr)) -		goto err; -  	return 0;  err:  	pp_handle->pm_en = 0; -	kfree(pp_handle->eventmgr);  	kfree(pp_handle->hwmgr);  	pp_handle->hwmgr = NULL; -	pp_handle->eventmgr = NULL;  	return PP_DPM_DISABLED;  }  static int pp_hw_fini(void *handle)  { -	struct pp_eventmgr *eventmgr;  	struct pp_instance *pp_handle = (struct pp_instance *)handle;  	int ret = 0;  	ret = pp_check(pp_handle); - -	if (ret == 0) { -		eventmgr = pp_handle->eventmgr; - -		if (eventmgr->pp_eventmgr_fini != NULL) -			eventmgr->pp_eventmgr_fini(eventmgr); - +	if (ret == 0)  		hwmgr_hw_fini(pp_handle); -	} +  	return 0;  } @@ -244,8 +218,6 @@ static int pp_set_powergating_state(void *handle,  static int pp_suspend(void *handle)  { -	struct pp_eventmgr *eventmgr; -	struct pem_event_data event_data = { {0} };  	struct pp_instance *pp_handle = (struct pp_instance *)handle;  	int ret = 0; @@ -256,16 +228,11 @@ static int pp_suspend(void *handle)  	else if (ret != 0)  		return ret; -	eventmgr = pp_handle->eventmgr; -	pem_handle_event(eventmgr, AMD_PP_EVENT_SUSPEND, &event_data); - -	return 0; +	return hwmgr_hw_suspend(pp_handle);  }  static int pp_resume(void *handle)  { -	struct pp_eventmgr *eventmgr; -	struct pem_event_data event_data = { {0} };  	struct pp_smumgr *smumgr;  	int ret, ret1;  	struct pp_instance *pp_handle = (struct pp_instance *)handle; @@ -290,11 +257,7 @@ static int pp_resume(void *handle)  	if (ret1 == PP_DPM_DISABLED)  		return 0; -	eventmgr = pp_handle->eventmgr; - -	pem_handle_event(eventmgr, AMD_PP_EVENT_RESUME, &event_data); - -	return 0; +	return hwmgr_hw_resume(pp_handle);  }  const struct amd_ip_funcs pp_ip_funcs = { @@ -344,6 +307,7 @@ static int pp_dpm_force_performance_level(void *handle,  	}  	mutex_lock(&pp_handle->pp_lock); +	hwmgr_handle_task(pp_handle, AMD_PP_TASK_READJUST_POWER_STATE, NULL, NULL);  	hwmgr->hwmgr_func->force_dpm_level(hwmgr, level);  	mutex_unlock(&pp_handle->pp_lock);  	return 0; @@ -461,60 +425,21 @@ static int pp_dpm_powergate_uvd(void *handle, bool gate)  	return ret;  } -static enum PP_StateUILabel power_state_convert(enum amd_pm_state_type  state) -{ -	switch (state) { -	case POWER_STATE_TYPE_BATTERY: -		return PP_StateUILabel_Battery; -	case POWER_STATE_TYPE_BALANCED: -		return PP_StateUILabel_Balanced; -	case POWER_STATE_TYPE_PERFORMANCE: -		return PP_StateUILabel_Performance; -	default: -		return PP_StateUILabel_None; -	} -} - -static int pp_dpm_dispatch_tasks(void *handle, enum amd_pp_event event_id, +static int pp_dpm_dispatch_tasks(void *handle, enum amd_pp_task task_id,  		void *input, void *output)  {  	int ret = 0; -	struct pem_event_data data = { {0} };  	struct pp_instance *pp_handle = (struct pp_instance *)handle;  	ret = pp_check(pp_handle);  	if (ret != 0)  		return ret; -	mutex_lock(&pp_handle->pp_lock); -	switch (event_id) { -	case AMD_PP_EVENT_DISPLAY_CONFIG_CHANGE: -		ret = pem_handle_event(pp_handle->eventmgr, event_id, &data); -		break; -	case AMD_PP_EVENT_ENABLE_USER_STATE: -	{ -		enum amd_pm_state_type  ps; - -		if (input == NULL) { -			ret = -EINVAL; -			break; -		} -		ps = *(unsigned long *)input; -		data.requested_ui_label = power_state_convert(ps); -		ret = pem_handle_event(pp_handle->eventmgr, event_id, &data); -		break; -	} -	case AMD_PP_EVENT_COMPLETE_INIT: -		ret = pem_handle_event(pp_handle->eventmgr, event_id, &data); -		break; -	case AMD_PP_EVENT_READJUST_POWER_STATE: -		ret = pem_handle_event(pp_handle->eventmgr, event_id, &data); -		break; -	default: -		break; -	} +	mutex_lock(&pp_handle->pp_lock); +	ret = hwmgr_handle_task(pp_handle, task_id, input, output);  	mutex_unlock(&pp_handle->pp_lock); +  	return ret;  } @@ -1190,10 +1115,8 @@ int amd_powerplay_destroy(void *handle)  	struct pp_instance *instance = (struct pp_instance *)handle;  	if (instance->pm_en) { -		kfree(instance->eventmgr);  		kfree(instance->hwmgr);  		instance->hwmgr = NULL; -		instance->eventmgr = NULL;  	}  	kfree(instance->smu_mgr); @@ -1206,8 +1129,6 @@ int amd_powerplay_destroy(void *handle)  int amd_powerplay_reset(void *handle)  {  	struct pp_instance *instance = (struct pp_instance *)handle; -	struct pp_eventmgr *eventmgr; -	struct pem_event_data event_data = { {0} };  	int ret;  	if (cgs_is_virtualization_enabled(instance->smu_mgr->device)) @@ -1217,7 +1138,7 @@ int amd_powerplay_reset(void *handle)  	if (ret != 0)  		return ret; -	ret = pp_hw_fini(handle); +	ret = pp_hw_fini(instance);  	if (ret)  		return ret; @@ -1225,16 +1146,7 @@ int amd_powerplay_reset(void *handle)  	if (ret)  		return PP_DPM_DISABLED; -	eventmgr = instance->eventmgr; - -	if (eventmgr->pp_eventmgr_init == NULL) -		return PP_DPM_DISABLED; - -	ret = eventmgr->pp_eventmgr_init(eventmgr); -	if (ret) -		return ret; - -	return pem_handle_event(eventmgr, AMD_PP_EVENT_COMPLETE_INIT, &event_data); +	return hwmgr_handle_task(instance, AMD_PP_TASK_COMPLETE_INIT, NULL, NULL);  }  /* export this function to DAL */ diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile b/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile index f0277c16c2bf..79119d6cd07f 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile @@ -9,7 +9,8 @@ HARDWARE_MGR = hwmgr.o processpptables.o functiontables.o \  		smu7_hwmgr.o smu7_powertune.o smu7_thermal.o \  		smu7_clockpowergating.o \  		vega10_processpptables.o vega10_hwmgr.o vega10_powertune.o \ -		vega10_thermal.o pp_overdriver.o rv_hwmgr.o +		vega10_thermal.o rv_hwmgr.o pp_psm.o\ +		pp_overdriver.o  AMD_PP_HWMGR = $(addprefix $(AMD_PP_PATH)/hwmgr/,$(HARDWARE_MGR)) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c index 967f50f54384..ce378bd21661 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c @@ -26,6 +26,10 @@  #include "hardwaremanager.h"  #include "power_state.h" + +#define TEMP_RANGE_MIN (90 * 1000) +#define TEMP_RANGE_MAX (120 * 1000) +  #define PHM_FUNC_CHECK(hw) \  	do {							\  		if ((hw) == NULL || (hw)->hwmgr_func == NULL)	\ @@ -292,7 +296,19 @@ int phm_register_thermal_interrupt(struct pp_hwmgr *hwmgr, const void *info)  */  int phm_start_thermal_controller(struct pp_hwmgr *hwmgr, struct PP_TemperatureRange *temperature_range)  { -	return phm_dispatch_table(hwmgr, &(hwmgr->start_thermal_controller), temperature_range, NULL); +	struct PP_TemperatureRange range; + +	if (temperature_range == NULL) { +		range.max = TEMP_RANGE_MAX; +		range.min = TEMP_RANGE_MIN; +	} else { +		range.max = temperature_range->max; +		range.min = temperature_range->min; +	} +	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, +			PHM_PlatformCaps_ThermalController)) +		return phm_dispatch_table(hwmgr, &(hwmgr->start_thermal_controller), &range, NULL); +	return 0;  } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c index 9547f265a8bb..c6157bcdf7d6 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c @@ -35,9 +35,9 @@  #include "ppsmc.h"  #include "pp_acpi.h"  #include "amd_acpi.h" +#include "pp_psm.h"  extern int cz_init_function_pointers(struct pp_hwmgr *hwmgr); -  static int polaris_set_asic_special_caps(struct pp_hwmgr *hwmgr);  static void hwmgr_init_default_caps(struct pp_hwmgr *hwmgr);  static int hwmgr_set_user_specify_caps(struct pp_hwmgr *hwmgr); @@ -131,80 +131,6 @@ int hwmgr_early_init(struct pp_instance *handle)  	return 0;  } -static int hw_init_power_state_table(struct pp_hwmgr *hwmgr) -{ -	int result; -	unsigned int i; -	unsigned int table_entries; -	struct pp_power_state *state; -	int size; - -	if (hwmgr->hwmgr_func->get_num_of_pp_table_entries == NULL) -		return -EINVAL; - -	if (hwmgr->hwmgr_func->get_power_state_size == NULL) -		return -EINVAL; - -	hwmgr->num_ps = table_entries = hwmgr->hwmgr_func->get_num_of_pp_table_entries(hwmgr); - -	hwmgr->ps_size = size = hwmgr->hwmgr_func->get_power_state_size(hwmgr) + -					  sizeof(struct pp_power_state); - -	hwmgr->ps = kzalloc(size * table_entries, GFP_KERNEL); -	if (hwmgr->ps == NULL) -		return -ENOMEM; - -	hwmgr->request_ps = kzalloc(size, GFP_KERNEL); -	if (hwmgr->request_ps == NULL) { -		kfree(hwmgr->ps); -		hwmgr->ps = NULL; -		return -ENOMEM; -	} - -	hwmgr->current_ps = kzalloc(size, GFP_KERNEL); -	if (hwmgr->current_ps == NULL) { -		kfree(hwmgr->request_ps); -		kfree(hwmgr->ps); -		hwmgr->request_ps = NULL; -		hwmgr->ps = NULL; -		return -ENOMEM; -	} - -	state = hwmgr->ps; - -	for (i = 0; i < table_entries; i++) { -		result = hwmgr->hwmgr_func->get_pp_table_entry(hwmgr, i, state); - -		if (state->classification.flags & PP_StateClassificationFlag_Boot) { -			hwmgr->boot_ps = state; -			memcpy(hwmgr->current_ps, state, size); -			memcpy(hwmgr->request_ps, state, size); -		} - -		state->id = i + 1; /* assigned unique num for every power state id */ - -		if (state->classification.flags & PP_StateClassificationFlag_Uvd) -			hwmgr->uvd_ps = state; -		state = (struct pp_power_state *)((unsigned long)state + size); -	} - -	return 0; -} - -static int hw_fini_power_state_table(struct pp_hwmgr *hwmgr) -{ -	if (hwmgr == NULL) -		return -EINVAL; - -	kfree(hwmgr->current_ps); -	kfree(hwmgr->request_ps); -	kfree(hwmgr->ps); -	hwmgr->request_ps = NULL; -	hwmgr->ps = NULL; -	hwmgr->current_ps = NULL; -	return 0; -} -  int hwmgr_hw_init(struct pp_instance *handle)  {  	struct pp_hwmgr *hwmgr; @@ -228,9 +154,22 @@ int hwmgr_hw_init(struct pp_instance *handle)  	if (ret)  		goto err1; -	ret = hw_init_power_state_table(hwmgr); +	ret = psm_init_power_state_table(hwmgr); +	if (ret) +		goto err2; + +	ret = phm_setup_asic(hwmgr);  	if (ret)  		goto err2; + +	ret = phm_enable_dynamic_state_management(hwmgr); +	if (ret) +		goto err2; +	ret = phm_start_thermal_controller(hwmgr, NULL); +	ret |= psm_set_performance_states(hwmgr); +	if (ret) +		goto err2; +  	return 0;  err2:  	if (hwmgr->hwmgr_func->backend_fini) @@ -247,19 +186,138 @@ int hwmgr_hw_fini(struct pp_instance *handle)  {  	struct pp_hwmgr *hwmgr; -	if (handle == NULL) +	if (handle == NULL || handle->hwmgr == NULL)  		return -EINVAL;  	hwmgr = handle->hwmgr; +	phm_stop_thermal_controller(hwmgr); +	psm_set_boot_states(hwmgr); +	phm_display_configuration_changed(hwmgr); +	psm_adjust_power_state_dynamic(hwmgr, false, NULL); +	phm_disable_dynamic_state_management(hwmgr); +	phm_disable_clock_power_gatings(hwmgr); +  	if (hwmgr->hwmgr_func->backend_fini)  		hwmgr->hwmgr_func->backend_fini(hwmgr);  	if (hwmgr->pptable_func->pptable_fini)  		hwmgr->pptable_func->pptable_fini(hwmgr); -	return hw_fini_power_state_table(hwmgr); +	return psm_fini_power_state_table(hwmgr);  } +int hwmgr_hw_suspend(struct pp_instance *handle) +{ +	struct pp_hwmgr *hwmgr; +	int ret = 0; + +	if (handle == NULL || handle->hwmgr == NULL) +		return -EINVAL; +	hwmgr = handle->hwmgr; +	phm_disable_smc_firmware_ctf(hwmgr); +	ret = psm_set_boot_states(hwmgr); +	if (ret) +		return ret; +	ret = psm_adjust_power_state_dynamic(hwmgr, false, NULL); +	if (ret) +		return ret; +	ret = phm_power_down_asic(hwmgr); + +	return ret; +} + +int hwmgr_hw_resume(struct pp_instance *handle) +{ +	struct pp_hwmgr *hwmgr; +	int ret = 0; + +	if (handle == NULL || handle->hwmgr == NULL) +		return -EINVAL; + +	hwmgr = handle->hwmgr; +	ret = phm_setup_asic(hwmgr); +	if (ret) +		return ret; + +	ret = phm_enable_dynamic_state_management(hwmgr); +	if (ret) +		return ret; +	ret = phm_start_thermal_controller(hwmgr, NULL); +	if (ret) +		return ret; + +	ret |= psm_set_performance_states(hwmgr); +	if (ret) +		return ret; + +	ret = psm_adjust_power_state_dynamic(hwmgr, false, NULL); + +	return ret; +} + +static enum PP_StateUILabel power_state_convert(enum amd_pm_state_type  state) +{ +	switch (state) { +	case POWER_STATE_TYPE_BATTERY: +		return PP_StateUILabel_Battery; +	case POWER_STATE_TYPE_BALANCED: +		return PP_StateUILabel_Balanced; +	case POWER_STATE_TYPE_PERFORMANCE: +		return PP_StateUILabel_Performance; +	default: +		return PP_StateUILabel_None; +	} +} + +int hwmgr_handle_task(struct pp_instance *handle, enum amd_pp_task task_id, +		void *input, void *output) +{ +	int ret = 0; +	struct pp_hwmgr *hwmgr; + +	if (handle == NULL || handle->hwmgr == NULL) +		return -EINVAL; + +	hwmgr = handle->hwmgr; + +	switch (task_id) { +	case AMD_PP_TASK_DISPLAY_CONFIG_CHANGE: +		ret = phm_set_cpu_power_state(hwmgr); +		if (ret) +			return ret; +		ret = psm_set_performance_states(hwmgr); +		if (ret) +			return ret; +		ret = psm_adjust_power_state_dynamic(hwmgr, false, NULL); +		break; +	case AMD_PP_TASK_ENABLE_USER_STATE: +	{ +		enum amd_pm_state_type ps; +		enum PP_StateUILabel requested_ui_label; +		struct pp_power_state *requested_ps; + +		if (input == NULL) { +			ret = -EINVAL; +			break; +		} +		ps = *(unsigned long *)input; + +		requested_ui_label = power_state_convert(ps); +		ret = psm_set_user_performance_state(hwmgr, requested_ui_label, requested_ps); +		if (ret) +			return ret; +		ret = psm_adjust_power_state_dynamic(hwmgr, false, requested_ps); +		break; +	} +	case AMD_PP_TASK_COMPLETE_INIT: +	case AMD_PP_TASK_READJUST_POWER_STATE: +		ret = psm_adjust_power_state_dynamic(hwmgr, false, NULL); +		break; +	default: +		break; +	} +	return ret; +}  /**   * Returns once the part of the register indicated by the mask has   * reached the given value. diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.c b/drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.c new file mode 100644 index 000000000000..7656324957a8 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.c @@ -0,0 +1,246 @@ +/* + * Copyright 2017 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 <linux/types.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include "pp_psm.h" + +int psm_init_power_state_table(struct pp_hwmgr *hwmgr) +{ +	int result; +	unsigned int i; +	unsigned int table_entries; +	struct pp_power_state *state; +	int size; + +	if (hwmgr->hwmgr_func->get_num_of_pp_table_entries == NULL) +		return -EINVAL; + +	if (hwmgr->hwmgr_func->get_power_state_size == NULL) +		return -EINVAL; + +	hwmgr->num_ps = table_entries = hwmgr->hwmgr_func->get_num_of_pp_table_entries(hwmgr); + +	hwmgr->ps_size = size = hwmgr->hwmgr_func->get_power_state_size(hwmgr) + +					  sizeof(struct pp_power_state); + +	hwmgr->ps = kzalloc(size * table_entries, GFP_KERNEL); +	if (hwmgr->ps == NULL) +		return -ENOMEM; + +	hwmgr->request_ps = kzalloc(size, GFP_KERNEL); +	if (hwmgr->request_ps == NULL) { +		kfree(hwmgr->ps); +		hwmgr->ps = NULL; +		return -ENOMEM; +	} + +	hwmgr->current_ps = kzalloc(size, GFP_KERNEL); +	if (hwmgr->current_ps == NULL) { +		kfree(hwmgr->request_ps); +		kfree(hwmgr->ps); +		hwmgr->request_ps = NULL; +		hwmgr->ps = NULL; +		return -ENOMEM; +	} + +	state = hwmgr->ps; + +	for (i = 0; i < table_entries; i++) { +		result = hwmgr->hwmgr_func->get_pp_table_entry(hwmgr, i, state); + +		if (state->classification.flags & PP_StateClassificationFlag_Boot) { +			hwmgr->boot_ps = state; +			memcpy(hwmgr->current_ps, state, size); +			memcpy(hwmgr->request_ps, state, size); +		} + +		state->id = i + 1; /* assigned unique num for every power state id */ + +		if (state->classification.flags & PP_StateClassificationFlag_Uvd) +			hwmgr->uvd_ps = state; +		state = (struct pp_power_state *)((unsigned long)state + size); +	} + +	return 0; +} + +int psm_fini_power_state_table(struct pp_hwmgr *hwmgr) +{ +	if (hwmgr == NULL) +		return -EINVAL; + +	kfree(hwmgr->current_ps); +	kfree(hwmgr->request_ps); +	kfree(hwmgr->ps); +	hwmgr->request_ps = NULL; +	hwmgr->ps = NULL; +	hwmgr->current_ps = NULL; +	return 0; +} + +static int psm_get_ui_state(struct pp_hwmgr *hwmgr, +				enum PP_StateUILabel ui_label, +				unsigned long *state_id) +{ +	struct pp_power_state *state; +	int table_entries; +	int i; + +	table_entries = hwmgr->num_ps; +	state = hwmgr->ps; + +	for (i = 0; i < table_entries; i++) { +		if (state->classification.ui_label & ui_label) { +			*state_id = state->id; +			return 0; +		} +		state = (struct pp_power_state *)((unsigned long)state + hwmgr->ps_size); +	} +	return -EINVAL; +} + +static int psm_get_state_by_classification(struct pp_hwmgr *hwmgr, +					enum PP_StateClassificationFlag flag, +					unsigned long *state_id) +{ +	struct pp_power_state *state; +	int table_entries; +	int i; + +	table_entries = hwmgr->num_ps; +	state = hwmgr->ps; + +	for (i = 0; i < table_entries; i++) { +		if (state->classification.flags & flag) { +			*state_id = state->id; +			return 0; +		} +		state = (struct pp_power_state *)((unsigned long)state + hwmgr->ps_size); +	} +	return -EINVAL; +} + +static int psm_set_states(struct pp_hwmgr *hwmgr, unsigned long state_id) +{ +	struct pp_power_state *state; +	int table_entries; +	int i; + +	table_entries = hwmgr->num_ps; + +	state = hwmgr->ps; + +	for (i = 0; i < table_entries; i++) { +		if (state->id == state_id) { +			memcpy(hwmgr->request_ps, state, hwmgr->ps_size); +			return 0; +		} +		state = (struct pp_power_state *)((unsigned long)state + hwmgr->ps_size); +	} +	return -EINVAL; +} + +int psm_set_boot_states(struct pp_hwmgr *hwmgr) +{ +	unsigned long state_id; +	int ret = -EINVAL; + +	if (!psm_get_state_by_classification(hwmgr, PP_StateClassificationFlag_Boot, +					&state_id)) +		ret = psm_set_states(hwmgr, state_id); + +	return ret; +} + +int psm_set_performance_states(struct pp_hwmgr *hwmgr) +{ +	unsigned long state_id; +	int ret = -EINVAL; + +	if (!psm_get_ui_state(hwmgr, PP_StateUILabel_Performance, +					&state_id)) +		ret = psm_set_states(hwmgr, state_id); + +	return ret; +} + +int psm_set_user_performance_state(struct pp_hwmgr *hwmgr, +					enum PP_StateUILabel label_id, +					struct pp_power_state *state) +{ +	int table_entries; +	int i; + +	table_entries = hwmgr->num_ps; +	state = hwmgr->ps; + +restart_search: +	for (i = 0; i < table_entries; i++) { +		if (state->classification.ui_label & label_id) +			return 0; +		state = (struct pp_power_state *)((unsigned long)state + hwmgr->ps_size); +	} + +	switch (label_id) { +	case PP_StateUILabel_Battery: +	case PP_StateUILabel_Balanced: +		label_id = PP_StateUILabel_Performance; +		goto restart_search; +	default: +		break; +	} +	return -EINVAL; +} + +int psm_adjust_power_state_dynamic(struct pp_hwmgr *hwmgr, bool skip, +						struct pp_power_state *new_ps) +{ +	struct pp_power_state *pcurrent; +	struct pp_power_state *requested; +	bool equal; + +	if (skip) +		return 0; + +	if (new_ps != NULL) +		requested = new_ps; +	else +		requested = hwmgr->request_ps; + +	pcurrent = hwmgr->current_ps; + +	phm_apply_state_adjust_rules(hwmgr, requested, pcurrent); + +	if (pcurrent == NULL || (0 != phm_check_states_equal(hwmgr, +			&pcurrent->hardware, &requested->hardware, &equal))) +		equal = false; + +	if (!equal || phm_check_smc_update_required_for_display_configuration(hwmgr)) { +		phm_set_power_state(hwmgr, &pcurrent->hardware, &requested->hardware); +		memcpy(hwmgr->current_ps, hwmgr->request_ps, hwmgr->ps_size); +	} +	return 0; +} + diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.h b/drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.h new file mode 100644 index 000000000000..aa44e60ec1b6 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.h @@ -0,0 +1,40 @@ +/* + * Copyright 2017 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. + * + */ + +#ifndef PP_PSM_H +#define PP_PSM_H + +#include "hwmgr.h" + +int psm_init_power_state_table(struct pp_hwmgr *hwmgr); +int psm_fini_power_state_table(struct pp_hwmgr *hwmgr); +int psm_set_boot_states(struct pp_hwmgr *hwmgr); +int psm_set_performance_states(struct pp_hwmgr *hwmgr); +int psm_set_user_performance_state(struct pp_hwmgr *hwmgr, +					enum PP_StateUILabel label_id, +					struct pp_power_state *state); +int psm_adjust_power_state_dynamic(struct pp_hwmgr *hwmgr, +				bool skip, +				struct pp_power_state *new_ps); + +#endif diff --git a/drivers/gpu/drm/amd/powerplay/inc/amd_powerplay.h b/drivers/gpu/drm/amd/powerplay/inc/amd_powerplay.h index 07e9c0b5915d..f471b99f456b 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/amd_powerplay.h +++ b/drivers/gpu/drm/amd/powerplay/inc/amd_powerplay.h @@ -50,94 +50,12 @@ enum amd_pp_sensors {  	AMDGPU_PP_SENSOR_GPU_POWER,  }; -enum amd_pp_event { -	AMD_PP_EVENT_INITIALIZE = 0, -	AMD_PP_EVENT_UNINITIALIZE, -	AMD_PP_EVENT_POWER_SOURCE_CHANGE, -	AMD_PP_EVENT_SUSPEND, -	AMD_PP_EVENT_RESUME, -	AMD_PP_EVENT_ENTER_REST_STATE, -	AMD_PP_EVENT_EXIT_REST_STATE, -	AMD_PP_EVENT_DISPLAY_CONFIG_CHANGE, -	AMD_PP_EVENT_THERMAL_NOTIFICATION, -	AMD_PP_EVENT_VBIOS_NOTIFICATION, -	AMD_PP_EVENT_ENTER_THERMAL_STATE, -	AMD_PP_EVENT_EXIT_THERMAL_STATE, -	AMD_PP_EVENT_ENTER_FORCED_STATE, -	AMD_PP_EVENT_EXIT_FORCED_STATE, -	AMD_PP_EVENT_ENTER_EXCLUSIVE_MODE, -	AMD_PP_EVENT_EXIT_EXCLUSIVE_MODE, -	AMD_PP_EVENT_ENTER_SCREEN_SAVER, -	AMD_PP_EVENT_EXIT_SCREEN_SAVER, -	AMD_PP_EVENT_VPU_RECOVERY_BEGIN, -	AMD_PP_EVENT_VPU_RECOVERY_END, -	AMD_PP_EVENT_ENABLE_POWER_PLAY, -	AMD_PP_EVENT_DISABLE_POWER_PLAY, -	AMD_PP_EVENT_CHANGE_POWER_SOURCE_UI_LABEL, -	AMD_PP_EVENT_ENABLE_USER2D_PERFORMANCE, -	AMD_PP_EVENT_DISABLE_USER2D_PERFORMANCE, -	AMD_PP_EVENT_ENABLE_USER3D_PERFORMANCE, -	AMD_PP_EVENT_DISABLE_USER3D_PERFORMANCE, -	AMD_PP_EVENT_ENABLE_OVER_DRIVE_TEST, -	AMD_PP_EVENT_DISABLE_OVER_DRIVE_TEST, -	AMD_PP_EVENT_ENABLE_REDUCED_REFRESH_RATE, -	AMD_PP_EVENT_DISABLE_REDUCED_REFRESH_RATE, -	AMD_PP_EVENT_ENABLE_GFX_CLOCK_GATING, -	AMD_PP_EVENT_DISABLE_GFX_CLOCK_GATING, -	AMD_PP_EVENT_ENABLE_CGPG, -	AMD_PP_EVENT_DISABLE_CGPG, -	AMD_PP_EVENT_ENTER_TEXT_MODE, -	AMD_PP_EVENT_EXIT_TEXT_MODE, -	AMD_PP_EVENT_VIDEO_START, -	AMD_PP_EVENT_VIDEO_STOP, -	AMD_PP_EVENT_ENABLE_USER_STATE, -	AMD_PP_EVENT_DISABLE_USER_STATE, -	AMD_PP_EVENT_READJUST_POWER_STATE, -	AMD_PP_EVENT_START_INACTIVITY, -	AMD_PP_EVENT_STOP_INACTIVITY, -	AMD_PP_EVENT_LINKED_ADAPTERS_READY, -	AMD_PP_EVENT_ADAPTER_SAFE_TO_DISABLE, -	AMD_PP_EVENT_COMPLETE_INIT, -	AMD_PP_EVENT_CRITICAL_THERMAL_FAULT, -	AMD_PP_EVENT_BACKLIGHT_CHANGED, -	AMD_PP_EVENT_ENABLE_VARI_BRIGHT, -	AMD_PP_EVENT_DISABLE_VARI_BRIGHT, -	AMD_PP_EVENT_ENABLE_VARI_BRIGHT_ON_POWER_XPRESS, -	AMD_PP_EVENT_DISABLE_VARI_BRIGHT_ON_POWER_XPRESS, -	AMD_PP_EVENT_SET_VARI_BRIGHT_LEVEL, -	AMD_PP_EVENT_VARI_BRIGHT_MONITOR_MEASUREMENT, -	AMD_PP_EVENT_SCREEN_ON, -	AMD_PP_EVENT_SCREEN_OFF, -	AMD_PP_EVENT_PRE_DISPLAY_CONFIG_CHANGE, -	AMD_PP_EVENT_ENTER_ULP_STATE, -	AMD_PP_EVENT_EXIT_ULP_STATE, -	AMD_PP_EVENT_REGISTER_IP_STATE, -	AMD_PP_EVENT_UNREGISTER_IP_STATE, -	AMD_PP_EVENT_ENTER_MGPU_MODE, -	AMD_PP_EVENT_EXIT_MGPU_MODE, -	AMD_PP_EVENT_ENTER_MULTI_GPU_MODE, -	AMD_PP_EVENT_PRE_SUSPEND, -	AMD_PP_EVENT_PRE_RESUME, -	AMD_PP_EVENT_ENTER_BACOS, -	AMD_PP_EVENT_EXIT_BACOS, -	AMD_PP_EVENT_RESUME_BACO, -	AMD_PP_EVENT_RESET_BACO, -	AMD_PP_EVENT_PRE_DISPLAY_PHY_ACCESS, -	AMD_PP_EVENT_POST_DISPLAY_PHY_CCESS, -	AMD_PP_EVENT_START_COMPUTE_APPLICATION, -	AMD_PP_EVENT_STOP_COMPUTE_APPLICATION, -	AMD_PP_EVENT_REDUCE_POWER_LIMIT, -	AMD_PP_EVENT_ENTER_FRAME_LOCK, -	AMD_PP_EVENT_EXIT_FRAME_LOOCK, -	AMD_PP_EVENT_LONG_IDLE_REQUEST_BACO, -	AMD_PP_EVENT_LONG_IDLE_ENTER_BACO, -	AMD_PP_EVENT_LONG_IDLE_EXIT_BACO, -	AMD_PP_EVENT_HIBERNATE, -	AMD_PP_EVENT_CONNECTED_STANDBY, -	AMD_PP_EVENT_ENTER_SELF_REFRESH, -	AMD_PP_EVENT_EXIT_SELF_REFRESH, -	AMD_PP_EVENT_START_AVFS_BTC, -	AMD_PP_EVENT_MAX +enum amd_pp_task { +	AMD_PP_TASK_DISPLAY_CONFIG_CHANGE, +	AMD_PP_TASK_ENABLE_USER_STATE, +	AMD_PP_TASK_READJUST_POWER_STATE, +	AMD_PP_TASK_COMPLETE_INIT, +	AMD_PP_TASK_MAX  };  struct amd_pp_init { @@ -366,7 +284,7 @@ struct amd_powerplay_funcs {  	int (*get_mclk)(void *handle, bool low);  	int (*powergate_vce)(void *handle, bool gate);  	int (*powergate_uvd)(void *handle, bool gate); -	int (*dispatch_tasks)(void *handle, enum amd_pp_event event_id, +	int (*dispatch_tasks)(void *handle, enum amd_pp_task task_id,  				   void *input, void *output);  	int (*set_fan_control_mode)(void *handle, uint32_t mode);  	int (*get_fan_control_mode)(void *handle); diff --git a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h index b1a6372608de..c649354f08ca 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h @@ -797,6 +797,11 @@ struct pp_hwmgr {  extern int hwmgr_early_init(struct pp_instance *handle);  extern int hwmgr_hw_init(struct pp_instance *handle);  extern int hwmgr_hw_fini(struct pp_instance *handle); +extern int hwmgr_hw_suspend(struct pp_instance *handle); +extern int hwmgr_hw_resume(struct pp_instance *handle); +extern int hwmgr_handle_task(struct pp_instance *handle, +				enum amd_pp_task task_id, +				void *input, void *output);  extern int phm_wait_on_register(struct pp_hwmgr *hwmgr, uint32_t index,  				uint32_t value, uint32_t mask); diff --git a/drivers/gpu/drm/amd/powerplay/inc/pp_instance.h b/drivers/gpu/drm/amd/powerplay/inc/pp_instance.h index 4c3b537a714f..5bf2ee449e42 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/pp_instance.h +++ b/drivers/gpu/drm/amd/powerplay/inc/pp_instance.h @@ -25,7 +25,6 @@  #include "smumgr.h"  #include "hwmgr.h" -#include "eventmgr.h"  #define PP_VALID  0x1F1F1F1F @@ -38,7 +37,6 @@ struct pp_instance {  	void *device;  	struct pp_smumgr *smu_mgr;  	struct pp_hwmgr *hwmgr; -	struct pp_eventmgr *eventmgr;  	struct mutex pp_lock;  };  | 

