linux-mtd.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
From: Michael Walle <michael@walle.cc>
To: linux-mtd@lists.infradead.org, linux-kernel@vger.kernel.org
Cc: Vignesh Raghavendra <vigneshr@ti.com>,
	Rahul Bedarkar <rahul.bedarkar@imgtec.com>,
	Tudor Ambarus <tudor.ambarus@microchip.com>,
	Richard Weinberger <richard@nod.at>,
	Rahul Bedarkar <rahulbedarkar89@gmail.com>,
	Miquel Raynal <miquel.raynal@bootlin.com>,
	Brian Norris <computersforpeace@gmail.com>
Subject: Re: [PATCH 2/2] mtd: spi-nor: implement OTP support for Winbond flashes
Date: Mon, 13 Jan 2020 09:39:12 +0100	[thread overview]
Message-ID: <8f337b25da830aff047d3b12e5534190@walle.cc> (raw)
In-Reply-To: <20200108233654.29027-3-michael@walle.cc>

Am 2020-01-09 00:36, schrieb Michael Walle:
> Use the new OTP ops to implement OTP access on Winbond flashes. Most
> Winbond flashes provides up to four different OTP areas ("Security
> Registers"). Newer flashes uses the first OTP area for SFDP data. Thus,
> this only handles the last three areas and leave the first untouched.
> 
> This was tested on a Winbond W25Q32JW. Please note, that there is a
> variant of the W25Q32JW which reuses the same JEDEC ID as the W25Q32FW
> which could support all four OTP areas. But because we cannot 
> distiguish
> between these two, the driver only uses three areas on the W25Q32FW.
> 
> Signed-off-by: Michael Walle <michael@walle.cc>
> ---
>  drivers/mtd/spi-nor/spi-nor.c | 132 ++++++++++++++++++++++++++++++++++
>  include/linux/mtd/spi-nor.h   |  14 ++++
>  2 files changed, 146 insertions(+)
> 
> diff --git a/drivers/mtd/spi-nor/spi-nor.c 
> b/drivers/mtd/spi-nor/spi-nor.c
> index 5eabaec70508..99d365cb63b1 100644
> --- a/drivers/mtd/spi-nor/spi-nor.c
> +++ b/drivers/mtd/spi-nor/spi-nor.c
> @@ -2641,17 +2641,20 @@ static const struct flash_info spi_nor_ids[] = 
> {
>  		"w25q16dw", INFO(0xef6015, 0, 64 * 1024,  32,
>  			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
>  			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
> +			OTP_INFO(256, 3, 0x1000, 0x1000)
>  	},
>  	{
>  		"w25q16jwim", INFO(0xef8015, 0, 64 * 1024,  32,
>  			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
>  			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
> +			OTP_INFO(256, 3, 0x1000, 0x1000)
>  	},
>  	{ "w25x32", INFO(0xef3016, 0, 64 * 1024,  64, SECT_4K) },
>  	{
>  		"w25q16jv-im/jm", INFO(0xef7015, 0, 64 * 1024,  32,
>  			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
>  			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
> +			OTP_INFO(256, 3, 0x1000, 0x1000)
>  	},
>  	{ "w25q20cl", INFO(0xef4012, 0, 64 * 1024,  4, SECT_4K) },
>  	{ "w25q20bw", INFO(0xef5012, 0, 64 * 1024,  4, SECT_4K) },
> @@ -2661,16 +2664,19 @@ static const struct flash_info spi_nor_ids[] = 
> {
>  		"w25q32dw", INFO(0xef6016, 0, 64 * 1024,  64,
>  			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
>  			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
> +			OTP_INFO(256, 3, 0x1000, 0x1000)
>  	},
>  	{
>  		"w25q32jv", INFO(0xef7016, 0, 64 * 1024,  64,
>  			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
>  			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
> +			OTP_INFO(256, 3, 0x1000, 0x1000)
>  	},
>  	{
>  		"w25q32jwim", INFO(0xef8016, 0, 64 * 1024,  64,
>  			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
>  			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
> +			OTP_INFO(256, 3, 0x1000, 0x1000)
>  	},
>  	{ "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) },
>  	{ "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
> @@ -2678,26 +2684,31 @@ static const struct flash_info spi_nor_ids[] = 
> {
>  		"w25q64dw", INFO(0xef6017, 0, 64 * 1024, 128,
>  			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
>  			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
> +			OTP_INFO(256, 3, 0x1000, 0x1000)
>  	},
>  	{
>  		"w25q64jwim", INFO(0xef8017, 0, 64 * 1024, 128,
>  			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
>  			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
> +			OTP_INFO(256, 3, 0x1000, 0x1000)
>  	},
>  	{
>  		"w25q128fw", INFO(0xef6018, 0, 64 * 1024, 256,
>  			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
>  			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
> +			OTP_INFO(256, 3, 0x1000, 0x1000)
>  	},
>  	{
>  		"w25q128jv", INFO(0xef7018, 0, 64 * 1024, 256,
>  			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
>  			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
> +			OTP_INFO(256, 3, 0x1000, 0x1000)
>  	},
>  	{
>  		"w25q128jwim", INFO(0xef8018, 0, 64 * 1024, 256,
>  			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
>  			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
> +			OTP_INFO(256, 3, 0x1000, 0x1000)
>  	},
>  	{ "w25q80", INFO(0xef5014, 0, 64 * 1024,  16, SECT_4K) },
>  	{ "w25q80bl", INFO(0xef4014, 0, 64 * 1024,  16, SECT_4K) },
> @@ -4645,6 +4656,125 @@ static int spi_nor_setup(struct spi_nor *nor,
>  	return nor->params.setup(nor, hwcaps);
>  }
> 
> +static int winbond_otp_read(struct spi_nor *nor, loff_t addr, uint64_t 
> len,
> +			    u8 *buf)
> +{
> +	u8 addr_width, read_opcode, read_dummy;
> +	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;
> +
> +	nor->read_opcode = SPINOR_OP_WB_RSECR;
> +	nor->addr_width = 3;
> +	nor->read_dummy = 8;
> +	nor->read_proto = SNOR_PROTO_1_1_1;
> +
> +	ret = spi_nor_read_raw(nor, addr, len, buf);
> +
> +	nor->read_opcode = read_opcode;
> +	nor->addr_width = addr_width;
> +	nor->read_dummy = read_dummy;
> +	nor->read_proto = read_proto;
> +
> +	return ret;
> +}
> +
> +static int winbond_otp_write(struct spi_nor *nor, loff_t addr, 
> uint64_t len,
> +			     u8 *buf)
> +{
> +	u8 addr_width, program_opcode;
> +	enum spi_nor_protocol write_proto;
> +	int ret;
> +
> +	program_opcode = nor->program_opcode;
> +	addr_width = nor->addr_width;
> +	write_proto = nor->write_proto;
> +
> +	nor->program_opcode = SPINOR_OP_WB_PSECR;
> +	nor->addr_width = 3;
> +	nor->write_proto = SNOR_PROTO_1_1_1;
> +
> +	/*
> +	 * We only support a write to one single page. For now all winbond
> +	 * flashes only have one page per OTP region.
> +	 */
> +	ret = spi_nor_write_enable(nor);
> +	if (ret)
> +		goto out;
> +
> +	ret = spi_nor_write_data(nor, addr, len, buf);
> +	if (ret < 0)
> +		goto out;
> +
> +	ret = spi_nor_wait_till_ready(nor);
> +
> +out:
> +	nor->program_opcode = program_opcode;
> +	nor->addr_width = addr_width;
> +	nor->write_proto = write_proto;
> +
> +	return ret;
> +}
> +
> +static int _winbond_otp_lock_bit(unsigned int region)
> +{
> +	static const int lock_bits[] = { SR2_WB_LB1, SR2_WB_LB2, SR2_WB_LB3 
> };
> +
> +	if (region >= ARRAY_SIZE(lock_bits))
> +		return -EINVAL;
> +
> +	return lock_bits[region];
> +}
> +
> +static int winbond_otp_lock(struct spi_nor *nor, unsigned int region)
> +{
> +	int lock_bit;
> +	u8 sr2;

will be "u8 *sr2 = nor->bouncebuf"; in the next version

> +	int ret;
> +
> +	lock_bit = _winbond_otp_lock_bit(region);
> +	if (lock_bit < 0)
> +		return lock_bit;
> +
> +	ret = spi_nor_read_cr(nor, &sr2);
> +	if (ret)
> +		return ret;
> +
> +	/* check if its already locked */
> +	if (sr2 & lock_bit)
> +		return 0;
> +
> +	return spi_nor_write_16bit_cr_and_check(nor, sr2 | lock_bit);
> +}
> +
> +static int winbond_otp_is_locked(struct spi_nor *nor, unsigned int 
> region)
> +{
> +	int lock_bit;
> +	u8 sr2;

likewise

> +	int ret;
> +
> +	lock_bit = _winbond_otp_lock_bit(region);
> +	if (lock_bit < 0)
> +		return lock_bit;
> +
> +	ret = spi_nor_read_cr(nor, &sr2);
> +	if (ret)
> +		return ret;
> +
> +	return (sr2 & lock_bit);
> +}
> +
> +static const struct spi_nor_otp_ops winbond_otp_ops = {
> +	.read = winbond_otp_read,
> +	.write = winbond_otp_write,
> +	.lock = winbond_otp_lock,
> +	.is_locked = winbond_otp_is_locked,
> +};
> +
>  static void atmel_set_default_init(struct spi_nor *nor)
>  {
>  	nor->flags |= SNOR_F_HAS_LOCK;
> @@ -4681,6 +4811,8 @@ static void st_micron_set_default_init(struct
> spi_nor *nor)
>  static void winbond_set_default_init(struct spi_nor *nor)
>  {
>  	nor->params.set_4byte = winbond_set_4byte;
> +	if (nor->params.otp_info.n_otps)
> +		nor->params.otp_ops = &winbond_otp_ops;
>  }
> 
>  /**
> diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
> index e427dcd72f79..cc847ed06ef3 100644
> --- a/include/linux/mtd/spi-nor.h
> +++ b/include/linux/mtd/spi-nor.h
> @@ -121,6 +121,20 @@
>  #define SPINOR_OP_RD_EVCR      0x65    /* Read EVCR register */
>  #define SPINOR_OP_WD_EVCR      0x61    /* Write EVCR register */
> 
> +/* Used for Winbond flashes only. */
> +#define SPINOR_OP_WB_ESECR	0x44	/* Erase Security registers */
> +#define SPINOR_OP_WB_PSECR	0x42	/* Program Security registers */
> +#define SPINOR_OP_WB_RSECR	0x48	/* Read Security registers */
> +
> +/*
> + * Warning: LB0 (and thus the security register 0) is used for the 
> SFDP
> + * data on all newer flashes.
> + */
> +#define SR2_WB_LB0		BIT(2)	/* Security Register Lock Bit 0 */
> +#define SR2_WB_LB1		BIT(3)	/* Security Register Lock Bit 1 */
> +#define SR2_WB_LB2		BIT(4)	/* Security Register Lock Bit 2 */
> +#define SR2_WB_LB3		BIT(5)	/* Security Register Lock Bit 3 */
> +
>  /* Status Register bits. */
>  #define SR_WIP			BIT(0)	/* Write in progress */
>  #define SR_WEL			BIT(1)	/* Write enable latch */

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

      reply	other threads:[~2020-01-13  8:39 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-01-08 23:36 [PATCH 0/2] mtd: spi-nor: OTP support Michael Walle
2020-01-08 23:36 ` [PATCH 1/2] mtd: spi-nor: add " Michael Walle
2020-01-13  8:37   ` Michael Walle
2020-01-08 23:36 ` [PATCH 2/2] mtd: spi-nor: implement OTP support for Winbond flashes Michael Walle
2020-01-13  8:39   ` Michael Walle [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=8f337b25da830aff047d3b12e5534190@walle.cc \
    --to=michael@walle.cc \
    --cc=computersforpeace@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mtd@lists.infradead.org \
    --cc=miquel.raynal@bootlin.com \
    --cc=rahul.bedarkar@imgtec.com \
    --cc=rahulbedarkar89@gmail.com \
    --cc=richard@nod.at \
    --cc=tudor.ambarus@microchip.com \
    --cc=vigneshr@ti.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).