Commit 3dd8aa0e authored by Miquel Raynal's avatar Miquel Raynal
Browse files

Merge tag 'spi-nor/for-6.17' into mtd/next



SPI NOR changes for 6.17

Notable changes:

- Fix exiting 4-byte addressing on Infineon SEMPER flashes. These
  flashes do not support the standard EX4B opcode (E9h), and use a
  vendor-specific opcode (B8h) instead.

- Fix unlocking of flashes that are write-protected at power-on. This
  was caused by using an uninitialized mtd_info in
  spi_nor_try_unlock_all().

Signed-off-by: default avatarMiquel Raynal <miquel.raynal@bootlin.com>
parents 56eb7c13 2e3a7476
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -20,7 +20,7 @@ properties:
          - pattern: "^((((micron|spansion|st),)?\
              (m25p(40|80|16|32|64|128)|\
              n25q(32b|064|128a11|128a13|256a|512a|164k)))|\
              atmel,at25df(321a|641|081a)|\
              atmel,at(25|26)df(321a|641|081a)|\
              everspin,mr25h(10|40|128|256)|\
              (mxicy|macronix),mx25l(4005a|1606e|6405d|8005|12805d|25635e)|\
              (mxicy|macronix),mx25u(4033|4035)|\
+4 −4
Original line number Diff line number Diff line
@@ -189,7 +189,7 @@ static int mt25qu512a_post_bfpt_fixup(struct spi_nor *nor,
	return 0;
}

static struct spi_nor_fixups mt25qu512a_fixups = {
static const struct spi_nor_fixups mt25qu512a_fixups = {
	.post_bfpt = mt25qu512a_post_bfpt_fixup,
};

@@ -225,15 +225,15 @@ static int st_nor_two_die_late_init(struct spi_nor *nor)
	return spi_nor_set_4byte_addr_mode(nor, true);
}

static struct spi_nor_fixups n25q00_fixups = {
static const struct spi_nor_fixups n25q00_fixups = {
	.late_init = st_nor_four_die_late_init,
};

static struct spi_nor_fixups mt25q01_fixups = {
static const struct spi_nor_fixups mt25q01_fixups = {
	.late_init = st_nor_two_die_late_init,
};

static struct spi_nor_fixups mt25q02_fixups = {
static const struct spi_nor_fixups mt25q02_fixups = {
	.late_init = st_nor_four_die_late_init,
};

+33 −2
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@

#define SPINOR_OP_CLSR		0x30	/* Clear status register 1 */
#define SPINOR_OP_CLPEF		0x82	/* Clear program/erase failure flags */
#define SPINOR_OP_CYPRESS_EX4B	0xB8	/* Exit 4-byte address mode */
#define SPINOR_OP_CYPRESS_DIE_ERASE		0x61	/* Chip (die) erase */
#define SPINOR_OP_RD_ANY_REG			0x65	/* Read any register */
#define SPINOR_OP_WR_ANY_REG			0x71	/* Write any register */
@@ -58,6 +59,13 @@
		   SPI_MEM_OP_DUMMY(ndummy, 0),				\
		   SPI_MEM_OP_DATA_IN(1, buf, 0))

#define CYPRESS_NOR_EN4B_EX4B_OP(enable)				\
	SPI_MEM_OP(SPI_MEM_OP_CMD(enable ? SPINOR_OP_EN4B :		\
					   SPINOR_OP_CYPRESS_EX4B, 0),	\
		   SPI_MEM_OP_NO_ADDR,					\
		   SPI_MEM_OP_NO_DUMMY,					\
		   SPI_MEM_OP_NO_DATA)

#define SPANSION_OP(opcode)						\
	SPI_MEM_OP(SPI_MEM_OP_CMD(opcode, 0),				\
		   SPI_MEM_OP_NO_ADDR,					\
@@ -356,6 +364,20 @@ static int cypress_nor_quad_enable_volatile(struct spi_nor *nor)
	return 0;
}

static int cypress_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable)
{
	int ret;
	struct spi_mem_op op = CYPRESS_NOR_EN4B_EX4B_OP(enable);

	spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);

	ret = spi_mem_exec_op(nor->spimem, &op);
	if (ret)
		dev_dbg(nor->dev, "error %d setting 4-byte mode\n", ret);

	return ret;
}

/**
 * cypress_nor_determine_addr_mode_by_sr1() - Determine current address mode
 *                                            (3 or 4-byte) by querying status
@@ -526,6 +548,9 @@ s25fs256t_post_bfpt_fixup(struct spi_nor *nor,
	struct spi_mem_op op;
	int ret;

	/* Assign 4-byte address mode method that is not determined in BFPT */
	nor->params->set_4byte_addr_mode = cypress_nor_set_4byte_addr_mode;

	ret = cypress_nor_set_addr_mode_nbytes(nor);
	if (ret)
		return ret;
@@ -578,7 +603,7 @@ static int s25fs256t_late_init(struct spi_nor *nor)
	return 0;
}

