From mboxrd@z Thu Jan 1 00:00:00 1970 From: tkuw584924 at gmail.com Date: Fri, 19 Feb 2021 10:56:01 +0900 Subject: [PATCH v5 07/10] mtd: spi-nor-core: Add non-uniform erase for Spansion/Cypress In-Reply-To: References: Message-ID: <25396fac5db76216aa495bd77cbe4ec2e264880c.1613622392.git.Takahiro.Kuwano@infineon.com> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de From: Takahiro Kuwano Some of Spansion/Cypress chips have overlaid 4KB sectors at top and/or bottom, depending on the device configuration, while U-Boot supports uniform sector layout only. The spansion_erase_non_uniform() erases overlaid 4KB sectors, non-overlaid portion of normal sector, and remaining normal sectors, by selecting correct erase command and size based on the address to erase and size of overlaid portion in parameters. Signed-off-by: Takahiro Kuwano --- Changes in v5: - New in v5, introduce spansion_erase_non_uniform() as a replacement for spansion_overlaid_erase() in v4 drivers/mtd/spi/spi-nor-core.c | 72 ++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index e5fc0e7965..46948ed41b 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -793,6 +793,78 @@ erase_err: return ret; } +#ifdef CONFIG_SPI_FLASH_SPANSION +/** + * spansion_erase_non_uniform() - erase non-uniform sectors for Spansion/Cypress + * chips + * @mtd: pointer to a 'struct mtd_info' + * @instr: pointer to a 'struct erase_info' + * @ovlsz_top: size of overlaid portion at the top address + * @ovlsz_btm: size of overlaid portion at the bottom address + * + * Erase an address range on the nor chip that can contain 4KB sectors overlaid + * on top and/or bottom. The appropriate erase opcode and size are chosen by + * address to erase and size of overlaid portion. + * + * Return: 0 on success, -errno otherwise. + */ +static int spansion_erase_non_uniform(struct mtd_info *mtd, + struct erase_info *instr, u32 ovlsz_top, + u32 ovlsz_btm) +{ + struct spi_nor *nor = mtd_to_spi_nor(mtd); + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(nor->erase_opcode, 1), + SPI_MEM_OP_ADDR(nor->addr_width, instr->addr, 1), + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_NO_DATA); + u32 len = instr->len; + u32 erasesize; + int ret; + + while (len) { + /* 4KB sectors */ + if (op.addr.val < ovlsz_btm || + op.addr.val >= mtd->size - ovlsz_top) { + op.cmd.opcode = SPINOR_OP_BE_4K; + erasesize = SZ_4K; + + /* Non-overlaid portion in the normal sector at the bottom */ + } else if (op.addr.val == ovlsz_btm) { + op.cmd.opcode = nor->erase_opcode; + erasesize = mtd->erasesize - ovlsz_btm; + + /* Non-overlaid portion in the normal sector at the top */ + } else if (op.addr.val == mtd->size - mtd->erasesize) { + op.cmd.opcode = nor->erase_opcode; + erasesize = mtd->erasesize - ovlsz_top; + + /* Normal sectors */ + } else { + op.cmd.opcode = nor->erase_opcode; + erasesize = mtd->erasesize; + } + + write_enable(nor); + + ret = spi_mem_exec_op(nor->spi, &op); + if (ret) + break; + + op.addr.val += erasesize; + len -= erasesize; + + ret = spi_nor_wait_till_ready(nor); + if (ret) + break; + } + + write_disable(nor); + + return ret; +} +#endif + #if defined(CONFIG_SPI_FLASH_STMICRO) || defined(CONFIG_SPI_FLASH_SST) /* Write status register and ensure bits in mask match written values */ static int write_sr_and_check(struct spi_nor *nor, u8 status_new, u8 mask) -- 2.25.1