* [PATCH 2/6] drm/amdgpu: remove eeprom from the smu i2c handlers
2020-07-21 16:52 [PATCH 1/6] drm/amdgpu: move i2c bus lock out of ras structure Alex Deucher
@ 2020-07-21 16:52 ` Alex Deucher
2020-07-21 16:52 ` [PATCH 3/6] drm/amdgpu/vega20: enable the smu i2c bus for all boards Alex Deucher
` (3 subsequent siblings)
4 siblings, 0 replies; 10+ messages in thread
From: Alex Deucher @ 2020-07-21 16:52 UTC (permalink / raw)
To: amd-gfx; +Cc: Alex Deucher
The driver uses it for EEPROM access, but it's just an i2c bus.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c | 52 +++++++++----------
drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.h | 4 +-
.../drm/amd/powerplay/smumgr/vega20_smumgr.c | 4 +-
3 files changed, 30 insertions(+), 30 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c b/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c
index f3d0324c4a7f..d55bf64770c4 100644
--- a/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c
+++ b/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c
@@ -536,12 +536,12 @@ static bool smu_v11_0_i2c_bus_unlock(struct i2c_adapter *control)
return false;
}
-/***************************** EEPROM I2C GLUE ****************************/
+/***************************** I2C GLUE ****************************/
-static uint32_t smu_v11_0_i2c_eeprom_read_data(struct i2c_adapter *control,
- uint8_t address,
- uint8_t *data,
- uint32_t numbytes)
+static uint32_t smu_v11_0_i2c_read_data(struct i2c_adapter *control,
+ uint8_t address,
+ uint8_t *data,
+ uint32_t numbytes)
{
uint32_t ret = 0;
@@ -561,10 +561,10 @@ static uint32_t smu_v11_0_i2c_eeprom_read_data(struct i2c_adapter *control,
return ret;
}
-static uint32_t smu_v11_0_i2c_eeprom_write_data(struct i2c_adapter *control,
- uint8_t address,
- uint8_t *data,
- uint32_t numbytes)
+static uint32_t smu_v11_0_i2c_write_data(struct i2c_adapter *control,
+ uint8_t address,
+ uint8_t *data,
+ uint32_t numbytes)
{
uint32_t ret;
@@ -624,7 +624,7 @@ static const struct i2c_lock_operations smu_v11_0_i2c_i2c_lock_ops = {
.unlock_bus = unlock_bus,
};
-static int smu_v11_0_i2c_eeprom_i2c_xfer(struct i2c_adapter *i2c_adap,
+static int smu_v11_0_i2c_xfer(struct i2c_adapter *i2c_adap,
struct i2c_msg *msgs, int num)
{
int i, ret;
@@ -639,13 +639,13 @@ static int smu_v11_0_i2c_eeprom_i2c_xfer(struct i2c_adapter *i2c_adap,
for (i = 0; i < num; i++) {
if (msgs[i].flags & I2C_M_RD)
- ret = smu_v11_0_i2c_eeprom_read_data(i2c_adap,
- (uint8_t)msgs[i].addr,
- msgs[i].buf, msgs[i].len);
+ ret = smu_v11_0_i2c_read_data(i2c_adap,
+ (uint8_t)msgs[i].addr,
+ msgs[i].buf, msgs[i].len);
else
- ret = smu_v11_0_i2c_eeprom_write_data(i2c_adap,
- (uint8_t)msgs[i].addr,
- msgs[i].buf, msgs[i].len);
+ ret = smu_v11_0_i2c_write_data(i2c_adap,
+ (uint8_t)msgs[i].addr,
+ msgs[i].buf, msgs[i].len);
if (ret != I2C_OK) {
num = -EIO;
@@ -657,18 +657,18 @@ static int smu_v11_0_i2c_eeprom_i2c_xfer(struct i2c_adapter *i2c_adap,
return num;
}
-static u32 smu_v11_0_i2c_eeprom_i2c_func(struct i2c_adapter *adap)
+static u32 smu_v11_0_i2c_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
-static const struct i2c_algorithm smu_v11_0_i2c_eeprom_i2c_algo = {
- .master_xfer = smu_v11_0_i2c_eeprom_i2c_xfer,
- .functionality = smu_v11_0_i2c_eeprom_i2c_func,
+static const struct i2c_algorithm smu_v11_0_i2c_algo = {
+ .master_xfer = smu_v11_0_i2c_xfer,
+ .functionality = smu_v11_0_i2c_func,
};
-int smu_v11_0_i2c_eeprom_control_init(struct i2c_adapter *control)
+int smu_v11_0_i2c_control_init(struct i2c_adapter *control)
{
struct amdgpu_device *adev = to_amdgpu_device(control);
int res;
@@ -676,8 +676,8 @@ int smu_v11_0_i2c_eeprom_control_init(struct i2c_adapter *control)
control->owner = THIS_MODULE;
control->class = I2C_CLASS_SPD;
control->dev.parent = &adev->pdev->dev;
- control->algo = &smu_v11_0_i2c_eeprom_i2c_algo;
- snprintf(control->name, sizeof(control->name), "AMDGPU EEPROM");
+ control->algo = &smu_v11_0_i2c_algo;
+ snprintf(control->name, sizeof(control->name), "AMDGPU SMU");
control->lock_ops = &smu_v11_0_i2c_i2c_lock_ops;
res = i2c_add_adapter(control);
@@ -687,7 +687,7 @@ int smu_v11_0_i2c_eeprom_control_init(struct i2c_adapter *control)
return res;
}
-void smu_v11_0_i2c_eeprom_control_fini(struct i2c_adapter *control)
+void smu_v11_0_i2c_control_fini(struct i2c_adapter *control)
{
i2c_del_adapter(control);
}
@@ -715,9 +715,9 @@ bool smu_v11_0_i2c_test_bus(struct i2c_adapter *control)
smu_v11_0_i2c_init(control);
/* Write 0xde to address 0x0000 on the EEPROM */
- ret = smu_v11_0_i2c_eeprom_write_data(control, I2C_TARGET_ADDR, data, 6);
+ ret = smu_v11_0_i2c_write_data(control, I2C_TARGET_ADDR, data, 6);
- ret = smu_v11_0_i2c_eeprom_read_data(control, I2C_TARGET_ADDR, data, 6);
+ ret = smu_v11_0_i2c_read_data(control, I2C_TARGET_ADDR, data, 6);
smu_v11_0_i2c_fini(control);
diff --git a/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.h b/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.h
index 973f28d68e70..44467c05f642 100644
--- a/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.h
+++ b/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.h
@@ -28,7 +28,7 @@
struct i2c_adapter;
-int smu_v11_0_i2c_eeprom_control_init(struct i2c_adapter *control);
-void smu_v11_0_i2c_eeprom_control_fini(struct i2c_adapter *control);
+int smu_v11_0_i2c_control_init(struct i2c_adapter *control);
+void smu_v11_0_i2c_control_fini(struct i2c_adapter *control);
#endif
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/vega20_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/vega20_smumgr.c
index c2e0fbbccf56..d1b7955bb4c7 100644
--- a/drivers/gpu/drm/amd/powerplay/smumgr/vega20_smumgr.c
+++ b/drivers/gpu/drm/amd/powerplay/smumgr/vega20_smumgr.c
@@ -523,7 +523,7 @@ static int vega20_smu_init(struct pp_hwmgr *hwmgr)
priv->smu_tables.entry[TABLE_ACTIVITY_MONITOR_COEFF].size = sizeof(DpmActivityMonitorCoeffInt_t);
if (adev->psp.ras.ras) {
- ret = smu_v11_0_i2c_eeprom_control_init(&adev->pm.smu_i2c);
+ ret = smu_v11_0_i2c_control_init(&adev->pm.smu_i2c);
if (ret)
goto err4;
}
@@ -563,7 +563,7 @@ static int vega20_smu_fini(struct pp_hwmgr *hwmgr)
struct amdgpu_device *adev = hwmgr->adev;
if (adev->psp.ras.ras)
- smu_v11_0_i2c_eeprom_control_fini(&adev->pm.smu_i2c);
+ smu_v11_0_i2c_control_fini(&adev->pm.smu_i2c);
if (priv) {
amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_PPTABLE].handle,
--
2.25.4
_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 3/6] drm/amdgpu/vega20: enable the smu i2c bus for all boards
2020-07-21 16:52 [PATCH 1/6] drm/amdgpu: move i2c bus lock out of ras structure Alex Deucher
2020-07-21 16:52 ` [PATCH 2/6] drm/amdgpu: remove eeprom from the smu i2c handlers Alex Deucher
@ 2020-07-21 16:52 ` Alex Deucher
2020-07-21 16:52 ` [PATCH 4/6] drm/amdgpu/swSMU: remove eeprom from the smu i2c handlers Alex Deucher
` (2 subsequent siblings)
4 siblings, 0 replies; 10+ messages in thread
From: Alex Deucher @ 2020-07-21 16:52 UTC (permalink / raw)
To: amd-gfx; +Cc: Alex Deucher
There is no longer a ras dependency so it's safe to expose
on all boards.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
drivers/gpu/drm/amd/powerplay/smumgr/vega20_smumgr.c | 11 ++++-------
1 file changed, 4 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/vega20_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/vega20_smumgr.c
index d1b7955bb4c7..cf43629d29d2 100644
--- a/drivers/gpu/drm/amd/powerplay/smumgr/vega20_smumgr.c
+++ b/drivers/gpu/drm/amd/powerplay/smumgr/vega20_smumgr.c
@@ -522,11 +522,9 @@ static int vega20_smu_init(struct pp_hwmgr *hwmgr)
priv->smu_tables.entry[TABLE_ACTIVITY_MONITOR_COEFF].version = 0x01;
priv->smu_tables.entry[TABLE_ACTIVITY_MONITOR_COEFF].size = sizeof(DpmActivityMonitorCoeffInt_t);
- if (adev->psp.ras.ras) {
- ret = smu_v11_0_i2c_control_init(&adev->pm.smu_i2c);
- if (ret)
- goto err4;
- }
+ ret = smu_v11_0_i2c_control_init(&adev->pm.smu_i2c);
+ if (ret)
+ goto err4;
return 0;
@@ -562,8 +560,7 @@ static int vega20_smu_fini(struct pp_hwmgr *hwmgr)
(struct vega20_smumgr *)(hwmgr->smu_backend);
struct amdgpu_device *adev = hwmgr->adev;
- if (adev->psp.ras.ras)
- smu_v11_0_i2c_control_fini(&adev->pm.smu_i2c);
+ smu_v11_0_i2c_control_fini(&adev->pm.smu_i2c);
if (priv) {
amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_PPTABLE].handle,
--
2.25.4
_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 4/6] drm/amdgpu/swSMU: remove eeprom from the smu i2c handlers
2020-07-21 16:52 [PATCH 1/6] drm/amdgpu: move i2c bus lock out of ras structure Alex Deucher
2020-07-21 16:52 ` [PATCH 2/6] drm/amdgpu: remove eeprom from the smu i2c handlers Alex Deucher
2020-07-21 16:52 ` [PATCH 3/6] drm/amdgpu/vega20: enable the smu i2c bus for all boards Alex Deucher
@ 2020-07-21 16:52 ` Alex Deucher
2020-07-21 16:52 ` [PATCH 5/6] drm/amdgpu/navi1x: add SMU i2c support Alex Deucher
2020-07-21 16:52 ` [PATCH 6/6] drm/amdgpu/sienna_cichlid: " Alex Deucher
4 siblings, 0 replies; 10+ messages in thread
From: Alex Deucher @ 2020-07-21 16:52 UTC (permalink / raw)
To: amd-gfx; +Cc: Alex Deucher
The driver uses it for EEPROM access, but it's just an i2c bus.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
drivers/gpu/drm/amd/powerplay/arcturus_ppt.c | 60 ++++++++++----------
1 file changed, 30 insertions(+), 30 deletions(-)
diff --git a/drivers/gpu/drm/amd/powerplay/arcturus_ppt.c b/drivers/gpu/drm/amd/powerplay/arcturus_ppt.c
index 56dc20a617fd..7ab606734dcf 100644
--- a/drivers/gpu/drm/amd/powerplay/arcturus_ppt.c
+++ b/drivers/gpu/drm/amd/powerplay/arcturus_ppt.c
@@ -1947,7 +1947,7 @@ static int arcturus_dpm_set_vcn_enable(struct smu_context *smu, bool enable)
return ret;
}
-static void arcturus_fill_eeprom_i2c_req(SwI2cRequest_t *req, bool write,
+static void arcturus_fill_i2c_req(SwI2cRequest_t *req, bool write,
uint8_t address, uint32_t numbytes,
uint8_t *data)
{
@@ -1981,7 +1981,7 @@ static void arcturus_fill_eeprom_i2c_req(SwI2cRequest_t *req, bool write,
}
}
-static int arcturus_i2c_eeprom_read_data(struct i2c_adapter *control,
+static int arcturus_i2c_read_data(struct i2c_adapter *control,
uint8_t address,
uint8_t *data,
uint32_t numbytes)
@@ -1993,7 +1993,7 @@ static int arcturus_i2c_eeprom_read_data(struct i2c_adapter *control,
struct smu_table *table = &smu_table->driver_table;
memset(&req, 0, sizeof(req));
- arcturus_fill_eeprom_i2c_req(&req, false, address, numbytes, data);
+ arcturus_fill_i2c_req(&req, false, address, numbytes, data);
mutex_lock(&adev->smu.mutex);
/* Now read data starting with that address */
@@ -2008,18 +2008,18 @@ static int arcturus_i2c_eeprom_read_data(struct i2c_adapter *control,
for (i = 0; i < numbytes; i++)
data[i] = res->SwI2cCmds[i].Data;
- dev_dbg(adev->dev, "arcturus_i2c_eeprom_read_data, address = %x, bytes = %d, 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_eeprom_read_data - error occurred :%x", ret);
+ dev_err(adev->dev, "arcturus_i2c_read_data - error occurred :%x", ret);
return ret;
}
-static int arcturus_i2c_eeprom_write_data(struct i2c_adapter *control,
+static int arcturus_i2c_write_data(struct i2c_adapter *control,
uint8_t address,
uint8_t *data,
uint32_t numbytes)
@@ -2029,7 +2029,7 @@ static int arcturus_i2c_eeprom_write_data(struct i2c_adapter *control,
struct amdgpu_device *adev = to_amdgpu_device(control);
memset(&req, 0, sizeof(req));
- arcturus_fill_eeprom_i2c_req(&req, true, address, numbytes, data);
+ arcturus_fill_i2c_req(&req, true, address, numbytes, data);
mutex_lock(&adev->smu.mutex);
ret = smu_update_table(&adev->smu, SMU_TABLE_I2C_COMMANDS, 0, &req, true);
@@ -2055,7 +2055,7 @@ static int arcturus_i2c_eeprom_write_data(struct i2c_adapter *control,
return ret;
}
-static int arcturus_i2c_eeprom_i2c_xfer(struct i2c_adapter *i2c_adap,
+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;
@@ -2078,18 +2078,18 @@ static int arcturus_i2c_eeprom_i2c_xfer(struct i2c_adapter *i2c_adap,
data_chunk[1] = (next_eeprom_addr & 0xff);
if (msgs[i].flags & I2C_M_RD) {
- ret = arcturus_i2c_eeprom_read_data(i2c_adap,
- (uint8_t)msgs[i].addr,
- data_chunk, MAX_SW_I2C_COMMANDS);
+ 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_eeprom_write_data(i2c_adap,
- (uint8_t)msgs[i].addr,
- data_chunk, MAX_SW_I2C_COMMANDS);
+ ret = arcturus_i2c_write_data(i2c_adap,
+ (uint8_t)msgs[i].addr,
+ data_chunk, MAX_SW_I2C_COMMANDS);
}
if (ret) {
@@ -2106,17 +2106,17 @@ static int arcturus_i2c_eeprom_i2c_xfer(struct i2c_adapter *i2c_adap,
data_chunk[1] = (next_eeprom_addr & 0xff);
if (msgs[i].flags & I2C_M_RD) {
- ret = arcturus_i2c_eeprom_read_data(i2c_adap,
- (uint8_t)msgs[i].addr,
- data_chunk, (data_size % data_chunk_size) + 2);
+ 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_eeprom_write_data(i2c_adap,
- (uint8_t)msgs[i].addr,
- data_chunk, (data_size % data_chunk_size) + 2);
+ ret = arcturus_i2c_write_data(i2c_adap,
+ (uint8_t)msgs[i].addr,
+ data_chunk, (data_size % data_chunk_size) + 2);
}
if (ret) {
@@ -2130,15 +2130,15 @@ static int arcturus_i2c_eeprom_i2c_xfer(struct i2c_adapter *i2c_adap,
return num;
}
-static u32 arcturus_i2c_eeprom_i2c_func(struct i2c_adapter *adap)
+static u32 arcturus_i2c_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
-static const struct i2c_algorithm arcturus_i2c_eeprom_i2c_algo = {
- .master_xfer = arcturus_i2c_eeprom_i2c_xfer,
- .functionality = arcturus_i2c_eeprom_i2c_func,
+static const struct i2c_algorithm arcturus_i2c_algo = {
+ .master_xfer = arcturus_i2c_xfer,
+ .functionality = arcturus_i2c_func,
};
static bool arcturus_i2c_adapter_is_added(struct i2c_adapter *control)
@@ -2148,7 +2148,7 @@ static bool arcturus_i2c_adapter_is_added(struct i2c_adapter *control)
return control->dev.parent == &adev->pdev->dev;
}
-static int arcturus_i2c_eeprom_control_init(struct smu_context *smu, struct i2c_adapter *control)
+static int arcturus_i2c_control_init(struct smu_context *smu, struct i2c_adapter *control)
{
struct amdgpu_device *adev = to_amdgpu_device(control);
int res;
@@ -2160,8 +2160,8 @@ static int arcturus_i2c_eeprom_control_init(struct smu_context *smu, struct i2c_
control->owner = THIS_MODULE;
control->class = I2C_CLASS_SPD;
control->dev.parent = &adev->pdev->dev;
- control->algo = &arcturus_i2c_eeprom_i2c_algo;
- snprintf(control->name, sizeof(control->name), "AMDGPU EEPROM");
+ control->algo = &arcturus_i2c_algo;
+ snprintf(control->name, sizeof(control->name), "AMDGPU SMU");
res = i2c_add_adapter(control);
if (res)
@@ -2170,7 +2170,7 @@ static int arcturus_i2c_eeprom_control_init(struct smu_context *smu, struct i2c_
return res;
}
-static void arcturus_i2c_eeprom_control_fini(struct smu_context *smu, struct i2c_adapter *control)
+static void arcturus_i2c_control_fini(struct smu_context *smu, struct i2c_adapter *control)
{
if (!arcturus_i2c_adapter_is_added(control))
return;
@@ -2346,8 +2346,8 @@ static const struct pptable_funcs arcturus_ppt_funcs = {
.get_power_limit = arcturus_get_power_limit,
.is_dpm_running = arcturus_is_dpm_running,
.dpm_set_vcn_enable = arcturus_dpm_set_vcn_enable,
- .i2c_eeprom_init = arcturus_i2c_eeprom_control_init,
- .i2c_eeprom_fini = arcturus_i2c_eeprom_control_fini,
+ .i2c_eeprom_init = arcturus_i2c_control_init,
+ .i2c_eeprom_fini = arcturus_i2c_control_fini,
.get_unique_id = arcturus_get_unique_id,
.init_microcode = smu_v11_0_init_microcode,
.load_microcode = smu_v11_0_load_microcode,
--
2.25.4
_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 5/6] drm/amdgpu/navi1x: add SMU i2c support
2020-07-21 16:52 [PATCH 1/6] drm/amdgpu: move i2c bus lock out of ras structure Alex Deucher
` (2 preceding siblings ...)
2020-07-21 16:52 ` [PATCH 4/6] drm/amdgpu/swSMU: remove eeprom from the smu i2c handlers Alex Deucher
@ 2020-07-21 16:52 ` Alex Deucher
2020-07-21 16:56 ` Deucher, Alexander
2020-07-21 16:52 ` [PATCH 6/6] drm/amdgpu/sienna_cichlid: " Alex Deucher
4 siblings, 1 reply; 10+ messages in thread
From: Alex Deucher @ 2020-07-21 16:52 UTC (permalink / raw)
To: amd-gfx; +Cc: Alex Deucher
Enable SMU i2c bus access for navi1x asics.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
drivers/gpu/drm/amd/powerplay/navi10_ppt.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/gpu/drm/amd/powerplay/navi10_ppt.c b/drivers/gpu/drm/amd/powerplay/navi10_ppt.c
index ead135f39c7e..56267e6c600e 100644
--- a/drivers/gpu/drm/amd/powerplay/navi10_ppt.c
+++ b/drivers/gpu/drm/amd/powerplay/navi10_ppt.c
@@ -23,6 +23,7 @@
#include <linux/firmware.h>
#include <linux/pci.h>
+#include <linux/i2c.h>
#include "amdgpu.h"
#include "amdgpu_smu.h"
#include "smu_internal.h"
@@ -52,6 +53,8 @@
#undef pr_info
#undef pr_debug
+#define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c))
+
#define FEATURE_MASK(feature) (1ULL << feature)
#define SMC_DPM_FEATURE ( \
FEATURE_MASK(FEATURE_DPM_PREFETCHER_BIT) | \
--
2.25.4
_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH 5/6] drm/amdgpu/navi1x: add SMU i2c support
2020-07-21 16:52 ` [PATCH 5/6] drm/amdgpu/navi1x: add SMU i2c support Alex Deucher
@ 2020-07-21 16:56 ` Deucher, Alexander
0 siblings, 0 replies; 10+ messages in thread
From: Deucher, Alexander @ 2020-07-21 16:56 UTC (permalink / raw)
To: Alex Deucher, amd-gfx
[-- Attachment #1.1: Type: text/plain, Size: 1314 bytes --]
[AMD Official Use Only - Internal Distribution Only]
Ignore this. Sent out the wrong version.
Alex
________________________________
From: Alex Deucher <alexdeucher@gmail.com>
Sent: Tuesday, July 21, 2020 12:52 PM
To: amd-gfx@lists.freedesktop.org <amd-gfx@lists.freedesktop.org>
Cc: Deucher, Alexander <Alexander.Deucher@amd.com>
Subject: [PATCH 5/6] drm/amdgpu/navi1x: add SMU i2c support
Enable SMU i2c bus access for navi1x asics.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
drivers/gpu/drm/amd/powerplay/navi10_ppt.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/gpu/drm/amd/powerplay/navi10_ppt.c b/drivers/gpu/drm/amd/powerplay/navi10_ppt.c
index ead135f39c7e..56267e6c600e 100644
--- a/drivers/gpu/drm/amd/powerplay/navi10_ppt.c
+++ b/drivers/gpu/drm/amd/powerplay/navi10_ppt.c
@@ -23,6 +23,7 @@
#include <linux/firmware.h>
#include <linux/pci.h>
+#include <linux/i2c.h>
#include "amdgpu.h"
#include "amdgpu_smu.h"
#include "smu_internal.h"
@@ -52,6 +53,8 @@
#undef pr_info
#undef pr_debug
+#define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c))
+
#define FEATURE_MASK(feature) (1ULL << feature)
#define SMC_DPM_FEATURE ( \
FEATURE_MASK(FEATURE_DPM_PREFETCHER_BIT) | \
--
2.25.4
[-- Attachment #1.2: Type: text/html, Size: 2731 bytes --]
[-- Attachment #2: Type: text/plain, Size: 154 bytes --]
_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 6/6] drm/amdgpu/sienna_cichlid: add SMU i2c support
2020-07-21 16:52 [PATCH 1/6] drm/amdgpu: move i2c bus lock out of ras structure Alex Deucher
` (3 preceding siblings ...)
2020-07-21 16:52 ` [PATCH 5/6] drm/amdgpu/navi1x: add SMU i2c support Alex Deucher
@ 2020-07-21 16:52 ` Alex Deucher
2020-07-21 17:01 ` Andrey Grodzovsky
2020-07-21 18:01 ` Andrey Grodzovsky
4 siblings, 2 replies; 10+ messages in thread
From: Alex Deucher @ 2020-07-21 16:52 UTC (permalink / raw)
To: amd-gfx; +Cc: Alex Deucher
Enable SMU i2c bus access for sienna_cichlid asics.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
.../drm/amd/powerplay/sienna_cichlid_ppt.c | 239 ++++++++++++++++++
1 file changed, 239 insertions(+)
diff --git a/drivers/gpu/drm/amd/powerplay/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/powerplay/sienna_cichlid_ppt.c
index 5faef41b63a3..e1857fbb0a6f 100644
--- a/drivers/gpu/drm/amd/powerplay/sienna_cichlid_ppt.c
+++ b/drivers/gpu/drm/amd/powerplay/sienna_cichlid_ppt.c
@@ -23,6 +23,7 @@
#include <linux/firmware.h>
#include <linux/pci.h>
+#include <linux/i2c.h>
#include "amdgpu.h"
#include "amdgpu_smu.h"
#include "smu_internal.h"
@@ -52,6 +53,8 @@
#undef pr_info
#undef pr_debug
+#define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c))
+
#define FEATURE_MASK(feature) (1ULL << feature)
#define SMC_DPM_FEATURE ( \
FEATURE_MASK(FEATURE_DPM_PREFETCHER_BIT) | \
@@ -455,6 +458,8 @@ static int sienna_cichlid_tables_init(struct smu_context *smu, struct smu_table
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t),
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
+ SMU_TABLE_INIT(tables, SMU_TABLE_I2C_COMMANDS, sizeof(SwI2cRequest_t),
+ PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
SMU_TABLE_INIT(tables, SMU_TABLE_OVERDRIVE, sizeof(OverDriveTable_t),
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
SMU_TABLE_INIT(tables, SMU_TABLE_PMSTATUSLOG, SMU11_TOOL_SIZE,
@@ -2487,6 +2492,238 @@ 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;
+
+ BUG_ON(numbytes > MAX_SW_I2C_COMMANDS);
+
+ 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 sienna_cichlid_i2c_read_data(struct i2c_adapter *control,
+ uint8_t address,
+ uint8_t *data,
+ uint32_t numbytes)
+{
+ uint32_t i, ret = 0;
+ SwI2cRequest_t req;
+ struct amdgpu_device *adev = to_amdgpu_device(control);
+ struct smu_table_context *smu_table = &adev->smu.smu_table;
+ struct smu_table *table = &smu_table->driver_table;
+
+ 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_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);
+
+ return ret;
+}
+
+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);
+
+ memset(&req, 0, sizeof(req));
+ sienna_cichlid_fill_i2c_req(&req, true, address, numbytes, data);
+
+ mutex_lock(&adev->smu.mutex);
+ ret = smu_update_table(&adev->smu, SMU_TABLE_I2C_COMMANDS, 0, &req, true);
+ mutex_unlock(&adev->smu.mutex);
+
+ 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;
+ }
+
+ 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;
+ }
+ }
+ }
+
+fail:
+ return num;
+}
+
+static u32 sienna_cichlid_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+
+static const struct i2c_algorithm sienna_cichlid_i2c_algo = {
+ .master_xfer = sienna_cichlid_i2c_xfer,
+ .functionality = sienna_cichlid_i2c_func,
+};
+
+static bool sienna_cichlid_i2c_adapter_is_added(struct i2c_adapter *control)
+{
+ struct amdgpu_device *adev = to_amdgpu_device(control);
+
+ return control->dev.parent == &adev->pdev->dev;
+}
+
+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;
+
+ /* smu_i2c_eeprom_init may be called twice in sriov */
+ if (sienna_cichlid_i2c_adapter_is_added(control))
+ return 0;
+
+ control->owner = THIS_MODULE;
+ control->class = I2C_CLASS_SPD;
+ control->dev.parent = &adev->pdev->dev;
+ control->algo = &sienna_cichlid_i2c_algo;
+ snprintf(control->name, sizeof(control->name), "AMDGPU SMU");
+
+ res = i2c_add_adapter(control);
+ if (res)
+ DRM_ERROR("Failed to register hw i2c, err: %d\n", res);
+
+ return res;
+}
+
+static void sienna_cichlid_i2c_control_fini(struct smu_context *smu, struct i2c_adapter *control)
+{
+ if (!sienna_cichlid_i2c_adapter_is_added(control))
+ return;
+
+ i2c_del_adapter(control);
+}
+
+
static const struct pptable_funcs sienna_cichlid_ppt_funcs = {
.tables_init = sienna_cichlid_tables_init,
.alloc_dpm_context = sienna_cichlid_allocate_dpm_context,
@@ -2500,6 +2737,8 @@ static const struct pptable_funcs sienna_cichlid_ppt_funcs = {
.set_default_dpm_table = sienna_cichlid_set_default_dpm_table,
.dpm_set_vcn_enable = sienna_cichlid_dpm_set_vcn_enable,
.dpm_set_jpeg_enable = sienna_cichlid_dpm_set_jpeg_enable,
+ .i2c_eeprom_init = sienna_cichlid_i2c_control_init,
+ .i2c_eeprom_fini = sienna_cichlid_i2c_control_fini,
.print_clk_levels = sienna_cichlid_print_clk_levels,
.force_clk_levels = sienna_cichlid_force_clk_levels,
.populate_umd_state_clk = sienna_cichlid_populate_umd_state_clk,
--
2.25.4
_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH 6/6] drm/amdgpu/sienna_cichlid: add SMU i2c support
2020-07-21 16:52 ` [PATCH 6/6] drm/amdgpu/sienna_cichlid: " Alex Deucher
@ 2020-07-21 17:01 ` Andrey Grodzovsky
2020-07-21 17:02 ` Deucher, Alexander
2020-07-21 18:01 ` Andrey Grodzovsky
1 sibling, 1 reply; 10+ messages in thread
From: Andrey Grodzovsky @ 2020-07-21 17:01 UTC (permalink / raw)
To: Alex Deucher, amd-gfx; +Cc: Alex Deucher
Looks like same code as arcturus - should we make it common helper code and
reuse in both ?
Andrey
On 7/21/20 12:52 PM, Alex Deucher wrote:
> Enable SMU i2c bus access for sienna_cichlid asics.
>
> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
> ---
> .../drm/amd/powerplay/sienna_cichlid_ppt.c | 239 ++++++++++++++++++
> 1 file changed, 239 insertions(+)
>
> diff --git a/drivers/gpu/drm/amd/powerplay/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/powerplay/sienna_cichlid_ppt.c
> index 5faef41b63a3..e1857fbb0a6f 100644
> --- a/drivers/gpu/drm/amd/powerplay/sienna_cichlid_ppt.c
> +++ b/drivers/gpu/drm/amd/powerplay/sienna_cichlid_ppt.c
> @@ -23,6 +23,7 @@
>
> #include <linux/firmware.h>
> #include <linux/pci.h>
> +#include <linux/i2c.h>
> #include "amdgpu.h"
> #include "amdgpu_smu.h"
> #include "smu_internal.h"
> @@ -52,6 +53,8 @@
> #undef pr_info
> #undef pr_debug
>
> +#define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c))
> +
> #define FEATURE_MASK(feature) (1ULL << feature)
> #define SMC_DPM_FEATURE ( \
> FEATURE_MASK(FEATURE_DPM_PREFETCHER_BIT) | \
> @@ -455,6 +458,8 @@ static int sienna_cichlid_tables_init(struct smu_context *smu, struct smu_table
> PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
> SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t),
> PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
> + SMU_TABLE_INIT(tables, SMU_TABLE_I2C_COMMANDS, sizeof(SwI2cRequest_t),
> + PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
> SMU_TABLE_INIT(tables, SMU_TABLE_OVERDRIVE, sizeof(OverDriveTable_t),
> PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
> SMU_TABLE_INIT(tables, SMU_TABLE_PMSTATUSLOG, SMU11_TOOL_SIZE,
> @@ -2487,6 +2492,238 @@ 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;
> +
> + BUG_ON(numbytes > MAX_SW_I2C_COMMANDS);
> +
> + 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 */172.31.4.187
> + 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)
> +{
> + uint32_t i, ret = 0;
> + SwI2cRequest_t req;
> + struct amdgpu_device *adev = to_amdgpu_device(control);
> + struct smu_table_context *smu_table = &adev->smu.smu_table;
> + struct smu_table *table = &smu_table->driver_table;
> +
> + 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_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);
> +
> + return ret;
> +}
> +
> +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);
> +
> + memset(&req, 0, sizeof(req));
> + sienna_cichlid_fill_i2c_req(&req, true, address, numbytes, data);
> +
> + mutex_lock(&adev->smu.mutex);
> + ret = smu_update_table(&adev->smu, SMU_TABLE_I2C_COMMANDS, 0, &req, true);
> + mutex_unlock(&adev->smu.mutex);
> +
> + 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;
> + }
> +
> + 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;
> + }
> + }
> + }
> +
> +fail:
> + return num;
> +}
> +
> +static u32 sienna_cichlid_i2c_func(struct i2c_adapter *adap)
> +{
> + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
> +}
> +
> +
> +static const struct i2c_algorithm sienna_cichlid_i2c_algo = {
> + .master_xfer = sienna_cichlid_i2c_xfer,
> + .functionality = sienna_cichlid_i2c_func,
> +};
> +
> +static bool sienna_cichlid_i2c_adapter_is_added(struct i2c_adapter *control)
> +{
> + struct amdgpu_device *adev = to_amdgpu_device(control);
> +
> + return control->dev.parent == &adev->pdev->dev;
> +}
> +
> +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;
> +
> + /* smu_i2c_eeprom_init may be called twice in sriov */
> + if (sienna_cichlid_i2c_adapter_is_added(control))
> + return 0;
> +
> + control->owner = THIS_MODULE;
> + control->class = I2C_CLASS_SPD;
> + control->dev.parent = &adev->pdev->dev;
> + control->algo = &sienna_cichlid_i2c_algo;
> + snprintf(control->name, sizeof(control->name), "AMDGPU SMU");
> +
> + res = i2c_add_adapter(control);
> + if (res)
> + DRM_ERROR("Failed to register hw i2c, err: %d\n", res);
> +
> + return res;
> +}
> +
> +static void sienna_cichlid_i2c_control_fini(struct smu_context *smu, struct i2c_adapter *control)
> +{
> + if (!sienna_cichlid_i2c_adapter_is_added(control))
> + return;
> +
> + i2c_del_adapter(control);
> +}
> +
> +
> static const struct pptable_funcs sienna_cichlid_ppt_funcs = {
> .tables_init = sienna_cichlid_tables_init,
> .alloc_dpm_context = sienna_cichlid_allocate_dpm_context,
> @@ -2500,6 +2737,8 @@ static const struct pptable_funcs sienna_cichlid_ppt_funcs = {
> .set_default_dpm_table = sienna_cichlid_set_default_dpm_table,
> .dpm_set_vcn_enable = sienna_cichlid_dpm_set_vcn_enable,
> .dpm_set_jpeg_enable = sienna_cichlid_dpm_set_jpeg_enable,
> + .i2c_eeprom_init = sienna_cichlid_i2c_control_init,
> + .i2c_eeprom_fini = sienna_cichlid_i2c_control_fini,
> .print_clk_levels = sienna_cichlid_print_clk_levels,
> .force_clk_levels = sienna_cichlid_force_clk_levels,
> .populate_umd_state_clk = sienna_cichlid_populate_umd_state_clk,
_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 6/6] drm/amdgpu/sienna_cichlid: add SMU i2c support
2020-07-21 17:01 ` Andrey Grodzovsky
@ 2020-07-21 17:02 ` Deucher, Alexander
0 siblings, 0 replies; 10+ messages in thread
From: Deucher, Alexander @ 2020-07-21 17:02 UTC (permalink / raw)
To: Grodzovsky, Andrey, Alex Deucher, amd-gfx
[-- Attachment #1.1: Type: text/plain, Size: 12951 bytes --]
[AMD Official Use Only - Internal Distribution Only]
I tried that at first, but the smu i2c interface structures are different per asic.
Alex
________________________________
From: Grodzovsky, Andrey <Andrey.Grodzovsky@amd.com>
Sent: Tuesday, July 21, 2020 1:01 PM
To: Alex Deucher <alexdeucher@gmail.com>; amd-gfx@lists.freedesktop.org <amd-gfx@lists.freedesktop.org>
Cc: Deucher, Alexander <Alexander.Deucher@amd.com>
Subject: Re: [PATCH 6/6] drm/amdgpu/sienna_cichlid: add SMU i2c support
Looks like same code as arcturus - should we make it common helper code and
reuse in both ?
Andrey
On 7/21/20 12:52 PM, Alex Deucher wrote:
> Enable SMU i2c bus access for sienna_cichlid asics.
>
> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
> ---
> .../drm/amd/powerplay/sienna_cichlid_ppt.c | 239 ++++++++++++++++++
> 1 file changed, 239 insertions(+)
>
> diff --git a/drivers/gpu/drm/amd/powerplay/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/powerplay/sienna_cichlid_ppt.c
> index 5faef41b63a3..e1857fbb0a6f 100644
> --- a/drivers/gpu/drm/amd/powerplay/sienna_cichlid_ppt.c
> +++ b/drivers/gpu/drm/amd/powerplay/sienna_cichlid_ppt.c
> @@ -23,6 +23,7 @@
>
> #include <linux/firmware.h>
> #include <linux/pci.h>
> +#include <linux/i2c.h>
> #include "amdgpu.h"
> #include "amdgpu_smu.h"
> #include "smu_internal.h"
> @@ -52,6 +53,8 @@
> #undef pr_info
> #undef pr_debug
>
> +#define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c))
> +
> #define FEATURE_MASK(feature) (1ULL << feature)
> #define SMC_DPM_FEATURE ( \
> FEATURE_MASK(FEATURE_DPM_PREFETCHER_BIT) | \
> @@ -455,6 +458,8 @@ static int sienna_cichlid_tables_init(struct smu_context *smu, struct smu_table
> PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
> SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t),
> PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
> + SMU_TABLE_INIT(tables, SMU_TABLE_I2C_COMMANDS, sizeof(SwI2cRequest_t),
> + PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
> SMU_TABLE_INIT(tables, SMU_TABLE_OVERDRIVE, sizeof(OverDriveTable_t),
> PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
> SMU_TABLE_INIT(tables, SMU_TABLE_PMSTATUSLOG, SMU11_TOOL_SIZE,
> @@ -2487,6 +2492,238 @@ 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;
> +
> + BUG_ON(numbytes > MAX_SW_I2C_COMMANDS);
> +
> + 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 */172.31.4.187
> + 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)
> +{
> + uint32_t i, ret = 0;
> + SwI2cRequest_t req;
> + struct amdgpu_device *adev = to_amdgpu_device(control);
> + struct smu_table_context *smu_table = &adev->smu.smu_table;
> + struct smu_table *table = &smu_table->driver_table;
> +
> + 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_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);
> +
> + return ret;
> +}
> +
> +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);
> +
> + memset(&req, 0, sizeof(req));
> + sienna_cichlid_fill_i2c_req(&req, true, address, numbytes, data);
> +
> + mutex_lock(&adev->smu.mutex);
> + ret = smu_update_table(&adev->smu, SMU_TABLE_I2C_COMMANDS, 0, &req, true);
> + mutex_unlock(&adev->smu.mutex);
> +
> + 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;
> + }
> +
> + 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;
> + }
> + }
> + }
> +
> +fail:
> + return num;
> +}
> +
> +static u32 sienna_cichlid_i2c_func(struct i2c_adapter *adap)
> +{
> + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
> +}
> +
> +
> +static const struct i2c_algorithm sienna_cichlid_i2c_algo = {
> + .master_xfer = sienna_cichlid_i2c_xfer,
> + .functionality = sienna_cichlid_i2c_func,
> +};
> +
> +static bool sienna_cichlid_i2c_adapter_is_added(struct i2c_adapter *control)
> +{
> + struct amdgpu_device *adev = to_amdgpu_device(control);
> +
> + return control->dev.parent == &adev->pdev->dev;
> +}
> +
> +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;
> +
> + /* smu_i2c_eeprom_init may be called twice in sriov */
> + if (sienna_cichlid_i2c_adapter_is_added(control))
> + return 0;
> +
> + control->owner = THIS_MODULE;
> + control->class = I2C_CLASS_SPD;
> + control->dev.parent = &adev->pdev->dev;
> + control->algo = &sienna_cichlid_i2c_algo;
> + snprintf(control->name, sizeof(control->name), "AMDGPU SMU");
> +
> + res = i2c_add_adapter(control);
> + if (res)
> + DRM_ERROR("Failed to register hw i2c, err: %d\n", res);
> +
> + return res;
> +}
> +
> +static void sienna_cichlid_i2c_control_fini(struct smu_context *smu, struct i2c_adapter *control)
> +{
> + if (!sienna_cichlid_i2c_adapter_is_added(control))
> + return;
> +
> + i2c_del_adapter(control);
> +}
> +
> +
> static const struct pptable_funcs sienna_cichlid_ppt_funcs = {
> .tables_init = sienna_cichlid_tables_init,
> .alloc_dpm_context = sienna_cichlid_allocate_dpm_context,
> @@ -2500,6 +2737,8 @@ static const struct pptable_funcs sienna_cichlid_ppt_funcs = {
> .set_default_dpm_table = sienna_cichlid_set_default_dpm_table,
> .dpm_set_vcn_enable = sienna_cichlid_dpm_set_vcn_enable,
> .dpm_set_jpeg_enable = sienna_cichlid_dpm_set_jpeg_enable,
> + .i2c_eeprom_init = sienna_cichlid_i2c_control_init,
> + .i2c_eeprom_fini = sienna_cichlid_i2c_control_fini,
> .print_clk_levels = sienna_cichlid_print_clk_levels,
> .force_clk_levels = sienna_cichlid_force_clk_levels,
> .populate_umd_state_clk = sienna_cichlid_populate_umd_state_clk,
[-- Attachment #1.2: Type: text/html, Size: 31070 bytes --]
[-- Attachment #2: Type: text/plain, Size: 154 bytes --]
_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 6/6] drm/amdgpu/sienna_cichlid: add SMU i2c support
2020-07-21 16:52 ` [PATCH 6/6] drm/amdgpu/sienna_cichlid: " Alex Deucher
2020-07-21 17:01 ` Andrey Grodzovsky
@ 2020-07-21 18:01 ` Andrey Grodzovsky
1 sibling, 0 replies; 10+ messages in thread
From: Andrey Grodzovsky @ 2020-07-21 18:01 UTC (permalink / raw)
To: Alex Deucher, amd-gfx; +Cc: Alex Deucher
Series besides patch 5/6 which you said is the wrong version is Reviewed-by:
Andrey Grodzovsky <andrey.grodzovsky@amd.com>
Andrey
On 7/21/20 12:52 PM, Alex Deucher wrote:
> Enable SMU i2c bus access for sienna_cichlid asics.
>
> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
> ---
> .../drm/amd/powerplay/sienna_cichlid_ppt.c | 239 ++++++++++++++++++
> 1 file changed, 239 insertions(+)
>
> diff --git a/drivers/gpu/drm/amd/powerplay/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/powerplay/sienna_cichlid_ppt.c
> index 5faef41b63a3..e1857fbb0a6f 100644
> --- a/drivers/gpu/drm/amd/powerplay/sienna_cichlid_ppt.c
> +++ b/drivers/gpu/drm/amd/powerplay/sienna_cichlid_ppt.c
> @@ -23,6 +23,7 @@
>
> #include <linux/firmware.h>
> #include <linux/pci.h>
> +#include <linux/i2c.h>
> #include "amdgpu.h"
> #include "amdgpu_smu.h"
> #include "smu_internal.h"
> @@ -52,6 +53,8 @@
> #undef pr_info
> #undef pr_debug
>
> +#define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c))
> +
> #define FEATURE_MASK(feature) (1ULL << feature)
> #define SMC_DPM_FEATURE ( \
> FEATURE_MASK(FEATURE_DPM_PREFETCHER_BIT) | \
> @@ -455,6 +458,8 @@ static int sienna_cichlid_tables_init(struct smu_context *smu, struct smu_table
> PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
> SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t),
> PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
> + SMU_TABLE_INIT(tables, SMU_TABLE_I2C_COMMANDS, sizeof(SwI2cRequest_t),
> + PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
> SMU_TABLE_INIT(tables, SMU_TABLE_OVERDRIVE, sizeof(OverDriveTable_t),
> PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
> SMU_TABLE_INIT(tables, SMU_TABLE_PMSTATUSLOG, SMU11_TOOL_SIZE,
> @@ -2487,6 +2492,238 @@ 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;
> +
> + BUG_ON(numbytes > MAX_SW_I2C_COMMANDS);
> +
> + 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 sienna_cichlid_i2c_read_data(struct i2c_adapter *control,
> + uint8_t address,
> + uint8_t *data,
> + uint32_t numbytes)
> +{
> + uint32_t i, ret = 0;
> + SwI2cRequest_t req;
> + struct amdgpu_device *adev = to_amdgpu_device(control);
> + struct smu_table_context *smu_table = &adev->smu.smu_table;
> + struct smu_table *table = &smu_table->driver_table;
> +
> + 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_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);
> +
> + return ret;
> +}
> +
> +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);
> +
> + memset(&req, 0, sizeof(req));
> + sienna_cichlid_fill_i2c_req(&req, true, address, numbytes, data);
> +
> + mutex_lock(&adev->smu.mutex);
> + ret = smu_update_table(&adev->smu, SMU_TABLE_I2C_COMMANDS, 0, &req, true);
> + mutex_unlock(&adev->smu.mutex);
> +
> + 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;
> + }
> +
> + 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;
> + }
> + }
> + }
> +
> +fail:
> + return num;
> +}
> +
> +static u32 sienna_cichlid_i2c_func(struct i2c_adapter *adap)
> +{
> + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
> +}
> +
> +
> +static const struct i2c_algorithm sienna_cichlid_i2c_algo = {
> + .master_xfer = sienna_cichlid_i2c_xfer,
> + .functionality = sienna_cichlid_i2c_func,
> +};
> +
> +static bool sienna_cichlid_i2c_adapter_is_added(struct i2c_adapter *control)
> +{
> + struct amdgpu_device *adev = to_amdgpu_device(control);
> +
> + return control->dev.parent == &adev->pdev->dev;
> +}
> +
> +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;
> +
> + /* smu_i2c_eeprom_init may be called twice in sriov */
> + if (sienna_cichlid_i2c_adapter_is_added(control))
> + return 0;
> +
> + control->owner = THIS_MODULE;
> + control->class = I2C_CLASS_SPD;
> + control->dev.parent = &adev->pdev->dev;
> + control->algo = &sienna_cichlid_i2c_algo;
> + snprintf(control->name, sizeof(control->name), "AMDGPU SMU");
> +
> + res = i2c_add_adapter(control);
> + if (res)
> + DRM_ERROR("Failed to register hw i2c, err: %d\n", res);
> +
> + return res;
> +}
> +
> +static void sienna_cichlid_i2c_control_fini(struct smu_context *smu, struct i2c_adapter *control)
> +{
> + if (!sienna_cichlid_i2c_adapter_is_added(control))
> + return;
> +
> + i2c_del_adapter(control);
> +}
> +
> +
> static const struct pptable_funcs sienna_cichlid_ppt_funcs = {
> .tables_init = sienna_cichlid_tables_init,
> .alloc_dpm_context = sienna_cichlid_allocate_dpm_context,
> @@ -2500,6 +2737,8 @@ static const struct pptable_funcs sienna_cichlid_ppt_funcs = {
> .set_default_dpm_table = sienna_cichlid_set_default_dpm_table,
> .dpm_set_vcn_enable = sienna_cichlid_dpm_set_vcn_enable,
> .dpm_set_jpeg_enable = sienna_cichlid_dpm_set_jpeg_enable,
> + .i2c_eeprom_init = sienna_cichlid_i2c_control_init,
> + .i2c_eeprom_fini = sienna_cichlid_i2c_control_fini,
> .print_clk_levels = sienna_cichlid_print_clk_levels,
> .force_clk_levels = sienna_cichlid_force_clk_levels,
> .populate_umd_state_clk = sienna_cichlid_populate_umd_state_clk,
_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx
^ permalink raw reply [flat|nested] 10+ messages in thread