All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [U-BOOT PATCH 0/3] add support for spi-nor device on HiFive Unleashed board
@ 2019-08-13 16:59 Sagar Shrikant Kadam
  2019-08-13 16:59 ` [U-Boot] [U-BOOT PATCH 1/3] spi: nor: add spi-nor-fixup handlers for nor devices Sagar Shrikant Kadam
                   ` (3 more replies)
  0 siblings, 4 replies; 10+ messages in thread
From: Sagar Shrikant Kadam @ 2019-08-13 16:59 UTC (permalink / raw)
  To: u-boot

This patch series adds support for 32MiB SPI-NOR flash (is25wp256 from
ISSI). Many thanks to Bhargav Shah <bhargavshah1988@gmail.com> for 
porting the spi-nor patches from linux to U-boot in order to support
this device.
Ref: linux patches which are under review
https://lkml.org/lkml/2019/7/2/859

Linux has an option of registering post-bfpt fixups in order to over-ride
the incorrect configuration of flash devices due to wrong SFDP entries read
from the flash device during nor scan phase. The 1st patch introduces this
support to register post bfpt fixup hook similar to that done in linux.

The second patch in the series enables support for the flash device in
single I/O mode. A post bfpt fixup is registered because the flash device
gets BFPT_DWORD1_ADDRESS_BYTES_3_ONLY from BFPT table for address width,
whereas the flash can support 4 byte address width.
The SPI_NOR_HAS_BP3 bit indicates that the flash protection block has BP0
to BP3 bits.

Lock/Unlock mechanism:
The implementation is based on stm_lock/unlock scheme and is validated for
different number of blocks passed to sf command. Unlock scheme unilateraly
clears all the protection bits of all blocks in the status register.

The series is based on the master branch of[1]
[1] https://gitlab.denx.de/u-boot/custodians/u-boot-riscv

and is available in dev/sagark/hifive-spi-nor_v2 branch of[2]
[2] https://github.com/sagsifive/u-boot.

Flash operations like erase/read/write lock/unlock are verified and
data integrity is checked using sf commands as follows:

=> sf write 0x80600000 0x0 0x2000000
device 0 whole chip
SF: 33554432 bytes @ 0x0 Written: OK
=> sf read 0x82700000 0x0 0x2000000
device 0 whole chip
SF: 33554432 bytes @ 0x0 Read: OK
=> cmp.b 0x80600000 0x82700000 0x2000000
Total of 33554432 byte(s) were the same

=> sf protect lock 0x1000000 0x1000000
=> mw 0x80600000 0x12345678 0x2000000
=> sf write 0x80600000 0x0 0x2000000
   Reset the board to flush out data from memory
=> sf probe
=> sf read 0x80600000 0x0 0x2000000
   In memory dump after sf read from address 0x80600000 we can see that
   upper 16MiB flash section is protected.


Sagar Shrikant Kadam (3):
  spi: nor: add spi-nor-fixup handlers for nor devices
  spi: nor: add support for is25wp256
  spi: riscv: use single bit mode for spi transfers

 board/sifive/fu540/Kconfig     |   5 +
 drivers/mtd/spi/sf_internal.h  |  23 +++
 drivers/mtd/spi/spi-nor-core.c | 373 +++++++++++++++++++++++++++++++++++------
 drivers/mtd/spi/spi-nor-ids.c  |   5 +
 drivers/spi/spi-sifive.c       |   7 +-
 include/linux/mtd/spi-nor.h    |   8 +
 6 files changed, 363 insertions(+), 58 deletions(-)

-- 
2.7.4

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [U-Boot] [U-BOOT PATCH 1/3] spi: nor: add spi-nor-fixup handlers for nor devices
  2019-08-13 16:59 [U-Boot] [U-BOOT PATCH 0/3] add support for spi-nor device on HiFive Unleashed board Sagar Shrikant Kadam
@ 2019-08-13 16:59 ` Sagar Shrikant Kadam
  2019-08-26 12:51   ` Bin Meng
  2019-08-13 16:59 ` [U-Boot] [U-BOOT PATCH 2/3] spi: nor: add support for is25wp256 Sagar Shrikant Kadam
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 10+ messages in thread
From: Sagar Shrikant Kadam @ 2019-08-13 16:59 UTC (permalink / raw)
  To: u-boot

Add support for spi_nor_fixups similar to that done in linux.
Flash vendor specific fixups can be registered in spi_nor_ids.
and will be called after BFPT parsing to fix any wrong parameter
read from SFDP.

Signed-off-by: Sagar Shrikant Kadam <sagar.kadam@sifive.com>
---
 drivers/mtd/spi/sf_internal.h  |  5 +++++
 drivers/mtd/spi/spi-nor-core.c | 33 +++++++++++++++++++++++++++++++--
 2 files changed, 36 insertions(+), 2 deletions(-)

diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index a6bf734..c5e68d8 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -65,6 +65,11 @@ struct flash_info {
 #define NO_CHIP_ERASE		BIT(12) /* Chip does not support chip erase */
 #define SPI_NOR_SKIP_SFDP	BIT(13)	/* Skip parsing of SFDP tables */
 #define USE_CLSR		BIT(14)	/* use CLSR command */
+
+#ifdef CONFIG_SPI_FLASH_SFDP_SUPPORT
+	/* Part specific fixup hooks */
+	const struct spi_nor_fixups	*fixups;
+#endif
 };
 
 extern const struct flash_info spi_nor_ids[];
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 1acff74..4306d19 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -1623,6 +1623,33 @@ static const struct sfdp_bfpt_erase sfdp_bfpt_erases[] = {
 static int spi_nor_hwcaps_read2cmd(u32 hwcaps);
 
 /**
+ * struct spi_nor_fixups - SPI NOR fixup hooks
+ * @post_bfpt: called after the BFPT table has been parsed
+ *
+ * Those hooks can be used to tweak the SPI NOR configuration when the SFDP
+ * table is broken or not available.
+ */
+struct spi_nor_fixups {
+	int (*post_bfpt)(struct spi_nor *nor,
+			 const struct sfdp_parameter_header *bfpt_header,
+			 const struct sfdp_bfpt *bfpt,
+			 struct spi_nor_flash_parameter *params);
+};
+
+static int
+spi_nor_post_bfpt_fixups(struct spi_nor *nor,
+			 const struct sfdp_parameter_header *bfpt_header,
+			 const struct sfdp_bfpt *bfpt,
+			 struct spi_nor_flash_parameter *params)
+{
+	if (nor->info->fixups && nor->info->fixups->post_bfpt)
+		return nor->info->fixups->post_bfpt(nor, bfpt_header, bfpt,
+				params);
+
+	return 0;
+}
+
+/**
  * spi_nor_parse_bfpt() - read and parse the Basic Flash Parameter Table.
  * @nor:		pointer to a 'struct spi_nor'
  * @bfpt_header:	pointer to the 'struct sfdp_parameter_header' describing
@@ -1760,7 +1787,8 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
 
 	/* Stop here if not JESD216 rev A or later. */
 	if (bfpt_header->length < BFPT_DWORD_MAX)
-		return 0;
+		return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt,
+				params);
 
 	/* Page size: this field specifies 'N' so the page size = 2^N bytes. */
 	params->page_size = bfpt.dwords[BFPT_DWORD(11)];
@@ -1793,7 +1821,8 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
 		return -EINVAL;
 	}
 
-	return 0;
+	return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt,
+			params);
 }
 
 /**
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [U-Boot] [U-BOOT PATCH 2/3] spi: nor: add support for is25wp256
  2019-08-13 16:59 [U-Boot] [U-BOOT PATCH 0/3] add support for spi-nor device on HiFive Unleashed board Sagar Shrikant Kadam
  2019-08-13 16:59 ` [U-Boot] [U-BOOT PATCH 1/3] spi: nor: add spi-nor-fixup handlers for nor devices Sagar Shrikant Kadam
@ 2019-08-13 16:59 ` Sagar Shrikant Kadam
  2019-08-26 10:02   ` Bin Meng
  2019-08-13 16:59 ` [U-Boot] [U-BOOT PATCH 3/3] spi: riscv: use single bit mode for spi transfers Sagar Shrikant Kadam
  2019-08-27 10:48 ` [U-Boot] [U-BOOT PATCH 0/3] add support for spi-nor device on HiFive Unleashed board Bin Meng
  3 siblings, 1 reply; 10+ messages in thread
From: Sagar Shrikant Kadam @ 2019-08-13 16:59 UTC (permalink / raw)
  To: u-boot

Enable support for spi nor device(is25wp256) mounted on
HiFive Unleashed Rev A00 board.

Thanks to Bhargav Shah for porting this patch which is based on
linux patches https://lkml.org/lkml/2019/7/2/859.

Additionally, set the proper number of sectors in the device id table,
so that the sf probe shows the correct size of the flash device.
Added SPI_NOR_HAS_BP3 bit to indicate that this nor device has BP3 bit
present for the lock/unlock mechanism.
Registered a post bfpt fixup handler for this device as the address width
advertised by the flash during nor scan is not correct.

This flash is tested for plain SPI mode although it also supports QUAD
I/O mode.

Signed-off-by: Bhargav Shah <bhargavshah1988@gmail.com>
Signed-off-by: Sagar Shrikant Kadam <sagar.kadam@sifive.com>
---
 board/sifive/fu540/Kconfig     |   5 +
 drivers/mtd/spi/sf_internal.h  |  18 +++
 drivers/mtd/spi/spi-nor-core.c | 340 +++++++++++++++++++++++++++++++++++------
 drivers/mtd/spi/spi-nor-ids.c  |   5 +
 include/linux/mtd/spi-nor.h    |   8 +
 5 files changed, 326 insertions(+), 50 deletions(-)

diff --git a/board/sifive/fu540/Kconfig b/board/sifive/fu540/Kconfig
index 5d65080..f9d5ec1 100644
--- a/board/sifive/fu540/Kconfig
+++ b/board/sifive/fu540/Kconfig
@@ -40,6 +40,11 @@ config BOARD_SPECIFIC_OPTIONS # dummy
 	imply SIFIVE_SERIAL
 	imply SPI
 	imply SPI_SIFIVE
