diff mbox series

[v7,5/7] spi: mxic: Add support for swapping byte

Message ID 20231221090702.103027-6-jaimeliao.tw@gmail.com
State Changes Requested
Delegated to: Ambarus Tudor
Headers show
Series Add octal DTR support for Macronix flash | expand

Commit Message

liao jaime Dec. 21, 2023, 9:07 a.m. UTC
From: JaimeLiao <jaimeliao@mxic.com.tw>

Some SPI-NOR flash swap the bytes on a 16-bit boundary when
configured in Octal DTR mode. It means data format D0 D1 D2 D3
would be swapped to D1 D0 D3 D2. So that whether controller
support swapping bytes should be checked before enable Octal
DTR mode. Add swap byte support on a 16-bit boundary when
configured in Octal DTR mode for Macronix xSPI host controller
dirver.

According dtr_swab in operation to enable/disable Macronix
xSPI host controller swap byte feature.

To make sure swap byte feature is working well, program data in
1S-1S-1S mode then read back and compare read data in 8D-8D-8D
mode.

This feature have been validated on byte-swap flash and
non-byte-swap flash.

Macronix xSPI host controller bit "HC_CFG_DATA_PASS" determine
the byte swap feature disabled/enabled and swap byte feature is
working on 8D-8D-8D mode only.

Signed-off-by: JaimeLiao <jaimeliao@mxic.com.tw>
---
 drivers/spi/spi-mxic.c | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)

Comments

Michael Walle Jan. 5, 2024, 12:37 p.m. UTC | #1
Hi,

> Some SPI-NOR flash swap the bytes on a 16-bit boundary when
> configured in Octal DTR mode. It means data format D0 D1 D2 D3
> would be swapped to D1 D0 D3 D2. So that whether controller
> support swapping bytes should be checked before enable Octal
> DTR mode. Add swap byte support on a 16-bit boundary when
> configured in Octal DTR mode for Macronix xSPI host controller
> dirver.
> 
> According dtr_swab in operation to enable/disable Macronix
> xSPI host controller swap byte feature.
> 
> To make sure swap byte feature is working well, program data in
> 1S-1S-1S mode then read back and compare read data in 8D-8D-8D
> mode.
> 
> This feature have been validated on byte-swap flash and
> non-byte-swap flash.
> 
> Macronix xSPI host controller bit "HC_CFG_DATA_PASS" determine
> the byte swap feature disabled/enabled and swap byte feature is
> working on 8D-8D-8D mode only.
> 
> Signed-off-by: JaimeLiao <jaimeliao@mxic.com.tw>
> ---
>  drivers/spi/spi-mxic.c | 19 +++++++++++++++----
>  1 file changed, 15 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c
> index 60c9f3048ac9..8dc83adaaa88 100644
> --- a/drivers/spi/spi-mxic.c
> +++ b/drivers/spi/spi-mxic.c
> @@ -294,7 +294,8 @@ static void mxic_spi_hw_init(struct mxic_spi *mxic)
>  	       mxic->regs + HC_CFG);
>  }
> 
> -static u32 mxic_spi_prep_hc_cfg(struct spi_device *spi, u32 flags)
> +static u32 mxic_spi_prep_hc_cfg(const struct spi_mem_op *op,
> +				struct spi_device *spi, u32 flags)

Not my driver, but because it caught my eye: I wouldn't pass
spi_mem_op. Maybe just "bool swap16"?

