Line data Source code
1 : /*
2 : * Copyright 2019 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 : #define SWSMU_CODE_LAYER_L3
24 :
25 : #include <linux/firmware.h>
26 : #include "amdgpu.h"
27 : #include "amdgpu_smu.h"
28 : #include "atomfirmware.h"
29 : #include "amdgpu_atomfirmware.h"
30 : #include "amdgpu_atombios.h"
31 : #include "smu_v12_0.h"
32 : #include "soc15_common.h"
33 : #include "atom.h"
34 : #include "smu_cmn.h"
35 :
36 : #include "asic_reg/mp/mp_12_0_0_offset.h"
37 : #include "asic_reg/mp/mp_12_0_0_sh_mask.h"
38 : #include "asic_reg/smuio/smuio_12_0_0_offset.h"
39 : #include "asic_reg/smuio/smuio_12_0_0_sh_mask.h"
40 :
41 : /*
42 : * DO NOT use these for err/warn/info/debug messages.
43 : * Use dev_err, dev_warn, dev_info and dev_dbg instead.
44 : * They are more MGPU friendly.
45 : */
46 : #undef pr_err
47 : #undef pr_warn
48 : #undef pr_info
49 : #undef pr_debug
50 :
51 : // because some SMU12 based ASICs use older ip offset tables
52 : // we should undefine this register from the smuio12 header
53 : // to prevent confusion down the road
54 : #undef mmPWR_MISC_CNTL_STATUS
55 :
56 : #define smnMP1_FIRMWARE_FLAGS 0x3010024
57 :
58 0 : int smu_v12_0_check_fw_status(struct smu_context *smu)
59 : {
60 0 : struct amdgpu_device *adev = smu->adev;
61 : uint32_t mp1_fw_flags;
62 :
63 0 : mp1_fw_flags = RREG32_PCIE(MP1_Public |
64 : (smnMP1_FIRMWARE_FLAGS & 0xffffffff));
65 :
66 0 : if ((mp1_fw_flags & MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED_MASK) >>
67 : MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED__SHIFT)
68 : return 0;
69 :
70 0 : return -EIO;
71 : }
72 :
73 0 : int smu_v12_0_check_fw_version(struct smu_context *smu)
74 : {
75 0 : struct amdgpu_device *adev = smu->adev;
76 0 : uint32_t if_version = 0xff, smu_version = 0xff;
77 : uint8_t smu_program, smu_major, smu_minor, smu_debug;
78 0 : int ret = 0;
79 :
80 0 : ret = smu_cmn_get_smc_version(smu, &if_version, &smu_version);
81 0 : if (ret)
82 : return ret;
83 :
84 0 : smu_program = (smu_version >> 24) & 0xff;
85 0 : smu_major = (smu_version >> 16) & 0xff;
86 0 : smu_minor = (smu_version >> 8) & 0xff;
87 0 : smu_debug = (smu_version >> 0) & 0xff;
88 0 : if (smu->is_apu)
89 0 : adev->pm.fw_version = smu_version;
90 :
91 : /*
92 : * 1. if_version mismatch is not critical as our fw is designed
93 : * to be backward compatible.
94 : * 2. New fw usually brings some optimizations. But that's visible
95 : * only on the paired driver.
96 : * Considering above, we just leave user a warning message instead
97 : * of halt driver loading.
98 : */
99 0 : if (if_version != smu->smc_driver_if_version) {
100 0 : dev_info(smu->adev->dev, "smu driver if version = 0x%08x, smu fw if version = 0x%08x, "
101 : "smu fw program = %d, smu fw version = 0x%08x (%d.%d.%d)\n",
102 : smu->smc_driver_if_version, if_version,
103 : smu_program, smu_version, smu_major, smu_minor, smu_debug);
104 0 : dev_warn(smu->adev->dev, "SMU driver if version not matched\n");
105 : }
106 :
107 : return ret;
108 : }
109 :
110 0 : int smu_v12_0_powergate_sdma(struct smu_context *smu, bool gate)
111 : {
112 0 : if (!smu->is_apu)
113 : return 0;
114 :
115 0 : if (gate)
116 0 : return smu_cmn_send_smc_msg(smu, SMU_MSG_PowerDownSdma, NULL);
117 : else
118 0 : return smu_cmn_send_smc_msg(smu, SMU_MSG_PowerUpSdma, NULL);
119 : }
120 :
121 0 : int smu_v12_0_set_gfx_cgpg(struct smu_context *smu, bool enable)
122 : {
123 : /* Until now the SMU12 only implemented for Renoir series so here neen't do APU check. */
124 0 : if (!(smu->adev->pg_flags & AMD_PG_SUPPORT_GFX_PG) || smu->adev->in_s0ix)
125 : return 0;
126 :
127 0 : return smu_cmn_send_smc_msg_with_param(smu,
128 : SMU_MSG_SetGfxCGPG,
129 : enable ? 1 : 0,
130 : NULL);
131 : }
132 :
133 : /**
134 : * smu_v12_0_get_gfxoff_status - get gfxoff status
135 : *
136 : * @smu: amdgpu_device pointer
137 : *
138 : * This function will be used to get gfxoff status
139 : *
140 : * Returns 0=GFXOFF(default).
141 : * Returns 1=Transition out of GFX State.
142 : * Returns 2=Not in GFXOFF.
143 : * Returns 3=Transition into GFXOFF.
144 : */
145 0 : uint32_t smu_v12_0_get_gfxoff_status(struct smu_context *smu)
146 : {
147 : uint32_t reg;
148 0 : uint32_t gfxOff_Status = 0;
149 0 : struct amdgpu_device *adev = smu->adev;
150 :
151 0 : reg = RREG32_SOC15(SMUIO, 0, mmSMUIO_GFX_MISC_CNTL);
152 0 : gfxOff_Status = (reg & SMUIO_GFX_MISC_CNTL__PWR_GFXOFF_STATUS_MASK)
153 0 : >> SMUIO_GFX_MISC_CNTL__PWR_GFXOFF_STATUS__SHIFT;
154 :
155 0 : return gfxOff_Status;
156 : }
157 :
158 0 : int smu_v12_0_gfx_off_control(struct smu_context *smu, bool enable)
159 : {
160 0 : int ret = 0, timeout = 500;
161 :
162 0 : if (enable) {
163 0 : ret = smu_cmn_send_smc_msg(smu, SMU_MSG_AllowGfxOff, NULL);
164 :
165 : } else {
166 0 : ret = smu_cmn_send_smc_msg(smu, SMU_MSG_DisallowGfxOff, NULL);
167 :
168 : /* confirm gfx is back to "on" state, timeout is 0.5 second */
169 0 : while (!(smu_v12_0_get_gfxoff_status(smu) == 2)) {
170 0 : msleep(1);
171 0 : timeout--;
172 0 : if (timeout == 0) {
173 0 : DRM_ERROR("disable gfxoff timeout and failed!\n");
174 0 : break;
175 : }
176 : }
177 : }
178 :
179 0 : return ret;
180 : }
181 :
182 0 : int smu_v12_0_fini_smc_tables(struct smu_context *smu)
183 : {
184 0 : struct smu_table_context *smu_table = &smu->smu_table;
185 :
186 0 : kfree(smu_table->clocks_table);
187 0 : smu_table->clocks_table = NULL;
188 :
189 0 : kfree(smu_table->metrics_table);
190 0 : smu_table->metrics_table = NULL;
191 :
192 0 : kfree(smu_table->watermarks_table);
193 0 : smu_table->watermarks_table = NULL;
194 :
195 0 : kfree(smu_table->gpu_metrics_table);
196 0 : smu_table->gpu_metrics_table = NULL;
197 :
198 0 : return 0;
199 : }
200 :
201 0 : int smu_v12_0_set_default_dpm_tables(struct smu_context *smu)
202 : {
203 0 : struct smu_table_context *smu_table = &smu->smu_table;
204 :
205 0 : return smu_cmn_update_table(smu, SMU_TABLE_DPMCLOCKS, 0, smu_table->clocks_table, false);
206 : }
207 :
208 0 : int smu_v12_0_mode2_reset(struct smu_context *smu){
209 0 : return smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GfxDeviceDriverReset, SMU_RESET_MODE_2, NULL);
210 : }
211 :
212 0 : int smu_v12_0_set_soft_freq_limited_range(struct smu_context *smu, enum smu_clk_type clk_type,
213 : uint32_t min, uint32_t max)
214 : {
215 0 : int ret = 0;
216 :
217 0 : if (!smu_cmn_clk_dpm_is_enabled(smu, clk_type))
218 : return 0;
219 :
220 0 : switch (clk_type) {
221 : case SMU_GFXCLK:
222 : case SMU_SCLK:
223 0 : ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinGfxClk, min, NULL);
224 0 : if (ret)
225 : return ret;
226 :
227 0 : ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxGfxClk, max, NULL);
228 : if (ret)
229 : return ret;
230 : break;
231 : case SMU_FCLK:
232 : case SMU_MCLK:
233 : case SMU_UCLK:
234 0 : ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinFclkByFreq, min, NULL);
235 0 : if (ret)
236 : return ret;
237 :
238 0 : ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxFclkByFreq, max, NULL);
239 : if (ret)
240 : return ret;
241 : break;
242 : case SMU_SOCCLK:
243 0 : ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinSocclkByFreq, min, NULL);
244 0 : if (ret)
245 : return ret;
246 :
247 0 : ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxSocclkByFreq, max, NULL);
248 : if (ret)
249 : return ret;
250 : break;
251 : case SMU_VCLK:
252 0 : ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinVcn, min, NULL);
253 0 : if (ret)
254 : return ret;
255 :
256 0 : ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxVcn, max, NULL);
257 : if (ret)
258 : return ret;
259 : break;
260 : default:
261 : return -EINVAL;
262 : }
263 :
264 : return ret;
265 : }
266 :
267 0 : int smu_v12_0_set_driver_table_location(struct smu_context *smu)
268 : {
269 0 : struct smu_table *driver_table = &smu->smu_table.driver_table;
270 0 : int ret = 0;
271 :
272 0 : if (driver_table->mc_address) {
273 0 : ret = smu_cmn_send_smc_msg_with_param(smu,
274 : SMU_MSG_SetDriverDramAddrHigh,
275 0 : upper_32_bits(driver_table->mc_address),
276 : NULL);
277 0 : if (!ret)
278 0 : ret = smu_cmn_send_smc_msg_with_param(smu,
279 : SMU_MSG_SetDriverDramAddrLow,
280 0 : lower_32_bits(driver_table->mc_address),
281 : NULL);
282 : }
283 :
284 0 : return ret;
285 : }
286 :
287 0 : static int smu_v12_0_atom_get_smu_clockinfo(struct amdgpu_device *adev,
288 : uint8_t clk_id,
289 : uint8_t syspll_id,
290 : uint32_t *clk_freq)
291 : {
292 0 : struct atom_get_smu_clock_info_parameters_v3_1 input = {0};
293 : struct atom_get_smu_clock_info_output_parameters_v3_1 *output;
294 : int ret, index;
295 :
296 0 : input.clk_id = clk_id;
297 0 : input.syspll_id = syspll_id;
298 : input.command = GET_SMU_CLOCK_INFO_V3_1_GET_CLOCK_FREQ;
299 0 : index = get_index_into_master_table(atom_master_list_of_command_functions_v2_1,
300 : getsmuclockinfo);
301 :
302 0 : ret = amdgpu_atom_execute_table(adev->mode_info.atom_context, index,
303 : (uint32_t *)&input);
304 0 : if (ret)
305 : return -EINVAL;
306 :
307 0 : output = (struct atom_get_smu_clock_info_output_parameters_v3_1 *)&input;
308 0 : *clk_freq = le32_to_cpu(output->atom_smu_outputclkfreq.smu_clock_freq_hz) / 10000;
309 :
310 0 : return 0;
311 : }
312 :
313 0 : int smu_v12_0_get_vbios_bootup_values(struct smu_context *smu)
314 : {
315 : int ret, index;
316 : uint16_t size;
317 : uint8_t frev, crev;
318 : struct atom_common_table_header *header;
319 : struct atom_firmware_info_v3_1 *v_3_1;
320 : struct atom_firmware_info_v3_3 *v_3_3;
321 :
322 0 : index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
323 : firmwareinfo);
324 :
325 0 : ret = amdgpu_atombios_get_data_table(smu->adev, index, &size, &frev, &crev,
326 : (uint8_t **)&header);
327 0 : if (ret)
328 : return ret;
329 :
330 0 : if (header->format_revision != 3) {
331 0 : dev_err(smu->adev->dev, "unknown atom_firmware_info version! for smu12\n");
332 0 : return -EINVAL;
333 : }
334 :
335 0 : switch (header->content_revision) {
336 : case 0:
337 : case 1:
338 : case 2:
339 0 : v_3_1 = (struct atom_firmware_info_v3_1 *)header;
340 0 : smu->smu_table.boot_values.revision = v_3_1->firmware_revision;
341 0 : smu->smu_table.boot_values.gfxclk = v_3_1->bootup_sclk_in10khz;
342 0 : smu->smu_table.boot_values.uclk = v_3_1->bootup_mclk_in10khz;
343 0 : smu->smu_table.boot_values.socclk = 0;
344 0 : smu->smu_table.boot_values.dcefclk = 0;
345 0 : smu->smu_table.boot_values.vddc = v_3_1->bootup_vddc_mv;
346 0 : smu->smu_table.boot_values.vddci = v_3_1->bootup_vddci_mv;
347 0 : smu->smu_table.boot_values.mvddc = v_3_1->bootup_mvddc_mv;
348 0 : smu->smu_table.boot_values.vdd_gfx = v_3_1->bootup_vddgfx_mv;
349 0 : smu->smu_table.boot_values.cooling_id = v_3_1->coolingsolution_id;
350 0 : smu->smu_table.boot_values.pp_table_id = 0;
351 0 : smu->smu_table.boot_values.firmware_caps = v_3_1->firmware_capability;
352 0 : break;
353 : case 3:
354 : case 4:
355 : default:
356 0 : v_3_3 = (struct atom_firmware_info_v3_3 *)header;
357 0 : smu->smu_table.boot_values.revision = v_3_3->firmware_revision;
358 0 : smu->smu_table.boot_values.gfxclk = v_3_3->bootup_sclk_in10khz;
359 0 : smu->smu_table.boot_values.uclk = v_3_3->bootup_mclk_in10khz;
360 0 : smu->smu_table.boot_values.socclk = 0;
361 0 : smu->smu_table.boot_values.dcefclk = 0;
362 0 : smu->smu_table.boot_values.vddc = v_3_3->bootup_vddc_mv;
363 0 : smu->smu_table.boot_values.vddci = v_3_3->bootup_vddci_mv;
364 0 : smu->smu_table.boot_values.mvddc = v_3_3->bootup_mvddc_mv;
365 0 : smu->smu_table.boot_values.vdd_gfx = v_3_3->bootup_vddgfx_mv;
366 0 : smu->smu_table.boot_values.cooling_id = v_3_3->coolingsolution_id;
367 0 : smu->smu_table.boot_values.pp_table_id = v_3_3->pplib_pptable_id;
368 0 : smu->smu_table.boot_values.firmware_caps = v_3_3->firmware_capability;
369 : }
370 :
371 0 : smu->smu_table.boot_values.format_revision = header->format_revision;
372 0 : smu->smu_table.boot_values.content_revision = header->content_revision;
373 :
374 0 : smu_v12_0_atom_get_smu_clockinfo(smu->adev,
375 : (uint8_t)SMU12_SYSPLL0_SOCCLK_ID,
376 : (uint8_t)SMU12_SYSPLL0_ID,
377 : &smu->smu_table.boot_values.socclk);
378 :
379 0 : smu_v12_0_atom_get_smu_clockinfo(smu->adev,
380 : (uint8_t)SMU12_SYSPLL1_DCFCLK_ID,
381 : (uint8_t)SMU12_SYSPLL1_ID,
382 : &smu->smu_table.boot_values.dcefclk);
383 :
384 0 : smu_v12_0_atom_get_smu_clockinfo(smu->adev,
385 : (uint8_t)SMU12_SYSPLL0_VCLK_ID,
386 : (uint8_t)SMU12_SYSPLL0_ID,
387 : &smu->smu_table.boot_values.vclk);
388 :
389 0 : smu_v12_0_atom_get_smu_clockinfo(smu->adev,
390 : (uint8_t)SMU12_SYSPLL0_DCLK_ID,
391 : (uint8_t)SMU12_SYSPLL0_ID,
392 : &smu->smu_table.boot_values.dclk);
393 :
394 0 : if ((smu->smu_table.boot_values.format_revision == 3) &&
395 0 : (smu->smu_table.boot_values.content_revision >= 2))
396 0 : smu_v12_0_atom_get_smu_clockinfo(smu->adev,
397 : (uint8_t)SMU12_SYSPLL3_0_FCLK_ID,
398 : (uint8_t)SMU12_SYSPLL3_0_ID,
399 : &smu->smu_table.boot_values.fclk);
400 :
401 0 : smu_v12_0_atom_get_smu_clockinfo(smu->adev,
402 : (uint8_t)SMU12_SYSPLL0_LCLK_ID,
403 : (uint8_t)SMU12_SYSPLL0_ID,
404 : &smu->smu_table.boot_values.lclk);
405 :
406 0 : return 0;
407 : }
|