[<prev] [next>] [day] [month] [year] [list]
Message-Id: <20251118065012.1418279-1-carlos.song@nxp.com>
Date: Tue, 18 Nov 2025 14:50:12 +0800
From: Carlos Song <carlos.song@....com>
To: broonie@...nel.org,
shawnguo@...nel.org,
s.hauer@...gutronix.de,
kernel@...gutronix.de,
festevam@...il.com,
frank.li@....com
Cc: linux-spi@...r.kernel.org,
imx@...ts.linux.dev,
linux-arm-kernel@...ts.infradead.org,
linux-kernel@...r.kernel.org,
Carlos Song <carlos.song@....com>,
Clark Wang <xiaoning.wang@....com>
Subject: [PATCH v3] spi: imx: add 16/32 bits per word support for target PIO mode
Enable 16/32 bits per word support for spi-imx target PIO mode.
Signed-off-by: Carlos Song <carlos.song@....com>
Signed-off-by: Clark Wang <xiaoning.wang@....com>
---
In SPI target mode, we write/read 32 bits word in 32 bits width TXFIFO and
RXFIFO. 32 bits point is used to get the logic value from memory. CPU only
handle the logic value with FIFO, logic value is the same with value in
FIFO. However, in different CPU endian, the logic value is different.
For example from TX:
SPI tx_buff bytes order in memory:
addr0 addr1 addr2 addr3
0x11 0x22 0x33 0x44
For little endian CPU:
Get a logic value by u32 point: 0x44332211, CPU send logic value to bus
following little endian, the bytes flow in AXI bus:
0x11 0x22 0x33 0x44
but when write 32 bits word to FIFO, all bytes are grouped to one 32
bits word following the little endian to 0x44332211.
so 0x44332211 is writed to TXFIFO:
bit31~24 bit23~16 bit15~bit8 bit7~bit0
0x44 0x33 0x22 0x11
For big endian CPU:
Get a logic value by u32 point: 0x11223344, CPU send logic value to bus
following big endian, the bytes flow in AXI bus:
0x11 0x22 0x33 0x44
but when write 32 bits word to FIFO, all bytes are grouped to one 32
bits word following the big endian to 0x11223344.
so 0x11223344 is writen to TXFIFO:
bit31~24 bit23~16 bit15~bit8 bit7~bit0
0x11 0x22 0x33 0x44
Because SPI spec is not ruled for bytes order, so SPI should keep bytes
order following the CPU endian.
The bytes order in memory is the same with logic value in big endian.
So don't need to handle data for big endian CPU.
But for little endian SOC, there is some diferences:
1. When bits per word = 8:
every word is byte, so bytes order should always keep the same with memory,
u32 word is 0x44332211, but CPU should send logic value 0x11223344.
So we should swap every bytes for the u32 word 0x44332211.
2. When bits per word = 16:
every word is two bytes, so every half word should be little endian:
u32 word is 0x44332211, but CPU should send logic value 0x22114433
so we should swap every half word for the u32 word 0x44332211.
3. When bits per word = 32:
every word is 4 bytes, so every 4 bytes word should be little endian:
u32 word is 0x44332211 CPU should send logic value 0x44332211,
so don't need to do any bytes swap for this word.
---
drivers/spi/spi-imx.c | 21 +++++++++++++++++++--
1 file changed, 19 insertions(+), 2 deletions(-)
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index 1dd20e9d9605..b8b79bb7fec3 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -425,8 +425,15 @@ static void spi_imx_buf_tx_swap(struct spi_imx_data *spi_imx)
static void mx53_ecspi_rx_target(struct spi_imx_data *spi_imx)
{
- u32 val = ioread32be(spi_imx->base + MXC_CSPIRXDATA);
+ u32 val = readl(spi_imx->base + MXC_CSPIRXDATA);
+#ifdef __LITTLE_ENDIAN
+ unsigned int bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word);
+ if (bytes_per_word == 1)
+ swab32s(&val);
+ else if (bytes_per_word == 2)
+ swahw32s(&val);
+#endif
if (spi_imx->rx_buf) {
int n_bytes = spi_imx->target_burst % sizeof(val);
@@ -447,6 +454,9 @@ static void mx53_ecspi_tx_target(struct spi_imx_data *spi_imx)
{
u32 val = 0;
int n_bytes = spi_imx->count % sizeof(val);
+#ifdef __LITTLE_ENDIAN
+ unsigned int bytes_per_word;
+#endif
if (!n_bytes)
n_bytes = sizeof(val);
@@ -459,7 +469,14 @@ static void mx53_ecspi_tx_target(struct spi_imx_data *spi_imx)
spi_imx->count -= n_bytes;
- iowrite32be(val, spi_imx->base + MXC_CSPITXDATA);
+#ifdef __LITTLE_ENDIAN
+ bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word);
+ if (bytes_per_word == 1)
+ swab32s(&val);
+ else if (bytes_per_word == 2)
+ swahw32s(&val);
+#endif
+ writel(val, spi_imx->base + MXC_CSPITXDATA);
}
/* MX51 eCSPI */
--
2.34.1
Powered by blists - more mailing lists