Hi,
Patch 1-2: write path fixes
The sst write path is completely broken since v5.7-rc1 and in rare cases
since the support of the sst_write() function (49aac4aec53c).
Patch 3: cleanup
I've tested my patches with a small test app to ensure writes starting
on an odd address and with dd to test even start addresses. My dut was
an public available imx6q-sabrelite (rev.D).
Other testers are welcome :)
Regards,
Marco
Marco Felsch (3):
mtd: spi-nor: sst: fix write support for SST_WRITE marked devices
mtd: spi-nor: sst: add missing write_enable
mtd: spi-nor: sst: move sst_write_second to local driver
drivers/mtd/spi-nor/core.c | 15 +++++++++------
drivers/mtd/spi-nor/sst.c | 15 +++++++++++----
include/linux/mtd/spi-nor.h | 2 --
3 files changed, 20 insertions(+), 12 deletions(-)
--
2.20.1
The sst write support for devices using the special SST_WRITE routine
is broken since commit commit df5c21002cf4 ("mtd: spi-nor: use spi-mem
dirmap API") because the spi_nor_create_write_dirmap() function checks
SPINOR_OP_AAI_WP and sst_write_second. These checks are not valid during
probe. The check seems also to be broken since the "op->addr.nbytes = 0"
causes the devm_spi_mem_dirmap_create() function to return
PTR_ERR(-EINVAL) and the probe() function will fail.
It seems that the commit only copy'n'pasted the existing logic. Use the
correct SST_WRITE flag and return 0 to fix both issues.
Fixes: df5c21002cf4 ("mtd: spi-nor: use spi-mem dirmap API")
Signed-off-by: Marco Felsch <[email protected]>
---
drivers/mtd/spi-nor/core.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
index 65eff4ce6ab1..31869ac245a8 100644
--- a/drivers/mtd/spi-nor/core.c
+++ b/drivers/mtd/spi-nor/core.c
@@ -3289,15 +3289,21 @@ static int spi_nor_create_write_dirmap(struct spi_nor *nor)
};
struct spi_mem_op *op = &info.op_tmpl;
+ /*
+ * Most SST SPI-NOR's have a special write routine.which should so
+ * dirmap.wdesc is not supported for these.
+ */
+ if (nor->info->flags & SST_WRITE) {
+ nor->dirmap.wdesc = NULL;
+ return 0;
+ }
+
/* get transfer protocols. */
op->cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->write_proto);
op->addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->write_proto);
op->dummy.buswidth = op->addr.buswidth;
op->data.buswidth = spi_nor_get_protocol_data_nbits(nor->write_proto);
- if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)
- op->addr.nbytes = 0;
-
nor->dirmap.wdesc = devm_spi_mem_dirmap_create(nor->dev, nor->spimem,
&info);
return PTR_ERR_OR_ZERO(nor->dirmap.wdesc);
--
2.20.1
According the datasheet [1] the WEL is automatically reset after the
Byte-Program instruction completion. So if we program the device with
byte-size set to 32 and starting from an odd address only the first and
the last byte is written. Fix this by (re-)anble the write support for
the first SPINOR_OP_AAI_WP sequence.
[1] http://ww1.microchip.com/downloads/en/DeviceDoc/20005044C.pdf;
"4.3.2 WRITE ENABLE LATCH (WEL)"
Signed-off-by: Marco Felsch <[email protected]>
---
drivers/mtd/spi-nor/sst.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/mtd/spi-nor/sst.c b/drivers/mtd/spi-nor/sst.c
index e0af6d25d573..644252e27a2a 100644
--- a/drivers/mtd/spi-nor/sst.c
+++ b/drivers/mtd/spi-nor/sst.c
@@ -79,6 +79,13 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
/* Write out most of the data here. */
for (; actual < len - 1; actual += 2) {
+ /* Enable write support if odd address was written before */
+ if (actual == 1) {
+ ret = spi_nor_write_enable(nor);
+ if (ret)
+ goto out;
+ }
+
nor->program_opcode = SPINOR_OP_AAI_WP;
/* write two bytes. */
--
2.20.1
On 9/11/20 8:17 PM, Marco Felsch wrote:
> The sst write support for devices using the special SST_WRITE routine
> is broken since commit commit df5c21002cf4 ("mtd: spi-nor: use spi-mem
> dirmap API") because the spi_nor_create_write_dirmap() function checks
> SPINOR_OP_AAI_WP and sst_write_second. These checks are not valid during
> probe. The check seems also to be broken since the "op->addr.nbytes = 0"
> causes the devm_spi_mem_dirmap_create() function to return
> PTR_ERR(-EINVAL) and the probe() function will fail.
>
> It seems that the commit only copy'n'pasted the existing logic. Use the
> correct SST_WRITE flag and return 0 to fix both issues.
>
> Fixes: df5c21002cf4 ("mtd: spi-nor: use spi-mem dirmap API")
> Signed-off-by: Marco Felsch <[email protected]>
> ---
> drivers/mtd/spi-nor/core.c | 12 +++++++++---
> 1 file changed, 9 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
> index 65eff4ce6ab1..31869ac245a8 100644
> --- a/drivers/mtd/spi-nor/core.c
> +++ b/drivers/mtd/spi-nor/core.c
> @@ -3289,15 +3289,21 @@ static int spi_nor_create_write_dirmap(struct spi_nor *nor)
> };
> struct spi_mem_op *op = &info.op_tmpl;
>
> + /*
> + * Most SST SPI-NOR's have a special write routine.which should so
s/SPI-NOR/SPI NOR.
> + * dirmap.wdesc is not supported for these.
Or How about more readable version:
"Most SST flashes have special sequence for writing data to the flash
and therefore cannot support writes through direct mapping APIs."
> + */
> + if (nor->info->flags & SST_WRITE) {
> + nor->dirmap.wdesc = NULL;
nor->dirmap.wdesc is known to be NULL at this point. So no need to set
to NULL again.
> + return 0;
> + }
> +
> /* get transfer protocols. */
> op->cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->write_proto);
> op->addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->write_proto);
> op->dummy.buswidth = op->addr.buswidth;
> op->data.buswidth = spi_nor_get_protocol_data_nbits(nor->write_proto);
>
> - if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)
> - op->addr.nbytes = 0;
> -
> nor->dirmap.wdesc = devm_spi_mem_dirmap_create(nor->dev, nor->spimem,
> &info);
> return PTR_ERR_OR_ZERO(nor->dirmap.wdesc);
>
On 9/14/20 3:00 PM, Vignesh Raghavendra wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
>
> On 9/11/20 8:17 PM, Marco Felsch wrote:
>> The sst write support for devices using the special SST_WRITE routine
>> is broken since commit commit df5c21002cf4 ("mtd: spi-nor: use spi-mem
>> dirmap API") because the spi_nor_create_write_dirmap() function checks
>> SPINOR_OP_AAI_WP and sst_write_second. These checks are not valid during
>> probe. The check seems also to be broken since the "op->addr.nbytes = 0"
>> causes the devm_spi_mem_dirmap_create() function to return
>> PTR_ERR(-EINVAL) and the probe() function will fail.
>>
>> It seems that the commit only copy'n'pasted the existing logic. Use the
>> correct SST_WRITE flag and return 0 to fix both issues.
>>
>> Fixes: df5c21002cf4 ("mtd: spi-nor: use spi-mem dirmap API")
>> Signed-off-by: Marco Felsch <[email protected]>
>> ---
>> drivers/mtd/spi-nor/core.c | 12 +++++++++---
>> 1 file changed, 9 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
>> index 65eff4ce6ab1..31869ac245a8 100644
>> --- a/drivers/mtd/spi-nor/core.c
>> +++ b/drivers/mtd/spi-nor/core.c
>> @@ -3289,15 +3289,21 @@ static int spi_nor_create_write_dirmap(struct spi_nor *nor)
>> };
>> struct spi_mem_op *op = &info.op_tmpl;
>>
>> + /*
>> + * Most SST SPI-NOR's have a special write routine.which should so
>
> s/SPI-NOR/SPI NOR.
>
>> + * dirmap.wdesc is not supported for these.
>
> Or How about more readable version:
>
> "Most SST flashes have special sequence for writing data to the flash
> and therefore cannot support writes through direct mapping APIs."
>
>> + */
>> + if (nor->info->flags & SST_WRITE) {
>> + nor->dirmap.wdesc = NULL;
>
> nor->dirmap.wdesc is known to be NULL at this point. So no need to set
> to NULL again.
>
>> + return 0;
>> + }
>> +
>> /* get transfer protocols. */
>> op->cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->write_proto);
>> op->addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->write_proto);
>> op->dummy.buswidth = op->addr.buswidth;
>> op->data.buswidth = spi_nor_get_protocol_data_nbits(nor->write_proto);
>>
>> - if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)
>> - op->addr.nbytes = 0;
>> -
>> nor->dirmap.wdesc = devm_spi_mem_dirmap_create(nor->dev, nor->spimem,
>> &info);
>> return PTR_ERR_OR_ZERO(nor->dirmap.wdesc);
>>
With Vignesh's comments addressed, one can add:
Reviewed-by: Tudor Ambarus <[email protected]>
Hello Marco,
On Fri, Sep 11, 2020 at 04:47:00PM +0200, Marco Felsch wrote:
> Hi,
>
> Patch 1-2: write path fixes
> The sst write path is completely broken since v5.7-rc1 and in rare cases
> since the support of the sst_write() function (49aac4aec53c).
>
> Patch 3: cleanup
>
> I've tested my patches with a small test app to ensure writes starting
> on an odd address and with dd to test even start addresses. My dut was
> an public available imx6q-sabrelite (rev.D).
> Other testers are welcome :)
>
> Regards,
> Marco
>
> Marco Felsch (3):
> mtd: spi-nor: sst: fix write support for SST_WRITE marked devices
> mtd: spi-nor: sst: add missing write_enable
> mtd: spi-nor: sst: move sst_write_second to local driver
>
> drivers/mtd/spi-nor/core.c | 15 +++++++++------
> drivers/mtd/spi-nor/sst.c | 15 +++++++++++----
> include/linux/mtd/spi-nor.h | 2 --
> 3 files changed, 20 insertions(+), 12 deletions(-)
>
> --
> 2.20.1
My colleague, Joerg, has validated that these patches fix an issue we
saw where performing multi-byte writes to a SST25VF016B would fail.
Tested-by: Joerg Hofrichter <[email protected]>
Thanks,
Michael