Patchwork [U-Boot,2/2] fsl_i2c: add workaround for the erratum I2C A004447

login
register
mail settings
Submitter Chunhe Lan
Date July 26, 2013, 9:39 a.m.
Message ID <1374831543-10131-2-git-send-email-Chunhe.Lan@freescale.com>
Download mbox | patch
Permalink /patch/262100/
State Superseded
Delegated to: Heiko Schocher
Headers show

Comments

Chunhe Lan - July 26, 2013, 9:39 a.m.
This workaround is for the erratum I2C A004447. Device reference
manual provides a scheme that allows the I2C master controller
to generate nine SCL pulses, which enable an I2C slave device
that held SDA low to release SDA. However, due to this erratum,
this scheme no longer works. In addition, when I2C is used as
a source of the PBL, the state machine is not able to recover.

At the same time, use the CONFIG_SYS_FSL_A004447_VERSION macro
instead of hard-code value 0x11 and 0x20.

The CONFIG_SYS_FSL_A004447_VERSION = 0x00 represents that one
version of platform has this I2C errata. So enable this errata
by IS_SVR_REV(svr, maj, min) function.

Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
Signed-off-by: Chunhe Lan <Chunhe.Lan@freescale.com>
Cc: Scott Wood <scottwood@freescale.com>
---
 arch/powerpc/cpu/mpc85xx/cmd_errata.c     |    6 ++++++
 arch/powerpc/include/asm/config_mpc85xx.h |   16 ++++++++++++++++
 arch/powerpc/include/asm/fsl_i2c.h        |    1 +
 arch/powerpc/include/asm/processor.h      |    2 ++
 drivers/i2c/fsl_i2c.c                     |   15 ++++++++++++---
 5 files changed, 37 insertions(+), 3 deletions(-)
Scott Wood - July 26, 2013, 4:26 p.m.
On 07/26/2013 04:39:03 AM, Chunhe Lan wrote:
> diff --git a/arch/powerpc/include/asm/processor.h  
> b/arch/powerpc/include/asm/processor.h
> index 56b22d8..156acba 100644
> --- a/arch/powerpc/include/asm/processor.h
> +++ b/arch/powerpc/include/asm/processor.h
> @@ -1073,6 +1073,8 @@
>  #define IS_SVR_REV(svr, maj, min) \
>  	((SVR_MAJ(svr) == maj) && (SVR_MIN(svr) == min))
> 
> +#define FIT_SVR_REV(svr, version)	((svr & 0xff) <= version)

I don't understand how you get "FIT" from "<=".  Why can't the caller  
do <= by itself?

Why does SVR_REV return the low 16 bits rather than the low 8 bits?

Could we try to synchronize what U-Boot does with this Linux patch:
http://patchwork.ozlabs.org/patch/259598/

> diff --git a/drivers/i2c/fsl_i2c.c b/drivers/i2c/fsl_i2c.c
> index ef0004d..694247c 100644
> --- a/drivers/i2c/fsl_i2c.c
> +++ b/drivers/i2c/fsl_i2c.c
> @@ -227,6 +227,15 @@ static int i2c_fixup(const struct fsl_i2c *dev)
>  	const unsigned long long timeout =  
> usec2ticks(CONFIG_I2C_MBB_TIMEOUT);
>  	unsigned long long timeval = 0;
>  	int ret = -1;
> +	unsigned int flags = 0;
> +
> +#ifdef CONFIG_SYS_FSL_ERRATUM_I2C_A004447
> +	unsigned int svr = get_svr();
> +	if ((SVR_SOC_VER(svr) == SVR_8548 && IS_SVR_REV(svr, 3, 1)) ||
> +	    (SVR_SOC_VER(svr) == SVR_P1010 && IS_SVR_REV(svr, 1, 0)) ||
> +	     FIT_SVR_REV(svr, CONFIG_SYS_FSL_A004447_VERSION))
> +		flags = I2C_CR_BIT6;
> +#endif

Why can't P1010 use CONFIG_SYS_FSL_A004447_VERSION?

-Scott

Patch

