diff options
Diffstat (limited to 'drivers/mtd/spi-nor/core.c')
| -rw-r--r-- | drivers/mtd/spi-nor/core.c | 2182 |
1 files changed, 1304 insertions, 878 deletions
diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index cc08bd707378..d3f8a78efd3b 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -7,20 +7,22 @@ * Copyright (C) 2014, Freescale Semiconductor, Inc. */ +#include <linux/cleanup.h> +#include <linux/delay.h> +#include <linux/device.h> #include <linux/err.h> #include <linux/errno.h> +#include <linux/math64.h> #include <linux/module.h> -#include <linux/device.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/spi-nor.h> #include <linux/mutex.h> -#include <linux/math64.h> +#include <linux/of.h> +#include <linux/regulator/consumer.h> +#include <linux/sched/task_stack.h> #include <linux/sizes.h> #include <linux/slab.h> - -#include <linux/mtd/mtd.h> -#include <linux/of_platform.h> -#include <linux/sched/task_stack.h> #include <linux/spi/flash.h> -#include <linux/mtd/spi-nor.h> #include "core.h" @@ -38,7 +40,7 @@ */ #define CHIP_ERASE_2MB_READY_WAIT_JIFFIES (40UL * HZ) -#define SPI_NOR_MAX_ADDR_WIDTH 4 +#define SPI_NOR_MAX_ADDR_NBYTES 4 #define SPI_NOR_SRST_SLEEP_MIN 200 #define SPI_NOR_SRST_SLEEP_MAX 400 @@ -113,6 +115,9 @@ void spi_nor_spimem_setup_op(const struct spi_nor *nor, op->cmd.opcode = (op->cmd.opcode << 8) | ext; op->cmd.nbytes = 2; } + + if (proto == SNOR_PROTO_8_8_8_DTR && nor->flags & SNOR_F_SWAP16) + op->data.swap16 = true; } /** @@ -157,8 +162,8 @@ static int spi_nor_spimem_exec_op(struct spi_nor *nor, struct spi_mem_op *op) return spi_mem_exec_op(nor->spimem, op); } -static int spi_nor_controller_ops_read_reg(struct spi_nor *nor, u8 opcode, - u8 *buf, size_t len) +int spi_nor_controller_ops_read_reg(struct spi_nor *nor, u8 opcode, + u8 *buf, size_t len) { if (spi_nor_protocol_is_dtr(nor->reg_proto)) return -EOPNOTSUPP; @@ -166,8 +171,8 @@ static int spi_nor_controller_ops_read_reg(struct spi_nor *nor, u8 opcode, return nor->controller_ops->read_reg(nor, opcode, buf, len); } -static int spi_nor_controller_ops_write_reg(struct spi_nor *nor, u8 opcode, - const u8 *buf, size_t len) +int spi_nor_controller_ops_write_reg(struct spi_nor *nor, u8 opcode, + const u8 *buf, size_t len) { if (spi_nor_protocol_is_dtr(nor->reg_proto)) return -EOPNOTSUPP; @@ -177,7 +182,7 @@ static int spi_nor_controller_ops_write_reg(struct spi_nor *nor, u8 opcode, static int spi_nor_controller_ops_erase(struct spi_nor *nor, loff_t offs) { - if (spi_nor_protocol_is_dtr(nor->write_proto)) + if (spi_nor_protocol_is_dtr(nor->reg_proto)) return -EOPNOTSUPP; return nor->controller_ops->erase(nor, offs); @@ -198,7 +203,7 @@ static ssize_t spi_nor_spimem_read_data(struct spi_nor *nor, loff_t from, { struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 0), - SPI_MEM_OP_ADDR(nor->addr_width, from, 0), + SPI_MEM_OP_ADDR(nor->addr_nbytes, from, 0), SPI_MEM_OP_DUMMY(nor->read_dummy, 0), SPI_MEM_OP_DATA_IN(len, buf, 0)); bool usebouncebuf; @@ -262,7 +267,7 @@ static ssize_t spi_nor_spimem_write_data(struct spi_nor *nor, loff_t to, { struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 0), - SPI_MEM_OP_ADDR(nor->addr_width, to, 0), + SPI_MEM_OP_ADDR(nor->addr_nbytes, to, 0), SPI_MEM_OP_NO_DUMMY, SPI_MEM_OP_DATA_OUT(len, buf, 0)); ssize_t nbytes; @@ -308,6 +313,52 @@ ssize_t spi_nor_write_data(struct spi_nor *nor, loff_t to, size_t len, } /** + * spi_nor_read_any_reg() - read any register from flash memory, nonvolatile or + * volatile. + * @nor: pointer to 'struct spi_nor'. + * @op: SPI memory operation. op->data.buf must be DMA-able. + * @proto: SPI protocol to use for the register operation. + * + * Return: zero on success, -errno otherwise + */ +int spi_nor_read_any_reg(struct spi_nor *nor, struct spi_mem_op *op, + enum spi_nor_protocol proto) +{ + if (!nor->spimem) + return -EOPNOTSUPP; + + spi_nor_spimem_setup_op(nor, op, proto); + return spi_nor_spimem_exec_op(nor, op); +} + +/** + * spi_nor_write_any_volatile_reg() - write any volatile register to flash + * memory. + * @nor: pointer to 'struct spi_nor' + * @op: SPI memory operation. op->data.buf must be DMA-able. + * @proto: SPI protocol to use for the register operation. + * + * Writing volatile registers are instant according to some manufacturers + * (Cypress, Micron) and do not need any status polling. + * + * Return: zero on success, -errno otherwise + */ +int spi_nor_write_any_volatile_reg(struct spi_nor *nor, struct spi_mem_op *op, + enum spi_nor_protocol proto) +{ + int ret; + + if (!nor->spimem) + return -EOPNOTSUPP; + + ret = spi_nor_write_enable(nor); + if (ret) + return ret; + spi_nor_spimem_setup_op(nor, op, proto); + return spi_nor_spimem_exec_op(nor, op); +} + +/** * spi_nor_write_enable() - Set write enable latch with Write Enable command. * @nor: pointer to 'struct spi_nor'. * @@ -318,11 +369,7 @@ int spi_nor_write_enable(struct spi_nor *nor) int ret; if (nor->spimem) { - struct spi_mem_op op = - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WREN, 0), - SPI_MEM_OP_NO_ADDR, - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_NO_DATA); + struct spi_mem_op op = SPI_NOR_WREN_OP; spi_nor_spimem_setup_op(nor, &op, nor->reg_proto); @@ -349,11 +396,7 @@ int spi_nor_write_disable(struct spi_nor *nor) int ret; if (nor->spimem) { - struct spi_mem_op op = - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WRDI, 0), - SPI_MEM_OP_NO_ADDR, - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_NO_DATA); + struct spi_mem_op op = SPI_NOR_WRDI_OP; spi_nor_spimem_setup_op(nor, &op, nor->reg_proto); @@ -370,67 +413,50 @@ int spi_nor_write_disable(struct spi_nor *nor) } /** - * spi_nor_read_sr() - Read the Status Register. + * spi_nor_read_id() - Read the JEDEC ID. * @nor: pointer to 'struct spi_nor'. - * @sr: pointer to a DMA-able buffer where the value of the - * Status Register will be written. Should be at least 2 bytes. + * @naddr: number of address bytes to send. Can be zero if the operation + * does not need to send an address. + * @ndummy: number of dummy bytes to send after an opcode or address. Can + * be zero if the operation does not require dummy bytes. + * @id: pointer to a DMA-able buffer where the value of the JEDEC ID + * will be written. + * @proto: the SPI protocol for register operation. * * Return: 0 on success, -errno otherwise. */ -int spi_nor_read_sr(struct spi_nor *nor, u8 *sr) +int spi_nor_read_id(struct spi_nor *nor, u8 naddr, u8 ndummy, u8 *id, + enum spi_nor_protocol proto) { int ret; if (nor->spimem) { struct spi_mem_op op = - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDSR, 0), - SPI_MEM_OP_NO_ADDR, - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_IN(1, sr, 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); + SPI_NOR_READID_OP(naddr, ndummy, id, SPI_NOR_MAX_ID_LEN); + spi_nor_spimem_setup_op(nor, &op, proto); ret = spi_mem_exec_op(nor->spimem, &op); } else { - ret = spi_nor_controller_ops_read_reg(nor, SPINOR_OP_RDSR, sr, - 1); + ret = nor->controller_ops->read_reg(nor, SPINOR_OP_RDID, id, + SPI_NOR_MAX_ID_LEN); } - - if (ret) - dev_dbg(nor->dev, "error %d reading SR\n", ret); - 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. + * spi_nor_read_sr() - Read the Status Register. + * @nor: pointer to 'struct spi_nor'. + * @sr: pointer to a DMA-able buffer where the value of the + * 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 spi_nor_read_sr(struct spi_nor *nor, u8 *sr) { 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)); + struct spi_mem_op op = SPI_NOR_RDSR_OP(sr); if (nor->reg_proto == SNOR_PROTO_8_8_8_DTR) { op.addr.nbytes = nor->params->rdsr_addr_nbytes; @@ -446,12 +472,12 @@ static int spi_nor_read_fsr(struct spi_nor *nor, u8 *fsr) ret = spi_mem_exec_op(nor->spimem, &op); } else { - ret = spi_nor_controller_ops_read_reg(nor, SPINOR_OP_RDFSR, fsr, + ret = spi_nor_controller_ops_read_reg(nor, SPINOR_OP_RDSR, sr, 1); } if (ret) - dev_dbg(nor->dev, "error %d reading FSR\n", ret); + dev_dbg(nor->dev, "error %d reading SR\n", ret); return ret; } @@ -470,11 +496,7 @@ int spi_nor_read_cr(struct spi_nor *nor, u8 *cr) int ret; if (nor->spimem) { - struct spi_mem_op op = - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDCR, 0), - SPI_MEM_OP_NO_ADDR, - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_IN(1, cr, 0)); + struct spi_mem_op op = SPI_NOR_RDCR_OP(cr); spi_nor_spimem_setup_op(nor, &op, nor->reg_proto); @@ -491,26 +513,21 @@ int spi_nor_read_cr(struct spi_nor *nor, u8 *cr) } /** - * spi_nor_set_4byte_addr_mode() - Enter/Exit 4-byte address mode. + * spi_nor_set_4byte_addr_mode_en4b_ex4b() - Enter/Exit 4-byte address mode + * using SPINOR_OP_EN4B/SPINOR_OP_EX4B. Typically used by + * Winbond and Macronix. * @nor: pointer to 'struct spi_nor'. * @enable: true to enter the 4-byte address mode, false to exit the 4-byte * address mode. * * Return: 0 on success, -errno otherwise. */ -int spi_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable) +int spi_nor_set_4byte_addr_mode_en4b_ex4b(struct spi_nor *nor, bool enable) { int ret; if (nor->spimem) { - struct spi_mem_op op = - SPI_MEM_OP(SPI_MEM_OP_CMD(enable ? - SPINOR_OP_EN4B : - SPINOR_OP_EX4B, - 0), - SPI_MEM_OP_NO_ADDR, - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_NO_DATA); + struct spi_mem_op op = SPI_NOR_EN4B_EX4B_OP(enable); spi_nor_spimem_setup_op(nor, &op, nor->reg_proto); @@ -529,259 +546,136 @@ int spi_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable) } /** - * spansion_set_4byte_addr_mode() - Set 4-byte address mode for Spansion - * flashes. + * spi_nor_set_4byte_addr_mode_wren_en4b_ex4b() - Set 4-byte address mode using + * SPINOR_OP_WREN followed by SPINOR_OP_EN4B or SPINOR_OP_EX4B. Typically used + * by ST and Micron flashes. * @nor: pointer to 'struct spi_nor'. * @enable: true to enter the 4-byte address mode, false to exit the 4-byte * address mode. * * Return: 0 on success, -errno otherwise. */ -static int spansion_set_4byte_addr_mode(struct spi_nor *nor, bool enable) +int spi_nor_set_4byte_addr_mode_wren_en4b_ex4b(struct spi_nor *nor, bool enable) { int ret; - nor->bouncebuf[0] = enable << 7; - - if (nor->spimem) { - struct spi_mem_op op = - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_BRWR, 0), - SPI_MEM_OP_NO_ADDR, - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_OUT(1, nor->bouncebuf, 0)); - - 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_BRWR, - nor->bouncebuf, 1); - } + ret = spi_nor_write_enable(nor); + if (ret) + return ret; + ret = spi_nor_set_4byte_addr_mode_en4b_ex4b(nor, enable); if (ret) - dev_dbg(nor->dev, "error %d setting 4-byte mode\n", ret); + return ret; - return ret; + return spi_nor_write_disable(nor); } /** - * spi_nor_write_ear() - Write Extended Address Register. + * spi_nor_set_4byte_addr_mode_brwr() - Set 4-byte address mode using + * SPINOR_OP_BRWR. Typically used by Spansion flashes. * @nor: pointer to 'struct spi_nor'. - * @ear: value to write to the Extended Address Register. + * @enable: true to enter the 4-byte address mode, false to exit the 4-byte + * address mode. + * + * 8-bit volatile bank register used to define A[30:A24] bits. MSB (bit[7]) is + * used to enable/disable 4-byte address mode. When MSB is set to ‘1’, 4-byte + * address mode is active and A[30:24] bits are don’t care. Write instruction is + * SPINOR_OP_BRWR(17h) with 1 byte of data. * * Return: 0 on success, -errno otherwise. */ -int spi_nor_write_ear(struct spi_nor *nor, u8 ear) +int spi_nor_set_4byte_addr_mode_brwr(struct spi_nor *nor, bool enable) { int ret; - nor->bouncebuf[0] = ear; + nor->bouncebuf[0] = enable << 7; if (nor->spimem) { - struct spi_mem_op op = - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WREAR, 0), - SPI_MEM_OP_NO_ADDR, - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_OUT(1, nor->bouncebuf, 0)); + struct spi_mem_op op = SPI_NOR_BRWR_OP(nor->bouncebuf); 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_WREAR, + ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_BRWR, nor->bouncebuf, 1); } if (ret) - dev_dbg(nor->dev, "error %d writing EAR\n", ret); + dev_dbg(nor->dev, "error %d setting 4-byte mode\n", ret); return ret; } /** - * spi_nor_xread_sr() - Read the Status Register on S3AN flashes. + * spi_nor_sr_ready() - Query the Status Register to see if the flash is ready + * for new commands. * @nor: pointer to 'struct spi_nor'. - * @sr: pointer to a DMA-able buffer where the value of the - * Status Register will be written. * - * Return: 0 on success, -errno otherwise. + * Return: 1 if ready, 0 if not ready, -errno on errors. */ -int spi_nor_xread_sr(struct spi_nor *nor, u8 *sr) +int spi_nor_sr_ready(struct spi_nor *nor) { int ret; - if (nor->spimem) { - struct spi_mem_op op = - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_XRDSR, 0), - SPI_MEM_OP_NO_ADDR, - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_IN(1, sr, 0)); - - 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_XRDSR, sr, - 1); - } - + ret = spi_nor_read_sr(nor, nor->bouncebuf); if (ret) - dev_dbg(nor->dev, "error %d reading XRDSR\n", ret); + return ret; - return ret; + return !(nor->bouncebuf[0] & SR_WIP); } /** - * spi_nor_xsr_ready() - Query the Status Register of the S3AN flash to see if - * the flash is ready for new commands. + * spi_nor_use_parallel_locking() - Checks if RWW locking scheme shall be used * @nor: pointer to 'struct spi_nor'. * - * Return: 1 if ready, 0 if not ready, -errno on errors. + * Return: true if parallel locking is enabled, false otherwise. */ -static int spi_nor_xsr_ready(struct spi_nor *nor) +static bool spi_nor_use_parallel_locking(struct spi_nor *nor) { - int ret; - - ret = spi_nor_xread_sr(nor, nor->bouncebuf); - if (ret) - return ret; - - return !!(nor->bouncebuf[0] & XSR_RDY); + return nor->flags & SNOR_F_RWW; } -/** - * spi_nor_clear_sr() - Clear the Status Register. - * @nor: pointer to 'struct spi_nor'. - */ -static void spi_nor_clear_sr(struct spi_nor *nor) +/* Locking helpers for status read operations */ +static int spi_nor_rww_start_rdst(struct spi_nor *nor) { - int ret; + struct spi_nor_rww *rww = &nor->rww; - if (nor->spimem) { - struct spi_mem_op op = - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_CLSR, 0), - SPI_MEM_OP_NO_ADDR, - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_NO_DATA); + guard(mutex)(&nor->lock); - spi_nor_spimem_setup_op(nor, &op, nor->reg_proto); + if (rww->ongoing_io || rww->ongoing_rd) + return -EAGAIN; - ret = spi_mem_exec_op(nor->spimem, &op); - } else { - ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_CLSR, - NULL, 0); - } + rww->ongoing_io = true; + rww->ongoing_rd = true; - if (ret) - dev_dbg(nor->dev, "error %d clearing SR\n", ret); + return 0; } -/** - * spi_nor_sr_ready() - Query the 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_sr_ready(struct spi_nor *nor) +static void spi_nor_rww_end_rdst(struct spi_nor *nor) { - int ret = spi_nor_read_sr(nor, nor->bouncebuf); - - if (ret) - return ret; - - if (nor->flags & SNOR_F_USE_CLSR && - 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"); - - spi_nor_clear_sr(nor); + struct spi_nor_rww *rww = &nor->rww; - /* - * 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; + guard(mutex)(&nor->lock); - return -EIO; - } - - return !(nor->bouncebuf[0] & SR_WIP); + rww->ongoing_io = false; + rww->ongoing_rd = false; } -/** - * 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) +static int spi_nor_lock_rdst(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 (spi_nor_use_parallel_locking(nor)) + return spi_nor_rww_start_rdst(nor); - if (ret) - dev_dbg(nor->dev, "error %d clearing FSR\n", ret); + return 0; } -/** - * 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) +static void spi_nor_unlock_rdst(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; + if (spi_nor_use_parallel_locking(nor)) { + spi_nor_rww_end_rdst(nor); + wake_up(&nor->rww.wait); } - - return !!(nor->bouncebuf[0] & FSR_READY); } /** @@ -792,18 +686,21 @@ static int spi_nor_fsr_ready(struct spi_nor *nor) */ static int spi_nor_ready(struct spi_nor *nor) { - int sr, fsr; + int ret; + + ret = spi_nor_lock_rdst(nor); + if (ret) + return 0; - if (nor->flags & SNOR_F_READY_XSR_RDY) - sr = spi_nor_xsr_ready(nor); + /* Flashes might override the standard routine. */ + if (nor->params->ready) + ret = nor->params->ready(nor); else - 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; + ret = spi_nor_sr_ready(nor); + + spi_nor_unlock_rdst(nor); + + return ret; } /** @@ -868,11 +765,7 @@ int spi_nor_global_block_unlock(struct spi_nor *nor) return ret; if (nor->spimem) { - struct spi_mem_op op = - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_GBULK, 0), - SPI_MEM_OP_NO_ADDR, - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_NO_DATA); + struct spi_mem_op op = SPI_NOR_GBULK_OP; spi_nor_spimem_setup_op(nor, &op, nor->reg_proto); @@ -907,11 +800,7 @@ int spi_nor_write_sr(struct spi_nor *nor, const u8 *sr, size_t len) return ret; if (nor->spimem) { - struct spi_mem_op op = - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WRSR, 0), - SPI_MEM_OP_NO_ADDR, - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_OUT(len, sr, 0)); + struct spi_mem_op op = SPI_NOR_WRSR_OP(sr, len); spi_nor_spimem_setup_op(nor, &op, nor->reg_proto); @@ -980,21 +869,22 @@ static int spi_nor_write_16bit_sr_and_check(struct spi_nor *nor, u8 sr1) ret = spi_nor_read_cr(nor, &sr_cr[1]); if (ret) return ret; - } else if (nor->params->quad_enable) { + } else if (spi_nor_get_protocol_width(nor->read_proto) == 4 && + spi_nor_get_protocol_width(nor->write_proto) == 4 && + nor->params->quad_enable) { /* * If the Status Register 2 Read command (35h) is not * supported, we should at least be sure we don't * change the value of the SR2 Quad Enable bit. * - * We can safely assume that when the Quad Enable method is - * set, the value of the QE bit is one, as a consequence of the - * nor->params->quad_enable() call. + * When the Quad Enable method is set and the buswidth is 4, we + * can safely assume that the value of the QE bit is one, as a + * consequence of the nor->params->quad_enable() call. * - * We can safely assume that the Quad Enable bit is present in - * the Status Register 2 at BIT(1). According to the JESD216 - * revB standard, BFPT DWORDS[15], bits 22:20, the 16-bit - * Write Status (01h) command is available just for the cases - * in which the QE bit is described in SR2 at BIT(1). + * According to the JESD216 revB standard, BFPT DWORDS[15], + * bits 22:20, the 16-bit Write Status (01h) command is + * available just for the cases in which the QE bit is + * described in SR2 at BIT(1). */ sr_cr[1] = SR2_QUAD_EN_BIT1; } else { @@ -1007,6 +897,15 @@ static int spi_nor_write_16bit_sr_and_check(struct spi_nor *nor, u8 sr1) if (ret) return ret; + ret = spi_nor_read_sr(nor, sr_cr); + if (ret) + return ret; + + if (sr1 != sr_cr[0]) { + dev_dbg(nor->dev, "SR: Read back test failed\n"); + return -EIO; + } + if (nor->flags & SNOR_F_NO_READ_CR) return 0; @@ -1111,11 +1010,7 @@ static int spi_nor_write_sr2(struct spi_nor *nor, const u8 *sr2) return ret; if (nor->spimem) { - struct spi_mem_op op = - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WRSR2, 0), - SPI_MEM_OP_NO_ADDR, - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_OUT(1, sr2, 0)); + struct spi_mem_op op = SPI_NOR_WRSR2_OP(sr2); spi_nor_spimem_setup_op(nor, &op, nor->reg_proto); @@ -1147,11 +1042,7 @@ static int spi_nor_read_sr2(struct spi_nor *nor, u8 *sr2) int ret; if (nor->spimem) { - struct spi_mem_op op = - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDSR2, 0), - SPI_MEM_OP_NO_ADDR, - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_IN(1, sr2, 0)); + struct spi_mem_op op = SPI_NOR_RDSR2_OP(sr2); spi_nor_spimem_setup_op(nor, &op, nor->reg_proto); @@ -1168,28 +1059,32 @@ static int spi_nor_read_sr2(struct spi_nor *nor, u8 *sr2) } /** - * spi_nor_erase_chip() - Erase the entire flash memory. + * spi_nor_erase_die() - Erase the entire die. * @nor: pointer to 'struct spi_nor'. + * @addr: address of the die. + * @die_size: size of the die. * * Return: 0 on success, -errno otherwise. */ -static int spi_nor_erase_chip(struct spi_nor *nor) +static int spi_nor_erase_die(struct spi_nor *nor, loff_t addr, size_t die_size) { + bool multi_die = nor->mtd.size != die_size; int ret; - dev_dbg(nor->dev, " %lldKiB\n", (long long)(nor->mtd.size >> 10)); + dev_dbg(nor->dev, " %lldKiB\n", (long long)(die_size >> 10)); if (nor->spimem) { struct spi_mem_op op = - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_CHIP_ERASE, 0), - SPI_MEM_OP_NO_ADDR, - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_NO_DATA); + SPI_NOR_DIE_ERASE_OP(nor->params->die_erase_opcode, + nor->addr_nbytes, addr, multi_die); - spi_nor_spimem_setup_op(nor, &op, nor->write_proto); + spi_nor_spimem_setup_op(nor, &op, nor->reg_proto); ret = spi_mem_exec_op(nor->spimem, &op); } else { + if (multi_die) + return -EOPNOTSUPP; + ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_CHIP_ERASE, NULL, 0); @@ -1262,7 +1157,7 @@ static u8 spi_nor_convert_3to4_erase(u8 opcode) static bool spi_nor_has_uniform_erase(const struct spi_nor *nor) { - return !!nor->params->erase_map.uniform_erase_type; + return !!nor->params->erase_map.uniform_region.erase_mask; } static void spi_nor_set_4byte_opcodes(struct spi_nor *nor) @@ -1284,35 +1179,265 @@ static void spi_nor_set_4byte_opcodes(struct spi_nor *nor) } } -int spi_nor_lock_and_prep(struct spi_nor *nor) +static int spi_nor_prep(struct spi_nor *nor) { int ret = 0; - mutex_lock(&nor->lock); - - if (nor->controller_ops && nor->controller_ops->prepare) { + if (nor->controller_ops && nor->controller_ops->prepare) ret = nor->controller_ops->prepare(nor); - if (ret) { - mutex_unlock(&nor->lock); - return ret; - } - } + return ret; } -void spi_nor_unlock_and_unprep(struct spi_nor *nor) +static void spi_nor_unprep(struct spi_nor *nor) { if (nor->controller_ops && nor->controller_ops->unprepare) nor->controller_ops->unprepare(nor); - mutex_unlock(&nor->lock); } -static u32 spi_nor_convert_addr(struct spi_nor *nor, loff_t addr) +static void spi_nor_offset_to_banks(u64 bank_size, loff_t start, size_t len, + u8 *first, u8 *last) +{ + /* This is currently safe, the number of banks being very small */ + *first = DIV_ROUND_DOWN_ULL(start, bank_size); + *last = DIV_ROUND_DOWN_ULL(start + len - 1, bank_size); +} + +/* Generic helpers for internal locking and serialization */ +static bool spi_nor_rww_start_io(struct spi_nor *nor) { - if (!nor->params->convert_addr) - return addr; + struct spi_nor_rww *rww = &nor->rww; + + guard(mutex)(&nor->lock); + + if (rww->ongoing_io) + return false; + + rww->ongoing_io = true; - return nor->params->convert_addr(nor, addr); + return true; +} + +static void spi_nor_rww_end_io(struct spi_nor *nor) +{ + guard(mutex)(&nor->lock); + nor->rww.ongoing_io = false; +} + +static int spi_nor_lock_device(struct spi_nor *nor) +{ + if (!spi_nor_use_parallel_locking(nor)) + return 0; + + return wait_event_killable(nor->rww.wait, spi_nor_rww_start_io(nor)); +} + +static void spi_nor_unlock_device(struct spi_nor *nor) +{ + if (spi_nor_use_parallel_locking(nor)) { + spi_nor_rww_end_io(nor); + wake_up(&nor->rww.wait); + } +} + +/* Generic helpers for internal locking and serialization */ +static bool spi_nor_rww_start_exclusive(struct spi_nor *nor) +{ + struct spi_nor_rww *rww = &nor->rww; + + mutex_lock(&nor->lock); + + if (rww->ongoing_io || rww->ongoing_rd || rww->ongoing_pe) + return false; + + rww->ongoing_io = true; + rww->ongoing_rd = true; + rww->ongoing_pe = true; + + return true; +} + +static void spi_nor_rww_end_exclusive(struct spi_nor *nor) +{ + struct spi_nor_rww *rww = &nor->rww; + + guard(mutex)(&nor->lock); + rww->ongoing_io = false; + rww->ongoing_rd = false; + rww->ongoing_pe = false; +} + +int spi_nor_prep_and_lock(struct spi_nor *nor) +{ + int ret; + + ret = spi_nor_prep(nor); + if (ret) + return ret; + + if (!spi_nor_use_parallel_locking(nor)) + mutex_lock(&nor->lock); + else + ret = wait_event_killable(nor->rww.wait, + spi_nor_rww_start_exclusive(nor)); + + return ret; +} + +void spi_nor_unlock_and_unprep(struct spi_nor *nor) +{ + if (!spi_nor_use_parallel_locking(nor)) { + mutex_unlock(&nor->lock); + } else { + spi_nor_rww_end_exclusive(nor); + wake_up(&nor->rww.wait); + } + + spi_nor_unprep(nor); +} + +/* Internal locking helpers for program and erase operations */ +static bool spi_nor_rww_start_pe(struct spi_nor *nor, loff_t start, size_t len) +{ + struct spi_nor_rww *rww = &nor->rww; + unsigned int used_banks = 0; + u8 first, last; + int bank; + + guard(mutex)(&nor->lock); + + if (rww->ongoing_io || rww->ongoing_rd || rww->ongoing_pe) + return false; + + spi_nor_offset_to_banks(nor->params->bank_size, start, len, &first, &last); + for (bank = first; bank <= last; bank++) { + if (rww->used_banks & BIT(bank)) + return false; + + used_banks |= BIT(bank); + } + + rww->used_banks |= used_banks; + rww->ongoing_pe = true; + + return true; +} + +static void spi_nor_rww_end_pe(struct spi_nor *nor, loff_t start, size_t len) +{ + struct spi_nor_rww *rww = &nor->rww; + u8 first, last; + int bank; + + guard(mutex)(&nor->lock); + + spi_nor_offset_to_banks(nor->params->bank_size, start, len, &first, &last); + for (bank = first; bank <= last; bank++) + rww->used_banks &= ~BIT(bank); + + rww->ongoing_pe = false; +} + +static int spi_nor_prep_and_lock_pe(struct spi_nor *nor, loff_t start, size_t len) +{ + int ret; + + ret = spi_nor_prep(nor); + if (ret) + return ret; + + if (!spi_nor_use_parallel_locking(nor)) + mutex_lock(&nor->lock); + else + ret = wait_event_killable(nor->rww.wait, + spi_nor_rww_start_pe(nor, start, len)); + + return ret; +} + +static void spi_nor_unlock_and_unprep_pe(struct spi_nor *nor, loff_t start, size_t len) +{ + if (!spi_nor_use_parallel_locking(nor)) { + mutex_unlock(&nor->lock); + } else { + spi_nor_rww_end_pe(nor, start, len); + wake_up(&nor->rww.wait); + } + + spi_nor_unprep(nor); +} + +/* Internal locking helpers for read operations */ +static bool spi_nor_rww_start_rd(struct spi_nor *nor, loff_t start, size_t len) +{ + struct spi_nor_rww *rww = &nor->rww; + unsigned int used_banks = 0; + u8 first, last; + int bank; + + guard(mutex)(&nor->lock); + + if (rww->ongoing_io || rww->ongoing_rd) + return false; + + spi_nor_offset_to_banks(nor->params->bank_size, start, len, &first, &last); + for (bank = first; bank <= last; bank++) { + if (rww->used_banks & BIT(bank)) + return false; + + used_banks |= BIT(bank); + } + + rww->used_banks |= used_banks; + rww->ongoing_io = true; + rww->ongoing_rd = true; + + return true; +} + +static void spi_nor_rww_end_rd(struct spi_nor *nor, loff_t start, size_t len) +{ + struct spi_nor_rww *rww = &nor->rww; + u8 first, last; + int bank; + + guard(mutex)(&nor->lock); + + spi_nor_offset_to_banks(nor->params->bank_size, start, len, &first, &last); + for (bank = first; bank <= last; bank++) + nor->rww.used_banks &= ~BIT(bank); + + rww->ongoing_io = false; + rww->ongoing_rd = false; +} + +static int spi_nor_prep_and_lock_rd(struct spi_nor *nor, loff_t start, size_t len) +{ + int ret; + + ret = spi_nor_prep(nor); + if (ret) + return ret; + + if (!spi_nor_use_parallel_locking(nor)) + mutex_lock(&nor->lock); + else + ret = wait_event_killable(nor->rww.wait, + spi_nor_rww_start_rd(nor, start, len)); + + return ret; +} + +static void spi_nor_unlock_and_unprep_rd(struct spi_nor *nor, loff_t start, size_t len) +{ + if (!spi_nor_use_parallel_locking(nor)) { + mutex_unlock(&nor->lock); + } else { + spi_nor_rww_end_rd(nor, start, len); + wake_up(&nor->rww.wait); + } + + spi_nor_unprep(nor); } /* @@ -1322,16 +1447,12 @@ int spi_nor_erase_sector(struct spi_nor *nor, u32 addr) { int i; - addr = spi_nor_convert_addr(nor, addr); - if (nor->spimem) { struct spi_mem_op op = - SPI_MEM_OP(SPI_MEM_OP_CMD(nor->erase_opcode, 0), - SPI_MEM_OP_ADDR(nor->addr_width, addr, 0), - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_NO_DATA); + SPI_NOR_SECTOR_ERASE_OP(nor->erase_opcode, + nor->addr_nbytes, addr); - spi_nor_spimem_setup_op(nor, &op, nor->write_proto); + spi_nor_spimem_setup_op(nor, &op, nor->reg_proto); return spi_mem_exec_op(nor->spimem, &op); } else if (nor->controller_ops->erase) { @@ -1342,13 +1463,13 @@ int spi_nor_erase_sector(struct spi_nor *nor, u32 addr) * Default implementation, if driver doesn't have a specialized HW * control */ - for (i = nor->addr_width - 1; i >= 0; i--) { + for (i = nor->addr_nbytes - 1; i >= 0; i--) { nor->bouncebuf[i] = addr & 0xff; addr >>= 8; } return spi_nor_controller_ops_write_reg(nor, nor->erase_opcode, - nor->bouncebuf, nor->addr_width); + nor->bouncebuf, nor->addr_nbytes); } /** @@ -1388,7 +1509,6 @@ spi_nor_find_best_erase_type(const struct spi_nor_erase_map *map, const struct spi_nor_erase_type *erase; u32 rem; int i; - u8 erase_mask = region->offset & SNOR_ERASE_TYPE_MASK; /* * Erase types are ordered by size, with the smallest erase type at @@ -1396,14 +1516,15 @@ spi_nor_find_best_erase_type(const struct spi_nor_erase_map *map, */ for (i = SNOR_ERASE_TYPE_MAX - 1; i >= 0; i--) { /* Does the erase region support the tested erase type? */ - if (!(erase_mask & BIT(i))) + if (!(region->erase_mask & BIT(i))) continue; erase = &map->erase_type[i]; + if (!erase->size) + continue; /* Alignment is not mandatory for overlaid regions */ - if (region->offset & SNOR_OVERLAID_REGION && - region->size <= len) + if (region->overlaid && region->size <= len) return erase; /* Don't erase more than what the user has asked for. */ @@ -1418,59 +1539,6 @@ spi_nor_find_best_erase_type(const struct spi_nor_erase_map *map, return NULL; } -static u64 spi_nor_region_is_last(const struct spi_nor_erase_region *region) -{ - return region->offset & SNOR_LAST_REGION; -} - -static u64 spi_nor_region_end(const struct spi_nor_erase_region *region) -{ - return (region->offset & ~SNOR_ERASE_FLAGS_MASK) + region->size; -} - -/** - * spi_nor_region_next() - get the next spi nor region - * @region: pointer to a structure that describes a SPI NOR erase region - * - * Return: the next spi nor region or NULL if last region. - */ -struct spi_nor_erase_region * -spi_nor_region_next(struct spi_nor_erase_region *region) -{ - if (spi_nor_region_is_last(region)) - return NULL; - region++; - return region; -} - -/** - * spi_nor_find_erase_region() - find the region of the serial flash memory in - * which the offset fits - * @map: the erase map of the SPI NOR - * @addr: offset in the serial flash memory - * - * Return: a pointer to the spi_nor_erase_region struct, ERR_PTR(-errno) - * otherwise. - */ -static struct spi_nor_erase_region * -spi_nor_find_erase_region(const struct spi_nor_erase_map *map, u64 addr) -{ - struct spi_nor_erase_region *region = map->regions; - u64 region_start = region->offset & ~SNOR_ERASE_FLAGS_MASK; - u64 region_end = region_start + region->size; - - while (addr < region_start || addr >= region_end) { - region = spi_nor_region_next(region); - if (!region) - return ERR_PTR(-EINVAL); - - region_start = region->offset & ~SNOR_ERASE_FLAGS_MASK; - region_end = region_start + region->size; - } - - return region; -} - /** * spi_nor_init_erase_cmd() - initialize an erase command * @region: pointer to a structure that describes a SPI NOR erase region @@ -1493,7 +1561,7 @@ spi_nor_init_erase_cmd(const struct spi_nor_erase_region *region, cmd->opcode = erase->opcode; cmd->count = 1; - if (region->offset & SNOR_OVERLAID_REGION) + if (region->overlaid) cmd->size = region->size; else cmd->size = erase->size; @@ -1537,44 +1605,36 @@ static int spi_nor_init_erase_cmd_list(struct spi_nor *nor, struct spi_nor_erase_region *region; struct spi_nor_erase_command *cmd = NULL; u64 region_end; + unsigned int i; int ret = -EINVAL; - region = spi_nor_find_erase_region(map, addr); - if (IS_ERR(region)) - return PTR_ERR(region); - - region_end = spi_nor_region_end(region); + for (i = 0; i < map->n_regions && len; i++) { + region = &map->regions[i]; + region_end = region->offset + region->size; - while (len) { - erase = spi_nor_find_best_erase_type(map, region, addr, len); - if (!erase) - goto destroy_erase_cmd_list; - - if (prev_erase != erase || - erase->size != cmd->size || - region->offset & SNOR_OVERLAID_REGION) { - cmd = spi_nor_init_erase_cmd(region, erase); - if (IS_ERR(cmd)) { - ret = PTR_ERR(cmd); + while (len && addr >= region->offset && addr < region_end) { + erase = spi_nor_find_best_erase_type(map, region, addr, + len); + if (!erase) goto destroy_erase_cmd_list; - } - - list_add_tail(&cmd->list, erase_list); - } else { - cmd->count++; - } - addr += cmd->size; - len -= cmd->size; + if (prev_erase != erase || erase->size != cmd->size || + region->overlaid) { + cmd = spi_nor_init_erase_cmd(region, erase); + if (IS_ERR(cmd)) { + ret = PTR_ERR(cmd); + goto destroy_erase_cmd_list; + } + + list_add_tail(&cmd->list, erase_list); + } else { + cmd->count++; + } - if (len && addr >= region_end) { - region = spi_nor_region_next(region); - if (!region) - goto destroy_erase_cmd_list; - region_end = spi_nor_region_end(region); + len -= cmd->size; + addr += cmd->size; + prev_erase = erase; } - - prev_erase = erase; } return 0; @@ -1611,11 +1671,18 @@ static int spi_nor_erase_multi_sectors(struct spi_nor *nor, u64 addr, u32 len) dev_vdbg(nor->dev, "erase_cmd->size = 0x%08x, erase_cmd->opcode = 0x%02x, erase_cmd->count = %u\n", cmd->size, cmd->opcode, cmd->count); - ret = spi_nor_write_enable(nor); + ret = spi_nor_lock_device(nor); if (ret) goto destroy_erase_cmd_list; + ret = spi_nor_write_enable(nor); + if (ret) { + spi_nor_unlock_device(nor); + goto destroy_erase_cmd_list; + } + ret = spi_nor_erase_sector(nor, addr); + spi_nor_unlock_device(nor); if (ret) goto destroy_erase_cmd_list; @@ -1637,6 +1704,51 @@ destroy_erase_cmd_list: return ret; } +static int spi_nor_erase_dice(struct spi_nor *nor, loff_t addr, + size_t len, size_t die_size) +{ + unsigned long timeout; + int ret; + + /* + * Scale the timeout linearly with the size of the flash, with + * a minimum calibrated to an old 2MB flash. We could try to + * pull these from CFI/SFDP, but these values should be good + * enough for now. + */ + timeout = max(CHIP_ERASE_2MB_READY_WAIT_JIFFIES, + CHIP_ERASE_2MB_READY_WAIT_JIFFIES * + (unsigned long)(nor->mtd.size / SZ_2M)); + + do { + ret = spi_nor_lock_device(nor); + if (ret) + return ret; + + ret = spi_nor_write_enable(nor); + if (ret) { + spi_nor_unlock_device(nor); + return ret; + } + + ret = spi_nor_erase_die(nor, addr, die_size); + + spi_nor_unlock_device(nor); + if (ret) + return ret; + + ret = spi_nor_wait_till_ready_with_timeout(nor, timeout); + if (ret) + return ret; + + addr += die_size; + len -= die_size; + + } while (len); + + return 0; +} + /* * Erase an address range on the nor chip. The address range may extend * one or more erase sectors. Return an error if there is a problem erasing. @@ -1644,8 +1756,10 @@ destroy_erase_cmd_list: static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) { struct spi_nor *nor = mtd_to_spi_nor(mtd); - u32 addr, len; - uint32_t rem; + u8 n_dice = nor->params->n_dice; + bool multi_die_erase = false; + u32 addr, len, rem; + size_t die_size; int ret; dev_dbg(nor->dev, "at 0x%llx, len %lld\n", (long long)instr->addr, @@ -1660,32 +1774,22 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) addr = instr->addr; len = instr->len; - ret = spi_nor_lock_and_prep(nor); + if (n_dice) { + die_size = div_u64(mtd->size, n_dice); + if (!(len & (die_size - 1)) && !(addr & (die_size - 1))) + multi_die_erase = true; + } else { + die_size = mtd->size; + } + + ret = spi_nor_prep_and_lock_pe(nor, instr->addr, instr->len); if (ret) return ret; - /* whole-chip erase? */ - if (len == mtd->size && !(nor->flags & SNOR_F_NO_OP_CHIP_ERASE)) { - unsigned long timeout; - - ret = spi_nor_write_enable(nor); - if (ret) - goto erase_err; - - ret = spi_nor_erase_chip(nor); - if (ret) - goto erase_err; - - /* - * Scale the timeout linearly with the size of the flash, with - * a minimum calibrated to an old 2MB flash. We could try to - * pull these from CFI/SFDP, but these values should be good - * enough for now. - */ - timeout = max(CHIP_ERASE_2MB_READY_WAIT_JIFFIES, - CHIP_ERASE_2MB_READY_WAIT_JIFFIES * - (unsigned long)(mtd->size / SZ_2M)); - ret = spi_nor_wait_till_ready_with_timeout(nor, timeout); + /* chip (die) erase? */ + if ((len == mtd->size && !(nor->flags & SNOR_F_NO_OP_CHIP_ERASE)) || + multi_die_erase) { + ret = spi_nor_erase_dice(nor, addr, len, die_size); if (ret) goto erase_err; @@ -1697,11 +1801,18 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) /* "sector"-at-a-time erase */ } else if (spi_nor_has_uniform_erase(nor)) { while (len) { - ret = spi_nor_write_enable(nor); + ret = spi_nor_lock_device(nor); if (ret) goto erase_err; + ret = spi_nor_write_enable(nor); + if (ret) { + spi_nor_unlock_device(nor); + goto erase_err; + } + ret = spi_nor_erase_sector(nor, addr); + spi_nor_unlock_device(nor); if (ret) goto erase_err; @@ -1723,7 +1834,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) ret = spi_nor_write_disable(nor); erase_err: - spi_nor_unlock_and_unprep(nor); + spi_nor_unlock_and_unprep_pe(nor, instr->addr, instr->len); return ret; } @@ -1830,11 +1941,9 @@ int spi_nor_sr2_bit7_quad_enable(struct spi_nor *nor) static const struct spi_nor_manufacturer *manufacturers[] = { &spi_nor_atmel, - &spi_nor_catalyst, &spi_nor_eon, &spi_nor_esmt, &spi_nor_everspin, - &spi_nor_fujitsu, &spi_nor_gigadevice, &spi_nor_intel, &spi_nor_issi, @@ -1844,82 +1953,159 @@ static const struct spi_nor_manufacturer *manufacturers[] = { &spi_nor_spansion, &spi_nor_sst, &spi_nor_winbond, - &spi_nor_xilinx, &spi_nor_xmc, }; -static const struct flash_info * -spi_nor_search_part_by_id(const struct flash_info *parts, unsigned int nparts, - const u8 *id) +static const struct flash_info spi_nor_generic_flash = { + .name = "spi-nor-generic", +}; + +static const struct flash_info *spi_nor_match_id(struct spi_nor *nor, + const u8 *id) { - unsigned int i; + const struct flash_info *part; + unsigned int i, j; - for (i = 0; i < nparts; i++) { - if (parts[i].id_len && - !memcmp(parts[i].id, id, parts[i].id_len)) - return &parts[i]; + for (i = 0; i < ARRAY_SIZE(manufacturers); i++) { + for (j = 0; j < manufacturers[i]->nparts; j++) { + part = &manufacturers[i]->parts[j]; + if (part->id && + !memcmp(part->id->bytes, id, part->id->len)) { + nor->manufacturer = manufacturers[i]; + return part; + } + } } return NULL; } -static const struct flash_info *spi_nor_read_id(struct spi_nor *nor) +static const struct flash_info *spi_nor_detect(struct spi_nor *nor) { const struct flash_info *info; u8 *id = nor->bouncebuf; - unsigned int i; int ret; - if (nor->spimem) { - struct spi_mem_op op = - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDID, 1), - SPI_MEM_OP_NO_ADDR, - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_IN(SPI_NOR_MAX_ID_LEN, id, 1)); - - ret = spi_mem_exec_op(nor->spimem, &op); - } else { - ret = nor->controller_ops->read_reg(nor, SPINOR_OP_RDID, id, - SPI_NOR_MAX_ID_LEN); - } + ret = spi_nor_read_id(nor, 0, 0, id, nor->reg_proto); if (ret) { dev_dbg(nor->dev, "error %d reading JEDEC ID\n", ret); return ERR_PTR(ret); } - for (i = 0; i < ARRAY_SIZE(manufacturers); i++) { - info = spi_nor_search_part_by_id(manufacturers[i]->parts, - manufacturers[i]->nparts, - id); - if (info) { - nor->manufacturer = manufacturers[i]; - return info; - } + /* Cache the complete flash ID. */ + nor->id = devm_kmemdup(nor->dev, id, SPI_NOR_MAX_ID_LEN, GFP_KERNEL); + if (!nor->id) + return ERR_PTR(-ENOMEM); + + info = spi_nor_match_id(nor, id); + + /* Fallback to a generic flash described only by its SFDP data. */ + if (!info) { + ret = spi_nor_check_sfdp_signature(nor); + if (!ret) + info = &spi_nor_generic_flash; } - dev_err(nor->dev, "unrecognized JEDEC id bytes: %*ph\n", - SPI_NOR_MAX_ID_LEN, id); - return ERR_PTR(-ENODEV); + if (!info) { + dev_err(nor->dev, "unrecognized JEDEC id bytes: %*ph\n", + SPI_NOR_MAX_ID_LEN, id); + return ERR_PTR(-ENODEV); + } + return info; +} + +/* + * On Octal DTR capable flashes, reads cannot start or end at an odd + * address in Octal DTR mode. Extra bytes need to be read at the start + * or end to make sure both the start address and length remain even. + */ +static int spi_nor_octal_dtr_read(struct spi_nor *nor, loff_t from, size_t len, + u_char *buf) +{ + u_char *tmp_buf; + size_t tmp_len; + loff_t start, end; + int ret, bytes_read; + + if (IS_ALIGNED(from, 2) && IS_ALIGNED(len, 2)) + return spi_nor_read_data(nor, from, len, buf); + else if (IS_ALIGNED(from, 2) && len > PAGE_SIZE) + return spi_nor_read_data(nor, from, round_down(len, PAGE_SIZE), + buf); + + tmp_buf = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!tmp_buf) + return -ENOMEM; + + start = round_down(from, 2); + end = round_up(from + len, 2); + + /* + * Avoid allocating too much memory. The requested read length might be + * quite large. Allocating a buffer just as large (slightly bigger, in + * fact) would put unnecessary memory pressure on the system. + * + * For example if the read is from 3 to 1M, then this will read from 2 + * to 4098. The reads from 4098 to 1M will then not need a temporary + * buffer so they can proceed as normal. + */ + tmp_len = min_t(size_t, end - start, PAGE_SIZE); + + ret = spi_nor_read_data(nor, start, tmp_len, tmp_buf); + if (ret == 0) { + ret = -EIO; + goto out; + } + if (ret < 0) + goto out; + + /* + * More bytes are read than actually requested, but that number can't be + * reported to the calling function or it will confuse its calculations. + * Calculate how many of the _requested_ bytes were read. + */ + bytes_read = ret; + + if (from != start) + ret -= from - start; + + /* + * Only account for extra bytes at the end if they were actually read. + * For example, if the total length was truncated because of temporary + * buffer size limit then the adjustment for the extra bytes at the end + * is not needed. + */ + if (start + bytes_read == end) + ret -= end - (from + len); + + memcpy(buf, tmp_buf + (from - start), ret); +out: + kfree(tmp_buf); + return ret; } static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { struct spi_nor *nor = mtd_to_spi_nor(mtd); + loff_t from_lock = from; + size_t len_lock = len; ssize_t ret; dev_dbg(nor->dev, "from 0x%08x, len %zd\n", (u32)from, len); - ret = spi_nor_lock_and_prep(nor); + ret = spi_nor_prep_and_lock_rd(nor, from_lock, len_lock); if (ret) return ret; while (len) { loff_t addr = from; - addr = spi_nor_convert_addr(nor, addr); + if (nor->read_proto == SNOR_PROTO_8_8_8_DTR) + ret = spi_nor_octal_dtr_read(nor, addr, len, buf); + else + ret = spi_nor_read_data(nor, addr, len, buf); - ret = spi_nor_read_data(nor, addr, len, buf); if (ret == 0) { /* We shouldn't see 0-length reads */ ret = -EIO; @@ -1937,7 +2123,70 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, ret = 0; read_err: - spi_nor_unlock_and_unprep(nor); + spi_nor_unlock_and_unprep_rd(nor, from_lock, len_lock); + + return ret; +} + +/* + * On Octal DTR capable flashes, writes cannot start or end at an odd address + * in Octal DTR mode. Extra 0xff bytes need to be appended or prepended to + * make sure the start address and end address are even. 0xff is used because + * on NOR flashes a program operation can only flip bits from 1 to 0, not the + * other way round. 0 to 1 flip needs to happen via erases. + */ +static int spi_nor_octal_dtr_write(struct spi_nor *nor, loff_t to, size_t len, + const u8 *buf) +{ + u8 *tmp_buf; + size_t bytes_written; + loff_t start, end; + int ret; + + if (IS_ALIGNED(to, 2) && IS_ALIGNED(len, 2)) + return spi_nor_write_data(nor, to, len, buf); + + tmp_buf = kmalloc(nor->params->page_size, GFP_KERNEL); + if (!tmp_buf) + return -ENOMEM; + + memset(tmp_buf, 0xff, nor->params->page_size); + + start = round_down(to, 2); + end = round_up(to + len, 2); + + memcpy(tmp_buf + (to - start), buf, len); + + ret = spi_nor_write_data(nor, start, end - start, tmp_buf); + if (ret == 0) { + ret = -EIO; + goto out; + } + if (ret < 0) + goto out; + + /* + * More bytes are written than actually requested, but that number can't + * be reported to the calling function or it will confuse its + * calculations. Calculate how many of the _requested_ bytes were + * written. + */ + bytes_written = ret; + + if (to != start) + ret -= to - start; + + /* + * Only account for extra bytes at the end if they were actually + * written. For example, if for some reason the controller could only + * complete a partial write then the adjustment for the extra bytes at + * the end is not needed. + */ + if (start + bytes_written == end) + ret -= end - (to + len); + +out: + kfree(tmp_buf); return ret; } @@ -1950,42 +2199,40 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) { struct spi_nor *nor = mtd_to_spi_nor(mtd); - size_t page_offset, page_remain, i; + size_t i; ssize_t ret; + u32 page_size = nor->params->page_size; dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len); - ret = spi_nor_lock_and_prep(nor); + ret = spi_nor_prep_and_lock_pe(nor, to, len); if (ret) return ret; for (i = 0; i < len; ) { ssize_t written; loff_t addr = to + i; - - /* - * If page_size is a power of two, the offset can be quickly - * calculated with an AND operation. On the other cases we - * need to do a modulus operation (more expensive). - */ - if (is_power_of_2(nor->page_size)) { - page_offset = addr & (nor->page_size - 1); - } else { - uint64_t aux = addr; - - page_offset = do_div(aux, nor->page_size); - } + size_t page_offset = addr & (page_size - 1); /* the size of data remaining on the first page */ - page_remain = min_t(size_t, - nor->page_size - page_offset, len - i); + size_t page_remain = min_t(size_t, page_size - page_offset, len - i); - addr = spi_nor_convert_addr(nor, addr); + ret = spi_nor_lock_device(nor); + if (ret) + goto write_err; ret = spi_nor_write_enable(nor); - if (ret) + if (ret) { + spi_nor_unlock_device(nor); goto write_err; + } - ret = spi_nor_write_data(nor, addr, page_remain, buf + i); + if (nor->write_proto == SNOR_PROTO_8_8_8_DTR) + ret = spi_nor_octal_dtr_write(nor, addr, page_remain, + buf + i); + else + ret = spi_nor_write_data(nor, addr, page_remain, + buf + i); + spi_nor_unlock_device(nor); if (ret < 0) goto write_err; written = ret; @@ -1998,7 +2245,8 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, } write_err: - spi_nor_unlock_and_unprep(nor); + spi_nor_unlock_and_unprep_pe(nor, to, len); + return ret; } @@ -2079,7 +2327,7 @@ int spi_nor_hwcaps_read2cmd(u32 hwcaps) ARRAY_SIZE(hwcaps_read2cmd)); } -static int spi_nor_hwcaps_pp2cmd(u32 hwcaps) +int spi_nor_hwcaps_pp2cmd(u32 hwcaps) { static const int hwcaps_pp2cmd[][2] = { { SNOR_HWCAPS_PP, SNOR_CMD_PP }, @@ -2115,7 +2363,7 @@ static int spi_nor_spimem_check_op(struct spi_nor *nor, */ op->addr.nbytes = 4; if (!spi_mem_supports_op(nor->spimem, op)) { - if (nor->mtd.size > SZ_16M) + if (nor->params->size > SZ_16M) return -EOPNOTSUPP; /* If flash size <= 16MB, 3 address bytes are sufficient */ @@ -2138,15 +2386,13 @@ static int spi_nor_spimem_check_op(struct spi_nor *nor, static int spi_nor_spimem_check_readop(struct spi_nor *nor, const struct spi_nor_read_command *read) { - struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(read->opcode, 0), - SPI_MEM_OP_ADDR(3, 0, 0), - SPI_MEM_OP_DUMMY(1, 0), - SPI_MEM_OP_DATA_IN(1, NULL, 0)); + struct spi_mem_op op = SPI_NOR_READ_OP(read->opcode); spi_nor_spimem_setup_op(nor, &op, read->proto); /* convert the dummy cycles to the number of bytes */ - op.dummy.nbytes = (nor->read_dummy * op.dummy.buswidth) / 8; + op.dummy.nbytes = (read->num_mode_clocks + read->num_wait_states) * + op.dummy.buswidth / 8; if (spi_nor_protocol_is_dtr(nor->read_proto)) op.dummy.nbytes *= 2; @@ -2164,10 +2410,7 @@ static int spi_nor_spimem_check_readop(struct spi_nor *nor, static int spi_nor_spimem_check_pp(struct spi_nor *nor, const struct spi_nor_pp_command *pp) { - struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(pp->opcode, 0), - SPI_MEM_OP_ADDR(3, 0, 0), - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_OUT(1, NULL, 0)); + struct spi_mem_op op = SPI_NOR_PP_OP(pp->opcode); spi_nor_spimem_setup_op(nor, &op, pp->proto); @@ -2216,6 +2459,16 @@ spi_nor_spimem_adjust_hwcaps(struct spi_nor *nor, u32 *hwcaps) ¶ms->page_programs[ppidx])) *hwcaps &= ~BIT(cap); } + + /* Some SPI controllers might not support CR read opcode. */ + if (!(nor->flags & SNOR_F_NO_READ_CR)) { + struct spi_mem_op op = SPI_NOR_RDCR_OP(nor->bouncebuf); + + spi_nor_spimem_setup_op(nor, &op, nor->reg_proto); + + if (spi_nor_spimem_check_op(nor, &op)) + nor->flags |= SNOR_F_NO_READ_CR; + } } /** @@ -2235,6 +2488,15 @@ void spi_nor_set_erase_type(struct spi_nor_erase_type *erase, u32 size, } /** + * spi_nor_mask_erase_type() - mask out a SPI NOR erase type + * @erase: pointer to a structure that describes a SPI NOR erase type + */ +void spi_nor_mask_erase_type(struct spi_nor_erase_type *erase) +{ + erase->size = 0; +} + +/** * spi_nor_init_uniform_erase_map() - Initialize uniform erase map * @map: the erase map of the SPI NOR * @erase_mask: bitmask encoding erase types that can erase the entire @@ -2244,12 +2506,11 @@ void spi_nor_set_erase_type(struct spi_nor_erase_type *erase, u32 size, void spi_nor_init_uniform_erase_map(struct spi_nor_erase_map *map, u8 erase_mask, u64 flash_size) { - /* Offset 0 with erase_mask and SNOR_LAST_REGION bit set */ - map->uniform_region.offset = (erase_mask & SNOR_ERASE_TYPE_MASK) | - SNOR_LAST_REGION; + map->uniform_region.offset = 0; map->uniform_region.size = flash_size; + map->uniform_region.erase_mask = erase_mask; map->regions = &map->uniform_region; - map->uniform_erase_type = erase_mask; + map->n_regions = 1; } int spi_nor_post_bfpt_fixups(struct spi_nor *nor, @@ -2325,9 +2586,6 @@ static int spi_nor_select_pp(struct spi_nor *nor, /** * spi_nor_select_uniform_erase() - select optimum uniform erase type * @map: the erase map of the SPI NOR - * @wanted_size: the erase type size to search for. Contains the value of - * info->sector_size or of the "small sector" size in case - * CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is defined. * * Once the optimum uniform sector erase command is found, disable all the * other. @@ -2335,24 +2593,32 @@ static int spi_nor_select_pp(struct spi_nor *nor, * Return: pointer to erase type on success, NULL otherwise. */ static const struct spi_nor_erase_type * -spi_nor_select_uniform_erase(struct spi_nor_erase_map *map, - const u32 wanted_size) +spi_nor_select_uniform_erase(struct spi_nor_erase_map *map) { const struct spi_nor_erase_type *tested_erase, *erase = NULL; int i; - u8 uniform_erase_type = map->uniform_erase_type; + u8 uniform_erase_type = map->uniform_region.erase_mask; + /* + * Search for the biggest erase size, except for when compiled + * to use 4k erases. + */ for (i = SNOR_ERASE_TYPE_MAX - 1; i >= 0; i--) { if (!(uniform_erase_type & BIT(i))) continue; tested_erase = &map->erase_type[i]; + /* Skip masked erase types. */ + if (!tested_erase->size) + continue; + /* - * If the current erase size is the one, stop here: + * If the current erase size is the 4k one, stop here, * we have found the right uniform Sector Erase command. */ - if (tested_erase->size == wanted_size) { + if (IS_ENABLED(CONFIG_MTD_SPI_NOR_USE_4K_SECTORS) && + tested_erase->size == SZ_4K) { erase = tested_erase; break; } @@ -2370,8 +2636,7 @@ spi_nor_select_uniform_erase(struct spi_nor_erase_map *map, return NULL; /* Disable all other Sector Erase commands. */ - map->uniform_erase_type &= ~SNOR_ERASE_TYPE_MASK; - map->uniform_erase_type |= BIT(erase - map->erase_type); + map->uniform_region.erase_mask = BIT(erase - map->erase_type); return erase; } @@ -2380,7 +2645,6 @@ static int spi_nor_select_erase(struct spi_nor *nor) struct spi_nor_erase_map *map = &nor->params->erase_map; const struct spi_nor_erase_type *erase = NULL; struct mtd_info *mtd = &nor->mtd; - u32 wanted_size = nor->info->sector_size; int i; /* @@ -2391,13 +2655,8 @@ static int spi_nor_select_erase(struct spi_nor *nor) * manage the SPI flash memory as uniform with a single erase sector * size, when possible. */ -#ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS - /* prefer "small sector" erase if possible */ - wanted_size = 4096u; -#endif - if (spi_nor_has_uniform_erase(nor)) { - erase = spi_nor_select_uniform_erase(map, wanted_size); + erase = spi_nor_select_uniform_erase(map); if (!erase) return -EINVAL; nor->erase_opcode = erase->opcode; @@ -2423,8 +2682,51 @@ static int spi_nor_select_erase(struct spi_nor *nor) return 0; } -static int spi_nor_default_setup(struct spi_nor *nor, - const struct spi_nor_hwcaps *hwcaps) +static int spi_nor_set_addr_nbytes(struct spi_nor *nor) +{ + if (nor->params->addr_nbytes) { + nor->addr_nbytes = nor->params->addr_nbytes; + } else if (nor->read_proto == SNOR_PROTO_8_8_8_DTR) { + /* + * In 8D-8D-8D mode, one byte takes half a cycle to transfer. So + * in this protocol an odd addr_nbytes cannot be used because + * then the address phase would only span a cycle and a half. + * Half a cycle would be left over. We would then have to start + * the dummy phase in the middle of a cycle and so too the data + * phase, and we will end the transaction with half a cycle left + * over. + * + * Force all 8D-8D-8D flashes to use an addr_nbytes of 4 to + * avoid this situation. + */ + nor->addr_nbytes = 4; + } else if (nor->info->addr_nbytes) { + nor->addr_nbytes = nor->info->addr_nbytes; + } else { + nor->addr_nbytes = 3; + } + + if (nor->addr_nbytes == 3 && nor->params->size > 0x1000000) { + /* enable 4-byte addressing if the device exceeds 16MiB */ + nor->addr_nbytes = 4; + } + + if (nor->addr_nbytes > SPI_NOR_MAX_ADDR_NBYTES) { + dev_dbg(nor->dev, "The number of address bytes is too large: %u\n", + nor->addr_nbytes); + return -EINVAL; + } + + /* Set 4byte opcodes when possible. */ + if (nor->addr_nbytes == 4 && nor->flags & SNOR_F_4B_OPCODES && + !(nor->flags & SNOR_F_HAS_4BAIT)) + spi_nor_set_4byte_opcodes(nor); + + return 0; +} + +static int spi_nor_setup(struct spi_nor *nor, + const struct spi_nor_hwcaps *hwcaps) { struct spi_nor_flash_parameter *params = nor->params; u32 ignored_mask, shared_mask; @@ -2481,16 +2783,7 @@ static int spi_nor_default_setup(struct spi_nor *nor, return err; } - return 0; -} - -static int spi_nor_setup(struct spi_nor *nor, - const struct spi_nor_hwcaps *hwcaps) -{ - if (!nor->params->setup) - return 0; - - return nor->params->setup(nor, hwcaps); + return spi_nor_set_addr_nbytes(nor); } /** @@ -2509,107 +2802,51 @@ static void spi_nor_manufacturer_init_params(struct spi_nor *nor) } /** - * spi_nor_sfdp_init_params() - Initialize the flash's parameters and settings - * based on JESD216 SFDP standard. - * @nor: pointer to a 'struct spi_nor'. - * - * The method has a roll-back mechanism: in case the SFDP parsing fails, the - * legacy flash parameters and settings will be restored. - */ -static void spi_nor_sfdp_init_params(struct spi_nor *nor) -{ - struct spi_nor_flash_parameter sfdp_params; - - memcpy(&sfdp_params, nor->params, sizeof(sfdp_params)); - - if (spi_nor_parse_sfdp(nor)) { - memcpy(nor->params, &sfdp_params, sizeof(*nor->params)); - nor->addr_width = 0; - nor->flags &= ~SNOR_F_4B_OPCODES; - } -} - -/** - * spi_nor_info_init_params() - Initialize the flash's parameters and settings - * based on nor->info data. + * spi_nor_no_sfdp_init_params() - Initialize the flash's parameters and + * settings based on nor->info->sfdp_flags. This method should be called only by + * flashes that do not define SFDP tables. If the flash supports SFDP but the + * information is wrong and the settings from this function can not be retrieved + * by parsing SFDP, one should instead use the fixup hooks and update the wrong + * bits. * @nor: pointer to a 'struct spi_nor'. */ -static void spi_nor_info_init_params(struct spi_nor *nor) +static void spi_nor_no_sfdp_init_params(struct spi_nor *nor) { struct spi_nor_flash_parameter *params = nor->params; struct spi_nor_erase_map *map = ¶ms->erase_map; const struct flash_info *info = nor->info; - struct device_node *np = spi_nor_get_flash_node(nor); + const u8 no_sfdp_flags = info->no_sfdp_flags; u8 i, erase_mask; - /* Initialize default flash parameters and settings. */ - params->quad_enable = spi_nor_sr2_bit1_quad_enable; - params->set_4byte_addr_mode = spansion_set_4byte_addr_mode; - params->setup = spi_nor_default_setup; - params->otp.org = &info->otp_org; - - /* Default to 16-bit Write Status (01h) Command */ - nor->flags |= SNOR_F_HAS_16BIT_SR; - - /* Set SPI NOR sizes. */ - params->writesize = 1; - params->size = (u64)info->sector_size * info->n_sectors; - params->page_size = info->page_size; - - if (!(info->flags & SPI_NOR_NO_FR)) { - /* Default to Fast Read for DT and non-DT platform devices. */ - params->hwcaps.mask |= SNOR_HWCAPS_READ_FAST; - - /* Mask out Fast Read if not requested at DT instantiation. */ - if (np && !of_property_read_bool(np, "m25p,fast-read")) - params->hwcaps.mask &= ~SNOR_HWCAPS_READ_FAST; - } - - /* (Fast) Read settings. */ - params->hwcaps.mask |= SNOR_HWCAPS_READ; - spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ], - 0, 0, SPINOR_OP_READ, - SNOR_PROTO_1_1_1); - - if (params->hwcaps.mask & SNOR_HWCAPS_READ_FAST) - spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_FAST], - 0, 8, SPINOR_OP_READ_FAST, - SNOR_PROTO_1_1_1); - - if (info->flags & SPI_NOR_DUAL_READ) { + if (no_sfdp_flags & SPI_NOR_DUAL_READ) { params->hwcaps.mask |= SNOR_HWCAPS_READ_1_1_2; spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_1_1_2], 0, 8, SPINOR_OP_READ_1_1_2, SNOR_PROTO_1_1_2); } - if (info->flags & SPI_NOR_QUAD_READ) { + if (no_sfdp_flags & SPI_NOR_QUAD_READ) { params->hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4; spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_1_1_4], 0, 8, SPINOR_OP_READ_1_1_4, SNOR_PROTO_1_1_4); } - if (info->flags & SPI_NOR_OCTAL_READ) { + if (no_sfdp_flags & SPI_NOR_OCTAL_READ) { params->hwcaps.mask |= SNOR_HWCAPS_READ_1_1_8; spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_1_1_8], 0, 8, SPINOR_OP_READ_1_1_8, SNOR_PROTO_1_1_8); } - if (info->flags & SPI_NOR_OCTAL_DTR_READ) { + if (no_sfdp_flags & SPI_NOR_OCTAL_DTR_READ) { params->hwcaps.mask |= SNOR_HWCAPS_READ_8_8_8_DTR; spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_8_8_8_DTR], 0, 20, SPINOR_OP_READ_FAST, SNOR_PROTO_8_8_8_DTR); } - /* Page Program settings. */ - params->hwcaps.mask |= SNOR_HWCAPS_PP; - spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP], - SPINOR_OP_PP, SNOR_PROTO_1_1_1); - - if (info->flags & SPI_NOR_OCTAL_DTR_PP) { + if (no_sfdp_flags & SPI_NOR_OCTAL_DTR_PP) { params->hwcaps.mask |= SNOR_HWCAPS_PP_8_8_8_DTR; /* * Since xSPI Page Program opcode is backward compatible with @@ -2625,58 +2862,219 @@ static void spi_nor_info_init_params(struct spi_nor *nor) */ erase_mask = 0; i = 0; - if (info->flags & SECT_4K_PMC) { - erase_mask |= BIT(i); - spi_nor_set_erase_type(&map->erase_type[i], 4096u, - SPINOR_OP_BE_4K_PMC); - i++; - } else if (info->flags & SECT_4K) { + if (no_sfdp_flags & SECT_4K) { erase_mask |= BIT(i); spi_nor_set_erase_type(&map->erase_type[i], 4096u, SPINOR_OP_BE_4K); i++; } erase_mask |= BIT(i); - spi_nor_set_erase_type(&map->erase_type[i], info->sector_size, + spi_nor_set_erase_type(&map->erase_type[i], + info->sector_size ?: SPI_NOR_DEFAULT_SECTOR_SIZE, SPINOR_OP_SE); spi_nor_init_uniform_erase_map(map, erase_mask, params->size); } /** - * spi_nor_post_sfdp_fixups() - Updates the flash's parameters and settings - * after SFDP has been parsed (is also called for SPI NORs that do not - * support RDSFDP). + * spi_nor_init_flags() - Initialize NOR flags for settings that are not defined + * in the JESD216 SFDP standard, thus can not be retrieved when parsing SFDP. * @nor: pointer to a 'struct spi_nor' - * - * Typically used to tweak various parameters that could not be extracted by - * other means (i.e. when information provided by the SFDP/flash_info tables - * are incomplete or wrong). */ -static void spi_nor_post_sfdp_fixups(struct spi_nor *nor) +static void spi_nor_init_flags(struct spi_nor *nor) { - if (nor->manufacturer && nor->manufacturer->fixups && - nor->manufacturer->fixups->post_sfdp) - nor->manufacturer->fixups->post_sfdp(nor); + struct device_node *np = spi_nor_get_flash_node(nor); + const u16 flags = nor->info->flags; + + if (of_property_read_bool(np, "broken-flash-reset")) + nor->flags |= SNOR_F_BROKEN_RESET; + + if (of_property_read_bool(np, "no-wp")) + nor->flags |= SNOR_F_NO_WP; + + if (flags & SPI_NOR_SWP_IS_VOLATILE) + nor->flags |= SNOR_F_SWP_IS_VOLATILE; + + if (flags & SPI_NOR_HAS_LOCK) + nor->flags |= SNOR_F_HAS_LOCK; + + if (flags & SPI_NOR_HAS_TB) { + nor->flags |= SNOR_F_HAS_SR_TB; + if (flags & SPI_NOR_TB_SR_BIT6) + nor->flags |= SNOR_F_HAS_SR_TB_BIT6; + } + + if (flags & SPI_NOR_4BIT_BP) { + nor->flags |= SNOR_F_HAS_4BIT_BP; + if (flags & SPI_NOR_BP3_SR_BIT6) + nor->flags |= SNOR_F_HAS_SR_BP3_BIT6; + } + + if (flags & SPI_NOR_RWW && nor->params->n_banks > 1 && + !nor->controller_ops) + nor->flags |= SNOR_F_RWW; +} + +/** + * spi_nor_init_fixup_flags() - Initialize NOR flags for settings that can not + * be discovered by SFDP for this particular flash because the SFDP table that + * indicates this support is not defined in the flash. In case the table for + * this support is defined but has wrong values, one should instead use a + * post_sfdp() hook to set the SNOR_F equivalent flag. + * @nor: pointer to a 'struct spi_nor' + */ +static void spi_nor_init_fixup_flags(struct spi_nor *nor) +{ + const u8 fixup_flags = nor->info->fixup_flags; + + if (fixup_flags & SPI_NOR_4B_OPCODES) + nor->flags |= SNOR_F_4B_OPCODES; - if (nor->info->fixups && nor->info->fixups->post_sfdp) - nor->info->fixups->post_sfdp(nor); + if (fixup_flags & SPI_NOR_IO_MODE_EN_VOLATILE) + nor->flags |= SNOR_F_IO_MODE_EN_VOLATILE; } /** * spi_nor_late_init_params() - Late initialization of default flash parameters. * @nor: pointer to a 'struct spi_nor' * - * Used to set default flash parameters and settings when the ->default_init() - * hook or the SFDP parser let voids. + * Used to initialize flash parameters that are not declared in the JESD216 + * SFDP standard, or where SFDP tables are not defined at all. + * Will replace the spi_nor_manufacturer_init_params() method. */ -static void spi_nor_late_init_params(struct spi_nor *nor) +static int spi_nor_late_init_params(struct spi_nor *nor) { + struct spi_nor_flash_parameter *params = nor->params; + int ret; + + if (nor->manufacturer && nor->manufacturer->fixups && + nor->manufacturer->fixups->late_init) { + ret = nor->manufacturer->fixups->late_init(nor); + if (ret) + return ret; + } + + /* Needed by some flashes late_init hooks. */ + spi_nor_init_flags(nor); + + if (nor->info->fixups && nor->info->fixups->late_init) { + ret = nor->info->fixups->late_init(nor); + if (ret) + return ret; + } + + if (!nor->params->die_erase_opcode) + nor->params->die_erase_opcode = SPINOR_OP_CHIP_ERASE; + + /* Default method kept for backward compatibility. */ + if (!params->set_4byte_addr_mode) + params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_brwr; + + spi_nor_init_fixup_flags(nor); + /* * NOR protection support. When locking_ops are not provided, we pick * the default ones. */ if (nor->flags & SNOR_F_HAS_LOCK && !nor->params->locking_ops) spi_nor_init_default_locking_ops(nor); + + if (params->n_banks > 1) + params->bank_size = div_u64(params->size, params->n_banks); + + return 0; +} + +/** + * spi_nor_sfdp_init_params_deprecated() - Deprecated way of initializing flash + * parameters and settings based on JESD216 SFDP standard. + * @nor: pointer to a 'struct spi_nor'. + * + * The method has a roll-back mechanism: in case the SFDP parsing fails, the + * legacy flash parameters and settings will be restored. + */ +static void spi_nor_sfdp_init_params_deprecated(struct spi_nor *nor) +{ + struct spi_nor_flash_parameter sfdp_params; + + memcpy(&sfdp_params, nor->params, sizeof(sfdp_params)); + + if (spi_nor_parse_sfdp(nor)) { + memcpy(nor->params, &sfdp_params, sizeof(*nor->params)); + nor->flags &= ~SNOR_F_4B_OPCODES; + } +} + +/** + * spi_nor_init_params_deprecated() - Deprecated way of initializing flash + * parameters and settings. + * @nor: pointer to a 'struct spi_nor'. + * + * The method assumes that flash doesn't support SFDP so it initializes flash + * parameters in spi_nor_no_sfdp_init_params() which later on can be overwritten + * when parsing SFDP, if supported. + */ +static void spi_nor_init_params_deprecated(struct spi_nor *nor) +{ + spi_nor_no_sfdp_init_params(nor); + + spi_nor_manufacturer_init_params(nor); + + if (nor->info->no_sfdp_flags & (SPI_NOR_DUAL_READ | + SPI_NOR_QUAD_READ | + SPI_NOR_OCTAL_READ | + SPI_NOR_OCTAL_DTR_READ)) + spi_nor_sfdp_init_params_deprecated(nor); +} + +/** + * spi_nor_init_default_params() - Default initialization of flash parameters + * and settings. Done for all flashes, regardless is they define SFDP tables + * or not. + * @nor: pointer to a 'struct spi_nor'. + */ +static void spi_nor_init_default_params(struct spi_nor *nor) +{ + struct spi_nor_flash_parameter *params = nor->params; + const struct flash_info *info = nor->info; + struct device_node *np = spi_nor_get_flash_node(nor); + + params->quad_enable = spi_nor_sr2_bit1_quad_enable; + params->otp.org = info->otp; + + /* Default to 16-bit Write Status (01h) Command */ + nor->flags |= SNOR_F_HAS_16BIT_SR; + + /* Set SPI NOR sizes. */ + params->writesize = 1; + params->size = info->size; + params->bank_size = params->size; + params->page_size = info->page_size ?: SPI_NOR_DEFAULT_PAGE_SIZE; + params->n_banks = info->n_banks ?: SPI_NOR_DEFAULT_N_BANKS; + + /* Default to Fast Read for non-DT and enable it if requested by DT. */ + if (!np || of_property_read_bool(np, "m25p,fast-read")) + params->hwcaps.mask |= SNOR_HWCAPS_READ_FAST; + + /* (Fast) Read settings. */ + params->hwcaps.mask |= SNOR_HWCAPS_READ; + spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ], + 0, 0, SPINOR_OP_READ, + SNOR_PROTO_1_1_1); + + if (params->hwcaps.mask & SNOR_HWCAPS_READ_FAST) + spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_FAST], + 0, 8, SPINOR_OP_READ_FAST, + SNOR_PROTO_1_1_1); + /* Page Program settings. */ + params->hwcaps.mask |= SNOR_HWCAPS_PP; + spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP], + SPINOR_OP_PP, SNOR_PROTO_1_1_1); + + if (info->flags & SPI_NOR_QUAD_PP) { + params->hwcaps.mask |= SNOR_HWCAPS_PP_1_1_4; + spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP_1_1_4], + SPINOR_OP_PP_1_1_4, SNOR_PROTO_1_1_4); + } } /** @@ -2699,56 +3097,66 @@ static void spi_nor_late_init_params(struct spi_nor *nor) * which can be overwritten by: * 3/ SFDP flash parameters initialization. JESD216 SFDP is a standard and * should be more accurate that the above. - * spi_nor_sfdp_init_params() + * spi_nor_parse_sfdp() or spi_nor_no_sfdp_init_params() * * Please note that there is a ->post_bfpt() fixup hook that can overwrite * the flash parameters and settings immediately after parsing the Basic * Flash Parameter Table. + * spi_nor_post_sfdp_fixups() is called after the SFDP tables are parsed. + * It is used to tweak various flash parameters when information provided + * by the SFDP tables are wrong. * * which can be overwritten by: - * 4/ Post SFDP flash parameters initialization. Used to tweak various - * parameters that could not be extracted by other means (i.e. when - * information provided by the SFDP/flash_info tables are incomplete or - * wrong). - * spi_nor_post_sfdp_fixups() - * - * 5/ Late default flash parameters initialization, used when the - * ->default_init() hook or the SFDP parser do not set specific params. + * 4/ Late flash parameters initialization, used to initialize flash + * parameters that are not declared in the JESD216 SFDP standard, or where SFDP + * tables are not defined at all. * spi_nor_late_init_params() + * + * Return: 0 on success, -errno otherwise. */ static int spi_nor_init_params(struct spi_nor *nor) { + int ret; + nor->params = devm_kzalloc(nor->dev, sizeof(*nor->params), GFP_KERNEL); if (!nor->params) return -ENOMEM; - spi_nor_info_init_params(nor); + spi_nor_init_default_params(nor); - spi_nor_manufacturer_init_params(nor); - - if ((nor->info->flags & (SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_OCTAL_READ | SPI_NOR_OCTAL_DTR_READ)) && - !(nor->info->flags & SPI_NOR_SKIP_SFDP)) - spi_nor_sfdp_init_params(nor); + if (spi_nor_needs_sfdp(nor)) { + ret = spi_nor_parse_sfdp(nor); + if (ret) { + dev_err(nor->dev, "BFPT parsing failed. Please consider using SPI_NOR_SKIP_SFDP when declaring the flash\n"); + return ret; + } + } else if (nor->info->no_sfdp_flags & SPI_NOR_SKIP_SFDP) { + spi_nor_no_sfdp_init_params(nor); + } else { + spi_nor_init_params_deprecated(nor); + } - spi_nor_post_sfdp_fixups(nor); + ret = spi_nor_late_init_params(nor); + if (ret) + return ret; - spi_nor_late_init_params(nor); + if (WARN_ON(!is_power_of_2(nor->params->page_size))) + return -EINVAL; return 0; } -/** spi_nor_octal_dtr_enable() - enable Octal DTR I/O if needed +/** spi_nor_set_octal_dtr() - enable or disable Octal DTR I/O. * @nor: pointer to a 'struct spi_nor' * @enable: whether to enable or disable Octal DTR * * Return: 0 on success, -errno otherwise. */ -static int spi_nor_octal_dtr_enable(struct spi_nor *nor, bool enable) +static int spi_nor_set_octal_dtr(struct spi_nor *nor, bool enable) { int ret; - if (!nor->params->octal_dtr_enable) + if (!nor->params->set_octal_dtr) return 0; if (!(nor->read_proto == SNOR_PROTO_8_8_8_DTR && @@ -2758,7 +3166,7 @@ static int spi_nor_octal_dtr_enable(struct spi_nor *nor, bool enable) if (!(nor->flags & SNOR_F_IO_MODE_EN_VOLATILE)) return 0; - ret = nor->params->octal_dtr_enable(nor, enable); + ret = nor->params->set_octal_dtr(nor, enable); if (ret) return ret; @@ -2788,11 +3196,50 @@ static int spi_nor_quad_enable(struct spi_nor *nor) return nor->params->quad_enable(nor); } +/** + * spi_nor_set_4byte_addr_mode() - Set address mode. + * @nor: pointer to a 'struct spi_nor'. + * @enable: enable/disable 4 byte address mode. + * + * Return: 0 on success, -errno otherwise. + */ +int spi_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable) +{ + struct spi_nor_flash_parameter *params = nor->params; + int ret; + + if (enable) { + /* + * If the RESET# pin isn't hooked up properly, or the system + * otherwise doesn't perform a reset command in the boot + * sequence, it's impossible to 100% protect against unexpected + * reboots (e.g., crashes). Warn the user (or hopefully, system + * designer) that this is bad. + */ + WARN_ONCE(nor->flags & SNOR_F_BROKEN_RESET, + "enabling reset hack; may not recover from unexpected reboots\n"); + } + + ret = params->set_4byte_addr_mode(nor, enable); + if (ret && ret != -EOPNOTSUPP) + return ret; + + if (enable) { + params->addr_nbytes = 4; + params->addr_mode_nbytes = 4; + } else { + params->addr_nbytes = 3; + params->addr_mode_nbytes = 3; + } + + return 0; +} + static int spi_nor_init(struct spi_nor *nor) { int err; - err = spi_nor_octal_dtr_enable(nor, true); + err = spi_nor_set_octal_dtr(nor, true); if (err) { dev_dbg(nor->dev, "octal mode not supported\n"); return err; @@ -2819,20 +3266,10 @@ static int spi_nor_init(struct spi_nor *nor) nor->flags & SNOR_F_SWP_IS_VOLATILE)) spi_nor_try_unlock_all(nor); - if (nor->addr_width == 4 && + if (nor->addr_nbytes == 4 && nor->read_proto != SNOR_PROTO_8_8_8_DTR && - !(nor->flags & SNOR_F_4B_OPCODES)) { - /* - * If the RESET# pin isn't hooked up properly, or the system - * otherwise doesn't perform a reset command in the boot - * sequence, it's impossible to 100% protect against unexpected - * reboots (e.g., crashes). Warn the user (or hopefully, system - * designer) that this is bad. - */ - WARN_ONCE(nor->flags & SNOR_F_BROKEN_RESET, - "enabling reset hack; may not recover from unexpected reboots\n"); - nor->params->set_4byte_addr_mode(nor, true); - } + !(nor->flags & SNOR_F_4B_OPCODES)) + return spi_nor_set_4byte_addr_mode(nor, true); return 0; } @@ -2857,23 +3294,18 @@ static void spi_nor_soft_reset(struct spi_nor *nor) struct spi_mem_op op; int ret; - op = (struct spi_mem_op)SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_SRSTEN, 0), - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_NO_ADDR, - SPI_MEM_OP_NO_DATA); + op = (struct spi_mem_op)SPINOR_SRSTEN_OP; spi_nor_spimem_setup_op(nor, &op, nor->reg_proto); ret = spi_mem_exec_op(nor->spimem, &op); if (ret) { - dev_warn(nor->dev, "Software reset failed: %d\n", ret); + if (ret != -EOPNOTSUPP) + dev_warn(nor->dev, "Software reset failed: %d\n", ret); return; } - op = (struct spi_mem_op)SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_SRST, 0), - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_NO_ADDR, - SPI_MEM_OP_NO_DATA); + op = (struct spi_mem_op)SPINOR_SRST_OP; spi_nor_spimem_setup_op(nor, &op, nor->reg_proto); @@ -2898,7 +3330,7 @@ static int spi_nor_suspend(struct mtd_info *mtd) int ret; /* Disable octal DTR mode if we enabled it. */ - ret = spi_nor_octal_dtr_enable(nor, false); + ret = spi_nor_set_octal_dtr(nor, false); if (ret) dev_err(nor->dev, "suspend() failed\n"); @@ -2949,26 +3381,36 @@ static void spi_nor_put_device(struct mtd_info *mtd) module_put(dev->driver->owner); } -void spi_nor_restore(struct spi_nor *nor) +static void spi_nor_restore(struct spi_nor *nor) { + int ret; + /* restore the addressing mode */ - if (nor->addr_width == 4 && !(nor->flags & SNOR_F_4B_OPCODES) && - nor->flags & SNOR_F_BROKEN_RESET) - nor->params->set_4byte_addr_mode(nor, false); + if (nor->addr_nbytes == 4 && !(nor->flags & SNOR_F_4B_OPCODES) && + nor->flags & SNOR_F_BROKEN_RESET) { + ret = spi_nor_set_4byte_addr_mode(nor, false); + if (ret) + /* + * Do not stop the execution in the hope that the flash + * will default to the 3-byte address mode after the + * software reset. + */ + dev_err(nor->dev, "Failed to exit 4-byte address mode, err = %d\n", ret); + } if (nor->flags & SNOR_F_SOFT_RESET) spi_nor_soft_reset(nor); } -EXPORT_SYMBOL_GPL(spi_nor_restore); -static const struct flash_info *spi_nor_match_id(struct spi_nor *nor, - const char *name) +static const struct flash_info *spi_nor_match_name(struct spi_nor *nor, + const char *name) { unsigned int i, j; for (i = 0; i < ARRAY_SIZE(manufacturers); i++) { for (j = 0; j < manufacturers[i]->nparts; j++) { - if (!strcmp(name, manufacturers[i]->parts[j].name)) { + if (manufacturers[i]->parts[j].name && + !strcmp(name, manufacturers[i]->parts[j].name)) { nor->manufacturer = manufacturers[i]; return &manufacturers[i]->parts[j]; } @@ -2978,97 +3420,144 @@ static const struct flash_info *spi_nor_match_id(struct spi_nor *nor, return NULL; } -static int spi_nor_set_addr_width(struct spi_nor *nor) +static const struct flash_info *spi_nor_get_flash_info(struct spi_nor *nor, + const char *name) { - if (nor->addr_width) { - /* already configured from SFDP */ - } else if (nor->read_proto == SNOR_PROTO_8_8_8_DTR) { + const struct flash_info *info = NULL; + + if (name) + info = spi_nor_match_name(nor, name); + /* + * Auto-detect if chip name wasn't specified or not found, or the chip + * has an ID. If the chip supposedly has an ID, we also do an + * auto-detection to compare it later. + */ + if (!info || info->id) { + const struct flash_info *jinfo; + + jinfo = spi_nor_detect(nor); + if (IS_ERR(jinfo)) + return jinfo; + /* - * In 8D-8D-8D mode, one byte takes half a cycle to transfer. So - * in this protocol an odd address width cannot be used because - * then the address phase would only span a cycle and a half. - * Half a cycle would be left over. We would then have to start - * the dummy phase in the middle of a cycle and so too the data - * phase, and we will end the transaction with half a cycle left - * over. - * - * Force all 8D-8D-8D flashes to use an address width of 4 to - * avoid this situation. + * If caller has specified name of flash model that can normally + * be detected using JEDEC, let's verify it. */ - nor->addr_width = 4; - } else if (nor->info->addr_width) { - nor->addr_width = nor->info->addr_width; - } else { - nor->addr_width = 3; + if (info && jinfo != info) + dev_warn(nor->dev, "found %s, expected %s\n", + jinfo->name, info->name); + + /* If info was set before, JEDEC knows better. */ + info = jinfo; } - if (nor->addr_width == 3 && nor->mtd.size > 0x1000000) { - /* enable 4-byte addressing if the device exceeds 16MiB */ - nor->addr_width = 4; + return info; +} + +static u32 +spi_nor_get_region_erasesize(const struct spi_nor_erase_region *region, + const struct spi_nor_erase_type *erase_type) +{ + int i; + + if (region->overlaid) + return region->size; + + for (i = SNOR_ERASE_TYPE_MAX - 1; i >= 0; i--) { + if (region->erase_mask & BIT(i)) + return erase_type[i].size; } - if (nor->addr_width > SPI_NOR_MAX_ADDR_WIDTH) { - dev_dbg(nor->dev, "address width is too large: %u\n", - nor->addr_width); - return -EINVAL; + return 0; +} + +static int spi_nor_set_mtd_eraseregions(struct spi_nor *nor) +{ + const struct spi_nor_erase_map *map = &nor->params->erase_map; + const struct spi_nor_erase_region *region = map->regions; + struct mtd_erase_region_info *mtd_region; + struct mtd_info *mtd = &nor->mtd; + u32 erasesize, i; + + mtd_region = devm_kcalloc(nor->dev, map->n_regions, sizeof(*mtd_region), + GFP_KERNEL); + if (!mtd_region) + return -ENOMEM; + + for (i = 0; i < map->n_regions; i++) { + erasesize = spi_nor_get_region_erasesize(®ion[i], + map->erase_type); + if (!erasesize) + return -EINVAL; + + mtd_region[i].erasesize = erasesize; + mtd_region[i].numblocks = div_u64(region[i].size, erasesize); + mtd_region[i].offset = region[i].offset; } - /* Set 4byte opcodes when possible. */ - if (nor->addr_width == 4 && nor->flags & SNOR_F_4B_OPCODES && - !(nor->flags & SNOR_F_HAS_4BAIT)) - spi_nor_set_4byte_opcodes(nor); + mtd->numeraseregions = map->n_regions; + mtd->eraseregions = mtd_region; return 0; } -static void spi_nor_debugfs_init(struct spi_nor *nor, - const struct flash_info *info) +static int spi_nor_set_mtd_info(struct spi_nor *nor) { struct mtd_info *mtd = &nor->mtd; + struct device *dev = nor->dev; + + spi_nor_set_mtd_locking_ops(nor); + spi_nor_set_mtd_otp_ops(nor); + + mtd->dev.parent = dev; + if (!mtd->name) + mtd->name = dev_name(dev); + mtd->type = MTD_NORFLASH; + mtd->flags = MTD_CAP_NORFLASH; + /* Unset BIT_WRITEABLE to enable JFFS2 write buffer for ECC'd NOR */ + if (nor->flags & SNOR_F_ECC) + mtd->flags &= ~MTD_BIT_WRITEABLE; + if (nor->info->flags & SPI_NOR_NO_ERASE) + mtd->flags |= MTD_NO_ERASE; + else + mtd->_erase = spi_nor_erase; + mtd->writesize = nor->params->writesize; + mtd->writebufsize = nor->params->page_size; + mtd->size = nor->params->size; + mtd->_read = spi_nor_read; + /* Might be already set by some SST flashes. */ + if (!mtd->_write) + mtd->_write = spi_nor_write; + mtd->_suspend = spi_nor_suspend; + mtd->_resume = spi_nor_resume; + mtd->_get_device = spi_nor_get_device; + mtd->_put_device = spi_nor_put_device; + + if (!spi_nor_has_uniform_erase(nor)) + return spi_nor_set_mtd_eraseregions(nor); - mtd->dbg.partname = info->name; - mtd->dbg.partid = devm_kasprintf(nor->dev, GFP_KERNEL, "spi-nor:%*phN", - info->id_len, info->id); + return 0; } -static const struct flash_info *spi_nor_get_flash_info(struct spi_nor *nor, - const char *name) +static int spi_nor_hw_reset(struct spi_nor *nor) { - const struct flash_info *info = NULL; + struct gpio_desc *reset; - if (name) - info = spi_nor_match_id(nor, name); - /* Try to auto-detect if chip name wasn't specified or not found */ - if (!info) - info = spi_nor_read_id(nor); - if (IS_ERR_OR_NULL(info)) - return ERR_PTR(-ENOENT); + reset = devm_gpiod_get_optional(nor->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR_OR_NULL(reset)) + return PTR_ERR_OR_ZERO(reset); /* - * If caller has specified name of flash model that can normally be - * detected using JEDEC, let's verify it. + * Experimental delay values by looking at different flash device + * vendors datasheets. */ - if (name && info->id_len) { - const struct flash_info *jinfo; - - jinfo = spi_nor_read_id(nor); - if (IS_ERR(jinfo)) { - return jinfo; - } else if (jinfo != info) { - /* - * JEDEC knows better, so overwrite platform ID. We - * can't trust partitions any longer, but we'll let - * mtd apply them anyway, since some partitions may be - * marked read-only, and we don't want to lose that - * information, even if it's not 100% accurate. - */ - dev_warn(nor->dev, "found %s, expected %s\n", - jinfo->name, info->name); - info = jinfo; - } - } + usleep_range(1, 5); + gpiod_set_value_cansleep(reset, 1); + usleep_range(100, 150); + gpiod_set_value_cansleep(reset, 0); + usleep_range(1000, 1200); - return info; + return 0; } int spi_nor_scan(struct spi_nor *nor, const char *name, @@ -3076,10 +3565,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, { const struct flash_info *info; struct device *dev = nor->dev; - struct mtd_info *mtd = &nor->mtd; - struct device_node *np = spi_nor_get_flash_node(nor); int ret; - int i; ret = spi_nor_check(nor); if (ret) @@ -3094,7 +3580,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, * We need the bounce buffer early to read/write registers when going * through the spi-mem layer (buffers have to be DMA-able). * For spi-mem drivers, we'll reallocate a new buffer if - * nor->page_size turns out to be greater than PAGE_SIZE (which + * nor->params->page_size turns out to be greater than PAGE_SIZE (which * shouldn't happen before long since NOR pages are usually less * than 1KB) after spi_nor_scan() returns. */ @@ -3104,128 +3590,50 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, if (!nor->bouncebuf) return -ENOMEM; + ret = spi_nor_hw_reset(nor); + if (ret) + return ret; + info = spi_nor_get_flash_info(nor, name); if (IS_ERR(info)) return PTR_ERR(info); nor->info = info; - spi_nor_debugfs_init(nor, info); - mutex_init(&nor->lock); - /* - * Make sure the XSR_RDY flag is set before calling - * spi_nor_wait_till_ready(). Xilinx S3AN share MFR - * with Atmel SPI NOR. - */ - if (info->flags & SPI_NOR_XSR_RDY) - nor->flags |= SNOR_F_READY_XSR_RDY; - - if (info->flags & SPI_NOR_HAS_LOCK) - nor->flags |= SNOR_F_HAS_LOCK; - - mtd->_write = spi_nor_write; - /* Init flash parameters based on flash_info struct and SFDP */ ret = spi_nor_init_params(nor); if (ret) return ret; - if (!mtd->name) - mtd->name = dev_name(dev); - mtd->priv = nor; - mtd->type = MTD_NORFLASH; - mtd->writesize = nor->params->writesize; - mtd->flags = MTD_CAP_NORFLASH; - mtd->size = nor->params->size; - mtd->_erase = spi_nor_erase; - mtd->_read = spi_nor_read; - mtd->_suspend = spi_nor_suspend; - mtd->_resume = spi_nor_resume; - mtd->_get_device = spi_nor_get_device; - mtd->_put_device = spi_nor_put_device; - - if (info->flags & USE_FSR) - nor->flags |= SNOR_F_USE_FSR; - if (info->flags & SPI_NOR_HAS_TB) { - nor->flags |= SNOR_F_HAS_SR_TB; - if (info->flags & SPI_NOR_TB_SR_BIT6) - nor->flags |= SNOR_F_HAS_SR_TB_BIT6; - } - - if (info->flags & NO_CHIP_ERASE) - nor->flags |= SNOR_F_NO_OP_CHIP_ERASE; - if (info->flags & USE_CLSR) - nor->flags |= SNOR_F_USE_CLSR; - if (info->flags & SPI_NOR_SWP_IS_VOLATILE) - nor->flags |= SNOR_F_SWP_IS_VOLATILE; - - if (info->flags & SPI_NOR_4BIT_BP) { - nor->flags |= SNOR_F_HAS_4BIT_BP; - if (info->flags & SPI_NOR_BP3_SR_BIT6) - nor->flags |= SNOR_F_HAS_SR_BP3_BIT6; - } - - if (info->flags & SPI_NOR_NO_ERASE) - mtd->flags |= MTD_NO_ERASE; - - mtd->dev.parent = dev; - nor->page_size = nor->params->page_size; - mtd->writebufsize = nor->page_size; - - if (of_property_read_bool(np, "broken-flash-reset")) - nor->flags |= SNOR_F_BROKEN_RESET; + if (spi_nor_use_parallel_locking(nor)) + init_waitqueue_head(&nor->rww.wait); /* * Configure the SPI memory: * - select op codes for (Fast) Read, Page Program and Sector Erase. * - set the number of dummy cycles (mode cycles + wait states). * - set the SPI protocols for register and memory accesses. + * - set the number of address bytes. */ ret = spi_nor_setup(nor, hwcaps); if (ret) return ret; - if (info->flags & SPI_NOR_4B_OPCODES) - nor->flags |= SNOR_F_4B_OPCODES; - - if (info->flags & SPI_NOR_IO_MODE_EN_VOLATILE) - nor->flags |= SNOR_F_IO_MODE_EN_VOLATILE; - - ret = spi_nor_set_addr_width(nor); + /* Send all the required SPI flash commands to initialize device */ + ret = spi_nor_init(nor); if (ret) return ret; - spi_nor_register_locking_ops(nor); - - /* Send all the required SPI flash commands to initialize device */ - ret = spi_nor_init(nor); + /* No mtd_info fields should be used up to this point. */ + ret = spi_nor_set_mtd_info(nor); if (ret) return ret; - /* Configure OTP parameters and ops */ - spi_nor_otp_init(nor); - - dev_info(dev, "%s (%lld Kbytes)\n", info->name, - (long long)mtd->size >> 10); - - dev_dbg(dev, - "mtd .name = %s, .size = 0x%llx (%lldMiB), " - ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n", - mtd->name, (long long)mtd->size, (long long)(mtd->size >> 20), - mtd->erasesize, mtd->erasesize / 1024, mtd->numeraseregions); - - if (mtd->numeraseregions) - for (i = 0; i < mtd->numeraseregions; i++) - dev_dbg(dev, - "mtd.eraseregions[%d] = { .offset = 0x%llx, " - ".erasesize = 0x%.8x (%uKiB), " - ".numblocks = %d }\n", - i, (long long)mtd->eraseregions[i].offset, - mtd->eraseregions[i].erasesize, - mtd->eraseregions[i].erasesize / 1024, - mtd->eraseregions[i].numblocks); + dev_dbg(dev, "Manufacturer and device ID: %*phN\n", + SPI_NOR_MAX_ID_LEN, nor->id); + return 0; } EXPORT_SYMBOL_GPL(spi_nor_scan); @@ -3234,11 +3642,11 @@ static int spi_nor_create_read_dirmap(struct spi_nor *nor) { struct spi_mem_dirmap_info info = { .op_tmpl = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 0), - SPI_MEM_OP_ADDR(nor->addr_width, 0, 0), + SPI_MEM_OP_ADDR(nor->addr_nbytes, 0, 0), SPI_MEM_OP_DUMMY(nor->read_dummy, 0), SPI_MEM_OP_DATA_IN(0, NULL, 0)), .offset = 0, - .length = nor->mtd.size, + .length = nor->params->size, }; struct spi_mem_op *op = &info.op_tmpl; @@ -3265,11 +3673,11 @@ static int spi_nor_create_write_dirmap(struct spi_nor *nor) { struct spi_mem_dirmap_info info = { .op_tmpl = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 0), - SPI_MEM_OP_ADDR(nor->addr_width, 0, 0), + SPI_MEM_OP_ADDR(nor->addr_nbytes, 0, 0), SPI_MEM_OP_NO_DUMMY, SPI_MEM_OP_DATA_OUT(0, NULL, 0)), .offset = 0, - .length = nor->mtd.size, + .length = nor->params->size, }; struct spi_mem_op *op = &info.op_tmpl; @@ -3293,7 +3701,8 @@ static int spi_nor_create_write_dirmap(struct spi_nor *nor) static int spi_nor_probe(struct spi_mem *spimem) { struct spi_device *spi = spimem->spi; - struct flash_platform_data *data = dev_get_platdata(&spi->dev); + struct device *dev = &spi->dev; + struct flash_platform_data *data = dev_get_platdata(dev); struct spi_nor *nor; /* * Enable all caps by default. The core will mask them after @@ -3303,13 +3712,17 @@ static int spi_nor_probe(struct spi_mem *spimem) char *flash_name; int ret; - nor = devm_kzalloc(&spi->dev, sizeof(*nor), GFP_KERNEL); + ret = devm_regulator_get_enable(dev, "vcc"); + if (ret) + return ret; + + nor = devm_kzalloc(dev, sizeof(*nor), GFP_KERNEL); if (!nor) return -ENOMEM; nor->spimem = spimem; - nor->dev = &spi->dev; - spi_nor_set_flash_node(nor, spi->dev.of_node); + nor->dev = dev; + spi_nor_set_flash_node(nor, dev->of_node); spi_mem_set_drvdata(spimem, nor); @@ -3336,16 +3749,17 @@ static int spi_nor_probe(struct spi_mem *spimem) if (ret) return ret; + spi_nor_debugfs_register(nor); + /* * None of the existing parts have > 512B pages, but let's play safe * and add this logic so that if anyone ever adds support for such * a NOR we don't end up with buffer overflows. */ - if (nor->page_size > PAGE_SIZE) { - nor->bouncebuf_size = nor->page_size; - devm_kfree(nor->dev, nor->bouncebuf); - nor->bouncebuf = devm_kmalloc(nor->dev, - nor->bouncebuf_size, + if (nor->params->page_size > PAGE_SIZE) { + nor->bouncebuf_size = nor->params->page_size; + devm_kfree(dev, nor->bouncebuf); + nor->bouncebuf = devm_kmalloc(dev, nor->bouncebuf_size, GFP_KERNEL); if (!nor->bouncebuf) return -ENOMEM; @@ -3389,8 +3803,8 @@ static void spi_nor_shutdown(struct spi_mem *spimem) * encourage new users to add support to the spi-nor library, and simply bind * against a generic string here (e.g., "jedec,spi-nor"). * - * Many flash names are kept here in this list (as well as in spi-nor.c) to - * keep them available as module aliases for existing platforms. + * Many flash names are kept here in this list to keep them available + * as module aliases for existing platforms. */ static const struct spi_device_id spi_nor_dev_ids[] = { /* @@ -3465,7 +3879,19 @@ static struct spi_mem_driver spi_nor_driver = { .remove = spi_nor_remove, .shutdown = spi_nor_shutdown, }; -module_spi_mem_driver(spi_nor_driver); + +static int __init spi_nor_module_init(void) +{ + return spi_mem_driver_register(&spi_nor_driver); +} +module_init(spi_nor_module_init); + +static void __exit spi_nor_module_exit(void) +{ + spi_mem_driver_unregister(&spi_nor_driver); + spi_nor_debugfs_shutdown(); +} +module_exit(spi_nor_module_exit); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Huang Shijie <shijie8@gmail.com>"); |