+	imply SPI_FLASH
+	imply SPI_FLASH_ISSI
+	imply SPI_FLASH_SFDP_SUPPORT
+	imply CMD_MTD
+	imply CMD_SF
 	imply MMC
 	imply MMC_SPI
 	imply MMC_BROKEN_CD
diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index c5e68d8..6523107 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -65,6 +65,13 @@ struct flash_info {
 #define NO_CHIP_ERASE		BIT(12) /* Chip does not support chip erase */
 #define SPI_NOR_SKIP_SFDP	BIT(13)	/* Skip parsing of SFDP tables */
 #define USE_CLSR		BIT(14)	/* use CLSR command */
+#define SPI_NOR_HAS_BP3		BIT(15)	/*
+					 * Flash SR has block protect bits
+					 * for lock/unlock purpose, few support
+					 * BP0-BP2 while few support BP0-BP3.
+					 * This flag identifies devices that
+					 * support BP3 bit.
+					 */
 
 #ifdef CONFIG_SPI_FLASH_SFDP_SUPPORT
 	/* Part specific fixup hooks */
@@ -72,6 +79,17 @@ struct flash_info {
 #endif
 };
 
+#ifdef CONFIG_SPI_FLASH_SFDP_SUPPORT
+/*
+ * Declare manufacturer specific fixup handlers that
+ * can be registered as fixup's in flash info table
+ * so as to update any wrong/broken SFDP parameter.
+ */
+#ifdef CONFIG_SPI_FLASH_ISSI
+extern struct spi_nor_fixups is25wp256_fixups;
+#endif
+#endif
+
 extern const struct flash_info spi_nor_ids[];
 
 #define JEDEC_MFR(info)	((info)->id[0])
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 4306d19..46d278d 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -582,7 +582,8 @@ erase_err:
 	return ret;
 }
 
-#if defined(CONFIG_SPI_FLASH_STMICRO) || defined(CONFIG_SPI_FLASH_SST)
+#if defined(CONFIG_SPI_FLASH_STMICRO) || defined(CONFIG_SPI_FLASH_SST) || \
+	defined(CONFIG_SPI_FLASH_ISSI)
 /* Write status register and ensure bits in mask match written values */
 static int write_sr_and_check(struct spi_nor *nor, u8 status_new, u8 mask)
 {
@@ -604,14 +605,45 @@ static int write_sr_and_check(struct spi_nor *nor, u8 status_new, u8 mask)
 	return ((ret & mask) != (status_new & mask)) ? -EIO : 0;
 }
 
+/**
+ * spi_nor_read_fr() -read function register
+ * @nor: pointer to a 'struct spi_nor'.
+ *
+ * ISSI devices have top/bottom area protection bits selection into function
+ * reg. The bits in FR are OTP. So once it's written, it cannot be changed.
+ *
+ * Return: Value in function register or negative if error.
+ */
+static int spi_nor_read_fr(struct spi_nor *nor)
+{
+	int ret;
+	u8 val;
+
+	ret = nor->read_reg(nor, SPINOR_OP_RDFR, &val, 1);
+	if (ret < 0) {
+		pr_err("error %d reading FR\n", ret);
+		return ret;
+	}
+
+	return val;
+}
+
 static void stm_get_locked_range(struct spi_nor *nor, u8 sr, loff_t *ofs,
 				 uint64_t *len)
 {
 	struct mtd_info *mtd = &nor->mtd;
-	u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
-	int shift = ffs(mask) - 1;
+	u8 mask = 0;
+	u8 fr = 0;
+	int shift = 0;
 	int pow;
 
+	if (nor->flags & SNOR_F_HAS_BP3)
+		mask = SR_BP3 | SR_BP2 | SR_BP1 | SR_BP0;
+	else
+		mask = SR_BP2 | SR_BP1 | SR_BP0;
+
+	shift = ffs(mask) - 1;
+
 	if (!(sr & mask)) {
 		/* No protection */
 		*ofs = 0;
@@ -619,10 +651,20 @@ static void stm_get_locked_range(struct spi_nor *nor, u8 sr, loff_t *ofs,
 	} else {
 		pow = ((sr & mask) ^ mask) >> shift;
 		*len = mtd->size >> pow;
-		if (nor->flags & SNOR_F_HAS_SR_TB && sr & SR_TB)
-			*ofs = 0;
-		else
-			*ofs = mtd->size - *len;
+
+		/* ISSI device's have top/bottom select bit in func reg */
+		if (JEDEC_MFR(nor->info) == SNOR_MFR_ISSI) {
+			fr = spi_nor_read_fr(nor);
+			if (nor->flags & SNOR_F_HAS_SR_TB && fr & FR_TB)
+				*ofs = 0;
+			else
+				*ofs = mtd->size - *len;
+		} else {
+			if (nor->flags & SNOR_F_HAS_SR_TB && sr & SR_TB)
+				*ofs = 0;
+			else
+				*ofs = mtd->size - *len;
+		}
 	}
 }
 
@@ -649,18 +691,109 @@ static int stm_check_lock_status_sr(struct spi_nor *nor, loff_t ofs, u64 len,
 		return (ofs >= lock_offs + lock_len) || (ofs + len <= lock_offs);
 }
 
-static int stm_is_locked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
-			    u8 sr)
+/*
+ * check if memory region is locked
+ *
+ * Returns false if region is locked 0 otherwise.
+ */
+static int spi_nor_is_locked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
+				u8 sr)
 {
 	return stm_check_lock_status_sr(nor, ofs, len, sr, true);
 }
 
-static int stm_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
-			      u8 sr)
+/*
+ * check if memory region is unlocked
+ *
+ * Returns false if region is locked 0 otherwise.
+ */
+static int spi_nor_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
+				  u8 sr)
 {
 	return stm_check_lock_status_sr(nor, ofs, len, sr, false);
 }
 
+/**
+ * spi_nor_select_zone() - Select top area or bottom area to lock/unlock
+ * @nor: pointer to a 'struct spi_nor'.
+ * @ofs: offset from which to lock memory.
+ * @len: number of bytes to unlock.
+ * @sr: status register
+ * @tb: pointer to top/bottom bool used in caller function
+ * @op: zone selection is for lock/unlock operation. 1: lock 0:unlock
+ *
+ * Select the top area / bottom area pattern to protect memory blocks.
+ *
+ * Returns negative on errors, 0 on success.
+ */
+static int spi_nor_select_zone(struct spi_nor *nor, loff_t ofs, uint64_t len,
+			       u8 sr, bool *tb, bool op)
+{
+	int retval;
+	bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB;
+
+	if (op) {
+		/* Select for lock zone operation */
+
+		/*
+		 * If nothing in our range is unlocked, we don't need
+		 * to do anything.
+		 */
+		if (spi_nor_is_locked_sr(nor, ofs, len, sr))
+			return 0;
+
+		/*
+		 * If anything below us is unlocked, we can't use 'bottom'
+		 * protection.
+		 */
+		if (!spi_nor_is_locked_sr(nor, 0, ofs, sr))
+			can_be_bottom = false;
+
+		/*
+		 * If anything above us is unlocked, we can't use 'top'
+		 * protection.
+		 */
+		if (!spi_nor_is_locked_sr(nor, ofs + len,
+					  nor->mtd.size - (ofs + len), sr))
+			can_be_top = false;
+	} else {
+		/* Select unlock zone */
+
+		/*
+		 * If nothing in our range is locked, we don't need to
+		 * do anything.
+		 */
+		if (spi_nor_is_unlocked_sr(nor, ofs, len, sr))
+			return 0;
+
+		/*
+		 * If anything below us is locked, we can't use 'top'
+		 * protection
+		 */
+		if (!spi_nor_is_unlocked_sr(nor, 0, ofs, sr))
+			can_be_top = false;
+
+		/*
+		 * If anything above us is locked, we can't use 'bottom'
+		 * protection
+		 */
+		if (!spi_nor_is_unlocked_sr(nor, ofs + len,
+					    nor->mtd.size - (ofs + len), sr))
+			can_be_bottom = false;
+	}
+
+	if (!can_be_bottom && !can_be_top) {
+		retval = -EINVAL;
+	} else {
+		/* Prefer top, if both are valid */
+		*tb = can_be_top;
+		retval = 1;
+	}
+
+	return retval;
+}
+
+#if !defined(CONFIG_SPI_FLASH_ISSI)
 /*
  * Lock a region of the flash. Compatible with ST Micro and similar flash.
  * Supports the block protection bits BP{0,1,2} in the status register
@@ -698,33 +831,19 @@ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
 	struct mtd_info *mtd = &nor->mtd;
 	int status_old, status_new;
 	u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
-	u8 shift = ffs(mask) - 1, pow, val;
+	u8 shift = ffs(mask) - 1, pow, val, ret;
 	loff_t lock_len;
-	bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB;
 	bool use_top;
 
 	status_old = read_sr(nor);
 	if (status_old < 0)
 		return status_old;
 
-	/* If nothing in our range is unlocked, we don't need to do anything */
-	if (stm_is_locked_sr(nor, ofs, len, status_old))
+	ret = spi_nor_select_zone(nor, ofs, len, status_old, &use_top, 1);
+	if (!ret)
 		return 0;
-
-	/* If anything below us is unlocked, we can't use 'bottom' protection */
-	if (!stm_is_locked_sr(nor, 0, ofs, status_old))
-		can_be_bottom = false;
-
-	/* If anything above us is unlocked, we can't use 'top' protection */
-	if (!stm_is_locked_sr(nor, ofs + len, mtd->size - (ofs + len),
-			      status_old))
-		can_be_top = false;
-
-	if (!can_be_bottom && !can_be_top)
-		return -EINVAL;
-
-	/* Prefer top, if both are valid */
-	use_top = can_be_top;
+	else if (ret < 0)
+		return ret;
 
 	/* lock_len: length of region that should end up locked */
 	if (use_top)
@@ -778,33 +897,19 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
 	struct mtd_info *mtd = &nor->mtd;
 	int status_old, status_new;
 	u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
-	u8 shift = ffs(mask) - 1, pow, val;
+	u8 shift = ffs(mask) - 1, pow, val, ret;
 	loff_t lock_len;
-	bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB;
 	bool use_top;
 
 	status_old = read_sr(nor);
 	if (status_old < 0)
 		return status_old;
 
