All the mail mirrored from lore.kernel.org
 help / color / mirror / Atom feed
From: Luben Tuikov <luben.tuikov@amd.com>
To: amd-gfx@lists.freedesktop.org
Cc: Alexander Deucher <Alexander.Deucher@amd.com>,
	Andrey Grodzovsky <Andrey.Grodzovsky@amd.com>,
	Luben Tuikov <luben.tuikov@amd.com>
Subject: [PATCH 40/40] drm/amdgpu: Correctly disable the I2C IP block
Date: Mon, 14 Jun 2021 13:46:32 -0400	[thread overview]
Message-ID: <20210614174632.20818-41-luben.tuikov@amd.com> (raw)
In-Reply-To: <20210614174632.20818-1-luben.tuikov@amd.com>

On long transfers to the EEPROM device,
i.e. write, it is observed that the driver aborts
the transfer.

The reason for this is that the driver isn't
patient enough--the IC_STATUS register's contents
is 0x27, which is MST_ACTIVITY | TFE | TFNF |
ACTIVITY. That is, while the transmission FIFO is
empty, we, the I2C master device, are still
driving the bus.

Implement the correct procedure to disable
the block, as described in the DesignWare I2C
Databook, section 3.8.3 Disabling DW_apb_i2c on
page 56. Now there are no premature aborts on long
data transfers.

Cc: Alexander Deucher <Alexander.Deucher@amd.com>
Cc: Andrey Grodzovsky <Andrey.Grodzovsky@amd.com>
Signed-off-by: Luben Tuikov <luben.tuikov@amd.com>
---
 drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c | 80 +++++++++++++++++-----
 1 file changed, 62 insertions(+), 18 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 751ea2517c4380..7d74d6204d8d0a 100644
--- a/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c
+++ b/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c
@@ -54,12 +54,48 @@ static void smu_v11_0_i2c_set_clock_gating(struct i2c_adapter *control, bool en)
 	WREG32_SOC15(SMUIO, 0, mmSMUIO_PWRMGT, reg);
 }
 
+/* The T_I2C_POLL_US is defined as follows:
+ *
+ * "Define a timer interval (t_i2c_poll) equal to 10 times the
+ *  signalling period for the highest I2C transfer speed used in the
+ *  system and supported by DW_apb_i2c. For instance, if the highest
+ *  I2C data transfer mode is 400 kb/s, then t_i2c_poll is 25 us."  --
+ * DesignWare DW_apb_i2c Databook, Version 1.21a, section 3.8.3.1,
+ * page 56, with grammar and syntax corrections.
+ *
+ * Vcc for our device is at 1.8V which puts it at 400 kHz,
+ * see Atmel AT24CM02 datasheet, section 8.3 DC Characteristics table, page 14.
+ *
+ * The procedure to disable the IP block is described in section
+ * 3.8.3 Disabling DW_apb_i2c on page 56.
+ */
+#define I2C_SPEED_MODE_FAST     2
+#define T_I2C_POLL_US           25
+#define I2C_MAX_T_POLL_COUNT    1000
 
-static void smu_v11_0_i2c_enable(struct i2c_adapter *control, bool enable)
+static int smu_v11_0_i2c_enable(struct i2c_adapter *control, bool enable)
 {
 	struct amdgpu_device *adev = to_amdgpu_device(control);
 
 	WREG32_SOC15(SMUIO, 0, mmCKSVII2C_IC_ENABLE, enable ? 1 : 0);
+
+	if (!enable) {
+		int ii;
+
+		for (ii = I2C_MAX_T_POLL_COUNT; ii > 0; ii--) {
+			u32 en_stat = RREG32_SOC15(SMUIO,
+						   0,
+						   mmCKSVII2C_IC_ENABLE_STATUS);
+			if (REG_GET_FIELD(en_stat, CKSVII2C_IC_ENABLE_STATUS, IC_EN))
+				udelay(T_I2C_POLL_US);
+			else
+				return I2C_OK;
+		}
+
+		return I2C_ABORT;
+	}
+
+	return I2C_OK;
 }
 
 static void smu_v11_0_i2c_clear_status(struct i2c_adapter *control)
