All of lore.kernel.org
 help / color / mirror / Atom feed
From: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH v5 1/2] SPI Flash: add support of sst26wf* flash ICs protection ops
Date: Thu, 12 Apr 2018 12:59:24 +0000	[thread overview]
Message-ID: <1523537963.24239.1.camel@synopsys.com> (raw)
In-Reply-To: <20180410114045.22121-2-Eugeniy.Paltsev@synopsys.com>

Hi Jagan,

Maybe you have any comments or remarks about this patch? And if you don't could you please apply it.
Thanks!

On Tue, 2018-04-10 at 14:40 +0300, Eugeniy Paltsev wrote:
> sst26wf flash series block protection implementation differs
> from other SST series, so add specific implementation
> flash_lock/flash_unlock/flash_is_locked functions for sst26wf
> flash ICs.
> 
> Signed-off-by: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
> ---
> Changes v4->v5:
>  * Return EACCES when flash is locked instead of custom define (SF_LOCKED)
>  * Add SST26_CTL_* prefix to sst27 lock ops enum.
>  * Move all sst26 code inside of existing CONFIG_SPI_FLASH_SST #ifdef.
> 
> Changes v3->v4:
>  * Make sst26_process_bpr() and sst26_lock_ctl() functions static.
> 
> Changes v2->v3:
>  * Move SST26 command defenition to sf_internal.h
>  * Merge sst26_set_bpr, sst26_clear_bpr and sst26_check_bpr functions
>    into single sst26_process_bpr function.
>  * Use SF_UNLOCKED/SF_LOCKED instead of magic numbers in
>    sst26_lock_ctl()
> 
> Changes v1->v2:
>  * Use generic defines from linux/sizes.h instead of custom ones.
> 
>  drivers/mtd/spi/sf_internal.h |  13 ++++
>  drivers/mtd/spi/spi_flash.c   | 168 ++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 181 insertions(+)
> 
> diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
> index 839cdbe1b0..614a293234 100644
> --- a/drivers/mtd/spi/sf_internal.h
> +++ b/drivers/mtd/spi/sf_internal.h
> @@ -87,6 +87,19 @@ enum spi_nor_option_flags {
>  
>  /* SST specific */
>  #ifdef CONFIG_SPI_FLASH_SST
> +#define SST26_CMD_READ_BPR		0x72
> +#define SST26_CMD_WRITE_BPR		0x42
> +
> +#define SST26_BPR_8K_NUM		4
> +#define SST26_MAX_BPR_REG_LEN		(18 + 1)
> +#define SST26_BOUND_REG_SIZE		((32 + SST26_BPR_8K_NUM * 8) * SZ_1K)
> +
> +enum lock_ctl {
> +	SST26_CTL_LOCK,
> +	SST26_CTL_UNLOCK,
> +	SST26_CTL_CHECK
> +};
> +
>  # define CMD_SST_BP		0x02    /* Byte Program */
>  # define CMD_SST_AAI_WP		0xAD	/* Auto Address Incr Word Program */
>  
> diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
> index 2e61685d3e..5e5bd5d533 100644
> --- a/drivers/mtd/spi/spi_flash.c
> +++ b/drivers/mtd/spi/spi_flash.c
> @@ -16,6 +16,7 @@
>  #include <spi.h>
>  #include <spi_flash.h>
>  #include <linux/log2.h>
> +#include <linux/sizes.h>
>  #include <dma.h>
>  
>  #include "sf_internal.h"
> @@ -541,6 +542,164 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
>  }
>  
>  #ifdef CONFIG_SPI_FLASH_SST
> +static bool sst26_process_bpr(u32 bpr_size, u8 *cmd, u32 bit, enum lock_ctl ctl)
> +{
> +	switch (ctl) {
> +		case SST26_CTL_LOCK:
> +			cmd[bpr_size - (bit / 8) - 1] |= BIT(bit % 8);
> +			break;
> +		case SST26_CTL_UNLOCK:
> +			cmd[bpr_size - (bit / 8) - 1] &= ~BIT(bit % 8);
> +			break;
> +		case SST26_CTL_CHECK:
> +			return !!(cmd[bpr_size - (bit / 8) - 1] & BIT(bit % 8));
> +	}
> +
> +	return false;
> +}
> +
> +/*
> + * sst26wf016/sst26wf032/sst26wf064 have next block protection:
> + * 4x   - 8  KByte blocks - read & write protection bits - upper addresses
> + * 1x   - 32 KByte blocks - write protection bits
> + * rest - 64 KByte blocks - write protection bits
> + * 1x   - 32 KByte blocks - write protection bits
> + * 4x   - 8  KByte blocks - read & write protection bits - lower addresses
> + *
> + * We'll support only per 64k lock/unlock so lower and upper 64 KByte region
> + * will be treated as single block.
> + */
> +
> +/*
> + * Lock, unlock or check lock status of the flash region of the flash (depending
> + * on the lock_ctl value)
> + */
> +static int sst26_lock_ctl(struct spi_flash *flash, u32 ofs, size_t len, enum lock_ctl ctl)
> +{
> +	u32 i, bpr_ptr, rptr_64k, lptr_64k, bpr_size;
> +	bool lower_64k = false, upper_64k = false;
> +	u8 cmd, bpr_buff[SST26_MAX_BPR_REG_LEN] = {};
> +	int ret;
> +
> +	/* Check length and offset for 64k alignment */
> +	if ((ofs & (SZ_64K - 1)) || (len & (SZ_64K - 1)))
> +		return -EINVAL;
> +
> +	if (ofs + len > flash->size)
> +		return -EINVAL;
> +
> +	/* SST26 family has only 16 Mbit, 32 Mbit and 64 Mbit IC */
> +	if (flash->size != SZ_2M &&
> +	    flash->size != SZ_4M &&
> +	    flash->size != SZ_8M)
> +		return -EINVAL;
> +
> +	bpr_size = 2 + (flash->size / SZ_64K / 8);
> +
> +	cmd = SST26_CMD_READ_BPR;
> +	ret = spi_flash_read_common(flash, &cmd, 1, bpr_buff, bpr_size);
> +	if (ret < 0) {
> +		printf("SF: fail to read block-protection register\n");
> +		return ret;
> +	}
> +
> +	rptr_64k = min_t(u32, ofs + len , flash->size - SST26_BOUND_REG_SIZE);
> +	lptr_64k = max_t(u32, ofs, SST26_BOUND_REG_SIZE);
> +
> +	upper_64k = ((ofs + len) > (flash->size - SST26_BOUND_REG_SIZE));
> +	lower_64k = (ofs < SST26_BOUND_REG_SIZE);
> +
> +	/* Lower bits in block-protection register are about 64k region */
> +	bpr_ptr = lptr_64k / SZ_64K - 1;
> +
> +	/* Process 64K blocks region */
> +	while (lptr_64k < rptr_64k) {
> +		if (sst26_process_bpr(bpr_size, bpr_buff, bpr_ptr, ctl))
> +			return EACCES;
> +
> +		bpr_ptr++;
> +		lptr_64k += SZ_64K;
> +	}
> +
> +	/* 32K and 8K region bits in BPR are after 64k region bits */
> +	bpr_ptr = (flash->size - 2 * SST26_BOUND_REG_SIZE) / SZ_64K;
> +
> +	/* Process lower 32K block region */
> +	if (lower_64k)
> +		if (sst26_process_bpr(bpr_size, bpr_buff, bpr_ptr, ctl))
> +			return EACCES;
> +
> +	bpr_ptr++;
> +
> +	/* Process upper 32K block region */
> +	if (upper_64k)
> +		if (sst26_process_bpr(bpr_size, bpr_buff, bpr_ptr, ctl))
> +			return EACCES;
> +
> +	bpr_ptr++;
> +
> +	/* Process lower 8K block regions */
> +	for (i = 0; i < SST26_BPR_8K_NUM; i++) {
> +		if (lower_64k)
> +			if (sst26_process_bpr(bpr_size, bpr_buff, bpr_ptr, ctl))
> +				return EACCES;
> +
> +		/* In 8K area BPR has both read and write protection bits */
> +		bpr_ptr += 2;
> +	}
> +
> +	/* Process upper 8K block regions */
> +	for (i = 0; i < SST26_BPR_8K_NUM; i++) {
> +		if (upper_64k)
> +			if (sst26_process_bpr(bpr_size, bpr_buff, bpr_ptr, ctl))
> +				return EACCES;
> +
> +		/* In 8K area BPR has both read and write protection bits */
> +		bpr_ptr += 2;
> +	}
> +
> +	/* If we check region status we don't need to write BPR back */
> +	if (ctl == SST26_CTL_CHECK)
> +		return 0;
> +
> +	cmd = SST26_CMD_WRITE_BPR;
> +	ret = spi_flash_write_common(flash, &cmd, 1, bpr_buff, bpr_size);
> +	if (ret < 0) {
> +		printf("SF: fail to write block-protection register\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int sst26_unlock(struct spi_flash *flash, u32 ofs, size_t len)
> +{
> +	return sst26_lock_ctl(flash, ofs, len, SST26_CTL_UNLOCK);
> +}
> +
> +static int sst26_lock(struct spi_flash *flash, u32 ofs, size_t len)
> +{
> +	return sst26_lock_ctl(flash, ofs, len, SST26_CTL_LOCK);
> +}
> +
> +/*
> + * Returns EACCES (positive value) if region is locked, 0 if region is unlocked,
> + * and negative on errors.
> + */
> +static int sst26_is_locked(struct spi_flash *flash, u32 ofs, size_t len)
> +{
> +	/*
> +	 * is_locked function is used for check before reading or erasing flash
> +	 * region, so offset and length might be not 64k allighned, so adjust
> +	 * them to be 64k allighned as sst26_lock_ctl works only with 64k
> +	 * allighned regions.
> +	 */
> +	ofs -= ofs & (SZ_64K - 1);
> +	len = len & (SZ_64K - 1) ? (len & ~(SZ_64K - 1)) + SZ_64K : len;
> +
> +	return sst26_lock_ctl(flash, ofs, len, SST26_CTL_CHECK);
> +}
> +
>  static int sst_byte_write(struct spi_flash *flash, u32 offset, const void *buf)
>  {
>  	struct spi_slave *spi = flash->spi;
> @@ -1033,6 +1192,15 @@ int spi_flash_scan(struct spi_flash *flash)
>  	}
>  #endif
>  
> +/* sst26wf series block protection implementation differs from other series */
> +#if defined(CONFIG_SPI_FLASH_SST)
> +	if (JEDEC_MFR(info) == SPI_FLASH_CFI_MFR_SST && info->id[1] == 0x26) {
> +		flash->flash_lock = sst26_lock;
> +		flash->flash_unlock = sst26_unlock;
> +		flash->flash_is_locked = sst26_is_locked;
> +	}
> +#endif
> +
>  	/* Compute the flash size */
>  	flash->shift = (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) ? 1 : 0;
>  	flash->page_size = info->page_size;
-- 
 Eugeniy Paltsev

  reply	other threads:[~2018-04-12 12:59 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-04-10 11:40 [U-Boot] [PATCH v5 0/2] SF: add support for sst26wf016, sst26wf032, sst26wf064 Eugeniy Paltsev
2018-04-10 11:40 ` [U-Boot] [PATCH v5 1/2] SPI Flash: add support of sst26wf* flash ICs protection ops Eugeniy Paltsev
2018-04-12 12:59   ` Eugeniy Paltsev [this message]
2018-04-16 13:52   ` Eugeniy Paltsev
2018-04-10 11:40 ` [U-Boot] [PATCH v5 2/2] SF: add support for sst26wf016, sst26wf032, sst26wf064 Eugeniy Paltsev
2018-04-19 11:25 ` [U-Boot] [PATCH v5 0/2] " Jagan Teki

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=1523537963.24239.1.camel@synopsys.com \
    --to=eugeniy.paltsev@synopsys.com \
    --cc=u-boot@lists.denx.de \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.