diff --git a/arch/powerpc/cpu/mpc85xx/cmd_errata.c b/arch/powerpc/cpu/mpc85xx/cmd_errata.c
index a7ed877..b5c451a 100644
--- a/arch/powerpc/cpu/mpc85xx/cmd_errata.c
+++ b/arch/powerpc/cpu/mpc85xx/cmd_errata.c
@@ -261,6 +261,12 @@  static int do_errata(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 #ifdef CONFIG_SYS_FSL_ERRATUM_A006593
 	puts("Work-around for Erratum A006593 enabled\n");
 #endif
+#ifdef CONFIG_SYS_FSL_ERRATUM_I2C_A004447
+	if ((SVR_SOC_VER(svr) == SVR_8548 && IS_SVR_REV(svr, 3, 1)) ||
+	    (SVR_SOC_VER(svr) == SVR_P1010 && IS_SVR_REV(svr, 1, 0)) ||
+	     FIT_SVR_REV(svr, CONFIG_SYS_FSL_A004447_VERSION))
+		puts("Work-around for Erratum I2C-A004447 enabled\n");
+#endif
 	return 0;
 }
 
diff --git a/arch/powerpc/include/asm/config_mpc85xx.h b/arch/powerpc/include/asm/config_mpc85xx.h
index 1d46b14..f1d513e 100644
--- a/arch/powerpc/include/asm/config_mpc85xx.h
+++ b/arch/powerpc/include/asm/config_mpc85xx.h
@@ -81,6 +81,8 @@ 
 #define CONFIG_SYS_FSL_SRIO_IB_WIN_NUM	5
 #define CONFIG_SYS_FSL_RMU
 #define CONFIG_SYS_FSL_SRIO_MSG_UNIT_NUM	2
+#define CONFIG_SYS_FSL_ERRATUM_I2C_A004447
+#define CONFIG_SYS_FSL_A004447_VERSION	0x00
 
 #elif defined(CONFIG_MPC8555)
 #define CONFIG_MAX_CPUS			1
@@ -146,6 +148,8 @@ 
 #define CONFIG_SYS_FSL_ERRATUM_IFC_A002769
 #define CONFIG_SYS_FSL_ERRATUM_P1010_A003549
 #define CONFIG_SYS_FSL_ERRATUM_IFC_A003399
+#define CONFIG_SYS_FSL_ERRATUM_I2C_A004447
+#define CONFIG_SYS_FSL_A004447_VERSION	0x00
 
 /* P1011 is single core version of P1020 */
 #elif defined(CONFIG_P1011)
@@ -263,6 +267,8 @@ 
 #define CONFIG_SYS_FM_MURAM_SIZE	0x10000
 #define CONFIG_SYS_FSL_PCIE_COMPAT	"fsl,qoriq-pcie-v2.2"
 #define CONFIG_SYS_CCSRBAR_DEFAULT	0xff600000
+#define CONFIG_SYS_FSL_ERRATUM_I2C_A004447
+#define CONFIG_SYS_FSL_A004447_VERSION	0x11
 
 /* P1024 is lower end variant of P1020 */
 #elif defined(CONFIG_P1024)
@@ -347,6 +353,8 @@ 
 #define CONFIG_SYS_FSL_CORENET_SNOOPVEC_COREONLY 0xf0000000
 #define CONFIG_SYS_FSL_ERRATUM_SRIO_A004034
 #define CONFIG_SYS_FSL_ERRATUM_A004849
+#define CONFIG_SYS_FSL_ERRATUM_I2C_A004447
+#define CONFIG_SYS_FSL_A004447_VERSION	0x11
 
 #elif defined(CONFIG_PPC_P3041)
 #define CONFIG_SYS_FSL_QORIQ_CHASSIS1
@@ -380,6 +388,8 @@ 
 #define CONFIG_SYS_FSL_CORENET_SNOOPVEC_COREONLY 0xf0000000
 #define CONFIG_SYS_FSL_ERRATUM_SRIO_A004034
 #define CONFIG_SYS_FSL_ERRATUM_A004849
+#define CONFIG_SYS_FSL_ERRATUM_I2C_A004447
+#define CONFIG_SYS_FSL_A004447_VERSION	0x20
 
 #elif defined(CONFIG_PPC_P4080) /* also supports P4040 */
 #define CONFIG_SYS_FSL_QORIQ_CHASSIS1
@@ -424,6 +434,8 @@ 
 #define CONFIG_SYS_FSL_ERRATUM_A004849
 #define CONFIG_SYS_FSL_ERRATUM_A004580
 #define CONFIG_SYS_P4080_ERRATUM_PCIE_A003
+#define CONFIG_SYS_FSL_ERRATUM_I2C_A004447
+#define CONFIG_SYS_FSL_A004447_VERSION	0x20
 
 #elif defined(CONFIG_PPC_P5020) /* also supports P5010 */
 #define CONFIG_SYS_PPC64		/* 64-bit core */
