All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v5 0/6] hw/ssi: imx_spi: Fix various bugs in the imx_spi model
@ 2021-01-12 14:55 Bin Meng
  2021-01-12 14:55 ` [PATCH v5 1/6] hw/ssi: imx_spi: Use a macro for number of chip selects supported Bin Meng
                   ` (5 more replies)
  0 siblings, 6 replies; 7+ messages in thread
From: Bin Meng @ 2021-01-12 14:55 UTC (permalink / raw)
  To: Peter Maydell, Jean-Christophe Dubois, Alistair Francis,
	Philippe Mathieu-Daudé,
	qemu-arm, qemu-devel
  Cc: Bin Meng

From: Bin Meng <bin.meng@windriver.com>

This series fixes a bunch of bugs in current implementation of the imx
spi controller, including the following issues:

- chip select signal was not lower down when spi controller is disabled
- remove imx_spi_update_irq() in imx_spi_reset()
- round up the tx burst length to be multiple of 8
- transfer incorrect data when the burst length is larger than 32 bit
- spi controller tx and rx fifo endianness is incorrect

Tested with upstream U-Boot v2020.10 (polling mode) and VxWorks 7
(interrupt mode).

Changes in v5:
- rename imx_spi_hard_reset() to imx_spi_soft_reset()
- round up the burst length to be multiple of 8

Changes in v4:
- adujst the patch 2,3 order
- rename imx_spi_soft_reset() to imx_spi_hard_reset() to avoid confusion
- s/normal/common/ in the commit message
- log the burst length value in the log message

Changes in v3:
- new patch: remove imx_spi_update_irq() in imx_spi_reset()
- Move the chip selects disable out of imx_spi_reset()
- new patch: log unimplemented burst length
- Simplify the tx fifo endianness handling

Changes in v2:
- Fix the "Fixes" tag in the commit message
- Use ternary operator as Philippe suggested

Bin Meng (5):
  hw/ssi: imx_spi: Use a macro for number of chip selects supported
  hw/ssi: imx_spi: Remove imx_spi_update_irq() in imx_spi_reset()
  hw/ssi: imx_spi: Round up the burst length to be multiple of 8
  hw/ssi: imx_spi: Correct the burst length > 32 bit transfer logic
  hw/ssi: imx_spi: Correct tx and rx fifo endianness

Xuzhou Cheng (1):
  hw/ssi: imx_spi: Disable chip selects when controller is disabled

 include/hw/ssi/imx_spi.h |  5 ++++-
 hw/ssi/imx_spi.c         | 46 +++++++++++++++++++++++++++++-----------
 2 files changed, 38 insertions(+), 13 deletions(-)

-- 
2.25.1



^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v5 1/6] hw/ssi: imx_spi: Use a macro for number of chip selects supported
  2021-01-12 14:55 [PATCH v5 0/6] hw/ssi: imx_spi: Fix various bugs in the imx_spi model Bin Meng
@ 2021-01-12 14:55 ` Bin Meng
  2021-01-12 14:55 ` [PATCH v5 2/6] hw/ssi: imx_spi: Remove imx_spi_update_irq() in imx_spi_reset() Bin Meng
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Bin Meng @ 2021-01-12 14:55 UTC (permalink / raw)
  To: Peter Maydell, Jean-Christophe Dubois, Alistair Francis,
	Philippe Mathieu-Daudé,
	qemu-arm, qemu-devel
  Cc: Bin Meng

From: Bin Meng <bin.meng@windriver.com>

Avoid using a magic number (4) everywhere for the number of chip
selects supported.

Signed-off-by: Bin Meng <bin.meng@windriver.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
---

(no changes since v1)

 include/hw/ssi/imx_spi.h | 5 ++++-
 hw/ssi/imx_spi.c         | 4 ++--
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/include/hw/ssi/imx_spi.h b/include/hw/ssi/imx_spi.h
index b82b17f364..eeaf49bbac 100644
--- a/include/hw/ssi/imx_spi.h
+++ b/include/hw/ssi/imx_spi.h
@@ -77,6 +77,9 @@
 
 #define EXTRACT(value, name) extract32(value, name##_SHIFT, name##_LENGTH)
 
+/* number of chip selects supported */
+#define ECSPI_NUM_CS 4
+
 #define TYPE_IMX_SPI "imx.spi"
 OBJECT_DECLARE_SIMPLE_TYPE(IMXSPIState, IMX_SPI)
 