static struct spi_nor_fixups s25fs256t_fixups = {
static const struct spi_nor_fixups s25fs256t_fixups = {
	.post_bfpt = s25fs256t_post_bfpt_fixup,
	.post_sfdp = s25fs256t_post_sfdp_fixup,
	.late_init = s25fs256t_late_init,
@@ -591,6 +616,9 @@ s25hx_t_post_bfpt_fixup(struct spi_nor *nor,
{
	int ret;

	/* Assign 4-byte address mode method that is not determined in BFPT */
	nor->params->set_4byte_addr_mode = cypress_nor_set_4byte_addr_mode;

	ret = cypress_nor_set_addr_mode_nbytes(nor);
	if (ret)
		return ret;
@@ -650,7 +678,7 @@ static int s25hx_t_late_init(struct spi_nor *nor)
	return 0;
}

static struct spi_nor_fixups s25hx_t_fixups = {
static const struct spi_nor_fixups s25hx_t_fixups = {
	.post_bfpt = s25hx_t_post_bfpt_fixup,
	.post_sfdp = s25hx_t_post_sfdp_fixup,
	.late_init = s25hx_t_late_init,
@@ -718,6 +746,9 @@ static int s28hx_t_post_bfpt_fixup(struct spi_nor *nor,
				   const struct sfdp_parameter_header *bfpt_header,
				   const struct sfdp_bfpt *bfpt)
{
	/* Assign 4-byte address mode method that is not determined in BFPT */
	nor->params->set_4byte_addr_mode = cypress_nor_set_4byte_addr_mode;

	return cypress_nor_set_addr_mode_nbytes(nor);
}

+8 −11
Original line number Diff line number Diff line
@@ -56,7 +56,6 @@ static u64 spi_nor_get_min_prot_length_sr(struct spi_nor *nor)
static void spi_nor_get_locked_range_sr(struct spi_nor *nor, u8 sr, loff_t *ofs,
					u64 *len)
{
	struct mtd_info *mtd = &nor->mtd;
	u64 min_prot_len;
	u8 mask = spi_nor_get_sr_bp_mask(nor);
	u8 tb_mask = spi_nor_get_sr_tb_mask(nor);
@@ -77,13 +76,13 @@ static void spi_nor_get_locked_range_sr(struct spi_nor *nor, u8 sr, loff_t *ofs,
	min_prot_len = spi_nor_get_min_prot_length_sr(nor);
	*len = min_prot_len << (bp - 1);

	if (*len > mtd->size)
		*len = mtd->size;
	if (*len > nor->params->size)
		*len = nor->params->size;

	if (nor->flags & SNOR_F_HAS_SR_TB && sr & tb_mask)
		*ofs = 0;
	else
		*ofs = mtd->size - *len;
		*ofs = nor->params->size - *len;
}

/*
@@ -158,7 +157,6 @@ static bool spi_nor_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, u64 len,
 */
static int spi_nor_sr_lock(struct spi_nor *nor, loff_t ofs, u64 len)
{
	struct mtd_info *mtd = &nor->mtd;
	u64 min_prot_len;
	int ret, status_old, status_new;
	u8 mask = spi_nor_get_sr_bp_mask(nor);
@@ -183,7 +181,7 @@ static int spi_nor_sr_lock(struct spi_nor *nor, loff_t ofs, u64 len)
		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, mtd->size - (ofs + len),
	if (!spi_nor_is_locked_sr(nor, ofs + len, nor->params->size - (ofs + len),
				  status_old))
		can_be_top = false;

@@ -195,11 +193,11 @@ static int spi_nor_sr_lock(struct spi_nor *nor, loff_t ofs, u64 len)

	/* lock_len: length of region that should end up locked */
	if (use_top)
		lock_len = mtd->size - ofs;
		lock_len = nor->params->size - ofs;
	else
		lock_len = ofs + len;

	if (lock_len == mtd->size) {
	if (lock_len == nor->params->size) {
		val = mask;
	} else {
		min_prot_len = spi_nor_get_min_prot_length_sr(nor);
@@ -248,7 +246,6 @@ static int spi_nor_sr_lock(struct spi_nor *nor, loff_t ofs, u64 len)
 */
static int spi_nor_sr_unlock(struct spi_nor *nor, loff_t ofs, u64 len)
{
	struct mtd_info *mtd = &nor->mtd;
	u64 min_prot_len;
	int ret, status_old, status_new;
	u8 mask = spi_nor_get_sr_bp_mask(nor);
@@ -273,7 +270,7 @@ static int spi_nor_sr_unlock(struct spi_nor *nor, loff_t ofs, u64 len)
		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, mtd->size - (ofs + len),
	if (!spi_nor_is_unlocked_sr(nor, ofs + len, nor->params->size - (ofs + len),
				    status_old))
		can_be_bottom = false;

@@ -285,7 +282,7 @@ static int spi_nor_sr_unlock(struct spi_nor *nor, loff_t ofs, u64 len)

	/* lock_len: length of region that should remain locked */
	if (use_top)
		lock_len = mtd->size - (ofs + len);
		lock_len = nor->params->size - (ofs + len);
	else
		lock_len = ofs;