diff mbox series

[1/4] mtd: spi-nor-core: Do not start or end writes at odd address in DTR mode

Message ID 20240401-b4-upstream-j721s2-ospi-support-v1-1-20e4a0024db9@ti.com
State New
Delegated to: Jagannadha Sutradharudu Teki
Headers show
Series Enable OSPI boot for j721s2 | expand

Commit Message

Manorit Chawdhry April 1, 2024, 5:46 a.m. UTC
From: Pratyush Yadav <p.yadav@ti.com>

On DTR capable flashes like Micron Xcella the writes cannot start or end
at an odd address in DTR mode. Extra 0xff bytes need to be prepended or
appended respectively to make sure both the start and end addresses are
even.

Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
Reviewed-by: Vignesh Raghavendra <vigneshr@ti.com>
Signed-off-by: Apurva Nandan <a-nandan@ti.com>
Signed-off-by: Vignesh Raghavendra <vigneshr@ti.com>
Signed-off-by: Manorit Chawdhry <m-chawdhry@ti.com>
---
 drivers/mtd/spi/spi-nor-core.c | 59 +++++++++++++++++++++++++++++++++++++++---
 1 file changed, 55 insertions(+), 4 deletions(-)

Comments

Jonathan Humphreys April 1, 2024, 5:08 p.m. UTC | #1
Manorit Chawdhry <m-chawdhry@ti.com> writes:

> From: Pratyush Yadav <p.yadav@ti.com>
>
> On DTR capable flashes like Micron Xcella the writes cannot start or end
> at an odd address in DTR mode. Extra 0xff bytes need to be prepended or
> appended respectively to make sure both the start and end addresses are
> even.
>
> Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
> Reviewed-by: Vignesh Raghavendra <vigneshr@ti.com>
> Signed-off-by: Apurva Nandan <a-nandan@ti.com>
> Signed-off-by: Vignesh Raghavendra <vigneshr@ti.com>
> Signed-off-by: Manorit Chawdhry <m-chawdhry@ti.com>
> ---
>  drivers/mtd/spi/spi-nor-core.c | 59 +++++++++++++++++++++++++++++++++++++++---
>  1 file changed, 55 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
> index f86003ca8c06..2b000151c97d 100644
> --- a/drivers/mtd/spi/spi-nor-core.c
> +++ b/drivers/mtd/spi/spi-nor-core.c
> @@ -1805,11 +1805,62 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
>  		if (ret < 0)
>  			return ret;
>  #endif
> +
>  		write_enable(nor);
> -		ret = nor->write(nor, addr, page_remain, buf + i);
> -		if (ret < 0)
> -			goto write_err;
> -		written = ret;
> +
> +		/*
> +		 * On DTR capable flashes like Micron Xcella the writes cannot
> +		 * start or end at an odd address in DTR mode. So we need to
> +		 * append or prepend extra 0xff bytes to make sure the start
> +		 * address and end address are even.
> +		 */
> +		if (spi_nor_protocol_is_dtr(nor->write_proto) &&
> +		    ((addr | page_remain) & 1)) {
> +			u_char *tmp;
> +			size_t extra_bytes = 0;
> +
> +			tmp = kmalloc(nor->page_size, 0);
> +			if (!tmp) {
> +				ret = -ENOMEM;
> +				goto write_err;
> +			}
> +
> +			/* Prepend a 0xff byte if the start address is odd. */
> +			if (addr & 1) {
> +				tmp[0] = 0xff;
> +				memcpy(tmp + 1, buf + i, page_remain);
> +				addr--;
> +				page_remain++;
> +				extra_bytes++;
> +			} else {
> +				memcpy(tmp, buf + i, page_remain);
> +			}
> +
> +			/* Append a 0xff byte if the end address is odd. */
> +			if ((addr + page_remain) & 1) {
> +				tmp[page_remain + extra_bytes] = 0xff;
> +				extra_bytes++;
> +				page_remain++;
> +			}
> +
> +			ret = nor->write(nor, addr, page_remain, tmp);
> +
> +			kfree(tmp);
> +
> +			if (ret < 0)
> +				goto write_err;
> +
> +			/*
> +			 * We write extra bytes but they are not part of the
> +			 * original write.
> +			 */
> +			written = ret - extra_bytes;
> +		} else {
> +			ret = nor->write(nor, addr, page_remain, buf + i);
> +			if (ret < 0)
> +				goto write_err;
> +			written = ret;
> +		}
>  
>  		ret = spi_nor_wait_till_ready(nor);
>  		if (ret)
>
> -- 
> 2.43.2

Thanks for upstreaming!

Tested-by: Jonathan Humphreys <j-humphreys@ti.com>
diff mbox series

Patch

diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index f86003ca8c06..2b000151c97d 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -1805,11 +1805,62 @@  static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
 		if (ret < 0)
 			return ret;
 #endif
+
 		write_enable(nor);
-		ret = nor->write(nor, addr, page_remain, buf + i);
-		if (ret < 0)
-			goto write_err;
-		written = ret;
+
+		/*
+		 * On DTR capable flashes like Micron Xcella the writes cannot
+		 * start or end at an odd address in DTR mode. So we need to
+		 * append or prepend extra 0xff bytes to make sure the start
+		 * address and end address are even.
+		 */
+		if (spi_nor_protocol_is_dtr(nor->write_proto) &&
+		    ((addr | page_remain) & 1)) {
+			u_char *tmp;
+			size_t extra_bytes = 0;
+
+			tmp = kmalloc(nor->page_size, 0);
+			if (!tmp) {
+				ret = -ENOMEM;
+				goto write_err;
+			}
+
+			/* Prepend a 0xff byte if the start address is odd. */
+			if (addr & 1) {
+				tmp[0] = 0xff;
+				memcpy(tmp + 1, buf + i, page_remain);
+				addr--;
+				page_remain++;
+				extra_bytes++;
+			} else {
+				memcpy(tmp, buf + i, page_remain);
+			}
+
+			/* Append a 0xff byte if the end address is odd. */
+			if ((addr + page_remain) & 1) {
+				tmp[page_remain + extra_bytes] = 0xff;
+				extra_bytes++;
+				page_remain++;
+			}
+
+			ret = nor->write(nor, addr, page_remain, tmp);
+
+			kfree(tmp);
+
+			if (ret < 0)
+				goto write_err;
+
+			/*
+			 * We write extra bytes but they are not part of the
+			 * original write.
+			 */
+			written = ret - extra_bytes;
+		} else {
+			ret = nor->write(nor, addr, page_remain, buf + i);
+			if (ret < 0)
+				goto write_err;
+			written = ret;
+		}
 
 		ret = spi_nor_wait_till_ready(nor);
 		if (ret)