@@ -454,6 +466,8 @@ 
 #define CONFIG_SYS_FSL_ERRATUM_A004510_SVR_REV	0x10
 #define CONFIG_SYS_FSL_CORENET_SNOOPVEC_COREONLY 0xc0000000
 #define CONFIG_SYS_FSL_ERRATUM_SRIO_A004034
+#define CONFIG_SYS_FSL_ERRATUM_I2C_A004447
+#define CONFIG_SYS_FSL_A004447_VERSION	0x20
 
 #elif defined(CONFIG_PPC_P5040)
 #define CONFIG_SYS_PPC64
@@ -512,6 +526,8 @@ 
 #define CONFIG_SYS_FSL_ERRATUM_ESDHC111
 #define CONFIG_SYS_FSL_ESDHC_P1010_BROKEN_SDCLK
 #define CONFIG_SYS_FSL_PCIE_COMPAT	"fsl,qoriq-pcie-v2.2"
+#define CONFIG_SYS_FSL_ERRATUM_I2C_A004447
+#define CONFIG_SYS_FSL_A004447_VERSION	0x11
 
 #elif defined(CONFIG_PPC_T4240) || defined(CONFIG_PPC_T4160)
 #define CONFIG_E6500
diff --git a/arch/powerpc/include/asm/fsl_i2c.h b/arch/powerpc/include/asm/fsl_i2c.h
index 4f71341..d6537fd 100644
--- a/arch/powerpc/include/asm/fsl_i2c.h
+++ b/arch/powerpc/include/asm/fsl_i2c.h
@@ -54,6 +54,7 @@  typedef struct fsl_i2c {
 #define I2C_CR_MTX	0x10
 #define I2C_CR_TXAK	0x08
 #define I2C_CR_RSTA	0x04
+#define I2C_CR_BIT6	0x02	/* required for workaround A004447 */
 #define I2C_CR_BCST	0x01
 
 	u8 sr;		/* I2C status register */
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index 56b22d8..156acba 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -1073,6 +1073,8 @@ 
 #define IS_SVR_REV(svr, maj, min) \
 	((SVR_MAJ(svr) == maj) && (SVR_MIN(svr) == min))
 
+#define FIT_SVR_REV(svr, version)	((svr & 0xff) <= version)
+
 /*
  * SVR_SOC_VER() Version Values
  */
diff --git a/drivers/i2c/fsl_i2c.c b/drivers/i2c/fsl_i2c.c
index ef0004d..694247c 100644
--- a/drivers/i2c/fsl_i2c.c
+++ b/drivers/i2c/fsl_i2c.c
@@ -227,6 +227,15 @@  static int i2c_fixup(const struct fsl_i2c *dev)
 	const unsigned long long timeout = usec2ticks(CONFIG_I2C_MBB_TIMEOUT);
 	unsigned long long timeval = 0;
 	int ret = -1;
+	unsigned int flags = 0;
+
+#ifdef CONFIG_SYS_FSL_ERRATUM_I2C_A004447
+	unsigned int svr = get_svr();
+	if ((SVR_SOC_VER(svr) == SVR_8548 && IS_SVR_REV(svr, 3, 1)) ||
+	    (SVR_SOC_VER(svr) == SVR_P1010 && IS_SVR_REV(svr, 1, 0)) ||
+	     FIT_SVR_REV(svr, CONFIG_SYS_FSL_A004447_VERSION))
+		flags = I2C_CR_BIT6;
+#endif
 
 	writeb(I2C_CR_MEN | I2C_CR_MSTA, &dev->cr);
 
@@ -240,8 +249,8 @@  static int i2c_fixup(const struct fsl_i2c *dev)
 		/* SDA is stuck low */
 		writeb(0, &dev->cr);
 		udelay(100);
-		writeb(I2C_CR_MSTA, &dev->cr);
-		writeb(I2C_CR_MEN | I2C_CR_MSTA, &dev->cr);
+		writeb(I2C_CR_MSTA | flags, &dev->cr);
+		writeb(I2C_CR_MEN | I2C_CR_MSTA | flags, &dev->cr);
 	}
 
 	readb(&dev->dr);
@@ -254,7 +263,7 @@  static int i2c_fixup(const struct fsl_i2c *dev)
 	ret = 0;
 
 err:
-	writeb(I2C_CR_MEN, &dev->cr);
+	writeb(I2C_CR_MEN | flags, &dev->cr);
 	writeb(0, &dev->sr);
 	udelay(100);