Commit ebe57d0c authored by Luben Tuikov's avatar Luben Tuikov Committed by Alex Deucher

drm/amd/pm: Simplify managed I2C transfer functions

Now that we have an I2C quirk table for
SMU-managed I2C controllers, the I2C core does the
checks for us, so we don't need to do them, and so
simplify the managed I2C transfer functions.

Also, for Arcturus and Navi10, fix setting the
command type from "cmd->CmdConfig" to "cmd->Cmd".
The latter is what appears to be taking in
the enumeration I2C_CMD_... as an integer,
not a bit-flag.

For Sienna, the "Cmd" field seems to have been
eliminated, and command type and flags all live in
the "CmdConfig" field--this is left untouched.

Fix: Detect and add changing of direction
bit-flag, as this is necessary for the SMU to
detect the direction change in the 1-d array of
data it gets.

Cc: Jean Delvare <jdelvare@suse.de>
Cc: Alexander Deucher <Alexander.Deucher@amd.com>
Cc: Andrey Grodzovsky <Andrey.Grodzovsky@amd.com>
Cc: Lijo Lazar <Lijo.Lazar@amd.com>
Cc: Stanley Yang <Stanley.Yang@amd.com>
Cc: Hawking Zhang <Hawking.Zhang@amd.com>
Signed-off-by: default avatarLuben Tuikov <luben.tuikov@amd.com>
Acked-by: default avatarAlexander Deucher <Alexander.Deucher@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 16736627
...@@ -1937,31 +1937,14 @@ static int arcturus_dpm_set_vcn_enable(struct smu_context *smu, bool enable) ...@@ -1937,31 +1937,14 @@ static int arcturus_dpm_set_vcn_enable(struct smu_context *smu, bool enable)
} }
static int arcturus_i2c_xfer(struct i2c_adapter *i2c_adap, static int arcturus_i2c_xfer(struct i2c_adapter *i2c_adap,
struct i2c_msg *msgs, int num) struct i2c_msg *msg, int num_msgs)
{ {
struct amdgpu_device *adev = to_amdgpu_device(i2c_adap); struct amdgpu_device *adev = to_amdgpu_device(i2c_adap);
struct smu_table_context *smu_table = &adev->smu.smu_table; struct smu_table_context *smu_table = &adev->smu.smu_table;
struct smu_table *table = &smu_table->driver_table; struct smu_table *table = &smu_table->driver_table;
SwI2cRequest_t *req, *res = (SwI2cRequest_t *)table->cpu_addr; SwI2cRequest_t *req, *res = (SwI2cRequest_t *)table->cpu_addr;
short available_bytes = MAX_SW_I2C_COMMANDS; int i, j, r, c;
int i, j, r, c, num_done = 0; u16 dir;
u8 slave;
/* only support a single slave addr per transaction */
slave = msgs[0].addr;
for (i = 0; i < num; i++) {
if (slave != msgs[i].addr)
return -EINVAL;
available_bytes -= msgs[i].len;
if (available_bytes >= 0) {
num_done++;
} else {
/* This message and all the follwing won't be processed */
available_bytes += msgs[i].len;
break;
}
}
req = kzalloc(sizeof(*req), GFP_KERNEL); req = kzalloc(sizeof(*req), GFP_KERNEL);
if (!req) if (!req)
...@@ -1969,33 +1952,38 @@ static int arcturus_i2c_xfer(struct i2c_adapter *i2c_adap, ...@@ -1969,33 +1952,38 @@ static int arcturus_i2c_xfer(struct i2c_adapter *i2c_adap,
req->I2CcontrollerPort = 0; req->I2CcontrollerPort = 0;
req->I2CSpeed = I2C_SPEED_FAST_400K; req->I2CSpeed = I2C_SPEED_FAST_400K;
req->SlaveAddress = slave << 1; /* 8 bit addresses */ req->SlaveAddress = msg[0].addr << 1; /* wants an 8-bit address */
req->NumCmds = MAX_SW_I2C_COMMANDS - available_bytes;; dir = msg[0].flags & I2C_M_RD;
c = 0;
for (i = 0; i < num_done; i++) {
struct i2c_msg *msg = &msgs[i];
for (j = 0; j < msg->len; j++) { for (c = i = 0; i < num_msgs; i++) {
SwI2cCmd_t *cmd = &req->SwI2cCmds[c++]; for (j = 0; j < msg[i].len; j++, c++) {
SwI2cCmd_t *cmd = &req->SwI2cCmds[c];
if (!(msg[i].flags & I2C_M_RD)) { if (!(msg[i].flags & I2C_M_RD)) {
/* write */ /* write */
cmd->CmdConfig |= I2C_CMD_WRITE; cmd->Cmd = I2C_CMD_WRITE;
cmd->RegisterAddr = msg->buf[j]; 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 * Insert STOP if we are at the last byte of either last
* message for the transaction or the client explicitly * message for the transaction or the client explicitly
* requires a STOP at this particular message. * requires a STOP at this particular message.
*/ */
if ((j == msg->len -1 ) && if ((j == msg[i].len - 1) &&
((i == num_done - 1) || (msg[i].flags & I2C_M_STOP))) ((i == num_msgs - 1) || (msg[i].flags & I2C_M_STOP))) {
cmd->CmdConfig &= ~CMDCONFIG_RESTART_MASK;
cmd->CmdConfig |= CMDCONFIG_STOP_MASK; cmd->CmdConfig |= CMDCONFIG_STOP_MASK;
}
if ((j == 0) && !(msg[i].flags & I2C_M_NOSTART))
cmd->CmdConfig |= CMDCONFIG_RESTART_BIT;
} }
} }
mutex_lock(&adev->smu.mutex); mutex_lock(&adev->smu.mutex);
...@@ -2004,22 +1992,20 @@ static int arcturus_i2c_xfer(struct i2c_adapter *i2c_adap, ...@@ -2004,22 +1992,20 @@ static int arcturus_i2c_xfer(struct i2c_adapter *i2c_adap,
if (r) if (r)
goto fail; goto fail;
c = 0; for (c = i = 0; i < num_msgs; i++) {
for (i = 0; i < num_done; i++) { if (!(msg[i].flags & I2C_M_RD)) {
struct i2c_msg *msg = &msgs[i]; c += msg[i].len;
continue;
for (j = 0; j < msg->len; j++) { }
SwI2cCmd_t *cmd = &res->SwI2cCmds[c++]; for (j = 0; j < msg[i].len; j++, c++) {
SwI2cCmd_t *cmd = &res->SwI2cCmds[c];
if (msg[i].flags & I2C_M_RD) msg[i].buf[j] = cmd->Data;
msg->buf[j] = cmd->Data;
} }
} }
r = num_done; r = num_msgs;
fail: fail:
kfree(req); kfree(req);
return r; return r;
} }
......
...@@ -2736,31 +2736,14 @@ static ssize_t navi10_get_legacy_gpu_metrics(struct smu_context *smu, ...@@ -2736,31 +2736,14 @@ static ssize_t navi10_get_legacy_gpu_metrics(struct smu_context *smu,
} }
static int navi10_i2c_xfer(struct i2c_adapter *i2c_adap, static int navi10_i2c_xfer(struct i2c_adapter *i2c_adap,
struct i2c_msg *msgs, int num) struct i2c_msg *msg, int num_msgs)
{ {
struct amdgpu_device *adev = to_amdgpu_device(i2c_adap); struct amdgpu_device *adev = to_amdgpu_device(i2c_adap);
struct smu_table_context *smu_table = &adev->smu.smu_table; struct smu_table_context *smu_table = &adev->smu.smu_table;
struct smu_table *table = &smu_table->driver_table; struct smu_table *table = &smu_table->driver_table;
SwI2cRequest_t *req, *res = (SwI2cRequest_t *)table->cpu_addr; SwI2cRequest_t *req, *res = (SwI2cRequest_t *)table->cpu_addr;
short available_bytes = MAX_SW_I2C_COMMANDS; int i, j, r, c;
int i, j, r, c, num_done = 0; u16 dir;
u8 slave;
/* only support a single slave addr per transaction */
slave = msgs[0].addr;
for (i = 0; i < num; i++) {
if (slave != msgs[i].addr)
return -EINVAL;
available_bytes -= msgs[i].len;
if (available_bytes >= 0) {
num_done++;
} else {
/* This message and all the follwing won't be processed */
available_bytes += msgs[i].len;
break;
}
}
req = kzalloc(sizeof(*req), GFP_KERNEL); req = kzalloc(sizeof(*req), GFP_KERNEL);
if (!req) if (!req)
...@@ -2768,33 +2751,38 @@ static int navi10_i2c_xfer(struct i2c_adapter *i2c_adap, ...@@ -2768,33 +2751,38 @@ static int navi10_i2c_xfer(struct i2c_adapter *i2c_adap,
req->I2CcontrollerPort = 0; req->I2CcontrollerPort = 0;
req->I2CSpeed = I2C_SPEED_FAST_400K; req->I2CSpeed = I2C_SPEED_FAST_400K;
req->SlaveAddress = slave << 1; /* 8 bit addresses */ req->SlaveAddress = msg[0].addr << 1; /* wants an 8-bit address */
req->NumCmds = MAX_SW_I2C_COMMANDS - available_bytes;; dir = msg[0].flags & I2C_M_RD;
c = 0; for (c = i = 0; i < num_msgs; i++) {
for (i = 0; i < num_done; i++) { for (j = 0; j < msg[i].len; j++, c++) {
struct i2c_msg *msg = &msgs[i]; SwI2cCmd_t *cmd = &req->SwI2cCmds[c];
for (j = 0; j < msg->len; j++) {
SwI2cCmd_t *cmd = &req->SwI2cCmds[c++];
if (!(msg[i].flags & I2C_M_RD)) { if (!(msg[i].flags & I2C_M_RD)) {
/* write */ /* write */
cmd->CmdConfig |= I2C_CMD_WRITE; cmd->Cmd = I2C_CMD_WRITE;
cmd->RegisterAddr = msg->buf[j]; 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 * Insert STOP if we are at the last byte of either last
* message for the transaction or the client explicitly * message for the transaction or the client explicitly
* requires a STOP at this particular message. * requires a STOP at this particular message.
*/ */
if ((j == msg->len -1 ) && if ((j == msg[i].len - 1) &&
((i == num_done - 1) || (msg[i].flags & I2C_M_STOP))) ((i == num_msgs - 1) || (msg[i].flags & I2C_M_STOP))) {
cmd->CmdConfig &= ~CMDCONFIG_RESTART_MASK;
cmd->CmdConfig |= CMDCONFIG_STOP_MASK; cmd->CmdConfig |= CMDCONFIG_STOP_MASK;
}
if ((j == 0) && !(msg[i].flags & I2C_M_NOSTART))
cmd->CmdConfig |= CMDCONFIG_RESTART_BIT;
} }
} }
mutex_lock(&adev->smu.mutex); mutex_lock(&adev->smu.mutex);
...@@ -2803,22 +2791,20 @@ static int navi10_i2c_xfer(struct i2c_adapter *i2c_adap, ...@@ -2803,22 +2791,20 @@ static int navi10_i2c_xfer(struct i2c_adapter *i2c_adap,
if (r) if (r)
goto fail; goto fail;
c = 0; for (c = i = 0; i < num_msgs; i++) {
for (i = 0; i < num_done; i++) { if (!(msg[i].flags & I2C_M_RD)) {
struct i2c_msg *msg = &msgs[i]; c += msg[i].len;
continue;
for (j = 0; j < msg->len; j++) { }
SwI2cCmd_t *cmd = &res->SwI2cCmds[c++]; for (j = 0; j < msg[i].len; j++, c++) {
SwI2cCmd_t *cmd = &res->SwI2cCmds[c];
if (msg[i].flags & I2C_M_RD) msg[i].buf[j] = cmd->Data;
msg->buf[j] = cmd->Data;
} }
} }
r = num_done; r = num_msgs;
fail: fail:
kfree(req); kfree(req);
return r; return r;
} }
......
...@@ -3443,31 +3443,14 @@ static void sienna_cichlid_dump_pptable(struct smu_context *smu) ...@@ -3443,31 +3443,14 @@ static void sienna_cichlid_dump_pptable(struct smu_context *smu)
} }
static int sienna_cichlid_i2c_xfer(struct i2c_adapter *i2c_adap, static int sienna_cichlid_i2c_xfer(struct i2c_adapter *i2c_adap,
struct i2c_msg *msgs, int num) struct i2c_msg *msg, int num_msgs)
{ {
struct amdgpu_device *adev = to_amdgpu_device(i2c_adap); struct amdgpu_device *adev = to_amdgpu_device(i2c_adap);
struct smu_table_context *smu_table = &adev->smu.smu_table; struct smu_table_context *smu_table = &adev->smu.smu_table;
struct smu_table *table = &smu_table->driver_table; struct smu_table *table = &smu_table->driver_table;
SwI2cRequest_t *req, *res = (SwI2cRequest_t *)table->cpu_addr; SwI2cRequest_t *req, *res = (SwI2cRequest_t *)table->cpu_addr;
short available_bytes = MAX_SW_I2C_COMMANDS; int i, j, r, c;
int i, j, r, c, num_done = 0; u16 dir;
u8 slave;
/* only support a single slave addr per transaction */
slave = msgs[0].addr;
for (i = 0; i < num; i++) {
if (slave != msgs[i].addr)
return -EINVAL;
available_bytes -= msgs[i].len;
if (available_bytes >= 0) {
num_done++;
} else {
/* This message and all the follwing won't be processed */
available_bytes += msgs[i].len;
break;
}
}
req = kzalloc(sizeof(*req), GFP_KERNEL); req = kzalloc(sizeof(*req), GFP_KERNEL);
if (!req) if (!req)
...@@ -3475,33 +3458,38 @@ static int sienna_cichlid_i2c_xfer(struct i2c_adapter *i2c_adap, ...@@ -3475,33 +3458,38 @@ static int sienna_cichlid_i2c_xfer(struct i2c_adapter *i2c_adap,
req->I2CcontrollerPort = 1; req->I2CcontrollerPort = 1;
req->I2CSpeed = I2C_SPEED_FAST_400K; req->I2CSpeed = I2C_SPEED_FAST_400K;
req->SlaveAddress = slave << 1; /* 8 bit addresses */ req->SlaveAddress = msg[0].addr << 1; /* wants an 8-bit address */
req->NumCmds = MAX_SW_I2C_COMMANDS - available_bytes;; dir = msg[0].flags & I2C_M_RD;
c = 0; for (c = i = 0; i < num_msgs; i++) {
for (i = 0; i < num_done; i++) { for (j = 0; j < msg[i].len; j++, c++) {
struct i2c_msg *msg = &msgs[i]; SwI2cCmd_t *cmd = &req->SwI2cCmds[c];
for (j = 0; j < msg->len; j++) {
SwI2cCmd_t *cmd = &req->SwI2cCmds[c++];
if (!(msg[i].flags & I2C_M_RD)) { if (!(msg[i].flags & I2C_M_RD)) {
/* write */ /* write */
cmd->CmdConfig |= CMDCONFIG_READWRITE_MASK; cmd->CmdConfig |= CMDCONFIG_READWRITE_MASK;
cmd->ReadWriteData = msg->buf[j]; 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 * Insert STOP if we are at the last byte of either last
* message for the transaction or the client explicitly * message for the transaction or the client explicitly
* requires a STOP at this particular message. * requires a STOP at this particular message.
*/ */
if ((j == msg->len -1 ) && if ((j == msg[i].len - 1) &&
((i == num_done - 1) || (msg[i].flags & I2C_M_STOP))) ((i == num_msgs - 1) || (msg[i].flags & I2C_M_STOP))) {
cmd->CmdConfig &= ~CMDCONFIG_RESTART_MASK;
cmd->CmdConfig |= CMDCONFIG_STOP_MASK; cmd->CmdConfig |= CMDCONFIG_STOP_MASK;
}
if ((j == 0) && !(msg[i].flags & I2C_M_NOSTART))
cmd->CmdConfig |= CMDCONFIG_RESTART_BIT;
} }
} }
mutex_lock(&adev->smu.mutex); mutex_lock(&adev->smu.mutex);
...@@ -3510,22 +3498,20 @@ static int sienna_cichlid_i2c_xfer(struct i2c_adapter *i2c_adap, ...@@ -3510,22 +3498,20 @@ static int sienna_cichlid_i2c_xfer(struct i2c_adapter *i2c_adap,
if (r) if (r)
goto fail; goto fail;
c = 0; for (c = i = 0; i < num_msgs; i++) {
for (i = 0; i < num_done; i++) { if (!(msg[i].flags & I2C_M_RD)) {
struct i2c_msg *msg = &msgs[i]; c += msg[i].len;
continue;
for (j = 0; j < msg->len; j++) { }
SwI2cCmd_t *cmd = &res->SwI2cCmds[c++]; for (j = 0; j < msg[i].len; j++, c++) {
SwI2cCmd_t *cmd = &res->SwI2cCmds[c];
if (msg[i].flags & I2C_M_RD) msg[i].buf[j] = cmd->ReadWriteData;
msg->buf[j] = cmd->ReadWriteData;
} }
} }
r = num_done; r = num_msgs;
fail: fail:
kfree(req); kfree(req);
return r; return r;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment