Path: blob/master/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hardwaremanager.c
26552 views
/*1* Copyright 2015 Advanced Micro Devices, Inc.2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice shall be included in11* all copies or substantial portions of the Software.12*13* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR14* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,15* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL16* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR17* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,18* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR19* OTHER DEALINGS IN THE SOFTWARE.20*21*/22#include "pp_debug.h"23#include <linux/errno.h>24#include "hwmgr.h"25#include "hardwaremanager.h"26#include "power_state.h"272829#define TEMP_RANGE_MIN (0)30#define TEMP_RANGE_MAX (80 * 1000)3132#define PHM_FUNC_CHECK(hw) \33do { \34if ((hw) == NULL || (hw)->hwmgr_func == NULL) \35return -EINVAL; \36} while (0)3738int phm_setup_asic(struct pp_hwmgr *hwmgr)39{40PHM_FUNC_CHECK(hwmgr);4142if (NULL != hwmgr->hwmgr_func->asic_setup)43return hwmgr->hwmgr_func->asic_setup(hwmgr);4445return 0;46}4748int phm_power_down_asic(struct pp_hwmgr *hwmgr)49{50PHM_FUNC_CHECK(hwmgr);5152if (NULL != hwmgr->hwmgr_func->power_off_asic)53return hwmgr->hwmgr_func->power_off_asic(hwmgr);5455return 0;56}5758int phm_set_power_state(struct pp_hwmgr *hwmgr,59const struct pp_hw_power_state *pcurrent_state,60const struct pp_hw_power_state *pnew_power_state)61{62struct phm_set_power_state_input states;6364PHM_FUNC_CHECK(hwmgr);6566states.pcurrent_state = pcurrent_state;67states.pnew_state = pnew_power_state;6869if (NULL != hwmgr->hwmgr_func->power_state_set)70return hwmgr->hwmgr_func->power_state_set(hwmgr, &states);7172return 0;73}7475int phm_enable_dynamic_state_management(struct pp_hwmgr *hwmgr)76{77struct amdgpu_device *adev = NULL;78int ret = -EINVAL;79PHM_FUNC_CHECK(hwmgr);80adev = hwmgr->adev;8182/* Skip for suspend/resume case */83if (!hwmgr->pp_one_vf && smum_is_dpm_running(hwmgr)84&& !amdgpu_passthrough(adev) && adev->in_suspend85&& adev->asic_type != CHIP_RAVEN) {86pr_info("dpm has been enabled\n");87return 0;88}8990if (NULL != hwmgr->hwmgr_func->dynamic_state_management_enable)91ret = hwmgr->hwmgr_func->dynamic_state_management_enable(hwmgr);9293return ret;94}9596int phm_disable_dynamic_state_management(struct pp_hwmgr *hwmgr)97{98int ret = -EINVAL;99100PHM_FUNC_CHECK(hwmgr);101102if (!hwmgr->not_vf)103return 0;104105if (!smum_is_dpm_running(hwmgr)) {106pr_info("dpm has been disabled\n");107return 0;108}109110if (hwmgr->hwmgr_func->dynamic_state_management_disable)111ret = hwmgr->hwmgr_func->dynamic_state_management_disable(hwmgr);112113return ret;114}115116int phm_force_dpm_levels(struct pp_hwmgr *hwmgr, enum amd_dpm_forced_level level)117{118int ret = 0;119120PHM_FUNC_CHECK(hwmgr);121122if (hwmgr->hwmgr_func->force_dpm_level != NULL)123ret = hwmgr->hwmgr_func->force_dpm_level(hwmgr, level);124125return ret;126}127128int phm_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,129struct pp_power_state *adjusted_ps,130const struct pp_power_state *current_ps)131{132PHM_FUNC_CHECK(hwmgr);133134if (hwmgr->hwmgr_func->apply_state_adjust_rules != NULL)135return hwmgr->hwmgr_func->apply_state_adjust_rules(136hwmgr,137adjusted_ps,138current_ps);139return 0;140}141142int phm_apply_clock_adjust_rules(struct pp_hwmgr *hwmgr)143{144PHM_FUNC_CHECK(hwmgr);145146if (hwmgr->hwmgr_func->apply_clocks_adjust_rules != NULL)147return hwmgr->hwmgr_func->apply_clocks_adjust_rules(hwmgr);148return 0;149}150151int phm_disable_clock_power_gatings(struct pp_hwmgr *hwmgr)152{153PHM_FUNC_CHECK(hwmgr);154155if (NULL != hwmgr->hwmgr_func->disable_clock_power_gating)156return hwmgr->hwmgr_func->disable_clock_power_gating(hwmgr);157158return 0;159}160161int phm_pre_display_configuration_changed(struct pp_hwmgr *hwmgr)162{163PHM_FUNC_CHECK(hwmgr);164165if (NULL != hwmgr->hwmgr_func->pre_display_config_changed)166hwmgr->hwmgr_func->pre_display_config_changed(hwmgr);167168return 0;169170}171172int phm_display_configuration_changed(struct pp_hwmgr *hwmgr)173{174PHM_FUNC_CHECK(hwmgr);175176if (NULL != hwmgr->hwmgr_func->display_config_changed)177hwmgr->hwmgr_func->display_config_changed(hwmgr);178179return 0;180}181182int phm_notify_smc_display_config_after_ps_adjustment(struct pp_hwmgr *hwmgr)183{184PHM_FUNC_CHECK(hwmgr);185186if (NULL != hwmgr->hwmgr_func->notify_smc_display_config_after_ps_adjustment)187hwmgr->hwmgr_func->notify_smc_display_config_after_ps_adjustment(hwmgr);188189return 0;190}191192int phm_stop_thermal_controller(struct pp_hwmgr *hwmgr)193{194PHM_FUNC_CHECK(hwmgr);195196if (!hwmgr->not_vf)197return 0;198199if (hwmgr->hwmgr_func->stop_thermal_controller == NULL)200return -EINVAL;201202return hwmgr->hwmgr_func->stop_thermal_controller(hwmgr);203}204205int phm_register_irq_handlers(struct pp_hwmgr *hwmgr)206{207PHM_FUNC_CHECK(hwmgr);208209if (hwmgr->hwmgr_func->register_irq_handlers != NULL)210return hwmgr->hwmgr_func->register_irq_handlers(hwmgr);211212return 0;213}214215/**216* phm_start_thermal_controller - Initializes the thermal controller subsystem.217*218* @hwmgr: the address of the powerplay hardware manager.219* Exception PP_Result_Failed if any of the paramters is NULL, otherwise the return value from the dispatcher.220*/221int phm_start_thermal_controller(struct pp_hwmgr *hwmgr)222{223int ret = 0;224struct PP_TemperatureRange range = {225TEMP_RANGE_MIN,226TEMP_RANGE_MAX,227TEMP_RANGE_MAX,228TEMP_RANGE_MIN,229TEMP_RANGE_MAX,230TEMP_RANGE_MAX,231TEMP_RANGE_MIN,232TEMP_RANGE_MAX,233TEMP_RANGE_MAX,2340};235struct amdgpu_device *adev = hwmgr->adev;236237if (!hwmgr->not_vf)238return 0;239240if (hwmgr->hwmgr_func->get_thermal_temperature_range)241hwmgr->hwmgr_func->get_thermal_temperature_range(242hwmgr, &range);243244if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,245PHM_PlatformCaps_ThermalController)246&& hwmgr->hwmgr_func->start_thermal_controller != NULL)247ret = hwmgr->hwmgr_func->start_thermal_controller(hwmgr, &range);248249adev->pm.dpm.thermal.min_temp = range.min;250adev->pm.dpm.thermal.max_temp = range.max;251adev->pm.dpm.thermal.max_edge_emergency_temp = range.edge_emergency_max;252adev->pm.dpm.thermal.min_hotspot_temp = range.hotspot_min;253adev->pm.dpm.thermal.max_hotspot_crit_temp = range.hotspot_crit_max;254adev->pm.dpm.thermal.max_hotspot_emergency_temp = range.hotspot_emergency_max;255adev->pm.dpm.thermal.min_mem_temp = range.mem_min;256adev->pm.dpm.thermal.max_mem_crit_temp = range.mem_crit_max;257adev->pm.dpm.thermal.max_mem_emergency_temp = range.mem_emergency_max;258adev->pm.dpm.thermal.sw_ctf_threshold = range.sw_ctf_threshold;259260return ret;261}262263264bool phm_check_smc_update_required_for_display_configuration(struct pp_hwmgr *hwmgr)265{266if (hwmgr == NULL ||267hwmgr->hwmgr_func == NULL)268return false;269270if (hwmgr->pp_one_vf)271return false;272273if (hwmgr->hwmgr_func->check_smc_update_required_for_display_configuration == NULL)274return false;275276return hwmgr->hwmgr_func->check_smc_update_required_for_display_configuration(hwmgr);277}278279280int phm_check_states_equal(struct pp_hwmgr *hwmgr,281const struct pp_hw_power_state *pstate1,282const struct pp_hw_power_state *pstate2,283bool *equal)284{285PHM_FUNC_CHECK(hwmgr);286287if (hwmgr->hwmgr_func->check_states_equal == NULL)288return -EINVAL;289290return hwmgr->hwmgr_func->check_states_equal(hwmgr, pstate1, pstate2, equal);291}292293int phm_store_dal_configuration_data(struct pp_hwmgr *hwmgr,294const struct amd_pp_display_configuration *display_config)295{296int index = 0;297int number_of_active_display = 0;298299PHM_FUNC_CHECK(hwmgr);300301if (display_config == NULL)302return -EINVAL;303304if (NULL != hwmgr->hwmgr_func->set_min_deep_sleep_dcefclk)305hwmgr->hwmgr_func->set_min_deep_sleep_dcefclk(hwmgr, display_config->min_dcef_deep_sleep_set_clk);306307for (index = 0; index < display_config->num_path_including_non_display; index++) {308if (display_config->displays[index].controller_id != 0)309number_of_active_display++;310}311312if (NULL != hwmgr->hwmgr_func->set_active_display_count)313hwmgr->hwmgr_func->set_active_display_count(hwmgr, number_of_active_display);314315if (hwmgr->hwmgr_func->store_cc6_data == NULL)316return -EINVAL;317318/* TODO: pass other display configuration in the future */319320if (hwmgr->hwmgr_func->store_cc6_data)321hwmgr->hwmgr_func->store_cc6_data(hwmgr,322display_config->cpu_pstate_separation_time,323display_config->cpu_cc6_disable,324display_config->cpu_pstate_disable,325display_config->nb_pstate_switch_disable);326327return 0;328}329330int phm_get_dal_power_level(struct pp_hwmgr *hwmgr,331struct amd_pp_simple_clock_info *info)332{333PHM_FUNC_CHECK(hwmgr);334335if (info == NULL || hwmgr->hwmgr_func->get_dal_power_level == NULL)336return -EINVAL;337return hwmgr->hwmgr_func->get_dal_power_level(hwmgr, info);338}339340int phm_set_cpu_power_state(struct pp_hwmgr *hwmgr)341{342PHM_FUNC_CHECK(hwmgr);343344if (hwmgr->hwmgr_func->set_cpu_power_state != NULL)345return hwmgr->hwmgr_func->set_cpu_power_state(hwmgr);346347return 0;348}349350351int phm_get_performance_level(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *state,352PHM_PerformanceLevelDesignation designation, uint32_t index,353PHM_PerformanceLevel *level)354{355PHM_FUNC_CHECK(hwmgr);356if (hwmgr->hwmgr_func->get_performance_level == NULL)357return -EINVAL;358359return hwmgr->hwmgr_func->get_performance_level(hwmgr, state, designation, index, level);360361362}363364365/**366* phm_get_clock_info367*368* @hwmgr: the address of the powerplay hardware manager.369* @state: the address of the Power State structure.370* @pclock_info: the address of PP_ClockInfo structure where the result will be returned.371* @designation: PHM performance level designation372* Exception PP_Result_Failed if any of the paramters is NULL, otherwise the return value from the back-end.373*/374int phm_get_clock_info(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *state, struct pp_clock_info *pclock_info,375PHM_PerformanceLevelDesignation designation)376{377int result;378PHM_PerformanceLevel performance_level = {0};379380PHM_FUNC_CHECK(hwmgr);381382PP_ASSERT_WITH_CODE((NULL != state), "Invalid Input!", return -EINVAL);383PP_ASSERT_WITH_CODE((NULL != pclock_info), "Invalid Input!", return -EINVAL);384385result = phm_get_performance_level(hwmgr, state, PHM_PerformanceLevelDesignation_Activity, 0, &performance_level);386387PP_ASSERT_WITH_CODE((0 == result), "Failed to retrieve minimum clocks.", return result);388389390pclock_info->min_mem_clk = performance_level.memory_clock;391pclock_info->min_eng_clk = performance_level.coreClock;392pclock_info->min_bus_bandwidth = performance_level.nonLocalMemoryFreq * performance_level.nonLocalMemoryWidth;393394395result = phm_get_performance_level(hwmgr, state, designation,396(hwmgr->platform_descriptor.hardwareActivityPerformanceLevels - 1), &performance_level);397398PP_ASSERT_WITH_CODE((0 == result), "Failed to retrieve maximum clocks.", return result);399400pclock_info->max_mem_clk = performance_level.memory_clock;401pclock_info->max_eng_clk = performance_level.coreClock;402pclock_info->max_bus_bandwidth = performance_level.nonLocalMemoryFreq * performance_level.nonLocalMemoryWidth;403404return 0;405}406407int phm_get_current_shallow_sleep_clocks(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *state, struct pp_clock_info *clock_info)408{409PHM_FUNC_CHECK(hwmgr);410411if (hwmgr->hwmgr_func->get_current_shallow_sleep_clocks == NULL)412return -EINVAL;413414return hwmgr->hwmgr_func->get_current_shallow_sleep_clocks(hwmgr, state, clock_info);415416}417418int phm_get_clock_by_type(struct pp_hwmgr *hwmgr, enum amd_pp_clock_type type, struct amd_pp_clocks *clocks)419{420PHM_FUNC_CHECK(hwmgr);421422if (hwmgr->hwmgr_func->get_clock_by_type == NULL)423return -EINVAL;424425return hwmgr->hwmgr_func->get_clock_by_type(hwmgr, type, clocks);426427}428429int phm_get_clock_by_type_with_latency(struct pp_hwmgr *hwmgr,430enum amd_pp_clock_type type,431struct pp_clock_levels_with_latency *clocks)432{433PHM_FUNC_CHECK(hwmgr);434435if (hwmgr->hwmgr_func->get_clock_by_type_with_latency == NULL)436return -EINVAL;437438return hwmgr->hwmgr_func->get_clock_by_type_with_latency(hwmgr, type, clocks);439440}441442int phm_get_clock_by_type_with_voltage(struct pp_hwmgr *hwmgr,443enum amd_pp_clock_type type,444struct pp_clock_levels_with_voltage *clocks)445{446PHM_FUNC_CHECK(hwmgr);447448if (hwmgr->hwmgr_func->get_clock_by_type_with_voltage == NULL)449return -EINVAL;450451return hwmgr->hwmgr_func->get_clock_by_type_with_voltage(hwmgr, type, clocks);452453}454455int phm_set_watermarks_for_clocks_ranges(struct pp_hwmgr *hwmgr,456void *clock_ranges)457{458PHM_FUNC_CHECK(hwmgr);459460if (!hwmgr->hwmgr_func->set_watermarks_for_clocks_ranges)461return -EINVAL;462463return hwmgr->hwmgr_func->set_watermarks_for_clocks_ranges(hwmgr,464clock_ranges);465}466467int phm_display_clock_voltage_request(struct pp_hwmgr *hwmgr,468struct pp_display_clock_request *clock)469{470PHM_FUNC_CHECK(hwmgr);471472if (!hwmgr->hwmgr_func->display_clock_voltage_request)473return -EINVAL;474475return hwmgr->hwmgr_func->display_clock_voltage_request(hwmgr, clock);476}477478int phm_get_max_high_clocks(struct pp_hwmgr *hwmgr, struct amd_pp_simple_clock_info *clocks)479{480PHM_FUNC_CHECK(hwmgr);481482if (hwmgr->hwmgr_func->get_max_high_clocks == NULL)483return -EINVAL;484485return hwmgr->hwmgr_func->get_max_high_clocks(hwmgr, clocks);486}487488int phm_disable_smc_firmware_ctf(struct pp_hwmgr *hwmgr)489{490PHM_FUNC_CHECK(hwmgr);491492if (!hwmgr->not_vf)493return 0;494495if (hwmgr->hwmgr_func->disable_smc_firmware_ctf == NULL)496return -EINVAL;497498return hwmgr->hwmgr_func->disable_smc_firmware_ctf(hwmgr);499}500501int phm_set_active_display_count(struct pp_hwmgr *hwmgr, uint32_t count)502{503PHM_FUNC_CHECK(hwmgr);504505if (!hwmgr->hwmgr_func->set_active_display_count)506return -EINVAL;507508return hwmgr->hwmgr_func->set_active_display_count(hwmgr, count);509}510511512