summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/amd/pm
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2021-07-30 16:48:35 +1000
committerDave Airlie <airlied@redhat.com>2021-07-30 16:48:35 +1000
commit04d505de7f82c8f2daa6139b460b05dc01e354e0 (patch)
treea5b4f62c721cffa1ff4f1625d76e9d8f79a9d0df /drivers/gpu/drm/amd/pm
parentf1b7996551a40a4ebb551130c83077a0cabcb935 (diff)
parent544dcd74b7093ad4befac99b11d90331aa73348e (diff)
Merge tag 'amd-drm-next-5.15-2021-07-29' of https://gitlab.freedesktop.org/agd5f/linux into drm-next
amd-drm-next-5.15-2021-07-29: amdgpu: - VCN/JPEG power down sequencing fixes - Various navi pcie link handling fixes - Clockgating fixes - Yellow Carp fixes - Beige Goby fixes - Misc code cleanups - S0ix fixes - SMU i2c bus rework - EEPROM handling rework - PSP ucode handling cleanup - SMU error handling rework - AMD HDMI freesync fixes - USB PD firmware update rework - MMIO based vram access rework - Misc display fixes - Backlight fixes - Add initial Cyan Skillfish support - Overclocking fixes suspend/resume amdkfd: - Sysfs leak fix - Add counters for vm faults and migration - GPUVM TLB optimizations radeon: - Misc fixes Signed-off-by: Dave Airlie <airlied@redhat.com> From: Alex Deucher <alexander.deucher@amd.com> Link: https://patchwork.freedesktop.org/patch/msgid/20210730033455.3852-1-alexander.deucher@amd.com
Diffstat (limited to 'drivers/gpu/drm/amd/pm')
-rw-r--r--drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h1
-rw-r--r--drivers/gpu/drm/amd/pm/inc/amdgpu_smu.h8
-rw-r--r--drivers/gpu/drm/amd/pm/inc/smu11_driver_if_cyan_skillfish.h95
-rw-r--r--drivers/gpu/drm/amd/pm/inc/smu11_driver_if_sienna_cichlid.h65
-rw-r--r--drivers/gpu/drm/amd/pm/inc/smu_v11_0.h5
-rw-r--r--drivers/gpu/drm/amd/pm/inc/smu_v11_8_pmfw.h152
-rw-r--r--drivers/gpu/drm/amd/pm/inc/smu_v11_8_ppsmc.h70
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c13
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/Makefile1
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c246
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c76
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.h29
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c173
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c494
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c28
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c243
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c286
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h3
18 files changed, 1312 insertions, 676 deletions
diff --git a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
index f6e0e7d8a007..d03e6fa2bf1a 100644
--- a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
+++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
@@ -450,6 +450,7 @@ struct amdgpu_pm {
/* Used for I2C access to various EEPROMs on relevant ASICs */
struct i2c_adapter smu_i2c;
+ struct mutex smu_i2c_mutex;
struct list_head pm_attr_list;
};
diff --git a/drivers/gpu/drm/amd/pm/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/inc/amdgpu_smu.h
index 3e89852e4820..c2c201b8e3cf 100644
--- a/drivers/gpu/drm/amd/pm/inc/amdgpu_smu.h
+++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_smu.h
@@ -231,6 +231,7 @@ struct smu_user_dpm_profile {
uint32_t power_limit;
uint32_t fan_speed_percent;
uint32_t flags;
+ uint32_t user_od;
/* user clock state information */
uint32_t clk_mask[SMU_CLK_COUNT];
@@ -352,6 +353,7 @@ struct smu_table_context
void *overdrive_table;
void *boot_overdrive_table;
+ void *user_overdrive_table;
uint32_t gpu_metrics_table_size;
void *gpu_metrics_table;
@@ -624,6 +626,12 @@ struct pptable_funcs {
long *input, uint32_t size);
/**
+ * @restore_user_od_settings: Restore the user customized
+ * OD settings on S3/S4/Runpm resume.
+ */
+ int (*restore_user_od_settings)(struct smu_context *smu);
+
+ /**
* @get_clock_by_type_with_latency: Get the speed and latency of a clock
* domain.
*/
diff --git a/drivers/gpu/drm/amd/pm/inc/smu11_driver_if_cyan_skillfish.h b/drivers/gpu/drm/amd/pm/inc/smu11_driver_if_cyan_skillfish.h
new file mode 100644
index 000000000000..8a08ecc34c69
--- /dev/null
+++ b/drivers/gpu/drm/amd/pm/inc/smu11_driver_if_cyan_skillfish.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2021 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 __SMU11_DRIVER_IF_CYAN_SKILLFISH_H__
+#define __SMU11_DRIVER_IF_CYAN_SKILLFISH_H__
+
+// *** IMPORTANT ***
+// Always increment the interface version if
+// any structure is changed in this file
+#define MP1_DRIVER_IF_VERSION 0x8
+
+#define TABLE_BIOS_IF 0 // Called by BIOS
+#define TABLE_WATERMARKS 1 // Called by Driver; defined here, but not used, for backward compatible
+#define TABLE_PMSTATUSLOG 3 // Called by Tools for Agm logging
+#define TABLE_DPMCLOCKS 4 // Called by Driver; defined here, but not used, for backward compatible
+#define TABLE_MOMENTARY_PM 5 // Called by Tools; defined here, but not used, for backward compatible
+#define TABLE_COUNT 6
+
+#define NUM_DSPCLK_LEVELS 8
+#define NUM_SOCCLK_DPM_LEVELS 8
+#define NUM_DCEFCLK_DPM_LEVELS 4
+#define NUM_FCLK_DPM_LEVELS 4
+#define NUM_MEMCLK_DPM_LEVELS 4
+
+#define NUMBER_OF_PSTATES 8
+#define NUMBER_OF_CORES 8
+
+typedef enum {
+ S3_TYPE_ENTRY,
+ S5_TYPE_ENTRY,
+} Sleep_Type_e;
+
+typedef enum {
+ GFX_OFF = 0,
+ GFX_ON = 1,
+} GFX_Mode_e;
+
+typedef enum {
+ CPU_P0 = 0,
+ CPU_P1,
+ CPU_P2,
+ CPU_P3,
+ CPU_P4,
+ CPU_P5,
+ CPU_P6,
+ CPU_P7
+} CPU_PState_e;
+
+typedef enum {
+ CPU_CORE0 = 0,
+ CPU_CORE1,
+ CPU_CORE2,
+ CPU_CORE3,
+ CPU_CORE4,
+ CPU_CORE5,
+ CPU_CORE6,
+ CPU_CORE7
+} CORE_ID_e;
+
+typedef enum {
+ DF_DPM0 = 0,
+ DF_DPM1,
+ DF_DPM2,
+ DF_DPM3,
+ DF_PState_Count
+} DF_PState_e;
+
+typedef enum {
+ GFX_DPM0 = 0,
+ GFX_DPM1,
+ GFX_DPM2,
+ GFX_DPM3,
+ GFX_PState_Count
+} GFX_PState_e;
+
+#endif
diff --git a/drivers/gpu/drm/amd/pm/inc/smu11_driver_if_sienna_cichlid.h b/drivers/gpu/drm/amd/pm/inc/smu11_driver_if_sienna_cichlid.h
index 61c87c39be80..63b8701fd466 100644
--- a/drivers/gpu/drm/amd/pm/inc/smu11_driver_if_sienna_cichlid.h
+++ b/drivers/gpu/drm/amd/pm/inc/smu11_driver_if_sienna_cichlid.h
@@ -131,7 +131,7 @@
#define FEATURE_GFX_EDC_BIT 49
#define FEATURE_GFX_PER_PART_VMIN_BIT 50
#define FEATURE_SMART_SHIFT_BIT 51
-#define FEATURE_SPARE_52_BIT 52
+#define FEATURE_APT_BIT 52
#define FEATURE_SPARE_53_BIT 53
#define FEATURE_SPARE_54_BIT 54
#define FEATURE_SPARE_55_BIT 55
@@ -211,6 +211,7 @@ typedef enum {
#define THROTTLER_FIT_BIT 17
#define THROTTLER_PPM_BIT 18
#define THROTTLER_APCC_BIT 19
+#define THROTTLER_COUNT 20
// FW DState Features Control Bits
// FW DState Features Control Bits
@@ -1406,7 +1407,67 @@ typedef struct {
} SmuMetrics_t;
typedef struct {
- SmuMetrics_t SmuMetrics;
+ uint32_t CurrClock[PPCLK_COUNT];
+
+ uint16_t AverageGfxclkFrequencyPreDs;
+ uint16_t AverageGfxclkFrequencyPostDs;
+ uint16_t AverageFclkFrequencyPreDs;
+ uint16_t AverageFclkFrequencyPostDs;
+ uint16_t AverageUclkFrequencyPreDs ;
+ uint16_t AverageUclkFrequencyPostDs ;
+
+
+ uint16_t AverageGfxActivity ;
+ uint16_t AverageUclkActivity ;
+ uint8_t CurrSocVoltageOffset ;
+ uint8_t CurrGfxVoltageOffset ;
+ uint8_t CurrMemVidOffset ;
+ uint8_t Padding8 ;
+ uint16_t AverageSocketPower ;
+ uint16_t TemperatureEdge ;
+ uint16_t TemperatureHotspot ;
+ uint16_t TemperatureMem ;
+ uint16_t TemperatureVrGfx ;
+ uint16_t TemperatureVrMem0 ;
+ uint16_t TemperatureVrMem1 ;
+ uint16_t TemperatureVrSoc ;
+ uint16_t TemperatureLiquid0 ;
+ uint16_t TemperatureLiquid1 ;
+ uint16_t TemperaturePlx ;
+ uint16_t Padding16 ;
+ uint32_t AccCnt ;
+ uint8_t ThrottlingPercentage[THROTTLER_COUNT];
+
+
+ uint8_t LinkDpmLevel;
+ uint8_t CurrFanPwm;
+ uint16_t CurrFanSpeed;
+
+ //BACO metrics, PMFW-1721
+ //metrics for D3hot entry/exit and driver ARM msgs
+ uint8_t D3HotEntryCountPerMode[D3HOT_SEQUENCE_COUNT];
+ uint8_t D3HotExitCountPerMode[D3HOT_SEQUENCE_COUNT];
+ uint8_t ArmMsgReceivedCountPerMode[D3HOT_SEQUENCE_COUNT];
+
+ //PMFW-4362
+ uint32_t EnergyAccumulator;
+ uint16_t AverageVclk0Frequency ;
+ uint16_t AverageDclk0Frequency ;
+ uint16_t AverageVclk1Frequency ;
+ uint16_t AverageDclk1Frequency ;
+ uint16_t VcnActivityPercentage ; //place holder, David N. to provide full sequence
+ uint8_t PcieRate ;
+ uint8_t PcieWidth ;
+ uint16_t AverageGfxclkFrequencyTarget;
+ uint16_t Padding16_2;
+
+} SmuMetrics_V2_t;
+
+typedef struct {
+ union {
+ SmuMetrics_t SmuMetrics;
+ SmuMetrics_V2_t SmuMetrics_V2;
+ };
uint32_t Spare[1];
// Padding - ignore
diff --git a/drivers/gpu/drm/amd/pm/inc/smu_v11_0.h b/drivers/gpu/drm/amd/pm/inc/smu_v11_0.h
index f61b5c914a3d..403bc1bf8a77 100644
--- a/drivers/gpu/drm/amd/pm/inc/smu_v11_0.h
+++ b/drivers/gpu/drm/amd/pm/inc/smu_v11_0.h
@@ -30,11 +30,12 @@
#define SMU11_DRIVER_IF_VERSION_NV10 0x37
#define SMU11_DRIVER_IF_VERSION_NV12 0x38
#define SMU11_DRIVER_IF_VERSION_NV14 0x38
-#define SMU11_DRIVER_IF_VERSION_Sienna_Cichlid 0x3D
+#define SMU11_DRIVER_IF_VERSION_Sienna_Cichlid 0x40
#define SMU11_DRIVER_IF_VERSION_Navy_Flounder 0xE
#define SMU11_DRIVER_IF_VERSION_VANGOGH 0x03
#define SMU11_DRIVER_IF_VERSION_Dimgrey_Cavefish 0xF
#define SMU11_DRIVER_IF_VERSION_Beige_Goby 0xD
+#define SMU11_DRIVER_IF_VERSION_Cyan_Skillfish 0x8
/* MP Apertures */
#define MP0_Public 0x03800000
@@ -302,5 +303,7 @@ void smu_v11_0_interrupt_work(struct smu_context *smu);
int smu_v11_0_set_light_sbr(struct smu_context *smu, bool enable);
+int smu_v11_0_restore_user_od_settings(struct smu_context *smu);
+
#endif
#endif
diff --git a/drivers/gpu/drm/amd/pm/inc/smu_v11_8_pmfw.h b/drivers/gpu/drm/amd/pm/inc/smu_v11_8_pmfw.h
new file mode 100644
index 000000000000..bd4fcb6b9610
--- /dev/null
+++ b/drivers/gpu/drm/amd/pm/inc/smu_v11_8_pmfw.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2021 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 __SMU_V11_8_0_PMFW_H__
+#define __SMU_V11_8_0_PMFW_H__
+
+#pragma pack(push, 1)
+
+#define ENABLE_DEBUG_FEATURES
+
+// Feature Control Defines
+#define FEATURE_CCLK_CONTROLLER_BIT 0
+#define FEATURE_GFXCLK_EFFT_FREQ_BIT 1
+#define FEATURE_DATA_CALCULATION_BIT 2
+#define FEATURE_THERMAL_BIT 3
+#define FEATURE_PLL_POWER_DOWN_BIT 4
+#define FEATURE_FCLK_DPM_BIT 5
+#define FEATURE_GFX_DPM_BIT 6
+#define FEATURE_DS_GFXCLK_BIT 7
+#define FEATURE_DS_SOCCLK_BIT 8
+#define FEATURE_DS_LCLK_BIT 9
+#define FEATURE_CORE_CSTATES_BIT 10
+#define FEATURE_G6_SSC_BIT 11 //G6 memory UCLK and UCLK_DIV SS
+#define FEATURE_RM_BIT 12
+#define FEATURE_SOC_DPM_BIT 13
+#define FEATURE_DS_SMNCLK_BIT 14
+#define FEATURE_DS_MP1CLK_BIT 15
+#define FEATURE_DS_MP0CLK_BIT 16
+#define FEATURE_MGCG_BIT 17
+#define FEATURE_DS_FUSE_SRAM_BIT 18
+#define FEATURE_GFX_CKS_BIT 19
+#define FEATURE_FP_THROTTLING_BIT 20
+#define FEATURE_PROCHOT_BIT 21
+#define FEATURE_CPUOFF_BIT 22
+#define FEATURE_UMC_THROTTLE_BIT 23
+#define FEATURE_DF_THROTTLE_BIT 24
+#define FEATURE_DS_MP3CLK_BIT 25
+#define FEATURE_DS_SHUBCLK_BIT 26
+#define FEATURE_TDC_BIT 27 //Legacy APM_BIT
+#define FEATURE_UMC_CAL_SHARING_BIT 28
+#define FEATURE_DFLL_BTC_CALIBRATION_BIT 29
+#define FEATURE_EDC_BIT 30
+#define FEATURE_DLDO_BIT 31
+#define FEATURE_MEAS_DRAM_BLACKOUT_BIT 32
+#define FEATURE_CC1_BIT 33
+#define FEATURE_PPT_BIT 34
+#define FEATURE_STAPM_BIT 35
+#define FEATURE_CSTATE_BOOST_BIT 36
+#define FEATURE_SPARE_37_BIT 37
+#define FEATURE_SPARE_38_BIT 38
+#define FEATURE_SPARE_39_BIT 39
+#define FEATURE_SPARE_40_BIT 40
+#define FEATURE_SPARE_41_BIT 41
+#define FEATURE_SPARE_42_BIT 42
+#define FEATURE_SPARE_43_BIT 43
+#define FEATURE_SPARE_44_BIT 44
+#define FEATURE_SPARE_45_BIT 45
+#define FEATURE_SPARE_46_BIT 46
+#define FEATURE_SPARE_47_BIT 47
+#define FEATURE_SPARE_48_BIT 48
+#define FEATURE_SPARE_49_BIT 49
+#define FEATURE_SPARE_50_BIT 50
+#define FEATURE_SPARE_51_BIT 51
+#define FEATURE_SPARE_52_BIT 52
+#define FEATURE_SPARE_53_BIT 53
+#define FEATURE_SPARE_54_BIT 54
+#define FEATURE_SPARE_55_BIT 55
+#define FEATURE_SPARE_56_BIT 56
+#define FEATURE_SPARE_57_BIT 57
+#define FEATURE_SPARE_58_BIT 58
+#define FEATURE_SPARE_59_BIT 59
+#define FEATURE_SPARE_60_BIT 60
+#define FEATURE_SPARE_61_BIT 61
+#define FEATURE_SPARE_62_BIT 62
+#define FEATURE_SPARE_63_BIT 63
+
+#define NUM_FEATURES 64
+
+#define FEATURE_CCLK_CONTROLLER_MASK (1 << FEATURE_CCLK_CONTROLLER_BIT)
+#define FEATURE_DATA_CALCULATION_MASK (1 << FEATURE_DATA_CALCULATION_BIT)
+#define FEATURE_THERMAL_MASK (1 << FEATURE_THERMAL_BIT)
+#define FEATURE_PLL_POWER_DOWN_MASK (1 << FEATURE_PLL_POWER_DOWN_BIT)
+#define FEATURE_FCLK_DPM_MASK (1 << FEATURE_FCLK_DPM_BIT)
+#define FEATURE_GFX_DPM_MASK (1 << FEATURE_GFX_DPM_BIT)
+#define FEATURE_DS_GFXCLK_MASK (1 << FEATURE_DS_GFXCLK_BIT)
+#define FEATURE_DS_SOCCLK_MASK (1 << FEATURE_DS_SOCCLK_BIT)
+#define FEATURE_DS_LCLK_MASK (1 << FEATURE_DS_LCLK_BIT)
+#define FEATURE_RM_MASK (1 << FEATURE_RM_BIT)
+#define FEATURE_DS_SMNCLK_MASK (1 << FEATURE_DS_SMNCLK_BIT)
+#define FEATURE_DS_MP1CLK_MASK (1 << FEATURE_DS_MP1CLK_BIT)
+#define FEATURE_DS_MP0CLK_MASK (1 << FEATURE_DS_MP0CLK_BIT)
+#define FEATURE_MGCG_MASK (1 << FEATURE_MGCG_BIT)
+#define FEATURE_DS_FUSE_SRAM_MASK (1 << FEATURE_DS_FUSE_SRAM_BIT)
+#define FEATURE_PROCHOT_MASK (1 << FEATURE_PROCHOT_BIT)
+#define FEATURE_CPUOFF_MASK (1 << FEATURE_CPUOFF_BIT)
+#define FEATURE_GFX_CKS_MASK (1 << FEATURE_GFX_CKS_BIT)
+#define FEATURE_UMC_THROTTLE_MASK (1 << FEATURE_UMC_THROTTLE_BIT)
+#define FEATURE_DF_THROTTLE_MASK (1 << FEATURE_DF_THROTTLE_BIT)
+#define FEATURE_SOC_DPM_MASK (1 << FEATURE_SOC_DPM_BIT)
+
+typedef struct {
+ // MP1_EXT_SCRATCH0
+ uint32_t SPARE1 : 4;
+ uint32_t SPARE2 : 4;
+ uint32_t SPARE3 : 4;
+ uint32_t CurrLevel_LCLK : 4;
+ uint32_t CurrLevel_MP0CLK : 4;
+ uint32_t CurrLevel_FCLK : 4;
+ uint32_t CurrLevel_SOCCLK : 4;
+ uint32_t CurrLevel_DCEFCLK : 4;
+ // MP1_EXT_SCRATCH1
+ uint32_t SPARE4 : 4;
+ uint32_t SPARE5 : 4;
+ uint32_t SPARE6 : 4;
+ uint32_t TargLevel_LCLK : 4;
+ uint32_t TargLevel_MP0CLK : 4;
+ uint32_t TargLevel_FCLK : 4;
+ uint32_t TargLevel_SOCCLK : 4;
+ uint32_t TargLevel_DCEFCLK : 4;
+ // MP1_EXT_SCRATCH2
+ uint32_t CurrLevel_SHUBCLK : 4;
+ uint32_t TargLevel_SHUBCLK : 4;
+ uint32_t Reserved : 24;
+ // MP1_EXT_SCRATCH3-4
+ uint32_t Reserved2[2];
+ // MP1_EXT_SCRATCH5
+ uint32_t FeatureStatus[NUM_FEATURES / 32];
+} FwStatus_t;
+
+#pragma pack(pop)
+
+#endif
diff --git a/drivers/gpu/drm/amd/pm/inc/smu_v11_8_ppsmc.h b/drivers/gpu/drm/amd/pm/inc/smu_v11_8_ppsmc.h
new file mode 100644
index 000000000000..6e6088760b18
--- /dev/null
+++ b/drivers/gpu/drm/amd/pm/inc/smu_v11_8_ppsmc.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2021 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 SMU_11_8_0_PPSMC_H
+#define SMU_11_8_0_PPSMC_H
+
+// SMU Response Codes:
+#define PPSMC_Result_OK 0x1
+#define PPSMC_Result_Failed 0xFF
+#define PPSMC_Result_UnknownCmd 0xFE
+#define PPSMC_Result_CmdRejectedPrereq 0xFD
+#define PPSMC_Result_CmdRejectedBusy 0xFC
+
+// Message Definitions:
+#define PPSMC_MSG_TestMessage 0x1
+#define PPSMC_MSG_GetSmuVersion 0x2
+#define PPSMC_MSG_GetDriverIfVersion 0x3
+#define PPSMC_MSG_SetDriverTableDramAddrHigh 0x4
+#define PPSMC_MSG_SetDriverTableDramAddrLow 0x5
+#define PPSMC_MSG_TransferTableSmu2Dram 0x6
+#define PPSMC_MSG_TransferTableDram2Smu 0x7
+#define PPSMC_MSG_Rsvd1 0xA
+#define PPSMC_MSG_RequestCorePstate 0xB
+#define PPSMC_MSG_QueryCorePstate 0xC
+#define PPSMC_MSG_Rsvd2 0xD
+#define PPSMC_MSG_RequestGfxclk 0xE
+#define PPSMC_MSG_QueryGfxclk 0xF
+#define PPSMC_MSG_QueryVddcrSocClock 0x11
+#define PPSMC_MSG_QueryDfPstate 0x13
+#define PPSMC_MSG_Rsvd3 0x14
+#define PPSMC_MSG_ConfigureS3PwrOffRegisterAddressHigh 0x16
+#define PPSMC_MSG_ConfigureS3PwrOffRegisterAddressLow 0x17
+#define PPSMC_MSG_RequestActiveWgp 0x18
+#define PPSMC_MSG_SetMinDeepSleepGfxclkFreq 0x19
+#define PPSMC_MSG_SetMaxDeepSleepDfllGfxDiv 0x1A
+#define PPSMC_MSG_StartTelemetryReporting 0x1B
+#define PPSMC_MSG_StopTelemetryReporting 0x1C
+#define PPSMC_MSG_ClearTelemetryMax 0x1D
+#define PPSMC_MSG_QueryActiveWgp 0x1E
+#define PPSMC_MSG_SetCoreEnableMask 0x2C
+#define PPSMC_MSG_InitiateGcRsmuSoftReset 0x2E
+#define PPSMC_MSG_GfxCacWeightOperation 0x2F
+#define PPSMC_MSG_L3CacWeightOperation 0x30
+#define PPSMC_MSG_PackCoreCacWeight 0x31
+#define PPSMC_MSG_SetDriverTableVMID 0x34
+#define PPSMC_MSG_SetSoftMinCclk 0x35
+#define PPSMC_MSG_SetSoftMaxCclk 0x36
+#define PPSMC_Message_Count 0x37
+
+#endif
diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
index ebe672142808..71afc2d20b12 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
@@ -36,6 +36,7 @@
#include "vangogh_ppt.h"
#include "aldebaran_ppt.h"
#include "yellow_carp_ppt.h"
+#include "cyan_skillfish_ppt.h"
#include "amd_pcie.h"
/*
@@ -416,6 +417,15 @@ static void smu_restore_dpm_user_profile(struct smu_context *smu)
}
}
+ /* Restore user customized OD settings */
+ if (smu->user_dpm_profile.user_od) {
+ if (smu->ppt_funcs->restore_user_od_settings) {
+ ret = smu->ppt_funcs->restore_user_od_settings(smu);
+ if (ret)
+ dev_err(smu->adev->dev, "Failed to upload customized OD settings\n");
+ }
+ }
+
/* Disable restore flag */
smu->user_dpm_profile.flags &= ~SMU_DPM_USER_PROFILE_RESTORE;
}
@@ -588,6 +598,9 @@ static int smu_set_funcs(struct amdgpu_device *adev)
case CHIP_YELLOW_CARP:
yellow_carp_set_ppt_funcs(smu);
break;
+ case CHIP_CYAN_SKILLFISH:
+ cyan_skillfish_set_ppt_funcs(smu);
+ break;
default:
return -EINVAL;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/Makefile b/drivers/gpu/drm/amd/pm/swsmu/smu11/Makefile
index 0138c982dfd3..f9b2e16f6431 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/Makefile
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/Makefile
@@ -27,6 +27,7 @@ SMU11_MGR = arcturus_ppt.o \
navi10_ppt.o \
sienna_cichlid_ppt.o \
vangogh_ppt.o \
+ cyan_skillfish_ppt.o \
smu_v11_0.o
AMD_SWSMU_SMU11MGR = $(addprefix $(AMD_SWSMU_PATH)/smu11/,$(SMU11_MGR))
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
index 094df6f87cfc..6ec8492f71f5 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
@@ -1936,197 +1936,77 @@ static int arcturus_dpm_set_vcn_enable(struct smu_context *smu, bool enable)
return ret;
}
-static void arcturus_fill_i2c_req(SwI2cRequest_t *req, bool write,
- uint8_t address, uint32_t numbytes,
- uint8_t *data)
-{
- int i;
-
- req->I2CcontrollerPort = 0;
- req->I2CSpeed = 2;
- req->SlaveAddress = address;
- req->NumCmds = numbytes;
-
- for (i = 0; i < numbytes; i++) {
- SwI2cCmd_t *cmd = &req->SwI2cCmds[i];
-
- /* First 2 bytes are always write for lower 2b EEPROM address */
- if (i < 2)
- cmd->Cmd = 1;
- else
- cmd->Cmd = write;
-
-
- /* Add RESTART for read after address filled */
- cmd->CmdConfig |= (i == 2 && !write) ? CMDCONFIG_RESTART_MASK : 0;
-
- /* Add STOP in the end */
- cmd->CmdConfig |= (i == (numbytes - 1)) ? CMDCONFIG_STOP_MASK : 0;
-
- /* Fill with data regardless if read or write to simplify code */
- cmd->RegisterAddr = data[i];
- }
-}
-
-static int arcturus_i2c_read_data(struct i2c_adapter *control,
- uint8_t address,
- uint8_t *data,
- uint32_t numbytes)
+static int arcturus_i2c_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msg, int num_msgs)
{
- uint32_t i, ret = 0;
- SwI2cRequest_t req;
- struct amdgpu_device *adev = to_amdgpu_device(control);
+ struct amdgpu_device *adev = to_amdgpu_device(i2c_adap);
struct smu_table_context *smu_table = &adev->smu.smu_table;
struct smu_table *table = &smu_table->driver_table;
+ SwI2cRequest_t *req, *res = (SwI2cRequest_t *)table->cpu_addr;
+ int i, j, r, c;
+ u16 dir;
- if (numbytes > MAX_SW_I2C_COMMANDS) {
- dev_err(adev->dev, "numbytes requested %d is over max allowed %d\n",
- numbytes, MAX_SW_I2C_COMMANDS);
- return -EINVAL;
- }
-
- memset(&req, 0, sizeof(req));
- arcturus_fill_i2c_req(&req, false, address, numbytes, data);
-
- mutex_lock(&adev->smu.mutex);
- /* Now read data starting with that address */
- ret = smu_cmn_update_table(&adev->smu, SMU_TABLE_I2C_COMMANDS, 0, &req,
- true);
- mutex_unlock(&adev->smu.mutex);
-
- if (!ret) {
- SwI2cRequest_t *res = (SwI2cRequest_t *)table->cpu_addr;
-
- /* Assume SMU fills res.SwI2cCmds[i].Data with read bytes */
- for (i = 0; i < numbytes; i++)
- data[i] = res->SwI2cCmds[i].Data;
-
- dev_dbg(adev->dev, "arcturus_i2c_read_data, address = %x, bytes = %d, data :",
- (uint16_t)address, numbytes);
-
- print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE,
- 8, 1, data, numbytes, false);
- } else
- dev_err(adev->dev, "arcturus_i2c_read_data - error occurred :%x", ret);
+ req = kzalloc(sizeof(*req), GFP_KERNEL);
+ if (!req)
+ return -ENOMEM;
- return ret;
-}
+ req->I2CcontrollerPort = 0;
+ req->I2CSpeed = I2C_SPEED_FAST_400K;
+ req->SlaveAddress = msg[0].addr << 1; /* wants an 8-bit address */
+ dir = msg[0].flags & I2C_M_RD;
+
+ for (c = i = 0; i < num_msgs; i++) {
+ for (j = 0; j < msg[i].len; j++, c++) {
+ SwI2cCmd_t *cmd = &req->SwI2cCmds[c];
+
+ if (!(msg[i].flags & I2C_M_RD)) {
+ /* write */
+ cmd->Cmd = I2C_CMD_WRITE;
+ cmd->RegisterAddr = msg[i].buf[j];
+ }
-static int arcturus_i2c_write_data(struct i2c_adapter *control,
- uint8_t address,
- uint8_t *data,
- uint32_t numbytes)
-{
- uint32_t ret;
- SwI2cRequest_t req;
- struct amdgpu_device *adev = to_amdgpu_device(control);
+ if ((dir ^ msg[i].flags) & I2C_M_RD) {
+ /* The direction changes.
+ */
+ dir = msg[i].flags & I2C_M_RD;
+ cmd->CmdConfig |= CMDCONFIG_RESTART_MASK;
+ }
- if (numbytes > MAX_SW_I2C_COMMANDS) {
- dev_err(adev->dev, "numbytes requested %d is over max allowed %d\n",
- numbytes, MAX_SW_I2C_COMMANDS);
- return -EINVAL;
+ req->NumCmds++;
+
+ /*
+ * Insert STOP if we are at the last byte of either last
+ * message for the transaction or the client explicitly
+ * requires a STOP at this particular message.
+ */
+ if ((j == msg[i].len - 1) &&
+ ((i == num_msgs - 1) || (msg[i].flags & I2C_M_STOP))) {
+ cmd->CmdConfig &= ~CMDCONFIG_RESTART_MASK;
+ cmd->CmdConfig |= CMDCONFIG_STOP_MASK;
+ }
+ }
}
-
- memset(&req, 0, sizeof(req));
- arcturus_fill_i2c_req(&req, true, address, numbytes, data);
-
mutex_lock(&adev->smu.mutex);
- ret = smu_cmn_update_table(&adev->smu, SMU_TABLE_I2C_COMMANDS, 0, &req, true);
+ r = smu_cmn_update_table(&adev->smu, SMU_TABLE_I2C_COMMANDS, 0, req, true);
mutex_unlock(&adev->smu.mutex);
+ if (r)
+ goto fail;
- if (!ret) {
- dev_dbg(adev->dev, "arcturus_i2c_write(), address = %x, bytes = %d , data: ",
- (uint16_t)address, numbytes);
-
- print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE,
- 8, 1, data, numbytes, false);
- /*
- * According to EEPROM spec there is a MAX of 10 ms required for
- * EEPROM to flush internal RX buffer after STOP was issued at the
- * end of write transaction. During this time the EEPROM will not be
- * responsive to any more commands - so wait a bit more.
- */
- msleep(10);
-
- } else
- dev_err(adev->dev, "arcturus_i2c_write- error occurred :%x", ret);
-
- return ret;
-}
-
-static int arcturus_i2c_xfer(struct i2c_adapter *i2c_adap,
- struct i2c_msg *msgs, int num)
-{
- uint32_t i, j, ret, data_size, data_chunk_size, next_eeprom_addr = 0;
- uint8_t *data_ptr, data_chunk[MAX_SW_I2C_COMMANDS] = { 0 };
-
- for (i = 0; i < num; i++) {
- /*
- * SMU interface allows at most MAX_SW_I2C_COMMANDS bytes of data at
- * once and hence the data needs to be spliced into chunks and sent each
- * chunk separately
- */
- data_size = msgs[i].len - 2;
- data_chunk_size = MAX_SW_I2C_COMMANDS - 2;
- next_eeprom_addr = (msgs[i].buf[0] << 8 & 0xff00) | (msgs[i].buf[1] & 0xff);
- data_ptr = msgs[i].buf + 2;
-
- for (j = 0; j < data_size / data_chunk_size; j++) {
- /* Insert the EEPROM dest addess, bits 0-15 */
- data_chunk[0] = ((next_eeprom_addr >> 8) & 0xff);
- data_chunk[1] = (next_eeprom_addr & 0xff);
-
- if (msgs[i].flags & I2C_M_RD) {
- ret = arcturus_i2c_read_data(i2c_adap,
- (uint8_t)msgs[i].addr,
- data_chunk, MAX_SW_I2C_COMMANDS);
-
- memcpy(data_ptr, data_chunk + 2, data_chunk_size);
- } else {
-
- memcpy(data_chunk + 2, data_ptr, data_chunk_size);
-
- ret = arcturus_i2c_write_data(i2c_adap,
- (uint8_t)msgs[i].addr,
- data_chunk, MAX_SW_I2C_COMMANDS);
- }
-
- if (ret) {
- num = -EIO;
- goto fail;
- }
-
- next_eeprom_addr += data_chunk_size;
- data_ptr += data_chunk_size;
+ for (c = i = 0; i < num_msgs; i++) {
+ if (!(msg[i].flags & I2C_M_RD)) {
+ c += msg[i].len;
+ continue;
}
+ for (j = 0; j < msg[i].len; j++, c++) {
+ SwI2cCmd_t *cmd = &res->SwI2cCmds[c];
- if (data_size % data_chunk_size) {
- data_chunk[0] = ((next_eeprom_addr >> 8) & 0xff);
- data_chunk[1] = (next_eeprom_addr & 0xff);
-
- if (msgs[i].flags & I2C_M_RD) {
- ret = arcturus_i2c_read_data(i2c_adap,
- (uint8_t)msgs[i].addr,
- data_chunk, (data_size % data_chunk_size) + 2);
-
- memcpy(data_ptr, data_chunk + 2, data_size % data_chunk_size);
- } else {
- memcpy(data_chunk + 2, data_ptr, data_size % data_chunk_size);
-
- ret = arcturus_i2c_write_data(i2c_adap,
- (uint8_t)msgs[i].addr,
- data_chunk, (data_size % data_chunk_size) + 2);
- }
-
- if (ret) {
- num = -EIO;
- goto fail;
- }
+ msg[i].buf[j] = cmd->Data;
}
}
-
+ r = num_msgs;
fail:
- return num;
+ kfree(req);
+ return r;
}
static u32 arcturus_i2c_func(struct i2c_adapter *adap)
@@ -2140,15 +2020,25 @@ static const struct i2c_algorithm arcturus_i2c_algo = {
.functionality = arcturus_i2c_func,
};
+
+static const struct i2c_adapter_quirks arcturus_i2c_control_quirks = {
+ .flags = I2C_AQ_COMB | I2C_AQ_COMB_SAME_ADDR | I2C_AQ_NO_ZERO_LEN,
+ .max_read_len = MAX_SW_I2C_COMMANDS,
+ .max_write_len = MAX_SW_I2C_COMMANDS,
+ .max_comb_1st_msg_len = 2,
+ .max_comb_2nd_msg_len = MAX_SW_I2C_COMMANDS - 2,
+};
+
static int arcturus_i2c_control_init(struct smu_context *smu, struct i2c_adapter *control)
{
struct amdgpu_device *adev = to_amdgpu_device(control);
int res;
control->owner = THIS_MODULE;
- control->class = I2C_CLASS_SPD;
+ control->class = I2C_CLASS_HWMON;
control->dev.parent = &adev->pdev->dev;
control->algo = &arcturus_i2c_algo;
+ control->quirks = &arcturus_i2c_control_quirks;
snprintf(control->name, sizeof(control->name), "AMDGPU SMU");
res = i2c_add_adapter(control);
@@ -2288,7 +2178,9 @@ static void arcturus_log_thermal_throttling_event(struct smu_context *smu)
dev_warn(adev->dev, "WARN: GPU thermal throttling temperature reached, expect performance decrease. %s.\n",
log_buf);
- kgd2kfd_smi_event_throttle(smu->adev->kfd.dev, throttler_status);
+ kgd2kfd_smi_event_throttle(smu->adev->kfd.dev,
+ smu_cmn_get_indep_throttler_status(throttler_status,
+ arcturus_throttler_map));
}
static uint16_t arcturus_get_current_pcie_link_speed(struct smu_context *smu)
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c
new file mode 100644
index 000000000000..b05f9541accc
--- /dev/null
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2021 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.
+ *
+ */
+
+#define SWSMU_CODE_LAYER_L2
+
+#include "amdgpu.h"
+#include "amdgpu_smu.h"
+#include "smu_v11_0.h"
+#include "smu11_driver_if_cyan_skillfish.h"
+#include "cyan_skillfish_ppt.h"
+#include "smu_v11_8_ppsmc.h"
+#include "smu_v11_8_pmfw.h"
+#include "smu_cmn.h"
+#include "soc15_common.h"
+
+/*
+ * DO NOT use these for err/warn/info/debug messages.
+ * Use dev_err, dev_warn, dev_info and dev_dbg instead.
+ * They are more MGPU friendly.
+ */
+
+#undef pr_err
+#undef pr_warn
+#undef pr_info
+#undef pr_debug
+
+static struct cmn2asic_msg_mapping cyan_skillfish_message_map[SMU_MSG_MAX_COUNT] = {
+ MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 0),
+ MSG_MAP(GetSmuVersion, PPSMC_MSG_GetSmuVersion, 0),
+ MSG_MAP(GetDriverIfVersion, PPSMC_MSG_GetDriverIfVersion, 0),
+ MSG_MAP(SetDriverDramAddrHigh, PPSMC_MSG_SetDriverTableDramAddrHigh, 0),
+ MSG_MAP(SetDriverDramAddrLow, PPSMC_MSG_SetDriverTableDramAddrLow, 0),
+ MSG_MAP(TransferTableSmu2Dram, PPSMC_MSG_TransferTableSmu2Dram, 0),
+ MSG_MAP(TransferTableDram2Smu, PPSMC_MSG_TransferTableDram2Smu, 0),
+};
+
+static const struct pptable_funcs cyan_skillfish_ppt_funcs = {
+
+ .check_fw_status = smu_v11_0_check_fw_status,
+ .check_fw_version = smu_v11_0_check_fw_version,
+ .init_power = smu_v11_0_init_power,
+ .fini_power = smu_v11_0_fini_power,
+ .register_irq_handler = smu_v11_0_register_irq_handler,
+ .notify_memory_pool_location = smu_v11_0_notify_memory_pool_location,
+ .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param,
+ .send_smc_msg = smu_cmn_send_smc_msg,
+ .set_driver_table_location = smu_v11_0_set_driver_table_location,
+ .interrupt_work = smu_v11_0_interrupt_work,
+};
+
+void cyan_skillfish_set_ppt_funcs(struct smu_context *smu)
+{
+ smu->ppt_funcs = &cyan_skillfish_ppt_funcs;
+ smu->message_map = cyan_skillfish_message_map;
+ smu->is_apu = true;
+}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.h b/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.h
new file mode 100644
index 000000000000..76cd7229e383
--- /dev/null
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2021 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 __CYAN_SKILLFISH_PPT_H__
+#define __CYAN_SKILLFISH_PPT_H__
+
+extern void cyan_skillfish_set_ppt_funcs(struct smu_context *smu);
+
+#endif
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
index 1ba42b69ce74..d7722c229ddd 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
@@ -2294,41 +2294,52 @@ static int navi10_set_default_od_settings(struct smu_context *smu)
(OverDriveTable_t *)smu->smu_table.overdrive_table;
OverDriveTable_t *boot_od_table =
(OverDriveTable_t *)smu->smu_table.boot_overdrive_table;
+ OverDriveTable_t *user_od_table =
+ (OverDriveTable_t *)smu->smu_table.user_overdrive_table;
int ret = 0;
- ret = smu_cmn_update_table(smu, SMU_TABLE_OVERDRIVE, 0, (void *)od_table, false);
+ /*
+ * For S3/S4/Runpm resume, no need to setup those overdrive tables again as
+ * - either they already have the default OD settings got during cold bootup
+ * - or they have some user customized OD settings which cannot be overwritten
+ */
+ if (smu->adev->in_suspend)
+ return 0;
+
+ ret = smu_cmn_update_table(smu, SMU_TABLE_OVERDRIVE, 0, (void *)boot_od_table, false);
if (ret) {
dev_err(smu->adev->dev, "Failed to get overdrive table!\n");
return ret;
}
- if (!od_table->GfxclkVolt1) {
+ if (!boot_od_table->GfxclkVolt1) {
ret = navi10_overdrive_get_gfx_clk_base_voltage(smu,
- &od_table->GfxclkVolt1,
- od_table->GfxclkFreq1);
+ &boot_od_table->GfxclkVolt1,
+ boot_od_table->GfxclkFreq1);
if (ret)
return ret;
}
- if (!od_table->GfxclkVolt2) {
+ if (!boot_od_table->GfxclkVolt2) {
ret = navi10_overdrive_get_gfx_clk_base_voltage(smu,
- &od_table->GfxclkVolt2,
- od_table->GfxclkFreq2);
+ &boot_od_table->GfxclkVolt2,
+ boot_od_table->GfxclkFreq2);
if (ret)
return ret;
}
- if (!od_table->GfxclkVolt3) {
+ if (!boot_od_table->GfxclkVolt3) {
ret = navi10_overdrive_get_gfx_clk_base_voltage(smu,
- &od_table->GfxclkVolt3,
- od_table->GfxclkFreq3);
+ &boot_od_table->GfxclkVolt3,
+ boot_od_table->GfxclkFreq3);
if (ret)
return ret;
}
- memcpy(boot_od_table, od_table, sizeof(OverDriveTable_t));
+ navi10_dump_od_table(smu, boot_od_table);
- navi10_dump_od_table(smu, od_table);
+ memcpy(od_table, boot_od_table, sizeof(OverDriveTable_t));
+ memcpy(user_od_table, boot_od_table, sizeof(OverDriveTable_t));
return 0;
}
@@ -2429,11 +2440,20 @@ static int navi10_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABL
memcpy(table_context->overdrive_table, table_context->boot_overdrive_table, sizeof(OverDriveTable_t));
break;
case PP_OD_COMMIT_DPM_TABLE:
- navi10_dump_od_table(smu, od_table);
- ret = smu_cmn_update_table(smu, SMU_TABLE_OVERDRIVE, 0, (void *)od_table, true);
- if (ret) {
- dev_err(smu->adev->dev, "Failed to import overdrive table!\n");
- return ret;
+ if (memcmp(od_table, table_context->user_overdrive_table, sizeof(OverDriveTable_t))) {
+ navi10_dump_od_table(smu, od_table);
+ ret = smu_cmn_update_table(smu, SMU_TABLE_OVERDRIVE, 0, (void *)od_table, true);
+ if (ret) {
+ dev_err(smu->adev->dev, "Failed to import overdrive table!\n");
+ return ret;
+ }
+ memcpy(table_context->user_overdrive_table, od_table, sizeof(OverDriveTable_t));
+ smu->user_dpm_profile.user_od = true;
+
+ if (!memcmp(table_context->user_overdrive_table,
+ table_context->boot_overdrive_table,
+ sizeof(OverDriveTable_t)))
+ smu->user_dpm_profile.user_od = false;
}
break;
case PP_OD_EDIT_VDDC_CURVE:
@@ -2735,6 +2755,122 @@ static ssize_t navi10_get_legacy_gpu_metrics(struct smu_context *smu,
return sizeof(struct gpu_metrics_v1_3);
}
+static int navi10_i2c_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msg, int num_msgs)
+{
+ struct amdgpu_device *adev = to_amdgpu_device(i2c_adap);
+ struct smu_table_context *smu_table = &adev->smu.smu_table;
+ struct smu_table *table = &smu_table->driver_table;
+ SwI2cRequest_t *req, *res = (SwI2cRequest_t *)table->cpu_addr;
+ int i, j, r, c;
+ u16 dir;
+
+ req = kzalloc(sizeof(*req), GFP_KERNEL);
+ if (!req)
+ return -ENOMEM;
+
+ req->I2CcontrollerPort = 0;
+ req->I2CSpeed = I2C_SPEED_FAST_400K;
+ req->SlaveAddress = msg[0].addr << 1; /* wants an 8-bit address */
+ dir = msg[0].flags & I2C_M_RD;
+
+ for (c = i = 0; i < num_msgs; i++) {
+ for (j = 0; j < msg[i].len; j++, c++) {
+ SwI2cCmd_t *cmd = &req->SwI2cCmds[c];
+
+ if (!(msg[i].flags & I2C_M_RD)) {
+ /* write */
+ cmd->Cmd = I2C_CMD_WRITE;
+ cmd->RegisterAddr = msg[i].buf[j];
+ }
+
+ if ((dir ^ msg[i].flags) & I2C_M_RD) {
+ /* The direction changes.
+ */
+ dir = msg[i].flags & I2C_M_RD;
+ cmd->CmdConfig |= CMDCONFIG_RESTART_MASK;
+ }
+
+ req->NumCmds++;
+
+ /*
+ * Insert STOP if we are at the last byte of either last
+ * message for the transaction or the client explicitly
+ * requires a STOP at this particular message.
+ */
+ if ((j == msg[i].len - 1) &&
+ ((i == num_msgs - 1) || (msg[i].flags & I2C_M_STOP))) {
+ cmd->CmdConfig &= ~CMDCONFIG_RESTART_MASK;
+ cmd->CmdConfig |= CMDCONFIG_STOP_MASK;
+ }
+ }
+ }
+ mutex_lock(&adev->smu.mutex);
+ r = smu_cmn_update_table(&adev->smu, SMU_TABLE_I2C_COMMANDS, 0, req, true);
+ mutex_unlock(&adev->smu.mutex);
+ if (r)
+ goto fail;
+
+ for (c = i = 0; i < num_msgs; i++) {
+ if (!(msg[i].flags & I2C_M_RD)) {
+ c += msg[i].len;
+ continue;
+ }
+ for (j = 0; j < msg[i].len; j++, c++) {
+ SwI2cCmd_t *cmd = &res->SwI2cCmds[c];
+
+ msg[i].buf[j] = cmd->Data;
+ }
+ }
+ r = num_msgs;
+fail:
+ kfree(req);
+ return r;
+}
+
+static u32 navi10_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+
+static const struct i2c_algorithm navi10_i2c_algo = {
+ .master_xfer = navi10_i2c_xfer,
+ .functionality = navi10_i2c_func,
+};
+
+static const struct i2c_adapter_quirks navi10_i2c_control_quirks = {
+ .flags = I2C_AQ_COMB | I2C_AQ_COMB_SAME_ADDR | I2C_AQ_NO_ZERO_LEN,
+ .max_read_len = MAX_SW_I2C_COMMANDS,
+ .max_write_len = MAX_SW_I2C_COMMANDS,
+ .max_comb_1st_msg_len = 2,
+ .max_comb_2nd_msg_len = MAX_SW_I2C_COMMANDS - 2,
+};
+
+static int navi10_i2c_control_init(struct smu_context *smu, struct i2c_adapter *control)
+{
+ struct amdgpu_device *adev = to_amdgpu_device(control);
+ int res;
+
+ control->owner = THIS_MODULE;
+ control->class = I2C_CLASS_HWMON;
+ control->dev.parent = &adev->pdev->dev;
+ control->algo = &navi10_i2c_algo;
+ snprintf(control->name, sizeof(control->name), "AMDGPU SMU");
+ control->quirks = &navi10_i2c_control_quirks;
+
+ res = i2c_add_adapter(control);
+ if (res)
+ DRM_ERROR("Failed to register hw i2c, err: %d\n", res);
+
+ return res;
+}
+
+static void navi10_i2c_control_fini(struct smu_context *smu, struct i2c_adapter *control)
+{
+ i2c_del_adapter(control);
+}
+
static ssize_t navi10_get_gpu_metrics(struct smu_context *smu,
void **table)
{
@@ -3078,6 +3214,8 @@ static const struct pptable_funcs navi10_ppt_funcs = {
.set_default_dpm_table = navi10_set_default_dpm_table,
.dpm_set_vcn_enable = navi10_dpm_set_vcn_enable,
.dpm_set_jpeg_enable = navi10_dpm_set_jpeg_enable,
+ .i2c_init = navi10_i2c_control_init,
+ .i2c_fini = navi10_i2c_control_fini,
.print_clk_levels = navi10_print_clk_levels,
.force_clk_levels = navi10_force_clk_levels,
.populate_umd_state_clk = navi10_populate_umd_state_clk,
@@ -3144,6 +3282,7 @@ static const struct pptable_funcs navi10_ppt_funcs = {
.set_soft_freq_limited_range = smu_v11_0_set_soft_freq_limited_range,
.set_default_od_settings = navi10_set_default_od_settings,
.od_edit_dpm_table = navi10_od_edit_dpm_table,
+ .restore_user_od_settings = smu_v11_0_restore_user_od_settings,
.run_btc = navi10_run_btc,
.set_power_source = smu_v11_0_set_power_source,
.get_pp_feature_mask = smu_cmn_get_pp_feature_mask,
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
index c751f717a0da..90e40aacb8f6 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
@@ -489,6 +489,26 @@ err0_out:
return -ENOMEM;
}
+static uint32_t sienna_cichlid_get_throttler_status_locked(struct smu_context *smu)
+{
+ struct smu_table_context *smu_table= &smu->smu_table;
+ SmuMetricsExternal_t *metrics_ext =
+ (SmuMetricsExternal_t *)(smu_table->metrics_table);
+ uint32_t throttler_status = 0;
+ int i;
+
+ if ((smu->adev->asic_type == CHIP_SIENNA_CICHLID) &&
+ (smu->smc_fw_version >= 0x3A4300)) {
+ for (i = 0; i < THROTTLER_COUNT; i++)
+ throttler_status |=
+ (metrics_ext->SmuMetrics_V2.ThrottlingPercentage[i] ? 1U << i : 0);
+ } else {
+ throttler_status = metrics_ext->SmuMetrics.ThrottlerStatus;
+ }
+
+ return throttler_status;
+}
+
static int sienna_cichlid_get_smu_metrics_data(struct smu_context *smu,
MetricsMember_t member,
uint32_t *value)
@@ -496,6 +516,11 @@ static int sienna_cichlid_get_smu_metrics_data(struct smu_context *smu,
struct smu_table_context *smu_table= &smu->smu_table;
SmuMetrics_t *metrics =
&(((SmuMetricsExternal_t *)(smu_table->metrics_table))->SmuMetrics);
+ SmuMetrics_V2_t *metrics_v2 =
+ &(((SmuMetricsExternal_t *)(smu_table->metrics_table))->SmuMetrics_V2);
+ bool use_metrics_v2 = ((smu->adev->asic_type == CHIP_SIENNA_CICHLID) &&
+ (smu->smc_fw_version >= 0x3A4300)) ? true : false;
+ uint16_t average_gfx_activity;
int ret = 0;
mutex_lock(&smu->metrics_lock);
@@ -510,78 +535,96 @@ static int sienna_cichlid_get_smu_metrics_data(struct smu_context *smu,
switch (member) {
case METRICS_CURR_GFXCLK:
- *value = metrics->CurrClock[PPCLK_GFXCLK];
+ *value = use_metrics_v2 ? metrics_v2->CurrClock[PPCLK_GFXCLK] :
+ metrics->CurrClock[PPCLK_GFXCLK];
break;
case METRICS_CURR_SOCCLK:
- *value = metrics->CurrClock[PPCLK_SOCCLK];
+ *value = use_metrics_v2 ? metrics_v2->CurrClock[PPCLK_SOCCLK] :
+ metrics->CurrClock[PPCLK_SOCCLK];
break;
case METRICS_CURR_UCLK:
- *value = metrics->CurrClock[PPCLK_UCLK];
+ *value = use_metrics_v2 ? metrics_v2->CurrClock[PPCLK_UCLK] :
+ metrics->CurrClock[PPCLK_UCLK];
break;
case METRICS_CURR_VCLK:
- *value = metrics->CurrClock[PPCLK_VCLK_0];
+ *value = use_metrics_v2 ? metrics_v2->CurrClock[PPCLK_VCLK_0] :
+ metrics->CurrClock[PPCLK_VCLK_0];
break;
case METRICS_CURR_VCLK1:
- *value = metrics->CurrClock[PPCLK_VCLK_1];
+ *value = use_metrics_v2 ? metrics_v2->CurrClock[PPCLK_VCLK_1] :
+ metrics->CurrClock[PPCLK_VCLK_1];
break;
case METRICS_CURR_DCLK:
- *value = metrics->CurrClock[PPCLK_DCLK_0];
+ *value = use_metrics_v2 ? metrics_v2->CurrClock[PPCLK_DCLK_0] :
+ metrics->CurrClock[PPCLK_DCLK_0];
break;
case METRICS_CURR_DCLK1:
- *value = metrics->CurrClock[PPCLK_DCLK_1];
+ *value = use_metrics_v2 ? metrics_v2->CurrClock[PPCLK_DCLK_1] :
+ metrics->CurrClock[PPCLK_DCLK_1];
break;
case METRICS_CURR_DCEFCLK:
- *value = metrics->CurrClock[PPCLK_DCEFCLK];
+ *value = use_metrics_v2 ? metrics_v2->CurrClock[PPCLK_DCEFCLK] :
+ metrics->CurrClock[PPCLK_DCEFCLK];
break;
case METRICS_CURR_FCLK:
- *value = metrics->CurrClock[PPCLK_FCLK];
+ *value = use_metrics_v2 ? metrics_v2->CurrClock[PPCLK_FCLK] :
+ metrics->CurrClock[PPCLK_FCLK];
break;
case METRICS_AVERAGE_GFXCLK:
- if (metrics->AverageGfxActivity <= SMU_11_0_7_GFX_BUSY_THRESHOLD)
- *value = metrics->AverageGfxclkFrequencyPostDs;
+ average_gfx_activity = use_metrics_v2 ? metrics_v2->AverageGfxActivity :
+ metrics->AverageGfxActivity;
+ if (average_gfx_activity <= SMU_11_0_7_GFX_BUSY_THRESHOLD)
+ *value = use_metrics_v2 ? metrics_v2->AverageGfxclkFrequencyPostDs :
+ metrics->AverageGfxclkFrequencyPostDs;
else
- *value = metrics->AverageGfxclkFrequencyPreDs;
+ *value = use_metrics_v2 ? metrics_v2->AverageGfxclkFrequencyPreDs :
+ metrics->AverageGfxclkFrequencyPreDs;
break;
case METRICS_AVERAGE_FCLK:
- *value = metrics->AverageFclkFrequencyPostDs;
+ *value = use_metrics_v2 ? metrics_v2->AverageFclkFrequencyPostDs :
+ metrics->AverageFclkFrequencyPostDs;
break;
case METRICS_AVERAGE_UCLK:
- *value = metrics->AverageUclkFrequencyPostDs;
+ *value = use_metrics_v2 ? metrics_v2->AverageUclkFrequencyPostDs :
+ metrics->AverageUclkFrequencyPostDs;
break;
case METRICS_AVERAGE_GFXACTIVITY:
- *value = metrics->AverageGfxActivity;
+ *value = use_metrics_v2 ? metrics_v2->AverageGfxActivity :
+ metrics->AverageGfxActivity;
break;
case METRICS_AVERAGE_MEMACTIVITY:
- *value = metrics->AverageUclkActivity;
+ *value = use_metrics_v2 ? metrics_v2->AverageUclkActivity :
+ metrics->AverageUclkActivity;
break;
case METRICS_AVERAGE_SOCKETPOWER:
- *value = metrics->AverageSocketPower << 8;
+ *value = use_metrics_v2 ? metrics_v2->AverageSocketPower << 8 :
+ metrics->AverageSocketPower << 8;
break;
case METRICS_TEMPERATURE_EDGE:
- *value = metrics->TemperatureEdge *
+ *value = (use_metrics_v2 ? metrics_v2->TemperatureEdge : metrics->TemperatureEdge) *
SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
break;
case METRICS_TEMPERATURE_HOTSPOT:
- *value = metrics->TemperatureHotspot *
+ *value = (use_metrics_v2 ? metrics_v2->TemperatureHotspot : metrics->TemperatureHotspot) *
SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
break;
case METRICS_TEMPERATURE_MEM:
- *value = metrics->TemperatureMem *
+ *value = (use_metrics_v2 ? metrics_v2->TemperatureMem : metrics->TemperatureMem) *
SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
break;
case METRICS_TEMPERATURE_VRGFX:
- *value = metrics->TemperatureVrGfx *
+ *value = (use_metrics_v2 ? metrics_v2->TemperatureVrGfx : metrics->TemperatureVrGfx) *
SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
break;
case METRICS_TEMPERATURE_VRSOC:
- *value = metrics->TemperatureVrSoc *
+ *value = (use_metrics_v2 ? metrics_v2->TemperatureVrSoc : metrics->TemperatureVrSoc) *
SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
break;
case METRICS_THROTTLER_STATUS:
- *value = metrics->ThrottlerStatus;
+ *value = sienna_cichlid_get_throttler_status_locked(smu);
break;
case METRICS_CURR_FANSPEED:
- *value = metrics->CurrFanSpeed;
+ *value = use_metrics_v2 ? metrics_v2->CurrFanSpeed : metrics->CurrFanSpeed;
break;
default:
*value = UINT_MAX;
@@ -1911,18 +1954,29 @@ static int sienna_cichlid_set_default_od_settings(struct smu_context *smu)
(OverDriveTable_t *)smu->smu_table.overdrive_table;
OverDriveTable_t *boot_od_table =
(OverDriveTable_t *)smu->smu_table.boot_overdrive_table;
+ OverDriveTable_t *user_od_table =
+ (OverDriveTable_t *)smu->smu_table.user_overdrive_table;
int ret = 0;
+ /*
+ * For S3/S4/Runpm resume, no need to setup those overdrive tables again as
+ * - either they already have the default OD settings got during cold bootup
+ * - or they have some user customized OD settings which cannot be overwritten
+ */
+ if (smu->adev->in_suspend)
+ return 0;
+
ret = smu_cmn_update_table(smu, SMU_TABLE_OVERDRIVE,
- 0, (void *)od_table, false);
+ 0, (void *)boot_od_table, false);
if (ret) {
dev_err(smu->adev->dev, "Failed to get overdrive table!\n");
return ret;
}
- memcpy(boot_od_table, od_table, sizeof(OverDriveTable_t));
+ sienna_cichlid_dump_od_table(smu, boot_od_table);
- sienna_cichlid_dump_od_table(smu, od_table);
+ memcpy(od_table, boot_od_table, sizeof(OverDriveTable_t));
+ memcpy(user_od_table, boot_od_table, sizeof(OverDriveTable_t));
return 0;
}
@@ -2085,13 +2139,20 @@ static int sienna_cichlid_od_edit_dpm_table(struct smu_context *smu,
fallthrough;
case PP_OD_COMMIT_DPM_TABLE:
- sienna_cichlid_dump_od_table(smu, od_table);
+ if (memcmp(od_table, table_context->user_overdrive_table, sizeof(OverDriveTable_t))) {
+ sienna_cichlid_dump_od_table(smu, od_table);
+ ret = smu_cmn_update_table(smu, SMU_TABLE_OVERDRIVE, 0, (void *)od_table, true);
+ if (ret) {
+ dev_err(smu->adev->dev, "Failed to import overdrive table!\n");
+ return ret;
+ }
+ memcpy(table_context->user_overdrive_table, od_table, sizeof(OverDriveTable_t));
+ smu->user_dpm_profile.user_od = true;
- ret = smu_cmn_update_table(smu, SMU_TABLE_OVERDRIVE,
- 0, (void *)od_table, true);
- if (ret) {
- dev_err(smu->adev->dev, "Failed to import overdrive table!\n");
- return ret;
+ if (!memcmp(table_context->user_overdrive_table,
+ table_context->boot_overdrive_table,
+ sizeof(OverDriveTable_t)))
+ smu->user_dpm_profile.user_od = false;
}
break;
@@ -3442,197 +3503,77 @@ static void sienna_cichlid_dump_pptable(struct smu_context *smu)
dev_info(smu->adev->dev, "MmHubPadding[7] = 0x%x\n", pptable->MmHubPadding[7]);
}
-static void sienna_cichlid_fill_i2c_req(SwI2cRequest_t *req, bool write,
- uint8_t address, uint32_t numbytes,
- uint8_t *data)
-{
- int i;
-
- req->I2CcontrollerPort = 1;
- req->I2CSpeed = 2;
- req->SlaveAddress = address;
- req->NumCmds = numbytes;
-
- for (i = 0; i < numbytes; i++) {
- SwI2cCmd_t *cmd = &req->SwI2cCmds[i];
-
- /* First 2 bytes are always write for lower 2b EEPROM address */
- if (i < 2)
- cmd->CmdConfig = CMDCONFIG_READWRITE_MASK;
- else
- cmd->CmdConfig = write ? CMDCONFIG_READWRITE_MASK : 0;
-
-
- /* Add RESTART for read after address filled */
- cmd->CmdConfig |= (i == 2 && !write) ? CMDCONFIG_RESTART_MASK : 0;
-
- /* Add STOP in the end */
- cmd->CmdConfig |= (i == (numbytes - 1)) ? CMDCONFIG_STOP_MASK : 0;
-
- /* Fill with data regardless if read or write to simplify code */
- cmd->ReadWriteData = data[i];
- }
-}
-
-static int sienna_cichlid_i2c_read_data(struct i2c_adapter *control,
- uint8_t address,
- uint8_t *data,
- uint32_t numbytes)
+static int sienna_cichlid_i2c_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msg, int num_msgs)
{
- uint32_t i, ret = 0;
- SwI2cRequest_t req;
- struct amdgpu_device *adev = to_amdgpu_device(control);
+ struct amdgpu_device *adev = to_amdgpu_device(i2c_adap);
struct smu_table_context *smu_table = &adev->smu.smu_table;
struct smu_table *table = &smu_table->driver_table;
+ SwI2cRequest_t *req, *res = (SwI2cRequest_t *)table->cpu_addr;
+ int i, j, r, c;
+ u16 dir;
- if (numbytes > MAX_SW_I2C_COMMANDS) {
- dev_err(adev->dev, "numbytes requested %d is over max allowed %d\n",
- numbytes, MAX_SW_I2C_COMMANDS);
- return -EINVAL;
- }
-
- memset(&req, 0, sizeof(req));
- sienna_cichlid_fill_i2c_req(&req, false, address, numbytes, data);
-
- mutex_lock(&adev->smu.mutex);
- /* Now read data starting with that address */
- ret = smu_cmn_update_table(&adev->smu, SMU_TABLE_I2C_COMMANDS, 0, &req,
- true);
- mutex_unlock(&adev->smu.mutex);
-
- if (!ret) {
- SwI2cRequest_t *res = (SwI2cRequest_t *)table->cpu_addr;
-
- /* Assume SMU fills res.SwI2cCmds[i].Data with read bytes */
- for (i = 0; i < numbytes; i++)
- data[i] = res->SwI2cCmds[i].ReadWriteData;
-
- dev_dbg(adev->dev, "sienna_cichlid_i2c_read_data, address = %x, bytes = %d, data :",
- (uint16_t)address, numbytes);
-
- print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE,
- 8, 1, data, numbytes, false);
- } else
- dev_err(adev->dev, "sienna_cichlid_i2c_read_data - error occurred :%x", ret);
+ req = kzalloc(sizeof(*req), GFP_KERNEL);
+ if (!req)
+ return -ENOMEM;
- return ret;
-}
+ req->I2CcontrollerPort = 1;
+ req->I2CSpeed = I2C_SPEED_FAST_400K;
+ req->SlaveAddress = msg[0].addr << 1; /* wants an 8-bit address */
+ dir = msg[0].flags & I2C_M_RD;
+
+ for (c = i = 0; i < num_msgs; i++) {
+ for (j = 0; j < msg[i].len; j++, c++) {
+ SwI2cCmd_t *cmd = &req->SwI2cCmds[c];
+
+ if (!(msg[i].flags & I2C_M_RD)) {
+ /* write */
+ cmd->CmdConfig |= CMDCONFIG_READWRITE_MASK;
+ cmd->ReadWriteData = msg[i].buf[j];
+ }
-static int sienna_cichlid_i2c_write_data(struct i2c_adapter *control,
- uint8_t address,
- uint8_t *data,
- uint32_t numbytes)
-{
- uint32_t ret;
- SwI2cRequest_t req;
- struct amdgpu_device *adev = to_amdgpu_device(control);
+ if ((dir ^ msg[i].flags) & I2C_M_RD) {
+ /* The direction changes.
+ */
+ dir = msg[i].flags & I2C_M_RD;
+ cmd->CmdConfig |= CMDCONFIG_RESTART_MASK;
+ }
- if (numbytes > MAX_SW_I2C_COMMANDS) {
- dev_err(adev->dev, "numbytes requested %d is over max allowed %d\n",
- numbytes, MAX_SW_I2C_COMMANDS);
- return -EINVAL;
+ req->NumCmds++;
+
+ /*
+ * Insert STOP if we are at the last byte of either last
+ * message for the transaction or the client explicitly
+ * requires a STOP at this particular message.
+ */
+ if ((j == msg[i].len - 1) &&
+ ((i == num_msgs - 1) || (msg[i].flags & I2C_M_STOP))) {
+ cmd->CmdConfig &= ~CMDCONFIG_RESTART_MASK;
+ cmd->CmdConfig |= CMDCONFIG_STOP_MASK;
+ }
+ }
}
-
- memset(&req, 0, sizeof(req));
- sienna_cichlid_fill_i2c_req(&req, true, address, numbytes, data);
-
mutex_lock(&adev->smu.mutex);
- ret = smu_cmn_update_table(&adev->smu, SMU_TABLE_I2C_COMMANDS, 0, &req, true);
+ r = smu_cmn_update_table(&adev->smu, SMU_TABLE_I2C_COMMANDS, 0, req, true);
mutex_unlock(&adev->smu.mutex);
+ if (r)
+ goto fail;
- if (!ret) {
- dev_dbg(adev->dev, "sienna_cichlid_i2c_write(), address = %x, bytes = %d , data: ",
- (uint16_t)address, numbytes);
-
- print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE,
- 8, 1, data, numbytes, false);
- /*
- * According to EEPROM spec there is a MAX of 10 ms required for
- * EEPROM to flush internal RX buffer after STOP was issued at the
- * end of write transaction. During this time the EEPROM will not be
- * responsive to any more commands - so wait a bit more.
- */
- msleep(10);
-
- } else
- dev_err(adev->dev, "sienna_cichlid_i2c_write- error occurred :%x", ret);
-
- return ret;
-}
-
-static int sienna_cichlid_i2c_xfer(struct i2c_adapter *i2c_adap,
- struct i2c_msg *msgs, int num)
-{
- uint32_t i, j, ret, data_size, data_chunk_size, next_eeprom_addr = 0;
- uint8_t *data_ptr, data_chunk[MAX_SW_I2C_COMMANDS] = { 0 };
-
- for (i = 0; i < num; i++) {
- /*
- * SMU interface allows at most MAX_SW_I2C_COMMANDS bytes of data at
- * once and hence the data needs to be spliced into chunks and sent each
- * chunk separately
- */
- data_size = msgs[i].len - 2;
- data_chunk_size = MAX_SW_I2C_COMMANDS - 2;
- next_eeprom_addr = (msgs[i].buf[0] << 8 & 0xff00) | (msgs[i].buf[1] & 0xff);
- data_ptr = msgs[i].buf + 2;
-
- for (j = 0; j < data_size / data_chunk_size; j++) {
- /* Insert the EEPROM dest addess, bits 0-15 */
- data_chunk[0] = ((next_eeprom_addr >> 8) & 0xff);
- data_chunk[1] = (next_eeprom_addr & 0xff);
-
- if (msgs[i].flags & I2C_M_RD) {
- ret = sienna_cichlid_i2c_read_data(i2c_adap,
- (uint8_t)msgs[i].addr,
- data_chunk, MAX_SW_I2C_COMMANDS);
-
- memcpy(data_ptr, data_chunk + 2, data_chunk_size);
- } else {
-
- memcpy(data_chunk + 2, data_ptr, data_chunk_size);
-
- ret = sienna_cichlid_i2c_write_data(i2c_adap,
- (uint8_t)msgs[i].addr,
- data_chunk, MAX_SW_I2C_COMMANDS);
- }
-
- if (ret) {
- num = -EIO;
- goto fail;
- }
-
- next_eeprom_addr += data_chunk_size;
- data_ptr += data_chunk_size;
+ for (c = i = 0; i < num_msgs; i++) {
+ if (!(msg[i].flags & I2C_M_RD)) {
+ c += msg[i].len;
+ continue;
}
+ for (j = 0; j < msg[i].len; j++, c++) {
+ SwI2cCmd_t *cmd = &res->SwI2cCmds[c];
- if (data_size % data_chunk_size) {
- data_chunk[0] = ((next_eeprom_addr >> 8) & 0xff);
- data_chunk[1] = (next_eeprom_addr & 0xff);
-
- if (msgs[i].flags & I2C_M_RD) {
- ret = sienna_cichlid_i2c_read_data(i2c_adap,
- (uint8_t)msgs[i].addr,
- data_chunk, (data_size % data_chunk_size) + 2);
-
- memcpy(data_ptr, data_chunk + 2, data_size % data_chunk_size);
- } else {
- memcpy(data_chunk + 2, data_ptr, data_size % data_chunk_size);
-
- ret = sienna_cichlid_i2c_write_data(i2c_adap,
- (uint8_t)msgs[i].addr,
- data_chunk, (data_size % data_chunk_size) + 2);
- }
-
- if (ret) {
- num = -EIO;
- goto fail;
- }
+ msg[i].buf[j] = cmd->ReadWriteData;
}
}
-
+ r = num_msgs;
fail:
- return num;
+ kfree(req);
+ return r;
}
static u32 sienna_cichlid_i2c_func(struct i2c_adapter *adap)
@@ -3646,16 +3587,25 @@ static const struct i2c_algorithm sienna_cichlid_i2c_algo = {
.functionality = sienna_cichlid_i2c_func,
};
+static const struct i2c_adapter_quirks sienna_cichlid_i2c_control_quirks = {
+ .flags = I2C_AQ_COMB | I2C_AQ_COMB_SAME_ADDR | I2C_AQ_NO_ZERO_LEN,
+ .max_read_len = MAX_SW_I2C_COMMANDS,
+ .max_write_len = MAX_SW_I2C_COMMANDS,
+ .max_comb_1st_msg_len = 2,
+ .max_comb_2nd_msg_len = MAX_SW_I2C_COMMANDS - 2,
+};
+
static int sienna_cichlid_i2c_control_init(struct smu_context *smu, struct i2c_adapter *control)
{
struct amdgpu_device *adev = to_amdgpu_device(control);
int res;
control->owner = THIS_MODULE;
- control->class = I2C_CLASS_SPD;
+ control->class = I2C_CLASS_HWMON;
control->dev.parent = &adev->pdev->dev;
control->algo = &sienna_cichlid_i2c_algo;
snprintf(control->name, sizeof(control->name), "AMDGPU SMU");
+ control->quirks = &sienna_cichlid_i2c_control_quirks;
res = i2c_add_adapter(control);
if (res)
@@ -3678,65 +3628,94 @@ static ssize_t sienna_cichlid_get_gpu_metrics(struct smu_context *smu,
SmuMetricsExternal_t metrics_external;
SmuMetrics_t *metrics =
&(metrics_external.SmuMetrics);
+ SmuMetrics_V2_t *metrics_v2 =
+ &(metrics_external.SmuMetrics_V2);
struct amdgpu_device *adev = smu->adev;
- uint32_t smu_version;
+ bool use_metrics_v2 = ((adev->asic_type == CHIP_SIENNA_CICHLID) &&
+ (smu->smc_fw_version >= 0x3A4300)) ? true : false;
+ uint16_t average_gfx_activity;
int ret = 0;
- ret = smu_cmn_get_metrics_table(smu,
- &metrics_external,
- true);
- if (ret)
+ mutex_lock(&smu->metrics_lock);
+ ret = smu_cmn_get_metrics_table_locked(smu,
+ &metrics_external,
+ true);
+ if (ret) {
+ mutex_unlock(&smu->metrics_lock);
return ret;
+ }
smu_cmn_init_soft_gpu_metrics(gpu_metrics, 1, 3);
- gpu_metrics->temperature_edge = metrics->TemperatureEdge;
- gpu_metrics->temperature_hotspot = metrics->TemperatureHotspot;
- gpu_metrics->temperature_mem = metrics->TemperatureMem;
- gpu_metrics->temperature_vrgfx = metrics->TemperatureVrGfx;
- gpu_metrics->temperature_vrsoc = metrics->TemperatureVrSoc;
- gpu_metrics->temperature_vrmem = metrics->TemperatureVrMem0;
-
- gpu_metrics->average_gfx_activity = metrics->AverageGfxActivity;
- gpu_metrics->average_umc_activity = metrics->AverageUclkActivity;
- gpu_metrics->average_mm_activity = metrics->VcnActivityPercentage;
-
- gpu_metrics->average_socket_power = metrics->AverageSocketPower;
- gpu_metrics->energy_accumulator = metrics->EnergyAccumulator;
-
- if (metrics->AverageGfxActivity <= SMU_11_0_7_GFX_BUSY_THRESHOLD)
- gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPostDs;
+ gpu_metrics->temperature_edge =
+ use_metrics_v2 ? metrics_v2->TemperatureEdge : metrics->TemperatureEdge;
+ gpu_metrics->temperature_hotspot =
+ use_metrics_v2 ? metrics_v2->TemperatureHotspot : metrics->TemperatureHotspot;
+ gpu_metrics->temperature_mem =
+ use_metrics_v2 ? metrics_v2->TemperatureMem : metrics->TemperatureMem;
+ gpu_metrics->temperature_vrgfx =
+ use_metrics_v2 ? metrics_v2->TemperatureVrGfx : metrics->TemperatureVrGfx;
+ gpu_metrics->temperature_vrsoc =
+ use_metrics_v2 ? metrics_v2->TemperatureVrSoc : metrics->TemperatureVrSoc;
+ gpu_metrics->temperature_vrmem =
+ use_metrics_v2 ? metrics_v2->TemperatureVrMem0 : metrics->TemperatureVrMem0;
+
+ gpu_metrics->average_gfx_activity =
+ use_metrics_v2 ? metrics_v2->AverageGfxActivity : metrics->AverageGfxActivity;
+ gpu_metrics->average_umc_activity =
+ use_metrics_v2 ? metrics_v2->AverageUclkActivity : metrics->AverageUclkActivity;
+ gpu_metrics->average_mm_activity =
+ use_metrics_v2 ? metrics_v2->VcnActivityPercentage : metrics->VcnActivityPercentage;
+
+ gpu_metrics->average_socket_power =
+ use_metrics_v2 ? metrics_v2->AverageSocketPower : metrics->AverageSocketPower;
+ gpu_metrics->energy_accumulator =
+ use_metrics_v2 ? metrics_v2->EnergyAccumulator : metrics->EnergyAccumulator;
+
+ average_gfx_activity = use_metrics_v2 ? metrics_v2->AverageGfxActivity : metrics->AverageGfxActivity;
+ if (average_gfx_activity <= SMU_11_0_7_GFX_BUSY_THRESHOLD)
+ gpu_metrics->average_gfxclk_frequency =
+ use_metrics_v2 ? metrics_v2->AverageGfxclkFrequencyPostDs : metrics->AverageGfxclkFrequencyPostDs;
else
- gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPreDs;
- gpu_metrics->average_uclk_frequency = metrics->AverageUclkFrequencyPostDs;
- gpu_metrics->average_vclk0_frequency = metrics->AverageVclk0Frequency;
- gpu_metrics->average_dclk0_frequency = metrics->AverageDclk0Frequency;
- gpu_metrics->average_vclk1_frequency = metrics->AverageVclk1Frequency;
- gpu_metrics->average_dclk1_frequency = metrics->AverageDclk1Frequency;
-
- gpu_metrics->current_gfxclk = metrics->CurrClock[PPCLK_GFXCLK];
- gpu_metrics->current_socclk = metrics->CurrClock[PPCLK_SOCCLK];
- gpu_metrics->current_uclk = metrics->CurrClock[PPCLK_UCLK];
- gpu_metrics->current_vclk0 = metrics->CurrClock[PPCLK_VCLK_0];
- gpu_metrics->current_dclk0 = metrics->CurrClock[PPCLK_DCLK_0];
- gpu_metrics->current_vclk1 = metrics->CurrClock[PPCLK_VCLK_1];
- gpu_metrics->current_dclk1 = metrics->CurrClock[PPCLK_DCLK_1];
-
- gpu_metrics->throttle_status = metrics->ThrottlerStatus;
+ gpu_metrics->average_gfxclk_frequency =
+ use_metrics_v2 ? metrics_v2->AverageGfxclkFrequencyPreDs : metrics->AverageGfxclkFrequencyPreDs;
+ gpu_metrics->average_uclk_frequency =
+ use_metrics_v2 ? metrics_v2->AverageUclkFrequencyPostDs : metrics->AverageUclkFrequencyPostDs;
+ gpu_metrics->average_vclk0_frequency =
+ use_metrics_v2 ? metrics_v2->AverageVclk0Frequency : metrics->AverageVclk0Frequency;
+ gpu_metrics->average_dclk0_frequency =
+ use_metrics_v2 ? metrics_v2->AverageDclk0Frequency : metrics->AverageDclk0Frequency;
+ gpu_metrics->average_vclk1_frequency =
+ use_metrics_v2 ? metrics_v2->AverageVclk1Frequency : metrics->AverageVclk1Frequency;
+ gpu_metrics->average_dclk1_frequency =
+ use_metrics_v2 ? metrics_v2->AverageDclk1Frequency : metrics->AverageDclk1Frequency;
+
+ gpu_metrics->current_gfxclk =
+ use_metrics_v2 ? metrics_v2->CurrClock[PPCLK_GFXCLK] : metrics->CurrClock[PPCLK_GFXCLK];
+ gpu_metrics->current_socclk =
+ use_metrics_v2 ? metrics_v2->CurrClock[PPCLK_SOCCLK] : metrics->CurrClock[PPCLK_SOCCLK];
+ gpu_metrics->current_uclk =
+ use_metrics_v2 ? metrics_v2->CurrClock[PPCLK_UCLK] : metrics->CurrClock[PPCLK_UCLK];
+ gpu_metrics->current_vclk0 =
+ use_metrics_v2 ? metrics_v2->CurrClock[PPCLK_VCLK_0] : metrics->CurrClock[PPCLK_VCLK_0];
+ gpu_metrics->current_dclk0 =
+ use_metrics_v2 ? metrics_v2->CurrClock[PPCLK_DCLK_0] : metrics->CurrClock[PPCLK_DCLK_0];
+ gpu_metrics->current_vclk1 =
+ use_metrics_v2 ? metrics_v2->CurrClock[PPCLK_VCLK_1] : metrics->CurrClock[PPCLK_VCLK_1];
+ gpu_metrics->current_dclk1 =
+ use_metrics_v2 ? metrics_v2->CurrClock[PPCLK_DCLK_1] : metrics->CurrClock[PPCLK_DCLK_1];
+
+ gpu_metrics->throttle_status = sienna_cichlid_get_throttler_status_locked(smu);
gpu_metrics->indep_throttle_status =
- smu_cmn_get_indep_throttler_status(metrics->ThrottlerStatus,
+ smu_cmn_get_indep_throttler_status(gpu_metrics->throttle_status,
sienna_cichlid_throttler_map);
- gpu_metrics->current_fan_speed = metrics->CurrFanSpeed;
+ gpu_metrics->current_fan_speed = use_metrics_v2 ? metrics_v2->CurrFanSpeed : metrics->CurrFanSpeed;
- ret = smu_cmn_get_smc_version(smu, NULL, &smu_version);
- if (ret)
- return ret;
-
- if (((adev->asic_type == CHIP_SIENNA_CICHLID) && smu_version > 0x003A1E00) ||
- ((adev->asic_type == CHIP_NAVY_FLOUNDER) && smu_version > 0x00410400)) {
- gpu_metrics->pcie_link_width = metrics->PcieWidth;
- gpu_metrics->pcie_link_speed = link_speed[metrics->PcieRate];
+ if (((adev->asic_type == CHIP_SIENNA_CICHLID) && smu->smc_fw_version > 0x003A1E00) ||
+ ((adev->asic_type == CHIP_NAVY_FLOUNDER) && smu->smc_fw_version > 0x00410400)) {
+ gpu_metrics->pcie_link_width = use_metrics_v2 ? metrics_v2->PcieWidth : metrics->PcieWidth;
+ gpu_metrics->pcie_link_speed = link_speed[use_metrics_v2 ? metrics_v2->PcieRate : metrics->PcieRate];
} else {
gpu_metrics->pcie_link_width =
smu_v11_0_get_current_pcie_link_width(smu);
@@ -3744,6 +3723,8 @@ static ssize_t sienna_cichlid_get_gpu_metrics(struct smu_context *smu,
smu_v11_0_get_current_pcie_link_speed(smu);
}
+ mutex_unlock(&smu->metrics_lock);
+
gpu_metrics->system_clock_counter = ktime_get_boottime_ns();
*table = (void *)gpu_metrics;
@@ -3939,6 +3920,7 @@ static const struct pptable_funcs sienna_cichlid_ppt_funcs = {
.set_soft_freq_limited_range = smu_v11_0_set_soft_freq_limited_range,
.set_default_od_settings = sienna_cichlid_set_default_od_settings,
.od_edit_dpm_table = sienna_cichlid_od_edit_dpm_table,
+ .restore_user_od_settings = smu_v11_0_restore_user_od_settings,
.run_btc = sienna_cichlid_run_btc,
.set_power_source = smu_v11_0_set_power_source,
.get_pp_feature_mask = smu_cmn_get_pp_feature_mask,
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c
index 0a5d46ac9ccd..b5419e8eba89 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c
@@ -266,6 +266,9 @@ int smu_v11_0_check_fw_version(struct smu_context *smu)
case CHIP_BEIGE_GOBY:
smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_Beige_Goby;
break;
+ case CHIP_CYAN_SKILLFISH:
+ smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_Cyan_Skillfish;
+ break;
default:
dev_err(smu->adev->dev, "smu unsupported asic type:%d.\n", smu->adev->asic_type);
smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_INV;
@@ -422,10 +425,20 @@ int smu_v11_0_init_smc_tables(struct smu_context *smu)
ret = -ENOMEM;
goto err3_out;
}
+
+ smu_table->user_overdrive_table =
+ kzalloc(tables[SMU_TABLE_OVERDRIVE].size, GFP_KERNEL);
+ if (!smu_table->user_overdrive_table) {
+ ret = -ENOMEM;
+ goto err4_out;
+ }
+
}
return 0;
+err4_out:
+ kfree(smu_table->boot_overdrive_table);
err3_out:
kfree(smu_table->overdrive_table);
err2_out:
@@ -442,12 +455,14 @@ int smu_v11_0_fini_smc_tables(struct smu_context *smu)
struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
kfree(smu_table->gpu_metrics_table);
+ kfree(smu_table->user_overdrive_table);
kfree(smu_table->boot_overdrive_table);
kfree(smu_table->overdrive_table);
kfree(smu_table->max_sustainable_clocks);
kfree(smu_table->driver_pptable);
kfree(smu_table->clocks_table);
smu_table->gpu_metrics_table = NULL;
+ smu_table->user_overdrive_table = NULL;
smu_table->boot_overdrive_table = NULL;
smu_table->overdrive_table = NULL;
smu_table->max_sustainable_clocks = NULL;
@@ -2101,3 +2116,16 @@ int smu_v11_0_deep_sleep_control(struct smu_context *smu,
return ret;
}
+
+int smu_v11_0_restore_user_od_settings(struct smu_context *smu)
+{
+ struct smu_table_context *table_context = &smu->smu_table;
+ void *user_od_table = table_context->user_overdrive_table;
+ int ret = 0;
+
+ ret = smu_cmn_update_table(smu, SMU_TABLE_OVERDRIVE, 0, (void *)user_od_table, true);
+ if (ret)
+ dev_err(smu->adev->dev, "Failed to import overdrive table!\n");
+
+ return ret;
+}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c
index cb5485cf243f..856eeaf293b8 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c
@@ -1451,197 +1451,77 @@ static bool aldebaran_is_dpm_running(struct smu_context *smu)
return !!(feature_enabled & SMC_DPM_FEATURE);
}
-static void aldebaran_fill_i2c_req(SwI2cRequest_t *req, bool write,
- uint8_t address, uint32_t numbytes,
- uint8_t *data)
-{
- int i;
-
- req->I2CcontrollerPort = 0;
- req->I2CSpeed = 2;
- req->SlaveAddress = address;
- req->NumCmds = numbytes;
-
- for (i = 0; i < numbytes; i++) {
- SwI2cCmd_t *cmd = &req->SwI2cCmds[i];
-
- /* First 2 bytes are always write for lower 2b EEPROM address */
- if (i < 2)
- cmd->CmdConfig = CMDCONFIG_READWRITE_MASK;
- else
- cmd->CmdConfig = write ? CMDCONFIG_READWRITE_MASK : 0;
-
-
- /* Add RESTART for read after address filled */
- cmd->CmdConfig |= (i == 2 && !write) ? CMDCONFIG_RESTART_MASK : 0;
-
- /* Add STOP in the end */
- cmd->CmdConfig |= (i == (numbytes - 1)) ? CMDCONFIG_STOP_MASK : 0;
-
- /* Fill with data regardless if read or write to simplify code */
- cmd->ReadWriteData = data[i];
- }
-}
-
-static int aldebaran_i2c_read_data(struct i2c_adapter *control,
- uint8_t address,
- uint8_t *data,
- uint32_t numbytes)
+static int aldebaran_i2c_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msg, int num_msgs)
{
- uint32_t i, ret = 0;
- SwI2cRequest_t req;
- struct amdgpu_device *adev = to_amdgpu_device(control);
+ struct amdgpu_device *adev = to_amdgpu_device(i2c_adap);
struct smu_table_context *smu_table = &adev->smu.smu_table;
struct smu_table *table = &smu_table->driver_table;
+ SwI2cRequest_t *req, *res = (SwI2cRequest_t *)table->cpu_addr;
+ int i, j, r, c;
+ u16 dir;
- if (numbytes > MAX_SW_I2C_COMMANDS) {
- dev_err(adev->dev, "numbytes requested %d is over max allowed %d\n",
- numbytes, MAX_SW_I2C_COMMANDS);
- return -EINVAL;
- }
-
- memset(&req, 0, sizeof(req));
- aldebaran_fill_i2c_req(&req, false, address, numbytes, data);
-
- mutex_lock(&adev->smu.mutex);
- /* Now read data starting with that address */
- ret = smu_cmn_update_table(&adev->smu, SMU_TABLE_I2C_COMMANDS, 0, &req,
- true);
- mutex_unlock(&adev->smu.mutex);
-
- if (!ret) {
- SwI2cRequest_t *res = (SwI2cRequest_t *)table->cpu_addr;
-
- /* Assume SMU fills res.SwI2cCmds[i].Data with read bytes */
- for (i = 0; i < numbytes; i++)
- data[i] = res->SwI2cCmds[i].ReadWriteData;
-
- dev_dbg(adev->dev, "aldebaran_i2c_read_data, address = %x, bytes = %d, data :",
- (uint16_t)address, numbytes);
-
- print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE,
- 8, 1, data, numbytes, false);
- } else
- dev_err(adev->dev, "aldebaran_i2c_read_data - error occurred :%x", ret);
+ req = kzalloc(sizeof(*req), GFP_KERNEL);
+ if (!req)
+ return -ENOMEM;
- return ret;
-}
+ req->I2CcontrollerPort = 0;
+ req->I2CSpeed = I2C_SPEED_FAST_400K;
+ req->SlaveAddress = msg[0].addr << 1; /* wants an 8-bit address */
+ dir = msg[0].flags & I2C_M_RD;
+
+ for (c = i = 0; i < num_msgs; i++) {
+ for (j = 0; j < msg[i].len; j++, c++) {
+ SwI2cCmd_t *cmd = &req->SwI2cCmds[c];
+
+ if (!(msg[i].flags & I2C_M_RD)) {
+ /* write */
+ cmd->CmdConfig |= CMDCONFIG_READWRITE_MASK;
+ cmd->ReadWriteData = msg[i].buf[j];
+ }
-static int aldebaran_i2c_write_data(struct i2c_adapter *control,
- uint8_t address,
- uint8_t *data,
- uint32_t numbytes)
-{
- uint32_t ret;
- SwI2cRequest_t req;
- struct amdgpu_device *adev = to_amdgpu_device(control);
+ if ((dir ^ msg[i].flags) & I2C_M_RD) {
+ /* The direction changes.
+ */
+ dir = msg[i].flags & I2C_M_RD;
+ cmd->CmdConfig |= CMDCONFIG_RESTART_MASK;
+ }
- if (numbytes > MAX_SW_I2C_COMMANDS) {
- dev_err(adev->dev, "numbytes requested %d is over max allowed %d\n",
- numbytes, MAX_SW_I2C_COMMANDS);
- return -EINVAL;
+ req->NumCmds++;
+
+ /*
+ * Insert STOP if we are at the last byte of either last
+ * message for the transaction or the client explicitly
+ * requires a STOP at this particular message.
+ */
+ if ((j == msg[i].len - 1) &&
+ ((i == num_msgs - 1) || (msg[i].flags & I2C_M_STOP))) {
+ cmd->CmdConfig &= ~CMDCONFIG_RESTART_MASK;
+ cmd->CmdConfig |= CMDCONFIG_STOP_MASK;
+ }
+ }
}
-
- memset(&req, 0, sizeof(req));
- aldebaran_fill_i2c_req(&req, true, address, numbytes, data);
-
mutex_lock(&adev->smu.mutex);
- ret = smu_cmn_update_table(&adev->smu, SMU_TABLE_I2C_COMMANDS, 0, &req, true);
+ r = smu_cmn_update_table(&adev->smu, SMU_TABLE_I2C_COMMANDS, 0, req, true);
mutex_unlock(&adev->smu.mutex);
+ if (r)
+ goto fail;
- if (!ret) {
- dev_dbg(adev->dev, "aldebaran_i2c_write(), address = %x, bytes = %d , data: ",
- (uint16_t)address, numbytes);
-
- print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE,
- 8, 1, data, numbytes, false);
- /*
- * According to EEPROM spec there is a MAX of 10 ms required for
- * EEPROM to flush internal RX buffer after STOP was issued at the
- * end of write transaction. During this time the EEPROM will not be
- * responsive to any more commands - so wait a bit more.
- */
- msleep(10);
-
- } else
- dev_err(adev->dev, "aldebaran_i2c_write- error occurred :%x", ret);
-
- return ret;
-}
-
-static int aldebaran_i2c_xfer(struct i2c_adapter *i2c_adap,
- struct i2c_msg *msgs, int num)
-{
- uint32_t i, j, ret, data_size, data_chunk_size, next_eeprom_addr = 0;
- uint8_t *data_ptr, data_chunk[MAX_SW_I2C_COMMANDS] = { 0 };
-
- for (i = 0; i < num; i++) {
- /*
- * SMU interface allows at most MAX_SW_I2C_COMMANDS bytes of data at
- * once and hence the data needs to be spliced into chunks and sent each
- * chunk separately
- */
- data_size = msgs[i].len - 2;
- data_chunk_size = MAX_SW_I2C_COMMANDS - 2;
- next_eeprom_addr = (msgs[i].buf[0] << 8 & 0xff00) | (msgs[i].buf[1] & 0xff);
- data_ptr = msgs[i].buf + 2;
-
- for (j = 0; j < data_size / data_chunk_size; j++) {
- /* Insert the EEPROM dest addess, bits 0-15 */
- data_chunk[0] = ((next_eeprom_addr >> 8) & 0xff);
- data_chunk[1] = (next_eeprom_addr & 0xff);
-
- if (msgs[i].flags & I2C_M_RD) {
- ret = aldebaran_i2c_read_data(i2c_adap,
- (uint8_t)msgs[i].addr,
- data_chunk, MAX_SW_I2C_COMMANDS);
-
- memcpy(data_ptr, data_chunk + 2, data_chunk_size);
- } else {
-
- memcpy(data_chunk + 2, data_ptr, data_chunk_size);
-
- ret = aldebaran_i2c_write_data(i2c_adap,
- (uint8_t)msgs[i].addr,
- data_chunk, MAX_SW_I2C_COMMANDS);
- }
-
- if (ret) {
- num = -EIO;
- goto fail;
- }
-
- next_eeprom_addr += data_chunk_size;
- data_ptr += data_chunk_size;
+ for (c = i = 0; i < num_msgs; i++) {
+ if (!(msg[i].flags & I2C_M_RD)) {
+ c += msg[i].len;
+ continue;
}
+ for (j = 0; j < msg[i].len; j++, c++) {
+ SwI2cCmd_t *cmd = &res->SwI2cCmds[c];
- if (data_size % data_chunk_size) {
- data_chunk[0] = ((next_eeprom_addr >> 8) & 0xff);
- data_chunk[1] = (next_eeprom_addr & 0xff);
-
- if (msgs[i].flags & I2C_M_RD) {
- ret = aldebaran_i2c_read_data(i2c_adap,
- (uint8_t)msgs[i].addr,
- data_chunk, (data_size % data_chunk_size) + 2);
-
- memcpy(data_ptr, data_chunk + 2, data_size % data_chunk_size);
- } else {
- memcpy(data_chunk + 2, data_ptr, data_size % data_chunk_size);
-
- ret = aldebaran_i2c_write_data(i2c_adap,
- (uint8_t)msgs[i].addr,
- data_chunk, (data_size % data_chunk_size) + 2);
- }
-
- if (ret) {
- num = -EIO;
- goto fail;
- }
+ msg[i].buf[j] = cmd->ReadWriteData;
}
}
-
+ r = num_msgs;
fail:
- return num;
+ kfree(req);
+ return r;
}
static u32 aldebaran_i2c_func(struct i2c_adapter *adap)
@@ -1655,6 +1535,14 @@ static const struct i2c_algorithm aldebaran_i2c_algo = {
.functionality = aldebaran_i2c_func,
};
+static const struct i2c_adapter_quirks aldebaran_i2c_control_quirks = {
+ .flags = I2C_AQ_COMB | I2C_AQ_COMB_SAME_ADDR | I2C_AQ_NO_ZERO_LEN,
+ .max_read_len = MAX_SW_I2C_COMMANDS,
+ .max_write_len = MAX_SW_I2C_COMMANDS,
+ .max_comb_1st_msg_len = 2,
+ .max_comb_2nd_msg_len = MAX_SW_I2C_COMMANDS - 2,
+};
+
static int aldebaran_i2c_control_init(struct smu_context *smu, struct i2c_adapter *control)
{
struct amdgpu_device *adev = to_amdgpu_device(control);
@@ -1665,6 +1553,7 @@ static int aldebaran_i2c_control_init(struct smu_context *smu, struct i2c_adapte
control->dev.parent = &adev->pdev->dev;
control->algo = &aldebaran_i2c_algo;
snprintf(control->name, sizeof(control->name), "AMDGPU SMU");
+ control->quirks = &aldebaran_i2c_control_quirks;
res = i2c_add_adapter(control);
if (res)
@@ -1764,7 +1653,9 @@ static void aldebaran_log_thermal_throttling_event(struct smu_context *smu)
dev_warn(adev->dev, "WARN: GPU thermal throttling temperature reached, expect performance decrease. %s.\n",
log_buf);
- kgd2kfd_smi_event_throttle(smu->adev->kfd.dev, throttler_status);
+ kgd2kfd_smi_event_throttle(smu->adev->kfd.dev,
+ smu_cmn_get_indep_throttler_status(throttler_status,
+ aldebaran_throttler_map));
}
static int aldebaran_get_current_pcie_link_speed(struct smu_context *smu)
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
index e802f9a95f08..415be74df28c 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
@@ -55,7 +55,7 @@
#undef __SMU_DUMMY_MAP
#define __SMU_DUMMY_MAP(type) #type
-static const char* __smu_message_names[] = {
+static const char * const __smu_message_names[] = {
SMU_MESSAGE_TYPES
};
@@ -76,55 +76,256 @@ static void smu_cmn_read_arg(struct smu_context *smu,
*arg = RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_82);
}
-int smu_cmn_wait_for_response(struct smu_context *smu)
+/* Redefine the SMU error codes here.
+ *
+ * Note that these definitions are redundant and should be removed
+ * when the SMU has exported a unified header file containing these
+ * macros, which header file we can just include and use the SMU's
+ * macros. At the moment, these error codes are defined by the SMU
+ * per-ASIC unfortunately, yet we're a one driver for all ASICs.
+ */
+#define SMU_RESP_NONE 0
+#define SMU_RESP_OK 1
+#define SMU_RESP_CMD_FAIL 0xFF
+#define SMU_RESP_CMD_UNKNOWN 0xFE
+#define SMU_RESP_CMD_BAD_PREREQ 0xFD
+#define SMU_RESP_BUSY_OTHER 0xFC
+#define SMU_RESP_DEBUG_END 0xFB
+
+/**
+ * __smu_cmn_poll_stat -- poll for a status from the SMU
+ * smu: a pointer to SMU context
+ *
+ * Returns the status of the SMU, which could be,
+ * 0, the SMU is busy with your previous command;
+ * 1, execution status: success, execution result: success;
+ * 0xFF, execution status: success, execution result: failure;
+ * 0xFE, unknown command;
+ * 0xFD, valid command, but bad (command) prerequisites;
+ * 0xFC, the command was rejected as the SMU is busy;
+ * 0xFB, "SMC_Result_DebugDataDumpEnd".
+ *
+ * The values here are not defined by macros, because I'd rather we
+ * include a single header file which defines them, which is
+ * maintained by the SMU FW team, so that we're impervious to firmware
+ * changes. At the moment those values are defined in various header
+ * files, one for each ASIC, yet here we're a single ASIC-agnostic
+ * interface. Such a change can be followed-up by a subsequent patch.
+ */
+static u32 __smu_cmn_poll_stat(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
- uint32_t cur_value, i, timeout = adev->usec_timeout * 20;
+ int timeout = adev->usec_timeout * 20;
+ u32 reg;
- for (i = 0; i < timeout; i++) {
- cur_value = RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90);
- if ((cur_value & MP1_C2PMSG_90__CONTENT_MASK) != 0)
- return cur_value;
+ for ( ; timeout > 0; timeout--) {
+ reg = RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90);
+ if ((reg & MP1_C2PMSG_90__CONTENT_MASK) != 0)
+ break;
udelay(1);
}
- /* timeout means wrong logic */
- if (i == timeout)
- return -ETIME;
-
- return RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90);
+ return reg;
}
-int smu_cmn_send_msg_without_waiting(struct smu_context *smu,
- uint16_t msg, uint32_t param)
+static void __smu_cmn_reg_print_error(struct smu_context *smu,
+ u32 reg_c2pmsg_90,
+ int msg_index,
+ u32 param,
+ enum smu_message_type msg)
{
struct amdgpu_device *adev = smu->adev;
- int ret;
+ const char *message = smu_get_message_name(smu, msg);
- ret = smu_cmn_wait_for_response(smu);
- if (ret != 0x1) {
- dev_err(adev->dev, "Msg issuing pre-check failed(0x%x) and "
- "SMU may be not in the right state!\n", ret);
- if (ret != -ETIME)
- ret = -EIO;
- return ret;
+ switch (reg_c2pmsg_90) {
+ case SMU_RESP_NONE:
+ dev_err_ratelimited(adev->dev,
+ "SMU: I'm not done with your previous command!");
+ break;
+ case SMU_RESP_OK:
+ /* The SMU executed the command. It completed with a
+ * successful result.
+ */
+ break;
+ case SMU_RESP_CMD_FAIL:
+ /* The SMU executed the command. It completed with an
+ * unsuccessful result.
+ */
+ break;
+ case SMU_RESP_CMD_UNKNOWN:
+ dev_err_ratelimited(adev->dev,
+ "SMU: unknown command: index:%d param:0x%08X message:%s",
+ msg_index, param, message);
+ break;
+ case SMU_RESP_CMD_BAD_PREREQ:
+ dev_err_ratelimited(adev->dev,
+ "SMU: valid command, bad prerequisites: index:%d param:0x%08X message:%s",
+ msg_index, param, message);
+ break;
+ case SMU_RESP_BUSY_OTHER:
+ dev_err_ratelimited(adev->dev,
+ "SMU: I'm very busy for your command: index:%d param:0x%08X message:%s",
+ msg_index, param, message);
+ break;
+ case SMU_RESP_DEBUG_END:
+ dev_err_ratelimited(adev->dev,
+ "SMU: I'm debugging!");
+ break;
+ default:
+ dev_err_ratelimited(adev->dev,
+ "SMU: response:0x%08X for index:%d param:0x%08X message:%s?",
+ reg_c2pmsg_90, msg_index, param, message);
+ break;
}
+}
+
+static int __smu_cmn_reg2errno(struct smu_context *smu, u32 reg_c2pmsg_90)
+{
+ int res;
+
+ switch (reg_c2pmsg_90) {
+ case SMU_RESP_NONE:
+ /* The SMU is busy--still executing your command.
+ */
+ res = -ETIME;
+ break;
+ case SMU_RESP_OK:
+ res = 0;
+ break;
+ case SMU_RESP_CMD_FAIL:
+ /* Command completed successfully, but the command
+ * status was failure.
+ */
+ res = -EIO;
+ break;
+ case SMU_RESP_CMD_UNKNOWN:
+ /* Unknown command--ignored by the SMU.
+ */
+ res = -EOPNOTSUPP;
+ break;
+ case SMU_RESP_CMD_BAD_PREREQ:
+ /* Valid command--bad prerequisites.
+ */
+ res = -EINVAL;
+ break;
+ case SMU_RESP_BUSY_OTHER:
+ /* The SMU is busy with other commands. The client
+ * should retry in 10 us.
+ */
+ res = -EBUSY;
+ break;
+ default:
+ /* Unknown or debug response from the SMU.
+ */
+ res = -EREMOTEIO;
+ break;
+ }
+
+ return res;
+}
+
+static void __smu_cmn_send_msg(struct smu_context *smu,
+ u16 msg,
+ u32 param)
+{
+ struct amdgpu_device *adev = smu->adev;
WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90, 0);
WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_82, param);
WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_66, msg);
+}
- return 0;
+/**
+ * smu_cmn_send_msg_without_waiting -- send the message; don't wait for status
+ * @smu: pointer to an SMU context
+ * @msg_index: message index
+ * @param: message parameter to send to the SMU
+ *
+ * Send a message to the SMU with the parameter passed. Do not wait
+ * for status/result of the message, thus the "without_waiting".
+ *
+ * Return 0 on success, -errno on error if we weren't able to _send_
+ * the message for some reason. See __smu_cmn_reg2errno() for details
+ * of the -errno.
+ */
+int smu_cmn_send_msg_without_waiting(struct smu_context *smu,
+ uint16_t msg_index,
+ uint32_t param)
+{
+ u32 reg;
+ int res;
+
+ if (smu->adev->no_hw_access)
+ return 0;
+
+ reg = __smu_cmn_poll_stat(smu);
+ res = __smu_cmn_reg2errno(smu, reg);
+ if (reg == SMU_RESP_NONE ||
+ reg == SMU_RESP_BUSY_OTHER ||
+ res == -EREMOTEIO)
+ goto Out;
+ __smu_cmn_send_msg(smu, msg_index, param);
+ res = 0;
+Out:
+ return res;
+}
+
+/**
+ * smu_cmn_wait_for_response -- wait for response from the SMU
+ * @smu: pointer to an SMU context
+ *
+ * Wait for status from the SMU.
+ *
+ * Return 0 on success, -errno on error, indicating the execution
+ * status and result of the message being waited for. See
+ * __smu_cmn_reg2errno() for details of the -errno.
+ */
+int smu_cmn_wait_for_response(struct smu_context *smu)
+{
+ u32 reg;
+
+ reg = __smu_cmn_poll_stat(smu);
+ return __smu_cmn_reg2errno(smu, reg);
}
+/**
+ * smu_cmn_send_smc_msg_with_param -- send a message with parameter
+ * @smu: pointer to an SMU context
+ * @msg: message to send
+ * @param: parameter to send to the SMU
+ * @read_arg: pointer to u32 to return a value from the SMU back
+ * to the caller
+ *
+ * Send the message @msg with parameter @param to the SMU, wait for
+ * completion of the command, and return back a value from the SMU in
+ * @read_arg pointer.
+ *
+ * Return 0 on success, -errno on error, if we weren't able to send
+ * the message or if the message completed with some kind of
+ * error. See __smu_cmn_reg2errno() for details of the -errno.
+ *
+ * If we weren't able to send the message to the SMU, we also print
+ * the error to the standard log.
+ *
+ * Command completion status is printed only if the -errno is
+ * -EREMOTEIO, indicating that the SMU returned back an
+ * undefined/unknown/unspecified result. All other cases are
+ * well-defined, not printed, but instead given back to the client to
+ * decide what further to do.
+ *
+ * The return value, @read_arg is read back regardless, to give back
+ * more information to the client, which on error would most likely be
+ * @param, but we can't assume that. This also eliminates more
+ * conditionals.
+ */
int smu_cmn_send_smc_msg_with_param(struct smu_context *smu,
enum smu_message_type msg,
uint32_t param,
uint32_t *read_arg)
{
- struct amdgpu_device *adev = smu->adev;
- int ret = 0, index = 0;
+ int res, index;
+ u32 reg;
if (smu->adev->no_hw_access)
return 0;
@@ -136,31 +337,24 @@ int smu_cmn_send_smc_msg_with_param(struct smu_context *smu,
return index == -EACCES ? 0 : index;
mutex_lock(&smu->message_lock);
- ret = smu_cmn_send_msg_without_waiting(smu, (uint16_t)index, param);
- if (ret)
- goto out;
-
- ret = smu_cmn_wait_for_response(smu);
- if (ret != 0x1) {
- if (ret == -ETIME) {
- dev_err(adev->dev, "message: %15s (%d) \tparam: 0x%08x is timeout (no response)\n",
- smu_get_message_name(smu, msg), index, param);
- } else {
- dev_err(adev->dev, "failed send message: %15s (%d) \tparam: 0x%08x response %#x\n",
- smu_get_message_name(smu, msg), index, param,
- ret);
- ret = -EIO;
- }
- goto out;
+ reg = __smu_cmn_poll_stat(smu);
+ res = __smu_cmn_reg2errno(smu, reg);
+ if (reg == SMU_RESP_NONE ||
+ reg == SMU_RESP_BUSY_OTHER ||
+ res == -EREMOTEIO) {
+ __smu_cmn_reg_print_error(smu, reg, index, param, msg);
+ goto Out;
}
-
+ __smu_cmn_send_msg(smu, (uint16_t) index, param);
+ reg = __smu_cmn_poll_stat(smu);
+ res = __smu_cmn_reg2errno(smu, reg);
+ if (res == -EREMOTEIO)
+ __smu_cmn_reg_print_error(smu, reg, index, param, msg);
if (read_arg)
smu_cmn_read_arg(smu, read_arg);
-
- ret = 0; /* 0 as driver return value */
-out:
+Out:
mutex_unlock(&smu->message_lock);
- return ret;
+ return res;
}
int smu_cmn_send_smc_msg(struct smu_context *smu,
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
index 9add5f16ff56..16993daa2ae0 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
@@ -27,7 +27,8 @@
#if defined(SWSMU_CODE_LAYER_L2) || defined(SWSMU_CODE_LAYER_L3) || defined(SWSMU_CODE_LAYER_L4)
int smu_cmn_send_msg_without_waiting(struct smu_context *smu,
- uint16_t msg, uint32_t param);
+ uint16_t msg_index,
+ uint32_t param);
int smu_cmn_send_smc_msg_with_param(struct smu_context *smu,
enum smu_message_type msg,
uint32_t param,