-	/* If nothing in our range is locked, we don't need to do anything */
-	if (stm_is_unlocked_sr(nor, ofs, len, status_old))
+	ret = spi_nor_select_zone(nor, ofs, len, status_old, &use_top, 0);
+	if (!ret)
 		return 0;
-
-	/* If anything below us is locked, we can't use 'top' protection */
-	if (!stm_is_unlocked_sr(nor, 0, ofs, status_old))
-		can_be_top = false;
-
-	/* If anything above us is locked, we can't use 'bottom' protection */
-	if (!stm_is_unlocked_sr(nor, ofs + len, mtd->size - (ofs + len),
-				status_old))
-		can_be_bottom = false;
-
-	if (!can_be_bottom && !can_be_top)
-		return -EINVAL;
-
-	/* Prefer top, if both are valid */
-	use_top = can_be_top;
+	else if (ret < 0)
+		return ret;
 
 	/* lock_len: length of region that should remain locked */
 	if (use_top)
@@ -866,8 +971,9 @@ static int stm_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len)
 	if (status < 0)
 		return status;
 
-	return stm_is_locked_sr(nor, ofs, len, status);
+	return spi_nor_is_locked_sr(nor, ofs, len, status);
 }
+#endif /* !CONFIG_SPI_FLASH_ISSI*/
 #endif /* CONFIG_SPI_FLASH_STMICRO */
 
 static const struct flash_info *spi_nor_read_id(struct spi_nor *nor)
@@ -1142,6 +1248,105 @@ static int macronix_quad_enable(struct spi_nor *nor)
 }
 #endif
 
