Merge tag 'drm-misc-next-fixes-2021-09-09' of git://anongit.freedesktop.org/drm/drm...
[linux-2.6-microblaze.git] / drivers / gpu / drm / amd / pm / swsmu / smu11 / arcturus_ppt.c
index 094df6f..e343cc2 100644 (file)
 
 #define smnPCIE_ESM_CTRL                       0x111003D0
 
+#define mmCG_FDO_CTRL0_ARCT                    0x8B
+#define mmCG_FDO_CTRL0_ARCT_BASE_IDX           0
+
+#define mmCG_FDO_CTRL1_ARCT                    0x8C
+#define mmCG_FDO_CTRL1_ARCT_BASE_IDX           0
+
+#define mmCG_FDO_CTRL2_ARCT                    0x8D
+#define mmCG_FDO_CTRL2_ARCT_BASE_IDX           0
+
+#define mmCG_TACH_CTRL_ARCT                    0x8E
+#define mmCG_TACH_CTRL_ARCT_BASE_IDX           0
+
+#define mmCG_TACH_STATUS_ARCT                  0x8F
+#define mmCG_TACH_STATUS_ARCT_BASE_IDX         0
+
+#define mmCG_THERMAL_STATUS_ARCT               0x90
+#define mmCG_THERMAL_STATUS_ARCT_BASE_IDX      0
+
 static const struct cmn2asic_msg_mapping arcturus_message_map[SMU_MSG_MAX_COUNT] = {
        MSG_MAP(TestMessage,                         PPSMC_MSG_TestMessage,                     0),
        MSG_MAP(GetSmuVersion,                       PPSMC_MSG_GetSmuVersion,                   1),
@@ -163,14 +181,14 @@ static const struct cmn2asic_mapping arcturus_feature_mask_map[SMU_FEATURE_COUNT
        FEA_MAP(DPM_SOCCLK),
        FEA_MAP(DPM_FCLK),
        FEA_MAP(DPM_MP0CLK),
-       ARCTURUS_FEA_MAP(SMU_FEATURE_XGMI_BIT, FEATURE_DPM_XGMI_BIT),
+       FEA_MAP(DPM_XGMI),
        FEA_MAP(DS_GFXCLK),
        FEA_MAP(DS_SOCCLK),
        FEA_MAP(DS_LCLK),
        FEA_MAP(DS_FCLK),
        FEA_MAP(DS_UCLK),
        FEA_MAP(GFX_ULV),
-       ARCTURUS_FEA_MAP(SMU_FEATURE_VCN_PG_BIT, FEATURE_DPM_VCN_BIT),
+       ARCTURUS_FEA_MAP(SMU_FEATURE_VCN_DPM_BIT, FEATURE_DPM_VCN_BIT),
        FEA_MAP(RSMU_SMN_CG),
        FEA_MAP(WAFL_CG),
        FEA_MAP(PPT),
@@ -465,10 +483,8 @@ static int arcturus_append_powerplay_table(struct smu_context *smu)
 
        if ((smc_dpm_table->table_header.format_revision == 4) &&
            (smc_dpm_table->table_header.content_revision == 6))
-               memcpy(&smc_pptable->MaxVoltageStepGfx,
-                      &smc_dpm_table->maxvoltagestepgfx,
-                      sizeof(*smc_dpm_table) - offsetof(struct atom_smc_dpm_info_v4_6, maxvoltagestepgfx));
-
+               smu_memcpy_trailing(smc_pptable, MaxVoltageStepGfx, BoardReserved,
+                                   smc_dpm_table, maxvoltagestepgfx);
        return 0;
 }
 
@@ -721,13 +737,13 @@ static int arcturus_get_current_clk_freq_by_table(struct smu_context *smu,
                        member_type = METRICS_AVERAGE_SOCCLK;
                break;
        case PPCLK_VCLK:
-               if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT))
+               if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_DPM_BIT))
                        member_type = METRICS_CURR_VCLK;
                else
                        member_type = METRICS_AVERAGE_VCLK;
                break;
        case PPCLK_DCLK:
-               if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT))
+               if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_DPM_BIT))
                        member_type = METRICS_CURR_DCLK;
                else
                        member_type = METRICS_AVERAGE_DCLK;