@@ -89,7 +92,7 @@ struct IMXSPIState {
 
     qemu_irq irq;
 
-    qemu_irq cs_lines[4];
+    qemu_irq cs_lines[ECSPI_NUM_CS];
 
     SSIBus *bus;
 
diff --git a/hw/ssi/imx_spi.c b/hw/ssi/imx_spi.c
index d8885ae454..e605049a21 100644
--- a/hw/ssi/imx_spi.c
+++ b/hw/ssi/imx_spi.c
@@ -361,7 +361,7 @@ static void imx_spi_write(void *opaque, hwaddr offset, uint64_t value,
 
             /* We are in master mode */
 
-            for (i = 0; i < 4; i++) {
+            for (i = 0; i < ECSPI_NUM_CS; i++) {
                 qemu_set_irq(s->cs_lines[i],
                              i == imx_spi_selected_channel(s) ? 0 : 1);
             }
@@ -424,7 +424,7 @@ static void imx_spi_realize(DeviceState *dev, Error **errp)
     sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
     sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
 
-    for (i = 0; i < 4; ++i) {
+    for (i = 0; i < ECSPI_NUM_CS; ++i) {
         sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->cs_lines[i]);
     }
 
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v5 2/6] hw/ssi: imx_spi: Remove imx_spi_update_irq() in imx_spi_reset()
  2021-01-12 14:55 [PATCH v5 0/6] hw/ssi: imx_spi: Fix various bugs in the imx_spi model Bin Meng
  2021-01-12 14:55 ` [PATCH v5 1/6] hw/ssi: imx_spi: Use a macro for number of chip selects supported Bin Meng
@ 2021-01-12 14:55 ` Bin Meng
  2021-01-12 14:55 ` [PATCH v5 3/6] hw/ssi: imx_spi: Disable chip selects when controller is disabled Bin Meng
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Bin Meng @ 2021-01-12 14:55 UTC (permalink / raw)
  To: Peter Maydell, Jean-Christophe Dubois, Alistair Francis,
	Philippe Mathieu-Daudé,
	qemu-arm, qemu-devel
  Cc: Bin Meng

From: Bin Meng <bin.meng@windriver.com>

Usually the approach is that the device on the other end of the line
is going to reset its state anyway, so there's no need to actively
signal an irq line change during the reset hook.

Move imx_spi_update_irq() out of imx_spi_reset(), to a new function
imx_spi_soft_reset() that is called when the controller is disabled.

Signed-off-by: Bin Meng <bin.meng@windriver.com>

---

Changes in v5:
- rename imx_spi_hard_reset() to imx_spi_soft_reset()

Changes in v4:
- adujst the patch 2,3 order
- rename imx_spi_soft_reset() to imx_spi_hard_reset() to avoid confusion

Changes in v3:
- new patch: remove imx_spi_update_irq() in imx_spi_reset()

 hw/ssi/imx_spi.c | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/hw/ssi/imx_spi.c b/hw/ssi/imx_spi.c
index e605049a21..4d488b159a 100644
--- a/hw/ssi/imx_spi.c
+++ b/hw/ssi/imx_spi.c
@@ -241,11 +241,16 @@ static void imx_spi_reset(DeviceState *dev)
     imx_spi_rxfifo_reset(s);
     imx_spi_txfifo_reset(s);
 
-    imx_spi_update_irq(s);
-
     s->burst_length = 0;
 }
 
+static void imx_spi_soft_reset(IMXSPIState *s)
+{
+    imx_spi_reset(DEVICE(s));
+
+    imx_spi_update_irq(s);
+}
+
 static uint64_t imx_spi_read(void *opaque, hwaddr offset, unsigned size)
 {
     uint32_t value = 0;
@@ -351,8 +356,9 @@ static void imx_spi_write(void *opaque, hwaddr offset, uint64_t value,
         s->regs[ECSPI_CONREG] = value;
 
         if (!imx_spi_is_enabled(s)) {
-            /* device is disabled, so this is a reset */
-            imx_spi_reset(DEVICE(s));
+            /* device is disabled, so this is a soft reset */
+            imx_spi_soft_reset(s);
+
             return;
         }
 
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v5 3/6] hw/ssi: imx_spi: Disable chip selects when controller is disabled
  2021-01-12 14:55 [PATCH v5 0/6] hw/ssi: imx_spi: Fix various bugs in the imx_spi model Bin Meng
  2021-01-12 14:55 ` [PATCH v5 1/6] hw/ssi: imx_spi: Use a macro for number of chip selects supported Bin Meng
  2021-01-12 14:55 ` [PATCH v5 2/6] hw/ssi: imx_spi: Remove imx_spi_update_irq() in imx_spi_reset() Bin Meng
@ 2021-01-12 14:55 ` Bin Meng
  2021-01-12 14:55 ` [PATCH v5 4/6] hw/ssi: imx_spi: Round up the burst length to be multiple of 8 Bin Meng
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Bin Meng @ 2021-01-12 14:55 UTC (permalink / raw)
  To: Peter Maydell, Jean-Christophe Dubois, Alistair Francis,
	Philippe Mathieu-Daudé,
	qemu-arm, qemu-devel
  Cc: Xuzhou Cheng, Bin Meng

From: Xuzhou Cheng <xuzhou.cheng@windriver.com>

When a write to ECSPI_CONREG register to disable the SPI controller,
imx_spi_reset() is called to reset the controller, but chip select
lines should have been disabled, otherwise the state machine of any
devices (e.g.: SPI flashes) connected to the SPI master is stuck to
its last state and responds incorrectly to any follow-up commands.

Fixes: c906a3a01582 ("i.MX: Add the Freescale SPI Controller")
Signed-off-by: Xuzhou Cheng <xuzhou.cheng@windriver.com>
Signed-off-by: Bin Meng <bin.meng@windriver.com>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

---

(no changes since v3)

Changes in v3:
- Move the chip selects disable out of imx_spi_reset()

Changes in v2:
- Fix the "Fixes" tag in the commit message

 hw/ssi/imx_spi.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/hw/ssi/imx_spi.c b/hw/ssi/imx_spi.c
index 4d488b159a..880939f595 100644
--- a/hw/ssi/imx_spi.c
+++ b/hw/ssi/imx_spi.c
@@ -246,9 +246,15 @@ static void imx_spi_reset(DeviceState *dev)
 
 static void imx_spi_soft_reset(IMXSPIState *s)
 {
+    int i;
+
     imx_spi_reset(DEVICE(s));
 
     imx_spi_update_irq(s);
+
+    for (i = 0; i < ECSPI_NUM_CS; i++) {
+        qemu_set_irq(s->cs_lines[i], 1);
+    }
 }
 
 static uint64_t imx_spi_read(void *opaque, hwaddr offset, unsigned size)
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v5 4/6] hw/ssi: imx_spi: Round up the burst length to be multiple of 8
  2021-01-12 14:55 [PATCH v5 0/6] hw/ssi: imx_spi: Fix various bugs in the imx_spi model Bin Meng
                   ` (2 preceding siblings ...)
  2021-01-12 14:55 ` [PATCH v5 3/6] hw/ssi: imx_spi: Disable chip selects when controller is disabled Bin Meng
@ 2021-01-12 14:55 ` Bin Meng
  2021-01-12 14:55 ` [PATCH v5 5/6] hw/ssi: imx_spi: Correct the burst length > 32 bit transfer logic Bin Meng
  2021-01-12 14:55 ` [PATCH v5 6/6] hw/ssi: imx_spi: Correct tx and rx fifo endianness Bin Meng
  5 siblings, 0 replies; 7+ messages in thread
From: Bin Meng @ 2021-01-12 14:55 UTC (permalink / raw)
  To: Peter Maydell, Jean-Christophe Dubois, Alistair Francis,
	Philippe Mathieu-Daudé,
	qemu-arm, qemu-devel
  Cc: Bin Meng

From: Bin Meng <bin.meng@windriver.com>

Current implementation of the imx spi controller expects the burst
length to be multiple of 8, which is the most common use case.

In case the burst length is not what we expect, log it to give user
a chance to notice it, and round it up to be multiple of 8.

Signed-off-by: Bin Meng <bin.meng@windriver.com>

---

Changes in v5:
- round up the burst length to be multiple of 8

Changes in v4:
- s/normal/common/ in the commit message
- log the burst length value in the log message

Changes in v3:
- new patch: log unimplemented burst length

 hw/ssi/imx_spi.c | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/hw/ssi/imx_spi.c b/hw/ssi/imx_spi.c
index 880939f595..b7456de065 100644
--- a/hw/ssi/imx_spi.c
+++ b/hw/ssi/imx_spi.c
@@ -128,7 +128,20 @@ static uint8_t imx_spi_selected_channel(IMXSPIState *s)
 
 static uint32_t imx_spi_burst_length(IMXSPIState *s)
 {
-    return EXTRACT(s->regs[ECSPI_CONREG], ECSPI_CONREG_BURST_LENGTH) + 1;
+    uint32_t burst;
+
+    burst = EXTRACT(s->regs[ECSPI_CONREG], ECSPI_CONREG_BURST_LENGTH) + 1;
+    if (burst % 8) {
+        qemu_log_mask(LOG_UNIMP,
+                      "[%s]%s: burst length (%d) not multiple of 8!\n",
+                      TYPE_IMX_SPI, __func__, burst);
+        burst = ROUND_UP(burst, 8);
+        qemu_log_mask(LOG_UNIMP,
+                      "[%s]%s: burst length rounded up to %d; this may not work.\n",
+                      TYPE_IMX_SPI, __func__, burst);
+    }
+
+    return burst;
 }
 
 static bool imx_spi_is_enabled(IMXSPIState *s)
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v5 5/6] hw/ssi: imx_spi: Correct the burst length > 32 bit transfer logic
  2021-01-12 14:55 [PATCH v5 0/6] hw/ssi: imx_spi: Fix various bugs in the imx_spi model Bin Meng
                   ` (3 preceding siblings ...)
  2021-01-12 14:55 ` [PATCH v5 4/6] hw/ssi: imx_spi: Round up the burst length to be multiple of 8 Bin Meng
@ 2021-01-12 14:55 ` Bin Meng
  2021-01-12 14:55 ` [PATCH v5 6/6] hw/ssi: imx_spi: Correct tx and rx fifo endianness Bin Meng
  5 siblings, 0 replies; 7+ messages in thread
From: Bin Meng @ 2021-01-12 14:55 UTC (permalink / raw)
  To: Peter Maydell, Jean-Christophe Dubois, Alistair Francis,
	Philippe Mathieu-Daudé,
	qemu-arm, qemu-devel
  Cc: Bin Meng

From: Bin Meng <bin.meng@windriver.com>

For the ECSPIx_CONREG register BURST_LENGTH field, the manual says:

0x020 A SPI burst contains the 1 LSB in first word and all 32 bits in second word.
0x021 A SPI burst contains the 2 LSB in first word and all 32 bits in second word.

Current logic uses either s->burst_length or 32, whichever smaller,
to determine how many bits it should read from the tx fifo each time.
For example, for a 48 bit burst length, current logic transfers the
first 32 bit from the first word in the tx fifo, followed by a 16
bit from the second word in the tx fifo, which is wrong. The correct
logic should be: transfer the first 16 bit from the first word in
the tx fifo, followed by a 32 bit from the second word in the tx fifo.

With this change, SPI flash can be successfully probed by U-Boot on
imx6 sabrelite board.

  => sf probe
  SF: Detected sst25vf016b with page size 256 Bytes, erase size 4 KiB, total 2 MiB

Fixes: c906a3a01582 ("i.MX: Add the Freescale SPI Controller")
Signed-off-by: Bin Meng <bin.meng@windriver.com>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

---

(no changes since v2)

Changes in v2:
- Use ternary operator as Philippe suggested

 hw/ssi/imx_spi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/ssi/imx_spi.c b/hw/ssi/imx_spi.c
index b7456de065..5c2d818560 100644
--- a/hw/ssi/imx_spi.c
+++ b/hw/ssi/imx_spi.c
@@ -191,7 +191,7 @@ static void imx_spi_flush_txfifo(IMXSPIState *s)
 
         DPRINTF("data tx:0x%08x\n", tx);
 
-        tx_burst = MIN(s->burst_length, 32);
+        tx_burst = (s->burst_length % 32) ? : 32;
 
         rx = 0;
 
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v5 6/6] hw/ssi: imx_spi: Correct tx and rx fifo endianness
  2021-01-12 14:55 [PATCH v5 0/6] hw/ssi: imx_spi: Fix various bugs in the imx_spi model Bin Meng
                   ` (4 preceding siblings ...)
  2021-01-12 14:55 ` [PATCH v5 5/6] hw/ssi: imx_spi: Correct the burst length > 32 bit transfer logic Bin Meng
