mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-30 06:10:56 +00:00
mtd: spi-nor: move all micron-st specifics into micron-st.c
The flag status register is only available on micron flashes. Move all the functions around that into the micron module. This is almost a mechanical move except for the spi_nor_fsr_ready() which now also checks the normal status register. Previously, this was done in spi_nor_ready(). Signed-off-by: Michael Walle <michael@walle.cc> Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com> Tested-by: Pratyush Yadav <p.yadav@ti.com> # on mt35xu512aba, s28hs512t Reviewed-by: Pratyush Yadav <p.yadav@ti.com> Link: https://lore.kernel.org/r/20220223134358.1914798-25-michael@walle.cc
This commit is contained in:
parent
56b852e863
commit
c770abe52d
3 changed files with 135 additions and 130 deletions
|
@ -412,50 +412,6 @@ int spi_nor_read_sr(struct spi_nor *nor, u8 *sr)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* spi_nor_read_fsr() - Read the Flag Status Register.
|
||||
* @nor: pointer to 'struct spi_nor'
|
||||
* @fsr: pointer to a DMA-able buffer where the value of the
|
||||
* Flag Status Register will be written. Should be at least 2
|
||||
* bytes.
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise.
|
||||
*/
|
||||
static int spi_nor_read_fsr(struct spi_nor *nor, u8 *fsr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (nor->spimem) {
|
||||
struct spi_mem_op op =
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDFSR, 0),
|
||||
SPI_MEM_OP_NO_ADDR,
|
||||
SPI_MEM_OP_NO_DUMMY,
|
||||
SPI_MEM_OP_DATA_IN(1, fsr, 0));
|
||||
|
||||
if (nor->reg_proto == SNOR_PROTO_8_8_8_DTR) {
|
||||
op.addr.nbytes = nor->params->rdsr_addr_nbytes;
|
||||
op.dummy.nbytes = nor->params->rdsr_dummy;
|
||||
/*
|
||||
* We don't want to read only one byte in DTR mode. So,
|
||||
* read 2 and then discard the second byte.
|
||||
*/
|
||||
op.data.nbytes = 2;
|
||||
}
|
||||
|
||||
spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
|
||||
|
||||
ret = spi_mem_exec_op(nor->spimem, &op);
|
||||
} else {
|
||||
ret = spi_nor_controller_ops_read_reg(nor, SPINOR_OP_RDFSR, fsr,
|
||||
1);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
dev_dbg(nor->dev, "error %d reading FSR\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* spi_nor_read_cr() - Read the Configuration Register using the
|
||||
* SPINOR_OP_RDCR (35h) command.
|
||||
|
@ -664,75 +620,6 @@ int spi_nor_sr_ready(struct spi_nor *nor)
|
|||
return !(nor->bouncebuf[0] & SR_WIP);
|
||||
}
|
||||
|
||||
/**
|
||||
* spi_nor_clear_fsr() - Clear the Flag Status Register.
|
||||
* @nor: pointer to 'struct spi_nor'.
|
||||
*/
|
||||
static void spi_nor_clear_fsr(struct spi_nor *nor)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (nor->spimem) {
|
||||
struct spi_mem_op op =
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_CLFSR, 0),
|
||||
SPI_MEM_OP_NO_ADDR,
|
||||
SPI_MEM_OP_NO_DUMMY,
|
||||
SPI_MEM_OP_NO_DATA);
|
||||
|
||||
spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
|
||||
|
||||
ret = spi_mem_exec_op(nor->spimem, &op);
|
||||
} else {
|
||||
ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_CLFSR,
|
||||
NULL, 0);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
dev_dbg(nor->dev, "error %d clearing FSR\n", ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* spi_nor_fsr_ready() - Query the Flag Status Register to see if the flash is
|
||||
* ready for new commands.
|
||||
* @nor: pointer to 'struct spi_nor'.
|
||||
*
|
||||
* Return: 1 if ready, 0 if not ready, -errno on errors.
|
||||
*/
|
||||
static int spi_nor_fsr_ready(struct spi_nor *nor)
|
||||
{
|
||||
int ret = spi_nor_read_fsr(nor, nor->bouncebuf);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (nor->bouncebuf[0] & (FSR_E_ERR | FSR_P_ERR)) {
|
||||
if (nor->bouncebuf[0] & FSR_E_ERR)
|
||||
dev_err(nor->dev, "Erase operation failed.\n");
|
||||
else
|
||||
dev_err(nor->dev, "Program operation failed.\n");
|
||||
|
||||
if (nor->bouncebuf[0] & FSR_PT_ERR)
|
||||
dev_err(nor->dev,
|
||||
"Attempted to modify a protected sector.\n");
|
||||
|
||||
spi_nor_clear_fsr(nor);
|
||||
|
||||
/*
|
||||
* WEL bit remains set to one when an erase or page program
|
||||
* error occurs. Issue a Write Disable command to protect
|
||||
* against inadvertent writes that can possibly corrupt the
|
||||
* contents of the memory.
|
||||
*/
|
||||
ret = spi_nor_write_disable(nor);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return !!(nor->bouncebuf[0] & FSR_READY);
|
||||
}
|
||||
|
||||
/**
|
||||
* spi_nor_ready() - Query the flash to see if it is ready for new commands.
|
||||
* @nor: pointer to 'struct spi_nor'.
|
||||
|
@ -741,19 +628,11 @@ static int spi_nor_fsr_ready(struct spi_nor *nor)
|
|||
*/
|
||||
static int spi_nor_ready(struct spi_nor *nor)
|
||||
{
|
||||
int sr, fsr;
|
||||
|
||||
/* Flashes might override the standard routine. */
|
||||
if (nor->params->ready)
|
||||
return nor->params->ready(nor);
|
||||
|
||||
sr = spi_nor_sr_ready(nor);
|
||||
if (sr < 0)
|
||||
return sr;
|
||||
fsr = nor->flags & SNOR_F_USE_FSR ? spi_nor_fsr_ready(nor) : 1;
|
||||
if (fsr < 0)
|
||||
return fsr;
|
||||
return sr && fsr;
|
||||
return spi_nor_sr_ready(nor);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
#include "core.h"
|
||||
|
||||
#define SPINOR_OP_RDFSR 0x70 /* Read flag status register */
|
||||
#define SPINOR_OP_CLFSR 0x50 /* Clear flag status register */
|
||||
#define SPINOR_OP_MT_DTR_RD 0xfd /* Fast Read opcode in DTR mode */
|
||||
#define SPINOR_OP_MT_RD_ANY_REG 0x85 /* Read volatile register */
|
||||
#define SPINOR_OP_MT_WR_ANY_REG 0x81 /* Write volatile register */
|
||||
|
@ -17,6 +19,12 @@
|
|||
#define SPINOR_MT_OCT_DTR 0xe7 /* Enable Octal DTR. */
|
||||
#define SPINOR_MT_EXSPI 0xff /* Enable Extended SPI (default) */
|
||||
|
||||
/* Flag Status Register bits */
|
||||
#define FSR_READY BIT(7) /* Device status, 0 = Busy, 1 = Ready */
|
||||
#define FSR_E_ERR BIT(5) /* Erase operation status */
|
||||
#define FSR_P_ERR BIT(4) /* Program operation status */
|
||||
#define FSR_PT_ERR BIT(1) /* Protection error bit */
|
||||
|
||||
static int micron_st_nor_octal_dtr_enable(struct spi_nor *nor, bool enable)
|
||||
{
|
||||
struct spi_mem_op op;
|
||||
|
@ -273,6 +281,125 @@ static int micron_st_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable)
|
|||
return spi_nor_write_disable(nor);
|
||||
}
|
||||
|
||||
/**
|
||||
* spi_nor_read_fsr() - Read the Flag Status Register.
|
||||
* @nor: pointer to 'struct spi_nor'
|
||||
* @fsr: pointer to a DMA-able buffer where the value of the
|
||||
* Flag Status Register will be written. Should be at least 2
|
||||
* bytes.
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise.
|
||||
*/
|
||||
static int spi_nor_read_fsr(struct spi_nor *nor, u8 *fsr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (nor->spimem) {
|
||||
struct spi_mem_op op =
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDFSR, 0),
|
||||
SPI_MEM_OP_NO_ADDR,
|
||||
SPI_MEM_OP_NO_DUMMY,
|
||||
SPI_MEM_OP_DATA_IN(1, fsr, 0));
|
||||
|
||||
if (nor->reg_proto == SNOR_PROTO_8_8_8_DTR) {
|
||||
op.addr.nbytes = nor->params->rdsr_addr_nbytes;
|
||||
op.dummy.nbytes = nor->params->rdsr_dummy;
|
||||
/*
|
||||
* We don't want to read only one byte in DTR mode. So,
|
||||
* read 2 and then discard the second byte.
|
||||
*/
|
||||
op.data.nbytes = 2;
|
||||
}
|
||||
|
||||
spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
|
||||
|
||||
ret = spi_mem_exec_op(nor->spimem, &op);
|
||||
} else {
|
||||
ret = spi_nor_controller_ops_read_reg(nor, SPINOR_OP_RDFSR, fsr,
|
||||
1);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
dev_dbg(nor->dev, "error %d reading FSR\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* spi_nor_clear_fsr() - Clear the Flag Status Register.
|
||||
* @nor: pointer to 'struct spi_nor'.
|
||||
*/
|
||||
static void spi_nor_clear_fsr(struct spi_nor *nor)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (nor->spimem) {
|
||||
struct spi_mem_op op =
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_CLFSR, 0),
|
||||
SPI_MEM_OP_NO_ADDR,
|
||||
SPI_MEM_OP_NO_DUMMY,
|
||||
SPI_MEM_OP_NO_DATA);
|
||||
|
||||
spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
|
||||
|
||||
ret = spi_mem_exec_op(nor->spimem, &op);
|
||||
} else {
|
||||
ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_CLFSR,
|
||||
NULL, 0);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
dev_dbg(nor->dev, "error %d clearing FSR\n", ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* spi_nor_fsr_ready() - Query the Status Register as well as the Flag Status
|
||||
* Register to see if the flash is ready for new commands. If there are any
|
||||
* errors in the FSR clear them.
|
||||
* @nor: pointer to 'struct spi_nor'.
|
||||
*
|
||||
* Return: 1 if ready, 0 if not ready, -errno on errors.
|
||||
*/
|
||||
static int spi_nor_fsr_ready(struct spi_nor *nor)
|
||||
{
|
||||
int sr_ready, ret;
|
||||
|
||||
sr_ready = spi_nor_sr_ready(nor);
|
||||
if (sr_ready < 0)
|
||||
return sr_ready;
|
||||
|
||||
ret = spi_nor_read_fsr(nor, nor->bouncebuf);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (nor->bouncebuf[0] & (FSR_E_ERR | FSR_P_ERR)) {
|
||||
if (nor->bouncebuf[0] & FSR_E_ERR)
|
||||
dev_err(nor->dev, "Erase operation failed.\n");
|
||||
else
|
||||
dev_err(nor->dev, "Program operation failed.\n");
|
||||
|
||||
if (nor->bouncebuf[0] & FSR_PT_ERR)
|
||||
dev_err(nor->dev,
|
||||
"Attempted to modify a protected sector.\n");
|
||||
|
||||
spi_nor_clear_fsr(nor);
|
||||
|
||||
/*
|
||||
* WEL bit remains set to one when an erase or page program
|
||||
* error occurs. Issue a Write Disable command to protect
|
||||
* against inadvertent writes that can possibly corrupt the
|
||||
* contents of the memory.
|
||||
*/
|
||||
ret = spi_nor_write_disable(nor);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return sr_ready && !!(nor->bouncebuf[0] & FSR_READY);
|
||||
}
|
||||
|
||||
static void micron_st_nor_default_init(struct spi_nor *nor)
|
||||
{
|
||||
nor->flags |= SNOR_F_HAS_LOCK;
|
||||
|
@ -281,8 +408,15 @@ static void micron_st_nor_default_init(struct spi_nor *nor)
|
|||
nor->params->set_4byte_addr_mode = micron_st_nor_set_4byte_addr_mode;
|
||||
}
|
||||
|
||||
static void micron_st_nor_late_init(struct spi_nor *nor)
|
||||
{
|
||||
if (nor->flags & SNOR_F_USE_FSR)
|
||||
nor->params->ready = spi_nor_fsr_ready;
|
||||
}
|
||||
|
||||
static const struct spi_nor_fixups micron_st_nor_fixups = {
|
||||
.default_init = micron_st_nor_default_init,
|
||||
.late_init = micron_st_nor_late_init,
|
||||
};
|
||||
|
||||
const struct spi_nor_manufacturer spi_nor_micron = {
|
||||
|
|
|
@ -47,8 +47,6 @@
|
|||
#define SPINOR_OP_RDID 0x9f /* Read JEDEC ID */
|
||||
#define SPINOR_OP_RDSFDP 0x5a /* Read SFDP */
|
||||
#define SPINOR_OP_RDCR 0x35 /* Read configuration register */
|
||||
#define SPINOR_OP_RDFSR 0x70 /* Read flag status register */
|
||||
#define SPINOR_OP_CLFSR 0x50 /* Clear flag status register */
|
||||
#define SPINOR_OP_RDEAR 0xc8 /* Read Extended Address Register */
|
||||
#define SPINOR_OP_WREAR 0xc5 /* Write Extended Address Register */
|
||||
#define SPINOR_OP_SRSTEN 0x66 /* Software Reset Enable */
|
||||
|
@ -126,12 +124,6 @@
|
|||
/* Enhanced Volatile Configuration Register bits */
|
||||
#define EVCR_QUAD_EN_MICRON BIT(7) /* Micron Quad I/O */
|
||||
|
||||
/* Flag Status Register bits */
|
||||
#define FSR_READY BIT(7) /* Device status, 0 = Busy, 1 = Ready */
|
||||
#define FSR_E_ERR BIT(5) /* Erase operation status */
|
||||
#define FSR_P_ERR BIT(4) /* Program operation status */
|
||||
#define FSR_PT_ERR BIT(1) /* Protection error bit */
|
||||
|
||||
/* Status Register 2 bits. */
|
||||
#define SR2_QUAD_EN_BIT1 BIT(1)
|
||||
#define SR2_LB1 BIT(3) /* Security Register Lock Bit 1 */
|
||||
|
|
Loading…
Reference in a new issue