Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 39071cf8 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'mtd/fixes-for-5.2-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux

Pull mtd fixes from Miquel Raynal:

 - Set the raw NAND number of targets to the right value

 - Fix a bug uncovered by a recent patch on Spansion SPI-NOR flashes

* tag 'mtd/fixes-for-5.2-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux:
  mtd: spi-nor: use 16-bit WRR command when QE is set on spansion flashes
  mtd: rawnand: initialize ntargets with maxchips
parents 26df62aa 191f5c2e
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -4662,7 +4662,6 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
	memorg = nanddev_get_memorg(&chip->base);
	memorg->planes_per_lun = 1;
	memorg->luns_per_target = 1;
	memorg->ntargets = 1;

	/*
	 * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
@@ -5027,6 +5026,8 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips,
	if (ret)
		return ret;

	memorg->ntargets = maxchips;

	/* Read the flash type */
	ret = nand_detect(chip, table);
	if (ret) {
+108 −11
Original line number Diff line number Diff line
@@ -1636,6 +1636,95 @@ static int sr2_bit7_quad_enable(struct spi_nor *nor)
	return 0;
}

/**
 * spi_nor_clear_sr_bp() - clear the Status Register Block Protection bits.
 * @nor:        pointer to a 'struct spi_nor'
 *
 * Read-modify-write function that clears the Block Protection bits from the
 * Status Register without affecting other bits.
 *
 * Return: 0 on success, -errno otherwise.
 */
static int spi_nor_clear_sr_bp(struct spi_nor *nor)
{
	int ret;
	u8 mask = SR_BP2 | SR_BP1 | SR_BP0;

	ret = read_sr(nor);
	if (ret < 0) {
		dev_err(nor->dev, "error while reading status register\n");
		return ret;
	}

	write_enable(nor);

	ret = write_sr(nor, ret & ~mask);
	if (ret) {
		dev_err(nor->dev, "write to status register failed\n");
		return ret;
	}

	ret = spi_nor_wait_till_ready(nor);
	if (ret)
		dev_err(nor->dev, "timeout while writing status register\n");
	return ret;
}

/**
 * spi_nor_spansion_clear_sr_bp() - clear the Status Register Block Protection
 * bits on spansion flashes.
 * @nor:        pointer to a 'struct spi_nor'
 *
 * Read-modify-write function that clears the Block Protection bits from the
 * Status Register without affecting other bits. The function is tightly
 * coupled with the spansion_quad_enable() function. Both assume that the Write
 * Register with 16 bits, together with the Read Configuration Register (35h)
 * instructions are supported.
 *
 * Return: 0 on success, -errno otherwise.
 */
static int spi_nor_spansion_clear_sr_bp(struct spi_nor *nor)
{
	int ret;
	u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
	u8 sr_cr[2] = {0};

	/* Check current Quad Enable bit value. */
	ret = read_cr(nor);
	if (ret < 0) {
		dev_err(nor->dev,
			"error while reading configuration register\n");
		return ret;
	}

	/*
	 * When the configuration register Quad Enable bit is one, only the
	 * Write Status (01h) command with two data bytes may be used.
	 */
	if (ret & CR_QUAD_EN_SPAN) {
		sr_cr[1] = ret;

		ret = read_sr(nor);
		if (ret < 0) {
			dev_err(nor->dev,
				"error while reading status register\n");
			return ret;
		}
		sr_cr[0] = ret & ~mask;

		ret = write_sr_cr(nor, sr_cr);
		if (ret)
			dev_err(nor->dev, "16-bit write register failed\n");
		return ret;
	}

	/*
	 * If the Quad Enable bit is zero, use the Write Status (01h) command
	 * with one data byte.
	 */
	return spi_nor_clear_sr_bp(nor);
}

/* Used when the "_ext_id" is two bytes at most */
#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)	\
		.id = {							\
@@ -3660,6 +3749,8 @@ static int spi_nor_init_params(struct spi_nor *nor,
		default:
			/* Kept only for backward compatibility purpose. */
			params->quad_enable = spansion_quad_enable;
			if (nor->clear_sr_bp)
				nor->clear_sr_bp = spi_nor_spansion_clear_sr_bp;
			break;
		}

@@ -3912,17 +4003,13 @@ static int spi_nor_init(struct spi_nor *nor)
{
	int err;

	/*
	 * Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up
	 * with the software protection bits set
	 */
	if (JEDEC_MFR(nor->info) == SNOR_MFR_ATMEL ||
	    JEDEC_MFR(nor->info) == SNOR_MFR_INTEL ||
	    JEDEC_MFR(nor->info) == SNOR_MFR_SST ||
	    nor->info->flags & SPI_NOR_HAS_LOCK) {
		write_enable(nor);
		write_sr(nor, 0);
		spi_nor_wait_till_ready(nor);
	if (nor->clear_sr_bp) {
		err = nor->clear_sr_bp(nor);
		if (err) {
			dev_err(nor->dev,
				"fail to clear block protection bits\n");
			return err;
		}
	}

	if (nor->quad_enable) {
@@ -4047,6 +4134,16 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
	if (info->flags & SPI_S3AN)
		nor->flags |=  SNOR_F_READY_XSR_RDY;

	/*
	 * Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up
	 * with the software protection bits set.
	 */
	if (JEDEC_MFR(nor->info) == SNOR_MFR_ATMEL ||
	    JEDEC_MFR(nor->info) == SNOR_MFR_INTEL ||
	    JEDEC_MFR(nor->info) == SNOR_MFR_SST ||
	    nor->info->flags & SPI_NOR_HAS_LOCK)
		nor->clear_sr_bp = spi_nor_clear_sr_bp;

	/* Parse the Serial Flash Discoverable Parameters table. */
	ret = spi_nor_init_params(nor, &params);
	if (ret)
+3 −0
Original line number Diff line number Diff line
@@ -373,6 +373,8 @@ struct flash_info;
 * @flash_unlock:	[FLASH-SPECIFIC] unlock a region of the SPI NOR
 * @flash_is_locked:	[FLASH-SPECIFIC] check if a region of the SPI NOR is
 * @quad_enable:	[FLASH-SPECIFIC] enables SPI NOR quad mode
 * @clear_sr_bp:	[FLASH-SPECIFIC] clears the Block Protection Bits from
 *			the SPI NOR Status Register.
 *			completely locked
 * @priv:		the private data
 */
@@ -410,6 +412,7 @@ struct spi_nor {
	int (*flash_unlock)(struct spi_nor *nor, loff_t ofs, uint64_t len);
	int (*flash_is_locked)(struct spi_nor *nor, loff_t ofs, uint64_t len);
	int (*quad_enable)(struct spi_nor *nor);
	int (*clear_sr_bp)(struct spi_nor *nor);

	void *priv;
};