@@ -756,7 +772,7 @@ static int arcturus_print_clk_levels(struct smu_context *smu,
        uint32_t gen_speed, lane_width;
 
        if (amdgpu_ras_intr_triggered())
-               return snprintf(buf, PAGE_SIZE, "unavailable\n");
+               return sysfs_emit(buf, "unavailable\n");
 
        dpm_context = smu_dpm->dpm_context;
 
@@ -780,7 +796,7 @@ static int arcturus_print_clk_levels(struct smu_context *smu,
                 * And it's safe to assume that is always the current clock.
                 */
                for (i = 0; i < clocks.num_levels; i++)
-                       size += sprintf(buf + size, "%d: %uMhz %s\n", i,
+                       size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i,
                                        clocks.data[i].clocks_in_khz / 1000,
                                        (clocks.num_levels == 1) ? "*" :
                                        (arcturus_freqs_in_same_level(
@@ -803,7 +819,7 @@ static int arcturus_print_clk_levels(struct smu_context *smu,
                }
 
                for (i = 0; i < clocks.num_levels; i++)
-                       size += sprintf(buf + size, "%d: %uMhz %s\n",
+                       size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n",
                                i, clocks.data[i].clocks_in_khz / 1000,
                                (clocks.num_levels == 1) ? "*" :
                                (arcturus_freqs_in_same_level(
@@ -826,7 +842,7 @@ static int arcturus_print_clk_levels(struct smu_context *smu,
                }
 
                for (i = 0; i < clocks.num_levels; i++)
-                       size += sprintf(buf + size, "%d: %uMhz %s\n",
+                       size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n",
                                i, clocks.data[i].clocks_in_khz / 1000,
                                (clocks.num_levels == 1) ? "*" :
                                (arcturus_freqs_in_same_level(
@@ -849,7 +865,7 @@ static int arcturus_print_clk_levels(struct smu_context *smu,
                }
 
                for (i = 0; i < single_dpm_table->count; i++)
-                       size += sprintf(buf + size, "%d: %uMhz %s\n",
+                       size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n",
                                i, single_dpm_table->dpm_levels[i].value,
                                (clocks.num_levels == 1) ? "*" :
                                (arcturus_freqs_in_same_level(
@@ -872,7 +888,7 @@ static int arcturus_print_clk_levels(struct smu_context *smu,
                }
 
                for (i = 0; i < single_dpm_table->count; i++)
-                       size += sprintf(buf + size, "%d: %uMhz %s\n",
+                       size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n",
                                i, single_dpm_table->dpm_levels[i].value,
                                (clocks.num_levels == 1) ? "*" :
                                (arcturus_freqs_in_same_level(
@@ -895,7 +911,7 @@ static int arcturus_print_clk_levels(struct smu_context *smu,
                }
 
                for (i = 0; i < single_dpm_table->count; i++)
-                       size += sprintf(buf + size, "%d: %uMhz %s\n",
+                       size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n",
                                i, single_dpm_table->dpm_levels[i].value,
                                (clocks.num_levels == 1) ? "*" :
                                (arcturus_freqs_in_same_level(
@@ -906,7 +922,7 @@ static int arcturus_print_clk_levels(struct smu_context *smu,
        case SMU_PCIE:
                gen_speed = smu_v11_0_get_current_pcie_link_speed_level(smu);
                lane_width = smu_v11_0_get_current_pcie_link_width_level(smu);
-               size += sprintf(buf + size, "0: %s %s %dMhz *\n",
+               size += sysfs_emit_at(buf, size, "0: %s %s %dMhz *\n",
                                (gen_speed == 0) ? "2.5GT/s," :
                                (gen_speed == 1) ? "5.0GT/s," :
                                (gen_speed == 2) ? "8.0GT/s," :
@@ -1162,11 +1178,29 @@ static int arcturus_read_sensor(struct smu_context *smu,
        return ret;
 }
 
-static int arcturus_get_fan_speed_percent(struct smu_context *smu,
-                                         uint32_t *speed)
+static int arcturus_set_fan_static_mode(struct smu_context *smu,
+                                       uint32_t mode)
 {
-       int ret;
-       u32 rpm;
+       struct amdgpu_device *adev = smu->adev;
+
+       WREG32_SOC15(THM, 0, mmCG_FDO_CTRL2_ARCT,
+                    REG_SET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL2_ARCT),
+                                  CG_FDO_CTRL2, TMIN, 0));
+       WREG32_SOC15(THM, 0, mmCG_FDO_CTRL2_ARCT,
+                    REG_SET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL2_ARCT),
+                                  CG_FDO_CTRL2, FDO_PWM_MODE, mode));
+
+       return 0;
+}
+
+static int arcturus_get_fan_speed_rpm(struct smu_context *smu,
+                                     uint32_t *speed)
+{
+       struct amdgpu_device *adev = smu->adev;
+       uint32_t crystal_clock_freq = 2500;
+       uint32_t tach_status;
+       uint64_t tmp64;
+       int ret = 0;
 
        if (!speed)
                return -EINVAL;
@@ -1175,14 +1209,112 @@ static int arcturus_get_fan_speed_percent(struct smu_context *smu,
        case AMD_FAN_CTRL_AUTO:
                ret = arcturus_get_smu_metrics_data(smu,
                                                    METRICS_CURR_FANSPEED,
-                                                   &rpm);
-               if (!ret && smu->fan_max_rpm)
-                       *speed = rpm * 100 / smu->fan_max_rpm;
-               return ret;
+                                                   speed);
+               break;
        default:
-               *speed = smu->user_dpm_profile.fan_speed_percent;
+               /*
+                * For pre Sienna Cichlid ASICs, the 0 RPM may be not correctly
+                * detected via register retrieving. To workaround this, we will
+                * report the fan speed as 0 RPM if user just requested such.
+                */
+               if ((smu->user_dpm_profile.flags & SMU_CUSTOM_FAN_SPEED_RPM)
+                    && !smu->user_dpm_profile.fan_speed_rpm) {
+                       *speed = 0;
+                       return 0;
+               }
+
+               tmp64 = (uint64_t)crystal_clock_freq * 60 * 10000;
+               tach_status = RREG32_SOC15(THM, 0, mmCG_TACH_STATUS_ARCT);
+               if (tach_status) {
+                       do_div(tmp64, tach_status);
+                       *speed = (uint32_t)tmp64;
+               } else {
+                       *speed = 0;
+               }
+
+               break;
+       }
+
+       return ret;
+}
+
+static int arcturus_set_fan_speed_pwm(struct smu_context *smu,
+                                     uint32_t speed)
+{
+       struct amdgpu_device *adev = smu->adev;
+       uint32_t duty100, duty;
+       uint64_t tmp64;
+
+       speed = MIN(speed, 255);
+
+       duty100 = REG_GET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL1_ARCT),
+                               CG_FDO_CTRL1, FMAX_DUTY100);
+       if (!duty100)
+               return -EINVAL;
+
+       tmp64 = (uint64_t)speed * duty100;
+       do_div(tmp64, 255);
+       duty = (uint32_t)tmp64;
+
+       WREG32_SOC15(THM, 0, mmCG_FDO_CTRL0_ARCT,
+                    REG_SET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL0_ARCT),
+                                  CG_FDO_CTRL0, FDO_STATIC_DUTY, duty));
+
+       return arcturus_set_fan_static_mode(smu, FDO_PWM_MODE_STATIC);
+}
+
+static int arcturus_set_fan_speed_rpm(struct smu_context *smu,
+                                     uint32_t speed)
+{
+       struct amdgpu_device *adev = smu->adev;
+       /*
+        * crystal_clock_freq used for fan speed rpm calculation is
+        * always 25Mhz. So, hardcode it as 2500(in 10K unit).
+        */
+       uint32_t crystal_clock_freq = 2500;
+       uint32_t tach_period;
+
+       tach_period = 60 * crystal_clock_freq * 10000 / (8 * speed);
+       WREG32_SOC15(THM, 0, mmCG_TACH_CTRL_ARCT,
+                    REG_SET_FIELD(RREG32_SOC15(THM, 0, mmCG_TACH_CTRL_ARCT),
+                                  CG_TACH_CTRL, TARGET_PERIOD,
+                                  tach_period));
+
+       return arcturus_set_fan_static_mode(smu, FDO_PWM_MODE_STATIC_RPM);
+}
+
+static int arcturus_get_fan_speed_pwm(struct smu_context *smu,
+                                     uint32_t *speed)
+{
+       struct amdgpu_device *adev = smu->adev;
+       uint32_t duty100, duty;
+       uint64_t tmp64;
+
+       /*
+        * For pre Sienna Cichlid ASICs, the 0 RPM may be not correctly
+        * detected via register retrieving. To workaround this, we will
+        * report the fan speed as 0 PWM if user just requested such.
+        */
+       if ((smu->user_dpm_profile.flags & SMU_CUSTOM_FAN_SPEED_PWM)
+            && !smu->user_dpm_profile.fan_speed_pwm) {
+               *speed = 0;
                return 0;
        }
+
+       duty100 = REG_GET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL1_ARCT),
+                               CG_FDO_CTRL1, FMAX_DUTY100);
+       duty = REG_GET_FIELD(RREG32_SOC15(THM, 0, mmCG_THERMAL_STATUS_ARCT),
+                               CG_THERMAL_STATUS, FDO_PWM_DUTY);
+
+       if (duty100) {
+               tmp64 = (uint64_t)duty * 255;
+               do_div(tmp64, duty100);
+               *speed = MIN((uint32_t)tmp64, 255);
+       } else {
+               *speed = 0;
+       }
+
+       return 0;
 }
 
 static int arcturus_get_fan_parameters(struct smu_context *smu)
@@ -1272,11 +1404,11 @@ static int arcturus_get_power_profile_mode(struct smu_context *smu,
                return result;
 
        if (smu_version >= 0x360d00)
-               size += sprintf(buf + size, "%16s %s %s %s %s %s %s %s %s %s %s\n",
+               size += sysfs_emit_at(buf, size, "%16s %s %s %s %s %s %s %s %s %s %s\n",
                        title[0], title[1], title[2], title[3], title[4], title[5],
                        title[6], title[7], title[8], title[9], title[10]);
        else
-               size += sprintf(buf + size, "%16s\n",
+               size += sysfs_emit_at(buf, size, "%16s\n",
                        title[0]);
 
        for (i = 0; i <= PP_SMC_POWER_PROFILE_CUSTOM; i++) {
@@ -1302,11 +1434,11 @@ static int arcturus_get_power_profile_mode(struct smu_context *smu,
                        }
                }
 
-               size += sprintf(buf + size, "%2d %14s%s\n",
+               size += sysfs_emit_at(buf, size, "%2d %14s%s\n",
                        i, profile_name[i], (i == smu->power_profile_mode) ? "*" : " ");
 
                if (smu_version >= 0x360d00) {
-                       size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
+                       size += sysfs_emit_at(buf, size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
                                " ",
                                0,
                                "GFXCLK",
@@ -1320,7 +1452,7 @@ static int arcturus_get_power_profile_mode(struct smu_context *smu,
                                activity_monitor.Gfx_PD_Data_error_coeff,
                                activity_monitor.Gfx_PD_Data_error_rate_coeff);
 
-                       size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
+                       size += sysfs_emit_at(buf, size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
                                " ",
                                1,
                                "UCLK",
@@ -1916,16 +2048,16 @@ static int arcturus_dpm_set_vcn_enable(struct smu_context *smu, bool enable)
        int ret = 0;
 
        if (enable) {
-               if (!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) {
-                       ret = smu_cmn_feature_set_enabled(smu, SMU_FEATURE_VCN_PG_BIT, 1);
+               if (!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_DPM_BIT)) {
+                       ret = smu_cmn_feature_set_enabled(smu, SMU_FEATURE_VCN_DPM_BIT, 1);
                        if (ret) {
                                dev_err(smu->adev->dev, "[EnableVCNDPM] failed!\n");
                                return ret;
                        }
                }
        } else {
-               if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) {
-                       ret = smu_cmn_feature_set_enabled(smu, SMU_FEATURE_VCN_PG_BIT, 0);
+               if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_DPM_BIT)) {
+                       ret = smu_cmn_feature_set_enabled(smu, SMU_FEATURE_VCN_DPM_BIT, 0);
                        if (ret) {
                                dev_err(smu->adev->dev, "[DisableVCNDPM] failed!\n");
                                return ret;
@@ -1936,197 +2068,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 +2152,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 +2310,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)
@@ -2378,7 +2402,8 @@ static const struct pptable_funcs arcturus_ppt_funcs = {
        .print_clk_levels = arcturus_print_clk_levels,
        .force_clk_levels = arcturus_force_clk_levels,
        .read_sensor = arcturus_read_sensor,
-       .get_fan_speed_percent = arcturus_get_fan_speed_percent,
+       .get_fan_speed_pwm = arcturus_get_fan_speed_pwm,
+       .get_fan_speed_rpm = arcturus_get_fan_speed_rpm,
        .get_power_profile_mode = arcturus_get_power_profile_mode,
        .set_power_profile_mode = arcturus_set_power_profile_mode,
        .set_performance_level = arcturus_set_performance_level,
@@ -2423,7 +2448,8 @@ static const struct pptable_funcs arcturus_ppt_funcs = {
        .display_clock_voltage_request = smu_v11_0_display_clock_voltage_request,
        .get_fan_control_mode = smu_v11_0_get_fan_control_mode,
        .set_fan_control_mode = smu_v11_0_set_fan_control_mode,
-       .set_fan_speed_percent = smu_v11_0_set_fan_speed_percent,
+       .set_fan_speed_pwm = arcturus_set_fan_speed_pwm,
+       .set_fan_speed_rpm = arcturus_set_fan_speed_rpm,
        .set_xgmi_pstate = smu_v11_0_set_xgmi_pstate,
        .gfx_off_control = smu_v11_0_gfx_off_control,
        .register_irq_handler = smu_v11_0_register_irq_handler,