]> git.baikalelectronics.ru Git - kernel.git/commitdiff
drm/pm/swsmu: add ras eeprom i2c function for smu13 v13_0_0
authorYiPeng Chai <YiPeng.Chai@amd.com>
Tue, 21 Jun 2022 06:06:56 +0000 (14:06 +0800)
committerAlex Deucher <alexander.deucher@amd.com>
Mon, 25 Jul 2022 13:31:03 +0000 (09:31 -0400)
Add ras eeprom i2c function for smu13 v13_0_0.

Signed-off-by: YiPeng Chai <YiPeng.Chai@amd.com>
Acked-by: Evan Quan <evan.quan@amd.com>
Acked-by: Alex Deucher <alexander.deucher@amd.com>
Reviewed-by: Hawking Zhang <Hawking.Zhang@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c

index ce2fa04e3926a6f4fcd7987a47b432b75e32074c..2b83191e800643bb79a0ad560fe91665006a8d33 100644 (file)
@@ -196,6 +196,7 @@ static struct cmn2asic_mapping smu_v13_0_0_table_map[SMU_TABLE_COUNT] = {
        TAB_MAP(DRIVER_SMU_CONFIG),
        TAB_MAP(ACTIVITY_MONITOR_COEFF),
        [SMU_TABLE_COMBO_PPTABLE] = {1, TABLE_COMBO_PPTABLE},
+       TAB_MAP(I2C_COMMANDS),
 };
 
 static struct cmn2asic_mapping smu_v13_0_0_pwr_src_map[SMU_POWER_SOURCE_COUNT] = {
@@ -1606,9 +1607,165 @@ static bool smu_v13_0_0_is_mode1_reset_supported(struct smu_context *smu)
        return true;
 }
 
+static int smu_v13_0_0_i2c_xfer(struct i2c_adapter *i2c_adap,
+                                  struct i2c_msg *msg, int num_msgs)
+{
+       struct amdgpu_smu_i2c_bus *smu_i2c = i2c_get_adapdata(i2c_adap);
+       struct amdgpu_device *adev = smu_i2c->adev;
+       struct smu_context *smu = adev->powerplay.pp_handle;
+       struct smu_table_context *smu_table = &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 (!adev->pm.dpm_enabled)
+               return -EBUSY;
+
+       req = kzalloc(sizeof(*req), GFP_KERNEL);
+       if (!req)
+               return -ENOMEM;
+
+       req->I2CcontrollerPort = smu_i2c->port;
+       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];
+                       }
+
+                       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->pm.mutex);
+       r = smu_cmn_update_table(smu, SMU_TABLE_I2C_COMMANDS, 0, req, true);
+       mutex_unlock(&adev->pm.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->ReadWriteData;
+               }
+       }
+       r = num_msgs;
+fail:
+       kfree(req);
+       return r;
+}
+
+static u32 smu_v13_0_0_i2c_func(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm smu_v13_0_0_i2c_algo = {
+       .master_xfer = smu_v13_0_0_i2c_xfer,
+       .functionality = smu_v13_0_0_i2c_func,
+};
+
+static const struct i2c_adapter_quirks smu_v13_0_0_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 smu_v13_0_0_i2c_control_init(struct smu_context *smu)
+{
+       struct amdgpu_device *adev = smu->adev;
+       int res, i;
+
+       for (i = 0; i < MAX_SMU_I2C_BUSES; i++) {
+               struct amdgpu_smu_i2c_bus *smu_i2c = &adev->pm.smu_i2c[i];
+               struct i2c_adapter *control = &smu_i2c->adapter;
+
+               smu_i2c->adev = adev;
+               smu_i2c->port = i;
+               mutex_init(&smu_i2c->mutex);
+               control->owner = THIS_MODULE;
+               control->class = I2C_CLASS_SPD;
+               control->dev.parent = &adev->pdev->dev;
+               control->algo = &smu_v13_0_0_i2c_algo;
+               snprintf(control->name, sizeof(control->name), "AMDGPU SMU %d", i);
+               control->quirks = &smu_v13_0_0_i2c_control_quirks;
+               i2c_set_adapdata(control, smu_i2c);
+
+               res = i2c_add_adapter(control);
+               if (res) {
+                       DRM_ERROR("Failed to register hw i2c, err: %d\n", res);
+                       goto Out_err;
+               }
+       }
+
+       /* assign the buses used for the FRU EEPROM and RAS EEPROM */
+       /* XXX ideally this would be something in a vbios data table */
+       adev->pm.ras_eeprom_i2c_bus = &adev->pm.smu_i2c[1].adapter;
+       adev->pm.fru_eeprom_i2c_bus = &adev->pm.smu_i2c[0].adapter;
+
+       return 0;
+Out_err:
+       for ( ; i >= 0; i--) {
+               struct amdgpu_smu_i2c_bus *smu_i2c = &adev->pm.smu_i2c[i];
+               struct i2c_adapter *control = &smu_i2c->adapter;
+
+               i2c_del_adapter(control);
+       }
+       return res;
+}
+
+static void smu_v13_0_0_i2c_control_fini(struct smu_context *smu)
+{
+       struct amdgpu_device *adev = smu->adev;
+       int i;
+
+       for (i = 0; i < MAX_SMU_I2C_BUSES; i++) {
+               struct amdgpu_smu_i2c_bus *smu_i2c = &adev->pm.smu_i2c[i];
+               struct i2c_adapter *control = &smu_i2c->adapter;
+
+               i2c_del_adapter(control);
+       }
+       adev->pm.ras_eeprom_i2c_bus = NULL;
+       adev->pm.fru_eeprom_i2c_bus = NULL;
+}
+
 static const struct pptable_funcs smu_v13_0_0_ppt_funcs = {
        .get_allowed_feature_mask = smu_v13_0_0_get_allowed_feature_mask,
        .set_default_dpm_table = smu_v13_0_0_set_default_dpm_table,
+       .i2c_init = smu_v13_0_0_i2c_control_init,
+       .i2c_fini = smu_v13_0_0_i2c_control_fini,
        .is_dpm_running = smu_v13_0_0_is_dpm_running,
        .dump_pptable = smu_v13_0_0_dump_pptable,
        .init_microcode = smu_v13_0_init_microcode,