+/**
+ * issi_lock() - set BP[0123] write-protection.
+ * @nor: pointer to a 'struct spi_nor'.
+ * @ofs: offset from which to lock memory.
+ * @len: number of bytes to unlock.
+ *
+ * Lock a region of the flash.Implementation is based on stm_lock
+ * Supports the block protection bits BP{0,1,2,3} in status register
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int issi_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
+{
+	int status_old, status_new, blk_prot;
+	u8 mask = SR_BP3 | SR_BP2 | SR_BP1 | SR_BP0;
+	u8 shift = ffs(mask) - 1;
+	u8 pow, ret;
+	bool use_top = false;
+	loff_t lock_len;
+
+	status_old = read_sr(nor);
+
+	/* if status reg is Write protected don't update bit protection */
+	if (status_old & SR_SRWD) {
+		dev_err(nor->dev,
+			"SR is write protected, can't update BP bits...\n");
+		return -EINVAL;
+	}
+
+	ret = spi_nor_select_zone(nor, ofs, len, status_old, &use_top, 1);
+	if (!ret)
+		/* Older protected blocks include the new requested block's */
+		return 0;
+	else if (ret < 0)
+		return ret;
+
+	/* lock_len: length of region that should end up locked */
+	if (use_top)
+		lock_len = nor->mtd.size - ofs;
+	else
+		lock_len = ofs + len;
+
+	pow = order_base_2(lock_len);
+	blk_prot = mask & (((pow + 1) & 0xf) << shift);
+	if (lock_len <= 0) {
+		dev_err(nor->dev, "invalid Length to protect");
+		return -EINVAL;
+	}
+
+	status_new = status_old | blk_prot;
+	if (status_old == status_new)
+		return 0;
+
+	return write_sr_and_check(nor, status_new, mask);
+}
+
+/**
+ * issi_unlock() - clear BP[0123] write-protection.
+ * @nor: pointer to a 'struct spi_nor'.
+ * @ofs: offset from which to unlock memory.
+ * @len: number of bytes to unlock.
+ *
+ * Bits [2345] of the Status Register are BP[0123].
+ * ISSI chips use a different block protection scheme than other chips.
+ * Just disable the write-protect unilaterally.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int issi_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
+{
+	int ret, val;
+	u8 mask = SR_BP0 | SR_BP1 | SR_BP2 | SR_BP3;
+
+	val = read_sr(nor);
+	if (val < 0)
+		return val;
+	if (!(val & mask))
+		return 0;
+
+	write_enable(nor);
+
+	write_sr(nor, val & ~mask);
+
+	ret = spi_nor_wait_till_ready(nor);
+	if (ret)
+		return ret;
+
+	ret = read_sr(nor);
+	if (!(ret & mask)) {
+		dev_info(nor->dev, "ISSI block protect bits cleared SR: 0x%x\n",
+			 ret);
+		ret = 0;
+	} else {
+		dev_err(nor->dev, "ISSI block protect bits not cleared\n");
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
 #if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND)
 /*
  * Write status Register and configuration register with 2 bytes
@@ -1649,6 +1854,28 @@ spi_nor_post_bfpt_fixups(struct spi_nor *nor,
 	return 0;
 }
 
+static int is25wp256_post_bfpt_fixups(struct spi_nor *nor,
+				      const struct sfdp_parameter_header
+						*bfpt_header,
+				      const struct sfdp_bfpt *bfpt,
+				      struct spi_nor_flash_parameter *params)
+
+{
+	/* IS25WP256 supports 4B opcodes, but the BFPT advertises a
+	 * BFPT_DWORD1_ADDRESS_BYTES_3_ONLY address width.
+	 * Overwrite the address width advertised by the BFPT.
+	 */
+	if ((bfpt->dwords[BFPT_DWORD(1)] & BFPT_DWORD1_ADDRESS_BYTES_MASK) ==
+			BFPT_DWORD1_ADDRESS_BYTES_3_ONLY)
+		nor->addr_width = 4;
+
+	return 0;
+}
+
+struct spi_nor_fixups is25wp256_fixups = {
+	.post_bfpt = is25wp256_post_bfpt_fixups,
+};
+
 /**
  * spi_nor_parse_bfpt() - read and parse the Basic Flash Parameter Table.
  * @nor:		pointer to a 'struct spi_nor'
@@ -2318,6 +2545,16 @@ int spi_nor_scan(struct spi_nor *nor)
 	mtd->_erase = spi_nor_erase;
 	mtd->_read = spi_nor_read;
 
+#if defined(CONFIG_SPI_FLASH_ISSI)
+	/* NOR protection support for ISSI chips */
+	if (JEDEC_MFR(info) == SNOR_MFR_ISSI &&
+	    info->flags & SPI_NOR_HAS_LOCK &&
+	    info->flags & SPI_NOR_HAS_BP3) {
+		nor->flash_lock = issi_lock;
+		nor->flash_unlock = issi_unlock;
+	}
+#endif
+
 #if defined(CONFIG_SPI_FLASH_STMICRO) || defined(CONFIG_SPI_FLASH_SST)
 	/* NOR protection support for STmicro/Micron chips and similar */
 	if (JEDEC_MFR(info) == SNOR_MFR_ST ||
@@ -2347,6 +2584,8 @@ int spi_nor_scan(struct spi_nor *nor)
 	if (info->flags & USE_CLSR)
 		nor->flags |= SNOR_F_USE_CLSR;
 
+	if (info->flags & SPI_NOR_HAS_BP3)
+		nor->flags |= SNOR_F_HAS_BP3;
 	if (info->flags & SPI_NOR_NO_ERASE)
 		mtd->flags |= MTD_NO_ERASE;
 
@@ -2377,6 +2616,7 @@ int spi_nor_scan(struct spi_nor *nor)
 		/* enable 4-byte addressing if the device exceeds 16MiB */
 		nor->addr_width = 4;
 		if (JEDEC_MFR(info) == SNOR_MFR_SPANSION ||
+		    JEDEC_MFR(info) == SNOR_MFR_ISSI ||
 		    info->flags & SPI_NOR_4B_OPCODES)
 			spi_nor_set_4byte_opcodes(nor, info);
 #else
diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c
index a3920ba..0d97aa9 100644
--- a/drivers/mtd/spi/spi-nor-ids.c
+++ b/drivers/mtd/spi/spi-nor-ids.c
@@ -128,6 +128,11 @@ const struct flash_info spi_nor_ids[] = {
 			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
 	{ INFO("is25wp128",  0x9d7018, 0, 64 * 1024, 256,
 			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+	{ INFO("is25wp256", 0x9d7019, 0, 64 * 1024, 512,
+			SECT_4K | SPI_NOR_4B_OPCODES | SPI_NOR_HAS_LOCK |
+			SPI_NOR_HAS_TB | SPI_NOR_HAS_BP3)
+			.fixups = &is25wp256_fixups
+	},
 #endif
 #ifdef CONFIG_SPI_FLASH_MACRONIX	/* MACRONIX */
 	/* Macronix */
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 88e80af..2fe7812 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -26,6 +26,7 @@
 #define SNOR_MFR_SPANSION	CFI_MFR_AMD
 #define SNOR_MFR_SST		CFI_MFR_SST
 #define SNOR_MFR_WINBOND	0xef /* Also used by some Spansion */
+#define SNOR_MFR_ISSI		0x9d
 
 /*
  * Note on opcode nomenclature: some opcodes have a format like
@@ -39,6 +40,8 @@
 #define SPINOR_OP_WREN		0x06	/* Write enable */
 #define SPINOR_OP_RDSR		0x05	/* Read status register */
 #define SPINOR_OP_WRSR		0x01	/* Write status register 1 byte */
+#define SPINOR_OP_RDFR		0x48	/* Read Function register */
+#define SPINOR_OP_WRFR		0x42	/* Write Function register 1 byte */
 #define SPINOR_OP_RDSR2		0x3f	/* Read status register 2 */
 #define SPINOR_OP_WRSR2		0x3e	/* Write status register 2 */
 #define SPINOR_OP_READ		0x03	/* Read data bytes (low frequency) */
@@ -119,6 +122,7 @@
 #define SR_BP0			BIT(2)	/* Block protect 0 */
 #define SR_BP1			BIT(3)	/* Block protect 1 */
 #define SR_BP2			BIT(4)	/* Block protect 2 */
+#define SR_BP3			BIT(5)	/* Block protect 3 */
 #define SR_TB			BIT(5)	/* Top/Bottom protect */
 #define SR_SRWD			BIT(7)	/* SR write protect */
 /* Spansion/Cypress specific status bits */
@@ -130,6 +134,9 @@
 /* Enhanced Volatile Configuration Register bits */
 #define EVCR_QUAD_EN_MICRON	BIT(7)	/* Micron Quad I/O */
 
+/* Function register bit */
+#define FR_TB			BIT(1)	/*ISSI: Top/Bottom protect */
+
 /* Flag Status Register bits */
 #define FSR_READY		BIT(7)	/* Device status, 0 = Busy, 1 = Ready */
 #define FSR_E_ERR		BIT(5)	/* Erase operation status */
@@ -234,6 +241,7 @@ enum spi_nor_option_flags {
 	SNOR_F_READY_XSR_RDY	= BIT(4),
 	SNOR_F_USE_CLSR		= BIT(5),
 	SNOR_F_BROKEN_RESET	= BIT(6),
+	SNOR_F_HAS_BP3		= BIT(7),
 };
 
 /**
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [U-Boot] [U-BOOT PATCH 3/3] spi: riscv: use single bit mode for spi transfers
  2019-08-13 16:59 [U-Boot] [U-BOOT PATCH 0/3] add support for spi-nor device on HiFive Unleashed board Sagar Shrikant Kadam
  2019-08-13 16:59 ` [U-Boot] [U-BOOT PATCH 1/3] spi: nor: add spi-nor-fixup handlers for nor devices Sagar Shrikant Kadam
  2019-08-13 16:59 ` [U-Boot] [U-BOOT PATCH 2/3] spi: nor: add support for is25wp256 Sagar Shrikant Kadam
@ 2019-08-13 16:59 ` Sagar Shrikant Kadam
  2019-08-26 12:55   ` Bin Meng
  2019-08-27 10:48 ` [U-Boot] [U-BOOT PATCH 0/3] add support for spi-nor device on HiFive Unleashed board Bin Meng
  3 siblings, 1 reply; 10+ messages in thread
From: Sagar Shrikant Kadam @ 2019-08-13 16:59 UTC (permalink / raw)
  To: u-boot

Use the SPI controller in FU540-C000 soc in one bit mode, rather than using
spi-tx-bus-width and spi-rx-bus-width passed from the device tree.

This patch handles a case where controller mode in format register (0x40)
is configured as per the width specified in the dt-node of the slave
device. For instance if spi-tx-bus-width and spi-rx-bus-width in the flash
device node in dt is set to 4 bit mode, the controller gets configured in
QUAD mode, whereas the spi nor scan tries to read the JEDEC ID with the
reg_proto set to SNOR_PROTO_1_1_1 and fails.

Signed-off-by: Sagar Shrikant Kadam <sagar.kadam@sifive.com>
---
 drivers/spi/spi-sifive.c | 7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/drivers/spi/spi-sifive.c b/drivers/spi/spi-sifive.c
index 969bd4b..7cf3ea4 100644
--- a/drivers/spi/spi-sifive.c
+++ b/drivers/spi/spi-sifive.c
@@ -146,12 +146,7 @@ static void sifive_spi_prep_transfer(struct sifive_spi *spi,
 
 	/* Number of wires ? */
 	cr &= ~SIFIVE_SPI_FMT_PROTO_MASK;
-	if ((slave->mode & SPI_TX_QUAD) || (slave->mode & SPI_RX_QUAD))
-		cr |= SIFIVE_SPI_FMT_PROTO_QUAD;
-	else if ((slave->mode & SPI_TX_DUAL) || (slave->mode & SPI_RX_DUAL))
-		cr |= SIFIVE_SPI_FMT_PROTO_DUAL;
-	else
-		cr |= SIFIVE_SPI_FMT_PROTO_SINGLE;
+	cr |= SIFIVE_SPI_FMT_PROTO_SINGLE;
 
 	/* SPI direction in/out ? */
 	cr &= ~SIFIVE_SPI_FMT_DIR;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [U-Boot] [U-BOOT PATCH 2/3] spi: nor: add support for is25wp256
  2019-08-13 16:59 ` [U-Boot] [U-BOOT PATCH 2/3] spi: nor: add support for is25wp256 Sagar Shrikant Kadam
@ 2019-08-26 10:02   ` Bin Meng
  0 siblings, 0 replies; 10+ messages in thread
From: Bin Meng @ 2019-08-26 10:02 UTC (permalink / raw)
  To: u-boot

On Wed, Aug 14, 2019 at 1:23 AM Sagar Shrikant Kadam
<sagar.kadam@sifive.com> wrote:
>
> Enable support for spi nor device(is25wp256) mounted on
> HiFive Unleashed Rev A00 board.
>
> Thanks to Bhargav Shah for porting this patch which is based on
> linux patches https://lkml.org/lkml/2019/7/2/859.
>
> Additionally, set the proper number of sectors in the device id table,
> so that the sf probe shows the correct size of the flash device.
> Added SPI_NOR_HAS_BP3 bit to indicate that this nor device has BP3 bit
> present for the lock/unlock mechanism.
> Registered a post bfpt fixup handler for this device as the address width
> advertised by the flash during nor scan is not correct.
>
> This flash is tested for plain SPI mode although it also supports QUAD
> I/O mode.
>
> Signed-off-by: Bhargav Shah <bhargavshah1988@gmail.com>
> Signed-off-by: Sagar Shrikant Kadam <sagar.kadam@sifive.com>
> ---
>  board/sifive/fu540/Kconfig     |   5 +
>  drivers/mtd/spi/sf_internal.h  |  18 +++
>  drivers/mtd/spi/spi-nor-core.c | 340 +++++++++++++++++++++++++++++++++++------
>  drivers/mtd/spi/spi-nor-ids.c  |   5 +
>  include/linux/mtd/spi-nor.h    |   8 +
>  5 files changed, 326 insertions(+), 50 deletions(-)
>
> diff --git a/board/sifive/fu540/Kconfig b/board/sifive/fu540/Kconfig
> index 5d65080..f9d5ec1 100644
> --- a/board/sifive/fu540/Kconfig
> +++ b/board/sifive/fu540/Kconfig
> @@ -40,6 +40,11 @@ config BOARD_SPECIFIC_OPTIONS # dummy
>         imply SIFIVE_SERIAL
>         imply SPI
>         imply SPI_SIFIVE
> +       imply SPI_FLASH
> +       imply SPI_FLASH_ISSI
> +       imply SPI_FLASH_SFDP_SUPPORT
> +       imply CMD_MTD
> +       imply CMD_SF
>         imply MMC
>         imply MMC_SPI
>         imply MMC_BROKEN_CD

This should be a separate patch.

> diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
> index c5e68d8..6523107 100644
> --- a/drivers/mtd/spi/sf_internal.h
> +++ b/drivers/mtd/spi/sf_internal.h
> @@ -65,6 +65,13 @@ struct flash_info {
>  #define NO_CHIP_ERASE          BIT(12) /* Chip does not support chip erase */
>  #define SPI_NOR_SKIP_SFDP      BIT(13) /* Skip parsing of SFDP tables */
>  #define USE_CLSR               BIT(14) /* use CLSR command */
> +#define SPI_NOR_HAS_BP3                BIT(15) /*
> +                                        * Flash SR has block protect bits
> +                                        * for lock/unlock purpose, few support
> +                                        * BP0-BP2 while few support BP0-BP3.
> +                                        * This flag identifies devices that
> +                                        * support BP3 bit.
> +                                        */
>
>  #ifdef CONFIG_SPI_FLASH_SFDP_SUPPORT
>         /* Part specific fixup hooks */
> @@ -72,6 +79,17 @@ struct flash_info {
>  #endif
>  };
>
> +#ifdef CONFIG_SPI_FLASH_SFDP_SUPPORT
> +/*
> + * Declare manufacturer specific fixup handlers that
> + * can be registered as fixup's in flash info table
> + * so as to update any wrong/broken SFDP parameter.
> + */
> +#ifdef CONFIG_SPI_FLASH_ISSI
> +extern struct spi_nor_fixups is25wp256_fixups;
> +#endif
> +#endif
> +
>  extern const struct flash_info spi_nor_ids[];
>
>  #define JEDEC_MFR(info)        ((info)->id[0])
> diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
> index 4306d19..46d278d 100644
> --- a/drivers/mtd/spi/spi-nor-core.c
> +++ b/drivers/mtd/spi/spi-nor-core.c
> @@ -582,7 +582,8 @@ erase_err:
>         return ret;
>  }
>
> -#if defined(CONFIG_SPI_FLASH_STMICRO) || defined(CONFIG_SPI_FLASH_SST)
> +#if defined(CONFIG_SPI_FLASH_STMICRO) || defined(CONFIG_SPI_FLASH_SST) || \
> +       defined(CONFIG_SPI_FLASH_ISSI)
>  /* Write status register and ensure bits in mask match written values */
>  static int write_sr_and_check(struct spi_nor *nor, u8 status_new, u8 mask)
>  {
> @@ -604,14 +605,45 @@ static int write_sr_and_check(struct spi_nor *nor, u8 status_new, u8 mask)
>         return ((ret & mask) != (status_new & mask)) ? -EIO : 0;
>  }
>
> +/**
> + * spi_nor_read_fr() -read function register
> + * @nor: pointer to a 'struct spi_nor'.
> + *
> + * ISSI devices have top/bottom area protection bits selection into function
> + * reg. The bits in FR are OTP. So once it's written, it cannot be changed.
> + *
> + * Return: Value in function register or negative if error.
> + */
> +static int spi_nor_read_fr(struct spi_nor *nor)
> +{
> +       int ret;
> +       u8 val;
> +
> +       ret = nor->read_reg(nor, SPINOR_OP_RDFR, &val, 1);
> +       if (ret < 0) {
> +               pr_err("error %d reading FR\n", ret);
> +               return ret;
> +       }
> +
> +       return val;
> +}
> +
>  static void stm_get_locked_range(struct spi_nor *nor, u8 sr, loff_t *ofs,
>                                  uint64_t *len)
>  {
>         struct mtd_info *mtd = &nor->mtd;
> -       u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
> -       int shift = ffs(mask) - 1;
> +       u8 mask = 0;
> +       u8 fr = 0;
> +       int shift = 0;
>         int pow;
>
> +       if (nor->flags & SNOR_F_HAS_BP3)
> +               mask = SR_BP3 | SR_BP2 | SR_BP1 | SR_BP0;
> +       else
> +               mask = SR_BP2 | SR_BP1 | SR_BP0;
> +
> +       shift = ffs(mask) - 1;
> +
>         if (!(sr & mask)) {
>                 /* No protection */
>                 *ofs = 0;
> @@ -619,10 +651,20 @@ static void stm_get_locked_range(struct spi_nor *nor, u8 sr, loff_t *ofs,
>         } else {
>                 pow = ((sr & mask) ^ mask) >> shift;
>                 *len = mtd->size >> pow;
> -               if (nor->flags & SNOR_F_HAS_SR_TB && sr & SR_TB)
> -                       *ofs = 0;
> -               else
> -                       *ofs = mtd->size - *len;
> +
> +               /* ISSI device's have top/bottom select bit in func reg */
> +               if (JEDEC_MFR(nor->info) == SNOR_MFR_ISSI) {
> +                       fr = spi_nor_read_fr(nor);
> +                       if (nor->flags & SNOR_F_HAS_SR_TB && fr & FR_TB)
> +                               *ofs = 0;
> +                       else
> +                               *ofs = mtd->size - *len;
> +               } else {
> +                       if (nor->flags & SNOR_F_HAS_SR_TB && sr & SR_TB)
> +                               *ofs = 0;
> +                       else
> +                               *ofs = mtd->size - *len;
> +               }
>         }
>  }
>
> @@ -649,18 +691,109 @@ static int stm_check_lock_status_sr(struct spi_nor *nor, loff_t ofs, u64 len,
>                 return (ofs >= lock_offs + lock_len) || (ofs + len <= lock_offs);
>  }
>
> -static int stm_is_locked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
> -                           u8 sr)
> +/*
> + * check if memory region is locked
> + *
> + * Returns false if region is locked 0 otherwise.
> + */
> +static int spi_nor_is_locked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
> +                               u8 sr)
>  {
>         return stm_check_lock_status_sr(nor, ofs, len, sr, true);
>  }
>
> -static int stm_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
> -                             u8 sr)
> +/*
> + * check if memory region is unlocked
> + *
> + * Returns false if region is locked 0 otherwise.
> + */
> +static int spi_nor_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
> +                                 u8 sr)
>  {
>         return stm_check_lock_status_sr(nor, ofs, len, sr, false);
>  }
>
> +/**
> + * spi_nor_select_zone() - Select top area or bottom area to lock/unlock
> + * @nor: pointer to a 'struct spi_nor'.
> + * @ofs: offset from which to lock memory.
> + * @len: number of bytes to unlock.
> + * @sr: status register
> + * @tb: pointer to top/bottom bool used in caller function
> + * @op: zone selection is for lock/unlock operation. 1: lock 0:unlock
> + *
> + * Select the top area / bottom area pattern to protect memory blocks.
> + *
> + * Returns negative on errors, 0 on success.
> + */
> +static int spi_nor_select_zone(struct spi_nor *nor, loff_t ofs, uint64_t len,
> +                              u8 sr, bool *tb, bool op)
> +{
> +       int retval;
> +       bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB;
> +
> +       if (op) {
> +               /* Select for lock zone operation */
> +
> +               /*
> +                * If nothing in our range is unlocked, we don't need
> +                * to do anything.
> +                */
> +               if (spi_nor_is_locked_sr(nor, ofs, len, sr))
> +                       return 0;
> +
> +               /*
> +                * If anything below us is unlocked, we can't use 'bottom'
> +                * protection.
> +                */
> +               if (!spi_nor_is_locked_sr(nor, 0, ofs, sr))
> +                       can_be_bottom = false;
> +
> +               /*
> +                * If anything above us is unlocked, we can't use 'top'
> +                * protection.
> +                */
> +               if (!spi_nor_is_locked_sr(nor, ofs + len,
> +                                         nor->mtd.size - (ofs + len), sr))
> +                       can_be_top = false;
> +       } else {
> +               /* Select unlock zone */
> +
> +               /*
> +                * If nothing in our range is locked, we don't need to
> +                * do anything.
> +                */
> +               if (spi_nor_is_unlocked_sr(nor, ofs, len, sr))
> +                       return 0;
> +
> +               /*
> +                * If anything below us is locked, we can't use 'top'
> +                * protection
> +                */
> +               if (!spi_nor_is_unlocked_sr(nor, 0, ofs, sr))
> +                       can_be_top = false;
> +
> +               /*
> +                * If anything above us is locked, we can't use 'bottom'
> +                * protection
> +                */
> +               if (!spi_nor_is_unlocked_sr(nor, ofs + len,
> +                                           nor->mtd.size - (ofs + len), sr))
> +                       can_be_bottom = false;
> +       }
> +
> +       if (!can_be_bottom && !can_be_top) {
> +               retval = -EINVAL;
> +       } else {
> +               /* Prefer top, if both are valid */
> +               *tb = can_be_top;
> +               retval = 1;
> +       }
> +
> +       return retval;
> +}
> +
> +#if !defined(CONFIG_SPI_FLASH_ISSI)
>  /*
>   * Lock a region of the flash. Compatible with ST Micro and similar flash.
>   * Supports the block protection bits BP{0,1,2} in the status register
> @@ -698,33 +831,19 @@ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
>         struct mtd_info *mtd = &nor->mtd;
>         int status_old, status_new;
>         u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
> -       u8 shift = ffs(mask) - 1, pow, val;
> +       u8 shift = ffs(mask) - 1, pow, val, ret;
>         loff_t lock_len;
> -       bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB;
>         bool use_top;
>
>         status_old = read_sr(nor);
>         if (status_old < 0)
>                 return status_old;
>
> -       /* If nothing in our range is unlocked, we don't need to do anything */
> -       if (stm_is_locked_sr(nor, ofs, len, status_old))
> +       ret = spi_nor_select_zone(nor, ofs, len, status_old, &use_top, 1);
> +       if (!ret)
>                 return 0;
> -
> -       /* If anything below us is unlocked, we can't use 'bottom' protection */
> -       if (!stm_is_locked_sr(nor, 0, ofs, status_old))
> -               can_be_bottom = false;
> -
> -       /* If anything above us is unlocked, we can't use 'top' protection */
> -       if (!stm_is_locked_sr(nor, ofs + len, mtd->size - (ofs + len),
> -                             status_old))
> -               can_be_top = false;
> -
> -       if (!can_be_bottom && !can_be_top)
> -               return -EINVAL;
> -
> -       /* Prefer top, if both are valid */
> -       use_top = can_be_top;
> +       else if (ret < 0)
> +               return ret;
>
>         /* lock_len: length of region that should end up locked */
>         if (use_top)
> @@ -778,33 +897,19 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
>         struct mtd_info *mtd = &nor->mtd;
>         int status_old, status_new;
>         u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
> -       u8 shift = ffs(mask) - 1, pow, val;
> +       u8 shift = ffs(mask) - 1, pow, val, ret;
>         loff_t lock_len;
> -       bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB;
>         bool use_top;
>
>         status_old = read_sr(nor);
>         if (status_old < 0)
>                 return status_old;
>
> -       /* If nothing in our range is locked, we don't need to do anything */
> -       if (stm_is_unlocked_sr(nor, ofs, len, status_old))
> +       ret = spi_nor_select_zone(nor, ofs, len, status_old, &use_top, 0);
> +       if (!ret)
>                 return 0;
> -
> -       /* If anything below us is locked, we can't use 'top' protection */
> -       if (!stm_is_unlocked_sr(nor, 0, ofs, status_old))
> -               can_be_top = false;
> -
> -       /* If anything above us is locked, we can't use 'bottom' protection */
> -       if (!stm_is_unlocked_sr(nor, ofs + len, mtd->size - (ofs + len),
> -                               status_old))
> -               can_be_bottom = false;
> -
> -       if (!can_be_bottom && !can_be_top)
> -               return -EINVAL;
> -
> -       /* Prefer top, if both are valid */
> -       use_top = can_be_top;
> +       else if (ret < 0)
> +               return ret;
>
>         /* lock_len: length of region that should remain locked */
>         if (use_top)
> @@ -866,8 +971,9 @@ static int stm_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len)
>         if (status < 0)
>                 return status;
>
> -       return stm_is_locked_sr(nor, ofs, len, status);
> +       return spi_nor_is_locked_sr(nor, ofs, len, status);
>  }
> +#endif /* !CONFIG_SPI_FLASH_ISSI*/
>  #endif /* CONFIG_SPI_FLASH_STMICRO */
>
>  static const struct flash_info *spi_nor_read_id(struct spi_nor *nor)
> @@ -1142,6 +1248,105 @@ static int macronix_quad_enable(struct spi_nor *nor)
>  }
>  #endif
>
> +/**
> + * issi_lock() - set BP[0123] write-protection.
> + * @nor: pointer to a 'struct spi_nor'.
> + * @ofs: offset from which to lock memory.
> + * @len: number of bytes to unlock.
> + *
> + * Lock a region of the flash.Implementation is based on stm_lock
> + * Supports the block protection bits BP{0,1,2,3} in status register
> + *
> + * Return: 0 on success, -errno otherwise.
> + */
> +static int issi_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
> +{
> +       int status_old, status_new, blk_prot;
> +       u8 mask = SR_BP3 | SR_BP2 | SR_BP1 | SR_BP0;
> +       u8 shift = ffs(mask) - 1;
> +       u8 pow, ret;
> +       bool use_top = false;
> +       loff_t lock_len;
> +
> +       status_old = read_sr(nor);
> +
> +       /* if status reg is Write protected don't update bit protection */
> +       if (status_old & SR_SRWD) {
> +               dev_err(nor->dev,
> +                       "SR is write protected, can't update BP bits...\n");
> +               return -EINVAL;
> +       }
> +
> +       ret = spi_nor_select_zone(nor, ofs, len, status_old, &use_top, 1);
> +       if (!ret)
> +               /* Older protected blocks include the new requested block's */
> +               return 0;
> +       else if (ret < 0)
> +               return ret;
> +
> +       /* lock_len: length of region that should end up locked */
> +       if (use_top)
> +               lock_len = nor->mtd.size - ofs;
> +       else
> +               lock_len = ofs + len;
> +
> +       pow = order_base_2(lock_len);
> +       blk_prot = mask & (((pow + 1) & 0xf) << shift);
> +       if (lock_len <= 0) {
> +               dev_err(nor->dev, "invalid Length to protect");
> +               return -EINVAL;
> +       }
> +
> +       status_new = status_old | blk_prot;
> +       if (status_old == status_new)
> +               return 0;
> +
> +       return write_sr_and_check(nor, status_new, mask);
> +}
> +
> +/**
> + * issi_unlock() - clear BP[0123] write-protection.
> + * @nor: pointer to a 'struct spi_nor'.
> + * @ofs: offset from which to unlock memory.
> + * @len: number of bytes to unlock.
> + *
> + * Bits [2345] of the Status Register are BP[0123].
> + * ISSI chips use a different block protection scheme than other chips.
> + * Just disable the write-protect unilaterally.
> + *
> + * Return: 0 on success, -errno otherwise.
> + */
> +static int issi_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
> +{
> +       int ret, val;
> +       u8 mask = SR_BP0 | SR_BP1 | SR_BP2 | SR_BP3;
> +
> +       val = read_sr(nor);
> +       if (val < 0)
> +               return val;
> +       if (!(val & mask))
> +               return 0;
> +
> +       write_enable(nor);
> +
> +       write_sr(nor, val & ~mask);
> +
> +       ret = spi_nor_wait_till_ready(nor);
> +       if (ret)
> +               return ret;
> +
> +       ret = read_sr(nor);
> +       if (!(ret & mask)) {
> +               dev_info(nor->dev, "ISSI block protect bits cleared SR: 0x%x\n",
> +                        ret);
> +               ret = 0;
> +       } else {
> +               dev_err(nor->dev, "ISSI block protect bits not cleared\n");
> +               ret = -EINVAL;
> +       }
> +       return ret;
> +}
> +
>  #if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND)
>  /*
>   * Write status Register and configuration register with 2 bytes
> @@ -1649,6 +1854,28 @@ spi_nor_post_bfpt_fixups(struct spi_nor *nor,
>         return 0;
>  }
>
> +static int is25wp256_post_bfpt_fixups(struct spi_nor *nor,
> +                                     const struct sfdp_parameter_header
> +                                               *bfpt_header,
> +                                     const struct sfdp_bfpt *bfpt,
> +                                     struct spi_nor_flash_parameter *params)
> +
> +{
> +       /* IS25WP256 supports 4B opcodes, but the BFPT advertises a
> +        * BFPT_DWORD1_ADDRESS_BYTES_3_ONLY address width.
> +        * Overwrite the address width advertised by the BFPT.
> +        */
> +       if ((bfpt->dwords[BFPT_DWORD(1)] & BFPT_DWORD1_ADDRESS_BYTES_MASK) ==
> +                       BFPT_DWORD1_ADDRESS_BYTES_3_ONLY)
> +               nor->addr_width = 4;
> +
> +       return 0;
> +}
> +
> +struct spi_nor_fixups is25wp256_fixups = {
> +       .post_bfpt = is25wp256_post_bfpt_fixups,
> +};
> +
>  /**
>   * spi_nor_parse_bfpt() - read and parse the Basic Flash Parameter Table.
>   * @nor:               pointer to a 'struct spi_nor'
> @@ -2318,6 +2545,16 @@ int spi_nor_scan(struct spi_nor *nor)
>         mtd->_erase = spi_nor_erase;
>         mtd->_read = spi_nor_read;
>
> +#if defined(CONFIG_SPI_FLASH_ISSI)
> +       /* NOR protection support for ISSI chips */
> +       if (JEDEC_MFR(info) == SNOR_MFR_ISSI &&
> +           info->flags & SPI_NOR_HAS_LOCK &&
> +           info->flags & SPI_NOR_HAS_BP3) {
> +               nor->flash_lock = issi_lock;
> +               nor->flash_unlock = issi_unlock;
> +       }
> +#endif
> +
>  #if defined(CONFIG_SPI_FLASH_STMICRO) || defined(CONFIG_SPI_FLASH_SST)
>         /* NOR protection support for STmicro/Micron chips and similar */
>         if (JEDEC_MFR(info) == SNOR_MFR_ST ||
> @@ -2347,6 +2584,8 @@ int spi_nor_scan(struct spi_nor *nor)
>         if (info->flags & USE_CLSR)
>                 nor->flags |= SNOR_F_USE_CLSR;
>
> +       if (info->flags & SPI_NOR_HAS_BP3)
> +               nor->flags |= SNOR_F_HAS_BP3;
>         if (info->flags & SPI_NOR_NO_ERASE)
>                 mtd->flags |= MTD_NO_ERASE;
>
> @@ -2377,6 +2616,7 @@ int spi_nor_scan(struct spi_nor *nor)
>                 /* enable 4-byte addressing if the device exceeds 16MiB */
>                 nor->addr_width = 4;
>                 if (JEDEC_MFR(info) == SNOR_MFR_SPANSION ||
> +                   JEDEC_MFR(info) == SNOR_MFR_ISSI ||
>                     info->flags & SPI_NOR_4B_OPCODES)
>                         spi_nor_set_4byte_opcodes(nor, info);
>  #else
> diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c
> index a3920ba..0d97aa9 100644
> --- a/drivers/mtd/spi/spi-nor-ids.c
> +++ b/drivers/mtd/spi/spi-nor-ids.c
> @@ -128,6 +128,11 @@ const struct flash_info spi_nor_ids[] = {
>                         SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
>         { INFO("is25wp128",  0x9d7018, 0, 64 * 1024, 256,
>                         SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
> +       { INFO("is25wp256", 0x9d7019, 0, 64 * 1024, 512,
> +                       SECT_4K | SPI_NOR_4B_OPCODES | SPI_NOR_HAS_LOCK |
> +                       SPI_NOR_HAS_TB | SPI_NOR_HAS_BP3)
> +                       .fixups = &is25wp256_fixups

Updating spi-nor-ids.c should be a separate patch following the
spi-nor core changes.

> +       },
>  #endif
>  #ifdef CONFIG_SPI_FLASH_MACRONIX       /* MACRONIX */
>         /* Macronix */
> diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
> index 88e80af..2fe7812 100644
> --- a/include/linux/mtd/spi-nor.h
> +++ b/include/linux/mtd/spi-nor.h
> @@ -26,6 +26,7 @@
>  #define SNOR_MFR_SPANSION      CFI_MFR_AMD
>  #define SNOR_MFR_SST           CFI_MFR_SST
>  #define SNOR_MFR_WINBOND       0xef /* Also used by some Spansion */
> +#define SNOR_MFR_ISSI          0x9d
>
>  /*
>   * Note on opcode nomenclature: some opcodes have a format like
> @@ -39,6 +40,8 @@
>  #define SPINOR_OP_WREN         0x06    /* Write enable */
>  #define SPINOR_OP_RDSR         0x05    /* Read status register */
>  #define SPINOR_OP_WRSR         0x01    /* Write status register 1 byte */
> +#define SPINOR_OP_RDFR         0x48    /* Read Function register */
> +#define SPINOR_OP_WRFR         0x42    /* Write Function register 1 byte */
>  #define SPINOR_OP_RDSR2                0x3f    /* Read status register 2 */
>  #define SPINOR_OP_WRSR2                0x3e    /* Write status register 2 */
>  #define SPINOR_OP_READ         0x03    /* Read data bytes (low frequency) */
> @@ -119,6 +122,7 @@
>  #define SR_BP0                 BIT(2)  /* Block protect 0 */
>  #define SR_BP1                 BIT(3)  /* Block protect 1 */
>  #define SR_BP2                 BIT(4)  /* Block protect 2 */
> +#define SR_BP3                 BIT(5)  /* Block protect 3 */
>  #define SR_TB                  BIT(5)  /* Top/Bottom protect */
>  #define SR_SRWD                        BIT(7)  /* SR write protect */
>  /* Spansion/Cypress specific status bits */
> @@ -130,6 +134,9 @@
>  /* Enhanced Volatile Configuration Register bits */
>  #define EVCR_QUAD_EN_MICRON    BIT(7)  /* Micron Quad I/O */
>
> +/* Function register bit */
> +#define FR_TB                  BIT(1)  /*ISSI: Top/Bottom protect */
> +
>  /* Flag Status Register bits */
>  #define FSR_READY              BIT(7)  /* Device status, 0 = Busy, 1 = Ready */
>  #define FSR_E_ERR              BIT(5)  /* Erase operation status */
> @@ -234,6 +241,7 @@ enum spi_nor_option_flags {
>         SNOR_F_READY_XSR_RDY    = BIT(4),
>         SNOR_F_USE_CLSR         = BIT(5),
>         SNOR_F_BROKEN_RESET     = BIT(6),
> +       SNOR_F_HAS_BP3          = BIT(7),
>  };
>
>  /**

Regards,
Bin

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [U-Boot] [U-BOOT PATCH 1/3] spi: nor: add spi-nor-fixup handlers for nor devices
  2019-08-13 16:59 ` [U-Boot] [U-BOOT PATCH 1/3] spi: nor: add spi-nor-fixup handlers for nor devices Sagar Shrikant Kadam
@ 2019-08-26 12:51   ` Bin Meng
  0 siblings, 0 replies; 10+ messages in thread
From: Bin Meng @ 2019-08-26 12:51 UTC (permalink / raw)
  To: u-boot

On Wed, Aug 14, 2019 at 1:36 AM Sagar Shrikant Kadam
<sagar.kadam@sifive.com> wrote:
>
> Add support for spi_nor_fixups similar to that done in linux.
> Flash vendor specific fixups can be registered in spi_nor_ids.
> and will be called after BFPT parsing to fix any wrong parameter
> read from SFDP.
>
> Signed-off-by: Sagar Shrikant Kadam <sagar.kadam@sifive.com>
> ---
>  drivers/mtd/spi/sf_internal.h  |  5 +++++
>  drivers/mtd/spi/spi-nor-core.c | 33 +++++++++++++++++++++++++++++++--
>  2 files changed, 36 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
> index a6bf734..c5e68d8 100644
> --- a/drivers/mtd/spi/sf_internal.h
> +++ b/drivers/mtd/spi/sf_internal.h
> @@ -65,6 +65,11 @@ struct flash_info {
>  #define NO_CHIP_ERASE          BIT(12) /* Chip does not support chip erase */
>  #define SPI_NOR_SKIP_SFDP      BIT(13) /* Skip parsing of SFDP tables */
>  #define USE_CLSR               BIT(14) /* use CLSR command */
> +
> +#ifdef CONFIG_SPI_FLASH_SFDP_SUPPORT
> +       /* Part specific fixup hooks */
> +       const struct spi_nor_fixups     *fixups;
> +#endif
>  };
>
>  extern const struct flash_info spi_nor_ids[];
> diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
> index 1acff74..4306d19 100644
> --- a/drivers/mtd/spi/spi-nor-core.c
> +++ b/drivers/mtd/spi/spi-nor-core.c
> @@ -1623,6 +1623,33 @@ static const struct sfdp_bfpt_erase sfdp_bfpt_erases[] = {
>  static int spi_nor_hwcaps_read2cmd(u32 hwcaps);
>
>  /**
> + * struct spi_nor_fixups - SPI NOR fixup hooks
> + * @post_bfpt: called after the BFPT table has been parsed
> + *
> + * Those hooks can be used to tweak the SPI NOR configuration when the SFDP
> + * table is broken or not available.
> + */
> +struct spi_nor_fixups {
> +       int (*post_bfpt)(struct spi_nor *nor,
> +                        const struct sfdp_parameter_header *bfpt_header,
> +                        const struct sfdp_bfpt *bfpt,
> +                        struct spi_nor_flash_parameter *params);
> +};
> +
> +static int

nits: this should be in the same line as the function name

> +spi_nor_post_bfpt_fixups(struct spi_nor *nor,
> +                        const struct sfdp_parameter_header *bfpt_header,
> +                        const struct sfdp_bfpt *bfpt,
> +                        struct spi_nor_flash_parameter *params)
> +{
> +       if (nor->info->fixups && nor->info->fixups->post_bfpt)
> +               return nor->info->fixups->post_bfpt(nor, bfpt_header, bfpt,
> +                               params);
> +
> +       return 0;
> +}
> +
> +/**
>   * spi_nor_parse_bfpt() - read and parse the Basic Flash Parameter Table.
>   * @nor:               pointer to a 'struct spi_nor'
>   * @bfpt_header:       pointer to the 'struct sfdp_parameter_header' describing
> @@ -1760,7 +1787,8 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
>
>         /* Stop here if not JESD216 rev A or later. */
>         if (bfpt_header->length < BFPT_DWORD_MAX)
> -               return 0;
> +               return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt,
> +                               params);
>
>         /* Page size: this field specifies 'N' so the page size = 2^N bytes. */
>         params->page_size = bfpt.dwords[BFPT_DWORD(11)];
> @@ -1793,7 +1821,8 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
>                 return -EINVAL;
>         }
>
> -       return 0;
> +       return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt,
> +                       params);
>  }
>

