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

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
...@@ -4662,7 +4662,6 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type) ...@@ -4662,7 +4662,6 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
memorg = nanddev_get_memorg(&chip->base); memorg = nanddev_get_memorg(&chip->base);
memorg->planes_per_lun = 1; memorg->planes_per_lun = 1;
memorg->luns_per_target = 1; memorg->luns_per_target = 1;
memorg->ntargets = 1;
/* /*
* Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx) * 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, ...@@ -5027,6 +5026,8 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips,
if (ret) if (ret)
return ret; return ret;
memorg->ntargets = maxchips;
/* Read the flash type */ /* Read the flash type */
ret = nand_detect(chip, table); ret = nand_detect(chip, table);
if (ret) { if (ret) {
......
...@@ -1636,6 +1636,95 @@ static int sr2_bit7_quad_enable(struct spi_nor *nor) ...@@ -1636,6 +1636,95 @@ static int sr2_bit7_quad_enable(struct spi_nor *nor)
return 0; 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 */ /* Used when the "_ext_id" is two bytes at most */
#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \
.id = { \ .id = { \
...@@ -3660,6 +3749,8 @@ static int spi_nor_init_params(struct spi_nor *nor, ...@@ -3660,6 +3749,8 @@ static int spi_nor_init_params(struct spi_nor *nor,
default: default:
/* Kept only for backward compatibility purpose. */ /* Kept only for backward compatibility purpose. */
params->quad_enable = spansion_quad_enable; params->quad_enable = spansion_quad_enable;
if (nor->clear_sr_bp)
nor->clear_sr_bp = spi_nor_spansion_clear_sr_bp;
break; break;
} }
...@@ -3912,17 +4003,13 @@ static int spi_nor_init(struct spi_nor *nor) ...@@ -3912,17 +4003,13 @@ static int spi_nor_init(struct spi_nor *nor)
{ {
int err; int err;
/* if (nor->clear_sr_bp) {
* Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up err = nor->clear_sr_bp(nor);
* with the software protection bits set if (err) {
*/ dev_err(nor->dev,
if (JEDEC_MFR(nor->info) == SNOR_MFR_ATMEL || "fail to clear block protection bits\n");
JEDEC_MFR(nor->info) == SNOR_MFR_INTEL || return err;
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->quad_enable) { if (nor->quad_enable) {
...@@ -4047,6 +4134,16 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, ...@@ -4047,6 +4134,16 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
if (info->flags & SPI_S3AN) if (info->flags & SPI_S3AN)
nor->flags |= SNOR_F_READY_XSR_RDY; 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. */ /* Parse the Serial Flash Discoverable Parameters table. */
ret = spi_nor_init_params(nor, &params); ret = spi_nor_init_params(nor, &params);
if (ret) if (ret)
......
...@@ -373,6 +373,8 @@ struct flash_info; ...@@ -373,6 +373,8 @@ struct flash_info;
* @flash_unlock: [FLASH-SPECIFIC] unlock a region of the SPI NOR * @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 * @flash_is_locked: [FLASH-SPECIFIC] check if a region of the SPI NOR is
* @quad_enable: [FLASH-SPECIFIC] enables SPI NOR quad mode * @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 * completely locked
* @priv: the private data * @priv: the private data
*/ */
...@@ -410,6 +412,7 @@ struct spi_nor { ...@@ -410,6 +412,7 @@ struct spi_nor {
int (*flash_unlock)(struct spi_nor *nor, loff_t ofs, uint64_t len); 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 (*flash_is_locked)(struct spi_nor *nor, loff_t ofs, uint64_t len);
int (*quad_enable)(struct spi_nor *nor); int (*quad_enable)(struct spi_nor *nor);
int (*clear_sr_bp)(struct spi_nor *nor);
void *priv; void *priv;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment