Skip to content

Commit 3e0930f

Browse files
committed
mtd: spi-nor: Rework the disabling of block write protection
spi_nor_unlock() unlocks blocks of memory or the entire flash memory array, if requested. clear_sr_bp() unlocks the entire flash memory array at boot time. This calls for some unification, clear_sr_bp() is just an optimization for the case when the unlock request covers the entire flash size. Get rid of clear_sr_bp() and introduce spi_nor_unlock_all(), which is just a call to spi_nor_unlock() for the entire flash memory array. This fixes a bug that was present in spi_nor_spansion_clear_sr_bp(). When the QE bit was zero, we used the Write Status (01h) command with one data byte, which might cleared the Status Register 2. We now always use the Write Status (01h) command with two data bytes when SNOR_F_HAS_16BIT_SR is set, to avoid clearing the Status Register 2. The SNOR_F_NO_READ_CR case is treated as well. When the flash doesn't support the CR Read command, we make an assumption about the value of the QE bit. In spi_nor_init(), call spi_nor_quad_enable() first, then spi_nor_unlock_all(), so that at the spi_nor_unlock_all() time we can be sure the QE bit has value one, because of the previous call to spi_nor_quad_enable(). Get rid of the MFR handling and implement specific manufacturer default_init() fixup hooks. Note that this changes a bit the logic for the SNOR_MFR_ATMEL, SNOR_MFR_INTEL and SNOR_MFR_SST cases. Before this patch, the Atmel, Intel and SST chips did not set the locking ops, but unlocked the entire flash at boot time, while now they are setting the locking ops to stm_locking_ops. This should work, since the disable of the block protection at the boot time used the same Status Register bits to unlock the flash, as in the stm_locking_ops case. Suggested-by: Boris Brezillon <boris.brezillon@collabora.com> Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com> Reviewed-by: Vignesh Raghavendra <vigneshr@ti.com>
1 parent 39d1e33 commit 3e0930f

File tree

2 files changed

+50
-93
lines changed

2 files changed

+50
-93
lines changed

drivers/mtd/spi-nor/spi-nor.c

Lines changed: 50 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -2185,74 +2185,6 @@ static int sr2_bit7_quad_enable(struct spi_nor *nor)
21852185
return 0;
21862186
}
21872187