@@ -81,8 +117,13 @@ static void smu_v11_0_i2c_configure(struct i2c_adapter *control)
 	reg = REG_SET_FIELD(reg, CKSVII2C_IC_CON, IC_RESTART_EN, 1);
 	reg = REG_SET_FIELD(reg, CKSVII2C_IC_CON, IC_10BITADDR_MASTER, 0);
 	reg = REG_SET_FIELD(reg, CKSVII2C_IC_CON, IC_10BITADDR_SLAVE, 0);
-	/* Standard mode */
-	reg = REG_SET_FIELD(reg, CKSVII2C_IC_CON, IC_MAX_SPEED_MODE, 2);
+	/* The values of IC_MAX_SPEED_MODE are,
+	 * 1: standard mode, 0 - 100 Kb/s,
+	 * 2: fast mode, <= 400 Kb/s, or fast mode plus, <= 1000 Kb/s,
+	 * 3: high speed mode, <= 3.4 Mb/s.
+	 */
+	reg = REG_SET_FIELD(reg, CKSVII2C_IC_CON, IC_MAX_SPEED_MODE,
+			    I2C_SPEED_MODE_FAST);
 	reg = REG_SET_FIELD(reg, CKSVII2C_IC_CON, IC_MASTER_MODE, 1);
 
 	WREG32_SOC15(SMUIO, 0, mmCKSVII2C_IC_CON, reg);
@@ -404,7 +445,6 @@ static void smu_v11_0_i2c_abort(struct i2c_adapter *control)
 	DRM_DEBUG_DRIVER("I2C_Abort() Done.");
 }
 
