drivers/spi/spi-imx.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-)
Enable 16/32 bits per word support for spi-imx target PIO mode.
Signed-off-by: Carlos Song <carlos.song@nxp.com>
Signed-off-by: Clark Wang <xiaoning.wang@nxp.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
On Tue, 18 Nov 2025 14:50:12 +0800, Carlos Song wrote:
> Enable 16/32 bits per word support for spi-imx target PIO mode.
>
>
Applied to
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next
Thanks!
[1/1] spi: imx: add 16/32 bits per word support for target PIO mode
commit: 4dbb5f6e1b4eed64037d4462977c196acab2af16
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
On Tue, Nov 18, 2025 at 02:50:12PM +0800, Carlos Song wrote:
> Enable 16/32 bits per word support for spi-imx target PIO mode.
>
> Signed-off-by: Carlos Song <carlos.song@nxp.com>
> Signed-off-by: Clark Wang <xiaoning.wang@nxp.com>
Reviewed-by: Frank Li <Frank.Li@nxp.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
>
© 2016 - 2025 Red Hat, Inc.