Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2019 Advanced Micro Devices, Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
0021  */
0022 
0023 #define SWSMU_CODE_LAYER_L3
0024 
0025 #include <linux/firmware.h>
0026 #include "amdgpu.h"
0027 #include "amdgpu_smu.h"
0028 #include "atomfirmware.h"
0029 #include "amdgpu_atomfirmware.h"
0030 #include "amdgpu_atombios.h"
0031 #include "smu_v12_0.h"
0032 #include "soc15_common.h"
0033 #include "atom.h"
0034 #include "smu_cmn.h"
0035 
0036 #include "asic_reg/mp/mp_12_0_0_offset.h"
0037 #include "asic_reg/mp/mp_12_0_0_sh_mask.h"
0038 #include "asic_reg/smuio/smuio_12_0_0_offset.h"
0039 #include "asic_reg/smuio/smuio_12_0_0_sh_mask.h"
0040 
0041 /*
0042  * DO NOT use these for err/warn/info/debug messages.
0043  * Use dev_err, dev_warn, dev_info and dev_dbg instead.
0044  * They are more MGPU friendly.
0045  */
0046 #undef pr_err
0047 #undef pr_warn
0048 #undef pr_info
0049 #undef pr_debug
0050 
0051 // because some SMU12 based ASICs use older ip offset tables
0052 // we should undefine this register from the smuio12 header
0053 // to prevent confusion down the road
0054 #undef mmPWR_MISC_CNTL_STATUS
0055 
0056 #define smnMP1_FIRMWARE_FLAGS                                0x3010024
0057 
0058 int smu_v12_0_check_fw_status(struct smu_context *smu)
0059 {
0060     struct amdgpu_device *adev = smu->adev;
0061     uint32_t mp1_fw_flags;
0062 
0063     mp1_fw_flags = RREG32_PCIE(MP1_Public |
0064         (smnMP1_FIRMWARE_FLAGS & 0xffffffff));
0065 
0066     if ((mp1_fw_flags & MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED_MASK) >>
0067         MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED__SHIFT)
0068         return 0;
0069 
0070     return -EIO;
0071 }
0072 
0073 int smu_v12_0_check_fw_version(struct smu_context *smu)
0074 {
0075     struct amdgpu_device *adev = smu->adev;
0076     uint32_t if_version = 0xff, smu_version = 0xff;
0077     uint8_t smu_program, smu_major, smu_minor, smu_debug;
0078     int ret = 0;
0079 
0080     ret = smu_cmn_get_smc_version(smu, &if_version, &smu_version);
0081     if (ret)
0082         return ret;
0083 
0084     smu_program = (smu_version >> 24) & 0xff;
0085     smu_major = (smu_version >> 16) & 0xff;
0086     smu_minor = (smu_version >> 8) & 0xff;
0087     smu_debug = (smu_version >> 0) & 0xff;
0088     if (smu->is_apu)
0089         adev->pm.fw_version = smu_version;
0090 
0091     /*
0092      * 1. if_version mismatch is not critical as our fw is designed
0093      * to be backward compatible.
0094      * 2. New fw usually brings some optimizations. But that's visible
0095      * only on the paired driver.
0096      * Considering above, we just leave user a warning message instead
0097      * of halt driver loading.
0098      */
0099     if (if_version != smu->smc_driver_if_version) {
0100         dev_info(smu->adev->dev, "smu driver if version = 0x%08x, smu fw if version = 0x%08x, "
0101             "smu fw program = %d, smu fw version = 0x%08x (%d.%d.%d)\n",
0102             smu->smc_driver_if_version, if_version,
0103             smu_program, smu_version, smu_major, smu_minor, smu_debug);
0104         dev_warn(smu->adev->dev, "SMU driver if version not matched\n");
0105     }
0106 
0107     return ret;
0108 }
0109 
0110 int smu_v12_0_powergate_sdma(struct smu_context *smu, bool gate)
0111 {
0112     if (!smu->is_apu)
0113         return 0;
0114 
0115     if (gate)
0116         return smu_cmn_send_smc_msg(smu, SMU_MSG_PowerDownSdma, NULL);
0117     else
0118         return smu_cmn_send_smc_msg(smu, SMU_MSG_PowerUpSdma, NULL);
0119 }
0120 
0121 int smu_v12_0_set_gfx_cgpg(struct smu_context *smu, bool enable)
0122 {
0123     /* Until now the SMU12 only implemented for Renoir series so here neen't do APU check. */
0124     if (!(smu->adev->pg_flags & AMD_PG_SUPPORT_GFX_PG) || smu->adev->in_s0ix)
0125         return 0;
0126 
0127     return smu_cmn_send_smc_msg_with_param(smu,
0128         SMU_MSG_SetGfxCGPG,
0129         enable ? 1 : 0,
0130         NULL);
0131 }
0132 
0133 /**
0134  * smu_v12_0_get_gfxoff_status - get gfxoff status
0135  *
0136  * @smu: amdgpu_device pointer
0137  *
0138  * This function will be used to get gfxoff status
0139  *
0140  * Returns 0=GFXOFF(default).
0141  * Returns 1=Transition out of GFX State.
0142  * Returns 2=Not in GFXOFF.
0143  * Returns 3=Transition into GFXOFF.
0144  */
0145 uint32_t smu_v12_0_get_gfxoff_status(struct smu_context *smu)
0146 {
0147     uint32_t reg;
0148     uint32_t gfxOff_Status = 0;
0149     struct amdgpu_device *adev = smu->adev;
0150 
0151     reg = RREG32_SOC15(SMUIO, 0, mmSMUIO_GFX_MISC_CNTL);
0152     gfxOff_Status = (reg & SMUIO_GFX_MISC_CNTL__PWR_GFXOFF_STATUS_MASK)
0153         >> SMUIO_GFX_MISC_CNTL__PWR_GFXOFF_STATUS__SHIFT;
0154 
0155     return gfxOff_Status;
0156 }
0157 
0158 int smu_v12_0_gfx_off_control(struct smu_context *smu, bool enable)
0159 {
0160     int ret = 0, timeout = 500;
0161 
0162     if (enable) {
0163         ret = smu_cmn_send_smc_msg(smu, SMU_MSG_AllowGfxOff, NULL);
0164 
0165     } else {
0166         ret = smu_cmn_send_smc_msg(smu, SMU_MSG_DisallowGfxOff, NULL);
0167 
0168         /* confirm gfx is back to "on" state, timeout is 0.5 second */
0169         while (!(smu_v12_0_get_gfxoff_status(smu) == 2)) {
0170             msleep(1);
0171             timeout--;
0172             if (timeout == 0) {
0173                 DRM_ERROR("disable gfxoff timeout and failed!\n");
0174                 break;
0175             }
0176         }
0177     }
0178 
0179     return ret;
0180 }
0181 
0182 int smu_v12_0_fini_smc_tables(struct smu_context *smu)
0183 {
0184     struct smu_table_context *smu_table = &smu->smu_table;
0185 
0186     kfree(smu_table->clocks_table);
0187     smu_table->clocks_table = NULL;
0188 
0189     kfree(smu_table->metrics_table);
0190     smu_table->metrics_table = NULL;
0191 
0192     kfree(smu_table->watermarks_table);
0193     smu_table->watermarks_table = NULL;
0194 
0195     kfree(smu_table->gpu_metrics_table);
0196     smu_table->gpu_metrics_table = NULL;
0197 
0198     return 0;
0199 }
0200 
0201 int smu_v12_0_set_default_dpm_tables(struct smu_context *smu)
0202 {
0203     struct smu_table_context *smu_table = &smu->smu_table;
0204 
0205     return smu_cmn_update_table(smu, SMU_TABLE_DPMCLOCKS, 0, smu_table->clocks_table, false);
0206 }
0207 
0208 int smu_v12_0_mode2_reset(struct smu_context *smu){
0209     return smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GfxDeviceDriverReset, SMU_RESET_MODE_2, NULL);
0210 }
0211 
0212 int smu_v12_0_set_soft_freq_limited_range(struct smu_context *smu, enum smu_clk_type clk_type,
0213                 uint32_t min, uint32_t max)
0214 {
0215     int ret = 0;
0216 
0217     if (!smu_cmn_clk_dpm_is_enabled(smu, clk_type))
0218         return 0;
0219 
0220     switch (clk_type) {
0221     case SMU_GFXCLK:
0222     case SMU_SCLK:
0223         ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinGfxClk, min, NULL);
0224         if (ret)
0225             return ret;
0226 
0227         ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxGfxClk, max, NULL);
0228         if (ret)
0229             return ret;
0230     break;
0231     case SMU_FCLK:
0232     case SMU_MCLK:
0233     case SMU_UCLK:
0234         ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinFclkByFreq, min, NULL);
0235         if (ret)
0236             return ret;
0237 
0238         ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxFclkByFreq, max, NULL);
0239         if (ret)
0240             return ret;
0241     break;
0242     case SMU_SOCCLK:
0243         ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinSocclkByFreq, min, NULL);
0244         if (ret)
0245             return ret;
0246 
0247         ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxSocclkByFreq, max, NULL);
0248         if (ret)
0249             return ret;
0250     break;
0251     case SMU_VCLK:
0252         ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinVcn, min, NULL);
0253         if (ret)
0254             return ret;
0255 
0256         ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxVcn, max, NULL);
0257         if (ret)
0258             return ret;
0259     break;
0260     default:
0261         return -EINVAL;
0262     }
0263 
0264     return ret;
0265 }
0266 
0267 int smu_v12_0_set_driver_table_location(struct smu_context *smu)
0268 {
0269     struct smu_table *driver_table = &smu->smu_table.driver_table;
0270     int ret = 0;
0271 
0272     if (driver_table->mc_address) {
0273         ret = smu_cmn_send_smc_msg_with_param(smu,
0274                 SMU_MSG_SetDriverDramAddrHigh,
0275                 upper_32_bits(driver_table->mc_address),
0276                 NULL);
0277         if (!ret)
0278             ret = smu_cmn_send_smc_msg_with_param(smu,
0279                 SMU_MSG_SetDriverDramAddrLow,
0280                 lower_32_bits(driver_table->mc_address),
0281                 NULL);
0282     }
0283 
0284     return ret;
0285 }
0286 
0287 static int smu_v12_0_atom_get_smu_clockinfo(struct amdgpu_device *adev,
0288                         uint8_t clk_id,
0289                         uint8_t syspll_id,
0290                         uint32_t *clk_freq)
0291 {
0292     struct atom_get_smu_clock_info_parameters_v3_1 input = {0};
0293     struct atom_get_smu_clock_info_output_parameters_v3_1 *output;
0294     int ret, index;
0295 
0296     input.clk_id = clk_id;
0297     input.syspll_id = syspll_id;
0298     input.command = GET_SMU_CLOCK_INFO_V3_1_GET_CLOCK_FREQ;
0299     index = get_index_into_master_table(atom_master_list_of_command_functions_v2_1,
0300                         getsmuclockinfo);
0301 
0302     ret = amdgpu_atom_execute_table(adev->mode_info.atom_context, index,
0303                     (uint32_t *)&input);
0304     if (ret)
0305         return -EINVAL;
0306 
0307     output = (struct atom_get_smu_clock_info_output_parameters_v3_1 *)&input;
0308     *clk_freq = le32_to_cpu(output->atom_smu_outputclkfreq.smu_clock_freq_hz) / 10000;
0309 
0310     return 0;
0311 }
0312 
0313 int smu_v12_0_get_vbios_bootup_values(struct smu_context *smu)
0314 {
0315     int ret, index;
0316     uint16_t size;
0317     uint8_t frev, crev;
0318     struct atom_common_table_header *header;
0319     struct atom_firmware_info_v3_1 *v_3_1;
0320     struct atom_firmware_info_v3_3 *v_3_3;
0321 
0322     index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
0323                         firmwareinfo);
0324 
0325     ret = amdgpu_atombios_get_data_table(smu->adev, index, &size, &frev, &crev,
0326                       (uint8_t **)&header);
0327     if (ret)
0328         return ret;
0329 
0330     if (header->format_revision != 3) {
0331         dev_err(smu->adev->dev, "unknown atom_firmware_info version! for smu12\n");
0332         return -EINVAL;
0333     }
0334 
0335     switch (header->content_revision) {
0336     case 0:
0337     case 1:
0338     case 2:
0339         v_3_1 = (struct atom_firmware_info_v3_1 *)header;
0340         smu->smu_table.boot_values.revision = v_3_1->firmware_revision;
0341         smu->smu_table.boot_values.gfxclk = v_3_1->bootup_sclk_in10khz;
0342         smu->smu_table.boot_values.uclk = v_3_1->bootup_mclk_in10khz;
0343         smu->smu_table.boot_values.socclk = 0;
0344         smu->smu_table.boot_values.dcefclk = 0;
0345         smu->smu_table.boot_values.vddc = v_3_1->bootup_vddc_mv;
0346         smu->smu_table.boot_values.vddci = v_3_1->bootup_vddci_mv;
0347         smu->smu_table.boot_values.mvddc = v_3_1->bootup_mvddc_mv;
0348         smu->smu_table.boot_values.vdd_gfx = v_3_1->bootup_vddgfx_mv;
0349         smu->smu_table.boot_values.cooling_id = v_3_1->coolingsolution_id;
0350         smu->smu_table.boot_values.pp_table_id = 0;
0351         smu->smu_table.boot_values.firmware_caps = v_3_1->firmware_capability;
0352         break;
0353     case 3:
0354     case 4:
0355     default:
0356         v_3_3 = (struct atom_firmware_info_v3_3 *)header;
0357         smu->smu_table.boot_values.revision = v_3_3->firmware_revision;
0358         smu->smu_table.boot_values.gfxclk = v_3_3->bootup_sclk_in10khz;
0359         smu->smu_table.boot_values.uclk = v_3_3->bootup_mclk_in10khz;
0360         smu->smu_table.boot_values.socclk = 0;
0361         smu->smu_table.boot_values.dcefclk = 0;
0362         smu->smu_table.boot_values.vddc = v_3_3->bootup_vddc_mv;
0363         smu->smu_table.boot_values.vddci = v_3_3->bootup_vddci_mv;
0364         smu->smu_table.boot_values.mvddc = v_3_3->bootup_mvddc_mv;
0365         smu->smu_table.boot_values.vdd_gfx = v_3_3->bootup_vddgfx_mv;
0366         smu->smu_table.boot_values.cooling_id = v_3_3->coolingsolution_id;
0367         smu->smu_table.boot_values.pp_table_id = v_3_3->pplib_pptable_id;
0368         smu->smu_table.boot_values.firmware_caps = v_3_3->firmware_capability;
0369     }
0370 
0371     smu->smu_table.boot_values.format_revision = header->format_revision;
0372     smu->smu_table.boot_values.content_revision = header->content_revision;
0373 
0374     smu_v12_0_atom_get_smu_clockinfo(smu->adev,
0375                      (uint8_t)SMU12_SYSPLL0_SOCCLK_ID,
0376                      (uint8_t)SMU12_SYSPLL0_ID,
0377                      &smu->smu_table.boot_values.socclk);
0378 
0379     smu_v12_0_atom_get_smu_clockinfo(smu->adev,
0380                      (uint8_t)SMU12_SYSPLL1_DCFCLK_ID,
0381                      (uint8_t)SMU12_SYSPLL1_ID,
0382                      &smu->smu_table.boot_values.dcefclk);
0383 
0384     smu_v12_0_atom_get_smu_clockinfo(smu->adev,
0385                      (uint8_t)SMU12_SYSPLL0_VCLK_ID,
0386                      (uint8_t)SMU12_SYSPLL0_ID,
0387                      &smu->smu_table.boot_values.vclk);
0388 
0389     smu_v12_0_atom_get_smu_clockinfo(smu->adev,
0390                      (uint8_t)SMU12_SYSPLL0_DCLK_ID,
0391                      (uint8_t)SMU12_SYSPLL0_ID,
0392                      &smu->smu_table.boot_values.dclk);
0393 
0394     if ((smu->smu_table.boot_values.format_revision == 3) &&
0395         (smu->smu_table.boot_values.content_revision >= 2))
0396         smu_v12_0_atom_get_smu_clockinfo(smu->adev,
0397                          (uint8_t)SMU12_SYSPLL3_0_FCLK_ID,
0398                          (uint8_t)SMU12_SYSPLL3_0_ID,
0399                          &smu->smu_table.boot_values.fclk);
0400 
0401     smu_v12_0_atom_get_smu_clockinfo(smu->adev,
0402                      (uint8_t)SMU12_SYSPLL0_LCLK_ID,
0403                      (uint8_t)SMU12_SYSPLL0_ID,
0404                      &smu->smu_table.boot_values.lclk);
0405 
0406     return 0;
0407 }