diff options
Diffstat (limited to 'drivers/mtd/spi-nor/core.c')
| -rw-r--r-- | drivers/mtd/spi-nor/core.c | 2991 |
1 files changed, 1712 insertions, 1279 deletions
diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 0369d98b2d12..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,85 @@ */ #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 + +/** + * spi_nor_get_cmd_ext() - Get the command opcode extension based on the + * extension type. + * @nor: pointer to a 'struct spi_nor' + * @op: pointer to the 'struct spi_mem_op' whose properties + * need to be initialized. + * + * Right now, only "repeat" and "invert" are supported. + * + * Return: The opcode extension. + */ +static u8 spi_nor_get_cmd_ext(const struct spi_nor *nor, + const struct spi_mem_op *op) +{ + switch (nor->cmd_ext_type) { + case SPI_NOR_EXT_INVERT: + return ~op->cmd.opcode; + + case SPI_NOR_EXT_REPEAT: + return op->cmd.opcode; + + default: + dev_err(nor->dev, "Unknown command extension type\n"); + return 0; + } +} + +/** + * spi_nor_spimem_setup_op() - Set up common properties of a spi-mem op. + * @nor: pointer to a 'struct spi_nor' + * @op: pointer to the 'struct spi_mem_op' whose properties + * need to be initialized. + * @proto: the protocol from which the properties need to be set. + */ +void spi_nor_spimem_setup_op(const struct spi_nor *nor, + struct spi_mem_op *op, + const enum spi_nor_protocol proto) +{ + u8 ext; + + op->cmd.buswidth = spi_nor_get_protocol_inst_nbits(proto); + + if (op->addr.nbytes) + op->addr.buswidth = spi_nor_get_protocol_addr_nbits(proto); + + if (op->dummy.nbytes) + op->dummy.buswidth = spi_nor_get_protocol_addr_nbits(proto); + + if (op->data.nbytes) + op->data.buswidth = spi_nor_get_protocol_data_nbits(proto); + + if (spi_nor_protocol_is_dtr(proto)) { + /* + * SPIMEM supports mixed DTR modes, but right now we can only + * have all phases either DTR or STR. IOW, SPIMEM can have + * something like 4S-4D-4D, but SPI NOR can't. So, set all 4 + * phases to either DTR or STR. + */ + op->cmd.dtr = true; + op->addr.dtr = true; + op->dummy.dtr = true; + op->data.dtr = true; + + /* 2 bytes per clock cycle in DTR mode. */ + op->dummy.nbytes *= 2; + + ext = spi_nor_get_cmd_ext(nor, op); + 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; +} /** * spi_nor_spimem_bounce() - check if a bounce buffer is needed for the data @@ -82,6 +162,32 @@ static int spi_nor_spimem_exec_op(struct spi_nor *nor, struct spi_mem_op *op) return spi_mem_exec_op(nor->spimem, op); } +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; + + return nor->controller_ops->read_reg(nor, opcode, buf, 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; + + return nor->controller_ops->write_reg(nor, opcode, buf, len); +} + +static int spi_nor_controller_ops_erase(struct spi_nor *nor, loff_t offs) +{ + if (spi_nor_protocol_is_dtr(nor->reg_proto)) + return -EOPNOTSUPP; + + return nor->controller_ops->erase(nor, offs); +} + /** * spi_nor_spimem_read_data() - read data from flash's memory region via * spi-mem @@ -96,22 +202,20 @@ static ssize_t spi_nor_spimem_read_data(struct spi_nor *nor, loff_t from, size_t len, u8 *buf) { struct spi_mem_op op = - SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 1), - SPI_MEM_OP_ADDR(nor->addr_width, from, 1), - SPI_MEM_OP_DUMMY(nor->read_dummy, 1), - SPI_MEM_OP_DATA_IN(len, buf, 1)); + SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 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; ssize_t nbytes; int error; - /* get transfer protocols. */ - op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->read_proto); - op.addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->read_proto); - op.dummy.buswidth = op.addr.buswidth; - op.data.buswidth = spi_nor_get_protocol_data_nbits(nor->read_proto); + spi_nor_spimem_setup_op(nor, &op, nor->read_proto); /* convert the dummy cycles to the number of bytes */ op.dummy.nbytes = (nor->read_dummy * op.dummy.buswidth) / 8; + if (spi_nor_protocol_is_dtr(nor->read_proto)) + op.dummy.nbytes *= 2; usebouncebuf = spi_nor_spimem_bounce(nor, &op); @@ -162,20 +266,18 @@ static ssize_t spi_nor_spimem_write_data(struct spi_nor *nor, loff_t to, size_t len, const u8 *buf) { struct spi_mem_op op = - SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 1), - SPI_MEM_OP_ADDR(nor->addr_width, to, 1), + SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 0), + SPI_MEM_OP_ADDR(nor->addr_nbytes, to, 0), SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_OUT(len, buf, 1)); + SPI_MEM_OP_DATA_OUT(len, buf, 0)); ssize_t nbytes; int error; - op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->write_proto); - op.addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->write_proto); - op.data.buswidth = spi_nor_get_protocol_data_nbits(nor->write_proto); - if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second) op.addr.nbytes = 0; + spi_nor_spimem_setup_op(nor, &op, nor->write_proto); + if (spi_nor_spimem_bounce(nor, &op)) memcpy(nor->bouncebuf, buf, op.data.nbytes); @@ -211,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'. * @@ -221,16 +369,14 @@ 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, 1), - 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); ret = spi_mem_exec_op(nor->spimem, &op); } else { - ret = nor->controller_ops->write_reg(nor, SPINOR_OP_WREN, - NULL, 0); + ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_WREN, + NULL, 0); } if (ret) @@ -250,16 +396,14 @@ 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, 1), - 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); ret = spi_mem_exec_op(nor->spimem, &op); } else { - ret = nor->controller_ops->write_reg(nor, SPINOR_OP_WRDI, - NULL, 0); + ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_WRDI, + NULL, 0); } if (ret) @@ -269,63 +413,71 @@ 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. + * @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. */ -static 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, 1), - SPI_MEM_OP_NO_ADDR, - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_IN(1, sr, 1)); + 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 = 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. + * 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, 1), - SPI_MEM_OP_NO_ADDR, - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_IN(1, fsr, 1)); + 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; + op.dummy.nbytes = nor->params->rdsr_dummy; + /* + * We don't want to read only one byte in DTR mode. So, + * read 2 and then discard the second byte. + */ + op.data.nbytes = 2; + } + + spi_nor_spimem_setup_op(nor, &op, nor->reg_proto); ret = spi_mem_exec_op(nor->spimem, &op); } else { - ret = nor->controller_ops->read_reg(nor, SPINOR_OP_RDFSR, - fsr, 1); + 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; } @@ -339,20 +491,19 @@ static int spi_nor_read_fsr(struct spi_nor *nor, u8 *fsr) * * Return: 0 on success, -errno otherwise. */ -static int spi_nor_read_cr(struct spi_nor *nor, u8 *cr) +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, 1), - SPI_MEM_OP_NO_ADDR, - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_IN(1, cr, 1)); + struct spi_mem_op op = SPI_NOR_RDCR_OP(cr); + + spi_nor_spimem_setup_op(nor, &op, nor->reg_proto); ret = spi_mem_exec_op(nor->spimem, &op); } else { - ret = nor->controller_ops->read_reg(nor, SPINOR_OP_RDCR, cr, 1); + ret = spi_nor_controller_ops_read_reg(nor, SPINOR_OP_RDCR, cr, + 1); } if (ret) @@ -362,33 +513,30 @@ static 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, - 1), - 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); ret = spi_mem_exec_op(nor->spimem, &op); } else { - ret = nor->controller_ops->write_reg(nor, - enable ? SPINOR_OP_EN4B : - SPINOR_OP_EX4B, - NULL, 0); + ret = spi_nor_controller_ops_write_reg(nor, + enable ? SPINOR_OP_EN4B : + SPINOR_OP_EX4B, + NULL, 0); } if (ret) @@ -398,249 +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, 1), - SPI_MEM_OP_NO_ADDR, - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_OUT(1, nor->bouncebuf, 1)); - - ret = spi_mem_exec_op(nor->spimem, &op); - } else { - ret = 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, 1), - SPI_MEM_OP_NO_ADDR, - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_OUT(1, nor->bouncebuf, 1)); - - ret = spi_mem_exec_op(nor->spimem, &op); - } else { - ret = nor->controller_ops->write_reg(nor, SPINOR_OP_WREAR, - nor->bouncebuf, 1); - } - - if (ret) - dev_dbg(nor->dev, "error %d writing EAR\n", ret); - - return ret; -} - -/** - * spi_nor_xread_sr() - Read the Status Register on S3AN flashes. - * @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. - */ -int spi_nor_xread_sr(struct spi_nor *nor, u8 *sr) -{ - int ret; + struct spi_mem_op op = SPI_NOR_BRWR_OP(nor->bouncebuf); - if (nor->spimem) { - struct spi_mem_op op = - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_XRDSR, 1), - SPI_MEM_OP_NO_ADDR, - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_IN(1, sr, 1)); + spi_nor_spimem_setup_op(nor, &op, nor->reg_proto); ret = spi_mem_exec_op(nor->spimem, &op); } else { - ret = nor->controller_ops->read_reg(nor, SPINOR_OP_XRDSR, - sr, 1); + ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_BRWR, + nor->bouncebuf, 1); } if (ret) - dev_dbg(nor->dev, "error %d reading XRDSR\n", ret); + dev_dbg(nor->dev, "error %d setting 4-byte mode\n", ret); return ret; } /** - * spi_nor_xsr_ready() - Query the Status Register of the S3AN flash to see if - * the flash is ready for new commands. + * 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_xsr_ready(struct spi_nor *nor) +int spi_nor_sr_ready(struct spi_nor *nor) { int ret; - ret = spi_nor_xread_sr(nor, nor->bouncebuf); + ret = spi_nor_read_sr(nor, nor->bouncebuf); if (ret) return ret; - return !!(nor->bouncebuf[0] & XSR_RDY); + return !(nor->bouncebuf[0] & SR_WIP); } /** - * spi_nor_clear_sr() - Clear the Status Register. + * spi_nor_use_parallel_locking() - Checks if RWW locking scheme shall be used * @nor: pointer to 'struct spi_nor'. + * + * Return: true if parallel locking is enabled, false otherwise. */ -static void spi_nor_clear_sr(struct spi_nor *nor) +static bool spi_nor_use_parallel_locking(struct spi_nor *nor) { - int ret; - - if (nor->spimem) { - struct spi_mem_op op = - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_CLSR, 1), - SPI_MEM_OP_NO_ADDR, - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_NO_DATA); - - ret = spi_mem_exec_op(nor->spimem, &op); - } else { - ret = nor->controller_ops->write_reg(nor, SPINOR_OP_CLSR, - NULL, 0); - } - - if (ret) - dev_dbg(nor->dev, "error %d clearing SR\n", ret); + return nor->flags & SNOR_F_RWW; } -/** - * 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) +/* Locking helpers for status read operations */ +static int spi_nor_rww_start_rdst(struct spi_nor *nor) { - int ret = spi_nor_read_sr(nor, nor->bouncebuf); + struct spi_nor_rww *rww = &nor->rww; - if (ret) - return ret; + guard(mutex)(&nor->lock); - 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); - - /* - * 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; + if (rww->ongoing_io || rww->ongoing_rd) + return -EAGAIN; - return -EIO; - } + rww->ongoing_io = true; + rww->ongoing_rd = true; - return !(nor->bouncebuf[0] & SR_WIP); + return 0; } -/** - * 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 void spi_nor_rww_end_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_CLFSR, 1), - SPI_MEM_OP_NO_ADDR, - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_NO_DATA); + guard(mutex)(&nor->lock); - ret = spi_mem_exec_op(nor->spimem, &op); - } else { - ret = nor->controller_ops->write_reg(nor, SPINOR_OP_CLFSR, - NULL, 0); - } - - if (ret) - dev_dbg(nor->dev, "error %d clearing FSR\n", ret); + rww->ongoing_io = false; + rww->ongoing_rd = false; } -/** - * 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 int spi_nor_lock_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); + if (spi_nor_use_parallel_locking(nor)) + return spi_nor_rww_start_rdst(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 0; +} - return -EIO; +static void spi_nor_unlock_rdst(struct spi_nor *nor) +{ + if (spi_nor_use_parallel_locking(nor)) { + spi_nor_rww_end_rdst(nor); + wake_up(&nor->rww.wait); } - - return !!(nor->bouncebuf[0] & FSR_READY); } /** @@ -651,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; - if (nor->flags & SNOR_F_READY_XSR_RDY) - sr = spi_nor_xsr_ready(nor); + ret = spi_nor_lock_rdst(nor); + if (ret) + return 0; + + /* 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; } /** @@ -713,6 +751,39 @@ int spi_nor_wait_till_ready(struct spi_nor *nor) } /** + * spi_nor_global_block_unlock() - Unlock Global Block Protection. + * @nor: pointer to 'struct spi_nor'. + * + * Return: 0 on success, -errno otherwise. + */ +int spi_nor_global_block_unlock(struct spi_nor *nor) +{ + int ret; + + ret = spi_nor_write_enable(nor); + if (ret) + return ret; + + if (nor->spimem) { + struct spi_mem_op op = SPI_NOR_GBULK_OP; + + spi_nor_spimem_setup_op(nor, &op, nor->reg_proto); + + ret = spi_mem_exec_op(nor->spimem, &op); + } else { + ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_GBULK, + NULL, 0); + } + + if (ret) { + dev_dbg(nor->dev, "error %d on Global Block Unlock\n", ret); + return ret; + } + + return spi_nor_wait_till_ready(nor); +} + +/** * spi_nor_write_sr() - Write the Status Register. * @nor: pointer to 'struct spi_nor'. * @sr: pointer to DMA-able buffer to write to the Status Register. @@ -720,7 +791,7 @@ int spi_nor_wait_till_ready(struct spi_nor *nor) * * Return: 0 on success, -errno otherwise. */ -static int spi_nor_write_sr(struct spi_nor *nor, const u8 *sr, size_t len) +int spi_nor_write_sr(struct spi_nor *nor, const u8 *sr, size_t len) { int ret; @@ -729,16 +800,14 @@ static 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, 1), - SPI_MEM_OP_NO_ADDR, - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_OUT(len, sr, 1)); + struct spi_mem_op op = SPI_NOR_WRSR_OP(sr, len); + + spi_nor_spimem_setup_op(nor, &op, nor->reg_proto); ret = spi_mem_exec_op(nor->spimem, &op); } else { - ret = nor->controller_ops->write_reg(nor, SPINOR_OP_WRSR, - sr, len); + ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_WRSR, sr, + len); } if (ret) { @@ -800,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 { @@ -827,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; @@ -854,7 +933,7 @@ static int spi_nor_write_16bit_sr_and_check(struct spi_nor *nor, u8 sr1) * * Return: 0 on success, -errno otherwise. */ -static int spi_nor_write_16bit_cr_and_check(struct spi_nor *nor, u8 cr) +int spi_nor_write_16bit_cr_and_check(struct spi_nor *nor, u8 cr) { int ret; u8 *sr_cr = nor->bouncebuf; @@ -906,7 +985,7 @@ static int spi_nor_write_16bit_cr_and_check(struct spi_nor *nor, u8 cr) * * Return: 0 on success, -errno otherwise. */ -static int spi_nor_write_sr_and_check(struct spi_nor *nor, u8 sr1) +int spi_nor_write_sr_and_check(struct spi_nor *nor, u8 sr1) { if (nor->flags & SNOR_F_HAS_16BIT_SR) return spi_nor_write_16bit_sr_and_check(nor, sr1); @@ -931,16 +1010,14 @@ 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, 1), - SPI_MEM_OP_NO_ADDR, - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_OUT(1, sr2, 1)); + struct spi_mem_op op = SPI_NOR_WRSR2_OP(sr2); + + spi_nor_spimem_setup_op(nor, &op, nor->reg_proto); ret = spi_mem_exec_op(nor->spimem, &op); } else { - ret = nor->controller_ops->write_reg(nor, SPINOR_OP_WRSR2, - sr2, 1); + ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_WRSR2, + sr2, 1); } if (ret) { @@ -965,16 +1042,14 @@ 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, 1), - SPI_MEM_OP_NO_ADDR, - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_IN(1, sr2, 1)); + struct spi_mem_op op = SPI_NOR_RDSR2_OP(sr2); + + spi_nor_spimem_setup_op(nor, &op, nor->reg_proto); ret = spi_mem_exec_op(nor->spimem, &op); } else { - ret = nor->controller_ops->read_reg(nor, SPINOR_OP_RDSR2, - sr2, 1); + ret = spi_nor_controller_ops_read_reg(nor, SPINOR_OP_RDSR2, sr2, + 1); } if (ret) @@ -984,28 +1059,35 @@ 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, 1), - 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->reg_proto); ret = spi_mem_exec_op(nor->spimem, &op); } else { - ret = nor->controller_ops->write_reg(nor, SPINOR_OP_CHIP_ERASE, - NULL, 0); + if (multi_die) + return -EOPNOTSUPP; + + ret = spi_nor_controller_ops_write_reg(nor, + SPINOR_OP_CHIP_ERASE, + NULL, 0); } if (ret) @@ -1075,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) @@ -1097,69 +1179,297 @@ 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) +{ + struct spi_nor_rww *rww = &nor->rww; + + guard(mutex)(&nor->lock); + + if (rww->ongoing_io) + return false; + + rww->ongoing_io = true; + + 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) { - if (!nor->params->convert_addr) - return addr; + 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); + } - return nor->params->convert_addr(nor, addr); + spi_nor_unprep(nor); } /* * Initiate the erasure of a single sector */ -static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr) +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, 1), - SPI_MEM_OP_ADDR(nor->addr_width, addr, 1), - 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->reg_proto); return spi_mem_exec_op(nor->spimem, &op); } else if (nor->controller_ops->erase) { - return nor->controller_ops->erase(nor, addr); + return spi_nor_controller_ops_erase(nor, 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 nor->controller_ops->write_reg(nor, nor->erase_opcode, - nor->bouncebuf, nor->addr_width); + return spi_nor_controller_ops_write_reg(nor, nor->erase_opcode, + nor->bouncebuf, nor->addr_nbytes); } /** @@ -1199,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 @@ -1207,82 +1516,29 @@ 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]; - - /* Don't erase more than what the user has asked for. */ - if (erase->size > len) + if (!erase->size) continue; /* Alignment is not mandatory for overlaid regions */ - if (region->offset & SNOR_OVERLAID_REGION) + if (region->overlaid && region->size <= len) return erase; - spi_nor_div_by_erase_size(erase, addr, &rem); - if (rem) + /* Don't erase more than what the user has asked for. */ + if (erase->size > len) continue; - else + + spi_nor_div_by_erase_size(erase, addr, &rem); + if (!rem) return erase; } 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 @@ -1305,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; @@ -1349,43 +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); - - while (len) { - erase = spi_nor_find_best_erase_type(map, region, addr, len); - if (!erase) - goto destroy_erase_cmd_list; + for (i = 0; i < map->n_regions && len; i++) { + region = &map->regions[i]; + region_end = region->offset + region->size; - if (prev_erase != erase || - 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; @@ -1419,20 +1668,30 @@ static int spi_nor_erase_multi_sectors(struct spi_nor *nor, u64 addr, u32 len) list_for_each_entry_safe(cmd, next, &erase_list, list) { nor->erase_opcode = cmd->opcode; while (cmd->count) { - ret = spi_nor_write_enable(nor); + 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_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; - addr += cmd->size; - cmd->count--; - ret = spi_nor_wait_till_ready(nor); if (ret) goto destroy_erase_cmd_list; + + addr += cmd->size; + cmd->count--; } list_del(&cmd->list); kfree(cmd); @@ -1445,15 +1704,62 @@ 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 is there is a problem erasing. + * one or more erase sectors. Return an error if there is a problem erasing. */ 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, @@ -1468,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; @@ -1505,20 +1801,27 @@ 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; - addr += mtd->erasesize; - len -= mtd->erasesize; - ret = spi_nor_wait_till_ready(nor); if (ret) goto erase_err; + + addr += mtd->erasesize; + len -= mtd->erasesize; } /* erase multiple sectors */ @@ -1531,381 +1834,11 @@ 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; } -static u8 spi_nor_get_sr_bp_mask(struct spi_nor *nor) -{ - u8 mask = SR_BP2 | SR_BP1 | SR_BP0; - - if (nor->flags & SNOR_F_HAS_SR_BP3_BIT6) - return mask | SR_BP3_BIT6; - - if (nor->flags & SNOR_F_HAS_4BIT_BP) - return mask | SR_BP3; - - return mask; -} - -static u8 spi_nor_get_sr_tb_mask(struct spi_nor *nor) -{ - if (nor->flags & SNOR_F_HAS_SR_TB_BIT6) - return SR_TB_BIT6; - else - return SR_TB_BIT5; -} - -static u64 spi_nor_get_min_prot_length_sr(struct spi_nor *nor) -{ - unsigned int bp_slots, bp_slots_needed; - u8 mask = spi_nor_get_sr_bp_mask(nor); - - /* Reserved one for "protect none" and one for "protect all". */ - bp_slots = (1 << hweight8(mask)) - 2; - bp_slots_needed = ilog2(nor->info->n_sectors); - - if (bp_slots_needed > bp_slots) - return nor->info->sector_size << - (bp_slots_needed - bp_slots); - else - return nor->info->sector_size; -} - -static void spi_nor_get_locked_range_sr(struct spi_nor *nor, u8 sr, loff_t *ofs, - uint64_t *len) -{ - struct mtd_info *mtd = &nor->mtd; - u64 min_prot_len; - u8 mask = spi_nor_get_sr_bp_mask(nor); - u8 tb_mask = spi_nor_get_sr_tb_mask(nor); - u8 bp, val = sr & mask; - - if (nor->flags & SNOR_F_HAS_SR_BP3_BIT6 && val & SR_BP3_BIT6) - val = (val & ~SR_BP3_BIT6) | SR_BP3; - - bp = val >> SR_BP_SHIFT; - - if (!bp) { - /* No protection */ - *ofs = 0; - *len = 0; - return; - } - - min_prot_len = spi_nor_get_min_prot_length_sr(nor); - *len = min_prot_len << (bp - 1); - - if (*len > mtd->size) - *len = mtd->size; - - if (nor->flags & SNOR_F_HAS_SR_TB && sr & tb_mask) - *ofs = 0; - else - *ofs = mtd->size - *len; -} - -/* - * Return 1 if the entire region is locked (if @locked is true) or unlocked (if - * @locked is false); 0 otherwise - */ -static int spi_nor_check_lock_status_sr(struct spi_nor *nor, loff_t ofs, - uint64_t len, u8 sr, bool locked) -{ - loff_t lock_offs; - uint64_t lock_len; - - if (!len) - return 1; - - spi_nor_get_locked_range_sr(nor, sr, &lock_offs, &lock_len); - - if (locked) - /* Requested range is a sub-range of locked range */ - return (ofs + len <= lock_offs + lock_len) && (ofs >= lock_offs); - else - /* Requested range does not overlap with locked range */ - return (ofs >= lock_offs + lock_len) || (ofs + len <= lock_offs); -} - -static int spi_nor_is_locked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len, - u8 sr) -{ - return spi_nor_check_lock_status_sr(nor, ofs, len, sr, true); -} - -static int spi_nor_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len, - u8 sr) -{ - return spi_nor_check_lock_status_sr(nor, ofs, len, sr, false); -} - -/* - * Lock a region of the flash. Compatible with ST Micro and similar flash. - * Supports the block protection bits BP{0,1,2}/BP{0,1,2,3} in the status - * register - * (SR). Does not support these features found in newer SR bitfields: - * - SEC: sector/block protect - only handle SEC=0 (block protect) - * - CMP: complement protect - only support CMP=0 (range is not complemented) - * - * Support for the following is provided conditionally for some flash: - * - TB: top/bottom protect - * - * Sample table portion for 8MB flash (Winbond w25q64fw): - * - * SEC | TB | BP2 | BP1 | BP0 | Prot Length | Protected Portion - * -------------------------------------------------------------------------- - * X | X | 0 | 0 | 0 | NONE | NONE - * 0 | 0 | 0 | 0 | 1 | 128 KB | Upper 1/64 - * 0 | 0 | 0 | 1 | 0 | 256 KB | Upper 1/32 - * 0 | 0 | 0 | 1 | 1 | 512 KB | Upper 1/16 - * 0 | 0 | 1 | 0 | 0 | 1 MB | Upper 1/8 - * 0 | 0 | 1 | 0 | 1 | 2 MB | Upper 1/4 - * 0 | 0 | 1 | 1 | 0 | 4 MB | Upper 1/2 - * X | X | 1 | 1 | 1 | 8 MB | ALL - * ------|-------|-------|-------|-------|---------------|------------------- - * 0 | 1 | 0 | 0 | 1 | 128 KB | Lower 1/64 - * 0 | 1 | 0 | 1 | 0 | 256 KB | Lower 1/32 - * 0 | 1 | 0 | 1 | 1 | 512 KB | Lower 1/16 - * 0 | 1 | 1 | 0 | 0 | 1 MB | Lower 1/8 - * 0 | 1 | 1 | 0 | 1 | 2 MB | Lower 1/4 - * 0 | 1 | 1 | 1 | 0 | 4 MB | Lower 1/2 - * - * Returns negative on errors, 0 on success. - */ -static int spi_nor_sr_lock(struct spi_nor *nor, loff_t ofs, uint64_t len) -{ - struct mtd_info *mtd = &nor->mtd; - u64 min_prot_len; - int ret, status_old, status_new; - u8 mask = spi_nor_get_sr_bp_mask(nor); - u8 tb_mask = spi_nor_get_sr_tb_mask(nor); - u8 pow, val; - loff_t lock_len; - bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB; - bool use_top; - - ret = spi_nor_read_sr(nor, nor->bouncebuf); - if (ret) - return ret; - - status_old = nor->bouncebuf[0]; - - /* If nothing in our range is unlocked, we don't need to do anything */ - if (spi_nor_is_locked_sr(nor, ofs, len, status_old)) - return 0; - - /* If anything below us is unlocked, we can't use 'bottom' protection */ - if (!spi_nor_is_locked_sr(nor, 0, ofs, status_old)) - can_be_bottom = false; - - /* If anything above us is unlocked, we can't use 'top' protection */ - if (!spi_nor_is_locked_sr(nor, ofs + len, mtd->size - (ofs + len), - status_old)) - can_be_top = false; - - if (!can_be_bottom && !can_be_top) - return -EINVAL; - - /* Prefer top, if both are valid */ - use_top = can_be_top; - - /* lock_len: length of region that should end up locked */ - if (use_top) - lock_len = mtd->size - ofs; - else - lock_len = ofs + len; - - if (lock_len == mtd->size) { - val = mask; - } else { - min_prot_len = spi_nor_get_min_prot_length_sr(nor); - pow = ilog2(lock_len) - ilog2(min_prot_len) + 1; - val = pow << SR_BP_SHIFT; - - if (nor->flags & SNOR_F_HAS_SR_BP3_BIT6 && val & SR_BP3) - val = (val & ~SR_BP3) | SR_BP3_BIT6; - - if (val & ~mask) - return -EINVAL; - - /* Don't "lock" with no region! */ - if (!(val & mask)) - return -EINVAL; - } - - status_new = (status_old & ~mask & ~tb_mask) | val; - - /* Disallow further writes if WP pin is asserted */ - status_new |= SR_SRWD; - - if (!use_top) - status_new |= tb_mask; - - /* Don't bother if they're the same */ - if (status_new == status_old) - return 0; - - /* Only modify protection if it will not unlock other areas */ - if ((status_new & mask) < (status_old & mask)) - return -EINVAL; - - return spi_nor_write_sr_and_check(nor, status_new); -} - -/* - * Unlock a region of the flash. See spi_nor_sr_lock() for more info - * - * Returns negative on errors, 0 on success. - */ -static int spi_nor_sr_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len) -{ - struct mtd_info *mtd = &nor->mtd; - u64 min_prot_len; - int ret, status_old, status_new; - u8 mask = spi_nor_get_sr_bp_mask(nor); - u8 tb_mask = spi_nor_get_sr_tb_mask(nor); - u8 pow, val; - loff_t lock_len; - bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB; - bool use_top; - - ret = spi_nor_read_sr(nor, nor->bouncebuf); - if (ret) - return ret; - - status_old = nor->bouncebuf[0]; - - /* If nothing in our range is locked, we don't need to do anything */ - if (spi_nor_is_unlocked_sr(nor, ofs, len, status_old)) - return 0; - - /* If anything below us is locked, we can't use 'top' protection */ - if (!spi_nor_is_unlocked_sr(nor, 0, ofs, status_old)) - can_be_top = false; - - /* If anything above us is locked, we can't use 'bottom' protection */ - if (!spi_nor_is_unlocked_sr(nor, ofs + len, mtd->size - (ofs + len), - status_old)) - can_be_bottom = false; - - if (!can_be_bottom && !can_be_top) - return -EINVAL; - - /* Prefer top, if both are valid */ - use_top = can_be_top; - - /* lock_len: length of region that should remain locked */ - if (use_top) - lock_len = mtd->size - (ofs + len); - else - lock_len = ofs; - - if (lock_len == 0) { - val = 0; /* fully unlocked */ - } else { - min_prot_len = spi_nor_get_min_prot_length_sr(nor); - pow = ilog2(lock_len) - ilog2(min_prot_len) + 1; - val = pow << SR_BP_SHIFT; - - if (nor->flags & SNOR_F_HAS_SR_BP3_BIT6 && val & SR_BP3) - val = (val & ~SR_BP3) | SR_BP3_BIT6; - - /* Some power-of-two sizes are not supported */ - if (val & ~mask) - return -EINVAL; - } - - status_new = (status_old & ~mask & ~tb_mask) | val; - - /* Don't protect status register if we're fully unlocked */ - if (lock_len == 0) - status_new &= ~SR_SRWD; - - if (!use_top) - status_new |= tb_mask; - - /* Don't bother if they're the same */ - if (status_new == status_old) - return 0; - - /* Only modify protection if it will not lock other areas */ - if ((status_new & mask) > (status_old & mask)) - return -EINVAL; - - return spi_nor_write_sr_and_check(nor, status_new); -} - -/* - * Check if a region of the flash is (completely) locked. See spi_nor_sr_lock() - * for more info. - * - * Returns 1 if entire region is locked, 0 if any portion is unlocked, and - * negative on errors. - */ -static int spi_nor_sr_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len) -{ - int ret; - - ret = spi_nor_read_sr(nor, nor->bouncebuf); - if (ret) - return ret; - - return spi_nor_is_locked_sr(nor, ofs, len, nor->bouncebuf[0]); -} - -static const struct spi_nor_locking_ops spi_nor_sr_locking_ops = { - .lock = spi_nor_sr_lock, - .unlock = spi_nor_sr_unlock, - .is_locked = spi_nor_sr_is_locked, -}; - -static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) -{ - struct spi_nor *nor = mtd_to_spi_nor(mtd); - int ret; - - ret = spi_nor_lock_and_prep(nor); - if (ret) - return ret; - - ret = nor->params->locking_ops->lock(nor, ofs, len); - - spi_nor_unlock_and_unprep(nor); - return ret; -} - -static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) -{ - struct spi_nor *nor = mtd_to_spi_nor(mtd); - int ret; - - ret = spi_nor_lock_and_prep(nor); - if (ret) - return ret; - - ret = nor->params->locking_ops->unlock(nor, ofs, len); - - spi_nor_unlock_and_unprep(nor); - return ret; -} - -static int spi_nor_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len) -{ - struct spi_nor *nor = mtd_to_spi_nor(mtd); - int ret; - - ret = spi_nor_lock_and_prep(nor); - if (ret) - return ret; - - ret = nor->params->locking_ops->is_locked(nor, ofs, len); - - spi_nor_unlock_and_unprep(nor); - return ret; -} - /** * spi_nor_sr1_bit6_quad_enable() - Set the Quad Enable BIT(6) in the Status * Register 1. @@ -2008,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, @@ -2022,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; + } + + 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; - dev_err(nor->dev, "unrecognized JEDEC id bytes: %*ph\n", - SPI_NOR_MAX_ID_LEN, id); - return ERR_PTR(-ENODEV); + /* + * 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; @@ -2115,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; } @@ -2128,45 +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). - * Power of two numbers have only one bit set and we can use - * the instruction hweight32 to detect if we need to do a - * modulus (do_div()) or not. - */ - if (hweight32(nor->page_size) == 1) { - 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; @@ -2179,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; } @@ -2204,7 +2271,7 @@ static int spi_nor_check(struct spi_nor *nor) return 0; } -static void +void spi_nor_set_read_settings(struct spi_nor_read_command *read, u8 num_mode_clocks, u8 num_wait_states, @@ -2253,13 +2320,14 @@ int spi_nor_hwcaps_read2cmd(u32 hwcaps) { SNOR_HWCAPS_READ_1_8_8, SNOR_CMD_READ_1_8_8 }, { SNOR_HWCAPS_READ_8_8_8, SNOR_CMD_READ_8_8_8 }, { SNOR_HWCAPS_READ_1_8_8_DTR, SNOR_CMD_READ_1_8_8_DTR }, + { SNOR_HWCAPS_READ_8_8_8_DTR, SNOR_CMD_READ_8_8_8_DTR }, }; return spi_nor_hwcaps2cmd(hwcaps, hwcaps_read2cmd, 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 }, @@ -2269,6 +2337,7 @@ static int spi_nor_hwcaps_pp2cmd(u32 hwcaps) { SNOR_HWCAPS_PP_1_1_8, SNOR_CMD_PP_1_1_8 }, { SNOR_HWCAPS_PP_1_8_8, SNOR_CMD_PP_1_8_8 }, { SNOR_HWCAPS_PP_8_8_8, SNOR_CMD_PP_8_8_8 }, + { SNOR_HWCAPS_PP_8_8_8_DTR, SNOR_CMD_PP_8_8_8_DTR }, }; return spi_nor_hwcaps2cmd(hwcaps, hwcaps_pp2cmd, @@ -2281,7 +2350,7 @@ static int spi_nor_hwcaps_pp2cmd(u32 hwcaps) *@nor: pointer to a 'struct spi_nor' *@op: pointer to op template to be checked * - * Returns 0 if operation is supported, -ENOTSUPP otherwise. + * Returns 0 if operation is supported, -EOPNOTSUPP otherwise. */ static int spi_nor_spimem_check_op(struct spi_nor *nor, struct spi_mem_op *op) @@ -2294,13 +2363,13 @@ 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) - return -ENOTSUPP; + if (nor->params->size > SZ_16M) + return -EOPNOTSUPP; /* If flash size <= 16MB, 3 address bytes are sufficient */ op->addr.nbytes = 3; if (!spi_mem_supports_op(nor->spimem, op)) - return -ENOTSUPP; + return -EOPNOTSUPP; } return 0; @@ -2312,22 +2381,20 @@ static int spi_nor_spimem_check_op(struct spi_nor *nor, *@nor: pointer to a 'struct spi_nor' *@read: pointer to op template to be checked * - * Returns 0 if operation is supported, -ENOTSUPP otherwise. + * Returns 0 if operation is supported, -EOPNOTSUPP otherwise. */ 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, 1), - SPI_MEM_OP_ADDR(3, 0, 1), - SPI_MEM_OP_DUMMY(0, 1), - SPI_MEM_OP_DATA_IN(0, NULL, 1)); + struct spi_mem_op op = SPI_NOR_READ_OP(read->opcode); + + spi_nor_spimem_setup_op(nor, &op, read->proto); - op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(read->proto); - op.addr.buswidth = spi_nor_get_protocol_addr_nbits(read->proto); - op.data.buswidth = spi_nor_get_protocol_data_nbits(read->proto); - op.dummy.buswidth = op.addr.buswidth; + /* convert the dummy cycles to the number of bytes */ 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; return spi_nor_spimem_check_op(nor, &op); } @@ -2338,19 +2405,14 @@ static int spi_nor_spimem_check_readop(struct spi_nor *nor, *@nor: pointer to a 'struct spi_nor' *@pp: pointer to op template to be checked * - * Returns 0 if operation is supported, -ENOTSUPP otherwise. + * Returns 0 if operation is supported, -EOPNOTSUPP otherwise. */ 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, 1), - SPI_MEM_OP_ADDR(3, 0, 1), - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_OUT(0, NULL, 1)); + struct spi_mem_op op = SPI_NOR_PP_OP(pp->opcode); - op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(pp->proto); - op.addr.buswidth = spi_nor_get_protocol_addr_nbits(pp->proto); - op.data.buswidth = spi_nor_get_protocol_data_nbits(pp->proto); + spi_nor_spimem_setup_op(nor, &op, pp->proto); return spi_nor_spimem_check_op(nor, &op); } @@ -2368,12 +2430,16 @@ spi_nor_spimem_adjust_hwcaps(struct spi_nor *nor, u32 *hwcaps) struct spi_nor_flash_parameter *params = nor->params; unsigned int cap; - /* DTR modes are not supported yet, mask them all. */ - *hwcaps &= ~SNOR_HWCAPS_DTR; - /* X-X-X modes are not supported yet, mask them all. */ *hwcaps &= ~SNOR_HWCAPS_X_X_X; + /* + * If the reset line is broken, we do not want to enter a stateful + * mode. + */ + if (nor->flags & SNOR_F_BROKEN_RESET) + *hwcaps &= ~(SNOR_HWCAPS_X_X_X | SNOR_HWCAPS_X_X_X_DTR); + for (cap = 0; cap < sizeof(*hwcaps) * BITS_PER_BYTE; cap++) { int rdidx, ppidx; @@ -2393,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; + } } /** @@ -2412,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 @@ -2421,32 +2506,29 @@ 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, const struct sfdp_parameter_header *bfpt_header, - const struct sfdp_bfpt *bfpt, - struct spi_nor_flash_parameter *params) + const struct sfdp_bfpt *bfpt) { int ret; if (nor->manufacturer && nor->manufacturer->fixups && nor->manufacturer->fixups->post_bfpt) { ret = nor->manufacturer->fixups->post_bfpt(nor, bfpt_header, - bfpt, params); + bfpt); if (ret) return ret; } if (nor->info->fixups && nor->info->fixups->post_bfpt) - return nor->info->fixups->post_bfpt(nor, bfpt_header, bfpt, - params); + return nor->info->fixups->post_bfpt(nor, bfpt_header, bfpt); return 0; } @@ -2504,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. @@ -2514,30 +2593,38 @@ 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; } /* - * Otherwise, the current erase size is still a valid canditate. + * Otherwise, the current erase size is still a valid candidate. * Select the biggest valid candidate. */ if (!erase && tested_erase->size) @@ -2549,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; } @@ -2559,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; /* @@ -2570,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; @@ -2602,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; @@ -2628,7 +2751,7 @@ static int spi_nor_default_setup(struct spi_nor *nor, * controller directly implements the spi_nor interface. * Yet another reason to switch to spi-mem. */ - ignored_mask = SNOR_HWCAPS_X_X_X; + ignored_mask = SNOR_HWCAPS_X_X_X | SNOR_HWCAPS_X_X_X_DTR; if (shared_mask & ignored_mask) { dev_dbg(nor->dev, "SPI n-n-n protocols are not supported.\n"); @@ -2660,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); } /** @@ -2688,96 +2802,59 @@ 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, &sfdp_params)) { - nor->addr_width = 0; - nor->flags &= ~SNOR_F_4B_OPCODES; - } else { - memcpy(nor->params, &sfdp_params, sizeof(*nor->params)); - } -} - -/** - * 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 legacy 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; - /* Default to 16-bit Write Status (01h) Command */ - nor->flags |= SNOR_F_HAS_16BIT_SR; - - /* Set SPI NOR sizes. */ - 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); } - /* 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 (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); + } + + 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 + * Legacy SPI, use Legacy SPI opcode there as well. + */ + spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP_8_8_8_DTR], + SPINOR_OP_PP, SNOR_PROTO_8_8_8_DTR); + } /* * Sector Erase settings. Sort Erase Types in ascending order, with the @@ -2785,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 (nor->info->fixups && nor->info->fixups->post_sfdp) - nor->info->fixups->post_sfdp(nor); + 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 (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) - nor->params->locking_ops = &spi_nor_sr_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); + } } /** @@ -2859,40 +3097,83 @@ 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 (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); + } + + ret = spi_nor_late_init_params(nor); + if (ret) + return ret; + + if (WARN_ON(!is_power_of_2(nor->params->page_size))) + return -EINVAL; + + return 0; +} + +/** 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_set_octal_dtr(struct spi_nor *nor, bool enable) +{ + int ret; + + if (!nor->params->set_octal_dtr) + return 0; + + if (!(nor->read_proto == SNOR_PROTO_8_8_8_DTR && + nor->write_proto == SNOR_PROTO_8_8_8_DTR)) + return 0; - if ((nor->info->flags & (SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)) && - !(nor->info->flags & SPI_NOR_SKIP_SFDP)) - spi_nor_sfdp_init_params(nor); + if (!(nor->flags & SNOR_F_IO_MODE_EN_VOLATILE)) + return 0; - spi_nor_post_sfdp_fixups(nor); + ret = nor->params->set_octal_dtr(nor, enable); + if (ret) + return ret; - spi_nor_late_init_params(nor); + if (enable) + nor->reg_proto = SNOR_PROTO_8_8_8_DTR; + else + nor->reg_proto = SNOR_PROTO_1_1_1; return 0; } @@ -2916,18 +3197,40 @@ static int spi_nor_quad_enable(struct spi_nor *nor) } /** - * spi_nor_unlock_all() - Unlocks the entire flash memory array. - * @nor: pointer to a 'struct spi_nor'. + * spi_nor_set_4byte_addr_mode() - Set address mode. + * @nor: pointer to a 'struct spi_nor'. + * @enable: enable/disable 4 byte address mode. * - * Some SPI NOR flashes are write protected by default after a power-on reset - * cycle, in order to avoid inadvertent writes during power-up. Backward - * compatibility imposes to unlock the entire flash memory array at power-up - * by default. + * Return: 0 on success, -errno otherwise. */ -static int spi_nor_unlock_all(struct spi_nor *nor) +int spi_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable) { - if (nor->flags & SNOR_F_HAS_LOCK) - return spi_nor_unlock(&nor->mtd, 0, nor->params->size); + 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; } @@ -2936,34 +3239,104 @@ static int spi_nor_init(struct spi_nor *nor) { int err; - err = spi_nor_quad_enable(nor); + err = spi_nor_set_octal_dtr(nor, true); if (err) { - dev_dbg(nor->dev, "quad mode not supported\n"); + dev_dbg(nor->dev, "octal mode not supported\n"); return err; } - err = spi_nor_unlock_all(nor); + err = spi_nor_quad_enable(nor); if (err) { - dev_dbg(nor->dev, "Failed to unlock the entire flash memory array\n"); + dev_dbg(nor->dev, "quad mode not supported\n"); return err; } - if (nor->addr_width == 4 && !(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); - } + /* + * Some SPI NOR flashes are write protected by default after a power-on + * reset cycle, in order to avoid inadvertent writes during power-up. + * Backward compatibility imposes to unlock the entire flash memory + * array at power-up by default. Depending on the kernel configuration + * (1) do nothing, (2) always unlock the entire flash array or (3) + * unlock the entire flash array only when the software write + * protection bits are volatile. The latter is indicated by + * SNOR_F_SWP_IS_VOLATILE. + */ + if (IS_ENABLED(CONFIG_MTD_SPI_NOR_SWP_DISABLE) || + (IS_ENABLED(CONFIG_MTD_SPI_NOR_SWP_DISABLE_ON_VOLATILE) && + nor->flags & SNOR_F_SWP_IS_VOLATILE)) + spi_nor_try_unlock_all(nor); + + if (nor->addr_nbytes == 4 && + nor->read_proto != SNOR_PROTO_8_8_8_DTR && + !(nor->flags & SNOR_F_4B_OPCODES)) + return spi_nor_set_4byte_addr_mode(nor, true); return 0; } +/** + * spi_nor_soft_reset() - Perform a software reset + * @nor: pointer to 'struct spi_nor' + * + * Performs a "Soft Reset and Enter Default Protocol Mode" sequence which resets + * the device to its power-on-reset state. This is useful when the software has + * made some changes to device (volatile) registers and needs to reset it before + * shutting down, for example. + * + * Not every flash supports this sequence. The same set of opcodes might be used + * for some other operation on a flash that does not support this. Support for + * this sequence can be discovered via SFDP in the BFPT table. + * + * Return: 0 on success, -errno otherwise. + */ +static void spi_nor_soft_reset(struct spi_nor *nor) +{ + struct spi_mem_op op; + int ret; + + 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) { + if (ret != -EOPNOTSUPP) + dev_warn(nor->dev, "Software reset failed: %d\n", ret); + return; + } + + op = (struct spi_mem_op)SPINOR_SRST_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); + return; + } + + /* + * Software Reset is not instant, and the delay varies from flash to + * flash. Looking at a few flashes, most range somewhere below 100 + * microseconds. So, sleep for a range of 200-400 us. + */ + usleep_range(SPI_NOR_SRST_SLEEP_MIN, SPI_NOR_SRST_SLEEP_MAX); +} + +/* mtd suspend handler */ +static int spi_nor_suspend(struct mtd_info *mtd) +{ + struct spi_nor *nor = mtd_to_spi_nor(mtd); + int ret; + + /* Disable octal DTR mode if we enabled it. */ + ret = spi_nor_set_octal_dtr(nor, false); + if (ret) + dev_err(nor->dev, "suspend() failed\n"); + + return ret; +} + /* mtd resume handler */ static void spi_nor_resume(struct mtd_info *mtd) { @@ -2977,23 +3350,67 @@ static void spi_nor_resume(struct mtd_info *mtd) dev_err(dev, "resume() failed\n"); } -void spi_nor_restore(struct spi_nor *nor) +static int spi_nor_get_device(struct mtd_info *mtd) { + struct mtd_info *master = mtd_get_master(mtd); + struct spi_nor *nor = mtd_to_spi_nor(master); + struct device *dev; + + if (nor->spimem) + dev = nor->spimem->spi->controller->dev.parent; + else + dev = nor->dev; + + if (!try_module_get(dev->driver->owner)) + return -ENODEV; + + return 0; +} + +static void spi_nor_put_device(struct mtd_info *mtd) +{ + struct mtd_info *master = mtd_get_master(mtd); + struct spi_nor *nor = mtd_to_spi_nor(master); + struct device *dev; + + if (nor->spimem) + dev = nor->spimem->spi->controller->dev.parent; + else + dev = nor->dev; + + module_put(dev->driver->owner); +} + +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]; } @@ -3003,81 +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->info->addr_width) { - nor->addr_width = nor->info->addr_width; - } else if (nor->mtd.size > 0x1000000) { - /* enable 4-byte addressing if the device exceeds 16MiB */ - nor->addr_width = 4; - } else { - nor->addr_width = 3; + 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; + + /* + * If caller has specified name of flash model that can normally + * be detected using JEDEC, let's verify it. + */ + 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 > SPI_NOR_MAX_ADDR_WIDTH) { - dev_dbg(nor->dev, "address width is too large: %u\n", - nor->addr_width); - return -EINVAL; + 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; } - /* 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); + 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; + } + + 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; - mtd->dbg.partname = info->name; - mtd->dbg.partid = devm_kasprintf(nor->dev, GFP_KERNEL, "spi-nor:%*phN", - info->id_len, info->id); + if (!spi_nor_has_uniform_erase(nor)) + return spi_nor_set_mtd_eraseregions(nor); + + 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; + usleep_range(1, 5); + gpiod_set_value_cansleep(reset, 1); + usleep_range(100, 150); + gpiod_set_value_cansleep(reset, 0); + usleep_range(1000, 1200); - 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; - } - } - - return info; + return 0; } int spi_nor_scan(struct spi_nor *nor, const char *name, @@ -3085,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) @@ -3103,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. */ @@ -3113,121 +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 = 1; - mtd->flags = MTD_CAP_NORFLASH; - mtd->size = nor->params->size; - mtd->_erase = spi_nor_erase; - mtd->_read = spi_nor_read; - mtd->_resume = spi_nor_resume; - - if (nor->params->locking_ops) { - mtd->_lock = spi_nor_lock; - mtd->_unlock = spi_nor_unlock; - mtd->_is_locked = spi_nor_is_locked; - } - - 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_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; - - 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; - /* 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; - 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); @@ -3235,23 +3641,28 @@ EXPORT_SYMBOL_GPL(spi_nor_scan); 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, 1), - SPI_MEM_OP_ADDR(nor->addr_width, 0, 1), - SPI_MEM_OP_DUMMY(nor->read_dummy, 1), - SPI_MEM_OP_DATA_IN(0, NULL, 1)), + .op_tmpl = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 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; - /* get transfer protocols. */ - op->cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->read_proto); - op->addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->read_proto); - op->dummy.buswidth = op->addr.buswidth; - op->data.buswidth = spi_nor_get_protocol_data_nbits(nor->read_proto); + spi_nor_spimem_setup_op(nor, op, nor->read_proto); /* convert the dummy cycles to the number of bytes */ op->dummy.nbytes = (nor->read_dummy * op->dummy.buswidth) / 8; + if (spi_nor_protocol_is_dtr(nor->read_proto)) + op->dummy.nbytes *= 2; + + /* + * Since spi_nor_spimem_setup_op() only sets buswidth when the number + * of data bytes is non-zero, the data buswidth won't be set here. So, + * do it explicitly. + */ + op->data.buswidth = spi_nor_get_protocol_data_nbits(nor->read_proto); nor->dirmap.rdesc = devm_spi_mem_dirmap_create(nor->dev, nor->spimem, &info); @@ -3261,24 +3672,27 @@ static int spi_nor_create_read_dirmap(struct spi_nor *nor) 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, 1), - SPI_MEM_OP_ADDR(nor->addr_width, 0, 1), + .op_tmpl = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 0), + SPI_MEM_OP_ADDR(nor->addr_nbytes, 0, 0), SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_OUT(0, NULL, 1)), + 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; - /* get transfer protocols. */ - op->cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->write_proto); - op->addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->write_proto); - op->dummy.buswidth = op->addr.buswidth; - op->data.buswidth = spi_nor_get_protocol_data_nbits(nor->write_proto); - if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second) op->addr.nbytes = 0; + spi_nor_spimem_setup_op(nor, op, nor->write_proto); + + /* + * Since spi_nor_spimem_setup_op() only sets buswidth when the number + * of data bytes is non-zero, the data buswidth won't be set here. So, + * do it explicitly. + */ + op->data.buswidth = spi_nor_get_protocol_data_nbits(nor->write_proto); + nor->dirmap.wdesc = devm_spi_mem_dirmap_create(nor->dev, nor->spimem, &info); return PTR_ERR_OR_ZERO(nor->dirmap.wdesc); @@ -3287,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 @@ -3297,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); @@ -3330,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; @@ -3383,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[] = { /* @@ -3451,6 +3871,7 @@ static struct spi_mem_driver spi_nor_driver = { .driver = { .name = "spi-nor", .of_match_table = spi_nor_of_table, + .dev_groups = spi_nor_sysfs_groups, }, .id_table = spi_nor_dev_ids, }, @@ -3458,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>"); |
