Commit b93f410b authored by Miquel Raynal's avatar Miquel Raynal
Browse files

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

SPI NOR changes for 6.11

Notable changes:

- Drop support for Xilinx S3AN flashes. These flashes are for the very
  old Xilinx Spartan 3 FPGAs and they need some awkward code in the core
  to support. Drop support for these flashes, along with the special
  handling we needed for them in the core like non-power-of-2 page size
  handling and the .setup() callback.

- Fix regression for old w25q128 flashes without SFDP tables. Commit
  83e824a4 ("mtd: spi-nor: Correct flags for Winbond w25q128")
  dropped support for such devices under the assumption that they aren't
  being used anymore. Users have now surfaced [0] so fix the regression
  by supporting both kind of devices.

- Core cleanups including removal of SPI_NOR_NO_FR flag and
  simplification of spi_nor_get_flash_info().

[0] https://lore.kernel.org/r/CALxbwRo_-9CaJmt7r7ELgu+vOcgk=xZcGHobnKf=oT2=u4d4aA@mail.gmail.com/



Signed-off-by: default avatarMiquel Raynal <miquel.raynal@bootlin.com>
parents 2538af03 d35df777
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -13,7 +13,6 @@ spi-nor-objs += micron-st.o
spi-nor-objs			+= spansion.o
spi-nor-objs			+= sst.o
spi-nor-objs			+= winbond.o
spi-nor-objs			+= xilinx.o
spi-nor-objs			+= xmc.o
spi-nor-$(CONFIG_DEBUG_FS)	+= debugfs.o
obj-$(CONFIG_MTD_SPI_NOR)	+= spi-nor.o
+72 −116
Original line number Diff line number Diff line
@@ -1463,14 +1463,6 @@ static void spi_nor_unlock_and_unprep_rd(struct spi_nor *nor, loff_t start, size
	spi_nor_unprep(nor);
}

static u32 spi_nor_convert_addr(struct spi_nor *nor, loff_t addr)
{
	if (!nor->params->convert_addr)
		return addr;

	return nor->params->convert_addr(nor, addr);
}

/*
 * Initiate the erasure of a single sector
 */
