mtd: spi-nor: spansion: Add a new ->ready() hook for multi-chip device
For multi-chip devices, we need to make sure the all dice in the device are ready. The cypress_nor_sr_ready_and_clear() reads SR in each die and returns true only when all dice are ready. This function also takes care for program or erase error handling by reusing spansion_nor_clear_sr(). To do that, spansion_nor_clear_sr() is moved to top. Signed-off-by: Takahiro Kuwano <Takahiro.Kuwano@infineon.com> Link: https://lore.kernel.org/r/3e4a64613ee733e002279349c75083433be45bf5.1680849425.git.Takahiro.Kuwano@infineon.com Signed-off-by: Tudor Ambarus <tudor.ambarus@linaro.org>
This commit is contained in:
parent
f24d423a5c
commit
91f3c430f6
|
@ -63,6 +63,84 @@
|
||||||
SPI_MEM_OP_NO_DUMMY, \
|
SPI_MEM_OP_NO_DUMMY, \
|
||||||
SPI_MEM_OP_NO_DATA)
|
SPI_MEM_OP_NO_DATA)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* spansion_nor_clear_sr() - Clear the Status Register.
|
||||||
|
* @nor: pointer to 'struct spi_nor'.
|
||||||
|
*/
|
||||||
|
static void spansion_nor_clear_sr(struct spi_nor *nor)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (nor->spimem) {
|
||||||
|
struct spi_mem_op op = SPANSION_CLSR_OP;
|
||||||
|
|
||||||
|
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_CLSR,
|
||||||
|
NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
dev_dbg(nor->dev, "error %d clearing SR\n", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cypress_nor_sr_ready_and_clear_reg(struct spi_nor *nor, u64 addr)
|
||||||
|
{
|
||||||
|
struct spi_mem_op op =
|
||||||
|
CYPRESS_NOR_RD_ANY_REG_OP(nor->params->addr_mode_nbytes, addr,
|
||||||
|
0, nor->bouncebuf);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (nor->bouncebuf[0] & (SR_E_ERR | SR_P_ERR)) {
|
||||||
|
if (nor->bouncebuf[0] & SR_E_ERR)
|
||||||
|
dev_err(nor->dev, "Erase Error occurred\n");
|
||||||
|
else
|
||||||
|
dev_err(nor->dev, "Programming Error occurred\n");
|
||||||
|
|
||||||
|
spansion_nor_clear_sr(nor);
|
||||||
|
|
||||||
|
ret = spi_nor_write_disable(nor);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !(nor->bouncebuf[0] & SR_WIP);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* cypress_nor_sr_ready_and_clear() - Query the Status Register of each die by
|
||||||
|
* using Read Any Register command to see if the whole flash is ready for new
|
||||||
|
* commands and clear it if there are any errors.
|
||||||
|
* @nor: pointer to 'struct spi_nor'.
|
||||||
|
*
|
||||||
|
* Return: 1 if ready, 0 if not ready, -errno on errors.
|
||||||
|
*/
|
||||||
|
static int cypress_nor_sr_ready_and_clear(struct spi_nor *nor)
|
||||||
|
{
|
||||||
|
struct spi_nor_flash_parameter *params = nor->params;
|
||||||
|
u64 addr;
|
||||||
|
int ret;
|
||||||
|
u8 i;
|
||||||
|
|
||||||
|
for (i = 0; i < params->n_dice; i++) {
|
||||||
|
addr = params->vreg_offset[i] + SPINOR_REG_CYPRESS_STR1;
|
||||||
|
ret = cypress_nor_sr_ready_and_clear_reg(nor, addr);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
else if (ret == 0)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int cypress_nor_octal_dtr_en(struct spi_nor *nor)
|
static int cypress_nor_octal_dtr_en(struct spi_nor *nor)
|
||||||
{
|
{
|
||||||
struct spi_mem_op op;
|
struct spi_mem_op op;
|
||||||
|
@ -506,10 +584,16 @@ static int s25hx_t_post_sfdp_fixup(struct spi_nor *nor)
|
||||||
|
|
||||||
static void s25hx_t_late_init(struct spi_nor *nor)
|
static void s25hx_t_late_init(struct spi_nor *nor)
|
||||||
{
|
{
|
||||||
|
struct spi_nor_flash_parameter *params = nor->params;
|
||||||
|
|
||||||
/* Fast Read 4B requires mode cycles */
|
/* Fast Read 4B requires mode cycles */
|
||||||
nor->params->reads[SNOR_CMD_READ_FAST].num_mode_clocks = 8;
|
params->reads[SNOR_CMD_READ_FAST].num_mode_clocks = 8;
|
||||||
|
|
||||||
cypress_nor_ecc_init(nor);
|
cypress_nor_ecc_init(nor);
|
||||||
|
|
||||||
|
/* Replace ready() with multi die version */
|
||||||
|
if (params->n_dice)
|
||||||
|
params->ready = cypress_nor_sr_ready_and_clear;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct spi_nor_fixups s25hx_t_fixups = {
|
static struct spi_nor_fixups s25hx_t_fixups = {
|
||||||
|
@ -741,29 +825,6 @@ static const struct flash_info spansion_nor_parts[] = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* spansion_nor_clear_sr() - Clear the Status Register.
|
|
||||||
* @nor: pointer to 'struct spi_nor'.
|
|
||||||
*/
|
|
||||||
static void spansion_nor_clear_sr(struct spi_nor *nor)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (nor->spimem) {
|
|
||||||
struct spi_mem_op op = SPANSION_CLSR_OP;
|
|
||||||
|
|
||||||
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_CLSR,
|
|
||||||
NULL, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret)
|
|
||||||
dev_dbg(nor->dev, "error %d clearing SR\n", ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* spansion_nor_sr_ready_and_clear() - Query the Status Register to see if the
|
* spansion_nor_sr_ready_and_clear() - Query the Status Register to see if the
|
||||||
* flash is ready for new commands and clear it if there are any errors.
|
* flash is ready for new commands and clear it if there are any errors.
|
||||||
|
|
Loading…
Reference in New Issue