Regards,
Bin

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [U-Boot] [U-BOOT PATCH 3/3] spi: riscv: use single bit mode for spi transfers
  2019-08-13 16:59 ` [U-Boot] [U-BOOT PATCH 3/3] spi: riscv: use single bit mode for spi transfers Sagar Shrikant Kadam
@ 2019-08-26 12:55   ` Bin Meng
  0 siblings, 0 replies; 10+ messages in thread
From: Bin Meng @ 2019-08-26 12:55 UTC (permalink / raw)
  To: u-boot

On Wed, Aug 14, 2019 at 1:18 AM Sagar Shrikant Kadam
<sagar.kadam@sifive.com> wrote:
>
> Use the SPI controller in FU540-C000 soc in one bit mode, rather than using
> spi-tx-bus-width and spi-rx-bus-width passed from the device tree.
>
> This patch handles a case where controller mode in format register (0x40)
> is configured as per the width specified in the dt-node of the slave
> device. For instance if spi-tx-bus-width and spi-rx-bus-width in the flash
> device node in dt is set to 4 bit mode, the controller gets configured in
> QUAD mode, whereas the spi nor scan tries to read the JEDEC ID with the
> reg_proto set to SNOR_PROTO_1_1_1 and fails.
>
> Signed-off-by: Sagar Shrikant Kadam <sagar.kadam@sifive.com>
> ---
>  drivers/spi/spi-sifive.c | 7 +------
>  1 file changed, 1 insertion(+), 6 deletions(-)
>
> diff --git a/drivers/spi/spi-sifive.c b/drivers/spi/spi-sifive.c
> index 969bd4b..7cf3ea4 100644
> --- a/drivers/spi/spi-sifive.c
> +++ b/drivers/spi/spi-sifive.c
> @@ -146,12 +146,7 @@ static void sifive_spi_prep_transfer(struct sifive_spi *spi,
>
>         /* Number of wires ? */
>         cr &= ~SIFIVE_SPI_FMT_PROTO_MASK;
> -       if ((slave->mode & SPI_TX_QUAD) || (slave->mode & SPI_RX_QUAD))
> -               cr |= SIFIVE_SPI_FMT_PROTO_QUAD;
> -       else if ((slave->mode & SPI_TX_DUAL) || (slave->mode & SPI_RX_DUAL))
> -               cr |= SIFIVE_SPI_FMT_PROTO_DUAL;
> -       else
> -               cr |= SIFIVE_SPI_FMT_PROTO_SINGLE;
> +       cr |= SIFIVE_SPI_FMT_PROTO_SINGLE;

This change makes the SPI controller no longer a QSPI any more. Why?

I actually have a local spi-nor version that works on HiFive Unleashed
without this changes at all and JEDEC ID can be read correctly.

>
>         /* SPI direction in/out ? */
>         cr &= ~SIFIVE_SPI_FMT_DIR;
> --

Regards,
Bin

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [U-Boot] [U-BOOT PATCH 0/3] add support for spi-nor device on HiFive Unleashed board
  2019-08-13 16:59 [U-Boot] [U-BOOT PATCH 0/3] add support for spi-nor device on HiFive Unleashed board Sagar Shrikant Kadam
                   ` (2 preceding siblings ...)
  2019-08-13 16:59 ` [U-Boot] [U-BOOT PATCH 3/3] spi: riscv: use single bit mode for spi transfers Sagar Shrikant Kadam
@ 2019-08-27 10:48 ` Bin Meng
  2019-08-28  5:45   ` Sagar Kadam
  3 siblings, 1 reply; 10+ messages in thread
From: Bin Meng @ 2019-08-27 10:48 UTC (permalink / raw)
  To: u-boot

On Wed, Aug 14, 2019 at 1:08 AM Sagar Shrikant Kadam
<sagar.kadam@sifive.com> wrote:
>
> This patch series adds support for 32MiB SPI-NOR flash (is25wp256 from
> ISSI). Many thanks to Bhargav Shah <bhargavshah1988@gmail.com> for
> porting the spi-nor patches from linux to U-boot in order to support
> this device.
> Ref: linux patches which are under review
> https://lkml.org/lkml/2019/7/2/859
>
> Linux has an option of registering post-bfpt fixups in order to over-ride
> the incorrect configuration of flash devices due to wrong SFDP entries read
> from the flash device during nor scan phase. The 1st patch introduces this
> support to register post bfpt fixup hook similar to that done in linux.
>
> The second patch in the series enables support for the flash device in
> single I/O mode. A post bfpt fixup is registered because the flash device
> gets BFPT_DWORD1_ADDRESS_BYTES_3_ONLY from BFPT table for address width,
> whereas the flash can support 4 byte address width.
> The SPI_NOR_HAS_BP3 bit indicates that the flash protection block has BP0
> to BP3 bits.
>
> Lock/Unlock mechanism:
> The implementation is based on stm_lock/unlock scheme and is validated for
> different number of blocks passed to sf command. Unlock scheme unilateraly
> clears all the protection bits of all blocks in the status register.
>
> The series is based on the master branch of[1]
> [1] https://gitlab.denx.de/u-boot/custodians/u-boot-riscv
>
> and is available in dev/sagark/hifive-spi-nor_v2 branch of[2]
> [2] https://github.com/sagsifive/u-boot.
>
> Flash operations like erase/read/write lock/unlock are verified and
> data integrity is checked using sf commands as follows:
>
> => sf write 0x80600000 0x0 0x2000000
> device 0 whole chip
> SF: 33554432 bytes @ 0x0 Written: OK
> => sf read 0x82700000 0x0 0x2000000
> device 0 whole chip
> SF: 33554432 bytes @ 0x0 Read: OK
> => cmp.b 0x80600000 0x82700000 0x2000000
> Total of 33554432 byte(s) were the same
>
> => sf protect lock 0x1000000 0x1000000
> => mw 0x80600000 0x12345678 0x2000000
> => sf write 0x80600000 0x0 0x2000000
>    Reset the board to flush out data from memory
> => sf probe
> => sf read 0x80600000 0x0 0x2000000
>    In memory dump after sf read from address 0x80600000 we can see that
>    upper 16MiB flash section is protected.
>
>
> Sagar Shrikant Kadam (3):
>   spi: nor: add spi-nor-fixup handlers for nor devices
>   spi: nor: add support for is25wp256
>   spi: riscv: use single bit mode for spi transfers
>
>  board/sifive/fu540/Kconfig     |   5 +
>  drivers/mtd/spi/sf_internal.h  |  23 +++
>  drivers/mtd/spi/spi-nor-core.c | 373 +++++++++++++++++++++++++++++++++++------
>  drivers/mtd/spi/spi-nor-ids.c  |   5 +
>  drivers/spi/spi-sifive.c       |   7 +-
>  include/linux/mtd/spi-nor.h    |   8 +
>  6 files changed, 363 insertions(+), 58 deletions(-)
>
> --

Warning! This patch series will brick the HiFive Unleashed board.

What I did was only:
=> sf probe

everything looks good as long as you don't power off the board.

But when you power off the board and power on, there is no console
output anymore.

I then re-flashed the board using SD card rescue image, and confirmed
that this single "sf probe" command will brick the board (once again!)

Regards,
Bin

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [U-Boot] [U-BOOT PATCH 0/3] add support for spi-nor device on HiFive Unleashed board
  2019-08-27 10:48 ` [U-Boot] [U-BOOT PATCH 0/3] add support for spi-nor device on HiFive Unleashed board Bin Meng
@ 2019-08-28  5:45   ` Sagar Kadam
  2019-08-28  6:18     ` Bin Meng
  0 siblings, 1 reply; 10+ messages in thread
From: Sagar Kadam @ 2019-08-28  5:45 UTC (permalink / raw)
  To: u-boot

Hello Bin,

On Tue, Aug 27, 2019 at 3:48 AM Bin Meng <bmeng.cn@gmail.com> wrote:
>
> On Wed, Aug 14, 2019 at 1:08 AM Sagar Shrikant Kadam
> <sagar.kadam@sifive.com> wrote:
> >
> > This patch series adds support for 32MiB SPI-NOR flash (is25wp256 from
> > ISSI). Many thanks to Bhargav Shah <bhargavshah1988@gmail.com> for
> > porting the spi-nor patches from linux to U-boot in order to support
> > this device.
> > Ref: linux patches which are under review
> > https://lkml.org/lkml/2019/7/2/859
> >
> > Linux has an option of registering post-bfpt fixups in order to over-ride
> > the incorrect configuration of flash devices due to wrong SFDP entries read
> > from the flash device during nor scan phase. The 1st patch introduces this
> > support to register post bfpt fixup hook similar to that done in linux.
> >
> > The second patch in the series enables support for the flash device in
> > single I/O mode. A post bfpt fixup is registered because the flash device
> > gets BFPT_DWORD1_ADDRESS_BYTES_3_ONLY from BFPT table for address width,
> > whereas the flash can support 4 byte address width.
> > The SPI_NOR_HAS_BP3 bit indicates that the flash protection block has BP0
> > to BP3 bits.
> >
> > Lock/Unlock mechanism:
> > The implementation is based on stm_lock/unlock scheme and is validated for
> > different number of blocks passed to sf command. Unlock scheme unilateraly
> > clears all the protection bits of all blocks in the status register.
> >
> > The series is based on the master branch of[1]
> > [1] https://gitlab.denx.de/u-boot/custodians/u-boot-riscv
> >
> > and is available in dev/sagark/hifive-spi-nor_v2 branch of[2]
> > [2] https://github.com/sagsifive/u-boot.
> >
> > Flash operations like erase/read/write lock/unlock are verified and
> > data integrity is checked using sf commands as follows:
> >
> > => sf write 0x80600000 0x0 0x2000000
> > device 0 whole chip
> > SF: 33554432 bytes @ 0x0 Written: OK
> > => sf read 0x82700000 0x0 0x2000000
> > device 0 whole chip
> > SF: 33554432 bytes @ 0x0 Read: OK
> > => cmp.b 0x80600000 0x82700000 0x2000000
> > Total of 33554432 byte(s) were the same
> >
> > => sf protect lock 0x1000000 0x1000000
> > => mw 0x80600000 0x12345678 0x2000000
> > => sf write 0x80600000 0x0 0x2000000
> >    Reset the board to flush out data from memory
> > => sf probe
> > => sf read 0x80600000 0x0 0x2000000
> >    In memory dump after sf read from address 0x80600000 we can see that
> >    upper 16MiB flash section is protected.
> >
> >
> > Sagar Shrikant Kadam (3):
> >   spi: nor: add spi-nor-fixup handlers for nor devices
> >   spi: nor: add support for is25wp256
> >   spi: riscv: use single bit mode for spi transfers
> >
> >  board/sifive/fu540/Kconfig     |   5 +
> >  drivers/mtd/spi/sf_internal.h  |  23 +++
> >  drivers/mtd/spi/spi-nor-core.c | 373 +++++++++++++++++++++++++++++++++++------
> >  drivers/mtd/spi/spi-nor-ids.c  |   5 +
> >  drivers/spi/spi-sifive.c       |   7 +-
> >  include/linux/mtd/spi-nor.h    |   8 +
> >  6 files changed, 363 insertions(+), 58 deletions(-)
> >
> > --
>
> Warning! This patch series will brick the HiFive Unleashed board.
>
> What I did was only:
> => sf probe
>
> everything looks good as long as you don't power off the board.
>
> But when you power off the board and power on, there is no console
> output anymore.
>
Does disconnecting and connecting back the terminal emulator work here?

> I then re-flashed the board using SD card rescue image, and confirmed
> that this single "sf probe" command will brick the board (once again!)
>
I would like to understand the situation here can you please elaborate it, so
that I can reproduce it at my end.
What is the boot mode you are using to test these patches?
Are you loading fsbl and U-boot from Flash or from SD Card?

Thanks & BR,
Sagar Kadam

> Regards,
> Bin

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [U-Boot] [U-BOOT PATCH 0/3] add support for spi-nor device on HiFive Unleashed board
  2019-08-28  5:45   ` Sagar Kadam
@ 2019-08-28  6:18     ` Bin Meng
  0 siblings, 0 replies; 10+ messages in thread
From: Bin Meng @ 2019-08-28  6:18 UTC (permalink / raw)
  To: u-boot

Hi Sagar,

On Wed, Aug 28, 2019 at 1:46 PM Sagar Kadam <sagar.kadam@sifive.com> wrote:
>
> Hello Bin,
>
> On Tue, Aug 27, 2019 at 3:48 AM Bin Meng <bmeng.cn@gmail.com> wrote:
> >
> > On Wed, Aug 14, 2019 at 1:08 AM Sagar Shrikant Kadam
> > <sagar.kadam@sifive.com> wrote:
> > >
> > > This patch series adds support for 32MiB SPI-NOR flash (is25wp256 from
> > > ISSI). Many thanks to Bhargav Shah <bhargavshah1988@gmail.com> for
> > > porting the spi-nor patches from linux to U-boot in order to support
> > > this device.
> > > Ref: linux patches which are under review
> > > https://lkml.org/lkml/2019/7/2/859
> > >
> > > Linux has an option of registering post-bfpt fixups in order to over-ride
> > > the incorrect configuration of flash devices due to wrong SFDP entries read
> > > from the flash device during nor scan phase. The 1st patch introduces this
> > > support to register post bfpt fixup hook similar to that done in linux.
> > >
> > > The second patch in the series enables support for the flash device in
> > > single I/O mode. A post bfpt fixup is registered because the flash device
> > > gets BFPT_DWORD1_ADDRESS_BYTES_3_ONLY from BFPT table for address width,
> > > whereas the flash can support 4 byte address width.
> > > The SPI_NOR_HAS_BP3 bit indicates that the flash protection block has BP0
> > > to BP3 bits.
> > >
> > > Lock/Unlock mechanism:
> > > The implementation is based on stm_lock/unlock scheme and is validated for
> > > different number of blocks passed to sf command. Unlock scheme unilateraly
> > > clears all the protection bits of all blocks in the status register.
> > >
> > > The series is based on the master branch of[1]
> > > [1] https://gitlab.denx.de/u-boot/custodians/u-boot-riscv
> > >
> > > and is available in dev/sagark/hifive-spi-nor_v2 branch of[2]
> > > [2] https://github.com/sagsifive/u-boot.
> > >
> > > Flash operations like erase/read/write lock/unlock are verified and
> > > data integrity is checked using sf commands as follows:
> > >
> > > => sf write 0x80600000 0x0 0x2000000
> > > device 0 whole chip
> > > SF: 33554432 bytes @ 0x0 Written: OK
> > > => sf read 0x82700000 0x0 0x2000000
> > > device 0 whole chip
> > > SF: 33554432 bytes @ 0x0 Read: OK
> > > => cmp.b 0x80600000 0x82700000 0x2000000
> > > Total of 33554432 byte(s) were the same
> > >
> > > => sf protect lock 0x1000000 0x1000000
> > > => mw 0x80600000 0x12345678 0x2000000
> > > => sf write 0x80600000 0x0 0x2000000
> > >    Reset the board to flush out data from memory
> > > => sf probe
> > > => sf read 0x80600000 0x0 0x2000000
> > >    In memory dump after sf read from address 0x80600000 we can see that
> > >    upper 16MiB flash section is protected.
> > >
> > >
> > > Sagar Shrikant Kadam (3):
> > >   spi: nor: add spi-nor-fixup handlers for nor devices
> > >   spi: nor: add support for is25wp256
> > >   spi: riscv: use single bit mode for spi transfers
> > >
> > >  board/sifive/fu540/Kconfig     |   5 +
> > >  drivers/mtd/spi/sf_internal.h  |  23 +++
> > >  drivers/mtd/spi/spi-nor-core.c | 373 +++++++++++++++++++++++++++++++++++------
> > >  drivers/mtd/spi/spi-nor-ids.c  |   5 +
> > >  drivers/spi/spi-sifive.c       |   7 +-
> > >  include/linux/mtd/spi-nor.h    |   8 +
> > >  6 files changed, 363 insertions(+), 58 deletions(-)
> > >
> > > --
> >
> > Warning! This patch series will brick the HiFive Unleashed board.
> >
> > What I did was only:
> > => sf probe
> >
> > everything looks good as long as you don't power off the board.
> >
> > But when you power off the board and power on, there is no console
> > output anymore.
> >
> Does disconnecting and connecting back the terminal emulator work here?

No.

>
> > I then re-flashed the board using SD card rescue image, and confirmed
> > that this single "sf probe" command will brick the board (once again!)
> >
> I would like to understand the situation here can you please elaborate it, so
> that I can reproduce it at my end.
> What is the boot mode you are using to test these patches?

MSEL = 1111

> Are you loading fsbl and U-boot from Flash or from SD Card?

FSBL in SPI, and OpenSBI/U-Boot in SD.

Regards,
Bin

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2019-08-28  6:18 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-08-13 16:59 [U-Boot] [U-BOOT PATCH 0/3] add support for spi-nor device on HiFive Unleashed board Sagar Shrikant Kadam
2019-08-13 16:59 ` [U-Boot] [U-BOOT PATCH 1/3] spi: nor: add spi-nor-fixup handlers for nor devices Sagar Shrikant Kadam
2019-08-26 12:51   ` Bin Meng
2019-08-13 16:59 ` [U-Boot] [U-BOOT PATCH 2/3] spi: nor: add support for is25wp256 Sagar Shrikant Kadam
2019-08-26 10:02   ` Bin Meng
2019-08-13 16:59 ` [U-Boot] [U-BOOT PATCH 3/3] spi: riscv: use single bit mode for spi transfers Sagar Shrikant Kadam
2019-08-26 12:55   ` Bin Meng
2019-08-27 10:48 ` [U-Boot] [U-BOOT PATCH 0/3] add support for spi-nor device on HiFive Unleashed board Bin Meng
2019-08-28  5:45   ` Sagar Kadam
2019-08-28  6:18     ` Bin Meng

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.