@@ -1478,8 +1470,6 @@ int spi_nor_erase_sector(struct spi_nor *nor, u32 addr)
{
	int i;

	addr = spi_nor_convert_addr(nor, addr);

	if (nor->spimem) {
		struct spi_mem_op op =
			SPI_NOR_SECTOR_ERASE_OP(nor->erase_opcode,
@@ -1986,7 +1976,6 @@ static const struct spi_nor_manufacturer *manufacturers[] = {
	&spi_nor_spansion,
	&spi_nor_sst,
	&spi_nor_winbond,
	&spi_nor_xilinx,
	&spi_nor_xmc,
};

@@ -2065,8 +2054,6 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
	while (len) {
		loff_t addr = from;

		addr = spi_nor_convert_addr(nor, addr);

		ret = spi_nor_read_data(nor, addr, len, buf);
		if (ret == 0) {
			/* We shouldn't see 0-length reads */
@@ -2099,7 +2086,7 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
	size_t *retlen, const u_char *buf)
{
	struct spi_nor *nor = mtd_to_spi_nor(mtd);
	size_t page_offset, page_remain, i;
	size_t i;
	ssize_t ret;
	u32 page_size = nor->params->page_size;

@@ -2112,23 +2099,9 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
	for (i = 0; i < len; ) {
		ssize_t written;
		loff_t addr = to + i;

		/*
		 * If page_size is a power of two, the offset can be quickly
		 * calculated with an AND operation. On the other cases we
		 * need to do a modulus operation (more expensive).
		 */
		if (is_power_of_2(page_size)) {
			page_offset = addr & (page_size - 1);
		} else {
			u64 aux = addr;

			page_offset = do_div(aux, page_size);
		}
		size_t page_offset = addr & (page_size - 1);
		/* the size of data remaining on the first page */
		page_remain = min_t(size_t, page_size - page_offset, len - i);

		addr = spi_nor_convert_addr(nor, addr);
		size_t page_remain = min_t(size_t, page_size - page_offset, len - i);

		ret = spi_nor_lock_device(nor);
		if (ret)
@@ -2581,7 +2554,50 @@ static int spi_nor_select_erase(struct spi_nor *nor)
	return 0;
}

static int spi_nor_default_setup(struct spi_nor *nor,
static int spi_nor_set_addr_nbytes(struct spi_nor *nor)
{
	if (nor->params->addr_nbytes) {
		nor->addr_nbytes = nor->params->addr_nbytes;
	} else if (nor->read_proto == SNOR_PROTO_8_8_8_DTR) {
		/*
		 * In 8D-8D-8D mode, one byte takes half a cycle to transfer. So
		 * in this protocol an odd addr_nbytes cannot be used because
		 * then the address phase would only span a cycle and a half.
		 * Half a cycle would be left over. We would then have to start
		 * the dummy phase in the middle of a cycle and so too the data
		 * phase, and we will end the transaction with half a cycle left
		 * over.
		 *
		 * Force all 8D-8D-8D flashes to use an addr_nbytes of 4 to
		 * avoid this situation.
		 */
		nor->addr_nbytes = 4;
	} else if (nor->info->addr_nbytes) {
		nor->addr_nbytes = nor->info->addr_nbytes;
	} else {
		nor->addr_nbytes = 3;
	}

	if (nor->addr_nbytes == 3 && nor->params->size > 0x1000000) {
		/* enable 4-byte addressing if the device exceeds 16MiB */
		nor->addr_nbytes = 4;
	}

	if (nor->addr_nbytes > SPI_NOR_MAX_ADDR_NBYTES) {
		dev_dbg(nor->dev, "The number of address bytes is too large: %u\n",
			nor->addr_nbytes);
		return -EINVAL;
	}

	/* Set 4byte opcodes when possible. */
	if (nor->addr_nbytes == 4 && nor->flags & SNOR_F_4B_OPCODES &&
	    !(nor->flags & SNOR_F_HAS_4BAIT))
		spi_nor_set_4byte_opcodes(nor);

	return 0;
}

static int spi_nor_setup(struct spi_nor *nor,
			 const struct spi_nor_hwcaps *hwcaps)
{
	struct spi_nor_flash_parameter *params = nor->params;
@@ -2639,64 +2655,6 @@ static int spi_nor_default_setup(struct spi_nor *nor,
		return err;
	}

	return 0;
}

static int spi_nor_set_addr_nbytes(struct spi_nor *nor)
{
	if (nor->params->addr_nbytes) {
		nor->addr_nbytes = nor->params->addr_nbytes;
	} else if (nor->read_proto == SNOR_PROTO_8_8_8_DTR) {
		/*
		 * In 8D-8D-8D mode, one byte takes half a cycle to transfer. So
		 * in this protocol an odd addr_nbytes cannot be used because
		 * then the address phase would only span a cycle and a half.
		 * Half a cycle would be left over. We would then have to start
		 * the dummy phase in the middle of a cycle and so too the data
		 * phase, and we will end the transaction with half a cycle left
		 * over.
		 *
		 * Force all 8D-8D-8D flashes to use an addr_nbytes of 4 to
		 * avoid this situation.
		 */
		nor->addr_nbytes = 4;
	} else if (nor->info->addr_nbytes) {
		nor->addr_nbytes = nor->info->addr_nbytes;
	} else {
		nor->addr_nbytes = 3;
	}

	if (nor->addr_nbytes == 3 && nor->params->size > 0x1000000) {
		/* enable 4-byte addressing if the device exceeds 16MiB */
		nor->addr_nbytes = 4;
	}

	if (nor->addr_nbytes > SPI_NOR_MAX_ADDR_NBYTES) {
		dev_dbg(nor->dev, "The number of address bytes is too large: %u\n",
			nor->addr_nbytes);
		return -EINVAL;
	}

	/* Set 4byte opcodes when possible. */
	if (nor->addr_nbytes == 4 && nor->flags & SNOR_F_4B_OPCODES &&
	    !(nor->flags & SNOR_F_HAS_4BAIT))
		spi_nor_set_4byte_opcodes(nor);

	return 0;
}

static int spi_nor_setup(struct spi_nor *nor,
			 const struct spi_nor_hwcaps *hwcaps)
{
	int ret;

	if (nor->params->setup)
		ret = nor->params->setup(nor, hwcaps);
	else
		ret = spi_nor_default_setup(nor, hwcaps);
	if (ret)
		return ret;

	return spi_nor_set_addr_nbytes(nor);
}

@@ -2965,15 +2923,10 @@ static void spi_nor_init_default_params(struct spi_nor *nor)
	params->page_size = info->page_size ?: SPI_NOR_DEFAULT_PAGE_SIZE;
	params->n_banks = info->n_banks ?: SPI_NOR_DEFAULT_N_BANKS;

	if (!(info->flags & SPI_NOR_NO_FR)) {
		/* Default to Fast Read for DT and non-DT platform devices. */
	/* Default to Fast Read for non-DT and enable it if requested by DT. */
	if (!np || of_property_read_bool(np, "m25p,fast-read"))
		params->hwcaps.mask |= SNOR_HWCAPS_READ_FAST;

		/* Mask out Fast Read if not requested at DT instantiation. */
		if (np && !of_property_read_bool(np, "m25p,fast-read"))
			params->hwcaps.mask &= ~SNOR_HWCAPS_READ_FAST;
	}

	/* (Fast) Read settings. */
	params->hwcaps.mask |= SNOR_HWCAPS_READ;
	spi_nor_set_read_settings(&params->reads[SNOR_CMD_READ],
@@ -3055,7 +3008,14 @@ static int spi_nor_init_params(struct spi_nor *nor)
		spi_nor_init_params_deprecated(nor);
	}

	return spi_nor_late_init_params(nor);
	ret = spi_nor_late_init_params(nor);
	if (ret)
		return ret;

	if (WARN_ON(!is_power_of_2(nor->params->page_size)))
		return -EINVAL;

	return 0;
}

/** spi_nor_set_octal_dtr() - enable or disable Octal DTR I/O.
@@ -3338,33 +3298,29 @@ static const struct flash_info *spi_nor_get_flash_info(struct spi_nor *nor,

	if (name)
		info = spi_nor_match_name(nor, name);
	/* Try to auto-detect if chip name wasn't specified or not found */
	if (!info)
		return spi_nor_detect(nor);

	/*
	 * If caller has specified name of flash model that can normally be
	 * detected using JEDEC, let's verify it.
	 * Auto-detect if chip name wasn't specified or not found, or the chip
	 * has an ID. If the chip supposedly has an ID, we also do an
	 * auto-detection to compare it later.
	 */
	if (name && info->id) {
	if (!info || info->id) {
		const struct flash_info *jinfo;

		jinfo = spi_nor_detect(nor);
		if (IS_ERR(jinfo)) {
		if (IS_ERR(jinfo))
			return jinfo;
		} else if (jinfo != info) {

		/*
			 * JEDEC knows better, so overwrite platform ID. We
			 * can't trust partitions any longer, but we'll let
			 * mtd apply them anyway, since some partitions may be
			 * marked read-only, and we don't want to loose that
			 * information, even if it's not 100% accurate.
		 * If caller has specified name of flash model that can normally
		 * be detected using JEDEC, let's verify it.
		 */
		if (info && jinfo != info)
			dev_warn(nor->dev, "found %s, expected %s\n",
				 jinfo->name, info->name);

		/* If info was set before, JEDEC knows better. */
		info = jinfo;
	}
	}

	return info;
}
+0 −12
Original line number Diff line number Diff line
@@ -366,13 +366,6 @@ struct spi_nor_otp {
 * @set_octal_dtr:	enables or disables SPI NOR octal DTR mode.
 * @quad_enable:	enables SPI NOR quad mode.
 * @set_4byte_addr_mode: puts the SPI NOR in 4 byte addressing mode.
 * @convert_addr:	converts an absolute address into something the flash
 *                      will understand. Particularly useful when pagesize is
 *                      not a power-of-2.
 * @setup:		(optional) configures the SPI NOR memory. Useful for
 *			SPI NOR flashes that have peculiarities to the SPI NOR
 *			standard e.g. different opcodes, specific address
 *			calculation, page size, etc.
 * @ready:		(optional) flashes might use a different mechanism
 *			than reading the status register to indicate they
 *			are ready for a new command
@@ -403,8 +396,6 @@ struct spi_nor_flash_parameter {
	int (*set_octal_dtr)(struct spi_nor *nor, bool enable);
	int (*quad_enable)(struct spi_nor *nor);
	int (*set_4byte_addr_mode)(struct spi_nor *nor, bool enable);
	u32 (*convert_addr)(struct spi_nor *nor, u32 addr);
	int (*setup)(struct spi_nor *nor, const struct spi_nor_hwcaps *hwcaps);
	int (*ready)(struct spi_nor *nor);

	const struct spi_nor_locking_ops *locking_ops;
@@ -479,7 +470,6 @@ struct spi_nor_id {
 *                            Usually these will power-up in a write-protected
 *                            state.
 *   SPI_NOR_NO_ERASE:        no erase command needed.
 *   SPI_NOR_NO_FR:           can't do fastread.
 *   SPI_NOR_QUAD_PP:         flash supports Quad Input Page Program.
 *   SPI_NOR_RWW:             flash supports reads while write.
 *
@@ -528,7 +518,6 @@ struct flash_info {
#define SPI_NOR_BP3_SR_BIT6		BIT(4)
#define SPI_NOR_SWP_IS_VOLATILE		BIT(5)
#define SPI_NOR_NO_ERASE		BIT(6)
#define SPI_NOR_NO_FR			BIT(7)
#define SPI_NOR_QUAD_PP			BIT(8)
#define SPI_NOR_RWW			BIT(9)

@@ -603,7 +592,6 @@ extern const struct spi_nor_manufacturer spi_nor_st;
extern const struct spi_nor_manufacturer spi_nor_spansion;
extern const struct spi_nor_manufacturer spi_nor_sst;
extern const struct spi_nor_manufacturer spi_nor_winbond;
extern const struct spi_nor_manufacturer spi_nor_xilinx;
extern const struct spi_nor_manufacturer spi_nor_xmc;

extern const struct attribute_group *spi_nor_sysfs_groups[];
+15 −4
Original line number Diff line number Diff line
@@ -14,28 +14,39 @@ static const struct flash_info everspin_nor_parts[] = {
		.size = SZ_16K,
		.sector_size = SZ_16K,
		.addr_nbytes = 2,
		.flags = SPI_NOR_NO_ERASE | SPI_NOR_NO_FR,
		.flags = SPI_NOR_NO_ERASE,
	}, {
		.name = "mr25h256",
		.size = SZ_32K,
		.sector_size = SZ_32K,
		.addr_nbytes = 2,
		.flags = SPI_NOR_NO_ERASE | SPI_NOR_NO_FR,
		.flags = SPI_NOR_NO_ERASE,
	}, {
		.name = "mr25h10",
		.size = SZ_128K,
		.sector_size = SZ_128K,
		.flags = SPI_NOR_NO_ERASE | SPI_NOR_NO_FR,
		.flags = SPI_NOR_NO_ERASE,
	}, {
		.name = "mr25h40",
		.size = SZ_512K,
		.sector_size = SZ_512K,
		.flags = SPI_NOR_NO_ERASE | SPI_NOR_NO_FR,
		.flags = SPI_NOR_NO_ERASE,
	}
};

static void everspin_nor_default_init(struct spi_nor *nor)
{
	/* Everspin FRAMs don't support the fast read opcode. */
	nor->params->hwcaps.mask &= ~SNOR_HWCAPS_READ_FAST;
}

static const struct spi_nor_fixups everspin_nor_fixups = {
	.default_init = everspin_nor_default_init,
};

const struct spi_nor_manufacturer spi_nor_everspin = {
	.name = "everspin",
	.parts = everspin_nor_parts,
	.nparts = ARRAY_SIZE(everspin_nor_parts),
	.fixups = &everspin_nor_fixups,
};
+2 −0
Original line number Diff line number Diff line
@@ -105,7 +105,9 @@ static const struct flash_info winbond_nor_parts[] = {
	}, {
		.id = SNOR_ID(0xef, 0x40, 0x18),
		.name = "w25q128",
		.size = SZ_16M,
		.flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB,
		.no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
	}, {
		.id = SNOR_ID(0xef, 0x40, 0x19),
		.name = "w25q256",
Loading