1/* 2 * Copyright 2014 Advanced Micro Devices, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 */ 23 24#include <linux/firmware.h> 25#include "drmP.h" 26#include "amdgpu.h" 27#include "iceland_smumgr.h" 28 29MODULE_FIRMWARE("amdgpu/topaz_smc.bin"); 30 31static void iceland_dpm_set_funcs(struct amdgpu_device *adev); 32 33static int iceland_dpm_early_init(void *handle) 34{ 35 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 36 37 iceland_dpm_set_funcs(adev); 38 39 return 0; 40} 41 42static int iceland_dpm_init_microcode(struct amdgpu_device *adev) 43{ 44 char fw_name[30] = "amdgpu/topaz_smc.bin"; 45 int err; 46 47 err = request_firmware(&adev->pm.fw, fw_name, adev->dev); 48 if (err) 49 goto out; 50 err = amdgpu_ucode_validate(adev->pm.fw); 51 52out: 53 if (err) { 54 DRM_ERROR("Failed to load firmware \"%s\"", fw_name); 55 release_firmware(adev->pm.fw); 56 adev->pm.fw = NULL; 57 } 58 return err; 59} 60 61static int iceland_dpm_sw_init(void *handle) 62{ 63 int ret; 64 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 65 66 ret = iceland_dpm_init_microcode(adev); 67 if (ret) 68 return ret; 69 70 return 0; 71} 72 73static int iceland_dpm_sw_fini(void *handle) 74{ 75 return 0; 76} 77 78static int iceland_dpm_hw_init(void *handle) 79{ 80 int ret; 81 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 82 83 mutex_lock(&adev->pm.mutex); 84 85 /* smu init only needs to be called at startup, not resume. 86 * It should be in sw_init, but requires the fw info gathered 87 * in sw_init from other IP modules. 88 */ 89 ret = iceland_smu_init(adev); 90 if (ret) { 91 DRM_ERROR("SMU initialization failed\n"); 92 goto fail; 93 } 94 95 ret = iceland_smu_start(adev); 96 if (ret) { 97 DRM_ERROR("SMU start failed\n"); 98 goto fail; 99 } 100 101 mutex_unlock(&adev->pm.mutex); 102 return 0; 103 104fail: 105 adev->firmware.smu_load = false; 106 mutex_unlock(&adev->pm.mutex); 107 return -EINVAL; 108} 109 110static int iceland_dpm_hw_fini(void *handle) 111{ 112 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 113 114 mutex_lock(&adev->pm.mutex); 115 /* smu fini only needs to be called at teardown, not suspend. 116 * It should be in sw_fini, but we put it here for symmetry 117 * with smu init. 118 */ 119 iceland_smu_fini(adev); 120 mutex_unlock(&adev->pm.mutex); 121 return 0; 122} 123 124static int iceland_dpm_suspend(void *handle) 125{ 126 return 0; 127} 128 129static int iceland_dpm_resume(void *handle) 130{ 131 int ret; 132 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 133 134 mutex_lock(&adev->pm.mutex); 135 136 ret = iceland_smu_start(adev); 137 if (ret) { 138 DRM_ERROR("SMU start failed\n"); 139 goto fail; 140 } 141 142fail: 143 mutex_unlock(&adev->pm.mutex); 144 return ret; 145} 146 147static int iceland_dpm_set_clockgating_state(void *handle, 148 enum amd_clockgating_state state) 149{ 150 return 0; 151} 152 153static int iceland_dpm_set_powergating_state(void *handle, 154 enum amd_powergating_state state) 155{ 156 return 0; 157} 158 159const struct amd_ip_funcs iceland_dpm_ip_funcs = { 160 .early_init = iceland_dpm_early_init, 161 .late_init = NULL, 162 .sw_init = iceland_dpm_sw_init, 163 .sw_fini = iceland_dpm_sw_fini, 164 .hw_init = iceland_dpm_hw_init, 165 .hw_fini = iceland_dpm_hw_fini, 166 .suspend = iceland_dpm_suspend, 167 .resume = iceland_dpm_resume, 168 .is_idle = NULL, 169 .wait_for_idle = NULL, 170 .soft_reset = NULL, 171 .print_status = NULL, 172 .set_clockgating_state = iceland_dpm_set_clockgating_state, 173 .set_powergating_state = iceland_dpm_set_powergating_state, 174}; 175 176static const struct amdgpu_dpm_funcs iceland_dpm_funcs = { 177 .get_temperature = NULL, 178 .pre_set_power_state = NULL, 179 .set_power_state = NULL, 180 .post_set_power_state = NULL, 181 .display_configuration_changed = NULL, 182 .get_sclk = NULL, 183 .get_mclk = NULL, 184 .print_power_state = NULL, 185 .debugfs_print_current_performance_level = NULL, 186 .force_performance_level = NULL, 187 .vblank_too_short = NULL, 188 .powergate_uvd = NULL, 189}; 190 191static void iceland_dpm_set_funcs(struct amdgpu_device *adev) 192{ 193 if (NULL == adev->pm.funcs) 194 adev->pm.funcs = &iceland_dpm_funcs; 195} 196