>  {
>  	int nio = 1;
> 
> @@ -305,6 +306,13 @@ static u32 mxic_spi_prep_hc_cfg(struct spi_device 
> *spi, u32 flags)
>  	else if (spi->mode & (SPI_TX_DUAL | SPI_RX_DUAL))
>  		nio = 2;
> 
> +	if (op->data.dtr) {

Checking this seems to be redundant with checking dtr_swab16.

> +		if (op->data.dtr_swab16)
> +			flags &= ~HC_CFG_DATA_PASS;
> +		else
> +			flags |= HC_CFG_DATA_PASS;

Mhh, this is strange. Given that dtr_swap16 is a new flag means
that you are now setting the HC_CFG_DATA_PASS bit by default.
Something to keep in mind if you have any users which already use
8d8d8d mode nowadays.

Also clearing the flag seems superfluous.

-michael

> +	}
> +
>  	return flags | HC_CFG_NIO(nio) |
>  	       HC_CFG_TYPE(spi_get_chipselect(spi, 0), HC_CFG_TYPE_SPI_NOR) |
>  	       HC_CFG_SLV_ACT(spi_get_chipselect(spi, 0)) | 
> HC_CFG_IDLE_SIO_LVL(1);
> @@ -397,7 +405,8 @@ static ssize_t mxic_spi_mem_dirmap_read(struct 
> spi_mem_dirmap_desc *desc,
>  	if (WARN_ON(offs + desc->info.offset + len > U32_MAX))
>  		return -EINVAL;
> 
> -	writel(mxic_spi_prep_hc_cfg(desc->mem->spi, 0), mxic->regs + HC_CFG);
> +	writel(mxic_spi_prep_hc_cfg(&desc->info.op_tmpl,
> +				    desc->mem->spi, 0), mxic->regs + HC_CFG);
> 
>  	writel(mxic_spi_mem_prep_op_cfg(&desc->info.op_tmpl, len),
>  	       mxic->regs + LRD_CFG);
> @@ -441,7 +450,8 @@ static ssize_t mxic_spi_mem_dirmap_write(struct 
> spi_mem_dirmap_desc *desc,
>  	if (WARN_ON(offs + desc->info.offset + len > U32_MAX))
>  		return -EINVAL;
> 
> -	writel(mxic_spi_prep_hc_cfg(desc->mem->spi, 0), mxic->regs + HC_CFG);
> +	writel(mxic_spi_prep_hc_cfg(&desc->info.op_tmpl,
> +				    desc->mem->spi, 0), mxic->regs + HC_CFG);
> 
>  	writel(mxic_spi_mem_prep_op_cfg(&desc->info.op_tmpl, len),
>  	       mxic->regs + LWR_CFG);
> @@ -518,7 +528,7 @@ static int mxic_spi_mem_exec_op(struct spi_mem 
> *mem,
>  	if (ret)
>  		return ret;
> 
> -	writel(mxic_spi_prep_hc_cfg(mem->spi, HC_CFG_MAN_CS_EN),
> +	writel(mxic_spi_prep_hc_cfg(op, mem->spi, HC_CFG_MAN_CS_EN),
>  	       mxic->regs + HC_CFG);
> 
>  	writel(HC_EN_BIT, mxic->regs + HC_EN);
> @@ -572,6 +582,7 @@ static const struct spi_controller_mem_ops 
> mxic_spi_mem_ops = {
> 
>  static const struct spi_controller_mem_caps mxic_spi_mem_caps = {
>  	.dtr = true,
> +	.dtr_swab16 = true,
>  	.ecc = true,
>  };
liao jaime Jan. 12, 2024, 5:14 a.m. UTC | #2
Hi Michael


>
> Hi,
>
> > Some SPI-NOR flash swap the bytes on a 16-bit boundary when
> > configured in Octal DTR mode. It means data format D0 D1 D2 D3
> > would be swapped to D1 D0 D3 D2. So that whether controller
> > support swapping bytes should be checked before enable Octal
> > DTR mode. Add swap byte support on a 16-bit boundary when
> > configured in Octal DTR mode for Macronix xSPI host controller
> > dirver.
> >
> > According dtr_swab in operation to enable/disable Macronix
> > xSPI host controller swap byte feature.
> >
> > To make sure swap byte feature is working well, program data in
> > 1S-1S-1S mode then read back and compare read data in 8D-8D-8D
> > mode.
> >
> > This feature have been validated on byte-swap flash and
> > non-byte-swap flash.
> >
> > Macronix xSPI host controller bit "HC_CFG_DATA_PASS" determine
> > the byte swap feature disabled/enabled and swap byte feature is
> > working on 8D-8D-8D mode only.
> >
> > Signed-off-by: JaimeLiao <jaimeliao@mxic.com.tw>
> > ---
> >  drivers/spi/spi-mxic.c | 19 +++++++++++++++----
> >  1 file changed, 15 insertions(+), 4 deletions(-)
> >
> > diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c
> > index 60c9f3048ac9..8dc83adaaa88 100644
> > --- a/drivers/spi/spi-mxic.c
> > +++ b/drivers/spi/spi-mxic.c
> > @@ -294,7 +294,8 @@ static void mxic_spi_hw_init(struct mxic_spi *mxic)
> >              mxic->regs + HC_CFG);
> >  }
> >
> > -static u32 mxic_spi_prep_hc_cfg(struct spi_device *spi, u32 flags)
> > +static u32 mxic_spi_prep_hc_cfg(const struct spi_mem_op *op,
> > +                             struct spi_device *spi, u32 flags)
>
> Not my driver, but because it caught my eye: I wouldn't pass
> spi_mem_op. Maybe just "bool swap16"?
Thanks, I will change this next patch.

>
> >  {
> >       int nio = 1;
> >
> > @@ -305,6 +306,13 @@ static u32 mxic_spi_prep_hc_cfg(struct spi_device
> > *spi, u32 flags)
> >       else if (spi->mode & (SPI_TX_DUAL | SPI_RX_DUAL))
> >               nio = 2;
> >
> > +     if (op->data.dtr) {
>
> Checking this seems to be redundant with checking dtr_swab16.
Got it.

>
> > +             if (op->data.dtr_swab16)
> > +                     flags &= ~HC_CFG_DATA_PASS;
> > +             else
> > +                     flags |= HC_CFG_DATA_PASS;
>
> Mhh, this is strange. Given that dtr_swap16 is a new flag means
> that you are now setting the HC_CFG_DATA_PASS bit by default.
> Something to keep in mind if you have any users which already use
> 8d8d8d mode nowadays.
>
> Also clearing the flag seems superfluous.
>
> -michael
>
> > +     }
> > +
> >       return flags | HC_CFG_NIO(nio) |
> >              HC_CFG_TYPE(spi_get_chipselect(spi, 0), HC_CFG_TYPE_SPI_NOR) |
> >              HC_CFG_SLV_ACT(spi_get_chipselect(spi, 0)) |
> > HC_CFG_IDLE_SIO_LVL(1);
> > @@ -397,7 +405,8 @@ static ssize_t mxic_spi_mem_dirmap_read(struct
> > spi_mem_dirmap_desc *desc,
> >       if (WARN_ON(offs + desc->info.offset + len > U32_MAX))
> >               return -EINVAL;
> >
> > -     writel(mxic_spi_prep_hc_cfg(desc->mem->spi, 0), mxic->regs + HC_CFG);
> > +     writel(mxic_spi_prep_hc_cfg(&desc->info.op_tmpl,
> > +                                 desc->mem->spi, 0), mxic->regs + HC_CFG);
> >
> >       writel(mxic_spi_mem_prep_op_cfg(&desc->info.op_tmpl, len),
> >              mxic->regs + LRD_CFG);
> > @@ -441,7 +450,8 @@ static ssize_t mxic_spi_mem_dirmap_write(struct
> > spi_mem_dirmap_desc *desc,
> >       if (WARN_ON(offs + desc->info.offset + len > U32_MAX))
> >               return -EINVAL;
> >
> > -     writel(mxic_spi_prep_hc_cfg(desc->mem->spi, 0), mxic->regs + HC_CFG);
> > +     writel(mxic_spi_prep_hc_cfg(&desc->info.op_tmpl,
> > +                                 desc->mem->spi, 0), mxic->regs + HC_CFG);
> >
> >       writel(mxic_spi_mem_prep_op_cfg(&desc->info.op_tmpl, len),
> >              mxic->regs + LWR_CFG);
> > @@ -518,7 +528,7 @@ static int mxic_spi_mem_exec_op(struct spi_mem
> > *mem,
> >       if (ret)
> >               return ret;
> >
> > -     writel(mxic_spi_prep_hc_cfg(mem->spi, HC_CFG_MAN_CS_EN),
> > +     writel(mxic_spi_prep_hc_cfg(op, mem->spi, HC_CFG_MAN_CS_EN),
> >              mxic->regs + HC_CFG);
> >
> >       writel(HC_EN_BIT, mxic->regs + HC_EN);
> > @@ -572,6 +582,7 @@ static const struct spi_controller_mem_ops
> > mxic_spi_mem_ops = {
> >
> >  static const struct spi_controller_mem_caps mxic_spi_mem_caps = {
> >       .dtr = true,
> > +     .dtr_swab16 = true,
> >       .ecc = true,
> >  };

Thanks
Jaime
diff mbox series

Patch

diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c
index 60c9f3048ac9..8dc83adaaa88 100644
--- a/drivers/spi/spi-mxic.c
+++ b/drivers/spi/spi-mxic.c
@@ -294,7 +294,8 @@  static void mxic_spi_hw_init(struct mxic_spi *mxic)
 	       mxic->regs + HC_CFG);
 }
 
-static u32 mxic_spi_prep_hc_cfg(struct spi_device *spi, u32 flags)
+static u32 mxic_spi_prep_hc_cfg(const struct spi_mem_op *op,
+				struct spi_device *spi, u32 flags)
 {
 	int nio = 1;
 
@@ -305,6 +306,13 @@  static u32 mxic_spi_prep_hc_cfg(struct spi_device *spi, u32 flags)
 	else if (spi->mode & (SPI_TX_DUAL | SPI_RX_DUAL))
 		nio = 2;
 
+	if (op->data.dtr) {
+		if (op->data.dtr_swab16)
+			flags &= ~HC_CFG_DATA_PASS;
+		else
+			flags |= HC_CFG_DATA_PASS;
+	}
+
 	return flags | HC_CFG_NIO(nio) |
 	       HC_CFG_TYPE(spi_get_chipselect(spi, 0), HC_CFG_TYPE_SPI_NOR) |
 	       HC_CFG_SLV_ACT(spi_get_chipselect(spi, 0)) | HC_CFG_IDLE_SIO_LVL(1);
@@ -397,7 +405,8 @@  static ssize_t mxic_spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc,
 	if (WARN_ON(offs + desc->info.offset + len > U32_MAX))
 		return -EINVAL;
 
-	writel(mxic_spi_prep_hc_cfg(desc->mem->spi, 0), mxic->regs + HC_CFG);
+	writel(mxic_spi_prep_hc_cfg(&desc->info.op_tmpl,
+				    desc->mem->spi, 0), mxic->regs + HC_CFG);
 
 	writel(mxic_spi_mem_prep_op_cfg(&desc->info.op_tmpl, len),
 	       mxic->regs + LRD_CFG);
@@ -441,7 +450,8 @@  static ssize_t mxic_spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc,
 	if (WARN_ON(offs + desc->info.offset + len > U32_MAX))
 		return -EINVAL;
 
-	writel(mxic_spi_prep_hc_cfg(desc->mem->spi, 0), mxic->regs + HC_CFG);
+	writel(mxic_spi_prep_hc_cfg(&desc->info.op_tmpl,
+				    desc->mem->spi, 0), mxic->regs + HC_CFG);
 
 	writel(mxic_spi_mem_prep_op_cfg(&desc->info.op_tmpl, len),
 	       mxic->regs + LWR_CFG);
@@ -518,7 +528,7 @@  static int mxic_spi_mem_exec_op(struct spi_mem *mem,
 	if (ret)
 		return ret;
 
-	writel(mxic_spi_prep_hc_cfg(mem->spi, HC_CFG_MAN_CS_EN),
+	writel(mxic_spi_prep_hc_cfg(op, mem->spi, HC_CFG_MAN_CS_EN),
 	       mxic->regs + HC_CFG);
 
 	writel(HC_EN_BIT, mxic->regs + HC_EN);
@@ -572,6 +582,7 @@  static const struct spi_controller_mem_ops mxic_spi_mem_ops = {
 
 static const struct spi_controller_mem_caps mxic_spi_mem_caps = {
 	.dtr = true,
+	.dtr_swab16 = true,
 	.ecc = true,
 };