@ 2021-01-12 14:55 ` Bin Meng
  5 siblings, 0 replies; 7+ messages in thread
From: Bin Meng @ 2021-01-12 14:55 UTC (permalink / raw)
  To: Peter Maydell, Jean-Christophe Dubois, Alistair Francis,
	Philippe Mathieu-Daudé,
	qemu-arm, qemu-devel
  Cc: Bin Meng

From: Bin Meng <bin.meng@windriver.com>

The endianness of data exchange between tx and rx fifo is incorrect.
Earlier bytes are supposed to show up on MSB and later bytes on LSB,
ie: in big endian. The manual does not explicitly say this, but the
U-Boot and Linux driver codes have a swap on the data transferred
to tx fifo and from rx fifo.

With this change, U-Boot read from / write to SPI flash tests pass.

  => sf test 1ff000 1000
  SPI flash test:
  0 erase: 0 ticks, 4096000 KiB/s 32768.000 Mbps
  1 check: 3 ticks, 1333 KiB/s 10.664 Mbps
  2 write: 235 ticks, 17 KiB/s 0.136 Mbps
  3 read: 2 ticks, 2000 KiB/s 16.000 Mbps
  Test passed
  0 erase: 0 ticks, 4096000 KiB/s 32768.000 Mbps
  1 check: 3 ticks, 1333 KiB/s 10.664 Mbps
  2 write: 235 ticks, 17 KiB/s 0.136 Mbps
  3 read: 2 ticks, 2000 KiB/s 16.000 Mbps

Fixes: c906a3a01582 ("i.MX: Add the Freescale SPI Controller")
Signed-off-by: Bin Meng <bin.meng@windriver.com>

---

(no changes since v3)

Changes in v3:
- Simplify the tx fifo endianness handling

 hw/ssi/imx_spi.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/hw/ssi/imx_spi.c b/hw/ssi/imx_spi.c
index 5c2d818560..bbbf6afce5 100644
--- a/hw/ssi/imx_spi.c
+++ b/hw/ssi/imx_spi.c
@@ -175,7 +175,6 @@ static void imx_spi_flush_txfifo(IMXSPIState *s)
 
     while (!fifo32_is_empty(&s->tx_fifo)) {
         int tx_burst = 0;
-        int index = 0;
 
         if (s->burst_length <= 0) {
             s->burst_length = imx_spi_burst_length(s);
@@ -196,7 +195,7 @@ static void imx_spi_flush_txfifo(IMXSPIState *s)
         rx = 0;
 
         while (tx_burst > 0) {
-            uint8_t byte = tx & 0xff;
+            uint8_t byte = tx >> (tx_burst - 8);
 
             DPRINTF("writing 0x%02x\n", (uint32_t)byte);
 
@@ -205,13 +204,11 @@ static void imx_spi_flush_txfifo(IMXSPIState *s)
 
             DPRINTF("0x%02x read\n", (uint32_t)byte);
 
-            tx = tx >> 8;
-            rx |= (byte << (index * 8));
+            rx = (rx << 8) | byte;
 
             /* Remove 8 bits from the actual burst */
             tx_burst -= 8;
             s->burst_length -= 8;
-            index++;
         }
 
         DPRINTF("data rx:0x%08x\n", rx);
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2021-01-12 15:03 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-01-12 14:55 [PATCH v5 0/6] hw/ssi: imx_spi: Fix various bugs in the imx_spi model Bin Meng
2021-01-12 14:55 ` [PATCH v5 1/6] hw/ssi: imx_spi: Use a macro for number of chip selects supported Bin Meng
2021-01-12 14:55 ` [PATCH v5 2/6] hw/ssi: imx_spi: Remove imx_spi_update_irq() in imx_spi_reset() Bin Meng
2021-01-12 14:55 ` [PATCH v5 3/6] hw/ssi: imx_spi: Disable chip selects when controller is disabled Bin Meng
2021-01-12 14:55 ` [PATCH v5 4/6] hw/ssi: imx_spi: Round up the burst length to be multiple of 8 Bin Meng
2021-01-12 14:55 ` [PATCH v5 5/6] hw/ssi: imx_spi: Correct the burst length > 32 bit transfer logic Bin Meng
2021-01-12 14:55 ` [PATCH v5 6/6] hw/ssi: imx_spi: Correct tx and rx fifo endianness Bin Meng

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.