Skip to contentSkip to conversation

spi: kirkwood_spi: implement workaround for FE-9144572

PATCH New Chris Packham 3 participants 5 messages Oct 13, 2017 – Oct 16, 2017

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 spi: kirkwood_spi: implement workaround for FE-9144572

Erratum NO. FE-9144572: The device SPI interface supports frequencies of up to 50 MHz. However, due to this erratum, when the device core clock is 250 MHz and the SPI interfaces is configured for 50MHz SPI clock and CPOL=CPHA=1 there might occur data corruption on reads from the SPI device.

Implement the workaround by setting the TMISO_SAMPLE value to 0x2 in the timing1 register.

---

 arch/arm/include/asm/arch-mvebu/spi.h |  6 ++++
 drivers/spi/kirkwood_spi.c            | 62 +++++++++++++++++++++++++++++++++--
 2 files changed, 65 insertions(+), 3 deletions(-)
arch/arm/include/asm/arch-mvebu/spi.h +6 -0
index 3545aed17347..1de510ea6da9 100644
@@ -57,6 +57,12 @@ struct kwspi_registers {
 #define KWSPI_TXLSBF		(1 << 13)
 #define KWSPI_RXLSBF		(1 << 14)
 
+/* Timing Parameters 1 Register */
+#define KW_SPI_TMISO_SAMPLE_OFFSET	6
+#define KW_SPI_TMISO_SAMPLE_MASK	(0x3 << KW_SPI_TMISO_SAMPLE_OFFSET)
+#define KW_SPI_TMISO_SAMPLE_1		(1 << KW_SPI_TMISO_SAMPLE_OFFSET)
+#define KW_SPI_TMISO_SAMPLE_2		(2 << KW_SPI_TMISO_SAMPLE_OFFSET)
+
 #define KWSPI_IRQUNMASK		1 /* unmask SPI interrupt */
 #define KWSPI_IRQMASK		0 /* mask SPI interrupt */
 #define KWSPI_SMEMRDIRQ		1 /* SerMem data xfer ready irq */
drivers/spi/kirkwood_spi.c +59 -3

91 lines not on this page · raw message

Signature · 1 line
2.14.2
#1 lore raw

PATCH 1/1 spi: kirkwood_spi: implement workaround for FE-9144572

Quoted 11 lines · Chris Packham

Erratum NO. FE-9144572: The device SPI interface supports frequencies of up to 50 MHz. However, due to this erratum, when the device core clock is 250 MHz and the SPI interfaces is configured for 50MHz SPI clock and CPOL=CPHA=1 there might occur data corruption on reads from the SPI device.

Implement the workaround by setting the TMISO_SAMPLE value to 0x2 in the timing1 register.

---

I've based this as much as I can on the equivalent implementation in the Linux kernel[1], but there are differences in the u-boot spi infrastructure that means I can't be as specific when qualifying whether the workaround is needed.

[1] - https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/spi/spi-orion.c#n248

Quoted 124 lines
 arch/arm/include/asm/arch-mvebu/spi.h |  6 ++++
 drivers/spi/kirkwood_spi.c            | 62 +++++++++++++++++++++++++++++++++--
 2 files changed, 65 insertions(+), 3 deletions(-)
arch/arm/include/asm/arch-mvebu/spi.h +6 -0
index 3545aed17347..1de510ea6da9 100644
@@ -57,6 +57,12 @@ struct kwspi_registers {
 #define KWSPI_TXLSBF           (1 << 13)
 #define KWSPI_RXLSBF           (1 << 14)
 
+/* Timing Parameters 1 Register */
+#define KW_SPI_TMISO_SAMPLE_OFFSET     6
+#define KW_SPI_TMISO_SAMPLE_MASK       (0x3 << KW_SPI_TMISO_SAMPLE_OFFSET)
+#define KW_SPI_TMISO_SAMPLE_1          (1 << KW_SPI_TMISO_SAMPLE_OFFSET)
+#define KW_SPI_TMISO_SAMPLE_2          (2 << KW_SPI_TMISO_SAMPLE_OFFSET)
+
 #define KWSPI_IRQUNMASK                1 /* unmask SPI interrupt */
 #define KWSPI_IRQMASK          0 /* mask SPI interrupt */
 #define KWSPI_SMEMRDIRQ                1 /* SerMem data xfer ready irq */
drivers/spi/kirkwood_spi.c +59 -4
index 0c6bd295cde9..7992556d49eb 100644
@@ -243,6 +243,16 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
 
 /* Here now the DM part */
 
+enum mvebu_spi_type {
+       ORION_SPI,
+       ARMADA_SPI,
+};
+
+struct mvebu_spi_dev {
+       enum mvebu_spi_type     typ;
+       bool                    is_errata_50mhz_ac;
+};
+
 struct mvebu_spi_platdata {
        struct kwspi_registers *spireg;
 };
@@ -269,10 +279,30 @@ static int mvebu_spi_set_speed(struct udevice *bus, uint hz)
        return 0;
 }
 
+static void
+mvebu_spi_50mhz_ac_timing_erratum(struct udevice *bus, uint mode)
+{
+       struct mvebu_spi_platdata *plat = dev_get_platdata(bus);
+       struct kwspi_registers *reg = plat->spireg;
+       u32 data = readl(&reg->timing1);
+
+       data &= ~KW_SPI_TMISO_SAMPLE_MASK;
+
+       if (CONFIG_SYS_TCLK == 250000000 &&
+           mode & SPI_CPOL &&
+           mode & SPI_CPHA)
+               data |= KW_SPI_TMISO_SAMPLE_2;
+       else
+               data |= KW_SPI_TMISO_SAMPLE_1;
+
+       writel(data, &reg->timing1);
+}
+
 static int mvebu_spi_set_mode(struct udevice *bus, uint mode)
 {
        struct mvebu_spi_platdata *plat = dev_get_platdata(bus);
        struct kwspi_registers *reg = plat->spireg;
+       const struct mvebu_spi_dev *drvdata;
        u32 data = readl(&reg->cfg);
 
        data &= ~(KWSPI_CPHA | KWSPI_CPOL | KWSPI_RXLSBF | KWSPI_TXLSBF);
@@ -286,6 +316,10 @@ static int mvebu_spi_set_mode(struct udevice *bus, uint mode)
 
        writel(data, &reg->cfg);
 
+       drvdata = (struct mvebu_spi_dev *)dev_get_driver_data(bus);
+       if (drvdata->is_errata_50mhz_ac)
+               mvebu_spi_50mhz_ac_timing_erratum(bus, mode);
+
        return 0;
 }
 
@@ -343,10 +377,32 @@ static const struct dm_spi_ops mvebu_spi_ops = {
         */
 };
 
+static const struct mvebu_spi_dev armada_xp_spi_dev_data = {
+       .typ = ARMADA_SPI,
+};
+
+static const struct mvebu_spi_dev armada_375_spi_dev_data = {
+       .typ = ARMADA_SPI,
+};
+
+static const struct mvebu_spi_dev armada_380_spi_dev_data = {
+       .typ = ARMADA_SPI,
+       .is_errata_50mhz_ac = true,
+};
+
 static const struct udevice_id mvebu_spi_ids[] = {
-       { .compatible = "marvell,armada-375-spi" },
-       { .compatible = "marvell,armada-380-spi" },
-       { .compatible = "marvell,armada-xp-spi" },
+       {
+               .compatible = "marvell,armada-375-spi",
+               .data = (ulong)&armada_375_spi_dev_data
+       },
+       {
+               .compatible = "marvell,armada-380-spi",
+               .data = (ulong)&armada_380_spi_dev_data
+       },
+       {
+               .compatible = "marvell,armada-xp-spi",
+               .data = (ulong)&armada_xp_spi_dev_data
+       },
        { }
 };
 
--

2.14.2

#2 lore raw

PATCH 1/1 spi: kirkwood_spi: implement workaround for FE-9144572

In reply to Chris Packham
Quoted 123 lines · Chris Packham

Erratum NO. FE-9144572: The device SPI interface supports frequencies of up to 50 MHz. However, due to this erratum, when the device core clock is 250 MHz and the SPI interfaces is configured for 50MHz SPI clock and CPOL=CPHA=1 there might occur data corruption on reads from the SPI device.

Implement the workaround by setting the TMISO_SAMPLE value to 0x2 in the timing1 register.

---

  arch/arm/include/asm/arch-mvebu/spi.h |  6 ++++
  drivers/spi/kirkwood_spi.c            | 62 +++++++++++++++++++++++++++++++++--
  2 files changed, 65 insertions(+), 3 deletions(-)
arch/arm/include/asm/arch-mvebu/spi.h +6 -0
index 3545aed17347..1de510ea6da9 100644
@@ -57,6 +57,12 @@ struct kwspi_registers {
  #define KWSPI_TXLSBF		(1 << 13)
  #define KWSPI_RXLSBF		(1 << 14)
 
+/* Timing Parameters 1 Register */
+#define KW_SPI_TMISO_SAMPLE_OFFSET	6
+#define KW_SPI_TMISO_SAMPLE_MASK	(0x3 << KW_SPI_TMISO_SAMPLE_OFFSET)
+#define KW_SPI_TMISO_SAMPLE_1		(1 << KW_SPI_TMISO_SAMPLE_OFFSET)
+#define KW_SPI_TMISO_SAMPLE_2		(2 << KW_SPI_TMISO_SAMPLE_OFFSET)
+
  #define KWSPI_IRQUNMASK		1 /* unmask SPI interrupt */
  #define KWSPI_IRQMASK		0 /* mask SPI interrupt */
  #define KWSPI_SMEMRDIRQ		1 /* SerMem data xfer ready irq */
drivers/spi/kirkwood_spi.c +52 -3
index 0c6bd295cde9..7992556d49eb 100644
@@ -243,6 +243,16 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
 
  /* Here now the DM part */
 
+enum mvebu_spi_type {
+	ORION_SPI,
+	ARMADA_SPI,
+};
+
+struct mvebu_spi_dev {
+	enum mvebu_spi_type	typ;
+	bool			is_errata_50mhz_ac;
+};
+
  struct mvebu_spi_platdata {
  	struct kwspi_registers *spireg;
  };
@@ -269,10 +279,30 @@ static int mvebu_spi_set_speed(struct udevice *bus, uint hz)
  	return 0;
  }
 
+static void
+mvebu_spi_50mhz_ac_timing_erratum(struct udevice *bus, uint mode)
+{
+	struct mvebu_spi_platdata *plat = dev_get_platdata(bus);
+	struct kwspi_registers *reg = plat->spireg;
+	u32 data = readl(&reg->timing1);
+
+	data &= ~KW_SPI_TMISO_SAMPLE_MASK;
+
+	if (CONFIG_SYS_TCLK == 250000000 &&
+	    mode & SPI_CPOL &&
+	    mode & SPI_CPHA)
+		data |= KW_SPI_TMISO_SAMPLE_2;
+	else
+		data |= KW_SPI_TMISO_SAMPLE_1;
+
+	writel(data, &reg->timing1);
+}
+
  static int mvebu_spi_set_mode(struct udevice *bus, uint mode)
  {
  	struct mvebu_spi_platdata *plat = dev_get_platdata(bus);
  	struct kwspi_registers *reg = plat->spireg;
+	const struct mvebu_spi_dev *drvdata;
  	u32 data = readl(&reg->cfg);
 
  	data &= ~(KWSPI_CPHA | KWSPI_CPOL | KWSPI_RXLSBF | KWSPI_TXLSBF);
@@ -286,6 +316,10 @@ static int mvebu_spi_set_mode(struct udevice *bus, uint mode)
 
  	writel(data, &reg->cfg);
 
+	drvdata = (struct mvebu_spi_dev *)dev_get_driver_data(bus);
+	if (drvdata->is_errata_50mhz_ac)
+		mvebu_spi_50mhz_ac_timing_erratum(bus, mode);
+
  	return 0;
  }
 
@@ -343,10 +377,32 @@ static const struct dm_spi_ops mvebu_spi_ops = {
  	 */
  };
 
+static const struct mvebu_spi_dev armada_xp_spi_dev_data = {
+	.typ = ARMADA_SPI,
+};
+
+static const struct mvebu_spi_dev armada_375_spi_dev_data = {
+	.typ = ARMADA_SPI,
+};
+
+static const struct mvebu_spi_dev armada_380_spi_dev_data = {
+	.typ = ARMADA_SPI,
+	.is_errata_50mhz_ac = true,
+};
+
  static const struct udevice_id mvebu_spi_ids[] = {
-	{ .compatible = "marvell,armada-375-spi" },
-	{ .compatible = "marvell,armada-380-spi" },
-	{ .compatible = "marvell,armada-xp-spi" },
+	{
+		.compatible = "marvell,armada-375-spi",
+		.data = (ulong)&armada_375_spi_dev_data
+	},
+	{

drivers/spi/kirkwood_spi.c static const struct dm_spi_ops mvebu_spi_ops = { · line 408

Quoted 10 lines
drivers/spi/kirkwood_spi.c +7 -0
+		.compatible = "marvell,armada-380-spi",
+		.data = (ulong)&armada_380_spi_dev_data
+	},
+	{
+		.compatible = "marvell,armada-xp-spi",
+		.data = (ulong)&armada_xp_spi_dev_data
+	},
  	{ }
  };
 

Thanks,
Stefan

#3 lore raw

PATCH 1/1 spi: kirkwood_spi: implement workaround for FE-9144572

In reply to Chris Packham
Quoted 38 lines · Chris Packham

Erratum NO. FE-9144572: The device SPI interface supports frequencies of up to 50 MHz. However, due to this erratum, when the device core clock is 250 MHz and the SPI interfaces is configured for 50MHz SPI clock and CPOL=CPHA=1 there might occur data corruption on reads from the SPI device.

Implement the workaround by setting the TMISO_SAMPLE value to 0x2 in the timing1 register.

---

 arch/arm/include/asm/arch-mvebu/spi.h |  6 ++++
 drivers/spi/kirkwood_spi.c            | 62 +++++++++++++++++++++++++++++++++--
 2 files changed, 65 insertions(+), 3 deletions(-)
arch/arm/include/asm/arch-mvebu/spi.h +6 -0
index 3545aed17347..1de510ea6da9 100644
@@ -57,6 +57,12 @@ struct kwspi_registers {
 #define KWSPI_TXLSBF           (1 << 13)
 #define KWSPI_RXLSBF           (1 << 14)
 
+/* Timing Parameters 1 Register */
+#define KW_SPI_TMISO_SAMPLE_OFFSET     6
+#define KW_SPI_TMISO_SAMPLE_MASK       (0x3 << KW_SPI_TMISO_SAMPLE_OFFSET)
+#define KW_SPI_TMISO_SAMPLE_1          (1 << KW_SPI_TMISO_SAMPLE_OFFSET)
+#define KW_SPI_TMISO_SAMPLE_2          (2 << KW_SPI_TMISO_SAMPLE_OFFSET)
+
 #define KWSPI_IRQUNMASK                1 /* unmask SPI interrupt */
 #define KWSPI_IRQMASK          0 /* mask SPI interrupt */
 #define KWSPI_SMEMRDIRQ                1 /* SerMem data xfer ready irq */
drivers/spi/kirkwood_spi.c +0 -0
index 0c6bd295cde9..7992556d49eb 100644

drivers/spi/kirkwood_spi.c int spi_xfer(struct spi_slave *slave, unsigned int bitlen, · line 247

Quoted 5 lines
drivers/spi/kirkwood_spi.c +2 -0
@@ -243,6 +243,16 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
 
 /* Here now the DM part */
 
+enum mvebu_spi_type {
+       ORION_SPI,

This is never used, since there is a separate driver in orion - any plan to merge them as single driver? otherwise it's no need.

Quoted 12 lines
drivers/spi/kirkwood_spi.c +8 -0
+       ARMADA_SPI,
+};
+
+struct mvebu_spi_dev {
+       enum mvebu_spi_type     typ;
+       bool                    is_errata_50mhz_ac;
+};
+
 struct mvebu_spi_platdata {
        struct kwspi_registers *spireg;
 };

drivers/spi/kirkwood_spi.c static int mvebu_spi_set_speed(struct udevice *bus, uint hz) · line 288

Quoted 10 lines
drivers/spi/kirkwood_spi.c +7 -0
@@ -269,10 +279,30 @@ static int mvebu_spi_set_speed(struct udevice *bus, uint hz)
        return 0;
 }
 
+static void
+mvebu_spi_50mhz_ac_timing_erratum(struct udevice *bus, uint mode)
+{
+       struct mvebu_spi_platdata *plat = dev_get_platdata(bus);
+       struct kwspi_registers *reg = plat->spireg;
+       u32 data = readl(&reg->timing1);
+

Better to have description of errata.

thanks!

Signature · 4 lines
Jagan Teki
Free Software Engineer | www.openedev.com
U-Boot, Linux | Upstream Maintainer
Hyderabad, India.
#4 lore raw

PATCH 1/1 spi: kirkwood_spi: implement workaround for FE-9144572

Quoted 40 lines · Jagan Teki
Quoted 39 lines · Chris Packham

Erratum NO. FE-9144572: The device SPI interface supports frequencies of up to 50 MHz. However, due to this erratum, when the device core clock is 250 MHz and the SPI interfaces is configured for 50MHz SPI clock and CPOL=CPHA=1 there might occur data corruption on reads from the SPI device.

Implement the workaround by setting the TMISO_SAMPLE value to 0x2 in the timing1 register.

---

 arch/arm/include/asm/arch-mvebu/spi.h |  6 ++++
 drivers/spi/kirkwood_spi.c            | 62 +++++++++++++++++++++++++++++++++--
 2 files changed, 65 insertions(+), 3 deletions(-)
arch/arm/include/asm/arch-mvebu/spi.h +6 -0
index 3545aed17347..1de510ea6da9 100644
@@ -57,6 +57,12 @@ struct kwspi_registers {
 #define KWSPI_TXLSBF           (1 << 13)
 #define KWSPI_RXLSBF           (1 << 14)
 
+/* Timing Parameters 1 Register */
+#define KW_SPI_TMISO_SAMPLE_OFFSET     6
+#define KW_SPI_TMISO_SAMPLE_MASK       (0x3 << KW_SPI_TMISO_SAMPLE_OFFSET)
+#define KW_SPI_TMISO_SAMPLE_1          (1 << KW_SPI_TMISO_SAMPLE_OFFSET)
+#define KW_SPI_TMISO_SAMPLE_2          (2 << KW_SPI_TMISO_SAMPLE_OFFSET)
+
 #define KWSPI_IRQUNMASK                1 /* unmask SPI interrupt */
 #define KWSPI_IRQMASK          0 /* mask SPI interrupt */
 #define KWSPI_SMEMRDIRQ                1 /* SerMem data xfer ready irq */
drivers/spi/kirkwood_spi.c +0 -0
index 0c6bd295cde9..7992556d49eb 100644
@@ -243,6 +243,16 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
 
Quoted 8 lines

drivers/spi/kirkwood_spi.c int spi_xfer(struct spi_slave *slave, unsigned int bitlen, · line 247

Quoted 4 lines
drivers/spi/kirkwood_spi.c +2 -0
 /* Here now the DM part */
 
+enum mvebu_spi_type {
+       ORION_SPI,

This is never used, since there is a separate driver in orion - any plan to merge them as single driver? otherwise it's no need.

I actually do have access to some Kirkwood hardware. But a distinct lack of round tuits to port it to master/DM/etc.

For now I'll drop the type. It can be added back if/when a user emerges.

Quoted 15 lines
Quoted 15 lines
drivers/spi/kirkwood_spi.c +8 -0
+       ARMADA_SPI,
+};
+
+struct mvebu_spi_dev {
+       enum mvebu_spi_type     typ;
+       bool                    is_errata_50mhz_ac;
+};
+
 struct mvebu_spi_platdata {
        struct kwspi_registers *spireg;
 };
@@ -269,10 +279,30 @@ static int mvebu_spi_set_speed(struct udevice *bus, uint hz)
        return 0;
 }
 
Quoted 10 lines

drivers/spi/kirkwood_spi.c static int mvebu_spi_set_speed(struct udevice *bus, uint hz) · line 288

Quoted 7 lines
drivers/spi/kirkwood_spi.c +7 -0
+static void
+mvebu_spi_50mhz_ac_timing_erratum(struct udevice *bus, uint mode)
+{
+       struct mvebu_spi_platdata *plat = dev_get_platdata(bus);
+       struct kwspi_registers *reg = plat->spireg;
+       u32 data = readl(&reg->timing1);
+

Better to have description of errata.

Will add in v2.

Quoted 6 lines

thanks!
--
Jagan Teki
Free Software Engineer | www.openedev.com
U-Boot, Linux | Upstream Maintainer
Hyderabad, India.