-
 static bool smu_v11_0_i2c_activity_done(struct i2c_adapter *control)
 {
 	struct amdgpu_device *adev = to_amdgpu_device(control);
@@ -416,7 +456,6 @@ static bool smu_v11_0_i2c_activity_done(struct i2c_adapter *control)
 	reg_ic_enable_status = RREG32_SOC15(SMUIO, 0, mmCKSVII2C_IC_ENABLE_STATUS);
 	reg_ic_enable = RREG32_SOC15(SMUIO, 0, mmCKSVII2C_IC_ENABLE);
 
-
 	if ((REG_GET_FIELD(reg_ic_enable, CKSVII2C_IC_ENABLE, ENABLE) == 0) &&
 	    (REG_GET_FIELD(reg_ic_enable_status, CKSVII2C_IC_ENABLE_STATUS, IC_EN) == 1)) {
 		/*
@@ -446,6 +485,8 @@ static bool smu_v11_0_i2c_activity_done(struct i2c_adapter *control)
 
 static void smu_v11_0_i2c_init(struct i2c_adapter *control)
 {
+	int res;
+
 	/* Disable clock gating */
 	smu_v11_0_i2c_set_clock_gating(control, false);
 
@@ -453,7 +494,9 @@ static void smu_v11_0_i2c_init(struct i2c_adapter *control)
 		DRM_WARN("I2C busy !");
 
 	/* Disable I2C */
-	smu_v11_0_i2c_enable(control, false);
+	res = smu_v11_0_i2c_enable(control, false);
+	if (res != I2C_OK)
+		smu_v11_0_i2c_abort(control);
 
 	/* Configure I2C to operate as master and in standard mode */
 	smu_v11_0_i2c_configure(control);
@@ -466,21 +509,22 @@ static void smu_v11_0_i2c_init(struct i2c_adapter *control)
 static void smu_v11_0_i2c_fini(struct i2c_adapter *control)
 {
 	struct amdgpu_device *adev = to_amdgpu_device(control);
-	uint32_t reg_ic_enable_status, reg_ic_enable;
+	u32 status, enable, en_stat;
+	int res;
 
-	smu_v11_0_i2c_enable(control, false);
+	res = smu_v11_0_i2c_enable(control, false);
+	if (res != I2C_OK) {
+		status  = RREG32_SOC15(SMUIO, 0, mmCKSVII2C_IC_STATUS);
+		enable  = RREG32_SOC15(SMUIO, 0, mmCKSVII2C_IC_ENABLE);
+		en_stat = RREG32_SOC15(SMUIO, 0, mmCKSVII2C_IC_ENABLE_STATUS);
 
-	/* Double check if disabled, else force abort */
-	reg_ic_enable_status = RREG32_SOC15(SMUIO, 0, mmCKSVII2C_IC_ENABLE_STATUS);
-	reg_ic_enable = RREG32_SOC15(SMUIO, 0, mmCKSVII2C_IC_ENABLE);
-
-	if ((REG_GET_FIELD(reg_ic_enable, CKSVII2C_IC_ENABLE, ENABLE) == 0) &&
-	    (REG_GET_FIELD(reg_ic_enable_status,
-			   CKSVII2C_IC_ENABLE_STATUS, IC_EN) == 1)) {
-		/*
-		 * Nobody is using I2C engine, but engine remains active because
-		 * someone missed to send STOP
+		/* Nobody is using the I2C engine, yet it remains
+		 * active, possibly because someone missed to send
+		 * STOP.
 		 */
+		DRM_DEBUG_DRIVER("Aborting from fini: status:0x%08x "
+				 "enable:0x%08x enable_stat:0x%08x",
+				 status, enable, en_stat);
 		smu_v11_0_i2c_abort(control);
 	}
 
-- 
2.32.0

_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

  parent reply	other threads:[~2021-06-14 17:47 UTC|newest]

Thread overview: 44+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-06-14 17:45 [PATCH 00/40] I2C fixes (revision 1) Luben Tuikov
2021-06-14 17:45 ` [PATCH 01/40] drm/amdgpu: add a mutex for the smu11 i2c bus (v2) Luben Tuikov
2021-06-14 17:45 ` [PATCH 02/40] drm/amdgpu/pm: rework i2c xfers on sienna cichlid (v4) Luben Tuikov
2021-06-14 17:45 ` [PATCH 03/40] drm/amdgpu/pm: rework i2c xfers on arcturus (v4) Luben Tuikov
2021-06-14 17:45 ` [PATCH 04/40] drm/amdgpu/pm: add smu i2c implementation for navi1x (v4) Luben Tuikov
2021-06-14 17:45 ` [PATCH 05/40] drm/amdgpu: add new helper for handling EEPROM i2c transfers Luben Tuikov
2021-06-14 17:45 ` [PATCH 06/40] drm/amdgpu/ras: switch ras eeprom handling to use generic helper Luben Tuikov
2021-06-14 17:45 ` [PATCH 07/40] drm/amdgpu/ras: switch fru eeprom handling to use generic helper (v2) Luben Tuikov
2021-06-14 17:46 ` [PATCH 08/40] drm/amdgpu: i2c subsystem uses 7 bit addresses Luben Tuikov
2021-06-14 17:46 ` [PATCH 09/40] drm/amdgpu: add I2C_CLASS_HWMON to SMU i2c buses Luben Tuikov
2021-06-14 17:46 ` [PATCH 10/40] drm/amdgpu: rework smu11 i2c for generic operation Luben Tuikov
2021-06-14 17:46 ` [PATCH 11/40] drm/amdgpu: only set restart on first cmd of the smu i2c transaction Luben Tuikov
2021-06-14 17:46 ` [PATCH 12/40] drm/amdgpu: Remember to wait 10ms for write buffer flush v2 Luben Tuikov
2021-06-14 17:46 ` [PATCH 13/40] dmr/amdgpu: Add RESTART handling also to smu_v11_0_i2c (VG20) Luben Tuikov
2021-06-14 17:46 ` [PATCH 14/40] drm/amdgpu: Drop i > 0 restriction for issuing RESTART Luben Tuikov
2021-06-14 17:46 ` [PATCH 15/40] drm/amdgpu: Send STOP for the last byte of msg only Luben Tuikov
2021-06-14 17:46 ` [PATCH 16/40] drm/amd/pm: SMU I2C: Return number of messages processed Luben Tuikov
2021-06-14 17:46 ` [PATCH 17/40] drm/amdgpu/pm: ADD I2C quirk adapter table Luben Tuikov
2021-06-14 17:46 ` [PATCH 18/40] drm/amdgpu: Fix Vega20 I2C to be agnostic (v2) Luben Tuikov
2021-06-14 17:46 ` [PATCH 19/40] drm/amdgpu: Fixes to the AMDGPU EEPROM driver Luben Tuikov
2021-06-14 17:46 ` [PATCH 20/40] drm/amdgpu: EEPROM respects I2C quirks Luben Tuikov
2021-06-15 18:48   ` Alex Deucher
2021-06-14 17:46 ` [PATCH 21/40] drm/amdgpu: I2C EEPROM full memory addressing Luben Tuikov
2021-06-14 17:46 ` [PATCH 22/40] drm/amdgpu: RAS and FRU now use 19-bit I2C address Luben Tuikov
2021-06-14 17:46 ` [PATCH 23/40] drm/amdgpu: Fix wrap-around bugs in RAS Luben Tuikov
2021-06-14 17:46 ` [PATCH 24/40] drm/amdgpu: I2C class is HWMON Luben Tuikov
2021-06-14 17:46 ` [PATCH 25/40] drm/amdgpu: RAS: EEPROM --> RAS Luben Tuikov
2021-06-14 17:46 ` [PATCH 26/40] drm/amdgpu: Rename misspelled function Luben Tuikov
2021-06-14 17:46 ` [PATCH 27/40] drm/amdgpu: RAS xfer to read/write Luben Tuikov
2021-06-14 17:46 ` [PATCH 28/40] drm/amdgpu: EEPROM: add explicit read and write Luben Tuikov
2021-06-14 17:46 ` [PATCH 29/40] drm/amd/pm: Extend the I2C quirk table Luben Tuikov
2021-06-14 17:46 ` [PATCH 30/40] drm/amd/pm: Simplify managed I2C transfer functions Luben Tuikov
2021-06-14 17:46 ` [PATCH 31/40] drm/amdgpu: Fix width of I2C address Luben Tuikov
2021-06-14 17:46 ` [PATCH 32/40] drm/amdgpu: Return result fix in RAS Luben Tuikov
2021-06-14 17:46 ` [PATCH 33/40] drm/amdgpu: Fix amdgpu_ras_eeprom_init() Luben Tuikov
2021-06-14 17:46 ` [PATCH 34/40] drm/amdgpu: Simplify RAS EEPROM checksum calculations Luben Tuikov
2021-06-14 17:46 ` [PATCH 35/40] drm/amdgpu: Use explicit cardinality for clarity Luben Tuikov
2021-06-14 17:46 ` [PATCH 36/40] drm/amdgpu: Optimizations to EEPROM RAS table I/O Luben Tuikov
2021-06-15 18:55   ` Alex Deucher
2021-06-14 17:46 ` [PATCH 37/40] drm/amdgpu: RAS EEPROM table is now in debugfs Luben Tuikov
2021-06-14 17:46 ` [PATCH 38/40] drm/amdgpu: Fix koops when accessing RAS EEPROM Luben Tuikov
2021-06-14 17:46 ` [PATCH 39/40] drm/amdgpu: Use a single loop Luben Tuikov
2021-06-14 17:46 ` Luben Tuikov [this message]
2021-06-15 18:47   ` [PATCH 40/40] drm/amdgpu: Correctly disable the I2C IP block Alex Deucher

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210614174632.20818-41-luben.tuikov@amd.com \
    --to=luben.tuikov@amd.com \
    --cc=Alexander.Deucher@amd.com \
    --cc=Andrey.Grodzovsky@amd.com \
    --cc=amd-gfx@lists.freedesktop.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.