2188-
/**
2189-
* spi_nor_clear_sr_bp() - clear the Status Register Block Protection bits.
2190-
* @nor: pointer to a 'struct spi_nor'
2191-
*
2192-
* Read-modify-write function that clears the Block Protection bits from the
2193-
* Status Register without affecting other bits.
2194-
*
2195-
* Return: 0 on success, -errno otherwise.
2196-
*/
2197-
static int spi_nor_clear_sr_bp(struct spi_nor *nor)
2198-
{
2199-
int ret;
2200-
u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
2201-
2202-
ret = spi_nor_read_sr(nor, nor->bouncebuf);
2203-
if (ret)
2204-
return ret;
2205-
2206-
nor->bouncebuf[0] &= ~mask;
2207-
2208-
return spi_nor_write_sr(nor, nor->bouncebuf, 1);
2209-
}
2210-
2211-
/**
2212-
* spi_nor_spansion_clear_sr_bp() - clear the Status Register Block Protection
2213-
* bits on spansion flashes.
2214-
* @nor: pointer to a 'struct spi_nor'
2215-
*
2216-
* Read-modify-write function that clears the Block Protection bits from the
2217-
* Status Register without affecting other bits. The function is tightly
2218-
* coupled with the spansion_read_cr_quad_enable() function. Both assume that
2219-
* the Write Register with 16 bits, together with the Read Configuration
2220-
* Register (35h) instructions are supported.
2221-
*
2222-
* Return: 0 on success, -errno otherwise.
2223-
*/
2224-
static int spi_nor_spansion_clear_sr_bp(struct spi_nor *nor)
2225-
{
2226-
int ret;
2227-
u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
2228-
u8 *sr_cr = nor->bouncebuf;
2229-
2230-
/* Check current Quad Enable bit value. */
2231-
ret = spi_nor_read_cr(nor, &sr_cr[1]);
2232-
if (ret)
2233-
return ret;
2234-
2235-
/*
2236-
* When the configuration register Quad Enable bit is one, only the
2237-
* Write Status (01h) command with two data bytes may be used.
2238-
*/
2239-
if (sr_cr[1] & CR_QUAD_EN_SPAN) {
2240-
ret = spi_nor_read_sr(nor, sr_cr);
2241-
if (ret)
2242-
return ret;
2243-
2244-
sr_cr[0] &= ~mask;
2245-
2246-
return spi_nor_write_sr(nor, sr_cr, 2);
2247-
}
2248-
2249-
/*
2250-
* If the Quad Enable bit is zero, use the Write Status (01h) command
2251-
* with one data byte.
2252-
*/
2253-
return spi_nor_clear_sr_bp(nor);
2254-
}
2255-
22562188
/* Used when the "_ext_id" is two bytes at most */
22572189
#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \
22582190
.id = { \
@@ -4634,12 +4566,27 @@ static int spi_nor_setup(struct spi_nor *nor,
46344566
return nor->params.setup(nor, hwcaps);
46354567
}
46364568

4569+
static void atmel_set_default_init(struct spi_nor *nor)
4570+
{
4571+
nor->flags |= SNOR_F_HAS_LOCK;
4572+
}
4573+
4574+
static void intel_set_default_init(struct spi_nor *nor)
4575+
{
4576+
nor->flags |= SNOR_F_HAS_LOCK;
4577+
}
4578+
46374579
static void macronix_set_default_init(struct spi_nor *nor)
46384580
{
46394581
nor->params.quad_enable = macronix_quad_enable;
46404582
nor->params.set_4byte = macronix_set_4byte;
46414583
}
46424584

4585+
static void sst_set_default_init(struct spi_nor *nor)
4586+
{
4587+
nor->flags |= SNOR_F_HAS_LOCK;
4588+
}
4589+
46434590
static void st_micron_set_default_init(struct spi_nor *nor)
46444591
{
46454592
nor->flags |= SNOR_F_HAS_LOCK;
@@ -4661,6 +4608,14 @@ static void spi_nor_manufacturer_init_params(struct spi_nor *nor)
46614608
{
46624609
/* Init flash parameters based on MFR */
46634610
switch (JEDEC_MFR(nor->info)) {
4611+
case SNOR_MFR_ATMEL:
4612+
atmel_set_default_init(nor);
4613+
break;
4614+
4615+
case SNOR_MFR_INTEL:
4616+
intel_set_default_init(nor);
4617+
break;
4618+
46644619
case SNOR_MFR_MACRONIX:
46654620
macronix_set_default_init(nor);
46664621
break;
@@ -4670,6 +4625,10 @@ static void spi_nor_manufacturer_init_params(struct spi_nor *nor)
46704625
st_micron_set_default_init(nor);
46714626
break;
46724627

4628+
case SNOR_MFR_SST:
4629+
sst_set_default_init(nor);
4630+
break;
4631+
46734632
case SNOR_MFR_WINBOND:
46744633
winbond_set_default_init(nor);
46754634
break;
@@ -4930,28 +4889,39 @@ static int spi_nor_quad_enable(struct spi_nor *nor)
49304889
return nor->params.quad_enable(nor);
49314890
}
49324891

4933-
static int spi_nor_init(struct spi_nor *nor)
4892+
/**
4893+
* spi_nor_unlock_all() - Unlocks the entire flash memory array.
4894+
* @nor: pointer to a 'struct spi_nor'.
4895+
*
4896+
* Some SPI NOR flashes are write protected by default after a power-on reset
4897+
* cycle, in order to avoid inadvertent writes during power-up. Backward
4898+
* compatibility imposes to unlock the entire flash memory array at power-up
4899+
* by default.
4900+
*/
4901+
static int spi_nor_unlock_all(struct spi_nor *nor)
49344902
{
4935-
int err;
4903+
if (nor->flags & SNOR_F_HAS_LOCK)
4904+
return spi_nor_unlock(&nor->mtd, 0, nor->params.size);
49364905

4937-
if (nor->clear_sr_bp) {
4938-
if (nor->params.quad_enable == spansion_read_cr_quad_enable)
4939-
nor->clear_sr_bp = spi_nor_spansion_clear_sr_bp;
4906+
return 0;
4907+
}
49404908

4941-
err = nor->clear_sr_bp(nor);
4942-
if (err) {
4943-
dev_dbg(nor->dev,
4944-
"fail to clear block protection bits\n");
4945-
return err;
4946-
}
4947-
}
4909+
static int spi_nor_init(struct spi_nor *nor)
4910+
{
4911+
int err;
49484912

49494913
err = spi_nor_quad_enable(nor);
49504914
if (err) {
49514915
dev_dbg(nor->dev, "quad mode not supported\n");
49524916
return err;
49534917
}
49544918

4919+
err = spi_nor_unlock_all(nor);
4920+
if (err) {
4921+
dev_dbg(nor->dev, "Failed to unlock the entire flash memory array\n");
4922+
return err;
4923+
}
4924+
49554925
if (nor->addr_width == 4 && !(nor->flags & SNOR_F_4B_OPCODES)) {
49564926
/*
49574927
* If the RESET# pin isn't hooked up properly, or the system
@@ -5134,16 +5104,6 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
51345104
if (info->flags & SPI_NOR_HAS_LOCK)
51355105
nor->flags |= SNOR_F_HAS_LOCK;
51365106

5137-
/*
5138-
* Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up
5139-
* with the software protection bits set.
5140-
*/
5141-
if (JEDEC_MFR(nor->info) == SNOR_MFR_ATMEL ||
5142-
JEDEC_MFR(nor->info) == SNOR_MFR_INTEL ||
5143-
JEDEC_MFR(nor->info) == SNOR_MFR_SST ||
5144-
nor->info->flags & SPI_NOR_HAS_LOCK)
5145-
nor->clear_sr_bp = spi_nor_clear_sr_bp;
5146-
51475107
/* Init flash parameters based on flash_info struct and SFDP */
51485108
spi_nor_init_params(nor);
51495109

include/linux/mtd/spi-nor.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -581,8 +581,6 @@ struct flash_info;
581581
* @write_proto: the SPI protocol for write operations
582582
* @reg_proto the SPI protocol for read_reg/write_reg/erase operations
583583
* @controller_ops: SPI NOR controller driver specific operations.
584-
* @clear_sr_bp: [FLASH-SPECIFIC] clears the Block Protection Bits from
585-
* the SPI NOR Status Register.
586584
* @params: [FLASH-SPECIFIC] SPI-NOR flash parameters and settings.
587585
* The structure includes legacy flash parameters and
588586
* settings that can be overwritten by the spi_nor_fixups
@@ -611,7 +609,6 @@ struct spi_nor {
611609

612610
const struct spi_nor_controller_ops *controller_ops;
613611

614-
int (*clear_sr_bp)(struct spi_nor *nor);
615612
struct spi_nor_flash_parameter params;
616613

617614
void *priv;

0 commit comments

Comments
 (0)