[PATCH v4 2/4] mtd: spi-nor: implement OTP support for Winbond and similar flashes

Michael Walle michael at walle.cc
Mon Mar 15 10:29:44 GMT 2021


Am 2021-03-15 09:20, schrieb Tudor.Ambarus at microchip.com:
> On 3/6/21 2:05 AM, Michael Walle wrote:
>> EXTERNAL EMAIL: Do not click links or open attachments unless you know 
>> the content is safe
>> 
>> Use the new OTP ops to implement OTP access on Winbond flashes. Most
>> Winbond flashes provides up to four different OTP regions ("Security
>> Registers").
>> 
>> Winbond devices use a special opcode to read and write to the OTP
>> regions, just like the RDSFDP opcode. In fact, it seems that the
>> (undocumented) first OTP area of the newer flashes is the actual SFDP
>> table.
>> 
>> On a side note, Winbond devices also allow erasing the OTP regions as
>> long as the area isn't locked down.
>> 
>> Signed-off-by: Michael Walle <michael at walle.cc>
>> ---
>>  drivers/mtd/spi-nor/core.c  |   2 +-
>>  drivers/mtd/spi-nor/core.h  |   6 ++
>>  drivers/mtd/spi-nor/otp.c   | 164 
>> ++++++++++++++++++++++++++++++++++++
>>  include/linux/mtd/spi-nor.h |   9 ++
>>  4 files changed, 180 insertions(+), 1 deletion(-)
>> 
>> diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
>> index 0c5c757fa95b..ef7df26896f1 100644
>> --- a/drivers/mtd/spi-nor/core.c
>> +++ b/drivers/mtd/spi-nor/core.c
>> @@ -1034,7 +1034,7 @@ static int 
>> spi_nor_write_16bit_sr_and_check(struct spi_nor *nor, u8 sr1)
>>   *
>>   * Return: 0 on success, -errno otherwise.
>>   */
>> -static int spi_nor_write_16bit_cr_and_check(struct spi_nor *nor, u8 
>> cr)
>> +int spi_nor_write_16bit_cr_and_check(struct spi_nor *nor, u8 cr)
>>  {
>>         int ret;
>>         u8 *sr_cr = nor->bouncebuf;
>> diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h
>> index ec8da1243846..dfbf6ba42b57 100644
>> --- a/drivers/mtd/spi-nor/core.h
>> +++ b/drivers/mtd/spi-nor/core.h
>> @@ -496,6 +496,7 @@ int spi_nor_read_sr(struct spi_nor *nor, u8 *sr);
>>  int spi_nor_read_cr(struct spi_nor *nor, u8 *cr);
>>  int spi_nor_write_sr(struct spi_nor *nor, const u8 *sr, size_t len);
>>  int spi_nor_write_sr_and_check(struct spi_nor *nor, u8 sr1);
>> +int spi_nor_write_16bit_cr_and_check(struct spi_nor *nor, u8 cr);
>> 
>>  int spi_nor_xread_sr(struct spi_nor *nor, u8 *sr);
>>  ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t 
>> len,
>> @@ -503,6 +504,11 @@ ssize_t spi_nor_read_data(struct spi_nor *nor, 
>> loff_t from, size_t len,
>>  ssize_t spi_nor_write_data(struct spi_nor *nor, loff_t to, size_t 
>> len,
>>                            const u8 *buf);
>> 
>> +int spi_nor_otp_read_secr(struct spi_nor *nor, loff_t addr, size_t 
>> len, u8 *buf);
>> +int spi_nor_otp_write_secr(struct spi_nor *nor, loff_t addr, size_t 
>> len, u8 *buf);
>> +int spi_nor_otp_lock_sr2(struct spi_nor *nor, unsigned int region);
>> +int spi_nor_otp_is_locked_sr2(struct spi_nor *nor, unsigned int 
>> region);
>> +
>>  int spi_nor_hwcaps_read2cmd(u32 hwcaps);
>>  u8 spi_nor_convert_3to4_read(u8 opcode);
>>  void spi_nor_set_read_settings(struct spi_nor_read_command *read,
>> diff --git a/drivers/mtd/spi-nor/otp.c b/drivers/mtd/spi-nor/otp.c
>> index 4e301fd5156b..4e8da9108c77 100644
>> --- a/drivers/mtd/spi-nor/otp.c
>> +++ b/drivers/mtd/spi-nor/otp.c
>> @@ -15,6 +15,170 @@
>>  #define spi_nor_otp_region_len(nor) ((nor)->params->otp.org->len)
>>  #define spi_nor_otp_n_regions(nor) 
>> ((nor)->params->otp.org->n_regions)
>> 
>> +/**
>> + * spi_nor_otp_read_secr() - read OTP data
>> + * @nor:       pointer to 'struct spi_nor'
>> + * @from:       offset to read from
>> + * @len:        number of bytes to read
>> + * @buf:        pointer to dst buffer
> 
> is buf DMA-able?

That's actually the same description as spi_nor_read_data().
Looks like the spimem will provide a DMA-able buffer on
the fly if necessary. I'm not sure about the the
spi_nor_controller_ops.

>> + *
>> + * Read OTP data from one region by using the SPINOR_OP_RSECR 
>> commands. This
>> + * method is used on GigaDevice and Winbond flashes.
>> + *
>> + * Return: number of bytes read successfully, -errno otherwise
>> + */
>> +int spi_nor_otp_read_secr(struct spi_nor *nor, loff_t addr, size_t 
>> len, u8 *buf)
>> +{
>> +       u8 addr_width, read_opcode, read_dummy;
>> +       struct spi_mem_dirmap_desc *rdesc;
>> +       enum spi_nor_protocol read_proto;
>> +       int ret;
>> +
>> +       read_opcode = nor->read_opcode;
>> +       addr_width = nor->addr_width;
>> +       read_dummy = nor->read_dummy;
>> +       read_proto = nor->read_proto;
>> +       rdesc = nor->dirmap.rdesc;
>> +
>> +       nor->read_opcode = SPINOR_OP_RSECR;
>> +       nor->addr_width = 3;
>> +       nor->read_dummy = 8;
>> +       nor->read_proto = SNOR_PROTO_1_1_1;
> 
> any winbond/gigadevice flashes with octal dtr support? Do they
> provide SEC Register opcodes for octal dtr?

AFAIK there are no winbond flashes with 8 bit I/O. There are
4bit/DTR modes, but not for the security registers.

I don't know what you had in mind. But I don't think it is
worth to read the 3x 256byte data faster than single bit I/O.

-michael



More information about the linux-mtd mailing list